Merge tag 'split-asm_system_h-for-linus-20120328' of git://git.kernel.org/pub/scm...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 28 Mar 2012 22:58:21 +0000 (15:58 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 28 Mar 2012 22:58:21 +0000 (15:58 -0700)
Pull "Disintegrate and delete asm/system.h" from David Howells:
 "Here are a bunch of patches to disintegrate asm/system.h into a set of
  separate bits to relieve the problem of circular inclusion
  dependencies.

  I've built all the working defconfigs from all the arches that I can
  and made sure that they don't break.

  The reason for these patches is that I recently encountered a circular
  dependency problem that came about when I produced some patches to
  optimise get_order() by rewriting it to use ilog2().

  This uses bitops - and on the SH arch asm/bitops.h drags in
  asm-generic/get_order.h by a circuituous route involving asm/system.h.

  The main difficulty seems to be asm/system.h.  It holds a number of
  low level bits with no/few dependencies that are commonly used (eg.
  memory barriers) and a number of bits with more dependencies that
  aren't used in many places (eg.  switch_to()).

  These patches break asm/system.h up into the following core pieces:

    (1) asm/barrier.h

        Move memory barriers here.  This already done for MIPS and Alpha.

    (2) asm/switch_to.h

        Move switch_to() and related stuff here.

    (3) asm/exec.h

        Move arch_align_stack() here.  Other process execution related bits
        could perhaps go here from asm/processor.h.

    (4) asm/cmpxchg.h

        Move xchg() and cmpxchg() here as they're full word atomic ops and
        frequently used by atomic_xchg() and atomic_cmpxchg().

    (5) asm/bug.h

        Move die() and related bits.

    (6) asm/auxvec.h

        Move AT_VECTOR_SIZE_ARCH here.

  Other arch headers are created as needed on a per-arch basis."

Fixed up some conflicts from other header file cleanups and moving code
around that has happened in the meantime, so David's testing is somewhat
weakened by that.  We'll find out anything that got broken and fix it..

* tag 'split-asm_system_h-for-linus-20120328' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-asm_system: (38 commits)
  Delete all instances of asm/system.h
  Remove all #inclusions of asm/system.h
  Add #includes needed to permit the removal of asm/system.h
  Move all declarations of free_initmem() to linux/mm.h
  Disintegrate asm/system.h for OpenRISC
  Split arch_align_stack() out from asm-generic/system.h
  Split the switch_to() wrapper out of asm-generic/system.h
  Move the asm-generic/system.h xchg() implementation to asm-generic/cmpxchg.h
  Create asm-generic/barrier.h
  Make asm-generic/cmpxchg.h #include asm-generic/cmpxchg-local.h
  Disintegrate asm/system.h for Xtensa
  Disintegrate asm/system.h for Unicore32 [based on ver #3, changed by gxt]
  Disintegrate asm/system.h for Tile
  Disintegrate asm/system.h for Sparc
  Disintegrate asm/system.h for SH
  Disintegrate asm/system.h for Score
  Disintegrate asm/system.h for S390
  Disintegrate asm/system.h for PowerPC
  Disintegrate asm/system.h for PA-RISC
  Disintegrate asm/system.h for MN10300
  ...

3198 files changed:
Documentation/00-INDEX
Documentation/ABI/testing/sysfs-block-dm [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-rpmsg [new file with mode: 0644]
Documentation/ABI/testing/sysfs-driver-samsung-laptop
Documentation/DocBook/kgdb.tmpl
Documentation/DocBook/media/v4l/biblio.xml
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/controls.xml
Documentation/DocBook/media/v4l/selection-api.xml
Documentation/DocBook/media/v4l/v4l2.xml
Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml
Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml
Documentation/DocBook/media/v4l/vidioc-g-selection.xml
Documentation/DocBook/media/v4l/vidioc-querycap.xml
Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
Documentation/backlight/lp855x-driver.txt [new file with mode: 0644]
Documentation/clk.txt [new file with mode: 0644]
Documentation/crc32.txt [new file with mode: 0644]
Documentation/device-mapper/thin-provisioning.txt
Documentation/device-mapper/verity.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/atmel-aic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/atmel-at91.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/atmel-pmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/fsl.txt
Documentation/devicetree/bindings/arm/mrvl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/omap/intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/spear.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/tegra/emc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/twd.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/vexpress.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/tegra20-apbdma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-omap.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-twl4030.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio_atmel.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio_i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
Documentation/devicetree/bindings/gpio/mrvl-gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/sodaville.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/mrvl-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/sirf-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/atmel-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/sa1100-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/serial/mrvl-serial.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/atmel-usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/tegra-usb.txt
Documentation/dma-buf-sharing.txt
Documentation/dvb/cards.txt
Documentation/dvb/lmedm04.txt
Documentation/edac.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/ext4.txt
Documentation/filesystems/nfs/idmapper.txt
Documentation/filesystems/nfs/pnfs.txt
Documentation/gpio.txt
Documentation/hwmon/lm90
Documentation/hwmon/mc13783-adc
Documentation/hwmon/mcp3021 [new file with mode: 0644]
Documentation/i2c/busses/i2c-i801
Documentation/kernel-parameters.txt
Documentation/laptops/asus-laptop.txt
Documentation/laptops/sony-laptop.txt
Documentation/leds/leds-lp5521.txt
Documentation/remoteproc.txt [new file with mode: 0644]
Documentation/rpmsg.txt [new file with mode: 0644]
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/fimc.txt [new file with mode: 0644]
Documentation/video4linux/gspca.txt
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/ppc-pv.txt
Documentation/watchdog/00-INDEX [deleted file]
Documentation/watchdog/convert_drivers_to_kernel_api.txt
Documentation/watchdog/watchdog-kernel-api.txt
MAINTAINERS
arch/Kconfig
arch/alpha/include/asm/mman.h
arch/alpha/include/asm/pci.h
arch/alpha/kernel/pci.c
arch/alpha/kernel/pci_impl.h
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/sys_titan.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/compressed/head.S
arch/arm/boot/dts/am3517_mt_ventoux.dts [new file with mode: 0644]
arch/arm/boot/dts/at91sam9g20.dtsi
arch/arm/boot/dts/at91sam9g25ek.dts [new file with mode: 0644]
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9m10g45ek.dts
arch/arm/boot/dts/at91sam9x5.dtsi [new file with mode: 0644]
arch/arm/boot/dts/at91sam9x5cm.dtsi [new file with mode: 0644]
arch/arm/boot/dts/db8500.dtsi [new file with mode: 0644]
arch/arm/boot/dts/exynos5250-smdk5250.dts [new file with mode: 0644]
arch/arm/boot/dts/exynos5250.dtsi [new file with mode: 0644]
arch/arm/boot/dts/highbank.dts
arch/arm/boot/dts/imx27-phytec-phycore.dts [new file with mode: 0644]
arch/arm/boot/dts/imx27.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx51-babbage.dts
arch/arm/boot/dts/imx6q-arm2.dts
arch/arm/boot/dts/imx6q-sabrelite.dts
arch/arm/boot/dts/imx6q.dtsi
arch/arm/boot/dts/kirkwood-dreamplug.dts [new file with mode: 0644]
arch/arm/boot/dts/kirkwood.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap3-beagle.dts
arch/arm/boot/dts/omap3-evm.dts [new file with mode: 0644]
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap4-panda.dts
arch/arm/boot/dts/omap4-sdp.dts
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/pxa168-aspenite.dts [new file with mode: 0644]
arch/arm/boot/dts/pxa168.dtsi [new file with mode: 0644]
arch/arm/boot/dts/snowball.dts [new file with mode: 0644]
arch/arm/boot/dts/spear600-evb.dts [new file with mode: 0644]
arch/arm/boot/dts/spear600.dtsi [new file with mode: 0644]
arch/arm/boot/dts/tegra-cardhu.dts
arch/arm/boot/dts/tegra-harmony.dts
arch/arm/boot/dts/tegra-paz00.dts
arch/arm/boot/dts/tegra-seaboard.dts
arch/arm/boot/dts/tegra-trimslice.dts
arch/arm/boot/dts/tegra-ventana.dts
arch/arm/boot/dts/tegra20.dtsi
arch/arm/boot/dts/tegra30.dtsi
arch/arm/boot/dts/usb_a9g20-dab-mmx.dtsi [new file with mode: 0644]
arch/arm/boot/dts/usb_a9g20.dts
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi [new file with mode: 0644]
arch/arm/boot/dts/vexpress-v2m.dtsi [new file with mode: 0644]
arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts [new file with mode: 0644]
arch/arm/boot/dts/vexpress-v2p-ca5s.dts [new file with mode: 0644]
arch/arm/boot/dts/vexpress-v2p-ca9.dts [new file with mode: 0644]
arch/arm/common/Kconfig
arch/arm/common/Makefile
arch/arm/common/it8152.c
arch/arm/common/sa1111.c
arch/arm/common/time-acorn.c [deleted file]
arch/arm/common/timer-sp.c
arch/arm/configs/at91cap9_defconfig [deleted file]
arch/arm/configs/at91sam9g20_defconfig
arch/arm/configs/imx_v4_v5_defconfig
arch/arm/configs/imx_v6_v7_defconfig
arch/arm/configs/lpc32xx_defconfig [new file with mode: 0644]
arch/arm/configs/magician_defconfig
arch/arm/configs/mini2440_defconfig
arch/arm/configs/mxs_defconfig
arch/arm/configs/s3c2410_defconfig
arch/arm/configs/tct_hammer_defconfig
arch/arm/configs/tegra_defconfig
arch/arm/configs/u8500_defconfig
arch/arm/include/asm/hardware/arm_timer.h
arch/arm/include/asm/hardware/entry-macro-iomd.S
arch/arm/include/asm/hardware/sa1111.h
arch/arm/include/asm/hardware/timer-sp.h
arch/arm/include/asm/localtimer.h
arch/arm/include/asm/pci.h
arch/arm/include/asm/pgtable-nommu.h
arch/arm/include/asm/smp_twd.h
arch/arm/include/asm/system_misc.h
arch/arm/kernel/Makefile
arch/arm/kernel/bios32.c
arch/arm/kernel/crunch-bits.S [deleted file]
arch/arm/kernel/crunch.c [deleted file]
arch/arm/kernel/ecard.c [deleted file]
arch/arm/kernel/ecard.h [deleted file]
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/process.c
arch/arm/kernel/smp.c
arch/arm/kernel/smp_twd.c
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/Makefile.boot
arch/arm/mach-at91/at91cap9.c [deleted file]
arch/arm/mach-at91/at91cap9_devices.c [deleted file]
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91rm9200_devices.c
arch/arm/mach-at91/at91rm9200_time.c
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam926x_time.c
arch/arm/mach-at91/at91sam9_alt_reset.S
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9g45_reset.S
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/at91sam9x5.c [new file with mode: 0644]
arch/arm/mach-at91/at91x40.c
arch/arm/mach-at91/at91x40_time.c
arch/arm/mach-at91/board-afeb-9260v1.c
arch/arm/mach-at91/board-cam60.c
arch/arm/mach-at91/board-cap9adk.c [deleted file]
arch/arm/mach-at91/board-cpu9krea.c
arch/arm/mach-at91/board-cpuat91.c
arch/arm/mach-at91/board-dt.c
arch/arm/mach-at91/board-eco920.c
arch/arm/mach-at91/board-flexibity.c
arch/arm/mach-at91/board-kb9202.c
arch/arm/mach-at91/board-neocore926.c
arch/arm/mach-at91/board-picotux200.c
arch/arm/mach-at91/board-qil-a9260.c
arch/arm/mach-at91/board-rm9200dk.c
arch/arm/mach-at91/board-rm9200ek.c
arch/arm/mach-at91/board-sam9-l9260.c
arch/arm/mach-at91/board-sam9260ek.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board-snapper9260.c
arch/arm/mach-at91/board-stamp9g20.c
arch/arm/mach-at91/board-usb-a926x.c
arch/arm/mach-at91/board-yl-9200.c
arch/arm/mach-at91/clock.c
arch/arm/mach-at91/cpuidle.c
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/gpio.c
arch/arm/mach-at91/include/mach/at91_matrix.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/at91_pio.h
arch/arm/mach-at91/include/mach/at91_pmc.h
arch/arm/mach-at91/include/mach/at91_ramc.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/at91_shdwc.h
arch/arm/mach-at91/include/mach/at91_st.h
arch/arm/mach-at91/include/mach/at91cap9.h [deleted file]
arch/arm/mach-at91/include/mach/at91cap9_matrix.h [deleted file]
arch/arm/mach-at91/include/mach/at91rm9200.h
arch/arm/mach-at91/include/mach/at91rm9200_mc.h
arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/at91sam9260.h
arch/arm/mach-at91/include/mach/at91sam9260_matrix.h
arch/arm/mach-at91/include/mach/at91sam9261.h
arch/arm/mach-at91/include/mach/at91sam9261_matrix.h
arch/arm/mach-at91/include/mach/at91sam9263.h
arch/arm/mach-at91/include/mach/at91sam9263_matrix.h
arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h
arch/arm/mach-at91/include/mach/at91sam9_sdramc.h
arch/arm/mach-at91/include/mach/at91sam9g45.h
arch/arm/mach-at91/include/mach/at91sam9g45_matrix.h
arch/arm/mach-at91/include/mach/at91sam9rl.h
arch/arm/mach-at91/include/mach/at91sam9rl_matrix.h
arch/arm/mach-at91/include/mach/at91sam9x5.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/at91x40.h
arch/arm/mach-at91/include/mach/board.h
arch/arm/mach-at91/include/mach/cpu.h
arch/arm/mach-at91/include/mach/entry-macro.S
arch/arm/mach-at91/include/mach/gpio.h
arch/arm/mach-at91/include/mach/hardware.h
arch/arm/mach-at91/include/mach/io.h
arch/arm/mach-at91/include/mach/system.h [deleted file]
arch/arm/mach-at91/irq.c
arch/arm/mach-at91/pm.c
arch/arm/mach-at91/pm.h
arch/arm/mach-at91/pm_slowclock.S
arch/arm/mach-at91/setup.c
arch/arm/mach-at91/soc.h
arch/arm/mach-bcmring/core.c
arch/arm/mach-bcmring/include/mach/entry-macro.S
arch/arm/mach-bcmring/include/mach/system.h [deleted file]
arch/arm/mach-clps711x/common.c
arch/arm/mach-clps711x/include/mach/entry-macro.S
arch/arm/mach-clps711x/include/mach/system.h [deleted file]
arch/arm/mach-cns3xxx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-cns3xxx/include/mach/system.h [deleted file]
arch/arm/mach-cns3xxx/pcie.c
arch/arm/mach-davinci/board-dm355-evm.c
arch/arm/mach-davinci/board-dm355-leopard.c
arch/arm/mach-davinci/board-dm365-evm.c
arch/arm/mach-davinci/board-dm644x-evm.c
arch/arm/mach-davinci/board-dm646x-evm.c
arch/arm/mach-davinci/board-neuros-osd2.c
arch/arm/mach-davinci/board-sffsdr.c
arch/arm/mach-davinci/cpufreq.c
arch/arm/mach-davinci/da850.c
arch/arm/mach-davinci/davinci.h [new file with mode: 0644]
arch/arm/mach-davinci/devices.c
arch/arm/mach-davinci/dm355.c
arch/arm/mach-davinci/dm365.c
arch/arm/mach-davinci/dm644x.c
arch/arm/mach-davinci/dm646x.c
arch/arm/mach-davinci/dma.c
arch/arm/mach-davinci/include/mach/dm355.h [deleted file]
arch/arm/mach-davinci/include/mach/dm365.h
arch/arm/mach-davinci/include/mach/dm644x.h [deleted file]
arch/arm/mach-davinci/include/mach/dm646x.h
arch/arm/mach-davinci/include/mach/edma.h
arch/arm/mach-davinci/include/mach/entry-macro.S
arch/arm/mach-davinci/include/mach/hardware.h
arch/arm/mach-davinci/include/mach/system.h [deleted file]
arch/arm/mach-dove/include/mach/entry-macro.S
arch/arm/mach-dove/include/mach/system.h [deleted file]
arch/arm/mach-dove/pcie.c
arch/arm/mach-ebsa110/core.c
arch/arm/mach-ebsa110/core.h [new file with mode: 0644]
arch/arm/mach-ebsa110/include/mach/entry-macro.S
arch/arm/mach-ebsa110/include/mach/hardware.h
arch/arm/mach-ebsa110/include/mach/system.h [deleted file]
arch/arm/mach-ebsa110/io.c
arch/arm/mach-ebsa110/leds.c
arch/arm/mach-ep93xx/Makefile
arch/arm/mach-ep93xx/adssphere.c
arch/arm/mach-ep93xx/clock.c
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/crunch-bits.S [new file with mode: 0644]
arch/arm/mach-ep93xx/crunch.c [new file with mode: 0644]
arch/arm/mach-ep93xx/dma.c
arch/arm/mach-ep93xx/edb93xx.c
arch/arm/mach-ep93xx/gesbc9312.c
arch/arm/mach-ep93xx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h
arch/arm/mach-ep93xx/include/mach/hardware.h
arch/arm/mach-ep93xx/include/mach/platform.h
arch/arm/mach-ep93xx/include/mach/system.h [deleted file]
arch/arm/mach-ep93xx/micro9.c
arch/arm/mach-ep93xx/simone.c
arch/arm/mach-ep93xx/snappercl15.c
arch/arm/mach-ep93xx/soc.h [new file with mode: 0644]
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-ep93xx/vision_ep9307.c
arch/arm/mach-exynos/Kconfig
arch/arm/mach-exynos/Makefile
arch/arm/mach-exynos/clock-exynos4.c [new file with mode: 0644]
arch/arm/mach-exynos/clock-exynos4.h [new file with mode: 0644]
arch/arm/mach-exynos/clock-exynos4210.c
arch/arm/mach-exynos/clock-exynos4212.c
arch/arm/mach-exynos/clock-exynos5.c [new file with mode: 0644]
arch/arm/mach-exynos/clock.c [deleted file]
arch/arm/mach-exynos/common.c
arch/arm/mach-exynos/common.h
arch/arm/mach-exynos/cpuidle.c
arch/arm/mach-exynos/dev-ahci.c
arch/arm/mach-exynos/dev-audio.c
arch/arm/mach-exynos/dev-uart.c [new file with mode: 0644]
arch/arm/mach-exynos/dma.c
arch/arm/mach-exynos/include/mach/cpufreq.h
arch/arm/mach-exynos/include/mach/debug-macro.S
arch/arm/mach-exynos/include/mach/entry-macro.S [deleted file]
arch/arm/mach-exynos/include/mach/exynos4-clock.h [deleted file]
arch/arm/mach-exynos/include/mach/gpio.h
arch/arm/mach-exynos/include/mach/irqs.h
arch/arm/mach-exynos/include/mach/map.h
arch/arm/mach-exynos/include/mach/pmu.h
arch/arm/mach-exynos/include/mach/regs-clock.h
arch/arm/mach-exynos/include/mach/regs-gpio.h
arch/arm/mach-exynos/include/mach/regs-pmu.h
arch/arm/mach-exynos/include/mach/system.h [deleted file]
arch/arm/mach-exynos/include/mach/uncompress.h
arch/arm/mach-exynos/mach-exynos4-dt.c
arch/arm/mach-exynos/mach-exynos5-dt.c [new file with mode: 0644]
arch/arm/mach-exynos/mach-nuri.c
arch/arm/mach-exynos/mach-origen.c
arch/arm/mach-exynos/mach-smdkv310.c
arch/arm/mach-exynos/mach-universal_c210.c
arch/arm/mach-exynos/mct.c
arch/arm/mach-exynos/platsmp.c
arch/arm/mach-exynos/pm.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-exynos/setup-i2c0.c
arch/arm/mach-footbridge/dc21285.c
arch/arm/mach-footbridge/include/mach/entry-macro.S
arch/arm/mach-footbridge/include/mach/system.h [deleted file]
arch/arm/mach-gemini/Makefile
arch/arm/mach-gemini/idle.c [new file with mode: 0644]
arch/arm/mach-gemini/include/mach/entry-macro.S
arch/arm/mach-gemini/include/mach/system.h
arch/arm/mach-gemini/irq.c
arch/arm/mach-h720x/common.c
arch/arm/mach-h720x/include/mach/entry-macro.S
arch/arm/mach-h720x/include/mach/system.h [deleted file]
arch/arm/mach-highbank/Makefile
arch/arm/mach-highbank/highbank.c
arch/arm/mach-highbank/include/mach/entry-macro.S [deleted file]
arch/arm/mach-highbank/include/mach/memory.h [deleted file]
arch/arm/mach-highbank/include/mach/system.h [deleted file]
arch/arm/mach-highbank/localtimer.c [deleted file]
arch/arm/mach-imx/Kconfig
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/Makefile.boot
arch/arm/mach-imx/clock-imx27.c
arch/arm/mach-imx/clock-imx31.c
arch/arm/mach-imx/clock-imx35.c
arch/arm/mach-imx/clock-imx6q.c
arch/arm/mach-imx/cpu-imx5.c
arch/arm/mach-imx/cpu_op-mx51.c
arch/arm/mach-imx/crmregs-imx3.h [new file with mode: 0644]
arch/arm/mach-imx/crmregs-imx31.h [deleted file]
arch/arm/mach-imx/devices-imx27.h
arch/arm/mach-imx/imx27-dt.c [new file with mode: 0644]
arch/arm/mach-imx/imx51-dt.c
arch/arm/mach-imx/imx53-dt.c
arch/arm/mach-imx/lluart.c
arch/arm/mach-imx/localtimer.c [deleted file]
arch/arm/mach-imx/mach-armadillo5x0.c
arch/arm/mach-imx/mach-imx27_visstrim_m10.c
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-imx/mach-mx21ads.c
arch/arm/mach-imx/mach-mx27_3ds.c
arch/arm/mach-imx/mach-mx31ads.c
arch/arm/mach-imx/mach-mx31moboard.c
arch/arm/mach-imx/mach-mx35_3ds.c
arch/arm/mach-imx/mach-pcm038.c
arch/arm/mach-imx/mm-imx3.c
arch/arm/mach-imx/mm-imx5.c
arch/arm/mach-imx/pm-imx27.c
arch/arm/mach-imx/pm-imx3.c [new file with mode: 0644]
arch/arm/mach-imx/pm-imx5.c
arch/arm/mach-integrator/core.c
arch/arm/mach-integrator/impd1.c
arch/arm/mach-integrator/include/mach/entry-macro.S
arch/arm/mach-integrator/include/mach/system.h [deleted file]
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-integrator/pci_v3.c
arch/arm/mach-iop13xx/include/mach/entry-macro.S
arch/arm/mach-iop13xx/include/mach/system.h [deleted file]
arch/arm/mach-iop13xx/pci.c
arch/arm/mach-iop32x/include/mach/entry-macro.S
arch/arm/mach-iop32x/include/mach/system.h [deleted file]
arch/arm/mach-iop33x/include/mach/entry-macro.S
arch/arm/mach-iop33x/include/mach/system.h [deleted file]
arch/arm/mach-ixp2000/include/mach/entry-macro.S
arch/arm/mach-ixp2000/include/mach/system.h [deleted file]
arch/arm/mach-ixp2000/ixdp2400.c
arch/arm/mach-ixp2000/ixdp2800.c
arch/arm/mach-ixp2000/ixdp2x00.c
arch/arm/mach-ixp2000/pci.c
arch/arm/mach-ixp23xx/core.c
arch/arm/mach-ixp23xx/include/mach/entry-macro.S
arch/arm/mach-ixp23xx/include/mach/system.h [deleted file]
arch/arm/mach-ixp23xx/pci.c
arch/arm/mach-ixp4xx/common-pci.c
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-ixp4xx/include/mach/entry-macro.S
arch/arm/mach-ixp4xx/include/mach/system.h [deleted file]
arch/arm/mach-kirkwood/Kconfig
arch/arm/mach-kirkwood/Makefile
arch/arm/mach-kirkwood/Makefile.boot
arch/arm/mach-kirkwood/board-dreamplug.c [new file with mode: 0644]
arch/arm/mach-kirkwood/board-dt.c [new file with mode: 0644]
arch/arm/mach-kirkwood/common.c
arch/arm/mach-kirkwood/common.h
arch/arm/mach-kirkwood/include/mach/entry-macro.S
arch/arm/mach-kirkwood/include/mach/system.h [deleted file]
arch/arm/mach-kirkwood/pcie.c
arch/arm/mach-ks8695/include/mach/entry-macro.S
arch/arm/mach-ks8695/include/mach/system.h [deleted file]
arch/arm/mach-ks8695/pci.c
arch/arm/mach-lpc32xx/Kconfig
arch/arm/mach-lpc32xx/clock.c
arch/arm/mach-lpc32xx/common.c
arch/arm/mach-lpc32xx/common.h
arch/arm/mach-lpc32xx/include/mach/board.h [new file with mode: 0644]
arch/arm/mach-lpc32xx/include/mach/entry-macro.S
arch/arm/mach-lpc32xx/include/mach/platform.h
arch/arm/mach-lpc32xx/include/mach/system.h [deleted file]
arch/arm/mach-lpc32xx/irq.c
arch/arm/mach-lpc32xx/phy3250.c
arch/arm/mach-lpc32xx/pm.c
arch/arm/mach-lpc32xx/timer.c
arch/arm/mach-mmp/Kconfig
arch/arm/mach-mmp/Makefile
arch/arm/mach-mmp/include/mach/entry-macro.S
arch/arm/mach-mmp/include/mach/pxa910.h
arch/arm/mach-mmp/include/mach/regs-apbc.h
arch/arm/mach-mmp/include/mach/regs-rtc.h [new file with mode: 0644]
arch/arm/mach-mmp/include/mach/system.h [deleted file]
arch/arm/mach-mmp/mmp-dt.c [new file with mode: 0644]
arch/arm/mach-mmp/mmp2.c
arch/arm/mach-mmp/pxa168.c
arch/arm/mach-mmp/pxa910.c
arch/arm/mach-mmp/ttc_dkb.c
arch/arm/mach-msm/idle.S [deleted file]
arch/arm/mach-msm/idle.c [new file with mode: 0644]
arch/arm/mach-msm/include/mach/entry-macro.S
arch/arm/mach-msm/include/mach/system.h
arch/arm/mach-msm/timer.c
arch/arm/mach-mv78xx0/include/mach/entry-macro.S
arch/arm/mach-mv78xx0/include/mach/system.h [deleted file]
arch/arm/mach-mv78xx0/pcie.c
arch/arm/mach-mxs/Kconfig
arch/arm/mach-mxs/Makefile
arch/arm/mach-mxs/clock-mx23.c
arch/arm/mach-mxs/clock-mx28.c
arch/arm/mach-mxs/devices-mx23.h
arch/arm/mach-mxs/devices-mx28.h
arch/arm/mach-mxs/devices.c
arch/arm/mach-mxs/devices/Kconfig
arch/arm/mach-mxs/devices/Makefile
arch/arm/mach-mxs/devices/amba-duart.c
arch/arm/mach-mxs/devices/platform-gpmi-nand.c [new file with mode: 0644]
arch/arm/mach-mxs/devices/platform-mxs-mmc.c
arch/arm/mach-mxs/include/mach/common.h
arch/arm/mach-mxs/include/mach/devices-common.h
arch/arm/mach-mxs/include/mach/digctl.h
arch/arm/mach-mxs/include/mach/entry-macro.S
arch/arm/mach-mxs/include/mach/mxs.h
arch/arm/mach-mxs/include/mach/system.h [deleted file]
arch/arm/mach-mxs/include/mach/uncompress.h
arch/arm/mach-mxs/mach-apx4devkit.c [new file with mode: 0644]
arch/arm/mach-mxs/mach-m28evk.c
arch/arm/mach-mxs/mach-mx28evk.c
arch/arm/mach-mxs/pm.c
arch/arm/mach-mxs/system.c
arch/arm/mach-netx/fb.c
arch/arm/mach-netx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-netx/include/mach/system.h [deleted file]
arch/arm/mach-nomadik/board-nhk8815.c
arch/arm/mach-nomadik/cpu-8815.c
arch/arm/mach-nomadik/include/mach/entry-macro.S [deleted file]
arch/arm/mach-nomadik/include/mach/setup.h [deleted file]
arch/arm/mach-nomadik/include/mach/system.h [deleted file]
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap1/ams-delta-fiq-handler.S
arch/arm/mach-omap1/ams-delta-fiq.c
arch/arm/mach-omap1/board-ams-delta.c
arch/arm/mach-omap1/board-fsample.c
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-htcherald.c
arch/arm/mach-omap1/board-innovator.c
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/board-osk.c
arch/arm/mach-omap1/board-palmte.c
arch/arm/mach-omap1/board-palmtt.c
arch/arm/mach-omap1/board-palmz71.c
arch/arm/mach-omap1/board-perseus2.c
arch/arm/mach-omap1/board-sx1.c
arch/arm/mach-omap1/board-voiceblue.c
arch/arm/mach-omap1/clock.c
arch/arm/mach-omap1/clock_data.c
arch/arm/mach-omap1/common.h
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap1/dma.c
arch/arm/mach-omap1/flash.c
arch/arm/mach-omap1/fpga.c
arch/arm/mach-omap1/gpio15xx.c
arch/arm/mach-omap1/gpio16xx.c
arch/arm/mach-omap1/gpio7xx.c
arch/arm/mach-omap1/id.c
arch/arm/mach-omap1/include/mach/entry-macro.S
arch/arm/mach-omap1/include/mach/hardware.h
arch/arm/mach-omap1/include/mach/io.h
arch/arm/mach-omap1/include/mach/memory.h
arch/arm/mach-omap1/include/mach/system.h [deleted file]
arch/arm/mach-omap1/io.c
arch/arm/mach-omap1/iomap.h [new file with mode: 0644]
arch/arm/mach-omap1/irq.c
arch/arm/mach-omap1/lcd_dma.c
arch/arm/mach-omap1/mcbsp.c
arch/arm/mach-omap1/pm.c
arch/arm/mach-omap1/reset.c
arch/arm/mach-omap1/sleep.S
arch/arm/mach-omap1/sram.S
arch/arm/mach-omap1/time.c
arch/arm/mach-omap1/timer32k.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/am35xx-emac.c [new file with mode: 0644]
arch/arm/mach-omap2/am35xx-emac.h [new file with mode: 0644]
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-cm-t3517.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-flash.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3logic.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3stalker.c
arch/arm/mach-omap2/board-omap3touchbook.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rm680.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-zoom-display.c
arch/arm/mach-omap2/board-zoom-peripherals.c
arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c
arch/arm/mach-omap2/clkt_clksel.c
arch/arm/mach-omap2/clkt_dpll.c
arch/arm/mach-omap2/clock2420_data.c
arch/arm/mach-omap2/clock2430.c
arch/arm/mach-omap2/clock2430_data.c
arch/arm/mach-omap2/clock2xxx.c
arch/arm/mach-omap2/clock3xxx.c
arch/arm/mach-omap2/clock3xxx_data.c
arch/arm/mach-omap2/clock44xx_data.c
arch/arm/mach-omap2/cm2xxx_3xxx.c
arch/arm/mach-omap2/cm44xx.c
arch/arm/mach-omap2/cminst44xx.c
arch/arm/mach-omap2/common-board-devices.c
arch/arm/mach-omap2/common.c
arch/arm/mach-omap2/common.h
arch/arm/mach-omap2/control.c
arch/arm/mach-omap2/control.h
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/dma.c
arch/arm/mach-omap2/emu.c
arch/arm/mach-omap2/gpio.c
arch/arm/mach-omap2/gpmc-nand.c
arch/arm/mach-omap2/gpmc-onenand.c
arch/arm/mach-omap2/gpmc-smsc911x.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/hsmmc.c
arch/arm/mach-omap2/hsmmc.h
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/include/mach/entry-macro.S [deleted file]
arch/arm/mach-omap2/include/mach/io.h
arch/arm/mach-omap2/include/mach/system.h [deleted file]
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/iomap.h [new file with mode: 0644]
arch/arm/mach-omap2/irq.c
arch/arm/mach-omap2/mcbsp.c
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/mux.h
arch/arm/mach-omap2/omap-hotplug.c
arch/arm/mach-omap2/omap-mpuss-lowpower.c
arch/arm/mach-omap2/omap-smp.c
arch/arm/mach-omap2/omap-wakeupgen.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/opp2420_data.c
arch/arm/mach-omap2/opp2430_data.c
arch/arm/mach-omap2/pm-debug.c
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/pm.h
arch/arm/mach-omap2/pm24xx.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/pm44xx.c
arch/arm/mach-omap2/powerdomain-common.c
arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
arch/arm/mach-omap2/powerdomain44xx.c
arch/arm/mach-omap2/powerdomains3xxx_data.c
arch/arm/mach-omap2/prcm_mpu44xx.c
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-omap2/prm_common.c
arch/arm/mach-omap2/prminst44xx.c
arch/arm/mach-omap2/sdram-nokia.c
arch/arm/mach-omap2/sdrc2xxx.c
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/sleep24xx.S
arch/arm/mach-omap2/sleep34xx.S
arch/arm/mach-omap2/smartreflex-class3.c
arch/arm/mach-omap2/smartreflex.c
arch/arm/mach-omap2/smartreflex.h
arch/arm/mach-omap2/sr_device.c
arch/arm/mach-omap2/sram242x.S
arch/arm/mach-omap2/sram243x.S
arch/arm/mach-omap2/sram34xx.S
arch/arm/mach-omap2/timer-mpu.c [deleted file]
arch/arm/mach-omap2/timer.c
arch/arm/mach-omap2/vc.c
arch/arm/mach-omap2/vp.c
arch/arm/mach-orion5x/include/mach/entry-macro.S
arch/arm/mach-orion5x/include/mach/system.h [deleted file]
arch/arm/mach-orion5x/pci.c
arch/arm/mach-picoxcell/include/mach/entry-macro.S [deleted file]
arch/arm/mach-picoxcell/include/mach/system.h [deleted file]
arch/arm/mach-pnx4008/include/mach/entry-macro.S
arch/arm/mach-pnx4008/include/mach/system.h [deleted file]
arch/arm/mach-prima2/include/mach/entry-macro.S
arch/arm/mach-prima2/include/mach/system.h [deleted file]
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-pxa/include/mach/balloon3.h
arch/arm/mach-pxa/include/mach/entry-macro.S [deleted file]
arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
arch/arm/mach-pxa/include/mach/system.h [deleted file]
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/pxa95x.c
arch/arm/mach-realview/core.h
arch/arm/mach-realview/include/mach/entry-macro.S [deleted file]
arch/arm/mach-realview/include/mach/irqs-eb.h
arch/arm/mach-realview/include/mach/irqs-pb1176.h
arch/arm/mach-realview/include/mach/system.h [deleted file]
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-realview/realview_pb1176.c
arch/arm/mach-realview/realview_pb11mp.c
arch/arm/mach-realview/realview_pba8.c
arch/arm/mach-realview/realview_pbx.c
arch/arm/mach-rpc/Makefile
arch/arm/mach-rpc/ecard.c [new file with mode: 0644]
arch/arm/mach-rpc/ecard.h [new file with mode: 0644]
arch/arm/mach-rpc/fiq.S [new file with mode: 0644]
arch/arm/mach-rpc/include/mach/entry-macro.S
arch/arm/mach-rpc/include/mach/irqs.h
arch/arm/mach-rpc/include/mach/system.h [deleted file]
arch/arm/mach-rpc/irq.c
arch/arm/mach-rpc/riscpc.c
arch/arm/mach-rpc/time.c [new file with mode: 0644]
arch/arm/mach-s3c2410/Kconfig
arch/arm/mach-s3c2410/Makefile
arch/arm/mach-s3c2410/Makefile.boot [deleted file]
arch/arm/mach-s3c2410/bast-ide.c [deleted file]
arch/arm/mach-s3c2410/bast-irq.c [deleted file]
arch/arm/mach-s3c2410/common.h [deleted file]
arch/arm/mach-s3c2410/dma.c [deleted file]
arch/arm/mach-s3c2410/h1940-bluetooth.c [deleted file]
arch/arm/mach-s3c2410/include/mach/anubis-cpld.h [deleted file]
arch/arm/mach-s3c2410/include/mach/anubis-irq.h [deleted file]
arch/arm/mach-s3c2410/include/mach/anubis-map.h [deleted file]
arch/arm/mach-s3c2410/include/mach/bast-cpld.h [deleted file]
arch/arm/mach-s3c2410/include/mach/bast-irq.h [deleted file]
arch/arm/mach-s3c2410/include/mach/bast-map.h [deleted file]
arch/arm/mach-s3c2410/include/mach/bast-pmu.h [deleted file]
arch/arm/mach-s3c2410/include/mach/debug-macro.S [deleted file]
arch/arm/mach-s3c2410/include/mach/dma.h [deleted file]
arch/arm/mach-s3c2410/include/mach/entry-macro.S [deleted file]
arch/arm/mach-s3c2410/include/mach/fb.h [deleted file]
arch/arm/mach-s3c2410/include/mach/gpio-fns.h [deleted file]
arch/arm/mach-s3c2410/include/mach/gpio-nrs.h [deleted file]
arch/arm/mach-s3c2410/include/mach/gpio-track.h [deleted file]
arch/arm/mach-s3c2410/include/mach/gpio.h [deleted file]
arch/arm/mach-s3c2410/include/mach/h1940-latch.h [deleted file]
arch/arm/mach-s3c2410/include/mach/h1940.h [deleted file]
arch/arm/mach-s3c2410/include/mach/hardware.h [deleted file]
arch/arm/mach-s3c2410/include/mach/idle.h [deleted file]
arch/arm/mach-s3c2410/include/mach/io.h [deleted file]
arch/arm/mach-s3c2410/include/mach/irqs.h [deleted file]
arch/arm/mach-s3c2410/include/mach/leds-gpio.h [deleted file]
arch/arm/mach-s3c2410/include/mach/map.h [deleted file]
arch/arm/mach-s3c2410/include/mach/osiris-cpld.h [deleted file]
arch/arm/mach-s3c2410/include/mach/osiris-map.h [deleted file]
arch/arm/mach-s3c2410/include/mach/otom-map.h [deleted file]
arch/arm/mach-s3c2410/include/mach/pm-core.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-clock.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-dsc.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-gpio.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-gpioj.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-irq.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-lcd.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-mem.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-power.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-s3c2412-mem.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-s3c2412.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-s3c2416-mem.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-s3c2416.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-sdi.h [deleted file]
arch/arm/mach-s3c2410/include/mach/spi.h [deleted file]
arch/arm/mach-s3c2410/include/mach/system.h [deleted file]
arch/arm/mach-s3c2410/include/mach/tick.h [deleted file]
arch/arm/mach-s3c2410/include/mach/timex.h [deleted file]
arch/arm/mach-s3c2410/include/mach/uncompress.h [deleted file]
arch/arm/mach-s3c2410/include/mach/vr1000-cpld.h [deleted file]
arch/arm/mach-s3c2410/include/mach/vr1000-irq.h [deleted file]
arch/arm/mach-s3c2410/include/mach/vr1000-map.h [deleted file]
arch/arm/mach-s3c2410/mach-amlm5900.c [deleted file]
arch/arm/mach-s3c2410/mach-bast.c [deleted file]
arch/arm/mach-s3c2410/mach-h1940.c [deleted file]
arch/arm/mach-s3c2410/mach-n30.c [deleted file]
arch/arm/mach-s3c2410/mach-otom.c [deleted file]
arch/arm/mach-s3c2410/mach-qt2410.c [deleted file]
arch/arm/mach-s3c2410/mach-smdk2410.c [deleted file]
arch/arm/mach-s3c2410/mach-tct_hammer.c [deleted file]
arch/arm/mach-s3c2410/mach-vr1000.c [deleted file]
arch/arm/mach-s3c2410/nor-simtec.c [deleted file]
arch/arm/mach-s3c2410/nor-simtec.h [deleted file]
arch/arm/mach-s3c2410/pm-h1940.S [deleted file]
arch/arm/mach-s3c2410/pm.c [deleted file]
arch/arm/mach-s3c2410/s3c2410.c [deleted file]
arch/arm/mach-s3c2410/sleep.S [deleted file]
arch/arm/mach-s3c2410/usb-simtec.c [deleted file]
arch/arm/mach-s3c2410/usb-simtec.h [deleted file]
arch/arm/mach-s3c2412/Kconfig
arch/arm/mach-s3c2412/Makefile
arch/arm/mach-s3c2412/clock.c [deleted file]
arch/arm/mach-s3c2412/dma.c [deleted file]
arch/arm/mach-s3c2412/irq.c [deleted file]
arch/arm/mach-s3c2412/mach-jive.c [deleted file]
arch/arm/mach-s3c2412/mach-smdk2413.c [deleted file]
arch/arm/mach-s3c2412/mach-vstms.c [deleted file]
arch/arm/mach-s3c2412/pm.c [deleted file]
arch/arm/mach-s3c2412/s3c2412.c [deleted file]
arch/arm/mach-s3c2412/sleep.S [deleted file]
arch/arm/mach-s3c2416/Kconfig [deleted file]
arch/arm/mach-s3c2416/Makefile [deleted file]
arch/arm/mach-s3c2416/clock.c [deleted file]
arch/arm/mach-s3c2416/irq.c [deleted file]
arch/arm/mach-s3c2416/mach-smdk2416.c [deleted file]
arch/arm/mach-s3c2416/pm.c [deleted file]
arch/arm/mach-s3c2416/s3c2416.c [deleted file]
arch/arm/mach-s3c2416/setup-sdhci-gpio.c [deleted file]
arch/arm/mach-s3c2440/Kconfig
arch/arm/mach-s3c2440/Makefile
arch/arm/mach-s3c2440/clock.c [deleted file]
arch/arm/mach-s3c2440/common.h [deleted file]
arch/arm/mach-s3c2440/dma.c [deleted file]
arch/arm/mach-s3c2440/include/mach/gta02.h [deleted file]
arch/arm/mach-s3c2440/irq.c [deleted file]
arch/arm/mach-s3c2440/mach-anubis.c [deleted file]
arch/arm/mach-s3c2440/mach-at2440evb.c [deleted file]
arch/arm/mach-s3c2440/mach-gta02.c [deleted file]
arch/arm/mach-s3c2440/mach-mini2440.c [deleted file]
arch/arm/mach-s3c2440/mach-nexcoder.c [deleted file]
arch/arm/mach-s3c2440/mach-osiris-dvs.c [deleted file]
arch/arm/mach-s3c2440/mach-osiris.c [deleted file]
arch/arm/mach-s3c2440/mach-rx1950.c [deleted file]
arch/arm/mach-s3c2440/mach-rx3715.c [deleted file]
arch/arm/mach-s3c2440/mach-smdk2440.c [deleted file]
arch/arm/mach-s3c2440/s3c2440.c [deleted file]
arch/arm/mach-s3c2440/s3c2442.c [deleted file]
arch/arm/mach-s3c2440/s3c244x-clock.c [deleted file]
arch/arm/mach-s3c2440/s3c244x-irq.c [deleted file]
arch/arm/mach-s3c2440/s3c244x.c [deleted file]
arch/arm/mach-s3c2443/Kconfig [deleted file]
arch/arm/mach-s3c2443/Makefile [deleted file]
arch/arm/mach-s3c2443/clock.c [deleted file]
arch/arm/mach-s3c2443/dma.c [deleted file]
arch/arm/mach-s3c2443/irq.c [deleted file]
arch/arm/mach-s3c2443/mach-smdk2443.c [deleted file]
arch/arm/mach-s3c2443/s3c2443.c [deleted file]
arch/arm/mach-s3c24xx/Kconfig [new file with mode: 0644]
arch/arm/mach-s3c24xx/Makefile [new file with mode: 0644]
arch/arm/mach-s3c24xx/Makefile.boot [new file with mode: 0644]
arch/arm/mach-s3c24xx/bast-ide.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/bast-irq.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/clock-s3c2412.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/clock-s3c2416.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/clock-s3c2440.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/clock-s3c2443.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/clock-s3c244x.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/common-s3c2443.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/common-smdk.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/dma-s3c2410.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/dma-s3c2412.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/dma-s3c2440.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/dma-s3c2443.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/h1940-bluetooth.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/anubis-cpld.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/anubis-irq.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/anubis-map.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/bast-cpld.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/bast-irq.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/bast-map.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/bast-pmu.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/dma.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/fb.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/gpio-fns.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/gpio-nrs.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/gpio-track.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/gta02.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/h1940-latch.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/h1940.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/idle.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/io.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/leds-gpio.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/map.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/osiris-cpld.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/osiris-map.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/otom-map.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/pm-core.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-clock.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-dsc.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-gpio.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-gpioj.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-irq.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-lcd.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-mem.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-power.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-s3c2412-mem.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-s3c2412.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-s3c2416-mem.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-s3c2416.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-s3c2443-clock.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/regs-sdi.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/tick.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/vr1000-cpld.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/vr1000-irq.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/include/mach/vr1000-map.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/irq-s3c2412.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/irq-s3c2416.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/irq-s3c2440.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/irq-s3c2443.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/irq-s3c244x.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-amlm5900.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-anubis.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-at2440evb.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-bast.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-gta02.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-h1940.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-jive.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-mini2440.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-n30.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-nexcoder.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-osiris-dvs.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-osiris.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-otom.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-qt2410.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-rx1950.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-rx3715.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-smdk2410.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-smdk2413.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-smdk2416.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-smdk2440.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-smdk2443.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-tct_hammer.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-vr1000.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/mach-vstms.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/pm-h1940.S [new file with mode: 0644]
arch/arm/mach-s3c24xx/pm-s3c2410.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/pm-s3c2412.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/pm-s3c2416.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/s3c2410.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/s3c2412.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/s3c2416.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/s3c2440.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/s3c2442.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/s3c2443.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/s3c244x.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/setup-i2c.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/setup-sdhci-gpio.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/setup-ts.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/simtec-audio.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/simtec-nor.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/simtec-pm.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/simtec-usb.c [new file with mode: 0644]
arch/arm/mach-s3c24xx/simtec.h [new file with mode: 0644]
arch/arm/mach-s3c24xx/sleep-s3c2410.S [new file with mode: 0644]
arch/arm/mach-s3c24xx/sleep-s3c2412.S [new file with mode: 0644]
arch/arm/mach-s3c64xx/Kconfig
arch/arm/mach-s3c64xx/Makefile
arch/arm/mach-s3c64xx/clock.c
arch/arm/mach-s3c64xx/common.h
arch/arm/mach-s3c64xx/cpuidle.c [new file with mode: 0644]
arch/arm/mach-s3c64xx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-s3c64xx/include/mach/system.h [deleted file]
arch/arm/mach-s3c64xx/irq-pm.c
arch/arm/mach-s3c64xx/mach-crag6410-module.c
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-s3c64xx/mach-smartq.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mach-s3c64xx/setup-usb-phy.c [new file with mode: 0644]
arch/arm/mach-s5p64x0/clock.c
arch/arm/mach-s5p64x0/common.c
arch/arm/mach-s5p64x0/dma.c
arch/arm/mach-s5p64x0/include/mach/entry-macro.S [deleted file]
arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
arch/arm/mach-s5p64x0/include/mach/system.h [deleted file]
arch/arm/mach-s5pc100/clock.c
arch/arm/mach-s5pc100/common.c
arch/arm/mach-s5pc100/dma.c
arch/arm/mach-s5pc100/include/mach/entry-macro.S
arch/arm/mach-s5pc100/include/mach/system.h [deleted file]
arch/arm/mach-s5pv210/Kconfig
arch/arm/mach-s5pv210/Makefile
arch/arm/mach-s5pv210/clock.c
arch/arm/mach-s5pv210/common.c
arch/arm/mach-s5pv210/dma.c
arch/arm/mach-s5pv210/include/mach/entry-macro.S [deleted file]
arch/arm/mach-s5pv210/include/mach/map.h
arch/arm/mach-s5pv210/include/mach/regs-sys.h
arch/arm/mach-s5pv210/include/mach/system.h [deleted file]
arch/arm/mach-s5pv210/mach-aquila.c
arch/arm/mach-s5pv210/mach-goni.c
arch/arm/mach-s5pv210/mach-smdkc110.c
arch/arm/mach-s5pv210/mach-smdkv210.c
arch/arm/mach-s5pv210/setup-usb-phy.c [new file with mode: 0644]
arch/arm/mach-sa1100/Makefile
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/badge4.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/clock.c
arch/arm/mach-sa1100/collie.c
arch/arm/mach-sa1100/dma.c [deleted file]
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/generic.h
arch/arm/mach-sa1100/h3100.c
arch/arm/mach-sa1100/h3600.c
arch/arm/mach-sa1100/h3xxx.c
arch/arm/mach-sa1100/hackkit.c
arch/arm/mach-sa1100/include/mach/SA-1100.h
arch/arm/mach-sa1100/include/mach/assabet.h
arch/arm/mach-sa1100/include/mach/cerf.h
arch/arm/mach-sa1100/include/mach/dma.h [deleted file]
arch/arm/mach-sa1100/include/mach/entry-macro.S
arch/arm/mach-sa1100/include/mach/irqs.h
arch/arm/mach-sa1100/include/mach/mcp.h
arch/arm/mach-sa1100/include/mach/nanoengine.h
arch/arm/mach-sa1100/include/mach/neponset.h
arch/arm/mach-sa1100/include/mach/shannon.h
arch/arm/mach-sa1100/include/mach/simpad.h
arch/arm/mach-sa1100/include/mach/system.h [deleted file]
arch/arm/mach-sa1100/irq.c
arch/arm/mach-sa1100/jornada720.c
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/nanoengine.c
arch/arm/mach-sa1100/neponset.c
arch/arm/mach-sa1100/pci-nanoengine.c
arch/arm/mach-sa1100/pleb.c
arch/arm/mach-sa1100/shannon.c
arch/arm/mach-sa1100/simpad.c
arch/arm/mach-sa1100/sleep.S
arch/arm/mach-sa1100/ssp.c
arch/arm/mach-sa1100/time.c
arch/arm/mach-shark/core.c
arch/arm/mach-shark/include/mach/entry-macro.S
arch/arm/mach-shark/include/mach/system.h [deleted file]
arch/arm/mach-shmobile/Makefile
arch/arm/mach-shmobile/board-ag5evm.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-bonito.c
arch/arm/mach-shmobile/board-g3evm.c
arch/arm/mach-shmobile/board-g4evm.c
arch/arm/mach-shmobile/board-kota2.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/clock.c
arch/arm/mach-shmobile/include/mach/common.h
arch/arm/mach-shmobile/include/mach/entry-macro.S [deleted file]
arch/arm/mach-shmobile/include/mach/system.h
arch/arm/mach-shmobile/localtimer.c [deleted file]
arch/arm/mach-shmobile/platsmp.c
arch/arm/mach-shmobile/setup-r8a7740.c
arch/arm/mach-shmobile/setup-r8a7779.c
arch/arm/mach-shmobile/setup-sh7367.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-shmobile/smp-r8a7779.c
arch/arm/mach-shmobile/smp-sh73a0.c
arch/arm/mach-shmobile/timer.c
arch/arm/mach-spear3xx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-spear3xx/include/mach/system.h [deleted file]
arch/arm/mach-spear3xx/spear300.c
arch/arm/mach-spear3xx/spear3xx.c
arch/arm/mach-spear6xx/Kconfig
arch/arm/mach-spear6xx/Makefile
arch/arm/mach-spear6xx/clock.c
arch/arm/mach-spear6xx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-spear6xx/include/mach/system.h [deleted file]
arch/arm/mach-spear6xx/spear600.c [deleted file]
arch/arm/mach-spear6xx/spear600_evb.c [deleted file]
arch/arm/mach-spear6xx/spear6xx.c
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/apbio.c [new file with mode: 0644]
arch/arm/mach-tegra/apbio.h [new file with mode: 0644]
arch/arm/mach-tegra/board-dt-tegra20.c
arch/arm/mach-tegra/board-dt-tegra30.c
arch/arm/mach-tegra/board-harmony-pinmux.c
arch/arm/mach-tegra/board-harmony-power.c
arch/arm/mach-tegra/board-harmony.c
arch/arm/mach-tegra/board-seaboard.c
arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/clock.h
arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/cpuidle.c [new file with mode: 0644]
arch/arm/mach-tegra/dma.c
arch/arm/mach-tegra/flowctrl.c [new file with mode: 0644]
arch/arm/mach-tegra/flowctrl.h [new file with mode: 0644]
arch/arm/mach-tegra/fuse.c
arch/arm/mach-tegra/fuse.h
arch/arm/mach-tegra/headsmp.S
arch/arm/mach-tegra/include/mach/clk.h
arch/arm/mach-tegra/include/mach/debug-macro.S
arch/arm/mach-tegra/include/mach/entry-macro.S [deleted file]
arch/arm/mach-tegra/include/mach/gpio-tegra.h
arch/arm/mach-tegra/include/mach/iomap.h
arch/arm/mach-tegra/include/mach/irammap.h [new file with mode: 0644]
arch/arm/mach-tegra/include/mach/irqs.h
arch/arm/mach-tegra/include/mach/powergate.h
arch/arm/mach-tegra/include/mach/smmu.h [new file with mode: 0644]
arch/arm/mach-tegra/include/mach/system.h [deleted file]
arch/arm/mach-tegra/include/mach/uncompress.h
arch/arm/mach-tegra/irq.c
arch/arm/mach-tegra/localtimer.c [deleted file]
arch/arm/mach-tegra/pcie.c
arch/arm/mach-tegra/platsmp.c
arch/arm/mach-tegra/pmc.c [new file with mode: 0644]
arch/arm/mach-tegra/pmc.h [new file with mode: 0644]
arch/arm/mach-tegra/powergate.c
arch/arm/mach-tegra/reset.c [new file with mode: 0644]
arch/arm/mach-tegra/reset.h [new file with mode: 0644]
arch/arm/mach-tegra/sleep.S [new file with mode: 0644]
arch/arm/mach-tegra/tegra2_clocks.c
arch/arm/mach-tegra/tegra2_emc.c
arch/arm/mach-tegra/tegra2_emc.h
arch/arm/mach-tegra/tegra30_clocks.c [new file with mode: 0644]
arch/arm/mach-tegra/timer.c
arch/arm/mach-tegra/usb_phy.c
arch/arm/mach-u300/Makefile
arch/arm/mach-u300/core.c
arch/arm/mach-u300/include/mach/entry-macro.S [deleted file]
arch/arm/mach-u300/include/mach/system.h [deleted file]
arch/arm/mach-u300/mmc.c [deleted file]
arch/arm/mach-u300/mmc.h [deleted file]
arch/arm/mach-ux500/Kconfig
arch/arm/mach-ux500/Makefile
arch/arm/mach-ux500/Makefile.boot
arch/arm/mach-ux500/board-mop500-pins.c
arch/arm/mach-ux500/board-mop500-regulators.c
arch/arm/mach-ux500/board-mop500-sdi.c
arch/arm/mach-ux500/board-mop500-u8500uib.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/board-mop500.h
arch/arm/mach-ux500/board-u5500-sdi.c
arch/arm/mach-ux500/board-u5500.c
arch/arm/mach-ux500/cache-l2x0.c
arch/arm/mach-ux500/clock.c
arch/arm/mach-ux500/clock.h
arch/arm/mach-ux500/cpu-db5500.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/cpu.c
arch/arm/mach-ux500/devices-common.c
arch/arm/mach-ux500/devices-common.h
arch/arm/mach-ux500/devices-db5500.h
arch/arm/mach-ux500/devices-db8500.c
arch/arm/mach-ux500/devices-db8500.h
arch/arm/mach-ux500/dma-db5500.c
arch/arm/mach-ux500/include/mach/db8500-regs.h
arch/arm/mach-ux500/include/mach/entry-macro.S [deleted file]
arch/arm/mach-ux500/include/mach/hardware.h
arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
arch/arm/mach-ux500/include/mach/irqs.h
arch/arm/mach-ux500/include/mach/setup.h
arch/arm/mach-ux500/include/mach/system.h [deleted file]
arch/arm/mach-ux500/include/mach/usb.h
arch/arm/mach-ux500/localtimer.c [deleted file]
arch/arm/mach-ux500/timer.c
arch/arm/mach-ux500/usb.c
arch/arm/mach-versatile/core.c
arch/arm/mach-versatile/core.h
arch/arm/mach-versatile/include/mach/entry-macro.S [deleted file]
arch/arm/mach-versatile/include/mach/system.h [deleted file]
arch/arm/mach-versatile/pci.c
arch/arm/mach-versatile/versatile_pb.c
arch/arm/mach-vexpress/Kconfig
arch/arm/mach-vexpress/Makefile.boot
arch/arm/mach-vexpress/core.h
arch/arm/mach-vexpress/ct-ca9x4.c
arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
arch/arm/mach-vexpress/include/mach/debug-macro.S
arch/arm/mach-vexpress/include/mach/entry-macro.S [deleted file]
arch/arm/mach-vexpress/include/mach/irqs.h
arch/arm/mach-vexpress/include/mach/motherboard.h
arch/arm/mach-vexpress/include/mach/system.h [deleted file]
arch/arm/mach-vexpress/include/mach/uncompress.h
arch/arm/mach-vexpress/platsmp.c
arch/arm/mach-vexpress/v2m.c
arch/arm/mach-vt8500/include/mach/entry-macro.S
arch/arm/mach-vt8500/include/mach/system.h
arch/arm/mach-w90x900/dev.c
arch/arm/mach-w90x900/include/mach/entry-macro.S
arch/arm/mach-w90x900/include/mach/system.h [deleted file]
arch/arm/mach-zynq/include/mach/entry-macro.S [deleted file]
arch/arm/mach-zynq/include/mach/system.h [deleted file]
arch/arm/mm/iomap.c
arch/arm/plat-iop/pci.c
arch/arm/plat-mxc/avic.c
arch/arm/plat-mxc/cpu.c
arch/arm/plat-mxc/devices/platform-ahci-imx.c
arch/arm/plat-mxc/devices/platform-mx2-camera.c
arch/arm/plat-mxc/epit.c
arch/arm/plat-mxc/include/mach/board-mx31ads.h [deleted file]
arch/arm/plat-mxc/include/mach/common.h
arch/arm/plat-mxc/include/mach/debug-macro.S
arch/arm/plat-mxc/include/mach/devices-common.h
arch/arm/plat-mxc/include/mach/dma.h
arch/arm/plat-mxc/include/mach/entry-macro.S [deleted file]
arch/arm/plat-mxc/include/mach/iomux-mx25.h
arch/arm/plat-mxc/include/mach/system.h [deleted file]
arch/arm/plat-mxc/pwm.c
arch/arm/plat-mxc/system.c
arch/arm/plat-mxc/time.c
arch/arm/plat-nomadik/include/plat/mtu.h
arch/arm/plat-nomadik/timer.c
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/clock.c
arch/arm/plat-omap/counter_32k.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/include/plat/board-ams-delta.h
arch/arm/plat-omap/include/plat/cpu.h
arch/arm/plat-omap/include/plat/gpio.h
arch/arm/plat-omap/include/plat/hardware.h
arch/arm/plat-omap/include/plat/io.h [deleted file]
arch/arm/plat-omap/include/plat/keypad.h
arch/arm/plat-omap/include/plat/mcspi.h
arch/arm/plat-omap/include/plat/omap_device.h
arch/arm/plat-omap/include/plat/omap_hwmod.h
arch/arm/plat-omap/include/plat/remoteproc.h [new file with mode: 0644]
arch/arm/plat-omap/include/plat/serial.h
arch/arm/plat-omap/include/plat/sram.h
arch/arm/plat-omap/include/plat/system.h [deleted file]
arch/arm/plat-omap/include/plat/tc.h
arch/arm/plat-omap/include/plat/uncompress.h
arch/arm/plat-omap/include/plat/usb.h
arch/arm/plat-omap/mailbox.c
arch/arm/plat-omap/mux.c
arch/arm/plat-omap/omap-pm-noop.c
arch/arm/plat-omap/omap_device.c
arch/arm/plat-omap/sram.c
arch/arm/plat-omap/usb.c
arch/arm/plat-orion/common.c
arch/arm/plat-orion/include/plat/audio.h
arch/arm/plat-s3c24xx/Kconfig
arch/arm/plat-s3c24xx/Makefile
arch/arm/plat-s3c24xx/common-smdk.c [deleted file]
arch/arm/plat-s3c24xx/cpu.c
arch/arm/plat-s3c24xx/pm-simtec.c [deleted file]
arch/arm/plat-s3c24xx/s3c2443-clock.c [deleted file]
arch/arm/plat-s3c24xx/setup-i2c.c [deleted file]
arch/arm/plat-s3c24xx/setup-ts.c [deleted file]
arch/arm/plat-s3c24xx/simtec-audio.c [deleted file]
arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c [deleted file]
arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c [deleted file]
arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c [deleted file]
arch/arm/plat-s5p/Kconfig
arch/arm/plat-s5p/Makefile
arch/arm/plat-s5p/clock.c
arch/arm/plat-s5p/irq-eint.c
arch/arm/plat-s5p/irq-gpioint.c
arch/arm/plat-s5p/irq-pm.c
arch/arm/plat-s5p/sleep.S
arch/arm/plat-samsung/Kconfig
arch/arm/plat-samsung/clock.c
arch/arm/plat-samsung/dev-backlight.c
arch/arm/plat-samsung/devs.c
arch/arm/plat-samsung/dma-ops.c
arch/arm/plat-samsung/include/plat/audio-simtec.h
arch/arm/plat-samsung/include/plat/clock.h
arch/arm/plat-samsung/include/plat/cpu.h
arch/arm/plat-samsung/include/plat/devs.h
arch/arm/plat-samsung/include/plat/dma-pl330.h
arch/arm/plat-samsung/include/plat/regs-dma.h
arch/arm/plat-samsung/include/plat/regs-rtc.h
arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h
arch/arm/plat-samsung/include/plat/rtc-core.h [new file with mode: 0644]
arch/arm/plat-samsung/include/plat/s3c2410.h
arch/arm/plat-samsung/include/plat/s3c2443.h
arch/arm/plat-samsung/include/plat/s5p-clock.h
arch/arm/plat-samsung/include/plat/sdhci.h
arch/arm/plat-samsung/include/plat/udc-hs.h
arch/arm/plat-samsung/include/plat/uncompress.h
arch/arm/plat-samsung/irq-vic-timer.c
arch/arm/plat-samsung/platformdata.c
arch/arm/plat-spear/include/plat/system.h [deleted file]
arch/arm/plat-versatile/Makefile
arch/arm/plat-versatile/localtimer.c [deleted file]
arch/avr32/boards/atngw100/setup.c
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/include/asm/io.h
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mach-at32ap/include/mach/board.h
arch/avr32/mach-at32ap/include/mach/cpu.h
arch/blackfin/Kconfig
arch/blackfin/include/asm/irq.h
arch/c6x/include/asm/pgtable.h
arch/hexagon/kernel/signal.c
arch/hexagon/kernel/vdso.c
arch/ia64/include/asm/kvm.h
arch/ia64/include/asm/kvm_host.h
arch/ia64/include/asm/pci.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/machine_kexec.c
arch/ia64/kernel/mca.c
arch/ia64/kvm/kvm-ia64.c
arch/ia64/pci/pci.c
arch/ia64/sn/kernel/huberror.c
arch/ia64/sn/kernel/io_common.c
arch/ia64/sn/kernel/io_init.c
arch/ia64/sn/kernel/irq.c
arch/ia64/sn/kernel/sn2/sn_hwperf.c
arch/ia64/sn/kernel/tiocx.c
arch/ia64/sn/pci/pcibr/pcibr_provider.c
arch/ia64/sn/pci/tioca_provider.c
arch/ia64/sn/pci/tioce_provider.c
arch/microblaze/Kconfig
arch/microblaze/boot/Makefile
arch/microblaze/include/asm/fixmap.h [new file with mode: 0644]
arch/microblaze/include/asm/highmem.h [new file with mode: 0644]
arch/microblaze/include/asm/mmu.h
arch/microblaze/include/asm/page.h
arch/microblaze/include/asm/pci-bridge.h
arch/microblaze/include/asm/pci.h
arch/microblaze/include/asm/pgtable.h
arch/microblaze/include/asm/setup.h
arch/microblaze/include/asm/uaccess.h
arch/microblaze/kernel/cpu/cpuinfo.c
arch/microblaze/kernel/early_printk.c
arch/microblaze/kernel/head.S
arch/microblaze/kernel/hw_exception_handler.S
arch/microblaze/kernel/intc.c
arch/microblaze/kernel/misc.S
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/timer.c
arch/microblaze/kernel/vmlinux.lds.S
arch/microblaze/mm/Makefile
arch/microblaze/mm/highmem.c [new file with mode: 0644]
arch/microblaze/mm/init.c
arch/microblaze/mm/pgtable.c
arch/microblaze/pci/pci-common.c
arch/mips/fw/arc/cmdline.c
arch/mips/fw/arc/identify.c
arch/mips/include/asm/mman.h
arch/mips/include/asm/pci.h
arch/mips/kernel/vdso.c
arch/mips/pci/fixup-cobalt.c
arch/mips/pci/pci-bcm1480.c
arch/mips/pci/pci-ip27.c
arch/mips/pci/pci-lantiq.c
arch/mips/pci/pci-sb1250.c
arch/mips/pci/pci-xlr.c
arch/mips/pci/pci.c
arch/mn10300/Kconfig
arch/mn10300/include/asm/pci.h
arch/mn10300/include/asm/reset-regs.h
arch/mn10300/unit-asb2305/pci.c
arch/openrisc/Kconfig
arch/openrisc/include/asm/page.h
arch/openrisc/include/asm/pgtable.h
arch/openrisc/include/asm/processor.h
arch/openrisc/include/asm/ptrace.h
arch/openrisc/include/asm/syscall.h
arch/openrisc/include/asm/uaccess.h
arch/openrisc/kernel/entry.S
arch/openrisc/kernel/head.S
arch/openrisc/kernel/ptrace.c
arch/openrisc/kernel/setup.c
arch/openrisc/kernel/signal.c
arch/openrisc/kernel/time.c
arch/openrisc/kernel/traps.c
arch/openrisc/mm/init.c
arch/parisc/include/asm/mman.h
arch/parisc/include/asm/pci.h
arch/parisc/kernel/pci.c
arch/parisc/math-emu/fpudispatch.c
arch/powerpc/boot/.gitignore
arch/powerpc/include/asm/iommu.h
arch/powerpc/include/asm/irq.h
arch/powerpc/include/asm/kvm.h
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/kvm_book3s_32.h
arch/powerpc/include/asm/kvm_book3s_64.h
arch/powerpc/include/asm/kvm_e500.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_para.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/mmu-book3e.h
arch/powerpc/include/asm/mmu-hash64.h
arch/powerpc/include/asm/pci-bridge.h
arch/powerpc/include/asm/pci.h
arch/powerpc/include/asm/perf_event_server.h
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/ppc-pci.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/rtas.h
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/udbg.h
arch/powerpc/include/asm/vio.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/kvm.c
arch/powerpc/kernel/kvm_emul.S
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/pci_of_scan.c
arch/powerpc/kernel/pmc.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/rtas_pci.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/udbg.c
arch/powerpc/kernel/vdso.c
arch/powerpc/kernel/vio.c
arch/powerpc/kvm/Kconfig
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_32_mmu_host.c
arch/powerpc/kvm/book3s_64_mmu_host.c
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_emulate.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_builtin.c
arch/powerpc/kvm/book3s_hv_rm_mmu.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_paired_singles.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/booke.h
arch/powerpc/kvm/booke_emulate.c
arch/powerpc/kvm/booke_interrupts.S
arch/powerpc/kvm/e500.c
arch/powerpc/kvm/e500_emulate.c
arch/powerpc/kvm/e500_tlb.c
arch/powerpc/kvm/e500_tlb.h
arch/powerpc/kvm/emulate.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/kvm/trace.h
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/power4-pmu.c
arch/powerpc/perf/ppc970-pmu.c
arch/powerpc/platforms/cell/beat_htab.c
arch/powerpc/platforms/maple/pci.c
arch/powerpc/platforms/pasemi/pci.c
arch/powerpc/platforms/powermac/pci.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/pseries/eeh.c
arch/powerpc/platforms/pseries/eeh_dev.c
arch/powerpc/platforms/pseries/io_event_irq.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/pci_dlpar.c
arch/powerpc/platforms/pseries/ras.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/wsp/wsp_pci.c
arch/powerpc/xmon/ppc-opc.c
arch/powerpc/xmon/spu-opc.c
arch/s390/Kconfig
arch/s390/include/asm/cpu_mf.h [new file with mode: 0644]
arch/s390/include/asm/irq.h
arch/s390/include/asm/kvm.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/perf_event.h
arch/s390/kernel/Makefile
arch/s390/kernel/irq.c
arch/s390/kernel/perf_cpum_cf.c [new file with mode: 0644]
arch/s390/kernel/perf_event.c [new file with mode: 0644]
arch/s390/kernel/vdso.c
arch/s390/kvm/Kconfig
arch/s390/kvm/diag.c
arch/s390/kvm/intercept.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/priv.c
arch/s390/kvm/sigp.c
arch/s390/mm/mmap.c
arch/s390/oprofile/hwsampler.c
arch/sh/boards/mach-highlander/setup.c
arch/sh/boards/mach-sdk7786/setup.c
arch/sh/drivers/pci/pci.c
arch/sh/include/asm/clock.h
arch/sh/include/asm/pci.h
arch/sh/kernel/cpu/sh2/clock-sh7619.c
arch/sh/kernel/cpu/sh2a/clock-sh7201.c
arch/sh/kernel/cpu/sh2a/clock-sh7203.c
arch/sh/kernel/cpu/sh2a/clock-sh7206.c
arch/sh/kernel/cpu/sh3/clock-sh3.c
arch/sh/kernel/cpu/sh3/clock-sh7705.c
arch/sh/kernel/cpu/sh3/clock-sh7706.c
arch/sh/kernel/cpu/sh3/clock-sh7709.c
arch/sh/kernel/cpu/sh3/clock-sh7710.c
arch/sh/kernel/cpu/sh3/clock-sh7712.c
arch/sh/kernel/cpu/sh4/clock-sh4-202.c
arch/sh/kernel/cpu/sh4/clock-sh4.c
arch/sh/kernel/cpu/sh4a/clock-sh7343.c
arch/sh/kernel/cpu/sh4a/clock-sh7366.c
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
arch/sh/kernel/cpu/sh4a/clock-sh7723.c
arch/sh/kernel/cpu/sh4a/clock-sh7724.c
arch/sh/kernel/cpu/sh4a/clock-sh7757.c
arch/sh/kernel/cpu/sh4a/clock-sh7763.c
arch/sh/kernel/cpu/sh4a/clock-sh7770.c
arch/sh/kernel/cpu/sh4a/clock-sh7780.c
arch/sh/kernel/cpu/sh4a/clock-sh7785.c
arch/sh/kernel/cpu/sh4a/clock-sh7786.c
arch/sh/kernel/cpu/sh4a/clock-shx3.c
arch/sh/kernel/cpu/sh5/clock-sh5.c
arch/sh/kernel/vsyscall/vsyscall.c
arch/sparc/Kconfig
arch/sparc/include/asm/irq_64.h
arch/sparc/include/asm/pci_32.h
arch/sparc/include/asm/pci_64.h
arch/sparc/include/asm/vga.h
arch/sparc/include/asm/vio.h
arch/sparc/kernel/ds.c
arch/sparc/kernel/leon_pci.c
arch/sparc/kernel/pci.c
arch/sparc/kernel/vio.c
arch/tile/mm/elf.c
arch/um/Kconfig.common
arch/um/Makefile
arch/um/defconfig
arch/um/drivers/chan.h
arch/um/drivers/chan_kern.c
arch/um/drivers/chan_user.h
arch/um/drivers/line.c
arch/um/drivers/line.h
arch/um/drivers/mconsole_kern.c
arch/um/drivers/net_kern.c
arch/um/drivers/port_kern.c
arch/um/drivers/random.c
arch/um/drivers/ssl.c
arch/um/drivers/stdio_console.c
arch/um/drivers/ubd.h [new file with mode: 0644]
arch/um/drivers/ubd_kern.c
arch/um/drivers/ubd_user.c
arch/um/drivers/ubd_user.h [deleted file]
arch/um/drivers/xterm_kern.c
arch/um/include/asm/Kbuild
arch/um/include/asm/asm-offsets.h [deleted file]
arch/um/include/asm/auxvec.h [deleted file]
arch/um/include/asm/current.h [deleted file]
arch/um/include/asm/delay.h [deleted file]
arch/um/include/asm/io.h [deleted file]
arch/um/include/asm/mutex.h [deleted file]
arch/um/include/asm/param.h [deleted file]
arch/um/include/asm/pci.h [deleted file]
arch/um/include/asm/pgalloc.h
arch/um/include/asm/pgtable.h
arch/um/include/asm/ptrace-generic.h
arch/um/include/shared/common-offsets.h
arch/um/include/shared/kern_util.h
arch/um/kernel/Makefile
arch/um/kernel/process.c
arch/um/kernel/sigio.c
arch/um/kernel/signal.c
arch/um/kernel/time.c
arch/um/os-Linux/Makefile
arch/um/os-Linux/user_syms.c
arch/um/scripts/Makefile.rules
arch/unicore32/include/asm/pci.h
arch/unicore32/kernel/pci.c
arch/unicore32/kernel/process.c
arch/x86/Kconfig
arch/x86/Makefile.um
arch/x86/boot/Makefile
arch/x86/include/asm/debugreg.h
arch/x86/include/asm/kgdb.h
arch/x86/include/asm/kvm.h
arch/x86/include/asm/kvm_emulate.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/tsc.h
arch/x86/include/asm/x86_init.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/irqinit.c
arch/x86/kernel/kgdb.c
arch/x86/kernel/kvmclock.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/tsc.c
arch/x86/kernel/x86_init.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/cpuid.h
arch/x86/kvm/emulate.c
arch/x86/kvm/i8259.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/mmu_audit.c
arch/x86/kvm/pmu.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/kmemcheck/selftest.c
arch/x86/pci/acpi.c
arch/x86/pci/fixup.c
arch/x86/pci/i386.c
arch/x86/pci/mrst.c
arch/x86/platform/ce4100/falconfalls.dts
arch/x86/platform/geode/Makefile
arch/x86/platform/geode/geos.c [new file with mode: 0644]
arch/x86/power/cpu.c
arch/x86/syscalls/syscall_32.tbl
arch/x86/um/Kconfig
arch/x86/um/asm/processor.h
arch/x86/um/asm/processor_32.h
arch/x86/um/asm/processor_64.h
arch/x86/um/bugs_32.c
arch/x86/um/mem_32.c
arch/x86/um/vdso/vma.c
arch/x86/vdso/vdso32-setup.c
arch/x86/vdso/vma.c
arch/x86/xen/setup.c
arch/x86/xen/smp.c
arch/xtensa/include/asm/mman.h
arch/xtensa/kernel/pci.c
crypto/Kconfig
crypto/crc32c.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/ec.c
drivers/acpi/video_detect.c
drivers/amba/bus.c
drivers/base/dma-buf.c
drivers/base/power/clock_ops.c
drivers/base/power/common.c
drivers/base/power/opp.c
drivers/base/regmap/regcache-lzo.c
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap-irq.c
drivers/block/drbd/drbd_nl.c
drivers/block/rbd.c
drivers/block/rbd_types.h
drivers/block/sunvdc.c
drivers/block/xen-blkfront.c
drivers/char/hw_random/nomadik-rng.c
drivers/char/hw_random/omap-rng.c
drivers/char/ipmi/ipmi_watchdog.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/clk-divider.c [new file with mode: 0644]
drivers/clk/clk-fixed-rate.c [new file with mode: 0644]
drivers/clk/clk-gate.c [new file with mode: 0644]
drivers/clk/clk-mux.c [new file with mode: 0644]
drivers/clk/clk.c [new file with mode: 0644]
drivers/clocksource/tcb_clksrc.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Makefile
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/db8500-cpufreq.c
drivers/cpufreq/exynos-cpufreq.c
drivers/cpufreq/exynos4210-cpufreq.c
drivers/cpufreq/exynos4x12-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/exynos5250-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/omap-cpufreq.c
drivers/cpufreq/s3c2416-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/s3c64xx-cpufreq.c
drivers/devfreq/exynos4_bus.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/imx-dma.c
drivers/dma/imx-sdma.c
drivers/dma/pl330.c
drivers/dma/sa11x0-dma.c [new file with mode: 0644]
drivers/edac/Kconfig
drivers/edac/amd64_edac.c
drivers/edac/amd76x_edac.c
drivers/edac/e752x_edac.c
drivers/edac/e7xxx_edac.c
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_stub.c
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/mce_amd.c
drivers/edac/mce_amd.h
drivers/edac/mce_amd_inj.c
drivers/edac/ppc4xx_edac.c
drivers/edac/r82600_edac.c
drivers/edac/sb_edac.c
drivers/edac/x38_edac.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-davinci.c
drivers/gpio/gpio-ep93xx.c
drivers/gpio/gpio-lpc32xx.c
drivers/gpio/gpio-mc9s08dz60.c [new file with mode: 0644]
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pl061.c
drivers/gpio/gpio-sa1100.c
drivers/gpio/gpio-samsung.c
drivers/gpio/gpio-sodaville.c [new file with mode: 0644]
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-tegra.c
drivers/gpio/gpio-tps65910.c
drivers/gpio/gpio-twl4030.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/gma500/mdfld_dsi_output.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/cayman_blit_shaders.c
drivers/gpu/drm/radeon/evergreen_blit_shaders.c
drivers/gpu/drm/radeon/evergreen_cs.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/r600_blit_shaders.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/reg_srcs/cayman
drivers/gpu/drm/radeon/reg_srcs/evergreen
drivers/gpu/drm/radeon/reg_srcs/r600
drivers/gpu/drm/radeon/si_blit_shaders.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/fam15h_power.c
drivers/hwmon/fschmd.c
drivers/hwmon/lm63.c
drivers/hwmon/lm90.c
drivers/hwmon/mc13783-adc.c
drivers/hwmon/mcp3021.c [new file with mode: 0644]
drivers/hwmon/w83793.c
drivers/hwmon/w83795.c
drivers/i2c/algos/i2c-algo-bit.c
drivers/i2c/algos/i2c-algo-pca.c
drivers/i2c/algos/i2c-algo-pcf.c
drivers/i2c/algos/i2c-algo-pcf.h
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-gpio.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-isch.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-sirf.c [new file with mode: 0644]
drivers/i2c/busses/i2c-tegra.c
drivers/i2c/busses/i2c-versatile.c
drivers/i2c/busses/i2c-xlr.c [new file with mode: 0644]
drivers/i2c/i2c-boardinfo.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-core.h
drivers/i2c/i2c-dev.c
drivers/i2c/i2c-smbus.c
drivers/i2c/muxes/pca9541.c
drivers/i2c/muxes/pca954x.c
drivers/input/keyboard/jornada720_kbd.c
drivers/input/misc/88pm860x_onkey.c
drivers/input/serio/ambakmi.c
drivers/input/serio/ams_delta_serio.c
drivers/input/serio/rpckbd.c
drivers/input/serio/sa1111ps2.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/jornada720_ts.c
drivers/input/touchscreen/mc13783_ts.c
drivers/iommu/Kconfig
drivers/iommu/Makefile
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_v2.c
drivers/iommu/tegra-gart.c [new file with mode: 0644]
drivers/iommu/tegra-smmu.c [new file with mode: 0644]
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-class.c
drivers/leds/led-core.c
drivers/leds/leds-88pm860x.c
drivers/leds/leds-ams-delta.c [deleted file]
drivers/leds/leds-gpio.c
drivers/leds/leds-lm3530.c
drivers/leds/leds-lp5521.c
drivers/leds/leds-lp5523.c
drivers/leds/leds-pca9633.c [new file with mode: 0644]
drivers/leds/leds-tca6507.c
drivers/md/Kconfig
drivers/md/Makefile
drivers/md/dm-bufio.c
drivers/md/dm-bufio.h
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-queue-length.c
drivers/md/dm-raid.c
drivers/md/dm-raid1.c
drivers/md/dm-round-robin.c
drivers/md/dm-service-time.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 [new file with mode: 0644]
drivers/md/dm.c
drivers/md/persistent-data/dm-btree-internal.h
drivers/md/persistent-data/dm-btree-remove.c
drivers/md/persistent-data/dm-btree.c
drivers/md/persistent-data/dm-space-map-common.c
drivers/media/common/tuners/Makefile
drivers/media/common/tuners/max2165.c
drivers/media/common/tuners/mt2063.c
drivers/media/common/tuners/mt2063.h
drivers/media/common/tuners/tuner-types.c
drivers/media/common/tuners/xc5000.c
drivers/media/common/tuners/xc5000.h
drivers/media/dvb/ddbridge/ddbridge-core.c
drivers/media/dvb/ddbridge/ddbridge.h
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/az6007.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/it913x.c
drivers/media/dvb/dvb-usb/lmedm04.c
drivers/media/dvb/dvb-usb/lmedm04.h
drivers/media/dvb/dvb-usb/mxl111sf.c
drivers/media/dvb/dvb-usb/rtl28xxu.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/rtl28xxu.h [new file with mode: 0644]
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/au8522_decoder.c
drivers/media/dvb/frontends/au8522_dig.c
drivers/media/dvb/frontends/cx22702.c
drivers/media/dvb/frontends/dib0090.c
drivers/media/dvb/frontends/dib9000.c
drivers/media/dvb/frontends/drxd_hard.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/it913x-fe-priv.h
drivers/media/dvb/frontends/it913x-fe.c
drivers/media/dvb/frontends/it913x-fe.h
drivers/media/dvb/frontends/lgdt330x.c
drivers/media/dvb/frontends/m88rs2000.c [new file with mode: 0644]
drivers/media/dvb/frontends/m88rs2000.h [new file with mode: 0644]
drivers/media/dvb/frontends/rtl2830.c [new file with mode: 0644]
drivers/media/dvb/frontends/rtl2830.h [new file with mode: 0644]
drivers/media/dvb/frontends/rtl2830_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_drv.c
drivers/media/dvb/frontends/stv0288.c
drivers/media/dvb/frontends/tda10071.c
drivers/media/dvb/ngene/ngene-cards.c
drivers/media/dvb/pt1/pt1.c
drivers/media/media-devnode.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-isa.c [new file with mode: 0644]
drivers/media/radio/radio-isa.h [new file with mode: 0644]
drivers/media/radio/radio-keene.c [new file with mode: 0644]
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-tea5764.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-zoltrix.c
drivers/media/radio/saa7706h.c
drivers/media/radio/si470x/radio-si470x-i2c.c
drivers/media/radio/si4713-i2c.c
drivers/media/radio/tef6862.c
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/fintek-cir.c
drivers/media/rc/fintek-cir.h
drivers/media/rc/gpio-ir-recv.c [new file with mode: 0644]
drivers/media/rc/ir-sony-decoder.c
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-it913x-v1.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-it913x-v2.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-kworld-pc150u.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
drivers/media/rc/mceusb.c
drivers/media/rc/rc-core-priv.h
drivers/media/rc/rc-main.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adp1653.c
drivers/media/video/adv7170.c
drivers/media/video/adv7175.c
drivers/media/video/adv7180.c
drivers/media/video/adv7183.c [new file with mode: 0644]
drivers/media/video/adv7183_regs.h [new file with mode: 0644]
drivers/media/video/adv7343.c
drivers/media/video/ak881x.c
drivers/media/video/aptina-pll.c [new file with mode: 0644]
drivers/media/video/aptina-pll.h [new file with mode: 0644]
drivers/media/video/as3645a.c
drivers/media/video/blackfin/Kconfig [new file with mode: 0644]
drivers/media/video/blackfin/Makefile [new file with mode: 0644]
drivers/media/video/blackfin/bfin_capture.c [new file with mode: 0644]
drivers/media/video/blackfin/ppi.c [new file with mode: 0644]
drivers/media/video/bt819.c
drivers/media/video/bt856.c
drivers/media/video/bt866.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/cs5345.c
drivers/media/video/cs53l32a.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx231xx/cx231xx-417.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx231xx/cx231xx-video.c
drivers/media/video/cx25821/cx25821-core.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/davinci/vpif.h
drivers/media/video/davinci/vpif_display.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-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/gspca/gl860/Makefile
drivers/media/video/gspca/m5602/Makefile
drivers/media/video/gspca/ov534_9.c
drivers/media/video/gspca/pac7302.c
drivers/media/video/gspca/sn9c20x.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/stv06xx/Makefile
drivers/media/video/gspca/zc3xx.c
drivers/media/video/imx074.c
drivers/media/video/indycam.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/Makefile
drivers/media/video/ivtv/ivtv-controls.c
drivers/media/video/ivtv/ivtv-controls.h
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ks0127.c
drivers/media/video/m52790.c
drivers/media/video/m5mols/m5mols_core.c
drivers/media/video/marvell-ccic/mcam-core.c
drivers/media/video/marvell-ccic/mcam-core.h
drivers/media/video/marvell-ccic/mmp-driver.c
drivers/media/video/msp3400-driver.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9m032.c [new file with mode: 0644]
drivers/media/video/mt9m111.c
drivers/media/video/mt9p031.c
drivers/media/video/mt9t001.c
drivers/media/video/mt9t031.c
drivers/media/video/mt9t112.c
drivers/media/video/mt9v011.c
drivers/media/video/mt9v022.c
drivers/media/video/mt9v032.c
drivers/media/video/mx2_camera.c
drivers/media/video/mx2_emmaprp.c [new file with mode: 0644]
drivers/media/video/noon010pc30.c
drivers/media/video/omap/omap_vout.c
drivers/media/video/ov2640.c
drivers/media/video/ov5642.c
drivers/media/video/ov6650.c
drivers/media/video/ov7670.c
drivers/media/video/ov772x.c
drivers/media/video/ov9640.c
drivers/media/video/ov9740.c
drivers/media/video/pvrusb2/pvrusb2-devattr.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pxa_camera.c
drivers/media/video/rj54n1cb0c.c
drivers/media/video/s2255drv.c
drivers/media/video/s5k6aa.c
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/s5p-fimc/fimc-core.h
drivers/media/video/s5p-fimc/fimc-mdevice.c
drivers/media/video/s5p-fimc/mipi-csis.c
drivers/media/video/s5p-g2d/g2d-hw.c
drivers/media/video/s5p-g2d/g2d.c
drivers/media/video/s5p-g2d/g2d.h
drivers/media/video/s5p-jpeg/jpeg-core.c
drivers/media/video/s5p-jpeg/jpeg-core.h
drivers/media/video/s5p-jpeg/jpeg-hw.h
drivers/media/video/s5p-mfc/s5p_mfc_pm.c
drivers/media/video/s5p-tv/Kconfig
drivers/media/video/s5p-tv/Makefile
drivers/media/video/s5p-tv/hdmi_drv.c
drivers/media/video/s5p-tv/hdmiphy_drv.c
drivers/media/video/s5p-tv/mixer_drv.c
drivers/media/video/s5p-tv/sdo_drv.c
drivers/media/video/s5p-tv/sii9234_drv.c [new file with mode: 0644]
drivers/media/video/saa6588.c
drivers/media/video/saa7110.c
drivers/media/video/saa7115.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/Makefile
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7164/Makefile
drivers/media/video/saa7164/saa7164-encoder.c
drivers/media/video/saa7164/saa7164-vbi.c
drivers/media/video/saa717x.c
drivers/media/video/saa7185.c
drivers/media/video/saa7191.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/soc_camera.c
drivers/media/video/sr030pc30.c
drivers/media/video/tda7432.c
drivers/media/video/tda9840.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/ths7303.c
drivers/media/video/tlv320aic23b.c
drivers/media/video/tm6000/tm6000-input.c
drivers/media/video/tuner-core.c
drivers/media/video/tvaudio.c
drivers/media/video/tveeprom.c
drivers/media/video/tvp514x.c
drivers/media/video/tvp5150.c
drivers/media/video/tvp7002.c
drivers/media/video/tw9910.c
drivers/media/video/upd64031a.c
drivers/media/video/upd64083.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_queue.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-ctrls.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-subdev.c
drivers/media/video/videobuf2-vmalloc.c
drivers/media/video/vivi.c
drivers/media/video/vp27smpx.c
drivers/media/video/vpx3220.c
drivers/media/video/vs6624.c [new file with mode: 0644]
drivers/media/video/vs6624_regs.h [new file with mode: 0644]
drivers/media/video/w9966.c
drivers/media/video/wm8739.c
drivers/media/video/wm8775.c
drivers/message/fusion/mptbase.c
drivers/mfd/88pm860x-core.c
drivers/mfd/88pm860x-i2c.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-i2c.c
drivers/mfd/anatop-mfd.c [new file with mode: 0644]
drivers/mfd/asic3.c
drivers/mfd/da9052-core.c
drivers/mfd/da9052-i2c.c
drivers/mfd/da9052-spi.c
drivers/mfd/db8500-prcmu.c
drivers/mfd/dbx500-prcmu-regs.h
drivers/mfd/mc13xxx-core.c
drivers/mfd/mcp-core.c
drivers/mfd/mcp-sa11x0.c
drivers/mfd/mfd-core.c
drivers/mfd/omap-usb-host.c
drivers/mfd/pcf50633-core.c
drivers/mfd/pcf50633-gpio.c
drivers/mfd/pcf50633-irq.c
drivers/mfd/rc5t583-irq.c [new file with mode: 0644]
drivers/mfd/rc5t583.c [new file with mode: 0644]
drivers/mfd/s5m-core.c
drivers/mfd/s5m-irq.c
drivers/mfd/sm501.c
drivers/mfd/stmpe.c
drivers/mfd/tps65090.c [new file with mode: 0644]
drivers/mfd/tps65217.c [new file with mode: 0644]
drivers/mfd/tps65910-irq.c
drivers/mfd/tps65910.c
drivers/mfd/twl-core.c
drivers/mfd/twl-core.h
drivers/mfd/twl4030-irq.c
drivers/mfd/twl6030-irq.c
drivers/mfd/ucb1x00-assabet.c
drivers/mfd/ucb1x00-core.c
drivers/mfd/ucb1x00-ts.c
drivers/mfd/wm831x-spi.c
drivers/mfd/wm8400-core.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-regmap.c
drivers/misc/atmel_tclib.c
drivers/mmc/host/Kconfig
drivers/mmc/host/at91_mci.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-tegra.c
drivers/mtd/Kconfig
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/devices/Kconfig
drivers/mtd/maps/Kconfig
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/mtdchar.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/onenand/Kconfig
drivers/mtd/ubi/build.c
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/wl.c
drivers/net/Space.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bonding.h
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/cnic_defs.h
drivers/net/ethernet/broadcom/cnic_if.h
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/cirrus/Kconfig
drivers/net/ethernet/cirrus/cs89x0.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/sun/sunvnet.c
drivers/net/irda/Kconfig
drivers/net/irda/sa1100_ir.c
drivers/net/usb/cdc-phonet.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/usbnet.c
drivers/net/wireless/iwlegacy/3945.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlwifi/iwl-agn-rx.c
drivers/net/xen-netfront.c
drivers/of/Kconfig
drivers/of/Makefile
drivers/of/gpio.c
drivers/of/of_mtd.c [new file with mode: 0644]
drivers/of/platform.c
drivers/parisc/dino.c
drivers/parisc/lba_pci.c
drivers/pci/Kconfig
drivers/pci/bus.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/cpci_hotplug_pci.c
drivers/pci/hotplug/cpcihp_generic.c
drivers/pci/hotplug/cpqphp_pci.c
drivers/pci/hotplug/fakephp.c
drivers/pci/hotplug/ibmphp_core.c
drivers/pci/hotplug/ibmphp_ebda.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/hotplug/rpadlpar_core.c
drivers/pci/hotplug/sgi_hotplug.c
drivers/pci/hotplug/shpchp_pci.c
drivers/pci/iov.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/Kconfig
drivers/pci/pcie/aspm.c
drivers/pci/pcie/portdrv.h
drivers/pci/pcie/portdrv_core.c
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/remove.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/pci/xen-pcifront.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/at91_cf.c
drivers/pcmcia/cardbus.c
drivers/pcmcia/pxa2xx_balloon3.c
drivers/pcmcia/pxa2xx_base.c
drivers/pcmcia/pxa2xx_cm_x255.c
drivers/pcmcia/pxa2xx_cm_x270.c
drivers/pcmcia/pxa2xx_colibri.c
drivers/pcmcia/pxa2xx_e740.c
drivers/pcmcia/pxa2xx_lubbock.c [deleted file]
drivers/pcmcia/pxa2xx_mainstone.c
drivers/pcmcia/pxa2xx_palmld.c
drivers/pcmcia/pxa2xx_palmtc.c
drivers/pcmcia/pxa2xx_palmtx.c
drivers/pcmcia/pxa2xx_sharpsl.c
drivers/pcmcia/pxa2xx_stargate2.c
drivers/pcmcia/pxa2xx_trizeps4.c
drivers/pcmcia/pxa2xx_viper.c
drivers/pcmcia/pxa2xx_vpac270.c
drivers/pcmcia/sa1100_assabet.c
drivers/pcmcia/sa1100_badge4.c [deleted file]
drivers/pcmcia/sa1100_cerf.c
drivers/pcmcia/sa1100_h3600.c
drivers/pcmcia/sa1100_jornada720.c [deleted file]
drivers/pcmcia/sa1100_nanoengine.c
drivers/pcmcia/sa1100_neponset.c [deleted file]
drivers/pcmcia/sa1100_shannon.c
drivers/pcmcia/sa1100_simpad.c
drivers/pcmcia/sa1111_badge4.c [new file with mode: 0644]
drivers/pcmcia/sa1111_generic.c
drivers/pcmcia/sa1111_generic.h
drivers/pcmcia/sa1111_jornada720.c [new file with mode: 0644]
drivers/pcmcia/sa1111_lubbock.c [new file with mode: 0644]
drivers/pcmcia/sa1111_neponset.c [new file with mode: 0644]
drivers/pcmcia/sa11xx_base.c
drivers/pcmcia/soc_common.c
drivers/pcmcia/soc_common.h
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/acerhdf.c
drivers/platform/x86/amilo-rfkill.c
drivers/platform/x86/apple-gmux.c [new file with mode: 0644]
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/asus-wmi.h
drivers/platform/x86/asus_acpi.c [deleted file]
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/eeepc-wmi.c
drivers/platform/x86/hdaps.c
drivers/platform/x86/intel_mid_powerbtn.c
drivers/platform/x86/intel_mid_thermal.c
drivers/platform/x86/intel_oaktrail.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/xo1-rfkill.c
drivers/power/apm_power.c
drivers/power/max8998_charger.c
drivers/power/power_supply.h
drivers/power/power_supply_leds.c
drivers/power/power_supply_sysfs.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/bq24022.c [deleted file]
drivers/remoteproc/Kconfig [new file with mode: 0644]
drivers/remoteproc/Makefile [new file with mode: 0644]
drivers/remoteproc/omap_remoteproc.c [new file with mode: 0644]
drivers/remoteproc/omap_remoteproc.h [new file with mode: 0644]
drivers/remoteproc/remoteproc_core.c [new file with mode: 0644]
drivers/remoteproc/remoteproc_debugfs.c [new file with mode: 0644]
drivers/remoteproc/remoteproc_internal.h [new file with mode: 0644]
drivers/remoteproc/remoteproc_virtio.c [new file with mode: 0644]
drivers/rpmsg/Kconfig [new file with mode: 0644]
drivers/rpmsg/Makefile [new file with mode: 0644]
drivers/rpmsg/virtio_rpmsg_bus.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-88pm860x.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-bq32k.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-coh901331.c
drivers/rtc/rtc-da9052.c [new file with mode: 0644]
drivers/rtc/rtc-davinci.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-ds1390.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-ds1672.c
drivers/rtc/rtc-ds3232.c
drivers/rtc/rtc-ds3234.c
drivers/rtc/rtc-em3027.c
drivers/rtc/rtc-fm3130.c
drivers/rtc/rtc-isl12022.c
drivers/rtc/rtc-isl1208.c
drivers/rtc/rtc-lpc32xx.c
drivers/rtc/rtc-ls1x.c [new file with mode: 0644]
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-m41t93.c
drivers/rtc/rtc-m41t94.c
drivers/rtc/rtc-max6900.c
drivers/rtc/rtc-max6902.c
drivers/rtc/rtc-max8925.c
drivers/rtc/rtc-mpc5121.c
drivers/rtc/rtc-mrst.c
drivers/rtc/rtc-mv.c
drivers/rtc/rtc-nuc900.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-pcf2123.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-pcf8583.c
drivers/rtc/rtc-pl030.c
drivers/rtc/rtc-pl031.c
drivers/rtc/rtc-pm8xxx.c
drivers/rtc/rtc-pxa.c
drivers/rtc/rtc-r9701.c
drivers/rtc/rtc-rs5c348.c
drivers/rtc/rtc-rs5c372.c
drivers/rtc/rtc-rv3029c2.c
drivers/rtc/rtc-rx8025.c
drivers/rtc/rtc-rx8581.c
drivers/rtc/rtc-s35390a.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-sh.c
drivers/rtc/rtc-spear.c
drivers/rtc/rtc-stk17ta8.c
drivers/rtc/rtc-twl.c
drivers/rtc/rtc-tx4939.c
drivers/rtc/rtc-vr41xx.c
drivers/rtc/rtc-x1205.c
drivers/s390/char/sclp_cmd.c
drivers/s390/cio/qdio_main.c
drivers/s390/cio/qdio_setup.c
drivers/scsi/arm/arxescsi.c
drivers/scsi/arm/fas216.c
drivers/scsi/arm/fas216.h
drivers/scsi/bnx2fc/bnx2fc_constants.h
drivers/scsi/bnx2i/57xx_iscsi_constants.h
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvstgt.c
drivers/scsi/mpt2sas/mpt2sas_base.c
drivers/sh/clk/cpg.c
drivers/spi/Kconfig
drivers/spi/spi-orion.c
drivers/spi/spi-s3c24xx.c
drivers/staging/iio/gyro/adis16060_core.c
drivers/staging/media/Kconfig
drivers/staging/media/as102/as102_drv.c
drivers/staging/media/as102/as102_drv.h
drivers/staging/media/as102/as102_fe.c
drivers/staging/media/as102/as102_fw.h
drivers/staging/media/as102/as102_usb_drv.c
drivers/staging/media/as102/as10x_cmd.h
drivers/staging/media/as102/as10x_types.h
drivers/staging/media/easycap/easycap_main.c
drivers/staging/media/go7007/go7007-v4l2.c
drivers/staging/media/go7007/s2250-board.c
drivers/staging/media/lirc/lirc_serial.c
drivers/staging/media/solo6x10/Kconfig
drivers/staging/media/solo6x10/core.c
drivers/staging/mei/wd.c
drivers/staging/rtl8187se/r8180_core.c
drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
drivers/staging/ste_rmi4/Makefile
drivers/staging/telephony/ixj.c
drivers/staging/wlags49_h2/hcf.c
drivers/tty/hvc/hvc_vio.c
drivers/tty/hvc/hvcs.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/imx.c
drivers/tty/serial/pxa.c
drivers/tty/serial/sa1100.c
drivers/tty/serial/sn_console.c
drivers/usb/Kconfig
drivers/usb/gadget/Kconfig
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/f_phonet.c
drivers/usb/host/ehci-atmel.c
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-sa1111.c
drivers/usb/host/pci-quirks.c
drivers/usb/serial/option.c
drivers/uwb/allocator.c
drivers/vhost/net.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/video/Kconfig
drivers/video/backlight/88pm860x_bl.c
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/aat2870_bl.c
drivers/video/backlight/adp5520_bl.c
drivers/video/backlight/adp8860_bl.c
drivers/video/backlight/adp8870_bl.c
drivers/video/backlight/ams369fg06.c
drivers/video/backlight/apple_bl.c
drivers/video/backlight/corgi_lcd.c
drivers/video/backlight/cr_bllcd.c
drivers/video/backlight/da903x_bl.c
drivers/video/backlight/ep93xx_bl.c
drivers/video/backlight/l4f00242t03.c
drivers/video/backlight/ld9040.c
drivers/video/backlight/lms283gf05.c
drivers/video/backlight/lp855x_bl.c [new file with mode: 0644]
drivers/video/backlight/ltv350qv.c
drivers/video/backlight/max8925_bl.c
drivers/video/backlight/omap1_bl.c
drivers/video/backlight/ot200_bl.c [new file with mode: 0644]
drivers/video/backlight/pandora_bl.c [new file with mode: 0644]
drivers/video/backlight/pcf50633-backlight.c
drivers/video/backlight/platform_lcd.c
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/s6e63m0.c
drivers/video/backlight/tdo24m.c
drivers/video/backlight/tosa_bl.c
drivers/video/backlight/tosa_lcd.c
drivers/video/backlight/vgg2432a4.c
drivers/video/backlight/wm831x_bl.c
drivers/video/ep93xx-fb.c
drivers/video/omap/lcd_ams_delta.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dss.c
drivers/video/sa1100fb.c
drivers/video/sa1100fb.h
drivers/video/uvesafb.c
drivers/watchdog/Kconfig
drivers/watchdog/acquirewdt.c
drivers/watchdog/advantechwdt.c
drivers/watchdog/alim1535_wdt.c
drivers/watchdog/alim7101_wdt.c
drivers/watchdog/ar7_wdt.c
drivers/watchdog/at32ap700x_wdt.c
drivers/watchdog/at91rm9200_wdt.c
drivers/watchdog/at91sam9_wdt.c
drivers/watchdog/ath79_wdt.c
drivers/watchdog/bcm47xx_wdt.c
drivers/watchdog/bcm63xx_wdt.c
drivers/watchdog/bfin_wdt.c
drivers/watchdog/booke_wdt.c
drivers/watchdog/coh901327_wdt.c
drivers/watchdog/cpu5wdt.c
drivers/watchdog/cpwd.c
drivers/watchdog/dw_wdt.c
drivers/watchdog/ep93xx_wdt.c
drivers/watchdog/eurotechwdt.c
drivers/watchdog/f71808e_wdt.c
drivers/watchdog/gef_wdt.c
drivers/watchdog/geodewdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/i6300esb.c
drivers/watchdog/iTCO_vendor_support.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/ib700wdt.c
drivers/watchdog/ibmasr.c
drivers/watchdog/imx2_wdt.c
drivers/watchdog/indydog.c
drivers/watchdog/intel_scu_watchdog.c
drivers/watchdog/intel_scu_watchdog.h
drivers/watchdog/iop_wdt.c
drivers/watchdog/it8712f_wdt.c
drivers/watchdog/it87_wdt.c
drivers/watchdog/ixp2000_wdt.c
drivers/watchdog/ixp4xx_wdt.c
drivers/watchdog/jz4740_wdt.c
drivers/watchdog/ks8695_wdt.c
drivers/watchdog/lantiq_wdt.c
drivers/watchdog/m54xx_wdt.c
drivers/watchdog/machzwd.c
drivers/watchdog/max63xx_wdt.c
drivers/watchdog/mixcomwd.c
drivers/watchdog/mpc8xxx_wdt.c
drivers/watchdog/mpcore_wdt.c
drivers/watchdog/mv64x60_wdt.c
drivers/watchdog/nuc900_wdt.c
drivers/watchdog/nv_tco.c
drivers/watchdog/octeon-wdt-main.c
drivers/watchdog/of_xilinx_wdt.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/orion_wdt.c
drivers/watchdog/pc87413_wdt.c
drivers/watchdog/pcwd.c
drivers/watchdog/pcwd_pci.c
drivers/watchdog/pcwd_usb.c
drivers/watchdog/pika_wdt.c
drivers/watchdog/pnx4008_wdt.c
drivers/watchdog/pnx833x_wdt.c
drivers/watchdog/rc32434_wdt.c
drivers/watchdog/riowd.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sa1100_wdt.c
drivers/watchdog/sb_wdog.c
drivers/watchdog/sbc60xxwdt.c
drivers/watchdog/sbc7240_wdt.c
drivers/watchdog/sbc8360.c
drivers/watchdog/sbc_epx_c3.c
drivers/watchdog/sbc_fitpc2_wdt.c
drivers/watchdog/sc1200wdt.c
drivers/watchdog/sc520_wdt.c
drivers/watchdog/sch311x_wdt.c
drivers/watchdog/scx200_wdt.c
drivers/watchdog/shwdt.c
drivers/watchdog/smsc37b787_wdt.c
drivers/watchdog/softdog.c
drivers/watchdog/sp5100_tco.c
drivers/watchdog/sp805_wdt.c
drivers/watchdog/stmp3xxx_wdt.c
drivers/watchdog/ts72xx_wdt.c
drivers/watchdog/twl4030_wdt.c
drivers/watchdog/txx9wdt.c
drivers/watchdog/via_wdt.c
drivers/watchdog/w83627hf_wdt.c
drivers/watchdog/w83697hf_wdt.c
drivers/watchdog/w83697ug_wdt.c
drivers/watchdog/w83877f_wdt.c
drivers/watchdog/w83977f_wdt.c
drivers/watchdog/wafer5823wdt.c
drivers/watchdog/watchdog_core.c
drivers/watchdog/watchdog_dev.c
drivers/watchdog/wdrtas.c
drivers/watchdog/wdt.c
drivers/watchdog/wdt285.c
drivers/watchdog/wdt977.c
drivers/watchdog/wdt_pci.c
drivers/watchdog/wm831x_wdt.c
drivers/watchdog/wm8350_wdt.c
drivers/watchdog/xen_wdt.c
drivers/xen/Kconfig
drivers/xen/events.c
drivers/xen/platform-pci.c
drivers/xen/tmem.c
drivers/xen/xen-acpi-processor.c
fs/9p/vfs_super.c
fs/aio.c
fs/attr.c
fs/bad_inode.c
fs/binfmt_elf.c
fs/binfmt_flat.c
fs/binfmt_misc.c
fs/bio.c
fs/block_dev.c
fs/buffer.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/snap.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/cifs/README
fs/cifs/cifs_debug.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/misc.c
fs/cifs/transport.c
fs/compat.c
fs/compat_ioctl.c
fs/dcache.c
fs/dcookies.c
fs/eventfd.c
fs/eventpoll.c
fs/ext3/balloc.c
fs/ext3/inode.c
fs/ext4/balloc.c
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/ext4_extents.h
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/fsync.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h
fs/ext4/migrate.c
fs/ext4/mmp.c
fs/ext4/namei.c
fs/ext4/page-io.c
fs/ext4/resize.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/fat/namei_vfat.c
fs/file.c
fs/fs-writeback.c
fs/fs_struct.c
fs/hostfs/hostfs.h
fs/hostfs/hostfs_kern.c
fs/hostfs/hostfs_user.c
fs/ioctl.c
fs/jbd2/checkpoint.c
fs/jbd2/commit.c
fs/jbd2/journal.c
fs/jbd2/recovery.c
fs/jbd2/revoke.c
fs/jbd2/transaction.c
fs/libfs.c
fs/lockd/clnt4xdr.c
fs/lockd/clntlock.c
fs/lockd/clntxdr.c
fs/lockd/host.c
fs/lockd/mon.c
fs/lockd/netns.h [new file with mode: 0644]
fs/lockd/svc.c
fs/lockd/svclock.c
fs/mpage.c
fs/namei.c
fs/nfs/Kconfig
fs/nfs/blocklayout/blocklayout.c
fs/nfs/blocklayout/blocklayout.h
fs/nfs/blocklayout/blocklayoutdev.c
fs/nfs/blocklayout/blocklayoutdm.c
fs/nfs/blocklayout/extents.c
fs/nfs/cache_lib.c
fs/nfs/cache_lib.h
fs/nfs/callback.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
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/dns_resolve.c
fs/nfs/dns_resolve.h
fs/nfs/file.c
fs/nfs/fscache.c
fs/nfs/idmap.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/mount_clnt.c
fs/nfs/namespace.c
fs/nfs/netns.h [new file with mode: 0644]
fs/nfs/nfs2xdr.c
fs/nfs/nfs3acl.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayout.h
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4namespace.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/nfsroot.c
fs/nfs/objlayout/objio_osd.c
fs/nfs/objlayout/objlayout.c
fs/nfs/objlayout/objlayout.h
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/pnfs_dev.c
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/nfs4callback.c
fs/nfsd/nfs4state.c
fs/nfsd/nfsctl.c
fs/nfsd/nfssvc.c
fs/nfsd/stats.c
fs/notify/notification.c
fs/pipe.c
fs/posix_acl.c
fs/proc/array.c
fs/proc/internal.h
fs/proc/kcore.c
fs/proc/namespaces.c
fs/proc/proc_sysctl.c
fs/proc/stat.c
fs/pstore/platform.c
fs/quota/dquot.c
fs/quota/quota.c
fs/read_write.c
fs/readdir.c
fs/reiserfs/reiserfs.h
fs/select.c
fs/seq_file.c
fs/splice.c
fs/stack.c
fs/stat.c
fs/statfs.c
fs/super.c
fs/sync.c
fs/ubifs/debug.c
fs/ubifs/debug.h
fs/ubifs/dir.c
fs/ubifs/recovery.c
fs/ubifs/sb.c
fs/ubifs/ubifs.h
fs/udf/balloc.c
fs/udf/ialloc.c
fs/udf/inode.c
fs/udf/super.c
fs/udf/udf_i.h
fs/xattr.c
fs/xattr_acl.c
fs/xfs/Makefile
fs/xfs/xfs_alloc.c
fs/xfs/xfs_alloc.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_bmap.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_da_btree.c
fs/xfs/xfs_dfrag.c
fs/xfs/xfs_dir2_block.c
fs/xfs/xfs_discard.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot.h
fs/xfs/xfs_file.c
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_inode_item.h
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_ioctl32.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_itable.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
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_qm.h
fs/xfs/xfs_qm_bhv.c
fs/xfs/xfs_qm_stats.c [deleted file]
fs/xfs/xfs_qm_stats.h [deleted file]
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_quota.h
fs/xfs/xfs_quota_priv.h
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_sb.h
fs/xfs/xfs_stats.c
fs/xfs/xfs_stats.h
fs/xfs/xfs_super.c
fs/xfs/xfs_super.h
fs/xfs/xfs_sync.c
fs/xfs/xfs_sync.h
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_dquot.c
fs/xfs/xfs_trans_inode.c
fs/xfs/xfs_trans_priv.h
fs/xfs/xfs_vnode.h
fs/xfs/xfs_vnodeops.h
include/asm-generic/bug.h
include/asm-generic/dma-mapping-common.h
include/asm-generic/gpio.h
include/asm-generic/mman-common.h
include/asm-generic/pci-bridge.h
include/asm-generic/pci.h
include/asm-generic/pgtable.h
include/asm-generic/tlbflush.h
include/asm-generic/vmlinux.lds.h
include/drm/drm_mode.h
include/drm/ttm/ttm_memory.h
include/linux/acpi.h
include/linux/amba/bus.h
include/linux/amba/mmci.h
include/linux/amba/pl022.h
include/linux/amd-iommu.h
include/linux/apple_bl.h [new file with mode: 0644]
include/linux/atmdev.h
include/linux/atmel_tc.h
include/linux/attribute_container.h
include/linux/bio.h
include/linux/bit_spinlock.h
include/linux/bitops.h
include/linux/bug.h
include/linux/c2port.h
include/linux/cdrom.h
include/linux/ceph/decode.h
include/linux/ceph/libceph.h
include/linux/ceph/mdsmap.h
include/linux/ceph/messenger.h
include/linux/clk-private.h [new file with mode: 0644]
include/linux/clk-provider.h [new file with mode: 0644]
include/linux/clk.h
include/linux/compiler-gcc.h
include/linux/cpu.h
include/linux/cpufreq.h
include/linux/cpumask.h
include/linux/crash_dump.h
include/linux/crc32.h
include/linux/crypto.h
include/linux/debug_locks.h
include/linux/dma-buf.h
include/linux/dmaengine.h
include/linux/edac.h
include/linux/elfcore.h
include/linux/ext3_fs.h
include/linux/fb.h
include/linux/firewire.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/gpio.h
include/linux/highmem.h
include/linux/hwmon-sysfs.h
include/linux/hwmon.h
include/linux/hwspinlock.h
include/linux/i2c-algo-bit.h
include/linux/i2c-algo-pcf.h
include/linux/i2c-dev.h
include/linux/i2c-mux.h
include/linux/i2c-smbus.h
include/linux/i2c.h
include/linux/i2c/at24.h
include/linux/i2c/twl.h
include/linux/i2o.h
include/linux/ide.h
include/linux/if_vlan.h
include/linux/io-mapping.h
include/linux/ioport.h
include/linux/ipmi.h
include/linux/ipmi_smi.h
include/linux/ivtv.h
include/linux/jbd2.h
include/linux/journal-head.h
include/linux/jz4740-adc.h
include/linux/kernel.h
include/linux/key.h
include/linux/kmod.h
include/linux/kprobes.h
include/linux/kvm.h
include/linux/kvm_host.h
include/linux/led-lm3530.h
include/linux/leds-lp5521.h
include/linux/lockd/bind.h
include/linux/lockd/lockd.h
include/linux/lockd/xdr4.h
include/linux/lp855x.h [new file with mode: 0644]
include/linux/magic.h
include/linux/maple.h
include/linux/memory_hotplug.h
include/linux/mfd/88pm860x.h
include/linux/mfd/abx500.h
include/linux/mfd/abx500/ab5500.h
include/linux/mfd/abx500/ab8500-gpio.h
include/linux/mfd/abx500/ab8500-sysctrl.h
include/linux/mfd/abx500/ab8500.h
include/linux/mfd/anatop.h [new file with mode: 0644]
include/linux/mfd/da9052/da9052.h
include/linux/mfd/db8500-prcmu.h
include/linux/mfd/dbx500-prcmu.h
include/linux/mfd/mc13xxx.h
include/linux/mfd/mcp.h
include/linux/mfd/pm8xxx/pm8921.h
include/linux/mfd/rc5t583.h [new file with mode: 0644]
include/linux/mfd/stmpe.h
include/linux/mfd/tc3589x.h
include/linux/mfd/tps65090.h [new file with mode: 0644]
include/linux/mfd/tps65217.h [new file with mode: 0644]
include/linux/mfd/tps65910.h
include/linux/mfd/ucb1x00.h
include/linux/mfd/wm8994/pdata.h
include/linux/mlx4/driver.h
include/linux/mm.h
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmc/ioctl.h
include/linux/mod_devicetable.h
include/linux/module.h
include/linux/moduleparam.h
include/linux/mtd/cfi.h
include/linux/netdevice.h
include/linux/nfs.h
include/linux/nfs4.h
include/linux/nfs_fs.h
include/linux/nfs_fs_i.h
include/linux/nfs_fs_sb.h
include/linux/nfs_idmap.h
include/linux/nfs_iostat.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/nilfs2_fs.h
include/linux/nmi.h
include/linux/of.h
include/linux/of_device.h
include/linux/of_gpio.h
include/linux/of_mtd.h [new file with mode: 0644]
include/linux/opp.h
include/linux/page-flags.h
include/linux/pci.h
include/linux/pci_regs.h
include/linux/phy.h
include/linux/pid_namespace.h
include/linux/pipe_fs_i.h
include/linux/platform_data/atmel.h [new file with mode: 0644]
include/linux/platform_data/tegra_emc.h [new file with mode: 0644]
include/linux/pm_domain.h
include/linux/poll.h
include/linux/posix_acl.h
include/linux/power_supply.h
include/linux/prctl.h
include/linux/ptrace.h
include/linux/radix-tree.h
include/linux/rcupdate.h
include/linux/regmap.h
include/linux/regset.h
include/linux/regulator/ab8500.h
include/linux/regulator/bq24022.h [deleted file]
include/linux/regulator/consumer.h
include/linux/relay.h
include/linux/remoteproc.h [new file with mode: 0644]
include/linux/rfkill.h
include/linux/rio_drv.h
include/linux/rpmsg.h [new file with mode: 0644]
include/linux/sa11x0-dma.h [new file with mode: 0644]
include/linux/scatterlist.h
include/linux/sched.h
include/linux/seq_file.h
include/linux/serial_pnx8xxx.h
include/linux/sh_clk.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/slub_def.h
include/linux/spi/mmc_spi.h
include/linux/spi/orion_spi.h
include/linux/spi/s3c24xx.h [new file with mode: 0644]
include/linux/spinlock.h
include/linux/ssb/ssb_driver_gige.h
include/linux/sunrpc/auth.h
include/linux/sunrpc/bc_xprt.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/debug.h
include/linux/sunrpc/metrics.h
include/linux/sunrpc/rpc_pipe_fs.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/stats.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc_xprt.h
include/linux/sunrpc/svcauth.h
include/linux/sunrpc/svcauth_gss.h
include/linux/sunrpc/svcsock.h
include/linux/sunrpc/xprt.h
include/linux/sunrpc/xprtsock.h
include/linux/swapops.h
include/linux/syscalls.h
include/linux/sysctl.h
include/linux/tracehook.h
include/linux/transport_class.h
include/linux/videodev2.h
include/linux/virtio_config.h
include/linux/virtio_ids.h
include/linux/watchdog.h
include/linux/wimax/debug.h
include/media/adv7183.h [new file with mode: 0644]
include/media/blackfin/bfin_capture.h [new file with mode: 0644]
include/media/blackfin/ppi.h [new file with mode: 0644]
include/media/davinci/vpif_types.h
include/media/gpio-ir-recv.h [new file with mode: 0644]
include/media/media-device.h
include/media/mt9m032.h [new file with mode: 0644]
include/media/rc-map.h
include/media/s5p_hdmi.h [new file with mode: 0644]
include/media/sh_mobile_ceu.h
include/media/sii9234.h [new file with mode: 0644]
include/media/tuner.h
include/media/v4l2-chip-ident.h
include/media/v4l2-ctrls.h
include/media/v4l2-dev.h
include/media/v4l2-ioctl.h
include/net/cfg80211.h
include/net/dst.h
include/net/ip_vs.h
include/net/mac80211.h
include/net/netfilter/nf_conntrack_l4proto.h
include/net/netfilter/nf_conntrack_timeout.h
include/net/netns/generic.h
include/net/red.h
include/net/sock.h
include/net/tcp.h
include/net/timewait_sock.h
include/net/udp.h
include/net/wpan-phy.h
include/scsi/osd_ore.h
include/scsi/scsi_device.h
include/scsi/scsi_netlink.h
include/scsi/scsi_transport.h
include/sound/compress_params.h
include/sound/core.h
include/sound/soc-dapm.h
include/sound/tea575x-tuner.h
include/trace/events/jbd2.h
include/trace/events/regmap.h
include/trace/events/rpm.h
include/trace/events/sunrpc.h [new file with mode: 0644]
include/trace/events/writeback.h
include/video/sa1100fb.h [new file with mode: 0644]
include/xen/interface/physdev.h
include/xen/tmem.h
include/xen/xenbus.h
init/calibrate.c
init/do_mounts.c
init/main.c
kernel/Makefile
kernel/debug/debug_core.c
kernel/debug/gdbstub.c
kernel/debug/kdb/kdb_bp.c
kernel/debug/kdb/kdb_io.c
kernel/debug/kdb/kdb_keyboard.c
kernel/debug/kdb/kdb_main.c
kernel/debug/kdb/kdb_private.h
kernel/exit.c
kernel/fork.c
kernel/kmod.c
kernel/module.c
kernel/params.c
kernel/pid_namespace.c
kernel/ptrace.c
kernel/signal.c
kernel/sys.c
kernel/sysctl.c
kernel/sysctl_check.c [deleted file]
kernel/watchdog.c
lib/Kconfig
lib/Kconfig.debug
lib/argv_split.c
lib/atomic64.c
lib/atomic64_test.c
lib/average.c
lib/bcd.c
lib/bitmap.c
lib/bsearch.c
lib/check_signature.c
lib/checksum.c
lib/cmdline.c
lib/cpu_rmap.c
lib/cpumask.c
lib/crc32.c
lib/crc32defs.h
lib/ctype.c
lib/debug_locks.c
lib/dec_and_lock.c
lib/devres.c
lib/div64.c
lib/dump_stack.c
lib/fault-inject.c
lib/find_last_bit.c
lib/find_next_bit.c
lib/flex_array.c
lib/gcd.c
lib/gen_crc32table.c
lib/genalloc.c
lib/halfmd4.c
lib/hexdump.c
lib/hweight.c
lib/idr.c
lib/int_sqrt.c
lib/iomap.c
lib/iomap_copy.c
lib/iommu-helper.c
lib/ioremap.c
lib/irq_regs.c
lib/kasprintf.c
lib/klist.c
lib/kobject.c
lib/kobject_uevent.c
lib/kstrtox.c
lib/lcm.c
lib/list_debug.c
lib/llist.c
lib/locking-selftest.c
lib/md5.c
lib/nlattr.c
lib/parser.c
lib/plist.c
lib/prio_tree.c
lib/radix-tree.c
lib/random32.c
lib/ratelimit.c
lib/rational.c
lib/rbtree.c
lib/rwsem-spinlock.c
lib/rwsem.c
lib/scatterlist.c
lib/sha1.c
lib/smp_processor_id.c
lib/spinlock_debug.c
lib/string.c
lib/string_helpers.c
lib/swiotlb.c
lib/syscall.c
lib/timerqueue.c
lib/uuid.c
lib/vsprintf.c
mm/hugetlb.c
mm/madvise.c
mm/memory.c
mm/oom_kill.c
mm/page-writeback.c
mm/slab.c
mm/slub.c
mm/vmscan.c
net/9p/client.c
net/ceph/ceph_common.c
net/ceph/messenger.c
net/ceph/osdmap.c
net/core/dev.c
net/core/skbuff.c
net/ipv4/devinet.c
net/ipv4/netfilter/iptable_filter.c
net/ipv6/netfilter/ip6table_filter.c
net/ipv6/route.c
net/l2tp/l2tp_ppp.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_proto.c
net/netfilter/nfnetlink_cttimeout.c
net/netfilter/xt_CT.c
net/netfilter/xt_LOG.c
net/netlabel/netlabel_kapi.c
net/rds/ib_cm.c
net/rds/iw_cm.c
net/rds/loop.c
net/rfkill/core.c
net/sunrpc/Kconfig
net/sunrpc/addr.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/gss_krb5_crypto.c
net/sunrpc/auth_gss/gss_krb5_mech.c
net/sunrpc/auth_gss/gss_krb5_seal.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/backchannel_rqst.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/netns.h
net/sunrpc/rpc_pipe.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/sched.c
net/sunrpc/stats.c
net/sunrpc/sunrpc.h
net/sunrpc/sunrpc_syms.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
net/sunrpc/sysctl.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtsock.c
net/sysctl_net.c
net/unix/af_unix.c
net/xfrm/xfrm_output.c
net/xfrm/xfrm_replay.c
samples/Kconfig
samples/Makefile
samples/rpmsg/Makefile [new file with mode: 0644]
samples/rpmsg/rpmsg_client_sample.c [new file with mode: 0644]
scripts/checkpatch.pl
scripts/get_maintainer.pl
security/apparmor/domain.c
security/apparmor/file.c
security/keys/key.c
security/keys/keyctl.c
security/keys/request_key.c
security/tomoyo/load_policy.c
sound/arm/aaci.c
sound/core/init.c
sound/core/pcm.c
sound/core/seq/seq.c
sound/core/timer.c
sound/i2c/other/tea575x-tuner.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/soc/imx/imx-audmux.c
sound/soc/omap/ams-delta.c
sound/soc/samsung/Kconfig
tools/perf/util/include/linux/bitops.h
tools/testing/ktest/ktest.pl
tools/testing/ktest/sample.conf
tools/virtio/linux/hrtimer.h [new file with mode: 0644]
tools/virtio/linux/module.h [new file with mode: 0644]
tools/virtio/linux/virtio.h
virt/kvm/assigned-dev.c
virt/kvm/kvm_main.c

index a1a6432..2214f12 100644 (file)
@@ -104,6 +104,8 @@ cpuidle/
        - info on CPU_IDLE, CPU idle state management subsystem.
 cputopology.txt
        - documentation on how CPU topology info is exported via sysfs.
+crc32.txt
+       - brief tutorial on CRC computation
 cris/
        - directory with info about Linux on CRIS architecture.
 crypto/
diff --git a/Documentation/ABI/testing/sysfs-block-dm b/Documentation/ABI/testing/sysfs-block-dm
new file mode 100644 (file)
index 0000000..87ca569
--- /dev/null
@@ -0,0 +1,25 @@
+What:          /sys/block/dm-<num>/dm/name
+Date:          January 2009
+KernelVersion: 2.6.29
+Contact:       dm-devel@redhat.com
+Description:   Device-mapper device name.
+               Read-only string containing mapped device name.
+Users:         util-linux, device-mapper udev rules
+
+What:          /sys/block/dm-<num>/dm/uuid
+Date:          January 2009
+KernelVersion: 2.6.29
+Contact:       dm-devel@redhat.com
+Description:   Device-mapper device UUID.
+               Read-only string containing DM-UUID or empty string
+               if DM-UUID is not set.
+Users:         util-linux, device-mapper udev rules
+
+What:          /sys/block/dm-<num>/dm/suspended
+Date:          June 2009
+KernelVersion: 2.6.31
+Contact:       dm-devel@redhat.com
+Description:   Device-mapper device suspend state.
+               Contains the value 1 while the device is suspended.
+               Otherwise it contains 0. Read-only attribute.
+Users:         util-linux, device-mapper udev rules
diff --git a/Documentation/ABI/testing/sysfs-bus-rpmsg b/Documentation/ABI/testing/sysfs-bus-rpmsg
new file mode 100644 (file)
index 0000000..189e419
--- /dev/null
@@ -0,0 +1,75 @@
+What:          /sys/bus/rpmsg/devices/.../name
+Date:          June 2011
+KernelVersion: 3.3
+Contact:       Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+               Every rpmsg device is a communication channel with a remote
+               processor. Channels are identified with a (textual) name,
+               which is maximum 32 bytes long (defined as RPMSG_NAME_SIZE in
+               rpmsg.h).
+
+               This sysfs entry contains the name of this channel.
+
+What:          /sys/bus/rpmsg/devices/.../src
+Date:          June 2011
+KernelVersion: 3.3
+Contact:       Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+               Every rpmsg device is a communication channel with a remote
+               processor. Channels have a local ("source") rpmsg address,
+               and remote ("destination") rpmsg address. When an entity
+               starts listening on one end of a channel, it assigns it with
+               a unique rpmsg address (a 32 bits integer). This way when
+               inbound messages arrive to this address, the rpmsg core
+               dispatches them to the listening entity (a kernel driver).
+
+               This sysfs entry contains the src (local) rpmsg address
+               of this channel. If it contains 0xffffffff, then an address
+               wasn't assigned (can happen if no driver exists for this
+               channel).
+
+What:          /sys/bus/rpmsg/devices/.../dst
+Date:          June 2011
+KernelVersion: 3.3
+Contact:       Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+               Every rpmsg device is a communication channel with a remote
+               processor. Channels have a local ("source") rpmsg address,
+               and remote ("destination") rpmsg address. When an entity
+               starts listening on one end of a channel, it assigns it with
+               a unique rpmsg address (a 32 bits integer). This way when
+               inbound messages arrive to this address, the rpmsg core
+               dispatches them to the listening entity.
+
+               This sysfs entry contains the dst (remote) rpmsg address
+               of this channel. If it contains 0xffffffff, then an address
+               wasn't assigned (can happen if the kernel driver that
+               is attached to this channel is exposing a service to the
+               remote processor. This make it a local rpmsg server,
+               and it is listening for inbound messages that may be sent
+               from any remote rpmsg client; it is not bound to a single
+               remote entity).
+
+What:          /sys/bus/rpmsg/devices/.../announce
+Date:          June 2011
+KernelVersion: 3.3
+Contact:       Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+               Every rpmsg device is a communication channel with a remote
+               processor. Channels are identified by a textual name (see
+               /sys/bus/rpmsg/devices/.../name above) and have a local
+               ("source") rpmsg address, and remote ("destination") rpmsg
+               address.
+
+               A channel is first created when an entity, whether local
+               or remote, starts listening on it for messages (and is thus
+               called an rpmsg server).
+
+               When that happens, a "name service" announcement is sent
+               to the other processor, in order to let it know about the
+               creation of the channel (this way remote clients know they
+               can start sending messages).
+
+               This sysfs entry tells us whether the channel is a local
+               server channel that is announced (values are either
+               true or false).
index e82e7c2..678819a 100644 (file)
@@ -17,3 +17,21 @@ Description: Some Samsung laptops have different "performance levels"
                Specifically, not all support the "overclock" option,
                and it's still unknown if this value even changes
                anything, other than making the user feel a bit better.
+
+What:          /sys/devices/platform/samsung/battery_life_extender
+Date:          December 1, 2011
+KernelVersion: 3.3
+Contact:       Corentin Chary <corentin.chary@gmail.com>
+Description:   Max battery charge level can be modified, battery cycle
+               life can be extended by reducing the max battery charge
+               level.
+               0 means normal battery mode (100% charge)
+               1 means battery life extender mode (80% charge)
+
+What:          /sys/devices/platform/samsung/usb_charge
+Date:          December 1, 2011
+KernelVersion: 3.3
+Contact:       Corentin Chary <corentin.chary@gmail.com>
+Description:   Use your USB ports to charge devices, even
+               when your laptop is powered off.
+               1 means enabled, 0 means disabled.
index d71b57f..4ee4ba3 100644 (file)
    </para>
   </para>
   </sect1>
+   <sect1 id="kgdbreboot">
+   <title>Run time parameter: kgdbreboot</title>
+   <para> The kgdbreboot feature allows you to change how the debugger
+   deals with the reboot notification.  You have 3 choices for the
+   behavior.  The default behavior is always set to 0.</para>
+   <orderedlist>
+   <listitem><para>echo -1 > /sys/module/debug_core/parameters/kgdbreboot</para>
+   <para>Ignore the reboot notification entirely.</para>
+   </listitem>
+   <listitem><para>echo 0 > /sys/module/debug_core/parameters/kgdbreboot</para>
+   <para>Send the detach message to any attached debugger client.</para>
+   </listitem>
+   <listitem><para>echo 1 > /sys/module/debug_core/parameters/kgdbreboot</para>
+   <para>Enter the debugger on reboot notify.</para>
+   </listitem>
+   </orderedlist>
+  </sect1>
   </chapter>
   <chapter id="usingKDB">
   <title>Using kdb</title>
index cea6fd3..7dc65c5 100644 (file)
@@ -128,6 +128,26 @@ url="http://www.ijg.org">http://www.ijg.org</ulink>)</corpauthor>
       <subtitle>Version 1.02</subtitle>
     </biblioentry>
 
+    <biblioentry id="itu-t81">
+      <abbrev>ITU-T.81</abbrev>
+      <authorgroup>
+       <corpauthor>International Telecommunication Union
+(<ulink url="http://www.itu.int">http://www.itu.int</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ITU-T Recommendation T.81
+"Information Technology &mdash; Digital Compression and Coding of Continous-Tone
+Still Images &mdash; Requirements and Guidelines"</title>
+    </biblioentry>
+
+    <biblioentry id="w3c-jpeg-jfif">
+      <abbrev>W3C JPEG JFIF</abbrev>
+      <authorgroup>
+       <corpauthor>The World Wide Web Consortium (<ulink
+url="http://www.w3.org/Graphics/JPEG">http://www.w3.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>JPEG JFIF</title>
+    </biblioentry>
+
     <biblioentry id="smpte12m">
       <abbrev>SMPTE&nbsp;12M</abbrev>
       <authorgroup>
index a2485b3..bce97c5 100644 (file)
@@ -2393,6 +2393,20 @@ details.</para>
            to the <link linkend="control">User controls class</link>.
          </para>
         </listitem>
+        <listitem>
+         <para>Added the device_caps field to struct v4l2_capabilities and added the new
+         V4L2_CAP_DEVICE_CAPS capability.</para>
+        </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 3.4</title>
+      <orderedlist>
+        <listitem>
+         <para>Added <link linkend="jpeg-controls">JPEG compression control
+         class</link>.</para>
+        </listitem>
       </orderedlist>
     </section>
 
index a1be378..b84f25e 100644 (file)
@@ -1286,6 +1286,49 @@ produce a slight hiss, but in the encoder itself, guaranteeing a fixed
 and reproducible audio bitstream. 0 = unmuted, 1 = muted.</entry>
              </row>
              <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-dec-playback">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_dec_playback</entry>
+             </row><row><entry spanname="descr">Determines how monolingual audio should be played back.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO</constant>&nbsp;</entry>
+                     <entry>Automatically determines the best playback mode.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO</constant>&nbsp;</entry>
+                     <entry>Stereo playback.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT</constant>&nbsp;</entry>
+                     <entry>Left channel playback.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT</constant>&nbsp;</entry>
+                     <entry>Right channel playback.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO</constant>&nbsp;</entry>
+                     <entry>Mono playback.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO</constant>&nbsp;</entry>
+                     <entry>Stereo playback with swapped left and right channels.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-dec-multilingual-playback">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_dec_playback</entry>
+             </row><row><entry spanname="descr">Determines how multilingual audio should be played back.</entry>
+             </row>
+             <row><entry></entry></row>
              <row id="v4l2-mpeg-video-encoding">
                <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ENCODING</constant>&nbsp;</entry>
                <entry>enum&nbsp;v4l2_mpeg_video_encoding</entry>
@@ -1447,6 +1490,22 @@ of the video. The supplied 32-bit integer is interpreted as follows (bit
                  </tbody>
                </entrytbl>
              </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-video-dec-pts">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DEC_PTS</constant>&nbsp;</entry>
+               <entry>integer64</entry>
+             </row><row><entry spanname="descr">This read-only control returns the
+33-bit video Presentation Time Stamp as defined in ITU T-REC-H.222.0 and ISO/IEC 13818-1 of
+the currently displayed frame. This is the same PTS as is used in &VIDIOC-DECODER-CMD;.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-video-dec-frame">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DEC_FRAME</constant>&nbsp;</entry>
+               <entry>integer64</entry>
+             </row><row><entry spanname="descr">This read-only control returns the
+frame counter of the frame that is currently displayed (decoded). This value is reset to 0 whenever
+the decoder is started.</entry>
+             </row>
 
 
              <row><entry></entry></row>
@@ -3377,6 +3436,167 @@ interface and may change in the future.</para>
        </tbody>
       </tgroup>
       </table>
+    </section>
+
+    <section id="jpeg-controls">
+      <title>JPEG Control Reference</title>
+      <para>The JPEG class includes controls for common features of JPEG
+      encoders and decoders. Currently it includes features for codecs
+      implementing progressive baseline DCT compression process with
+      Huffman entrophy coding.</para>
+      <table pgwide="1" frame="none" id="jpeg-control-id">
+      <title>JPEG Control IDs</title>
 
+      <tgroup cols="4">
+       <colspec colname="c1" colwidth="1*" />
+       <colspec colname="c2" colwidth="6*" />
+       <colspec colname="c3" colwidth="2*" />
+       <colspec colname="c4" colwidth="6*" />
+       <spanspec namest="c1" nameend="c2" spanname="id" />
+       <spanspec namest="c2" nameend="c4" spanname="descr" />
+       <thead>
+         <row>
+           <entry spanname="id" align="left">ID</entry>
+           <entry align="left">Type</entry>
+         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row><entry></entry></row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_JPEG_CLASS</constant>&nbsp;</entry>
+           <entry>class</entry>
+         </row><row><entry spanname="descr">The JPEG class descriptor. Calling
+         &VIDIOC-QUERYCTRL; for this control will return a description of this
+         control class.
+
+       </entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_JPEG_CHROMA_SUBSAMPLING</constant></entry>
+           <entry>menu</entry>
+         </row>
+         <row id="jpeg-chroma-subsampling-control">
+           <entry spanname="descr">The chroma subsampling factors describe how
+           each component of an input image is sampled, in respect to maximum
+           sample rate in each spatial dimension. See <xref linkend="itu-t81"/>,
+           clause A.1.1. for more details. The <constant>
+           V4L2_CID_JPEG_CHROMA_SUBSAMPLING</constant> control determines how
+           Cb and Cr components are downsampled after coverting an input image
+           from RGB to Y'CbCr color space.
+           </entry>
+         </row>
+         <row>
+           <entrytbl spanname="descr" cols="2">
+             <tbody valign="top">
+               <row>
+                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_444</constant>
+                 </entry><entry>No chroma subsampling, each pixel has
+                 Y, Cr and Cb values.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_422</constant>
+                 </entry><entry>Horizontally subsample Cr, Cb components
+                 by a factor of 2.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_420</constant>
+                 </entry><entry>Subsample Cr, Cb components horizontally
+                 and vertically by 2.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_411</constant>
+                 </entry><entry>Horizontally subsample Cr, Cb components
+                 by a factor of 4.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_410</constant>
+                 </entry><entry>Subsample Cr, Cb components horizontally
+                 by 4 and vertically by 2.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY</constant>
+                 </entry><entry>Use only luminance component.</entry>
+               </row>
+             </tbody>
+           </entrytbl>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_JPEG_RESTART_INTERVAL</constant>
+           </entry><entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">
+             The restart interval determines an interval of inserting RSTm
+             markers (m = 0..7). The purpose of these markers is to additionally
+             reinitialize the encoder process, in order to process blocks of
+             an image independently.
+             For the lossy compression processes the restart interval unit is
+             MCU (Minimum Coded Unit) and its value is contained in DRI
+             (Define Restart Interval) marker. If <constant>
+             V4L2_CID_JPEG_RESTART_INTERVAL</constant> control is set to 0,
+             DRI and RSTm markers will not be inserted.
+           </entry>
+         </row>
+         <row id="jpeg-quality-control">
+           <entry spanname="id"><constant>V4L2_CID_JPEG_COMPRESION_QUALITY</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">
+             <constant>V4L2_CID_JPEG_COMPRESION_QUALITY</constant> control
+             determines trade-off between image quality and size.
+             It provides simpler method for applications to control image quality,
+             without a need for direct reconfiguration of luminance and chrominance
+             quantization tables.
+
+             In cases where a driver uses quantization tables configured directly
+             by an application, using interfaces defined elsewhere, <constant>
+             V4L2_CID_JPEG_COMPRESION_QUALITY</constant> control should be set
+             by driver to 0.
+
+             <para>The value range of this control is driver-specific. Only
+             positive, non-zero values are meaningful. The recommended range
+             is 1 - 100, where larger values correspond to better image quality.
+             </para>
+           </entry>
+           </row>
+         <row id="jpeg-active-marker-control">
+           <entry spanname="id"><constant>V4L2_CID_JPEG_ACTIVE_MARKER</constant></entry>
+           <entry>bitmask</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Specify which JPEG markers are included
+           in compressed stream. This control is valid only for encoders.
+           </entry>
+         </row>
+         <row>
+           <entrytbl spanname="descr" cols="2">
+             <tbody valign="top">
+               <row>
+                 <entry><constant>V4L2_JPEG_ACTIVE_MARKER_APP0</constant></entry>
+                 <entry>Application data segment APP<subscript>0</subscript>.</entry>
+               </row><row>
+                 <entry><constant>V4L2_JPEG_ACTIVE_MARKER_APP1</constant></entry>
+                 <entry>Application data segment APP<subscript>1</subscript>.</entry>
+               </row><row>
+                 <entry><constant>V4L2_JPEG_ACTIVE_MARKER_COM</constant></entry>
+                 <entry>Comment segment.</entry>
+               </row><row>
+                 <entry><constant>V4L2_JPEG_ACTIVE_MARKER_DQT</constant></entry>
+                 <entry>Quantization tables segment.</entry>
+               </row><row>
+                 <entry><constant>V4L2_JPEG_ACTIVE_MARKER_DHT</constant></entry>
+                 <entry>Huffman tables segment.</entry>
+               </row>
+             </tbody>
+           </entrytbl>
+         </row>
+         <row><entry></entry></row>
+       </tbody>
+      </tgroup>
+      </table>
+      <para>For more details about JPEG specification, refer
+      to <xref linkend="itu-t81"/>, <xref linkend="jfif"/>,
+      <xref linkend="w3c-jpeg-jfif"/>.</para>
     </section>
 </section>
index 2f0bdb4..b299e47 100644 (file)
@@ -52,6 +52,10 @@ cropping and composing rectangles have the same size.</para>
          </textobject>
        </mediaobject>
       </figure>
+
+For complete list of the available selection targets see table <xref
+linkend="v4l2-sel-target"/>
+
     </section>
 
   <section>
@@ -186,7 +190,7 @@ V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.</para>
 
    <section>
 
-     <title>Scaling control.</title>
+     <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
@@ -200,7 +204,7 @@ the scaling ratios using these values.</para>
 
   <section>
 
-    <title>Comparison with old cropping API.</title>
+    <title>Comparison with old cropping API</title>
 
 <para>The selection API was introduced to cope with deficiencies of previous
 <link linkend="crop"> API </link>, that was designed to control simple capture
index e97c512..8ae3887 100644 (file)
@@ -128,6 +128,22 @@ structs, ioctls) must be noted in more detail in the history chapter
 applications. -->
 
       <revision>
+       <revnumber>3.4</revnumber>
+       <date>2012-01-25</date>
+       <authorinitials>sn</authorinitials>
+       <revremark>Added <link linkend="jpeg-controls">JPEG compression
+           control class.</link>
+       </revremark>
+      </revision>
+
+      <revision>
+       <revnumber>3.3</revnumber>
+       <date>2012-01-11</date>
+       <authorinitials>hv</authorinitials>
+       <revremark>Added device_caps field to struct v4l2_capabilities.</revremark>
+      </revision>
+
+      <revision>
        <revnumber>3.2</revnumber>
        <date>2011-08-26</date>
        <authorinitials>hv</authorinitials>
@@ -417,7 +433,7 @@ and discussions on the V4L mailing list.</revremark>
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.2</subtitle>
+ <subtitle>Revision 3.3</subtitle>
 
   <chapter id="common">
     &sub-common;
@@ -473,6 +489,7 @@ and discussions on the V4L mailing list.</revremark>
     &sub-cropcap;
     &sub-dbg-g-chip-ident;
     &sub-dbg-g-register;
+    &sub-decoder-cmd;
     &sub-dqevent;
     &sub-encoder-cmd;
     &sub-enumaudio;
diff --git a/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml b/Documentation/DocBook/media/v4l/vidioc-decoder-cmd.xml
new file mode 100644 (file)
index 0000000..74b87f6
--- /dev/null
@@ -0,0 +1,256 @@
+<refentry id="vidioc-decoder-cmd">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_DECODER_CMD, VIDIOC_TRY_DECODER_CMD</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_DECODER_CMD</refname>
+    <refname>VIDIOC_TRY_DECODER_CMD</refname>
+    <refpurpose>Execute an decoder command</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_decoder_cmd *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_DECODER_CMD, VIDIOC_TRY_DECODER_CMD</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+
+      <para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+    </note>
+
+    <para>These ioctls control an audio/video (usually MPEG-) decoder.
+<constant>VIDIOC_DECODER_CMD</constant> sends a command to the
+decoder, <constant>VIDIOC_TRY_DECODER_CMD</constant> can be used to
+try a command without actually executing it. To send a command applications
+must initialize all fields of a &v4l2-decoder-cmd; and call
+<constant>VIDIOC_DECODER_CMD</constant> or <constant>VIDIOC_TRY_DECODER_CMD</constant>
+with a pointer to this structure.</para>
+
+    <para>The <structfield>cmd</structfield> field must contain the
+command code. Some commands use the <structfield>flags</structfield> field for
+additional information.
+</para>
+
+    <para>A <function>write</function>() or &VIDIOC-STREAMON; call sends an implicit
+START command to the decoder if it has not been started yet.
+</para>
+
+    <para>A <function>close</function>() or &VIDIOC-STREAMOFF; call of a streaming
+file descriptor sends an implicit immediate STOP command to the decoder, and all
+buffered data is discarded.</para>
+
+    <para>These ioctls are optional, not all drivers may support
+them. They were introduced in Linux 3.3.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-decoder-cmd">
+      <title>struct <structname>v4l2_decoder_cmd</structname></title>
+      <tgroup cols="5">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>cmd</structfield></entry>
+            <entry></entry>
+            <entry></entry>
+           <entry>The decoder command, see <xref linkend="decoder-cmds" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+            <entry></entry>
+            <entry></entry>
+           <entry>Flags to go with the command. If no flags are defined for
+this command, drivers and applications must set this field to zero.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry>(anonymous)</entry>
+            <entry></entry>
+           <entry></entry>
+            <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct</entry>
+            <entry><structfield>start</structfield></entry>
+            <entry></entry>
+            <entry>Structure containing additional data for the
+<constant>V4L2_DEC_CMD_START</constant> command.</entry>
+         </row>
+         <row>
+            <entry></entry>
+            <entry></entry>
+           <entry>__s32</entry>
+           <entry><structfield>speed</structfield></entry>
+            <entry>Playback speed and direction. The playback speed is defined as
+<structfield>speed</structfield>/1000 of the normal speed. So 1000 is normal playback.
+Negative numbers denote reverse playback, so -1000 does reverse playback at normal
+speed. Speeds -1, 0 and 1 have special meanings: speed 0 is shorthand for 1000
+(normal playback). A speed of 1 steps just one frame forward, a speed of -1 steps
+just one frame back.
+           </entry>
+         </row>
+         <row>
+            <entry></entry>
+            <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>format</structfield></entry>
+            <entry>Format restrictions. This field is set by the driver, not the
+application. Possible values are <constant>V4L2_DEC_START_FMT_NONE</constant> if
+there are no format restrictions or <constant>V4L2_DEC_START_FMT_GOP</constant>
+if the decoder operates on full GOPs (<wordasword>Group Of Pictures</wordasword>).
+This is usually the case for reverse playback: the decoder needs full GOPs, which
+it can then play in reverse order. So to implement reverse playback the application
+must feed the decoder the last GOP in the video file, then the GOP before that, etc. etc.
+           </entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct</entry>
+            <entry><structfield>stop</structfield></entry>
+            <entry></entry>
+            <entry>Structure containing additional data for the
+<constant>V4L2_DEC_CMD_STOP</constant> command.</entry>
+         </row>
+         <row>
+            <entry></entry>
+            <entry></entry>
+           <entry>__u64</entry>
+           <entry><structfield>pts</structfield></entry>
+            <entry>Stop playback at this <structfield>pts</structfield> or immediately
+if the playback is already past that timestamp. Leave to 0 if you want to stop after the
+last frame was decoded.
+           </entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct</entry>
+            <entry><structfield>raw</structfield></entry>
+            <entry></entry>
+            <entry></entry>
+         </row>
+         <row>
+            <entry></entry>
+            <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>data</structfield>[16]</entry>
+           <entry>Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="decoder-cmds">
+      <title>Decoder Commands</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_DEC_CMD_START</constant></entry>
+           <entry>0</entry>
+           <entry>Start the decoder. When the decoder is already
+running or paused, this command will just change the playback speed.
+That means that calling <constant>V4L2_DEC_CMD_START</constant> when
+the decoder was paused will <emphasis>not</emphasis> resume the decoder.
+You have to explicitly call <constant>V4L2_DEC_CMD_RESUME</constant> for that.
+This command has one flag:
+<constant>V4L2_DEC_CMD_START_MUTE_AUDIO</constant>. If set, then audio will
+be muted when playing back at a non-standard speed.
+            </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_DEC_CMD_STOP</constant></entry>
+           <entry>1</entry>
+           <entry>Stop the decoder. When the decoder is already stopped,
+this command does nothing. This command has two flags:
+if <constant>V4L2_DEC_CMD_STOP_TO_BLACK</constant> is set, then the decoder will
+set the picture to black after it stopped decoding. Otherwise the last image will
+repeat. If <constant>V4L2_DEC_CMD_STOP_IMMEDIATELY</constant> is set, then the decoder
+stops immediately (ignoring the <structfield>pts</structfield> value), otherwise it
+will keep decoding until timestamp >= pts or until the last of the pending data from
+its internal buffers was decoded.
+</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_DEC_CMD_PAUSE</constant></entry>
+           <entry>2</entry>
+           <entry>Pause the decoder. When the decoder has not been
+started yet, the driver will return an &EPERM;. When the decoder is
+already paused, this command does nothing. This command has one flag:
+if <constant>V4L2_DEC_CMD_PAUSE_TO_BLACK</constant> is set, then set the
+decoder output to black when paused.
+</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_DEC_CMD_RESUME</constant></entry>
+           <entry>3</entry>
+           <entry>Resume decoding after a PAUSE command. When the
+decoder has not been started yet, the driver will return an &EPERM;.
+When the decoder is already running, this command does nothing. No
+flags are defined for this command.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <structfield>cmd</structfield> field is invalid.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EPERM</errorcode></term>
+       <listitem>
+         <para>The application sent a PAUSE or RESUME command when
+the decoder was not running.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
index af7f3f2..f431b3b 100644 (file)
@@ -74,15 +74,16 @@ only used by the STOP command and contains one bit: If the
 encoding will continue until the end of the current <wordasword>Group
 Of Pictures</wordasword>, otherwise it will stop immediately.</para>
 
-    <para>A <function>read</function>() call sends a START command to
-the encoder if it has not been started yet. After a STOP command,
+    <para>A <function>read</function>() or &VIDIOC-STREAMON; call sends an implicit
+START command to the encoder if it has not been started yet. After a STOP command,
 <function>read</function>() calls will read the remaining data
 buffered by the driver. When the buffer is empty,
 <function>read</function>() will return zero and the next
 <function>read</function>() call will restart the encoder.</para>
 
-    <para>A <function>close</function>() call sends an immediate STOP
-to the encoder, and all buffered data is discarded.</para>
+    <para>A <function>close</function>() or &VIDIOC-STREAMOFF; call of a streaming
+file descriptor sends an implicit immediate STOP to the encoder, and all buffered
+data is discarded.</para>
 
     <para>These ioctls are optional, not all drivers may support
 them. They were introduced in Linux 2.6.21.</para>
index 01ea24b..4874849 100644 (file)
   <refsect1>
     <title>Description</title>
 
+    <para>These ioctls are <emphasis role="bold">deprecated</emphasis>.
+    New drivers and applications should use <link linkend="jpeg-controls">
+    JPEG class controls</link> for image quality and JPEG markers control.
+    </para>
+
     <para>[to do]</para>
 
     <para>Ronald Bultje elaborates:</para>
@@ -86,7 +91,10 @@ to add them.</para>
          <row>
            <entry>int</entry>
            <entry><structfield>quality</structfield></entry>
-           <entry></entry>
+           <entry>Deprecated. If <link linkend="jpeg-quality-control"><constant>
+           V4L2_CID_JPEG_IMAGE_QUALITY</constant></link> control is exposed by
+           a driver applications should use it instead and ignore this field.
+           </entry>
          </row>
          <row>
            <entry>int</entry>
@@ -116,7 +124,11 @@ to add them.</para>
          <row>
            <entry>__u32</entry>
            <entry><structfield>jpeg_markers</structfield></entry>
-           <entry>See <xref linkend="jpeg-markers" />.</entry>
+           <entry>See <xref linkend="jpeg-markers"/>. Deprecated.
+           If <link linkend="jpeg-active-marker-control"><constant>
+           V4L2_CID_JPEG_ACTIVE_MARKER</constant></link> control
+           is exposed by a driver applications should use it instead
+           and ignore this field.</entry>
          </row>
        </tbody>
       </tgroup>
index a9d36e0..bb04eff 100644 (file)
 
     <para>The ioctls are used to query and configure selection rectangles.</para>
 
-<para> To query the cropping (composing) rectangle set <structfield>
-&v4l2-selection;::type </structfield> to the respective buffer type.  Do not
-use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
+<para> To query the cropping (composing) rectangle set &v4l2-selection;
+<structfield> type </structfield> field to the respective buffer type.
+Do not use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
 </constant> instead of <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
 </constant>.  Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
 <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>.  The next step is
-setting <structfield> &v4l2-selection;::target </structfield> to value
-<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant>
+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
-targets.  Fields <structfield> &v4l2-selection;::flags </structfield> and
-<structfield> &v4l2-selection;::reserved </structfield> are ignored and they
-must be filled with zeros.  The driver fills the rest of the structure or
+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
 returns &EINVAL; if incorrect buffer type or target was used. If cropping
 (composing) is not supported then the active rectangle is not mutable and it is
-always equal to the bounds rectangle.  Finally, structure <structfield>
-&v4l2-selection;::r </structfield> is filled with the current cropping
+always equal to the bounds rectangle.  Finally, the &v4l2-rect;
+<structfield>r</structfield> rectangle is filled with the current cropping
 (composing) coordinates. The coordinates are expressed in driver-dependent
 units. The only exception are rectangles for images in raw formats, whose
 coordinates are always expressed in pixels.  </para>
 
-<para> To change the cropping (composing) rectangle set <structfield>
-&v4l2-selection;::type </structfield> to the respective buffer type.  Do not
+<para> To change the cropping (composing) rectangle set the &v4l2-selection;
+<structfield>type</structfield> field to the respective buffer type.  Do not
 use multiplanar buffers.  Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE
 </constant> instead of <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
 </constant>.  Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of
 <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>.  The next step is
-setting <structfield> &v4l2-selection;::target </structfield> to value
-<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant>
+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
-targets.  Set desired active area into the field <structfield>
-&v4l2-selection;::r </structfield>.  Field <structfield>
-&v4l2-selection;::reserved </structfield> is ignored and must be filled with
-zeros.  The driver may adjust the rectangle coordinates. An application may
-introduce constraints to control rounding behaviour. Set the field
-<structfield> &v4l2-selection;::flags </structfield> to one of values:
+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
+coordinates of the requested rectangle. An application may
+introduce constraints to control rounding behaviour. The &v4l2-selection;
+<structfield>flags</structfield> field must be set to one of the following:
 
 <itemizedlist>
   <listitem>
@@ -129,7 +129,7 @@ and vertical offset and sizes are chosen according to following priority:
 
 <orderedlist>
   <listitem>
-    <para>Satisfy constraints from <structfield>&v4l2-selection;::flags</structfield>.</para>
+    <para>Satisfy constraints from &v4l2-selection; <structfield>flags</structfield>.</para>
   </listitem>
   <listitem>
     <para>Adjust width, height, left, and top to hardware limits and alignments.</para>
@@ -145,7 +145,7 @@ and vertical offset and sizes are chosen according to following priority:
   </listitem>
 </orderedlist>
 
-On success the field <structfield> &v4l2-selection;::r </structfield> contains
+On success the &v4l2-rect; <structfield>r</structfield> field contains
 the adjusted rectangle. When the parameters are unsuitable the application may
 modify the cropping (composing) or image parameters and repeat the cycle until
 satisfactory parameters have been negotiated. If constraints flags have to be
@@ -162,38 +162,38 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
        <tbody valign="top">
          <row>
             <entry><constant>V4L2_SEL_TGT_CROP_ACTIVE</constant></entry>
-            <entry>0</entry>
-            <entry>area that is currently cropped by hardware</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>1</entry>
-            <entry>suggested cropping rectangle that covers the "whole picture"</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>2</entry>
-            <entry>limits for the cropping rectangle</entry>
+            <entry>0x0002</entry>
+            <entry>Limits for the cropping rectangle.</entry>
          </row>
          <row>
             <entry><constant>V4L2_SEL_TGT_COMPOSE_ACTIVE</constant></entry>
-            <entry>256</entry>
-            <entry>area to which data are composed by hardware</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>257</entry>
-            <entry>suggested composing rectangle that covers the "whole picture"</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>258</entry>
-            <entry>limits for the composing rectangle</entry>
+            <entry>0x0102</entry>
+            <entry>Limits for the composing rectangle.</entry>
          </row>
          <row>
             <entry><constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant></entry>
-            <entry>259</entry>
-            <entry>the active area and all padding pixels that are inserted or modified by the hardware</entry>
+            <entry>0x0103</entry>
+            <entry>The active area and all padding pixels that are inserted or modified by hardware.</entry>
          </row>
        </tbody>
       </tgroup>
@@ -209,12 +209,14 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
          <row>
             <entry><constant>V4L2_SEL_FLAG_GE</constant></entry>
             <entry>0x00000001</entry>
-            <entry>indicate that adjusted rectangle must contain a rectangle from <structfield>&v4l2-selection;::r</structfield></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>indicate that adjusted rectangle must be inside a rectangle from <structfield>&v4l2-selection;::r</structfield></entry>
+            <entry>Indicates that the adjusted rectangle must be inside the original
+           &v4l2-rect; <structfield>r</structfield> rectangle.</entry>
          </row>
        </tbody>
       </tgroup>
@@ -245,27 +247,29 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
          <row>
            <entry>__u32</entry>
            <entry><structfield>type</structfield></entry>
-           <entry>Type of the buffer (from &v4l2-buf-type;)</entry>
+           <entry>Type of the buffer (from &v4l2-buf-type;).</entry>
          </row>
          <row>
            <entry>__u32</entry>
            <entry><structfield>target</structfield></entry>
-            <entry>used to select between <link linkend="v4l2-sel-target"> cropping and composing rectangles </link></entry>
+            <entry>Used to select between <link linkend="v4l2-sel-target"> cropping
+           and composing rectangles</link>.</entry>
          </row>
          <row>
            <entry>__u32</entry>
            <entry><structfield>flags</structfield></entry>
-            <entry>control over coordinates adjustments, refer to <link linkend="v4l2-sel-flags">selection flags</link></entry>
+            <entry>Flags controlling the selection rectangle adjustments, refer to
+           <link linkend="v4l2-sel-flags">selection flags</link>.</entry>
          </row>
          <row>
            <entry>&v4l2-rect;</entry>
            <entry><structfield>r</structfield></entry>
-           <entry>selection rectangle</entry>
+           <entry>The selection rectangle.</entry>
          </row>
          <row>
            <entry>__u32</entry>
            <entry><structfield>reserved[9]</structfield></entry>
-           <entry>Reserved fields for future use</entry>
+           <entry>Reserved fields for future use.</entry>
          </row>
        </tbody>
       </tgroup>
@@ -278,24 +282,24 @@ exist no rectangle </emphasis> that satisfies the constraints.</para>
       <varlistentry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
-         <para>The buffer <structfield> &v4l2-selection;::type </structfield>
-or <structfield> &v4l2-selection;::target </structfield> is not supported, or
-the <structfield> &v4l2-selection;::flags </structfield> are invalid.</para>
+         <para>Given buffer type <structfield>type</structfield> or
+the selection target <structfield>target</structfield> is not supported,
+or the <structfield>flags</structfield> argument is not valid.</para>
        </listitem>
       </varlistentry>
       <varlistentry>
        <term><errorcode>ERANGE</errorcode></term>
        <listitem>
-         <para>it is not possible to adjust a rectangle <structfield>
-&v4l2-selection;::r </structfield> that satisfies all contraints from
-<structfield> &v4l2-selection;::flags </structfield>.</para>
+         <para>It is not possible to adjust &v4l2-rect; <structfield>
+r</structfield> rectangle to satisfy all contraints given in the
+<structfield>flags</structfield> argument.</para>
        </listitem>
       </varlistentry>
       <varlistentry>
        <term><errorcode>EBUSY</errorcode></term>
        <listitem>
-         <para>it is not possible to apply change of selection rectangle at the moment.
-Usually because streaming is in progress.</para>
+         <para>It is not possible to apply change of the selection rectangle
+at the moment. Usually because streaming is in progress.</para>
        </listitem>
       </varlistentry>
     </variablelist>
index e3664d6..4643505 100644 (file)
@@ -124,12 +124,35 @@ printf ("Version: %u.%u.%u\n",
          <row>
            <entry>__u32</entry>
            <entry><structfield>capabilities</structfield></entry>
-           <entry>Device capabilities, see <xref
-               linkend="device-capabilities" />.</entry>
+           <entry>Available capabilities of the physical device as a whole, see <xref
+               linkend="device-capabilities" />. The same physical device can export
+               multiple devices in /dev (e.g. /dev/videoX, /dev/vbiY and /dev/radioZ).
+               The <structfield>capabilities</structfield> field should contain a union
+               of all capabilities available around the several V4L2 devices exported
+               to userspace.
+               For all those devices the <structfield>capabilities</structfield> field
+               returns the same set of capabilities. This allows applications to open
+               just one of the devices (typically the video device) and discover whether
+               video, vbi and/or radio are also supported.
+           </entry>
          </row>
          <row>
            <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
+           <entry><structfield>device_caps</structfield></entry>
+           <entry>Device capabilities of the opened device, see <xref
+               linkend="device-capabilities" />. Should contain the available capabilities
+               of that specific device node. So, for example, <structfield>device_caps</structfield>
+               of a radio device will only contain radio related capabilities and
+               no video or vbi capabilities. This field is only set if the <structfield>capabilities</structfield>
+               field contains the <constant>V4L2_CAP_DEVICE_CAPS</constant> capability.
+               Only the <structfield>capabilities</structfield> field can have the
+               <constant>V4L2_CAP_DEVICE_CAPS</constant> capability, <structfield>device_caps</structfield>
+               will never set <constant>V4L2_CAP_DEVICE_CAPS</constant>.
+           </entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[3]</entry>
            <entry>Reserved for future extensions. Drivers must set
 this array to zero.</entry>
          </row>
@@ -276,6 +299,13 @@ linkend="async">asynchronous</link> I/O methods.</entry>
            <entry>The device supports the <link
 linkend="mmap">streaming</link> I/O method.</entry>
          </row>
+         <row>
+           <entry><constant>V4L2_CAP_DEVICE_CAPS</constant></entry>
+           <entry>0x80000000</entry>
+           <entry>The driver fills the <structfield>device_caps</structfield>
+           field. This capability can only appear in the <structfield>capabilities</structfield>
+           field and never in the <structfield>device_caps</structfield> field.</entry>
+         </row>
        </tbody>
       </tgroup>
     </table>
index e013da8..18b1a82 100644 (file)
@@ -96,8 +96,8 @@ field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
          <row>
            <entry>__u32</entry>
            <entry><structfield>reserved</structfield>[7]</entry>
-           <entry>Reserved for future extensions. Drivers and
-           applications must set the array to zero.</entry>
+           <entry>Reserved for future extensions. Applications
+           must set the array to zero.</entry>
          </row>
        </tbody>
       </tgroup>
@@ -112,7 +112,7 @@ field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
        <term><errorcode>EINVAL</errorcode></term>
        <listitem>
          <para>The <structfield>tuner</structfield> index is out of
-bounds or the value in the <structfield>type</structfield> field is
+bounds, the wrap_around value is not supported or the value in the <structfield>type</structfield> field is
 wrong.</para>
        </listitem>
       </varlistentry>
diff --git a/Documentation/backlight/lp855x-driver.txt b/Documentation/backlight/lp855x-driver.txt
new file mode 100644 (file)
index 0000000..f5e4caa
--- /dev/null
@@ -0,0 +1,78 @@
+Kernel driver lp855x
+====================
+
+Backlight driver for LP855x ICs
+
+Supported chips:
+       Texas Instruments LP8550, LP8551, LP8552, LP8553 and LP8556
+
+Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+
+Description
+-----------
+
+* Brightness control
+
+Brightness can be controlled by the pwm input or the i2c command.
+The lp855x driver supports both cases.
+
+* Device attributes
+
+1) bl_ctl_mode
+Backlight control mode.
+Value : pwm based or register based
+
+2) chip_id
+The lp855x chip id.
+Value : lp8550/lp8551/lp8552/lp8553/lp8556
+
+Platform data for lp855x
+------------------------
+
+For supporting platform specific data, the lp855x platform data can be used.
+
+* name : Backlight driver name. If it is not defined, default name is set.
+* mode : Brightness control mode. PWM or register based.
+* device_control : Value of DEVICE CONTROL register.
+* initial_brightness : Initial value of backlight brightness.
+* pwm_data : Platform specific pwm generation functions.
+            Only valid when brightness is pwm input mode.
+            Functions should be implemented by PWM driver.
+            - pwm_set_intensity() : set duty of PWM
+            - pwm_get_intensity() : get current duty of PWM
+* load_new_rom_data :
+       0 : use default configuration data
+       1 : update values of eeprom or eprom registers on loading driver
+* size_program : Total size of lp855x_rom_data.
+* rom_data : List of new eeprom/eprom registers.
+
+example 1) lp8552 platform data : i2c register mode with new eeprom data
+
+#define EEPROM_A5_ADDR 0xA5
+#define EEPROM_A5_VAL  0x4f    /* EN_VSYNC=0 */
+
+static struct lp855x_rom_data lp8552_eeprom_arr[] = {
+       {EEPROM_A5_ADDR, EEPROM_A5_VAL},
+};
+
+static struct lp855x_platform_data lp8552_pdata = {
+       .name = "lcd-bl",
+       .mode = REGISTER_BASED,
+       .device_control = I2C_CONFIG(LP8552),
+       .initial_brightness = INITIAL_BRT,
+       .load_new_rom_data = 1,
+       .size_program = ARRAY_SIZE(lp8552_eeprom_arr),
+       .rom_data = lp8552_eeprom_arr,
+};
+
+example 2) lp8556 platform data : pwm input mode with default rom data
+
+static struct lp855x_platform_data lp8556_pdata = {
+       .mode = PWM_BASED,
+       .device_control = PWM_CONFIG(LP8556),
+       .initial_brightness = INITIAL_BRT,
+       .pwm_data = {
+                    .pwm_set_intensity = platform_pwm_set_intensity,
+                    .pwm_get_intensity = platform_pwm_get_intensity,
+                    },
+};
diff --git a/Documentation/clk.txt b/Documentation/clk.txt
new file mode 100644 (file)
index 0000000..1943fae
--- /dev/null
@@ -0,0 +1,233 @@
+               The Common Clk Framework
+               Mike Turquette <mturquette@ti.com>
+
+This document endeavours to explain the common clk framework details,
+and how to port a platform over to this framework.  It is not yet a
+detailed explanation of the clock api in include/linux/clk.h, but
+perhaps someday it will include that information.
+
+       Part 1 - introduction and interface split
+
+The common clk framework is an interface to control the clock nodes
+available on various devices today.  This may come in the form of clock
+gating, rate adjustment, muxing or other operations.  This framework is
+enabled with the CONFIG_COMMON_CLK option.
+
+The interface itself is divided into two halves, each shielded from the
+details of its counterpart.  First is the common definition of struct
+clk which unifies the framework-level accounting and infrastructure that
+has traditionally been duplicated across a variety of platforms.  Second
+is a common implementation of the clk.h api, defined in
+drivers/clk/clk.c.  Finally there is struct clk_ops, whose operations
+are invoked by the clk api implementation.
+
+The second half of the interface is comprised of the hardware-specific
+callbacks registered with struct clk_ops and the corresponding
+hardware-specific structures needed to model a particular clock.  For
+the remainder of this document any reference to a callback in struct
+clk_ops, such as .enable or .set_rate, implies the hardware-specific
+implementation of that code.  Likewise, references to struct clk_foo
+serve as a convenient shorthand for the implementation of the
+hardware-specific bits for the hypothetical "foo" hardware.
+
+Tying the two halves of this interface together is struct clk_hw, which
+is defined in struct clk_foo and pointed to within struct clk.  This
+allows easy for navigation between the two discrete halves of the common
+clock interface.
+
+       Part 2 - common data structures and api
+
+Below is the common struct clk definition from
+include/linux/clk-private.h, modified for brevity:
+
+       struct clk {
+               const char              *name;
+               const struct clk_ops    *ops;
+               struct clk_hw           *hw;
+               char                    **parent_names;
+               struct clk              **parents;
+               struct clk              *parent;
+               struct hlist_head       children;
+               struct hlist_node       child_node;
+               ...
+       };
+
+The members above make up the core of the clk tree topology.  The clk
+api itself defines several driver-facing functions which operate on
+struct clk.  That api is documented in include/linux/clk.h.
+
+Platforms and devices utilizing the common struct clk use the struct
+clk_ops pointer in struct clk to perform the hardware-specific parts of
+the operations defined in clk.h:
+
+       struct clk_ops {
+               int             (*prepare)(struct clk_hw *hw);
+               void            (*unprepare)(struct clk_hw *hw);
+               int             (*enable)(struct clk_hw *hw);
+               void            (*disable)(struct clk_hw *hw);
+               int             (*is_enabled)(struct clk_hw *hw);
+               unsigned long   (*recalc_rate)(struct clk_hw *hw,
+                                               unsigned long parent_rate);
+               long            (*round_rate)(struct clk_hw *hw, unsigned long,
+                                               unsigned long *);
+               int             (*set_parent)(struct clk_hw *hw, u8 index);
+               u8              (*get_parent)(struct clk_hw *hw);
+               int             (*set_rate)(struct clk_hw *hw, unsigned long);
+               void            (*init)(struct clk_hw *hw);
+       };
+
+       Part 3 - hardware clk implementations
+
+The strength of the common struct clk comes from its .ops and .hw pointers
+which abstract the details of struct clk from the hardware-specific bits, and
+vice versa.  To illustrate consider the simple gateable clk implementation in
+drivers/clk/clk-gate.c:
+
+struct clk_gate {
+       struct clk_hw   hw;
+       void __iomem    *reg;
+       u8              bit_idx;
+       ...
+};
+
+struct clk_gate contains struct clk_hw hw as well as hardware-specific
+knowledge about which register and bit controls this clk's gating.
+Nothing about clock topology or accounting, such as enable_count or
+notifier_count, is needed here.  That is all handled by the common
+framework code and struct clk.
+
+Let's walk through enabling this clk from driver code:
+
+       struct clk *clk;
+       clk = clk_get(NULL, "my_gateable_clk");
+
+       clk_prepare(clk);
+       clk_enable(clk);
+
+The call graph for clk_enable is very simple:
+
+clk_enable(clk);
+       clk->ops->enable(clk->hw);
+       [resolves to...]
+               clk_gate_enable(hw);
+               [resolves struct clk gate with to_clk_gate(hw)]
+                       clk_gate_set_bit(gate);
+
+And the definition of clk_gate_set_bit:
+
+static void clk_gate_set_bit(struct clk_gate *gate)
+{
+       u32 reg;
+
+       reg = __raw_readl(gate->reg);
+       reg |= BIT(gate->bit_idx);
+       writel(reg, gate->reg);
+}
+
+Note that to_clk_gate is defined as:
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, clk)
+
+This pattern of abstraction is used for every clock hardware
+representation.
+
+       Part 4 - supporting your own clk hardware
+
+When implementing support for a new type of clock it only necessary to
+include the following header:
+
+#include <linux/clk-provider.h>
+
+include/linux/clk.h is included within that header and clk-private.h
+must never be included from the code which implements the operations for
+a clock.  More on that below in Part 5.
+
+To construct a clk hardware structure for your platform you must define
+the following:
+
+struct clk_foo {
+       struct clk_hw hw;
+       ... hardware specific data goes here ...
+};
+
+To take advantage of your data you'll need to support valid operations
+for your clk:
+
+struct clk_ops clk_foo_ops {
+       .enable         = &clk_foo_enable;
+       .disable        = &clk_foo_disable;
+};
+
+Implement the above functions using container_of:
+
+#define to_clk_foo(_hw) container_of(_hw, struct clk_foo, hw)
+
+int clk_foo_enable(struct clk_hw *hw)
+{
+       struct clk_foo *foo;
+
+       foo = to_clk_foo(hw);
+
+       ... perform magic on foo ...
+
+       return 0;
+};
+
+Below is a matrix detailing which clk_ops are mandatory based upon the
+hardware capbilities of that clock.  A cell marked as "y" means
+mandatory, a cell marked as "n" implies that either including that
+callback is invalid or otherwise uneccesary.  Empty cells are either
+optional or must be evaluated on a case-by-case basis.
+
+                           clock hardware characteristics
+            -----------------------------------------------------------
+             | gate | change rate | single parent | multiplexer | root |
+             |------|-------------|---------------|-------------|------|
+.prepare     |      |             |               |             |      |
+.unprepare   |      |             |               |             |      |
+             |      |             |               |             |      |
+.enable      | y    |             |               |             |      |
+.disable     | y    |             |               |             |      |
+.is_enabled  | y    |             |               |             |      |
+             |      |             |               |             |      |
+.recalc_rate |      | y           |               |             |      |
+.round_rate  |      | y           |               |             |      |
+.set_rate    |      | y           |               |             |      |
+             |      |             |               |             |      |
+.set_parent  |      |             | n             | y           | n    |
+.get_parent  |      |             | n             | y           | n    |
+             |      |             |               |             |      |
+.init        |      |             |               |             |      |
+            -----------------------------------------------------------
+
+Finally, register your clock at run-time with a hardware-specific
+registration function.  This function simply populates struct clk_foo's
+data and then passes the common struct clk parameters to the framework
+with a call to:
+
+clk_register(...)
+
+See the basic clock types in drivers/clk/clk-*.c for examples.
+
+       Part 5 - static initialization of clock data
+
+For platforms with many clocks (often numbering into the hundreds) it
+may be desirable to statically initialize some clock data.  This
+presents a problem since the definition of struct clk should be hidden
+from everyone except for the clock core in drivers/clk/clk.c.
+
+To get around this problem struct clk's definition is exposed in
+include/linux/clk-private.h along with some macros for more easily
+initializing instances of the basic clock types.  These clocks must
+still be initialized with the common clock framework via a call to
+__clk_init.
+
+clk-private.h must NEVER be included by code which implements struct
+clk_ops callbacks, nor must it be included by any logic which pokes
+around inside of struct clk at run-time.  To do so is a layering
+violation.
+
+To better enforce this policy, always follow this simple rule: any
+statically initialized clock data MUST be defined in a separate file
+from the logic that implements its ops.  Basically separate the logic
+from the data and all is well.
diff --git a/Documentation/crc32.txt b/Documentation/crc32.txt
new file mode 100644 (file)
index 0000000..a08a7dd
--- /dev/null
@@ -0,0 +1,182 @@
+A brief CRC tutorial.
+
+A CRC is a long-division remainder.  You add the CRC to the message,
+and the whole thing (message+CRC) is a multiple of the given
+CRC polynomial.  To check the CRC, you can either check that the
+CRC matches the recomputed value, *or* you can check that the
+remainder computed on the message+CRC is 0.  This latter approach
+is used by a lot of hardware implementations, and is why so many
+protocols put the end-of-frame flag after the CRC.
+
+It's actually the same long division you learned in school, except that
+- We're working in binary, so the digits are only 0 and 1, and
+- When dividing polynomials, there are no carries.  Rather than add and
+  subtract, we just xor.  Thus, we tend to get a bit sloppy about
+  the difference between adding and subtracting.
+
+Like all division, the remainder is always smaller than the divisor.
+To produce a 32-bit CRC, the divisor is actually a 33-bit CRC polynomial.
+Since it's 33 bits long, bit 32 is always going to be set, so usually the
+CRC is written in hex with the most significant bit omitted.  (If you're
+familiar with the IEEE 754 floating-point format, it's the same idea.)
+
+Note that a CRC is computed over a string of *bits*, so you have
+to decide on the endianness of the bits within each byte.  To get
+the best error-detecting properties, this should correspond to the
+order they're actually sent.  For example, standard RS-232 serial is
+little-endian; the most significant bit (sometimes used for parity)
+is sent last.  And when appending a CRC word to a message, you should
+do it in the right order, matching the endianness.
+
+Just like with ordinary division, you proceed one digit (bit) at a time.
+Each step of the division you take one more digit (bit) of the dividend
+and append it to the current remainder.  Then you figure out the
+appropriate multiple of the divisor to subtract to being the remainder
+back into range.  In binary, this is easy - it has to be either 0 or 1,
+and to make the XOR cancel, it's just a copy of bit 32 of the remainder.
+
+When computing a CRC, we don't care about the quotient, so we can
+throw the quotient bit away, but subtract the appropriate multiple of
+the polynomial from the remainder and we're back to where we started,
+ready to process the next bit.
+
+A big-endian CRC written this way would be coded like:
+for (i = 0; i < input_bits; i++) {
+       multiple = remainder & 0x80000000 ? CRCPOLY : 0;
+       remainder = (remainder << 1 | next_input_bit()) ^ multiple;
+}
+
+Notice how, to get at bit 32 of the shifted remainder, we look
+at bit 31 of the remainder *before* shifting it.
+
+But also notice how the next_input_bit() bits we're shifting into
+the remainder don't actually affect any decision-making until
+32 bits later.  Thus, the first 32 cycles of this are pretty boring.
+Also, to add the CRC to a message, we need a 32-bit-long hole for it at
+the end, so we have to add 32 extra cycles shifting in zeros at the
+end of every message,
+
+These details lead to a standard trick: rearrange merging in the
+next_input_bit() until the moment it's needed.  Then the first 32 cycles
+can be precomputed, and merging in the final 32 zero bits to make room
+for the CRC can be skipped entirely.  This changes the code to:
+
+for (i = 0; i < input_bits; i++) {
+       remainder ^= next_input_bit() << 31;
+       multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+       remainder = (remainder << 1) ^ multiple;
+}
+
+With this optimization, the little-endian code is particularly simple:
+for (i = 0; i < input_bits; i++) {
+       remainder ^= next_input_bit();
+       multiple = (remainder & 1) ? CRCPOLY : 0;
+       remainder = (remainder >> 1) ^ multiple;
+}
+
+The most significant coefficient of the remainder polynomial is stored
+in the least significant bit of the binary "remainder" variable.
+The other details of endianness have been hidden in CRCPOLY (which must
+be bit-reversed) and next_input_bit().
+
+As long as next_input_bit is returning the bits in a sensible order, we don't
+*have* to wait until the last possible moment to merge in additional bits.
+We can do it 8 bits at a time rather than 1 bit at a time:
+for (i = 0; i < input_bytes; i++) {
+       remainder ^= next_input_byte() << 24;
+       for (j = 0; j < 8; j++) {
+               multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
+               remainder = (remainder << 1) ^ multiple;
+       }
+}
+
+Or in little-endian:
+for (i = 0; i < input_bytes; i++) {
+       remainder ^= next_input_byte();
+       for (j = 0; j < 8; j++) {
+               multiple = (remainder & 1) ? CRCPOLY : 0;
+               remainder = (remainder >> 1) ^ multiple;
+       }
+}
+
+If the input is a multiple of 32 bits, you can even XOR in a 32-bit
+word at a time and increase the inner loop count to 32.
+
+You can also mix and match the two loop styles, for example doing the
+bulk of a message byte-at-a-time and adding bit-at-a-time processing
+for any fractional bytes at the end.
+
+To reduce the number of conditional branches, software commonly uses
+the byte-at-a-time table method, popularized by Dilip V. Sarwate,
+"Computation of Cyclic Redundancy Checks via Table Look-Up", Comm. ACM
+v.31 no.8 (August 1998) p. 1008-1013.
+
+Here, rather than just shifting one bit of the remainder to decide
+in the correct multiple to subtract, we can shift a byte at a time.
+This produces a 40-bit (rather than a 33-bit) intermediate remainder,
+and the correct multiple of the polynomial to subtract is found using
+a 256-entry lookup table indexed by the high 8 bits.
+
+(The table entries are simply the CRC-32 of the given one-byte messages.)
+
+When space is more constrained, smaller tables can be used, e.g. two
+4-bit shifts followed by a lookup in a 16-entry table.
+
+It is not practical to process much more than 8 bits at a time using this
+technique, because tables larger than 256 entries use too much memory and,
+more importantly, too much of the L1 cache.
+
+To get higher software performance, a "slicing" technique can be used.
+See "High Octane CRC Generation with the Intel Slicing-by-8 Algorithm",
+ftp://download.intel.com/technology/comms/perfnet/download/slicing-by-8.pdf
+
+This does not change the number of table lookups, but does increase
+the parallelism.  With the classic Sarwate algorithm, each table lookup
+must be completed before the index of the next can be computed.
+
+A "slicing by 2" technique would shift the remainder 16 bits at a time,
+producing a 48-bit intermediate remainder.  Rather than doing a single
+lookup in a 65536-entry table, the two high bytes are looked up in
+two different 256-entry tables.  Each contains the remainder required
+to cancel out the corresponding byte.  The tables are different because the
+polynomials to cancel are different.  One has non-zero coefficients from
+x^32 to x^39, while the other goes from x^40 to x^47.
+
+Since modern processors can handle many parallel memory operations, this
+takes barely longer than a single table look-up and thus performs almost
+twice as fast as the basic Sarwate algorithm.
+
+This can be extended to "slicing by 4" using 4 256-entry tables.
+Each step, 32 bits of data is fetched, XORed with the CRC, and the result
+broken into bytes and looked up in the tables.  Because the 32-bit shift
+leaves the low-order bits of the intermediate remainder zero, the
+final CRC is simply the XOR of the 4 table look-ups.
+
+But this still enforces sequential execution: a second group of table
+look-ups cannot begin until the previous groups 4 table look-ups have all
+been completed.  Thus, the processor's load/store unit is sometimes idle.
+
+To make maximum use of the processor, "slicing by 8" performs 8 look-ups
+in parallel.  Each step, the 32-bit CRC is shifted 64 bits and XORed
+with 64 bits of input data.  What is important to note is that 4 of
+those 8 bytes are simply copies of the input data; they do not depend
+on the previous CRC at all.  Thus, those 4 table look-ups may commence
+immediately, without waiting for the previous loop iteration.
+
+By always having 4 loads in flight, a modern superscalar processor can
+be kept busy and make full use of its L1 cache.
+
+Two more details about CRC implementation in the real world:
+
+Normally, appending zero bits to a message which is already a multiple
+of a polynomial produces a larger multiple of that polynomial.  Thus,
+a basic CRC will not detect appended zero bits (or bytes).  To enable
+a CRC to detect this condition, it's common to invert the CRC before
+appending it.  This makes the remainder of the message+crc come out not
+as zero, but some fixed non-zero value.  (The CRC of the inversion
+pattern, 0xffffffff.)
+
+The same problem applies to zero bits prepended to the message, and a
+similar solution is used.  Instead of starting the CRC computation with
+a remainder of 0, an initial remainder of all ones is used.  As long as
+you start the same way on decoding, it doesn't make a difference.
index 1ff044d..3370bc4 100644 (file)
@@ -75,10 +75,12 @@ less sharing than average you'll need a larger-than-average metadata device.
 
 As a guide, we suggest you calculate the number of bytes to use in the
 metadata device as 48 * $data_dev_size / $data_block_size but round it up
-to 2MB if the answer is smaller.  The largest size supported is 16GB.
+to 2MB if the answer is smaller.  If you're creating large numbers of
+snapshots which are recording large amounts of change, you may find you
+need to increase this.
 
-If you're creating large numbers of snapshots which are recording large
-amounts of change, you may need find you need to increase this.
+The largest size supported is 16GB: If the device is larger,
+a warning will be issued and the excess space will not be used.
 
 Reloading a pool table
 ----------------------
@@ -167,6 +169,38 @@ ii) Using an internal snapshot.
 
     dmsetup create snap --table "0 2097152 thin /dev/mapper/pool 1"
 
+External snapshots
+------------------
+
+You can use an external _read only_ device as an origin for a
+thinly-provisioned volume.  Any read to an unprovisioned area of the
+thin device will be passed through to the origin.  Writes trigger
+the allocation of new blocks as usual.
+
+One use case for this is VM hosts that want to run guests on
+thinly-provisioned volumes but have the base image on another device
+(possibly shared between many VMs).
+
+You must not write to the origin device if you use this technique!
+Of course, you may write to the thin device and take internal snapshots
+of the thin volume.
+
+i) Creating a snapshot of an external device
+
+  This is the same as creating a thin device.
+  You don't mention the origin at this stage.
+
+    dmsetup message /dev/mapper/pool 0 "create_thin 0"
+
+ii) Using a snapshot of an external device.
+
+  Append an extra parameter to the thin target specifying the origin:
+
+    dmsetup create snap --table "0 2097152 thin /dev/mapper/pool 0 /dev/image"
+
+  N.B. All descendants (internal snapshots) of this snapshot require the
+  same extra origin parameter.
+
 Deactivation
 ------------
 
@@ -189,7 +223,13 @@ i) Constructor
              <low water mark (blocks)> [<number of feature args> [<arg>]*]
 
     Optional feature arguments:
-    - 'skip_block_zeroing': skips the zeroing of newly-provisioned blocks.
+
+      skip_block_zeroing: Skip the zeroing of newly-provisioned blocks.
+
+      ignore_discard: Disable discard support.
+
+      no_discard_passdown: Don't pass discards down to the underlying
+                          data device, but just remove the mapping.
 
     Data block size must be between 64KB (128 sectors) and 1GB
     (2097152 sectors) inclusive.
@@ -237,16 +277,6 @@ iii) Messages
 
        Deletes a thin device.  Irreversible.
 
-    trim <dev id> <new size in sectors>
-
-       Delete mappings from the end of a thin device.  Irreversible.
-       You might want to use this if you're reducing the size of
-       your thinly-provisioned device.  In many cases, due to the
-       sharing of blocks between devices, it is not possible to
-       determine in advance how much space 'trim' will release.  (In
-       future a userspace tool might be able to perform this
-       calculation.)
-
     set_transaction_id <current id> <new id>
 
        Userland volume managers, such as LVM, need a way to
@@ -262,7 +292,7 @@ iii) Messages
 
 i) Constructor
 
-    thin <pool dev> <dev id>
+    thin <pool dev> <dev id> [<external origin dev>]
 
     pool dev:
        the thin-pool device, e.g. /dev/mapper/my_pool or 253:0
@@ -271,6 +301,11 @@ i) Constructor
        the internal device identifier of the device to be
        activated.
 
+    external origin dev:
+       an optional block device outside the pool to be treated as a
+       read-only snapshot origin: reads to unprovisioned areas of the
+       thin target will be mapped to this device.
+
 The pool doesn't store any size against the thin devices.  If you
 load a thin target that is smaller than you've been using previously,
 then you'll have no access to blocks mapped beyond the end.  If you
diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt
new file mode 100644 (file)
index 0000000..32e4879
--- /dev/null
@@ -0,0 +1,194 @@
+dm-verity
+==========
+
+Device-Mapper's "verity" target provides transparent integrity checking of
+block devices using a cryptographic digest provided by the kernel crypto API.
+This target is read-only.
+
+Construction Parameters
+=======================
+    <version> <dev> <hash_dev> <hash_start>
+    <data_block_size> <hash_block_size>
+    <num_data_blocks> <hash_start_block>
+    <algorithm> <digest> <salt>
+
+<version>
+    This is the version number of the on-disk format.
+
+    0 is the original format used in the Chromium OS.
+       The salt is appended when hashing, digests are stored continuously and
+       the rest of the block is padded with zeros.
+
+    1 is the current format that should be used for new devices.
+       The salt is prepended when hashing and each digest is
+       padded with zeros to the power of two.
+
+<dev>
+    This is the device containing the data the integrity of which needs to be
+    checked.  It may be specified as a path, like /dev/sdaX, or a device number,
+    <major>:<minor>.
+
+<hash_dev>
+    This is the device that that supplies the hash tree data.  It may be
+    specified similarly to the device path and may be the same device.  If the
+    same device is used, the hash_start should be outside of the dm-verity
+    configured device size.
+
+<data_block_size>
+    The block size on a data device.  Each block corresponds to one digest on
+    the hash device.
+
+<hash_block_size>
+    The size of a hash block.
+
+<num_data_blocks>
+    The number of data blocks on the data device.  Additional blocks are
+    inaccessible.  You can place hashes to the same partition as data, in this
+    case hashes are placed after <num_data_blocks>.
+
+<hash_start_block>
+    This is the offset, in <hash_block_size>-blocks, from the start of hash_dev
+    to the root block of the hash tree.
+
+<algorithm>
+    The cryptographic hash algorithm used for this device.  This should
+    be the name of the algorithm, like "sha1".
+
+<digest>
+    The hexadecimal encoding of the cryptographic hash of the root hash block
+    and the salt.  This hash should be trusted as there is no other authenticity
+    beyond this point.
+
+<salt>
+    The hexadecimal encoding of the salt value.
+
+Theory of operation
+===================
+
+dm-verity is meant to be setup as part of a verified boot path.  This
+may be anything ranging from a boot using tboot or trustedgrub to just
+booting from a known-good device (like a USB drive or CD).
+
+When a dm-verity device is configured, it is expected that the caller
+has been authenticated in some way (cryptographic signatures, etc).
+After instantiation, all hashes will be verified on-demand during
+disk access.  If they cannot be verified up to the root node of the
+tree, the root hash, then the I/O will fail.  This should identify
+tampering with any data on the device and the hash data.
+
+Cryptographic hashes are used to assert the integrity of the device on a
+per-block basis.  This allows for a lightweight hash computation on first read
+into the page cache.  Block hashes are stored linearly-aligned to the nearest
+block the size of a page.
+
+Hash Tree
+---------
+
+Each node in the tree is a cryptographic hash.  If it is a leaf node, the hash
+is of some block data on disk.  If it is an intermediary node, then the hash is
+of a number of child nodes.
+
+Each entry in the tree is a collection of neighboring nodes that fit in one
+block.  The number is determined based on block_size and the size of the
+selected cryptographic digest algorithm.  The hashes are linearly-ordered in
+this entry and any unaligned trailing space is ignored but included when
+calculating the parent node.
+
+The tree looks something like:
+
+alg = sha256, num_blocks = 32768, block_size = 4096
+
+                                 [   root    ]
+                                /    . . .    \
+                     [entry_0]                 [entry_1]
+                    /  . . .  \                 . . .   \
+         [entry_0_0]   . . .  [entry_0_127]    . . . .  [entry_1_127]
+           / ... \             /   . . .  \             /           \
+     blk_0 ... blk_127  blk_16256   blk_16383      blk_32640 . . . blk_32767
+
+
+On-disk format
+==============
+
+Below is the recommended on-disk format. The verity kernel code does not
+read the on-disk header. It only reads the hash blocks which directly
+follow the header. It is expected that a user-space tool will verify the
+integrity of the verity_header and then call dmsetup with the correct
+parameters. Alternatively, the header can be omitted and the dmsetup
+parameters can be passed via the kernel command-line in a rooted chain
+of trust where the command-line is verified.
+
+The on-disk format is especially useful in cases where the hash blocks
+are on a separate partition. The magic number allows easy identification
+of the partition contents. Alternatively, the hash blocks can be stored
+in the same partition as the data to be verified. In such a configuration
+the filesystem on the partition would be sized a little smaller than
+the full-partition, leaving room for the hash blocks.
+
+struct superblock {
+       uint8_t signature[8]
+               "verity\0\0";
+
+       uint8_t version;
+               1 - current format
+
+       uint8_t data_block_bits;
+               log2(data block size)
+
+       uint8_t hash_block_bits;
+               log2(hash block size)
+
+       uint8_t pad1[1];
+               zero padding
+
+       uint16_t salt_size;
+               big-endian salt size
+
+       uint8_t pad2[2];
+               zero padding
+
+       uint32_t data_blocks_hi;
+               big-endian high 32 bits of the 64-bit number of data blocks
+
+       uint32_t data_blocks_lo;
+               big-endian low 32 bits of the 64-bit number of data blocks
+
+       uint8_t algorithm[16];
+               cryptographic algorithm
+
+       uint8_t salt[384];
+               salt (the salt size is specified above)
+
+       uint8_t pad3[88];
+               zero padding to 512-byte boundary
+}
+
+Directly following the header (and with sector number padded to the next hash
+block boundary) are the hash blocks which are stored a depth at a time
+(starting from the root), sorted in order of increasing index.
+
+Status
+======
+V (for Valid) is returned if every check performed so far was valid.
+If any check failed, C (for Corruption) is returned.
+
+Example
+=======
+
+Setup a device:
+  dmsetup create vroot --table \
+    "0 2097152 "\
+    "verity 1 /dev/sda1 /dev/sda2 4096 4096 2097152 1 "\
+    "4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 "\
+    "1234000000000000000000000000000000000000000000000000000000000000"
+
+A command line tool veritysetup is available to compute or verify
+the hash tree or activate the kernel driver.  This is available from
+the LVM2 upstream repository and may be supplied as a package called
+device-mapper-verity-tools:
+    git://sources.redhat.com/git/lvm2
+    http://sourceware.org/git/?p=lvm2.git
+    http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/verity?cvsroot=lvm2
+
+veritysetup -a vroot /dev/sda1 /dev/sda2 \
+       4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt
new file mode 100644 (file)
index 0000000..aabca4f
--- /dev/null
@@ -0,0 +1,38 @@
+* Advanced Interrupt Controller (AIC)
+
+Required properties:
+- compatible: Should be "atmel,<chip>-aic"
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupt-parent: For single AIC system, it is an empty property.
+- #interrupt-cells: The number of cells to define the interrupts. It sould be 2.
+  The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet).
+  The second cell is used to specify flags:
+    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.
+      Valid combinations are 1, 2, 3, 4, 8.
+      Default flag for internal sources should be set to 4 (active high).
+- reg: Should contain AIC registers location and length
+
+Examples:
+       /*
+        * AIC
+        */
+       aic: interrupt-controller@fffff000 {
+               compatible = "atmel,at91rm9200-aic";
+               interrupt-controller;
+               interrupt-parent;
+               #interrupt-cells = <2>;
+               reg = <0xfffff000 0x200>;
+       };
+
+       /*
+        * An interrupt generating device that is wired to an AIC.
+        */
+       dma: dma-controller@ffffec00 {
+               compatible = "atmel,at91sam9g45-dma";
+               reg = <0xffffec00 0x200>;
+               interrupts = <21 4>;
+       };
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
new file mode 100644 (file)
index 0000000..ecc81e3
--- /dev/null
@@ -0,0 +1,92 @@
+Atmel AT91 device tree bindings.
+================================
+
+PIT Timer required properties:
+- compatible: Should be "atmel,at91sam9260-pit"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt for the PIT which is the IRQ line
+  shared across all System Controller members.
+
+TC/TCLIB Timer required properties:
+- compatible: Should be "atmel,<chip>-pit".
+  <chip> can be "at91rm9200" or "at91sam9x5"
+- reg: Should contain registers location and length
+- interrupts: Should contain all interrupts for the TC block
+  Note that you can specify several interrupt cells if the TC
+  block has one interrupt per channel.
+
+Examples:
+
+One interrupt per TC block:
+       tcb0: timer@fff7c000 {
+               compatible = "atmel,at91rm9200-tcb";
+               reg = <0xfff7c000 0x100>;
+               interrupts = <18 4>;
+       };
+
+One interrupt per TC channel in a TC block:
+       tcb1: timer@fffdc000 {
+               compatible = "atmel,at91rm9200-tcb";
+               reg = <0xfffdc000 0x100>;
+               interrupts = <26 4 27 4 28 4>;
+       };
+
+RSTC Reset Controller required properties:
+- compatible: Should be "atmel,<chip>-rstc".
+  <chip> can be "at91sam9260" or "at91sam9g45"
+- reg: Should contain registers location and length
+
+Example:
+
+       rstc@fffffd00 {
+               compatible = "atmel,at91sam9260-rstc";
+               reg = <0xfffffd00 0x10>;
+       };
+
+RAMC SDRAM/DDR Controller required properties:
+- compatible: Should be "atmel,at91sam9260-sdramc",
+                       "atmel,at91sam9g45-ddramc",
+- reg: Should contain registers location and length
+  For at91sam9263 and at91sam9g45 you must specify 2 entries.
+
+Examples:
+
+       ramc0: ramc@ffffe800 {
+               compatible = "atmel,at91sam9g45-ddramc";
+               reg = <0xffffe800 0x200>;
+       };
+
+       ramc0: ramc@ffffe400 {
+               compatible = "atmel,at91sam9g45-ddramc";
+               reg = <0xffffe400 0x200
+                      0xffffe600 0x200>;
+       };
+
+SHDWC Shutdown Controller
+
+required properties:
+- compatible: Should be "atmel,<chip>-shdwc".
+  <chip> can be "at91sam9260", "at91sam9rl" or "at91sam9x5".
+- reg: Should contain registers location and length
+
+optional properties:
+- atmel,wakeup-mode: String, operation mode of the wakeup mode.
+  Supported values are: "none", "high", "low", "any".
+- atmel,wakeup-counter: Counter on Wake-up 0 (between 0x0 and 0xf).
+
+optional at91sam9260 properties:
+- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up.
+
+optional at91sam9rl properties:
+- atmel,wakeup-rtc-timer: boolean to enable Real-time Clock Wake-up.
+- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up.
+
+optional at91sam9x5 properties:
+- atmel,wakeup-rtc-timer: boolean to enable Real-time Clock Wake-up.
+
+Example:
+
+       rstc@fffffd00 {
+               compatible = "atmel,at91sam9260-rstc";
+               reg = <0xfffffd00 0x10>;
+       };
diff --git a/Documentation/devicetree/bindings/arm/atmel-pmc.txt b/Documentation/devicetree/bindings/arm/atmel-pmc.txt
new file mode 100644 (file)
index 0000000..389bed5
--- /dev/null
@@ -0,0 +1,11 @@
+* Power Management Controller (PMC)
+
+Required properties:
+- compatible: Should be "atmel,at91rm9200-pmc"
+- reg: Should contain PMC registers location and length
+
+Examples:
+       pmc: pmc@fffffc00 {
+               compatible = "atmel,at91rm9200-pmc";
+               reg = <0xfffffc00 0x100>;
+       };
index 54bddda..bfbc771 100644 (file)
@@ -28,3 +28,25 @@ Required root node properties:
 i.MX6 Quad SABRE Lite Board
 Required root node properties:
     - compatible = "fsl,imx6q-sabrelite", "fsl,imx6q";
+
+Generic i.MX boards
+-------------------
+
+No iomux setup is done for these boards, so this must have been configured
+by the bootloader for boards to work with the generic bindings.
+
+i.MX27 generic board
+Required root node properties:
+    - compatible = "fsl,imx27";
+
+i.MX51 generic board
+Required root node properties:
+    - compatible = "fsl,imx51";
+
+i.MX53 generic board
+Required root node properties:
+    - compatible = "fsl,imx53";
+
+i.MX6q generic board
+Required root node properties:
+    - compatible = "fsl,imx6q";
diff --git a/Documentation/devicetree/bindings/arm/mrvl.txt b/Documentation/devicetree/bindings/arm/mrvl.txt
new file mode 100644 (file)
index 0000000..d8de933
--- /dev/null
@@ -0,0 +1,6 @@
+Marvell Platforms Device Tree Bindings
+----------------------------------------------------
+
+PXA168 Aspenite Board
+Required root node properties:
+       - compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168";
diff --git a/Documentation/devicetree/bindings/arm/omap/intc.txt b/Documentation/devicetree/bindings/arm/omap/intc.txt
new file mode 100644 (file)
index 0000000..f2583e6
--- /dev/null
@@ -0,0 +1,27 @@
+* OMAP Interrupt Controller
+
+OMAP2/3 are using a TI interrupt controller that can support several
+configurable number of interrupts.
+
+Main node required properties:
+
+- compatible : should be:
+       "ti,omap2-intc"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The type shall be a <u32> and the value shall be 1.
+
+  The cell contains the interrupt number in the range [0-128].
+- ti,intc-size: Number of interrupts handled by the interrupt controller.
+- reg: physical base address and size of the intc registers map.
+
+Example:
+
+       intc: interrupt-controller@1 {
+               compatible = "ti,omap2-intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               ti,intc-size = <96>;
+               reg = <0x48200000 0x1000>;
+       };
+
diff --git a/Documentation/devicetree/bindings/arm/spear.txt b/Documentation/devicetree/bindings/arm/spear.txt
new file mode 100644 (file)
index 0000000..f8e54f0
--- /dev/null
@@ -0,0 +1,8 @@
+ST SPEAr Platforms Device Tree Bindings
+---------------------------------------
+
+Boards with the ST SPEAr600 SoC shall have the following properties:
+
+Required root node property:
+
+compatible = "st,spear600";
diff --git a/Documentation/devicetree/bindings/arm/tegra/emc.txt b/Documentation/devicetree/bindings/arm/tegra/emc.txt
new file mode 100644 (file)
index 0000000..09335f8
--- /dev/null
@@ -0,0 +1,100 @@
+Embedded Memory Controller
+
+Properties:
+- name : Should be emc
+- #address-cells : Should be 1
+- #size-cells : Should be 0
+- compatible : Should contain "nvidia,tegra20-emc".
+- reg : Offset and length of the register set for the device
+- nvidia,use-ram-code : If present, the sub-nodes will be addressed
+  and chosen using the ramcode board selector. If omitted, only one
+  set of tables can be present and said tables will be used
+  irrespective of ram-code configuration.
+
+Child device nodes describe the memory settings for different configurations and clock rates.
+
+Example:
+
+       emc@7000f400 {
+               #address-cells = < 1 >;
+               #size-cells = < 0 >;
+               compatible = "nvidia,tegra20-emc";
+               reg = <0x7000f4000 0x200>;
+       }
+
+
+Embedded Memory Controller ram-code table
+
+If the emc node has the nvidia,use-ram-code property present, then the
+next level of nodes below the emc table are used to specify which settings
+apply for which ram-code settings.
+
+If the emc node lacks the nvidia,use-ram-code property, this level is omitted
+and the tables are stored directly under the emc node (see below).
+
+Properties:
+
+- name : Should be emc-tables
+- nvidia,ram-code : the binary representation of the ram-code board strappings
+  for which this node (and children) are valid.
+
+
+
+Embedded Memory Controller configuration table
+
+This is a table containing the EMC register settings for the various
+operating speeds of the memory controller. They are always located as
+subnodes of the emc controller node.
+
+There are two ways of specifying which tables to use:
+
+* The simplest is if there is just one set of tables in the device tree,
+  and they will always be used (based on which frequency is used).
+  This is the preferred method, especially when firmware can fill in
+  this information based on the specific system information and just
+  pass it on to the kernel.
+
+* The slightly more complex one is when more than one memory configuration
+  might exist on the system.  The Tegra20 platform handles this during
+  early boot by selecting one out of possible 4 memory settings based
+  on a 2-pin "ram code" bootstrap setting on the board. The values of
+  these strappings can be read through a register in the SoC, and thus
+  used to select which tables to use.
+
+Properties:
+- name : Should be emc-table
+- compatible : Should contain "nvidia,tegra20-emc-table".
+- reg : either an opaque enumerator to tell different tables apart, or
+  the valid frequency for which the table should be used (in kHz).
+- clock-frequency : the clock frequency for the EMC at which this
+  table should be used (in kHz).
+- nvidia,emc-registers : a 46 word array of EMC registers to be programmed
+  for operation at the 'clock-frequency' setting.
+  The order and contents of the registers are:
+    RC, RFC, RAS, RP, R2W, W2R, R2P, W2P, RD_RCD, WR_RCD, RRD, REXT,
+    WDV, QUSE, QRST, QSAFE, RDV, REFRESH, BURST_REFRESH_NUM, PDEX2WR,
+    PDEX2RD, PCHG2PDEN, ACT2PDEN, AR2PDEN, RW2PDEN, TXSR, TCKE, TFAW,
+    TRPAB, TCLKSTABLE, TCLKSTOP, TREFBW, QUSE_EXTRA, FBIO_CFG6, ODT_WRITE,
+    ODT_READ, FBIO_CFG5, CFG_DIG_DLL, DLL_XFORM_DQS, DLL_XFORM_QUSE,
+    ZCAL_REF_CNT, ZCAL_WAIT_CNT, AUTO_CAL_INTERVAL, CFG_CLKTRIM_0,
+    CFG_CLKTRIM_1, CFG_CLKTRIM_2
+
+               emc-table@166000 {
+                       reg = <166000>;
+                       compatible = "nvidia,tegra20-emc-table";
+                       clock-frequency = < 166000 >;
+                       nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 >;
+               };
+
+               emc-table@333000 {
+                       reg = <333000>;
+                       compatible = "nvidia,tegra20-emc-table";
+                       clock-frequency = < 333000 >;
+                       nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 >;
+               };
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
new file mode 100644 (file)
index 0000000..b5846e2
--- /dev/null
@@ -0,0 +1,19 @@
+NVIDIA Tegra Power Management Controller (PMC)
+
+Properties:
+- name : Should be pmc
+- compatible : Should contain "nvidia,tegra<chip>-pmc".
+- reg : Offset and length of the register set for the device
+- nvidia,invert-interrupt : If present, inverts the PMU interrupt signal.
+  The PMU is an external Power Management Unit, whose interrupt output
+  signal is fed into the PMC. This signal is optionally inverted, and then
+  fed into the ARM GIC. The PMC is not involved in the detection or
+  handling of this interrupt signal, merely its inversion.
+
+Example:
+
+pmc@7000f400 {
+       compatible = "nvidia,tegra20-pmc";
+       reg = <0x7000e400 0x400>;
+       nvidia,invert-interrupt;
+};
diff --git a/Documentation/devicetree/bindings/arm/twd.txt b/Documentation/devicetree/bindings/arm/twd.txt
new file mode 100644 (file)
index 0000000..75b8610
--- /dev/null
@@ -0,0 +1,48 @@
+* ARM Timer Watchdog
+
+ARM 11MP, Cortex-A5 and Cortex-A9 are often associated with a per-core
+Timer-Watchdog (aka TWD), which provides both a per-cpu local timer
+and watchdog.
+
+The TWD is usually attached to a GIC to deliver its two per-processor
+interrupts.
+
+** Timer node required properties:
+
+- compatible : Should be one of:
+       "arm,cortex-a9-twd-timer"
+       "arm,cortex-a5-twd-timer"
+       "arm,arm11mp-twd-timer"
+
+- interrupts : One interrupt to each core
+
+- reg : Specify the base address and the size of the TWD timer
+       register window.
+
+Example:
+
+       twd-timer@2c000600 {
+               compatible = "arm,arm11mp-twd-timer"";
+               reg = <0x2c000600 0x20>;
+               interrupts = <1 13 0xf01>;
+       };
+
+** Watchdog node properties:
+
+- compatible : Should be one of:
+       "arm,cortex-a9-twd-wdt"
+       "arm,cortex-a5-twd-wdt"
+       "arm,arm11mp-twd-wdt"
+
+- interrupts : One interrupt to each core
+
+- reg : Specify the base address and the size of the TWD watchdog
+       register window.
+
+Example:
+
+       twd-watchdog@2c000620 {
+               compatible = "arm,arm11mp-twd-wdt";
+               reg = <0x2c000620 0x20>;
+               interrupts = <1 14 0xf01>;
+       };
diff --git a/Documentation/devicetree/bindings/arm/vexpress.txt b/Documentation/devicetree/bindings/arm/vexpress.txt
new file mode 100644 (file)
index 0000000..ec8b50c
--- /dev/null
@@ -0,0 +1,146 @@
+ARM Versatile Express boards family
+-----------------------------------
+
+ARM's Versatile Express platform consists of a motherboard and one
+or more daughterboards (tiles). The motherboard provides a set of
+peripherals. Processor and RAM "live" on the tiles.
+
+The motherboard and each core tile should be described by a separate
+Device Tree source file, with the tile's description including
+the motherboard file using a /include/ directive. As the motherboard
+can be initialized in one of two different configurations ("memory
+maps"), care must be taken to include the correct one.
+
+Required properties in the root node:
+- compatible value:
+       compatible = "arm,vexpress,<model>", "arm,vexpress";
+  where <model> is the full tile model name (as used in the tile's
+    Technical Reference Manual), eg.:
+    - for Coretile Express A5x2 (V2P-CA5s):
+       compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress";
+    - for Coretile Express A9x4 (V2P-CA9):
+       compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
+  If a tile comes in several variants or can be used in more then one
+  configuration, the compatible value should be:
+       compatible = "arm,vexpress,<model>,<variant>", \
+                               "arm,vexpress,<model>", "arm,vexpress";
+  eg:
+    - Coretile Express A15x2 (V2P-CA15) with Tech Chip 1:
+       compatible = "arm,vexpress,v2p-ca15,tc1", \
+                               "arm,vexpress,v2p-ca15", "arm,vexpress";
+    - LogicTile Express 13MG (V2F-2XV6) running Cortex-A7 (3 cores) SMM:
+       compatible = "arm,vexpress,v2f-2xv6,ca7x3", \
+                               "arm,vexpress,v2f-2xv6", "arm,vexpress";
+
+Optional properties in the root node:
+- tile model name (use name from the tile's Technical Reference
+  Manual, eg. "V2P-CA5s")
+       model = "<model>";
+- tile's HBI number (unique ARM's board model ID, visible on the
+  PCB's silkscreen) in hexadecimal transcription:
+       arm,hbi = <0xhbi>
+  eg:
+  - for Coretile Express A5x2 (V2P-CA5s) HBI-0191:
+       arm,hbi = <0x191>;
+  - Coretile Express A9x4 (V2P-CA9) HBI-0225:
+       arm,hbi = <0x225>;
+
+Top-level standard "cpus" node is required. It must contain a node
+with device_type = "cpu" property for every available core, eg.:
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a5";
+                       reg = <0>;
+               };
+       };
+
+The motherboard description file provides a single "motherboard" node
+using 2 address cells corresponding to the Static Memory Bus used
+between the motherboard and the tile. The first cell defines the Chip
+Select (CS) line number, the second cell address offset within the CS.
+All interrupt lines between the motherboard and the tile are active
+high and are described using single cell.
+
+Optional properties of the "motherboard" node:
+- motherboard's memory map variant:
+       arm,v2m-memory-map = "<name>";
+  where name is one of:
+  - "rs1" - for RS1 map (i.a. peripherals on CS3); this map is also
+            referred to as "ARM Cortex-A Series memory map":
+       arm,v2m-memory-map = "rs1";
+  When this property is missing, the motherboard is using the original
+  memory map (also known as the "Legacy memory map", primarily used
+  with the original CoreTile Express A9x4) with peripherals on CS7.
+
+Motherboard .dtsi files provide a set of labelled peripherals that
+can be used to obtain required phandle in the tile's "aliases" node:
+- UARTs, note that the numbers correspond to the physical connectors
+  on the motherboard's back panel:
+       v2m_serial0, v2m_serial1, v2m_serial2 and v2m_serial3
+- I2C controllers:
+       v2m_i2c_dvi and v2m_i2c_pcie
+- SP804 timers:
+       v2m_timer01 and v2m_timer23
+
+Current Linux implementation requires a "arm,v2m_timer" alias
+pointing at one of the motherboard's SP804 timers, if it is to be
+used as the system timer. This alias should be defined in the
+motherboard files.
+
+The tile description must define "ranges", "interrupt-map-mask" and
+"interrupt-map" properties to translate the motherboard's address
+and interrupt space into one used by the tile's processor.
+
+Abbreviated example:
+
+/dts-v1/;
+
+/ {
+       model = "V2P-CA5s";
+       arm,hbi = <0x225>;
+       compatible = "arm,vexpress-v2p-ca5s", "arm,vexpress";
+       interrupt-parent = <&gic>;
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       chosen { };
+
+       aliases {
+               serial0 = &v2m_serial0;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a5";
+                       reg = <0>;
+               };
+       };
+
+       gic: interrupt-controller@2c001000 {
+               compatible = "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               #address-cells = <0>;
+               interrupt-controller;
+               reg = <0x2c001000 0x1000>,
+                     <0x2c000100 0x100>;
+       };
+
+       motherboard {
+               /* CS0 is visible at 0x08000000 */
+               ranges = <0 0 0x08000000 0x04000000>;
+               interrupt-map-mask = <0 0 63>;
+               /* Active high IRQ 0 is connected to GIC's SPI0 */
+               interrupt-map = <0 0 0 &gic 0 0 4>;
+       };
+};
+
+/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt
new file mode 100644 (file)
index 0000000..90fa7da
--- /dev/null
@@ -0,0 +1,30 @@
+* NVIDIA Tegra APB DMA controller
+
+Required properties:
+- compatible: Should be "nvidia,<chip>-apbdma"
+- reg: Should contain DMA registers location and length. This shuld include
+  all of the per-channel registers.
+- interrupts: Should contain all of the per-channel DMA interrupts.
+
+Examples:
+
+apbdma: dma@6000a000 {
+       compatible = "nvidia,tegra20-apbdma";
+       reg = <0x6000a000 0x1200>;
+       interrupts = < 0 136 0x04
+                      0 137 0x04
+                      0 138 0x04
+                      0 139 0x04
+                      0 140 0x04
+                      0 141 0x04
+                      0 142 0x04
+                      0 143 0x04
+                      0 144 0x04
+                      0 145 0x04
+                      0 146 0x04
+                      0 147 0x04
+                      0 148 0x04
+                      0 149 0x04
+                      0 150 0x04
+                      0 151 0x04 >;
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-omap.txt b/Documentation/devicetree/bindings/gpio/gpio-omap.txt
new file mode 100644 (file)
index 0000000..bff51a2
--- /dev/null
@@ -0,0 +1,36 @@
+OMAP GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "ti,omap2-gpio" for OMAP2 controllers
+  - "ti,omap3-gpio" for OMAP3 controllers
+  - "ti,omap4-gpio" for OMAP4 controllers
+- #gpio-cells : Should be two.
+  - first cell is the pin number
+  - second cell is used to specify optional parameters (unused)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+- interrupt-controller: Mark the device node as an interrupt controller
+  The first cell is the GPIO number.
+  The second cell is used to specify flags:
+    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.
+
+OMAP specific properties:
+- ti,hwmods: Name of the hwmod associated to the GPIO:
+  "gpio<X>", <X> being the 1-based instance number from the HW spec
+
+
+Example:
+
+gpio4: gpio4 {
+    compatible = "ti,omap4-gpio";
+    ti,hwmods = "gpio4";
+    #gpio-cells = <2>;
+    gpio-controller;
+    #interrupt-cells = <2>;
+    interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt b/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt
new file mode 100644 (file)
index 0000000..16695d9
--- /dev/null
@@ -0,0 +1,23 @@
+twl4030 GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "ti,twl4030-gpio" for twl4030 GPIO controller
+- #gpio-cells : Should be two.
+  - first cell is the pin number
+  - second cell is used to specify optional parameters (unused)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+- interrupt-controller: Mark the device node as an interrupt controller
+  The first cell is the GPIO number.
+  The second cell is not used.
+
+Example:
+
+twl_gpio: gpio {
+    compatible = "ti,twl4030-gpio";
+    #gpio-cells = <2>;
+    gpio-controller;
+    #interrupt-cells = <2>;
+    interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio_atmel.txt b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
new file mode 100644 (file)
index 0000000..66efc80
--- /dev/null
@@ -0,0 +1,20 @@
+* Atmel GPIO controller (PIO)
+
+Required properties:
+- compatible: "atmel,<chip>-gpio", where <chip> is at91rm9200 or at91sam9x5.
+- reg: Should contain GPIO controller registers location and length
+- interrupts: Should be the port interrupt shared by all the pins.
+- #gpio-cells: Should be two.  The first cell is the pin number and
+  the second cell is used to specify optional parameters (currently
+  unused).
+- gpio-controller: Marks the device node as a GPIO controller.
+
+Example:
+       pioA: gpio@fffff200 {
+               compatible = "atmel,at91rm9200-gpio";
+               reg = <0xfffff200 0x100>;
+               interrupts = <2 4>;
+               #gpio-cells = <2>;
+               gpio-controller;
+       };
+
diff --git a/Documentation/devicetree/bindings/gpio/gpio_i2c.txt b/Documentation/devicetree/bindings/gpio/gpio_i2c.txt
new file mode 100644 (file)
index 0000000..4f8ec94
--- /dev/null
@@ -0,0 +1,32 @@
+Device-Tree bindings for i2c gpio driver
+
+Required properties:
+       - compatible = "i2c-gpio";
+       - gpios: sda and scl gpio
+
+
+Optional properties:
+       - i2c-gpio,sda-open-drain: sda as open drain
+       - i2c-gpio,scl-open-drain: scl as open drain
+       - i2c-gpio,scl-output-only: scl as output only
+       - i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform)
+       - i2c-gpio,timeout-ms: timeout to get data
+
+Example nodes:
+
+i2c@0 {
+       compatible = "i2c-gpio";
+       gpios = <&pioA 23 0 /* sda */
+                &pioA 24 0 /* scl */
+               >;
+       i2c-gpio,sda-open-drain;
+       i2c-gpio,scl-open-drain;
+       i2c-gpio,delay-us = <2>;        /* ~100 kHz */
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       rv3029c2@56 {
+               compatible = "rv3029c2";
+               reg = <0x56>;
+       };
+};
index eb4b530..023c952 100644 (file)
@@ -1,8 +1,40 @@
-NVIDIA Tegra 2 GPIO controller
+NVIDIA Tegra GPIO controller
 
 Required properties:
-- compatible : "nvidia,tegra20-gpio"
+- compatible : "nvidia,tegra<chip>-gpio"
+- reg : Physical base address and length of the controller's registers.
+- interrupts : The interrupt outputs from the controller. For Tegra20,
+  there should be 7 interrupts specified, and for Tegra30, there should
+  be 8 interrupts specified.
 - #gpio-cells : Should be two. The first cell is the pin number and the
   second cell is used to specify optional parameters:
   - bit 0 specifies polarity (0 for normal, 1 for inverted)
 - gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+  The first cell is the GPIO number.
+  The second cell is used to specify flags:
+    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.
+      Valid combinations are 1, 2, 3, 4, 8.
+- interrupt-controller : Marks the device node as an interrupt controller.
+
+Example:
+
+gpio: gpio@6000d000 {
+       compatible = "nvidia,tegra20-gpio";
+       reg = < 0x6000d000 0x1000 >;
+       interrupts = < 0 32 0x04
+                      0 33 0x04
+                      0 34 0x04
+                      0 35 0x04
+                      0 55 0x04
+                      0 87 0x04
+                      0 89 0x04 >;
+       #gpio-cells = <2>;
+       gpio-controller;
+       #interrupt-cells = <2>;
+       interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
new file mode 100644 (file)
index 0000000..1e34cfe
--- /dev/null
@@ -0,0 +1,23 @@
+* Marvell PXA GPIO controller
+
+Required properties:
+- compatible : Should be "mrvl,pxa-gpio" or "mrvl,mmp-gpio"
+- reg : Address and length of the register set for the device
+- interrupts : Should be the port interrupt shared by all gpio pins, if
+- interrupt-name : Should be the name of irq resource.
+  one number.
+- gpio-controller : Marks the device node as a gpio controller.
+- #gpio-cells : Should be one.  It is the pin number.
+
+Example:
+
+       gpio: gpio@d4019000 {
+               compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio";
+               reg = <0xd4019000 0x1000>;
+               interrupts = <49>, <17>, <18>;
+               interrupt-name = "gpio_mux", "gpio0", "gpio1";
+               gpio-controller;
+               #gpio-cells = <1>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+      };
diff --git a/Documentation/devicetree/bindings/gpio/sodaville.txt b/Documentation/devicetree/bindings/gpio/sodaville.txt
new file mode 100644 (file)
index 0000000..563eff2
--- /dev/null
@@ -0,0 +1,48 @@
+GPIO controller on CE4100 / Sodaville SoCs
+==========================================
+
+The bindings for CE4100's GPIO controller match the generic description
+which is covered by the gpio.txt file in this folder.
+
+The only additional property is the intel,muxctl property which holds the
+value which is written into the MUXCNTL register.
+
+There is no compatible property for now because the driver is probed via
+PCI id (vendor 0x8086 device 0x2e67).
+
+The interrupt specifier consists of two cells encoded as follows:
+ - <1st cell>: The interrupt-number that identifies the interrupt source.
+ - <2nd cell>: The level-sense information, encoded as follows:
+               4 - active high level-sensitive
+               8 - active low level-sensitive
+
+Example of the GPIO device and one user:
+
+       pcigpio: gpio@b,1 {
+                       /* two cells for GPIO and interrupt */
+                       #gpio-cells = <2>;
+                       #interrupt-cells = <2>;
+                       compatible = "pci8086,2e67.2",
+                                          "pci8086,2e67",
+                                          "pciclassff0000",
+                                          "pciclassff00";
+
+                       reg = <0x15900 0x0 0x0 0x0 0x0>;
+                       /* Interrupt line of the gpio device */
+                       interrupts = <15 1>;
+                       /* It is an interrupt and GPIO controller itself */
+                       interrupt-controller;
+                       gpio-controller;
+                       intel,muxctl = <0>;
+       };
+
+       testuser@20 {
+                       compatible = "example,testuser";
+                       /* User the 11th GPIO line as an active high triggered
+                        * level interrupt
+                        */
+                       interrupts = <11 8>;
+                       interrupt-parent = <&pcigpio>;
+                       /* Use this GPIO also with the gpio functions */
+                       gpios = <&pcigpio 11 0>;
+       };
diff --git a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
new file mode 100644 (file)
index 0000000..071eb3c
--- /dev/null
@@ -0,0 +1,37 @@
+* I2C
+
+Required properties :
+
+ - reg : Offset and length of the register set for the device
+ - compatible : should be "mrvl,mmp-twsi" where CHIP is the name of a
+   compatible processor, e.g. pxa168, pxa910, mmp2, mmp3.
+   For the pxa2xx/pxa3xx, an additional node "mrvl,pxa-i2c" is required
+   as shown in the example below.
+
+Recommended properties :
+
+ - interrupts : <a b> where a is the interrupt number and b is a
+   field that represents an encoding of the sense and level
+   information for the interrupt.  This should be encoded based on
+   the information in section 2) depending on the type of interrupt
+   controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+ - mrvl,i2c-polling : Disable interrupt of i2c controller. Polling
+   status register of i2c controller instead.
+ - mrvl,i2c-fast-mode : Enable fast mode of i2c controller.
+
+Examples:
+       twsi1: i2c@d4011000 {
+               compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+               reg = <0xd4011000 0x1000>;
+               interrupts = <7>;
+               mrvl,i2c-fast-mode;
+       };
+       
+       twsi2: i2c@d4025000 {
+               compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+               reg = <0xd4025000 0x1000>;
+               interrupts = <58>;
+       };
+
diff --git a/Documentation/devicetree/bindings/i2c/sirf-i2c.txt b/Documentation/devicetree/bindings/i2c/sirf-i2c.txt
new file mode 100644 (file)
index 0000000..7baf9e1
--- /dev/null
@@ -0,0 +1,19 @@
+I2C for SiRFprimaII platforms
+
+Required properties :
+- compatible : Must be "sirf,prima2-i2c"
+- reg: physical base address of the controller and length of memory mapped
+     region.
+- interrupts: interrupt number to the cpu.
+
+Optional properties:
+- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
+  The absence of the propoerty indicates the default frequency 100 kHz.
+
+Examples :
+
+i2c0: i2c@b00e0000 {
+    compatible = "sirf,prima2-i2c";
+    reg = <0xb00e0000 0x10000>;
+    interrupts = <24>;
+};
diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
new file mode 100644 (file)
index 0000000..5903ecf
--- /dev/null
@@ -0,0 +1,41 @@
+Atmel NAND flash
+
+Required properties:
+- compatible : "atmel,at91rm9200-nand".
+- reg : should specify localbus address and size used for the chip,
+       and if availlable the ECC.
+- atmel,nand-addr-offset : offset for the address latch.
+- atmel,nand-cmd-offset : offset for the command latch.
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+
+- gpios : specifies the gpio pins to control the NAND device. detect is an
+  optional gpio and may be set to 0 if not present.
+
+Optional properties:
+- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
+  Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
+  "soft_bch".
+- nand-bus-width : 8 or 16 bus width if not present 8
+- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+
+Examples:
+nand0: nand@40000000,0 {
+       compatible = "atmel,at91rm9200-nand";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       reg = <0x40000000 0x10000000
+              0xffffe800 0x200
+             >;
+       atmel,nand-addr-offset = <21>;
+       atmel,nand-cmd-offset = <22>;
+       nand-on-flash-bbt;
+       nand-ecc-mode = "soft";
+       gpios = <&pioC 13 0
+                &pioC 14 0
+                0
+               >;
+       partition@0 {
+               ...
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/nand.txt b/Documentation/devicetree/bindings/mtd/nand.txt
new file mode 100644 (file)
index 0000000..03855c8
--- /dev/null
@@ -0,0 +1,7 @@
+* MTD generic binding
+
+- nand-ecc-mode : String, operation mode of the NAND ecc mode.
+  Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
+  "soft_bch".
+- nand-bus-width : 8 or 16 bus width if not present 8
+- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
diff --git a/Documentation/devicetree/bindings/rtc/sa1100-rtc.txt b/Documentation/devicetree/bindings/rtc/sa1100-rtc.txt
new file mode 100644 (file)
index 0000000..0cda19a
--- /dev/null
@@ -0,0 +1,17 @@
+* Marvell Real Time Clock controller
+
+Required properties:
+- compatible: should be "mrvl,sa1100-rtc"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: Should be two. The first interrupt number is the rtc alarm
+  interrupt and the second interrupt number is the rtc hz interrupt.
+- interrupt-names: Assign name of irq resource.
+
+Example:
+       rtc: rtc@d4010000 {
+               compatible = "mrvl,mmp-rtc";
+               reg = <0xd4010000 0x1000>;
+               interrupts = <5>, <6>;
+               interrupt-name = "rtc 1Hz", "rtc alarm";
+       };
diff --git a/Documentation/devicetree/bindings/serial/mrvl-serial.txt b/Documentation/devicetree/bindings/serial/mrvl-serial.txt
new file mode 100644 (file)
index 0000000..d744340
--- /dev/null
@@ -0,0 +1,4 @@
+PXA UART controller
+
+Required properties:
+- compatible : should be "mrvl,mmp-uart" or "mrvl,pxa-uart".
diff --git a/Documentation/devicetree/bindings/usb/atmel-usb.txt b/Documentation/devicetree/bindings/usb/atmel-usb.txt
new file mode 100644 (file)
index 0000000..60bd215
--- /dev/null
@@ -0,0 +1,49 @@
+Atmel SOC USB controllers
+
+OHCI
+
+Required properties:
+ - compatible: Should be "atmel,at91rm9200-ohci" for USB controllers
+   used in host mode.
+ - num-ports: Number of ports.
+ - atmel,vbus-gpio: If present, specifies a gpio that needs to be
+   activated for the bus to be powered.
+ - atmel,oc-gpio: If present, specifies a gpio that needs to be
+   activated for the overcurrent detection.
+
+usb0: ohci@00500000 {
+       compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+       reg = <0x00500000 0x100000>;
+       interrupts = <20 4>;
+       num-ports = <2>;
+};
+
+EHCI
+
+Required properties:
+ - compatible: Should be "atmel,at91sam9g45-ehci" for USB controllers
+   used in host mode.
+
+usb1: ehci@00800000 {
+       compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+       reg = <0x00800000 0x100000>;
+       interrupts = <22 4>;
+};
+
+AT91 USB device controller
+
+Required properties:
+ - compatible: Should be "atmel,at91rm9200-udc"
+ - reg: Address and length of the register set for the device
+ - interrupts: Should contain macb interrupt
+
+Optional properties:
+ - atmel,vbus-gpio: If present, specifies a gpio that needs to be
+   activated for the bus to be powered.
+
+usb1: gadget@fffa4000 {
+       compatible = "atmel,at91rm9200-udc";
+       reg = <0xfffa4000 0x4000>;
+       interrupts = <10 4>;
+       atmel,vbus-gpio = <&pioC 5 0>;
+};
index 035d63d..007005d 100644 (file)
@@ -11,3 +11,16 @@ Required properties :
  - phy_type : Should be one of "ulpi" or "utmi".
  - nvidia,vbus-gpio : If present, specifies a gpio that needs to be
    activated for the bus to be powered.
+
+Optional properties:
+  - dr_mode : dual role mode. Indicates the working mode for
+   nvidia,tegra20-ehci compatible controllers.  Can be "host", "peripheral",
+   or "otg".  Default to "host" if not defined for backward compatibility.
+      host means this is a host controller
+      peripheral means it is device controller
+      otg means it can operate as either ("on the go")
+  - nvidia,has-legacy-mode : boolean indicates whether this controller can
+    operate in legacy mode (as APX 2500 / 2600). In legacy mode some
+    registers are accessed through the APB_MISC base address instead of
+    the USB controller. Since this is a legacy issue it probably does not
+    warrant a compatible string of its own.
index 225f96d..3bbd5c5 100644 (file)
@@ -32,8 +32,12 @@ The buffer-user
 *IMPORTANT*: [see https://lkml.org/lkml/2011/12/20/211 for more details]
 For this first version, A buffer shared using the dma_buf sharing API:
 - *may* be exported to user space using "mmap" *ONLY* by exporter, outside of
-   this framework.
-- may be used *ONLY* by importers that do not need CPU access to the buffer.
+  this framework.
+- with this new iteration of the dma-buf api cpu access from the kernel has been
+  enable, see below for the details.
+
+dma-buf operations for device dma only
+--------------------------------------
 
 The dma_buf buffer sharing API usage contains the following steps:
 
@@ -219,10 +223,120 @@ NOTES:
    If the exporter chooses not to allow an attach() operation once a
    map_dma_buf() API has been called, it simply returns an error.
 
-Miscellaneous notes:
+Kernel cpu access to a dma-buf buffer object
+--------------------------------------------
+
+The motivation to allow cpu access from the kernel to a dma-buf object from the
+importers side are:
+- fallback operations, e.g. if the devices is connected to a usb bus and the
+  kernel needs to shuffle the data around first before sending it away.
+- full transparency for existing users on the importer side, i.e. userspace
+  should not notice the difference between a normal object from that subsystem
+  and an imported one backed by a dma-buf. This is really important for drm
+  opengl drivers that expect to still use all the existing upload/download
+  paths.
+
+Access to a dma_buf from the kernel context involves three steps:
+
+1. Prepare access, which invalidate any necessary caches and make the object
+   available for cpu access.
+2. Access the object page-by-page with the dma_buf map apis
+3. Finish access, which will flush any necessary cpu caches and free reserved
+   resources.
+
+1. Prepare access
+
+   Before an importer can access a dma_buf object with the cpu from the kernel
+   context, it needs to notify the exporter of the access that is about to
+   happen.
+
+   Interface:
+      int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
+                                  size_t start, size_t len,
+                                  enum dma_data_direction direction)
+
+   This allows the exporter to ensure that the memory is actually available for
+   cpu access - the exporter might need to allocate or swap-in and pin the
+   backing storage. The exporter also needs to ensure that cpu access is
+   coherent for the given range and access direction. The range and access
+   direction can be used by the exporter to optimize the cache flushing, i.e.
+   access outside of the range or with a different direction (read instead of
+   write) might return stale or even bogus data (e.g. when the exporter needs to
+   copy the data to temporary storage).
+
+   This step might fail, e.g. in oom conditions.
+
+2. Accessing the buffer
+
+   To support dma_buf objects residing in highmem cpu access is page-based using
+   an api similar to kmap. Accessing a dma_buf is done in aligned chunks of
+   PAGE_SIZE size. Before accessing a chunk it needs to be mapped, which returns
+   a pointer in kernel virtual address space. Afterwards the chunk needs to be
+   unmapped again. There is no limit on how often a given chunk can be mapped
+   and unmapped, i.e. the importer does not need to call begin_cpu_access again
+   before mapping the same chunk again.
+
+   Interfaces:
+      void *dma_buf_kmap(struct dma_buf *, unsigned long);
+      void dma_buf_kunmap(struct dma_buf *, unsigned long, void *);
+
+   There are also atomic variants of these interfaces. Like for kmap they
+   facilitate non-blocking fast-paths. Neither the importer nor the exporter (in
+   the callback) is allowed to block when using these.
+
+   Interfaces:
+      void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long);
+      void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *);
+
+   For importers all the restrictions of using kmap apply, like the limited
+   supply of kmap_atomic slots. Hence an importer shall only hold onto at most 2
+   atomic dma_buf kmaps at the same time (in any given process context).
+
+   dma_buf kmap calls outside of the range specified in begin_cpu_access are
+   undefined. If the range is not PAGE_SIZE aligned, kmap needs to succeed on
+   the partial chunks at the beginning and end but may return stale or bogus
+   data outside of the range (in these partial chunks).
+
+   Note that these calls need to always succeed. The exporter needs to complete
+   any preparations that might fail in begin_cpu_access.
+
+3. Finish access
+
+   When the importer is done accessing the range specified in begin_cpu_access,
+   it needs to announce this to the exporter (to facilitate cache flushing and
+   unpinning of any pinned resources). The result of of any dma_buf kmap calls
+   after end_cpu_access is undefined.
+
+   Interface:
+      void dma_buf_end_cpu_access(struct dma_buf *dma_buf,
+                                 size_t start, size_t len,
+                                 enum dma_data_direction dir);
+
+
+Miscellaneous notes
+-------------------
+
 - Any exporters or users of the dma-buf buffer sharing framework must have
   a 'select DMA_SHARED_BUFFER' in their respective Kconfigs.
 
+- In order to avoid fd leaks on exec, the FD_CLOEXEC flag must be set
+  on the file descriptor.  This is not just a resource leak, but a
+  potential security hole.  It could give the newly exec'd application
+  access to buffers, via the leaked fd, to which it should otherwise
+  not be permitted access.
+
+  The problem with doing this via a separate fcntl() call, versus doing it
+  atomically when the fd is created, is that this is inherently racy in a
+  multi-threaded app[3].  The issue is made worse when it is library code
+  opening/creating the file descriptor, as the application may not even be
+  aware of the fd's.
+
+  To avoid this problem, userspace must have a way to request O_CLOEXEC
+  flag be set when the dma-buf fd is created.  So any API provided by
+  the exporting driver to create a dmabuf fd must provide a way to let
+  userspace control setting of O_CLOEXEC flag passed in to dma_buf_fd().
+
 References:
 [1] struct dma_buf_ops in include/linux/dma-buf.h
 [2] All interfaces mentioned above defined in include/linux/dma-buf.h
+[3] https://lwn.net/Articles/236486/
index cc09187..97709e9 100644 (file)
@@ -119,4 +119,5 @@ o Cards based on the Phillips saa7134 PCI bridge:
   - Compro Videomate DVB-T300
   - Compro Videomate DVB-T200
   - AVerMedia AVerTVHD MCE A180
+  - KWorld PC150-U ATSC Hybrid
 
index 10b5f04..f4b720a 100644 (file)
@@ -66,5 +66,16 @@ dd if=US290D.sys ibs=1 skip=36856 count=3976 of=dvb-usb-lme2510-s0194.fw
 For LME2510C
 dd if=US290D.sys ibs=1 skip=33152 count=3697 of=dvb-usb-lme2510c-s0194.fw
 
+---------------------------------------------------------------------
+
+The m88rs2000 tuner driver can be found in windows/system32/drivers
+
+US2B0D.sys (dated 29 Jun 2010)
+
+dd if=US2B0D.sys ibs=1 skip=34432 count=3871 of=dvb-usb-lme2510c-rs2000.fw
+
+We need to modify id of rs2000 firmware or it will warm boot id 3344:1120.
+
+echo -ne \\xF0\\x22 | dd conv=notrunc bs=1 count=2 seek=266 of=dvb-usb-lme2510c-rs2000.fw
 
 Copy the firmware file(s) to /lib/firmware
index 249822c..fdcc49f 100644 (file)
@@ -334,8 +334,8 @@ Sdram memory scrubbing 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.
+       If configuration fails or memory scrubbing is not implemented, accessing
+       that attribute will fail.
 
 
 
index 4bfd982..0cad480 100644 (file)
@@ -513,20 +513,6 @@ Who:       Bjorn Helgaas <bhelgaas@google.com>
 
 ----------------------------
 
-What:  The CAP9 SoC family will be removed
-When:  3.4
-Files: arch/arm/mach-at91/at91cap9.c
-       arch/arm/mach-at91/at91cap9_devices.c
-       arch/arm/mach-at91/include/mach/at91cap9.h
-       arch/arm/mach-at91/include/mach/at91cap9_matrix.h
-       arch/arm/mach-at91/include/mach/at91cap9_ddrsdr.h
-       arch/arm/mach-at91/board-cap9adk.c
-Why:   The code is not actively maintained and platforms are now hard to find.
-Who:   Nicolas Ferre <nicolas.ferre@atmel.com>
-       Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-
-----------------------------
-
 What:  Low Performance USB Block driver ("CONFIG_BLK_DEV_UB")
 When:  3.6
 Why:   This driver provides support for USB storage devices like "USB
index 8c10bf3..1b7f9ac 100644 (file)
@@ -144,9 +144,6 @@ journal_async_commit        Commit block can be written to disk without waiting
                        mount the device. This will enable 'journal_checksum'
                        internally.
 
-journal=update         Update the ext4 file system's journal to the current
-                       format.
-
 journal_dev=devnum     When the external journal device's major/minor numbers
                        have changed, this option allows the user to specify
                        the new journal location.  The journal device is
@@ -356,11 +353,6 @@ nouid32                    Disables 32-bit UIDs and GIDs.  This is for
                        interoperability  with  older kernels which only
                        store and expect 16-bit values.
 
-resize                 Allows to resize filesystem to the end of the last
-                       existing block group, further resize has to be done
-                       with resize2fs either online, or offline. It can be
-                       used only with conjunction with remount.
-
 block_validity         This options allows to enables/disables the in-kernel
 noblock_validity       facility for tracking filesystem metadata blocks
                        within internal data structures. This allows multi-
index 120fd3c..fe03d10 100644 (file)
@@ -4,13 +4,21 @@ ID Mapper
 =========
 Id mapper is used by NFS to translate user and group ids into names, and to
 translate user and group names into ids.  Part of this translation involves
-performing an upcall to userspace to request the information.  Id mapper will
-user request-key to perform this upcall and cache the result.  The program
-/usr/sbin/nfs.idmap should be called by request-key, and will perform the
-translation and initialize a key with the resulting information.
+performing an upcall to userspace to request the information.  There are two
+ways NFS could obtain this information: placing a call to /sbin/request-key
+or by placing a call to the rpc.idmap daemon.
+
+NFS will attempt to call /sbin/request-key first.  If this succeeds, the
+result will be cached using the generic request-key cache.  This call should
+only fail if /etc/request-key.conf is not configured for the id_resolver key
+type, see the "Configuring" section below if you wish to use the request-key
+method.
+
+If the call to /sbin/request-key fails (if /etc/request-key.conf is not
+configured with the id_resolver key type), then the idmapper will ask the
+legacy rpc.idmap daemon for the id mapping.  This result will be stored
+in a custom NFS idmap cache.
 
- NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this
- feature.
 
 ===========
 Configuring
index 983e14a..c7919c6 100644 (file)
@@ -53,3 +53,57 @@ lseg maintains an extra reference corresponding to the NFS_LSEG_VALID
 bit which holds it in the pnfs_layout_hdr's list.  When the final lseg
 is removed from the pnfs_layout_hdr's list, the NFS_LAYOUT_DESTROYED
 bit is set, preventing any new lsegs from being added.
+
+layout drivers
+--------------
+
+PNFS utilizes what is called layout drivers. The STD defines 3 basic
+layout types: "files" "objects" and "blocks". For each of these types
+there is a layout-driver with a common function-vectors table which
+are called by the nfs-client pnfs-core to implement the different layout
+types.
+
+Files-layout-driver code is in: fs/nfs/nfs4filelayout.c && nfs4filelayoutdev.c
+Objects-layout-deriver code is in: fs/nfs/objlayout/.. directory
+Blocks-layout-deriver code is in: fs/nfs/blocklayout/.. directory
+
+objects-layout setup
+--------------------
+
+As part of the full STD implementation the objlayoutdriver.ko needs, at times,
+to automatically login to yet undiscovered iscsi/osd devices. For this the
+driver makes up-calles to a user-mode script called *osd_login*
+
+The path_name of the script to use is by default:
+       /sbin/osd_login.
+This name can be overridden by the Kernel module parameter:
+       objlayoutdriver.osd_login_prog
+
+If Kernel does not find the osd_login_prog path it will zero it out
+and will not attempt farther logins. An admin can then write new value
+to the objlayoutdriver.osd_login_prog Kernel parameter to re-enable it.
+
+The /sbin/osd_login is part of the nfs-utils package, and should usually
+be installed on distributions that support this Kernel version.
+
+The API to the login script is as follows:
+       Usage: $0 -u <URI> -o <OSDNAME> -s <SYSTEMID>
+       Options:
+               -u              target uri e.g. iscsi://<ip>:<port>
+                               (allways exists)
+                               (More protocols can be defined in the future.
+                                The client does not interpret this string it is
+                                passed unchanged as recieved from the Server)
+               -o              osdname of the requested target OSD
+                               (Might be empty)
+                               (A string which denotes the OSD name, there is a
+                                limit of 64 chars on this string)
+               -s              systemid of the requested target OSD
+                               (Might be empty)
+                               (This string, if not empty is always an hex
+                                representation of the 20 bytes osd_system_id)
+
+blocks-layout setup
+-------------------
+
+TODO: Document the setup needs of the blocks layout driver
index 792faa3..620a078 100644 (file)
@@ -271,9 +271,26 @@ Some platforms may also use knowledge about what GPIOs are active for
 power management, such as by powering down unused chip sectors and, more
 easily, gating off unused clocks.
 
-Note that requesting a GPIO does NOT cause it to be configured in any
-way; it just marks that GPIO as in use.  Separate code must handle any
-pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown).
+For GPIOs that use pins known to the pinctrl subsystem, that subsystem should
+be informed of their use; a gpiolib driver's .request() operation may call
+pinctrl_request_gpio(), and a gpiolib driver's .free() operation may call
+pinctrl_free_gpio(). The pinctrl subsystem allows a pinctrl_request_gpio()
+to succeed concurrently with a pin or pingroup being "owned" by a device for
+pin multiplexing.
+
+Any programming of pin multiplexing hardware that is needed to route the
+GPIO signal to the appropriate pin should occur within a GPIO driver's
+.direction_input() or .direction_output() operations, and occur after any
+setup of an output GPIO's value. This allows a glitch-free migration from a
+pin's special function to GPIO. This is sometimes required when using a GPIO
+to implement a workaround on signals typically driven by a non-GPIO HW block.
+
+Some platforms allow some or all GPIO signals to be routed to different pins.
+Similarly, other aspects of the GPIO or pin may need to be configured, such as
+pullup/pulldown. Platform software should arrange that any such details are
+configured prior to gpio_request() being called for those GPIOs, e.g. using
+the pinctrl subsystem's mapping table, so that GPIO users need not be aware
+of these details.
 
 Also note that it's your responsibility to have stopped using a GPIO
 before you free it.
@@ -302,6 +319,8 @@ where 'flags' is currently defined to specify the following properties:
 
        * GPIOF_INIT_LOW        - as output, set initial level to LOW
        * GPIOF_INIT_HIGH       - as output, set initial level to HIGH
+       * GPIOF_OPEN_DRAIN      - gpio pin is open drain type.
+       * GPIOF_OPEN_SOURCE     - gpio pin is open source type.
 
 since GPIOF_INIT_* are only valid when configured as output, so group valid
 combinations as:
@@ -310,8 +329,19 @@ combinations as:
        * GPIOF_OUT_INIT_LOW    - configured as output, initial level LOW
        * GPIOF_OUT_INIT_HIGH   - configured as output, initial level HIGH
 
-In the future, these flags can be extended to support more properties such
-as open-drain status.
+When setting the flag as GPIOF_OPEN_DRAIN then it will assume that pins is
+open drain type. Such pins will not be driven to 1 in output mode. It is
+require to connect pull-up on such pins. By enabling this flag, gpio lib will
+make the direction to input when it is asked to set value of 1 in output mode
+to make the pin HIGH. The pin is make to LOW by driving value 0 in output mode.
+
+When setting the flag as GPIOF_OPEN_SOURCE then it will assume that pins is
+open source type. Such pins will not be driven to 0 in output mode. It is
+require to connect pull-down on such pin. By enabling this flag, gpio lib will
+make the direction to input when it is asked to set value of 0 in output mode
+to make the pin LOW. The pin is make to HIGH by driving value 1 in output mode.
+
+In the future, these flags can be extended to support more properties.
 
 Further more, to ease the claim/release of multiple GPIOs, 'struct gpio' is
 introduced to encapsulate all three fields as:
index 9cd14cf..b466974 100644 (file)
@@ -118,6 +118,10 @@ Supported chips:
     Addresses scanned: I2C 0x48 through 0x4F
     Datasheet: Publicly available at NXP website
                http://ics.nxp.com/products/interface/datasheet/sa56004x.pdf
+  * GMT G781
+    Prefix: 'g781'
+    Addresses scanned: I2C 0x4c, 0x4d
+    Datasheet: Not publicly available from GMT
 
 Author: Jean Delvare <khali@linux-fr.org>
 
index 044531a..d0e7b3f 100644 (file)
@@ -3,8 +3,11 @@ Kernel driver mc13783-adc
 
 Supported chips:
   * Freescale Atlas MC13783
-    Prefix: 'mc13783_adc'
+    Prefix: 'mc13783'
     Datasheet: http://www.freescale.com/files/rf_if/doc/data_sheet/MC13783.pdf?fsrch=1
+  * Freescale Atlas MC13892
+    Prefix: 'mc13892'
+    Datasheet: http://cache.freescale.com/files/analog/doc/data_sheet/MC13892.pdf?fsrch=1&sr=1
 
 Authors:
     Sascha Hauer <s.hauer@pengutronix.de>
@@ -13,20 +16,21 @@ Authors:
 Description
 -----------
 
-The Freescale MC13783 is a Power Management and Audio Circuit. Among
-other things it contains a 10-bit A/D converter. The converter has 16
-channels which can be used in different modes.
-The A/D converter has a resolution of 2.25mV. Channels 0-4 have
-a dedicated meaning with chip internal scaling applied. Channels 5-7
-can be used as general purpose inputs or alternatively in a dedicated
-mode. Channels 12-15 are occupied by the touchscreen if it's active.
+The Freescale MC13783 and MC13892 are Power Management and Audio Circuits.
+Among other things they contain a 10-bit A/D converter. The converter has 16
+(MC13783) resp. 12 (MC13892) channels which can be used in different modes. The
+A/D converter has a resolution of 2.25mV.
 
-Currently the driver only supports channels 2 and 5-15 with no alternative
-modes for channels 5-7.
+Some channels can be used as General Purpose inputs or in a dedicated mode with
+a chip internal scaling applied .
 
-See this table for the meaning of the different channels and their chip
-internal scaling:
+Currently the driver only supports the Application Supply channel (BP / BPSNS),
+the General Purpose inputs and touchscreen.
 
+See the following tables for the meaning of the different channels and their
+chip internal scaling:
+
+MC13783:
 Channel        Signal                                          Input Range     Scaling
 -------------------------------------------------------------------------------
 0      Battery Voltage (BATT)                          2.50 - 4.65V    -2.40V
@@ -34,7 +38,7 @@ Channel       Signal                                          Input Range     Scaling
 2      Application Supply (BP)                         2.50 - 4.65V    -2.40V
 3      Charger Voltage (CHRGRAW)                       0 - 10V /       /5
                                                        0 - 20V         /10
-4      Charger Current (CHRGISNSP-CHRGISNSN)           -0.25V - 0.25V  x4
+4      Charger Current (CHRGISNSP-CHRGISNSN)           -0.25 - 0.25V   x4
 5      General Purpose ADIN5 / Battery Pack Thermistor 0 - 2.30V       No
 6      General Purpose ADIN6 / Backup Voltage (LICELL) 0 - 2.30V /     No /
                                                        1.50 - 3.50V    -1.20V
@@ -48,3 +52,23 @@ Channel      Signal                                          Input Range     Scaling
 13     General Purpose TSX2 / Touchscreen X-plate 2    0 - 2.30V       No
 14     General Purpose TSY1 / Touchscreen Y-plate 1    0 - 2.30V       No
 15     General Purpose TSY2 / Touchscreen Y-plate 2    0 - 2.30V       No
+
+MC13892:
+Channel        Signal                                          Input Range     Scaling
+-------------------------------------------------------------------------------
+0      Battery Voltage (BATT)                          0 - 4.8V        /2
+1      Battery Current (BATT - BATTISNSCC)             -60 - 60 mV     x20
+2      Application Supply (BPSNS)                      0 - 4.8V        /2
+3      Charger Voltage (CHRGRAW)                       0 - 12V /       /5
+                                                       0 - 20V         /10
+4      Charger Current (CHRGISNS-BPSNS) /              -0.3 - 0.3V /   x4 /
+       Touchscreen X-plate 1                           0 - 2.4V        No
+5      General Purpose ADIN5 / Battery Pack Thermistor 0 - 2.4V        No
+6      General Purpose ADIN6 / Backup Voltage (LICELL) 0 - 2.4V /      No
+       Backup Voltage (LICELL)                         0 - 3.6V        x2/3
+7      General Purpose ADIN7 / UID / Die Temperature   0 - 2.4V /      No /
+                                                       0 - 4.8V        /2
+12     General Purpose TSX1 / Touchscreen X-plate 1    0 - 2.4V        No
+13     General Purpose TSX2 / Touchscreen X-plate 2    0 - 2.4V        No
+14     General Purpose TSY1 / Touchscreen Y-plate 1    0 - 2.4V        No
+15     General Purpose TSY2 / Touchscreen Y-plate 2    0 - 2.4V        No
diff --git a/Documentation/hwmon/mcp3021 b/Documentation/hwmon/mcp3021
new file mode 100644 (file)
index 0000000..325fd87
--- /dev/null
@@ -0,0 +1,22 @@
+Kernel driver MCP3021
+======================
+
+Supported chips:
+  * Microchip Technology MCP3021
+    Prefix: 'mcp3021'
+    Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21805a.pdf
+
+Author: Mingkai Hu
+
+Description
+-----------
+
+This driver implements support for the Microchip Technology MCP3021 chip.
+
+The Microchip Technology Inc. MCP3021 is a successive approximation A/D
+converter (ADC) with 10-bit resolution.
+This device provides one single-ended input with very low power consumption.
+Communication to the MCP3021 is performed using a 2-wire I2C compatible
+interface. Standard (100 kHz) and Fast (400 kHz) I2C modes are available.
+The default I2C device address is 0x4d (contact the Microchip factory for
+additional address options).
index 2871fd5..71f55bb 100644 (file)
@@ -20,6 +20,7 @@ Supported adapters:
   * Intel Patsburg (PCH)
   * Intel DH89xxCC (PCH)
   * Intel Panther Point (PCH)
+  * Intel Lynx Point (PCH)
    Datasheets: Publicly available at the Intel website
 
 On Intel Patsburg and later chipsets, both the normal host SMBus controller
index 247dcfd..e2f8c29 100644 (file)
@@ -1086,8 +1086,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        no_x2apic_optout
                                BIOS x2APIC opt-out request will be ignored
 
-       inttest=        [IA-64]
-
        iomem=          Disable strict checking of access to MMIO memory
                strict  regions from userspace.
                relaxed
@@ -1672,6 +1670,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        of returning the full 64-bit number.
                        The default is to return 64-bit inode numbers.
 
+       nfs.max_session_slots=
+                       [NFSv4.1] Sets the maximum number of session slots
+                       the client will attempt to negotiate with the server.
+                       This limits the number of simultaneous RPC requests
+                       that the client can send to the NFSv4.1 server.
+                       Note that there is little point in setting this
+                       value higher than the max_tcp_slot_table_limit.
+
        nfs.nfs4_disable_idmapping=
                        [NFSv4] When set to the default of '1', this option
                        ensures that both the RPC level authentication
@@ -1685,6 +1691,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        back to using the idmapper.
                        To turn off this behaviour, set the value to '0'.
 
+       nfs.send_implementation_id =
+                       [NFSv4.1] Send client implementation identification
+                       information in exchange_id requests.
+                       If zero, no implementation identification information
+                       will be sent.
+                       The default is to send the implementation identification
+                       information.
+
+
+       objlayoutdriver.osd_login_prog=
+                       [NFS] [OBJLAYOUT] sets the pathname to the program which
+                       is used to automatically discover and login into new
+                       osd-targets. Please see:
+                       Documentation/filesystems/pnfs.txt for more explanations
+
        nmi_debug=      [KNL,AVR32,SH] Specify one or more actions to take
                        when a NMI is triggered.
                        Format: [state][,regs][,debounce][,die]
@@ -1848,6 +1869,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        shutdown the other cpus.  Instead use the REBOOT_VECTOR
                        irq.
 
+       nomodule        Disable module load
+
        nopat           [X86] Disable PAT (page attribute table extension of
                        pagetables) support.
 
@@ -2124,8 +2147,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                                the default.
                                off: Turn ECRC off
                                on: Turn ECRC on.
-               realloc         reallocate PCI resources if allocations done by BIOS
-                               are erroneous.
+               realloc=        Enable/disable reallocating PCI bridge resources
+                               if allocations done by BIOS are too small to
+                               accommodate resources required by all child
+                               devices.
+                               off: Turn realloc off
+                               on: Turn realloc on
+               realloc         same as realloc=on
+               noari           do not use PCIe ARI.
 
        pcie_aspm=      [PCIE] Forcibly enable or disable PCIe Active State Power
                        Management.
@@ -2133,6 +2162,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                force   Enable ASPM even on devices that claim not to support it.
                        WARNING: Forcing ASPM on may cause system lockups.
 
+       pcie_hp=        [PCIE] PCI Express Hotplug driver options:
+               nomsi   Do not use MSI for PCI Express Native Hotplug (this
+                       makes all PCIe ports use INTx for hotplug services).
+
        pcie_ports=     [PCIE] PCIe ports handling:
                auto    Ask the BIOS whether or not to use native PCIe services
                        associated with PCIe ports (PME, hot-plug, AER).  Use
index 803e51f..a1e04d6 100644 (file)
@@ -45,7 +45,7 @@ Status
 Usage
 -----
 
-  Try "modprobe asus_acpi". Check your dmesg (simply type dmesg). You should
+  Try "modprobe asus-laptop". Check your dmesg (simply type dmesg). You should
   see some lines like this :
 
       Asus Laptop Extras version 0.42
index 2bd4e82..0d5ac7f 100644 (file)
@@ -17,6 +17,11 @@ subsystem. See the logs of acpid or /proc/acpi/event and
 devices are created by the driver. Additionally, loading the driver with the
 debug option will report all events in the kernel log.
 
+The "scancodes" passed to the input system (that can be remapped with udev)
+are indexes to the table "sony_laptop_input_keycode_map" in the sony-laptop.c
+module.  For example the "FN/E" key combination (EJECTCD on some models)
+generates the scancode 20 (0x14).
+
 Backlight control:
 ------------------
 If your laptop model supports it, you will find sysfs files in the
index c4d8d15..0e542ab 100644 (file)
@@ -43,17 +43,23 @@ Format: 10x mA i.e 10 means 1.0 mA
 example platform data:
 
 Note: chan_nr can have values between 0 and 2.
+The name of each channel can be configurable.
+If the name field is not defined, the default name will be set to 'xxxx:channelN'
+(XXXX : pdata->label or i2c client name, N : channel number)
 
 static struct lp5521_led_config lp5521_led_config[] = {
         {
+               .name = "red",
                 .chan_nr        = 0,
                 .led_current    = 50,
                .max_current    = 130,
         }, {
+               .name = "green",
                 .chan_nr        = 1,
                 .led_current    = 0,
                .max_current    = 130,
         }, {
+               .name = "blue",
                 .chan_nr        = 2,
                 .led_current    = 0,
                .max_current    = 130,
@@ -86,3 +92,60 @@ static struct lp5521_platform_data lp5521_platform_data = {
 
 If the current is set to 0 in the platform data, that channel is
 disabled and it is not visible in the sysfs.
+
+The 'update_config' : CONFIG register (ADDR 08h)
+This value is platform-specific data.
+If update_config is not defined, the CONFIG register is set with
+'LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT'.
+(Enable auto-powersave, set charge pump to auto, red to battery)
+
+example of update_config :
+
+#define LP5521_CONFIGS (LP5521_PWM_HF | LP5521_PWRSAVE_EN | \
+                       LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT | \
+                       LP5521_CLK_INT)
+
+static struct lp5521_platform_data lp5521_pdata = {
+       .led_config = lp5521_led_config,
+       .num_channels = ARRAY_SIZE(lp5521_led_config),
+       .clock_mode = LP5521_CLOCK_INT,
+       .update_config = LP5521_CONFIGS,
+};
+
+LED patterns : LP5521 has autonomous operation without external control.
+Pattern data can be defined in the platform data.
+
+example of led pattern data :
+
+/* RGB(50,5,0) 500ms on, 500ms off, infinite loop */
+static u8 pattern_red[] = {
+               0x40, 0x32, 0x60, 0x00, 0x40, 0x00, 0x60, 0x00,
+               };
+
+static u8 pattern_green[] = {
+               0x40, 0x05, 0x60, 0x00, 0x40, 0x00, 0x60, 0x00,
+               };
+
+static struct lp5521_led_pattern board_led_patterns[] = {
+       {
+               .r = pattern_red,
+               .g = pattern_green,
+               .size_r = ARRAY_SIZE(pattern_red),
+               .size_g = ARRAY_SIZE(pattern_green),
+       },
+};
+
+static struct lp5521_platform_data lp5521_platform_data = {
+        .led_config     = lp5521_led_config,
+        .num_channels   = ARRAY_SIZE(lp5521_led_config),
+        .clock_mode     = LP5521_CLOCK_EXT,
+       .patterns = board_led_patterns,
+       .num_patterns = ARRAY_SIZE(board_led_patterns),
+};
+
+Then predefined led pattern(s) can be executed via the sysfs.
+To start the pattern #1,
+# echo 1 > /sys/bus/i2c/devices/xxxx/led_pattern
+(xxxx : i2c bus & slave address)
+To end the pattern,
+# echo 0 > /sys/bus/i2c/devices/xxxx/led_pattern
diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
new file mode 100644 (file)
index 0000000..70a048c
--- /dev/null
@@ -0,0 +1,322 @@
+Remote Processor Framework
+
+1. Introduction
+
+Modern SoCs typically have heterogeneous remote processor devices in asymmetric
+multiprocessing (AMP) configurations, which may be running different instances
+of operating system, whether it's Linux or any other flavor of real-time OS.
+
+OMAP4, for example, has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP.
+In a typical configuration, the dual cortex-A9 is running Linux in a SMP
+configuration, and each of the other three cores (two M3 cores and a DSP)
+is running its own instance of RTOS in an AMP configuration.
+
+The remoteproc framework allows different platforms/architectures to
+control (power on, load firmware, power off) those remote processors while
+abstracting the hardware differences, so the entire driver doesn't need to be
+duplicated. In addition, this framework also adds rpmsg virtio devices
+for remote processors that supports this kind of communication. This way,
+platform-specific remoteproc drivers only need to provide a few low-level
+handlers, and then all rpmsg drivers will then just work
+(for more information about the virtio-based rpmsg bus and its drivers,
+please read Documentation/rpmsg.txt).
+Registration of other types of virtio devices is now also possible. Firmwares
+just need to publish what kind of virtio devices do they support, and then
+remoteproc will add those devices. This makes it possible to reuse the
+existing virtio drivers with remote processor backends at a minimal development
+cost.
+
+2. User API
+
+  int rproc_boot(struct rproc *rproc)
+    - Boot a remote processor (i.e. load its firmware, power it on, ...).
+      If the remote processor is already powered on, this function immediately
+      returns (successfully).
+      Returns 0 on success, and an appropriate error value otherwise.
+      Note: to use this function you should already have a valid rproc
+      handle. There are several ways to achieve that cleanly (devres, pdata,
+      the way remoteproc_rpmsg.c does this, or, if this becomes prevalent, we
+      might also consider using dev_archdata for this). See also
+      rproc_get_by_name() below.
+
+  void rproc_shutdown(struct rproc *rproc)
+    - Power off a remote processor (previously booted with rproc_boot()).
+      In case @rproc is still being used by an additional user(s), then
+      this function will just decrement the power refcount and exit,
+      without really powering off the device.
+      Every call to rproc_boot() must (eventually) be accompanied by a call
+      to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
+      Notes:
+      - we're not decrementing the rproc's refcount, only the power refcount.
+        which means that the @rproc handle stays valid even after
+        rproc_shutdown() returns, and users can still use it with a subsequent
+        rproc_boot(), if needed.
+      - don't call rproc_shutdown() to unroll rproc_get_by_name(), exactly
+        because rproc_shutdown() _does not_ decrement the refcount of @rproc.
+        To decrement the refcount of @rproc, use rproc_put() (but _only_ if
+        you acquired @rproc using rproc_get_by_name()).
+
+  struct rproc *rproc_get_by_name(const char *name)
+    - Find an rproc handle using the remote processor's name, and then
+      boot it. If it's already powered on, then just immediately return
+      (successfully). Returns the rproc handle on success, and NULL on failure.
+      This function increments the remote processor's refcount, so always
+      use rproc_put() to decrement it back once rproc isn't needed anymore.
+      Note: currently rproc_get_by_name() and rproc_put() are not used anymore
+      by the rpmsg bus and its drivers. We need to scrutinize the use cases
+      that still need them, and see if we can migrate them to use the non
+      name-based boot/shutdown interface.
+
+  void rproc_put(struct rproc *rproc)
+    - Decrement @rproc's power refcount and shut it down if it reaches zero
+      (essentially by just calling rproc_shutdown), and then decrement @rproc's
+      validity refcount too.
+      After this function returns, @rproc may _not_ be used anymore, and its
+      handle should be considered invalid.
+      This function should be called _iff_ the @rproc handle was grabbed by
+      calling rproc_get_by_name().
+
+3. Typical usage
+
+#include <linux/remoteproc.h>
+
+/* in case we were given a valid 'rproc' handle */
+int dummy_rproc_example(struct rproc *my_rproc)
+{
+       int ret;
+
+       /* let's power on and boot our remote processor */
+       ret = rproc_boot(my_rproc);
+       if (ret) {
+               /*
+                * something went wrong. handle it and leave.
+                */
+       }
+
+       /*
+        * our remote processor is now powered on... give it some work
+        */
+
+       /* let's shut it down now */
+       rproc_shutdown(my_rproc);
+}
+
+4. API for implementors
+
+  struct rproc *rproc_alloc(struct device *dev, const char *name,
+                               const struct rproc_ops *ops,
+                               const char *firmware, int len)
+    - Allocate a new remote processor handle, but don't register
+      it yet. Required parameters are the underlying device, the
+      name of this remote processor, platform-specific ops handlers,
+      the name of the firmware to boot this rproc with, and the
+      length of private data needed by the allocating rproc driver (in bytes).
+
+      This function should be used by rproc implementations during
+      initialization of the remote processor.
+      After creating an rproc handle using this function, and when ready,
+      implementations should then call rproc_register() to complete
+      the registration of the remote processor.
+      On success, the new rproc is returned, and on failure, NULL.
+
+      Note: _never_ directly deallocate @rproc, even if it was not registered
+      yet. Instead, if you just need to unroll rproc_alloc(), use rproc_free().
+
+  void rproc_free(struct rproc *rproc)
+    - Free an rproc handle that was allocated by rproc_alloc.
+      This function should _only_ be used if @rproc was only allocated,
+      but not registered yet.
+      If @rproc was already successfully registered (by calling
+      rproc_register()), then use rproc_unregister() instead.
+
+  int rproc_register(struct rproc *rproc)
+    - Register @rproc with the remoteproc framework, after it has been
+      allocated with rproc_alloc().
+      This is called by the platform-specific rproc implementation, whenever
+      a new remote processor device is probed.
+      Returns 0 on success and an appropriate error code otherwise.
+      Note: this function initiates an asynchronous firmware loading
+      context, which will look for virtio devices supported by the rproc's
+      firmware.
+      If found, those virtio devices will be created and added, so as a result
+      of registering this remote processor, additional virtio drivers might get
+      probed.
+
+  int rproc_unregister(struct rproc *rproc)
+    - Unregister a remote processor, and decrement its refcount.
+      If its refcount drops to zero, then @rproc will be freed. If not,
+      it will be freed later once the last reference is dropped.
+
+      This function should be called when the platform specific rproc
+      implementation decides to remove the rproc device. it should
+      _only_ be called if a previous invocation of rproc_register()
+      has completed successfully.
+
+      After rproc_unregister() returns, @rproc is _not_ valid anymore and
+      it shouldn't be used. More specifically, don't call rproc_free()
+      or try to directly free @rproc after rproc_unregister() returns;
+      none of these are needed, and calling them is a bug.
+
+      Returns 0 on success and -EINVAL if @rproc isn't valid.
+
+5. Implementation callbacks
+
+These callbacks should be provided by platform-specific remoteproc
+drivers:
+
+/**
+ * struct rproc_ops - platform-specific device handlers
+ * @start:     power on the device and boot it
+ * @stop:      power off the device
+ * @kick:      kick a virtqueue (virtqueue id given as a parameter)
+ */
+struct rproc_ops {
+       int (*start)(struct rproc *rproc);
+       int (*stop)(struct rproc *rproc);
+       void (*kick)(struct rproc *rproc, int vqid);
+};
+
+Every remoteproc implementation should at least provide the ->start and ->stop
+handlers. If rpmsg/virtio functionality is also desired, then the ->kick handler
+should be provided as well.
+
+The ->start() handler takes an rproc handle and should then power on the
+device and boot it (use rproc->priv to access platform-specific private data).
+The boot address, in case needed, can be found in rproc->bootaddr (remoteproc
+core puts there the ELF entry point).
+On success, 0 should be returned, and on failure, an appropriate error code.
+
+The ->stop() handler takes an rproc handle and powers the device down.
+On success, 0 is returned, and on failure, an appropriate error code.
+
+The ->kick() handler takes an rproc handle, and an index of a virtqueue
+where new message was placed in. Implementations should interrupt the remote
+processor and let it know it has pending messages. Notifying remote processors
+the exact virtqueue index to look in is optional: it is easy (and not
+too expensive) to go through the existing virtqueues and look for new buffers
+in the used rings.
+
+6. Binary Firmware Structure
+
+At this point remoteproc only supports ELF32 firmware binaries. However,
+it is quite expected that other platforms/devices which we'd want to
+support with this framework will be based on different binary formats.
+
+When those use cases show up, we will have to decouple the binary format
+from the framework core, so we can support several binary formats without
+duplicating common code.
+
+When the firmware is parsed, its various segments are loaded to memory
+according to the specified device address (might be a physical address
+if the remote processor is accessing memory directly).
+
+In addition to the standard ELF segments, most remote processors would
+also include a special section which we call "the resource table".
+
+The resource table contains system resources that the remote processor
+requires before it should be powered on, such as allocation of physically
+contiguous memory, or iommu mapping of certain on-chip peripherals.
+Remotecore will only power up the device after all the resource table's
+requirement are met.
+
+In addition to system resources, the resource table may also contain
+resource entries that publish the existence of supported features
+or configurations by the remote processor, such as trace buffers and
+supported virtio devices (and their configurations).
+
+The resource table begins with this header:
+
+/**
+ * struct resource_table - firmware resource table header
+ * @ver: version number
+ * @num: number of resource entries
+ * @reserved: reserved (must be zero)
+ * @offset: array of offsets pointing at the various resource entries
+ *
+ * The header of the resource table, as expressed by this structure,
+ * contains a version number (should we need to change this format in the
+ * future), the number of available resource entries, and their offsets
+ * in the table.
+ */
+struct resource_table {
+       u32 ver;
+       u32 num;
+       u32 reserved[2];
+       u32 offset[0];
+} __packed;
+
+Immediately following this header are the resource entries themselves,
+each of which begins with the following resource entry header:
+
+/**
+ * struct fw_rsc_hdr - firmware resource entry header
+ * @type: resource type
+ * @data: resource data
+ *
+ * Every resource entry begins with a 'struct fw_rsc_hdr' header providing
+ * its @type. The content of the entry itself will immediately follow
+ * this header, and it should be parsed according to the resource type.
+ */
+struct fw_rsc_hdr {
+       u32 type;
+       u8 data[0];
+} __packed;
+
+Some resources entries are mere announcements, where the host is informed
+of specific remoteproc configuration. Other entries require the host to
+do something (e.g. allocate a system resource). Sometimes a negotiation
+is expected, where the firmware requests a resource, and once allocated,
+the host should provide back its details (e.g. address of an allocated
+memory region).
+
+Here are the various resource types that are currently supported:
+
+/**
+ * enum fw_resource_type - types of resource entries
+ *
+ * @RSC_CARVEOUT:   request for allocation of a physically contiguous
+ *                 memory region.
+ * @RSC_DEVMEM:     request to iommu_map a memory-based peripheral.
+ * @RSC_TRACE:     announces the availability of a trace buffer into which
+ *                 the remote processor will be writing logs.
+ * @RSC_VDEV:       declare support for a virtio device, and serve as its
+ *                 virtio header.
+ * @RSC_LAST:       just keep this one at the end
+ *
+ * Please note that these values are used as indices to the rproc_handle_rsc
+ * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to
+ * check the validity of an index before the lookup table is accessed, so
+ * please update it as needed.
+ */
+enum fw_resource_type {
+       RSC_CARVEOUT    = 0,
+       RSC_DEVMEM      = 1,
+       RSC_TRACE       = 2,
+       RSC_VDEV        = 3,
+       RSC_LAST        = 4,
+};
+
+For more details regarding a specific resource type, please see its
+dedicated structure in include/linux/remoteproc.h.
+
+We also expect that platform-specific resource entries will show up
+at some point. When that happens, we could easily add a new RSC_PLATFORM
+type, and hand those resources to the platform-specific rproc driver to handle.
+
+7. Virtio and remoteproc
+
+The firmware should provide remoteproc information about virtio devices
+that it supports, and their configurations: a RSC_VDEV resource entry
+should specify the virtio device id (as in virtio_ids.h), virtio features,
+virtio config space, vrings information, etc.
+
+When a new remote processor is registered, the remoteproc framework
+will look for its resource table and will register the virtio devices
+it supports. A firmware may support any number of virtio devices, and
+of any type (a single remote processor can also easily support several
+rpmsg virtio devices this way, if desired).
+
+Of course, RSC_VDEV resource entries are only good enough for static
+allocation of virtio devices. Dynamic allocations will also be made possible
+using the rpmsg bus (similar to how we already do dynamic allocations of
+rpmsg channels; read more about it in rpmsg.txt).
diff --git a/Documentation/rpmsg.txt b/Documentation/rpmsg.txt
new file mode 100644 (file)
index 0000000..409d9f9
--- /dev/null
@@ -0,0 +1,293 @@
+Remote Processor Messaging (rpmsg) Framework
+
+Note: this document describes the rpmsg bus and how to write rpmsg drivers.
+To learn how to add rpmsg support for new platforms, check out remoteproc.txt
+(also a resident of Documentation/).
+
+1. Introduction
+
+Modern SoCs typically employ heterogeneous remote processor devices in
+asymmetric multiprocessing (AMP) configurations, which may be running
+different instances of operating system, whether it's Linux or any other
+flavor of real-time OS.
+
+OMAP4, for example, has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP.
+Typically, the dual cortex-A9 is running Linux in a SMP configuration,
+and each of the other three cores (two M3 cores and a DSP) is running
+its own instance of RTOS in an AMP configuration.
+
+Typically AMP remote processors employ dedicated DSP codecs and multimedia
+hardware accelerators, and therefore are often used to offload CPU-intensive
+multimedia tasks from the main application processor.
+
+These remote processors could also be used to control latency-sensitive
+sensors, drive random hardware blocks, or just perform background tasks
+while the main CPU is idling.
+
+Users of those remote processors can either be userland apps (e.g. multimedia
+frameworks talking with remote OMX components) or kernel drivers (controlling
+hardware accessible only by the remote processor, reserving kernel-controlled
+resources on behalf of the remote processor, etc..).
+
+Rpmsg is a virtio-based messaging bus that allows kernel drivers to communicate
+with remote processors available on the system. In turn, drivers could then
+expose appropriate user space interfaces, if needed.
+
+When writing a driver that exposes rpmsg communication to userland, please
+keep in mind that remote processors might have direct access to the
+system's physical memory and other sensitive hardware resources (e.g. on
+OMAP4, remote cores and hardware accelerators may have direct access to the
+physical memory, gpio banks, dma controllers, i2c bus, gptimers, mailbox
+devices, hwspinlocks, etc..). Moreover, those remote processors might be
+running RTOS where every task can access the entire memory/devices exposed
+to the processor. To minimize the risks of rogue (or buggy) userland code
+exploiting remote bugs, and by that taking over the system, it is often
+desired to limit userland to specific rpmsg channels (see definition below)
+it can send messages on, and if possible, minimize how much control
+it has over the content of the messages.
+
+Every rpmsg device is a communication channel with a remote processor (thus
+rpmsg devices are called channels). Channels are identified by a textual name
+and have a local ("source") rpmsg address, and remote ("destination") rpmsg
+address.
+
+When a driver starts listening on a channel, its rx callback is bound with
+a unique rpmsg local address (a 32-bit integer). This way when inbound messages
+arrive, the rpmsg core dispatches them to the appropriate driver according
+to their destination address (this is done by invoking the driver's rx handler
+with the payload of the inbound message).
+
+
+2. User API
+
+  int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len);
+   - sends a message across to the remote processor on a given channel.
+     The caller should specify the channel, the data it wants to send,
+     and its length (in bytes). The message will be sent on the specified
+     channel, i.e. its source and destination address fields will be
+     set to the channel's src and dst addresses.
+
+     In case there are no TX buffers available, the function will block until
+     one becomes available (i.e. until the remote processor consumes
+     a tx buffer and puts it back on virtio's used descriptor ring),
+     or a timeout of 15 seconds elapses. When the latter happens,
+     -ERESTARTSYS is returned.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst);
+   - sends a message across to the remote processor on a given channel,
+     to a destination address provided by the caller.
+     The caller should specify the channel, the data it wants to send,
+     its length (in bytes), and an explicit destination address.
+     The message will then be sent to the remote processor to which the
+     channel belongs, using the channel's src address, and the user-provided
+     dst address (thus the channel's dst address will be ignored).
+
+     In case there are no TX buffers available, the function will block until
+     one becomes available (i.e. until the remote processor consumes
+     a tx buffer and puts it back on virtio's used descriptor ring),
+     or a timeout of 15 seconds elapses. When the latter happens,
+     -ERESTARTSYS is returned.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+                                                       void *data, int len);
+   - sends a message across to the remote processor, using the src and dst
+     addresses provided by the user.
+     The caller should specify the channel, the data it wants to send,
+     its length (in bytes), and explicit source and destination addresses.
+     The message will then be sent to the remote processor to which the
+     channel belongs, but the channel's src and dst addresses will be
+     ignored (and the user-provided addresses will be used instead).
+
+     In case there are no TX buffers available, the function will block until
+     one becomes available (i.e. until the remote processor consumes
+     a tx buffer and puts it back on virtio's used descriptor ring),
+     or a timeout of 15 seconds elapses. When the latter happens,
+     -ERESTARTSYS is returned.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len);
+   - sends a message across to the remote processor on a given channel.
+     The caller should specify the channel, the data it wants to send,
+     and its length (in bytes). The message will be sent on the specified
+     channel, i.e. its source and destination address fields will be
+     set to the channel's src and dst addresses.
+
+     In case there are no TX buffers available, the function will immediately
+     return -ENOMEM without waiting until one becomes available.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
+   - sends a message across to the remote processor on a given channel,
+     to a destination address provided by the user.
+     The user should specify the channel, the data it wants to send,
+     its length (in bytes), and an explicit destination address.
+     The message will then be sent to the remote processor to which the
+     channel belongs, using the channel's src address, and the user-provided
+     dst address (thus the channel's dst address will be ignored).
+
+     In case there are no TX buffers available, the function will immediately
+     return -ENOMEM without waiting until one becomes available.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+                                                       void *data, int len);
+   - sends a message across to the remote processor, using source and
+     destination addresses provided by the user.
+     The user should specify the channel, the data it wants to send,
+     its length (in bytes), and explicit source and destination addresses.
+     The message will then be sent to the remote processor to which the
+     channel belongs, but the channel's src and dst addresses will be
+     ignored (and the user-provided addresses will be used instead).
+
+     In case there are no TX buffers available, the function will immediately
+     return -ENOMEM without waiting until one becomes available.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rpdev,
+               void (*cb)(struct rpmsg_channel *, void *, int, void *, u32),
+               void *priv, u32 addr);
+   - every rpmsg address in the system is bound to an rx callback (so when
+     inbound messages arrive, they are dispatched by the rpmsg bus using the
+     appropriate callback handler) by means of an rpmsg_endpoint struct.
+
+     This function allows drivers to create such an endpoint, and by that,
+     bind a callback, and possibly some private data too, to an rpmsg address
+     (either one that is known in advance, or one that will be dynamically
+     assigned for them).
+
+     Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint
+     is already created for them when they are probed by the rpmsg bus
+     (using the rx callback they provide when they registered to the rpmsg bus).
+
+     So things should just work for simple drivers: they already have an
+     endpoint, their rx callback is bound to their rpmsg address, and when
+     relevant inbound messages arrive (i.e. messages which their dst address
+     equals to the src address of their rpmsg channel), the driver's handler
+     is invoked to process it.
+
+     That said, more complicated drivers might do need to allocate
+     additional rpmsg addresses, and bind them to different rx callbacks.
+     To accomplish that, those drivers need to call this function.
+     Drivers should provide their channel (so the new endpoint would bind
+     to the same remote processor their channel belongs to), an rx callback
+     function, an optional private data (which is provided back when the
+     rx callback is invoked), and an address they want to bind with the
+     callback. If addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
+     dynamically assign them an available rpmsg address (drivers should have
+     a very good reason why not to always use RPMSG_ADDR_ANY here).
+
+     Returns a pointer to the endpoint on success, or NULL on error.
+
+  void rpmsg_destroy_ept(struct rpmsg_endpoint *ept);
+   - destroys an existing rpmsg endpoint. user should provide a pointer
+     to an rpmsg endpoint that was previously created with rpmsg_create_ept().
+
+  int register_rpmsg_driver(struct rpmsg_driver *rpdrv);
+   - registers an rpmsg driver with the rpmsg bus. user should provide
+     a pointer to an rpmsg_driver struct, which contains the driver's
+     ->probe() and ->remove() functions, an rx callback, and an id_table
+     specifying the names of the channels this driver is interested to
+     be probed with.
+
+  void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv);
+   - unregisters an rpmsg driver from the rpmsg bus. user should provide
+     a pointer to a previously-registered rpmsg_driver struct.
+     Returns 0 on success, and an appropriate error value on failure.
+
+
+3. Typical usage
+
+The following is a simple rpmsg driver, that sends an "hello!" message
+on probe(), and whenever it receives an incoming message, it dumps its
+content to the console.
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rpmsg.h>
+
+static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len,
+                                               void *priv, u32 src)
+{
+       print_hex_dump(KERN_INFO, "incoming message:", DUMP_PREFIX_NONE,
+                                               16, 1, data, len, true);
+}
+
+static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
+{
+       int err;
+
+       dev_info(&rpdev->dev, "chnl: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst);
+
+       /* send a message on our channel */
+       err = rpmsg_send(rpdev, "hello!", 6);
+       if (err) {
+               pr_err("rpmsg_send failed: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static void __devexit rpmsg_sample_remove(struct rpmsg_channel *rpdev)
+{
+       dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
+}
+
+static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
+       { .name = "rpmsg-client-sample" },
+       { },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);
+
+static struct rpmsg_driver rpmsg_sample_client = {
+       .drv.name       = KBUILD_MODNAME,
+       .drv.owner      = THIS_MODULE,
+       .id_table       = rpmsg_driver_sample_id_table,
+       .probe          = rpmsg_sample_probe,
+       .callback       = rpmsg_sample_cb,
+       .remove         = __devexit_p(rpmsg_sample_remove),
+};
+
+static int __init init(void)
+{
+       return register_rpmsg_driver(&rpmsg_sample_client);
+}
+module_init(init);
+
+static void __exit fini(void)
+{
+       unregister_rpmsg_driver(&rpmsg_sample_client);
+}
+module_exit(fini);
+
+Note: a similar sample which can be built and loaded can be found
+in samples/rpmsg/.
+
+4. Allocations of rpmsg channels:
+
+At this point we only support dynamic allocations of rpmsg channels.
+
+This is possible only with remote processors that have the VIRTIO_RPMSG_F_NS
+virtio device feature set. This feature bit means that the remote
+processor supports dynamic name service announcement messages.
+
+When this feature is enabled, creation of rpmsg devices (i.e. channels)
+is completely dynamic: the remote processor announces the existence of a
+remote rpmsg service by sending a name service message (which contains
+the name and rpmsg addr of the remote service, see struct rpmsg_ns_msg).
+
+This message is then handled by the rpmsg bus, which in turn dynamically
+creates and registers an rpmsg channel (which represents the remote service).
+If/when a relevant rpmsg driver is registered, it will be immediately probed
+by the bus, and can then start sending messages to the remote service.
+
+The plan is also to add static creation of rpmsg channels via the virtio
+config space, but it's not implemented yet.
index 23584d0..f316d18 100644 (file)
@@ -32,3 +32,4 @@
  31 -> Leadtek Winfast PxDVR3200 H XC4000                  [107d:6f39]
  32 -> MPX-885
  33 -> Mygica X8507                                        [14f1:8502]
+ 34 -> TerraTec Cinergy T PCIe Dual                        [153b:117e]
index eee18e6..fa4b3f9 100644 (file)
@@ -59,7 +59,7 @@
  58 -> Pinnacle PCTV HD 800i                               [11bd:0051]
  59 -> DViCO FusionHDTV 5 PCI nano                         [18ac:d530]
  60 -> Pinnacle Hybrid PCTV                                [12ab:1788]
- 61 -> Leadtek TV2000 XP Global                            [107d:6f18,107d:6618]
+ 61 -> Leadtek TV2000 XP Global                            [107d:6f18,107d:6618,107d:6619]
  62 -> PowerColor RA330                                    [14f1:ea3d]
  63 -> Geniatech X8000-MT DVBT                             [14f1:8852]
  64 -> DViCO FusionHDTV DVB-T PRO                          [18ac:db30]
@@ -87,3 +87,5 @@
  86 -> TeVii S464 DVB-S/S2                                 [d464:9022]
  87 -> Leadtek WinFast DTV2000 H PLUS                      [107d:6f42]
  88 -> Leadtek WinFast DTV1800 H (XC4000)                  [107d:6f38]
+ 89 -> Leadtek TV2000 XP Global (SC4100)                   [107d:6f36]
+ 90 -> Leadtek TV2000 XP Global (XC4100)                   [107d:6f43]
index e7be3ac..d99262d 100644 (file)
@@ -7,7 +7,7 @@
   6 -> Terratec Cinergy 200 USB                 (em2800)
   7 -> Leadtek Winfast USB II                   (em2800)        [0413:6023]
   8 -> Kworld USB2800                           (em2800)
-  9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker  (em2820/em2840) [1b80:e302,1b80:e304,2304:0207,2304:021a]
+  9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker  (em2820/em2840) [1b80:e302,1b80:e304,2304:0207,2304:021a,093b:a003]
  10 -> Hauppauge WinTV HVR 900                  (em2880)        [2040:6500]
  11 -> Terratec Hybrid XS                       (em2880)
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
@@ -61,7 +61,7 @@
  61 -> Pixelview PlayTV Box 4 USB 2.0           (em2820/em2840)
  62 -> Gadmei TVR200                            (em2820/em2840)
  63 -> Kaiomy TVnPC U2                          (em2860)        [eb1a:e303]
- 64 -> Easy Cap Capture DC-60                   (em2860)
+ 64 -> Easy Cap Capture DC-60                   (em2860)        [1b80:e309]
  65 -> IO-DATA GV-MVP/SZ                        (em2820/em2840) [04bb:0515]
  66 -> Empire dual TV                           (em2880)
  67 -> Terratec Grabby                          (em2860)        [0ccd:0096,0ccd:10AF]
  76 -> KWorld PlusTV 340U or UB435-Q (ATSC)     (em2870)        [1b80:a340]
  77 -> EM2874 Leadership ISDBT                  (em2874)
  78 -> PCTV nanoStick T2 290e                   (em28174)
- 79 -> Terratec Cinergy H5                      (em2884)        [0ccd:10a2,0ccd:10ad]
+ 79 -> Terratec Cinergy H5                      (em2884)        [0ccd:008e,0ccd:00ac,0ccd:10a2,0ccd:10ad]
  80 -> PCTV DVB-S2 Stick (460e)                 (em28174)
  81 -> Hauppauge WinTV HVR 930C                 (em2884)        [2040:1605]
  82 -> Terratec Cinergy HTC Stick               (em2884)        [0ccd:00b2]
+ 83 -> Honestech Vidbox NW03                    (em2860)        [eb1a:5006]
+ 84 -> MaxMedia UB425-TC                        (em2874)        [1b80:e425]
+ 85 -> PCTV QuatroStick (510e)                  (em2884)        [2304:0242]
+ 86 -> PCTV QuatroStick nano (520e)             (em2884)        [2013:0251]
index e7ef38a..34f3b33 100644 (file)
 186 -> Beholder BeholdTV 501                    [5ace:5010]
 187 -> Beholder BeholdTV 503 FM                 [5ace:5030]
 188 -> Sensoray 811/911                         [6000:0811,6000:0911]
+189 -> Kworld PC150-U                           [17de:a134]
index 6323b7a..c83f6e4 100644 (file)
@@ -78,10 +78,11 @@ tuner=77 - TCL tuner MF02GIP-5N-E
 tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
 tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
 tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
-tuner=81 - Xceive 4000 tuner
 tuner=81 - Partsnic (Daewoo) PTI-5NF05
 tuner=82 - Philips CU1216L
 tuner=83 - NXP TDA18271
 tuner=84 - Sony BTF-Pxn01Z
 tuner=85 - Philips FQ1236 MK5
 tuner=86 - Tena TNF5337 MFD
+tuner=87 - Xceive 4000 tuner
+tuner=88 - Xceive 5000C tuner
diff --git a/Documentation/video4linux/fimc.txt b/Documentation/video4linux/fimc.txt
new file mode 100644 (file)
index 0000000..eb04970
--- /dev/null
@@ -0,0 +1,178 @@
+Samsung S5P/EXYNOS4 FIMC driver
+
+Copyright (C) 2012 Samsung Electronics Co., Ltd.
+---------------------------------------------------------------------------
+
+The FIMC (Fully Interactive Mobile Camera) device available in Samsung
+SoC Application Processors is an integrated camera host interface, color
+space converter, image resizer and rotator.  It's also capable of capturing
+data from LCD controller (FIMD) through the SoC internal writeback data
+path.  There are multiple FIMC instances in the SoCs (up to 4), having
+slightly different capabilities, like pixel alignment constraints, rotator
+availability, LCD writeback support, etc. The driver is located at
+drivers/media/video/s5p-fimc directory.
+
+1. Supported SoCs
+=================
+
+S5PC100 (mem-to-mem only), S5PV210, EXYNOS4210
+
+2. Supported features
+=====================
+
+ - camera parallel interface capture (ITU-R.BT601/565);
+ - camera serial interface capture (MIPI-CSI2);
+ - memory-to-memory processing (color space conversion, scaling, mirror
+   and rotation);
+ - dynamic pipeline re-configuration at runtime (re-attachment of any FIMC
+   instance to any parallel video input or any MIPI-CSI front-end);
+ - runtime PM and system wide suspend/resume
+
+Not currently supported:
+ - LCD writeback input
+ - per frame clock gating (mem-to-mem)
+
+3. Files partitioning
+=====================
+
+- media device driver
+  drivers/media/video/s5p-fimc/fimc-mdevice.[ch]
+
+ - camera capture video device driver
+  drivers/media/video/s5p-fimc/fimc-capture.c
+
+ - MIPI-CSI2 receiver subdev
+  drivers/media/video/s5p-fimc/mipi-csis.[ch]
+
+ - video post-processor (mem-to-mem)
+  drivers/media/video/s5p-fimc/fimc-core.c
+
+ - common files
+  drivers/media/video/s5p-fimc/fimc-core.h
+  drivers/media/video/s5p-fimc/fimc-reg.h
+  drivers/media/video/s5p-fimc/regs-fimc.h
+
+4. User space interfaces
+========================
+
+4.1. Media device interface
+
+The driver supports Media Controller API as defined at
+http://http://linuxtv.org/downloads/v4l-dvb-apis/media_common.html
+The media device driver name is "SAMSUNG S5P FIMC".
+
+The purpose of this interface is to allow changing assignment of FIMC instances
+to the SoC peripheral camera input at runtime and optionally to control internal
+connections of the MIPI-CSIS device(s) to the FIMC entities.
+
+The media device interface allows to configure the SoC for capturing image
+data from the sensor through more than one FIMC instance (e.g. for simultaneous
+viewfinder and still capture setup).
+Reconfiguration is done by enabling/disabling media links created by the driver
+during initialization. The internal device topology can be easily discovered
+through media entity and links enumeration.
+
+4.2. Memory-to-memory video node
+
+V4L2 memory-to-memory interface at /dev/video? device node.  This is standalone
+video device, it has no media pads. However please note the mem-to-mem and
+capture video node operation on same FIMC instance is not allowed.  The driver
+detects such cases but the applications should prevent them to avoid an
+undefined behaviour.
+
+4.3. Capture video node
+
+The driver supports V4L2 Video Capture Interface as defined at:
+http://linuxtv.org/downloads/v4l-dvb-apis/devices.html
+
+At the capture and mem-to-mem video nodes only the multi-planar API is
+supported. For more details see:
+http://linuxtv.org/downloads/v4l-dvb-apis/planar-apis.html
+
+4.4. Camera capture subdevs
+
+Each FIMC instance exports a sub-device node (/dev/v4l-subdev?), a sub-device
+node is also created per each available and enabled at the platform level
+MIPI-CSI receiver device (currently up to two).
+
+4.5. sysfs
+
+In order to enable more precise camera pipeline control through the sub-device
+API the driver creates a sysfs entry associated with "s5p-fimc-md" platform
+device. The entry path is: /sys/platform/devices/s5p-fimc-md/subdev_conf_mode.
+
+In typical use case there could be a following capture pipeline configuration:
+sensor subdev -> mipi-csi subdev -> fimc subdev -> video node
+
+When we configure these devices through sub-device API at user space, the
+configuration flow must be from left to right, and the video node is
+configured as last one.
+When we don't use sub-device user space API the whole configuration of all
+devices belonging to the pipeline is done at the video node driver.
+The sysfs entry allows to instruct the capture node driver not to configure
+the sub-devices (format, crop), to avoid resetting the subdevs' configuration
+when the last configuration steps at the video node is performed.
+
+For full sub-device control support (subdevs configured at user space before
+starting streaming):
+# echo "sub-dev" > /sys/platform/devices/s5p-fimc-md/subdev_conf_mode
+
+For V4L2 video node control only (subdevs configured internally by the host
+driver):
+# echo "vid-dev" > /sys/platform/devices/s5p-fimc-md/subdev_conf_mode
+This is a default option.
+
+5. Device mapping to video and subdev device nodes
+==================================================
+
+There are associated two video device nodes with each device instance in
+hardware - video capture and mem-to-mem and additionally a subdev node for
+more precise FIMC capture subsystem control. In addition a separate v4l2
+sub-device node is created per each MIPI-CSIS device.
+
+How to find out which /dev/video? or /dev/v4l-subdev? is assigned to which
+device?
+
+You can either grep through the kernel log to find relevant information, i.e.
+# dmesg | grep -i fimc
+(note that udev, if present, might still have rearranged the video nodes),
+
+or retrieve the information from /dev/media? with help of the media-ctl tool:
+# media-ctl -p
+
+6. Platform support
+===================
+
+The machine code (plat-s5p and arch/arm/mach-*) must select following options
+
+CONFIG_S5P_DEV_FIMC0       mandatory
+CONFIG_S5P_DEV_FIMC1  \
+CONFIG_S5P_DEV_FIMC2  |    optional
+CONFIG_S5P_DEV_FIMC3  |
+CONFIG_S5P_SETUP_FIMC /
+CONFIG_S5P_SETUP_MIPIPHY \
+CONFIG_S5P_DEV_CSIS0     | optional for MIPI-CSI interface
+CONFIG_S5P_DEV_CSIS1     /
+
+Except that, relevant s5p_device_fimc? should be registered in the machine code
+in addition to a "s5p-fimc-md" platform device to which the media device driver
+is bound.  The "s5p-fimc-md" device instance is required even if only mem-to-mem
+operation is used.
+
+The description of sensor(s) attached to FIMC/MIPI-CSIS camera inputs should be
+passed as the "s5p-fimc-md" device platform_data.  The platform data structure
+is defined in file include/media/s5p_fimc.h.
+
+7. Build
+========
+
+This driver depends on following config options:
+PLAT_S5P,
+PM_RUNTIME,
+I2C,
+REGULATOR,
+VIDEO_V4L2_SUBDEV_API,
+
+If the driver is built as a loadable kernel module (CONFIG_VIDEO_SAMSUNG_S5P_FIMC=m)
+two modules are created (in addition to the core v4l2 modules): s5p-fimc.ko and
+optional s5p-csis.ko (MIPI-CSI receiver subdev).
index f2060f0..e6c2842 100644 (file)
@@ -217,6 +217,7 @@ ov534_9             06f8:3003       Hercules Dualpix HD Weblog
 sonixj         06f8:3004       Hercules Classic Silver
 sonixj         06f8:3008       Hercules Deluxe Optical Glass
 pac7302                06f8:3009       Hercules Classic Link
+pac7302                06f8:301b       Hercules Link
 nw80x          0728:d001       AVerMedia Camguard
 spca508                0733:0110       ViewQuest VQ110
 spca501                0733:0401       Intel Create and Share
index e1d94bf..6386f8c 100644 (file)
@@ -95,7 +95,7 @@ described as 'basic' will be available.
 Capability: basic
 Architectures: all
 Type: system ioctl
-Parameters: none
+Parameters: machine type identifier (KVM_VM_*)
 Returns: a VM fd that can be used to control the new virtual machine.
 
 The new VM has no virtual cpus and no memory.  An mmap() of a VM fd
@@ -103,6 +103,11 @@ will access the virtual machine's physical address space; offset zero
 corresponds to guest physical address zero.  Use of mmap() on a VM fd
 is discouraged if userspace memory allocation (KVM_CAP_USER_MEMORY) is
 available.
+You most certainly want to use 0 as machine type.
+
+In order to create user controlled virtual machines on S390, check
+KVM_CAP_S390_UCONTROL and use the flag KVM_VM_S390_UCONTROL as
+privileged user (CAP_SYS_ADMIN).
 
 4.3 KVM_GET_MSR_INDEX_LIST
 
@@ -213,6 +218,11 @@ allocation of vcpu ids.  For example, if userspace wants
 single-threaded guest vcpus, it should make all vcpu ids be a multiple
 of the number of vcpus per vcore.
 
+For virtual cpus that have been created with S390 user controlled virtual
+machines, the resulting vcpu fd can be memory mapped at page offset
+KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of the virtual
+cpu's hardware control block.
+
 4.8 KVM_GET_DIRTY_LOG (vm ioctl)
 
 Capability: basic
@@ -1159,6 +1169,14 @@ following flags are specified:
 
 /* Depends on KVM_CAP_IOMMU */
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
+/* The following two depend on KVM_CAP_PCI_2_3 */
+#define KVM_DEV_ASSIGN_PCI_2_3         (1 << 1)
+#define KVM_DEV_ASSIGN_MASK_INTX       (1 << 2)
+
+If KVM_DEV_ASSIGN_PCI_2_3 is set, the kernel will manage legacy INTx interrupts
+via the PCI-2.3-compliant device-level mask, thus enable IRQ sharing with other
+assigned devices or host devices. KVM_DEV_ASSIGN_MASK_INTX specifies the
+guest's view on the INTx mask, see KVM_ASSIGN_SET_INTX_MASK for details.
 
 The KVM_DEV_ASSIGN_ENABLE_IOMMU flag is a mandatory option to ensure
 isolation of the device.  Usages not specifying this flag are deprecated.
@@ -1399,6 +1417,71 @@ The following flags are defined:
 If datamatch flag is set, the event will be signaled only if the written value
 to the registered address is equal to datamatch in struct kvm_ioeventfd.
 
+4.59 KVM_DIRTY_TLB
+
+Capability: KVM_CAP_SW_TLB
+Architectures: ppc
+Type: vcpu ioctl
+Parameters: struct kvm_dirty_tlb (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_dirty_tlb {
+       __u64 bitmap;
+       __u32 num_dirty;
+};
+
+This must be called whenever userspace has changed an entry in the shared
+TLB, prior to calling KVM_RUN on the associated vcpu.
+
+The "bitmap" field is the userspace address of an array.  This array
+consists of a number of bits, equal to the total number of TLB entries as
+determined by the last successful call to KVM_CONFIG_TLB, rounded up to the
+nearest multiple of 64.
+
+Each bit corresponds to one TLB entry, ordered the same as in the shared TLB
+array.
+
+The array is little-endian: the bit 0 is the least significant bit of the
+first byte, bit 8 is the least significant bit of the second byte, etc.
+This avoids any complications with differing word sizes.
+
+The "num_dirty" field is a performance hint for KVM to determine whether it
+should skip processing the bitmap and just invalidate everything.  It must
+be set to the number of set bits in the bitmap.
+
+4.60 KVM_ASSIGN_SET_INTX_MASK
+
+Capability: KVM_CAP_PCI_2_3
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_assigned_pci_dev (in)
+Returns: 0 on success, -1 on error
+
+Allows userspace to mask PCI INTx interrupts from the assigned device.  The
+kernel will not deliver INTx interrupts to the guest between setting and
+clearing of KVM_ASSIGN_SET_INTX_MASK via this interface.  This enables use of
+and emulation of PCI 2.3 INTx disable command register behavior.
+
+This may be used for both PCI 2.3 devices supporting INTx disable natively and
+older devices lacking this support. Userspace is responsible for emulating the
+read value of the INTx disable bit in the guest visible PCI command register.
+When modifying the INTx disable state, userspace should precede updating the
+physical device command register by calling this ioctl to inform the kernel of
+the new intended INTx mask state.
+
+Note that the kernel uses the device INTx disable bit to internally manage the
+device interrupt state for PCI 2.3 devices.  Reads of this register may
+therefore not match the expected value.  Writes should always use the guest
+intended INTx disable value rather than attempting to read-copy-update the
+current physical device state.  Races between user and kernel updates to the
+INTx disable bit are handled lazily in the kernel.  It's possible the device
+may generate unintended interrupts, but they will not be injected into the
+guest.
+
+See KVM_ASSIGN_DEV_IRQ for the data structure.  The target device is specified
+by assigned_dev_id.  In the flags field, only KVM_DEV_ASSIGN_MASK_INTX is
+evaluated.
+
 4.62 KVM_CREATE_SPAPR_TCE
 
 Capability: KVM_CAP_SPAPR_TCE
@@ -1491,6 +1574,101 @@ following algorithm:
 Some guests configure the LINT1 NMI input to cause a panic, aiding in
 debugging.
 
+4.65 KVM_S390_UCAS_MAP
+
+Capability: KVM_CAP_S390_UCONTROL
+Architectures: s390
+Type: vcpu ioctl
+Parameters: struct kvm_s390_ucas_mapping (in)
+Returns: 0 in case of success
+
+The parameter is defined like this:
+       struct kvm_s390_ucas_mapping {
+               __u64 user_addr;
+               __u64 vcpu_addr;
+               __u64 length;
+       };
+
+This ioctl maps the memory at "user_addr" with the length "length" to
+the vcpu's address space starting at "vcpu_addr". All parameters need to
+be alligned by 1 megabyte.
+
+4.66 KVM_S390_UCAS_UNMAP
+
+Capability: KVM_CAP_S390_UCONTROL
+Architectures: s390
+Type: vcpu ioctl
+Parameters: struct kvm_s390_ucas_mapping (in)
+Returns: 0 in case of success
+
+The parameter is defined like this:
+       struct kvm_s390_ucas_mapping {
+               __u64 user_addr;
+               __u64 vcpu_addr;
+               __u64 length;
+       };
+
+This ioctl unmaps the memory in the vcpu's address space starting at
+"vcpu_addr" with the length "length". The field "user_addr" is ignored.
+All parameters need to be alligned by 1 megabyte.
+
+4.67 KVM_S390_VCPU_FAULT
+
+Capability: KVM_CAP_S390_UCONTROL
+Architectures: s390
+Type: vcpu ioctl
+Parameters: vcpu absolute address (in)
+Returns: 0 in case of success
+
+This call creates a page table entry on the virtual cpu's address space
+(for user controlled virtual machines) or the virtual machine's address
+space (for regular virtual machines). This only works for minor faults,
+thus it's recommended to access subject memory page via the user page
+table upfront. This is useful to handle validity intercepts for user
+controlled virtual machines to fault in the virtual cpu's lowcore pages
+prior to calling the KVM_RUN ioctl.
+
+4.68 KVM_SET_ONE_REG
+
+Capability: KVM_CAP_ONE_REG
+Architectures: all
+Type: vcpu ioctl
+Parameters: struct kvm_one_reg (in)
+Returns: 0 on success, negative value on failure
+
+struct kvm_one_reg {
+       __u64 id;
+       __u64 addr;
+};
+
+Using this ioctl, a single vcpu register can be set to a specific value
+defined by user space with the passed in struct kvm_one_reg, where id
+refers to the register identifier as described below and addr is a pointer
+to a variable with the respective size. There can be architecture agnostic
+and architecture specific registers. Each have their own range of operation
+and their own constants and width. To keep track of the implemented
+registers, find a list below:
+
+  Arch  |       Register        | Width (bits)
+        |                       |
+  PPC   | KVM_REG_PPC_HIOR      | 64
+
+4.69 KVM_GET_ONE_REG
+
+Capability: KVM_CAP_ONE_REG
+Architectures: all
+Type: vcpu ioctl
+Parameters: struct kvm_one_reg (in and out)
+Returns: 0 on success, negative value on failure
+
+This ioctl allows to receive the value of a single register implemented
+in a vcpu. The register to read is indicated by the "id" field of the
+kvm_one_reg struct passed in. On success, the register value can be found
+at the memory location pointed to by "addr".
+
+The list of registers accessible using this interface is identical to the
+list in 4.64.
+
 5. The kvm_run structure
 
 Application code obtains a pointer to the kvm_run structure by
@@ -1651,6 +1829,20 @@ s390 specific.
 
 s390 specific.
 
+               /* KVM_EXIT_S390_UCONTROL */
+               struct {
+                       __u64 trans_exc_code;
+                       __u32 pgm_code;
+               } s390_ucontrol;
+
+s390 specific. A page fault has occurred for a user controlled virtual
+machine (KVM_VM_S390_UNCONTROL) on it's host page table that cannot be
+resolved by the kernel.
+The program code and the translation exception code that were placed
+in the cpu's lowcore are presented here as defined by the z Architecture
+Principles of Operation Book in the Chapter for Dynamic Address Translation
+(DAT)
+
                /* KVM_EXIT_DCR */
                struct {
                        __u32 dcrn;
@@ -1693,6 +1885,29 @@ developer registration required to access it).
                /* Fix the size of the union. */
                char padding[256];
        };
+
+       /*
+        * shared registers between kvm and userspace.
+        * kvm_valid_regs specifies the register classes set by the host
+        * kvm_dirty_regs specified the register classes dirtied by userspace
+        * struct kvm_sync_regs is architecture specific, as well as the
+        * bits for kvm_valid_regs and kvm_dirty_regs
+        */
+       __u64 kvm_valid_regs;
+       __u64 kvm_dirty_regs;
+       union {
+               struct kvm_sync_regs regs;
+               char padding[1024];
+       } s;
+
+If KVM_CAP_SYNC_REGS is defined, these fields allow userspace to access
+certain guest registers without having to call SET/GET_*REGS. Thus we can
+avoid some system call overhead if userspace has to handle the exit.
+Userspace can query the validity of the structure by checking
+kvm_valid_regs for specific bits. These bits are architecture specific
+and usually define the validity of a groups of registers. (e.g. one bit
+ for general purpose registers)
+
 };
 
 6. Capabilities that can be enabled
@@ -1741,3 +1956,45 @@ HTAB address part of SDR1 contains an HVA instead of a GPA, as PAPR keeps the
 HTAB invisible to the guest.
 
 When this capability is enabled, KVM_EXIT_PAPR_HCALL can occur.
+
+6.3 KVM_CAP_SW_TLB
+
+Architectures: ppc
+Parameters: args[0] is the address of a struct kvm_config_tlb
+Returns: 0 on success; -1 on error
+
+struct kvm_config_tlb {
+       __u64 params;
+       __u64 array;
+       __u32 mmu_type;
+       __u32 array_len;
+};
+
+Configures the virtual CPU's TLB array, establishing a shared memory area
+between userspace and KVM.  The "params" and "array" fields are userspace
+addresses of mmu-type-specific data structures.  The "array_len" field is an
+safety mechanism, and should be set to the size in bytes of the memory that
+userspace has reserved for the array.  It must be at least the size dictated
+by "mmu_type" and "params".
+
+While KVM_RUN is active, the shared region is under control of KVM.  Its
+contents are undefined, and any modification by userspace results in
+boundedly undefined behavior.
+
+On return from KVM_RUN, the shared region will reflect the current state of
+the guest's TLB.  If userspace makes any changes, it must call KVM_DIRTY_TLB
+to tell KVM which entries have been changed, prior to calling KVM_RUN again
+on this vcpu.
+
+For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
+ - The "params" field is of type "struct kvm_book3e_206_tlb_params".
+ - The "array" field points to an array of type "struct
+   kvm_book3e_206_tlb_entry".
+ - The array consists of all entries in the first TLB, followed by all
+   entries in the second TLB.
+ - Within a TLB, entries are ordered first by increasing set number.  Within a
+   set, entries are ordered by way (increasing ESEL).
+ - The hash for determining set number in TLB0 is: (MAS2 >> 12) & (num_sets - 1)
+   where "num_sets" is the tlb_sizes[] value divided by the tlb_ways[] value.
+ - The tsize field of mas1 shall be set to 4K on TLB0, even though the
+   hardware ignores this value for TLB0.
index 2b7ce19..6e7c370 100644 (file)
@@ -81,28 +81,8 @@ additional registers to the magic page. If you add fields to the magic page,
 also define a new hypercall feature to indicate that the host can give you more
 registers. Only if the host supports the additional features, make use of them.
 
-The magic page has the following layout as described in
-arch/powerpc/include/asm/kvm_para.h:
-
-struct kvm_vcpu_arch_shared {
-       __u64 scratch1;
-       __u64 scratch2;
-       __u64 scratch3;
-       __u64 critical;         /* Guest may not get interrupts if == r1 */
-       __u64 sprg0;
-       __u64 sprg1;
-       __u64 sprg2;
-       __u64 sprg3;
-       __u64 srr0;
-       __u64 srr1;
-       __u64 dar;
-       __u64 msr;
-       __u32 dsisr;
-       __u32 int_pending;      /* Tells the guest if we have an interrupt */
-};
-
-Additions to the page must only occur at the end. Struct fields are always 32
-or 64 bit aligned, depending on them being 32 or 64 bit wide respectively.
+The magic page layout is described by struct kvm_vcpu_arch_shared
+in arch/powerpc/include/asm/kvm_para.h.
 
 Magic page features
 ===================
diff --git a/Documentation/watchdog/00-INDEX b/Documentation/watchdog/00-INDEX
deleted file mode 100644 (file)
index fc9082a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-00-INDEX
-       - this file.
-convert_drivers_to_kernel_api.txt
-       - how-to for converting old watchdog drivers to the new kernel API.
-hpwdt.txt
-       - information on the HP iLO2 NMI watchdog
-pcwd-watchdog.txt
-       - documentation for Berkshire Products PC Watchdog ISA cards.
-src/
-       - directory holding watchdog related example programs.
-watchdog-api.txt
-       - description of the Linux Watchdog driver API.
-watchdog-kernel-api.txt
-       - description of the Linux WatchDog Timer Driver Core kernel API.
-watchdog-parameters.txt
-       - information on driver parameters (for drivers other than
-         the ones that have driver-specific files here)
-wdt.txt
-       - description of the Watchdog Timer Interfaces for Linux.
index be8119b..271b885 100644 (file)
@@ -59,6 +59,10 @@ Here is a overview of the functions and probably needed actions:
        WDIOC_GETTIMEOUT:
                No preparations needed
 
+       WDIOC_GETTIMELEFT:
+               It needs get_timeleft() callback to be defined. Otherwise it
+               will return EOPNOTSUPP
+
   Other IOCTLs can be served using the ioctl-callback. Note that this is mainly
   intended for porting old drivers; new drivers should not invent private IOCTLs.
   Private IOCTLs are processed first. When the callback returns with
index 9e16246..227f6cd 100644 (file)
@@ -1,6 +1,6 @@
 The Linux WatchDog Timer Driver Core kernel API.
 ===============================================
-Last reviewed: 29-Nov-2011
+Last reviewed: 16-Mar-2012
 
 Wim Van Sebroeck <wim@iguana.be>
 
@@ -77,6 +77,7 @@ struct watchdog_ops {
        int (*ping)(struct watchdog_device *);
        unsigned int (*status)(struct watchdog_device *);
        int (*set_timeout)(struct watchdog_device *, unsigned int);
+       unsigned int (*get_timeleft)(struct watchdog_device *);
        long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
 };
 
@@ -117,11 +118,13 @@ they are supported. These optional routines/operations are:
   status of the device is reported with watchdog WDIOF_* status flags/bits.
 * set_timeout: this routine checks and changes the timeout of the watchdog
   timer device. It returns 0 on success, -EINVAL for "parameter out of range"
-  and -EIO for "could not write value to the watchdog". On success the timeout
-  value of the watchdog_device will be changed to the value that was just used
-  to re-program the watchdog timer device.
+  and -EIO for "could not write value to the watchdog". On success this
+  routine should set the timeout value of the watchdog_device to the
+  achieved timeout value (which may be different from the requested one
+  because the watchdog does not necessarily has a 1 second resolution).
   (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
   watchdog's info structure).
+* get_timeleft: this routines returns the time that's left before a reset.
 * ioctl: if this routine is present then it will be called first before we do
   our own internal ioctl call handling. This routine should return -ENOIOCTLCMD
   if a command is not supported. The parameters that are passed to the ioctl
index 95eba31..f9faade 100644 (file)
@@ -163,7 +163,7 @@ M:  Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:     linux-serial@vger.kernel.org
 W:     http://serial.sourceforge.net
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 F:     drivers/tty/serial/8250*
 F:     include/linux/serial_8250.h
 
@@ -464,6 +464,7 @@ ALPHA PORT
 M:     Richard Henderson <rth@twiddle.net>
 M:     Ivan Kokshaysky <ink@jurassic.park.msu.ru>
 M:     Matt Turner <mattst88@gmail.com>
+S:     Odd Fixes
 L:     linux-alpha@vger.kernel.org
 F:     arch/alpha/
 
@@ -503,7 +504,7 @@ F:  arch/x86/include/asm/geode.h
 AMD IOMMU (AMD-VI)
 M:     Joerg Roedel <joerg.roedel@amd.com>
 L:     iommu@lists.linux-foundation.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
 S:     Supported
 F:     drivers/iommu/amd_iommu*.[ch]
 F:     include/linux/amd-iommu.h
@@ -715,6 +716,7 @@ S:  Maintained
 ARM/CLKDEV SUPPORT
 M:     Russell King <linux@arm.linux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
 F:     arch/arm/include/asm/clkdev.h
 F:     drivers/clk/clkdev.c
 
@@ -784,7 +786,6 @@ M:  Sascha Hauer <kernel@pengutronix.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 T:     git git://git.pengutronix.de/git/imx/linux-2.6.git
-F:     arch/arm/mach-mx*/
 F:     arch/arm/mach-imx/
 F:     arch/arm/plat-mxc/
 
@@ -814,9 +815,12 @@ S: Maintained
 
 ARM/H4700 (HP IPAQ HX4700) MACHINE SUPPORT
 M:     Philipp Zabel <philipp.zabel@gmail.com>
+M:     Paul Parsons <lost.distance@yahoo.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-pxa/hx4700.c
 F:     arch/arm/mach-pxa/include/mach/hx4700.h
+F:     sound/soc/pxa/hx4700.c
 
 ARM/HP JORNADA 7XX MACHINE SUPPORT
 M:     Kristoffer Ericson <kristoffer.ericson@gmail.com>
@@ -1502,7 +1506,7 @@ F:        drivers/i2c/busses/i2c-bfin-twi.c
 
 BLOCK LAYER
 M:     Jens Axboe <axboe@kernel.dk>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 S:     Maintained
 F:     block/
 
@@ -1640,7 +1644,7 @@ BTTV VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@infradead.org>
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     Documentation/video4linux/bttv/
 F:     drivers/media/video/bt8xx/bttv*
@@ -1670,7 +1674,7 @@ F:        fs/cachefiles/
 CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER
 M:     Jonathan Corbet <corbet@lwn.net>
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     Documentation/video4linux/cafe_ccic
 F:     drivers/media/video/marvell-ccic/
@@ -1841,6 +1845,7 @@ F:        include/linux/cleancache.h
 
 CLK API
 M:     Russell King <linux@arm.linux.org.uk>
+S:     Maintained
 F:     include/linux/clk.h
 
 CISCO FCOE HBA DRIVER
@@ -2036,7 +2041,7 @@ CX18 VIDEO4LINUX DRIVER
 M:     Andy Walls <awalls@md.metrocast.net>
 L:     ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:     http://linuxtv.org
 W:     http://www.ivtvdriver.org/index.php/Cx18
 S:     Maintained
@@ -2220,13 +2225,16 @@ W:      http://lanana.org/docs/device-list/index.html
 S:     Maintained
 
 DEVICE-MAPPER  (LVM)
-P:     Alasdair Kergon
+M:     Alasdair Kergon <agk@redhat.com>
+M:     dm-devel@redhat.com
 L:     dm-devel@redhat.com
 W:     http://sources.redhat.com/dm
 Q:     http://patchwork.kernel.org/project/dm-devel/list/
+T:     quilt http://people.redhat.com/agk/patches/linux/editing/
 S:     Maintained
 F:     Documentation/device-mapper/
 F:     drivers/md/dm*
+F:     drivers/md/persistent-data/
 F:     include/linux/device-mapper.h
 F:     include/linux/dm-*.h
 
@@ -2350,7 +2358,7 @@ F:        Documentation/blockdev/drbd/
 
 DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
 S:     Supported
 F:     Documentation/kobject.txt
 F:     drivers/base/
@@ -2372,7 +2380,7 @@ INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
 M:     Keith Packard <keithp@keithp.com>
 L:     intel-gfx@lists.freedesktop.org (subscribers-only)
 L:     dri-devel@lists.freedesktop.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux.git
 S:     Supported
 F:     drivers/gpu/drm/i915
 F:     include/drm/i915*
@@ -2966,8 +2974,8 @@ GFS2 FILE SYSTEM
 M:     Steven Whitehouse <swhiteho@redhat.com>
 L:     cluster-devel@redhat.com
 W:     http://sources.redhat.com/cluster/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-fixes.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw.git
 S:     Supported
 F:     Documentation/filesystems/gfs2*.txt
 F:     fs/gfs2/
@@ -3008,42 +3016,42 @@ F:      drivers/net/ethernet/aeroflex/
 GSPCA FINEPIX SUBDRIVER
 M:     Frank Zago <frank@zago.net>
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     drivers/media/video/gspca/finepix.c
 
 GSPCA GL860 SUBDRIVER
 M:     Olivier Lorin <o.lorin@laposte.net>
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     drivers/media/video/gspca/gl860/
 
 GSPCA M5602 SUBDRIVER
 M:     Erik Andren <erik.andren@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     drivers/media/video/gspca/m5602/
 
 GSPCA PAC207 SONIXB SUBDRIVER
 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-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     drivers/media/video/gspca/pac207.c
 
 GSPCA SN9C20X SUBDRIVER
 M:     Brian Johnson <brijohn@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     drivers/media/video/gspca/sn9c20x.c
 
 GSPCA T613 SUBDRIVER
 M:     Leandro Costantino <lcostantino@gmail.com>
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     drivers/media/video/gspca/t613.c
 
@@ -3051,7 +3059,7 @@ GSPCA USB WEBCAM DRIVER
 M:     Jean-Francois Moine <moinejf@free.fr>
 W:     http://moinejf.free.fr
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     drivers/media/video/gspca/
 
@@ -3337,7 +3345,7 @@ IDE SUBSYSTEM
 M:     "David S. Miller" <davem@davemloft.net>
 L:     linux-ide@vger.kernel.org
 Q:     http://patchwork.ozlabs.org/project/linux-ide/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide.git
 S:     Maintained
 F:     Documentation/ide/
 F:     drivers/ide/
@@ -3449,7 +3457,7 @@ F:        firmware/isci/
 INTEL IDLE DRIVER
 M:     Len Brown <lenb@kernel.org>
 L:     linux-pm@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-idle-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git
 S:     Supported
 F:     drivers/idle/intel_idle.c
 
@@ -3756,7 +3764,7 @@ IVTV VIDEO4LINUX DRIVER
 M:     Andy Walls <awalls@md.metrocast.net>
 L:     ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:     http://www.ivtvdriver.org
 S:     Maintained
 F:     Documentation/video4linux/*.ivtv
@@ -3852,8 +3860,8 @@ F:        fs/autofs4/
 
 KERNEL BUILD + files below scripts/ (unless maintained elsewhere)
 M:     Michal Marek <mmarek@suse.cz>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6.git for-next
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6.git rc-fixes
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git for-next
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git rc-fixes
 L:     linux-kbuild@vger.kernel.org
 S:     Maintained
 F:     Documentation/kbuild/
@@ -4233,12 +4241,14 @@ F:      Documentation/hwmon/ltc4261
 F:     drivers/hwmon/ltc4261.c
 
 LTP (Linux Test Project)
-M:     Rishikesh K Rajak <risrajak@linux.vnet.ibm.com>
-M:     Garrett Cooper <yanegomi@gmail.com>
+M:     Shubham Goyal <shubham@linux.vnet.ibm.com>
 M:     Mike Frysinger <vapier@gentoo.org>
-M:     Subrata Modak <subrata@linux.vnet.ibm.com>
+M:     Cyril Hrubis <chrubis@suse.cz>
+M:     Caspar Zhang <caspar@casparzhang.com>
+M:     Wanlong Gao <gaowanlong@cn.fujitsu.com>
 L:     ltp-list@lists.sourceforge.net (subscribers-only)
 W:     http://ltp.sourceforge.net/
+T:     git git://github.com/linux-test-project/ltp.git
 T:     git git://ltp.git.sourceforge.net/gitroot/ltp/ltp-dev
 S:     Maintained
 
@@ -4276,7 +4286,7 @@ MAC80211
 M:     Johannes Berg <johannes@sipsolutions.net>
 L:     linux-wireless@vger.kernel.org
 W:     http://linuxwireless.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
 S:     Maintained
 F:     Documentation/networking/mac80211-injection.txt
 F:     include/net/mac80211.h
@@ -4287,7 +4297,7 @@ M:        Stefano Brivio <stefano.brivio@polimi.it>
 M:     Mattias Nissler <mattias.nissler@gmx.de>
 L:     linux-wireless@vger.kernel.org
 W:     http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/PID
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
 S:     Maintained
 F:     net/mac80211/rc80211_pid*
 
@@ -4359,7 +4369,7 @@ P:        LinuxTV.org Project
 L:     linux-media@vger.kernel.org
 W:     http://linuxtv.org
 Q:     http://patchwork.kernel.org/project/linux-media/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     Documentation/dvb/
 F:     Documentation/video4linux/
@@ -4416,6 +4426,13 @@ T:       git git://git.monstr.eu/linux-2.6-microblaze.git
 S:     Supported
 F:     arch/microblaze/
 
+MICROCHANNEL ARCHITECTURE (MCA)
+M:     James Bottomley <James.Bottomley@HansenPartnership.com>
+S:     Maintained
+F:     Documentation/mca.txt
+F:     drivers/mca/
+F:     include/linux/mca*
+
 MICROTEK X6 SCANNER
 M:     Oliver Neukum <oliver@neukum.name>
 S:     Maintained
@@ -4431,14 +4448,6 @@ S:       Supported
 F:     Documentation/mips/
 F:     arch/mips/
 
-MISCELLANEOUS MCA-SUPPORT
-M:     James Bottomley <James.Bottomley@HansenPartnership.com>
-S:     Maintained
-F:     Documentation/ia64/mca.txt
-F:     Documentation/mca.txt
-F:     drivers/mca/
-F:     include/linux/mca*
-
 MODULE SUPPORT
 M:     Rusty Russell <rusty@rustcorp.com.au>
 S:     Maintained
@@ -4646,7 +4655,7 @@ M:        James Morris <jmorris@namei.org>
 M:     Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
 M:     Patrick McHardy <kaber@trash.net>
 L:     netdev@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
 S:     Maintained
 F:     net/ipv4/
 F:     net/ipv6/
@@ -4662,7 +4671,7 @@ NETWORKING [WIRELESS]
 M:     "John W. Linville" <linville@tuxdriver.com>
 L:     linux-wireless@vger.kernel.org
 Q:     http://patchwork.kernel.org/project/linux-wireless/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git
 S:     Maintained
 F:     net/mac80211/
 F:     net/rfkill/
@@ -4675,8 +4684,8 @@ F:        drivers/net/wireless/
 NETWORKING DRIVERS
 L:     netdev@vger.kernel.org
 W:     http://www.linuxfoundation.org/en/Net
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
 S:     Odd Fixes
 F:     drivers/net/
 F:     include/linux/if_*
@@ -4892,7 +4901,7 @@ F:        drivers/char/pcmcia/cm4040_cs.*
 OMNIVISION OV7670 SENSOR DRIVER
 M:     Jonathan Corbet <corbet@lwn.net>
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     drivers/media/video/ov7670.c
 
@@ -5067,7 +5076,7 @@ M:        Helge Deller <deller@gmx.de>
 L:     linux-parisc@vger.kernel.org
 W:     http://www.parisc-linux.org/
 Q:     http://patchwork.kernel.org/project/linux-parisc/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/parisc-2.6.git
 S:     Maintained
 F:     arch/parisc/
 F:     drivers/parisc/
@@ -5120,17 +5129,17 @@ F:      Documentation/PCI/pci-error-recovery.txt
 F:     Documentation/powerpc/eeh-pci-error-recovery.txt
 
 PCI SUBSYSTEM
-M:     Jesse Barnes <jbarnes@virtuousgeek.org>
+M:     Bjorn Helgaas <bhelgaas@google.com>
 L:     linux-pci@vger.kernel.org
 Q:     http://patchwork.kernel.org/project/linux-pci/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci.git
 S:     Supported
 F:     Documentation/PCI/
 F:     drivers/pci/
 F:     include/linux/pci*
 
 PCI HOTPLUG
-M:     Jesse Barnes <jbarnes@virtuousgeek.org>
+M:     Bjorn Helgaas <bhelgaas@google.com>
 L:     linux-pci@vger.kernel.org
 S:     Supported
 F:     drivers/pci/hotplug
@@ -5408,7 +5417,7 @@ M:        Mike Isely <isely@pobox.com>
 L:     pvrusb2@isely.net       (subscribers-only)
 L:     linux-media@vger.kernel.org
 W:     http://www.isely.net/pvrusb2/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     Documentation/video4linux/README.pvrusb2
 F:     drivers/media/video/pvrusb2/
@@ -5416,7 +5425,7 @@ F:        drivers/media/video/pvrusb2/
 PXA2xx/PXA3xx SUPPORT
 M:     Eric Miao <eric.y.miao@gmail.com>
 M:     Russell King <linux@arm.linux.org.uk>
-M:     Haojian Zhuang <haojian.zhuang@marvell.com>
+M:     Haojian Zhuang <haojian.zhuang@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://github.com/hzhuang1/linux.git
 T:     git git://git.linaro.org/people/ycmiao/pxa-linux.git
@@ -5431,7 +5440,7 @@ F:        sound/soc/pxa
 
 MMP SUPPORT
 M:     Eric Miao <eric.y.miao@gmail.com>
-M:     Haojian Zhuang <haojian.zhuang@marvell.com>
+M:     Haojian Zhuang <haojian.zhuang@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://github.com/hzhuang1/linux.git
 T:     git git://git.linaro.org/people/ycmiao/pxa-linux.git
@@ -5574,7 +5583,7 @@ RCUTORTURE MODULE
 M:     Josh Triplett <josh@freedesktop.org>
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
 S:     Supported
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
 F:     Documentation/RCU/torture.txt
 F:     kernel/rcutorture.c
 
@@ -5599,7 +5608,7 @@ M:        Dipankar Sarma <dipankar@in.ibm.com>
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
 W:     http://www.rdrop.com/users/paulmck/rclock/
 S:     Supported
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
 F:     Documentation/RCU/
 F:     include/linux/rcu*
 F:     include/linux/srcu*
@@ -5628,6 +5637,13 @@ S:       Supported
 F:     drivers/base/regmap/
 F:     include/linux/regmap.h
 
+REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM
+M:     Ohad Ben-Cohen <ohad@wizery.com>
+S:     Maintained
+F:     drivers/remoteproc/
+F:     Documentation/remoteproc.txt
+F:     include/linux/remoteproc.txt
+
 RFKILL
 M:     Johannes Berg <johannes@sipsolutions.net>
 L:     linux-wireless@vger.kernel.org
@@ -5753,13 +5769,19 @@ F:      drivers/mmc/host/s3cmci.*
 SAA7146 VIDEO4LINUX-2 DRIVER
 M:     Michael Hunold <michael@mihu.de>
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:     http://www.mihu.de/linux/saa7146
 S:     Maintained
 F:     drivers/media/common/saa7146*
 F:     drivers/media/video/*7146*
 F:     include/media/*7146*
 
+SAMSUNG LAPTOP DRIVER
+M:     Corentin Chary <corentincj@iksaif.net>
+L:     platform-driver-x86@vger.kernel.org
+S:     Maintained
+F:     drivers/platform/x86/samsung-laptop.c
+
 SAMSUNG AUDIO (ASoC) DRIVERS
 M:     Sangbeom Kim <sbkim73@samsung.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -6058,7 +6080,8 @@ F:        arch/arm/mach-s3c2410/bast-irq.c
 TI DAVINCI MACHINE SUPPORT
 M:     Sekhar Nori <nsekhar@ti.com>
 M:     Kevin Hilman <khilman@ti.com>
-L:     davinci-linux-open-source@linux.davincidsp.com (subscribers-only)
+L:     davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers)
+T:     git git://gitorious.org/linux-davinci/linux-davinci.git
 Q:     http://patchwork.kernel.org/project/linux-davinci/list/
 S:     Supported
 F:     arch/arm/mach-davinci
@@ -6176,7 +6199,7 @@ F:        arch/ia64/sn/
 SOC-CAMERA V4L2 SUBSYSTEM
 M:     Guennadi Liakhovetski <g.liakhovetski@gmx.de>
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 S:     Maintained
 F:     include/media/v4l2*
 F:     drivers/media/video/v4l2*
@@ -6248,8 +6271,8 @@ SPARC + UltraSPARC (sparc/sparc64)
 M:     "David S. Miller" <davem@davemloft.net>
 L:     sparclinux@vger.kernel.org
 Q:     http://patchwork.ozlabs.org/project/sparclinux/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git
 S:     Maintained
 F:     arch/sparc/
 F:     drivers/sbus/
@@ -6257,8 +6280,8 @@ F:        drivers/sbus/
 SPARC SERIAL DRIVERS
 M:     "David S. Miller" <davem@davemloft.net>
 L:     sparclinux@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next.git
 S:     Maintained
 F:     include/linux/sunserialcore.h
 F:     drivers/tty/serial/suncore.c
@@ -6563,7 +6586,7 @@ L:        linux-scsi@vger.kernel.org
 L:     target-devel@vger.kernel.org
 L:     http://groups.google.com/group/linux-iscsi-target-dev
 W:     http://www.linux-iscsi.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core.git master
 S:     Supported
 F:     drivers/target/
 F:     include/target/
@@ -6601,9 +6624,10 @@ F:       include/linux/if_team.h
 TEGRA SUPPORT
 M:     Colin Cross <ccross@android.com>
 M:     Olof Johansson <olof@lixom.net>
-M:     Stephen Warren <swarren@nvidia.com>
+M:     Stephen Warren <swarren@wwwdotorg.org>
 L:     linux-tegra@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/olof/tegra.git
+Q:     http://patchwork.ozlabs.org/project/linux-tegra/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra.git
 S:     Supported
 F:     arch/arm/mach-tegra
 
@@ -6754,7 +6778,7 @@ K:        ^Subject:.*(?i)trivial
 TTY LAYER
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 S:     Supported
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 F:     drivers/tty/
 F:     drivers/tty/serial/serial_core.c
 F:     include/linux/serial_core.h
@@ -6922,7 +6946,7 @@ USB ET61X[12]51 DRIVER
 M:     Luca Risolia <luca.risolia@studio.unibo.it>
 L:     linux-usb@vger.kernel.org
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:     http://www.linux-projects.org
 S:     Maintained
 F:     drivers/media/video/et61x251/
@@ -7078,7 +7102,7 @@ USB SN9C1xx DRIVER
 M:     Luca Risolia <luca.risolia@studio.unibo.it>
 L:     linux-usb@vger.kernel.org
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:     http://www.linux-projects.org
 S:     Maintained
 F:     Documentation/video4linux/sn9c102.txt
@@ -7088,7 +7112,7 @@ USB SUBSYSTEM
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:     linux-usb@vger.kernel.org
 W:     http://www.linux-usb.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
 S:     Supported
 F:     Documentation/usb/
 F:     drivers/net/usb/
@@ -7114,7 +7138,7 @@ USB VIDEO CLASS
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 L:     linux-uvc-devel@lists.berlios.de (subscribers-only)
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:     http://www.ideasonboard.org/uvc/
 S:     Maintained
 F:     drivers/media/video/uvc/
@@ -7123,7 +7147,7 @@ USB W996[87]CF DRIVER
 M:     Luca Risolia <luca.risolia@studio.unibo.it>
 L:     linux-usb@vger.kernel.org
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:     http://www.linux-projects.org
 S:     Maintained
 F:     Documentation/video4linux/w9968cf.txt
@@ -7152,7 +7176,7 @@ USB ZR364XX DRIVER
 M:     Antoine Jacquet <royale@zerezo.com>
 L:     linux-usb@vger.kernel.org
 L:     linux-media@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
 W:     http://royale.zerezo.com/zr364xx/
 S:     Maintained
 F:     Documentation/video4linux/zr364xx.txt
@@ -7302,7 +7326,7 @@ M:        Liam Girdwood <lrg@ti.com>
 M:     Mark Brown <broonie@opensource.wolfsonmicro.com>
 W:     http://opensource.wolfsonmicro.com/node/15
 W:     http://www.slimlogic.co.uk/?p=48
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lrg/regulator.git
 S:     Supported
 F:     drivers/regulator/
 F:     include/linux/regulator/
index 5b448a7..a6f14f6 100644 (file)
@@ -120,6 +120,9 @@ config HAVE_KRETPROBES
 
 config HAVE_OPTPROBES
        bool
+
+config HAVE_NMI_WATCHDOG
+       bool
 #
 # An arch should select this if it provides all these things:
 #
index 72db984..cbeb361 100644 (file)
 #define MADV_HUGEPAGE  14              /* Worth backing with hugepages */
 #define MADV_NOHUGEPAGE        15              /* Not worth backing with hugepages */
 
+#define MADV_DONTDUMP   16             /* Explicity exclude from the core dump,
+                                          overrides the coredump filter bits */
+#define MADV_DODUMP    17              /* Clear the MADV_NODUMP flag */
+
 /* compatibility flags */
 #define MAP_FILE       0
 
index 28d0497..d01afb7 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/dma-mapping.h>
 #include <asm/scatterlist.h>
 #include <asm/machvec.h>
+#include <asm-generic/pci-bridge.h>
 
 /*
  * The following structure is used to manage multiple PCI busses.
@@ -99,12 +100,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
        return channel ? 15 : 14;
 }
 
-extern void pcibios_resource_to_bus(struct pci_dev *, struct pci_bus_region *,
-                                   struct resource *);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                                   struct pci_bus_region *region);
-
 #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
 
 static inline int pci_proc_domain(struct pci_bus *bus)
index 8c723c1..1a62963 100644 (file)
@@ -43,12 +43,10 @@ const char *const pci_mem_names[] = {
 
 const char pci_hae0_name[] = "HAE0";
 
-/* Indicate whether we respect the PCI setup left by console. */
 /*
- * Make this long-lived  so that we know when shutting down
- * whether we probed only or not.
+ * If PCI_PROBE_ONLY in pci_flags is set, we don't change any PCI resource
+ * assignments.
  */
-int pci_probe_only;
 
 /*
  * The PCI controller list.
@@ -215,7 +213,7 @@ pdev_save_srm_config(struct pci_dev *dev)
        struct pdev_srm_saved_conf *tmp;
        static int printed = 0;
 
-       if (!alpha_using_srm || pci_probe_only)
+       if (!alpha_using_srm || pci_has_flag(PCI_PROBE_ONLY))
                return;
 
        if (!printed) {
@@ -242,7 +240,7 @@ pci_restore_srm_config(void)
        struct pdev_srm_saved_conf *tmp;
 
        /* No need to restore if probed only. */
-       if (pci_probe_only)
+       if (pci_has_flag(PCI_PROBE_ONLY))
                return;
 
        /* Restore SRM config. */
@@ -253,46 +251,17 @@ pci_restore_srm_config(void)
 #endif
 
 void __devinit
-pcibios_fixup_resource(struct resource *res, struct resource *root)
-{
-       res->start += root->start;
-       res->end += root->start;
-}
-
-void __devinit
-pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
-{
-       /* Update device resources.  */
-       struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
-       int i;
-
-       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-               if (!dev->resource[i].start)
-                       continue;
-               if (dev->resource[i].flags & IORESOURCE_IO)
-                       pcibios_fixup_resource(&dev->resource[i],
-                                              hose->io_space);
-               else if (dev->resource[i].flags & IORESOURCE_MEM)
-                       pcibios_fixup_resource(&dev->resource[i],
-                                              hose->mem_space);
-       }
-}
-
-void __devinit
 pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev = bus->self;
 
-       if (pci_probe_only && dev &&
+       if (pci_has_flag(PCI_PROBE_ONLY) && dev &&
                   (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
                pci_read_bridge_bases(bus);
-               pcibios_fixup_device_resources(dev, bus);
        } 
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                pdev_save_srm_config(dev);
-               if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
-                       pcibios_fixup_device_resources(dev, bus);
        }
 }
 
@@ -302,42 +271,6 @@ pcibios_update_irq(struct pci_dev *dev, int irq)
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                        struct resource *res)
-{
-       struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
-       unsigned long offset = 0;
-
-       if (res->flags & IORESOURCE_IO)
-               offset = hose->io_space->start;
-       else if (res->flags & IORESOURCE_MEM)
-               offset = hose->mem_space->start;
-
-       region->start = res->start - offset;
-       region->end = res->end - offset;
-}
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                            struct pci_bus_region *region)
-{
-       struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
-       unsigned long offset = 0;
-
-       if (res->flags & IORESOURCE_IO)
-               offset = hose->io_space->start;
-       else if (res->flags & IORESOURCE_MEM)
-               offset = hose->mem_space->start;
-
-       res->start = region->start + offset;
-       res->end = region->end + offset;
-}
-
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-#endif
-
 int
 pcibios_enable_device(struct pci_dev *dev, int mask)
 {
@@ -374,7 +307,8 @@ pcibios_claim_one_bus(struct pci_bus *b)
 
                        if (r->parent || !r->start || !r->flags)
                                continue;
-                       if (pci_probe_only || (r->flags & IORESOURCE_PCI_FIXED))
+                       if (pci_has_flag(PCI_PROBE_ONLY) ||
+                           (r->flags & IORESOURCE_PCI_FIXED))
                                pci_claim_resource(dev, i);
                }
        }
@@ -416,8 +350,10 @@ common_init_pci(void)
                        hose->mem_space->end = end;
 
                INIT_LIST_HEAD(&resources);
-               pci_add_resource(&resources, hose->io_space);
-               pci_add_resource(&resources, hose->mem_space);
+               pci_add_resource_offset(&resources, hose->io_space,
+                                       hose->io_space->start);
+               pci_add_resource_offset(&resources, hose->mem_space,
+                                       hose->mem_space->start);
 
                bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops,
                                        hose, &resources);
index 85457b2..2b0ac42 100644 (file)
@@ -173,9 +173,6 @@ extern void pci_restore_srm_config(void);
 extern struct pci_controller *hose_head, **hose_tail;
 extern struct pci_controller *pci_isa_hose;
 
-/* Indicate that we trust the console to configure things properly.  */
-extern int pci_probe_only;
-
 extern unsigned long alpha_agpgart_size;
 
 extern void common_init_pci(void);
index e8b4f6f..14a4b6a 100644 (file)
@@ -383,7 +383,8 @@ marvel_init_pci(void)
 
        marvel_register_error_handlers();
 
-       pci_probe_only = 1;
+       /* Indicate that we trust the console to configure things properly */
+       pci_set_flags(PCI_PROBE_ONLY);
        common_init_pci();
        locate_and_init_vga(NULL);
 
index 9de928c..2533db2 100644 (file)
@@ -330,7 +330,8 @@ titan_init_pci(void)
         */
        titan_late_init();
  
-       pci_probe_only = 1;
+       /* Indicate that we trust the console to configure things properly */
+       pci_set_flags(PCI_PROBE_ONLY);
        common_init_pci();
        SMC669_Init(0);
        locate_and_init_vga(NULL);
index dfb0312..5098564 100644 (file)
@@ -186,6 +186,9 @@ config GENERIC_ISA_DMA
 config FIQ
        bool
 
+config NEED_RET_TO_USER
+       bool
+
 config ARCH_MTD_XIP
        bool
 
@@ -322,9 +325,10 @@ config ARCH_AT91
        select ARCH_REQUIRE_GPIOLIB
        select HAVE_CLK
        select CLKDEV_LOOKUP
+       select IRQ_DOMAIN
        help
          This enables support for systems based on the Atmel AT91RM9200,
-         AT91SAM9 and AT91CAP9 processors.
+         AT91SAM9 processors.
 
 config ARCH_BCMRING
        bool "Broadcom BCMRING"
@@ -479,6 +483,7 @@ config ARCH_IOP13XX
        select ARCH_SUPPORTS_MSI
        select VMSPLIT_1G
        select NEED_MACH_MEMORY_H
+       select NEED_RET_TO_USER
        help
          Support for Intel's IOP13XX (XScale) family of processors.
 
@@ -486,6 +491,7 @@ config ARCH_IOP32X
        bool "IOP32x-based"
        depends on MMU
        select CPU_XSCALE
+       select NEED_RET_TO_USER
        select PLAT_IOP
        select PCI
        select ARCH_REQUIRE_GPIOLIB
@@ -497,6 +503,7 @@ config ARCH_IOP33X
        bool "IOP33x-based"
        depends on MMU
        select CPU_XSCALE
+       select NEED_RET_TO_USER
        select PLAT_IOP
        select PCI
        select ARCH_REQUIRE_GPIOLIB
@@ -731,7 +738,6 @@ config ARCH_RPC
        bool "RiscPC"
        select ARCH_ACORN
        select FIQ
-       select TIMER_ACORN
        select ARCH_MAY_HAVE_PC_FDC
        select HAVE_PATA_PLATFORM
        select ISA_DMA_API
@@ -754,31 +760,31 @@ config ARCH_SA1100
        select ARCH_HAS_CPUFREQ
        select CPU_FREQ
        select GENERIC_CLOCKEVENTS
-       select HAVE_CLK
+       select CLKDEV_LOOKUP
        select HAVE_SCHED_CLOCK
        select TICK_ONESHOT
        select ARCH_REQUIRE_GPIOLIB
        select HAVE_IDE
        select NEED_MACH_MEMORY_H
+       select SPARSE_IRQ
        help
          Support for StrongARM 11x0 based boards.
 
-config ARCH_S3C2410
-       bool "Samsung S3C2410, S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443, S3C2450"
+config ARCH_S3C24XX
+       bool "Samsung S3C24XX SoCs"
        select GENERIC_GPIO
        select ARCH_HAS_CPUFREQ
        select HAVE_CLK
        select CLKDEV_LOOKUP
        select ARCH_USES_GETTIMEOFFSET
        select HAVE_S3C2410_I2C if I2C
+       select HAVE_S3C_RTC if RTC_CLASS
+       select HAVE_S3C2410_WATCHDOG if WATCHDOG
        help
-         Samsung S3C2410X CPU based systems, such as the Simtec Electronics
-         BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
-         the Samsung SMDK2410 development board (and derivatives).
-
-         Note, the S3C2416 and the S3C2450 are so close that they even share
-         the same SoC ID code. This means that there is no separate machine
-         directory (no arch/arm/mach-s3c2450) as the S3C2416 was first.
+         Samsung S3C2410, S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443
+         and S3C2450 SoCs based systems, such as the Simtec Electronics BAST
+         (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or the
+         Samsung SMDK2410 development board (and derivatives).
 
 config ARCH_S3C64XX
        bool "Samsung S3C64XX"
@@ -901,6 +907,7 @@ config ARCH_U300
 
 config ARCH_U8500
        bool "ST-Ericsson U8500 Series"
+       depends on MMU
        select CPU_V7
        select ARM_AMBA
        select GENERIC_CLOCKEVENTS
@@ -1066,12 +1073,10 @@ source "arch/arm/plat-s5p/Kconfig"
 
 source "arch/arm/plat-spear/Kconfig"
 
-if ARCH_S3C2410
-source "arch/arm/mach-s3c2410/Kconfig"
+source "arch/arm/mach-s3c24xx/Kconfig"
+if ARCH_S3C24XX
 source "arch/arm/mach-s3c2412/Kconfig"
-source "arch/arm/mach-s3c2416/Kconfig"
 source "arch/arm/mach-s3c2440/Kconfig"
-source "arch/arm/mach-s3c2443/Kconfig"
 endif
 
 if ARCH_S3C64XX
@@ -1127,6 +1132,7 @@ config PLAT_VERSATILE
 config ARM_TIMER_SP804
        bool
        select CLKSRC_MMIO
+       select HAVE_SCHED_CLOCK
 
 source arch/arm/mm/Kconfig
 
@@ -1577,7 +1583,8 @@ config LOCAL_TIMERS
 config ARCH_NR_GPIO
        int
        default 1024 if ARCH_SHMOBILE || ARCH_TEGRA
-       default 350 if ARCH_U8500
+       default 355 if ARCH_U8500
+       default 264 if MACH_H4700
        default 0
        help
          Maximum number of GPIOs in the system.
@@ -1588,7 +1595,7 @@ source kernel/Kconfig.preempt
 
 config HZ
        int
-       default 200 if ARCH_EBSA110 || ARCH_S3C2410 || ARCH_S5P64X0 || \
+       default 200 if ARCH_EBSA110 || ARCH_S3C24XX || ARCH_S5P64X0 || \
                ARCH_S5PV210 || ARCH_EXYNOS4
        default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
        default AT91_TIMER_HZ if ARCH_AT91
@@ -2114,7 +2121,7 @@ config CPU_FREQ_S3C
 
 config CPU_FREQ_S3C24XX
        bool "CPUfreq driver for Samsung S3C24XX series CPUs (EXPERIMENTAL)"
-       depends on ARCH_S3C2410 && CPU_FREQ && EXPERIMENTAL
+       depends on ARCH_S3C24XX && CPU_FREQ && EXPERIMENTAL
        select CPU_FREQ_S3C
        help
          This enables the CPUfreq driver for the Samsung S3C24XX family
index e0d236d..66ca801 100644 (file)
@@ -81,47 +81,14 @@ choice
        prompt "Kernel low-level debugging port"
        depends on DEBUG_LL
 
-       config DEBUG_LL_UART_NONE
-               bool "No low-level debugging UART"
-               help
-                 Say Y here if your platform doesn't provide a UART option
-                 below. This relies on your platform choosing the right UART
-                 definition internally in order for low-level debugging to
-                 work.
-
-       config DEBUG_ICEDCC
-               bool "Kernel low-level debugging via EmbeddedICE DCC channel"
-               help
-                 Say Y here if you want the debug print routines to direct
-                 their output to the EmbeddedICE macrocell's DCC channel using
-                 co-processor 14. This is known to work on the ARM9 style ICE
-                 channel and on the XScale with the PEEDI.
-
-                 Note that the system will appear to hang during boot if there
-                 is nothing connected to read from the DCC.
-
        config AT91_DEBUG_LL_DBGU0
                bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10 and 9rl"
                depends on HAVE_AT91_DBGU0
 
        config AT91_DEBUG_LL_DBGU1
-               bool "Kernel low-level debugging on 9263, 9g45 and cap9"
+               bool "Kernel low-level debugging on 9263 and 9g45"
                depends on HAVE_AT91_DBGU1
 
-       config DEBUG_FOOTBRIDGE_COM1
-               bool "Kernel low-level debugging messages via footbridge 8250 at PCI COM1"
-               depends on FOOTBRIDGE
-               help
-                 Say Y here if you want the debug print routines to direct
-                 their output to the 8250 at PCI COM1.
-
-       config DEBUG_DC21285_PORT
-               bool "Kernel low-level debugging messages via footbridge serial port"
-               depends on FOOTBRIDGE
-               help
-                 Say Y here if you want the debug print routines to direct
-                 their output to the serial port in the DC21285 (Footbridge).
-
        config DEBUG_CLPS711X_UART1
                bool "Kernel low-level debugging messages via UART1"
                depends on ARCH_CLPS711X
@@ -136,6 +103,20 @@ choice
                  Say Y here if you want the debug print routines to direct
                  their output to the second serial port on these devices.
 
+       config DEBUG_DC21285_PORT
+               bool "Kernel low-level debugging messages via footbridge serial port"
+               depends on FOOTBRIDGE
+               help
+                 Say Y here if you want the debug print routines to direct
+                 their output to the serial port in the DC21285 (Footbridge).
+
+       config DEBUG_FOOTBRIDGE_COM1
+               bool "Kernel low-level debugging messages via footbridge 8250 at PCI COM1"
+               depends on FOOTBRIDGE
+               help
+                 Say Y here if you want the debug print routines to direct
+                 their output to the 8250 at PCI COM1.
+
        config DEBUG_HIGHBANK_UART
                bool "Kernel low-level debugging messages via Highbank UART"
                depends on ARCH_HIGHBANK
@@ -199,45 +180,49 @@ choice
                  Say Y here if you want kernel low-level debugging support
                  on i.MX50 or i.MX53.
 
-       config DEBUG_IMX6Q_UART
-               bool "i.MX6Q Debug UART"
+       config DEBUG_IMX6Q_UART4
+               bool "i.MX6Q Debug UART4"
                depends on SOC_IMX6Q
                help
                  Say Y here if you want kernel low-level debugging support
-                 on i.MX6Q.
+                 on i.MX6Q UART4.
 
-       config DEBUG_S3C_UART0
-               depends on PLAT_SAMSUNG
-               bool "Use S3C UART 0 for low-level debug"
+       config DEBUG_MSM_UART1
+               bool "Kernel low-level debugging messages via MSM UART1"
+               depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
                help
                  Say Y here if you want the debug print routines to direct
-                 their output to UART 0. The port must have been initialised
-                 by the boot-loader before use.
-
-                 The uncompressor code port configuration is now handled
-                 by CONFIG_S3C_LOWLEVEL_UART_PORT.
+                 their output to the first serial port on MSM devices.
 
-       config DEBUG_S3C_UART1
-               depends on PLAT_SAMSUNG
-               bool "Use S3C UART 1 for low-level debug"
+       config DEBUG_MSM_UART2
+               bool "Kernel low-level debugging messages via MSM UART2"
+               depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
                help
                  Say Y here if you want the debug print routines to direct
-                 their output to UART 1. The port must have been initialised
-                 by the boot-loader before use.
+                 their output to the second serial port on MSM devices.
 
-                 The uncompressor code port configuration is now handled
-                 by CONFIG_S3C_LOWLEVEL_UART_PORT.
+       config DEBUG_MSM_UART3
+               bool "Kernel low-level debugging messages via MSM UART3"
+               depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
+               help
+                 Say Y here if you want the debug print routines to direct
+                 their output to the third serial port on MSM devices.
 
-       config DEBUG_S3C_UART2
-               depends on PLAT_SAMSUNG
-               bool "Use S3C UART 2 for low-level debug"
+       config DEBUG_MSM8660_UART
+               bool "Kernel low-level debugging messages via MSM 8660 UART"
+               depends on ARCH_MSM8X60
+               select MSM_HAS_DEBUG_UART_HS
                help
                  Say Y here if you want the debug print routines to direct
-                 their output to UART 2. The port must have been initialised
-                 by the boot-loader before use.
+                 their output to the serial port on MSM 8660 devices.
 
-                 The uncompressor code port configuration is now handled
-                 by CONFIG_S3C_LOWLEVEL_UART_PORT.
+       config DEBUG_MSM8960_UART
+               bool "Kernel low-level debugging messages via MSM 8960 UART"
+               depends on ARCH_MSM8960
+               select MSM_HAS_DEBUG_UART_HS
+               help
+                 Say Y here if you want the debug print routines to direct
+                 their output to the serial port on MSM 8960 devices.
 
        config DEBUG_REALVIEW_STD_PORT
                bool "RealView Default UART"
@@ -255,42 +240,57 @@ choice
                  their output to the standard serial port on the RealView
                  PB1176 platform.
 
-       config DEBUG_MSM_UART1
-               bool "Kernel low-level debugging messages via MSM UART1"
-               depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
+       config DEBUG_S3C_UART0
+               depends on PLAT_SAMSUNG
+               bool "Use S3C UART 0 for low-level debug"
                help
                  Say Y here if you want the debug print routines to direct
-                 their output to the first serial port on MSM devices.
+                 their output to UART 0. The port must have been initialised
+                 by the boot-loader before use.
 
-       config DEBUG_MSM_UART2
-               bool "Kernel low-level debugging messages via MSM UART2"
-               depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
+                 The uncompressor code port configuration is now handled
+                 by CONFIG_S3C_LOWLEVEL_UART_PORT.
+
+       config DEBUG_S3C_UART1
+               depends on PLAT_SAMSUNG
+               bool "Use S3C UART 1 for low-level debug"
                help
                  Say Y here if you want the debug print routines to direct
-                 their output to the second serial port on MSM devices.
+                 their output to UART 1. The port must have been initialised
+                 by the boot-loader before use.
 
-       config DEBUG_MSM_UART3
-               bool "Kernel low-level debugging messages via MSM UART3"
-               depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50
+                 The uncompressor code port configuration is now handled
+                 by CONFIG_S3C_LOWLEVEL_UART_PORT.
+
+       config DEBUG_S3C_UART2
+               depends on PLAT_SAMSUNG
+               bool "Use S3C UART 2 for low-level debug"
                help
                  Say Y here if you want the debug print routines to direct
-                 their output to the third serial port on MSM devices.
+                 their output to UART 2. The port must have been initialised
+                 by the boot-loader before use.
 
-       config DEBUG_MSM8660_UART
-               bool "Kernel low-level debugging messages via MSM 8660 UART"
-               depends on ARCH_MSM8X60
-               select MSM_HAS_DEBUG_UART_HS
+                 The uncompressor code port configuration is now handled
+                 by CONFIG_S3C_LOWLEVEL_UART_PORT.
+
+       config DEBUG_LL_UART_NONE
+               bool "No low-level debugging UART"
                help
-                 Say Y here if you want the debug print routines to direct
-                 their output to the serial port on MSM 8660 devices.
+                 Say Y here if your platform doesn't provide a UART option
+                 below. This relies on your platform choosing the right UART
+                 definition internally in order for low-level debugging to
+                 work.
 
-       config DEBUG_MSM8960_UART
-               bool "Kernel low-level debugging messages via MSM 8960 UART"
-               depends on ARCH_MSM8960
-               select MSM_HAS_DEBUG_UART_HS
+       config DEBUG_ICEDCC
+               bool "Kernel low-level debugging via EmbeddedICE DCC channel"
                help
                  Say Y here if you want the debug print routines to direct
-                 their output to the serial port on MSM 8960 devices.
+                 their output to the EmbeddedICE macrocell's DCC channel using
+                 co-processor 14. This is known to work on the ARM9 style ICE
+                 channel and on the XScale with the PEEDI.
+
+                 Note that the system will appear to hang during boot if there
+                 is nothing connected to read from the DCC.
 
 endchoice
 
index 1683bfb..dcb088e 100644 (file)
@@ -174,12 +174,13 @@ machine-$(CONFIG_ARCH_PRIMA2)             := prima2
 machine-$(CONFIG_ARCH_PXA)             := pxa
 machine-$(CONFIG_ARCH_REALVIEW)                := realview
 machine-$(CONFIG_ARCH_RPC)             := rpc
-machine-$(CONFIG_ARCH_S3C2410)         := s3c2410 s3c2412 s3c2416 s3c2440 s3c2443
+machine-$(CONFIG_ARCH_S3C24XX)         := s3c24xx s3c2412 s3c2440
 machine-$(CONFIG_ARCH_S3C64XX)         := s3c64xx
 machine-$(CONFIG_ARCH_S5P64X0)         := s5p64x0
 machine-$(CONFIG_ARCH_S5PC100)         := s5pc100
 machine-$(CONFIG_ARCH_S5PV210)         := s5pv210
 machine-$(CONFIG_ARCH_EXYNOS4)         := exynos
+machine-$(CONFIG_ARCH_EXYNOS5)         := exynos
 machine-$(CONFIG_ARCH_SA1100)          := sa1100
 machine-$(CONFIG_ARCH_SHARK)           := shark
 machine-$(CONFIG_ARCH_SHMOBILE)        := shmobile
index c5d6025..5f6045f 100644 (file)
@@ -58,7 +58,7 @@
                add     \rb, \rb, #0x00010000   @ Ser1
 #endif
                .endm
-#elif defined(CONFIG_ARCH_S3C2410)
+#elif defined(CONFIG_ARCH_S3C24XX)
                .macro loadsp, rb, tmp
                mov     \rb, #0x50000000
                add     \rb, \rb, #0x4000 * CONFIG_S3C_LOWLEVEL_UART_PORT
diff --git a/arch/arm/boot/dts/am3517_mt_ventoux.dts b/arch/arm/boot/dts/am3517_mt_ventoux.dts
new file mode 100644 (file)
index 0000000..5eb26d7
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 Ilya Yanok, EmCraft Systems
+ *
+ * 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.
+ */
+/dts-v1/;
+
+/include/ "omap3.dtsi"
+
+/ {
+       model = "TeeJet Mt.Ventoux";
+       compatible = "teejet,mt_ventoux", "ti,omap3";
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x10000000>; /* 256 MB */
+       };
+
+       /* AM35xx doesn't have IVA */
+       soc {
+               iva {
+                       status = "disabled";
+               };
+       };
+};
index 07603b8..92f3662 100644 (file)
                serial4 = &usart3;
                serial5 = &usart4;
                serial6 = &usart5;
+               gpio0 = &pioA;
+               gpio1 = &pioB;
+               gpio2 = &pioC;
+               tcb0 = &tcb0;
+               tcb1 = &tcb1;
        };
        cpus {
                cpu@0 {
                        ranges;
 
                        aic: interrupt-controller@fffff000 {
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                                compatible = "atmel,at91rm9200-aic";
                                interrupt-controller;
                                interrupt-parent;
                                reg = <0xfffff000 0x200>;
                        };
 
+                       ramc0: ramc@ffffea00 {
+                               compatible = "atmel,at91sam9260-sdramc";
+                               reg = <0xffffea00 0x200>;
+                       };
+
+                       pmc: pmc@fffffc00 {
+                               compatible = "atmel,at91rm9200-pmc";
+                               reg = <0xfffffc00 0x100>;
+                       };
+
+                       rstc@fffffd00 {
+                               compatible = "atmel,at91sam9260-rstc";
+                               reg = <0xfffffd00 0x10>;
+                       };
+
+                       shdwc@fffffd10 {
+                               compatible = "atmel,at91sam9260-shdwc";
+                               reg = <0xfffffd10 0x10>;
+                       };
+
+                       pit: timer@fffffd30 {
+                               compatible = "atmel,at91sam9260-pit";
+                               reg = <0xfffffd30 0xf>;
+                               interrupts = <1 4>;
+                       };
+
+                       tcb0: timer@fffa0000 {
+                               compatible = "atmel,at91rm9200-tcb";
+                               reg = <0xfffa0000 0x100>;
+                               interrupts = <17 4 18 4 19 4>;
+                       };
+
+                       tcb1: timer@fffdc000 {
+                               compatible = "atmel,at91rm9200-tcb";
+                               reg = <0xfffdc000 0x100>;
+                               interrupts = <26 4 27 4 28 4>;
+                       };
+
+                       pioA: gpio@fffff400 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff400 0x100>;
+                               interrupts = <2 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioB: gpio@fffff600 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff600 0x100>;
+                               interrupts = <3 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioC: gpio@fffff800 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff800 0x100>;
+                               interrupts = <4 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
                        dbgu: serial@fffff200 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffff200 0x200>;
-                               interrupts = <1>;
+                               interrupts = <1 4>;
                                status = "disabled";
                        };
 
                        usart0: serial@fffb0000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffb0000 0x200>;
-                               interrupts = <6>;
+                               interrupts = <6 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart1: serial@fffb4000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffb4000 0x200>;
-                               interrupts = <7>;
+                               interrupts = <7 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart2: serial@fffb8000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffb8000 0x200>;
-                               interrupts = <8>;
+                               interrupts = <8 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart3: serial@fffd0000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffd0000 0x200>;
-                               interrupts = <23>;
+                               interrupts = <23 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart4: serial@fffd4000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffd4000 0x200>;
-                               interrupts = <24>;
+                               interrupts = <24 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart5: serial@fffd8000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffd8000 0x200>;
-                               interrupts = <25>;
+                               interrupts = <25 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        macb0: ethernet@fffc4000 {
                                compatible = "cdns,at32ap7000-macb", "cdns,macb";
                                reg = <0xfffc4000 0x100>;
-                               interrupts = <21>;
+                               interrupts = <21 4>;
+                               status = "disabled";
+                       };
+
+                       usb1: gadget@fffa4000 {
+                               compatible = "atmel,at91rm9200-udc";
+                               reg = <0xfffa4000 0x4000>;
+                               interrupts = <10 4>;
                                status = "disabled";
                        };
                };
+
+               nand0: nand@40000000 {
+                       compatible = "atmel,at91rm9200-nand";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0x40000000 0x10000000
+                              0xffffe800 0x200
+                             >;
+                       atmel,nand-addr-offset = <21>;
+                       atmel,nand-cmd-offset = <22>;
+                       gpios = <&pioC 13 0
+                                &pioC 14 0
+                                0
+                               >;
+                       status = "disabled";
+               };
+
+               usb0: ohci@00500000 {
+                       compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+                       reg = <0x00500000 0x100000>;
+                       interrupts = <20 4>;
+                       status = "disabled";
+               };
+       };
+
+       i2c@0 {
+               compatible = "i2c-gpio";
+               gpios = <&pioA 23 0 /* sda */
+                        &pioA 24 0 /* scl */
+                       >;
+               i2c-gpio,sda-open-drain;
+               i2c-gpio,scl-open-drain;
+               i2c-gpio,delay-us = <2>;        /* ~100 kHz */
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
        };
 };
diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
new file mode 100644 (file)
index 0000000..ac0dc00
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * at91sam9g25ek.dts - Device Tree file for AT91SAM9G25-EK board
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9x5.dtsi"
+/include/ "at91sam9x5cm.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9G25-EK";
+       compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+
+       chosen {
+               bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+       };
+
+       ahb {
+               apb {
+                       dbgu: serial@fffff200 {
+                               status = "okay";
+                       };
+
+                       usart0: serial@f801c000 {
+                               status = "okay";
+                       };
+
+                       macb0: ethernet@f802c000 {
+                               phy-mode = "rmii";
+                               status = "okay";
+                       };
+               };
+
+               usb0: ohci@00600000 {
+                       status = "okay";
+                       num-ports = <2>;
+                       atmel,vbus-gpio = <&pioD 19 0
+                                          &pioD 20 0
+                                         >;
+               };
+
+               usb1: ehci@00700000 {
+                       status = "okay";
+               };
+       };
+};
index fffa005..3d0c32f 100644 (file)
                serial2 = &usart1;
                serial3 = &usart2;
                serial4 = &usart3;
+               gpio0 = &pioA;
+               gpio1 = &pioB;
+               gpio2 = &pioC;
+               gpio3 = &pioD;
+               gpio4 = &pioE;
+               tcb0 = &tcb0;
+               tcb1 = &tcb1;
        };
        cpus {
                cpu@0 {
                        ranges;
 
                        aic: interrupt-controller@fffff000 {
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                                compatible = "atmel,at91rm9200-aic";
                                interrupt-controller;
                                interrupt-parent;
                                reg = <0xfffff000 0x200>;
                        };
 
+                       ramc0: ramc@ffffe400 {
+                               compatible = "atmel,at91sam9g45-ddramc";
+                               reg = <0xffffe400 0x200
+                                      0xffffe600 0x200>;
+                       };
+
+                       pmc: pmc@fffffc00 {
+                               compatible = "atmel,at91rm9200-pmc";
+                               reg = <0xfffffc00 0x100>;
+                       };
+
+                       rstc@fffffd00 {
+                               compatible = "atmel,at91sam9g45-rstc";
+                               reg = <0xfffffd00 0x10>;
+                       };
+
+                       pit: timer@fffffd30 {
+                               compatible = "atmel,at91sam9260-pit";
+                               reg = <0xfffffd30 0xf>;
+                               interrupts = <1 4>;
+                       };
+
+
+                       shdwc@fffffd10 {
+                               compatible = "atmel,at91sam9rl-shdwc";
+                               reg = <0xfffffd10 0x10>;
+                       };
+
+                       tcb0: timer@fff7c000 {
+                               compatible = "atmel,at91rm9200-tcb";
+                               reg = <0xfff7c000 0x100>;
+                               interrupts = <18 4>;
+                       };
+
+                       tcb1: timer@fffd4000 {
+                               compatible = "atmel,at91rm9200-tcb";
+                               reg = <0xfffd4000 0x100>;
+                               interrupts = <18 4>;
+                       };
+
                        dma: dma-controller@ffffec00 {
                                compatible = "atmel,at91sam9g45-dma";
                                reg = <0xffffec00 0x200>;
-                               interrupts = <21>;
+                               interrupts = <21 4>;
+                       };
+
+                       pioA: gpio@fffff200 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff200 0x100>;
+                               interrupts = <2 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioB: gpio@fffff400 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff400 0x100>;
+                               interrupts = <3 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioC: gpio@fffff600 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff600 0x100>;
+                               interrupts = <4 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioD: gpio@fffff800 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffff800 0x100>;
+                               interrupts = <5 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioE: gpio@fffffa00 {
+                               compatible = "atmel,at91rm9200-gpio";
+                               reg = <0xfffffa00 0x100>;
+                               interrupts = <5 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
                        };
 
                        dbgu: serial@ffffee00 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xffffee00 0x200>;
-                               interrupts = <1>;
+                               interrupts = <1 4>;
                                status = "disabled";
                        };
 
                        usart0: serial@fff8c000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff8c000 0x200>;
-                               interrupts = <7>;
+                               interrupts = <7 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart1: serial@fff90000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff90000 0x200>;
-                               interrupts = <8>;
+                               interrupts = <8 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart2: serial@fff94000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff94000 0x200>;
-                               interrupts = <9>;
+                               interrupts = <9 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart3: serial@fff98000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff98000 0x200>;
-                               interrupts = <10>;
+                               interrupts = <10 4>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        macb0: ethernet@fffbc000 {
                                compatible = "cdns,at32ap7000-macb", "cdns,macb";
                                reg = <0xfffbc000 0x100>;
-                               interrupts = <25>;
+                               interrupts = <25 4>;
                                status = "disabled";
                        };
                };
+
+               nand0: nand@40000000 {
+                       compatible = "atmel,at91rm9200-nand";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0x40000000 0x10000000
+                              0xffffe200 0x200
+                             >;
+                       atmel,nand-addr-offset = <21>;
+                       atmel,nand-cmd-offset = <22>;
+                       gpios = <&pioC 8 0
+                                &pioC 14 0
+                                0
+                               >;
+                       status = "disabled";
+               };
+
+               usb0: ohci@00700000 {
+                       compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+                       reg = <0x00700000 0x100000>;
+                       interrupts = <22 4>;
+                       status = "disabled";
+               };
+
+               usb1: ehci@00800000 {
+                       compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+                       reg = <0x00800000 0x100000>;
+                       interrupts = <22 4>;
+                       status = "disabled";
+               };
+       };
+
+       i2c@0 {
+               compatible = "i2c-gpio";
+               gpios = <&pioA 20 0 /* sda */
+                        &pioA 21 0 /* scl */
+                       >;
+               i2c-gpio,sda-open-drain;
+               i2c-gpio,scl-open-drain;
+               i2c-gpio,delay-us = <5>;        /* ~100 kHz */
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
        };
 };
index a387e77..c4c8ae4 100644 (file)
        compatible = "atmel,at91sam9m10g45ek", "atmel,at91sam9g45", "atmel,at91sam9";
 
        chosen {
-               bootargs = "mem=64M console=ttyS0,115200 mtdparts=atmel_nand:4M(bootstrap/uboot/kernel)ro,60M(rootfs),-(data) root=/dev/mtdblock1 rw rootfstype=jffs2";
+               bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2";
        };
 
        memory@70000000 {
                reg = <0x70000000 0x4000000>;
        };
 
+       clocks {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               main_clock: clock@0 {
+                       compatible = "atmel,osc", "fixed-clock";
+                       clock-frequency = <12000000>;
+               };
+       };
+
        ahb {
                apb {
                        dbgu: serial@ffffee00 {
                                status = "okay";
                        };
                };
+
+               nand0: nand@40000000 {
+                       nand-bus-width = <8>;
+                       nand-ecc-mode = "soft";
+                       nand-on-flash-bbt;
+                       status = "okay";
+
+                       boot@0 {
+                               label = "bootstrap/uboot/kernel";
+                               reg = <0x0 0x400000>;
+                       };
+
+                       rootfs@400000 {
+                               label = "rootfs";
+                               reg = <0x400000 0x3C00000>;
+                       };
+
+                       data@4000000 {
+                               label = "data";
+                               reg = <0x4000000 0xC000000>;
+                       };
+               };
+
+               usb0: ohci@00700000 {
+                       status = "okay";
+                       num-ports = <2>;
+                       atmel,vbus-gpio = <&pioD 1 0
+                                          &pioD 3 0>;
+               };
+
+               usb1: ehci@00800000 {
+                       status = "okay";
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               d8 {
+                       label = "d8";
+                       gpios = <&pioD 30 0>;
+                       linux,default-trigger = "heartbeat";
+               };
+
+               d6 {
+                       label = "d6";
+                       gpios = <&pioD 0 1>;
+                       linux,default-trigger = "nand-disk";
+               };
+
+               d7 {
+                       label = "d7";
+                       gpios = <&pioD 31 1>;
+                       linux,default-trigger = "mmc0";
+               };
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               left_click {
+                       label = "left_click";
+                       gpios = <&pioB 6 1>;
+                       linux,code = <272>;
+                       gpio-key,wakeup;
+               };
+
+               right_click {
+                       label = "right_click";
+                       gpios = <&pioB 7 1>;
+                       linux,code = <273>;
+                       gpio-key,wakeup;
+               };
+
+               left {
+                       label = "Joystick Left";
+                       gpios = <&pioB 14 1>;
+                       linux,code = <105>;
+               };
+
+               right {
+                       label = "Joystick Right";
+                       gpios = <&pioB 15 1>;
+                       linux,code = <106>;
+               };
+
+               up {
+                       label = "Joystick Up";
+                       gpios = <&pioB 16 1>;
+                       linux,code = <103>;
+               };
+
+               down {
+                       label = "Joystick Down";
+                       gpios = <&pioB 17 1>;
+                       linux,code = <108>;
+               };
+
+               enter {
+                       label = "Joystick Press";
+                       gpios = <&pioB 18 1>;
+                       linux,code = <28>;
+               };
        };
 };
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
new file mode 100644 (file)
index 0000000..c111001
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * at91sam9x5.dtsi - Device Tree Include file for AT91SAM9x5 family SoC
+ *                   applies to AT91SAM9G15, AT91SAM9G25, AT91SAM9G35,
+ *                   AT91SAM9X25, AT91SAM9X35 SoC
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+       model = "Atmel AT91SAM9x5 family SoC";
+       compatible = "atmel,at91sam9x5";
+       interrupt-parent = <&aic>;
+
+       aliases {
+               serial0 = &dbgu;
+               serial1 = &usart0;
+               serial2 = &usart1;
+               serial3 = &usart2;
+               gpio0 = &pioA;
+               gpio1 = &pioB;
+               gpio2 = &pioC;
+               gpio3 = &pioD;
+               tcb0 = &tcb0;
+               tcb1 = &tcb1;
+       };
+       cpus {
+               cpu@0 {
+                       compatible = "arm,arm926ejs";
+               };
+       };
+
+       memory@20000000 {
+               reg = <0x20000000 0x10000000>;
+       };
+
+       ahb {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               apb {
+                       compatible = "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       aic: interrupt-controller@fffff000 {
+                               #interrupt-cells = <2>;
+                               compatible = "atmel,at91rm9200-aic";
+                               interrupt-controller;
+                               interrupt-parent;
+                               reg = <0xfffff000 0x200>;
+                       };
+
+                       ramc0: ramc@ffffe800 {
+                               compatible = "atmel,at91sam9g45-ddramc";
+                               reg = <0xffffe800 0x200>;
+                       };
+
+                       pmc: pmc@fffffc00 {
+                               compatible = "atmel,at91rm9200-pmc";
+                               reg = <0xfffffc00 0x100>;
+                       };
+
+                       rstc@fffffe00 {
+                               compatible = "atmel,at91sam9g45-rstc";
+                               reg = <0xfffffe00 0x10>;
+                       };
+
+                       shdwc@fffffe10 {
+                               compatible = "atmel,at91sam9x5-shdwc";
+                               reg = <0xfffffe10 0x10>;
+                       };
+
+                       pit: timer@fffffe30 {
+                               compatible = "atmel,at91sam9260-pit";
+                               reg = <0xfffffe30 0xf>;
+                               interrupts = <1 4>;
+                       };
+
+                       tcb0: timer@f8008000 {
+                               compatible = "atmel,at91sam9x5-tcb";
+                               reg = <0xf8008000 0x100>;
+                               interrupts = <17 4>;
+                       };
+
+                       tcb1: timer@f800c000 {
+                               compatible = "atmel,at91sam9x5-tcb";
+                               reg = <0xf800c000 0x100>;
+                               interrupts = <17 4>;
+                       };
+
+                       dma0: dma-controller@ffffec00 {
+                               compatible = "atmel,at91sam9g45-dma";
+                               reg = <0xffffec00 0x200>;
+                               interrupts = <20 4>;
+                       };
+
+                       dma1: dma-controller@ffffee00 {
+                               compatible = "atmel,at91sam9g45-dma";
+                               reg = <0xffffee00 0x200>;
+                               interrupts = <21 4>;
+                       };
+
+                       pioA: gpio@fffff400 {
+                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                               reg = <0xfffff400 0x100>;
+                               interrupts = <2 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioB: gpio@fffff600 {
+                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                               reg = <0xfffff600 0x100>;
+                               interrupts = <2 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioC: gpio@fffff800 {
+                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                               reg = <0xfffff800 0x100>;
+                               interrupts = <3 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       pioD: gpio@fffffa00 {
+                               compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+                               reg = <0xfffffa00 0x100>;
+                               interrupts = <3 4>;
+                               #gpio-cells = <2>;
+                               gpio-controller;
+                               interrupt-controller;
+                       };
+
+                       dbgu: serial@fffff200 {
+                               compatible = "atmel,at91sam9260-usart";
+                               reg = <0xfffff200 0x200>;
+                               interrupts = <1 4>;
+                               status = "disabled";
+                       };
+
+                       usart0: serial@f801c000 {
+                               compatible = "atmel,at91sam9260-usart";
+                               reg = <0xf801c000 0x200>;
+                               interrupts = <5 4>;
+                               atmel,use-dma-rx;
+                               atmel,use-dma-tx;
+                               status = "disabled";
+                       };
+
+                       usart1: serial@f8020000 {
+                               compatible = "atmel,at91sam9260-usart";
+                               reg = <0xf8020000 0x200>;
+                               interrupts = <6 4>;
+                               atmel,use-dma-rx;
+                               atmel,use-dma-tx;
+                               status = "disabled";
+                       };
+
+                       usart2: serial@f8024000 {
+                               compatible = "atmel,at91sam9260-usart";
+                               reg = <0xf8024000 0x200>;
+                               interrupts = <7 4>;
+                               atmel,use-dma-rx;
+                               atmel,use-dma-tx;
+                               status = "disabled";
+                       };
+
+                       macb0: ethernet@f802c000 {
+                               compatible = "cdns,at32ap7000-macb", "cdns,macb";
+                               reg = <0xf802c000 0x100>;
+                               interrupts = <24 4>;
+                               status = "disabled";
+                       };
+
+                       macb1: ethernet@f8030000 {
+                               compatible = "cdns,at32ap7000-macb", "cdns,macb";
+                               reg = <0xf8030000 0x100>;
+                               interrupts = <27 4>;
+                               status = "disabled";
+                       };
+               };
+
+               nand0: nand@40000000 {
+                       compatible = "atmel,at91rm9200-nand";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0x40000000 0x10000000
+                             >;
+                       atmel,nand-addr-offset = <21>;
+                       atmel,nand-cmd-offset = <22>;
+                       gpios = <&pioC 8 0
+                                &pioC 14 0
+                                0
+                               >;
+                       status = "disabled";
+               };
+
+               usb0: ohci@00600000 {
+                       compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+                       reg = <0x00600000 0x100000>;
+                       interrupts = <22 4>;
+                       status = "disabled";
+               };
+
+               usb1: ehci@00700000 {
+                       compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+                       reg = <0x00700000 0x100000>;
+                       interrupts = <22 4>;
+                       status = "disabled";
+               };
+       };
+
+       i2c@0 {
+               compatible = "i2c-gpio";
+               gpios = <&pioA 30 0 /* sda */
+                        &pioA 31 0 /* scl */
+                       >;
+               i2c-gpio,sda-open-drain;
+               i2c-gpio,scl-open-drain;
+               i2c-gpio,delay-us = <2>;        /* ~100 kHz */
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       i2c@1 {
+               compatible = "i2c-gpio";
+               gpios = <&pioC 0 0 /* sda */
+                        &pioC 1 0 /* scl */
+                       >;
+               i2c-gpio,sda-open-drain;
+               i2c-gpio,scl-open-drain;
+               i2c-gpio,delay-us = <2>;        /* ~100 kHz */
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+
+       i2c@2 {
+               compatible = "i2c-gpio";
+               gpios = <&pioB 4 0 /* sda */
+                        &pioB 5 0 /* scl */
+                       >;
+               i2c-gpio,sda-open-drain;
+               i2c-gpio,scl-open-drain;
+               i2c-gpio,delay-us = <2>;        /* ~100 kHz */
+               #address-cells = <1>;
+               #size-cells = <0>;
+               status = "disabled";
+       };
+};
diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi
new file mode 100644 (file)
index 0000000..67936f8
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * at91sam9x5cm.dtsi - Device Tree Include file for AT91SAM9x5 CPU Module
+ *
+ *  Copyright (C) 2012 Atmel,
+ *                2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/ {
+       memory@20000000 {
+               reg = <0x20000000 0x8000000>;
+       };
+
+       clocks {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               main_clock: clock@0 {
+                       compatible = "atmel,osc", "fixed-clock";
+                       clock-frequency = <12000000>;
+               };
+       };
+
+       ahb {
+               nand0: nand@40000000 {
+                       nand-bus-width = <8>;
+                       nand-ecc-mode = "soft";
+                       nand-on-flash-bbt;
+                       status = "okay";
+
+                       at91bootstrap@0 {
+                               label = "at91bootstrap";
+                               reg = <0x0 0x40000>;
+                       };
+
+                       uboot@40000 {
+                               label = "u-boot";
+                               reg = <0x40000 0x80000>;
+                       };
+
+                       ubootenv@c0000 {
+                               label = "U-Boot Env";
+                               reg = <0xc0000 0x140000>;
+                       };
+
+                       kernel@200000 {
+                               label = "kernel";
+                               reg = <0x200000 0x600000>;
+                       };
+
+                       rootfs@800000 {
+                               label = "rootfs";
+                               reg = <0x800000 0x1f800000>;
+                       };
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               pb18 {
+                       label = "pb18";
+                       gpios = <&pioB 18 1>;
+                       linux,default-trigger = "heartbeat";
+               };
+
+               pd21 {
+                       label = "pd21";
+                       gpios = <&pioD 21 0>;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/db8500.dtsi b/arch/arm/boot/dts/db8500.dtsi
new file mode 100644 (file)
index 0000000..d73dce6
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2012 Linaro Ltd
+ *
+ * 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/ "skeleton.dtsi"
+
+/ {
+       soc-u9500 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "stericsson,db8500";
+               interrupt-parent = <&intc>;
+               ranges;
+
+               intc: interrupt-controller@a0411000 {
+                       compatible = "arm,cortex-a9-gic";
+                       #interrupt-cells = <3>;
+                       #address-cells = <1>;
+                       interrupt-controller;
+                       interrupt-parent;
+                       reg = <0xa0411000 0x1000>,
+                             <0xa0410100 0x100>;
+               };
+
+               L2: l2-cache {
+                       compatible = "arm,pl310-cache";
+                       reg = <0xa0412000 0x1000>;
+                       interrupts = <0 13 4>;
+                       cache-unified;
+                       cache-level = <2>;
+               };
+
+               pmu {
+                       compatible = "arm,cortex-a9-pmu";
+                       interrupts = <0 7 0x4>;
+               };
+
+               timer@a0410600 {
+                       compatible = "arm,cortex-a9-twd-timer";
+                       reg = <0xa0410600 0x20>;
+                       interrupts = <1 13 0x304>;
+               };
+
+               rtc@80154000 {
+                       compatible = "stericsson,db8500-rtc";
+                       reg = <0x80154000 0x1000>;
+                       interrupts = <0 18 0x4>;
+               };
+
+               gpio0: gpio@8012e000 {
+                       compatible = "stericsson,db8500-gpio",
+                               "stmicroelectronics,nomadik-gpio";
+                       reg =  <0x8012e000 0x80>;
+                       interrupts = <0 119 0x4>;
+                       supports-sleepmode;
+                       gpio-controller;
+               };
+
+               gpio1: gpio@8012e080 {
+                       compatible = "stericsson,db8500-gpio",
+                               "stmicroelectronics,nomadik-gpio";
+                       reg =  <0x8012e080 0x80>;
+                       interrupts = <0 120 0x4>;
+                       supports-sleepmode;
+                       gpio-controller;
+               };
+
+               gpio2: gpio@8000e000 {
+                       compatible = "stericsson,db8500-gpio",
+                               "stmicroelectronics,nomadik-gpio";
+                       reg =  <0x8000e000 0x80>;
+                       interrupts = <0 121 0x4>;
+                       supports-sleepmode;
+                       gpio-controller;
+               };
+
+               gpio3: gpio@8000e080 {
+                       compatible = "stericsson,db8500-gpio",
+                               "stmicroelectronics,nomadik-gpio";
+                       reg =  <0x8000e080 0x80>;
+                       interrupts = <0 122 0x4>;
+                       supports-sleepmode;
+                       gpio-controller;
+               };
+
+               gpio4: gpio@8000e100 {
+                       compatible = "stericsson,db8500-gpio",
+                               "stmicroelectronics,nomadik-gpio";
+                       reg =  <0x8000e100 0x80>;
+                       interrupts = <0 123 0x4>;
+                       supports-sleepmode;
+                       gpio-controller;
+               };
+
+               gpio5: gpio@8000e180 {
+                       compatible = "stericsson,db8500-gpio",
+                               "stmicroelectronics,nomadik-gpio";
+                       reg =  <0x8000e180 0x80>;
+                       interrupts = <0 124 0x4>;
+                       supports-sleepmode;
+                       gpio-controller;
+               };
+
+               gpio6: gpio@8011e000 {
+                       compatible = "stericsson,db8500-gpio",
+                               "stmicroelectronics,nomadik-gpio";
+                       reg =  <0x8011e000 0x80>;
+                       interrupts = <0 125 0x4>;
+                       supports-sleepmode;
+                       gpio-controller;
+               };
+
+               gpio7: gpio@8011e080 {
+                       compatible = "stericsson,db8500-gpio",
+                               "stmicroelectronics,nomadik-gpio";
+                       reg =  <0x8011e080 0x80>;
+                       interrupts = <0 126 0x4>;
+                       supports-sleepmode;
+                       gpio-controller;
+               };
+
+               gpio8: gpio@a03fe000 {
+                       compatible = "stericsson,db8500-gpio",
+                               "stmicroelectronics,nomadik-gpio";
+                       reg =  <0xa03fe000 0x80>;
+                       interrupts = <0 127 0x4>;
+                       supports-sleepmode;
+                       gpio-controller;
+               };
+
+               usb@a03e0000 {
+                       compatible = "stericsson,db8500-musb",
+                               "mentor,musb";
+                       reg = <0xa03e0000 0x10000>;
+                       interrupts = <0 23 0x4>;
+               };
+
+               dma-controller@801C0000 {
+                       compatible = "stericsson,db8500-dma40",
+                                       "stericsson,dma40";
+                       reg = <0x801C0000 0x1000 0x40010000 0x800>;
+                       interrupts = <0 25 0x4>;
+               };
+
+               prcmu@80157000 {
+                       compatible = "stericsson,db8500-prcmu";
+                       reg = <0x80157000 0x1000>;
+                       interrupts = <46 47>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       ab8500@5 {
+                               compatible = "stericsson,ab8500";
+                               reg = <5>; /* mailbox 5 is i2c */
+                               interrupts = <0 40 0x4>;
+                       };
+               };
+
+               i2c@80004000 {
+                       compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+                       reg = <0x80004000 0x1000>;
+                       interrupts = <0 21 0x4>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               i2c@80122000 {
+                       compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+                       reg = <0x80122000 0x1000>;
+                       interrupts = <0 22 0x4>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               i2c@80128000 {
+                       compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+                       reg = <0x80128000 0x1000>;
+                       interrupts = <0 55 0x4>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               i2c@80110000 {
+                       compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+                       reg = <0x80110000 0x1000>;
+                       interrupts = <0 12 0x4>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               i2c@8012a000 {
+                       compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+                       reg = <0x8012a000 0x1000>;
+                       interrupts = <0 51 0x4>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               ssp@80002000 {
+                       compatible = "arm,pl022", "arm,primecell";
+                       reg = <80002000 0x1000>;
+                       interrupts = <0 14 0x4>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+
+                       // Add one of these for each child device
+                       cs-gpios = <&gpio0 31 &gpio4 14 &gpio4 16 &gpio6 22 &gpio7 0>;
+
+               };
+
+               uart@80120000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x80120000 0x1000>;
+                       interrupts = <0 11 0x4>;
+                       status = "disabled";
+               };
+               uart@80121000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x80121000 0x1000>;
+                       interrupts = <0 19 0x4>;
+                       status = "disabled";
+               };
+               uart@80007000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x80007000 0x1000>;
+                       interrupts = <0 26 0x4>;
+                       status = "disabled";
+               };
+
+               sdi@80126000 {
+                       compatible = "arm,pl18x", "arm,primecell";
+                       reg = <0x80126000 0x1000>;
+                       interrupts = <0 60 0x4>;
+                       status = "disabled";
+               };
+               sdi@80118000 {
+                       compatible = "arm,pl18x", "arm,primecell";
+                       reg = <0x80118000 0x1000>;
+                       interrupts = <0 50 0x4>;
+                       status = "disabled";
+               };
+               sdi@80005000 {
+                       compatible = "arm,pl18x", "arm,primecell";
+                       reg = <0x80005000 0x1000>;
+                       interrupts = <0 41 0x4>;
+                       status = "disabled";
+               };
+               sdi@80119000 {
+                       compatible = "arm,pl18x", "arm,primecell";
+                       reg = <0x80119000 0x1000>;
+                       interrupts = <0 59 0x4>;
+                       status = "disabled";
+               };
+               sdi@80114000 {
+                       compatible = "arm,pl18x", "arm,primecell";
+                       reg = <0x80114000 0x1000>;
+                       interrupts = <0 99 0x4>;
+                       status = "disabled";
+               };
+               sdi@80008000 {
+                       compatible = "arm,pl18x", "arm,primecell";
+                       reg = <0x80114000 0x1000>;
+                       interrupts = <0 100 0x4>;
+                       status = "disabled";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
new file mode 100644 (file)
index 0000000..399d17b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * SAMSUNG SMDK5250 board device tree source
+ *
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/dts-v1/;
+/include/ "exynos5250.dtsi"
+
+/ {
+       model = "SAMSUNG SMDK5250 board based on EXYNOS5250";
+       compatible = "samsung,smdk5250", "samsung,exynos5250";
+
+       memory {
+               reg = <0x40000000 0x80000000>;
+       };
+
+       chosen {
+               bootargs = "root=/dev/ram0 rw ramdisk=8192 console=ttySAC1,115200";
+       };
+};
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
new file mode 100644 (file)
index 0000000..dfc4335
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * SAMSUNG EXYNOS5250 SoC device tree source
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * SAMSUNG EXYNOS5250 SoC device nodes are listed in this file.
+ * EXYNOS5250 based board files can include this file and provide
+ * values for board specfic bindings.
+ *
+ * Note: This file does not include device nodes for all the controllers in
+ * EXYNOS5250 SoC. As device tree coverage for EXYNOS5250 increases,
+ * additional nodes can be added to this file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/include/ "skeleton.dtsi"
+
+/ {
+       compatible = "samsung,exynos5250";
+       interrupt-parent = <&gic>;
+
+       gic:interrupt-controller@10490000 {
+               compatible = "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               interrupt-controller;
+               reg = <0x10490000 0x1000>, <0x10480000 0x100>;
+       };
+
+       watchdog {
+               compatible = "samsung,s3c2410-wdt";
+               reg = <0x101D0000 0x100>;
+               interrupts = <0 42 0>;
+       };
+
+       rtc {
+               compatible = "samsung,s3c6410-rtc";
+               reg = <0x101E0000 0x100>;
+               interrupts = <0 43 0>, <0 44 0>;
+       };
+
+       sdhci@12200000 {
+               compatible = "samsung,exynos4210-sdhci";
+               reg = <0x12200000 0x100>;
+               interrupts = <0 75 0>;
+       };
+
+       sdhci@12210000 {
+               compatible = "samsung,exynos4210-sdhci";
+               reg = <0x12210000 0x100>;
+               interrupts = <0 76 0>;
+       };
+
+       sdhci@12220000 {
+               compatible = "samsung,exynos4210-sdhci";
+               reg = <0x12220000 0x100>;
+               interrupts = <0 77 0>;
+       };
+
+       sdhci@12230000 {
+               compatible = "samsung,exynos4210-sdhci";
+               reg = <0x12230000 0x100>;
+               interrupts = <0 78 0>;
+       };
+
+       serial@12C00000 {
+               compatible = "samsung,exynos4210-uart";
+               reg = <0x12C00000 0x100>;
+               interrupts = <0 51 0>;
+       };
+
+       serial@12C10000 {
+               compatible = "samsung,exynos4210-uart";
+               reg = <0x12C10000 0x100>;
+               interrupts = <0 52 0>;
+       };
+
+       serial@12C20000 {
+               compatible = "samsung,exynos4210-uart";
+               reg = <0x12C20000 0x100>;
+               interrupts = <0 53 0>;
+       };
+
+       serial@12C30000 {
+               compatible = "samsung,exynos4210-uart";
+               reg = <0x12C30000 0x100>;
+               interrupts = <0 54 0>;
+       };
+
+       i2c@12C60000 {
+               compatible = "samsung,s3c2440-i2c";
+               reg = <0x12C60000 0x100>;
+               interrupts = <0 56 0>;
+       };
+
+       i2c@12C70000 {
+               compatible = "samsung,s3c2440-i2c";
+               reg = <0x12C70000 0x100>;
+               interrupts = <0 57 0>;
+       };
+
+       i2c@12C80000 {
+               compatible = "samsung,s3c2440-i2c";
+               reg = <0x12C80000 0x100>;
+               interrupts = <0 58 0>;
+       };
+
+       i2c@12C90000 {
+               compatible = "samsung,s3c2440-i2c";
+               reg = <0x12C90000 0x100>;
+               interrupts = <0 59 0>;
+       };
+
+       i2c@12CA0000 {
+               compatible = "samsung,s3c2440-i2c";
+               reg = <0x12CA0000 0x100>;
+               interrupts = <0 60 0>;
+       };
+
+       i2c@12CB0000 {
+               compatible = "samsung,s3c2440-i2c";
+               reg = <0x12CB0000 0x100>;
+               interrupts = <0 61 0>;
+       };
+
+       i2c@12CC0000 {
+               compatible = "samsung,s3c2440-i2c";
+               reg = <0x12CC0000 0x100>;
+               interrupts = <0 62 0>;
+       };
+
+       i2c@12CD0000 {
+               compatible = "samsung,s3c2440-i2c";
+               reg = <0x12CD0000 0x100>;
+               interrupts = <0 63 0>;
+       };
+
+       amba {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "arm,amba-bus";
+               interrupt-parent = <&gic>;
+               ranges;
+
+               pdma0: pdma@121A0000 {
+                       compatible = "arm,pl330", "arm,primecell";
+                       reg = <0x121A0000 0x1000>;
+                       interrupts = <0 34 0>;
+               };
+
+               pdma1: pdma@121B0000 {
+                       compatible = "arm,pl330", "arm,primecell";
+                       reg = <0x121B0000 0x1000>;
+                       interrupts = <0 35 0>;
+               };
+
+               mdma0: pdma@10800000 {
+                       compatible = "arm,pl330", "arm,primecell";
+                       reg = <0x10800000 0x1000>;
+                       interrupts = <0 33 0>;
+               };
+
+               mdma1: pdma@11C10000 {
+                       compatible = "arm,pl330", "arm,primecell";
+                       reg = <0x11C10000 0x1000>;
+                       interrupts = <0 124 0>;
+               };
+       };
+
+       gpio-controllers {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               gpio-controller;
+               ranges;
+
+               gpa0: gpio-controller@11400000 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400000 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpa1: gpio-controller@11400020 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400020 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpa2: gpio-controller@11400040 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400040 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpb0: gpio-controller@11400060 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400060 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpb1: gpio-controller@11400080 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400080 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpb2: gpio-controller@114000A0 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x114000A0 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpb3: gpio-controller@114000C0 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x114000C0 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpc0: gpio-controller@114000E0 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x114000E0 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpc1: gpio-controller@11400100 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400100 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpc2: gpio-controller@11400120 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400120 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpc3: gpio-controller@11400140 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400140 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpd0: gpio-controller@11400160 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400160 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpd1: gpio-controller@11400180 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400180 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpy0: gpio-controller@114001A0 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x114001A0 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpy1: gpio-controller@114001C0 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x114001C0 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpy2: gpio-controller@114001E0 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x114001E0 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpy3: gpio-controller@11400200 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400200 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpy4: gpio-controller@11400220 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400220 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpy5: gpio-controller@11400240 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400240 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpy6: gpio-controller@11400260 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400260 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpx0: gpio-controller@11400C00 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400C00 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpx1: gpio-controller@11400C20 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400C20 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpx2: gpio-controller@11400C40 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400C40 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpx3: gpio-controller@11400C60 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x11400C60 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpe0: gpio-controller@13400000 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x13400000 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpe1: gpio-controller@13400020 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x13400020 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpf0: gpio-controller@13400040 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x13400040 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpf1: gpio-controller@13400060 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x13400060 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpg0: gpio-controller@13400080 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x13400080 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpg1: gpio-controller@134000A0 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x134000A0 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpg2: gpio-controller@134000C0 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x134000C0 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gph0: gpio-controller@134000E0 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x134000E0 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gph1: gpio-controller@13400100 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x13400100 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpv0: gpio-controller@10D10000 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x10D10000 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpv1: gpio-controller@10D10020 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x10D10020 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpv2: gpio-controller@10D10040 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x10D10040 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpv3: gpio-controller@10D10060 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x10D10060 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpv4: gpio-controller@10D10080 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x10D10080 0x20>;
+                       #gpio-cells = <4>;
+               };
+
+               gpz: gpio-controller@03860000 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x03860000 0x20>;
+                       #gpio-cells = <4>;
+               };
+       };
+};
index 305635b..37c0ff9 100644 (file)
                ranges;
 
                timer@fff10600 {
-                       compatible = "arm,smp-twd";
+                       compatible = "arm,cortex-a9-twd-timer";
                        reg = <0xfff10600 0x20>;
-                       interrupts = <1 13 0xf04>;
+                       interrupts = <1 13 0xf01>;
                };
 
                watchdog@fff10620 {
-                       compatible = "arm,cortex-a9-wdt";
+                       compatible = "arm,cortex-a9-twd-wdt";
                        reg = <0xfff10620 0x20>;
-                       interrupts = <1 14 0xf04>;
+                       interrupts = <1 14 0xf01>;
                };
 
                intc: interrupt-controller@fff11000 {
diff --git a/arch/arm/boot/dts/imx27-phytec-phycore.dts b/arch/arm/boot/dts/imx27-phytec-phycore.dts
new file mode 100644 (file)
index 0000000..a51a08f
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 Sascha Hauer, Pengutronix
+ *
+ * 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
+ */
+
+/dts-v1/;
+/include/ "imx27.dtsi"
+
+/ {
+       model = "Phytec pcm038";
+       compatible = "phytec,imx27-pcm038", "fsl,imx27";
+
+       memory {
+               reg = <0x0 0x0>;
+       };
+
+       soc {
+               aipi@10000000 { /* aipi */
+
+                       wdog@10002000 {
+                               status = "okay";
+                       };
+
+                       uart@1000a000 {
+                               fsl,uart-has-rtscts;
+                               status = "okay";
+                       };
+
+                       uart@1000b000 {
+                               fsl,uart-has-rtscts;
+                               status = "okay";
+                       };
+
+                       uart@1000c000 {
+                               fsl,uart-has-rtscts;
+                               status = "okay";
+                       };
+
+                       fec@1002b000 {
+                               status = "okay";
+                       };
+
+                       i2c@1001d000 {
+                               clock-frequency = <400000>;
+                               status = "okay";
+                               at24@4c {
+                                       compatible = "at,24c32";
+                                       pagesize = <32>;
+                                       reg = <0x52>;
+                               };
+                               pcf8563@51 {
+                                       compatible = "nxp,pcf8563";
+                                       reg = <0x51>;
+                               };
+                               lm75@4a {
+                                       compatible = "national,lm75";
+                                       reg = <0x4a>;
+                               };
+                       };
+               };
+       };
+
+       nor_flash@c0000000 {
+               compatible = "cfi-flash";
+               bank-width = <2>;
+               reg = <0xc0000000 0x02000000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+       };
+};
diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi
new file mode 100644 (file)
index 0000000..bc5e7d5
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2012 Sascha Hauer, Pengutronix
+ *
+ * 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/ "skeleton.dtsi"
+
+/ {
+       aliases {
+               serial0 = &uart1;
+               serial1 = &uart2;
+               serial2 = &uart3;
+               serial3 = &uart4;
+               serial4 = &uart5;
+               serial5 = &uart6;
+       };
+
+       avic: avic-interrupt-controller@e0000000 {
+               compatible = "fsl,imx27-avic", "fsl,avic";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = <0x10040000 0x1000>;
+       };
+
+       clocks {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               osc26m {
+                       compatible = "fsl,imx-osc26m", "fixed-clock";
+                       clock-frequency = <26000000>;
+               };
+       };
+
+       soc {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "simple-bus";
+               interrupt-parent = <&avic>;
+               ranges;
+
+               aipi@10000000 { /* AIPI1 */
+                       compatible = "fsl,aipi-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0x10000000 0x10000000>;
+                       ranges;
+
+                       wdog@10002000 {
+                               compatible = "fsl,imx27-wdt", "fsl,imx21-wdt";
+                               reg = <0x10002000 0x4000>;
+                               interrupts = <27>;
+                               status = "disabled";
+                       };
+
+                       uart1: uart@1000a000 {
+                               compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+                               reg = <0x1000a000 0x1000>;
+                               interrupts = <20>;
+                               status = "disabled";
+                       };
+
+                       uart2: uart@1000b000 {
+                               compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+                               reg = <0x1000b000 0x1000>;
+                               interrupts = <19>;
+                               status = "disabled";
+                       };
+
+                       uart3: uart@1000c000 {
+                               compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+                               reg = <0x1000c000 0x1000>;
+                               interrupts = <18>;
+                               status = "disabled";
+                       };
+
+                       uart4: uart@1000d000 {
+                               compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+                               reg = <0x1000d000 0x1000>;
+                               interrupts = <17>;
+                               status = "disabled";
+                       };
+
+                       cspi1: cspi@1000e000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,imx27-cspi";
+                               reg = <0x1000e000 0x1000>;
+                               interrupts = <16>;
+                               status = "disabled";
+                       };
+
+                       cspi2: cspi@1000f000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,imx27-cspi";
+                               reg = <0x1000f000 0x1000>;
+                               interrupts = <15>;
+                               status = "disabled";
+                       };
+
+                       i2c1: i2c@10012000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,imx27-i2c", "fsl,imx1-i2c";
+                               reg = <0x10012000 0x1000>;
+                               interrupts = <12>;
+                               status = "disabled";
+                       };
+
+                       gpio1: gpio@10015000 {
+                               compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+                               reg = <0x10015000 0x100>;
+                               interrupts = <8>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+
+                       gpio2: gpio@10015100 {
+                               compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+                               reg = <0x10015100 0x100>;
+                               interrupts = <8>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+
+                       gpio3: gpio@10015200 {
+                               compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+                               reg = <0x10015200 0x100>;
+                               interrupts = <8>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+
+                       gpio4: gpio@10015300 {
+                               compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+                               reg = <0x10015300 0x100>;
+                               interrupts = <8>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+
+                       gpio5: gpio@10015400 {
+                               compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+                               reg = <0x10015400 0x100>;
+                               interrupts = <8>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+
+                       gpio6: gpio@10015500 {
+                               compatible = "fsl,imx27-gpio", "fsl,imx21-gpio";
+                               reg = <0x10015500 0x100>;
+                               interrupts = <8>;
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+
+                       cspi3: cspi@10017000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,imx27-cspi";
+                               reg = <0x10017000 0x1000>;
+                               interrupts = <6>;
+                               status = "disabled";
+                       };
+
+                       uart5: uart@1001b000 {
+                               compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+                               reg = <0x1001b000 0x1000>;
+                               interrupts = <49>;
+                               status = "disabled";
+                       };
+
+                       uart6: uart@1001c000 {
+                               compatible = "fsl,imx27-uart", "fsl,imx21-uart";
+                               reg = <0x1001c000 0x1000>;
+                               interrupts = <48>;
+                               status = "disabled";
+                       };
+
+                       i2c2: i2c@1001d000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,imx27-i2c", "fsl,imx1-i2c";
+                               reg = <0x1001d000 0x1000>;
+                               interrupts = <1>;
+                               status = "disabled";
+                       };
+
+                       fec: fec@1002b000 {
+                               compatible = "fsl,imx27-fec";
+                               reg = <0x1002b000 0x4000>;
+                               interrupts = <50>;
+                               status = "disabled";
+                       };
+               };
+       };
+};
index 564cb8c..9949e60 100644 (file)
                                                compatible = "fsl,mc13892";
                                                spi-max-frequency = <6000000>;
                                                reg = <0>;
-                                               mc13xxx-irq-gpios = <&gpio1 8 0>;
-                                               fsl,mc13xxx-uses-regulator;
+                                               interrupt-parent = <&gpio1>;
+                                               interrupts = <8>;
+
+                                               regulators {
+                                                       sw1_reg: sw1 {
+                                                               regulator-min-microvolt = <600000>;
+                                                               regulator-max-microvolt = <1375000>;
+                                                               regulator-boot-on;
+                                                               regulator-always-on;
+                                                       };
+
+                                                       sw2_reg: sw2 {
+                                                               regulator-min-microvolt = <900000>;
+                                                               regulator-max-microvolt = <1850000>;
+                                                               regulator-boot-on;
+                                                               regulator-always-on;
+                                                       };
+
+                                                       sw3_reg: sw3 {
+                                                               regulator-min-microvolt = <1100000>;
+                                                               regulator-max-microvolt = <1850000>;
+                                                               regulator-boot-on;
+                                                               regulator-always-on;
+                                                       };
+
+                                                       sw4_reg: sw4 {
+                                                               regulator-min-microvolt = <1100000>;
+                                                               regulator-max-microvolt = <1850000>;
+                                                               regulator-boot-on;
+                                                               regulator-always-on;
+                                                       };
+
+                                                       vpll_reg: vpll {
+                                                               regulator-min-microvolt = <1050000>;
+                                                               regulator-max-microvolt = <1800000>;
+                                                               regulator-boot-on;
+                                                               regulator-always-on;
+                                                       };
+
+                                                       vdig_reg: vdig {
+                                                               regulator-min-microvolt = <1650000>;
+                                                               regulator-max-microvolt = <1650000>;
+                                                               regulator-boot-on;
+                                                       };
+
+                                                       vsd_reg: vsd {
+                                                               regulator-min-microvolt = <1800000>;
+                                                               regulator-max-microvolt = <3150000>;
+                                                       };
+
+                                                       vusb2_reg: vusb2 {
+                                                               regulator-min-microvolt = <2400000>;
+                                                               regulator-max-microvolt = <2775000>;
+                                                               regulator-boot-on;
+                                                               regulator-always-on;
+                                                       };
+
+                                                       vvideo_reg: vvideo {
+                                                               regulator-min-microvolt = <2775000>;
+                                                               regulator-max-microvolt = <2775000>;
+                                                       };
+
+                                                       vaudio_reg: vaudio {
+                                                               regulator-min-microvolt = <2300000>;
+                                                               regulator-max-microvolt = <3000000>;
+                                                       };
+
+                                                       vcam_reg: vcam {
+                                                               regulator-min-microvolt = <2500000>;
+                                                               regulator-max-microvolt = <3000000>;
+                                                       };
+
+                                                       vgen1_reg: vgen1 {
+                                                               regulator-min-microvolt = <1200000>;
+                                                               regulator-max-microvolt = <1200000>;
+                                                       };
+
+                                                       vgen2_reg: vgen2 {
+                                                               regulator-min-microvolt = <1200000>;
+                                                               regulator-max-microvolt = <3150000>;
+                                                               regulator-always-on;
+                                                       };
+
+                                                       vgen3_reg: vgen3 {
+                                                               regulator-min-microvolt = <1800000>;
+                                                               regulator-max-microvolt = <2900000>;
+                                                               regulator-always-on;
+                                                       };
+                                               };
                                        };
 
                                        flash: at45db321d@1 {
index c3977e0..ce1c823 100644 (file)
                        usdhc@02198000 { /* uSDHC3 */
                                cd-gpios = <&gpio6 11 0>;
                                wp-gpios = <&gpio6 14 0>;
+                               vmmc-supply = <&reg_3p3v>;
                                status = "okay";
                        };
 
                        usdhc@0219c000 { /* uSDHC4 */
                                fsl,card-wired;
+                               vmmc-supply = <&reg_3p3v>;
                                status = "okay";
                        };
 
                };
        };
 
+       regulators {
+               compatible = "simple-bus";
+
+               reg_3p3v: 3p3v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "3P3V";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+               };
+       };
+
        leds {
                compatible = "gpio-leds";
 
index 08d920d..4663a4e 100644 (file)
                        usdhc@02198000 { /* uSDHC3 */
                                cd-gpios = <&gpio7 0 0>;
                                wp-gpios = <&gpio7 1 0>;
+                               vmmc-supply = <&reg_3p3v>;
                                status = "okay";
                        };
 
                        usdhc@0219c000 { /* uSDHC4 */
                                cd-gpios = <&gpio2 6 0>;
                                wp-gpios = <&gpio2 7 0>;
+                               vmmc-supply = <&reg_3p3v>;
                                status = "okay";
                        };
 
                        uart2: uart@021e8000 {
                                status = "okay";
                        };
+
+                       i2c@021a0000 { /* I2C1 */
+                               status = "okay";
+                               clock-frequency = <100000>;
+
+                               codec: sgtl5000@0a {
+                                       compatible = "fsl,sgtl5000";
+                                       reg = <0x0a>;
+                                       VDDA-supply = <&reg_2p5v>;
+                                       VDDIO-supply = <&reg_3p3v>;
+                               };
+                       };
+               };
+       };
+
+       regulators {
+               compatible = "simple-bus";
+
+               reg_2p5v: 2p5v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "2P5V";
+                       regulator-min-microvolt = <2500000>;
+                       regulator-max-microvolt = <2500000>;
+                       regulator-always-on;
+               };
+
+               reg_3p3v: 3p3v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "3P3V";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
                };
        };
 };
index 263e8f3..4905f51 100644 (file)
@@ -88,9 +88,9 @@
                ranges;
 
                timer@00a00600 {
-                       compatible = "arm,smp-twd";
-                       reg = <0x00a00600 0x100>;
-                       interrupts = <1 13 0xf4>;
+                       compatible = "arm,cortex-a9-twd-timer";
+                       reg = <0x00a00600 0x20>;
+                       interrupts = <1 13 0xf01>;
                };
 
                L2: l2-cache@00a02000 {
diff --git a/arch/arm/boot/dts/kirkwood-dreamplug.dts b/arch/arm/boot/dts/kirkwood-dreamplug.dts
new file mode 100644 (file)
index 0000000..a5376b8
--- /dev/null
@@ -0,0 +1,24 @@
+/dts-v1/;
+
+/include/ "kirkwood.dtsi"
+
+/ {
+       model = "Globalscale Technologies Dreamplug";
+       compatible = "globalscale,dreamplug-003-ds2001", "globalscale,dreamplug", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x20000000>;
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200n8 earlyprintk";
+       };
+
+       ocp@f1000000 {
+               serial@12000 {
+                       clock-frequency = <200000000>;
+                       status = "ok";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
new file mode 100644 (file)
index 0000000..3474ef8
--- /dev/null
@@ -0,0 +1,36 @@
+/include/ "skeleton.dtsi"
+
+/ {
+       compatible = "mrvl,kirkwood";
+
+       ocp@f1000000 {
+               compatible = "simple-bus";
+               ranges = <0 0xf1000000 0x1000000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               serial@12000 {
+                       compatible = "ns16550a";
+                       reg = <0x12000 0x100>;
+                       reg-shift = <2>;
+                       interrupts = <33>;
+                       /* set clock-frequency in board dts */
+                       status = "disabled";
+               };
+
+               serial@12100 {
+                       compatible = "ns16550a";
+                       reg = <0x12100 0x100>;
+                       reg-shift = <2>;
+                       interrupts = <34>;
+                       /* set clock-frequency in board dts */
+                       status = "disabled";
+               };
+
+               rtc@10300 {
+                       compatible = "mrvl,kirkwood-rtc", "mrvl,orion-rtc";
+                       reg = <0x10300 0x20>;
+                       interrupts = <53>;
+               };
+       };
+};
index 9486be6..9f72cd4 100644 (file)
        model = "TI OMAP3 BeagleBoard";
        compatible = "ti,omap3-beagle", "ti,omap3";
 
-       /*
-        * Since the initial device tree board file does not create any
-        * devices (MMC, network...), the only way to boot is to provide a
-        * ramdisk.
-        */
-       chosen {
-               bootargs = "root=/dev/ram0 rw console=ttyO2,115200n8 initrd=0x81600000,20M ramdisk_size=20480 no_console_suspend debug earlyprintk";
-       };
-
        memory {
                device_type = "memory";
                reg = <0x80000000 0x20000000>; /* 512 MB */
diff --git a/arch/arm/boot/dts/omap3-evm.dts b/arch/arm/boot/dts/omap3-evm.dts
new file mode 100644 (file)
index 0000000..2eee16e
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/dts-v1/;
+
+/include/ "omap3.dtsi"
+
+/ {
+       model = "TI OMAP3 EVM (OMAP3530, AM/DM37x)";
+       compatible = "ti,omap3-evm", "ti,omap3";
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x10000000>; /* 256 MB */
+       };
+};
index 216c331..c612135 100644 (file)
                ranges;
                ti,hwmods = "l3_main";
 
-               intc: interrupt-controller@1 {
-                       compatible = "ti,omap3-intc";
+               intc: interrupt-controller@48200000 {
+                       compatible = "ti,omap2-intc";
                        interrupt-controller;
                        #interrupt-cells = <1>;
+                       ti,intc-size = <96>;
+                       reg = <0x48200000 0x1000>;
                };
 
-               uart1: serial@0x4806a000 {
+               uart1: serial@4806a000 {
                        compatible = "ti,omap3-uart";
                        ti,hwmods = "uart1";
                        clock-frequency = <48000000>;
                };
 
-               uart2: serial@0x4806c000 {
+               uart2: serial@4806c000 {
                        compatible = "ti,omap3-uart";
                        ti,hwmods = "uart2";
                        clock-frequency = <48000000>;
                };
 
-               uart3: serial@0x49020000 {
+               uart3: serial@49020000 {
                        compatible = "ti,omap3-uart";
                        ti,hwmods = "uart3";
                        clock-frequency = <48000000>;
                };
 
-               uart4: serial@0x49042000 {
+               uart4: serial@49042000 {
                        compatible = "ti,omap3-uart";
                        ti,hwmods = "uart4";
                        clock-frequency = <48000000>;
                };
+
+               i2c1: i2c@48070000 {
+                       compatible = "ti,omap3-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ti,hwmods = "i2c1";
+               };
+
+               i2c2: i2c@48072000 {
+                       compatible = "ti,omap3-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ti,hwmods = "i2c2";
+               };
+
+               i2c3: i2c@48060000 {
+                       compatible = "ti,omap3-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ti,hwmods = "i2c3";
+               };
        };
 };
index c702657..9755ad5 100644 (file)
        model = "TI OMAP4 PandaBoard";
        compatible = "ti,omap4-panda", "ti,omap4430", "ti,omap4";
 
-       /*
-        * Since the initial device tree board file does not create any
-        * devices (MMC, network...), the only way to boot is to provide a
-        * ramdisk.
-        */
-       chosen {
-               bootargs = "root=/dev/ram0 rw console=ttyO2,115200n8 initrd=0x81600000,20M ramdisk_size=20480 no_console_suspend debug";
-       };
-
        memory {
                device_type = "memory";
                reg = <0x80000000 0x40000000>; /* 1 GB */
index 066e28c..63c6b2b 100644 (file)
        model = "TI OMAP4 SDP board";
        compatible = "ti,omap4-sdp", "ti,omap4430", "ti,omap4";
 
-       /*
-        * Since the initial device tree board file does not create any
-        * devices (MMC, network...), the only way to boot is to provide a
-        * ramdisk.
-        */
-       chosen {
-               bootargs = "root=/dev/ram0 rw console=ttyO2,115200n8 initrd=0x81600000,20M ramdisk_size=20480 no_console_suspend debug";
-       };
-
        memory {
                device_type = "memory";
                reg = <0x80000000 0x40000000>; /* 1 GB */
index e8fe75f..3d35559 100644 (file)
                gic: interrupt-controller@48241000 {
                        compatible = "arm,cortex-a9-gic";
                        interrupt-controller;
-                       #interrupt-cells = <1>;
+                       #interrupt-cells = <3>;
                        reg = <0x48241000 0x1000>,
                              <0x48240100 0x0100>;
                };
 
-               uart1: serial@0x4806a000 {
+               uart1: serial@4806a000 {
                        compatible = "ti,omap4-uart";
                        ti,hwmods = "uart1";
                        clock-frequency = <48000000>;
                };
 
-               uart2: serial@0x4806c000 {
+               uart2: serial@4806c000 {
                        compatible = "ti,omap4-uart";
                        ti,hwmods = "uart2";
                        clock-frequency = <48000000>;
                };
 
-               uart3: serial@0x48020000 {
+               uart3: serial@48020000 {
                        compatible = "ti,omap4-uart";
                        ti,hwmods = "uart3";
                        clock-frequency = <48000000>;
                };
 
-               uart4: serial@0x4806e000 {
+               uart4: serial@4806e000 {
                        compatible = "ti,omap4-uart";
                        ti,hwmods = "uart4";
                        clock-frequency = <48000000>;
                };
+
+               i2c1: i2c@48070000 {
+                       compatible = "ti,omap4-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ti,hwmods = "i2c1";
+               };
+
+               i2c2: i2c@48072000 {
+                       compatible = "ti,omap4-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ti,hwmods = "i2c2";
+               };
+
+               i2c3: i2c@48060000 {
+                       compatible = "ti,omap4-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ti,hwmods = "i2c3";
+               };
+
+               i2c4: i2c@48350000 {
+                       compatible = "ti,omap4-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ti,hwmods = "i2c4";
+               };
        };
 };
diff --git a/arch/arm/boot/dts/pxa168-aspenite.dts b/arch/arm/boot/dts/pxa168-aspenite.dts
new file mode 100644 (file)
index 0000000..e762fac
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (C) 2012 Marvell Technology Group Ltd.
+ *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/include/ "pxa168.dtsi"
+
+/ {
+       model = "Marvell PXA168 Aspenite Development Board";
+       compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168";
+
+       chosen {
+               bootargs = "console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on";
+       };
+
+       memory {
+               reg = <0x00000000 0x04000000>;
+       };
+
+       soc {
+               apb@d4000000 {
+                       uart1: uart@d4017000 {
+                               status = "okay";
+                       };
+                       twsi1: i2c@d4011000 {
+                               status = "okay";
+                       };
+                       rtc: rtc@d4010000 {
+                               status = "okay";
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/pxa168.dtsi b/arch/arm/boot/dts/pxa168.dtsi
new file mode 100644 (file)
index 0000000..d32d512
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ *  Copyright (C) 2012 Marvell Technology Group Ltd.
+ *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+       aliases {
+               serial0 = &uart1;
+               serial1 = &uart2;
+               serial2 = &uart3;
+               i2c0 = &twsi1;
+               i2c1 = &twsi2;
+       };
+
+       intc: intc-interrupt-controller@d4282000 {
+               compatible = "mrvl,mmp-intc", "mrvl,intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = <0xd4282000 0x1000>;
+       };
+
+       soc {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "simple-bus";
+               interrupt-parent = <&intc>;
+               ranges;
+
+               apb@d4000000 {  /* APB */
+                       compatible = "mrvl,apb-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0xd4000000 0x00200000>;
+                       ranges;
+
+                       uart1: uart@d4017000 {
+                               compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+                               reg = <0xd4017000 0x1000>;
+                               interrupts = <27>;
+                               status = "disabled";
+                       };
+
+                       uart2: uart@d4018000 {
+                               compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+                               reg = <0xd4018000 0x1000>;
+                               interrupts = <28>;
+                               status = "disabled";
+                       };
+
+                       uart3: uart@d4026000 {
+                               compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+                               reg = <0xd4026000 0x1000>;
+                               interrupts = <29>;
+                               status = "disabled";
+                       };
+
+                       gpio: gpio@d4019000 {
+                               compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio";
+                               reg = <0xd4019000 0x1000>;
+                               interrupts = <49>;
+                               interrupt-names = "gpio_mux";
+                               gpio-controller;
+                               #gpio-cells = <1>;
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+
+                       twsi1: i2c@d4011000 {
+                               compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+                               reg = <0xd4011000 0x1000>;
+                               interrupts = <7>;
+                               mrvl,i2c-fast-mode;
+                               status = "disabled";
+                       };
+
+                       twsi2: i2c@d4025000 {
+                               compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+                               reg = <0xd4025000 0x1000>;
+                               interrupts = <58>;
+                               status = "disabled";
+                       };
+
+                       rtc: rtc@d4010000 {
+                               compatible = "mrvl,mmp-rtc";
+                               reg = <0xd4010000 0x1000>;
+                               interrupts = <5 6>;
+                               interrupt-names = "rtc 1Hz", "rtc alarm";
+                               status = "disabled";
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/snowball.dts b/arch/arm/boot/dts/snowball.dts
new file mode 100644 (file)
index 0000000..359c6d6
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011 ST-Ericsson AB
+ *
+ * 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
+ */
+
+/dts-v1/;
+/include/ "db8500.dtsi"
+
+/ {
+       model = "Calao Systems Snowball platform with device tree";
+       compatible = "calaosystems,snowball-a9500";
+
+       memory {
+               reg = <0x00000000 0x20000000>;
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               button@1 {
+                       debounce_interval = <50>;
+                       wakeup = <1>;
+                       linux,code = <2>;
+                       label = "userpb";
+                       gpios = <&gpio1 0>;
+               };
+               button@2 {
+                       debounce_interval = <50>;
+                       wakeup = <1>;
+                       linux,code = <3>;
+                       label = "userpb";
+                       gpios = <&gpio4 23>;
+               };
+               button@3 {
+                       debounce_interval = <50>;
+                       wakeup = <1>;
+                       linux,code = <4>;
+                       label = "userpb";
+                       gpios = <&gpio4 23>;
+               };
+               button@4 {
+                       debounce_interval = <50>;
+                       wakeup = <1>;
+                       linux,code = <5>;
+                       label = "userpb";
+                       gpios = <&gpio5 1>;
+               };
+               button@5 {
+                       debounce_interval = <50>;
+                       wakeup = <1>;
+                       linux,code = <6>;
+                       label = "userpb";
+                       gpios = <&gpio5 2>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               used-led {
+                       label = "user_led";
+                       gpios = <&gpio4 14>;
+               };
+       };
+
+       soc-u9500 {
+
+               external-bus@50000000 {
+                       compatible = "simple-bus";
+                       reg = <0x50000000 0x10000000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       ethernet@50000000 {
+                               compatible = "smsc,9111";
+                               reg = <0x50000000 0x10000>;
+                               interrupts = <12>;
+                               interrupt-parent = <&gpio4>;
+                       };
+               };
+
+               sdi@80126000 {
+                       status = "enabled";
+                       cd-gpios = <&gpio6 26>;
+               };
+
+               sdi@80114000 {
+                       status = "enabled";
+               };
+
+               uart@80120000 {
+                       status = "okay";
+               };
+
+               uart@80121000 {
+                       status = "okay";
+               };
+
+               uart@80007000 {
+                       status = "okay";
+               };
+
+               i2c@80004000 {
+                       tc3589x@42 {
+                               //compatible = "tc3589x";
+                               reg = <0x42>;
+                               interrupts = <25>;
+                               interrupt-parent = <&gpio6>;
+                       };
+                       tps61052@33 {
+                               //compatible = "tps61052";
+                               reg = <0x33>;
+                       };
+               };
+
+               i2c@80128000 {
+                       lp5521@0x33 {
+                               // compatible = "lp5521";
+                               reg = <0x33>;
+                       };
+                       lp5521@0x34 {
+                               // compatible = "lp5521";
+                               reg = <0x34>;
+                       };
+                       bh1780@0x29 {
+                               // compatible = "rohm,bh1780gli";
+                               reg = <0x33>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/spear600-evb.dts b/arch/arm/boot/dts/spear600-evb.dts
new file mode 100644 (file)
index 0000000..636292e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
+ * 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
+ */
+
+/dts-v1/;
+/include/ "spear600.dtsi"
+
+/ {
+       model = "ST SPEAr600 Evaluation Board";
+       compatible = "st,spear600-evb", "st,spear600";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       memory {
+               device_type = "memory";
+               reg = <0 0x10000000>;
+       };
+
+       ahb {
+               gmac: ethernet@e0800000 {
+                       phy-mode = "gmii";
+                       status = "okay";
+               };
+
+               apb {
+                       serial@d0000000 {
+                               status = "okay";
+                       };
+
+                       serial@d0080000 {
+                               status = "okay";
+                       };
+
+                       i2c@d0200000 {
+                               clock-frequency = <400000>;
+                               status = "okay";
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi
new file mode 100644 (file)
index 0000000..ebe0885
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
+ * 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/ "skeleton.dtsi"
+
+/ {
+       compatible = "st,spear600";
+
+       cpus {
+               cpu@0 {
+                       compatible = "arm,arm926ejs";
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0 0x40000000>;
+       };
+
+       ahb {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "simple-bus";
+               ranges = <0xd0000000 0xd0000000 0x30000000>;
+
+               vic0: interrupt-controller@f1100000 {
+                       compatible = "arm,pl190-vic";
+                       interrupt-controller;
+                       reg = <0xf1100000 0x1000>;
+                       #interrupt-cells = <1>;
+               };
+
+               vic1: interrupt-controller@f1000000 {
+                       compatible = "arm,pl190-vic";
+                       interrupt-controller;
+                       reg = <0xf1000000 0x1000>;
+                       #interrupt-cells = <1>;
+               };
+
+               gmac: ethernet@e0800000 {
+                       compatible = "st,spear600-gmac";
+                       reg = <0xe0800000 0x8000>;
+                       interrupt-parent = <&vic1>;
+                       interrupts = <24 23>;
+                       interrupt-names = "macirq", "eth_wake_irq";
+                       status = "disabled";
+               };
+
+               fsmc: flash@d1800000 {
+                       compatible = "st,spear600-fsmc-nand";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0xd1800000 0x1000        /* FSMC Register */
+                              0xd2000000 0x4000>;      /* NAND Base */
+                       reg-names = "fsmc_regs", "nand_data";
+                       st,ale-off = <0x20000>;
+                       st,cle-off = <0x10000>;
+                       status = "disabled";
+               };
+
+               smi: flash@fc000000 {
+                       compatible = "st,spear600-smi";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0xfc000000 0x1000>;
+                       interrupt-parent = <&vic1>;
+                       interrupts = <12>;
+                       status = "disabled";
+               };
+
+               ehci@e1800000 {
+                       compatible = "st,spear600-ehci", "usb-ehci";
+                       reg = <0xe1800000 0x1000>;
+                       interrupt-parent = <&vic1>;
+                       interrupts = <27>;
+                       status = "disabled";
+               };
+
+               ehci@e2000000 {
+                       compatible = "st,spear600-ehci", "usb-ehci";
+                       reg = <0xe2000000 0x1000>;
+                       interrupt-parent = <&vic1>;
+                       interrupts = <29>;
+                       status = "disabled";
+               };
+
+               ohci@e1900000 {
+                       compatible = "st,spear600-ohci", "usb-ohci";
+                       reg = <0xe1900000 0x1000>;
+                       interrupt-parent = <&vic1>;
+                       interrupts = <26>;
+                       status = "disabled";
+               };
+
+               ohci@e2100000 {
+                       compatible = "st,spear600-ohci", "usb-ohci";
+                       reg = <0xe2100000 0x1000>;
+                       interrupt-parent = <&vic1>;
+                       interrupts = <28>;
+                       status = "disabled";
+               };
+
+               apb {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "simple-bus";
+                       ranges = <0xd0000000 0xd0000000 0x30000000>;
+
+                       serial@d0000000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0xd0000000 0x1000>;
+                               interrupt-parent = <&vic0>;
+                               interrupts = <24>;
+                               status = "disabled";
+                       };
+
+                       serial@d0080000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0xd0080000 0x1000>;
+                               interrupt-parent = <&vic0>;
+                               interrupts = <25>;
+                               status = "disabled";
+                       };
+
+                       /* local/cpu GPIO */
+                       gpio0: gpio@f0100000 {
+                               #gpio-cells = <2>;
+                               compatible = "arm,pl061", "arm,primecell";
+                               gpio-controller;
+                               reg = <0xf0100000 0x1000>;
+                               interrupt-parent = <&vic0>;
+                               interrupts = <18>;
+                       };
+
+                       /* basic GPIO */
+                       gpio1: gpio@fc980000 {
+                               #gpio-cells = <2>;
+                               compatible = "arm,pl061", "arm,primecell";
+                               gpio-controller;
+                               reg = <0xfc980000 0x1000>;
+                               interrupt-parent = <&vic1>;
+                               interrupts = <19>;
+                       };
+
+                       /* appl GPIO */
+                       gpio2: gpio@d8100000 {
+                               #gpio-cells = <2>;
+                               compatible = "arm,pl061", "arm,primecell";
+                               gpio-controller;
+                               reg = <0xd8100000 0x1000>;
+                               interrupt-parent = <&vic1>;
+                               interrupts = <4>;
+                       };
+
+                       i2c@d0200000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "snps,designware-i2c";
+                               reg = <0xd0200000 0x1000>;
+                               interrupt-parent = <&vic0>;
+                               interrupts = <28>;
+                               status = "disabled";
+                       };
+               };
+       };
+};
index 70c41fc..ac3fb75 100644 (file)
                clock-frequency = < 408000000 >;
        };
 
+       serial@70006040 {
+               status = "disable";
+       };
+
+       serial@70006200 {
+               status = "disable";
+       };
+
+       serial@70006300 {
+               status = "disable";
+       };
+
+       serial@70006400 {
+               status = "disable";
+       };
+
        i2c@7000c000 {
                clock-frequency = <100000>;
        };
        i2c@7000d000 {
                clock-frequency = <100000>;
        };
+
+       sdhci@78000000 {
+               cd-gpios = <&gpio 69 0>; /* gpio PI5 */
+               wp-gpios = <&gpio 155 0>; /* gpio PT3 */
+               power-gpios = <&gpio 31 0>; /* gpio PD7 */
+       };
+
+       sdhci@78000200 {
+               status = "disable";
+       };
+
+       sdhci@78000400 {
+               status = "disable";
+       };
+
+       sdhci@78000400 {
+               support-8bit;
+       };
 };
index 80afa1b..6e8447d 100644 (file)
                reg = < 0x00000000 0x40000000 >;
        };
 
+       pmc@7000f400 {
+               nvidia,invert-interrupt;
+       };
+
        i2c@7000c000 {
                clock-frequency = <400000>;
 
-               codec: wm8903@1a {
+               wm8903: wm8903@1a {
                        compatible = "wlf,wm8903";
                        reg = <0x1a>;
-                       interrupts = < 347 >;
+                       interrupt-parent = <&gpio>;
+                       interrupts = < 187 0x04 >;
 
                        gpio-controller;
                        #gpio-cells = <2>;
 
-                       /* 0x8000 = Not configured */
-                       gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;
+                       micdet-cfg = <0>;
+                       micdet-delay = <100>;
+                       gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
                };
        };
 
                clock-frequency = <400000>;
        };
 
-       sound {
-               compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903";
+       i2s@70002a00 {
+               status = "disable";
+       };
 
-               spkr-en-gpios = <&codec 2 0>;
-               hp-det-gpios = <&gpio 178 0>;
-               int-mic-en-gpios = <&gpio 184 0>;
-               ext-mic-en-gpios = <&gpio 185 0>;
+       sound {
+               compatible = "nvidia,tegra-audio-wm8903-harmony",
+                            "nvidia,tegra-audio-wm8903";
+               nvidia,model = "NVIDIA Tegra Harmony";
+
+               nvidia,audio-routing =
+                       "Headphone Jack", "HPOUTR",
+                       "Headphone Jack", "HPOUTL",
+                       "Int Spk", "ROP",
+                       "Int Spk", "RON",
+                       "Int Spk", "LOP",
+                       "Int Spk", "LON",
+                       "Mic Jack", "MICBIAS",
+                       "IN1L", "Mic Jack";
+
+               nvidia,i2s-controller = <&tegra_i2s1>;
+               nvidia,audio-codec = <&wm8903>;
+
+               nvidia,spkr-en-gpios = <&wm8903 2 0>;
+               nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+               nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
+               nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
        };
 
        serial@70006000 {
index 825d295..6c02abb 100644 (file)
 
        i2c@7000c000 {
                clock-frequency = <400000>;
+
+               alc5632: alc5632@1e {
+                       compatible = "realtek,alc5632";
+                       reg = <0x1e>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
        };
 
        i2c@7000c400 {
 
        i2c@7000d000 {
                clock-frequency = <400000>;
+
+               adt7461@4c {
+                       compatible = "adi,adt7461";
+                       reg = <0x4c>;
+               };
+       };
+
+       i2s@70002a00 {
+               status = "disable";
+       };
+
+       sound {
+               compatible = "nvidia,tegra-audio-alc5632-paz00",
+                       "nvidia,tegra-audio-alc5632";
+
+               nvidia,model = "Compal PAZ00";
+
+               nvidia,audio-routing =
+                       "Int Spk", "SPKOUT",
+                       "Int Spk", "SPKOUTN",
+                       "Headset Mic", "MICBIAS1",
+                       "MIC1", "Headset Mic",
+                       "Headset Stereophone", "HPR",
+                       "Headset Stereophone", "HPL",
+                       "DMICDAT", "Digital Mic";
+
+               nvidia,audio-codec = <&alc5632>;
+               nvidia,i2s-controller = <&tegra_i2s1>;
+               nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
        };
 
        serial@70006000 {
        sdhci@c8000600 {
                support-8bit;
        };
+
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               power {
+                       label = "Power";
+                       gpios = <&gpio 79 1>; /* gpio PJ7, active low */
+                       linux,code = <116>; /* KEY_POWER */
+                       gpio-key,wakeup;
+               };
+       };
+
+       gpio-leds {
+               compatible = "gpio-leds";
+
+               wifi {
+                       label = "wifi-led";
+                       gpios = <&gpio 24 0>;
+                       linux,default-trigger = "rfkill0";
+               };
+       };
 };
index b55a02e..dbf1c5a 100644 (file)
 
        i2c@7000c000 {
                clock-frequency = <400000>;
+
+               wm8903: wm8903@1a {
+                       compatible = "wlf,wm8903";
+                       reg = <0x1a>;
+                       interrupt-parent = <&gpio>;
+                       interrupts = < 187 0x04 >;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       micdet-cfg = <0>;
+                       micdet-delay = <100>;
+                       gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
+               };
        };
 
        i2c@7000c400 {
                };
        };
 
+       i2s@70002a00 {
+               status = "disable";
+       };
+
+       sound {
+               compatible = "nvidia,tegra-audio-wm8903-seaboard",
+                            "nvidia,tegra-audio-wm8903";
+               nvidia,model = "NVIDIA Tegra Seaboard";
+
+               nvidia,audio-routing =
+                       "Headphone Jack", "HPOUTR",
+                       "Headphone Jack", "HPOUTL",
+                       "Int Spk", "ROP",
+                       "Int Spk", "RON",
+                       "Int Spk", "LOP",
+                       "Int Spk", "LON",
+                       "Mic Jack", "MICBIAS",
+                       "IN1R", "Mic Jack";
+
+               nvidia,i2s-controller = <&tegra_i2s1>;
+               nvidia,audio-codec = <&wm8903>;
+
+               nvidia,spkr-en-gpios = <&wm8903 2 0>;
+               nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */
+       };
+
        serial@70006000 {
                status = "disable";
        };
 
        usb@c5000000 {
                nvidia,vbus-gpio = <&gpio 24 0>; /* PD0 */
+               dr_mode = "otg";
        };
 
        gpio-keys {
                        gpio-key,wakeup;
                };
        };
+
+       emc@7000f400 {
+               emc-table@190000 {
+                       reg = < 190000 >;
+                       compatible = "nvidia,tegra20-emc-table";
+                       clock-frequency = < 190000 >;
+                       nvidia,emc-registers = < 0x0000000c 0x00000026
+                               0x00000009 0x00000003 0x00000004 0x00000004
+                               0x00000002 0x0000000c 0x00000003 0x00000003
+                               0x00000002 0x00000001 0x00000004 0x00000005
+                               0x00000004 0x00000009 0x0000000d 0x0000059f
+                               0x00000000 0x00000003 0x00000003 0x00000003
+                               0x00000003 0x00000001 0x0000000b 0x000000c8
+                               0x00000003 0x00000007 0x00000004 0x0000000f
+                               0x00000002 0x00000000 0x00000000 0x00000002
+                               0x00000000 0x00000000 0x00000083 0xa06204ae
+                               0x007dc010 0x00000000 0x00000000 0x00000000
+                               0x00000000 0x00000000 0x00000000 0x00000000 >;
+               };
+
+               emc-table@380000 {
+                       reg = < 380000 >;
+                       compatible = "nvidia,tegra20-emc-table";
+                       clock-frequency = < 380000 >;
+                       nvidia,emc-registers = < 0x00000017 0x0000004b
+                               0x00000012 0x00000006 0x00000004 0x00000005
+                               0x00000003 0x0000000c 0x00000006 0x00000006
+                               0x00000003 0x00000001 0x00000004 0x00000005
+                               0x00000004 0x00000009 0x0000000d 0x00000b5f
+                               0x00000000 0x00000003 0x00000003 0x00000006
+                               0x00000006 0x00000001 0x00000011 0x000000c8
+                               0x00000003 0x0000000e 0x00000007 0x0000000f
+                               0x00000002 0x00000000 0x00000000 0x00000002
+                               0x00000000 0x00000000 0x00000083 0xe044048b
+                               0x007d8010 0x00000000 0x00000000 0x00000000
+                               0x00000000 0x00000000 0x00000000 0x00000000 >;
+               };
+       };
 };
index 3b3ee7d..2524768 100644 (file)
                status = "disable";
        };
 
+       i2s@70002800 {
+               status = "disable";
+       };
+
+       i2s@70002a00 {
+               status = "disable";
+       };
+
+       das@70000c00 {
+               status = "disable";
+       };
+
        serial@70006000 {
                clock-frequency = < 216000000 >;
        };
index c7d3b87..2dcff87 100644 (file)
 
        i2c@7000c000 {
                clock-frequency = <400000>;
+
+               wm8903: wm8903@1a {
+                       compatible = "wlf,wm8903";
+                       reg = <0x1a>;
+                       interrupt-parent = <&gpio>;
+                       interrupts = < 187 0x04 >;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       micdet-cfg = <0>;
+                       micdet-delay = <100>;
+                       gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
+               };
        };
 
        i2c@7000c400 {
                clock-frequency = <400000>;
        };
 
+       i2s@70002a00 {
+               status = "disable";
+       };
+
+       sound {
+               compatible = "nvidia,tegra-audio-wm8903-ventana",
+                            "nvidia,tegra-audio-wm8903";
+               nvidia,model = "NVIDIA Tegra Ventana";
+
+               nvidia,audio-routing =
+                       "Headphone Jack", "HPOUTR",
+                       "Headphone Jack", "HPOUTL",
+                       "Int Spk", "ROP",
+                       "Int Spk", "RON",
+                       "Int Spk", "LOP",
+                       "Int Spk", "LON",
+                       "Mic Jack", "MICBIAS",
+                       "IN1L", "Mic Jack";
+
+               nvidia,i2s-controller = <&tegra_i2s1>;
+               nvidia,audio-codec = <&wm8903>;
+
+               nvidia,spkr-en-gpios = <&wm8903 2 0>;
+               nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+               nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
+               nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
+       };
+
        serial@70006000 {
                status = "disable";
        };
index 3da7afd..108e894 100644 (file)
@@ -4,6 +4,11 @@
        compatible = "nvidia,tegra20";
        interrupt-parent = <&intc>;
 
+       pmc@7000f400 {
+               compatible = "nvidia,tegra20-pmc";
+               reg = <0x7000e400 0x400>;
+       };
+
        intc: interrupt-controller@50041000 {
                compatible = "arm,cortex-a9-gic";
                interrupt-controller;
                      < 0x50040100 0x0100 >;
        };
 
+       pmu {
+               compatible = "arm,cortex-a9-pmu";
+               interrupts = <0 56 0x04
+                             0 57 0x04>;
+       };
+
+       apbdma: dma@6000a000 {
+               compatible = "nvidia,tegra20-apbdma";
+               reg = <0x6000a000 0x1200>;
+               interrupts = < 0 104 0x04
+                              0 105 0x04
+                              0 106 0x04
+                              0 107 0x04
+                              0 108 0x04
+                              0 109 0x04
+                              0 110 0x04
+                              0 111 0x04
+                              0 112 0x04
+                              0 113 0x04
+                              0 114 0x04
+                              0 115 0x04
+                              0 116 0x04
+                              0 117 0x04
+                              0 118 0x04
+                              0 119 0x04 >;
+       };
+
        i2c@7000c000 {
                #address-cells = <1>;
                #size-cells = <0>;
                interrupts = < 0 53 0x04 >;
        };
 
-       i2s@70002800 {
+       tegra_i2s1: i2s@70002800 {
                compatible = "nvidia,tegra20-i2s";
                reg = <0x70002800 0x200>;
                interrupts = < 0 13 0x04 >;
-               dma-channel = < 2 >;
+               nvidia,dma-request-selector = < &apbdma 2 >;
        };
 
-       i2s@70002a00 {
+       tegra_i2s2: i2s@70002a00 {
                compatible = "nvidia,tegra20-i2s";
                reg = <0x70002a00 0x200>;
                interrupts = < 0 3 0x04 >;
-               dma-channel = < 1 >;
+               nvidia,dma-request-selector = < &apbdma 1 >;
        };
 
        das@70000c00 {
                               0 89 0x04 >;
                #gpio-cells = <2>;
                gpio-controller;
+               #interrupt-cells = <2>;
+               interrupt-controller;
        };
 
        pinmux: pinmux@70000000 {
                interrupts = < 0 91 0x04 >;
        };
 
+       emc@7000f400 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-emc";
+               reg = <0x7000f400 0x200>;
+       };
+
        sdhci@c8000000 {
                compatible = "nvidia,tegra20-sdhci";
                reg = <0xc8000000 0x200>;
                reg = <0xc5000000 0x4000>;
                interrupts = < 0 20 0x04 >;
                phy_type = "utmi";
+               nvidia,has-legacy-mode;
        };
 
        usb@c5004000 {
index ee7db98..62a7b39 100644 (file)
@@ -4,6 +4,11 @@
        compatible = "nvidia,tegra30";
        interrupt-parent = <&intc>;
 
+       pmc@7000f400 {
+               compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc";
+               reg = <0x7000e400 0x400>;
+       };
+
        intc: interrupt-controller@50041000 {
                compatible = "arm,cortex-a9-gic";
                interrupt-controller;
                      < 0x50040100 0x0100 >;
        };
 
+       pmu {
+               compatible = "arm,cortex-a9-pmu";
+               interrupts = <0 144 0x04
+                             0 145 0x04
+                             0 146 0x04
+                             0 147 0x04>;
+       };
+
+       apbdma: dma@6000a000 {
+               compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma";
+               reg = <0x6000a000 0x1400>;
+               interrupts = < 0 104 0x04
+                              0 105 0x04
+                              0 106 0x04
+                              0 107 0x04
+                              0 108 0x04
+                              0 109 0x04
+                              0 110 0x04
+                              0 111 0x04
+                              0 112 0x04
+                              0 113 0x04
+                              0 114 0x04
+                              0 115 0x04
+                              0 116 0x04
+                              0 117 0x04
+                              0 118 0x04
+                              0 119 0x04
+                              0 128 0x04
+                              0 129 0x04
+                              0 130 0x04
+                              0 131 0x04
+                              0 132 0x04
+                              0 133 0x04
+                              0 134 0x04
+                              0 135 0x04
+                              0 136 0x04
+                              0 137 0x04
+                              0 138 0x04
+                              0 139 0x04
+                              0 140 0x04
+                              0 141 0x04
+                              0 142 0x04
+                              0 143 0x04 >;
+       };
+
        i2c@7000c000 {
                #address-cells = <1>;
                #size-cells = <0>;
        gpio: gpio@6000d000 {
                compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio";
                reg = < 0x6000d000 0x1000 >;
-               interrupts = < 0 32 0x04 0 33 0x04 0 34 0x04 0 35 0x04 0 55 0x04 0 87 0x04 0 89 0x04 >;
+               interrupts = < 0 32 0x04
+                              0 33 0x04
+                              0 34 0x04
+                              0 35 0x04
+                              0 55 0x04
+                              0 87 0x04
+                              0 89 0x04
+                              0 125 0x04 >;
                #gpio-cells = <2>;
                gpio-controller;
+               #interrupt-cells = <2>;
+               interrupt-controller;
        };
 
        serial@70006000 {
diff --git a/arch/arm/boot/dts/usb_a9g20-dab-mmx.dtsi b/arch/arm/boot/dts/usb_a9g20-dab-mmx.dtsi
new file mode 100644 (file)
index 0000000..ad3eca1
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * calao-dab-mmx.dtsi - Device Tree Include file for Calao DAB-MMX Daughter Board
+ *
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/ {
+       ahb {
+               apb {
+                       usart1: serial@fffb4000 {
+                               status = "okay";
+                       };
+
+                       usart3: serial@fffd0000 {
+                               status = "okay";
+                       };
+               };
+       };
+
+       i2c-gpio@0 {
+               status = "okay";
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               user_led1 {
+                       label = "user_led1";
+                       gpios = <&pioB 20 1>;
+               };
+
+/*
+* led already used by mother board but active as high
+*              user_led2 {
+*                      label = "user_led2";
+*                      gpios = <&pioB 21 1>;
+*              };
+*/
+               user_led3 {
+                       label = "user_led3";
+                       gpios = <&pioB 22 1>;
+               };
+
+               user_led4 {
+                       label = "user_led4";
+                       gpios = <&pioB 23 1>;
+               };
+
+               red {
+                       label = "red";
+                       gpios = <&pioB 24 1>;
+               };
+
+               orange {
+                       label = "orange";
+                       gpios = <&pioB 30 1>;
+               };
+
+               green {
+                       label = "green";
+                       gpios = <&pioB 31 1>;
+               };
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               user_pb1 {
+                       label = "user_pb1";
+                       gpios = <&pioB 25 1>;
+                       linux,code = <0x100>;
+               };
+
+               user_pb2 {
+                       label = "user_pb2";
+                       gpios = <&pioB 13 1>;
+                       linux,code = <0x101>;
+               };
+
+               user_pb3 {
+                       label = "user_pb3";
+                       gpios = <&pioA 26 1>;
+                       linux,code = <0x102>;
+               };
+
+               user_pb4 {
+                       label = "user_pb4";
+                       gpios = <&pioC 9 1>;
+                       linux,code = <0x103>;
+               };
+       };
+};
index f04b535..3b3c4e0 100644 (file)
        compatible = "calao,usb-a9g20", "atmel,at91sam9g20", "atmel,at91sam9";
 
        chosen {
-               bootargs = "mem=64M console=ttyS0,115200 mtdparts=atmel_nand:128k(at91bootstrap),256k(barebox)ro,128k(bareboxenv),128k(bareboxenv2),4M(kernel),120M(rootfs),-(data) root=/dev/mtdblock5 rw rootfstype=ubifs";
+               bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
        };
 
        memory@20000000 {
                reg = <0x20000000 0x4000000>;
        };
 
+       clocks {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               main_clock: clock@0 {
+                       compatible = "atmel,osc", "fixed-clock";
+                       clock-frequency = <12000000>;
+               };
+       };
+
        ahb {
                apb {
                        dbgu: serial@fffff200 {
                                phy-mode = "rmii";
                                status = "okay";
                        };
+
+                       usb1: gadget@fffa4000 {
+                               atmel,vbus-gpio = <&pioC 5 0>;
+                               status = "okay";
+                       };
+               };
+
+               nand0: nand@40000000 {
+                       nand-bus-width = <8>;
+                       nand-ecc-mode = "soft";
+                       nand-on-flash-bbt;
+                       status = "okay";
+
+                       at91bootstrap@0 {
+                               label = "at91bootstrap";
+                               reg = <0x0 0x20000>;
+                       };
+
+                       barebox@20000 {
+                               label = "barebox";
+                               reg = <0x20000 0x40000>;
+                       };
+
+                       bareboxenv@60000 {
+                               label = "bareboxenv";
+                               reg = <0x60000 0x20000>;
+                       };
+
+                       bareboxenv2@80000 {
+                               label = "bareboxenv2";
+                               reg = <0x80000 0x20000>;
+                       };
+
+                       kernel@a0000 {
+                               label = "kernel";
+                               reg = <0xa0000 0x400000>;
+                       };
+
+                       rootfs@4a0000 {
+                               label = "rootfs";
+                               reg = <0x4a0000 0x7800000>;
+                       };
+
+                       data@7ca0000 {
+                               label = "data";
+                               reg = <0x7ca0000 0x8360000>;
+                       };
+               };
+
+               usb0: ohci@00500000 {
+                       num-ports = <2>;
+                       status = "okay";
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               user_led {
+                       label = "user_led";
+                       gpios = <&pioB 21 1>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               user_pb {
+                       label = "user_pb";
+                       gpios = <&pioB 10 1>;
+                       linux,code = <28>;
+                       gpio-key,wakeup;
+               };
+       };
+
+       i2c@0 {
+               status = "okay";
+
+               rv3029c2@56 {
+                       compatible = "rv3029c2";
+                       reg = <0x56>;
                };
        };
 };
diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
new file mode 100644 (file)
index 0000000..16076e2
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * Motherboard Express uATX
+ * V2M-P1
+ *
+ * HBI-0190D
+ *
+ * RS1 memory map ("ARM Cortex-A Series memory map" in the board's
+ * Technical Reference Manual)
+ *
+ * WARNING! The hardware described in this file is independent from the
+ * original variant (vexpress-v2m.dtsi), but there is a strong
+ * correspondence between the two configurations.
+ *
+ * TAKE CARE WHEN MAINTAINING THIS FILE TO PROPAGATE ANY RELEVANT
+ * CHANGES TO vexpress-v2m.dtsi!
+ */
+
+/ {
+       aliases {
+               arm,v2m_timer = &v2m_timer01;
+       };
+
+       motherboard {
+               compatible = "simple-bus";
+               arm,v2m-memory-map = "rs1";
+               #address-cells = <2>; /* SMB chipselect number and offset */
+               #size-cells = <1>;
+               #interrupt-cells = <1>;
+
+               flash@0,00000000 {
+                       compatible = "arm,vexpress-flash", "cfi-flash";
+                       reg = <0 0x00000000 0x04000000>,
+                             <4 0x00000000 0x04000000>;
+                       bank-width = <4>;
+               };
+
+               psram@1,00000000 {
+                       compatible = "arm,vexpress-psram", "mtd-ram";
+                       reg = <1 0x00000000 0x02000000>;
+                       bank-width = <4>;
+               };
+
+               vram@2,00000000 {
+                       compatible = "arm,vexpress-vram";
+                       reg = <2 0x00000000 0x00800000>;
+               };
+
+               ethernet@2,02000000 {
+                       compatible = "smsc,lan9118", "smsc,lan9115";
+                       reg = <2 0x02000000 0x10000>;
+                       interrupts = <15>;
+                       phy-mode = "mii";
+                       reg-io-width = <4>;
+                       smsc,irq-active-high;
+                       smsc,irq-push-pull;
+               };
+
+               usb@2,03000000 {
+                       compatible = "nxp,usb-isp1761";
+                       reg = <2 0x03000000 0x20000>;
+                       interrupts = <16>;
+                       port1-otg;
+               };
+
+               iofpga@3,00000000 {
+                       compatible = "arm,amba-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 3 0 0x200000>;
+
+                       sysreg@010000 {
+                               compatible = "arm,vexpress-sysreg";
+                               reg = <0x010000 0x1000>;
+                       };
+
+                       sysctl@020000 {
+                               compatible = "arm,sp810", "arm,primecell";
+                               reg = <0x020000 0x1000>;
+                       };
+
+                       /* PCI-E I2C bus */
+                       v2m_i2c_pcie: i2c@030000 {
+                               compatible = "arm,versatile-i2c";
+                               reg = <0x030000 0x1000>;
+
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               pcie-switch@60 {
+                                       compatible = "idt,89hpes32h8";
+                                       reg = <0x60>;
+                               };
+                       };
+
+                       aaci@040000 {
+                               compatible = "arm,pl041", "arm,primecell";
+                               reg = <0x040000 0x1000>;
+                               interrupts = <11>;
+                       };
+
+                       mmci@050000 {
+                               compatible = "arm,pl180", "arm,primecell";
+                               reg = <0x050000 0x1000>;
+                               interrupts = <9 10>;
+                       };
+
+                       kmi@060000 {
+                               compatible = "arm,pl050", "arm,primecell";
+                               reg = <0x060000 0x1000>;
+                               interrupts = <12>;
+                       };
+
+                       kmi@070000 {
+                               compatible = "arm,pl050", "arm,primecell";
+                               reg = <0x070000 0x1000>;
+                               interrupts = <13>;
+                       };
+
+                       v2m_serial0: uart@090000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0x090000 0x1000>;
+                               interrupts = <5>;
+                       };
+
+                       v2m_serial1: uart@0a0000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0x0a0000 0x1000>;
+                               interrupts = <6>;
+                       };
+
+                       v2m_serial2: uart@0b0000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0x0b0000 0x1000>;
+                               interrupts = <7>;
+                       };
+
+                       v2m_serial3: uart@0c0000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0x0c0000 0x1000>;
+                               interrupts = <8>;
+                       };
+
+                       wdt@0f0000 {
+                               compatible = "arm,sp805", "arm,primecell";
+                               reg = <0x0f0000 0x1000>;
+                               interrupts = <0>;
+                       };
+
+                       v2m_timer01: timer@110000 {
+                               compatible = "arm,sp804", "arm,primecell";
+                               reg = <0x110000 0x1000>;
+                               interrupts = <2>;
+                       };
+
+                       v2m_timer23: timer@120000 {
+                               compatible = "arm,sp804", "arm,primecell";
+                               reg = <0x120000 0x1000>;
+                       };
+
+                       /* DVI I2C bus */
+                       v2m_i2c_dvi: i2c@160000 {
+                               compatible = "arm,versatile-i2c";
+                               reg = <0x160000 0x1000>;
+
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               dvi-transmitter@39 {
+                                       compatible = "sil,sii9022-tpi", "sil,sii9022";
+                                       reg = <0x39>;
+                               };
+
+                               dvi-transmitter@60 {
+                                       compatible = "sil,sii9022-cpi", "sil,sii9022";
+                                       reg = <0x60>;
+                               };
+                       };
+
+                       rtc@170000 {
+                               compatible = "arm,pl031", "arm,primecell";
+                               reg = <0x170000 0x1000>;
+                               interrupts = <4>;
+                       };
+
+                       compact-flash@1a0000 {
+                               compatible = "arm,vexpress-cf", "ata-generic";
+                               reg = <0x1a0000 0x100
+                                      0x1a0100 0xf00>;
+                               reg-shift = <2>;
+                       };
+
+                       clcd@1f0000 {
+                               compatible = "arm,pl111", "arm,primecell";
+                               reg = <0x1f0000 0x1000>;
+                               interrupts = <14>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
new file mode 100644 (file)
index 0000000..a6c9c7c
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * Motherboard Express uATX
+ * V2M-P1
+ *
+ * HBI-0190D
+ *
+ * Original memory map ("Legacy memory map" in the board's
+ * Technical Reference Manual)
+ *
+ * WARNING! The hardware described in this file is independent from the
+ * RS1 variant (vexpress-v2m-rs1.dtsi), but there is a strong
+ * correspondence between the two configurations.
+ *
+ * TAKE CARE WHEN MAINTAINING THIS FILE TO PROPAGATE ANY RELEVANT
+ * CHANGES TO vexpress-v2m-rs1.dtsi!
+ */
+
+/ {
+       aliases {
+               arm,v2m_timer = &v2m_timer01;
+       };
+
+       motherboard {
+               compatible = "simple-bus";
+               #address-cells = <2>; /* SMB chipselect number and offset */
+               #size-cells = <1>;
+               #interrupt-cells = <1>;
+
+               flash@0,00000000 {
+                       compatible = "arm,vexpress-flash", "cfi-flash";
+                       reg = <0 0x00000000 0x04000000>,
+                             <1 0x00000000 0x04000000>;
+                       bank-width = <4>;
+               };
+
+               psram@2,00000000 {
+                       compatible = "arm,vexpress-psram", "mtd-ram";
+                       reg = <2 0x00000000 0x02000000>;
+                       bank-width = <4>;
+               };
+
+               vram@3,00000000 {
+                       compatible = "arm,vexpress-vram";
+                       reg = <3 0x00000000 0x00800000>;
+               };
+
+               ethernet@3,02000000 {
+                       compatible = "smsc,lan9118", "smsc,lan9115";
+                       reg = <3 0x02000000 0x10000>;
+                       interrupts = <15>;
+                       phy-mode = "mii";
+                       reg-io-width = <4>;
+                       smsc,irq-active-high;
+                       smsc,irq-push-pull;
+               };
+
+               usb@3,03000000 {
+                       compatible = "nxp,usb-isp1761";
+                       reg = <3 0x03000000 0x20000>;
+                       interrupts = <16>;
+                       port1-otg;
+               };
+
+               iofpga@7,00000000 {
+                       compatible = "arm,amba-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 7 0 0x20000>;
+
+                       sysreg@00000 {
+                               compatible = "arm,vexpress-sysreg";
+                               reg = <0x00000 0x1000>;
+                       };
+
+                       sysctl@01000 {
+                               compatible = "arm,sp810", "arm,primecell";
+                               reg = <0x01000 0x1000>;
+                       };
+
+                       /* PCI-E I2C bus */
+                       v2m_i2c_pcie: i2c@02000 {
+                               compatible = "arm,versatile-i2c";
+                               reg = <0x02000 0x1000>;
+
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               pcie-switch@60 {
+                                       compatible = "idt,89hpes32h8";
+                                       reg = <0x60>;
+                               };
+                       };
+
+                       aaci@04000 {
+                               compatible = "arm,pl041", "arm,primecell";
+                               reg = <0x04000 0x1000>;
+                               interrupts = <11>;
+                       };
+
+                       mmci@05000 {
+                               compatible = "arm,pl180", "arm,primecell";
+                               reg = <0x05000 0x1000>;
+                               interrupts = <9 10>;
+                       };
+
+                       kmi@06000 {
+                               compatible = "arm,pl050", "arm,primecell";
+                               reg = <0x06000 0x1000>;
+                               interrupts = <12>;
+                       };
+
+                       kmi@07000 {
+                               compatible = "arm,pl050", "arm,primecell";
+                               reg = <0x07000 0x1000>;
+                               interrupts = <13>;
+                       };
+
+                       v2m_serial0: uart@09000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0x09000 0x1000>;
+                               interrupts = <5>;
+                       };
+
+                       v2m_serial1: uart@0a000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0x0a000 0x1000>;
+                               interrupts = <6>;
+                       };
+
+                       v2m_serial2: uart@0b000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0x0b000 0x1000>;
+                               interrupts = <7>;
+                       };
+
+                       v2m_serial3: uart@0c000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0x0c000 0x1000>;
+                               interrupts = <8>;
+                       };
+
+                       wdt@0f000 {
+                               compatible = "arm,sp805", "arm,primecell";
+                               reg = <0x0f000 0x1000>;
+                               interrupts = <0>;
+                       };
+
+                       v2m_timer01: timer@11000 {
+                               compatible = "arm,sp804", "arm,primecell";
+                               reg = <0x11000 0x1000>;
+                               interrupts = <2>;
+                       };
+
+                       v2m_timer23: timer@12000 {
+                               compatible = "arm,sp804", "arm,primecell";
+                               reg = <0x12000 0x1000>;
+                       };
+
+                       /* DVI I2C bus */
+                       v2m_i2c_dvi: i2c@16000 {
+                               compatible = "arm,versatile-i2c";
+                               reg = <0x16000 0x1000>;
+
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               dvi-transmitter@39 {
+                                       compatible = "sil,sii9022-tpi", "sil,sii9022";
+                                       reg = <0x39>;
+                               };
+
+                               dvi-transmitter@60 {
+                                       compatible = "sil,sii9022-cpi", "sil,sii9022";
+                                       reg = <0x60>;
+                               };
+                       };
+
+                       rtc@17000 {
+                               compatible = "arm,pl031", "arm,primecell";
+                               reg = <0x17000 0x1000>;
+                               interrupts = <4>;
+                       };
+
+                       compact-flash@1a000 {
+                               compatible = "arm,vexpress-cf", "ata-generic";
+                               reg = <0x1a000 0x100
+                                      0x1a100 0xf00>;
+                               reg-shift = <2>;
+                       };
+
+                       clcd@1f000 {
+                               compatible = "arm,pl111", "arm,primecell";
+                               reg = <0x1f000 0x1000>;
+                               interrupts = <14>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
new file mode 100644 (file)
index 0000000..941b161
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * CoreTile Express A15x2 (version with Test Chip 1)
+ * Cortex-A15 MPCore (V2P-CA15)
+ *
+ * HBI-0237A
+ */
+
+/dts-v1/;
+
+/ {
+       model = "V2P-CA15";
+       arm,hbi = <0x237>;
+       compatible = "arm,vexpress,v2p-ca15,tc1", "arm,vexpress,v2p-ca15", "arm,vexpress";
+       interrupt-parent = <&gic>;
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       chosen { };
+
+       aliases {
+               serial0 = &v2m_serial0;
+               serial1 = &v2m_serial1;
+               serial2 = &v2m_serial2;
+               serial3 = &v2m_serial3;
+               i2c0 = &v2m_i2c_dvi;
+               i2c1 = &v2m_i2c_pcie;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a15";
+                       reg = <0>;
+               };
+
+               cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a15";
+                       reg = <1>;
+               };
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0x40000000>;
+       };
+
+       hdlcd@2b000000 {
+               compatible = "arm,hdlcd";
+               reg = <0x2b000000 0x1000>;
+               interrupts = <0 85 4>;
+       };
+
+       memory-controller@2b0a0000 {
+               compatible = "arm,pl341", "arm,primecell";
+               reg = <0x2b0a0000 0x1000>;
+       };
+
+       wdt@2b060000 {
+               compatible = "arm,sp805", "arm,primecell";
+               reg = <0x2b060000 0x1000>;
+               interrupts = <98>;
+       };
+
+       gic: interrupt-controller@2c001000 {
+               compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               #address-cells = <0>;
+               interrupt-controller;
+               reg = <0x2c001000 0x1000>,
+                     <0x2c002000 0x100>;
+       };
+
+       memory-controller@7ffd0000 {
+               compatible = "arm,pl354", "arm,primecell";
+               reg = <0x7ffd0000 0x1000>;
+               interrupts = <0 86 4>,
+                            <0 87 4>;
+       };
+
+       dma@7ffb0000 {
+               compatible = "arm,pl330", "arm,primecell";
+               reg = <0x7ffb0000 0x1000>;
+               interrupts = <0 92 4>,
+                            <0 88 4>,
+                            <0 89 4>,
+                            <0 90 4>,
+                            <0 91 4>;
+       };
+
+       pmu {
+               compatible = "arm,cortex-a15-pmu", "arm,cortex-a9-pmu";
+               interrupts = <0 68 4>,
+                            <0 69 4>;
+       };
+
+       motherboard {
+               ranges = <0 0 0x08000000 0x04000000>,
+                        <1 0 0x14000000 0x04000000>,
+                        <2 0 0x18000000 0x04000000>,
+                        <3 0 0x1c000000 0x04000000>,
+                        <4 0 0x0c000000 0x04000000>,
+                        <5 0 0x10000000 0x04000000>;
+
+               interrupt-map-mask = <0 0 63>;
+               interrupt-map = <0 0  0 &gic 0  0 4>,
+                               <0 0  1 &gic 0  1 4>,
+                               <0 0  2 &gic 0  2 4>,
+                               <0 0  3 &gic 0  3 4>,
+                               <0 0  4 &gic 0  4 4>,
+                               <0 0  5 &gic 0  5 4>,
+                               <0 0  6 &gic 0  6 4>,
+                               <0 0  7 &gic 0  7 4>,
+                               <0 0  8 &gic 0  8 4>,
+                               <0 0  9 &gic 0  9 4>,
+                               <0 0 10 &gic 0 10 4>,
+                               <0 0 11 &gic 0 11 4>,
+                               <0 0 12 &gic 0 12 4>,
+                               <0 0 13 &gic 0 13 4>,
+                               <0 0 14 &gic 0 14 4>,
+                               <0 0 15 &gic 0 15 4>,
+                               <0 0 16 &gic 0 16 4>,
+                               <0 0 17 &gic 0 17 4>,
+                               <0 0 18 &gic 0 18 4>,
+                               <0 0 19 &gic 0 19 4>,
+                               <0 0 20 &gic 0 20 4>,
+                               <0 0 21 &gic 0 21 4>,
+                               <0 0 22 &gic 0 22 4>,
+                               <0 0 23 &gic 0 23 4>,
+                               <0 0 24 &gic 0 24 4>,
+                               <0 0 25 &gic 0 25 4>,
+                               <0 0 26 &gic 0 26 4>,
+                               <0 0 27 &gic 0 27 4>,
+                               <0 0 28 &gic 0 28 4>,
+                               <0 0 29 &gic 0 29 4>,
+                               <0 0 30 &gic 0 30 4>,
+                               <0 0 31 &gic 0 31 4>,
+                               <0 0 32 &gic 0 32 4>,
+                               <0 0 33 &gic 0 33 4>,
+                               <0 0 34 &gic 0 34 4>,
+                               <0 0 35 &gic 0 35 4>,
+                               <0 0 36 &gic 0 36 4>,
+                               <0 0 37 &gic 0 37 4>,
+                               <0 0 38 &gic 0 38 4>,
+                               <0 0 39 &gic 0 39 4>,
+                               <0 0 40 &gic 0 40 4>,
+                               <0 0 41 &gic 0 41 4>,
+                               <0 0 42 &gic 0 42 4>;
+       };
+};
+
+/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/arch/arm/boot/dts/vexpress-v2p-ca5s.dts
new file mode 100644 (file)
index 0000000..6905e66
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * CoreTile Express A5x2
+ * Cortex-A5 MPCore (V2P-CA5s)
+ *
+ * HBI-0225B
+ */
+
+/dts-v1/;
+
+/ {
+       model = "V2P-CA5s";
+       arm,hbi = <0x225>;
+       compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress";
+       interrupt-parent = <&gic>;
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       chosen { };
+
+       aliases {
+               serial0 = &v2m_serial0;
+               serial1 = &v2m_serial1;
+               serial2 = &v2m_serial2;
+               serial3 = &v2m_serial3;
+               i2c0 = &v2m_i2c_dvi;
+               i2c1 = &v2m_i2c_pcie;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a5";
+                       reg = <0>;
+                       next-level-cache = <&L2>;
+               };
+
+               cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a5";
+                       reg = <1>;
+                       next-level-cache = <&L2>;
+               };
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0x40000000>;
+       };
+
+       hdlcd@2a110000 {
+               compatible = "arm,hdlcd";
+               reg = <0x2a110000 0x1000>;
+               interrupts = <0 85 4>;
+       };
+
+       memory-controller@2a150000 {
+               compatible = "arm,pl341", "arm,primecell";
+               reg = <0x2a150000 0x1000>;
+       };
+
+       memory-controller@2a190000 {
+               compatible = "arm,pl354", "arm,primecell";
+               reg = <0x2a190000 0x1000>;
+               interrupts = <0 86 4>,
+                            <0 87 4>;
+       };
+
+       scu@2c000000 {
+               compatible = "arm,cortex-a5-scu";
+               reg = <0x2c000000 0x58>;
+       };
+
+       timer@2c000600 {
+               compatible = "arm,cortex-a5-twd-timer";
+               reg = <0x2c000600 0x38>;
+               interrupts = <1 2 0x304>,
+                            <1 3 0x304>;
+       };
+
+       gic: interrupt-controller@2c001000 {
+               compatible = "arm,corex-a5-gic", "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               #address-cells = <0>;
+               interrupt-controller;
+               reg = <0x2c001000 0x1000>,
+                     <0x2c000100 0x100>;
+       };
+
+       L2: cache-controller@2c0f0000 {
+               compatible = "arm,pl310-cache";
+               reg = <0x2c0f0000 0x1000>;
+               interrupts = <0 84 4>;
+               cache-level = <2>;
+       };
+
+       pmu {
+               compatible = "arm,cortex-a5-pmu", "arm,cortex-a9-pmu";
+               interrupts = <0 68 4>,
+                            <0 69 4>;
+       };
+
+       motherboard {
+               ranges = <0 0 0x08000000 0x04000000>,
+                        <1 0 0x14000000 0x04000000>,
+                        <2 0 0x18000000 0x04000000>,
+                        <3 0 0x1c000000 0x04000000>,
+                        <4 0 0x0c000000 0x04000000>,
+                        <5 0 0x10000000 0x04000000>;
+
+               interrupt-map-mask = <0 0 63>;
+               interrupt-map = <0 0  0 &gic 0  0 4>,
+                               <0 0  1 &gic 0  1 4>,
+                               <0 0  2 &gic 0  2 4>,
+                               <0 0  3 &gic 0  3 4>,
+                               <0 0  4 &gic 0  4 4>,
+                               <0 0  5 &gic 0  5 4>,
+                               <0 0  6 &gic 0  6 4>,
+                               <0 0  7 &gic 0  7 4>,
+                               <0 0  8 &gic 0  8 4>,
+                               <0 0  9 &gic 0  9 4>,
+                               <0 0 10 &gic 0 10 4>,
+                               <0 0 11 &gic 0 11 4>,
+                               <0 0 12 &gic 0 12 4>,
+                               <0 0 13 &gic 0 13 4>,
+                               <0 0 14 &gic 0 14 4>,
+                               <0 0 15 &gic 0 15 4>,
+                               <0 0 16 &gic 0 16 4>,
+                               <0 0 17 &gic 0 17 4>,
+                               <0 0 18 &gic 0 18 4>,
+                               <0 0 19 &gic 0 19 4>,
+                               <0 0 20 &gic 0 20 4>,
+                               <0 0 21 &gic 0 21 4>,
+                               <0 0 22 &gic 0 22 4>,
+                               <0 0 23 &gic 0 23 4>,
+                               <0 0 24 &gic 0 24 4>,
+                               <0 0 25 &gic 0 25 4>,
+                               <0 0 26 &gic 0 26 4>,
+                               <0 0 27 &gic 0 27 4>,
+                               <0 0 28 &gic 0 28 4>,
+                               <0 0 29 &gic 0 29 4>,
+                               <0 0 30 &gic 0 30 4>,
+                               <0 0 31 &gic 0 31 4>,
+                               <0 0 32 &gic 0 32 4>,
+                               <0 0 33 &gic 0 33 4>,
+                               <0 0 34 &gic 0 34 4>,
+                               <0 0 35 &gic 0 35 4>,
+                               <0 0 36 &gic 0 36 4>,
+                               <0 0 37 &gic 0 37 4>,
+                               <0 0 38 &gic 0 38 4>,
+                               <0 0 39 &gic 0 39 4>,
+                               <0 0 40 &gic 0 40 4>,
+                               <0 0 41 &gic 0 41 4>,
+                               <0 0 42 &gic 0 42 4>;
+       };
+};
+
+/include/ "vexpress-v2m-rs1.dtsi"
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
new file mode 100644 (file)
index 0000000..da77869
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * CoreTile Express A9x4
+ * Cortex-A9 MPCore (V2P-CA9)
+ *
+ * HBI-0191B
+ */
+
+/dts-v1/;
+
+/ {
+       model = "V2P-CA9";
+       arm,hbi = <0x191>;
+       compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
+       interrupt-parent = <&gic>;
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       chosen { };
+
+       aliases {
+               serial0 = &v2m_serial0;
+               serial1 = &v2m_serial1;
+               serial2 = &v2m_serial2;
+               serial3 = &v2m_serial3;
+               i2c0 = &v2m_i2c_dvi;
+               i2c1 = &v2m_i2c_pcie;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a9";
+                       reg = <0>;
+                       next-level-cache = <&L2>;
+               };
+
+               cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a9";
+                       reg = <1>;
+                       next-level-cache = <&L2>;
+               };
+
+               cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a9";
+                       reg = <2>;
+                       next-level-cache = <&L2>;
+               };
+
+               cpu@3 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a9";
+                       reg = <3>;
+                       next-level-cache = <&L2>;
+               };
+       };
+
+       memory@60000000 {
+               device_type = "memory";
+               reg = <0x60000000 0x40000000>;
+       };
+
+       clcd@10020000 {
+               compatible = "arm,pl111", "arm,primecell";
+               reg = <0x10020000 0x1000>;
+               interrupts = <0 44 4>;
+       };
+
+       memory-controller@100e0000 {
+               compatible = "arm,pl341", "arm,primecell";
+               reg = <0x100e0000 0x1000>;
+       };
+
+       memory-controller@100e1000 {
+               compatible = "arm,pl354", "arm,primecell";
+               reg = <0x100e1000 0x1000>;
+               interrupts = <0 45 4>,
+                            <0 46 4>;
+       };
+
+       timer@100e4000 {
+               compatible = "arm,sp804", "arm,primecell";
+               reg = <0x100e4000 0x1000>;
+               interrupts = <0 48 4>,
+                            <0 49 4>;
+       };
+
+       watchdog@100e5000 {
+               compatible = "arm,sp805", "arm,primecell";
+               reg = <0x100e5000 0x1000>;
+               interrupts = <0 51 4>;
+       };
+
+       scu@1e000000 {
+               compatible = "arm,cortex-a9-scu";
+               reg = <0x1e000000 0x58>;
+       };
+
+       timer@1e000600 {
+               compatible = "arm,cortex-a9-twd-timer";
+               reg = <0x1e000600 0x20>;
+               interrupts = <1 2 0xf04>,
+                            <1 3 0xf04>;
+       };
+
+       gic: interrupt-controller@1e001000 {
+               compatible = "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               #address-cells = <0>;
+               interrupt-controller;
+               reg = <0x1e001000 0x1000>,
+                     <0x1e000100 0x100>;
+       };
+
+       L2: cache-controller@1e00a000 {
+               compatible = "arm,pl310-cache";
+               reg = <0x1e00a000 0x1000>;
+               interrupts = <0 43 4>;
+               cache-level = <2>;
+               arm,data-latency = <1 1 1>;
+               arm,tag-latency = <1 1 1>;
+       };
+
+       pmu {
+               compatible = "arm,cortex-a9-pmu";
+               interrupts = <0 60 4>,
+                            <0 61 4>,
+                            <0 62 4>,
+                            <0 63 4>;
+       };
+
+       motherboard {
+               ranges = <0 0 0x40000000 0x04000000>,
+                        <1 0 0x44000000 0x04000000>,
+                        <2 0 0x48000000 0x04000000>,
+                        <3 0 0x4c000000 0x04000000>,
+                        <7 0 0x10000000 0x00020000>;
+
+               interrupt-map-mask = <0 0 63>;
+               interrupt-map = <0 0  0 &gic 0  0 4>,
+                               <0 0  1 &gic 0  1 4>,
+                               <0 0  2 &gic 0  2 4>,
+                               <0 0  3 &gic 0  3 4>,
+                               <0 0  4 &gic 0  4 4>,
+                               <0 0  5 &gic 0  5 4>,
+                               <0 0  6 &gic 0  6 4>,
+                               <0 0  7 &gic 0  7 4>,
+                               <0 0  8 &gic 0  8 4>,
+                               <0 0  9 &gic 0  9 4>,
+                               <0 0 10 &gic 0 10 4>,
+                               <0 0 11 &gic 0 11 4>,
+                               <0 0 12 &gic 0 12 4>,
+                               <0 0 13 &gic 0 13 4>,
+                               <0 0 14 &gic 0 14 4>,
+                               <0 0 15 &gic 0 15 4>,
+                               <0 0 16 &gic 0 16 4>,
+                               <0 0 17 &gic 0 17 4>,
+                               <0 0 18 &gic 0 18 4>,
+                               <0 0 19 &gic 0 19 4>,
+                               <0 0 20 &gic 0 20 4>,
+                               <0 0 21 &gic 0 21 4>,
+                               <0 0 22 &gic 0 22 4>,
+                               <0 0 23 &gic 0 23 4>,
+                               <0 0 24 &gic 0 24 4>,
+                               <0 0 25 &gic 0 25 4>,
+                               <0 0 26 &gic 0 26 4>,
+                               <0 0 27 &gic 0 27 4>,
+                               <0 0 28 &gic 0 28 4>,
+                               <0 0 29 &gic 0 29 4>,
+                               <0 0 30 &gic 0 30 4>,
+                               <0 0 31 &gic 0 31 4>,
+                               <0 0 32 &gic 0 32 4>,
+                               <0 0 33 &gic 0 33 4>,
+                               <0 0 34 &gic 0 34 4>,
+                               <0 0 35 &gic 0 35 4>,
+                               <0 0 36 &gic 0 36 4>,
+                               <0 0 37 &gic 0 37 4>,
+                               <0 0 38 &gic 0 38 4>,
+                               <0 0 39 &gic 0 39 4>,
+                               <0 0 40 &gic 0 40 4>,
+                               <0 0 41 &gic 0 41 4>,
+                               <0 0 42 &gic 0 42 4>;
+       };
+};
+
+/include/ "vexpress-v2m.dtsi"
index 81a933e..3bb1d75 100644 (file)
@@ -35,9 +35,6 @@ config DMABOUNCE
        bool
        select ZONE_DMA
 
-config TIMER_ACORN
-       bool
-
 config SHARP_LOCOMO
        bool
 
index 6ea9b6f..69feafe 100644 (file)
@@ -9,7 +9,6 @@ obj-$(CONFIG_PL330)             += pl330.o
 obj-$(CONFIG_SA1111)           += sa1111.o
 obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o
 obj-$(CONFIG_DMABOUNCE)                += dmabounce.o
-obj-$(CONFIG_TIMER_ACORN)      += time-acorn.o
 obj-$(CONFIG_SHARP_LOCOMO)     += locomo.o
 obj-$(CONFIG_SHARP_PARAM)      += sharpsl_param.o
 obj-$(CONFIG_SHARP_SCOOP)      += scoop.o
index fb1f1cf..dcb1349 100644 (file)
@@ -299,8 +299,8 @@ int __init it8152_pci_setup(int nr, struct pci_sys_data *sys)
                goto err1;
        }
 
-       pci_add_resource(&sys->resources, &it8152_io);
-       pci_add_resource(&sys->resources, &it8152_mem);
+       pci_add_resource_offset(&sys->resources, &it8152_io, sys->io_offset);
+       pci_add_resource_offset(&sys->resources, &it8152_mem, sys->mem_offset);
 
        if (platform_notify || platform_notify_remove) {
                printk(KERN_ERR "PCI: Can't use platform_notify\n");
index 61691cd..9173d11 100644 (file)
@@ -16,6 +16,7 @@
  */
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -28,9 +29,8 @@
 #include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/mach/irq.h>
+#include <asm/mach-types.h>
 #include <asm/sizes.h>
 
 #include <asm/hardware/sa1111.h>
 #define IRQ_S1_CD_VALID                (52)
 #define IRQ_S0_BVD1_STSCHG     (53)
 #define IRQ_S1_BVD1_STSCHG     (54)
+#define SA1111_IRQ_NR          (55)
 
-extern void __init sa1110_mb_enable(void);
+extern void sa1110_mb_enable(void);
+extern void sa1110_mb_disable(void);
 
 /*
  * We keep the following data for the overall SA1111.  Note that the
@@ -104,6 +106,7 @@ struct sa1111 {
        int             irq_base;       /* base for cascaded on-chip IRQs */
        spinlock_t      lock;
        void __iomem    *base;
+       struct sa1111_platform_data *pdata;
 #ifdef CONFIG_PM
        void            *saved_state;
 #endif
@@ -118,6 +121,7 @@ static struct sa1111 *g_sa1111;
 struct sa1111_dev_info {
        unsigned long   offset;
        unsigned long   skpcr_mask;
+       bool            dma;
        unsigned int    devid;
        unsigned int    irq[6];
 };
@@ -126,6 +130,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
        {
                .offset         = SA1111_USB,
                .skpcr_mask     = SKPCR_UCLKEN,
+               .dma            = true,
                .devid          = SA1111_DEVID_USB,
                .irq = {
                        IRQ_USBPWR,
@@ -139,6 +144,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
        {
                .offset         = 0x0600,
                .skpcr_mask     = SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
+               .dma            = true,
                .devid          = SA1111_DEVID_SAC,
                .irq = {
                        AUDXMTDMADONEA,
@@ -155,7 +161,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
        {
                .offset         = SA1111_KBD,
                .skpcr_mask     = SKPCR_PTCLKEN,
-               .devid          = SA1111_DEVID_PS2,
+               .devid          = SA1111_DEVID_PS2_KBD,
                .irq = {
                        IRQ_TPRXINT,
                        IRQ_TPTXINT
@@ -164,7 +170,7 @@ static struct sa1111_dev_info sa1111_devices[] = {
        {
                .offset         = SA1111_MSE,
                .skpcr_mask     = SKPCR_PMCLKEN,
-               .devid          = SA1111_DEVID_PS2,
+               .devid          = SA1111_DEVID_PS2_MSE,
                .irq = {
                        IRQ_MSRXINT,
                        IRQ_MSTXINT
@@ -434,16 +440,28 @@ static struct irq_chip sa1111_high_chip = {
        .irq_set_wake   = sa1111_wake_highirq,
 };
 
-static void sa1111_setup_irq(struct sa1111 *sachip)
+static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base)
 {
        void __iomem *irqbase = sachip->base + SA1111_INTC;
-       unsigned int irq;
+       unsigned i, irq;
+       int ret;
 
        /*
         * We're guaranteed that this region hasn't been taken.
         */
        request_mem_region(sachip->phys + SA1111_INTC, 512, "irq");
 
+       ret = irq_alloc_descs(-1, irq_base, SA1111_IRQ_NR, -1);
+       if (ret <= 0) {
+               dev_err(sachip->dev, "unable to allocate %u irqs: %d\n",
+                       SA1111_IRQ_NR, ret);
+               if (ret == 0)
+                       ret = -EINVAL;
+               return ret;
+       }
+
+       sachip->irq_base = ret;
+
        /* disable all IRQs */
        sa1111_writel(0, irqbase + SA1111_INTEN0);
        sa1111_writel(0, irqbase + SA1111_INTEN1);
@@ -463,14 +481,16 @@ static void sa1111_setup_irq(struct sa1111 *sachip)
        sa1111_writel(~0, irqbase + SA1111_INTSTATCLR0);
        sa1111_writel(~0, irqbase + SA1111_INTSTATCLR1);
 
-       for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
+       for (i = IRQ_GPAIN0; i <= SSPROR; i++) {
+               irq = sachip->irq_base + i;
                irq_set_chip_and_handler(irq, &sa1111_low_chip,
                                         handle_edge_irq);
                irq_set_chip_data(irq, sachip);
                set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
        }
 
-       for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) {
+       for (i = AUDXMTDMADONEA; i <= IRQ_S1_BVD1_STSCHG; i++) {
+               irq = sachip->irq_base + i;
                irq_set_chip_and_handler(irq, &sa1111_high_chip,
                                         handle_edge_irq);
                irq_set_chip_data(irq, sachip);
@@ -483,6 +503,11 @@ static void sa1111_setup_irq(struct sa1111 *sachip)
        irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING);
        irq_set_handler_data(sachip->irq, sachip);
        irq_set_chained_handler(sachip->irq, sa1111_irq_handler);
+
+       dev_info(sachip->dev, "Providing IRQ%u-%u\n",
+               sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1);
+
+       return 0;
 }
 
 /*
@@ -581,41 +606,10 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
 }
 #endif
 
-#ifdef CONFIG_DMABOUNCE
-/*
- * According to the "Intel StrongARM SA-1111 Microprocessor Companion
- * Chip Specification Update" (June 2000), erratum #7, there is a
- * significant bug in the SA1111 SDRAM shared memory controller.  If
- * an access to a region of memory above 1MB relative to the bank base,
- * it is important that address bit 10 _NOT_ be asserted. Depending
- * on the configuration of the RAM, bit 10 may correspond to one
- * of several different (processor-relative) address bits.
- *
- * This routine only identifies whether or not a given DMA address
- * is susceptible to the bug.
- *
- * This should only get called for sa1111_device types due to the
- * way we configure our device dma_masks.
- */
-static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
-{
-       /*
-        * Section 4.6 of the "Intel StrongARM SA-1111 Development Module
-        * User's Guide" mentions that jumpers R51 and R52 control the
-        * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
-        * SDRAM bank 1 on Neponset). The default configuration selects
-        * Assabet, so any address in bank 1 is necessarily invalid.
-        */
-       return (machine_is_assabet() || machine_is_pfs168()) &&
-               (addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
-}
-#endif
-
 static void sa1111_dev_release(struct device *_dev)
 {
        struct sa1111_dev *dev = SA1111_DEV(_dev);
 
-       release_resource(&dev->res);
        kfree(dev);
 }
 
@@ -624,67 +618,58 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
                      struct sa1111_dev_info *info)
 {
        struct sa1111_dev *dev;
+       unsigned i;
        int ret;
 
        dev = kzalloc(sizeof(struct sa1111_dev), GFP_KERNEL);
        if (!dev) {
                ret = -ENOMEM;
-               goto out;
+               goto err_alloc;
        }
 
+       device_initialize(&dev->dev);
        dev_set_name(&dev->dev, "%4.4lx", info->offset);
        dev->devid       = info->devid;
        dev->dev.parent  = sachip->dev;
        dev->dev.bus     = &sa1111_bus_type;
        dev->dev.release = sa1111_dev_release;
-       dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
        dev->res.start   = sachip->phys + info->offset;
        dev->res.end     = dev->res.start + 511;
        dev->res.name    = dev_name(&dev->dev);
        dev->res.flags   = IORESOURCE_MEM;
        dev->mapbase     = sachip->base + info->offset;
        dev->skpcr_mask  = info->skpcr_mask;
-       memmove(dev->irq, info->irq, sizeof(dev->irq));
-
-       ret = request_resource(parent, &dev->res);
-       if (ret) {
-               printk("SA1111: failed to allocate resource for %s\n",
-                       dev->res.name);
-               dev_set_name(&dev->dev, NULL);
-               kfree(dev);
-               goto out;
-       }
-
 
-       ret = device_register(&dev->dev);
-       if (ret) {
-               release_resource(&dev->res);
-               kfree(dev);
-               goto out;
-       }
+       for (i = 0; i < ARRAY_SIZE(info->irq); i++)
+               dev->irq[i] = sachip->irq_base + info->irq[i];
 
-#ifdef CONFIG_DMABOUNCE
        /*
-        * If the parent device has a DMA mask associated with it,
-        * propagate it down to the children.
+        * If the parent device has a DMA mask associated with it, and
+        * this child supports DMA, propagate it down to the children.
         */
-       if (sachip->dev->dma_mask) {
+       if (info->dma && sachip->dev->dma_mask) {
                dev->dma_mask = *sachip->dev->dma_mask;
                dev->dev.dma_mask = &dev->dma_mask;
+               dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
+       }
 
-               if (dev->dma_mask != 0xffffffffUL) {
-                       ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
-                                       sa1111_needs_bounce);
-                       if (ret) {
-                               dev_err(&dev->dev, "SA1111: Failed to register"
-                                       " with dmabounce\n");
-                               device_unregister(&dev->dev);
-                       }
-               }
+       ret = request_resource(parent, &dev->res);
+       if (ret) {
+               dev_err(sachip->dev, "failed to allocate resource for %s\n",
+                       dev->res.name);
+               goto err_resource;
        }
-#endif
 
-out:
+       ret = device_add(&dev->dev);
+       if (ret)
+               goto err_add;
+       return 0;
+
+ err_add:
+       release_resource(&dev->res);
+ err_resource:
+       put_device(&dev->dev);
+ err_alloc:
        return ret;
 }
 
@@ -698,16 +683,21 @@ out:
  *     Returns:
  *     %-ENODEV        device not found.
  *     %-EBUSY         physical address already marked in-use.
+ *     %-EINVAL        no platform data passed
  *     %0              successful.
  */
 static int __devinit
 __sa1111_probe(struct device *me, struct resource *mem, int irq)
 {
+       struct sa1111_platform_data *pd = me->platform_data;
        struct sa1111 *sachip;
        unsigned long id;
        unsigned int has_devs;
        int i, ret = -ENODEV;
 
+       if (!pd)
+               return -EINVAL;
+
        sachip = kzalloc(sizeof(struct sa1111), GFP_KERNEL);
        if (!sachip)
                return -ENOMEM;
@@ -727,6 +717,7 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
        sachip->dev = me;
        dev_set_drvdata(sachip->dev, sachip);
 
+       sachip->pdata = pd;
        sachip->phys = mem->start;
        sachip->irq = irq;
 
@@ -759,6 +750,16 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
         */
        sa1111_wake(sachip);
 
+       /*
+        * The interrupt controller must be initialised before any
+        * other device to ensure that the interrupts are available.
+        */
+       if (sachip->irq != NO_IRQ) {
+               ret = sa1111_setup_irq(sachip, pd->irq_base);
+               if (ret)
+                       goto err_unmap;
+       }
+
 #ifdef CONFIG_ARCH_SA1100
        {
        unsigned int val;
@@ -789,24 +790,14 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
        }
 #endif
 
-       /*
-        * The interrupt controller must be initialised before any
-        * other device to ensure that the interrupts are available.
-        */
-       if (sachip->irq != NO_IRQ)
-               sa1111_setup_irq(sachip);
-
        g_sa1111 = sachip;
 
        has_devs = ~0;
-       if (machine_is_assabet() || machine_is_jornada720() ||
-           machine_is_badge4())
-               has_devs &= ~(1 << 4);
-       else
-               has_devs &= ~(1 << 1);
+       if (pd)
+               has_devs &= ~pd->disable_devs;
 
        for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++)
-               if (has_devs & (1 << i))
+               if (sa1111_devices[i].devid & has_devs)
                        sa1111_init_one_child(sachip, mem, &sa1111_devices[i]);
 
        return 0;
@@ -824,7 +815,10 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
 
 static int sa1111_remove_one(struct device *dev, void *data)
 {
-       device_unregister(dev);
+       struct sa1111_dev *sadev = SA1111_DEV(dev);
+       device_del(&sadev->dev);
+       release_resource(&sadev->res);
+       put_device(&sadev->dev);
        return 0;
 }
 
@@ -846,6 +840,7 @@ static void __sa1111_remove(struct sa1111 *sachip)
        if (sachip->irq != NO_IRQ) {
                irq_set_chained_handler(sachip->irq, NULL);
                irq_set_handler_data(sachip->irq, NULL);
+               irq_free_descs(sachip->irq_base, SA1111_IRQ_NR);
 
                release_mem_region(sachip->phys + SA1111_INTC, 512);
        }
@@ -904,6 +899,9 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
        save->skpwm0   = sa1111_readl(base + SA1111_SKPWM0);
        save->skpwm1   = sa1111_readl(base + SA1111_SKPWM1);
 
+       sa1111_writel(0, sachip->base + SA1111_SKPWM0);
+       sa1111_writel(0, sachip->base + SA1111_SKPWM1);
+
        base = sachip->base + SA1111_INTC;
        save->intpol0  = sa1111_readl(base + SA1111_INTPOL0);
        save->intpol1  = sa1111_readl(base + SA1111_INTPOL1);
@@ -919,13 +917,15 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
         */
        val = sa1111_readl(sachip->base + SA1111_SKCR);
        sa1111_writel(val | SKCR_SLEEP, sachip->base + SA1111_SKCR);
-       sa1111_writel(0, sachip->base + SA1111_SKPWM0);
-       sa1111_writel(0, sachip->base + SA1111_SKPWM1);
 
        clk_disable(sachip->clk);
 
        spin_unlock_irqrestore(&sachip->lock, flags);
 
+#ifdef CONFIG_ARCH_SA1100
+       sa1110_mb_disable();
+#endif
+
        return 0;
 }
 
@@ -966,6 +966,11 @@ static int sa1111_resume(struct platform_device *dev)
         */
        sa1111_wake(sachip);
 
+#ifdef CONFIG_ARCH_SA1100
+       /* Enable the memory bus request/grant signals */
+       sa1110_mb_enable();
+#endif
+
        /*
         * Only lock for write ops. Also, sa1111_wake must be called with
         * released spinlock!
@@ -1053,6 +1058,7 @@ static struct platform_driver sa1111_device_driver = {
        .resume         = sa1111_resume,
        .driver         = {
                .name   = "sa1111",
+               .owner  = THIS_MODULE,
        },
 };
 
@@ -1238,16 +1244,23 @@ EXPORT_SYMBOL(sa1111_set_sleep_io);
  *     sa1111_enable_device - enable an on-chip SA1111 function block
  *     @sadev: SA1111 function block device to enable
  */
-void sa1111_enable_device(struct sa1111_dev *sadev)
+int sa1111_enable_device(struct sa1111_dev *sadev)
 {
        struct sa1111 *sachip = sa1111_chip_driver(sadev);
        unsigned long flags;
        unsigned int val;
+       int ret = 0;
 
-       spin_lock_irqsave(&sachip->lock, flags);
-       val = sa1111_readl(sachip->base + SA1111_SKPCR);
-       sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
-       spin_unlock_irqrestore(&sachip->lock, flags);
+       if (sachip->pdata && sachip->pdata->enable)
+               ret = sachip->pdata->enable(sachip->pdata->data, sadev->devid);
+
+       if (ret == 0) {
+               spin_lock_irqsave(&sachip->lock, flags);
+               val = sa1111_readl(sachip->base + SA1111_SKPCR);
+               sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
+               spin_unlock_irqrestore(&sachip->lock, flags);
+       }
+       return ret;
 }
 EXPORT_SYMBOL(sa1111_enable_device);
 
@@ -1265,6 +1278,9 @@ void sa1111_disable_device(struct sa1111_dev *sadev)
        val = sa1111_readl(sachip->base + SA1111_SKPCR);
        sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
        spin_unlock_irqrestore(&sachip->lock, flags);
+
+       if (sachip->pdata && sachip->pdata->disable)
+               sachip->pdata->disable(sachip->pdata->data, sadev->devid);
 }
 EXPORT_SYMBOL(sa1111_disable_device);
 
@@ -1279,7 +1295,7 @@ static int sa1111_match(struct device *_dev, struct device_driver *_drv)
        struct sa1111_dev *dev = SA1111_DEV(_dev);
        struct sa1111_driver *drv = SA1111_DRV(_drv);
 
-       return dev->devid == drv->devid;
+       return dev->devid & drv->devid;
 }
 
 static int sa1111_bus_suspend(struct device *dev, pm_message_t state)
@@ -1304,6 +1320,14 @@ static int sa1111_bus_resume(struct device *dev)
        return ret;
 }
 
+static void sa1111_bus_shutdown(struct device *dev)
+{
+       struct sa1111_driver *drv = SA1111_DRV(dev->driver);
+
+       if (drv && drv->shutdown)
+               drv->shutdown(SA1111_DEV(dev));
+}
+
 static int sa1111_bus_probe(struct device *dev)
 {
        struct sa1111_dev *sadev = SA1111_DEV(dev);
@@ -1333,6 +1357,7 @@ struct bus_type sa1111_bus_type = {
        .remove         = sa1111_bus_remove,
        .suspend        = sa1111_bus_suspend,
        .resume         = sa1111_bus_resume,
+       .shutdown       = sa1111_bus_shutdown,
 };
 EXPORT_SYMBOL(sa1111_bus_type);
 
@@ -1349,9 +1374,70 @@ void sa1111_driver_unregister(struct sa1111_driver *driver)
 }
 EXPORT_SYMBOL(sa1111_driver_unregister);
 
+#ifdef CONFIG_DMABOUNCE
+/*
+ * According to the "Intel StrongARM SA-1111 Microprocessor Companion
+ * Chip Specification Update" (June 2000), erratum #7, there is a
+ * significant bug in the SA1111 SDRAM shared memory controller.  If
+ * an access to a region of memory above 1MB relative to the bank base,
+ * it is important that address bit 10 _NOT_ be asserted. Depending
+ * on the configuration of the RAM, bit 10 may correspond to one
+ * of several different (processor-relative) address bits.
+ *
+ * This routine only identifies whether or not a given DMA address
+ * is susceptible to the bug.
+ *
+ * This should only get called for sa1111_device types due to the
+ * way we configure our device dma_masks.
+ */
+static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
+{
+       /*
+        * Section 4.6 of the "Intel StrongARM SA-1111 Development Module
+        * User's Guide" mentions that jumpers R51 and R52 control the
+        * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
+        * SDRAM bank 1 on Neponset). The default configuration selects
+        * Assabet, so any address in bank 1 is necessarily invalid.
+        */
+       return (machine_is_assabet() || machine_is_pfs168()) &&
+               (addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
+}
+
+static int sa1111_notifier_call(struct notifier_block *n, unsigned long action,
+       void *data)
+{
+       struct sa1111_dev *dev = SA1111_DEV(data);
+
+       switch (action) {
+       case BUS_NOTIFY_ADD_DEVICE:
+               if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL) {
+                       int ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
+                                       sa1111_needs_bounce);
+                       if (ret)
+                               dev_err(&dev->dev, "failed to register with dmabounce: %d\n", ret);
+               }
+               break;
+
+       case BUS_NOTIFY_DEL_DEVICE:
+               if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL)
+                       dmabounce_unregister_dev(&dev->dev);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block sa1111_bus_notifier = {
+       .notifier_call = sa1111_notifier_call,
+};
+#endif
+
 static int __init sa1111_init(void)
 {
        int ret = bus_register(&sa1111_bus_type);
+#ifdef CONFIG_DMABOUNCE
+       if (ret == 0)
+               bus_register_notifier(&sa1111_bus_type, &sa1111_bus_notifier);
+#endif
        if (ret == 0)
                platform_driver_register(&sa1111_device_driver);
        return ret;
@@ -1360,6 +1446,9 @@ static int __init sa1111_init(void)
 static void __exit sa1111_exit(void)
 {
        platform_driver_unregister(&sa1111_device_driver);
+#ifdef CONFIG_DMABOUNCE
+       bus_unregister_notifier(&sa1111_bus_type, &sa1111_bus_notifier);
+#endif
        bus_unregister(&sa1111_bus_type);
 }
 
diff --git a/arch/arm/common/time-acorn.c b/arch/arm/common/time-acorn.c
deleted file mode 100644 (file)
index deeed56..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *  linux/arch/arm/common/time-acorn.c
- *
- *  Copyright (c) 1996-2000 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Changelog:
- *   24-Sep-1996       RMK     Created
- *   10-Oct-1996       RMK     Brought up to date with arch-sa110eval
- *   04-Dec-1997       RMK     Updated for new arch/arm/time.c
- *   13=Jun-2004       DS      Moved to arch/arm/common b/c shared w/CLPS7500
- */
-#include <linux/timex.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/hardware/ioc.h>
-
-#include <asm/mach/time.h>
-
-unsigned long ioc_timer_gettimeoffset(void)
-{
-       unsigned int count1, count2, status;
-       long offset;
-
-       ioc_writeb (0, IOC_T0LATCH);
-       barrier ();
-       count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
-       barrier ();
-       status = ioc_readb(IOC_IRQREQA);
-       barrier ();
-       ioc_writeb (0, IOC_T0LATCH);
-       barrier ();
-       count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
-
-       offset = count2;
-       if (count2 < count1) {
-               /*
-                * We have not had an interrupt between reading count1
-                * and count2.
-                */
-               if (status & (1 << 5))
-                       offset -= LATCH;
-       } else if (count2 > count1) {
-               /*
-                * We have just had another interrupt between reading
-                * count1 and count2.
-                */
-               offset -= LATCH;
-       }
-
-       offset = (LATCH - offset) * (tick_nsec / 1000);
-       return (offset + LATCH/2) / LATCH;
-}
-
-void __init ioctime_init(void)
-{
-       ioc_writeb(LATCH & 255, IOC_T0LTCHL);
-       ioc_writeb(LATCH >> 8, IOC_T0LTCHH);
-       ioc_writeb(0, IOC_T0GO);
-}
-
-static irqreturn_t
-ioc_timer_interrupt(int irq, void *dev_id)
-{
-       timer_tick();
-       return IRQ_HANDLED;
-}
-
-static struct irqaction ioc_timer_irq = {
-       .name           = "timer",
-       .flags          = IRQF_DISABLED,
-       .handler        = ioc_timer_interrupt
-};
-
-/*
- * Set up timer interrupt.
- */
-static void __init ioc_timer_init(void)
-{
-       ioctime_init();
-       setup_irq(IRQ_TIMER, &ioc_timer_irq);
-}
-
-struct sys_timer ioc_timer = {
-       .init           = ioc_timer_init,
-       .offset         = ioc_timer_gettimeoffset,
-};
-
index 8794a34..df13a3f 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 
+#include <asm/sched_clock.h>
 #include <asm/hardware/arm_timer.h>
 
 static long __init sp804_get_clock_rate(const char *name)
@@ -67,7 +68,16 @@ static long __init sp804_get_clock_rate(const char *name)
        return rate;
 }
 
-void __init sp804_clocksource_init(void __iomem *base, const char *name)
+static void __iomem *sched_clock_base;
+
+static u32 sp804_read(void)
+{
+       return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
+}
+
+void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
+                                                    const char *name,
+                                                    int use_sched_clock)
 {
        long rate = sp804_get_clock_rate(name);
 
@@ -83,6 +93,11 @@ void __init sp804_clocksource_init(void __iomem *base, const char *name)
 
        clocksource_mmio_init(base + TIMER_VALUE, name,
                rate, 200, 32, clocksource_mmio_readl_down);
+
+       if (use_sched_clock) {
+               sched_clock_base = base;
+               setup_sched_clock(sp804_read, 32, rate);
+       }
 }
 
 
diff --git a/arch/arm/configs/at91cap9_defconfig b/arch/arm/configs/at91cap9_defconfig
deleted file mode 100644 (file)
index 8826eb2..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91CAP9=y
-CONFIG_MACH_AT91CAP9ADK=y
-CONFIG_MTD_AT91_DATAFLASH_CARD=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_AEABI=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=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_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_NETDEVICES=y
-CONFIG_MII=y
-CONFIG_MACB=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ADS7846=y
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_FB=y
-CONFIG_FB_ATMEL=y
-CONFIG_LOGO=y
-# CONFIG_LOGO_LINUX_MONO is not set
-# CONFIG_LOGO_LINUX_CLUT224 is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_ETH=m
-CONFIG_USB_FILE_STORAGE=m
-CONFIG_MMC=y
-CONFIG_MMC_AT91=m
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91SAM9=y
-CONFIG_EXT2_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_USER=y
index 9123568..994d331 100644 (file)
@@ -74,6 +74,8 @@ CONFIG_LEGACY_PTY_COUNT=16
 CONFIG_SERIAL_ATMEL=y
 CONFIG_SERIAL_ATMEL_CONSOLE=y
 CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_GPIO=y
 CONFIG_SPI=y
 CONFIG_SPI_ATMEL=y
 CONFIG_SPI_SPIDEV=y
@@ -105,6 +107,7 @@ CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_RV3029C2=y
 CONFIG_RTC_DRV_AT91SAM9=y
 CONFIG_EXT2_FS=y
 CONFIG_MSDOS_FS=y
index a22e930..b5ac644 100644 (file)
@@ -45,6 +45,7 @@ CONFIG_FPE_NWFPE=y
 CONFIG_FPE_NWFPE_XP=y
 CONFIG_PM_DEBUG=y
 CONFIG_NET=y
+CONFIG_SMSC911X=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -68,6 +69,7 @@ CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_ADV_OPTIONS=y
 CONFIG_MTD_CFI_GEOMETRY=y
 # CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
 # CONFIG_MTD_CFI_I2 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_PHYSMAP=y
@@ -78,6 +80,8 @@ CONFIG_MISC_DEVICES=y
 CONFIG_EEPROM_AT24=y
 CONFIG_EEPROM_AT25=y
 CONFIG_NETDEVICES=y
+CONFIG_CS89x0=y
+CONFIG_CS89x0_PLATFORM=y
 CONFIG_DM9000=y
 CONFIG_SMC91X=y
 CONFIG_SMC911X=y
@@ -115,6 +119,21 @@ CONFIG_FB_IMX=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LCD_L4F00242T03=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_MEDIA=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_DMA_CONTIG=y
+CONFIG_VIDEOBUF2_CORE=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_OV2640=y
+CONFIG_VIDEO_MX2_HOSTSUPPORT=y
+CONFIG_VIDEO_MX2=y
 CONFIG_BACKLIGHT_PWM=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FONTS=y
index 3a4fb2e..dc6f641 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_CGROUPS=y
 CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_COMPAT_BRK is not set
@@ -12,7 +13,6 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_ARCH_MXC=y
 CONFIG_MACH_MX31LILLY=y
@@ -26,7 +26,6 @@ CONFIG_MACH_ARMADILLO5X0=y
 CONFIG_MACH_KZM_ARM11_01=y
 CONFIG_MACH_PCM043=y
 CONFIG_MACH_MX35_3DS=y
-CONFIG_MACH_EUKREA_CPUIMX35=y
 CONFIG_MACH_VPR200=y
 CONFIG_MACH_IMX51_DT=y
 CONFIG_MACH_MX51_3DS=y
@@ -82,8 +81,9 @@ CONFIG_PATA_IMX=y
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_CHELSIO is not set
+CONFIG_CS89x0=y
+CONFIG_CS89x0_PLATFORM=y
 # CONFIG_NET_VENDOR_FARADAY is not set
-CONFIG_FEC=y
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
@@ -126,7 +126,40 @@ CONFIG_WATCHDOG=y
 CONFIG_IMX2_WDT=y
 CONFIG_MFD_MC13XXX=y
 CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_MC13783=y
 CONFIG_REGULATOR_MC13892=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF2_CORE=y
+CONFIG_VIDEOBUF2_MEMOPS=y
+CONFIG_VIDEOBUF2_DMA_CONTIG=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_OV2640=y
+CONFIG_MX3_VIDEO=y
+CONFIG_VIDEO_MX3=y
+CONFIG_FB=y
+CONFIG_FB_MX3=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_L4F00242T03=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_MXC=y
diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig
new file mode 100644 (file)
index 0000000..fb20881
--- /dev/null
@@ -0,0 +1,145 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_LPC32XX=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200n81 root=/dev/ram0"
+CONFIG_CPU_IDLE=y
+CONFIG_FPE_NWFPE=y
+CONFIG_VFP=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=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_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_MUSEUM_IDS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_MISC_DEVICES=y
+CONFIG_EEPROM_AT25=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_PHYLIB=y
+CONFIG_SMSC_PHY=y
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_LPC32XX=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PNX=y
+CONFIG_SPI=y
+CONFIG_SPI_PL022=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_PNX4008_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=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_SEQUENCER=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_DYNAMIC_MINORS=y
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_SOC=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_MMC=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_ARMMMCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_RTC_DRV_LPC32XX=y
+CONFIG_EXT2_FS=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_WBUF_VERIFY=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_FTRACE is not set
+# CONFIG_ARM_UNWIND is not set
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
index 443675d..a691ef4 100644 (file)
@@ -101,7 +101,7 @@ CONFIG_MFD_ASIC3=y
 CONFIG_HTC_EGPIO=y
 CONFIG_HTC_PASIC3=y
 CONFIG_REGULATOR=y
-CONFIG_REGULATOR_BQ24022=y
+CONFIG_REGULATOR_GPIO=y
 CONFIG_FB=y
 CONFIG_FB_PXA=y
 CONFIG_FB_PXA_OVERLAY=y
index 2472a95..42da918 100644 (file)
@@ -13,7 +13,7 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_BLK_DEV_INTEGRITY=y
-CONFIG_ARCH_S3C2410=y
+CONFIG_ARCH_S3C24XX=y
 CONFIG_S3C_ADC=y
 CONFIG_S3C24XX_PWM=y
 CONFIG_MACH_MINI2440=y
index 6ee781b..1ebbf45 100644 (file)
@@ -77,10 +77,10 @@ CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
-CONFIG_I2C=m
+CONFIG_I2C=y
 # CONFIG_I2C_COMPAT is not set
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_MXS=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MXS=y
 CONFIG_SPI=y
 CONFIG_SPI_GPIO=m
 CONFIG_DEBUG_GPIO=y
@@ -90,6 +90,20 @@ CONFIG_GPIO_SYSFS=y
 CONFIG_DISPLAY_SUPPORT=m
 # CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+CONFIG_SND_DRIVERS=y
+CONFIG_SND_ARM=y
+CONFIG_SND_SOC=y
+CONFIG_SND_MXS_SOC=y
+CONFIG_SND_SOC_MXS_SGTL5000=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+CONFIG_SND_SOC_SGTL5000=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_MMC=y
 CONFIG_MMC_MXS=y
 CONFIG_RTC_CLASS=y
index f9096c1..193448f 100644 (file)
@@ -3,40 +3,47 @@ CONFIG_SYSVIPC=y
 CONFIG_IKCONFIG=m
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_S3C2410=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_ARCH_S3C24XX=y
 CONFIG_S3C_BOOT_ERROR_RESET=y
 CONFIG_S3C_ADC=y
 CONFIG_S3C24XX_PWM=y
-CONFIG_ARCH_SMDK2410=y
+CONFIG_CPU_S3C2412=y
+CONFIG_CPU_S3C2416=y
+CONFIG_CPU_S3C2440=y
+CONFIG_CPU_S3C2442=y
+CONFIG_CPU_S3C2443=y
+CONFIG_MACH_AML_M5900=y
+CONFIG_ARCH_BAST=y
 CONFIG_ARCH_H1940=y
 CONFIG_MACH_N30=y
-CONFIG_ARCH_BAST=y
 CONFIG_MACH_OTOM=y
-CONFIG_MACH_AML_M5900=y
+CONFIG_MACH_QT2410=y
+CONFIG_ARCH_SMDK2410=y
 CONFIG_MACH_TCT_HAMMER=y
 CONFIG_MACH_VR1000=y
-CONFIG_MACH_QT2410=y
 CONFIG_MACH_JIVE=y
 CONFIG_MACH_SMDK2412=y
 CONFIG_MACH_VSTMS=y
 CONFIG_MACH_SMDK2416=y
 CONFIG_MACH_ANUBIS=y
-CONFIG_MACH_NEO1973_GTA02=y
+CONFIG_MACH_AT2440EVB=y
+CONFIG_MACH_MINI2440=y
+CONFIG_MACH_NEXCODER_2440=y
 CONFIG_MACH_OSIRIS=y
 CONFIG_MACH_OSIRIS_DVS=m
 CONFIG_MACH_RX3715=y
 CONFIG_ARCH_S3C2440=y
-CONFIG_MACH_NEXCODER_2440=y
-CONFIG_SMDK2440_CPU2442=y
-CONFIG_MACH_AT2440EVB=y
-CONFIG_MACH_MINI2440=y
+CONFIG_MACH_NEO1973_GTA02=y
 CONFIG_MACH_RX1950=y
+CONFIG_SMDK2440_CPU2442=y
 CONFIG_MACH_SMDK2443=y
 # CONFIG_ARM_THUMB is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
@@ -45,7 +52,6 @@ CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0"
 CONFIG_FPE_NWFPE=y
 CONFIG_FPE_NWFPE_XP=y
 CONFIG_BINFMT_AOUT=y
-CONFIG_PM=y
 CONFIG_APM_EMULATION=m
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -58,7 +64,6 @@ CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
@@ -80,7 +85,6 @@ CONFIG_IPV6_MIP6=m
 CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
 CONFIG_IPV6_TUNNEL=m
 CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_EVENTS=y
 CONFIG_NF_CT_PROTO_DCCP=m
@@ -138,7 +142,6 @@ CONFIG_IP_VS=m
 CONFIG_NF_CONNTRACK_IPV4=m
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
 CONFIG_IP_NF_MATCH_AH=m
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_TTL=m
@@ -150,7 +153,6 @@ CONFIG_NF_NAT=m
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_NETMAP=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_NF_NAT_SNMP_BASIC=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_CLUSTERIP=m
 CONFIG_IP_NF_TARGET_ECN=m
@@ -177,8 +179,6 @@ CONFIG_IP6_NF_TARGET_REJECT=m
 CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
 CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
 CONFIG_BT_RFCOMM=m
 CONFIG_BT_RFCOMM_TTY=y
 CONFIG_BT_BNEP=m
@@ -199,7 +199,6 @@ CONFIG_MAC80211_MESH=y
 CONFIG_MAC80211_LEDS=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_REDBOOT_PARTS=y
 CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -221,9 +220,6 @@ CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_UB=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_ATA_OVER_ETH=m
-CONFIG_EEPROM_AT25=m
-CONFIG_EEPROM_LEGACY=m
-CONFIG_EEPROM_93CX6=m
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
@@ -240,7 +236,6 @@ CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
 CONFIG_DM9000=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_MOUSE_APPLETOUCH=m
@@ -274,7 +269,6 @@ CONFIG_JOYSTICK_XPAD_LEDS=y
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
 CONFIG_INPUT_MISC=y
-CONFIG_INPUT_ATI_REMOTE=m
 CONFIG_INPUT_ATI_REMOTE2=m
 CONFIG_INPUT_KEYSPAN_REMOTE=m
 CONFIG_INPUT_POWERMATE=m
@@ -300,7 +294,6 @@ CONFIG_I2C_SIMTEC=y
 CONFIG_SPI=y
 CONFIG_SPI_GPIO=m
 CONFIG_SPI_S3C24XX=m
-CONFIG_SPI_S3C24XX_GPIO=m
 CONFIG_SPI_SPIDEV=m
 CONFIG_SPI_TLE62X0=m
 CONFIG_SENSORS_LM75=m
@@ -315,7 +308,6 @@ CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_S3C2410=y
 CONFIG_FB_SM501=y
 CONFIG_BACKLIGHT_PWM=m
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_SOUND=y
 CONFIG_SND=y
@@ -330,10 +322,6 @@ CONFIG_SND_VERBOSE_PRINTK=y
 CONFIG_SND_USB_AUDIO=m
 CONFIG_SND_USB_CAIAQ=m
 CONFIG_SND_SOC=y
-CONFIG_SND_S3C24XX_SOC=y
-CONFIG_SND_S3C24XX_SOC_JIVE_WM8750=m
-CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710=m
-CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650=m
 # CONFIG_USB_HID is not set
 CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
@@ -387,9 +375,7 @@ CONFIG_MMC_TEST=m
 CONFIG_MMC_SDHCI=m
 CONFIG_MMC_SPI=m
 CONFIG_MMC_S3C=y
-CONFIG_LEDS_CLASS=m
 CONFIG_LEDS_S3C24XX=m
-CONFIG_LEDS_H1940=m
 CONFIG_LEDS_PCA9532=m
 CONFIG_LEDS_GPIO=m
 CONFIG_LEDS_PCA955X=m
@@ -410,8 +396,6 @@ CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT4_FS=m
 CONFIG_EXT4_FS_POSIX_ACL=y
-CONFIG_INOTIFY=y
-CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=m
 CONFIG_ISO9660_FS=y
@@ -436,9 +420,6 @@ CONFIG_NFSD=m
 CONFIG_NFSD_V3_ACL=y
 CONFIG_NFSD_V4=y
 CONFIG_CIFS=m
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_SOLARIS_X86_PARTITION=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_737=m
 CONFIG_NLS_CODEPAGE_775=m
@@ -481,9 +462,7 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 95c0f0d..1d24f84 100644 (file)
@@ -14,7 +14,7 @@ CONFIG_SLOB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_S3C2410=y
+CONFIG_ARCH_S3C24XX=y
 CONFIG_MACH_TCT_HAMMER=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
index fd5d304..351d670 100644 (file)
@@ -11,11 +11,14 @@ CONFIG_RT_GROUP_SCHED=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_ELF_CORE is not set
 CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARCH_TEGRA=y
@@ -27,18 +30,20 @@ CONFIG_MACH_PAZ00=y
 CONFIG_MACH_TRIMSLICE=y
 CONFIG_MACH_WARIO=y
 CONFIG_MACH_VENTANA=y
-CONFIG_TEGRA_DEBUG_UARTD=y
-CONFIG_ARM_ERRATA_742230=y
+CONFIG_TEGRA_EMC_SCALING_ENABLE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
-CONFIG_NR_CPUS=2
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 # CONFIG_OABI_COMPAT is not set
 CONFIG_HIGHMEM=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_IDLE=y
 CONFIG_VFP=y
 CONFIG_NET=y
 CONFIG_PACKET=y
@@ -68,7 +73,6 @@ CONFIG_IPV6_MULTIPLE_TABLES=y
 # CONFIG_FIRMWARE_IN_KERNEL is not set
 CONFIG_PROC_DEVICETREE=y
 CONFIG_BLK_DEV_LOOP=y
-CONFIG_MISC_DEVICES=y
 CONFIG_AD525X_DPOT=y
 CONFIG_AD525X_DPOT_I2C=y
 CONFIG_ICS932S401=y
@@ -76,6 +80,7 @@ CONFIG_APDS9802ALS=y
 CONFIG_ISL29003=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
@@ -85,8 +90,7 @@ CONFIG_USB_USBNET=y
 CONFIG_USB_NET_SMSC75XX=y
 CONFIG_USB_NET_SMSC95XX=y
 # CONFIG_WLAN is not set
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
+CONFIG_INPUT_EVDEV=y
 # CONFIG_VT is not set
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
@@ -96,13 +100,15 @@ CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 # CONFIG_I2C_COMPAT is not set
-# CONFIG_I2C_HELPER_AUTO is not set
 CONFIG_I2C_TEGRA=y
 CONFIG_SPI=y
 CONFIG_SPI_TEGRA=y
 CONFIG_SENSORS_LM90=y
 CONFIG_MFD_TPS6586X=y
 CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_GPIO=y
 CONFIG_REGULATOR_TPS6586X=y
 CONFIG_SOUND=y
 CONFIG_SND=y
@@ -116,11 +122,13 @@ CONFIG_SND_SOC=y
 CONFIG_SND_SOC_TEGRA=y
 CONFIG_SND_SOC_TEGRA_WM8903=y
 CONFIG_SND_SOC_TEGRA_TRIMSLICE=y
+CONFIG_SND_SOC_TEGRA_ALC5632=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_TEGRA=y
 CONFIG_USB_STORAGE=y
 CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=16
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_TEGRA=y
@@ -130,6 +138,11 @@ CONFIG_STAGING=y
 CONFIG_IIO=y
 CONFIG_SENSORS_ISL29018=y
 CONFIG_SENSORS_AK8975=y
+CONFIG_MFD_NVEC=y
+CONFIG_KEYBOARD_NVEC=y
+CONFIG_SERIO_NVEC_PS2=y
+CONFIG_TEGRA_IOMMU_GART=y
+CONFIG_TEGRA_IOMMU_SMMU=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
@@ -138,13 +151,12 @@ CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
 # CONFIG_DNOTIFY is not set
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_EFI_PARTITION=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
@@ -162,9 +174,8 @@ CONFIG_DEBUG_SG=y
 CONFIG_DEBUG_LL=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_TWOFISH=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TEGRA_AES=y
 CONFIG_CRC_CCITT=y
-CONFIG_CRC16=y
index 2d7b6e7..889d73a 100644 (file)
@@ -13,6 +13,7 @@ CONFIG_UX500_SOC_DB8500=y
 CONFIG_MACH_HREFV60=y
 CONFIG_MACH_SNOWBALL=y
 CONFIG_MACH_U5500=y
+CONFIG_MACH_UX500_DT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
index c0f4e7b..d6030ff 100644 (file)
@@ -9,7 +9,12 @@
  *
  * Integrator AP has 16-bit timers, Integrator CP, Versatile and Realview
  * can have 16-bit or 32-bit selectable via a bit in the control register.
+ *
+ * Every SP804 contains two identical timers.
  */
+#define TIMER_1_BASE   0x00
+#define TIMER_2_BASE   0x20
+
 #define TIMER_LOAD     0x00                    /* ACVR rw */
 #define TIMER_VALUE    0x04                    /* ACVR ro */
 #define TIMER_CTRL     0x08                    /* ACVR rw */
index e0af498..8c215ac 100644 (file)
 /* IOC / IOMD based hardware */
 #include <asm/hardware/iomd.h>
 
-               .macro  disable_fiq
-               mov     r12, #ioc_base_high
-               .if     ioc_base_low
-               orr     r12, r12, #ioc_base_low
-               .endif
-               strb    r12, [r12, #0x38]       @ Disable FIQ register
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldrb    \irqstat, [\base, #IOMD_IRQREQB]        @ get high priority first
                ldr     \tmp, =irq_prio_h
index 92ed254..7c2bbc7 100644 (file)
 #define SKPCR_DCLKEN   (1<<7)
 #define SKPCR_PWMCLKEN (1<<8)
 
-/*
- * USB Host controller
- */
+/* USB Host controller */
 #define SA1111_USB             0x0400
 
 /*
- * Offsets from SA1111_USB_BASE
- */
-#define SA1111_USB_STATUS      0x0118
-#define SA1111_USB_RESET       0x011c
-#define SA1111_USB_IRQTEST     0x0120
-
-#define USB_RESET_FORCEIFRESET (1 << 0)
-#define USB_RESET_FORCEHCRESET (1 << 1)
-#define USB_RESET_CLKGENRESET  (1 << 2)
-#define USB_RESET_SIMSCALEDOWN (1 << 3)
-#define USB_RESET_USBINTTEST   (1 << 4)
-#define USB_RESET_SLEEPSTBYEN  (1 << 5)
-#define USB_RESET_PWRSENSELOW  (1 << 6)
-#define USB_RESET_PWRCTRLLOW   (1 << 7)
-
-#define USB_STATUS_IRQHCIRMTWKUP  (1 <<  7)
-#define USB_STATUS_IRQHCIBUFFACC  (1 <<  8)
-#define USB_STATUS_NIRQHCIM       (1 <<  9)
-#define USB_STATUS_NHCIMFCLR      (1 << 10)
-#define USB_STATUS_USBPWRSENSE    (1 << 11)
-
-/*
  * Serial Audio Controller
  *
  * Registers
  *    PC_SSR           GPIO Block C Sleep State
  */
 
-#define _PA_DDR                _SA1111( 0x1000 )
-#define _PA_DRR                _SA1111( 0x1004 )
-#define _PA_DWR                _SA1111( 0x1004 )
-#define _PA_SDR                _SA1111( 0x1008 )
-#define _PA_SSR                _SA1111( 0x100c )
-#define _PB_DDR                _SA1111( 0x1010 )
-#define _PB_DRR                _SA1111( 0x1014 )
-#define _PB_DWR                _SA1111( 0x1014 )
-#define _PB_SDR                _SA1111( 0x1018 )
-#define _PB_SSR                _SA1111( 0x101c )
-#define _PC_DDR                _SA1111( 0x1020 )
-#define _PC_DRR                _SA1111( 0x1024 )
-#define _PC_DWR                _SA1111( 0x1024 )
-#define _PC_SDR                _SA1111( 0x1028 )
-#define _PC_SSR                _SA1111( 0x102c )
-
 #define SA1111_GPIO    0x1000
 
 #define SA1111_GPIO_PADDR      (0x000)
 #define SA1111_WAKEPOL0                0x0034
 #define SA1111_WAKEPOL1                0x0038
 
-/*
- * PS/2 Trackpad and Mouse Interfaces
- *
- * Registers
- *    PS2CR            Control Register
- *    PS2STAT          Status Register
- *    PS2DATA          Transmit/Receive Data register
- *    PS2CLKDIV                Clock Division Register
- *    PS2PRECNT                Clock Precount Register
- *    PS2TEST1         Test register 1
- *    PS2TEST2         Test register 2
- *    PS2TEST3         Test register 3
- *    PS2TEST4         Test register 4
- */
-
+/* PS/2 Trackpad and Mouse Interfaces */
 #define SA1111_KBD             0x0a00
 #define SA1111_MSE             0x0c00
 
-/*
- * These are offsets from the above bases.
- */
-#define SA1111_PS2CR           0x0000
-#define SA1111_PS2STAT         0x0004
-#define SA1111_PS2DATA         0x0008
-#define SA1111_PS2CLKDIV       0x000c
-#define SA1111_PS2PRECNT       0x0010
-
-#define PS2CR_ENA              0x08
-#define PS2CR_FKD              0x02
-#define PS2CR_FKC              0x01
-
-#define PS2STAT_STP            0x0100
-#define PS2STAT_TXE            0x0080
-#define PS2STAT_TXB            0x0040
-#define PS2STAT_RXF            0x0020
-#define PS2STAT_RXB            0x0010
-#define PS2STAT_ENA            0x0008
-#define PS2STAT_RXP            0x0004
-#define PS2STAT_KBD            0x0002
-#define PS2STAT_KBC            0x0001
+/* PCMCIA Interface */
+#define SA1111_PCMCIA          0x1600
 
-/*
- * PCMCIA Interface
- *
- * Registers
- *    PCSR     Status Register
- *    PCCR     Control Register
- *    PCSSR    Sleep State Register
- */
-
-#define SA1111_PCMCIA  0x1600
-
-/*
- * These are offsets from the above base.
- */
-#define SA1111_PCCR    0x0000
-#define SA1111_PCSSR   0x0004
-#define SA1111_PCSR    0x0008
-
-#define PCSR_S0_READY  (1<<0)
-#define PCSR_S1_READY  (1<<1)
-#define PCSR_S0_DETECT (1<<2)
-#define PCSR_S1_DETECT (1<<3)
-#define PCSR_S0_VS1    (1<<4)
-#define PCSR_S0_VS2    (1<<5)
-#define PCSR_S1_VS1    (1<<6)
-#define PCSR_S1_VS2    (1<<7)
-#define PCSR_S0_WP     (1<<8)
-#define PCSR_S1_WP     (1<<9)
-#define PCSR_S0_BVD1   (1<<10)
-#define PCSR_S0_BVD2   (1<<11)
-#define PCSR_S1_BVD1   (1<<12)
-#define PCSR_S1_BVD2   (1<<13)
-
-#define PCCR_S0_RST    (1<<0)
-#define PCCR_S1_RST    (1<<1)
-#define PCCR_S0_FLT    (1<<2)
-#define PCCR_S1_FLT    (1<<3)
-#define PCCR_S0_PWAITEN        (1<<4)
-#define PCCR_S1_PWAITEN        (1<<5)
-#define PCCR_S0_PSE    (1<<6)
-#define PCCR_S1_PSE    (1<<7)
-
-#define PCSSR_S0_SLEEP (1<<0)
-#define PCSSR_S1_SLEEP (1<<1)
 
 
 
 
 extern struct bus_type sa1111_bus_type;
 
-#define SA1111_DEVID_SBI       0
-#define SA1111_DEVID_SK                1
-#define SA1111_DEVID_USB       2
-#define SA1111_DEVID_SAC       3
-#define SA1111_DEVID_SSP       4
-#define SA1111_DEVID_PS2       5
-#define SA1111_DEVID_GPIO      6
-#define SA1111_DEVID_INT       7
-#define SA1111_DEVID_PCMCIA    8
+#define SA1111_DEVID_SBI       (1 << 0)
+#define SA1111_DEVID_SK                (1 << 1)
+#define SA1111_DEVID_USB       (1 << 2)
+#define SA1111_DEVID_SAC       (1 << 3)
+#define SA1111_DEVID_SSP       (1 << 4)
+#define SA1111_DEVID_PS2       (3 << 5)
+#define SA1111_DEVID_PS2_KBD   (1 << 5)
+#define SA1111_DEVID_PS2_MSE   (1 << 6)
+#define SA1111_DEVID_GPIO      (1 << 7)
+#define SA1111_DEVID_INT       (1 << 8)
+#define SA1111_DEVID_PCMCIA    (1 << 9)
 
 struct sa1111_dev {
        struct device   dev;
@@ -548,6 +432,7 @@ struct sa1111_driver {
        int (*remove)(struct sa1111_dev *);
        int (*suspend)(struct sa1111_dev *, pm_message_t);
        int (*resume)(struct sa1111_dev *);
+       void (*shutdown)(struct sa1111_dev *);
 };
 
 #define SA1111_DRV(_d) container_of((_d), struct sa1111_driver, drv)
@@ -555,9 +440,10 @@ struct sa1111_driver {
 #define SA1111_DRIVER_NAME(_sadev) ((_sadev)->dev.driver->name)
 
 /*
- * These frob the SKPCR register.
+ * These frob the SKPCR register, and call platform specific
+ * enable/disable functions.
  */
-void sa1111_enable_device(struct sa1111_dev *);
+int sa1111_enable_device(struct sa1111_dev *);
 void sa1111_disable_device(struct sa1111_dev *);
 
 unsigned int sa1111_pll_clock(struct sa1111_dev *);
@@ -580,6 +466,10 @@ void sa1111_set_sleep_io(struct sa1111_dev *sadev, unsigned int bits, unsigned i
 
 struct sa1111_platform_data {
        int     irq_base;       /* base for cascaded on-chip IRQs */
+       unsigned disable_devs;
+       void    *data;
+       int     (*enable)(void *, unsigned);
+       void    (*disable)(void *, unsigned);
 };
 
 #endif  /* _ASM_ARCH_SA1111 */
index 4384d81..2dd9d3f 100644 (file)
@@ -1,2 +1,15 @@
-void sp804_clocksource_init(void __iomem *, const char *);
+void __sp804_clocksource_and_sched_clock_init(void __iomem *,
+                                             const char *, int);
+
+static inline void sp804_clocksource_init(void __iomem *base, const char *name)
+{
+       __sp804_clocksource_and_sched_clock_init(base, name, 0);
+}
+
+static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base,
+                                                         const char *name)
+{
+       __sp804_clocksource_and_sched_clock_init(base, name, 1);
+}
+
 void sp804_clockevents_init(void __iomem *, unsigned int, const char *);
index c6a1842..f77ffc1 100644 (file)
 #define __ASM_ARM_LOCALTIMER_H
 
 #include <linux/errno.h>
-#include <linux/interrupt.h>
 
 struct clock_event_device;
 
-/*
- * Setup a per-cpu timer, whether it be a local timer or dummy broadcast
- */
-void percpu_timer_setup(void);
+struct local_timer_ops {
+       int  (*setup)(struct clock_event_device *);
+       void (*stop)(struct clock_event_device *);
+};
 
 #ifdef CONFIG_LOCAL_TIMERS
-
-#ifdef CONFIG_HAVE_ARM_TWD
-
-#include "smp_twd.h"
-
-#define local_timer_stop(c)    twd_timer_stop((c))
-
-#else
-
-/*
- * Stop the local timer
- */
-void local_timer_stop(struct clock_event_device *);
-
-#endif
-
 /*
- * Setup a local timer interrupt for a CPU.
+ * Register a local timer driver
  */
-int local_timer_setup(struct clock_event_device *);
-
+int local_timer_register(struct local_timer_ops *);
 #else
-
-static inline int local_timer_setup(struct clock_event_device *evt)
+static inline int local_timer_register(struct local_timer_ops *ops)
 {
        return -ENXIO;
 }
-
-static inline void local_timer_stop(struct clock_event_device *evt)
-{
-}
 #endif
 
 #endif
index da337ba..a98a2e1 100644 (file)
@@ -57,14 +57,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                                enum pci_mmap_state mmap_state, int write_combine);
 
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                        struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                       struct pci_bus_region *region);
-
 /*
  * Dummy implementation; always return 0.
  */
index ffc0e85..7ec60d6 100644 (file)
@@ -79,7 +79,6 @@ extern unsigned int kobjsize(const void *objp);
  * No page table caches to initialise.
  */
 #define pgtable_cache_init()   do { } while (0)
-#define io_remap_page_range    remap_page_range
 #define io_remap_pfn_range     remap_pfn_range
 
 
index ef9ffba..0f01f46 100644 (file)
 #define TWD_TIMER_CONTROL_PERIODIC     (1 << 1)
 #define TWD_TIMER_CONTROL_IT_ENABLE    (1 << 2)
 
-struct clock_event_device;
+#include <linux/ioport.h>
 
-extern void __iomem *twd_base;
+struct twd_local_timer {
+       struct resource res[2];
+};
 
-void twd_timer_setup(struct clock_event_device *);
-void twd_timer_stop(struct clock_event_device *);
+#define DEFINE_TWD_LOCAL_TIMER(name,base,irq)  \
+struct twd_local_timer name __initdata = {     \
+       .res    = {                             \
+               DEFINE_RES_MEM(base, 0x10),     \
+               DEFINE_RES_IRQ(irq),            \
+       },                                      \
+};
+
+int twd_local_timer_register(struct twd_local_timer *);
+
+#ifdef CONFIG_HAVE_ARM_TWD
+void twd_local_timer_of_register(void);
+#else
+static inline void twd_local_timer_of_register(void)
+{
+}
+#endif
 
 #endif
index 9e65b23..5a85f14 100644 (file)
@@ -11,6 +11,7 @@ extern void cpu_init(void);
 
 void soft_restart(unsigned long);
 extern void (*arm_pm_restart)(char str, const char *cmd);
+extern void (*arm_pm_idle)(void);
 
 #define UDBG_UNDEFINED (1 << 0)
 #define UDBG_SYSCALL   (1 << 1)
index 43b740d..3a27487 100644 (file)
@@ -23,7 +23,6 @@ obj-$(CONFIG_LEDS)            += leds.o
 obj-$(CONFIG_OC_ETM)           += etm.o
 
 obj-$(CONFIG_ISA_DMA_API)      += dma.o
-obj-$(CONFIG_ARCH_ACORN)       += ecard.o 
 obj-$(CONFIG_FIQ)              += fiq.o fiqasm.o
 obj-$(CONFIG_MODULES)          += armksyms.o module.o
 obj-$(CONFIG_ARTHUR)           += arthur.o
@@ -62,9 +61,6 @@ obj-$(CONFIG_SWP_EMULATE)     += swp_emulate.o
 CFLAGS_swp_emulate.o           := -Wa,-march=armv7-a
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
 
-obj-$(CONFIG_CRUNCH)           += crunch.o crunch-bits.o
-AFLAGS_crunch-bits.o           := -Wa,-mcpu=ep9312
-
 obj-$(CONFIG_CPU_XSCALE)       += xscale-cp0.o
 obj-$(CONFIG_CPU_XSC3)         += xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)       += xscale-cp0.o
index f58ba35..632df9a 100644 (file)
@@ -16,7 +16,6 @@
 #include <asm/mach/pci.h>
 
 static int debug_pci;
-static int use_firmware;
 
 /*
  * We can't use pci_find_device() here since we are
@@ -295,28 +294,6 @@ static inline int pdev_bad_for_parity(struct pci_dev *dev)
 }
 
 /*
- * Adjust the device resources from bus-centric to Linux-centric.
- */
-static void __devinit
-pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev)
-{
-       resource_size_t offset;
-       int i;
-
-       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-               if (dev->resource[i].start == 0)
-                       continue;
-               if (dev->resource[i].flags & IORESOURCE_MEM)
-                       offset = root->mem_offset;
-               else
-                       offset = root->io_offset;
-
-               dev->resource[i].start += offset;
-               dev->resource[i].end   += offset;
-       }
-}
-
-/*
  * pcibios_fixup_bus - Called after each bus is probed,
  * but before its children are examined.
  */
@@ -333,8 +310,6 @@ void pcibios_fixup_bus(struct pci_bus *bus)
        list_for_each_entry(dev, &bus->devices, bus_list) {
                u16 status;
 
-               pdev_fixup_device_resources(root, dev);
-
                pci_read_config_word(dev, PCI_STATUS, &status);
 
                /*
@@ -400,43 +375,6 @@ EXPORT_SYMBOL(pcibios_fixup_bus);
 #endif
 
 /*
- * Convert from Linux-centric to bus-centric addresses for bridge devices.
- */
-void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                        struct resource *res)
-{
-       struct pci_sys_data *root = dev->sysdata;
-       unsigned long offset = 0;
-
-       if (res->flags & IORESOURCE_IO)
-               offset = root->io_offset;
-       if (res->flags & IORESOURCE_MEM)
-               offset = root->mem_offset;
-
-       region->start = res->start - offset;
-       region->end   = res->end - offset;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void __devinit
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                       struct pci_bus_region *region)
-{
-       struct pci_sys_data *root = dev->sysdata;
-       unsigned long offset = 0;
-
-       if (res->flags & IORESOURCE_IO)
-               offset = root->io_offset;
-       if (res->flags & IORESOURCE_MEM)
-               offset = root->mem_offset;
-
-       res->start = region->start + offset;
-       res->end   = region->end + offset;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/*
  * Swizzle the device pin each time we cross a bridge.
  * This might update pin and returns the slot number.
  */
@@ -497,10 +435,10 @@ static void __init pcibios_init_hw(struct hw_pci *hw)
 
                if (ret > 0) {
                        if (list_empty(&sys->resources)) {
-                               pci_add_resource(&sys->resources,
-                                                &ioport_resource);
-                               pci_add_resource(&sys->resources,
-                                                &iomem_resource);
+                               pci_add_resource_offset(&sys->resources,
+                                        &ioport_resource, sys->io_offset);
+                               pci_add_resource_offset(&sys->resources,
+                                        &iomem_resource, sys->mem_offset);
                        }
 
                        sys->bus = hw->scan(nr, sys);
@@ -525,6 +463,7 @@ void __init pci_common_init(struct hw_pci *hw)
 
        INIT_LIST_HEAD(&hw->buses);
 
+       pci_add_flags(PCI_REASSIGN_ALL_RSRC);
        if (hw->preinit)
                hw->preinit();
        pcibios_init_hw(hw);
@@ -536,7 +475,7 @@ void __init pci_common_init(struct hw_pci *hw)
        list_for_each_entry(sys, &hw->buses, node) {
                struct pci_bus *bus = sys->bus;
 
-               if (!use_firmware) {
+               if (!pci_has_flag(PCI_PROBE_ONLY)) {
                        /*
                         * Size the bridge windows.
                         */
@@ -573,7 +512,7 @@ char * __init pcibios_setup(char *str)
                debug_pci = 1;
                return NULL;
        } else if (!strcmp(str, "firmware")) {
-               use_firmware = 1;
+               pci_add_flags(PCI_PROBE_ONLY);
                return NULL;
        }
        return str;
diff --git a/arch/arm/kernel/crunch-bits.S b/arch/arm/kernel/crunch-bits.S
deleted file mode 100644 (file)
index 0ec9bb4..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * arch/arm/kernel/crunch-bits.S
- * Cirrus MaverickCrunch context switching and handling
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
- *
- * Shamelessly stolen from the iWMMXt code by Nicolas Pitre, which is
- * Copyright (c) 2003-2004, MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-#include <asm/thread_info.h>
-#include <asm/asm-offsets.h>
-#include <mach/ep93xx-regs.h>
-
-/*
- * We can't use hex constants here due to a bug in gas.
- */
-#define CRUNCH_MVDX0           0
-#define CRUNCH_MVDX1           8
-#define CRUNCH_MVDX2           16
-#define CRUNCH_MVDX3           24
-#define CRUNCH_MVDX4           32
-#define CRUNCH_MVDX5           40
-#define CRUNCH_MVDX6           48
-#define CRUNCH_MVDX7           56
-#define CRUNCH_MVDX8           64
-#define CRUNCH_MVDX9           72
-#define CRUNCH_MVDX10          80
-#define CRUNCH_MVDX11          88
-#define CRUNCH_MVDX12          96
-#define CRUNCH_MVDX13          104
-#define CRUNCH_MVDX14          112
-#define CRUNCH_MVDX15          120
-#define CRUNCH_MVAX0L          128
-#define CRUNCH_MVAX0M          132
-#define CRUNCH_MVAX0H          136
-#define CRUNCH_MVAX1L          140
-#define CRUNCH_MVAX1M          144
-#define CRUNCH_MVAX1H          148
-#define CRUNCH_MVAX2L          152
-#define CRUNCH_MVAX2M          156
-#define CRUNCH_MVAX2H          160
-#define CRUNCH_MVAX3L          164
-#define CRUNCH_MVAX3M          168
-#define CRUNCH_MVAX3H          172
-#define CRUNCH_DSPSC           176
-
-#define CRUNCH_SIZE            184
-
-       .text
-
-/*
- * Lazy switching of crunch coprocessor context
- *
- * r10 = struct thread_info pointer
- * r9  = ret_from_exception
- * lr  = undefined instr exit
- *
- * called from prefetch exception handler with interrupts disabled
- */
-ENTRY(crunch_task_enable)
-       ldr     r8, =(EP93XX_APB_VIRT_BASE + 0x00130000)        @ syscon addr
-
-       ldr     r1, [r8, #0x80]
-       tst     r1, #0x00800000                 @ access to crunch enabled?
-       movne   pc, lr                          @ if so no business here
-       mov     r3, #0xaa                       @ unlock syscon swlock
-       str     r3, [r8, #0xc0]
-       orr     r1, r1, #0x00800000             @ enable access to crunch
-       str     r1, [r8, #0x80]
-
-       ldr     r3, =crunch_owner
-       add     r0, r10, #TI_CRUNCH_STATE       @ get task crunch save area
-       ldr     r2, [sp, #60]                   @ current task pc value
-       ldr     r1, [r3]                        @ get current crunch owner
-       str     r0, [r3]                        @ this task now owns crunch
-       sub     r2, r2, #4                      @ adjust pc back
-       str     r2, [sp, #60]
-
-       ldr     r2, [r8, #0x80]
-       mov     r2, r2                          @ flush out enable (@@@)
-
-       teq     r1, #0                          @ test for last ownership
-       mov     lr, r9                          @ normal exit from exception
-       beq     crunch_load                     @ no owner, skip save
-
-crunch_save:
-       cfstr64         mvdx0, [r1, #CRUNCH_MVDX0]      @ save 64b registers
-       cfstr64         mvdx1, [r1, #CRUNCH_MVDX1]
-       cfstr64         mvdx2, [r1, #CRUNCH_MVDX2]
-       cfstr64         mvdx3, [r1, #CRUNCH_MVDX3]
-       cfstr64         mvdx4, [r1, #CRUNCH_MVDX4]
-       cfstr64         mvdx5, [r1, #CRUNCH_MVDX5]
-       cfstr64         mvdx6, [r1, #CRUNCH_MVDX6]
-       cfstr64         mvdx7, [r1, #CRUNCH_MVDX7]
-       cfstr64         mvdx8, [r1, #CRUNCH_MVDX8]
-       cfstr64         mvdx9, [r1, #CRUNCH_MVDX9]
-       cfstr64         mvdx10, [r1, #CRUNCH_MVDX10]
-       cfstr64         mvdx11, [r1, #CRUNCH_MVDX11]
-       cfstr64         mvdx12, [r1, #CRUNCH_MVDX12]
-       cfstr64         mvdx13, [r1, #CRUNCH_MVDX13]
-       cfstr64         mvdx14, [r1, #CRUNCH_MVDX14]
-       cfstr64         mvdx15, [r1, #CRUNCH_MVDX15]
-
-#ifdef __ARMEB__
-#error fix me for ARMEB
-#endif
-
-       cfmv32al        mvfx0, mvax0                    @ save 72b accumulators
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0L]
-       cfmv32am        mvfx0, mvax0
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0M]
-       cfmv32ah        mvfx0, mvax0
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0H]
-       cfmv32al        mvfx0, mvax1
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1L]
-       cfmv32am        mvfx0, mvax1
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1M]
-       cfmv32ah        mvfx0, mvax1
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1H]
-       cfmv32al        mvfx0, mvax2
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2L]
-       cfmv32am        mvfx0, mvax2
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2M]
-       cfmv32ah        mvfx0, mvax2
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2H]
-       cfmv32al        mvfx0, mvax3
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3L]
-       cfmv32am        mvfx0, mvax3
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3M]
-       cfmv32ah        mvfx0, mvax3
-       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3H]
-
-       cfmv32sc        mvdx0, dspsc                    @ save status word
-       cfstr64         mvdx0, [r1, #CRUNCH_DSPSC]
-
-       teq             r0, #0                          @ anything to load?
-       cfldr64eq       mvdx0, [r1, #CRUNCH_MVDX0]      @ mvdx0 was clobbered
-       moveq           pc, lr
-
-crunch_load:
-       cfldr64         mvdx0, [r0, #CRUNCH_DSPSC]      @ load status word
-       cfmvsc32        dspsc, mvdx0
-
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0L]     @ load 72b accumulators
-       cfmval32        mvax0, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0M]
-       cfmvam32        mvax0, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0H]
-       cfmvah32        mvax0, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1L]
-       cfmval32        mvax1, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1M]
-       cfmvam32        mvax1, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1H]
-       cfmvah32        mvax1, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2L]
-       cfmval32        mvax2, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2M]
-       cfmvam32        mvax2, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2H]
-       cfmvah32        mvax2, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3L]
-       cfmval32        mvax3, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3M]
-       cfmvam32        mvax3, mvfx0
-       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3H]
-       cfmvah32        mvax3, mvfx0
-
-       cfldr64         mvdx0, [r0, #CRUNCH_MVDX0]      @ load 64b registers
-       cfldr64         mvdx1, [r0, #CRUNCH_MVDX1]
-       cfldr64         mvdx2, [r0, #CRUNCH_MVDX2]
-       cfldr64         mvdx3, [r0, #CRUNCH_MVDX3]
-       cfldr64         mvdx4, [r0, #CRUNCH_MVDX4]
-       cfldr64         mvdx5, [r0, #CRUNCH_MVDX5]
-       cfldr64         mvdx6, [r0, #CRUNCH_MVDX6]
-       cfldr64         mvdx7, [r0, #CRUNCH_MVDX7]
-       cfldr64         mvdx8, [r0, #CRUNCH_MVDX8]
-       cfldr64         mvdx9, [r0, #CRUNCH_MVDX9]
-       cfldr64         mvdx10, [r0, #CRUNCH_MVDX10]
-       cfldr64         mvdx11, [r0, #CRUNCH_MVDX11]
-       cfldr64         mvdx12, [r0, #CRUNCH_MVDX12]
-       cfldr64         mvdx13, [r0, #CRUNCH_MVDX13]
-       cfldr64         mvdx14, [r0, #CRUNCH_MVDX14]
-       cfldr64         mvdx15, [r0, #CRUNCH_MVDX15]
-
-       mov     pc, lr
-
-/*
- * Back up crunch regs to save area and disable access to them
- * (mainly for gdb or sleep mode usage)
- *
- * r0 = struct thread_info pointer of target task or NULL for any
- */
-ENTRY(crunch_task_disable)
-       stmfd   sp!, {r4, r5, lr}
-
-       mrs     ip, cpsr
-       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
-       msr     cpsr_c, r2
-
-       ldr     r4, =(EP93XX_APB_VIRT_BASE + 0x00130000)        @ syscon addr
-
-       ldr     r3, =crunch_owner
-       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
-       ldr     r1, [r3]                        @ get current crunch owner
-       teq     r1, #0                          @ any current owner?
-       beq     1f                              @ no: quit
-       teq     r0, #0                          @ any owner?
-       teqne   r1, r2                          @ or specified one?
-       bne     1f                              @ no: quit
-
-       ldr     r5, [r4, #0x80]                 @ enable access to crunch
-       mov     r2, #0xaa
-       str     r2, [r4, #0xc0]
-       orr     r5, r5, #0x00800000
-       str     r5, [r4, #0x80]
-
-       mov     r0, #0                          @ nothing to load
-       str     r0, [r3]                        @ no more current owner
-       ldr     r2, [r4, #0x80]                 @ flush out enable (@@@)
-       mov     r2, r2
-       bl      crunch_save
-
-       mov     r2, #0xaa                       @ disable access to crunch
-       str     r2, [r4, #0xc0]
-       bic     r5, r5, #0x00800000
-       str     r5, [r4, #0x80]
-       ldr     r5, [r4, #0x80]                 @ flush out enable (@@@)
-       mov     r5, r5
-
-1:     msr     cpsr_c, ip                      @ restore interrupt mode
-       ldmfd   sp!, {r4, r5, pc}
-
-/*
- * Copy crunch state to given memory address
- *
- * r0 = struct thread_info pointer of target task
- * r1 = memory address where to store crunch state
- *
- * this is called mainly in the creation of signal stack frames
- */
-ENTRY(crunch_task_copy)
-       mrs     ip, cpsr
-       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
-       msr     cpsr_c, r2
-
-       ldr     r3, =crunch_owner
-       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
-       ldr     r3, [r3]                        @ get current crunch owner
-       teq     r2, r3                          @ does this task own it...
-       beq     1f
-
-       @ current crunch values are in the task save area
-       msr     cpsr_c, ip                      @ restore interrupt mode
-       mov     r0, r1
-       mov     r1, r2
-       mov     r2, #CRUNCH_SIZE
-       b       memcpy
-
-1:     @ this task owns crunch regs -- grab a copy from there
-       mov     r0, #0                          @ nothing to load
-       mov     r3, lr                          @ preserve return address
-       bl      crunch_save
-       msr     cpsr_c, ip                      @ restore interrupt mode
-       mov     pc, r3
-
-/*
- * Restore crunch state from given memory address
- *
- * r0 = struct thread_info pointer of target task
- * r1 = memory address where to get crunch state from
- *
- * this is used to restore crunch state when unwinding a signal stack frame
- */
-ENTRY(crunch_task_restore)
-       mrs     ip, cpsr
-       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
-       msr     cpsr_c, r2
-
-       ldr     r3, =crunch_owner
-       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
-       ldr     r3, [r3]                        @ get current crunch owner
-       teq     r2, r3                          @ does this task own it...
-       beq     1f
-
-       @ this task doesn't own crunch regs -- use its save area
-       msr     cpsr_c, ip                      @ restore interrupt mode
-       mov     r0, r2
-       mov     r2, #CRUNCH_SIZE
-       b       memcpy
-
-1:     @ this task owns crunch regs -- load them directly
-       mov     r0, r1
-       mov     r1, #0                          @ nothing to save
-       mov     r3, lr                          @ preserve return address
-       bl      crunch_load
-       msr     cpsr_c, ip                      @ restore interrupt mode
-       mov     pc, r3
diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
deleted file mode 100644 (file)
index 25ef223..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * arch/arm/kernel/crunch.c
- * Cirrus MaverickCrunch context switching and handling
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
- *
- * 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/types.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <mach/ep93xx-regs.h>
-#include <asm/thread_notify.h>
-
-struct crunch_state *crunch_owner;
-
-void crunch_task_release(struct thread_info *thread)
-{
-       local_irq_disable();
-       if (crunch_owner == &thread->crunchstate)
-               crunch_owner = NULL;
-       local_irq_enable();
-}
-
-static int crunch_enabled(u32 devcfg)
-{
-       return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA);
-}
-
-static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
-{
-       struct thread_info *thread = (struct thread_info *)t;
-       struct crunch_state *crunch_state;
-       u32 devcfg;
-
-       crunch_state = &thread->crunchstate;
-
-       switch (cmd) {
-       case THREAD_NOTIFY_FLUSH:
-               memset(crunch_state, 0, sizeof(*crunch_state));
-
-               /*
-                * FALLTHROUGH: Ensure we don't try to overwrite our newly
-                * initialised state information on the first fault.
-                */
-
-       case THREAD_NOTIFY_EXIT:
-               crunch_task_release(thread);
-               break;
-
-       case THREAD_NOTIFY_SWITCH:
-               devcfg = __raw_readl(EP93XX_SYSCON_DEVCFG);
-               if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
-                       /*
-                        * We don't use ep93xx_syscon_swlocked_write() here
-                        * because we are on the context switch path and
-                        * preemption is already disabled.
-                        */
-                       devcfg ^= EP93XX_SYSCON_DEVCFG_CPENA;
-                       __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
-                       __raw_writel(devcfg, EP93XX_SYSCON_DEVCFG);
-               }
-               break;
-       }
-
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block crunch_notifier_block = {
-       .notifier_call  = crunch_do,
-};
-
-static int __init crunch_init(void)
-{
-       thread_register_notifier(&crunch_notifier_block);
-       elf_hwcap |= HWCAP_CRUNCH;
-
-       return 0;
-}
-
-late_initcall(crunch_init);
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
deleted file mode 100644 (file)
index 1651d49..0000000
+++ /dev/null
@@ -1,1232 +0,0 @@
-/*
- *  linux/arch/arm/kernel/ecard.c
- *
- *  Copyright 1995-2001 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Find all installed expansion cards, and handle interrupts from them.
- *
- *  Created from information from Acorns RiscOS3 PRMs
- *
- *  08-Dec-1996        RMK     Added code for the 9'th expansion card - the ether
- *                     podule slot.
- *  06-May-1997        RMK     Added blacklist for cards whose loader doesn't work.
- *  12-Sep-1997        RMK     Created new handling of interrupt enables/disables
- *                     - cards can now register their own routine to control
- *                     interrupts (recommended).
- *  29-Sep-1997        RMK     Expansion card interrupt hardware not being re-enabled
- *                     on reset from Linux. (Caused cards not to respond
- *                     under RiscOS without hard reset).
- *  15-Feb-1998        RMK     Added DMA support
- *  12-Sep-1998        RMK     Added EASI support
- *  10-Jan-1999        RMK     Run loaders in a simulated RISC OS environment.
- *  17-Apr-1999        RMK     Support for EASI Type C cycles.
- */
-#define ECARD_C
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-#include <linux/reboot.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/kthread.h>
-#include <linux/io.h>
-
-#include <asm/dma.h>
-#include <asm/ecard.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mmu_context.h>
-#include <asm/mach/irq.h>
-#include <asm/tlbflush.h>
-
-#include "ecard.h"
-
-#ifndef CONFIG_ARCH_RPC
-#define HAVE_EXPMASK
-#endif
-
-struct ecard_request {
-       void            (*fn)(struct ecard_request *);
-       ecard_t         *ec;
-       unsigned int    address;
-       unsigned int    length;
-       unsigned int    use_loader;
-       void            *buffer;
-       struct completion *complete;
-};
-
-struct expcard_blacklist {
-       unsigned short   manufacturer;
-       unsigned short   product;
-       const char      *type;
-};
-
-static ecard_t *cards;
-static ecard_t *slot_to_expcard[MAX_ECARDS];
-static unsigned int ectcr;
-#ifdef HAS_EXPMASK
-static unsigned int have_expmask;
-#endif
-
-/* List of descriptions of cards which don't have an extended
- * identification, or chunk directories containing a description.
- */
-static struct expcard_blacklist __initdata blacklist[] = {
-       { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
-};
-
-asmlinkage extern int
-ecard_loader_reset(unsigned long base, loader_t loader);
-asmlinkage extern int
-ecard_loader_read(int off, unsigned long base, loader_t loader);
-
-static inline unsigned short ecard_getu16(unsigned char *v)
-{
-       return v[0] | v[1] << 8;
-}
-
-static inline signed long ecard_gets24(unsigned char *v)
-{
-       return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
-}
-
-static inline ecard_t *slot_to_ecard(unsigned int slot)
-{
-       return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
-}
-
-/* ===================== Expansion card daemon ======================== */
-/*
- * Since the loader programs on the expansion cards need to be run
- * in a specific environment, create a separate task with this
- * environment up, and pass requests to this task as and when we
- * need to.
- *
- * This should allow 99% of loaders to be called from Linux.
- *
- * From a security standpoint, we trust the card vendors.  This
- * may be a misplaced trust.
- */
-static void ecard_task_reset(struct ecard_request *req)
-{
-       struct expansion_card *ec = req->ec;
-       struct resource *res;
-
-       res = ec->slot_no == 8
-               ? &ec->resource[ECARD_RES_MEMC]
-               : ec->easi
-                 ? &ec->resource[ECARD_RES_EASI]
-                 : &ec->resource[ECARD_RES_IOCSYNC];
-
-       ecard_loader_reset(res->start, ec->loader);
-}
-
-static void ecard_task_readbytes(struct ecard_request *req)
-{
-       struct expansion_card *ec = req->ec;
-       unsigned char *buf = req->buffer;
-       unsigned int len = req->length;
-       unsigned int off = req->address;
-
-       if (ec->slot_no == 8) {
-               void __iomem *base = (void __iomem *)
-                               ec->resource[ECARD_RES_MEMC].start;
-
-               /*
-                * The card maintains an index which increments the address
-                * into a 4096-byte page on each access.  We need to keep
-                * track of the counter.
-                */
-               static unsigned int index;
-               unsigned int page;
-
-               page = (off >> 12) * 4;
-               if (page > 256 * 4)
-                       return;
-
-               off &= 4095;
-
-               /*
-                * If we are reading offset 0, or our current index is
-                * greater than the offset, reset the hardware index counter.
-                */
-               if (off == 0 || index > off) {
-                       writeb(0, base);
-                       index = 0;
-               }
-
-               /*
-                * Increment the hardware index counter until we get to the
-                * required offset.  The read bytes are discarded.
-                */
-               while (index < off) {
-                       readb(base + page);
-                       index += 1;
-               }
-
-               while (len--) {
-                       *buf++ = readb(base + page);
-                       index += 1;
-               }
-       } else {
-               unsigned long base = (ec->easi
-                        ? &ec->resource[ECARD_RES_EASI]
-                        : &ec->resource[ECARD_RES_IOCSYNC])->start;
-               void __iomem *pbase = (void __iomem *)base;
-
-               if (!req->use_loader || !ec->loader) {
-                       off *= 4;
-                       while (len--) {
-                               *buf++ = readb(pbase + off);
-                               off += 4;
-                       }
-               } else {
-                       while(len--) {
-                               /*
-                                * The following is required by some
-                                * expansion card loader programs.
-                                */
-                               *(unsigned long *)0x108 = 0;
-                               *buf++ = ecard_loader_read(off++, base,
-                                                          ec->loader);
-                       }
-               }
-       }
-
-}
-
-static DECLARE_WAIT_QUEUE_HEAD(ecard_wait);
-static struct ecard_request *ecard_req;
-static DEFINE_MUTEX(ecard_mutex);
-
-/*
- * Set up the expansion card daemon's page tables.
- */
-static void ecard_init_pgtables(struct mm_struct *mm)
-{
-       struct vm_area_struct vma;
-
-       /* We want to set up the page tables for the following mapping:
-        *  Virtual     Physical
-        *  0x03000000  0x03000000
-        *  0x03010000  unmapped
-        *  0x03210000  0x03210000
-        *  0x03400000  unmapped
-        *  0x08000000  0x08000000
-        *  0x10000000  unmapped
-        *
-        * FIXME: we don't follow this 100% yet.
-        */
-       pgd_t *src_pgd, *dst_pgd;
-
-       src_pgd = pgd_offset(mm, (unsigned long)IO_BASE);
-       dst_pgd = pgd_offset(mm, IO_START);
-
-       memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
-
-       src_pgd = pgd_offset(mm, (unsigned long)EASI_BASE);
-       dst_pgd = pgd_offset(mm, EASI_START);
-
-       memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
-
-       vma.vm_flags = VM_EXEC;
-       vma.vm_mm = mm;
-
-       flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
-       flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE);
-}
-
-static int ecard_init_mm(void)
-{
-       struct mm_struct * mm = mm_alloc();
-       struct mm_struct *active_mm = current->active_mm;
-
-       if (!mm)
-               return -ENOMEM;
-
-       current->mm = mm;
-       current->active_mm = mm;
-       activate_mm(active_mm, mm);
-       mmdrop(active_mm);
-       ecard_init_pgtables(mm);
-       return 0;
-}
-
-static int
-ecard_task(void * unused)
-{
-       /*
-        * Allocate a mm.  We're not a lazy-TLB kernel task since we need
-        * to set page table entries where the user space would be.  Note
-        * that this also creates the page tables.  Failure is not an
-        * option here.
-        */
-       if (ecard_init_mm())
-               panic("kecardd: unable to alloc mm\n");
-
-       while (1) {
-               struct ecard_request *req;
-
-               wait_event_interruptible(ecard_wait, ecard_req != NULL);
-
-               req = xchg(&ecard_req, NULL);
-               if (req != NULL) {
-                       req->fn(req);
-                       complete(req->complete);
-               }
-       }
-}
-
-/*
- * Wake the expansion card daemon to action our request.
- *
- * FIXME: The test here is not sufficient to detect if the
- * kcardd is running.
- */
-static void ecard_call(struct ecard_request *req)
-{
-       DECLARE_COMPLETION_ONSTACK(completion);
-
-       req->complete = &completion;
-
-       mutex_lock(&ecard_mutex);
-       ecard_req = req;
-       wake_up(&ecard_wait);
-
-       /*
-        * Now wait for kecardd to run.
-        */
-       wait_for_completion(&completion);
-       mutex_unlock(&ecard_mutex);
-}
-
-/* ======================= Mid-level card control ===================== */
-
-static void
-ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
-{
-       struct ecard_request req;
-
-       req.fn          = ecard_task_readbytes;
-       req.ec          = ec;
-       req.address     = off;
-       req.length      = len;
-       req.use_loader  = useld;
-       req.buffer      = addr;
-
-       ecard_call(&req);
-}
-
-int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
-{
-       struct ex_chunk_dir excd;
-       int index = 16;
-       int useld = 0;
-
-       if (!ec->cid.cd)
-               return 0;
-
-       while(1) {
-               ecard_readbytes(&excd, ec, index, 8, useld);
-               index += 8;
-               if (c_id(&excd) == 0) {
-                       if (!useld && ec->loader) {
-                               useld = 1;
-                               index = 0;
-                               continue;
-                       }
-                       return 0;
-               }
-               if (c_id(&excd) == 0xf0) { /* link */
-                       index = c_start(&excd);
-                       continue;
-               }
-               if (c_id(&excd) == 0x80) { /* loader */
-                       if (!ec->loader) {
-                               ec->loader = kmalloc(c_len(&excd),
-                                                              GFP_KERNEL);
-                               if (ec->loader)
-                                       ecard_readbytes(ec->loader, ec,
-                                                       (int)c_start(&excd),
-                                                       c_len(&excd), useld);
-                               else
-                                       return 0;
-                       }
-                       continue;
-               }
-               if (c_id(&excd) == id && num-- == 0)
-                       break;
-       }
-
-       if (c_id(&excd) & 0x80) {
-               switch (c_id(&excd) & 0x70) {
-               case 0x70:
-                       ecard_readbytes((unsigned char *)excd.d.string, ec,
-                                       (int)c_start(&excd), c_len(&excd),
-                                       useld);
-                       break;
-               case 0x00:
-                       break;
-               }
-       }
-       cd->start_offset = c_start(&excd);
-       memcpy(cd->d.string, excd.d.string, 256);
-       return 1;
-}
-
-/* ======================= Interrupt control ============================ */
-
-static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
-{
-#ifdef HAS_EXPMASK
-       if (irqnr < 4 && have_expmask) {
-               have_expmask |= 1 << irqnr;
-               __raw_writeb(have_expmask, EXPMASK_ENABLE);
-       }
-#endif
-}
-
-static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
-{
-#ifdef HAS_EXPMASK
-       if (irqnr < 4 && have_expmask) {
-               have_expmask &= ~(1 << irqnr);
-               __raw_writeb(have_expmask, EXPMASK_ENABLE);
-       }
-#endif
-}
-
-static int ecard_def_irq_pending(ecard_t *ec)
-{
-       return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask;
-}
-
-static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
-{
-       panic("ecard_def_fiq_enable called - impossible");
-}
-
-static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
-{
-       panic("ecard_def_fiq_disable called - impossible");
-}
-
-static int ecard_def_fiq_pending(ecard_t *ec)
-{
-       return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask;
-}
-
-static expansioncard_ops_t ecard_default_ops = {
-       ecard_def_irq_enable,
-       ecard_def_irq_disable,
-       ecard_def_irq_pending,
-       ecard_def_fiq_enable,
-       ecard_def_fiq_disable,
-       ecard_def_fiq_pending
-};
-
-/*
- * Enable and disable interrupts from expansion cards.
- * (interrupts are disabled for these functions).
- *
- * They are not meant to be called directly, but via enable/disable_irq.
- */
-static void ecard_irq_unmask(struct irq_data *d)
-{
-       ecard_t *ec = slot_to_ecard(d->irq - 32);
-
-       if (ec) {
-               if (!ec->ops)
-                       ec->ops = &ecard_default_ops;
-
-               if (ec->claimed && ec->ops->irqenable)
-                       ec->ops->irqenable(ec, d->irq);
-               else
-                       printk(KERN_ERR "ecard: rejecting request to "
-                               "enable IRQs for %d\n", d->irq);
-       }
-}
-
-static void ecard_irq_mask(struct irq_data *d)
-{
-       ecard_t *ec = slot_to_ecard(d->irq - 32);
-
-       if (ec) {
-               if (!ec->ops)
-                       ec->ops = &ecard_default_ops;
-
-               if (ec->ops && ec->ops->irqdisable)
-                       ec->ops->irqdisable(ec, d->irq);
-       }
-}
-
-static struct irq_chip ecard_chip = {
-       .name           = "ECARD",
-       .irq_ack        = ecard_irq_mask,
-       .irq_mask       = ecard_irq_mask,
-       .irq_unmask     = ecard_irq_unmask,
-};
-
-void ecard_enablefiq(unsigned int fiqnr)
-{
-       ecard_t *ec = slot_to_ecard(fiqnr);
-
-       if (ec) {
-               if (!ec->ops)
-                       ec->ops = &ecard_default_ops;
-
-               if (ec->claimed && ec->ops->fiqenable)
-                       ec->ops->fiqenable(ec, fiqnr);
-               else
-                       printk(KERN_ERR "ecard: rejecting request to "
-                               "enable FIQs for %d\n", fiqnr);
-       }
-}
-
-void ecard_disablefiq(unsigned int fiqnr)
-{
-       ecard_t *ec = slot_to_ecard(fiqnr);
-
-       if (ec) {
-               if (!ec->ops)
-                       ec->ops = &ecard_default_ops;
-
-               if (ec->ops->fiqdisable)
-                       ec->ops->fiqdisable(ec, fiqnr);
-       }
-}
-
-static void ecard_dump_irq_state(void)
-{
-       ecard_t *ec;
-
-       printk("Expansion card IRQ state:\n");
-
-       for (ec = cards; ec; ec = ec->next) {
-               if (ec->slot_no == 8)
-                       continue;
-
-               printk("  %d: %sclaimed, ",
-                      ec->slot_no, ec->claimed ? "" : "not ");
-
-               if (ec->ops && ec->ops->irqpending &&
-                   ec->ops != &ecard_default_ops)
-                       printk("irq %spending\n",
-                              ec->ops->irqpending(ec) ? "" : "not ");
-               else
-                       printk("irqaddr %p, mask = %02X, status = %02X\n",
-                              ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
-       }
-}
-
-static void ecard_check_lockup(struct irq_desc *desc)
-{
-       static unsigned long last;
-       static int lockup;
-
-       /*
-        * If the timer interrupt has not run since the last million
-        * unrecognised expansion card interrupts, then there is
-        * something seriously wrong.  Disable the expansion card
-        * interrupts so at least we can continue.
-        *
-        * Maybe we ought to start a timer to re-enable them some time
-        * later?
-        */
-       if (last == jiffies) {
-               lockup += 1;
-               if (lockup > 1000000) {
-                       printk(KERN_ERR "\nInterrupt lockup detected - "
-                              "disabling all expansion card interrupts\n");
-
-                       desc->irq_data.chip->irq_mask(&desc->irq_data);
-                       ecard_dump_irq_state();
-               }
-       } else
-               lockup = 0;
-
-       /*
-        * If we did not recognise the source of this interrupt,
-        * warn the user, but don't flood the user with these messages.
-        */
-       if (!last || time_after(jiffies, last + 5*HZ)) {
-               last = jiffies;
-               printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
-               ecard_dump_irq_state();
-       }
-}
-
-static void
-ecard_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       ecard_t *ec;
-       int called = 0;
-
-       desc->irq_data.chip->irq_mask(&desc->irq_data);
-       for (ec = cards; ec; ec = ec->next) {
-               int pending;
-
-               if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8)
-                       continue;
-
-               if (ec->ops && ec->ops->irqpending)
-                       pending = ec->ops->irqpending(ec);
-               else
-                       pending = ecard_default_ops.irqpending(ec);
-
-               if (pending) {
-                       generic_handle_irq(ec->irq);
-                       called ++;
-               }
-       }
-       desc->irq_data.chip->irq_unmask(&desc->irq_data);
-
-       if (called == 0)
-               ecard_check_lockup(desc);
-}
-
-#ifdef HAS_EXPMASK
-static unsigned char priority_masks[] =
-{
-       0xf0, 0xf1, 0xf3, 0xf7, 0xff, 0xff, 0xff, 0xff
-};
-
-static unsigned char first_set[] =
-{
-       0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
-       0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00
-};
-
-static void
-ecard_irqexp_handler(unsigned int irq, struct irq_desc *desc)
-{
-       const unsigned int statusmask = 15;
-       unsigned int status;
-
-       status = __raw_readb(EXPMASK_STATUS) & statusmask;
-       if (status) {
-               unsigned int slot = first_set[status];
-               ecard_t *ec = slot_to_ecard(slot);
-
-               if (ec->claimed) {
-                       /*
-                        * this ugly code is so that we can operate a
-                        * prioritorising system:
-                        *
-                        * Card 0       highest priority
-                        * Card 1
-                        * Card 2
-                        * Card 3       lowest priority
-                        *
-                        * Serial cards should go in 0/1, ethernet/scsi in 2/3
-                        * otherwise you will lose serial data at high speeds!
-                        */
-                       generic_handle_irq(ec->irq);
-               } else {
-                       printk(KERN_WARNING "card%d: interrupt from unclaimed "
-                              "card???\n", slot);
-                       have_expmask &= ~(1 << slot);
-                       __raw_writeb(have_expmask, EXPMASK_ENABLE);
-               }
-       } else
-               printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
-}
-
-static int __init ecard_probeirqhw(void)
-{
-       ecard_t *ec;
-       int found;
-
-       __raw_writeb(0x00, EXPMASK_ENABLE);
-       __raw_writeb(0xff, EXPMASK_STATUS);
-       found = (__raw_readb(EXPMASK_STATUS) & 15) == 0;
-       __raw_writeb(0xff, EXPMASK_ENABLE);
-
-       if (found) {
-               printk(KERN_DEBUG "Expansion card interrupt "
-                      "management hardware found\n");
-
-               /* for each card present, set a bit to '1' */
-               have_expmask = 0x80000000;
-
-               for (ec = cards; ec; ec = ec->next)
-                       have_expmask |= 1 << ec->slot_no;
-
-               __raw_writeb(have_expmask, EXPMASK_ENABLE);
-       }
-
-       return found;
-}
-#else
-#define ecard_irqexp_handler NULL
-#define ecard_probeirqhw() (0)
-#endif
-
-static void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
-{
-       void __iomem *address = NULL;
-       int slot = ec->slot_no;
-
-       if (ec->slot_no == 8)
-               return ECARD_MEMC8_BASE;
-
-       ectcr &= ~(1 << slot);
-
-       switch (type) {
-       case ECARD_MEMC:
-               if (slot < 4)
-                       address = ECARD_MEMC_BASE + (slot << 14);
-               break;
-
-       case ECARD_IOC:
-               if (slot < 4)
-                       address = ECARD_IOC_BASE + (slot << 14);
-               else
-                       address = ECARD_IOC4_BASE + ((slot - 4) << 14);
-               if (address)
-                       address += speed << 19;
-               break;
-
-       case ECARD_EASI:
-               address = ECARD_EASI_BASE + (slot << 24);
-               if (speed == ECARD_FAST)
-                       ectcr |= 1 << slot;
-               break;
-
-       default:
-               break;
-       }
-
-#ifdef IOMD_ECTCR
-       iomd_writeb(ectcr, IOMD_ECTCR);
-#endif
-       return address;
-}
-
-static int ecard_prints(struct seq_file *m, ecard_t *ec)
-{
-       seq_printf(m, "  %d: %s ", ec->slot_no, ec->easi ? "EASI" : "    ");
-
-       if (ec->cid.id == 0) {
-               struct in_chunk_dir incd;
-
-               seq_printf(m, "[%04X:%04X] ",
-                       ec->cid.manufacturer, ec->cid.product);
-
-               if (!ec->card_desc && ec->cid.cd &&
-                   ecard_readchunk(&incd, ec, 0xf5, 0)) {
-                       ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL);
-
-                       if (ec->card_desc)
-                               strcpy((char *)ec->card_desc, incd.d.string);
-               }
-
-               seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
-       } else
-               seq_printf(m, "Simple card %d\n", ec->cid.id);
-
-       return 0;
-}
-
-static int ecard_devices_proc_show(struct seq_file *m, void *v)
-{
-       ecard_t *ec = cards;
-
-       while (ec) {
-               ecard_prints(m, ec);
-               ec = ec->next;
-       }
-       return 0;
-}
-
-static int ecard_devices_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, ecard_devices_proc_show, NULL);
-}
-
-static const struct file_operations bus_ecard_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ecard_devices_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
-
-static void ecard_proc_init(void)
-{
-       proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL);
-       proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops);
-}
-
-#define ec_set_resource(ec,nr,st,sz)                           \
-       do {                                                    \
-               (ec)->resource[nr].name = dev_name(&ec->dev);   \
-               (ec)->resource[nr].start = st;                  \
-               (ec)->resource[nr].end = (st) + (sz) - 1;       \
-               (ec)->resource[nr].flags = IORESOURCE_MEM;      \
-       } while (0)
-
-static void __init ecard_free_card(struct expansion_card *ec)
-{
-       int i;
-
-       for (i = 0; i < ECARD_NUM_RESOURCES; i++)
-               if (ec->resource[i].flags)
-                       release_resource(&ec->resource[i]);
-
-       kfree(ec);
-}
-
-static struct expansion_card *__init ecard_alloc_card(int type, int slot)
-{
-       struct expansion_card *ec;
-       unsigned long base;
-       int i;
-
-       ec = kzalloc(sizeof(ecard_t), GFP_KERNEL);
-       if (!ec) {
-               ec = ERR_PTR(-ENOMEM);
-               goto nomem;
-       }
-
-       ec->slot_no = slot;
-       ec->easi = type == ECARD_EASI;
-       ec->irq = NO_IRQ;
-       ec->fiq = NO_IRQ;
-       ec->dma = NO_DMA;
-       ec->ops = &ecard_default_ops;
-
-       dev_set_name(&ec->dev, "ecard%d", slot);
-       ec->dev.parent = NULL;
-       ec->dev.bus = &ecard_bus_type;
-       ec->dev.dma_mask = &ec->dma_mask;
-       ec->dma_mask = (u64)0xffffffff;
-       ec->dev.coherent_dma_mask = ec->dma_mask;
-
-       if (slot < 4) {
-               ec_set_resource(ec, ECARD_RES_MEMC,
-                               PODSLOT_MEMC_BASE + (slot << 14),
-                               PODSLOT_MEMC_SIZE);
-               base = PODSLOT_IOC0_BASE + (slot << 14);
-       } else
-               base = PODSLOT_IOC4_BASE + ((slot - 4) << 14);
-
-#ifdef CONFIG_ARCH_RPC
-       if (slot < 8) {
-               ec_set_resource(ec, ECARD_RES_EASI,
-                               PODSLOT_EASI_BASE + (slot << 24),
-                               PODSLOT_EASI_SIZE);
-       }
-
-       if (slot == 8) {
-               ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE);
-       } else
-#endif
-
-       for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++)
-               ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
-                               base + (i << 19), PODSLOT_IOC_SIZE);
-
-       for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
-               if (ec->resource[i].flags &&
-                   request_resource(&iomem_resource, &ec->resource[i])) {
-                       dev_err(&ec->dev, "resource(s) not available\n");
-                       ec->resource[i].end -= ec->resource[i].start;
-                       ec->resource[i].start = 0;
-                       ec->resource[i].flags = 0;
-               }
-       }
-
- nomem:
-       return ec;
-}
-
-static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct expansion_card *ec = ECARD_DEV(dev);
-       return sprintf(buf, "%u\n", ec->irq);
-}
-
-static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct expansion_card *ec = ECARD_DEV(dev);
-       return sprintf(buf, "%u\n", ec->dma);
-}
-
-static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct expansion_card *ec = ECARD_DEV(dev);
-       char *str = buf;
-       int i;
-
-       for (i = 0; i < ECARD_NUM_RESOURCES; i++)
-               str += sprintf(str, "%08x %08x %08lx\n",
-                               ec->resource[i].start,
-                               ec->resource[i].end,
-                               ec->resource[i].flags);
-
-       return str - buf;
-}
-
-static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct expansion_card *ec = ECARD_DEV(dev);
-       return sprintf(buf, "%u\n", ec->cid.manufacturer);
-}
-
-static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct expansion_card *ec = ECARD_DEV(dev);
-       return sprintf(buf, "%u\n", ec->cid.product);
-}
-
-static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct expansion_card *ec = ECARD_DEV(dev);
-       return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
-}
-
-static struct device_attribute ecard_dev_attrs[] = {
-       __ATTR(device,   S_IRUGO, ecard_show_device,    NULL),
-       __ATTR(dma,      S_IRUGO, ecard_show_dma,       NULL),
-       __ATTR(irq,      S_IRUGO, ecard_show_irq,       NULL),
-       __ATTR(resource, S_IRUGO, ecard_show_resources, NULL),
-       __ATTR(type,     S_IRUGO, ecard_show_type,      NULL),
-       __ATTR(vendor,   S_IRUGO, ecard_show_vendor,    NULL),
-       __ATTR_NULL,
-};
-
-
-int ecard_request_resources(struct expansion_card *ec)
-{
-       int i, err = 0;
-
-       for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
-               if (ecard_resource_end(ec, i) &&
-                   !request_mem_region(ecard_resource_start(ec, i),
-                                       ecard_resource_len(ec, i),
-                                       ec->dev.driver->name)) {
-                       err = -EBUSY;
-                       break;
-               }
-       }
-
-       if (err) {
-               while (i--)
-                       if (ecard_resource_end(ec, i))
-                               release_mem_region(ecard_resource_start(ec, i),
-                                                  ecard_resource_len(ec, i));
-       }
-       return err;
-}
-EXPORT_SYMBOL(ecard_request_resources);
-
-void ecard_release_resources(struct expansion_card *ec)
-{
-       int i;
-
-       for (i = 0; i < ECARD_NUM_RESOURCES; i++)
-               if (ecard_resource_end(ec, i))
-                       release_mem_region(ecard_resource_start(ec, i),
-                                          ecard_resource_len(ec, i));
-}
-EXPORT_SYMBOL(ecard_release_resources);
-
-void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data)
-{
-       ec->irq_data = irq_data;
-       barrier();
-       ec->ops = ops;
-}
-EXPORT_SYMBOL(ecard_setirq);
-
-void __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res,
-                          unsigned long offset, unsigned long maxsize)
-{
-       unsigned long start = ecard_resource_start(ec, res);
-       unsigned long end = ecard_resource_end(ec, res);
-
-       if (offset > (end - start))
-               return NULL;
-
-       start += offset;
-       if (maxsize && end - start > maxsize)
-               end = start + maxsize;
-       
-       return devm_ioremap(&ec->dev, start, end - start);
-}
-EXPORT_SYMBOL(ecardm_iomap);
-
-/*
- * Probe for an expansion card.
- *
- * If bit 1 of the first byte of the card is set, then the
- * card does not exist.
- */
-static int __init
-ecard_probe(int slot, card_type_t type)
-{
-       ecard_t **ecp;
-       ecard_t *ec;
-       struct ex_ecid cid;
-       void __iomem *addr;
-       int i, rc;
-
-       ec = ecard_alloc_card(type, slot);
-       if (IS_ERR(ec)) {
-               rc = PTR_ERR(ec);
-               goto nomem;
-       }
-
-       rc = -ENODEV;
-       if ((addr = __ecard_address(ec, type, ECARD_SYNC)) == NULL)
-               goto nodev;
-
-       cid.r_zero = 1;
-       ecard_readbytes(&cid, ec, 0, 16, 0);
-       if (cid.r_zero)
-               goto nodev;
-
-       ec->cid.id      = cid.r_id;
-       ec->cid.cd      = cid.r_cd;
-       ec->cid.is      = cid.r_is;
-       ec->cid.w       = cid.r_w;
-       ec->cid.manufacturer = ecard_getu16(cid.r_manu);
-       ec->cid.product = ecard_getu16(cid.r_prod);
-       ec->cid.country = cid.r_country;
-       ec->cid.irqmask = cid.r_irqmask;
-       ec->cid.irqoff  = ecard_gets24(cid.r_irqoff);
-       ec->cid.fiqmask = cid.r_fiqmask;
-       ec->cid.fiqoff  = ecard_gets24(cid.r_fiqoff);
-       ec->fiqaddr     =
-       ec->irqaddr     = addr;
-
-       if (ec->cid.is) {
-               ec->irqmask = ec->cid.irqmask;
-               ec->irqaddr += ec->cid.irqoff;
-               ec->fiqmask = ec->cid.fiqmask;
-               ec->fiqaddr += ec->cid.fiqoff;
-       } else {
-               ec->irqmask = 1;
-               ec->fiqmask = 4;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(blacklist); i++)
-               if (blacklist[i].manufacturer == ec->cid.manufacturer &&
-                   blacklist[i].product == ec->cid.product) {
-                       ec->card_desc = blacklist[i].type;
-                       break;
-               }
-
-       /*
-        * hook the interrupt handlers
-        */
-       if (slot < 8) {
-               ec->irq = 32 + slot;
-               irq_set_chip_and_handler(ec->irq, &ecard_chip,
-                                        handle_level_irq);
-               set_irq_flags(ec->irq, IRQF_VALID);
-       }
-
-       if (slot == 8)
-               ec->irq = 11;
-#ifdef CONFIG_ARCH_RPC
-       /* On RiscPC, only first two slots have DMA capability */
-       if (slot < 2)
-               ec->dma = 2 + slot;
-#endif
-
-       for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
-
-       *ecp = ec;
-       slot_to_expcard[slot] = ec;
-
-       device_register(&ec->dev);
-
-       return 0;
-
- nodev:
-       ecard_free_card(ec);
- nomem:
-       return rc;
-}
-
-/*
- * Initialise the expansion card system.
- * Locate all hardware - interrupt management and
- * actual cards.
- */
-static int __init ecard_init(void)
-{
-       struct task_struct *task;
-       int slot, irqhw;
-
-       task = kthread_run(ecard_task, NULL, "kecardd");
-       if (IS_ERR(task)) {
-               printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
-                      PTR_ERR(task));
-               return PTR_ERR(task);
-       }
-
-       printk("Probing expansion cards\n");
-
-       for (slot = 0; slot < 8; slot ++) {
-               if (ecard_probe(slot, ECARD_EASI) == -ENODEV)
-                       ecard_probe(slot, ECARD_IOC);
-       }
-
-       ecard_probe(8, ECARD_IOC);
-
-       irqhw = ecard_probeirqhw();
-
-       irq_set_chained_handler(IRQ_EXPANSIONCARD,
-                               irqhw ? ecard_irqexp_handler : ecard_irq_handler);
-
-       ecard_proc_init();
-
-       return 0;
-}
-
-subsys_initcall(ecard_init);
-
-/*
- *     ECARD "bus"
- */
-static const struct ecard_id *
-ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
-{
-       int i;
-
-       for (i = 0; ids[i].manufacturer != 65535; i++)
-               if (ec->cid.manufacturer == ids[i].manufacturer &&
-                   ec->cid.product == ids[i].product)
-                       return ids + i;
-
-       return NULL;
-}
-
-static int ecard_drv_probe(struct device *dev)
-{
-       struct expansion_card *ec = ECARD_DEV(dev);
-       struct ecard_driver *drv = ECARD_DRV(dev->driver);
-       const struct ecard_id *id;
-       int ret;
-
-       id = ecard_match_device(drv->id_table, ec);
-
-       ec->claimed = 1;
-       ret = drv->probe(ec, id);
-       if (ret)
-               ec->claimed = 0;
-       return ret;
-}
-
-static int ecard_drv_remove(struct device *dev)
-{
-       struct expansion_card *ec = ECARD_DEV(dev);
-       struct ecard_driver *drv = ECARD_DRV(dev->driver);
-
-       drv->remove(ec);
-       ec->claimed = 0;
-
-       /*
-        * Restore the default operations.  We ensure that the
-        * ops are set before we change the data.
-        */
-       ec->ops = &ecard_default_ops;
-       barrier();
-       ec->irq_data = NULL;
-
-       return 0;
-}
-
-/*
- * Before rebooting, we must make sure that the expansion card is in a
- * sensible state, so it can be re-detected.  This means that the first
- * page of the ROM must be visible.  We call the expansion cards reset
- * handler, if any.
- */
-static void ecard_drv_shutdown(struct device *dev)
-{
-       struct expansion_card *ec = ECARD_DEV(dev);
-       struct ecard_driver *drv = ECARD_DRV(dev->driver);
-       struct ecard_request req;
-
-       if (dev->driver) {
-               if (drv->shutdown)
-                       drv->shutdown(ec);
-               ec->claimed = 0;
-       }
-
-       /*
-        * If this card has a loader, call the reset handler.
-        */
-       if (ec->loader) {
-               req.fn = ecard_task_reset;
-               req.ec = ec;
-               ecard_call(&req);
-       }
-}
-
-int ecard_register_driver(struct ecard_driver *drv)
-{
-       drv->drv.bus = &ecard_bus_type;
-
-       return driver_register(&drv->drv);
-}
-
-void ecard_remove_driver(struct ecard_driver *drv)
-{
-       driver_unregister(&drv->drv);
-}
-
-static int ecard_match(struct device *_dev, struct device_driver *_drv)
-{
-       struct expansion_card *ec = ECARD_DEV(_dev);
-       struct ecard_driver *drv = ECARD_DRV(_drv);
-       int ret;
-
-       if (drv->id_table) {
-               ret = ecard_match_device(drv->id_table, ec) != NULL;
-       } else {
-               ret = ec->cid.id == drv->id;
-       }
-
-       return ret;
-}
-
-struct bus_type ecard_bus_type = {
-       .name           = "ecard",
-       .dev_attrs      = ecard_dev_attrs,
-       .match          = ecard_match,
-       .probe          = ecard_drv_probe,
-       .remove         = ecard_drv_remove,
-       .shutdown       = ecard_drv_shutdown,
-};
-
-static int ecard_bus_init(void)
-{
-       return bus_register(&ecard_bus_type);
-}
-
-postcore_initcall(ecard_bus_init);
-
-EXPORT_SYMBOL(ecard_readchunk);
-EXPORT_SYMBOL(ecard_register_driver);
-EXPORT_SYMBOL(ecard_remove_driver);
-EXPORT_SYMBOL(ecard_bus_type);
diff --git a/arch/arm/kernel/ecard.h b/arch/arm/kernel/ecard.h
deleted file mode 100644 (file)
index 4642d43..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *  ecard.h
- *
- *  Copyright 2007 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* Definitions internal to ecard.c - for it's use only!!
- *
- * External expansion card header as read from the card
- */
-struct ex_ecid {
-       unsigned char   r_irq:1;
-       unsigned char   r_zero:1;
-       unsigned char   r_fiq:1;
-       unsigned char   r_id:4;
-       unsigned char   r_a:1;
-
-       unsigned char   r_cd:1;
-       unsigned char   r_is:1;
-       unsigned char   r_w:2;
-       unsigned char   r_r1:4;
-
-       unsigned char   r_r2:8;
-
-       unsigned char   r_prod[2];
-
-       unsigned char   r_manu[2];
-
-       unsigned char   r_country;
-
-       unsigned char   r_fiqmask;
-       unsigned char   r_fiqoff[3];
-
-       unsigned char   r_irqmask;
-       unsigned char   r_irqoff[3];
-};
-
-/*
- * Chunk directory entry as read from the card
- */
-struct ex_chunk_dir {
-       unsigned char r_id;
-       unsigned char r_len[3];
-       unsigned long r_start;
-       union {
-               char string[256];
-               char data[1];
-       } d;
-#define c_id(x)                ((x)->r_id)
-#define c_len(x)       ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16))
-#define c_start(x)     ((x)->r_start)
-};
-
-typedef enum ecard_type {              /* Cards address space          */
-       ECARD_IOC,
-       ECARD_MEMC,
-       ECARD_EASI
-} card_type_t;
-
-typedef enum {                         /* Speed for ECARD_IOC space    */
-       ECARD_SLOW       = 0,
-       ECARD_MEDIUM     = 1,
-       ECARD_FAST       = 2,
-       ECARD_SYNC       = 3
-} card_speed_t;
index 093a415..8ec5eed 100644 (file)
@@ -19,7 +19,9 @@
 #include <asm/glue-df.h>
 #include <asm/glue-pf.h>
 #include <asm/vfpmacros.h>
+#ifndef CONFIG_MULTI_IRQ_HANDLER
 #include <mach/entry-macro.S>
+#endif
 #include <asm/thread_notify.h>
 #include <asm/unwind.h>
 #include <asm/unistd.h>
@@ -1101,7 +1103,6 @@ __stubs_start:
  * get out of that mode without clobbering one register.
  */
 vector_fiq:
-       disable_fiq
        subs    pc, lr, #4
 
 /*=============================================================================
index 9fd0ba9..54ee265 100644 (file)
 
 #include <asm/unistd.h>
 #include <asm/ftrace.h>
-#include <mach/entry-macro.S>
 #include <asm/unwind.h>
 
+#ifdef CONFIG_NEED_RET_TO_USER
+#include <mach/entry-macro.S>
+#else
+       .macro  arch_ret_to_user, tmp1, tmp2
+       .endm
+#endif
+
 #include "entry-header.S"
 
 
index 19917e8..7b9cdde 100644 (file)
@@ -60,8 +60,6 @@ extern void setup_mm_for_reboot(void);
 
 static volatile int hlt_counter;
 
-#include <mach/system.h>
-
 void disable_hlt(void)
 {
        hlt_counter++;
@@ -180,13 +178,17 @@ void cpu_idle_wait(void)
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
 /*
- * This is our default idle handler.  We need to disable
- * interrupts here to ensure we don't miss a wakeup call.
+ * This is our default idle handler.
  */
+
+void (*arm_pm_idle)(void);
+
 static void default_idle(void)
 {
-       if (!need_resched())
-               arch_idle();
+       if (arm_pm_idle)
+               arm_pm_idle();
+       else
+               cpu_do_idle();
        local_irq_enable();
 }
 
@@ -214,6 +216,10 @@ void cpu_idle(void)
                                cpu_die();
 #endif
 
+                       /*
+                        * We need to disable interrupts here
+                        * to ensure we don't miss a wakeup call.
+                        */
                        local_irq_disable();
 #ifdef CONFIG_PL310_ERRATA_769419
                        wmb();
@@ -221,19 +227,18 @@ void cpu_idle(void)
                        if (hlt_counter) {
                                local_irq_enable();
                                cpu_relax();
-                       } else {
+                       } else if (!need_resched()) {
                                stop_critical_timings();
                                if (cpuidle_idle_call())
                                        pm_idle();
                                start_critical_timings();
                                /*
-                                * This will eventually be removed - pm_idle
-                                * functions should always return with IRQs
-                                * enabled.
+                                * pm_idle functions must always
+                                * return with IRQs enabled.
                                 */
                                WARN_ON(irqs_disabled());
+                       } else
                                local_irq_enable();
-                       }
                }
                leds_event(led_idle_end);
                rcu_idle_exit();
@@ -532,8 +537,7 @@ int vectors_user_mapping(void)
        struct mm_struct *mm = current->mm;
        return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,
                                       VM_READ | VM_EXEC |
-                                      VM_MAYREAD | VM_MAYEXEC |
-                                      VM_ALWAYSDUMP | VM_RESERVED,
+                                      VM_MAYREAD | VM_MAYEXEC | VM_RESERVED,
                                       NULL);
 }
 
index d616ed5..8f8cce2 100644 (file)
@@ -246,6 +246,8 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
        store_cpu_topology(cpuid);
 }
 
+static void percpu_timer_setup(void);
+
 /*
  * This is the secondary CPU boot entry.  We're using this CPUs
  * idle thread stack, but a set of temporary page tables.
@@ -452,7 +454,20 @@ static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
        clockevents_register_device(evt);
 }
 
-void __cpuinit percpu_timer_setup(void)
+static struct local_timer_ops *lt_ops;
+
+#ifdef CONFIG_LOCAL_TIMERS
+int local_timer_register(struct local_timer_ops *ops)
+{
+       if (lt_ops)
+               return -EBUSY;
+
+       lt_ops = ops;
+       return 0;
+}
+#endif
+
+static void __cpuinit percpu_timer_setup(void)
 {
        unsigned int cpu = smp_processor_id();
        struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
@@ -460,7 +475,7 @@ void __cpuinit percpu_timer_setup(void)
        evt->cpumask = cpumask_of(cpu);
        evt->broadcast = smp_timer_broadcast;
 
-       if (local_timer_setup(evt))
+       if (!lt_ops || lt_ops->setup(evt))
                broadcast_timer_setup(evt);
 }
 
@@ -475,7 +490,8 @@ static void percpu_timer_stop(void)
        unsigned int cpu = smp_processor_id();
        struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
 
-       local_timer_stop(evt);
+       if (lt_ops)
+               lt_ops->stop(evt);
 }
 #endif
 
index 7a79b24..fef42b2 100644 (file)
 #include <linux/smp.h>
 #include <linux/jiffies.h>
 #include <linux/clockchips.h>
-#include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
 
 #include <asm/smp_twd.h>
 #include <asm/localtimer.h>
 #include <asm/hardware/gic.h>
 
 /* set up by the platform code */
-void __iomem *twd_base;
+static void __iomem *twd_base;
 
 static struct clk *twd_clk;
 static unsigned long twd_timer_rate;
 
 static struct clock_event_device __percpu **twd_evt;
+static int twd_ppi;
 
 static void twd_set_mode(enum clock_event_mode mode,
                        struct clock_event_device *clk)
@@ -77,7 +80,7 @@ static int twd_set_next_event(unsigned long evt,
  * If a local timer interrupt has occurred, acknowledge and return 1.
  * Otherwise, return 0.
  */
-int twd_timer_ack(void)
+static int twd_timer_ack(void)
 {
        if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
                __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
@@ -87,7 +90,7 @@ int twd_timer_ack(void)
        return 0;
 }
 
-void twd_timer_stop(struct clock_event_device *clk)
+static void twd_timer_stop(struct clock_event_device *clk)
 {
        twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
        disable_percpu_irq(clk->irq);
@@ -222,28 +225,10 @@ static struct clk *twd_get_clock(void)
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit twd_timer_setup(struct clock_event_device *clk)
+static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
        struct clock_event_device **this_cpu_clk;
 
-       if (!twd_evt) {
-               int err;
-
-               twd_evt = alloc_percpu(struct clock_event_device *);
-               if (!twd_evt) {
-                       pr_err("twd: can't allocate memory\n");
-                       return;
-               }
-
-               err = request_percpu_irq(clk->irq, twd_handler,
-                                        "twd", twd_evt);
-               if (err) {
-                       pr_err("twd: can't register interrupt %d (%d)\n",
-                              clk->irq, err);
-                       return;
-               }
-       }
-
        if (!twd_clk)
                twd_clk = twd_get_clock();
 
@@ -260,6 +245,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
        clk->rating = 350;
        clk->set_mode = twd_set_mode;
        clk->set_next_event = twd_set_next_event;
+       clk->irq = twd_ppi;
 
        this_cpu_clk = __this_cpu_ptr(twd_evt);
        *this_cpu_clk = clk;
@@ -267,4 +253,95 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
        clockevents_config_and_register(clk, twd_timer_rate,
                                        0xf, 0xffffffff);
        enable_percpu_irq(clk->irq, 0);
+
+       return 0;
+}
+
+static struct local_timer_ops twd_lt_ops __cpuinitdata = {
+       .setup  = twd_timer_setup,
+       .stop   = twd_timer_stop,
+};
+
+static int __init twd_local_timer_common_register(void)
+{
+       int err;
+
+       twd_evt = alloc_percpu(struct clock_event_device *);
+       if (!twd_evt) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+
+       err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt);
+       if (err) {
+               pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err);
+               goto out_free;
+       }
+
+       err = local_timer_register(&twd_lt_ops);
+       if (err)
+               goto out_irq;
+
+       return 0;
+
+out_irq:
+       free_percpu_irq(twd_ppi, twd_evt);
+out_free:
+       iounmap(twd_base);
+       twd_base = NULL;
+       free_percpu(twd_evt);
+
+       return err;
 }
+
+int __init twd_local_timer_register(struct twd_local_timer *tlt)
+{
+       if (twd_base || twd_evt)
+               return -EBUSY;
+
+       twd_ppi = tlt->res[1].start;
+
+       twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0]));
+       if (!twd_base)
+               return -ENOMEM;
+
+       return twd_local_timer_common_register();
+}
+
+#ifdef CONFIG_OF
+const static struct of_device_id twd_of_match[] __initconst = {
+       { .compatible = "arm,cortex-a9-twd-timer",      },
+       { .compatible = "arm,cortex-a5-twd-timer",      },
+       { .compatible = "arm,arm11mp-twd-timer",        },
+       { },
+};
+
+void __init twd_local_timer_of_register(void)
+{
+       struct device_node *np;
+       int err;
+
+       np = of_find_matching_node(NULL, twd_of_match);
+       if (!np) {
+               err = -ENODEV;
+               goto out;
+       }
+
+       twd_ppi = irq_of_parse_and_map(np, 0);
+       if (!twd_ppi) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       twd_base = of_iomap(np, 0);
+       if (!twd_base) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = twd_local_timer_common_register();
+
+out:
+       WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
+}
+#endif
index 71feb00..45db05d 100644 (file)
@@ -20,9 +20,11 @@ config HAVE_AT91_USART5
 
 config AT91_SAM9_ALT_RESET
        bool
+       default !ARCH_AT91X40
 
 config AT91_SAM9G45_RESET
        bool
+       default !ARCH_AT91X40
 
 menu "Atmel AT91 System-on-Chip"
 
@@ -45,7 +47,6 @@ config ARCH_AT91SAM9260
        select HAVE_AT91_USART4
        select HAVE_AT91_USART5
        select HAVE_NET_MACB
-       select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9261
        bool "AT91SAM9261"
@@ -53,7 +54,6 @@ config ARCH_AT91SAM9261
        select GENERIC_CLOCKEVENTS
        select HAVE_FB_ATMEL
        select HAVE_AT91_DBGU0
-       select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9G10
        bool "AT91SAM9G10"
@@ -61,7 +61,6 @@ config ARCH_AT91SAM9G10
        select GENERIC_CLOCKEVENTS
        select HAVE_AT91_DBGU0
        select HAVE_FB_ATMEL
-       select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9263
        bool "AT91SAM9263"
@@ -70,7 +69,6 @@ config ARCH_AT91SAM9263
        select HAVE_FB_ATMEL
        select HAVE_NET_MACB
        select HAVE_AT91_DBGU1
-       select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9RL
        bool "AT91SAM9RL"
@@ -79,7 +77,6 @@ config ARCH_AT91SAM9RL
        select HAVE_AT91_USART3
        select HAVE_FB_ATMEL
        select HAVE_AT91_DBGU0
-       select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9G20
        bool "AT91SAM9G20"
@@ -90,7 +87,6 @@ config ARCH_AT91SAM9G20
        select HAVE_AT91_USART4
        select HAVE_AT91_USART5
        select HAVE_NET_MACB
-       select AT91_SAM9_ALT_RESET
 
 config ARCH_AT91SAM9G45
        bool "AT91SAM9G45"
@@ -100,16 +96,14 @@ config ARCH_AT91SAM9G45
        select HAVE_FB_ATMEL
        select HAVE_NET_MACB
        select HAVE_AT91_DBGU1
-       select AT91_SAM9G45_RESET
 
-config ARCH_AT91CAP9
-       bool "AT91CAP9"
+config ARCH_AT91SAM9X5
+       bool "AT91SAM9x5 family"
        select CPU_ARM926T
        select GENERIC_CLOCKEVENTS
        select HAVE_FB_ATMEL
        select HAVE_NET_MACB
-       select HAVE_AT91_DBGU1
-       select AT91_SAM9G45_RESET
+       select HAVE_AT91_DBGU0
 
 config ARCH_AT91X40
        bool "AT91x40"
@@ -447,21 +441,6 @@ endif
 
 # ----------------------------------------------------------
 
-if ARCH_AT91CAP9
-
-comment "AT91CAP9 Board Type"
-
-config MACH_AT91CAP9ADK
-       bool "Atmel AT91CAP9A-DK Evaluation Kit"
-       select HAVE_AT91_DATAFLASH_CARD
-       help
-         Select this if you are using Atmel's AT91CAP9A-DK Evaluation Kit.
-         <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4138>
-
-endif
-
-# ----------------------------------------------------------
-
 if ARCH_AT91X40
 
 comment "AT91X40 Board Type"
@@ -544,7 +523,7 @@ config AT91_EARLY_DBGU0
        depends on HAVE_AT91_DBGU0
 
 config AT91_EARLY_DBGU1
-       bool "DBGU on 9263, 9g45 and cap9"
+       bool "DBGU on 9263 and 9g45"
        depends on HAVE_AT91_DBGU1
 
 config AT91_EARLY_USART0
index 705e1fb..8512e53 100644 (file)
@@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_AT91SAM9263)        += at91sam9263.o at91sam926x_time.o at91sam9263_d
 obj-$(CONFIG_ARCH_AT91SAM9RL)  += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91CAP9)    += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9X5)  += at91sam9x5.o at91sam926x_time.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91X40)     += at91x40.o at91x40_time.o
 
 # AT91RM9200 board-specific support
@@ -81,9 +81,6 @@ obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o
 # AT91SAM board with device-tree
 obj-$(CONFIG_MACH_AT91SAM_DT) += board-dt.o
 
-# AT91CAP9 board-specific support
-obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
-
 # AT91X40 board-specific support
 obj-$(CONFIG_MACH_AT91EB01)    += board-eb01.o
 
index 8ddafad..0da66ca 100644 (file)
@@ -3,11 +3,7 @@
 #   PARAMS_PHYS must be within 4MB of ZRELADDR
 #   INITRD_PHYS must be in RAM
 
-ifeq ($(CONFIG_ARCH_AT91CAP9),y)
-   zreladdr-y  += 0x70008000
-params_phys-y  := 0x70000100
-initrd_phys-y  := 0x70410000
-else ifeq ($(CONFIG_ARCH_AT91SAM9G45),y)
+ifeq ($(CONFIG_ARCH_AT91SAM9G45),y)
    zreladdr-y  += 0x70008000
 params_phys-y  := 0x70000100
 initrd_phys-y  := 0x70410000
@@ -17,4 +13,10 @@ params_phys-y        := 0x20000100
 initrd_phys-y  := 0x20410000
 endif
 
-dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb usb_a9g20.dtb
+# Keep dtb files sorted alphabetically for each SoC
+# sam9g20
+dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb
+# sam9g45
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
+# sam9x5
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
diff --git a/arch/arm/mach-at91/at91cap9.c b/arch/arm/mach-at91/at91cap9.c
deleted file mode 100644 (file)
index fc460e9..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * arch/arm/mach-at91/at91cap9.c
- *
- *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
- *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
- *  Copyright (C) 2007 Atmel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/module.h>
-
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/system_info.h>
-#include <asm/system_misc.h>
-
-#include <mach/cpu.h>
-#include <mach/at91cap9.h>
-#include <mach/at91_pmc.h>
-
-#include "soc.h"
-#include "generic.h"
-#include "clock.h"
-#include "sam9_smc.h"
-
-/* --------------------------------------------------------------------
- *  Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioABCD_clk = {
-       .name           = "pioABCD_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_PIOABCD,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mpb0_clk = {
-       .name           = "mpb0_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_MPB0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mpb1_clk = {
-       .name           = "mpb1_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_MPB1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mpb2_clk = {
-       .name           = "mpb2_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_MPB2,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mpb3_clk = {
-       .name           = "mpb3_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_MPB3,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mpb4_clk = {
-       .name           = "mpb4_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_MPB4,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
-       .name           = "usart0_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_US0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
-       .name           = "usart1_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_US1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
-       .name           = "usart2_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_US2,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc0_clk = {
-       .name           = "mci0_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_MCI0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc1_clk = {
-       .name           = "mci1_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_MCI1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk can_clk = {
-       .name           = "can_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_CAN,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi_clk = {
-       .name           = "twi_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_TWI,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
-       .name           = "spi0_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_SPI0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
-       .name           = "spi1_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_SPI1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc0_clk = {
-       .name           = "ssc0_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_SSC0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc1_clk = {
-       .name           = "ssc1_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_SSC1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ac97_clk = {
-       .name           = "ac97_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_AC97C,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tcb_clk = {
-       .name           = "tcb_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_TCB,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pwm_clk = {
-       .name           = "pwm_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_PWMC,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk macb_clk = {
-       .name           = "pclk",
-       .pmc_mask       = 1 << AT91CAP9_ID_EMAC,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk aestdes_clk = {
-       .name           = "aestdes_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_AESTDES,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk adc_clk = {
-       .name           = "adc_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_ADC,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk isi_clk = {
-       .name           = "isi_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_ISI,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk lcdc_clk = {
-       .name           = "lcdc_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_LCDC,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk dma_clk = {
-       .name           = "dma_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_DMA,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk udphs_clk = {
-       .name           = "udphs_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_UDPHS,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ohci_clk = {
-       .name           = "ohci_clk",
-       .pmc_mask       = 1 << AT91CAP9_ID_UHP,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk *periph_clocks[] __initdata = {
-       &pioABCD_clk,
-       &mpb0_clk,
-       &mpb1_clk,
-       &mpb2_clk,
-       &mpb3_clk,
-       &mpb4_clk,
-       &usart0_clk,
-       &usart1_clk,
-       &usart2_clk,
-       &mmc0_clk,
-       &mmc1_clk,
-       &can_clk,
-       &twi_clk,
-       &spi0_clk,
-       &spi1_clk,
-       &ssc0_clk,
-       &ssc1_clk,
-       &ac97_clk,
-       &tcb_clk,
-       &pwm_clk,
-       &macb_clk,
-       &aestdes_clk,
-       &adc_clk,
-       &isi_clk,
-       &lcdc_clk,
-       &dma_clk,
-       &udphs_clk,
-       &ohci_clk,
-       // irq0 .. irq1
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
-       /* One additional fake clock for macb_hclk */
-       CLKDEV_CON_ID("hclk", &macb_clk),
-       CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
-       CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
-       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
-       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
-       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
-       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
-       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
-       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
-       /* fake hclk clock */
-       CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
-       CLKDEV_CON_ID("pioA", &pioABCD_clk),
-       CLKDEV_CON_ID("pioB", &pioABCD_clk),
-       CLKDEV_CON_ID("pioC", &pioABCD_clk),
-       CLKDEV_CON_ID("pioD", &pioABCD_clk),
-};
-
-static struct clk_lookup usart_clocks_lookups[] = {
-       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
-       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
-       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
-       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
-};
-
-/*
- * The four programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
-       .name           = "pck0",
-       .pmc_mask       = AT91_PMC_PCK0,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 0,
-};
-static struct clk pck1 = {
-       .name           = "pck1",
-       .pmc_mask       = AT91_PMC_PCK1,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 1,
-};
-static struct clk pck2 = {
-       .name           = "pck2",
-       .pmc_mask       = AT91_PMC_PCK2,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 2,
-};
-static struct clk pck3 = {
-       .name           = "pck3",
-       .pmc_mask       = AT91_PMC_PCK3,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 3,
-};
-
-static void __init at91cap9_register_clocks(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
-               clk_register(periph_clocks[i]);
-
-       clkdev_add_table(periph_clocks_lookups,
-                        ARRAY_SIZE(periph_clocks_lookups));
-       clkdev_add_table(usart_clocks_lookups,
-                        ARRAY_SIZE(usart_clocks_lookups));
-
-       clk_register(&pck0);
-       clk_register(&pck1);
-       clk_register(&pck2);
-       clk_register(&pck3);
-}
-
-static struct clk_lookup console_clock_lookup;
-
-void __init at91cap9_set_console_clock(int id)
-{
-       if (id >= ARRAY_SIZE(usart_clocks_lookups))
-               return;
-
-       console_clock_lookup.con_id = "usart";
-       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
-       clkdev_add(&console_clock_lookup);
-}
-
-/* --------------------------------------------------------------------
- *  GPIO
- * -------------------------------------------------------------------- */
-
-static struct at91_gpio_bank at91cap9_gpio[] __initdata = {
-       {
-               .id             = AT91CAP9_ID_PIOABCD,
-               .regbase        = AT91CAP9_BASE_PIOA,
-       }, {
-               .id             = AT91CAP9_ID_PIOABCD,
-               .regbase        = AT91CAP9_BASE_PIOB,
-       }, {
-               .id             = AT91CAP9_ID_PIOABCD,
-               .regbase        = AT91CAP9_BASE_PIOC,
-       }, {
-               .id             = AT91CAP9_ID_PIOABCD,
-               .regbase        = AT91CAP9_BASE_PIOD,
-       }
-};
-
-/* --------------------------------------------------------------------
- *  AT91CAP9 processor initialization
- * -------------------------------------------------------------------- */
-
-static void __init at91cap9_map_io(void)
-{
-       at91_init_sram(0, AT91CAP9_SRAM_BASE, AT91CAP9_SRAM_SIZE);
-}
-
-static void __init at91cap9_ioremap_registers(void)
-{
-       at91_ioremap_shdwc(AT91CAP9_BASE_SHDWC);
-       at91_ioremap_rstc(AT91CAP9_BASE_RSTC);
-       at91sam926x_ioremap_pit(AT91CAP9_BASE_PIT);
-       at91sam9_ioremap_smc(0, AT91CAP9_BASE_SMC);
-}
-
-static void __init at91cap9_initialize(void)
-{
-       arm_pm_restart = at91sam9g45_restart;
-       at91_extern_irq = (1 << AT91CAP9_ID_IRQ0) | (1 << AT91CAP9_ID_IRQ1);
-
-       /* Register GPIO subsystem */
-       at91_gpio_init(at91cap9_gpio, 4);
-
-       /* Remember the silicon revision */
-       if (cpu_is_at91cap9_revB())
-               system_rev = 0xB;
-       else if (cpu_is_at91cap9_revC())
-               system_rev = 0xC;
-}
-
-/* --------------------------------------------------------------------
- *  Interrupt initialization
- * -------------------------------------------------------------------- */
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91cap9_default_irq_priority[NR_AIC_IRQS] __initdata = {
-       7,      /* Advanced Interrupt Controller (FIQ) */
-       7,      /* System Peripherals */
-       1,      /* Parallel IO Controller A, B, C and D */
-       0,      /* MP Block Peripheral 0 */
-       0,      /* MP Block Peripheral 1 */
-       0,      /* MP Block Peripheral 2 */
-       0,      /* MP Block Peripheral 3 */
-       0,      /* MP Block Peripheral 4 */
-       5,      /* USART 0 */
-       5,      /* USART 1 */
-       5,      /* USART 2 */
-       0,      /* Multimedia Card Interface 0 */
-       0,      /* Multimedia Card Interface 1 */
-       3,      /* CAN */
-       6,      /* Two-Wire Interface */
-       5,      /* Serial Peripheral Interface 0 */
-       5,      /* Serial Peripheral Interface 1 */
-       4,      /* Serial Synchronous Controller 0 */
-       4,      /* Serial Synchronous Controller 1 */
-       5,      /* AC97 Controller */
-       0,      /* Timer Counter 0, 1 and 2 */
-       0,      /* Pulse Width Modulation Controller */
-       3,      /* Ethernet */
-       0,      /* Advanced Encryption Standard, Triple DES*/
-       0,      /* Analog-to-Digital Converter */
-       0,      /* Image Sensor Interface */
-       3,      /* LCD Controller */
-       0,      /* DMA Controller */
-       2,      /* USB Device Port */
-       2,      /* USB Host port */
-       0,      /* Advanced Interrupt Controller (IRQ0) */
-       0,      /* Advanced Interrupt Controller (IRQ1) */
-};
-
-struct at91_init_soc __initdata at91cap9_soc = {
-       .map_io = at91cap9_map_io,
-       .default_irq_priority = at91cap9_default_irq_priority,
-       .ioremap_registers = at91cap9_ioremap_registers,
-       .register_clocks = at91cap9_register_clocks,
-       .init = at91cap9_initialize,
-};
diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c
deleted file mode 100644 (file)
index d298fb7..0000000
+++ /dev/null
@@ -1,1273 +0,0 @@
-/*
- * arch/arm/mach-at91/at91cap9_devices.c
- *
- *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
- *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
- *  Copyright (C) 2007 Atmel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/i2c-gpio.h>
-
-#include <video/atmel_lcdc.h>
-
-#include <mach/board.h>
-#include <mach/cpu.h>
-#include <mach/at91cap9.h>
-#include <mach/at91cap9_matrix.h>
-#include <mach/at91sam9_smc.h>
-
-#include "generic.h"
-
-
-/* --------------------------------------------------------------------
- *  USB Host
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
-static struct at91_usbh_data usbh_data;
-
-static struct resource usbh_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_UHP_BASE,
-               .end    = AT91CAP9_UHP_BASE + SZ_1M - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_UHP,
-               .end    = AT91CAP9_ID_UHP,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91_usbh_device = {
-       .name           = "at91_ohci",
-       .id             = -1,
-       .dev            = {
-                               .dma_mask               = &ohci_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &usbh_data,
-       },
-       .resource       = usbh_resources,
-       .num_resources  = ARRAY_SIZE(usbh_resources),
-};
-
-void __init at91_add_device_usbh(struct at91_usbh_data *data)
-{
-       int i;
-
-       if (!data)
-               return;
-
-       if (cpu_is_at91cap9_revB())
-               irq_set_irq_type(AT91CAP9_ID_UHP, IRQ_TYPE_LEVEL_HIGH);
-
-       /* Enable VBus control for UHP ports */
-       for (i = 0; i < data->ports; i++) {
-               if (gpio_is_valid(data->vbus_pin[i]))
-                       at91_set_gpio_output(data->vbus_pin[i], 0);
-       }
-
-       /* Enable overcurrent notification */
-       for (i = 0; i < data->ports; i++) {
-               if (data->overcurrent_pin[i])
-                       at91_set_gpio_input(data->overcurrent_pin[i], 1);
-       }
-
-       usbh_data = *data;
-       platform_device_register(&at91_usbh_device);
-}
-#else
-void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  USB HS Device (Gadget)
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_ATMEL_USBA) || defined(CONFIG_USB_ATMEL_USBA_MODULE)
-
-static struct resource usba_udc_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_UDPHS_FIFO,
-               .end    = AT91CAP9_UDPHS_FIFO + SZ_512K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_BASE_UDPHS,
-               .end    = AT91CAP9_BASE_UDPHS + SZ_1K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [2] = {
-               .start  = AT91CAP9_ID_UDPHS,
-               .end    = AT91CAP9_ID_UDPHS,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-#define EP(nam, idx, maxpkt, maxbk, dma, isoc)                 \
-       [idx] = {                                               \
-               .name           = nam,                          \
-               .index          = idx,                          \
-               .fifo_size      = maxpkt,                       \
-               .nr_banks       = maxbk,                        \
-               .can_dma        = dma,                          \
-               .can_isoc       = isoc,                         \
-       }
-
-static struct usba_ep_data usba_udc_ep[] = {
-       EP("ep0", 0,   64, 1, 0, 0),
-       EP("ep1", 1, 1024, 3, 1, 1),
-       EP("ep2", 2, 1024, 3, 1, 1),
-       EP("ep3", 3, 1024, 2, 1, 1),
-       EP("ep4", 4, 1024, 2, 1, 1),
-       EP("ep5", 5, 1024, 2, 1, 0),
-       EP("ep6", 6, 1024, 2, 1, 0),
-       EP("ep7", 7, 1024, 2, 0, 0),
-};
-
-#undef EP
-
-/*
- * pdata doesn't have room for any endpoints, so we need to
- * append room for the ones we need right after it.
- */
-static struct {
-       struct usba_platform_data pdata;
-       struct usba_ep_data ep[8];
-} usba_udc_data;
-
-static struct platform_device at91_usba_udc_device = {
-       .name           = "atmel_usba_udc",
-       .id             = -1,
-       .dev            = {
-                               .platform_data  = &usba_udc_data.pdata,
-       },
-       .resource       = usba_udc_resources,
-       .num_resources  = ARRAY_SIZE(usba_udc_resources),
-};
-
-void __init at91_add_device_usba(struct usba_platform_data *data)
-{
-       if (cpu_is_at91cap9_revB()) {
-               irq_set_irq_type(AT91CAP9_ID_UDPHS, IRQ_TYPE_LEVEL_HIGH);
-               at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS |
-                                                 AT91_MATRIX_UDPHS_BYPASS_LOCK);
-       }
-       else
-               at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS);
-
-       /*
-        * Invalid pins are 0 on AT91, but the usba driver is shared
-        * with AVR32, which use negative values instead. Once/if
-        * gpio_is_valid() is ported to AT91, revisit this code.
-        */
-       usba_udc_data.pdata.vbus_pin = -EINVAL;
-       usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep);
-       memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));
-
-       if (data && gpio_is_valid(data->vbus_pin)) {
-               at91_set_gpio_input(data->vbus_pin, 0);
-               at91_set_deglitch(data->vbus_pin, 1);
-               usba_udc_data.pdata.vbus_pin = data->vbus_pin;
-       }
-
-       /* Pullup pin is handled internally by USB device peripheral */
-
-       platform_device_register(&at91_usba_udc_device);
-}
-#else
-void __init at91_add_device_usba(struct usba_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  Ethernet
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
-static u64 eth_dmamask = DMA_BIT_MASK(32);
-static struct macb_platform_data eth_data;
-
-static struct resource eth_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_EMAC,
-               .end    = AT91CAP9_BASE_EMAC + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_EMAC,
-               .end    = AT91CAP9_ID_EMAC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_eth_device = {
-       .name           = "macb",
-       .id             = -1,
-       .dev            = {
-                               .dma_mask               = &eth_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &eth_data,
-       },
-       .resource       = eth_resources,
-       .num_resources  = ARRAY_SIZE(eth_resources),
-};
-
-void __init at91_add_device_eth(struct macb_platform_data *data)
-{
-       if (!data)
-               return;
-
-       if (gpio_is_valid(data->phy_irq_pin)) {
-               at91_set_gpio_input(data->phy_irq_pin, 0);
-               at91_set_deglitch(data->phy_irq_pin, 1);
-       }
-
-       /* Pins used for MII and RMII */
-       at91_set_A_periph(AT91_PIN_PB21, 0);    /* ETXCK_EREFCK */
-       at91_set_A_periph(AT91_PIN_PB22, 0);    /* ERXDV */
-       at91_set_A_periph(AT91_PIN_PB25, 0);    /* ERX0 */
-       at91_set_A_periph(AT91_PIN_PB26, 0);    /* ERX1 */
-       at91_set_A_periph(AT91_PIN_PB27, 0);    /* ERXER */
-       at91_set_A_periph(AT91_PIN_PB28, 0);    /* ETXEN */
-       at91_set_A_periph(AT91_PIN_PB23, 0);    /* ETX0 */
-       at91_set_A_periph(AT91_PIN_PB24, 0);    /* ETX1 */
-       at91_set_A_periph(AT91_PIN_PB30, 0);    /* EMDIO */
-       at91_set_A_periph(AT91_PIN_PB29, 0);    /* EMDC */
-
-       if (!data->is_rmii) {
-               at91_set_B_periph(AT91_PIN_PC25, 0);    /* ECRS */
-               at91_set_B_periph(AT91_PIN_PC26, 0);    /* ECOL */
-               at91_set_B_periph(AT91_PIN_PC22, 0);    /* ERX2 */
-               at91_set_B_periph(AT91_PIN_PC23, 0);    /* ERX3 */
-               at91_set_B_periph(AT91_PIN_PC27, 0);    /* ERXCK */
-               at91_set_B_periph(AT91_PIN_PC20, 0);    /* ETX2 */
-               at91_set_B_periph(AT91_PIN_PC21, 0);    /* ETX3 */
-               at91_set_B_periph(AT91_PIN_PC24, 0);    /* ETXER */
-       }
-
-       eth_data = *data;
-       platform_device_register(&at91cap9_eth_device);
-}
-#else
-void __init at91_add_device_eth(struct macb_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  MMC / SD
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc0_data, mmc1_data;
-
-static struct resource mmc0_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_MCI0,
-               .end    = AT91CAP9_BASE_MCI0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_MCI0,
-               .end    = AT91CAP9_ID_MCI0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_mmc0_device = {
-       .name           = "at91_mci",
-       .id             = 0,
-       .dev            = {
-                               .dma_mask               = &mmc_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &mmc0_data,
-       },
-       .resource       = mmc0_resources,
-       .num_resources  = ARRAY_SIZE(mmc0_resources),
-};
-
-static struct resource mmc1_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_MCI1,
-               .end    = AT91CAP9_BASE_MCI1 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_MCI1,
-               .end    = AT91CAP9_ID_MCI1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_mmc1_device = {
-       .name           = "at91_mci",
-       .id             = 1,
-       .dev            = {
-                               .dma_mask               = &mmc_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &mmc1_data,
-       },
-       .resource       = mmc1_resources,
-       .num_resources  = ARRAY_SIZE(mmc1_resources),
-};
-
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
-{
-       if (!data)
-               return;
-
-       /* input/irq */
-       if (gpio_is_valid(data->det_pin)) {
-               at91_set_gpio_input(data->det_pin, 1);
-               at91_set_deglitch(data->det_pin, 1);
-       }
-       if (gpio_is_valid(data->wp_pin))
-               at91_set_gpio_input(data->wp_pin, 1);
-       if (gpio_is_valid(data->vcc_pin))
-               at91_set_gpio_output(data->vcc_pin, 0);
-
-       if (mmc_id == 0) {              /* MCI0 */
-               /* CLK */
-               at91_set_A_periph(AT91_PIN_PA2, 0);
-
-               /* CMD */
-               at91_set_A_periph(AT91_PIN_PA1, 1);
-
-               /* DAT0, maybe DAT1..DAT3 */
-               at91_set_A_periph(AT91_PIN_PA0, 1);
-               if (data->wire4) {
-                       at91_set_A_periph(AT91_PIN_PA3, 1);
-                       at91_set_A_periph(AT91_PIN_PA4, 1);
-                       at91_set_A_periph(AT91_PIN_PA5, 1);
-               }
-
-               mmc0_data = *data;
-               platform_device_register(&at91cap9_mmc0_device);
-       } else {                        /* MCI1 */
-               /* CLK */
-               at91_set_A_periph(AT91_PIN_PA16, 0);
-
-               /* CMD */
-               at91_set_A_periph(AT91_PIN_PA17, 1);
-
-               /* DAT0, maybe DAT1..DAT3 */
-               at91_set_A_periph(AT91_PIN_PA18, 1);
-               if (data->wire4) {
-                       at91_set_A_periph(AT91_PIN_PA19, 1);
-                       at91_set_A_periph(AT91_PIN_PA20, 1);
-                       at91_set_A_periph(AT91_PIN_PA21, 1);
-               }
-
-               mmc1_data = *data;
-               platform_device_register(&at91cap9_mmc1_device);
-       }
-}
-#else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
-static struct atmel_nand_data nand_data;
-
-#define NAND_BASE      AT91_CHIPSELECT_3
-
-static struct resource nand_resources[] = {
-       [0] = {
-               .start  = NAND_BASE,
-               .end    = NAND_BASE + SZ_256M - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_BASE_ECC,
-               .end    = AT91CAP9_BASE_ECC + SZ_512 - 1,
-               .flags  = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device at91cap9_nand_device = {
-       .name           = "atmel_nand",
-       .id             = -1,
-       .dev            = {
-                               .platform_data  = &nand_data,
-       },
-       .resource       = nand_resources,
-       .num_resources  = ARRAY_SIZE(nand_resources),
-};
-
-void __init at91_add_device_nand(struct atmel_nand_data *data)
-{
-       unsigned long csa;
-
-       if (!data)
-               return;
-
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
-
-       /* enable pin */
-       if (gpio_is_valid(data->enable_pin))
-               at91_set_gpio_output(data->enable_pin, 1);
-
-       /* ready/busy pin */
-       if (gpio_is_valid(data->rdy_pin))
-               at91_set_gpio_input(data->rdy_pin, 1);
-
-       /* card detect pin */
-       if (gpio_is_valid(data->det_pin))
-               at91_set_gpio_input(data->det_pin, 1);
-
-       nand_data = *data;
-       platform_device_register(&at91cap9_nand_device);
-}
-#else
-void __init at91_add_device_nand(struct atmel_nand_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  TWI (i2c)
- * -------------------------------------------------------------------- */
-
-/*
- * Prefer the GPIO code since the TWI controller isn't robust
- * (gets overruns and underruns under load) and can only issue
- * repeated STARTs in one scenario (the driver doesn't yet handle them).
- */
-#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-
-static struct i2c_gpio_platform_data pdata = {
-       .sda_pin                = AT91_PIN_PB4,
-       .sda_is_open_drain      = 1,
-       .scl_pin                = AT91_PIN_PB5,
-       .scl_is_open_drain      = 1,
-       .udelay                 = 2,            /* ~100 kHz */
-};
-
-static struct platform_device at91cap9_twi_device = {
-       .name                   = "i2c-gpio",
-       .id                     = -1,
-       .dev.platform_data      = &pdata,
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-       at91_set_GPIO_periph(AT91_PIN_PB4, 1);          /* TWD (SDA) */
-       at91_set_multi_drive(AT91_PIN_PB4, 1);
-
-       at91_set_GPIO_periph(AT91_PIN_PB5, 1);          /* TWCK (SCL) */
-       at91_set_multi_drive(AT91_PIN_PB5, 1);
-
-       i2c_register_board_info(0, devices, nr_devices);
-       platform_device_register(&at91cap9_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_TWI,
-               .end    = AT91CAP9_BASE_TWI + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_TWI,
-               .end    = AT91CAP9_ID_TWI,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_twi_device = {
-       .name           = "at91_i2c",
-       .id             = -1,
-       .resource       = twi_resources,
-       .num_resources  = ARRAY_SIZE(twi_resources),
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-       /* pins used for TWI interface */
-       at91_set_B_periph(AT91_PIN_PB4, 0);             /* TWD */
-       at91_set_multi_drive(AT91_PIN_PB4, 1);
-
-       at91_set_B_periph(AT91_PIN_PB5, 0);             /* TWCK */
-       at91_set_multi_drive(AT91_PIN_PB5, 1);
-
-       i2c_register_board_info(0, devices, nr_devices);
-       platform_device_register(&at91cap9_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-/* --------------------------------------------------------------------
- *  SPI
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-static struct resource spi0_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_SPI0,
-               .end    = AT91CAP9_BASE_SPI0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_SPI0,
-               .end    = AT91CAP9_ID_SPI0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_spi0_device = {
-       .name           = "atmel_spi",
-       .id             = 0,
-       .dev            = {
-                               .dma_mask               = &spi_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = spi0_resources,
-       .num_resources  = ARRAY_SIZE(spi0_resources),
-};
-
-static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA5, AT91_PIN_PA3, AT91_PIN_PD0, AT91_PIN_PD1 };
-
-static struct resource spi1_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_SPI1,
-               .end    = AT91CAP9_BASE_SPI1 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_SPI1,
-               .end    = AT91CAP9_ID_SPI1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_spi1_device = {
-       .name           = "atmel_spi",
-       .id             = 1,
-       .dev            = {
-                               .dma_mask               = &spi_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = spi1_resources,
-       .num_resources  = ARRAY_SIZE(spi1_resources),
-};
-
-static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB15, AT91_PIN_PB16, AT91_PIN_PB17, AT91_PIN_PB18 };
-
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
-{
-       int i;
-       unsigned long cs_pin;
-       short enable_spi0 = 0;
-       short enable_spi1 = 0;
-
-       /* Choose SPI chip-selects */
-       for (i = 0; i < nr_devices; i++) {
-               if (devices[i].controller_data)
-                       cs_pin = (unsigned long) devices[i].controller_data;
-               else if (devices[i].bus_num == 0)
-                       cs_pin = spi0_standard_cs[devices[i].chip_select];
-               else
-                       cs_pin = spi1_standard_cs[devices[i].chip_select];
-
-               if (devices[i].bus_num == 0)
-                       enable_spi0 = 1;
-               else
-                       enable_spi1 = 1;
-
-               /* enable chip-select pin */
-               at91_set_gpio_output(cs_pin, 1);
-
-               /* pass chip-select pin to driver */
-               devices[i].controller_data = (void *) cs_pin;
-       }
-
-       spi_register_board_info(devices, nr_devices);
-
-       /* Configure SPI bus(es) */
-       if (enable_spi0) {
-               at91_set_B_periph(AT91_PIN_PA0, 0);     /* SPI0_MISO */
-               at91_set_B_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
-               at91_set_B_periph(AT91_PIN_PA2, 0);     /* SPI0_SPCK */
-
-               platform_device_register(&at91cap9_spi0_device);
-       }
-       if (enable_spi1) {
-               at91_set_A_periph(AT91_PIN_PB12, 0);    /* SPI1_MISO */
-               at91_set_A_periph(AT91_PIN_PB13, 0);    /* SPI1_MOSI */
-               at91_set_A_periph(AT91_PIN_PB14, 0);    /* SPI1_SPCK */
-
-               platform_device_register(&at91cap9_spi1_device);
-       }
-}
-#else
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  Timer/Counter block
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATMEL_TCLIB
-
-static struct resource tcb_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_TCB0,
-               .end    = AT91CAP9_BASE_TCB0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_TCB,
-               .end    = AT91CAP9_ID_TCB,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_tcb_device = {
-       .name           = "atmel_tcb",
-       .id             = 0,
-       .resource       = tcb_resources,
-       .num_resources  = ARRAY_SIZE(tcb_resources),
-};
-
-static void __init at91_add_device_tc(void)
-{
-       platform_device_register(&at91cap9_tcb_device);
-}
-#else
-static void __init at91_add_device_tc(void) { }
-#endif
-
-
-/* --------------------------------------------------------------------
- *  RTT
- * -------------------------------------------------------------------- */
-
-static struct resource rtt_resources[] = {
-       {
-               .start  = AT91CAP9_BASE_RTT,
-               .end    = AT91CAP9_BASE_RTT + SZ_16 - 1,
-               .flags  = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device at91cap9_rtt_device = {
-       .name           = "at91_rtt",
-       .id             = 0,
-       .resource       = rtt_resources,
-       .num_resources  = ARRAY_SIZE(rtt_resources),
-};
-
-static void __init at91_add_device_rtt(void)
-{
-       platform_device_register(&at91cap9_rtt_device);
-}
-
-
-/* --------------------------------------------------------------------
- *  Watchdog
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
-static struct resource wdt_resources[] = {
-       {
-               .start  = AT91CAP9_BASE_WDT,
-               .end    = AT91CAP9_BASE_WDT + SZ_16 - 1,
-               .flags  = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device at91cap9_wdt_device = {
-       .name           = "at91_wdt",
-       .id             = -1,
-       .resource       = wdt_resources,
-       .num_resources  = ARRAY_SIZE(wdt_resources),
-};
-
-static void __init at91_add_device_watchdog(void)
-{
-       platform_device_register(&at91cap9_wdt_device);
-}
-#else
-static void __init at91_add_device_watchdog(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  PWM
- * --------------------------------------------------------------------*/
-
-#if defined(CONFIG_ATMEL_PWM)
-static u32 pwm_mask;
-
-static struct resource pwm_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_PWMC,
-               .end    = AT91CAP9_BASE_PWMC + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_PWMC,
-               .end    = AT91CAP9_ID_PWMC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_pwm0_device = {
-       .name   = "atmel_pwm",
-       .id     = -1,
-       .dev    = {
-               .platform_data          = &pwm_mask,
-       },
-       .resource       = pwm_resources,
-       .num_resources  = ARRAY_SIZE(pwm_resources),
-};
-
-void __init at91_add_device_pwm(u32 mask)
-{
-       if (mask & (1 << AT91_PWM0))
-               at91_set_A_periph(AT91_PIN_PB19, 1);    /* enable PWM0 */
-
-       if (mask & (1 << AT91_PWM1))
-               at91_set_B_periph(AT91_PIN_PB8, 1);     /* enable PWM1 */
-
-       if (mask & (1 << AT91_PWM2))
-               at91_set_B_periph(AT91_PIN_PC29, 1);    /* enable PWM2 */
-
-       if (mask & (1 << AT91_PWM3))
-               at91_set_B_periph(AT91_PIN_PA11, 1);    /* enable PWM3 */
-
-       pwm_mask = mask;
-
-       platform_device_register(&at91cap9_pwm0_device);
-}
-#else
-void __init at91_add_device_pwm(u32 mask) {}
-#endif
-
-
-
-/* --------------------------------------------------------------------
- *  AC97
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SND_ATMEL_AC97C) || defined(CONFIG_SND_ATMEL_AC97C_MODULE)
-static u64 ac97_dmamask = DMA_BIT_MASK(32);
-static struct ac97c_platform_data ac97_data;
-
-static struct resource ac97_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_AC97C,
-               .end    = AT91CAP9_BASE_AC97C + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_AC97C,
-               .end    = AT91CAP9_ID_AC97C,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_ac97_device = {
-       .name           = "atmel_ac97c",
-       .id             = 1,
-       .dev            = {
-                               .dma_mask               = &ac97_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &ac97_data,
-       },
-       .resource       = ac97_resources,
-       .num_resources  = ARRAY_SIZE(ac97_resources),
-};
-
-void __init at91_add_device_ac97(struct ac97c_platform_data *data)
-{
-       if (!data)
-               return;
-
-       at91_set_A_periph(AT91_PIN_PA6, 0);     /* AC97FS */
-       at91_set_A_periph(AT91_PIN_PA7, 0);     /* AC97CK */
-       at91_set_A_periph(AT91_PIN_PA8, 0);     /* AC97TX */
-       at91_set_A_periph(AT91_PIN_PA9, 0);     /* AC97RX */
-
-       /* reset */
-       if (gpio_is_valid(data->reset_pin))
-               at91_set_gpio_output(data->reset_pin, 0);
-
-       ac97_data = *data;
-       platform_device_register(&at91cap9_ac97_device);
-}
-#else
-void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  LCD Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static u64 lcdc_dmamask = DMA_BIT_MASK(32);
-static struct atmel_lcdfb_info lcdc_data;
-
-static struct resource lcdc_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_LCDC_BASE,
-               .end    = AT91CAP9_LCDC_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_LCDC,
-               .end    = AT91CAP9_ID_LCDC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91_lcdc_device = {
-       .name           = "atmel_lcdfb",
-       .id             = 0,
-       .dev            = {
-                               .dma_mask               = &lcdc_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &lcdc_data,
-       },
-       .resource       = lcdc_resources,
-       .num_resources  = ARRAY_SIZE(lcdc_resources),
-};
-
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
-{
-       if (!data)
-               return;
-
-       if (cpu_is_at91cap9_revB())
-               irq_set_irq_type(AT91CAP9_ID_LCDC, IRQ_TYPE_LEVEL_HIGH);
-
-       at91_set_A_periph(AT91_PIN_PC1, 0);     /* LCDHSYNC */
-       at91_set_A_periph(AT91_PIN_PC2, 0);     /* LCDDOTCK */
-       at91_set_A_periph(AT91_PIN_PC3, 0);     /* LCDDEN */
-       at91_set_B_periph(AT91_PIN_PB9, 0);     /* LCDCC */
-       at91_set_A_periph(AT91_PIN_PC6, 0);     /* LCDD2 */
-       at91_set_A_periph(AT91_PIN_PC7, 0);     /* LCDD3 */
-       at91_set_A_periph(AT91_PIN_PC8, 0);     /* LCDD4 */
-       at91_set_A_periph(AT91_PIN_PC9, 0);     /* LCDD5 */
-       at91_set_A_periph(AT91_PIN_PC10, 0);    /* LCDD6 */
-       at91_set_A_periph(AT91_PIN_PC11, 0);    /* LCDD7 */
-       at91_set_A_periph(AT91_PIN_PC14, 0);    /* LCDD10 */
-       at91_set_A_periph(AT91_PIN_PC15, 0);    /* LCDD11 */
-       at91_set_A_periph(AT91_PIN_PC16, 0);    /* LCDD12 */
-       at91_set_A_periph(AT91_PIN_PC17, 0);    /* LCDD13 */
-       at91_set_A_periph(AT91_PIN_PC18, 0);    /* LCDD14 */
-       at91_set_A_periph(AT91_PIN_PC19, 0);    /* LCDD15 */
-       at91_set_A_periph(AT91_PIN_PC22, 0);    /* LCDD18 */
-       at91_set_A_periph(AT91_PIN_PC23, 0);    /* LCDD19 */
-       at91_set_A_periph(AT91_PIN_PC24, 0);    /* LCDD20 */
-       at91_set_A_periph(AT91_PIN_PC25, 0);    /* LCDD21 */
-       at91_set_A_periph(AT91_PIN_PC26, 0);    /* LCDD22 */
-       at91_set_A_periph(AT91_PIN_PC27, 0);    /* LCDD23 */
-
-       lcdc_data = *data;
-       platform_device_register(&at91_lcdc_device);
-}
-#else
-void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  SSC -- Synchronous Serial Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
-static u64 ssc0_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc0_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_SSC0,
-               .end    = AT91CAP9_BASE_SSC0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_SSC0,
-               .end    = AT91CAP9_ID_SSC0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_ssc0_device = {
-       .name   = "ssc",
-       .id     = 0,
-       .dev    = {
-               .dma_mask               = &ssc0_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = ssc0_resources,
-       .num_resources  = ARRAY_SIZE(ssc0_resources),
-};
-
-static inline void configure_ssc0_pins(unsigned pins)
-{
-       if (pins & ATMEL_SSC_TF)
-               at91_set_A_periph(AT91_PIN_PB0, 1);
-       if (pins & ATMEL_SSC_TK)
-               at91_set_A_periph(AT91_PIN_PB1, 1);
-       if (pins & ATMEL_SSC_TD)
-               at91_set_A_periph(AT91_PIN_PB2, 1);
-       if (pins & ATMEL_SSC_RD)
-               at91_set_A_periph(AT91_PIN_PB3, 1);
-       if (pins & ATMEL_SSC_RK)
-               at91_set_A_periph(AT91_PIN_PB4, 1);
-       if (pins & ATMEL_SSC_RF)
-               at91_set_A_periph(AT91_PIN_PB5, 1);
-}
-
-static u64 ssc1_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc1_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_SSC1,
-               .end    = AT91CAP9_BASE_SSC1 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_SSC1,
-               .end    = AT91CAP9_ID_SSC1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91cap9_ssc1_device = {
-       .name   = "ssc",
-       .id     = 1,
-       .dev    = {
-               .dma_mask               = &ssc1_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = ssc1_resources,
-       .num_resources  = ARRAY_SIZE(ssc1_resources),
-};
-
-static inline void configure_ssc1_pins(unsigned pins)
-{
-       if (pins & ATMEL_SSC_TF)
-               at91_set_A_periph(AT91_PIN_PB6, 1);
-       if (pins & ATMEL_SSC_TK)
-               at91_set_A_periph(AT91_PIN_PB7, 1);
-       if (pins & ATMEL_SSC_TD)
-               at91_set_A_periph(AT91_PIN_PB8, 1);
-       if (pins & ATMEL_SSC_RD)
-               at91_set_A_periph(AT91_PIN_PB9, 1);
-       if (pins & ATMEL_SSC_RK)
-               at91_set_A_periph(AT91_PIN_PB10, 1);
-       if (pins & ATMEL_SSC_RF)
-               at91_set_A_periph(AT91_PIN_PB11, 1);
-}
-
-/*
- * SSC controllers are accessed through library code, instead of any
- * kind of all-singing/all-dancing driver.  For example one could be
- * used by a particular I2S audio codec's driver, while another one
- * on the same system might be used by a custom data capture driver.
- */
-void __init at91_add_device_ssc(unsigned id, unsigned pins)
-{
-       struct platform_device *pdev;
-
-       /*
-        * NOTE: caller is responsible for passing information matching
-        * "pins" to whatever will be using each particular controller.
-        */
-       switch (id) {
-       case AT91CAP9_ID_SSC0:
-               pdev = &at91cap9_ssc0_device;
-               configure_ssc0_pins(pins);
-               break;
-       case AT91CAP9_ID_SSC1:
-               pdev = &at91cap9_ssc1_device;
-               configure_ssc1_pins(pins);
-               break;
-       default:
-               return;
-       }
-
-       platform_device_register(pdev);
-}
-
-#else
-void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  UART
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SERIAL_ATMEL)
-static struct resource dbgu_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_DBGU,
-               .end    = AT91CAP9_BASE_DBGU + SZ_512 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data dbgu_data = {
-       .use_dma_tx     = 0,
-       .use_dma_rx     = 0,            /* DBGU not capable of receive DMA */
-};
-
-static u64 dbgu_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91cap9_dbgu_device = {
-       .name           = "atmel_usart",
-       .id             = 0,
-       .dev            = {
-                               .dma_mask               = &dbgu_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &dbgu_data,
-       },
-       .resource       = dbgu_resources,
-       .num_resources  = ARRAY_SIZE(dbgu_resources),
-};
-
-static inline void configure_dbgu_pins(void)
-{
-       at91_set_A_periph(AT91_PIN_PC30, 0);            /* DRXD */
-       at91_set_A_periph(AT91_PIN_PC31, 1);            /* DTXD */
-}
-
-static struct resource uart0_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_US0,
-               .end    = AT91CAP9_BASE_US0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_US0,
-               .end    = AT91CAP9_ID_US0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data uart0_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-
-static u64 uart0_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91cap9_uart0_device = {
-       .name           = "atmel_usart",
-       .id             = 1,
-       .dev            = {
-                               .dma_mask               = &uart0_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &uart0_data,
-       },
-       .resource       = uart0_resources,
-       .num_resources  = ARRAY_SIZE(uart0_resources),
-};
-
-static inline void configure_usart0_pins(unsigned pins)
-{
-       at91_set_A_periph(AT91_PIN_PA22, 1);            /* TXD0 */
-       at91_set_A_periph(AT91_PIN_PA23, 0);            /* RXD0 */
-
-       if (pins & ATMEL_UART_RTS)
-               at91_set_A_periph(AT91_PIN_PA24, 0);    /* RTS0 */
-       if (pins & ATMEL_UART_CTS)
-               at91_set_A_periph(AT91_PIN_PA25, 0);    /* CTS0 */
-}
-
-static struct resource uart1_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_US1,
-               .end    = AT91CAP9_BASE_US1 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_US1,
-               .end    = AT91CAP9_ID_US1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data uart1_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-
-static u64 uart1_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91cap9_uart1_device = {
-       .name           = "atmel_usart",
-       .id             = 2,
-       .dev            = {
-                               .dma_mask               = &uart1_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &uart1_data,
-       },
-       .resource       = uart1_resources,
-       .num_resources  = ARRAY_SIZE(uart1_resources),
-};
-
-static inline void configure_usart1_pins(unsigned pins)
-{
-       at91_set_A_periph(AT91_PIN_PD0, 1);             /* TXD1 */
-       at91_set_A_periph(AT91_PIN_PD1, 0);             /* RXD1 */
-
-       if (pins & ATMEL_UART_RTS)
-               at91_set_B_periph(AT91_PIN_PD7, 0);     /* RTS1 */
-       if (pins & ATMEL_UART_CTS)
-               at91_set_B_periph(AT91_PIN_PD8, 0);     /* CTS1 */
-}
-
-static struct resource uart2_resources[] = {
-       [0] = {
-               .start  = AT91CAP9_BASE_US2,
-               .end    = AT91CAP9_BASE_US2 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91CAP9_ID_US2,
-               .end    = AT91CAP9_ID_US2,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data uart2_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-
-static u64 uart2_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91cap9_uart2_device = {
-       .name           = "atmel_usart",
-       .id             = 3,
-       .dev            = {
-                               .dma_mask               = &uart2_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &uart2_data,
-       },
-       .resource       = uart2_resources,
-       .num_resources  = ARRAY_SIZE(uart2_resources),
-};
-
-static inline void configure_usart2_pins(unsigned pins)
-{
-       at91_set_A_periph(AT91_PIN_PD2, 1);             /* TXD2 */
-       at91_set_A_periph(AT91_PIN_PD3, 0);             /* RXD2 */
-
-       if (pins & ATMEL_UART_RTS)
-               at91_set_B_periph(AT91_PIN_PD5, 0);     /* RTS2 */
-       if (pins & ATMEL_UART_CTS)
-               at91_set_B_periph(AT91_PIN_PD6, 0);     /* CTS2 */
-}
-
-static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];  /* the UARTs to use */
-struct platform_device *atmel_default_console_device;  /* the serial console device */
-
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
-{
-       struct platform_device *pdev;
-       struct atmel_uart_data *pdata;
-
-       switch (id) {
-               case 0:         /* DBGU */
-                       pdev = &at91cap9_dbgu_device;
-                       configure_dbgu_pins();
-                       break;
-               case AT91CAP9_ID_US0:
-                       pdev = &at91cap9_uart0_device;
-                       configure_usart0_pins(pins);
-                       break;
-               case AT91CAP9_ID_US1:
-                       pdev = &at91cap9_uart1_device;
-                       configure_usart1_pins(pins);
-                       break;
-               case AT91CAP9_ID_US2:
-                       pdev = &at91cap9_uart2_device;
-                       configure_usart2_pins(pins);
-                       break;
-               default:
-                       return;
-       }
-       pdata = pdev->dev.platform_data;
-       pdata->num = portnr;            /* update to mapped ID */
-
-       if (portnr < ATMEL_MAX_UART)
-               at91_uarts[portnr] = pdev;
-}
-
-void __init at91_set_serial_console(unsigned portnr)
-{
-       if (portnr < ATMEL_MAX_UART) {
-               atmel_default_console_device = at91_uarts[portnr];
-               at91cap9_set_console_clock(at91_uarts[portnr]->id);
-       }
-}
-
-void __init at91_add_device_serial(void)
-{
-       int i;
-
-       for (i = 0; i < ATMEL_MAX_UART; i++) {
-               if (at91_uarts[i])
-                       platform_device_register(at91_uarts[i]);
-       }
-
-       if (!atmel_default_console_device)
-               printk(KERN_INFO "AT91: No default serial console defined.\n");
-}
-#else
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
-void __init at91_add_device_serial(void) {}
-#endif
-
-
-/* -------------------------------------------------------------------- */
-/*
- * These devices are always present and don't need any board-specific
- * setup.
- */
-static int __init at91_add_standard_devices(void)
-{
-       at91_add_device_rtt();
-       at91_add_device_watchdog();
-       at91_add_device_tc();
-       return 0;
-}
-
-arch_initcall(at91_add_standard_devices);
index 413c027..364c193 100644 (file)
@@ -290,13 +290,22 @@ static struct at91_gpio_bank at91rm9200_gpio[] __initdata = {
        }
 };
 
+static void at91rm9200_idle(void)
+{
+       /*
+        * Disable the processor clock.  The processor will be automatically
+        * re-enabled by an interrupt or by a reset.
+        */
+       at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
+}
+
 static void at91rm9200_restart(char mode, const char *cmd)
 {
        /*
         * Perform a hardware reset with the use of the Watchdog timer.
         */
-       at91_sys_write(AT91_ST_WDMR, AT91_ST_RSTEN | AT91_ST_EXTEN | 1);
-       at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+       at91_st_write(AT91_ST_WDMR, AT91_ST_RSTEN | AT91_ST_EXTEN | 1);
+       at91_st_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
 /* --------------------------------------------------------------------
@@ -311,10 +320,13 @@ static void __init at91rm9200_map_io(void)
 
 static void __init at91rm9200_ioremap_registers(void)
 {
+       at91rm9200_ioremap_st(AT91RM9200_BASE_ST);
+       at91_ioremap_ramc(0, AT91RM9200_BASE_MC, 256);
 }
 
 static void __init at91rm9200_initialize(void)
 {
+       arm_pm_idle = at91rm9200_idle;
        arm_pm_restart = at91rm9200_restart;
        at91_extern_irq = (1 << AT91RM9200_ID_IRQ0) | (1 << AT91RM9200_ID_IRQ1)
                        | (1 << AT91RM9200_ID_IRQ2) | (1 << AT91RM9200_ID_IRQ3)
index 97676bd..99ce5c9 100644 (file)
@@ -21,6 +21,7 @@
 #include <mach/board.h>
 #include <mach/at91rm9200.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 #include "generic.h"
 
@@ -241,15 +242,15 @@ void __init at91_add_device_cf(struct at91_cf_data *data)
        data->chipselect = 4;           /* can only use EBI ChipSelect 4 */
 
        /* CF takes over CS4, CS5, CS6 */
-       csa = at91_sys_read(AT91_EBI_CSA);
-       at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH);
+       csa = at91_ramc_read(0, AT91_EBI_CSA);
+       at91_ramc_write(0, AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH);
 
        /*
         * Static memory controller timing adjustments.
         * REVISIT:  these timings are in terms of MCK cycles, so
         * when MCK changes (cpufreq etc) so must these values...
         */
-       at91_sys_write(AT91_SMC_CSR(4),
+       at91_ramc_write(0, AT91_SMC_CSR(4),
                                  AT91_SMC_ACSS_STD
                                | AT91_SMC_DBW_16
                                | AT91_SMC_BAT
@@ -407,11 +408,11 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
                return;
 
        /* enable the address range of CS3 */
-       csa = at91_sys_read(AT91_EBI_CSA);
-       at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS3A_SMC_SMARTMEDIA);
+       csa = at91_ramc_read(0, AT91_EBI_CSA);
+       at91_ramc_write(0, AT91_EBI_CSA, csa | AT91_EBI_CS3A_SMC_SMARTMEDIA);
 
        /* set the bus interface characteristics */
-       at91_sys_write(AT91_SMC_CSR(3), AT91_SMC_ACSS_STD | AT91_SMC_DBW_8 | AT91_SMC_WSEN
+       at91_ramc_write(0, AT91_SMC_CSR(3), AT91_SMC_ACSS_STD | AT91_SMC_DBW_8 | AT91_SMC_WSEN
                | AT91_SMC_NWS_(5)
                | AT91_SMC_TDF_(1)
                | AT91_SMC_RWSETUP_(0)  /* tDS Data Set up Time 30 - ns */
@@ -1114,7 +1115,6 @@ static inline void configure_usart3_pins(unsigned pins)
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];  /* the UARTs to use */
-struct platform_device *atmel_default_console_device;  /* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
index a028cdf..dd7f782 100644 (file)
@@ -43,9 +43,9 @@ static inline unsigned long read_CRTR(void)
 {
        unsigned long x1, x2;
 
-       x1 = at91_sys_read(AT91_ST_CRTR);
+       x1 = at91_st_read(AT91_ST_CRTR);
        do {
-               x2 = at91_sys_read(AT91_ST_CRTR);
+               x2 = at91_st_read(AT91_ST_CRTR);
                if (x1 == x2)
                        break;
                x1 = x2;
@@ -58,7 +58,7 @@ static inline unsigned long read_CRTR(void)
  */
 static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
 {
-       u32     sr = at91_sys_read(AT91_ST_SR) & irqmask;
+       u32     sr = at91_st_read(AT91_ST_SR) & irqmask;
 
        /*
         * irqs should be disabled here, but as the irq is shared they are only
@@ -110,22 +110,22 @@ static void
 clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev)
 {
        /* Disable and flush pending timer interrupts */
-       at91_sys_write(AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS);
-       (void) at91_sys_read(AT91_ST_SR);
+       at91_st_write(AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS);
+       at91_st_read(AT91_ST_SR);
 
        last_crtr = read_CRTR();
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
                /* PIT for periodic irqs; fixed rate of 1/HZ */
                irqmask = AT91_ST_PITS;
-               at91_sys_write(AT91_ST_PIMR, RM9200_TIMER_LATCH);
+               at91_st_write(AT91_ST_PIMR, RM9200_TIMER_LATCH);
                break;
        case CLOCK_EVT_MODE_ONESHOT:
                /* ALM for oneshot irqs, set by next_event()
                 * before 32 seconds have passed
                 */
                irqmask = AT91_ST_ALMS;
-               at91_sys_write(AT91_ST_RTAR, last_crtr);
+               at91_st_write(AT91_ST_RTAR, last_crtr);
                break;
        case CLOCK_EVT_MODE_SHUTDOWN:
        case CLOCK_EVT_MODE_UNUSED:
@@ -133,7 +133,7 @@ clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev)
                irqmask = 0;
                break;
        }
-       at91_sys_write(AT91_ST_IER, irqmask);
+       at91_st_write(AT91_ST_IER, irqmask);
 }
 
 static int
@@ -156,12 +156,12 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev)
        alm = read_CRTR();
 
        /* Cancel any pending alarm; flush any pending IRQ */
-       at91_sys_write(AT91_ST_RTAR, alm);
-       (void) at91_sys_read(AT91_ST_SR);
+       at91_st_write(AT91_ST_RTAR, alm);
+       at91_st_read(AT91_ST_SR);
 
        /* Schedule alarm by writing RTAR. */
        alm += delta;
-       at91_sys_write(AT91_ST_RTAR, alm);
+       at91_st_write(AT91_ST_RTAR, alm);
 
        return status;
 }
@@ -175,15 +175,24 @@ static struct clock_event_device clkevt = {
        .set_mode       = clkevt32k_mode,
 };
 
+void __iomem *at91_st_base;
+
+void __init at91rm9200_ioremap_st(u32 addr)
+{
+       at91_st_base = ioremap(addr, 256);
+       if (!at91_st_base)
+               panic("Impossible to ioremap ST\n");
+}
+
 /*
  * ST (system timer) module supports both clockevents and clocksource.
  */
 void __init at91rm9200_timer_init(void)
 {
        /* Disable all timer interrupts, and clear any pending ones */
-       at91_sys_write(AT91_ST_IDR,
+       at91_st_write(AT91_ST_IDR,
                AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
-       (void) at91_sys_read(AT91_ST_SR);
+       at91_st_read(AT91_ST_SR);
 
        /* Make IRQs happen for the system timer */
        setup_irq(AT91_ID_SYS, &at91rm9200_timer_irq);
@@ -192,7 +201,7 @@ void __init at91rm9200_timer_init(void)
         * directly for the clocksource and all clockevents, after adjusting
         * its prescaler from the 1 Hz default.
         */
-       at91_sys_write(AT91_ST_RTMR, 1);
+       at91_st_write(AT91_ST_RTMR, 1);
 
        /* Setup timer clockevent, with minimum of two ticks (important!!) */
        clkevt.mult = div_sc(AT91_SLOW_CLOCK, NSEC_PER_SEC, clkevt.shift);
index 79f5718..46f7742 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/module.h>
 
+#include <asm/proc-fns.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -209,6 +210,14 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
        CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
        CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
+       /* more tc lookup table for DT entries */
+       CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "fffdc000.timer", &tc3_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
+       CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &ohci_clk),
        /* fake hclk clock */
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
        CLKDEV_CON_ID("pioA", &pioA_clk),
@@ -310,27 +319,27 @@ static void __init at91sam9xe_map_io(void)
 
 static void __init at91sam9260_map_io(void)
 {
-       if (cpu_is_at91sam9xe()) {
+       if (cpu_is_at91sam9xe())
                at91sam9xe_map_io();
-       } else if (cpu_is_at91sam9g20()) {
-               at91_init_sram(0, AT91SAM9G20_SRAM0_BASE, AT91SAM9G20_SRAM0_SIZE);
-               at91_init_sram(1, AT91SAM9G20_SRAM1_BASE, AT91SAM9G20_SRAM1_SIZE);
-       } else {
-               at91_init_sram(0, AT91SAM9260_SRAM0_BASE, AT91SAM9260_SRAM0_SIZE);
-               at91_init_sram(1, AT91SAM9260_SRAM1_BASE, AT91SAM9260_SRAM1_SIZE);
-       }
+       else if (cpu_is_at91sam9g20())
+               at91_init_sram(0, AT91SAM9G20_SRAM_BASE, AT91SAM9G20_SRAM_SIZE);
+       else
+               at91_init_sram(0, AT91SAM9260_SRAM_BASE, AT91SAM9260_SRAM_SIZE);
 }
 
 static void __init at91sam9260_ioremap_registers(void)
 {
        at91_ioremap_shdwc(AT91SAM9260_BASE_SHDWC);
        at91_ioremap_rstc(AT91SAM9260_BASE_RSTC);
+       at91_ioremap_ramc(0, AT91SAM9260_BASE_SDRAMC, 512);
        at91sam926x_ioremap_pit(AT91SAM9260_BASE_PIT);
        at91sam9_ioremap_smc(0, AT91SAM9260_BASE_SMC);
+       at91_ioremap_matrix(AT91SAM9260_BASE_MATRIX);
 }
 
 static void __init at91sam9260_initialize(void)
 {
+       arm_pm_idle = at91sam9_idle;
        arm_pm_restart = at91sam9_alt_restart;
        at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
                        | (1 << AT91SAM9260_ID_IRQ2);
index 5a24f0b..7e5651e 100644 (file)
@@ -21,6 +21,7 @@
 #include <mach/cpu.h>
 #include <mach/at91sam9260.h>
 #include <mach/at91sam9260_matrix.h>
+#include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
 
 #include "generic.h"
@@ -422,8 +423,8 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
        if (!data)
                return;
 
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
+       csa = at91_matrix_read(AT91_MATRIX_EBICSA);
+       at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
        /* enable pin */
        if (gpio_is_valid(data->enable_pin))
@@ -641,7 +642,7 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
 static struct resource tcb0_resources[] = {
        [0] = {
                .start  = AT91SAM9260_BASE_TCB0,
-               .end    = AT91SAM9260_BASE_TCB0 + SZ_16K - 1,
+               .end    = AT91SAM9260_BASE_TCB0 + SZ_256 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -671,7 +672,7 @@ static struct platform_device at91sam9260_tcb0_device = {
 static struct resource tcb1_resources[] = {
        [0] = {
                .start  = AT91SAM9260_BASE_TCB1,
-               .end    = AT91SAM9260_BASE_TCB1 + SZ_16K - 1,
+               .end    = AT91SAM9260_BASE_TCB1 + SZ_256 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -698,8 +699,25 @@ static struct platform_device at91sam9260_tcb1_device = {
        .num_resources  = ARRAY_SIZE(tcb1_resources),
 };
 
+#if defined(CONFIG_OF)
+static struct of_device_id tcb_ids[] = {
+       { .compatible = "atmel,at91rm9200-tcb" },
+       { /*sentinel*/ }
+};
+#endif
+
 static void __init at91_add_device_tc(void)
 {
+#if defined(CONFIG_OF)
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, tcb_ids);
+       if (np) {
+               of_node_put(np);
+               return;
+       }
+#endif
+
        platform_device_register(&at91sam9260_tcb0_device);
        platform_device_register(&at91sam9260_tcb1_device);
 }
@@ -717,18 +735,42 @@ static struct resource rtt_resources[] = {
                .start  = AT91SAM9260_BASE_RTT,
                .end    = AT91SAM9260_BASE_RTT + SZ_16 - 1,
                .flags  = IORESOURCE_MEM,
-       }
+       }, {
+               .flags  = IORESOURCE_MEM,
+       },
 };
 
 static struct platform_device at91sam9260_rtt_device = {
        .name           = "at91_rtt",
        .id             = 0,
        .resource       = rtt_resources,
-       .num_resources  = ARRAY_SIZE(rtt_resources),
 };
 
+
+#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
+static void __init at91_add_device_rtt_rtc(void)
+{
+       at91sam9260_rtt_device.name = "rtc-at91sam9";
+       /*
+        * The second resource is needed:
+        * GPBR will serve as the storage for RTC time offset
+        */
+       at91sam9260_rtt_device.num_resources = 2;
+       rtt_resources[1].start = AT91SAM9260_BASE_GPBR +
+                                4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
+       rtt_resources[1].end = rtt_resources[1].start + 3;
+}
+#else
+static void __init at91_add_device_rtt_rtc(void)
+{
+       /* Only one resource is needed: RTT not used as RTC */
+       at91sam9260_rtt_device.num_resources = 1;
+}
+#endif
+
 static void __init at91_add_device_rtt(void)
 {
+       at91_add_device_rtt_rtc();
        platform_device_register(&at91sam9260_rtt_device);
 }
 
@@ -1139,7 +1181,6 @@ static inline void configure_usart5_pins(void)
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];  /* the UARTs to use */
-struct platform_device *atmel_default_console_device;  /* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
@@ -1264,7 +1305,7 @@ void __init at91_add_device_cf(struct at91_cf_data *data)
        if (!data)
                return;
 
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
+       csa = at91_matrix_read(AT91_MATRIX_EBICSA);
 
        switch (data->chipselect) {
        case 4:
@@ -1287,7 +1328,7 @@ void __init at91_add_device_cf(struct at91_cf_data *data)
                return;
        }
 
-       at91_sys_write(AT91_MATRIX_EBICSA, csa);
+       at91_matrix_write(AT91_MATRIX_EBICSA, csa);
 
        if (gpio_is_valid(data->rst_pin)) {
                at91_set_multi_drive(data->rst_pin, 0);
index 62818b9..7de81e6 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/module.h>
 
+#include <asm/proc-fns.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -283,12 +284,15 @@ static void __init at91sam9261_ioremap_registers(void)
 {
        at91_ioremap_shdwc(AT91SAM9261_BASE_SHDWC);
        at91_ioremap_rstc(AT91SAM9261_BASE_RSTC);
+       at91_ioremap_ramc(0, AT91SAM9261_BASE_SDRAMC, 512);
        at91sam926x_ioremap_pit(AT91SAM9261_BASE_PIT);
        at91sam9_ioremap_smc(0, AT91SAM9261_BASE_SMC);
+       at91_ioremap_matrix(AT91SAM9261_BASE_MATRIX);
 }
 
 static void __init at91sam9261_initialize(void)
 {
+       arm_pm_idle = at91sam9_idle;
        arm_pm_restart = at91sam9_alt_restart;
        at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
                        | (1 << AT91SAM9261_ID_IRQ2);
index 1e28bed..096da87 100644 (file)
@@ -24,6 +24,7 @@
 #include <mach/board.h>
 #include <mach/at91sam9261.h>
 #include <mach/at91sam9261_matrix.h>
+#include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
 
 #include "generic.h"
@@ -236,8 +237,8 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
        if (!data)
                return;
 
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
+       csa = at91_matrix_read(AT91_MATRIX_EBICSA);
+       at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
        /* enable pin */
        if (gpio_is_valid(data->enable_pin))
@@ -603,6 +604,8 @@ static struct resource rtt_resources[] = {
                .start  = AT91SAM9261_BASE_RTT,
                .end    = AT91SAM9261_BASE_RTT + SZ_16 - 1,
                .flags  = IORESOURCE_MEM,
+       }, {
+               .flags  = IORESOURCE_MEM,
        }
 };
 
@@ -610,11 +613,32 @@ static struct platform_device at91sam9261_rtt_device = {
        .name           = "at91_rtt",
        .id             = 0,
        .resource       = rtt_resources,
-       .num_resources  = ARRAY_SIZE(rtt_resources),
 };
 
+#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
+static void __init at91_add_device_rtt_rtc(void)
+{
+       at91sam9261_rtt_device.name = "rtc-at91sam9";
+       /*
+        * The second resource is needed:
+        * GPBR will serve as the storage for RTC time offset
+        */
+       at91sam9261_rtt_device.num_resources = 2;
+       rtt_resources[1].start = AT91SAM9261_BASE_GPBR +
+                                4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
+       rtt_resources[1].end = rtt_resources[1].start + 3;
+}
+#else
+static void __init at91_add_device_rtt_rtc(void)
+{
+       /* Only one resource is needed: RTT not used as RTC */
+       at91sam9261_rtt_device.num_resources = 1;
+}
+#endif
+
 static void __init at91_add_device_rtt(void)
 {
+       at91_add_device_rtt_rtc();
        platform_device_register(&at91sam9261_rtt_device);
 }
 
@@ -991,7 +1015,6 @@ static inline void configure_usart2_pins(unsigned pins)
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];  /* the UARTs to use */
-struct platform_device *atmel_default_console_device;  /* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
index 722ee08..ef301be 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/module.h>
 
+#include <asm/proc-fns.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -303,13 +304,17 @@ static void __init at91sam9263_ioremap_registers(void)
 {
        at91_ioremap_shdwc(AT91SAM9263_BASE_SHDWC);
        at91_ioremap_rstc(AT91SAM9263_BASE_RSTC);
+       at91_ioremap_ramc(0, AT91SAM9263_BASE_SDRAMC0, 512);
+       at91_ioremap_ramc(1, AT91SAM9263_BASE_SDRAMC1, 512);
        at91sam926x_ioremap_pit(AT91SAM9263_BASE_PIT);
        at91sam9_ioremap_smc(0, AT91SAM9263_BASE_SMC0);
        at91sam9_ioremap_smc(1, AT91SAM9263_BASE_SMC1);
+       at91_ioremap_matrix(AT91SAM9263_BASE_MATRIX);
 }
 
 static void __init at91sam9263_initialize(void)
 {
+       arm_pm_idle = at91sam9_idle;
        arm_pm_restart = at91sam9_alt_restart;
        at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
 
index 366a776..53688c4 100644 (file)
@@ -23,6 +23,7 @@
 #include <mach/board.h>
 #include <mach/at91sam9263.h>
 #include <mach/at91sam9263_matrix.h>
+#include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
 
 #include "generic.h"
@@ -409,7 +410,7 @@ void __init at91_add_device_cf(struct at91_cf_data *data)
         * we assume SMC timings are configured by board code,
         * except True IDE where timings are controlled by driver
         */
-       ebi0_csa = at91_sys_read(AT91_MATRIX_EBI0CSA);
+       ebi0_csa = at91_matrix_read(AT91_MATRIX_EBI0CSA);
        switch (data->chipselect) {
        case 4:
                at91_set_A_periph(AT91_PIN_PD6, 0);  /* EBI0_NCS4/CFCS0 */
@@ -428,7 +429,7 @@ void __init at91_add_device_cf(struct at91_cf_data *data)
                       data->chipselect);
                return;
        }
-       at91_sys_write(AT91_MATRIX_EBI0CSA, ebi0_csa);
+       at91_matrix_write(AT91_MATRIX_EBI0CSA, ebi0_csa);
 
        if (gpio_is_valid(data->det_pin)) {
                at91_set_gpio_input(data->det_pin, 1);
@@ -496,8 +497,8 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
        if (!data)
                return;
 
-       csa = at91_sys_read(AT91_MATRIX_EBI0CSA);
-       at91_sys_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA);
+       csa = at91_matrix_read(AT91_MATRIX_EBI0CSA);
+       at91_matrix_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA);
 
        /* enable pin */
        if (gpio_is_valid(data->enable_pin))
@@ -891,7 +892,8 @@ static struct platform_device at91sam9263_isi_device = {
        .num_resources  = ARRAY_SIZE(isi_resources),
 };
 
-void __init at91_add_device_isi(void)
+void __init at91_add_device_isi(struct isi_platform_data *data,
+               bool use_pck_as_mck)
 {
        at91_set_A_periph(AT91_PIN_PE0, 0);     /* ISI_D0 */
        at91_set_A_periph(AT91_PIN_PE1, 0);     /* ISI_D1 */
@@ -904,14 +906,20 @@ void __init at91_add_device_isi(void)
        at91_set_A_periph(AT91_PIN_PE8, 0);     /* ISI_PCK */
        at91_set_A_periph(AT91_PIN_PE9, 0);     /* ISI_HSYNC */
        at91_set_A_periph(AT91_PIN_PE10, 0);    /* ISI_VSYNC */
-       at91_set_B_periph(AT91_PIN_PE11, 0);    /* ISI_MCK (PCK3) */
        at91_set_B_periph(AT91_PIN_PE12, 0);    /* ISI_PD8 */
        at91_set_B_periph(AT91_PIN_PE13, 0);    /* ISI_PD9 */
        at91_set_B_periph(AT91_PIN_PE14, 0);    /* ISI_PD10 */
        at91_set_B_periph(AT91_PIN_PE15, 0);    /* ISI_PD11 */
+
+       if (use_pck_as_mck) {
+               at91_set_B_periph(AT91_PIN_PE11, 0);    /* ISI_MCK (PCK3) */
+
+               /* TODO: register the PCK for ISI_MCK and set its parent */
+       }
 }
 #else
-void __init at91_add_device_isi(void) {}
+void __init at91_add_device_isi(struct isi_platform_data *data,
+               bool use_pck_as_mck) {}
 #endif
 
 
@@ -959,6 +967,8 @@ static struct resource rtt0_resources[] = {
                .start  = AT91SAM9263_BASE_RTT0,
                .end    = AT91SAM9263_BASE_RTT0 + SZ_16 - 1,
                .flags  = IORESOURCE_MEM,
+       }, {
+               .flags  = IORESOURCE_MEM,
        }
 };
 
@@ -966,7 +976,6 @@ static struct platform_device at91sam9263_rtt0_device = {
        .name           = "at91_rtt",
        .id             = 0,
        .resource       = rtt0_resources,
-       .num_resources  = ARRAY_SIZE(rtt0_resources),
 };
 
 static struct resource rtt1_resources[] = {
@@ -974,6 +983,8 @@ static struct resource rtt1_resources[] = {
                .start  = AT91SAM9263_BASE_RTT1,
                .end    = AT91SAM9263_BASE_RTT1 + SZ_16 - 1,
                .flags  = IORESOURCE_MEM,
+       }, {
+               .flags  = IORESOURCE_MEM,
        }
 };
 
@@ -981,11 +992,53 @@ static struct platform_device at91sam9263_rtt1_device = {
        .name           = "at91_rtt",
        .id             = 1,
        .resource       = rtt1_resources,
-       .num_resources  = ARRAY_SIZE(rtt1_resources),
 };
 
+#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
+static void __init at91_add_device_rtt_rtc(void)
+{
+       struct platform_device *pdev;
+       struct resource *r;
+
+       switch (CONFIG_RTC_DRV_AT91SAM9_RTT) {
+       case 0:
+               /*
+                * The second resource is needed only for the chosen RTT:
+                * GPBR will serve as the storage for RTC time offset
+                */
+               at91sam9263_rtt0_device.num_resources = 2;
+               at91sam9263_rtt1_device.num_resources = 1;
+               pdev = &at91sam9263_rtt0_device;
+               r = rtt0_resources;
+               break;
+       case 1:
+               at91sam9263_rtt0_device.num_resources = 1;
+               at91sam9263_rtt1_device.num_resources = 2;
+               pdev = &at91sam9263_rtt1_device;
+               r = rtt1_resources;
+               break;
+       default:
+               pr_err("at91sam9263: only supports 2 RTT (%d)\n",
+                      CONFIG_RTC_DRV_AT91SAM9_RTT);
+               return;
+       }
+
+       pdev->name = "rtc-at91sam9";
+       r[1].start = AT91SAM9263_BASE_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
+       r[1].end = r[1].start + 3;
+}
+#else
+static void __init at91_add_device_rtt_rtc(void)
+{
+       /* Only one resource is needed: RTT not used as RTC */
+       at91sam9263_rtt0_device.num_resources = 1;
+       at91sam9263_rtt1_device.num_resources = 1;
+}
+#endif
+
 static void __init at91_add_device_rtt(void)
 {
+       at91_add_device_rtt_rtc();
        platform_device_register(&at91sam9263_rtt0_device);
        platform_device_register(&at91sam9263_rtt1_device);
 }
@@ -1371,7 +1424,6 @@ static inline void configure_usart2_pins(unsigned pins)
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];  /* the UARTs to use */
-struct platform_device *atmel_default_console_device;  /* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
index d89ead7..a94758b 100644 (file)
@@ -14,6 +14,9 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include <asm/mach/time.h>
 
@@ -133,7 +136,8 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
 static struct irqaction at91sam926x_pit_irq = {
        .name           = "at91_tick",
        .flags          = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = at91sam926x_pit_interrupt
+       .handler        = at91sam926x_pit_interrupt,
+       .irq            = AT91_ID_SYS,
 };
 
 static void at91sam926x_pit_reset(void)
@@ -149,6 +153,51 @@ static void at91sam926x_pit_reset(void)
        pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id pit_timer_ids[] = {
+       { .compatible = "atmel,at91sam9260-pit" },
+       { /* sentinel */ }
+};
+
+static int __init of_at91sam926x_pit_init(void)
+{
+       struct device_node      *np;
+       int                     ret;
+
+       np = of_find_matching_node(NULL, pit_timer_ids);
+       if (!np)
+               goto err;
+
+       pit_base_addr = of_iomap(np, 0);
+       if (!pit_base_addr)
+               goto node_err;
+
+       /* Get the interrupts property */
+       ret = irq_of_parse_and_map(np, 0);
+       if (!ret) {
+               pr_crit("AT91: PIT: Unable to get IRQ from DT\n");
+               goto ioremap_err;
+       }
+       at91sam926x_pit_irq.irq = ret;
+
+       of_node_put(np);
+
+       return 0;
+
+ioremap_err:
+       iounmap(pit_base_addr);
+node_err:
+       of_node_put(np);
+err:
+       return -EINVAL;
+}
+#else
+static int __init of_at91sam926x_pit_init(void)
+{
+       return -EINVAL;
+}
+#endif
+
 /*
  * Set up both clocksource and clockevent support.
  */
@@ -156,6 +205,10 @@ static void __init at91sam926x_pit_init(void)
 {
        unsigned long   pit_rate;
        unsigned        bits;
+       int             ret;
+
+       /* For device tree enabled device: initialize here */
+       of_at91sam926x_pit_init();
 
        /*
         * Use our actual MCK to figure out how many MCK/16 ticks per
@@ -177,7 +230,9 @@ static void __init at91sam926x_pit_init(void)
        clocksource_register_hz(&pit_clk, pit_rate);
 
        /* Set up irq handler */
-       setup_irq(AT91_ID_SYS, &at91sam926x_pit_irq);
+       ret = setup_irq(at91sam926x_pit_irq.irq, &at91sam926x_pit_irq);
+       if (ret)
+               pr_crit("AT91: PIT: Unable to setup IRQ\n");
 
        /* Set up and register clockevents */
        pit_clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, pit_clkevt.shift);
@@ -193,6 +248,15 @@ static void at91sam926x_pit_suspend(void)
 
 void __init at91sam926x_ioremap_pit(u32 addr)
 {
+#if defined(CONFIG_OF)
+       struct device_node *np =
+               of_find_matching_node(NULL, pit_timer_ids);
+
+       if (np) {
+               of_node_put(np);
+               return;
+       }
+#endif
        pit_base_addr = ioremap(addr, 16);
 
        if (!pit_base_addr)
index 518e423..7af2e10 100644 (file)
 
 #include <linux/linkage.h>
 #include <mach/hardware.h>
-#include <mach/at91sam9_sdramc.h>
+#include <mach/at91_ramc.h>
 #include <mach/at91_rstc.h>
 
                        .arm
 
                        .globl  at91sam9_alt_restart
 
-at91sam9_alt_restart:  ldr     r0, .at91_va_base_sdramc        @ preload constants
-                       ldr     r1, =at91_rstc_base
-                       ldr     r1, [r1]
+at91sam9_alt_restart:  ldr     r0, =at91_ramc_base             @ preload constants
+                       ldr     r0, [r0]
+                       ldr     r4, =at91_rstc_base
+                       ldr     r1, [r4]
 
                        mov     r2, #1
                        mov     r3, #AT91_SDRAMC_LPCB_POWER_DOWN
@@ -37,6 +38,3 @@ at91sam9_alt_restart: ldr     r0, .at91_va_base_sdramc        @ preload constants
                        str     r4, [r1, #AT91_RSTC_CR]         @ reset processor
 
                        b       .
-
-.at91_va_base_sdramc:
-       .word AT91_VA_BASE_SYS + AT91_SDRAMC0
index 47e8fdb..d222f83 100644 (file)
@@ -230,6 +230,11 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk),
        CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
        CLKDEV_CON_DEV_ID("usart", "fff98000.serial", &usart3_clk),
+       /* more tc lookup table for DT entries */
+       CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb0_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
+       CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
+       CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
        /* fake hclk clock */
        CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
        CLKDEV_CON_ID("pioA", &pioA_clk),
@@ -332,12 +337,16 @@ static void __init at91sam9g45_ioremap_registers(void)
 {
        at91_ioremap_shdwc(AT91SAM9G45_BASE_SHDWC);
        at91_ioremap_rstc(AT91SAM9G45_BASE_RSTC);
+       at91_ioremap_ramc(0, AT91SAM9G45_BASE_DDRSDRC1, 512);
+       at91_ioremap_ramc(1, AT91SAM9G45_BASE_DDRSDRC0, 512);
        at91sam926x_ioremap_pit(AT91SAM9G45_BASE_PIT);
        at91sam9_ioremap_smc(0, AT91SAM9G45_BASE_SMC);
+       at91_ioremap_matrix(AT91SAM9G45_BASE_MATRIX);
 }
 
 static void __init at91sam9g45_initialize(void)
 {
+       arm_pm_idle = at91sam9_idle;
        arm_pm_restart = at91sam9g45_restart;
        at91_extern_irq = (1 << AT91SAM9G45_ID_IRQ0);
 
index 96e2adc..4320b20 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
+#include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 #include <linux/atmel-mci.h>
 #include <mach/board.h>
 #include <mach/at91sam9g45.h>
 #include <mach/at91sam9g45_matrix.h>
+#include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at_hdmac.h>
 #include <mach/atmel-mci.h>
 
+#include <media/atmel-isi.h>
+
 #include "generic.h"
+#include "clock.h"
 
 
 /* --------------------------------------------------------------------
@@ -553,8 +558,8 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
        if (!data)
                return;
 
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
+       csa = at91_matrix_read(AT91_MATRIX_EBICSA);
+       at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
 
        /* enable pin */
        if (gpio_is_valid(data->enable_pin))
@@ -870,6 +875,96 @@ void __init at91_add_device_ac97(struct ac97c_platform_data *data)
 void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
 #endif
 
+/* --------------------------------------------------------------------
+ *  Image Sensor Interface
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
+static u64 isi_dmamask = DMA_BIT_MASK(32);
+static struct isi_platform_data isi_data;
+
+struct resource isi_resources[] = {
+       [0] = {
+               .start  = AT91SAM9G45_BASE_ISI,
+               .end    = AT91SAM9G45_BASE_ISI + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9G45_ID_ISI,
+               .end    = AT91SAM9G45_ID_ISI,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at91sam9g45_isi_device = {
+       .name           = "atmel_isi",
+       .id             = 0,
+       .dev            = {
+                       .dma_mask               = &isi_dmamask,
+                       .coherent_dma_mask      = DMA_BIT_MASK(32),
+                       .platform_data          = &isi_data,
+       },
+       .resource       = isi_resources,
+       .num_resources  = ARRAY_SIZE(isi_resources),
+};
+
+static struct clk_lookup isi_mck_lookups[] = {
+       CLKDEV_CON_DEV_ID("isi_mck", "atmel_isi.0", NULL),
+};
+
+void __init at91_add_device_isi(struct isi_platform_data *data,
+               bool use_pck_as_mck)
+{
+       struct clk *pck;
+       struct clk *parent;
+
+       if (!data)
+               return;
+       isi_data = *data;
+
+       at91_set_A_periph(AT91_PIN_PB20, 0);    /* ISI_D0 */
+       at91_set_A_periph(AT91_PIN_PB21, 0);    /* ISI_D1 */
+       at91_set_A_periph(AT91_PIN_PB22, 0);    /* ISI_D2 */
+       at91_set_A_periph(AT91_PIN_PB23, 0);    /* ISI_D3 */
+       at91_set_A_periph(AT91_PIN_PB24, 0);    /* ISI_D4 */
+       at91_set_A_periph(AT91_PIN_PB25, 0);    /* ISI_D5 */
+       at91_set_A_periph(AT91_PIN_PB26, 0);    /* ISI_D6 */
+       at91_set_A_periph(AT91_PIN_PB27, 0);    /* ISI_D7 */
+       at91_set_A_periph(AT91_PIN_PB28, 0);    /* ISI_PCK */
+       at91_set_A_periph(AT91_PIN_PB30, 0);    /* ISI_HSYNC */
+       at91_set_A_periph(AT91_PIN_PB29, 0);    /* ISI_VSYNC */
+       at91_set_B_periph(AT91_PIN_PB8, 0);     /* ISI_PD8 */
+       at91_set_B_periph(AT91_PIN_PB9, 0);     /* ISI_PD9 */
+       at91_set_B_periph(AT91_PIN_PB10, 0);    /* ISI_PD10 */
+       at91_set_B_periph(AT91_PIN_PB11, 0);    /* ISI_PD11 */
+
+       platform_device_register(&at91sam9g45_isi_device);
+
+       if (use_pck_as_mck) {
+               at91_set_B_periph(AT91_PIN_PB31, 0);    /* ISI_MCK (PCK1) */
+
+               pck = clk_get(NULL, "pck1");
+               parent = clk_get(NULL, "plla");
+
+               BUG_ON(IS_ERR(pck) || IS_ERR(parent));
+
+               if (clk_set_parent(pck, parent)) {
+                       pr_err("Failed to set PCK's parent\n");
+               } else {
+                       /* Register PCK as ISI_MCK */
+                       isi_mck_lookups[0].clk = pck;
+                       clkdev_add_table(isi_mck_lookups,
+                                       ARRAY_SIZE(isi_mck_lookups));
+               }
+
+               clk_put(pck);
+               clk_put(parent);
+       }
+}
+#else
+void __init at91_add_device_isi(struct isi_platform_data *data,
+               bool use_pck_as_mck) {}
+#endif
+
 
 /* --------------------------------------------------------------------
  *  LCD Controller
@@ -957,7 +1052,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
 static struct resource tcb0_resources[] = {
        [0] = {
                .start  = AT91SAM9G45_BASE_TCB0,
-               .end    = AT91SAM9G45_BASE_TCB0 + SZ_16K - 1,
+               .end    = AT91SAM9G45_BASE_TCB0 + SZ_256 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -978,7 +1073,7 @@ static struct platform_device at91sam9g45_tcb0_device = {
 static struct resource tcb1_resources[] = {
        [0] = {
                .start  = AT91SAM9G45_BASE_TCB1,
-               .end    = AT91SAM9G45_BASE_TCB1 + SZ_16K - 1,
+               .end    = AT91SAM9G45_BASE_TCB1 + SZ_256 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -995,8 +1090,25 @@ static struct platform_device at91sam9g45_tcb1_device = {
        .num_resources  = ARRAY_SIZE(tcb1_resources),
 };
 
+#if defined(CONFIG_OF)
+static struct of_device_id tcb_ids[] = {
+       { .compatible = "atmel,at91rm9200-tcb" },
+       { /*sentinel*/ }
+};
+#endif
+
 static void __init at91_add_device_tc(void)
 {
+#if defined(CONFIG_OF)
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, tcb_ids);
+       if (np) {
+               of_node_put(np);
+               return;
+       }
+#endif
+
        platform_device_register(&at91sam9g45_tcb0_device);
        platform_device_register(&at91sam9g45_tcb1_device);
 }
@@ -1099,6 +1211,8 @@ static struct resource rtt_resources[] = {
                .start  = AT91SAM9G45_BASE_RTT,
                .end    = AT91SAM9G45_BASE_RTT + SZ_16 - 1,
                .flags  = IORESOURCE_MEM,
+       }, {
+               .flags  = IORESOURCE_MEM,
        }
 };
 
@@ -1106,11 +1220,32 @@ static struct platform_device at91sam9g45_rtt_device = {
        .name           = "at91_rtt",
        .id             = 0,
        .resource       = rtt_resources,
-       .num_resources  = ARRAY_SIZE(rtt_resources),
 };
 
+#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
+static void __init at91_add_device_rtt_rtc(void)
+{
+       at91sam9g45_rtt_device.name = "rtc-at91sam9";
+       /*
+        * The second resource is needed:
+        * GPBR will serve as the storage for RTC time offset
+        */
+       at91sam9g45_rtt_device.num_resources = 2;
+       rtt_resources[1].start = AT91SAM9G45_BASE_GPBR +
+                                4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
+       rtt_resources[1].end = rtt_resources[1].start + 3;
+}
+#else
+static void __init at91_add_device_rtt_rtc(void)
+{
+       /* Only one resource is needed: RTT not used as RTC */
+       at91sam9g45_rtt_device.num_resources = 1;
+}
+#endif
+
 static void __init at91_add_device_rtt(void)
 {
+       at91_add_device_rtt_rtc();
        platform_device_register(&at91sam9g45_rtt_device);
 }
 
@@ -1565,7 +1700,6 @@ static inline void configure_usart3_pins(unsigned pins)
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];  /* the UARTs to use */
-struct platform_device *atmel_default_console_device;  /* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
index 0468be1..9d45718 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/linkage.h>
 #include <mach/hardware.h>
-#include <mach/at91sam9_ddrsdr.h>
+#include <mach/at91_ramc.h>
 #include <mach/at91_rstc.h>
 
                        .arm
                        .globl  at91sam9g45_restart
 
 at91sam9g45_restart:
-                       ldr     r0, .at91_va_base_sdramc0       @ preload constants
-                       ldr     r1, =at91_rstc_base
-                       ldr     r1, [r1]
+                       ldr     r5, =at91_ramc_base             @ preload constants
+                       ldr     r0, [r5]
+                       ldr     r4, =at91_rstc_base
+                       ldr     r1, [r4]
 
                        mov     r2, #1
                        mov     r3, #AT91_DDRSDRC_LPCB_POWER_DOWN
@@ -35,6 +36,3 @@ at91sam9g45_restart:
                        str     r4, [r1, #AT91_RSTC_CR]         @ reset processor
 
                        b       .
-
-.at91_va_base_sdramc0:
-       .word AT91_VA_BASE_SYS + AT91_DDRSDRC0
index 7ae4993..d9f2774 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/module.h>
 
+#include <asm/proc-fns.h>
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -288,12 +289,15 @@ static void __init at91sam9rl_ioremap_registers(void)
 {
        at91_ioremap_shdwc(AT91SAM9RL_BASE_SHDWC);
        at91_ioremap_rstc(AT91SAM9RL_BASE_RSTC);
+       at91_ioremap_ramc(0, AT91SAM9RL_BASE_SDRAMC, 512);
        at91sam926x_ioremap_pit(AT91SAM9RL_BASE_PIT);
        at91sam9_ioremap_smc(0, AT91SAM9RL_BASE_SMC);
+       at91_ioremap_matrix(AT91SAM9RL_BASE_MATRIX);
 }
 
 static void __init at91sam9rl_initialize(void)
 {
+       arm_pm_idle = at91sam9_idle;
        arm_pm_restart = at91sam9_alt_restart;
        at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0);
 
index 9be71c1..eda72e8 100644 (file)
@@ -20,6 +20,7 @@
 #include <mach/board.h>
 #include <mach/at91sam9rl.h>
 #include <mach/at91sam9rl_matrix.h>
+#include <mach/at91_matrix.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at_hdmac.h>
 
@@ -265,8 +266,8 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
        if (!data)
                return;
 
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
+       csa = at91_matrix_read(AT91_MATRIX_EBICSA);
+       at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
        /* enable pin */
        if (gpio_is_valid(data->enable_pin))
@@ -682,6 +683,8 @@ static struct resource rtt_resources[] = {
                .start  = AT91SAM9RL_BASE_RTT,
                .end    = AT91SAM9RL_BASE_RTT + SZ_16 - 1,
                .flags  = IORESOURCE_MEM,
+       }, {
+               .flags  = IORESOURCE_MEM,
        }
 };
 
@@ -689,11 +692,32 @@ static struct platform_device at91sam9rl_rtt_device = {
        .name           = "at91_rtt",
        .id             = 0,
        .resource       = rtt_resources,
-       .num_resources  = ARRAY_SIZE(rtt_resources),
 };
 
+#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
+static void __init at91_add_device_rtt_rtc(void)
+{
+       at91sam9rl_rtt_device.name = "rtc-at91sam9";
+       /*
+        * The second resource is needed:
+        * GPBR will serve as the storage for RTC time offset
+        */
+       at91sam9rl_rtt_device.num_resources = 2;
+       rtt_resources[1].start = AT91SAM9RL_BASE_GPBR +
+                                4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
+       rtt_resources[1].end = rtt_resources[1].start + 3;
+}
+#else
+static void __init at91_add_device_rtt_rtc(void)
+{
+       /* Only one resource is needed: RTT not used as RTC */
+       at91sam9rl_rtt_device.num_resources = 1;
+}
+#endif
+
 static void __init at91_add_device_rtt(void)
 {
+       at91_add_device_rtt_rtc();
        platform_device_register(&at91sam9rl_rtt_device);
 }
 
@@ -1128,7 +1152,6 @@ static inline void configure_usart3_pins(unsigned pins)
 }
 
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];  /* the UARTs to use */
-struct platform_device *atmel_default_console_device;  /* the serial console device */
 
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
new file mode 100644 (file)
index 0000000..b6831ee
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ *  Chip-specific setup code for the AT91SAM9x5 family
+ *
+ *  Copyright (C) 2010-2012 Atmel Corporation.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/at91sam9x5.h>
+#include <mach/at91_pmc.h>
+#include <mach/cpu.h>
+#include <mach/board.h>
+
+#include "soc.h"
+#include "generic.h"
+#include "clock.h"
+#include "sam9_smc.h"
+
+/* --------------------------------------------------------------------
+ *  Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioAB_clk = {
+       .name           = "pioAB_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_PIOAB,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioCD_clk = {
+       .name           = "pioCD_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_PIOCD,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk smd_clk = {
+       .name           = "smd_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_SMD,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+       .name           = "usart0_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_USART0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+       .name           = "usart1_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_USART1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+       .name           = "usart2_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_USART2,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* USART3 clock - Only for sam9g25/sam9x25 */
+static struct clk usart3_clk = {
+       .name           = "usart3_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_USART3,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi0_clk = {
+       .name           = "twi0_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_TWI0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi1_clk = {
+       .name           = "twi1_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_TWI1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi2_clk = {
+       .name           = "twi2_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_TWI2,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc0_clk = {
+       .name           = "mci0_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_MCI0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+       .name           = "spi0_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_SPI0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+       .name           = "spi1_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_SPI1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uart0_clk = {
+       .name           = "uart0_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_UART0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uart1_clk = {
+       .name           = "uart1_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_UART1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk tcb0_clk = {
+       .name           = "tcb0_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_TCB,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pwm_clk = {
+       .name           = "pwm_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_PWM,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk adc_clk = {
+       .name           = "adc_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_ADC,
+       .type   = CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma0_clk = {
+       .name           = "dma0_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_DMA0,
+       .type   = CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma1_clk = {
+       .name           = "dma1_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_DMA1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uhphs_clk = {
+       .name           = "uhphs",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_UHPHS,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk udphs_clk = {
+       .name           = "udphs_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_UDPHS,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* emac0 clock - Only for sam9g25/sam9x25/sam9g35/sam9x35 */
+static struct clk macb0_clk = {
+       .name           = "pclk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_EMAC0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* lcd clock - Only for sam9g15/sam9g35/sam9x35 */
+static struct clk lcdc_clk = {
+       .name           = "lcdc_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_LCDC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* isi clock - Only for sam9g25 */
+static struct clk isi_clk = {
+       .name           = "isi_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_ISI,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc1_clk = {
+       .name           = "mci1_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_MCI1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* emac1 clock - Only for sam9x25 */
+static struct clk macb1_clk = {
+       .name           = "pclk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_EMAC1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc_clk = {
+       .name           = "ssc_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_SSC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* can0 clock - Only for sam9x35 */
+static struct clk can0_clk = {
+       .name           = "can0_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_CAN0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* can1 clock - Only for sam9x35 */
+static struct clk can1_clk = {
+       .name           = "can1_clk",
+       .pmc_mask       = 1 << AT91SAM9X5_ID_CAN1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+       &pioAB_clk,
+       &pioCD_clk,
+       &smd_clk,
+       &usart0_clk,
+       &usart1_clk,
+       &usart2_clk,
+       &twi0_clk,
+       &twi1_clk,
+       &twi2_clk,
+       &mmc0_clk,
+       &spi0_clk,
+       &spi1_clk,
+       &uart0_clk,
+       &uart1_clk,
+       &tcb0_clk,
+       &pwm_clk,
+       &adc_clk,
+       &dma0_clk,
+       &dma1_clk,
+       &uhphs_clk,
+       &udphs_clk,
+       &mmc1_clk,
+       &ssc_clk,
+       // irq0
+};
+
+static struct clk_lookup periph_clocks_lookups[] = {
+       /* lookup table for DT entries */
+       CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+       CLKDEV_CON_DEV_ID("usart", "f801c000.serial", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart2_clk),
+       CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb0_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
+       CLKDEV_CON_ID("pioA", &pioAB_clk),
+       CLKDEV_CON_ID("pioB", &pioAB_clk),
+       CLKDEV_CON_ID("pioC", &pioCD_clk),
+       CLKDEV_CON_ID("pioD", &pioCD_clk),
+       /* additional fake clock for macb_hclk */
+       CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk),
+       CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
+       CLKDEV_CON_DEV_ID("hclk", "600000.ohci", &uhphs_clk),
+       CLKDEV_CON_DEV_ID("ohci_clk", "600000.ohci", &uhphs_clk),
+       CLKDEV_CON_DEV_ID("ehci_clk", "700000.ehci", &uhphs_clk),
+};
+
+/*
+ * The two programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+       .name           = "pck0",
+       .pmc_mask       = AT91_PMC_PCK0,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 0,
+};
+static struct clk pck1 = {
+       .name           = "pck1",
+       .pmc_mask       = AT91_PMC_PCK1,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 1,
+};
+
+static void __init at91sam9x5_register_clocks(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+               clk_register(periph_clocks[i]);
+
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+
+       if (cpu_is_at91sam9g25()
+       || cpu_is_at91sam9x25())
+               clk_register(&usart3_clk);
+
+       if (cpu_is_at91sam9g25()
+       || cpu_is_at91sam9x25()
+       || cpu_is_at91sam9g35()
+       || cpu_is_at91sam9x35())
+               clk_register(&macb0_clk);
+
+       if (cpu_is_at91sam9g15()
+       || cpu_is_at91sam9g35()
+       || cpu_is_at91sam9x35())
+               clk_register(&lcdc_clk);
+
+       if (cpu_is_at91sam9g25())
+               clk_register(&isi_clk);
+
+       if (cpu_is_at91sam9x25())
+               clk_register(&macb1_clk);
+
+       if (cpu_is_at91sam9x25()
+       || cpu_is_at91sam9x35()) {
+               clk_register(&can0_clk);
+               clk_register(&can1_clk);
+       }
+
+       clk_register(&pck0);
+       clk_register(&pck1);
+}
+
+/* --------------------------------------------------------------------
+ *  AT91SAM9x5 processor initialization
+ * -------------------------------------------------------------------- */
+
+static void __init at91sam9x5_map_io(void)
+{
+       at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
+}
+
+void __init at91sam9x5_initialize(void)
+{
+       at91_extern_irq = (1 << AT91SAM9X5_ID_IRQ0);
+
+       /* Register GPIO subsystem (using DT) */
+       at91_gpio_init(NULL, 0);
+}
+
+/* --------------------------------------------------------------------
+ *  Interrupt initialization
+ * -------------------------------------------------------------------- */
+/*
+ * The default interrupt priority levels (0 = lowest, 7 = highest).
+ */
+static unsigned int at91sam9x5_default_irq_priority[NR_AIC_IRQS] __initdata = {
+       7,      /* Advanced Interrupt Controller (FIQ) */
+       7,      /* System Peripherals */
+       1,      /* Parallel IO Controller A and B */
+       1,      /* Parallel IO Controller C and D */
+       4,      /* Soft Modem */
+       5,      /* USART 0 */
+       5,      /* USART 1 */
+       5,      /* USART 2 */
+       5,      /* USART 3 */
+       6,      /* Two-Wire Interface 0 */
+       6,      /* Two-Wire Interface 1 */
+       6,      /* Two-Wire Interface 2 */
+       0,      /* Multimedia Card Interface 0 */
+       5,      /* Serial Peripheral Interface 0 */
+       5,      /* Serial Peripheral Interface 1 */
+       5,      /* UART 0 */
+       5,      /* UART 1 */
+       0,      /* Timer Counter 0, 1, 2, 3, 4 and 5 */
+       0,      /* Pulse Width Modulation Controller */
+       0,      /* ADC Controller */
+       0,      /* DMA Controller 0 */
+       0,      /* DMA Controller 1 */
+       2,      /* USB Host High Speed port */
+       2,      /* USB Device High speed port */
+       3,      /* Ethernet MAC 0 */
+       3,      /* LDC Controller or Image Sensor Interface */
+       0,      /* Multimedia Card Interface 1 */
+       3,      /* Ethernet MAC 1 */
+       4,      /* Synchronous Serial Interface */
+       4,      /* CAN Controller 0 */
+       4,      /* CAN Controller 1 */
+       0,      /* Advanced Interrupt Controller (IRQ0) */
+};
+
+struct at91_init_soc __initdata at91sam9x5_soc = {
+       .map_io = at91sam9x5_map_io,
+       .default_irq_priority = at91sam9x5_default_irq_priority,
+       .register_clocks = at91sam9x5_register_clocks,
+       .init = at91sam9x5_initialize,
+};
index 56ba3bd..5400a1d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <asm/proc-fns.h>
 #include <asm/mach/arch.h>
 #include <mach/at91x40.h>
 #include <mach/at91_st.h>
@@ -37,8 +38,19 @@ unsigned long clk_get_rate(struct clk *clk)
        return AT91X40_MASTER_CLOCK;
 }
 
+static void at91x40_idle(void)
+{
+       /*
+        * Disable the processor clock.  The processor will be automatically
+        * re-enabled by an interrupt or by a reset.
+        */
+       __raw_writel(AT91_PS_CR_CPU, AT91_PS_CR);
+       cpu_do_idle();
+}
+
 void __init at91x40_initialize(unsigned long main_clock)
 {
+       arm_pm_idle = at91x40_idle;
        at91_extern_irq = (1 << AT91X40_ID_IRQ0) | (1 << AT91X40_ID_IRQ1)
                        | (1 << AT91X40_ID_IRQ2);
 }
index dfff289..6ca680a 100644 (file)
 #include <asm/mach/time.h>
 #include <mach/at91_tc.h>
 
+#define at91_tc_read(field) \
+       __raw_readl(AT91_TC + field)
+
+#define at91_tc_write(field, value) \
+       __raw_writel(value, AT91_TC + field);
+
 /*
  *     3 counter/timer units present.
  */
 
 static unsigned long at91x40_gettimeoffset(void)
 {
-       return (at91_sys_read(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_CV) * 1000000 / (AT91X40_MASTER_CLOCK / 128));
+       return (at91_tc_read(AT91_TC_CLK1BASE + AT91_TC_CV) * 1000000 / (AT91X40_MASTER_CLOCK / 128));
 }
 
 static irqreturn_t at91x40_timer_interrupt(int irq, void *dev_id)
 {
-       at91_sys_read(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_SR);
+       at91_tc_read(AT91_TC_CLK1BASE + AT91_TC_SR);
        timer_tick();
        return IRQ_HANDLED;
 }
@@ -57,20 +63,20 @@ void __init at91x40_timer_init(void)
 {
        unsigned int v;
 
-       at91_sys_write(AT91_TC + AT91_TC_BCR, 0);
-       v = at91_sys_read(AT91_TC + AT91_TC_BMR);
+       at91_tc_write(AT91_TC_BCR, 0);
+       v = at91_tc_read(AT91_TC_BMR);
        v = (v & ~AT91_TC_TC1XC1S) | AT91_TC_TC1XC1S_NONE;
-       at91_sys_write(AT91_TC + AT91_TC_BMR, v);
+       at91_tc_write(AT91_TC_BMR, v);
 
-       at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_CCR, AT91_TC_CLKDIS);
-       at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_CMR, (AT91_TC_TIMER_CLOCK4 | AT91_TC_CPCTRG));
-       at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_IDR, 0xffffffff);
-       at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_RC, (AT91X40_MASTER_CLOCK / 128) / HZ - 1);
-       at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_IER, (1<<4));
+       at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_CCR, AT91_TC_CLKDIS);
+       at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_CMR, (AT91_TC_TIMER_CLOCK4 | AT91_TC_CPCTRG));
+       at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_IDR, 0xffffffff);
+       at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_RC, (AT91X40_MASTER_CLOCK / 128) / HZ - 1);
+       at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_IER, (1<<4));
 
        setup_irq(AT91X40_ID_TC1, &at91x40_timer_irq);
 
-       at91_sys_write(AT91_TC + AT91_TC_CLK1BASE + AT91_TC_CCR, (AT91_TC_SWTRG | AT91_TC_CLKEN));
+       at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_CCR, (AT91_TC_SWTRG | AT91_TC_CLKEN));
 }
 
 struct sys_timer at91x40_timer = {
index 3bb4069..161efba 100644 (file)
@@ -138,6 +138,7 @@ static struct atmel_nand_data __initdata afeb9260_nand_data = {
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
        .bus_width_16   = 0,
+       .ecc_mode       = NAND_ECC_SOFT,
        .parts          = afeb9260_nand_partition,
        .num_parts      = ARRAY_SIZE(afeb9260_nand_partition),
        .det_pin        = -EINVAL,
index 8510e9e..c6d44ee 100644 (file)
@@ -140,6 +140,7 @@ static struct atmel_nand_data __initdata cam60_nand_data = {
        .det_pin        = -EINVAL,
        .rdy_pin        = AT91_PIN_PA9,
        .enable_pin     = AT91_PIN_PA7,
+       .ecc_mode       = NAND_ECC_SOFT,
        .parts          = cam60_nand_partition,
        .num_parts      = ARRAY_SIZE(cam60_nand_partition),
 };
diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c
deleted file mode 100644 (file)
index ac3de4f..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-cap9adk.c
- *
- *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
- *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
- *  Copyright (C) 2005 SAN People
- *  Copyright (C) 2007 Atmel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
-#include <linux/fb.h>
-#include <linux/mtd/physmap.h>
-
-#include <video/atmel_lcdc.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <mach/board.h>
-#include <mach/at91cap9_matrix.h>
-#include <mach/at91sam9_smc.h>
-#include <mach/system_rev.h>
-
-#include "sam9_smc.h"
-#include "generic.h"
-
-
-static void __init cap9adk_init_early(void)
-{
-       /* Initialize processor: 12 MHz crystal */
-       at91_initialize(12000000);
-
-       /* Setup the LEDs: USER1 and USER2 LED for cpu/timer... */
-       at91_init_leds(AT91_PIN_PA10, AT91_PIN_PA11);
-       /* ... POWER LED always on */
-       at91_set_gpio_output(AT91_PIN_PC29, 1);
-
-       /* Setup the serial ports and console */
-       at91_register_uart(0, 0, 0);            /* DBGU = ttyS0 */
-       at91_set_serial_console(0);
-}
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata cap9adk_usbh_data = {
-       .ports          = 2,
-       .vbus_pin       = {-EINVAL, -EINVAL},
-       .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB HS Device port
- */
-static struct usba_platform_data __initdata cap9adk_usba_udc_data = {
-       .vbus_pin       = AT91_PIN_PB31,
-};
-
-/*
- * ADS7846 Touchscreen
- */
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-static int ads7843_pendown_state(void)
-{
-       return !at91_get_gpio_value(AT91_PIN_PC4);      /* Touchscreen PENIRQ */
-}
-
-static struct ads7846_platform_data ads_info = {
-       .model                  = 7843,
-       .x_min                  = 150,
-       .x_max                  = 3830,
-       .y_min                  = 190,
-       .y_max                  = 3830,
-       .vref_delay_usecs       = 100,
-       .x_plate_ohms           = 450,
-       .y_plate_ohms           = 250,
-       .pressure_max           = 15000,
-       .debounce_max           = 1,
-       .debounce_rep           = 0,
-       .debounce_tol           = (~0),
-       .get_pendown_state      = ads7843_pendown_state,
-};
-
-static void __init cap9adk_add_device_ts(void)
-{
-       at91_set_gpio_input(AT91_PIN_PC4, 1);   /* Touchscreen PENIRQ */
-       at91_set_gpio_input(AT91_PIN_PC5, 1);   /* Touchscreen BUSY */
-}
-#else
-static void __init cap9adk_add_device_ts(void) {}
-#endif
-
-
-/*
- * SPI devices.
- */
-static struct spi_board_info cap9adk_spi_devices[] = {
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
-       {       /* DataFlash card */
-               .modalias       = "mtd_dataflash",
-               .chip_select    = 0,
-               .max_speed_hz   = 15 * 1000 * 1000,
-               .bus_num        = 0,
-       },
-#endif
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-       {
-               .modalias       = "ads7846",
-               .chip_select    = 3,            /* can be 2 or 3, depending on J2 jumper */
-               .max_speed_hz   = 125000 * 26,  /* (max sample rate @ 3V) * (cmd + data + overhead) */
-               .bus_num        = 0,
-               .platform_data  = &ads_info,
-               .irq            = AT91_PIN_PC4,
-       },
-#endif
-};
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct at91_mmc_data __initdata cap9adk_mmc_data = {
-       .wire4          = 1,
-       .det_pin        = -EINVAL,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata cap9adk_macb_data = {
-       .phy_irq_pin    = -EINVAL,
-       .is_rmii        = 1,
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata cap9adk_nand_partitions[] = {
-       {
-               .name   = "NAND partition",
-               .offset = 0,
-               .size   = MTDPART_SIZ_FULL,
-       },
-};
-
-static struct atmel_nand_data __initdata cap9adk_nand_data = {
-       .ale            = 21,
-       .cle            = 22,
-       .det_pin        = -EINVAL,
-       .rdy_pin        = -EINVAL,
-       .enable_pin     = AT91_PIN_PD15,
-       .parts          = cap9adk_nand_partitions,
-       .num_parts      = ARRAY_SIZE(cap9adk_nand_partitions),
-};
-
-static struct sam9_smc_config __initdata cap9adk_nand_smc_config = {
-       .ncs_read_setup         = 1,
-       .nrd_setup              = 2,
-       .ncs_write_setup        = 1,
-       .nwe_setup              = 2,
-
-       .ncs_read_pulse         = 6,
-       .nrd_pulse              = 4,
-       .ncs_write_pulse        = 6,
-       .nwe_pulse              = 4,
-
-       .read_cycle             = 8,
-       .write_cycle            = 8,
-
-       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
-       .tdf_cycles             = 1,
-};
-
-static void __init cap9adk_add_device_nand(void)
-{
-       unsigned long csa;
-
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
-
-       cap9adk_nand_data.bus_width_16 = board_have_nand_16bit();
-       /* setup bus-width (8 or 16) */
-       if (cap9adk_nand_data.bus_width_16)
-               cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_16;
-       else
-               cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
-       /* configure chip-select 3 (NAND) */
-       sam9_smc_configure(0, 3, &cap9adk_nand_smc_config);
-
-       at91_add_device_nand(&cap9adk_nand_data);
-}
-
-
-/*
- * NOR flash
- */
-static struct mtd_partition cap9adk_nor_partitions[] = {
-       {
-               .name           = "NOR partition",
-               .offset         = 0,
-               .size           = MTDPART_SIZ_FULL,
-       },
-};
-
-static struct physmap_flash_data cap9adk_nor_data = {
-       .width          = 2,
-       .parts          = cap9adk_nor_partitions,
-       .nr_parts       = ARRAY_SIZE(cap9adk_nor_partitions),
-};
-
-#define NOR_BASE       AT91_CHIPSELECT_0
-#define NOR_SIZE       SZ_8M
-
-static struct resource nor_flash_resources[] = {
-       {
-               .start  = NOR_BASE,
-               .end    = NOR_BASE + NOR_SIZE - 1,
-               .flags  = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device cap9adk_nor_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-                               .platform_data  = &cap9adk_nor_data,
-       },
-       .resource       = nor_flash_resources,
-       .num_resources  = ARRAY_SIZE(nor_flash_resources),
-};
-
-static struct sam9_smc_config __initdata cap9adk_nor_smc_config = {
-       .ncs_read_setup         = 2,
-       .nrd_setup              = 4,
-       .ncs_write_setup        = 2,
-       .nwe_setup              = 4,
-
-       .ncs_read_pulse         = 10,
-       .nrd_pulse              = 8,
-       .ncs_write_pulse        = 10,
-       .nwe_pulse              = 8,
-
-       .read_cycle             = 16,
-       .write_cycle            = 16,
-
-       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE | AT91_SMC_DBW_16,
-       .tdf_cycles             = 1,
-};
-
-static __init void cap9adk_add_device_nor(void)
-{
-       unsigned long csa;
-
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
-
-       /* configure chip-select 0 (NOR) */
-       sam9_smc_configure(0, 0, &cap9adk_nor_smc_config);
-
-       platform_device_register(&cap9adk_nor_flash);
-}
-
-
-/*
- * LCD Controller
- */
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static struct fb_videomode at91_tft_vga_modes[] = {
-       {
-               .name           = "TX09D50VM1CCA @ 60",
-               .refresh        = 60,
-               .xres           = 240,          .yres           = 320,
-               .pixclock       = KHZ2PICOS(4965),
-
-               .left_margin    = 1,            .right_margin   = 33,
-               .upper_margin   = 1,            .lower_margin   = 0,
-               .hsync_len      = 5,            .vsync_len      = 1,
-
-               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-               .vmode          = FB_VMODE_NONINTERLACED,
-       },
-};
-
-static struct fb_monspecs at91fb_default_monspecs = {
-       .manufacturer   = "HIT",
-       .monitor        = "TX09D70VM1CCA",
-
-       .modedb         = at91_tft_vga_modes,
-       .modedb_len     = ARRAY_SIZE(at91_tft_vga_modes),
-       .hfmin          = 15000,
-       .hfmax          = 64000,
-       .vfmin          = 50,
-       .vfmax          = 150,
-};
-
-#define AT91CAP9_DEFAULT_LCDCON2       (ATMEL_LCDC_MEMOR_LITTLE \
-                                       | ATMEL_LCDC_DISTYPE_TFT    \
-                                       | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
-
-static void at91_lcdc_power_control(int on)
-{
-       if (on)
-               at91_set_gpio_value(AT91_PIN_PC0, 0);   /* power up */
-       else
-               at91_set_gpio_value(AT91_PIN_PC0, 1);   /* power down */
-}
-
-/* Driver datas */
-static struct atmel_lcdfb_info __initdata cap9adk_lcdc_data = {
-       .default_bpp                    = 16,
-       .default_dmacon                 = ATMEL_LCDC_DMAEN,
-       .default_lcdcon2                = AT91CAP9_DEFAULT_LCDCON2,
-       .default_monspecs               = &at91fb_default_monspecs,
-       .atmel_lcdfb_power_control      = at91_lcdc_power_control,
-       .guard_time                     = 1,
-};
-
-#else
-static struct atmel_lcdfb_info __initdata cap9adk_lcdc_data;
-#endif
-
-
-/*
- * AC97
- */
-static struct ac97c_platform_data cap9adk_ac97_data = {
-       .reset_pin      = -EINVAL,
-};
-
-
-static void __init cap9adk_board_init(void)
-{
-       /* Serial */
-       at91_add_device_serial();
-       /* USB Host */
-       at91_add_device_usbh(&cap9adk_usbh_data);
-       /* USB HS */
-       at91_add_device_usba(&cap9adk_usba_udc_data);
-       /* SPI */
-       at91_add_device_spi(cap9adk_spi_devices, ARRAY_SIZE(cap9adk_spi_devices));
-       /* Touchscreen */
-       cap9adk_add_device_ts();
-       /* MMC */
-       at91_add_device_mmc(1, &cap9adk_mmc_data);
-       /* Ethernet */
-       at91_add_device_eth(&cap9adk_macb_data);
-       /* NAND */
-       cap9adk_add_device_nand();
-       /* NOR Flash */
-       cap9adk_add_device_nor();
-       /* I2C */
-       at91_add_device_i2c(NULL, 0);
-       /* LCD Controller */
-       at91_add_device_lcdc(&cap9adk_lcdc_data);
-       /* AC97 */
-       at91_add_device_ac97(&cap9adk_ac97_data);
-}
-
-MACHINE_START(AT91CAP9ADK, "Atmel AT91CAP9A-DK")
-       /* Maintainer: Stelian Pop <stelian.pop@leadtechdesign.com> */
-       .timer          = &at91sam926x_timer,
-       .map_io         = at91_map_io,
-       .init_early     = cap9adk_init_early,
-       .init_irq       = at91_init_irq_default,
-       .init_machine   = cap9adk_board_init,
-MACHINE_END
index 9ab3d1e..5f3680e 100644 (file)
@@ -43,6 +43,7 @@
 #include <mach/board.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91sam9260_matrix.h>
+#include <mach/at91_matrix.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
@@ -116,6 +117,7 @@ static struct atmel_nand_data __initdata cpu9krea_nand_data = {
        .enable_pin     = AT91_PIN_PC14,
        .bus_width_16   = 0,
        .det_pin        = -EINVAL,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 #ifdef CONFIG_MACH_CPU9260
@@ -238,8 +240,8 @@ static __init void cpu9krea_add_device_nor(void)
 {
        unsigned long csa;
 
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_VDDIOMSEL_3_3V);
+       csa = at91_matrix_read(AT91_MATRIX_EBICSA);
+       at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_VDDIOMSEL_3_3V);
 
        /* configure chip-select 0 (NOR) */
        sam9_smc_configure(0, 0, &cpu9krea_nor_smc_config);
index 368e142..e094cc8 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 #include <mach/cpu.h>
 
 #include "generic.h"
index bb6b434..c18d4d3 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/gpio.h>
-#include <linux/irqdomain.h>
+#include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 
-#include <mach/hardware.h>
 #include <mach/board.h>
-#include <mach/system_rev.h>
-#include <mach/at91sam9_smc.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init ek_init_early(void)
-{
-       /* Initialize processor: 12.000 MHz crystal */
-       at91_initialize(12000000);
-
-       /* DGBU on ttyS0. (Rx & Tx only) */
-       at91_register_uart(0, 0, 0);
-
-       /* set serial console to ttyS0 (ie, DBGU) */
-       at91_set_serial_console(0);
-}
-
-/* det_pin is not connected */
-static struct atmel_nand_data __initdata ek_nand_data = {
-       .ale            = 21,
-       .cle            = 22,
-       .det_pin        = -EINVAL,
-       .rdy_pin        = AT91_PIN_PC8,
-       .enable_pin     = AT91_PIN_PC14,
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
-       .ncs_read_setup         = 0,
-       .nrd_setup              = 2,
-       .ncs_write_setup        = 0,
-       .nwe_setup              = 2,
-
-       .ncs_read_pulse         = 4,
-       .nrd_pulse              = 4,
-       .ncs_write_pulse        = 4,
-       .nwe_pulse              = 4,
-
-       .read_cycle             = 7,
-       .write_cycle            = 7,
+static const struct of_device_id irq_of_match[] __initconst = {
 
-       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
-       .tdf_cycles             = 3,
-};
-
-static void __init ek_add_device_nand(void)
-{
-       ek_nand_data.bus_width_16 = board_have_nand_16bit();
-       /* setup bus-width (8 or 16) */
-       if (ek_nand_data.bus_width_16)
-               ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
-       else
-               ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
-       /* configure chip-select 3 (NAND) */
-       sam9_smc_configure(0, 3, &ek_nand_smc_config);
-
-       at91_add_device_nand(&ek_nand_data);
-}
-
-static const struct of_device_id aic_of_match[] __initconst = {
-       { .compatible = "atmel,at91rm9200-aic", },
-       {},
+       { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
+       { .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup },
+       { .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup },
+       { /*sentinel*/ }
 };
 
 static void __init at91_dt_init_irq(void)
 {
-       irq_domain_generate_simple(aic_of_match, 0xfffff000, 0);
-       at91_init_irq_default();
+       of_irq_init(irq_of_match);
 }
 
 static void __init at91_dt_device_init(void)
 {
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-
-       /* NAND */
-       ek_add_device_nand();
 }
 
 static const char *at91_dt_board_compat[] __initdata = {
        "atmel,at91sam9m10g45ek",
+       "atmel,at91sam9x5ek",
        "calao,usb-a9g20",
        NULL
 };
@@ -117,7 +59,7 @@ DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
-       .init_early     = ek_init_early,
+       .init_early     = at91_dt_initialize,
        .init_irq       = at91_dt_init_irq,
        .init_machine   = at91_dt_device_init,
        .dt_compat      = at91_dt_board_compat,
index 07ef35b..f23aabe 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 #include <mach/cpu.h>
 
 #include "generic.h"
@@ -110,7 +111,7 @@ static void __init eco920_board_init(void)
        at91_add_device_mmc(0, &eco920_mmc_data);
        platform_device_register(&eco920_flash);
 
-       at91_sys_write(AT91_SMC_CSR(7), AT91_SMC_RWHOLD_(1)
+       at91_ramc_write(0, AT91_SMC_CSR(7),     AT91_SMC_RWHOLD_(1)
                                | AT91_SMC_RWSETUP_(1)
                                | AT91_SMC_DBW_8
                                | AT91_SMC_WSEN
@@ -122,7 +123,7 @@ static void __init eco920_board_init(void)
        at91_set_deglitch(AT91_PIN_PA23, 1);
 
 /* Initialization of the Static Memory Controller for Chip Select 3 */
-       at91_sys_write(AT91_SMC_CSR(3),
+       at91_ramc_write(0, AT91_SMC_CSR(3),
                AT91_SMC_DBW_16  |      /* 16 bit */
                AT91_SMC_WSEN    |
                AT91_SMC_NWS_(5) |      /* wait states */
index eec02cd..1815152 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/mach-at91/board-flexibity.c
  *
- *  Copyright (C) 2010 Flexibity
+ *  Copyright (C) 2010-2011 Flexibity
  *  Copyright (C) 2005 SAN People
  *  Copyright (C) 2006 Atmel
  *
@@ -62,6 +62,13 @@ static struct at91_udc_data __initdata flexibity_udc_data = {
        .pullup_pin     = -EINVAL,              /* pull-up driven by UDC */
 };
 
+/* I2C devices */
+static struct i2c_board_info __initdata flexibity_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("ds1307", 0x68),
+       },
+};
+
 /* SPI devices */
 static struct spi_board_info flexibity_spi_devices[] = {
        {       /* DataFlash chip */
@@ -141,6 +148,9 @@ static void __init flexibity_board_init(void)
        at91_add_device_usbh(&flexibity_usbh_data);
        /* USB Device */
        at91_add_device_udc(&flexibity_udc_data);
+       /* I2C */
+       at91_add_device_i2c(flexibity_i2c_devices,
+               ARRAY_SIZE(flexibity_i2c_devices));
        /* SPI */
        at91_add_device_spi(flexibity_spi_devices,
                ARRAY_SIZE(flexibity_spi_devices));
index d75a4a2..59b92aa 100644 (file)
@@ -38,6 +38,7 @@
 #include <mach/board.h>
 #include <mach/cpu.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 #include "generic.h"
 
@@ -107,6 +108,7 @@ static struct atmel_nand_data __initdata kb9202_nand_data = {
        .det_pin        = -EINVAL,
        .rdy_pin        = AT91_PIN_PC29,
        .enable_pin     = AT91_PIN_PC28,
+       .ecc_mode       = NAND_ECC_SOFT,
        .parts          = kb9202_nand_partition,
        .num_parts      = ARRAY_SIZE(kb9202_nand_partition),
 };
index 3f8617c..57d5f6a 100644 (file)
@@ -190,6 +190,7 @@ static struct atmel_nand_data __initdata neocore926_nand_data = {
        .rdy_pin                = AT91_PIN_PB19,
        .rdy_pin_active_low     = 1,
        .enable_pin             = AT91_PIN_PD15,
+       .ecc_mode               = NAND_ECC_SOFT,
        .parts                  = neocore926_nand_partition,
        .num_parts              = ARRAY_SIZE(neocore926_nand_partition),
        .det_pin                = -EINVAL,
index ab024fa..59e35dd 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 #include "generic.h"
 
index e029d22..b6ed5ed 100644 (file)
@@ -138,6 +138,8 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .det_pin        = -EINVAL,
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
+       .ecc_mode       = NAND_ECC_SOFT,
+       .on_flash_bbt   = 1,
        .parts          = ek_nand_partition,
        .num_parts      = ARRAY_SIZE(ek_nand_partition),
 };
index 782f379..01332aa 100644 (file)
@@ -41,6 +41,7 @@
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 #include "generic.h"
 
@@ -149,6 +150,8 @@ static struct atmel_nand_data __initdata dk_nand_data = {
        .det_pin        = AT91_PIN_PB1,
        .rdy_pin        = AT91_PIN_PC2,
        .enable_pin     = -EINVAL,
+       .ecc_mode       = NAND_ECC_SOFT,
+       .on_flash_bbt   = 1,
        .parts          = dk_nand_partition,
        .num_parts      = ARRAY_SIZE(dk_nand_partition),
 };
index ef7c12a..11cbaa8 100644 (file)
@@ -41,6 +41,7 @@
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 #include "generic.h"
 
index 84bce58..e8b116b 100644 (file)
@@ -139,6 +139,7 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .det_pin        = -EINVAL,
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
+       .ecc_mode       = NAND_ECC_SOFT,
        .parts          = ek_nand_partition,
        .num_parts      = ARRAY_SIZE(ek_nand_partition),
 };
index be8233b..d5aec55 100644 (file)
@@ -181,6 +181,8 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .det_pin        = -EINVAL,
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
+       .ecc_mode       = NAND_ECC_SOFT,
+       .on_flash_bbt   = 1,
        .parts          = ek_nand_partition,
        .num_parts      = ARRAY_SIZE(ek_nand_partition),
 };
index 4089507..c3f9944 100644 (file)
@@ -187,6 +187,8 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .det_pin        = -EINVAL,
        .rdy_pin        = AT91_PIN_PC15,
        .enable_pin     = AT91_PIN_PC14,
+       .ecc_mode       = NAND_ECC_SOFT,
+       .on_flash_bbt   = 1,
        .parts          = ek_nand_partition,
        .num_parts      = ARRAY_SIZE(ek_nand_partition),
 };
index 29f6605..66f0ddf 100644 (file)
@@ -187,6 +187,8 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .det_pin        = -EINVAL,
        .rdy_pin        = AT91_PIN_PA22,
        .enable_pin     = AT91_PIN_PD15,
+       .ecc_mode       = NAND_ECC_SOFT,
+       .on_flash_bbt   = 1,
        .parts          = ek_nand_partition,
        .num_parts      = ARRAY_SIZE(ek_nand_partition),
 };
index 843d628..8923ec9 100644 (file)
@@ -166,6 +166,8 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
        .det_pin        = -EINVAL,
+       .ecc_mode       = NAND_ECC_SOFT,
+       .on_flash_bbt   = 1,
        .parts          = ek_nand_partition,
        .num_parts      = ARRAY_SIZE(ek_nand_partition),
 };
index ea0d1b9..e1bea73 100644 (file)
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/leds.h>
-#include <linux/clk.h>
 #include <linux/atmel-mci.h>
+#include <linux/delay.h>
 
 #include <mach/hardware.h>
 #include <video/atmel_lcdc.h>
+#include <media/soc_camera.h>
+#include <media/atmel-isi.h>
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -146,6 +148,8 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC8,
        .enable_pin     = AT91_PIN_PC14,
        .det_pin        = -EINVAL,
+       .ecc_mode       = NAND_ECC_SOFT,
+       .on_flash_bbt   = 1,
        .parts          = ek_nand_partition,
        .num_parts      = ARRAY_SIZE(ek_nand_partition),
 };
@@ -185,6 +189,71 @@ static void __init ek_add_device_nand(void)
 
 
 /*
+ *  ISI
+ */
+static struct isi_platform_data __initdata isi_data = {
+       .frate                  = ISI_CFG1_FRATE_CAPTURE_ALL,
+       /* to use codec and preview path simultaneously */
+       .full_mode              = 1,
+       .data_width_flags       = ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10,
+       /* ISI_MCK is provided by programmable clock or external clock */
+       .mck_hz                 = 25000000,
+};
+
+
+/*
+ * soc-camera OV2640
+ */
+#if defined(CONFIG_SOC_CAMERA_OV2640) || \
+       defined(CONFIG_SOC_CAMERA_OV2640_MODULE)
+static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link)
+{
+       /* ISI board for ek using default 8-bits connection */
+       return SOCAM_DATAWIDTH_8;
+}
+
+static int i2c_camera_power(struct device *dev, int on)
+{
+       /* enable or disable the camera */
+       pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
+       at91_set_gpio_output(AT91_PIN_PD13, !on);
+
+       if (!on)
+               goto out;
+
+       /* If enabled, give a reset impulse */
+       at91_set_gpio_output(AT91_PIN_PD12, 0);
+       msleep(20);
+       at91_set_gpio_output(AT91_PIN_PD12, 1);
+       msleep(100);
+
+out:
+       return 0;
+}
+
+static struct i2c_board_info i2c_camera = {
+       I2C_BOARD_INFO("ov2640", 0x30),
+};
+
+static struct soc_camera_link iclink_ov2640 = {
+       .bus_id                 = 0,
+       .board_info             = &i2c_camera,
+       .i2c_adapter_id         = 0,
+       .power                  = i2c_camera_power,
+       .query_bus_param        = isi_camera_query_bus_param,
+};
+
+static struct platform_device isi_ov2640 = {
+       .name   = "soc-camera-pdrv",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &iclink_ov2640,
+       },
+};
+#endif
+
+
+/*
  * LCD Controller
  */
 #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
@@ -377,7 +446,12 @@ static struct gpio_led ek_pwm_led[] = {
 #endif
 };
 
-
+static struct platform_device *devices[] __initdata = {
+#if defined(CONFIG_SOC_CAMERA_OV2640) || \
+       defined(CONFIG_SOC_CAMERA_OV2640_MODULE)
+       &isi_ov2640,
+#endif
+};
 
 static void __init ek_board_init(void)
 {
@@ -399,6 +473,8 @@ static void __init ek_board_init(void)
        ek_add_device_nand();
        /* I2C */
        at91_add_device_i2c(0, NULL, 0);
+       /* ISI, using programmable clock as ISI_MCK */
+       at91_add_device_isi(&isi_data, true);
        /* LCD Controller */
        at91_add_device_lcdc(&ek_lcdc_data);
        /* Touch Screen */
@@ -410,6 +486,8 @@ static void __init ek_board_init(void)
        /* LEDs */
        at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
        at91_pwm_leds(ek_pwm_led, ARRAY_SIZE(ek_pwm_led));
+       /* Other platform devices */
+       platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
 MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
index c1366d0..b109ce2 100644 (file)
@@ -94,6 +94,8 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .det_pin        = -EINVAL,
        .rdy_pin        = AT91_PIN_PD17,
        .enable_pin     = AT91_PIN_PB6,
+       .ecc_mode       = NAND_ECC_SOFT,
+       .on_flash_bbt   = 1,
        .parts          = ek_nand_partition,
        .num_parts      = ARRAY_SIZE(ek_nand_partition),
 };
index 4770db0..ebc9d01 100644 (file)
@@ -110,6 +110,7 @@ static struct atmel_nand_data __initdata snapper9260_nand_data = {
        .bus_width_16   = 0,
        .enable_pin     = -EINVAL,
        .det_pin        = -EINVAL,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct sam9_smc_config __initdata snapper9260_nand_smc_config = {
@@ -145,11 +146,11 @@ static struct i2c_board_info __initdata snapper9260_i2c_devices[] = {
                /* Audio codec */
                I2C_BOARD_INFO("tlv320aic23", 0x1a),
        },
-       {
+};
+
+static struct i2c_board_info __initdata snapper9260_i2c_isl1208 = {
                /* RTC */
                I2C_BOARD_INFO("isl1208", 0x6f),
-               .irq = gpio_to_irq(AT91_PIN_PA31),
-       },
 };
 
 static void __init snapper9260_add_device_nand(void)
@@ -163,6 +164,10 @@ static void __init snapper9260_board_init(void)
 {
        at91_add_device_i2c(snapper9260_i2c_devices,
                            ARRAY_SIZE(snapper9260_i2c_devices));
+
+       snapper9260_i2c_isl1208.irq = gpio_to_irq(AT91_PIN_PA31);
+       i2c_register_board_info(0, &snapper9260_i2c_isl1208, 1);
+
        at91_add_device_serial();
        at91_add_device_usbh(&snapper9260_usbh_data);
        at91_add_device_udc(&snapper9260_udc_data);
index 72eb3b4..7640049 100644 (file)
@@ -86,6 +86,7 @@ static struct atmel_nand_data __initdata nand_data = {
        .enable_pin     = AT91_PIN_PC14,
        .bus_width_16   = 0,
        .det_pin        = -EINVAL,
+       .ecc_mode       = NAND_ECC_SOFT,
 };
 
 static struct sam9_smc_config __initdata nand_smc_config = {
index 26c36fc..b7483a3 100644 (file)
@@ -198,6 +198,8 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .det_pin        = -EINVAL,
        .rdy_pin        = AT91_PIN_PA22,
        .enable_pin     = AT91_PIN_PD15,
+       .ecc_mode       = NAND_ECC_SOFT,
+       .on_flash_bbt   = 1,
        .parts          = ek_nand_partition,
        .num_parts      = ARRAY_SIZE(ek_nand_partition),
 };
index bbd553e..38dd279 100644 (file)
@@ -45,6 +45,7 @@
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 #include <mach/cpu.h>
 
 #include "generic.h"
@@ -181,6 +182,7 @@ static struct atmel_nand_data __initdata yl9200_nand_data = {
        .det_pin        = -EINVAL,
        .rdy_pin        = AT91_PIN_PC14,        /* R/!B (Sheet10) */
        .enable_pin     = AT91_PIN_PC15,        /* !CE  (Sheet10) */
+       .ecc_mode       = NAND_ECC_SOFT,
        .parts          = yl9200_nand_partition,
        .num_parts      = ARRAY_SIZE(yl9200_nand_partition),
 };
@@ -393,7 +395,7 @@ static void yl9200_init_video(void)
        at91_set_A_periph(AT91_PIN_PC6, 0);
 
        /* Initialization of the Static Memory Controller for Chip Select 2 */
-       at91_sys_write(AT91_SMC_CSR(2), AT91_SMC_DBW_16         /* 16 bit */
+       at91_ramc_write(0, AT91_SMC_CSR(2), AT91_SMC_DBW_16             /* 16 bit */
                        | AT91_SMC_WSEN | AT91_SMC_NWS_(0x4)    /* wait states */
                        | AT91_SMC_TDF_(0x100)                  /* float time */
        );
index 61873f3..a0f4d74 100644 (file)
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/of_address.h>
 
 #include <mach/hardware.h>
 #include <mach/at91_pmc.h>
 #include <mach/cpu.h>
 
+#include <asm/proc-fns.h>
+
 #include "clock.h"
 #include "generic.h"
 
+void __iomem *at91_pmc_base;
 
 /*
  * There's a lot more which can be done with clocks, including cpufreq
 /*
  * Chips have some kind of clocks : group them by functionality
  */
-#define cpu_has_utmi()         (  cpu_is_at91cap9() \
-                               || cpu_is_at91sam9rl() \
-                               || cpu_is_at91sam9g45())
+#define cpu_has_utmi()         (  cpu_is_at91sam9rl() \
+                               || cpu_is_at91sam9g45() \
+                               || cpu_is_at91sam9x5())
 
 #define cpu_has_800M_plla()    (  cpu_is_at91sam9g20() \
-                               || cpu_is_at91sam9g45())
+                               || cpu_is_at91sam9g45() \
+                               || cpu_is_at91sam9x5())
 
 #define cpu_has_300M_plla()    (cpu_is_at91sam9g10())
 
 #define cpu_has_pllb()         (!(cpu_is_at91sam9rl() \
-                               || cpu_is_at91sam9g45()))
+                               || cpu_is_at91sam9g45() \
+                               || cpu_is_at91sam9x5()))
 
-#define cpu_has_upll()         (cpu_is_at91sam9g45())
+#define cpu_has_upll()         (cpu_is_at91sam9g45() \
+                               || cpu_is_at91sam9x5())
 
 /* USB host HS & FS */
 #define cpu_has_uhp()          (!cpu_is_at91sam9rl())
 
 /* USB device FS only */
 #define cpu_has_udpfs()                (!(cpu_is_at91sam9rl() \
-                               || cpu_is_at91sam9g45()))
+                               || cpu_is_at91sam9g45() \
+                               || cpu_is_at91sam9x5()))
+
+#define cpu_has_plladiv2()     (cpu_is_at91sam9g45() \
+                               || cpu_is_at91sam9x5())
+
+#define cpu_has_mdiv3()                (cpu_is_at91sam9g45() \
+                               || cpu_is_at91sam9x5())
+
+#define cpu_has_alt_prescaler()        (cpu_is_at91sam9x5())
 
 static LIST_HEAD(clocks);
 static DEFINE_SPINLOCK(clk_lock);
@@ -111,11 +127,11 @@ static void pllb_mode(struct clk *clk, int is_on)
                value = 0;
 
        // REVISIT: Add work-around for AT91RM9200 Errata #26 ?
-       at91_sys_write(AT91_CKGR_PLLBR, value);
+       at91_pmc_write(AT91_CKGR_PLLBR, value);
 
        do {
                cpu_relax();
-       } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on);
+       } while ((at91_pmc_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on);
 }
 
 static struct clk pllb = {
@@ -130,31 +146,24 @@ static struct clk pllb = {
 static void pmc_sys_mode(struct clk *clk, int is_on)
 {
        if (is_on)
-               at91_sys_write(AT91_PMC_SCER, clk->pmc_mask);
+               at91_pmc_write(AT91_PMC_SCER, clk->pmc_mask);
        else
-               at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask);
+               at91_pmc_write(AT91_PMC_SCDR, clk->pmc_mask);
 }
 
 static void pmc_uckr_mode(struct clk *clk, int is_on)
 {
-       unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR);
-
-       if (cpu_is_at91sam9g45()) {
-               if (is_on)
-                       uckr |= AT91_PMC_BIASEN;
-               else
-                       uckr &= ~AT91_PMC_BIASEN;
-       }
+       unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
 
        if (is_on) {
                is_on = AT91_PMC_LOCKU;
-               at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask);
+               at91_pmc_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask);
        } else
-               at91_sys_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask));
+               at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask));
 
        do {
                cpu_relax();
-       } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on);
+       } while ((at91_pmc_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on);
 }
 
 /* USB function clocks (PLLB must be 48 MHz) */
@@ -190,9 +199,9 @@ struct clk mck = {
 static void pmc_periph_mode(struct clk *clk, int is_on)
 {
        if (is_on)
-               at91_sys_write(AT91_PMC_PCER, clk->pmc_mask);
+               at91_pmc_write(AT91_PMC_PCER, clk->pmc_mask);
        else
-               at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask);
+               at91_pmc_write(AT91_PMC_PCDR, clk->pmc_mask);
 }
 
 static struct clk __init *at91_css_to_clk(unsigned long css)
@@ -210,11 +219,24 @@ static struct clk __init *at91_css_to_clk(unsigned long css)
                                return &utmi_clk;
                        else if (cpu_has_pllb())
                                return &pllb;
+                       break;
+               /* alternate PMC: can use master clock */
+               case AT91_PMC_CSS_MASTER:
+                       return &mck;
        }
 
        return NULL;
 }
 
+static int pmc_prescaler_divider(u32 reg)
+{
+       if (cpu_has_alt_prescaler()) {
+               return 1 << ((reg & AT91_PMC_ALT_PRES) >> PMC_ALT_PRES_OFFSET);
+       } else {
+               return 1 << ((reg & AT91_PMC_PRES) >> PMC_PRES_OFFSET);
+       }
+}
+
 static void __clk_enable(struct clk *clk)
 {
        if (clk->parent)
@@ -316,12 +338,22 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 {
        unsigned long   flags;
        unsigned        prescale;
+       unsigned long   prescale_offset, css_mask;
        unsigned long   actual;
 
        if (!clk_is_programmable(clk))
                return -EINVAL;
        if (clk->users)
                return -EBUSY;
+
+       if (cpu_has_alt_prescaler()) {
+               prescale_offset = PMC_ALT_PRES_OFFSET;
+               css_mask = AT91_PMC_ALT_PCKR_CSS;
+       } else {
+               prescale_offset = PMC_PRES_OFFSET;
+               css_mask = AT91_PMC_CSS;
+       }
+
        spin_lock_irqsave(&clk_lock, flags);
 
        actual = clk->parent->rate_hz;
@@ -329,10 +361,10 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
                if (actual && actual <= rate) {
                        u32     pckr;
 
-                       pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
-                       pckr &= AT91_PMC_CSS;   /* clock selection */
-                       pckr |= prescale << 2;
-                       at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);
+                       pckr = at91_pmc_read(AT91_PMC_PCKR(clk->id));
+                       pckr &= css_mask;       /* keep clock selection */
+                       pckr |= prescale << prescale_offset;
+                       at91_pmc_write(AT91_PMC_PCKR(clk->id), pckr);
                        clk->rate_hz = actual;
                        break;
                }
@@ -366,7 +398,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
 
        clk->rate_hz = parent->rate_hz;
        clk->parent = parent;
-       at91_sys_write(AT91_PMC_PCKR(clk->id), parent->id);
+       at91_pmc_write(AT91_PMC_PCKR(clk->id), parent->id);
 
        spin_unlock_irqrestore(&clk_lock, flags);
        return 0;
@@ -378,11 +410,17 @@ static void __init init_programmable_clock(struct clk *clk)
 {
        struct clk      *parent;
        u32             pckr;
+       unsigned int    css_mask;
+
+       if (cpu_has_alt_prescaler())
+               css_mask = AT91_PMC_ALT_PCKR_CSS;
+       else
+               css_mask = AT91_PMC_CSS;
 
-       pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
-       parent = at91_css_to_clk(pckr & AT91_PMC_CSS);
+       pckr = at91_pmc_read(AT91_PMC_PCKR(clk->id));
+       parent = at91_css_to_clk(pckr & css_mask);
        clk->parent = parent;
-       clk->rate_hz = parent->rate_hz / (1 << ((pckr & AT91_PMC_PRES) >> 2));
+       clk->rate_hz = parent->rate_hz / pmc_prescaler_divider(pckr);
 }
 
 #endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
@@ -396,19 +434,24 @@ static int at91_clk_show(struct seq_file *s, void *unused)
        u32             scsr, pcsr, uckr = 0, sr;
        struct clk      *clk;
 
-       seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR));
-       seq_printf(s, "PCSR = %8x\n", pcsr = at91_sys_read(AT91_PMC_PCSR));
-       seq_printf(s, "MOR  = %8x\n", at91_sys_read(AT91_CKGR_MOR));
-       seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR));
-       seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR));
+       scsr = at91_pmc_read(AT91_PMC_SCSR);
+       pcsr = at91_pmc_read(AT91_PMC_PCSR);
+       sr = at91_pmc_read(AT91_PMC_SR);
+       seq_printf(s, "SCSR = %8x\n", scsr);
+       seq_printf(s, "PCSR = %8x\n", pcsr);
+       seq_printf(s, "MOR  = %8x\n", at91_pmc_read(AT91_CKGR_MOR));
+       seq_printf(s, "MCFR = %8x\n", at91_pmc_read(AT91_CKGR_MCFR));
+       seq_printf(s, "PLLA = %8x\n", at91_pmc_read(AT91_CKGR_PLLAR));
        if (cpu_has_pllb())
-               seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR));
-       if (cpu_has_utmi())
-               seq_printf(s, "UCKR = %8x\n", uckr = at91_sys_read(AT91_CKGR_UCKR));
-       seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR));
+               seq_printf(s, "PLLB = %8x\n", at91_pmc_read(AT91_CKGR_PLLBR));
+       if (cpu_has_utmi()) {
+               uckr = at91_pmc_read(AT91_CKGR_UCKR);
+               seq_printf(s, "UCKR = %8x\n", uckr);
+       }
+       seq_printf(s, "MCKR = %8x\n", at91_pmc_read(AT91_PMC_MCKR));
        if (cpu_has_upll())
-               seq_printf(s, "USB  = %8x\n", at91_sys_read(AT91_PMC_USB));
-       seq_printf(s, "SR   = %8x\n", sr = at91_sys_read(AT91_PMC_SR));
+               seq_printf(s, "USB  = %8x\n", at91_pmc_read(AT91_PMC_USB));
+       seq_printf(s, "SR   = %8x\n", sr);
 
        seq_printf(s, "\n");
 
@@ -596,16 +639,14 @@ static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock)
        if (cpu_is_at91rm9200()) {
                uhpck.pmc_mask = AT91RM9200_PMC_UHP;
                udpck.pmc_mask = AT91RM9200_PMC_UDP;
-               at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
+               at91_pmc_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
        } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() ||
                   cpu_is_at91sam9263() || cpu_is_at91sam9g20() ||
                   cpu_is_at91sam9g10()) {
                uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
                udpck.pmc_mask = AT91SAM926x_PMC_UDP;
-       } else if (cpu_is_at91cap9()) {
-               uhpck.pmc_mask = AT91CAP9_PMC_UHP;
        }
-       at91_sys_write(AT91_CKGR_PLLBR, 0);
+       at91_pmc_write(AT91_CKGR_PLLBR, 0);
 
        udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
        uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
@@ -622,16 +663,16 @@ static void __init at91_upll_usbfs_clock_init(unsigned long main_clock)
        /* Setup divider by 10 to reach 48 MHz */
        usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV;
 
-       at91_sys_write(AT91_PMC_USB, usbr);
+       at91_pmc_write(AT91_PMC_USB, usbr);
 
        /* Now set uhpck values */
        uhpck.parent = &utmi_clk;
        uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
        uhpck.rate_hz = utmi_clk.rate_hz;
-       uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8);
+       uhpck.rate_hz /= 1 + ((at91_pmc_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8);
 }
 
-int __init at91_clock_init(unsigned long main_clock)
+static int __init at91_pmc_init(unsigned long main_clock)
 {
        unsigned tmp, freq, mckr;
        int i;
@@ -645,14 +686,14 @@ int __init at91_clock_init(unsigned long main_clock)
         */
        if (!main_clock) {
                do {
-                       tmp = at91_sys_read(AT91_CKGR_MCFR);
+                       tmp = at91_pmc_read(AT91_CKGR_MCFR);
                } while (!(tmp & AT91_PMC_MAINRDY));
                main_clock = (tmp & AT91_PMC_MAINF) * (AT91_SLOW_CLOCK / 16);
        }
        main_clk.rate_hz = main_clock;
 
        /* report if PLLA is more than mildly overclocked */
-       plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR));
+       plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_pmc_read(AT91_CKGR_PLLAR));
        if (cpu_has_300M_plla()) {
                if (plla.rate_hz > 300000000)
                        pll_overclock = true;
@@ -666,8 +707,8 @@ int __init at91_clock_init(unsigned long main_clock)
        if (pll_overclock)
                pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);
 
-       if (cpu_is_at91sam9g45()) {
-               mckr = at91_sys_read(AT91_PMC_MCKR);
+       if (cpu_has_plladiv2()) {
+               mckr = at91_pmc_read(AT91_PMC_MCKR);
                plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12));      /* plla divisor by 2 */
        }
 
@@ -688,6 +729,10 @@ int __init at91_clock_init(unsigned long main_clock)
                 * (obtain the USB High Speed 480 MHz when input is 12 MHz)
                 */
                utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz;
+
+               /* UTMI bias and PLL are managed at the same time */
+               if (cpu_has_upll())
+                       utmi_clk.pmc_mask |= AT91_PMC_BIASEN;
        }
 
        /*
@@ -703,10 +748,10 @@ int __init at91_clock_init(unsigned long main_clock)
         * MCK and CPU derive from one of those primary clocks.
         * For now, assume this parentage won't change.
         */
-       mckr = at91_sys_read(AT91_PMC_MCKR);
+       mckr = at91_pmc_read(AT91_PMC_MCKR);
        mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
        freq = mck.parent->rate_hz;
-       freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2));                           /* prescale */
+       freq /= pmc_prescaler_divider(mckr);                                    /* prescale */
        if (cpu_is_at91rm9200()) {
                mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8));       /* mdiv */
        } else if (cpu_is_at91sam9g20()) {
@@ -714,13 +759,19 @@ int __init at91_clock_init(unsigned long main_clock)
                        freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq;    /* mdiv ; (x >> 7) = ((x >> 8) * 2) */
                if (mckr & AT91_PMC_PDIV)
                        freq /= 2;              /* processor clock division */
-       } else if (cpu_is_at91sam9g45()) {
+       } else if (cpu_has_mdiv3()) {
                mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ?
                        freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
        } else {
                mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8));              /* mdiv */
        }
 
+       if (cpu_has_alt_prescaler()) {
+               /* Programmable clocks can use MCK */
+               mck.type |= CLK_TYPE_PRIMARY;
+               mck.id = 4;
+       }
+
        /* Register the PMC's standard clocks */
        for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
                at91_clk_add(standard_pmc_clocks[i]);
@@ -748,6 +799,55 @@ int __init at91_clock_init(unsigned long main_clock)
        return 0;
 }
 
+#if defined(CONFIG_OF)
+static struct of_device_id pmc_ids[] = {
+       { .compatible = "atmel,at91rm9200-pmc" },
+       { /*sentinel*/ }
+};
+
+static struct of_device_id osc_ids[] = {
+       { .compatible = "atmel,osc" },
+       { /*sentinel*/ }
+};
+
+int __init at91_dt_clock_init(void)
+{
+       struct device_node *np;
+       u32 main_clock = 0;
+
+       np = of_find_matching_node(NULL, pmc_ids);
+       if (!np)
+               panic("unable to find compatible pmc node in dtb\n");
+
+       at91_pmc_base = of_iomap(np, 0);
+       if (!at91_pmc_base)
+               panic("unable to map pmc cpu registers\n");
+
+       of_node_put(np);
+
+       /* retrieve the freqency of fixed clocks from device tree */
+       np = of_find_matching_node(NULL, osc_ids);
+       if (np) {
+               u32 rate;
+               if (!of_property_read_u32(np, "clock-frequency", &rate))
+                       main_clock = rate;
+       }
+
+       of_node_put(np);
+
+       return at91_pmc_init(main_clock);
+}
+#endif
+
+int __init at91_clock_init(unsigned long main_clock)
+{
+       at91_pmc_base = ioremap(AT91_PMC, 256);
+       if (!at91_pmc_base)
+               panic("Impossible to ioremap AT91_PMC 0x%x\n", AT91_PMC);
+
+       return at91_pmc_init(main_clock);
+}
+
 /*
  * Several unused clocks may be active.  Turn them off.
  */
@@ -770,9 +870,15 @@ static int __init at91_clock_reset(void)
                pr_debug("Clocks: disable unused %s\n", clk->name);
        }
 
-       at91_sys_write(AT91_PMC_PCDR, pcdr);
-       at91_sys_write(AT91_PMC_SCDR, scdr);
+       at91_pmc_write(AT91_PMC_PCDR, pcdr);
+       at91_pmc_write(AT91_PMC_SCDR, scdr);
 
        return 0;
 }
 late_initcall(at91_clock_reset);
+
+void at91sam9_idle(void)
+{
+       at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
+       cpu_do_idle();
+}
index a851e6c..555d956 100644 (file)
@@ -39,20 +39,15 @@ static int at91_enter_idle(struct cpuidle_device *dev,
 {
        struct timeval before, after;
        int idle_time;
-       u32 saved_lpr;
 
        local_irq_disable();
        do_gettimeofday(&before);
        if (index == 0)
                /* Wait for interrupt state */
                cpu_do_idle();
-       else if (index == 1) {
-               asm("b 1f; .align 5; 1:");
-               asm("mcr p15, 0, r0, c7, c10, 4");      /* drain write buffer */
-               saved_lpr = sdram_selfrefresh_enable();
-               cpu_do_idle();
-               sdram_selfrefresh_disable(saved_lpr);
-       }
+       else if (index == 1)
+               at91_standby();
+
        do_gettimeofday(&after);
        local_irq_enable();
        idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
index 5941334..dd9b346 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/clkdev.h>
+#include <linux/of.h>
 
  /* Map io */
 extern void __init at91_map_io(void);
@@ -19,15 +20,20 @@ extern void __init at91_init_sram(int bank, unsigned long base,
 extern void __init at91rm9200_set_type(int type);
 extern void __init at91_initialize(unsigned long main_clock);
 extern void __init at91x40_initialize(unsigned long main_clock);
+extern void __init at91_dt_initialize(void);
 
  /* Interrupts */
 extern void __init at91_init_irq_default(void);
 extern void __init at91_init_interrupts(unsigned int priority[]);
 extern void __init at91x40_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
+extern int  __init at91_aic_of_init(struct device_node *node,
+                                   struct device_node *parent);
+
 
  /* Timer */
 struct sys_timer;
+extern void at91rm9200_ioremap_st(u32 addr);
 extern struct sys_timer at91rm9200_timer;
 extern void at91sam926x_ioremap_pit(u32 addr);
 extern struct sys_timer at91sam926x_timer;
@@ -45,9 +51,9 @@ extern void __init at91sam9261_set_console_clock(int id);
 extern void __init at91sam9263_set_console_clock(int id);
 extern void __init at91sam9rl_set_console_clock(int id);
 extern void __init at91sam9g45_set_console_clock(int id);
-extern void __init at91cap9_set_console_clock(int id);
 #ifdef CONFIG_AT91_PMC_UNIT
 extern int __init at91_clock_init(unsigned long main_clock);
+extern int __init at91_dt_clock_init(void);
 #else
 static int inline at91_clock_init(unsigned long main_clock) { return 0; }
 #endif
@@ -57,6 +63,9 @@ struct device;
 extern void at91_irq_suspend(void);
 extern void at91_irq_resume(void);
 
+/* idle */
+extern void at91sam9_idle(void);
+
 /* reset */
 extern void at91_ioremap_rstc(u32 base_addr);
 extern void at91sam9_alt_restart(char, const char *);
@@ -65,6 +74,12 @@ extern void at91sam9g45_restart(char, const char *);
 /* shutdown */
 extern void at91_ioremap_shdwc(u32 base_addr);
 
+/* Matrix */
+extern void at91_ioremap_matrix(u32 base_addr);
+
+/* Ram Controler */
+extern void at91_ioremap_ramc(int id, u32 addr, u32 size);
+
  /* GPIO */
 #define AT91RM9200_PQFP                3       /* AT91RM9200 PQFP package has 3 banks */
 #define AT91RM9200_BGA         4       /* AT91RM9200 BGA package has 4 banks */
@@ -75,5 +90,7 @@ struct at91_gpio_bank {
 };
 extern void __init at91_gpio_init(struct at91_gpio_bank *, int nr_banks);
 extern void __init at91_gpio_irq_setup(void);
+extern int  __init at91_gpio_of_irq_setup(struct device_node *node,
+                                         struct device_node *parent);
 
 extern int at91_extern_irq;
index 74d6783..325837a 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/clk.h>
 #include <linux/errno.h>
+#include <linux/device.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
 
 #include <mach/hardware.h>
 #include <mach/at91_pio.h>
 struct at91_gpio_chip {
        struct gpio_chip        chip;
        struct at91_gpio_chip   *next;          /* Bank sharing same clock */
-       int                     id;             /* ID of register bank */
-       void __iomem            *regbase;       /* Base of register bank */
+       int                     pioc_hwirq;     /* PIO bank interrupt identifier on AIC */
+       int                     pioc_virq;      /* PIO bank Linux virtual interrupt */
+       int                     pioc_idx;       /* PIO bank index */
+       void __iomem            *regbase;       /* PIO bank virtual address */
        struct clk              *clock;         /* associated clock */
+       struct irq_domain       *domain;        /* associated irq domain */
 };
 
 #define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
@@ -43,8 +51,9 @@ static int at91_gpiolib_direction_output(struct gpio_chip *chip,
                                         unsigned offset, int val);
 static int at91_gpiolib_direction_input(struct gpio_chip *chip,
                                        unsigned offset);
+static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
 
-#define AT91_GPIO_CHIP(name, base_gpio, nr_gpio)                       \
+#define AT91_GPIO_CHIP(name, nr_gpio)                                  \
        {                                                               \
                .chip = {                                               \
                        .label            = name,                       \
@@ -53,20 +62,28 @@ static int at91_gpiolib_direction_input(struct gpio_chip *chip,
                        .get              = at91_gpiolib_get,           \
                        .set              = at91_gpiolib_set,           \
                        .dbg_show         = at91_gpiolib_dbg_show,      \
-                       .base             = base_gpio,                  \
+                       .to_irq           = at91_gpiolib_to_irq,        \
                        .ngpio            = nr_gpio,                    \
                },                                                      \
        }
 
 static struct at91_gpio_chip gpio_chip[] = {
-       AT91_GPIO_CHIP("pioA", 0x00, 32),
-       AT91_GPIO_CHIP("pioB", 0x20, 32),
-       AT91_GPIO_CHIP("pioC", 0x40, 32),
-       AT91_GPIO_CHIP("pioD", 0x60, 32),
-       AT91_GPIO_CHIP("pioE", 0x80, 32),
+       AT91_GPIO_CHIP("pioA", 32),
+       AT91_GPIO_CHIP("pioB", 32),
+       AT91_GPIO_CHIP("pioC", 32),
+       AT91_GPIO_CHIP("pioD", 32),
+       AT91_GPIO_CHIP("pioE", 32),
 };
 
 static int gpio_banks;
+static unsigned long at91_gpio_caps;
+
+/* All PIO controllers support PIO3 features */
+#define AT91_GPIO_CAP_PIO3     (1 <<  0)
+
+#define has_pio3()     (at91_gpio_caps & AT91_GPIO_CAP_PIO3)
+
+/*--------------------------------------------------------------------------*/
 
 static inline void __iomem *pin_to_controller(unsigned pin)
 {
@@ -83,6 +100,25 @@ static inline unsigned pin_to_mask(unsigned pin)
 }
 
 
+static char peripheral_function(void __iomem *pio, unsigned mask)
+{
+       char    ret = 'X';
+       u8      select;
+
+       if (pio) {
+               if (has_pio3()) {
+                       select = !!(__raw_readl(pio + PIO_ABCDSR1) & mask);
+                       select |= (!!(__raw_readl(pio + PIO_ABCDSR2) & mask) << 1);
+                       ret = 'A' + select;
+               } else {
+                       ret = __raw_readl(pio + PIO_ABSR) & mask ?
+                                                       'B' : 'A';
+               }
+       }
+
+       return ret;
+}
+
 /*--------------------------------------------------------------------------*/
 
 /* Not all hardware capabilities are exposed through these calls; they
@@ -130,7 +166,14 @@ int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup)
 
        __raw_writel(mask, pio + PIO_IDR);
        __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
-       __raw_writel(mask, pio + PIO_ASR);
+       if (has_pio3()) {
+               __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask,
+                                                       pio + PIO_ABCDSR1);
+               __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
+                                                       pio + PIO_ABCDSR2);
+       } else {
+               __raw_writel(mask, pio + PIO_ASR);
+       }
        __raw_writel(mask, pio + PIO_PDR);
        return 0;
 }
@@ -150,7 +193,14 @@ int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup)
 
        __raw_writel(mask, pio + PIO_IDR);
        __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
-       __raw_writel(mask, pio + PIO_BSR);
+       if (has_pio3()) {
+               __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask,
+                                                       pio + PIO_ABCDSR1);
+               __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
+                                                       pio + PIO_ABCDSR2);
+       } else {
+               __raw_writel(mask, pio + PIO_BSR);
+       }
        __raw_writel(mask, pio + PIO_PDR);
        return 0;
 }
@@ -158,8 +208,50 @@ EXPORT_SYMBOL(at91_set_B_periph);
 
 
 /*
- * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and
- * configure it for an input.
+ * mux the pin to the "C" internal peripheral role.
+ */
+int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup)
+{
+       void __iomem    *pio = pin_to_controller(pin);
+       unsigned        mask = pin_to_mask(pin);
+
+       if (!pio || !has_pio3())
+               return -EINVAL;
+
+       __raw_writel(mask, pio + PIO_IDR);
+       __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
+       __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
+       __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+       __raw_writel(mask, pio + PIO_PDR);
+       return 0;
+}
+EXPORT_SYMBOL(at91_set_C_periph);
+
+
+/*
+ * mux the pin to the "D" internal peripheral role.
+ */
+int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup)
+{
+       void __iomem    *pio = pin_to_controller(pin);
+       unsigned        mask = pin_to_mask(pin);
+
+       if (!pio || !has_pio3())
+               return -EINVAL;
+
+       __raw_writel(mask, pio + PIO_IDR);
+       __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
+       __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
+       __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+       __raw_writel(mask, pio + PIO_PDR);
+       return 0;
+}
+EXPORT_SYMBOL(at91_set_D_periph);
+
+
+/*
+ * mux the pin to the gpio controller (instead of "A", "B", "C"
+ * or "D" peripheral), and configure it for an input.
  */
 int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup)
 {
@@ -179,8 +271,8 @@ EXPORT_SYMBOL(at91_set_gpio_input);
 
 
 /*
- * mux the pin to the gpio controller (instead of "A" or "B" peripheral),
- * and configure it for an output.
+ * mux the pin to the gpio controller (instead of "A", "B", "C"
+ * or "D" peripheral), and configure it for an output.
  */
 int __init_or_module at91_set_gpio_output(unsigned pin, int value)
 {
@@ -210,12 +302,37 @@ int __init_or_module at91_set_deglitch(unsigned pin, int is_on)
 
        if (!pio)
                return -EINVAL;
+
+       if (has_pio3() && is_on)
+               __raw_writel(mask, pio + PIO_IFSCDR);
        __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR));
        return 0;
 }
 EXPORT_SYMBOL(at91_set_deglitch);
 
 /*
+ * enable/disable the debounce filter;
+ */
+int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div)
+{
+       void __iomem    *pio = pin_to_controller(pin);
+       unsigned        mask = pin_to_mask(pin);
+
+       if (!pio || !has_pio3())
+               return -EINVAL;
+
+       if (is_on) {
+               __raw_writel(mask, pio + PIO_IFSCER);
+               __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR);
+               __raw_writel(mask, pio + PIO_IFER);
+       } else {
+               __raw_writel(mask, pio + PIO_IFDR);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(at91_set_debounce);
+
+/*
  * enable/disable the multi-driver; This is only valid for output and
  * allows the output pin to run as an open collector output.
  */
@@ -233,6 +350,41 @@ int __init_or_module at91_set_multi_drive(unsigned pin, int is_on)
 EXPORT_SYMBOL(at91_set_multi_drive);
 
 /*
+ * enable/disable the pull-down.
+ * If pull-up already enabled while calling the function, we disable it.
+ */
+int __init_or_module at91_set_pulldown(unsigned pin, int is_on)
+{
+       void __iomem    *pio = pin_to_controller(pin);
+       unsigned        mask = pin_to_mask(pin);
+
+       if (!pio || !has_pio3())
+               return -EINVAL;
+
+       /* Disable pull-up anyway */
+       __raw_writel(mask, pio + PIO_PUDR);
+       __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
+       return 0;
+}
+EXPORT_SYMBOL(at91_set_pulldown);
+
+/*
+ * disable Schmitt trigger
+ */
+int __init_or_module at91_disable_schmitt_trig(unsigned pin)
+{
+       void __iomem    *pio = pin_to_controller(pin);
+       unsigned        mask = pin_to_mask(pin);
+
+       if (!pio || !has_pio3())
+               return -EINVAL;
+
+       __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT);
+       return 0;
+}
+EXPORT_SYMBOL(at91_disable_schmitt_trig);
+
+/*
  * assuming the pin is muxed as a gpio output, set its value.
  */
 int at91_set_gpio_value(unsigned pin, int value)
@@ -273,9 +425,9 @@ static u32 backups[MAX_GPIO_BANKS];
 
 static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
 {
-       unsigned        pin = irq_to_gpio(d->irq);
-       unsigned        mask = pin_to_mask(pin);
-       unsigned        bank = pin / 32;
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       unsigned        mask = 1 << d->hwirq;
+       unsigned        bank = at91_gpio->pioc_idx;
 
        if (unlikely(bank >= MAX_GPIO_BANKS))
                return -EINVAL;
@@ -285,7 +437,7 @@ static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
        else
                wakeups[bank] &= ~mask;
 
-       irq_set_irq_wake(gpio_chip[bank].id, state);
+       irq_set_irq_wake(at91_gpio->pioc_virq, state);
 
        return 0;
 }
@@ -301,9 +453,10 @@ void at91_gpio_suspend(void)
                __raw_writel(backups[i], pio + PIO_IDR);
                __raw_writel(wakeups[i], pio + PIO_IER);
 
-               if (!wakeups[i])
+               if (!wakeups[i]) {
+                       clk_unprepare(gpio_chip[i].clock);
                        clk_disable(gpio_chip[i].clock);
-               else {
+               } else {
 #ifdef CONFIG_PM_DEBUG
                        printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]);
 #endif
@@ -318,8 +471,10 @@ void at91_gpio_resume(void)
        for (i = 0; i < gpio_banks; i++) {
                void __iomem    *pio = gpio_chip[i].regbase;
 
-               if (!wakeups[i])
-                       clk_enable(gpio_chip[i].clock);
+               if (!wakeups[i]) {
+                       if (clk_prepare(gpio_chip[i].clock) == 0)
+                               clk_enable(gpio_chip[i].clock);
+               }
 
                __raw_writel(wakeups[i], pio + PIO_IDR);
                __raw_writel(backups[i], pio + PIO_IER);
@@ -335,7 +490,10 @@ void at91_gpio_resume(void)
  * To use any AT91_PIN_* as an externally triggered IRQ, first call
  * at91_set_gpio_input() then maybe enable its glitch filter.
  * Then just request_irq() with the pin ID; it works like any ARM IRQ
- * handler, though it always triggers on rising and falling edges.
+ * handler.
+ * First implementation always triggers on rising and falling edges
+ * whereas the newer PIO3 can be additionally configured to trigger on
+ * level, edge with any polarity.
  *
  * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
  * configuring them with at91_set_a_periph() or at91_set_b_periph().
@@ -344,9 +502,9 @@ void at91_gpio_resume(void)
 
 static void gpio_irq_mask(struct irq_data *d)
 {
-       unsigned        pin = irq_to_gpio(d->irq);
-       void __iomem    *pio = pin_to_controller(pin);
-       unsigned        mask = pin_to_mask(pin);
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       void __iomem    *pio = at91_gpio->regbase;
+       unsigned        mask = 1 << d->hwirq;
 
        if (pio)
                __raw_writel(mask, pio + PIO_IDR);
@@ -354,9 +512,9 @@ static void gpio_irq_mask(struct irq_data *d)
 
 static void gpio_irq_unmask(struct irq_data *d)
 {
-       unsigned        pin = irq_to_gpio(d->irq);
-       void __iomem    *pio = pin_to_controller(pin);
-       unsigned        mask = pin_to_mask(pin);
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       void __iomem    *pio = at91_gpio->regbase;
+       unsigned        mask = 1 << d->hwirq;
 
        if (pio)
                __raw_writel(mask, pio + PIO_IER);
@@ -373,23 +531,66 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
        }
 }
 
+/* Alternate irq type for PIO3 support */
+static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
+{
+       struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+       void __iomem    *pio = at91_gpio->regbase;
+       unsigned        mask = 1 << d->hwirq;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               __raw_writel(mask, pio + PIO_ESR);
+               __raw_writel(mask, pio + PIO_REHLSR);
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               __raw_writel(mask, pio + PIO_ESR);
+               __raw_writel(mask, pio + PIO_FELLSR);
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               __raw_writel(mask, pio + PIO_LSR);
+               __raw_writel(mask, pio + PIO_FELLSR);
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               __raw_writel(mask, pio + PIO_LSR);
+               __raw_writel(mask, pio + PIO_REHLSR);
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               /*
+                * disable additional interrupt modes:
+                * fall back to default behavior
+                */
+               __raw_writel(mask, pio + PIO_AIMDR);
+               return 0;
+       case IRQ_TYPE_NONE:
+       default:
+               pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
+               return -EINVAL;
+       }
+
+       /* enable additional interrupt modes */
+       __raw_writel(mask, pio + PIO_AIMER);
+
+       return 0;
+}
+
 static struct irq_chip gpio_irqchip = {
        .name           = "GPIO",
        .irq_disable    = gpio_irq_mask,
        .irq_mask       = gpio_irq_mask,
        .irq_unmask     = gpio_irq_unmask,
-       .irq_set_type   = gpio_irq_type,
+       /* .irq_set_type is set dynamically */
        .irq_set_wake   = gpio_irq_set_wake,
 };
 
 static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 {
-       unsigned        irq_pin;
        struct irq_data *idata = irq_desc_get_irq_data(desc);
        struct irq_chip *chip = irq_data_get_irq_chip(idata);
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
        void __iomem    *pio = at91_gpio->regbase;
-       u32             isr;
+       unsigned long   isr;
+       int             n;
 
        /* temporarily mask (level sensitive) parent IRQ */
        chip->irq_ack(idata);
@@ -407,13 +608,10 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
                        continue;
                }
 
-               irq_pin = gpio_to_irq(at91_gpio->chip.base);
-
-               while (isr) {
-                       if (isr & 1)
-                               generic_handle_irq(irq_pin);
-                       irq_pin++;
-                       isr >>= 1;
+               n = find_first_bit(&isr, BITS_PER_LONG);
+               while (n < BITS_PER_LONG) {
+                       generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
+                       n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
                }
        }
        chip->irq_unmask(idata);
@@ -424,6 +622,33 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 
 #ifdef CONFIG_DEBUG_FS
 
+static void gpio_printf(struct seq_file *s, void __iomem *pio, unsigned mask)
+{
+       char    *trigger = NULL;
+       char    *polarity = NULL;
+
+       if (__raw_readl(pio + PIO_IMR) & mask) {
+               if (!has_pio3() || !(__raw_readl(pio + PIO_AIMMR) & mask )) {
+                       trigger = "edge";
+                       polarity = "both";
+               } else {
+                       if (__raw_readl(pio + PIO_ELSR) & mask) {
+                               trigger = "level";
+                               polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
+                                       "high" : "low";
+                       } else {
+                               trigger = "edge";
+                               polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
+                                               "rising" : "falling";
+                       }
+               }
+               seq_printf(s, "IRQ:%s-%s\t", trigger, polarity);
+       } else {
+               seq_printf(s, "GPIO:%s\t\t",
+                               __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
+       }
+}
+
 static int at91_gpio_show(struct seq_file *s, void *unused)
 {
        int bank, j;
@@ -431,7 +656,7 @@ static int at91_gpio_show(struct seq_file *s, void *unused)
        /* print heading */
        seq_printf(s, "Pin\t");
        for (bank = 0; bank < gpio_banks; bank++) {
-               seq_printf(s, "PIO%c\t", 'A' + bank);
+               seq_printf(s, "PIO%c\t\t", 'A' + bank);
        };
        seq_printf(s, "\n\n");
 
@@ -445,11 +670,10 @@ static int at91_gpio_show(struct seq_file *s, void *unused)
                        unsigned        mask = pin_to_mask(pin);
 
                        if (__raw_readl(pio + PIO_PSR) & mask)
-                               seq_printf(s, "GPIO:%s", __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
+                               gpio_printf(s, pio, mask);
                        else
-                               seq_printf(s, "%s", __raw_readl(pio + PIO_ABSR) & mask ? "B" : "A");
-
-                       seq_printf(s, "\t");
+                               seq_printf(s, "%c\t\t",
+                                               peripheral_function(pio, mask));
                }
 
                seq_printf(s, "\n");
@@ -488,46 +712,152 @@ postcore_initcall(at91_gpio_debugfs_init);
  */
 static struct lock_class_key gpio_lock_class;
 
+#if defined(CONFIG_OF)
+static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+                                                       irq_hw_number_t hw)
+{
+       struct at91_gpio_chip   *at91_gpio = h->host_data;
+
+       irq_set_lockdep_class(virq, &gpio_lock_class);
+
+       /*
+        * Can use the "simple" and not "edge" handler since it's
+        * shorter, and the AIC handles interrupts sanely.
+        */
+       irq_set_chip_and_handler(virq, &gpio_irqchip,
+                                handle_simple_irq);
+       set_irq_flags(virq, IRQF_VALID);
+       irq_set_chip_data(virq, at91_gpio);
+
+       return 0;
+}
+
+static struct irq_domain_ops at91_gpio_ops = {
+       .map    = at91_gpio_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+int __init at91_gpio_of_irq_setup(struct device_node *node,
+                                    struct device_node *parent)
+{
+       struct at91_gpio_chip   *prev = NULL;
+       int                     alias_idx = of_alias_get_id(node, "gpio");
+       struct at91_gpio_chip   *at91_gpio = &gpio_chip[alias_idx];
+
+       /* Setup proper .irq_set_type function */
+       if (has_pio3())
+               gpio_irqchip.irq_set_type = alt_gpio_irq_type;
+       else
+               gpio_irqchip.irq_set_type = gpio_irq_type;
+
+       /* Disable irqs of this PIO controller */
+       __raw_writel(~0, at91_gpio->regbase + PIO_IDR);
+
+       /* Setup irq domain */
+       at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
+                                               &at91_gpio_ops, at91_gpio);
+       if (!at91_gpio->domain)
+               panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
+                       at91_gpio->pioc_idx);
+
+       /* Setup chained handler */
+       if (at91_gpio->pioc_idx)
+               prev = &gpio_chip[at91_gpio->pioc_idx - 1];
+
+       /* The toplevel handler handles one bank of GPIOs, except
+        * on some SoC it can handles up to three...
+        * We only set up the handler for the first of the list.
+        */
+       if (prev && prev->next == at91_gpio)
+               return 0;
+
+       at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent),
+                                                       at91_gpio->pioc_hwirq);
+       irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
+       irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
+
+       return 0;
+}
+#else
+int __init at91_gpio_of_irq_setup(struct device_node *node,
+                                    struct device_node *parent)
+{
+       return -EINVAL;
+}
+#endif
+
+/*
+ * irqdomain initialization: pile up irqdomains on top of AIC range
+ */
+static void __init at91_gpio_irqdomain(struct at91_gpio_chip *at91_gpio)
+{
+       int irq_base;
+
+       irq_base = irq_alloc_descs(-1, 0, at91_gpio->chip.ngpio, 0);
+       if (irq_base < 0)
+               panic("at91_gpio.%d: error %d: couldn't allocate IRQ numbers.\n",
+                       at91_gpio->pioc_idx, irq_base);
+       at91_gpio->domain = irq_domain_add_legacy(NULL, at91_gpio->chip.ngpio,
+                                                 irq_base, 0,
+                                                 &irq_domain_simple_ops, NULL);
+       if (!at91_gpio->domain)
+               panic("at91_gpio.%d: couldn't allocate irq domain.\n",
+                       at91_gpio->pioc_idx);
+}
+
 /*
  * Called from the processor-specific init to enable GPIO interrupt support.
  */
 void __init at91_gpio_irq_setup(void)
 {
-       unsigned                pioc, irq = gpio_to_irq(0);
+       unsigned                pioc;
+       int                     gpio_irqnbr = 0;
        struct at91_gpio_chip   *this, *prev;
 
+       /* Setup proper .irq_set_type function */
+       if (has_pio3())
+               gpio_irqchip.irq_set_type = alt_gpio_irq_type;
+       else
+               gpio_irqchip.irq_set_type = gpio_irq_type;
+
        for (pioc = 0, this = gpio_chip, prev = NULL;
                        pioc++ < gpio_banks;
                        prev = this, this++) {
-               unsigned        id = this->id;
-               unsigned        i;
+               int offset;
 
                __raw_writel(~0, this->regbase + PIO_IDR);
 
-               for (i = 0, irq = gpio_to_irq(this->chip.base); i < 32;
-                    i++, irq++) {
-                       irq_set_lockdep_class(irq, &gpio_lock_class);
+               /* setup irq domain for this GPIO controller */
+               at91_gpio_irqdomain(this);
+
+               for (offset = 0; offset < this->chip.ngpio; offset++) {
+                       unsigned int virq = irq_find_mapping(this->domain, offset);
+                       irq_set_lockdep_class(virq, &gpio_lock_class);
 
                        /*
                         * Can use the "simple" and not "edge" handler since it's
                         * shorter, and the AIC handles interrupts sanely.
                         */
-                       irq_set_chip_and_handler(irq, &gpio_irqchip,
+                       irq_set_chip_and_handler(virq, &gpio_irqchip,
                                                 handle_simple_irq);
-                       set_irq_flags(irq, IRQF_VALID);
+                       set_irq_flags(virq, IRQF_VALID);
+                       irq_set_chip_data(virq, this);
+
+                       gpio_irqnbr++;
                }
 
                /* The toplevel handler handles one bank of GPIOs, except
-                * AT91SAM9263_ID_PIOCDE handles three... PIOC is first in
-                * the list, so we only set up that handler.
+                * on some SoC it can handles up to three...
+                * We only set up the handler for the first of the list.
                 */
                if (prev && prev->next == this)
                        continue;
 
-               irq_set_chip_data(id, this);
-               irq_set_chained_handler(id, gpio_irq_handler);
+               this->pioc_virq = irq_create_mapping(NULL, this->pioc_hwirq);
+               irq_set_chip_data(this->pioc_virq, this);
+               irq_set_chained_handler(this->pioc_virq, gpio_irq_handler);
        }
-       pr_info("AT91: %d gpio irqs in %d banks\n", irq - gpio_to_irq(0), gpio_banks);
+       pr_info("AT91: %d gpio irqs in %d banks\n", gpio_irqnbr, gpio_banks);
 }
 
 /* gpiolib support */
@@ -593,48 +923,175 @@ static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
                                           at91_get_gpio_value(pin) ?
                                           "set" : "clear");
                        else
-                               seq_printf(s, "[periph %s]\n",
-                                          __raw_readl(pio + PIO_ABSR) &
-                                          mask ? "B" : "A");
+                               seq_printf(s, "[periph %c]\n",
+                                          peripheral_function(pio, mask));
                }
        }
 }
 
+static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+       int virq;
+
+       if (offset < chip->ngpio)
+               virq = irq_create_mapping(at91_gpio->domain, offset);
+       else
+               virq = -ENXIO;
+
+       dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+                               chip->label, offset + chip->base, virq);
+       return virq;
+}
+
+static int __init at91_gpio_setup_clk(int idx)
+{
+       struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
+
+       /* retreive PIO controller's clock */
+       at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label);
+       if (IS_ERR(at91_gpio->clock)) {
+               pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", idx);
+               goto err;
+       }
+
+       if (clk_prepare(at91_gpio->clock))
+               goto clk_prep_err;
+
+       /* enable PIO controller's clock */
+       if (clk_enable(at91_gpio->clock)) {
+               pr_err("at91_gpio.%d, failed to enable clock, ignoring.\n", idx);
+               goto clk_err;
+       }
+
+       return 0;
+
+clk_err:
+       clk_unprepare(at91_gpio->clock);
+clk_prep_err:
+       clk_put(at91_gpio->clock);
+err:
+       return -EINVAL;
+}
+
+#ifdef CONFIG_OF_GPIO
+static void __init of_at91_gpio_init_one(struct device_node *np)
+{
+       int alias_idx;
+       struct at91_gpio_chip *at91_gpio;
+
+       if (!np)
+               return;
+
+       alias_idx = of_alias_get_id(np, "gpio");
+       if (alias_idx >= MAX_GPIO_BANKS) {
+               pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n",
+                                               alias_idx, MAX_GPIO_BANKS);
+               return;
+       }
+
+       at91_gpio = &gpio_chip[alias_idx];
+       at91_gpio->chip.base = alias_idx * at91_gpio->chip.ngpio;
+
+       at91_gpio->regbase = of_iomap(np, 0);
+       if (!at91_gpio->regbase) {
+               pr_err("at91_gpio.%d, failed to map registers, ignoring.\n",
+                                                               alias_idx);
+               return;
+       }
+
+       /* Get the interrupts property */
+       if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) {
+               pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n",
+                                                               alias_idx);
+               goto ioremap_err;
+       }
+
+       /* Get capabilities from compatibility property */
+       if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
+               at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
+
+       /* Setup clock */
+       if (at91_gpio_setup_clk(alias_idx))
+               goto ioremap_err;
+
+       at91_gpio->chip.of_node = np;
+       gpio_banks = max(gpio_banks, alias_idx + 1);
+       at91_gpio->pioc_idx = alias_idx;
+       return;
+
+ioremap_err:
+       iounmap(at91_gpio->regbase);
+}
+
+static int __init of_at91_gpio_init(void)
+{
+       struct device_node *np = NULL;
+
+       /*
+        * This isn't ideal, but it gets things hooked up until this
+        * driver is converted into a platform_device
+        */
+       for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio")
+               of_at91_gpio_init_one(np);
+
+       return gpio_banks > 0 ? 0 : -EINVAL;
+}
+#else
+static int __init of_at91_gpio_init(void)
+{
+       return -EINVAL;
+}
+#endif
+
+static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
+{
+       struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
+
+       at91_gpio->chip.base = idx * at91_gpio->chip.ngpio;
+       at91_gpio->pioc_hwirq = pioc_hwirq;
+       at91_gpio->pioc_idx = idx;
+
+       at91_gpio->regbase = ioremap(regbase, 512);
+       if (!at91_gpio->regbase) {
+               pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", idx);
+               return;
+       }
+
+       if (at91_gpio_setup_clk(idx))
+               goto ioremap_err;
+
+       gpio_banks = max(gpio_banks, idx + 1);
+       return;
+
+ioremap_err:
+       iounmap(at91_gpio->regbase);
+}
+
 /*
  * Called from the processor-specific init to enable GPIO pin support.
  */
 void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
 {
-       unsigned                i;
+       unsigned i;
        struct at91_gpio_chip *at91_gpio, *last = NULL;
 
        BUG_ON(nr_banks > MAX_GPIO_BANKS);
 
-       gpio_banks = nr_banks;
+       if (of_at91_gpio_init() < 0) {
+               /* No GPIO controller found in device tree */
+               for (i = 0; i < nr_banks; i++)
+                       at91_gpio_init_one(i, data[i].regbase, data[i].id);
+       }
 
-       for (i = 0; i < nr_banks; i++) {
+       for (i = 0; i < gpio_banks; i++) {
                at91_gpio = &gpio_chip[i];
 
-               at91_gpio->id = data[i].id;
-               at91_gpio->chip.base = i * 32;
-
-               at91_gpio->regbase = ioremap(data[i].regbase, 512);
-               if (!at91_gpio->regbase) {
-                       pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", i);
-                       continue;
-               }
-
-               at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label);
-               if (!at91_gpio->clock) {
-                       pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", i);
-                       continue;
-               }
-
-               /* enable PIO controller's clock */
-               clk_enable(at91_gpio->clock);
-
-               /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */
-               if (last && last->id == at91_gpio->id)
+               /*
+                * GPIO controller are grouped on some SoC:
+                * PIOC, PIOD and PIOE can share the same IRQ line
+                */
+               if (last && last->pioc_hwirq == at91_gpio->pioc_hwirq)
                        last->next = at91_gpio;
                last = at91_gpio;
 
diff --git a/arch/arm/mach-at91/include/mach/at91_matrix.h b/arch/arm/mach-at91/include/mach/at91_matrix.h
new file mode 100644 (file)
index 0000000..02fae9d
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#ifndef __MACH_AT91_MATRIX_H__
+#define __MACH_AT91_MATRIX_H__
+
+#ifndef __ASSEMBLY__
+extern void __iomem *at91_matrix_base;
+
+#define at91_matrix_read(field) \
+       __raw_readl(at91_matrix_base + field)
+
+#define at91_matrix_write(field, value) \
+       __raw_writel(value, at91_matrix_base + field);
+
+#else
+.extern at91_matrix_base
+#endif
+
+#endif /* __MACH_AT91_MATRIX_H__ */
index c6a31bf..732b11c 100644 (file)
 #define PIO_PUER       0x64    /* Pull-up Enable Register */
 #define PIO_PUSR       0x68    /* Pull-up Status Register */
 #define PIO_ASR                0x70    /* Peripheral A Select Register */
+#define PIO_ABCDSR1    0x70    /* Peripheral ABCD Select Register 1 [some sam9 only] */
 #define PIO_BSR                0x74    /* Peripheral B Select Register */
+#define PIO_ABCDSR2    0x74    /* Peripheral ABCD Select Register 2 [some sam9 only] */
 #define PIO_ABSR       0x78    /* AB Status Register */
+#define PIO_IFSCDR     0x80    /* Input Filter Slow Clock Disable Register */
+#define PIO_IFSCER     0x84    /* Input Filter Slow Clock Enable Register */
+#define PIO_IFSCSR     0x88    /* Input Filter Slow Clock Status Register */
+#define PIO_SCDR       0x8c    /* Slow Clock Divider Debouncing Register */
+#define                PIO_SCDR_DIV    (0x3fff <<  0)          /* Slow Clock Divider Mask */
+#define PIO_PPDDR      0x90    /* Pad Pull-down Disable Register */
+#define PIO_PPDER      0x94    /* Pad Pull-down Enable Register */
+#define PIO_PPDSR      0x98    /* Pad Pull-down Status Register */
 #define PIO_OWER       0xa0    /* Output Write Enable Register */
 #define PIO_OWDR       0xa4    /* Output Write Disable Register */
 #define PIO_OWSR       0xa8    /* Output Write Status Register */
+#define PIO_AIMER      0xb0    /* Additional Interrupt Modes Enable Register */
+#define PIO_AIMDR      0xb4    /* Additional Interrupt Modes Disable Register */
+#define PIO_AIMMR      0xb8    /* Additional Interrupt Modes Mask Register */
+#define PIO_ESR                0xc0    /* Edge Select Register */
+#define PIO_LSR                0xc4    /* Level Select Register */
+#define PIO_ELSR       0xc8    /* Edge/Level Status Register */
+#define PIO_FELLSR     0xd0    /* Falling Edge/Low Level Select Register */
+#define PIO_REHLSR     0xd4    /* Rising Edge/ High Level Select Register */
+#define PIO_FRLHSR     0xd8    /* Fall/Rise - Low/High Status Register */
+#define PIO_SCHMITT    0x100   /* Schmitt Trigger Register */
+
+#define ABCDSR_PERIPH_A        0x0
+#define ABCDSR_PERIPH_B        0x1
+#define ABCDSR_PERIPH_C        0x2
+#define ABCDSR_PERIPH_D        0x3
 
 #endif
index e46f93e..3660478 100644 (file)
 #ifndef AT91_PMC_H
 #define AT91_PMC_H
 
-#define        AT91_PMC_SCER           (AT91_PMC + 0x00)       /* System Clock Enable Register */
-#define        AT91_PMC_SCDR           (AT91_PMC + 0x04)       /* System Clock Disable Register */
+#ifndef __ASSEMBLY__
+extern void __iomem *at91_pmc_base;
 
-#define        AT91_PMC_SCSR           (AT91_PMC + 0x08)       /* System Clock Status Register */
+#define at91_pmc_read(field) \
+       __raw_readl(at91_pmc_base + field)
+
+#define at91_pmc_write(field, value) \
+       __raw_writel(value, at91_pmc_base + field)
+#else
+.extern at91_aic_base
+#endif
+
+#define        AT91_PMC_SCER           0x00                    /* System Clock Enable Register */
+#define        AT91_PMC_SCDR           0x04                    /* System Clock Disable Register */
+
+#define        AT91_PMC_SCSR           0x08                    /* System Clock Status Register */
 #define                AT91_PMC_PCK            (1 <<  0)               /* Processor Clock */
 #define                AT91RM9200_PMC_UDP      (1 <<  1)               /* USB Devcice Port Clock [AT91RM9200 only] */
 #define                AT91RM9200_PMC_MCKUDP   (1 <<  2)               /* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */
-#define                AT91CAP9_PMC_DDR        (1 <<  2)               /* DDR Clock [CAP9 revC & some SAM9 only] */
 #define                AT91RM9200_PMC_UHP      (1 <<  4)               /* USB Host Port Clock [AT91RM9200 only] */
 #define                AT91SAM926x_PMC_UHP     (1 <<  6)               /* USB Host Port Clock [AT91SAM926x only] */
-#define                AT91CAP9_PMC_UHP        (1 <<  6)               /* USB Host Port Clock [AT91CAP9 only] */
 #define                AT91SAM926x_PMC_UDP     (1 <<  7)               /* USB Devcice Port Clock [AT91SAM926x only] */
 #define                AT91_PMC_PCK0           (1 <<  8)               /* Programmable Clock 0 */
 #define                AT91_PMC_PCK1           (1 <<  9)               /* Programmable Clock 1 */
 #define                AT91_PMC_HCK0           (1 << 16)               /* AHB Clock (USB host) [AT91SAM9261 only] */
 #define                AT91_PMC_HCK1           (1 << 17)               /* AHB Clock (LCD) [AT91SAM9261 only] */
 
-#define        AT91_PMC_PCER           (AT91_PMC + 0x10)       /* Peripheral Clock Enable Register */
-#define        AT91_PMC_PCDR           (AT91_PMC + 0x14)       /* Peripheral Clock Disable Register */
-#define        AT91_PMC_PCSR           (AT91_PMC + 0x18)       /* Peripheral Clock Status Register */
+#define        AT91_PMC_PCER           0x10                    /* Peripheral Clock Enable Register */
+#define        AT91_PMC_PCDR           0x14                    /* Peripheral Clock Disable Register */
+#define        AT91_PMC_PCSR           0x18                    /* Peripheral Clock Status Register */
 
-#define        AT91_CKGR_UCKR          (AT91_PMC + 0x1C)       /* UTMI Clock Register [some SAM9, CAP9] */
+#define        AT91_CKGR_UCKR          0x1C                    /* UTMI Clock Register [some SAM9] */
 #define                AT91_PMC_UPLLEN         (1   << 16)             /* UTMI PLL Enable */
 #define                AT91_PMC_UPLLCOUNT      (0xf << 20)             /* UTMI PLL Start-up Time */
 #define                AT91_PMC_BIASEN         (1   << 24)             /* UTMI BIAS Enable */
 #define                AT91_PMC_BIASCOUNT      (0xf << 28)             /* UTMI BIAS Start-up Time */
 
-#define        AT91_CKGR_MOR           (AT91_PMC + 0x20)       /* Main Oscillator Register [not on SAM9RL] */
-#define                AT91_PMC_MOSCEN         (1    << 0)             /* Main Oscillator Enable */
-#define                AT91_PMC_OSCBYPASS      (1    << 1)             /* Oscillator Bypass [SAM9x, CAP9] */
-#define                AT91_PMC_OSCOUNT        (0xff << 8)             /* Main Oscillator Start-up Time */
+#define        AT91_CKGR_MOR           0x20                    /* Main Oscillator Register [not on SAM9RL] */
+#define                AT91_PMC_MOSCEN         (1    <<  0)            /* Main Oscillator Enable */
+#define                AT91_PMC_OSCBYPASS      (1    <<  1)            /* Oscillator Bypass */
+#define                AT91_PMC_MOSCRCEN       (1    <<  3)            /* Main On-Chip RC Oscillator Enable [some SAM9] */
+#define                AT91_PMC_OSCOUNT        (0xff <<  8)            /* Main Oscillator Start-up Time */
+#define                AT91_PMC_KEY            (0x37 << 16)            /* MOR Writing Key */
+#define                AT91_PMC_MOSCSEL        (1    << 24)            /* Main Oscillator Selection [some SAM9] */
+#define                AT91_PMC_CFDEN          (1    << 25)            /* Clock Failure Detector Enable [some SAM9] */
 
-#define        AT91_CKGR_MCFR          (AT91_PMC + 0x24)       /* Main Clock Frequency Register */
+#define        AT91_CKGR_MCFR          0x24                    /* Main Clock Frequency Register */
 #define                AT91_PMC_MAINF          (0xffff <<  0)          /* Main Clock Frequency */
 #define                AT91_PMC_MAINRDY        (1      << 16)          /* Main Clock Ready */
 
-#define        AT91_CKGR_PLLAR         (AT91_PMC + 0x28)       /* PLL A Register */
-#define        AT91_CKGR_PLLBR         (AT91_PMC + 0x2c)       /* PLL B Register */
+#define        AT91_CKGR_PLLAR         0x28                    /* PLL A Register */
+#define        AT91_CKGR_PLLBR         0x2c                    /* PLL B Register */
 #define                AT91_PMC_DIV            (0xff  <<  0)           /* Divider */
 #define                AT91_PMC_PLLCOUNT       (0x3f  <<  8)           /* PLL Counter */
 #define                AT91_PMC_OUT            (3     << 14)           /* PLL Clock Frequency Range */
 #define                        AT91_PMC_USBDIV_4               (2 << 28)
 #define                AT91_PMC_USB96M         (1     << 28)           /* Divider by 2 Enable (PLLB only) */
 
-#define        AT91_PMC_MCKR           (AT91_PMC + 0x30)       /* Master Clock Register */
+#define        AT91_PMC_MCKR           0x30                    /* Master Clock Register */
 #define                AT91_PMC_CSS            (3 <<  0)               /* Master Clock Selection */
 #define                        AT91_PMC_CSS_SLOW               (0 << 0)
 #define                        AT91_PMC_CSS_MAIN               (1 << 0)
 #define                        AT91_PMC_CSS_PLLA               (2 << 0)
 #define                        AT91_PMC_CSS_PLLB               (3 << 0)
 #define                        AT91_PMC_CSS_UPLL               (3 << 0)        /* [some SAM9 only] */
-#define                AT91_PMC_PRES           (7 <<  2)               /* Master Clock Prescaler */
-#define                        AT91_PMC_PRES_1                 (0 << 2)
-#define                        AT91_PMC_PRES_2                 (1 << 2)
-#define                        AT91_PMC_PRES_4                 (2 << 2)
-#define                        AT91_PMC_PRES_8                 (3 << 2)
-#define                        AT91_PMC_PRES_16                (4 << 2)
-#define                        AT91_PMC_PRES_32                (5 << 2)
-#define                        AT91_PMC_PRES_64                (6 << 2)
+#define                PMC_PRES_OFFSET         2
+#define                AT91_PMC_PRES           (7 <<  PMC_PRES_OFFSET)         /* Master Clock Prescaler */
+#define                        AT91_PMC_PRES_1                 (0 << PMC_PRES_OFFSET)
+#define                        AT91_PMC_PRES_2                 (1 << PMC_PRES_OFFSET)
+#define                        AT91_PMC_PRES_4                 (2 << PMC_PRES_OFFSET)
+#define                        AT91_PMC_PRES_8                 (3 << PMC_PRES_OFFSET)
+#define                        AT91_PMC_PRES_16                (4 << PMC_PRES_OFFSET)
+#define                        AT91_PMC_PRES_32                (5 << PMC_PRES_OFFSET)
+#define                        AT91_PMC_PRES_64                (6 << PMC_PRES_OFFSET)
+#define                PMC_ALT_PRES_OFFSET     4
+#define                AT91_PMC_ALT_PRES       (7 <<  PMC_ALT_PRES_OFFSET)             /* Master Clock Prescaler [alternate location] */
+#define                        AT91_PMC_ALT_PRES_1             (0 << PMC_ALT_PRES_OFFSET)
+#define                        AT91_PMC_ALT_PRES_2             (1 << PMC_ALT_PRES_OFFSET)
+#define                        AT91_PMC_ALT_PRES_4             (2 << PMC_ALT_PRES_OFFSET)
+#define                        AT91_PMC_ALT_PRES_8             (3 << PMC_ALT_PRES_OFFSET)
+#define                        AT91_PMC_ALT_PRES_16            (4 << PMC_ALT_PRES_OFFSET)
+#define                        AT91_PMC_ALT_PRES_32            (5 << PMC_ALT_PRES_OFFSET)
+#define                        AT91_PMC_ALT_PRES_64            (6 << PMC_ALT_PRES_OFFSET)
 #define                AT91_PMC_MDIV           (3 <<  8)               /* Master Clock Division */
 #define                        AT91RM9200_PMC_MDIV_1           (0 << 8)        /* [AT91RM9200 only] */
 #define                        AT91RM9200_PMC_MDIV_2           (1 << 8)
 #define                        AT91RM9200_PMC_MDIV_3           (2 << 8)
 #define                        AT91RM9200_PMC_MDIV_4           (3 << 8)
-#define                        AT91SAM9_PMC_MDIV_1             (0 << 8)        /* [SAM9,CAP9 only] */
+#define                        AT91SAM9_PMC_MDIV_1             (0 << 8)        /* [SAM9 only] */
 #define                        AT91SAM9_PMC_MDIV_2             (1 << 8)
 #define                        AT91SAM9_PMC_MDIV_4             (2 << 8)
 #define                        AT91SAM9_PMC_MDIV_6             (3 << 8)        /* [some SAM9 only] */
 #define                        AT91_PMC_PLLADIV2_OFF           (0 << 12)
 #define                        AT91_PMC_PLLADIV2_ON            (1 << 12)
 
-#define        AT91_PMC_USB            (AT91_PMC + 0x38)       /* USB Clock Register [some SAM9 only] */
+#define        AT91_PMC_USB            0x38                    /* USB Clock Register [some SAM9 only] */
 #define                AT91_PMC_USBS           (0x1 <<  0)             /* USB OHCI Input clock selection */
 #define                        AT91_PMC_USBS_PLLA              (0 << 0)
 #define                        AT91_PMC_USBS_UPLL              (1 << 0)
 #define                AT91_PMC_OHCIUSBDIV     (0xF <<  8)             /* Divider for USB OHCI Clock */
 
-#define        AT91_PMC_PCKR(n)        (AT91_PMC + 0x40 + ((n) * 4))   /* Programmable Clock 0-N Registers */
+#define        AT91_PMC_SMD            0x3c                    /* Soft Modem Clock Register [some SAM9 only] */
+#define                AT91_PMC_SMDS           (0x1  <<  0)            /* SMD input clock selection */
+#define                AT91_PMC_SMD_DIV        (0x1f <<  8)            /* SMD input clock divider */
+#define                AT91_PMC_SMDDIV(n)      (((n) <<  8) & AT91_PMC_SMD_DIV)
+
+#define        AT91_PMC_PCKR(n)        (0x40 + ((n) * 4))      /* Programmable Clock 0-N Registers */
+#define                AT91_PMC_ALT_PCKR_CSS   (0x7 <<  0)             /* Programmable Clock Source Selection [alternate length] */
+#define                        AT91_PMC_CSS_MASTER             (4 << 0)        /* [some SAM9 only] */
 #define                AT91_PMC_CSSMCK         (0x1 <<  8)             /* CSS or Master Clock Selection */
 #define                        AT91_PMC_CSSMCK_CSS             (0 << 8)
 #define                        AT91_PMC_CSSMCK_MCK             (1 << 8)
 
-#define        AT91_PMC_IER            (AT91_PMC + 0x60)       /* Interrupt Enable Register */
-#define        AT91_PMC_IDR            (AT91_PMC + 0x64)       /* Interrupt Disable Register */
-#define        AT91_PMC_SR             (AT91_PMC + 0x68)       /* Status Register */
+#define        AT91_PMC_IER            0x60                    /* Interrupt Enable Register */
+#define        AT91_PMC_IDR            0x64                    /* Interrupt Disable Register */
+#define        AT91_PMC_SR             0x68                    /* Status Register */
 #define                AT91_PMC_MOSCS          (1 <<  0)               /* MOSCS Flag */
 #define                AT91_PMC_LOCKA          (1 <<  1)               /* PLLA Lock */
 #define                AT91_PMC_LOCKB          (1 <<  2)               /* PLLB Lock */
 #define                AT91_PMC_MCKRDY         (1 <<  3)               /* Master Clock */
-#define                AT91_PMC_LOCKU          (1 <<  6)               /* UPLL Lock [some SAM9, AT91CAP9 only] */
-#define                AT91_PMC_OSCSEL         (1 <<  7)               /* Slow Clock Oscillator [AT91CAP9 revC only] */
+#define                AT91_PMC_LOCKU          (1 <<  6)               /* UPLL Lock [some SAM9] */
 #define                AT91_PMC_PCK0RDY        (1 <<  8)               /* Programmable Clock 0 */
 #define                AT91_PMC_PCK1RDY        (1 <<  9)               /* Programmable Clock 1 */
 #define                AT91_PMC_PCK2RDY        (1 << 10)               /* Programmable Clock 2 */
 #define                AT91_PMC_PCK3RDY        (1 << 11)               /* Programmable Clock 3 */
-#define        AT91_PMC_IMR            (AT91_PMC + 0x6c)       /* Interrupt Mask Register */
+#define                AT91_PMC_MOSCSELS       (1 << 16)               /* Main Oscillator Selection [some SAM9] */
+#define                AT91_PMC_MOSCRCS        (1 << 17)               /* Main On-Chip RC [some SAM9] */
+#define                AT91_PMC_CFDEV          (1 << 18)               /* Clock Failure Detector Event [some SAM9] */
+#define        AT91_PMC_IMR            0x6c                    /* Interrupt Mask Register */
+
+#define AT91_PMC_PROT          0xe4                    /* Write Protect Mode Register [some SAM9] */
+#define                AT91_PMC_WPEN           (0x1  <<  0)            /* Write Protect Enable */
+#define                AT91_PMC_WPKEY          (0xffffff << 8)         /* Write Protect Key */
+#define                AT91_PMC_PROTKEY        (0x504d43 << 8)         /* Activation Code */
 
-#define AT91_PMC_PROT          (AT91_PMC + 0xe4)       /* Protect Register [AT91CAP9 revC only] */
-#define                AT91_PMC_PROTKEY        0x504d4301      /* Activation Code */
+#define AT91_PMC_WPSR          0xe8                    /* Write Protect Status Register [some SAM9] */
+#define                AT91_PMC_WPVS           (0x1  <<  0)            /* Write Protect Violation Status */
+#define                AT91_PMC_WPVSRC         (0xffff  <<  8)         /* Write Protect Violation Source */
 
-#define AT91_PMC_VER           (AT91_PMC + 0xfc)       /* PMC Module Version [AT91CAP9 only] */
+#define AT91_PMC_PCR           0x10c                   /* Peripheral Control Register [some SAM9] */
+#define                AT91_PMC_PCR_PID        (0x3f  <<  0)           /* Peripheral ID */
+#define                AT91_PMC_PCR_CMD        (0x1  <<  12)           /* Command */
+#define                AT91_PMC_PCR_DIV        (0x3  <<  16)           /* Divisor Value */
+#define                AT91_PMC_PCRDIV(n)      (((n) <<  16) & AT91_PMC_PCR_DIV)
+#define                AT91_PMC_PCR_EN         (0x1  <<  28)           /* Enable */
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/at91_ramc.h b/arch/arm/mach-at91/include/mach/at91_ramc.h
new file mode 100644 (file)
index 0000000..d8aeb27
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Header file for the Atmel RAM Controller
+ *
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2 only
+ */
+
+#ifndef __AT91_RAMC_H__
+#define __AT91_RAMC_H__
+
+#ifndef __ASSEMBLY__
+extern void __iomem *at91_ramc_base[];
+
+#define at91_ramc_read(id, field) \
+       __raw_readl(at91_ramc_base[id] + field)
+
+#define at91_ramc_write(id, field, value) \
+       __raw_writel(value, at91_ramc_base[id] + field)
+#else
+.extern at91_ramc_base
+#endif
+
+#define AT91_MEMCTRL_MC                0
+#define AT91_MEMCTRL_SDRAMC    1
+#define AT91_MEMCTRL_DDRSDR    2
+
+#include <mach/at91rm9200_sdramc.h>
+#include <mach/at91sam9_ddrsdr.h>
+#include <mach/at91sam9_sdramc.h>
+
+#endif /* __AT91_RAMC_H__ */
index 1d4fe82..60478ea 100644 (file)
@@ -36,9 +36,11 @@ extern void __iomem *at91_shdwc_base;
 #define                        AT91_SHDW_WKMODE0_HIGH          1
 #define                        AT91_SHDW_WKMODE0_LOW           2
 #define                        AT91_SHDW_WKMODE0_ANYLEVEL      3
-#define                AT91_SHDW_CPTWK0        (0xf << 4)              /* Counter On Wake Up 0 */
+#define                AT91_SHDW_CPTWK0_MAX    0xf                     /* Maximum Counter On Wake Up 0 */
+#define                AT91_SHDW_CPTWK0        (AT91_SHDW_CPTWK0_MAX << 4) /* Counter On Wake Up 0 */
 #define                        AT91_SHDW_CPTWK0_(x)    ((x) << 4)
 #define                AT91_SHDW_RTTWKEN       (1   << 16)             /* Real Time Timer Wake-up Enable */
+#define                AT91_SHDW_RTCWKEN       (1   << 17)             /* Real Time Clock Wake-up Enable */
 
 #define AT91_SHDW_SR           0x08                    /* Shut Down Status Register */
 #define                AT91_SHDW_WAKEUP0       (1 <<  0)               /* Wake-up 0 Status */
index 8847173..969aac2 100644 (file)
 #ifndef AT91_ST_H
 #define AT91_ST_H
 
-#define        AT91_ST_CR              (AT91_ST + 0x00)        /* Control Register */
+#ifndef __ASSEMBLY__
+extern void __iomem *at91_st_base;
+
+#define at91_st_read(field) \
+       __raw_readl(at91_st_base + field)
+
+#define at91_st_write(field, value) \
+       __raw_writel(value, at91_st_base + field);
+#else
+.extern at91_st_base
+#endif
+
+#define        AT91_ST_CR              0x00                    /* Control Register */
 #define        AT91_ST_WDRST           (1 << 0)                /* Watchdog Timer Restart */
 
-#define        AT91_ST_PIMR            (AT91_ST + 0x04)        /* Period Interval Mode Register */
+#define        AT91_ST_PIMR            0x04                    /* Period Interval Mode Register */
 #define                AT91_ST_PIV             (0xffff <<  0)          /* Period Interval Value */
 
-#define        AT91_ST_WDMR            (AT91_ST + 0x08)        /* Watchdog Mode Register */
+#define        AT91_ST_WDMR            0x08                    /* Watchdog Mode Register */
 #define                AT91_ST_WDV             (0xffff <<  0)          /* Watchdog Counter Value */
 #define                AT91_ST_RSTEN           (1      << 16)          /* Reset Enable */
 #define                AT91_ST_EXTEN           (1      << 17)          /* External Signal Assertion Enable */
 
-#define        AT91_ST_RTMR            (AT91_ST + 0x0c)        /* Real-time Mode Register */
+#define        AT91_ST_RTMR            0x0c                    /* Real-time Mode Register */
 #define                AT91_ST_RTPRES          (0xffff <<  0)          /* Real-time Prescalar Value */
 
-#define        AT91_ST_SR              (AT91_ST + 0x10)        /* Status Register */
+#define        AT91_ST_SR              0x10                    /* Status Register */
 #define                AT91_ST_PITS            (1 << 0)                /* Period Interval Timer Status */
 #define                AT91_ST_WDOVF           (1 << 1)                /* Watchdog Overflow */
 #define                AT91_ST_RTTINC          (1 << 2)                /* Real-time Timer Increment */
 #define                AT91_ST_ALMS            (1 << 3)                /* Alarm Status */
 
-#define        AT91_ST_IER             (AT91_ST + 0x14)        /* Interrupt Enable Register */
-#define        AT91_ST_IDR             (AT91_ST + 0x18)        /* Interrupt Disable Register */
-#define        AT91_ST_IMR             (AT91_ST + 0x1c)        /* Interrupt Mask Register */
+#define        AT91_ST_IER             0x14                    /* Interrupt Enable Register */
+#define        AT91_ST_IDR             0x18                    /* Interrupt Disable Register */
+#define        AT91_ST_IMR             0x1c                    /* Interrupt Mask Register */
 
-#define        AT91_ST_RTAR            (AT91_ST + 0x20)        /* Real-time Alarm Register */
+#define        AT91_ST_RTAR            0x20                    /* Real-time Alarm Register */
 #define                AT91_ST_ALMV            (0xfffff << 0)          /* Alarm Value */
 
-#define        AT91_ST_CRTR            (AT91_ST + 0x24)        /* Current Real-time Register */
+#define        AT91_ST_CRTR            0x24                    /* Current Real-time Register */
 #define                AT91_ST_CRTV            (0xfffff << 0)          /* Current Real-Time Value */
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/at91cap9.h b/arch/arm/mach-at91/include/mach/at91cap9.h
deleted file mode 100644 (file)
index 61d9529..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91cap9.h
- *
- *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
- *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
- *  Copyright (C) 2007 Atmel Corporation.
- *
- * Common definitions.
- * Based on AT91CAP9 datasheet revision B (Preliminary).
- *
- * 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 AT91CAP9_H
-#define AT91CAP9_H
-
-/*
- * Peripheral identifiers/interrupts.
- */
-#define AT91CAP9_ID_PIOABCD    2       /* Parallel IO Controller A, B, C and D */
-#define AT91CAP9_ID_MPB0       3       /* MP Block Peripheral 0 */
-#define AT91CAP9_ID_MPB1       4       /* MP Block Peripheral 1 */
-#define AT91CAP9_ID_MPB2       5       /* MP Block Peripheral 2 */
-#define AT91CAP9_ID_MPB3       6       /* MP Block Peripheral 3 */
-#define AT91CAP9_ID_MPB4       7       /* MP Block Peripheral 4 */
-#define AT91CAP9_ID_US0                8       /* USART 0 */
-#define AT91CAP9_ID_US1                9       /* USART 1 */
-#define AT91CAP9_ID_US2                10      /* USART 2 */
-#define AT91CAP9_ID_MCI0       11      /* Multimedia Card Interface 0 */
-#define AT91CAP9_ID_MCI1       12      /* Multimedia Card Interface 1 */
-#define AT91CAP9_ID_CAN                13      /* CAN */
-#define AT91CAP9_ID_TWI                14      /* Two-Wire Interface */
-#define AT91CAP9_ID_SPI0       15      /* Serial Peripheral Interface 0 */
-#define AT91CAP9_ID_SPI1       16      /* Serial Peripheral Interface 0 */
-#define AT91CAP9_ID_SSC0       17      /* Serial Synchronous Controller 0 */
-#define AT91CAP9_ID_SSC1       18      /* Serial Synchronous Controller 1 */
-#define AT91CAP9_ID_AC97C      19      /* AC97 Controller */
-#define AT91CAP9_ID_TCB                20      /* Timer Counter 0, 1 and 2 */
-#define AT91CAP9_ID_PWMC       21      /* Pulse Width Modulation Controller */
-#define AT91CAP9_ID_EMAC       22      /* Ethernet */
-#define AT91CAP9_ID_AESTDES    23      /* Advanced Encryption Standard, Triple DES */
-#define AT91CAP9_ID_ADC                24      /* Analog-to-Digital Converter */
-#define AT91CAP9_ID_ISI                25      /* Image Sensor Interface */
-#define AT91CAP9_ID_LCDC       26      /* LCD Controller */
-#define AT91CAP9_ID_DMA                27      /* DMA Controller */
-#define AT91CAP9_ID_UDPHS      28      /* USB High Speed Device Port */
-#define AT91CAP9_ID_UHP                29      /* USB Host Port */
-#define AT91CAP9_ID_IRQ0       30      /* Advanced Interrupt Controller (IRQ0) */
-#define AT91CAP9_ID_IRQ1       31      /* Advanced Interrupt Controller (IRQ1) */
-
-/*
- * User Peripheral physical base addresses.
- */
-#define AT91CAP9_BASE_UDPHS            0xfff78000
-#define AT91CAP9_BASE_TCB0             0xfff7c000
-#define AT91CAP9_BASE_TC0              0xfff7c000
-#define AT91CAP9_BASE_TC1              0xfff7c040
-#define AT91CAP9_BASE_TC2              0xfff7c080
-#define AT91CAP9_BASE_MCI0             0xfff80000
-#define AT91CAP9_BASE_MCI1             0xfff84000
-#define AT91CAP9_BASE_TWI              0xfff88000
-#define AT91CAP9_BASE_US0              0xfff8c000
-#define AT91CAP9_BASE_US1              0xfff90000
-#define AT91CAP9_BASE_US2              0xfff94000
-#define AT91CAP9_BASE_SSC0             0xfff98000
-#define AT91CAP9_BASE_SSC1             0xfff9c000
-#define AT91CAP9_BASE_AC97C            0xfffa0000
-#define AT91CAP9_BASE_SPI0             0xfffa4000
-#define AT91CAP9_BASE_SPI1             0xfffa8000
-#define AT91CAP9_BASE_CAN              0xfffac000
-#define AT91CAP9_BASE_PWMC             0xfffb8000
-#define AT91CAP9_BASE_EMAC             0xfffbc000
-#define AT91CAP9_BASE_ADC              0xfffc0000
-#define AT91CAP9_BASE_ISI              0xfffc4000
-
-/*
- * System Peripherals (offset from AT91_BASE_SYS)
- */
-#define AT91_BCRAMC    (0xffffe400 - AT91_BASE_SYS)
-#define AT91_DDRSDRC0  (0xffffe600 - AT91_BASE_SYS)
-#define AT91_MATRIX    (0xffffea00 - AT91_BASE_SYS)
-#define AT91_PMC       (0xfffffc00 - AT91_BASE_SYS)
-#define AT91_GPBR      (cpu_is_at91cap9_revB() ?       \
-                       (0xfffffd50 - AT91_BASE_SYS) :  \
-                       (0xfffffd60 - AT91_BASE_SYS))
-
-#define AT91CAP9_BASE_ECC      0xffffe200
-#define AT91CAP9_BASE_DMA      0xffffec00
-#define AT91CAP9_BASE_SMC      0xffffe800
-#define AT91CAP9_BASE_DBGU     AT91_BASE_DBGU1
-#define AT91CAP9_BASE_PIOA     0xfffff200
-#define AT91CAP9_BASE_PIOB     0xfffff400
-#define AT91CAP9_BASE_PIOC     0xfffff600
-#define AT91CAP9_BASE_PIOD     0xfffff800
-#define AT91CAP9_BASE_RSTC     0xfffffd00
-#define AT91CAP9_BASE_SHDWC    0xfffffd10
-#define AT91CAP9_BASE_RTT      0xfffffd20
-#define AT91CAP9_BASE_PIT      0xfffffd30
-#define AT91CAP9_BASE_WDT      0xfffffd40
-
-#define AT91_USART0    AT91CAP9_BASE_US0
-#define AT91_USART1    AT91CAP9_BASE_US1
-#define AT91_USART2    AT91CAP9_BASE_US2
-
-
-/*
- * Internal Memory.
- */
-#define AT91CAP9_SRAM_BASE     0x00100000      /* Internal SRAM base address */
-#define AT91CAP9_SRAM_SIZE     (32 * SZ_1K)    /* Internal SRAM size (32Kb) */
-
-#define AT91CAP9_ROM_BASE      0x00400000      /* Internal ROM base address */
-#define AT91CAP9_ROM_SIZE      (32 * SZ_1K)    /* Internal ROM size (32Kb) */
-
-#define AT91CAP9_LCDC_BASE     0x00500000      /* LCD Controller */
-#define AT91CAP9_UDPHS_FIFO    0x00600000      /* USB High Speed Device Port */
-#define AT91CAP9_UHP_BASE      0x00700000      /* USB Host controller */
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/at91cap9_matrix.h b/arch/arm/mach-at91/include/mach/at91cap9_matrix.h
deleted file mode 100644 (file)
index 4b9d4af..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91cap9_matrix.h
- *
- *  Copyright (C) 2007 Stelian Pop <stelian.pop@leadtechdesign.com>
- *  Copyright (C) 2007 Lead Tech Design <www.leadtechdesign.com>
- *  Copyright (C) 2006 Atmel Corporation.
- *
- * Memory Controllers (MATRIX, EBI) - System peripherals registers.
- * Based on AT91CAP9 datasheet revision B (Preliminary).
- *
- * 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 AT91CAP9_MATRIX_H
-#define AT91CAP9_MATRIX_H
-
-#define AT91_MATRIX_MCFG0      (AT91_MATRIX + 0x00)    /* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1      (AT91_MATRIX + 0x04)    /* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2      (AT91_MATRIX + 0x08)    /* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3      (AT91_MATRIX + 0x0C)    /* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4      (AT91_MATRIX + 0x10)    /* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5      (AT91_MATRIX + 0x14)    /* Master Configuration Register 5 */
-#define AT91_MATRIX_MCFG6      (AT91_MATRIX + 0x18)    /* Master Configuration Register 6 */
-#define AT91_MATRIX_MCFG7      (AT91_MATRIX + 0x1C)    /* Master Configuration Register 7 */
-#define AT91_MATRIX_MCFG8      (AT91_MATRIX + 0x20)    /* Master Configuration Register 8 */
-#define AT91_MATRIX_MCFG9      (AT91_MATRIX + 0x24)    /* Master Configuration Register 9 */
-#define AT91_MATRIX_MCFG10     (AT91_MATRIX + 0x28)    /* Master Configuration Register 10 */
-#define AT91_MATRIX_MCFG11     (AT91_MATRIX + 0x2C)    /* Master Configuration Register 11 */
-#define                AT91_MATRIX_ULBT        (7 << 0)        /* Undefined Length Burst Type */
-#define                        AT91_MATRIX_ULBT_INFINITE       (0 << 0)
-#define                        AT91_MATRIX_ULBT_SINGLE         (1 << 0)
-#define                        AT91_MATRIX_ULBT_FOUR           (2 << 0)
-#define                        AT91_MATRIX_ULBT_EIGHT          (3 << 0)
-#define                        AT91_MATRIX_ULBT_SIXTEEN        (4 << 0)
-
-#define AT91_MATRIX_SCFG0      (AT91_MATRIX + 0x40)    /* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1      (AT91_MATRIX + 0x44)    /* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2      (AT91_MATRIX + 0x48)    /* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3      (AT91_MATRIX + 0x4C)    /* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4      (AT91_MATRIX + 0x50)    /* Slave Configuration Register 4 */
-#define AT91_MATRIX_SCFG5      (AT91_MATRIX + 0x54)    /* Slave Configuration Register 5 */
-#define AT91_MATRIX_SCFG6      (AT91_MATRIX + 0x58)    /* Slave Configuration Register 6 */
-#define AT91_MATRIX_SCFG7      (AT91_MATRIX + 0x5C)    /* Slave Configuration Register 7 */
-#define AT91_MATRIX_SCFG8      (AT91_MATRIX + 0x60)    /* Slave Configuration Register 8 */
-#define AT91_MATRIX_SCFG9      (AT91_MATRIX + 0x64)    /* Slave Configuration Register 9 */
-#define                AT91_MATRIX_SLOT_CYCLE          (0xff << 0)     /* Maximum Number of Allowed Cycles for a Burst */
-#define                AT91_MATRIX_DEFMSTR_TYPE        (3    << 16)    /* Default Master Type */
-#define                        AT91_MATRIX_DEFMSTR_TYPE_NONE   (0 << 16)
-#define                        AT91_MATRIX_DEFMSTR_TYPE_LAST   (1 << 16)
-#define                        AT91_MATRIX_DEFMSTR_TYPE_FIXED  (2 << 16)
-#define                AT91_MATRIX_FIXED_DEFMSTR       (0xf  << 18)    /* Fixed Index of Default Master */
-#define                AT91_MATRIX_ARBT                (3    << 24)    /* Arbitration Type */
-#define                        AT91_MATRIX_ARBT_ROUND_ROBIN    (0 << 24)
-#define                        AT91_MATRIX_ARBT_FIXED_PRIORITY (1 << 24)
-
-#define AT91_MATRIX_PRAS0      (AT91_MATRIX + 0x80)    /* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRBS0      (AT91_MATRIX + 0x84)    /* Priority Register B for Slave 0 */
-#define AT91_MATRIX_PRAS1      (AT91_MATRIX + 0x88)    /* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRBS1      (AT91_MATRIX + 0x8C)    /* Priority Register B for Slave 1 */
-#define AT91_MATRIX_PRAS2      (AT91_MATRIX + 0x90)    /* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRBS2      (AT91_MATRIX + 0x94)    /* Priority Register B for Slave 2 */
-#define AT91_MATRIX_PRAS3      (AT91_MATRIX + 0x98)    /* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRBS3      (AT91_MATRIX + 0x9C)    /* Priority Register B for Slave 3 */
-#define AT91_MATRIX_PRAS4      (AT91_MATRIX + 0xA0)    /* Priority Register A for Slave 4 */
-#define AT91_MATRIX_PRBS4      (AT91_MATRIX + 0xA4)    /* Priority Register B for Slave 4 */
-#define AT91_MATRIX_PRAS5      (AT91_MATRIX + 0xA8)    /* Priority Register A for Slave 5 */
-#define AT91_MATRIX_PRBS5      (AT91_MATRIX + 0xAC)    /* Priority Register B for Slave 5 */
-#define AT91_MATRIX_PRAS6      (AT91_MATRIX + 0xB0)    /* Priority Register A for Slave 6 */
-#define AT91_MATRIX_PRBS6      (AT91_MATRIX + 0xB4)    /* Priority Register B for Slave 6 */
-#define AT91_MATRIX_PRAS7      (AT91_MATRIX + 0xB8)    /* Priority Register A for Slave 7 */
-#define AT91_MATRIX_PRBS7      (AT91_MATRIX + 0xBC)    /* Priority Register B for Slave 7 */
-#define AT91_MATRIX_PRAS8      (AT91_MATRIX + 0xC0)    /* Priority Register A for Slave 8 */
-#define AT91_MATRIX_PRBS8      (AT91_MATRIX + 0xC4)    /* Priority Register B for Slave 8 */
-#define AT91_MATRIX_PRAS9      (AT91_MATRIX + 0xC8)    /* Priority Register A for Slave 9 */
-#define AT91_MATRIX_PRBS9      (AT91_MATRIX + 0xCC)    /* Priority Register B for Slave 9 */
-#define                AT91_MATRIX_M0PR                (3 << 0)        /* Master 0 Priority */
-#define                AT91_MATRIX_M1PR                (3 << 4)        /* Master 1 Priority */
-#define                AT91_MATRIX_M2PR                (3 << 8)        /* Master 2 Priority */
-#define                AT91_MATRIX_M3PR                (3 << 12)       /* Master 3 Priority */
-#define                AT91_MATRIX_M4PR                (3 << 16)       /* Master 4 Priority */
-#define                AT91_MATRIX_M5PR                (3 << 20)       /* Master 5 Priority */
-#define                AT91_MATRIX_M6PR                (3 << 24)       /* Master 6 Priority */
-#define                AT91_MATRIX_M7PR                (3 << 28)       /* Master 7 Priority */
-#define                AT91_MATRIX_M8PR                (3 << 0)        /* Master 8 Priority (in Register B) */
-#define                AT91_MATRIX_M9PR                (3 << 4)        /* Master 9 Priority (in Register B) */
-#define                AT91_MATRIX_M10PR               (3 << 8)        /* Master 10 Priority (in Register B) */
-#define                AT91_MATRIX_M11PR               (3 << 12)       /* Master 11 Priority (in Register B) */
-
-#define AT91_MATRIX_MRCR       (AT91_MATRIX + 0x100)   /* Master Remap Control Register */
-#define                AT91_MATRIX_RCB0                (1 << 0)        /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
-#define                AT91_MATRIX_RCB1                (1 << 1)        /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
-#define                AT91_MATRIX_RCB2                (1 << 2)
-#define                AT91_MATRIX_RCB3                (1 << 3)
-#define                AT91_MATRIX_RCB4                (1 << 4)
-#define                AT91_MATRIX_RCB5                (1 << 5)
-#define                AT91_MATRIX_RCB6                (1 << 6)
-#define                AT91_MATRIX_RCB7                (1 << 7)
-#define                AT91_MATRIX_RCB8                (1 << 8)
-#define                AT91_MATRIX_RCB9                (1 << 9)
-#define                AT91_MATRIX_RCB10               (1 << 10)
-#define                AT91_MATRIX_RCB11               (1 << 11)
-
-#define AT91_MPBS0_SFR         (AT91_MATRIX + 0x114)   /* MPBlock Slave 0 Special Function Register */
-#define AT91_MPBS1_SFR         (AT91_MATRIX + 0x11C)   /* MPBlock Slave 1 Special Function Register */
-
-#define AT91_MATRIX_UDPHS      (AT91_MATRIX + 0x118)   /* USBHS Special Function Register [AT91CAP9 only] */
-#define                AT91_MATRIX_SELECT_UDPHS        (0 << 31)       /* select High Speed UDP */
-#define                AT91_MATRIX_SELECT_UDP          (1 << 31)       /* select standard UDP */
-#define                AT91_MATRIX_UDPHS_BYPASS_LOCK   (1 << 30)       /* bypass lock bit */
-
-#define AT91_MATRIX_EBICSA     (AT91_MATRIX + 0x120)   /* EBI Chip Select Assignment Register */
-#define                AT91_MATRIX_EBI_CS1A            (1 << 1)        /* Chip Select 1 Assignment */
-#define                        AT91_MATRIX_EBI_CS1A_SMC                (0 << 1)
-#define                        AT91_MATRIX_EBI_CS1A_BCRAMC             (1 << 1)
-#define                AT91_MATRIX_EBI_CS3A            (1 << 3)        /* Chip Select 3 Assignment */
-#define                        AT91_MATRIX_EBI_CS3A_SMC                (0 << 3)
-#define                        AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA     (1 << 3)
-#define                AT91_MATRIX_EBI_CS4A            (1 << 4)        /* Chip Select 4 Assignment */
-#define                        AT91_MATRIX_EBI_CS4A_SMC                (0 << 4)
-#define                        AT91_MATRIX_EBI_CS4A_SMC_CF1            (1 << 4)
-#define                AT91_MATRIX_EBI_CS5A            (1 << 5)        /* Chip Select 5 Assignment */
-#define                        AT91_MATRIX_EBI_CS5A_SMC                (0 << 5)
-#define                        AT91_MATRIX_EBI_CS5A_SMC_CF2            (1 << 5)
-#define                AT91_MATRIX_EBI_DBPUC           (1 << 8)        /* Data Bus Pull-up Configuration */
-#define                AT91_MATRIX_EBI_DQSPDC          (1 << 9)        /* Data Qualifier Strobe Pull-Down Configuration */
-#define                AT91_MATRIX_EBI_VDDIOMSEL       (1 << 16)       /* Memory voltage selection */
-#define                        AT91_MATRIX_EBI_VDDIOMSEL_1_8V          (0 << 16)
-#define                        AT91_MATRIX_EBI_VDDIOMSEL_3_3V          (1 << 16)
-
-#define AT91_MPBS2_SFR         (AT91_MATRIX + 0x12C)   /* MPBlock Slave 2 Special Function Register */
-#define AT91_MPBS3_SFR         (AT91_MATRIX + 0x130)   /* MPBlock Slave 3 Special Function Register */
-#define AT91_APB_SFR           (AT91_MATRIX + 0x134)   /* APB Bridge Special Function Register */
-
-#endif
index bacb511..603e6aa 100644 (file)
 
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
-#define AT91_PMC       (0xfffffc00 - AT91_BASE_SYS)    /* Power Management Controller */
-#define AT91_ST                (0xfffffd00 - AT91_BASE_SYS)    /* System Timer */
-#define AT91_MC                (0xffffff00 - AT91_BASE_SYS)    /* Memory Controllers */
-
 #define AT91RM9200_BASE_DBGU   AT91_BASE_DBGU0 /* Debug Unit */
 #define AT91RM9200_BASE_PIOA   0xfffff400      /* PIO Controller A */
 #define AT91RM9200_BASE_PIOB   0xfffff600      /* PIO Controller B */
 #define AT91RM9200_BASE_PIOC   0xfffff800      /* PIO Controller C */
 #define AT91RM9200_BASE_PIOD   0xfffffa00      /* PIO Controller D */
+#define AT91RM9200_BASE_ST     0xfffffd00      /* System Timer */
 #define AT91RM9200_BASE_RTC    0xfffffe00      /* Real-Time Clock */
+#define AT91RM9200_BASE_MC     0xffffff00      /* Memory Controllers */
 
 #define AT91_USART0    AT91RM9200_BASE_US0
 #define AT91_USART1    AT91RM9200_BASE_US1
 #define AT91_USART2    AT91RM9200_BASE_US2
 #define AT91_USART3    AT91RM9200_BASE_US3
 
-#define AT91_MATRIX    0       /* not supported */
-
 /*
  * Internal Memory.
  */
index d34e4ed..aeaadfb 100644 (file)
 #define AT91RM9200_MC_H
 
 /* Memory Controller */
-#define AT91_MC_RCR            (AT91_MC + 0x00)        /* MC Remap Control Register */
+#define AT91_MC_RCR            0x00                    /* MC Remap Control Register */
 #define                AT91_MC_RCB             (1 <<  0)               /* Remap Command Bit */
 
-#define AT91_MC_ASR            (AT91_MC + 0x04)        /* MC Abort Status Register */
+#define AT91_MC_ASR            0x04                    /* MC Abort Status Register */
 #define                AT91_MC_UNADD           (1 <<  0)               /* Undefined Address Abort Status */
 #define                AT91_MC_MISADD          (1 <<  1)               /* Misaligned Address Abort Status */
 #define                AT91_MC_ABTSZ           (3 <<  8)               /* Abort Size Status */
 #define                AT91_MC_SVMST2          (1 << 26)               /* Saved UHP Abort Source */
 #define                AT91_MC_SVMST3          (1 << 27)               /* Saved EMAC Abort Source */
 
-#define AT91_MC_AASR           (AT91_MC + 0x08)        /* MC Abort Address Status Register */
+#define AT91_MC_AASR           0x08                    /* MC Abort Address Status Register */
 
-#define AT91_MC_MPR            (AT91_MC + 0x0c)        /* MC Master Priority Register */
+#define AT91_MC_MPR            0x0c                    /* MC Master Priority Register */
 #define                AT91_MPR_MSTP0          (7 <<  0)               /* ARM920T Priority */
 #define                AT91_MPR_MSTP1          (7 <<  4)               /* PDC Priority */
 #define                AT91_MPR_MSTP2          (7 <<  8)               /* UHP Priority */
 #define                AT91_MPR_MSTP3          (7 << 12)               /* EMAC Priority */
 
 /* External Bus Interface (EBI) registers */
-#define AT91_EBI_CSA           (AT91_MC + 0x60)        /* Chip Select Assignment Register */
+#define AT91_EBI_CSA           0x60                    /* Chip Select Assignment Register */
 #define                AT91_EBI_CS0A           (1 << 0)                /* Chip Select 0 Assignment */
 #define                        AT91_EBI_CS0A_SMC               (0 << 0)
 #define                        AT91_EBI_CS0A_BFC               (1 << 0)
@@ -66,7 +66,7 @@
 #define                AT91_EBI_DBPUC          (1 << 0)                /* Data Bus Pull-Up Configuration */
 
 /* Static Memory Controller (SMC) registers */
-#define        AT91_SMC_CSR(n)         (AT91_MC + 0x70 + ((n) * 4))/* SMC Chip Select Register */
+#define        AT91_SMC_CSR(n)         (0x70 + ((n) * 4))      /* SMC Chip Select Register */
 #define                AT91_SMC_NWS            (0x7f <<  0)            /* Number of Wait States */
 #define                        AT91_SMC_NWS_(x)        ((x) << 0)
 #define                AT91_SMC_WSEN           (1    <<  7)            /* Wait State Enable */
 #define                AT91_SMC_RWHOLD         (7 << 28)               /* Read & Write Signal Hold Time */
 #define                        AT91_SMC_RWHOLD_(x)     ((x) << 28)
 
-/* SDRAM Controller registers */
-#define AT91_SDRAMC_MR         (AT91_MC + 0x90)        /* Mode Register */
-#define                AT91_SDRAMC_MODE        (0xf << 0)              /* Command Mode */
-#define                        AT91_SDRAMC_MODE_NORMAL         (0 << 0)
-#define                        AT91_SDRAMC_MODE_NOP            (1 << 0)
-#define                        AT91_SDRAMC_MODE_PRECHARGE      (2 << 0)
-#define                        AT91_SDRAMC_MODE_LMR            (3 << 0)
-#define                        AT91_SDRAMC_MODE_REFRESH        (4 << 0)
-#define                AT91_SDRAMC_DBW         (1   << 4)              /* Data Bus Width */
-#define                        AT91_SDRAMC_DBW_32      (0 << 4)
-#define                        AT91_SDRAMC_DBW_16      (1 << 4)
-
-#define AT91_SDRAMC_TR         (AT91_MC + 0x94)        /* Refresh Timer Register */
-#define                AT91_SDRAMC_COUNT       (0xfff << 0)            /* Refresh Timer Count */
-
-#define AT91_SDRAMC_CR         (AT91_MC + 0x98)        /* Configuration Register */
-#define                AT91_SDRAMC_NC          (3   <<  0)             /* Number of Column Bits */
-#define                        AT91_SDRAMC_NC_8        (0 << 0)
-#define                        AT91_SDRAMC_NC_9        (1 << 0)
-#define                        AT91_SDRAMC_NC_10       (2 << 0)
-#define                        AT91_SDRAMC_NC_11       (3 << 0)
-#define                AT91_SDRAMC_NR          (3   <<  2)             /* Number of Row Bits */
-#define                        AT91_SDRAMC_NR_11       (0 << 2)
-#define                        AT91_SDRAMC_NR_12       (1 << 2)
-#define                        AT91_SDRAMC_NR_13       (2 << 2)
-#define                AT91_SDRAMC_NB          (1   <<  4)             /* Number of Banks */
-#define                        AT91_SDRAMC_NB_2        (0 << 4)
-#define                        AT91_SDRAMC_NB_4        (1 << 4)
-#define                AT91_SDRAMC_CAS         (3   <<  5)             /* CAS Latency */
-#define                        AT91_SDRAMC_CAS_2       (2 << 5)
-#define                AT91_SDRAMC_TWR         (0xf <<  7)             /* Write Recovery Delay */
-#define                AT91_SDRAMC_TRC         (0xf << 11)             /* Row Cycle Delay */
-#define                AT91_SDRAMC_TRP         (0xf << 15)             /* Row Precharge Delay */
-#define                AT91_SDRAMC_TRCD        (0xf << 19)             /* Row to Column Delay */
-#define                AT91_SDRAMC_TRAS        (0xf << 23)             /* Active to Precharge Delay */
-#define                AT91_SDRAMC_TXSR        (0xf << 27)             /* Exit Self Refresh to Active Delay */
-
-#define AT91_SDRAMC_SRR                (AT91_MC + 0x9c)        /* Self Refresh Register */
-#define AT91_SDRAMC_LPR                (AT91_MC + 0xa0)        /* Low Power Register */
-#define AT91_SDRAMC_IER                (AT91_MC + 0xa4)        /* Interrupt Enable Register */
-#define AT91_SDRAMC_IDR                (AT91_MC + 0xa8)        /* Interrupt Disable Register */
-#define AT91_SDRAMC_IMR                (AT91_MC + 0xac)        /* Interrupt Mask Register */
-#define AT91_SDRAMC_ISR                (AT91_MC + 0xb0)        /* Interrupt Status Register */
-
 /* Burst Flash Controller register */
-#define AT91_BFC_MR            (AT91_MC + 0xc0)        /* Mode Register */
+#define AT91_BFC_MR            0xc0                    /* Mode Register */
 #define                AT91_BFC_BFCOM          (3   <<  0)             /* Burst Flash Controller Operating Mode */
 #define                        AT91_BFC_BFCOM_DISABLED (0 << 0)
 #define                        AT91_BFC_BFCOM_ASYNC    (1 << 0)
diff --git a/arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h b/arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h
new file mode 100644 (file)
index 0000000..aa047f4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Memory Controllers (SDRAMC only) - System peripherals registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * 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 AT91RM9200_SDRAMC_H
+#define AT91RM9200_SDRAMC_H
+
+/* SDRAM Controller registers */
+#define AT91RM9200_SDRAMC_MR           0x90                    /* Mode Register */
+#define                AT91RM9200_SDRAMC_MODE  (0xf << 0)              /* Command Mode */
+#define                        AT91RM9200_SDRAMC_MODE_NORMAL           (0 << 0)
+#define                        AT91RM9200_SDRAMC_MODE_NOP              (1 << 0)
+#define                        AT91RM9200_SDRAMC_MODE_PRECHARGE        (2 << 0)
+#define                        AT91RM9200_SDRAMC_MODE_LMR              (3 << 0)
+#define                        AT91RM9200_SDRAMC_MODE_REFRESH  (4 << 0)
+#define                AT91RM9200_SDRAMC_DBW           (1   << 4)              /* Data Bus Width */
+#define                        AT91RM9200_SDRAMC_DBW_32        (0 << 4)
+#define                        AT91RM9200_SDRAMC_DBW_16        (1 << 4)
+
+#define AT91RM9200_SDRAMC_TR           0x94                    /* Refresh Timer Register */
+#define                AT91RM9200_SDRAMC_COUNT (0xfff << 0)            /* Refresh Timer Count */
+
+#define AT91RM9200_SDRAMC_CR           0x98                    /* Configuration Register */
+#define                AT91RM9200_SDRAMC_NC            (3   <<  0)             /* Number of Column Bits */
+#define                        AT91RM9200_SDRAMC_NC_8  (0 << 0)
+#define                        AT91RM9200_SDRAMC_NC_9  (1 << 0)
+#define                        AT91RM9200_SDRAMC_NC_10 (2 << 0)
+#define                        AT91RM9200_SDRAMC_NC_11 (3 << 0)
+#define                AT91RM9200_SDRAMC_NR            (3   <<  2)             /* Number of Row Bits */
+#define                        AT91RM9200_SDRAMC_NR_11 (0 << 2)
+#define                        AT91RM9200_SDRAMC_NR_12 (1 << 2)
+#define                        AT91RM9200_SDRAMC_NR_13 (2 << 2)
+#define                AT91RM9200_SDRAMC_NB            (1   <<  4)             /* Number of Banks */
+#define                        AT91RM9200_SDRAMC_NB_2  (0 << 4)
+#define                        AT91RM9200_SDRAMC_NB_4  (1 << 4)
+#define                AT91RM9200_SDRAMC_CAS           (3   <<  5)             /* CAS Latency */
+#define                        AT91RM9200_SDRAMC_CAS_2 (2 << 5)
+#define                AT91RM9200_SDRAMC_TWR           (0xf <<  7)             /* Write Recovery Delay */
+#define                AT91RM9200_SDRAMC_TRC           (0xf << 11)             /* Row Cycle Delay */
+#define                AT91RM9200_SDRAMC_TRP           (0xf << 15)             /* Row Precharge Delay */
+#define                AT91RM9200_SDRAMC_TRCD  (0xf << 19)             /* Row to Column Delay */
+#define                AT91RM9200_SDRAMC_TRAS  (0xf << 23)             /* Active to Precharge Delay */
+#define                AT91RM9200_SDRAMC_TXSR  (0xf << 27)             /* Exit Self Refresh to Active Delay */
+
+#define AT91RM9200_SDRAMC_SRR          0x9c                    /* Self Refresh Register */
+#define AT91RM9200_SDRAMC_LPR          0xa0                    /* Low Power Register */
+#define AT91RM9200_SDRAMC_IER          0xa4                    /* Interrupt Enable Register */
+#define AT91RM9200_SDRAMC_IDR          0xa8                    /* Interrupt Disable Register */
+#define AT91RM9200_SDRAMC_IMR          0xac                    /* Interrupt Mask Register */
+#define AT91RM9200_SDRAMC_ISR          0xb0                    /* Interrupt Status Register */
+
+#endif
index fa5ca27..08ae9af 100644 (file)
 #define AT91SAM9260_BASE_ADC           0xfffe0000
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
-#define AT91_SDRAMC0   (0xffffea00 - AT91_BASE_SYS)
-#define AT91_MATRIX    (0xffffee00 - AT91_BASE_SYS)
-#define AT91_PMC       (0xfffffc00 - AT91_BASE_SYS)
-#define AT91_GPBR      (0xfffffd50 - AT91_BASE_SYS)
-
 #define AT91SAM9260_BASE_ECC   0xffffe800
+#define AT91SAM9260_BASE_SDRAMC        0xffffea00
 #define AT91SAM9260_BASE_SMC   0xffffec00
+#define AT91SAM9260_BASE_MATRIX        0xffffee00
 #define AT91SAM9260_BASE_DBGU  AT91_BASE_DBGU0
 #define AT91SAM9260_BASE_PIOA  0xfffff400
 #define AT91SAM9260_BASE_PIOB  0xfffff600
@@ -96,6 +93,7 @@
 #define AT91SAM9260_BASE_RTT   0xfffffd20
 #define AT91SAM9260_BASE_PIT   0xfffffd30
 #define AT91SAM9260_BASE_WDT   0xfffffd40
+#define AT91SAM9260_BASE_GPBR  0xfffffd50
 
 #define AT91_USART0    AT91SAM9260_BASE_US0
 #define AT91_USART1    AT91SAM9260_BASE_US1
 #define AT91SAM9260_SRAM0_SIZE SZ_4K           /* Internal SRAM 0 size (4Kb) */
 #define AT91SAM9260_SRAM1_BASE 0x00300000      /* Internal SRAM 1 base address */
 #define AT91SAM9260_SRAM1_SIZE SZ_4K           /* Internal SRAM 1 size (4Kb) */
+#define AT91SAM9260_SRAM_BASE  0x002FF000      /* Internal SRAM base address */
+#define AT91SAM9260_SRAM_SIZE  SZ_8K           /* Internal SRAM size (8Kb) */
 
 #define AT91SAM9260_UHP_BASE   0x00500000      /* USB Host controller */
 
 #define AT91SAM9G20_SRAM0_SIZE SZ_16K          /* Internal SRAM 0 size (16Kb) */
 #define AT91SAM9G20_SRAM1_BASE 0x00300000      /* Internal SRAM 1 base address */
 #define AT91SAM9G20_SRAM1_SIZE SZ_16K          /* Internal SRAM 1 size (16Kb) */
+#define AT91SAM9G20_SRAM_BASE  0x002FC000      /* Internal SRAM base address */
+#define AT91SAM9G20_SRAM_SIZE  SZ_32K          /* Internal SRAM size (32Kb) */
 
 #define AT91SAM9G20_UHP_BASE   0x00500000      /* USB Host controller */
 
index 020f02e..f459df4 100644 (file)
 #ifndef AT91SAM9260_MATRIX_H
 #define AT91SAM9260_MATRIX_H
 
-#define AT91_MATRIX_MCFG0      (AT91_MATRIX + 0x00)    /* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1      (AT91_MATRIX + 0x04)    /* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2      (AT91_MATRIX + 0x08)    /* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3      (AT91_MATRIX + 0x0C)    /* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4      (AT91_MATRIX + 0x10)    /* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5      (AT91_MATRIX + 0x14)    /* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG0      0x00                    /* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1      0x04                    /* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2      0x08                    /* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3      0x0C                    /* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4      0x10                    /* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5      0x14                    /* Master Configuration Register 5 */
 #define                AT91_MATRIX_ULBT                (7 << 0)        /* Undefined Length Burst Type */
 #define                        AT91_MATRIX_ULBT_INFINITE       (0 << 0)
 #define                        AT91_MATRIX_ULBT_SINGLE         (1 << 0)
 #define                        AT91_MATRIX_ULBT_EIGHT          (3 << 0)
 #define                        AT91_MATRIX_ULBT_SIXTEEN        (4 << 0)
 
-#define AT91_MATRIX_SCFG0      (AT91_MATRIX + 0x40)    /* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1      (AT91_MATRIX + 0x44)    /* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2      (AT91_MATRIX + 0x48)    /* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3      (AT91_MATRIX + 0x4C)    /* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4      (AT91_MATRIX + 0x50)    /* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG0      0x40                    /* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1      0x44                    /* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2      0x48                    /* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3      0x4C                    /* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4      0x50                    /* Slave Configuration Register 4 */
 #define                AT91_MATRIX_SLOT_CYCLE          (0xff <<  0)    /* Maximum Number of Allowed Cycles for a Burst */
 #define                AT91_MATRIX_DEFMSTR_TYPE        (3    << 16)    /* Default Master Type */
 #define                        AT91_MATRIX_DEFMSTR_TYPE_NONE   (0 << 16)
 #define                        AT91_MATRIX_ARBT_ROUND_ROBIN    (0 << 24)
 #define                        AT91_MATRIX_ARBT_FIXED_PRIORITY (1 << 24)
 
-#define AT91_MATRIX_PRAS0      (AT91_MATRIX + 0x80)    /* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRAS1      (AT91_MATRIX + 0x88)    /* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRAS2      (AT91_MATRIX + 0x90)    /* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRAS3      (AT91_MATRIX + 0x98)    /* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRAS4      (AT91_MATRIX + 0xA0)    /* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRAS0      0x80                    /* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRAS1      0x88                    /* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRAS2      0x90                    /* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRAS3      0x98                    /* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRAS4      0xA0                    /* Priority Register A for Slave 4 */
 #define                AT91_MATRIX_M0PR                (3 << 0)        /* Master 0 Priority */
 #define                AT91_MATRIX_M1PR                (3 << 4)        /* Master 1 Priority */
 #define                AT91_MATRIX_M2PR                (3 << 8)        /* Master 2 Priority */
 #define                AT91_MATRIX_M4PR                (3 << 16)       /* Master 4 Priority */
 #define                AT91_MATRIX_M5PR                (3 << 20)       /* Master 5 Priority */
 
-#define AT91_MATRIX_MRCR       (AT91_MATRIX + 0x100)   /* Master Remap Control Register */
+#define AT91_MATRIX_MRCR       0x100                   /* Master Remap Control Register */
 #define                AT91_MATRIX_RCB0                (1 << 0)        /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
 #define                AT91_MATRIX_RCB1                (1 << 1)        /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
 
-#define AT91_MATRIX_EBICSA     (AT91_MATRIX + 0x11C)   /* EBI Chip Select Assignment Register */
+#define AT91_MATRIX_EBICSA     0x11C                   /* EBI Chip Select Assignment Register */
 #define                AT91_MATRIX_CS1A                (1 << 1)        /* Chip Select 1 Assignment */
 #define                        AT91_MATRIX_CS1A_SMC            (0 << 1)
 #define                        AT91_MATRIX_CS1A_SDRAMC         (1 << 1)
index 7cde2d3..44fbdc1 100644 (file)
 
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
-#define AT91_SDRAMC0   (0xffffea00 - AT91_BASE_SYS)
-#define AT91_MATRIX    (0xffffee00 - AT91_BASE_SYS)
-#define AT91_PMC       (0xfffffc00 - AT91_BASE_SYS)
-#define AT91_GPBR      (0xfffffd50 - AT91_BASE_SYS)
-
 #define AT91SAM9261_BASE_SMC   0xffffec00
+#define AT91SAM9261_BASE_MATRIX        0xffffee00
+#define AT91SAM9261_BASE_SDRAMC        0xffffea00
 #define AT91SAM9261_BASE_DBGU  AT91_BASE_DBGU0
 #define AT91SAM9261_BASE_PIOA  0xfffff400
 #define AT91SAM9261_BASE_PIOB  0xfffff600
@@ -80,6 +77,7 @@
 #define AT91SAM9261_BASE_RTT   0xfffffd20
 #define AT91SAM9261_BASE_PIT   0xfffffd30
 #define AT91SAM9261_BASE_WDT   0xfffffd40
+#define AT91SAM9261_BASE_GPBR  0xfffffd50
 
 #define AT91_USART0    AT91SAM9261_BASE_US0
 #define AT91_USART1    AT91SAM9261_BASE_US1
index 69c6501..a50cdf8 100644 (file)
 #ifndef AT91SAM9261_MATRIX_H
 #define AT91SAM9261_MATRIX_H
 
-#define AT91_MATRIX_MCFG       (AT91_MATRIX + 0x00)    /* Master Configuration Register */
+#define AT91_MATRIX_MCFG       0x00                    /* Master Configuration Register */
 #define                AT91_MATRIX_RCB0        (1 << 0)                /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
 #define                AT91_MATRIX_RCB1        (1 << 1)                /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
 
-#define AT91_MATRIX_SCFG0      (AT91_MATRIX + 0x04)    /* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1      (AT91_MATRIX + 0x08)    /* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2      (AT91_MATRIX + 0x0C)    /* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3      (AT91_MATRIX + 0x10)    /* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4      (AT91_MATRIX + 0x14)    /* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG0      0x04                    /* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1      0x08                    /* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2      0x0C                    /* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3      0x10                    /* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4      0x14                    /* Slave Configuration Register 4 */
 #define                AT91_MATRIX_SLOT_CYCLE          (0xff << 0)     /* Maximum Number of Allowed Cycles for a Burst */
 #define                AT91_MATRIX_DEFMSTR_TYPE        (3    << 16)    /* Default Master Type */
 #define                        AT91_MATRIX_DEFMSTR_TYPE_NONE   (0 << 16)
@@ -31,7 +31,7 @@
 #define                        AT91_MATRIX_DEFMSTR_TYPE_FIXED  (2 << 16)
 #define                AT91_MATRIX_FIXED_DEFMSTR       (7    << 18)    /* Fixed Index of Default Master */
 
-#define AT91_MATRIX_TCR                (AT91_MATRIX + 0x24)    /* TCM Configuration Register */
+#define AT91_MATRIX_TCR                0x24                    /* TCM Configuration Register */
 #define                AT91_MATRIX_ITCM_SIZE           (0xf << 0)      /* Size of ITCM enabled memory block */
 #define                        AT91_MATRIX_ITCM_0              (0 << 0)
 #define                        AT91_MATRIX_ITCM_16             (5 << 0)
@@ -43,7 +43,7 @@
 #define                        AT91_MATRIX_DTCM_32             (6 << 4)
 #define                        AT91_MATRIX_DTCM_64             (7 << 4)
 
-#define AT91_MATRIX_EBICSA     (AT91_MATRIX + 0x30)    /* EBI Chip Select Assignment Register */
+#define AT91_MATRIX_EBICSA     0x30                    /* EBI Chip Select Assignment Register */
 #define                AT91_MATRIX_CS1A                (1 << 1)        /* Chip Select 1 Assignment */
 #define                        AT91_MATRIX_CS1A_SMC            (0 << 1)
 #define                        AT91_MATRIX_CS1A_SDRAMC         (1 << 1)
@@ -58,7 +58,7 @@
 #define                        AT91_MATRIX_CS5A_SMC_CF2        (1 << 5)
 #define                AT91_MATRIX_DBPUC               (1 << 8)        /* Data Bus Pull-up Configuration */
 
-#define AT91_MATRIX_USBPUCR    (AT91_MATRIX + 0x34)    /* USB Pad Pull-Up Control Register */
+#define AT91_MATRIX_USBPUCR    0x34                    /* USB Pad Pull-Up Control Register */
 #define                AT91_MATRIX_USBPUCR_PUON        (1 << 30)       /* USB Device PAD Pull-up Enable */
 
 #endif
index 5949abd..d96cbb2 100644 (file)
 #define AT91SAM9263_BASE_2DGE          0xfffc8000
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
-#define AT91_SDRAMC0   (0xffffe200 - AT91_BASE_SYS)
-#define AT91_SDRAMC1   (0xffffe800 - AT91_BASE_SYS)
-#define AT91_MATRIX    (0xffffec00 - AT91_BASE_SYS)
-#define AT91_PMC       (0xfffffc00 - AT91_BASE_SYS)
-#define AT91_GPBR      (0xfffffd60 - AT91_BASE_SYS)
-
 #define AT91SAM9263_BASE_ECC0  0xffffe000
+#define AT91SAM9263_BASE_SDRAMC0 0xffffe200
 #define AT91SAM9263_BASE_SMC0  0xffffe400
 #define AT91SAM9263_BASE_ECC1  0xffffe600
+#define AT91SAM9263_BASE_SDRAMC1 0xffffe800
 #define AT91SAM9263_BASE_SMC1  0xffffea00
+#define AT91SAM9263_BASE_MATRIX        0xffffec00
 #define AT91SAM9263_BASE_DBGU  AT91_BASE_DBGU1
 #define AT91SAM9263_BASE_PIOA  0xfffff200
 #define AT91SAM9263_BASE_PIOB  0xfffff400
@@ -96,6 +93,7 @@
 #define AT91SAM9263_BASE_PIT   0xfffffd30
 #define AT91SAM9263_BASE_WDT   0xfffffd40
 #define AT91SAM9263_BASE_RTT1  0xfffffd50
+#define AT91SAM9263_BASE_GPBR  0xfffffd60
 
 #define AT91_USART0    AT91SAM9263_BASE_US0
 #define AT91_USART1    AT91SAM9263_BASE_US1
index 9b3efd3..ebb5fdb 100644 (file)
 #ifndef AT91SAM9263_MATRIX_H
 #define AT91SAM9263_MATRIX_H
 
-#define AT91_MATRIX_MCFG0      (AT91_MATRIX + 0x00)    /* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1      (AT91_MATRIX + 0x04)    /* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2      (AT91_MATRIX + 0x08)    /* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3      (AT91_MATRIX + 0x0C)    /* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4      (AT91_MATRIX + 0x10)    /* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5      (AT91_MATRIX + 0x14)    /* Master Configuration Register 5 */
-#define AT91_MATRIX_MCFG6      (AT91_MATRIX + 0x18)    /* Master Configuration Register 6 */
-#define AT91_MATRIX_MCFG7      (AT91_MATRIX + 0x1C)    /* Master Configuration Register 7 */
-#define AT91_MATRIX_MCFG8      (AT91_MATRIX + 0x20)    /* Master Configuration Register 8 */
+#define AT91_MATRIX_MCFG0      0x00                    /* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1      0x04                    /* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2      0x08                    /* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3      0x0C                    /* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4      0x10                    /* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5      0x14                    /* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG6      0x18                    /* Master Configuration Register 6 */
+#define AT91_MATRIX_MCFG7      0x1C                    /* Master Configuration Register 7 */
+#define AT91_MATRIX_MCFG8      0x20                    /* Master Configuration Register 8 */
 #define                AT91_MATRIX_ULBT        (7 << 0)        /* Undefined Length Burst Type */
 #define                        AT91_MATRIX_ULBT_INFINITE       (0 << 0)
 #define                        AT91_MATRIX_ULBT_SINGLE         (1 << 0)
 #define                        AT91_MATRIX_ULBT_EIGHT          (3 << 0)
 #define                        AT91_MATRIX_ULBT_SIXTEEN        (4 << 0)
 
-#define AT91_MATRIX_SCFG0      (AT91_MATRIX + 0x40)    /* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1      (AT91_MATRIX + 0x44)    /* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2      (AT91_MATRIX + 0x48)    /* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3      (AT91_MATRIX + 0x4C)    /* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4      (AT91_MATRIX + 0x50)    /* Slave Configuration Register 4 */
-#define AT91_MATRIX_SCFG5      (AT91_MATRIX + 0x54)    /* Slave Configuration Register 5 */
-#define AT91_MATRIX_SCFG6      (AT91_MATRIX + 0x58)    /* Slave Configuration Register 6 */
-#define AT91_MATRIX_SCFG7      (AT91_MATRIX + 0x5C)    /* Slave Configuration Register 7 */
+#define AT91_MATRIX_SCFG0      0x40                    /* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1      0x44                    /* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2      0x48                    /* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3      0x4C                    /* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4      0x50                    /* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG5      0x54                    /* Slave Configuration Register 5 */
+#define AT91_MATRIX_SCFG6      0x58                    /* Slave Configuration Register 6 */
+#define AT91_MATRIX_SCFG7      0x5C                    /* Slave Configuration Register 7 */
 #define                AT91_MATRIX_SLOT_CYCLE          (0xff << 0)     /* Maximum Number of Allowed Cycles for a Burst */
 #define                AT91_MATRIX_DEFMSTR_TYPE        (3    << 16)    /* Default Master Type */
 #define                        AT91_MATRIX_DEFMSTR_TYPE_NONE   (0 << 16)
 #define                        AT91_MATRIX_ARBT_ROUND_ROBIN    (0 << 24)
 #define                        AT91_MATRIX_ARBT_FIXED_PRIORITY (1 << 24)
 
-#define AT91_MATRIX_PRAS0      (AT91_MATRIX + 0x80)    /* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRBS0      (AT91_MATRIX + 0x84)    /* Priority Register B for Slave 0 */
-#define AT91_MATRIX_PRAS1      (AT91_MATRIX + 0x88)    /* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRBS1      (AT91_MATRIX + 0x8C)    /* Priority Register B for Slave 1 */
-#define AT91_MATRIX_PRAS2      (AT91_MATRIX + 0x90)    /* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRBS2      (AT91_MATRIX + 0x94)    /* Priority Register B for Slave 2 */
-#define AT91_MATRIX_PRAS3      (AT91_MATRIX + 0x98)    /* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRBS3      (AT91_MATRIX + 0x9C)    /* Priority Register B for Slave 3 */
-#define AT91_MATRIX_PRAS4      (AT91_MATRIX + 0xA0)    /* Priority Register A for Slave 4 */
-#define AT91_MATRIX_PRBS4      (AT91_MATRIX + 0xA4)    /* Priority Register B for Slave 4 */
-#define AT91_MATRIX_PRAS5      (AT91_MATRIX + 0xA8)    /* Priority Register A for Slave 5 */
-#define AT91_MATRIX_PRBS5      (AT91_MATRIX + 0xAC)    /* Priority Register B for Slave 5 */
-#define AT91_MATRIX_PRAS6      (AT91_MATRIX + 0xB0)    /* Priority Register A for Slave 6 */
-#define AT91_MATRIX_PRBS6      (AT91_MATRIX + 0xB4)    /* Priority Register B for Slave 6 */
-#define AT91_MATRIX_PRAS7      (AT91_MATRIX + 0xB8)    /* Priority Register A for Slave 7 */
-#define AT91_MATRIX_PRBS7      (AT91_MATRIX + 0xBC)    /* Priority Register B for Slave 7 */
+#define AT91_MATRIX_PRAS0      0x80                    /* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRBS0      0x84                    /* Priority Register B for Slave 0 */
+#define AT91_MATRIX_PRAS1      0x88                    /* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRBS1      0x8C                    /* Priority Register B for Slave 1 */
+#define AT91_MATRIX_PRAS2      0x90                    /* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRBS2      0x94                    /* Priority Register B for Slave 2 */
+#define AT91_MATRIX_PRAS3      0x98                    /* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRBS3      0x9C                    /* Priority Register B for Slave 3 */
+#define AT91_MATRIX_PRAS4      0xA0                    /* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRBS4      0xA4                    /* Priority Register B for Slave 4 */
+#define AT91_MATRIX_PRAS5      0xA8                    /* Priority Register A for Slave 5 */
+#define AT91_MATRIX_PRBS5      0xAC                    /* Priority Register B for Slave 5 */
+#define AT91_MATRIX_PRAS6      0xB0                    /* Priority Register A for Slave 6 */
+#define AT91_MATRIX_PRBS6      0xB4                    /* Priority Register B for Slave 6 */
+#define AT91_MATRIX_PRAS7      0xB8                    /* Priority Register A for Slave 7 */
+#define AT91_MATRIX_PRBS7      0xBC                    /* Priority Register B for Slave 7 */
 #define                AT91_MATRIX_M0PR                (3 << 0)        /* Master 0 Priority */
 #define                AT91_MATRIX_M1PR                (3 << 4)        /* Master 1 Priority */
 #define                AT91_MATRIX_M2PR                (3 << 8)        /* Master 2 Priority */
@@ -75,7 +75,7 @@
 #define                AT91_MATRIX_M7PR                (3 << 28)       /* Master 7 Priority */
 #define                AT91_MATRIX_M8PR                (3 << 0)        /* Master 8 Priority (in Register B) */
 
-#define AT91_MATRIX_MRCR       (AT91_MATRIX + 0x100)   /* Master Remap Control Register */
+#define AT91_MATRIX_MRCR       0x100                   /* Master Remap Control Register */
 #define                AT91_MATRIX_RCB0                (1 << 0)        /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
 #define                AT91_MATRIX_RCB1                (1 << 1)        /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
 #define                AT91_MATRIX_RCB2                (1 << 2)
@@ -86,7 +86,7 @@
 #define                AT91_MATRIX_RCB7                (1 << 7)
 #define                AT91_MATRIX_RCB8                (1 << 8)
 
-#define AT91_MATRIX_TCMR       (AT91_MATRIX + 0x114)   /* TCM Configuration Register */
+#define AT91_MATRIX_TCMR       0x114                   /* TCM Configuration Register */
 #define                AT91_MATRIX_ITCM_SIZE           (0xf << 0)      /* Size of ITCM enabled memory block */
 #define                        AT91_MATRIX_ITCM_0              (0 << 0)
 #define                        AT91_MATRIX_ITCM_16             (5 << 0)
@@ -96,7 +96,7 @@
 #define                        AT91_MATRIX_DTCM_16             (5 << 4)
 #define                        AT91_MATRIX_DTCM_32             (6 << 4)
 
-#define AT91_MATRIX_EBI0CSA    (AT91_MATRIX + 0x120)   /* EBI0 Chip Select Assignment Register */
+#define AT91_MATRIX_EBI0CSA    0x120                   /* EBI0 Chip Select Assignment Register */
 #define                AT91_MATRIX_EBI0_CS1A           (1 << 1)        /* Chip Select 1 Assignment */
 #define                        AT91_MATRIX_EBI0_CS1A_SMC               (0 << 1)
 #define                        AT91_MATRIX_EBI0_CS1A_SDRAMC            (1 << 1)
 #define                        AT91_MATRIX_EBI0_VDDIOMSEL_1_8V         (0 << 16)
 #define                        AT91_MATRIX_EBI0_VDDIOMSEL_3_3V         (1 << 16)
 
-#define AT91_MATRIX_EBI1CSA    (AT91_MATRIX + 0x124)   /* EBI1 Chip Select Assignment Register */
+#define AT91_MATRIX_EBI1CSA    0x124                   /* EBI1 Chip Select Assignment Register */
 #define                AT91_MATRIX_EBI1_CS1A           (1 << 1)        /* Chip Select 1 Assignment */
 #define                        AT91_MATRIX_EBI1_CS1A_SMC               (0 << 1)
 #define                        AT91_MATRIX_EBI1_CS1A_SDRAMC            (1 << 1)
index e2f8da8..0210797 100644 (file)
@@ -59,7 +59,6 @@
 #define                AT91_DDRSDRC_TRP        (0xf << 16)             /* Row precharge delay */
 #define                AT91_DDRSDRC_TRRD       (0xf << 20)             /* Active BankA to BankB */
 #define                AT91_DDRSDRC_TWTR       (0x7 << 24)             /* Internal Write to Read delay */
-#define                AT91CAP9_DDRSDRC_TWTR   (1   << 24)             /* Internal Write to Read delay */
 #define                AT91_DDRSDRC_RED_WRRD   (0x1 << 27)             /* Reduce Write to Read Delay [SAM9 Only] */
 #define                AT91_DDRSDRC_TMRD       (0xf << 28)             /* Load mode to active/refresh delay */
 
@@ -76,7 +75,6 @@
 #define                AT91_DDRSDRC_TRTP       (0x7  << 12)            /* Read to Precharge delay */
 
 #define AT91_DDRSDRC_LPR       0x1C    /* Low Power Register */
-#define AT91CAP9_DDRSDRC_LPR   0x18    /* Low Power Register */
 #define                AT91_DDRSDRC_LPCB       (3 << 0)                /* Low-power Configurations */
 #define                        AT91_DDRSDRC_LPCB_DISABLE               0
 #define                        AT91_DDRSDRC_LPCB_SELF_REFRESH          1
 #define                AT91_DDRSDRC_UPD_MR     (3 << 20)        /* Update load mode register and extended mode register */
 
 #define AT91_DDRSDRC_MDR       0x20    /* Memory Device Register */
-#define AT91CAP9_DDRSDRC_MDR   0x1C    /* Memory Device Register */
 #define                AT91_DDRSDRC_MD         (3 << 0)                /* Memory Device Type */
 #define                        AT91_DDRSDRC_MD_SDR             0
 #define                        AT91_DDRSDRC_MD_LOW_POWER_SDR   1
-#define                        AT91CAP9_DDRSDRC_MD_DDR         2
 #define                        AT91_DDRSDRC_MD_LOW_POWER_DDR   3
 #define                        AT91_DDRSDRC_MD_DDR2            6       /* [SAM9 Only] */
 #define                AT91_DDRSDRC_DBW        (1 << 4)                /* Data Bus Width */
 #define                        AT91_DDRSDRC_DBW_16BITS         (1 <<  4)
 
 #define AT91_DDRSDRC_DLL       0x24    /* DLL Information Register */
-#define AT91CAP9_DDRSDRC_DLL   0x20    /* DLL Information Register */
 #define                AT91_DDRSDRC_MDINC      (1 << 0)                /* Master Delay increment */
 #define                AT91_DDRSDRC_MDDEC      (1 << 1)                /* Master Delay decrement */
 #define                AT91_DDRSDRC_MDOVF      (1 << 2)                /* Master Delay Overflow */
-#define                AT91CAP9_DDRSDRC_SDCOVF (1 << 3)                /* Slave Delay Correction Overflow */
-#define                AT91CAP9_DDRSDRC_SDCUDF (1 << 4)                /* Slave Delay Correction Underflow */
-#define                AT91CAP9_DDRSDRC_SDERF  (1 << 5)                /* Slave Delay Correction error */
 #define                AT91_DDRSDRC_MDVAL      (0xff <<  8)            /* Master Delay value */
-#define                AT91CAP9_DDRSDRC_SDVAL  (0xff << 16)            /* Slave Delay value */
-#define                AT91CAP9_DDRSDRC_SDCVAL (0xff << 24)            /* Slave Delay Correction value */
 
 #define AT91_DDRSDRC_HS                0x2C    /* High Speed Register [SAM9 Only] */
 #define                AT91_DDRSDRC_DIS_ATCP_RD        (1 << 2)        /* Anticip read access is disabled */
 #define                AT91_DDRSDRC_WPVS       (1 << 0)                /* Write protect violation status */
 #define                AT91_DDRSDRC_WPVSRC     (0xffff << 8)           /* Write protect violation source */
 
-/* Register access macros */
-#define at91_ramc_read(num, reg) \
-       at91_sys_read(AT91_DDRSDRC##num + reg)
-#define at91_ramc_write(num, reg, value) \
-       at91_sys_write(AT91_DDRSDRC##num + reg, value)
-
 #endif
index 100f5a5..3d085a9 100644 (file)
 #define                        AT91_SDRAMC_MD_SDRAM            0
 #define                        AT91_SDRAMC_MD_LOW_POWER_SDRAM  1
 
-/* Register access macros */
-#define at91_ramc_read(num, reg) \
-       at91_sys_read(AT91_SDRAMC##num + reg)
-#define at91_ramc_write(num, reg, value) \
-       at91_sys_write(AT91_SDRAMC##num + reg, value)
-
 #endif
index dd9c95e..d052abc 100644 (file)
 #define AT91SAM9G45_BASE_TC5           0xfffd4080
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
-#define AT91_DDRSDRC1  (0xffffe400 - AT91_BASE_SYS)
-#define AT91_DDRSDRC0  (0xffffe600 - AT91_BASE_SYS)
-#define AT91_MATRIX    (0xffffea00 - AT91_BASE_SYS)
-#define AT91_PMC       (0xfffffc00 - AT91_BASE_SYS)
-#define AT91_GPBR      (0xfffffd60 - AT91_BASE_SYS)
-
 #define AT91SAM9G45_BASE_ECC   0xffffe200
+#define AT91SAM9G45_BASE_DDRSDRC1 0xffffe400
+#define AT91SAM9G45_BASE_DDRSDRC0 0xffffe600
 #define AT91SAM9G45_BASE_DMA   0xffffec00
 #define AT91SAM9G45_BASE_SMC   0xffffe800
+#define AT91SAM9G45_BASE_MATRIX        0xffffea00
 #define AT91SAM9G45_BASE_DBGU  AT91_BASE_DBGU1
 #define AT91SAM9G45_BASE_PIOA  0xfffff200
 #define AT91SAM9G45_BASE_PIOB  0xfffff400
 #define AT91SAM9G45_BASE_PIT   0xfffffd30
 #define AT91SAM9G45_BASE_WDT   0xfffffd40
 #define AT91SAM9G45_BASE_RTC   0xfffffdb0
+#define AT91SAM9G45_BASE_GPBR  0xfffffd60
 
 #define AT91_USART0    AT91SAM9G45_BASE_US0
 #define AT91_USART1    AT91SAM9G45_BASE_US1
index c972d60..b76e2ed 100644 (file)
 #ifndef AT91SAM9G45_MATRIX_H
 #define AT91SAM9G45_MATRIX_H
 
-#define AT91_MATRIX_MCFG0      (AT91_MATRIX + 0x00)    /* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1      (AT91_MATRIX + 0x04)    /* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2      (AT91_MATRIX + 0x08)    /* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3      (AT91_MATRIX + 0x0C)    /* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4      (AT91_MATRIX + 0x10)    /* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5      (AT91_MATRIX + 0x14)    /* Master Configuration Register 5 */
-#define AT91_MATRIX_MCFG6      (AT91_MATRIX + 0x18)    /* Master Configuration Register 6 */
-#define AT91_MATRIX_MCFG7      (AT91_MATRIX + 0x1C)    /* Master Configuration Register 7 */
-#define AT91_MATRIX_MCFG8      (AT91_MATRIX + 0x20)    /* Master Configuration Register 8 */
-#define AT91_MATRIX_MCFG9      (AT91_MATRIX + 0x24)    /* Master Configuration Register 9 */
-#define AT91_MATRIX_MCFG10     (AT91_MATRIX + 0x28)    /* Master Configuration Register 10 */
-#define AT91_MATRIX_MCFG11     (AT91_MATRIX + 0x2C)    /* Master Configuration Register 11 */
+#define AT91_MATRIX_MCFG0      0x00                    /* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1      0x04                    /* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2      0x08                    /* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3      0x0C                    /* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4      0x10                    /* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5      0x14                    /* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG6      0x18                    /* Master Configuration Register 6 */
+#define AT91_MATRIX_MCFG7      0x1C                    /* Master Configuration Register 7 */
+#define AT91_MATRIX_MCFG8      0x20                    /* Master Configuration Register 8 */
+#define AT91_MATRIX_MCFG9      0x24                    /* Master Configuration Register 9 */
+#define AT91_MATRIX_MCFG10     0x28                    /* Master Configuration Register 10 */
+#define AT91_MATRIX_MCFG11     0x2C                    /* Master Configuration Register 11 */
 #define                AT91_MATRIX_ULBT        (7 << 0)        /* Undefined Length Burst Type */
 #define                        AT91_MATRIX_ULBT_INFINITE       (0 << 0)
 #define                        AT91_MATRIX_ULBT_SINGLE         (1 << 0)
 #define                        AT91_MATRIX_ULBT_SIXTYFOUR      (6 << 0)
 #define                        AT91_MATRIX_ULBT_128            (7 << 0)
 
-#define AT91_MATRIX_SCFG0      (AT91_MATRIX + 0x40)    /* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1      (AT91_MATRIX + 0x44)    /* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2      (AT91_MATRIX + 0x48)    /* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3      (AT91_MATRIX + 0x4C)    /* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4      (AT91_MATRIX + 0x50)    /* Slave Configuration Register 4 */
-#define AT91_MATRIX_SCFG5      (AT91_MATRIX + 0x54)    /* Slave Configuration Register 5 */
-#define AT91_MATRIX_SCFG6      (AT91_MATRIX + 0x58)    /* Slave Configuration Register 6 */
-#define AT91_MATRIX_SCFG7      (AT91_MATRIX + 0x5C)    /* Slave Configuration Register 7 */
+#define AT91_MATRIX_SCFG0      0x40                    /* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1      0x44                    /* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2      0x48                    /* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3      0x4C                    /* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4      0x50                    /* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG5      0x54                    /* Slave Configuration Register 5 */
+#define AT91_MATRIX_SCFG6      0x58                    /* Slave Configuration Register 6 */
+#define AT91_MATRIX_SCFG7      0x5C                    /* Slave Configuration Register 7 */
 #define                AT91_MATRIX_SLOT_CYCLE          (0x1ff << 0)    /* Maximum Number of Allowed Cycles for a Burst */
 #define                AT91_MATRIX_DEFMSTR_TYPE        (3    << 16)    /* Default Master Type */
 #define                        AT91_MATRIX_DEFMSTR_TYPE_NONE   (0 << 16)
 #define                        AT91_MATRIX_DEFMSTR_TYPE_FIXED  (2 << 16)
 #define                AT91_MATRIX_FIXED_DEFMSTR       (0xf  << 18)    /* Fixed Index of Default Master */
 
-#define AT91_MATRIX_PRAS0      (AT91_MATRIX + 0x80)    /* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRBS0      (AT91_MATRIX + 0x84)    /* Priority Register B for Slave 0 */
-#define AT91_MATRIX_PRAS1      (AT91_MATRIX + 0x88)    /* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRBS1      (AT91_MATRIX + 0x8C)    /* Priority Register B for Slave 1 */
-#define AT91_MATRIX_PRAS2      (AT91_MATRIX + 0x90)    /* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRBS2      (AT91_MATRIX + 0x94)    /* Priority Register B for Slave 2 */
-#define AT91_MATRIX_PRAS3      (AT91_MATRIX + 0x98)    /* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRBS3      (AT91_MATRIX + 0x9C)    /* Priority Register B for Slave 3 */
-#define AT91_MATRIX_PRAS4      (AT91_MATRIX + 0xA0)    /* Priority Register A for Slave 4 */
-#define AT91_MATRIX_PRBS4      (AT91_MATRIX + 0xA4)    /* Priority Register B for Slave 4 */
-#define AT91_MATRIX_PRAS5      (AT91_MATRIX + 0xA8)    /* Priority Register A for Slave 5 */
-#define AT91_MATRIX_PRBS5      (AT91_MATRIX + 0xAC)    /* Priority Register B for Slave 5 */
-#define AT91_MATRIX_PRAS6      (AT91_MATRIX + 0xB0)    /* Priority Register A for Slave 6 */
-#define AT91_MATRIX_PRBS6      (AT91_MATRIX + 0xB4)    /* Priority Register B for Slave 6 */
-#define AT91_MATRIX_PRAS7      (AT91_MATRIX + 0xB8)    /* Priority Register A for Slave 7 */
-#define AT91_MATRIX_PRBS7      (AT91_MATRIX + 0xBC)    /* Priority Register B for Slave 7 */
+#define AT91_MATRIX_PRAS0      0x80                    /* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRBS0      0x84                    /* Priority Register B for Slave 0 */
+#define AT91_MATRIX_PRAS1      0x88                    /* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRBS1      0x8C                    /* Priority Register B for Slave 1 */
+#define AT91_MATRIX_PRAS2      0x90                    /* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRBS2      0x94                    /* Priority Register B for Slave 2 */
+#define AT91_MATRIX_PRAS3      0x98                    /* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRBS3      0x9C                    /* Priority Register B for Slave 3 */
+#define AT91_MATRIX_PRAS4      0xA0                    /* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRBS4      0xA4                    /* Priority Register B for Slave 4 */
+#define AT91_MATRIX_PRAS5      0xA8                    /* Priority Register A for Slave 5 */
+#define AT91_MATRIX_PRBS5      0xAC                    /* Priority Register B for Slave 5 */
+#define AT91_MATRIX_PRAS6      0xB0                    /* Priority Register A for Slave 6 */
+#define AT91_MATRIX_PRBS6      0xB4                    /* Priority Register B for Slave 6 */
+#define AT91_MATRIX_PRAS7      0xB8                    /* Priority Register A for Slave 7 */
+#define AT91_MATRIX_PRBS7      0xBC                    /* Priority Register B for Slave 7 */
 #define                AT91_MATRIX_M0PR                (3 << 0)        /* Master 0 Priority */
 #define                AT91_MATRIX_M1PR                (3 << 4)        /* Master 1 Priority */
 #define                AT91_MATRIX_M2PR                (3 << 8)        /* Master 2 Priority */
@@ -81,7 +81,7 @@
 #define                AT91_MATRIX_M10PR               (3 << 8)        /* Master 10 Priority (in Register B) */
 #define                AT91_MATRIX_M11PR               (3 << 12)       /* Master 11 Priority (in Register B) */
 
-#define AT91_MATRIX_MRCR       (AT91_MATRIX + 0x100)   /* Master Remap Control Register */
+#define AT91_MATRIX_MRCR       0x100                   /* Master Remap Control Register */
 #define                AT91_MATRIX_RCB0                (1 << 0)        /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
 #define                AT91_MATRIX_RCB1                (1 << 1)        /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
 #define                AT91_MATRIX_RCB2                (1 << 2)
@@ -95,7 +95,7 @@
 #define                AT91_MATRIX_RCB10               (1 << 10)
 #define                AT91_MATRIX_RCB11               (1 << 11)
 
-#define AT91_MATRIX_TCMR       (AT91_MATRIX + 0x110)   /* TCM Configuration Register */
+#define AT91_MATRIX_TCMR       0x110                   /* TCM Configuration Register */
 #define                AT91_MATRIX_ITCM_SIZE           (0xf << 0)      /* Size of ITCM enabled memory block */
 #define                        AT91_MATRIX_ITCM_0              (0 << 0)
 #define                        AT91_MATRIX_ITCM_32             (6 << 0)
 #define                        AT91_MATRIX_TCM_NO_WS           (0x0 << 11)
 #define                        AT91_MATRIX_TCM_ONE_WS          (0x1 << 11)
 
-#define AT91_MATRIX_VIDEO      (AT91_MATRIX + 0x118)   /* Video Mode Configuration Register */
+#define AT91_MATRIX_VIDEO      0x118                   /* Video Mode Configuration Register */
 #define                AT91C_VDEC_SEL                  (0x1 <<  0) /* Video Mode Selection */
 #define                        AT91C_VDEC_SEL_OFF              (0 << 0)
 #define                        AT91C_VDEC_SEL_ON               (1 << 0)
 
-#define AT91_MATRIX_EBICSA     (AT91_MATRIX + 0x128)   /* EBI Chip Select Assignment Register */
+#define AT91_MATRIX_EBICSA     0x128                   /* EBI Chip Select Assignment Register */
 #define                AT91_MATRIX_EBI_CS1A            (1 << 1)        /* Chip Select 1 Assignment */
 #define                        AT91_MATRIX_EBI_CS1A_SMC                (0 << 1)
 #define                        AT91_MATRIX_EBI_CS1A_SDRAMC             (1 << 1)
 #define                        AT91_MATRIX_EBI_DDR_IOSR_REDUCED        (0 << 18)
 #define                        AT91_MATRIX_EBI_DDR_IOSR_NORMAL         (1 << 18)
 
-#define AT91_MATRIX_WPMR       (AT91_MATRIX + 0x1E4)   /* Write Protect Mode Register */
+#define AT91_MATRIX_WPMR       0x1E4                   /* Write Protect Mode Register */
 #define                AT91_MATRIX_WPMR_WPEN           (1 << 0)        /* Write Protect ENable */
 #define                        AT91_MATRIX_WPMR_WP_WPDIS               (0 << 0)
 #define                        AT91_MATRIX_WPMR_WP_WPEN                (1 << 0)
 #define                AT91_MATRIX_WPMR_WPKEY          (0xFFFFFF << 8) /* Write Protect KEY */
 
-#define AT91_MATRIX_WPSR       (AT91_MATRIX + 0x1E8)   /* Write Protect Status Register */
+#define AT91_MATRIX_WPSR       0x1E8                   /* Write Protect Status Register */
 #define                AT91_MATRIX_WPSR_WPVS           (1 << 0)        /* Write Protect Violation Status */
 #define                        AT91_MATRIX_WPSR_NO_WPV         (0 << 0)
 #define                        AT91_MATRIX_WPSR_WPV            (1 << 0)
index d7bead7..e0073eb 100644 (file)
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
  */
-#define AT91_SDRAMC0   (0xffffea00 - AT91_BASE_SYS)
-#define AT91_MATRIX    (0xffffee00 - AT91_BASE_SYS)
-#define AT91_PMC       (0xfffffc00 - AT91_BASE_SYS)
 #define AT91_SCKCR     (0xfffffd50 - AT91_BASE_SYS)
-#define AT91_GPBR      (0xfffffd60 - AT91_BASE_SYS)
 
 #define AT91SAM9RL_BASE_DMA    0xffffe600
 #define AT91SAM9RL_BASE_ECC    0xffffe800
+#define AT91SAM9RL_BASE_SDRAMC 0xffffea00
 #define AT91SAM9RL_BASE_SMC    0xffffec00
+#define AT91SAM9RL_BASE_MATRIX 0xffffee00
 #define AT91SAM9RL_BASE_DBGU   AT91_BASE_DBGU0
 #define AT91SAM9RL_BASE_PIOA   0xfffff400
 #define AT91SAM9RL_BASE_PIOB   0xfffff600
@@ -88,6 +86,7 @@
 #define AT91SAM9RL_BASE_RTT    0xfffffd20
 #define AT91SAM9RL_BASE_PIT    0xfffffd30
 #define AT91SAM9RL_BASE_WDT    0xfffffd40
+#define AT91SAM9RL_BASE_GPBR   0xfffffd60
 #define AT91SAM9RL_BASE_RTC    0xfffffe00
 
 #define AT91_USART0    AT91SAM9RL_BASE_US0
index 5f91490..6d160ad 100644 (file)
 #ifndef AT91SAM9RL_MATRIX_H
 #define AT91SAM9RL_MATRIX_H
 
-#define AT91_MATRIX_MCFG0      (AT91_MATRIX + 0x00)    /* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1      (AT91_MATRIX + 0x04)    /* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2      (AT91_MATRIX + 0x08)    /* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3      (AT91_MATRIX + 0x0C)    /* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4      (AT91_MATRIX + 0x10)    /* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5      (AT91_MATRIX + 0x14)    /* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG0      0x00                    /* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1      0x04                    /* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2      0x08                    /* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3      0x0C                    /* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4      0x10                    /* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5      0x14                    /* Master Configuration Register 5 */
 #define                AT91_MATRIX_ULBT        (7 << 0)        /* Undefined Length Burst Type */
 #define                        AT91_MATRIX_ULBT_INFINITE       (0 << 0)
 #define                        AT91_MATRIX_ULBT_SINGLE         (1 << 0)
 #define                        AT91_MATRIX_ULBT_EIGHT          (3 << 0)
 #define                        AT91_MATRIX_ULBT_SIXTEEN        (4 << 0)
 
-#define AT91_MATRIX_SCFG0      (AT91_MATRIX + 0x40)    /* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1      (AT91_MATRIX + 0x44)    /* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2      (AT91_MATRIX + 0x48)    /* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3      (AT91_MATRIX + 0x4C)    /* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4      (AT91_MATRIX + 0x50)    /* Slave Configuration Register 4 */
-#define AT91_MATRIX_SCFG5      (AT91_MATRIX + 0x54)    /* Slave Configuration Register 5 */
+#define AT91_MATRIX_SCFG0      0x40                    /* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1      0x44                    /* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2      0x48                    /* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3      0x4C                    /* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4      0x50                    /* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG5      0x54                    /* Slave Configuration Register 5 */
 #define                AT91_MATRIX_SLOT_CYCLE          (0xff << 0)     /* Maximum Number of Allowed Cycles for a Burst */
 #define                AT91_MATRIX_DEFMSTR_TYPE        (3    << 16)    /* Default Master Type */
 #define                        AT91_MATRIX_DEFMSTR_TYPE_NONE   (0 << 16)
 #define                        AT91_MATRIX_ARBT_ROUND_ROBIN    (0 << 24)
 #define                        AT91_MATRIX_ARBT_FIXED_PRIORITY (1 << 24)
 
-#define AT91_MATRIX_PRAS0      (AT91_MATRIX + 0x80)    /* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRAS1      (AT91_MATRIX + 0x88)    /* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRAS2      (AT91_MATRIX + 0x90)    /* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRAS3      (AT91_MATRIX + 0x98)    /* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRAS4      (AT91_MATRIX + 0xA0)    /* Priority Register A for Slave 4 */
-#define AT91_MATRIX_PRAS5      (AT91_MATRIX + 0xA8)    /* Priority Register A for Slave 5 */
+#define AT91_MATRIX_PRAS0      0x80                    /* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRAS1      0x88                    /* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRAS2      0x90                    /* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRAS3      0x98                    /* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRAS4      0xA0                    /* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRAS5      0xA8                    /* Priority Register A for Slave 5 */
 #define                AT91_MATRIX_M0PR                (3 << 0)        /* Master 0 Priority */
 #define                AT91_MATRIX_M1PR                (3 << 4)        /* Master 1 Priority */
 #define                AT91_MATRIX_M2PR                (3 << 8)        /* Master 2 Priority */
@@ -56,7 +56,7 @@
 #define                AT91_MATRIX_M4PR                (3 << 16)       /* Master 4 Priority */
 #define                AT91_MATRIX_M5PR                (3 << 20)       /* Master 5 Priority */
 
-#define AT91_MATRIX_MRCR       (AT91_MATRIX + 0x100)   /* Master Remap Control Register */
+#define AT91_MATRIX_MRCR       0x100                   /* Master Remap Control Register */
 #define                AT91_MATRIX_RCB0                (1 << 0)        /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
 #define                AT91_MATRIX_RCB1                (1 << 1)        /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
 #define                AT91_MATRIX_RCB2                (1 << 2)
@@ -64,7 +64,7 @@
 #define                AT91_MATRIX_RCB4                (1 << 4)
 #define                AT91_MATRIX_RCB5                (1 << 5)
 
-#define AT91_MATRIX_TCMR       (AT91_MATRIX + 0x114)   /* TCM Configuration Register */
+#define AT91_MATRIX_TCMR       0x114                   /* TCM Configuration Register */
 #define                AT91_MATRIX_ITCM_SIZE           (0xf << 0)      /* Size of ITCM enabled memory block */
 #define                        AT91_MATRIX_ITCM_0              (0 << 0)
 #define                        AT91_MATRIX_ITCM_16             (5 << 0)
@@ -74,7 +74,7 @@
 #define                        AT91_MATRIX_DTCM_16             (5 << 4)
 #define                        AT91_MATRIX_DTCM_32             (6 << 4)
 
-#define AT91_MATRIX_EBICSA     (AT91_MATRIX + 0x120)   /* EBI0 Chip Select Assignment Register */
+#define AT91_MATRIX_EBICSA     0x120                   /* EBI0 Chip Select Assignment Register */
 #define                AT91_MATRIX_CS1A                (1 << 1)        /* Chip Select 1 Assignment */
 #define                        AT91_MATRIX_CS1A_SMC            (0 << 1)
 #define                        AT91_MATRIX_CS1A_SDRAMC         (1 << 1)
diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h
new file mode 100644 (file)
index 0000000..88e43d5
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Chip-specific header file for the AT91SAM9x5 family
+ *
+ *  Copyright (C) 2009-2012 Atmel Corporation.
+ *
+ * Common definitions.
+ * Based on AT91SAM9x5 datasheet.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef AT91SAM9X5_H
+#define AT91SAM9X5_H
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91SAM9X5_ID_PIOAB    2       /* Parallel I/O Controller A and B */
+#define AT91SAM9X5_ID_PIOCD    3       /* Parallel I/O Controller C and D */
+#define AT91SAM9X5_ID_SMD      4       /* SMD Soft Modem (SMD) */
+#define AT91SAM9X5_ID_USART0   5       /* USART 0 */
+#define AT91SAM9X5_ID_USART1   6       /* USART 1 */
+#define AT91SAM9X5_ID_USART2   7       /* USART 2 */
+#define AT91SAM9X5_ID_USART3   8       /* USART 3 */
+#define AT91SAM9X5_ID_TWI0     9       /* Two-Wire Interface 0 */
+#define AT91SAM9X5_ID_TWI1     10      /* Two-Wire Interface 1 */
+#define AT91SAM9X5_ID_TWI2     11      /* Two-Wire Interface 2 */
+#define AT91SAM9X5_ID_MCI0     12      /* High Speed Multimedia Card Interface 0 */
+#define AT91SAM9X5_ID_SPI0     13      /* Serial Peripheral Interface 0 */
+#define AT91SAM9X5_ID_SPI1     14      /* Serial Peripheral Interface 1 */
+#define AT91SAM9X5_ID_UART0    15      /* UART 0 */
+#define AT91SAM9X5_ID_UART1    16      /* UART 1 */
+#define AT91SAM9X5_ID_TCB      17      /* Timer Counter 0, 1, 2, 3, 4 and 5 */
+#define AT91SAM9X5_ID_PWM      18      /* Pulse Width Modulation Controller */
+#define AT91SAM9X5_ID_ADC      19      /* ADC Controller */
+#define AT91SAM9X5_ID_DMA0     20      /* DMA Controller 0 */
+#define AT91SAM9X5_ID_DMA1     21      /* DMA Controller 1 */
+#define AT91SAM9X5_ID_UHPHS    22      /* USB Host High Speed */
+#define AT91SAM9X5_ID_UDPHS    23      /* USB Device High Speed */
+#define AT91SAM9X5_ID_EMAC0    24      /* Ethernet MAC0 */
+#define AT91SAM9X5_ID_LCDC     25      /* LCD Controller */
+#define AT91SAM9X5_ID_ISI      25      /* Image Sensor Interface */
+#define AT91SAM9X5_ID_MCI1     26      /* High Speed Multimedia Card Interface 1 */
+#define AT91SAM9X5_ID_EMAC1    27      /* Ethernet MAC1 */
+#define AT91SAM9X5_ID_SSC      28      /* Synchronous Serial Controller */
+#define AT91SAM9X5_ID_CAN0     29      /* CAN Controller 0 */
+#define AT91SAM9X5_ID_CAN1     30      /* CAN Controller 1 */
+#define AT91SAM9X5_ID_IRQ0     31      /* Advanced Interrupt Controller */
+
+/*
+ * User Peripheral physical base addresses.
+ */
+#define AT91SAM9X5_BASE_USART0 0xf801c000
+#define AT91SAM9X5_BASE_USART1 0xf8020000
+#define AT91SAM9X5_BASE_USART2 0xf8024000
+
+/*
+ * Base addresses for early serial code (uncompress.h)
+ */
+#define AT91_DBGU      AT91_BASE_DBGU0
+#define AT91_USART0    AT91SAM9X5_BASE_USART0
+#define AT91_USART1    AT91SAM9X5_BASE_USART1
+#define AT91_USART2    AT91SAM9X5_BASE_USART2
+
+/*
+ * Internal Memory.
+ */
+#define AT91SAM9X5_SRAM_BASE   0x00300000      /* Internal SRAM base address */
+#define AT91SAM9X5_SRAM_SIZE   SZ_32K          /* Internal SRAM size (32Kb) */
+
+#define AT91SAM9X5_ROM_BASE    0x00400000      /* Internal ROM base address */
+#define AT91SAM9X5_ROM_SIZE    SZ_64K          /* Internal ROM size (64Kb) */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h
new file mode 100644 (file)
index 0000000..a606d39
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Matrix-centric header file for the AT91SAM9x5 family
+ *
+ *  Copyright (C) 2009-2012 Atmel Corporation.
+ *
+ * Only EBI related registers.
+ * Write Protect register definitions may be useful.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef AT91SAM9X5_MATRIX_H
+#define AT91SAM9X5_MATRIX_H
+
+#define AT91_MATRIX_EBICSA     (AT91_MATRIX + 0x120)   /* EBI Chip Select Assignment Register */
+#define                AT91_MATRIX_EBI_CS1A            (1 << 1)        /* Chip Select 1 Assignment */
+#define                        AT91_MATRIX_EBI_CS1A_SMC                (0 << 1)
+#define                        AT91_MATRIX_EBI_CS1A_SDRAMC             (1 << 1)
+#define                AT91_MATRIX_EBI_CS3A            (1 << 3)        /* Chip Select 3 Assignment */
+#define                        AT91_MATRIX_EBI_CS3A_SMC                (0 << 3)
+#define                        AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH      (1 << 3)
+#define                AT91_MATRIX_EBI_DBPUC           (1 << 8)        /* Data Bus Pull-up Configuration */
+#define                        AT91_MATRIX_EBI_DBPU_ON                 (0 << 8)
+#define                        AT91_MATRIX_EBI_DBPU_OFF                (1 << 8)
+#define                AT91_MATRIX_EBI_VDDIOMSEL       (1 << 16)       /* Memory voltage selection */
+#define                        AT91_MATRIX_EBI_VDDIOMSEL_1_8V          (0 << 16)
+#define                        AT91_MATRIX_EBI_VDDIOMSEL_3_3V          (1 << 16)
+#define                AT91_MATRIX_EBI_EBI_IOSR        (1 << 17)       /* EBI I/O slew rate selection */
+#define                        AT91_MATRIX_EBI_EBI_IOSR_REDUCED        (0 << 17)
+#define                        AT91_MATRIX_EBI_EBI_IOSR_NORMAL         (1 << 17)
+#define                AT91_MATRIX_EBI_DDR_IOSR        (1 << 18)       /* DDR2 dedicated port I/O slew rate selection */
+#define                        AT91_MATRIX_EBI_DDR_IOSR_REDUCED        (0 << 18)
+#define                        AT91_MATRIX_EBI_DDR_IOSR_NORMAL         (1 << 18)
+#define                AT91_MATRIX_NFD0_SELECT         (1 << 24)       /* NAND Flash Data Bus Selection */
+#define                        AT91_MATRIX_NFD0_ON_D0                  (0 << 24)
+#define                        AT91_MATRIX_NFD0_ON_D16                 (1 << 24)
+#define                AT91_MATRIX_DDR_MP_EN           (1 << 25)       /* DDR Multi-port Enable */
+#define                        AT91_MATRIX_MP_OFF                      (0 << 25)
+#define                        AT91_MATRIX_MP_ON                       (1 << 25)
+
+#define AT91_MATRIX_WPMR       (AT91_MATRIX + 0x1E4)   /* Write Protect Mode Register */
+#define                AT91_MATRIX_WPMR_WPEN           (1 << 0)        /* Write Protect ENable */
+#define                        AT91_MATRIX_WPMR_WP_WPDIS               (0 << 0)
+#define                        AT91_MATRIX_WPMR_WP_WPEN                (1 << 0)
+#define                AT91_MATRIX_WPMR_WPKEY          (0xFFFFFF << 8) /* Write Protect KEY */
+
+#define AT91_MATRIX_WPSR       (AT91_MATRIX + 0x1E8)   /* Write Protect Status Register */
+#define                AT91_MATRIX_WPSR_WPVS           (1 << 0)        /* Write Protect Violation Status */
+#define                        AT91_MATRIX_WPSR_NO_WPV         (0 << 0)
+#define                        AT91_MATRIX_WPSR_WPV            (1 << 0)
+#define                AT91_MATRIX_WPSR_WPVSRC         (0xFFFF << 8)   /* Write Protect Violation Source */
+
+#endif
index a57829f..9068021 100644 (file)
 #define AT91X40_ID_IRQ2                18      /* External IRQ 2 */
 
 /*
- * System Peripherals (offset from AT91_BASE_SYS)
+ * System Peripherals
  */
 #define AT91_BASE_SYS  0xffc00000
 
-#define AT91_EBI       (0xffe00000 - AT91_BASE_SYS)    /* External Bus Interface */
-#define AT91_SF                (0xfff00000 - AT91_BASE_SYS)    /* Special Function */
-#define AT91_USART1    (0xfffcc000 - AT91_BASE_SYS)    /* USART 1 */
-#define AT91_USART0    (0xfffd0000 - AT91_BASE_SYS)    /* USART 0 */
-#define AT91_TC                (0xfffe0000 - AT91_BASE_SYS)    /* Timer Counter */
-#define AT91_PIOA      (0xffff0000 - AT91_BASE_SYS)    /* PIO Controller A */
-#define AT91_PS                (0xffff4000 - AT91_BASE_SYS)    /* Power Save */
-#define AT91_WD                (0xffff8000 - AT91_BASE_SYS)    /* Watchdog Timer */
+#define AT91_EBI       0xffe00000      /* External Bus Interface */
+#define AT91_SF                0xfff00000      /* Special Function */
+#define AT91_USART1    0xfffcc000      /* USART 1 */
+#define AT91_USART0    0xfffd0000      /* USART 0 */
+#define AT91_TC                0xfffe0000      /* Timer Counter */
+#define AT91_PIOA      0xffff0000      /* PIO Controller A */
+#define AT91_PS                0xffff4000      /* Power Save */
+#define AT91_WD                0xffff8000      /* Watchdog Timer */
 
 /*
  * The AT91x40 series doesn't have a debug unit like the other AT91 parts.
index 3b33f07..544a5d5 100644 (file)
@@ -41,6 +41,7 @@
 #include <sound/atmel-ac97c.h>
 #include <linux/serial.h>
 #include <linux/platform_data/macb.h>
+#include <linux/platform_data/atmel.h>
 
  /* USB Device */
 struct at91_udc_data {
@@ -98,18 +99,6 @@ extern void __init at91_add_device_usbh(struct at91_usbh_data *data);
 extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data);
 extern void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data);
 
- /* NAND / SmartMedia */
-struct atmel_nand_data {
-       int             enable_pin;     /* chip enable */
-       int             det_pin;        /* card detect */
-       int             rdy_pin;        /* ready/busy */
-       u8              rdy_pin_active_low;     /* rdy_pin value is inverted */
-       u8              ale;            /* address line number connected to ALE */
-       u8              cle;            /* address line number connected to CLE */
-       u8              bus_width_16;   /* buswidth is 16 bit */
-       struct mtd_partition *parts;
-       unsigned int    num_parts;
-};
 extern void __init at91_add_device_nand(struct atmel_nand_data *data);
 
  /* I2C*/
@@ -179,7 +168,9 @@ extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
 extern void __init at91_add_device_ac97(struct ac97c_platform_data *data);
 
  /* ISI */
-extern void __init at91_add_device_isi(void);
+struct isi_platform_data;
+extern void __init at91_add_device_isi(struct isi_platform_data *data,
+               bool use_pck_as_mck);
 
  /* Touchscreen Controller */
 struct at91_tsadcc_data {
index f6ce936..0118c33 100644 (file)
@@ -25,7 +25,6 @@
 #define ARCH_ID_AT91SAM9G45MRL 0x819b05a2      /* aka 9G45-ES2 & non ES lots */
 #define ARCH_ID_AT91SAM9G45ES  0x819b05a1      /* 9G45-ES (Engineering Sample) */
 #define ARCH_ID_AT91SAM9X5     0x819a05a0
-#define ARCH_ID_AT91CAP9       0x039A03A0
 
 #define ARCH_ID_AT91SAM9XE128  0x329973a0
 #define ARCH_ID_AT91SAM9XE256  0x329a93a0
 #define ARCH_FAMILY_AT91SAM9   0x01900000
 #define ARCH_FAMILY_AT91SAM9XE 0x02900000
 
-/* PMC revision */
-#define ARCH_REVISION_CAP9_B   0x399
-#define ARCH_REVISION_CAP9_C   0x601
-
 /* RM9200 type */
 #define ARCH_REVISON_9200_BGA  (0 << 0)
 #define ARCH_REVISON_9200_PQFP (1 << 0)
@@ -63,9 +58,6 @@ enum at91_soc_type {
        /* 920T */
        AT91_SOC_RM9200,
 
-       /* CAP */
-       AT91_SOC_CAP9,
-
        /* SAM92xx */
        AT91_SOC_SAM9260, AT91_SOC_SAM9261, AT91_SOC_SAM9263,
 
@@ -86,9 +78,6 @@ enum at91_soc_subtype {
        /* RM9200 */
        AT91_SOC_RM9200_BGA, AT91_SOC_RM9200_PQFP,
 
-       /* CAP9 */
-       AT91_SOC_CAP9_REV_B, AT91_SOC_CAP9_REV_C,
-
        /* SAM9260 */
        AT91_SOC_SAM9XE,
 
@@ -195,16 +184,6 @@ static inline int at91_soc_is_detected(void)
 #define cpu_is_at91sam9x25()   (0)
 #endif
 
-#ifdef CONFIG_ARCH_AT91CAP9
-#define cpu_is_at91cap9()      (at91_soc_initdata.type == AT91_SOC_CAP9)
-#define cpu_is_at91cap9_revB() (at91_soc_initdata.subtype == AT91_SOC_CAP9_REV_B)
-#define cpu_is_at91cap9_revC() (at91_soc_initdata.subtype == AT91_SOC_CAP9_REV_C)
-#else
-#define cpu_is_at91cap9()      (0)
-#define cpu_is_at91cap9_revB() (0)
-#define cpu_is_at91cap9_revC() (0)
-#endif
-
 /*
  * Since this is ARM, we will never run on any AVR32 CPU. But these
  * definitions may reduce clutter in common drivers.
index 423eea0..903bf20 100644 (file)
 #include <mach/hardware.h>
 #include <mach/at91_aic.h>
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =at91_aic_base           @ base virtual address of AIC peripheral
        ldr     \base, [\base]
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
        ldr     \irqnr, [\base, #AT91_AIC_IVR]          @ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
        ldr     \irqstat, [\base, #AT91_AIC_ISR]        @ read interrupt source number
index e3fd225..eed465a 100644 (file)
 extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup);
+extern int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup);
+extern int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup);
 extern int __init_or_module at91_set_gpio_output(unsigned pin, int value);
 extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on);
+extern int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div);
 extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on);
+extern int __init_or_module at91_set_pulldown(unsigned pin, int is_on);
+extern int __init_or_module at91_disable_schmitt_trig(unsigned pin);
 
 /* callable at any time */
 extern int at91_set_gpio_value(unsigned pin, int value);
@@ -204,18 +209,6 @@ extern int at91_get_gpio_value(unsigned pin);
 extern void at91_gpio_suspend(void);
 extern void at91_gpio_resume(void);
 
-/*-------------------------------------------------------------------------*/
-
-/* wrappers for "new style" GPIO calls. the old AT91-specific ones should
- * eventually be removed (along with this errno.h inclusion), and the
- * gpio request/free calls should probably be implemented.
- */
-
-#include <asm/errno.h>
-
-#define gpio_to_irq(gpio) (gpio + NR_AIC_IRQS)
-#define irq_to_gpio(irq)  (irq - NR_AIC_IRQS)
-
 #endif /* __ASSEMBLY__ */
 
 #endif
index 2d0e4e9..e9e29a6 100644 (file)
@@ -19,7 +19,7 @@
 /* DBGU base */
 /* rm9200, 9260/9g20, 9261/9g10, 9rl */
 #define AT91_BASE_DBGU0        0xfffff200
-/* 9263, 9g45, cap9 */
+/* 9263, 9g45 */
 #define AT91_BASE_DBGU1        0xffffee00
 
 #if defined(CONFIG_ARCH_AT91RM9200)
@@ -34,8 +34,8 @@
 #include <mach/at91sam9rl.h>
 #elif defined(CONFIG_ARCH_AT91SAM9G45)
 #include <mach/at91sam9g45.h>
-#elif defined(CONFIG_ARCH_AT91CAP9)
-#include <mach/at91cap9.h>
+#elif defined(CONFIG_ARCH_AT91SAM9X5)
+#include <mach/at91sam9x5.h>
 #elif defined(CONFIG_ARCH_AT91X40)
 #include <mach/at91x40.h>
 #else
 
 /*
  * On all at91 have the Advanced Interrupt Controller starts at address
- * 0xfffff000
+ * 0xfffff000 and the Power Management Controller starts at 0xfffffc00
  */
 #define AT91_AIC       0xfffff000
+#define AT91_PMC       0xfffffc00
 
 /*
  * Peripheral identifiers/interrupts.
index 4ca09ef..4003001 100644 (file)
 #define __io(a)                __typesafe_io(a)
 #define __mem_pci(a)   (a)
 
-#ifndef __ASSEMBLY__
-
-static inline unsigned int at91_sys_read(unsigned int reg_offset)
-{
-       void __iomem *addr = (void __iomem *)AT91_VA_BASE_SYS;
-
-       return __raw_readl(addr + reg_offset);
-}
-
-static inline void at91_sys_write(unsigned int reg_offset, unsigned long value)
-{
-       void __iomem *addr = (void __iomem *)AT91_VA_BASE_SYS;
-
-       __raw_writel(value, addr + reg_offset);
-}
-
-#endif
-
 #endif
diff --git a/arch/arm/mach-at91/include/mach/system.h b/arch/arm/mach-at91/include/mach/system.h
deleted file mode 100644 (file)
index cbd64f3..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/system.h
- *
- *  Copyright (C) 2003 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <mach/hardware.h>
-#include <mach/at91_st.h>
-#include <mach/at91_dbgu.h>
-#include <mach/at91_pmc.h>
-
-static inline void arch_idle(void)
-{
-       /*
-        * Disable the processor clock.  The processor will be automatically
-        * re-enabled by an interrupt or by a reset.
-        */
-#ifdef AT91_PS
-       at91_sys_write(AT91_PS_CR, AT91_PS_CR_CPU);
-#else
-       at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK);
-#endif
-#ifndef CONFIG_CPU_ARM920T
-       /*
-        * Set the processor (CP15) into 'Wait for Interrupt' mode.
-        * Post-RM9200 processors need this in conjunction with the above
-        * to save power when idle.
-        */
-       cpu_do_idle();
-#endif
-}
-
-#endif
index be6b639..cfcfcbe 100644 (file)
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/types.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/err.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/map.h>
 
 void __iomem *at91_aic_base;
+static struct irq_domain *at91_aic_domain;
+static struct device_node *at91_aic_np;
 
 static void at91_aic_mask_irq(struct irq_data *d)
 {
        /* Disable interrupt on AIC */
-       at91_aic_write(AT91_AIC_IDCR, 1 << d->irq);
+       at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
 }
 
 static void at91_aic_unmask_irq(struct irq_data *d)
 {
        /* Enable interrupt on AIC */
-       at91_aic_write(AT91_AIC_IECR, 1 << d->irq);
+       at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
 }
 
 unsigned int at91_extern_irq;
 
-#define is_extern_irq(irq) ((1 << (irq)) & at91_extern_irq)
+#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
 
 static int at91_aic_set_type(struct irq_data *d, unsigned type)
 {
@@ -63,13 +71,13 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
                srctype = AT91_AIC_SRCTYPE_RISING;
                break;
        case IRQ_TYPE_LEVEL_LOW:
-               if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq))           /* only supported on external interrupts */
+               if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq))               /* only supported on external interrupts */
                        srctype = AT91_AIC_SRCTYPE_LOW;
                else
                        return -EINVAL;
                break;
        case IRQ_TYPE_EDGE_FALLING:
-               if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq))           /* only supported on external interrupts */
+               if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq))               /* only supported on external interrupts */
                        srctype = AT91_AIC_SRCTYPE_FALLING;
                else
                        return -EINVAL;
@@ -78,8 +86,8 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
                return -EINVAL;
        }
 
-       smr = at91_aic_read(AT91_AIC_SMR(d->irq)) & ~AT91_AIC_SRCTYPE;
-       at91_aic_write(AT91_AIC_SMR(d->irq), smr | srctype);
+       smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
+       at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
        return 0;
 }
 
@@ -90,13 +98,13 @@ static u32 backups;
 
 static int at91_aic_set_wake(struct irq_data *d, unsigned value)
 {
-       if (unlikely(d->irq >= 32))
+       if (unlikely(d->hwirq >= NR_AIC_IRQS))
                return -EINVAL;
 
        if (value)
-               wakeups |= (1 << d->irq);
+               wakeups |= (1 << d->hwirq);
        else
-               wakeups &= ~(1 << d->irq);
+               wakeups &= ~(1 << d->hwirq);
 
        return 0;
 }
@@ -127,46 +135,112 @@ static struct irq_chip at91_aic_chip = {
        .irq_set_wake   = at91_aic_set_wake,
 };
 
+static void __init at91_aic_hw_init(unsigned int spu_vector)
+{
+       int i;
+
+       /*
+        * Perform 8 End Of Interrupt Command to make sure AIC
+        * will not Lock out nIRQ
+        */
+       for (i = 0; i < 8; i++)
+               at91_aic_write(AT91_AIC_EOICR, 0);
+
+       /*
+        * Spurious Interrupt ID in Spurious Vector Register.
+        * When there is no current interrupt, the IRQ Vector Register
+        * reads the value stored in AIC_SPU
+        */
+       at91_aic_write(AT91_AIC_SPU, spu_vector);
+
+       /* No debugging in AIC: Debug (Protect) Control Register */
+       at91_aic_write(AT91_AIC_DCR, 0);
+
+       /* Disable and clear all interrupts initially */
+       at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
+       at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
+}
+
+#if defined(CONFIG_OF)
+static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+                                                       irq_hw_number_t hw)
+{
+       /* Put virq number in Source Vector Register */
+       at91_aic_write(AT91_AIC_SVR(hw), virq);
+
+       /* Active Low interrupt, without priority */
+       at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
+
+       irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq);
+       set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+       return 0;
+}
+
+static struct irq_domain_ops at91_aic_irq_ops = {
+       .map    = at91_aic_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
+int __init at91_aic_of_init(struct device_node *node,
+                                    struct device_node *parent)
+{
+       at91_aic_base = of_iomap(node, 0);
+       at91_aic_np = node;
+
+       at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
+                                               &at91_aic_irq_ops, NULL);
+       if (!at91_aic_domain)
+               panic("Unable to add AIC irq domain (DT)\n");
+
+       irq_set_default_host(at91_aic_domain);
+
+       at91_aic_hw_init(NR_AIC_IRQS);
+
+       return 0;
+}
+#endif
+
 /*
  * Initialize the AIC interrupt controller.
  */
 void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
 {
        unsigned int i;
+       int irq_base;
 
        at91_aic_base = ioremap(AT91_AIC, 512);
-
        if (!at91_aic_base)
-               panic("Impossible to ioremap AT91_AIC\n");
+               panic("Unable to ioremap AIC registers\n");
+
+       /* Add irq domain for AIC */
+       irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0);
+       if (irq_base < 0) {
+               WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
+               irq_base = 0;
+       }
+       at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS,
+                                               irq_base, 0,
+                                               &irq_domain_simple_ops, NULL);
+
+       if (!at91_aic_domain)
+               panic("Unable to add AIC irq domain\n");
+
+       irq_set_default_host(at91_aic_domain);
 
        /*
         * The IVR is used by macro get_irqnr_and_base to read and verify.
         * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
         */
        for (i = 0; i < NR_AIC_IRQS; i++) {
-               /* Put irq number in Source Vector Register: */
+               /* Put hardware irq number in Source Vector Register: */
                at91_aic_write(AT91_AIC_SVR(i), i);
                /* Active Low interrupt, with the specified priority */
                at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
 
                irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
                set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-
-               /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */
-               if (i < 8)
-                       at91_aic_write(AT91_AIC_EOICR, 0);
        }
 
-       /*
-        * Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS
-        * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU
-        */
-       at91_aic_write(AT91_AIC_SPU, NR_AIC_IRQS);
-
-       /* No debugging in AIC: Debug (Protect) Control Register */
-       at91_aic_write(AT91_AIC_DCR, 0);
-
-       /* Disable and clear all interrupts initially */
-       at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
-       at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
+       at91_aic_hw_init(NR_AIC_IRQS);
 }
index 1606379..f630250 100644 (file)
@@ -136,7 +136,7 @@ static int at91_pm_verify_clocks(void)
        unsigned long scsr;
        int i;
 
-       scsr = at91_sys_read(AT91_PMC_SCSR);
+       scsr = at91_pmc_read(AT91_PMC_SCSR);
 
        /* USB must not be using PLLB */
        if (cpu_is_at91rm9200()) {
@@ -150,11 +150,6 @@ static int at91_pm_verify_clocks(void)
                        pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
                        return 0;
                }
-       } else if (cpu_is_at91cap9()) {
-               if ((scsr & AT91CAP9_PMC_UHP) != 0) {
-                       pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
-                       return 0;
-               }
        }
 
 #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
@@ -165,7 +160,7 @@ static int at91_pm_verify_clocks(void)
                if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
                        continue;
 
-               css = at91_sys_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
+               css = at91_pmc_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
                if (css != AT91_PMC_CSS_SLOW) {
                        pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
                        return 0;
@@ -193,23 +188,23 @@ int at91_suspend_entering_slow_clock(void)
 EXPORT_SYMBOL(at91_suspend_entering_slow_clock);
 
 
-static void (*slow_clock)(void);
+static void (*slow_clock)(void __iomem *pmc, void __iomem *ramc0,
+                         void __iomem *ramc1, int memctrl);
 
 #ifdef CONFIG_AT91_SLOW_CLOCK
-extern void at91_slow_clock(void);
+extern void at91_slow_clock(void __iomem *pmc, void __iomem *ramc0,
+                           void __iomem *ramc1, int memctrl);
 extern u32 at91_slow_clock_sz;
 #endif
 
-
 static int at91_pm_enter(suspend_state_t state)
 {
-       u32 saved_lpr;
        at91_gpio_suspend();
        at91_irq_suspend();
 
        pr_debug("AT91: PM - wake mask %08x, pm state %d\n",
                        /* remember all the always-wake irqs */
-                       (at91_sys_read(AT91_PMC_PCSR)
+                       (at91_pmc_read(AT91_PMC_PCSR)
                                        | (1 << AT91_ID_FIQ)
                                        | (1 << AT91_ID_SYS)
                                        | (at91_extern_irq))
@@ -234,11 +229,18 @@ static int at91_pm_enter(suspend_state_t state)
                         * turning off the main oscillator; reverse on wakeup.
                         */
                        if (slow_clock) {
+                               int memctrl = AT91_MEMCTRL_SDRAMC;
+
+                               if (cpu_is_at91rm9200())
+                                       memctrl = AT91_MEMCTRL_MC;
+                               else if (cpu_is_at91sam9g45())
+                                       memctrl = AT91_MEMCTRL_DDRSDR;
 #ifdef CONFIG_AT91_SLOW_CLOCK
                                /* copy slow_clock handler to SRAM, and call it */
                                memcpy(slow_clock, at91_slow_clock, at91_slow_clock_sz);
 #endif
-                               slow_clock();
+                               slow_clock(at91_pmc_base, at91_ramc_base[0],
+                                          at91_ramc_base[1], memctrl);
                                break;
                        } else {
                                pr_info("AT91: PM - no slow clock mode enabled ...\n");
@@ -259,16 +261,7 @@ static int at91_pm_enter(suspend_state_t state)
                         * For ARM 926 based chips, this requirement is weaker
                         * as at91sam9 can access a RAM in self-refresh mode.
                         */
-                       asm volatile (  "mov r0, #0\n\t"
-                                       "b 1f\n\t"
-                                       ".align 5\n\t"
-                                       "1: mcr p15, 0, r0, c7, c10, 4\n\t"
-                                       : /* no output */
-                                       : /* no input */
-                                       : "r0");
-                       saved_lpr = sdram_selfrefresh_enable();
-                       wait_for_interrupt_enable();
-                       sdram_selfrefresh_disable(saved_lpr);
+                       at91_standby();
                        break;
 
                case PM_SUSPEND_ON:
@@ -316,7 +309,7 @@ static int __init at91_pm_init(void)
 
 #ifdef CONFIG_ARCH_AT91RM9200
        /* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */
-       at91_sys_write(AT91_SDRAMC_LPR, 0);
+       at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
 #endif
 
        suspend_set_ops(&at91_pm_ops);
index 7eb40d2..89f56f3 100644 (file)
@@ -1,5 +1,19 @@
+/*
+ * AT91 Power Management
+ *
+ * Copyright (C) 2005 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __ARCH_ARM_MACH_AT91_PM
+#define __ARCH_ARM_MACH_AT91_PM
+
+#include <mach/at91_ramc.h>
 #ifdef CONFIG_ARCH_AT91RM9200
-#include <mach/at91rm9200_mc.h>
+#include <mach/at91rm9200_sdramc.h>
 
 /*
  * The AT91RM9200 goes into self-refresh mode with this command, and will
  * still in self-refresh is "not recommended", but seems to work.
  */
 
-static inline u32 sdram_selfrefresh_enable(void)
+static inline void at91rm9200_standby(void)
 {
-       u32 saved_lpr = at91_sys_read(AT91_SDRAMC_LPR);
-
-       at91_sys_write(AT91_SDRAMC_LPR, 0);
-       at91_sys_write(AT91_SDRAMC_SRR, 1);
-       return saved_lpr;
+       u32 lpr = at91_ramc_read(0, AT91RM9200_SDRAMC_LPR);
+
+       asm volatile(
+               "b    1f\n\t"
+               ".align    5\n\t"
+               "1:  mcr    p15, 0, %0, c7, c10, 4\n\t"
+               "    str    %0, [%1, %2]\n\t"
+               "    str    %3, [%1, %4]\n\t"
+               "    mcr    p15, 0, %0, c7, c0, 4\n\t"
+               "    str    %5, [%1, %2]"
+               :
+               : "r" (0), "r" (AT91_BASE_SYS), "r" (AT91RM9200_SDRAMC_LPR),
+                 "r" (1), "r" (AT91RM9200_SDRAMC_SRR),
+                 "r" (lpr));
 }
 
-#define sdram_selfrefresh_disable(saved_lpr)   at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
-#define wait_for_interrupt_enable()            asm volatile ("mcr p15, 0, %0, c7, c0, 4" \
-                                                               : : "r" (0))
-
-#elif defined(CONFIG_ARCH_AT91CAP9)
-#include <mach/at91sam9_ddrsdr.h>
-
-
-static inline u32 sdram_selfrefresh_enable(void)
-{
-       u32 saved_lpr, lpr;
-
-       saved_lpr = at91_ramc_read(0, AT91CAP9_DDRSDRC_LPR);
-
-       lpr = saved_lpr & ~AT91_DDRSDRC_LPCB;
-       at91_ramc_write(0, AT91CAP9_DDRSDRC_LPR, lpr | AT91_DDRSDRC_LPCB_SELF_REFRESH);
-       return saved_lpr;
-}
-
-#define sdram_selfrefresh_disable(saved_lpr)   at91_ramc_write(0, AT91CAP9_DDRSDRC_LPR, saved_lpr)
-#define wait_for_interrupt_enable()            cpu_do_idle()
+#define at91_standby at91rm9200_standby
 
 #elif defined(CONFIG_ARCH_AT91SAM9G45)
-#include <mach/at91sam9_ddrsdr.h>
 
 /* We manage both DDRAM/SDRAM controllers, we need more than one value to
  * remember.
  */
-static u32 saved_lpr1;
-
-static inline u32 sdram_selfrefresh_enable(void)
+static inline void at91sam9g45_standby(void)
 {
-       /* Those tow values allow us to delay self-refresh activation
+       /* Those two values allow us to delay self-refresh activation
         * to the maximum. */
        u32 lpr0, lpr1;
-       u32 saved_lpr0;
+       u32 saved_lpr0, saved_lpr1;
 
        saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
        lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
@@ -69,18 +69,15 @@ static inline u32 sdram_selfrefresh_enable(void)
        at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
        at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1);
 
-       return saved_lpr0;
+       cpu_do_idle();
+
+       at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
+       at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
 }
 
-#define sdram_selfrefresh_disable(saved_lpr0)  \
-       do { \
-               at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); \
-               at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); \
-       } while (0)
-#define wait_for_interrupt_enable()            cpu_do_idle()
+#define at91_standby at91sam9g45_standby
 
 #else
-#include <mach/at91sam9_sdramc.h>
 
 #ifdef CONFIG_ARCH_AT91SAM9263
 /*
@@ -90,18 +87,23 @@ static inline u32 sdram_selfrefresh_enable(void)
 #warning Assuming EB1 SDRAM controller is *NOT* used
 #endif
 
-static inline u32 sdram_selfrefresh_enable(void)
+static inline void at91sam9_standby(void)
 {
        u32 saved_lpr, lpr;
 
        saved_lpr = at91_ramc_read(0, AT91_SDRAMC_LPR);
 
        lpr = saved_lpr & ~AT91_SDRAMC_LPCB;
-       at91_ramc_write(0, AT91_SDRAMC_LPR, lpr | AT91_SDRAMC_LPCB_SELF_REFRESH);
-       return saved_lpr;
+       at91_ramc_write(0, AT91_SDRAMC_LPR, lpr |
+                       AT91_SDRAMC_LPCB_SELF_REFRESH);
+
+       cpu_do_idle();
+
+       at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr);
 }
 
-#define sdram_selfrefresh_disable(saved_lpr)   at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr)
-#define wait_for_interrupt_enable()            cpu_do_idle()
+#define at91_standby at91sam9_standby
+
+#endif
 
 #endif
index 92dfb84..db54521 100644 (file)
 #include <linux/linkage.h>
 #include <mach/hardware.h>
 #include <mach/at91_pmc.h>
-
-#if defined(CONFIG_ARCH_AT91RM9200)
-#include <mach/at91rm9200_mc.h>
-#elif defined(CONFIG_ARCH_AT91CAP9) \
-       || defined(CONFIG_ARCH_AT91SAM9G45)
-#include <mach/at91sam9_ddrsdr.h>
-#else
-#include <mach/at91sam9_sdramc.h>
-#endif
+#include <mach/at91_ramc.h>
 
 
 #ifdef CONFIG_ARCH_AT91SAM9263
 #define PLLALOCK_TIMEOUT       1000
 #define PLLBLOCK_TIMEOUT       1000
 
+pmc    .req    r0
+sdramc .req    r1
+ramc1  .req    r2
+memctrl        .req    r3
+tmp1   .req    r4
+tmp2   .req    r5
 
 /*
  * Wait until master clock is ready (after switching master clock source)
  */
        .macro wait_mckrdy
-       mov     r4, #MCKRDY_TIMEOUT
-1:     sub     r4, r4, #1
-       cmp     r4, #0
+       mov     tmp2, #MCKRDY_TIMEOUT
+1:     sub     tmp2, tmp2, #1
+       cmp     tmp2, #0
        beq     2f
-       ldr     r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
-       tst     r3, #AT91_PMC_MCKRDY
+       ldr     tmp1, [pmc, #AT91_PMC_SR]
+       tst     tmp1, #AT91_PMC_MCKRDY
        beq     1b
 2:
        .endm
  * Wait until master oscillator has stabilized.
  */
        .macro wait_moscrdy
-       mov     r4, #MOSCRDY_TIMEOUT
-1:     sub     r4, r4, #1
-       cmp     r4, #0
+       mov     tmp2, #MOSCRDY_TIMEOUT
+1:     sub     tmp2, tmp2, #1
+       cmp     tmp2, #0
        beq     2f
-       ldr     r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
-       tst     r3, #AT91_PMC_MOSCS
+       ldr     tmp1, [pmc, #AT91_PMC_SR]
+       tst     tmp1, #AT91_PMC_MOSCS
        beq     1b
 2:
        .endm
  * Wait until PLLA has locked.
  */
        .macro wait_pllalock
-       mov     r4, #PLLALOCK_TIMEOUT
-1:     sub     r4, r4, #1
-       cmp     r4, #0
+       mov     tmp2, #PLLALOCK_TIMEOUT
+1:     sub     tmp2, tmp2, #1
+       cmp     tmp2, #0
        beq     2f
-       ldr     r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
-       tst     r3, #AT91_PMC_LOCKA
+       ldr     tmp1, [pmc, #AT91_PMC_SR]
+       tst     tmp1, #AT91_PMC_LOCKA
        beq     1b
 2:
        .endm
  * Wait until PLLB has locked.
  */
        .macro wait_pllblock
-       mov     r4, #PLLBLOCK_TIMEOUT
-1:     sub     r4, r4, #1
-       cmp     r4, #0
+       mov     tmp2, #PLLBLOCK_TIMEOUT
+1:     sub     tmp2, tmp2, #1
+       cmp     tmp2, #0
        beq     2f
-       ldr     r3, [r1, #(AT91_PMC_SR - AT91_PMC)]
-       tst     r3, #AT91_PMC_LOCKB
+       ldr     tmp1, [pmc, #AT91_PMC_SR]
+       tst     tmp1, #AT91_PMC_LOCKB
        beq     1b
 2:
        .endm
 
        .text
 
+/* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc,
+ *                     void __iomem *ramc1, int memctrl)
+ */
 ENTRY(at91_slow_clock)
        /* Save registers on stack */
-       stmfd   sp!, {r0 - r12, lr}
+       stmfd   sp!, {r4 - r12, lr}
 
        /*
         * Register usage:
-        *  R1 = Base address of AT91_PMC
-        *  R2 = Base address of RAM Controller (SDRAM, DDRSDR, or AT91_SYS)
-        *  R3 = temporary register
+        *  R0 = Base address of AT91_PMC
+        *  R1 = Base address of RAM Controller (SDRAM, DDRSDR, or AT91_SYS)
+        *  R2 = Base address of second RAM Controller or 0 if not present
+        *  R3 = Memory controller
         *  R4 = temporary register
-        *  R5 = Base address of second RAM Controller or 0 if not present
+        *  R5 = temporary register
         */
-       ldr     r1, .at91_va_base_pmc
-       ldr     r2, .at91_va_base_sdramc
-       ldr     r5, .at91_va_base_ramc1
 
        /* Drain write buffer */
-       mov     r0, #0
-       mcr     p15, 0, r0, c7, c10, 4
+       mov     tmp1, #0
+       mcr     p15, 0, tmp1, c7, c10, 4
+
+       cmp     memctrl, #AT91_MEMCTRL_MC
+       bne     ddr_sr_enable
 
-#ifdef CONFIG_ARCH_AT91RM9200
+       /*
+        * at91rm9200 Memory controller
+        */
        /* Put SDRAM in self-refresh mode */
-       mov     r3, #1
-       str     r3, [r2, #AT91_SDRAMC_SRR]
-#elif defined(CONFIG_ARCH_AT91CAP9) \
-       || defined(CONFIG_ARCH_AT91SAM9G45)
+       mov     tmp1, #1
+       str     tmp1, [sdramc, #AT91RM9200_SDRAMC_SRR]
+       b       sdr_sr_done
+
+       /*
+        * DDRSDR Memory controller
+        */
+ddr_sr_enable:
+       cmp     memctrl, #AT91_MEMCTRL_DDRSDR
+       bne     sdr_sr_enable
 
        /* prepare for DDRAM self-refresh mode */
-       ldr     r3, [r2, #AT91_DDRSDRC_LPR]
-       str     r3, .saved_sam9_lpr
-       bic     r3, #AT91_DDRSDRC_LPCB
-       orr     r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+       ldr     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
+       str     tmp1, .saved_sam9_lpr
+       bic     tmp1, #AT91_DDRSDRC_LPCB
+       orr     tmp1, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
        /* figure out if we use the second ram controller */
-       cmp     r5, #0
-       ldrne   r4, [r5, #AT91_DDRSDRC_LPR]
-       strne   r4, .saved_sam9_lpr1
-       bicne   r4, #AT91_DDRSDRC_LPCB
-       orrne   r4, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+       cmp     ramc1, #0
+       ldrne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+       strne   tmp2, .saved_sam9_lpr1
+       bicne   tmp2, #AT91_DDRSDRC_LPCB
+       orrne   tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
 
        /* Enable DDRAM self-refresh mode */
-       str     r3, [r2, #AT91_DDRSDRC_LPR]
-       strne   r4, [r5, #AT91_DDRSDRC_LPR]
-#else
+       str     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
+       strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+
+       b       sdr_sr_done
+
+       /*
+        * SDRAMC Memory controller
+        */
+sdr_sr_enable:
        /* Enable SDRAM self-refresh mode */
-       ldr     r3, [r2, #AT91_SDRAMC_LPR]
-       str     r3, .saved_sam9_lpr
+       ldr     tmp1, [sdramc, #AT91_SDRAMC_LPR]
+       str     tmp1, .saved_sam9_lpr
 
-       bic     r3, #AT91_SDRAMC_LPCB
-       orr     r3, #AT91_SDRAMC_LPCB_SELF_REFRESH
-       str     r3, [r2, #AT91_SDRAMC_LPR]
-#endif
+       bic     tmp1, #AT91_SDRAMC_LPCB
+       orr     tmp1, #AT91_SDRAMC_LPCB_SELF_REFRESH
+       str     tmp1, [sdramc, #AT91_SDRAMC_LPR]
 
+sdr_sr_done:
        /* Save Master clock setting */
-       ldr     r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
-       str     r3, .saved_mckr
+       ldr     tmp1, [pmc, #AT91_PMC_MCKR]
+       str     tmp1, .saved_mckr
 
        /*
         * Set the Master clock source to slow clock
         */
-       bic     r3, r3, #AT91_PMC_CSS
-       str     r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+       bic     tmp1, tmp1, #AT91_PMC_CSS
+       str     tmp1, [pmc, #AT91_PMC_MCKR]
 
        wait_mckrdy
 
@@ -177,61 +193,61 @@ ENTRY(at91_slow_clock)
         *
         * See AT91RM9200 errata #27 and #28 for details.
         */
-       mov     r3, #0
-       str     r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+       mov     tmp1, #0
+       str     tmp1, [pmc, #AT91_PMC_MCKR]
 
        wait_mckrdy
 #endif
 
        /* Save PLLA setting and disable it */
-       ldr     r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
-       str     r3, .saved_pllar
+       ldr     tmp1, [pmc, #AT91_CKGR_PLLAR]
+       str     tmp1, .saved_pllar
 
-       mov     r3, #AT91_PMC_PLLCOUNT
-       orr     r3, r3, #(1 << 29)              /* bit 29 always set */
-       str     r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
+       mov     tmp1, #AT91_PMC_PLLCOUNT
+       orr     tmp1, tmp1, #(1 << 29)          /* bit 29 always set */
+       str     tmp1, [pmc, #AT91_CKGR_PLLAR]
 
        /* Save PLLB setting and disable it */
-       ldr     r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
-       str     r3, .saved_pllbr
+       ldr     tmp1, [pmc, #AT91_CKGR_PLLBR]
+       str     tmp1, .saved_pllbr
 
-       mov     r3, #AT91_PMC_PLLCOUNT
-       str     r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
+       mov     tmp1, #AT91_PMC_PLLCOUNT
+       str     tmp1, [pmc, #AT91_CKGR_PLLBR]
 
        /* Turn off the main oscillator */
-       ldr     r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
-       bic     r3, r3, #AT91_PMC_MOSCEN
-       str     r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
+       ldr     tmp1, [pmc, #AT91_CKGR_MOR]
+       bic     tmp1, tmp1, #AT91_PMC_MOSCEN
+       str     tmp1, [pmc, #AT91_CKGR_MOR]
 
        /* Wait for interrupt */
-       mcr     p15, 0, r0, c7, c0, 4
+       mcr     p15, 0, tmp1, c7, c0, 4
 
        /* Turn on the main oscillator */
-       ldr     r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
-       orr     r3, r3, #AT91_PMC_MOSCEN
-       str     r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
+       ldr     tmp1, [pmc, #AT91_CKGR_MOR]
+       orr     tmp1, tmp1, #AT91_PMC_MOSCEN
+       str     tmp1, [pmc, #AT91_CKGR_MOR]
 
        wait_moscrdy
 
        /* Restore PLLB setting */
-       ldr     r3, .saved_pllbr
-       str     r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
+       ldr     tmp1, .saved_pllbr
+       str     tmp1, [pmc, #AT91_CKGR_PLLBR]
 
-       tst     r3, #(AT91_PMC_MUL &  0xff0000)
+       tst     tmp1, #(AT91_PMC_MUL &  0xff0000)
        bne     1f
-       tst     r3, #(AT91_PMC_MUL & ~0xff0000)
+       tst     tmp1, #(AT91_PMC_MUL & ~0xff0000)
        beq     2f
 1:
        wait_pllblock
 2:
 
        /* Restore PLLA setting */
-       ldr     r3, .saved_pllar
-       str     r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
+       ldr     tmp1, .saved_pllar
+       str     tmp1, [pmc, #AT91_CKGR_PLLAR]
 
-       tst     r3, #(AT91_PMC_MUL &  0xff0000)
+       tst     tmp1, #(AT91_PMC_MUL &  0xff0000)
        bne     3f
-       tst     r3, #(AT91_PMC_MUL & ~0xff0000)
+       tst     tmp1, #(AT91_PMC_MUL & ~0xff0000)
        beq     4f
 3:
        wait_pllalock
@@ -244,11 +260,11 @@ ENTRY(at91_slow_clock)
         *
         * See AT91RM9200 errata #27 and #28 for details.
         */
-       ldr     r3, .saved_mckr
-       tst     r3, #AT91_PMC_PRES
+       ldr     tmp1, .saved_mckr
+       tst     tmp1, #AT91_PMC_PRES
        beq     2f
-       and     r3, r3, #AT91_PMC_PRES
-       str     r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+       and     tmp1, tmp1, #AT91_PMC_PRES
+       str     tmp1, [pmc, #AT91_PMC_MCKR]
 
        wait_mckrdy
 #endif
@@ -256,32 +272,45 @@ ENTRY(at91_slow_clock)
        /*
         * Restore master clock setting
         */
-2:     ldr     r3, .saved_mckr
-       str     r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)]
+2:     ldr     tmp1, .saved_mckr
+       str     tmp1, [pmc, #AT91_PMC_MCKR]
 
        wait_mckrdy
 
-#ifdef CONFIG_ARCH_AT91RM9200
-       /* Do nothing - self-refresh is automatically disabled. */
-#elif defined(CONFIG_ARCH_AT91CAP9) \
-       || defined(CONFIG_ARCH_AT91SAM9G45)
+       /*
+        * at91rm9200 Memory controller
+        * Do nothing - self-refresh is automatically disabled.
+        */
+       cmp     memctrl, #AT91_MEMCTRL_MC
+       beq     ram_restored
+
+       /*
+        * DDRSDR Memory controller
+        */
+       cmp     memctrl, #AT91_MEMCTRL_DDRSDR
+       bne     sdr_en_restore
        /* Restore LPR on AT91 with DDRAM */
-       ldr     r3, .saved_sam9_lpr
-       str     r3, [r2, #AT91_DDRSDRC_LPR]
+       ldr     tmp1, .saved_sam9_lpr
+       str     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
 
        /* if we use the second ram controller */
-       cmp     r5, #0
-       ldrne   r4, .saved_sam9_lpr1
-       strne   r4, [r5, #AT91_DDRSDRC_LPR]
+       cmp     ramc1, #0
+       ldrne   tmp2, .saved_sam9_lpr1
+       strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
+
+       b       ram_restored
 
-#else
+       /*
+        * SDRAMC Memory controller
+        */
+sdr_en_restore:
        /* Restore LPR on AT91 with SDRAM */
-       ldr     r3, .saved_sam9_lpr
-       str     r3, [r2, #AT91_SDRAMC_LPR]
-#endif
+       ldr     tmp1, .saved_sam9_lpr
+       str     tmp1, [sdramc, #AT91_SDRAMC_LPR]
 
+ram_restored:
        /* Restore registers, and return */
-       ldmfd   sp!, {r0 - r12, pc}
+       ldmfd   sp!, {r4 - r12, pc}
 
 
 .saved_mckr:
@@ -299,27 +328,5 @@ ENTRY(at91_slow_clock)
 .saved_sam9_lpr1:
        .word 0
 
-.at91_va_base_pmc:
-       .word AT91_VA_BASE_SYS + AT91_PMC
-
-#ifdef CONFIG_ARCH_AT91RM9200
-.at91_va_base_sdramc:
-       .word AT91_VA_BASE_SYS
-#elif defined(CONFIG_ARCH_AT91CAP9) \
-       || defined(CONFIG_ARCH_AT91SAM9G45)
-.at91_va_base_sdramc:
-       .word AT91_VA_BASE_SYS + AT91_DDRSDRC0
-#else
-.at91_va_base_sdramc:
-       .word AT91_VA_BASE_SYS + AT91_SDRAMC0
-#endif
-
-.at91_va_base_ramc1:
-#if defined(CONFIG_ARCH_AT91SAM9G45)
-       .word AT91_VA_BASE_SYS + AT91_DDRSDRC1
-#else
-       .word 0
-#endif
-
 ENTRY(at91_slow_clock_sz)
        .word .-at91_slow_clock
index 69d3fc4..1083739 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/io.h>
 #include <linux/mm.h>
 #include <linux/pm.h>
+#include <linux/of_address.h>
 
 #include <asm/mach/map.h>
 
@@ -51,6 +52,19 @@ void __init at91_init_interrupts(unsigned int *priority)
        at91_gpio_irq_setup();
 }
 
+void __iomem *at91_ramc_base[2];
+
+void __init at91_ioremap_ramc(int id, u32 addr, u32 size)
+{
+       if (id < 0 || id > 1) {
+               pr_emerg("Wrong RAM controller id (%d), cannot continue\n", id);
+               BUG();
+       }
+       at91_ramc_base[id] = ioremap(addr, size);
+       if (!at91_ramc_base[id])
+               panic("Impossible to ioremap ramc.%d 0x%x\n", id, addr);
+}
+
 static struct map_desc sram_desc[2] __initdata;
 
 void __init at91_init_sram(int bank, unsigned long base, unsigned int length)
@@ -86,20 +100,6 @@ static void __init soc_detect(u32 dbgu_base)
        socid = cidr & ~AT91_CIDR_VERSION;
 
        switch (socid) {
-       case ARCH_ID_AT91CAP9: {
-#ifdef CONFIG_AT91_PMC_UNIT
-               u32 pmc_ver = at91_sys_read(AT91_PMC_VER);
-
-               if (pmc_ver == ARCH_REVISION_CAP9_B)
-                       at91_soc_initdata.subtype = AT91_SOC_CAP9_REV_B;
-               else if (pmc_ver == ARCH_REVISION_CAP9_C)
-                       at91_soc_initdata.subtype = AT91_SOC_CAP9_REV_C;
-#endif
-               at91_soc_initdata.type = AT91_SOC_CAP9;
-               at91_boot_soc = at91cap9_soc;
-               break;
-       }
-
        case ARCH_ID_AT91RM9200:
                at91_soc_initdata.type = AT91_SOC_RM9200;
                at91_boot_soc = at91rm9200_soc;
@@ -200,7 +200,6 @@ static void __init soc_detect(u32 dbgu_base)
 
 static const char *soc_name[] = {
        [AT91_SOC_RM9200]       = "at91rm9200",
-       [AT91_SOC_CAP9]         = "at91cap9",
        [AT91_SOC_SAM9260]      = "at91sam9260",
        [AT91_SOC_SAM9261]      = "at91sam9261",
        [AT91_SOC_SAM9263]      = "at91sam9263",
@@ -221,8 +220,6 @@ EXPORT_SYMBOL(at91_get_soc_type);
 static const char *soc_subtype_name[] = {
        [AT91_SOC_RM9200_BGA]   = "at91rm9200 BGA",
        [AT91_SOC_RM9200_PQFP]  = "at91rm9200 PQFP",
-       [AT91_SOC_CAP9_REV_B]   = "at91cap9 revB",
-       [AT91_SOC_CAP9_REV_C]   = "at91cap9 revC",
        [AT91_SOC_SAM9XE]       = "at91sam9xe",
        [AT91_SOC_SAM9G45ES]    = "at91sam9g45es",
        [AT91_SOC_SAM9M10]      = "at91sam9m10",
@@ -293,6 +290,159 @@ void __init at91_ioremap_rstc(u32 base_addr)
                panic("Impossible to ioremap at91_rstc_base\n");
 }
 
+void __iomem *at91_matrix_base;
+
+void __init at91_ioremap_matrix(u32 base_addr)
+{
+       at91_matrix_base = ioremap(base_addr, 512);
+       if (!at91_matrix_base)
+               panic("Impossible to ioremap at91_matrix_base\n");
+}
+
+#if defined(CONFIG_OF)
+static struct of_device_id rstc_ids[] = {
+       { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9_alt_restart },
+       { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart },
+       { /*sentinel*/ }
+};
+
+static void at91_dt_rstc(void)
+{
+       struct device_node *np;
+       const struct of_device_id *of_id;
+
+       np = of_find_matching_node(NULL, rstc_ids);
+       if (!np)
+               panic("unable to find compatible rstc node in dtb\n");
+
+       at91_rstc_base = of_iomap(np, 0);
+       if (!at91_rstc_base)
+               panic("unable to map rstc cpu registers\n");
+
+       of_id = of_match_node(rstc_ids, np);
+       if (!of_id)
+               panic("AT91: rtsc no restart function availlable\n");
+
+       arm_pm_restart = of_id->data;
+
+       of_node_put(np);
+}
+
+static struct of_device_id ramc_ids[] = {
+       { .compatible = "atmel,at91sam9260-sdramc" },
+       { .compatible = "atmel,at91sam9g45-ddramc" },
+       { /*sentinel*/ }
+};
+
+static void at91_dt_ramc(void)
+{
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, ramc_ids);
+       if (!np)
+               panic("unable to find compatible ram conroller node in dtb\n");
+
+       at91_ramc_base[0] = of_iomap(np, 0);
+       if (!at91_ramc_base[0])
+               panic("unable to map ramc[0] cpu registers\n");
+       /* the controller may have 2 banks */
+       at91_ramc_base[1] = of_iomap(np, 1);
+
+       of_node_put(np);
+}
+
+static struct of_device_id shdwc_ids[] = {
+       { .compatible = "atmel,at91sam9260-shdwc", },
+       { .compatible = "atmel,at91sam9rl-shdwc", },
+       { .compatible = "atmel,at91sam9x5-shdwc", },
+       { /*sentinel*/ }
+};
+
+static const char *shdwc_wakeup_modes[] = {
+       [AT91_SHDW_WKMODE0_NONE]        = "none",
+       [AT91_SHDW_WKMODE0_HIGH]        = "high",
+       [AT91_SHDW_WKMODE0_LOW]         = "low",
+       [AT91_SHDW_WKMODE0_ANYLEVEL]    = "any",
+};
+
+const int at91_dtget_shdwc_wakeup_mode(struct device_node *np)
+{
+       const char *pm;
+       int err, i;
+
+       err = of_property_read_string(np, "atmel,wakeup-mode", &pm);
+       if (err < 0)
+               return AT91_SHDW_WKMODE0_ANYLEVEL;
+
+       for (i = 0; i < ARRAY_SIZE(shdwc_wakeup_modes); i++)
+               if (!strcasecmp(pm, shdwc_wakeup_modes[i]))
+                       return i;
+
+       return -ENODEV;
+}
+
+static void at91_dt_shdwc(void)
+{
+       struct device_node *np;
+       int wakeup_mode;
+       u32 reg;
+       u32 mode = 0;
+
+       np = of_find_matching_node(NULL, shdwc_ids);
+       if (!np) {
+               pr_debug("AT91: unable to find compatible shutdown (shdwc) conroller node in dtb\n");
+               return;
+       }
+
+       at91_shdwc_base = of_iomap(np, 0);
+       if (!at91_shdwc_base)
+               panic("AT91: unable to map shdwc cpu registers\n");
+
+       wakeup_mode = at91_dtget_shdwc_wakeup_mode(np);
+       if (wakeup_mode < 0) {
+               pr_warn("AT91: shdwc unknown wakeup mode\n");
+               goto end;
+       }
+
+       if (!of_property_read_u32(np, "atmel,wakeup-counter", &reg)) {
+               if (reg > AT91_SHDW_CPTWK0_MAX) {
+                       pr_warn("AT91: shdwc wakeup conter 0x%x > 0x%x reduce it to 0x%x\n",
+                               reg, AT91_SHDW_CPTWK0_MAX, AT91_SHDW_CPTWK0_MAX);
+                       reg = AT91_SHDW_CPTWK0_MAX;
+               }
+               mode |= AT91_SHDW_CPTWK0_(reg);
+       }
+
+       if (of_property_read_bool(np, "atmel,wakeup-rtc-timer"))
+                       mode |= AT91_SHDW_RTCWKEN;
+
+       if (of_property_read_bool(np, "atmel,wakeup-rtt-timer"))
+                       mode |= AT91_SHDW_RTTWKEN;
+
+       at91_shdwc_write(AT91_SHDW_MR, wakeup_mode | mode);
+
+end:
+       pm_power_off = at91sam9_poweroff;
+
+       of_node_put(np);
+}
+
+void __init at91_dt_initialize(void)
+{
+       at91_dt_rstc();
+       at91_dt_ramc();
+       at91_dt_shdwc();
+
+       /* Init clock subsystem */
+       at91_dt_clock_init();
+
+       /* Register the processor-specific clocks */
+       at91_boot_soc.register_clocks();
+
+       at91_boot_soc.init();
+}
+#endif
+
 void __init at91_initialize(unsigned long main_clock)
 {
        at91_boot_soc.ioremap_registers();
index 4588ae6..5db4aa4 100644 (file)
@@ -13,7 +13,6 @@ struct at91_init_soc {
 };
 
 extern struct at91_init_soc at91_boot_soc;
-extern struct at91_init_soc at91cap9_soc;
 extern struct at91_init_soc at91rm9200_soc;
 extern struct at91_init_soc at91sam9260_soc;
 extern struct at91_init_soc at91sam9261_soc;
@@ -27,10 +26,6 @@ static inline int at91_soc_is_enabled(void)
        return at91_boot_soc.init != NULL;
 }
 
-#if !defined(CONFIG_ARCH_AT91CAP9)
-#define at91cap9_soc   at91_boot_soc
-#endif
-
 #if !defined(CONFIG_ARCH_AT91RM9200)
 #define at91rm9200_soc at91_boot_soc
 #endif
index 6b67b7e..22e4e0a 100644 (file)
 #include <mach/csp/chipcHw_inline.h>
 #include <mach/csp/tmrHw_reg.h>
 
-#define AMBA_DEVICE(name, initname, base, plat, size)       \
-static struct amba_device name##_device = {     \
-   .dev = {                                     \
-      .coherent_dma_mask = ~0,                  \
-      .init_name = initname,                    \
-      .platform_data = plat                     \
-   },                                           \
-   .res = {                                     \
-      .start = MM_ADDR_IO_##base,               \
-               .end = MM_ADDR_IO_##base + (size) - 1,    \
-      .flags = IORESOURCE_MEM                   \
-   },                                           \
-   .dma_mask = ~0,                              \
-   .irq = {                                     \
-      IRQ_##base                                \
-   }                                            \
-}
-
-
-AMBA_DEVICE(uartA, "uarta", UARTA, NULL, SZ_4K);
-AMBA_DEVICE(uartB, "uartb", UARTB, NULL, SZ_4K);
+static AMBA_APB_DEVICE(uartA, "uarta", MM_ADDR_IO_UARTA, { IRQ_UARTA }, NULL);
+static AMBA_APB_DEVICE(uartB, "uartb", MM_ADDR_IO_UARTB, { IRQ_UARTB }, NULL);
 
 static struct clk pll1_clk = {
        .name = "PLL1",
index 94c950d..2f316f0 100644 (file)
@@ -21,9 +21,6 @@
 #include <mach/hardware.h>
 #include <mach/csp/mm_io.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \base, =(MM_IO_BASE_INTC0)
                ldr     \irqstat, [\base, #0]           @ get status
@@ -77,6 +74,3 @@
 
                .macro  get_irqnr_preamble, base, tmp
                .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-bcmring/include/mach/system.h b/arch/arm/mach-bcmring/include/mach/system.h
deleted file mode 100644 (file)
index cb78250..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
index ac84f92..3c5b5bb 100644 (file)
@@ -226,3 +226,19 @@ void clps711x_restart(char mode, const char *cmd)
 {
        soft_restart(0);
 }
+
+static void clps711x_idle(void)
+{
+       clps_writel(1, HALT);
+       __asm__ __volatile__(
+       "mov    r0, r0\n\
+       mov     r0, r0");
+}
+
+static int __init clps711x_idle_init(void)
+{
+       arm_pm_idle = clps711x_idle;
+       return 0;
+}
+
+arch_initcall(clps711x_idle_init);
index 90fa2f7..125af59 100644 (file)
 #include <mach/hardware.h>
 #include <asm/hardware/clps7111.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
 #if (INTSR2 - INTSR1) != (INTMR2 - INTMR1)
 #error INTSR stride != INTMR stride
 #endif
diff --git a/arch/arm/mach-clps711x/include/mach/system.h b/arch/arm/mach-clps711x/include/mach/system.h
deleted file mode 100644 (file)
index 23d6ef8..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  arch/arm/mach-clps711x/include/mach/system.h
- *
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <asm/hardware/clps7111.h>
-
-static inline void arch_idle(void)
-{
-       clps_writel(1, HALT);
-       __asm__ __volatile__(
-       "mov    r0, r0\n\
-       mov     r0, r0");
-}
-
-#endif
diff --git a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S b/arch/arm/mach-cns3xxx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 01c57df..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Low-level IRQ helper macros for Cavium Networks platforms
- *
- * Copyright 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.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-cns3xxx/include/mach/system.h b/arch/arm/mach-cns3xxx/include/mach/system.h
deleted file mode 100644 (file)
index 9e56b7d..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2000 Deep Blue Solutions Ltd
- * Copyright 2003 ARM Limited
- * Copyright 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.
- */
-
-#ifndef __MACH_SYSTEM_H
-#define __MACH_SYSTEM_H
-
-#include <asm/proc-fns.h>
-
-static inline void arch_idle(void)
-{
-       /*
-        * This should do all the clock switching
-        * and wait for interrupt tricks
-        */
-       cpu_do_idle();
-}
-
-#endif
index e159d69..79d001f 100644 (file)
@@ -155,8 +155,8 @@ static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys)
        BUG_ON(request_resource(&iomem_resource, res_io) ||
               request_resource(&iomem_resource, res_mem));
 
-       pci_add_resource(&sys->resources, res_io);
-       pci_add_resource(&sys->resources, res_mem);
+       pci_add_resource_offset(&sys->resources, res_io, sys->io_offset);
+       pci_add_resource_offset(&sys->resources, res_mem, sys->mem_offset);
 
        return 1;
 }
index 275341f..82ed753 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/dm355.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
 #include <mach/nand.h>
 #include <mach/mmc.h>
 #include <mach/usb.h>
 
+#include "davinci.h"
+
 /* NOTE:  this is geared for the standard config, with a socketed
  * 2 GByte Micron NAND (MT29F16G08FAA) using 128KB sectors.  If you
  * swap chips, maybe with a different block size, partitioning may
index e99db28..d74a8b3 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/dm355.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
 #include <mach/nand.h>
 #include <mach/mmc.h>
 #include <mach/usb.h>
 
+#include "davinci.h"
+
 /* NOTE:  this is geared for the standard config, with a socketed
  * 2 GByte Micron NAND (MT29F16G08FAA) using 128KB sectors.  If you
  * swap chips, maybe with a different block size, partitioning may
index 849311d..5bce2b8 100644 (file)
@@ -32,7 +32,6 @@
 #include <asm/mach/arch.h>
 
 #include <mach/mux.h>
-#include <mach/dm365.h>
 #include <mach/common.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
@@ -42,6 +41,8 @@
 
 #include <media/tvp514x.h>
 
+#include "davinci.h"
+
 static inline int have_imager(void)
 {
        /* REVISIT when it's supported, trigger via Kconfig */
index 1247ecd..3683306 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/dm644x.h>
 #include <mach/common.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
@@ -40,6 +39,8 @@
 #include <mach/usb.h>
 #include <mach/aemif.h>
 
+#include "davinci.h"
+
 #define DM644X_EVM_PHY_ID              "davinci_mdio-0:01"
 #define LXT971_PHY_ID  (0x001378e2)
 #define LXT971_PHY_MASK        (0xfffffff0)
@@ -189,7 +190,7 @@ static struct platform_device davinci_fb_device = {
        .num_resources = 0,
 };
 
-static struct tvp514x_platform_data tvp5146_pdata = {
+static struct tvp514x_platform_data dm644xevm_tvp5146_pdata = {
        .clk_polarity = 0,
        .hs_polarity = 1,
        .vs_polarity = 1
@@ -197,7 +198,7 @@ static struct tvp514x_platform_data tvp5146_pdata = {
 
 #define TVP514X_STD_ALL        (V4L2_STD_NTSC | V4L2_STD_PAL)
 /* Inputs available at the TVP5146 */
-static struct v4l2_input tvp5146_inputs[] = {
+static struct v4l2_input dm644xevm_tvp5146_inputs[] = {
        {
                .index = 0,
                .name = "Composite",
@@ -217,7 +218,7 @@ static struct v4l2_input tvp5146_inputs[] = {
  * ouput that goes to vpfe. There is a one to one correspondence
  * with tvp5146_inputs
  */
-static struct vpfe_route tvp5146_routes[] = {
+static struct vpfe_route dm644xevm_tvp5146_routes[] = {
        {
                .input = INPUT_CVBS_VI2B,
                .output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
@@ -228,13 +229,13 @@ static struct vpfe_route tvp5146_routes[] = {
        },
 };
 
-static struct vpfe_subdev_info vpfe_sub_devs[] = {
+static struct vpfe_subdev_info dm644xevm_vpfe_sub_devs[] = {
        {
                .name = "tvp5146",
                .grp_id = 0,
-               .num_inputs = ARRAY_SIZE(tvp5146_inputs),
-               .inputs = tvp5146_inputs,
-               .routes = tvp5146_routes,
+               .num_inputs = ARRAY_SIZE(dm644xevm_tvp5146_inputs),
+               .inputs = dm644xevm_tvp5146_inputs,
+               .routes = dm644xevm_tvp5146_routes,
                .can_route = 1,
                .ccdc_if_params = {
                        .if_type = VPFE_BT656,
@@ -243,15 +244,15 @@ static struct vpfe_subdev_info vpfe_sub_devs[] = {
                },
                .board_info = {
                        I2C_BOARD_INFO("tvp5146", 0x5d),
-                       .platform_data = &tvp5146_pdata,
+                       .platform_data = &dm644xevm_tvp5146_pdata,
                },
        },
 };
 
-static struct vpfe_config vpfe_cfg = {
-       .num_subdevs = ARRAY_SIZE(vpfe_sub_devs),
+static struct vpfe_config dm644xevm_capture_cfg = {
+       .num_subdevs = ARRAY_SIZE(dm644xevm_vpfe_sub_devs),
        .i2c_adapter_id = 1,
-       .sub_devs = vpfe_sub_devs,
+       .sub_devs = dm644xevm_vpfe_sub_devs,
        .card_name = "DM6446 EVM",
        .ccdc = "DM6446 CCDC",
 };
@@ -612,6 +613,113 @@ static void __init evm_init_i2c(void)
        i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
 }
 
+#define VENC_STD_ALL   (V4L2_STD_NTSC | V4L2_STD_PAL)
+
+/* venc standard timings */
+static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = {
+       {
+               .name           = "ntsc",
+               .timings_type   = VPBE_ENC_STD,
+               .timings        = {V4L2_STD_525_60},
+               .interlaced     = 1,
+               .xres           = 720,
+               .yres           = 480,
+               .aspect         = {11, 10},
+               .fps            = {30000, 1001},
+               .left_margin    = 0x79,
+               .upper_margin   = 0x10,
+       },
+       {
+               .name           = "pal",
+               .timings_type   = VPBE_ENC_STD,
+               .timings        = {V4L2_STD_625_50},
+               .interlaced     = 1,
+               .xres           = 720,
+               .yres           = 576,
+               .aspect         = {54, 59},
+               .fps            = {25, 1},
+               .left_margin    = 0x7e,
+               .upper_margin   = 0x16,
+       },
+};
+
+/* venc dv preset timings */
+static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = {
+       {
+               .name           = "480p59_94",
+               .timings_type   = VPBE_ENC_DV_PRESET,
+               .timings        = {V4L2_DV_480P59_94},
+               .interlaced     = 0,
+               .xres           = 720,
+               .yres           = 480,
+               .aspect         = {1, 1},
+               .fps            = {5994, 100},
+               .left_margin    = 0x80,
+               .upper_margin   = 0x20,
+       },
+       {
+               .name           = "576p50",
+               .timings_type   = VPBE_ENC_DV_PRESET,
+               .timings        = {V4L2_DV_576P50},
+               .interlaced     = 0,
+               .xres           = 720,
+               .yres           = 576,
+               .aspect         = {1, 1},
+               .fps            = {50, 1},
+               .left_margin    = 0x7e,
+               .upper_margin   = 0x30,
+       },
+};
+
+/*
+ * The outputs available from VPBE + encoders. Keep the order same
+ * as that of encoders. First those from venc followed by that from
+ * encoders. Index in the output refers to index on a particular encoder.
+ * Driver uses this index to pass it to encoder when it supports more
+ * than one output. Userspace applications use index of the array to
+ * set an output.
+ */
+static struct vpbe_output dm644xevm_vpbe_outputs[] = {
+       {
+               .output         = {
+                       .index          = 0,
+                       .name           = "Composite",
+                       .type           = V4L2_OUTPUT_TYPE_ANALOG,
+                       .std            = VENC_STD_ALL,
+                       .capabilities   = V4L2_OUT_CAP_STD,
+               },
+               .subdev_name    = VPBE_VENC_SUBDEV_NAME,
+               .default_mode   = "ntsc",
+               .num_modes      = ARRAY_SIZE(dm644xevm_enc_std_timing),
+               .modes          = dm644xevm_enc_std_timing,
+       },
+       {
+               .output         = {
+                       .index          = 1,
+                       .name           = "Component",
+                       .type           = V4L2_OUTPUT_TYPE_ANALOG,
+                       .capabilities   = V4L2_OUT_CAP_PRESETS,
+               },
+               .subdev_name    = VPBE_VENC_SUBDEV_NAME,
+               .default_mode   = "480p59_94",
+               .num_modes      = ARRAY_SIZE(dm644xevm_enc_preset_timing),
+               .modes          = dm644xevm_enc_preset_timing,
+       },
+};
+
+static struct vpbe_config dm644xevm_display_cfg = {
+       .module_name    = "dm644x-vpbe-display",
+       .i2c_adapter_id = 1,
+       .osd            = {
+               .module_name    = VPBE_OSD_SUBDEV_NAME,
+       },
+       .venc           = {
+               .module_name    = VPBE_VENC_SUBDEV_NAME,
+       },
+       .num_outputs    = ARRAY_SIZE(dm644xevm_vpbe_outputs),
+       .outputs        = dm644xevm_vpbe_outputs,
+};
+
 static struct platform_device *davinci_evm_devices[] __initdata = {
        &davinci_fb_device,
        &rtc_dev,
@@ -624,8 +732,6 @@ static struct davinci_uart_config uart_config __initdata = {
 static void __init
 davinci_evm_map_io(void)
 {
-       /* setup input configuration for VPFE input devices */
-       dm644x_set_vpfe_config(&vpfe_cfg);
        dm644x_init();
 }
 
@@ -697,6 +803,7 @@ static __init void davinci_evm_init(void)
        evm_init_i2c();
 
        davinci_setup_mmc(0, &dm6446evm_mmc_config);
+       dm644x_init_video(&dm644xevm_capture_cfg, &dm644xevm_display_cfg);
 
        davinci_serial_init(&uart_config);
        dm644x_init_asp(&dm644x_evm_snd_data);
index 872ac69..d72ab94 100644 (file)
@@ -36,7 +36,6 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/dm646x.h>
 #include <mach/common.h>
 #include <mach/serial.h>
 #include <mach/i2c.h>
@@ -45,6 +44,7 @@
 #include <mach/cdce949.h>
 #include <mach/aemif.h>
 
+#include "davinci.h"
 #include "clock.h"
 
 #define NAND_BLOCK_SIZE                SZ_128K
@@ -410,8 +410,6 @@ static struct davinci_i2c_platform_data i2c_pdata = {
        .bus_delay      = 0 /* usec */,
 };
 
-#define VIDCLKCTL_OFFSET       (DAVINCI_SYSTEM_MODULE_BASE + 0x38)
-#define VSCLKDIS_OFFSET                (DAVINCI_SYSTEM_MODULE_BASE + 0x6c)
 #define VCH2CLK_MASK           (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8))
 #define VCH2CLK_SYSCLK8                (BIT(9))
 #define VCH2CLK_AUXCLK         (BIT(9) | BIT(8))
@@ -429,8 +427,6 @@ static struct davinci_i2c_platform_data i2c_pdata = {
 #define TVP5147_CH0            "tvp514x-0"
 #define TVP5147_CH1            "tvp514x-1"
 
-static void __iomem *vpif_vidclkctl_reg;
-static void __iomem *vpif_vsclkdis_reg;
 /* spin lock for updating above registers */
 static spinlock_t vpif_reg_lock;
 
@@ -441,14 +437,14 @@ static int set_vpif_clock(int mux_mode, int hd)
        int val = 0;
        int err = 0;
 
-       if (!vpif_vidclkctl_reg || !vpif_vsclkdis_reg || !cpld_client)
+       if (!cpld_client)
                return -ENXIO;
 
        /* disable the clock */
        spin_lock_irqsave(&vpif_reg_lock, flags);
-       value = __raw_readl(vpif_vsclkdis_reg);
+       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
        value |= (VIDCH3CLK | VIDCH2CLK);
-       __raw_writel(value, vpif_vsclkdis_reg);
+       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
        spin_unlock_irqrestore(&vpif_reg_lock, flags);
 
        val = i2c_smbus_read_byte(cpld_client);
@@ -464,7 +460,7 @@ static int set_vpif_clock(int mux_mode, int hd)
        if (err)
                return err;
 
-       value = __raw_readl(vpif_vidclkctl_reg);
+       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
        value &= ~(VCH2CLK_MASK);
        value &= ~(VCH3CLK_MASK);
 
@@ -473,13 +469,13 @@ static int set_vpif_clock(int mux_mode, int hd)
        else
                value |= (VCH2CLK_AUXCLK | VCH3CLK_AUXCLK);
 
-       __raw_writel(value, vpif_vidclkctl_reg);
+       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
 
        spin_lock_irqsave(&vpif_reg_lock, flags);
-       value = __raw_readl(vpif_vsclkdis_reg);
+       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
        /* enable the clock */
        value &= ~(VIDCH3CLK | VIDCH2CLK);
-       __raw_writel(value, vpif_vsclkdis_reg);
+       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
        spin_unlock_irqrestore(&vpif_reg_lock, flags);
 
        return 0;
@@ -564,7 +560,7 @@ static int setup_vpif_input_channel_mode(int mux_mode)
        int val;
        u32 value;
 
-       if (!vpif_vidclkctl_reg || !cpld_client)
+       if (!cpld_client)
                return -ENXIO;
 
        val = i2c_smbus_read_byte(cpld_client);
@@ -572,7 +568,7 @@ static int setup_vpif_input_channel_mode(int mux_mode)
                return val;
 
        spin_lock_irqsave(&vpif_reg_lock, flags);
-       value = __raw_readl(vpif_vidclkctl_reg);
+       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
        if (mux_mode) {
                val &= VPIF_INPUT_TWO_CHANNEL;
                value |= VIDCH1CLK;
@@ -580,7 +576,7 @@ static int setup_vpif_input_channel_mode(int mux_mode)
                val |= VPIF_INPUT_ONE_CHANNEL;
                value &= ~VIDCH1CLK;
        }
-       __raw_writel(value, vpif_vidclkctl_reg);
+       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VIDCLKCTL));
        spin_unlock_irqrestore(&vpif_reg_lock, flags);
 
        err = i2c_smbus_write_byte(cpld_client, val);
@@ -674,12 +670,6 @@ static struct vpif_capture_config dm646x_vpif_capture_cfg = {
 
 static void __init evm_init_video(void)
 {
-       vpif_vidclkctl_reg = ioremap(VIDCLKCTL_OFFSET, 4);
-       vpif_vsclkdis_reg = ioremap(VSCLKDIS_OFFSET, 4);
-       if (!vpif_vidclkctl_reg || !vpif_vsclkdis_reg) {
-               pr_err("Can't map VPIF VIDCLKCTL or VSCLKDIS registers\n");
-               return;
-       }
        spin_lock_init(&vpif_reg_lock);
 
        dm646x_setup_vpif(&dm646x_vpif_display_config,
index 8d34f51..a772bb4 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
-#include <mach/dm644x.h>
 #include <mach/common.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
@@ -39,6 +38,8 @@
 #include <mach/mmc.h>
 #include <mach/usb.h>
 
+#include "davinci.h"
+
 #define NEUROS_OSD2_PHY_ID             "davinci_mdio-0:01"
 #define LXT971_PHY_ID                  0x001378e2
 #define LXT971_PHY_MASK                        0xfffffff0
index 31da3c5..76e6750 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 
-#include <mach/dm644x.h>
 #include <mach/common.h>
 #include <mach/i2c.h>
 #include <mach/serial.h>
 #include <mach/mux.h>
 #include <mach/usb.h>
 
+#include "davinci.h"
+
 #define SFFSDR_PHY_ID          "davinci_mdio-0:01"
 static struct mtd_partition davinci_sffsdr_nandflash_partition[] = {
        /* U-Boot Environment: Block 0
index 5bba707..031048f 100644 (file)
@@ -95,7 +95,7 @@ static int davinci_target(struct cpufreq_policy *policy,
        if (freqs.old == freqs.new)
                return ret;
 
-       dev_dbg(&cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new);
+       dev_dbg(cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new);
 
        ret = cpufreq_frequency_table_target(policy, pdata->freq_table,
                                                freqs.new, relation, &idx);
index 992c4c4..b44dc84 100644 (file)
@@ -1026,7 +1026,7 @@ static int da850_round_armrate(struct clk *clk, unsigned long rate)
 }
 #endif
 
-int da850_register_pm(struct platform_device *pdev)
+int __init da850_register_pm(struct platform_device *pdev)
 {
        int ret;
        struct davinci_pm_config *pdata = pdev->dev.platform_data;
diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h
new file mode 100644 (file)
index 0000000..3e519da
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * This file contains the processor specific definitions
+ * of the TI DM644x, DM355, DM365, and DM646x.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated
+ * Copyright (c) 2007 Deep Root Systems, LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DAVINCI_H
+#define __DAVINCI_H
+
+#include <linux/clk.h>
+#include <linux/videodev2.h>
+#include <linux/davinci_emac.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#include <mach/asp.h>
+#include <mach/keyscan.h>
+#include <mach/hardware.h>
+
+#include <media/davinci/vpfe_capture.h>
+#include <media/davinci/vpif_types.h>
+#include <media/davinci/vpss.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpbe.h>
+#include <media/davinci/vpbe_osd.h>
+
+#define DAVINCI_SYSTEM_MODULE_BASE     0x01c40000
+#define SYSMOD_VIDCLKCTL               0x38
+#define SYSMOD_VPSS_CLKCTL             0x44
+#define SYSMOD_VDD3P3VPWDN             0x48
+#define SYSMOD_VSCLKDIS                        0x6c
+#define SYSMOD_PUPDCTL1                        0x7c
+
+extern void __iomem *davinci_sysmod_base;
+#define DAVINCI_SYSMOD_VIRT(x) (davinci_sysmod_base + (x))
+void davinci_map_sysmod(void);
+
+/* DM355 base addresses */
+#define DM355_ASYNC_EMIF_CONTROL_BASE  0x01e10000
+#define DM355_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
+
+#define ASP1_TX_EVT_EN 1
+#define ASP1_RX_EVT_EN 2
+
+/* DM365 base addresses */
+#define DM365_ASYNC_EMIF_CONTROL_BASE  0x01d10000
+#define DM365_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
+#define DM365_ASYNC_EMIF_DATA_CE1_BASE 0x04000000
+
+/* DM644x base addresses */
+#define DM644X_ASYNC_EMIF_CONTROL_BASE 0x01e00000
+#define DM644X_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
+#define DM644X_ASYNC_EMIF_DATA_CE1_BASE 0x04000000
+#define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000
+#define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000
+
+/* DM646x base addresses */
+#define DM646X_ASYNC_EMIF_CONTROL_BASE 0x20008000
+#define DM646X_ASYNC_EMIF_CS2_SPACE_BASE 0x42000000
+
+/* DM355 function declarations */
+void __init dm355_init(void);
+void dm355_init_spi0(unsigned chipselect_mask,
+               struct spi_board_info *info, unsigned len);
+void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata);
+void dm355_set_vpfe_config(struct vpfe_config *cfg);
+
+/* DM365 function declarations */
+void __init dm365_init(void);
+void __init dm365_init_asp(struct snd_platform_data *pdata);
+void __init dm365_init_vc(struct snd_platform_data *pdata);
+void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
+void __init dm365_init_rtc(void);
+void dm365_init_spi0(unsigned chipselect_mask,
+                       struct spi_board_info *info, unsigned len);
+void dm365_set_vpfe_config(struct vpfe_config *cfg);
+
+/* DM644x function declarations */
+void __init dm644x_init(void);
+void __init dm644x_init_asp(struct snd_platform_data *pdata);
+int __init dm644x_init_video(struct vpfe_config *, struct vpbe_config *);
+
+/* DM646x function declarations */
+void __init dm646x_init(void);
+void __init dm646x_init_mcasp0(struct snd_platform_data *pdata);
+void __init dm646x_init_mcasp1(struct snd_platform_data *pdata);
+int __init dm646x_init_edma(struct edma_rsv_info *rsv);
+void dm646x_video_init(void);
+void dm646x_setup_vpif(struct vpif_display_config *,
+                      struct vpif_capture_config *);
+#endif /*__DAVINCI_H */
index 50c0156..d2f9666 100644 (file)
@@ -23,6 +23,7 @@
 #include <mach/mmc.h>
 #include <mach/time.h>
 
+#include "davinci.h"
 #include "clock.h"
 
 #define DAVINCI_I2C_BASE            0x01C21000
 #define DM365_MMCSD0_BASE           0x01D11000
 #define DM365_MMCSD1_BASE           0x01D00000
 
-/* System control register offsets */
-#define DM64XX_VDD3P3V_PWDN    0x48
+void __iomem  *davinci_sysmod_base;
+
+void davinci_map_sysmod(void)
+{
+       davinci_sysmod_base = ioremap_nocache(DAVINCI_SYSTEM_MODULE_BASE,
+                                             0x800);
+       /*
+        * Throw a bug since a lot of board initialization code depends
+        * on system module availability. ioremap() failing this early
+        * need careful looking into anyway.
+        */
+       BUG_ON(!davinci_sysmod_base);
+}
 
 static struct resource i2c_resources[] = {
        {
@@ -212,12 +224,12 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
                        davinci_cfg_reg(DM355_SD1_DATA2);
                        davinci_cfg_reg(DM355_SD1_DATA3);
                } else if (cpu_is_davinci_dm365()) {
-                       void __iomem *pupdctl1 =
-                               IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c);
-
                        /* Configure pull down control */
-                       __raw_writel((__raw_readl(pupdctl1) & ~0xfc0),
-                                       pupdctl1);
+                       unsigned v;
+
+                       v = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_PUPDCTL1));
+                       __raw_writel(v & ~0xfc0,
+                                       DAVINCI_SYSMOD_VIRT(SYSMOD_PUPDCTL1));
 
                        mmcsd1_resources[0].start = DM365_MMCSD1_BASE;
                        mmcsd1_resources[0].end = DM365_MMCSD1_BASE +
@@ -246,11 +258,9 @@ void __init davinci_setup_mmc(int module, struct davinci_mmc_config *config)
                        mmcsd0_resources[2].start = IRQ_DM365_SDIOINT0;
                } else if (cpu_is_davinci_dm644x()) {
                        /* REVISIT: should this be in board-init code? */
-                       void __iomem *base =
-                               IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
-
                        /* Power-on 3.3V IO cells */
-                       __raw_writel(0, base + DM64XX_VDD3P3V_PWDN);
+                       __raw_writel(0,
+                               DAVINCI_SYSMOD_VIRT(SYSMOD_VDD3P3VPWDN));
                        /*Set up the pull regiter for MMC */
                        davinci_cfg_reg(DM644X_MSTK);
                }
index 19667cf..fd3d09a 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <asm/mach/map.h>
 
-#include <mach/dm355.h>
 #include <mach/cputype.h>
 #include <mach/edma.h>
 #include <mach/psc.h>
@@ -31,6 +30,7 @@
 #include <mach/spi.h>
 #include <mach/gpio-davinci.h>
 
+#include "davinci.h"
 #include "clock.h"
 #include "mux.h"
 
@@ -871,6 +871,7 @@ void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata)
 void __init dm355_init(void)
 {
        davinci_common_init(&davinci_soc_info_dm355);
+       davinci_map_sysmod();
 }
 
 static int __init dm355_init_devices(void)
index f15b435..1a2e953 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <asm/mach/map.h>
 
-#include <mach/dm365.h>
 #include <mach/cputype.h>
 #include <mach/edma.h>
 #include <mach/psc.h>
 #include <mach/spi.h>
 #include <mach/gpio-davinci.h>
 
+#include "davinci.h"
 #include "clock.h"
 #include "mux.h"
 
 #define DM365_REF_FREQ         24000000        /* 24 MHz on the DM365 EVM */
 
+/* Base of key scan register bank */
+#define DM365_KEYSCAN_BASE             0x01c69400
+
+#define DM365_RTC_BASE                 0x01c69000
+
+#define DAVINCI_DM365_VC_BASE          0x01d0c000
+#define DAVINCI_DMA_VC_TX              2
+#define DAVINCI_DMA_VC_RX              3
+
+#define DM365_EMAC_BASE                        0x01d07000
+#define DM365_EMAC_MDIO_BASE           (DM365_EMAC_BASE + 0x4000)
+#define DM365_EMAC_CNTRL_OFFSET                0x0000
+#define DM365_EMAC_CNTRL_MOD_OFFSET    0x3000
+#define DM365_EMAC_CNTRL_RAM_OFFSET    0x1000
+#define DM365_EMAC_CNTRL_RAM_SIZE      0x2000
+
 static struct pll_data pll1_data = {
        .num            = 1,
        .phys_base      = DAVINCI_PLL1_BASE,
@@ -1122,6 +1138,7 @@ void __init dm365_init_rtc(void)
 void __init dm365_init(void)
 {
        davinci_common_init(&davinci_soc_info_dm365);
+       davinci_map_sysmod();
 }
 
 static struct resource dm365_vpss_resources[] = {
index 43a48ee..c8b8666 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <asm/mach/map.h>
 
-#include <mach/dm644x.h>
 #include <mach/cputype.h>
 #include <mach/edma.h>
 #include <mach/irqs.h>
@@ -27,6 +26,7 @@
 #include <mach/asp.h>
 #include <mach/gpio-davinci.h>
 
+#include "davinci.h"
 #include "clock.h"
 #include "mux.h"
 
  */
 #define DM644X_REF_FREQ                27000000
 
+#define DM644X_EMAC_BASE               0x01c80000
+#define DM644X_EMAC_MDIO_BASE          (DM644X_EMAC_BASE + 0x4000)
+#define DM644X_EMAC_CNTRL_OFFSET       0x0000
+#define DM644X_EMAC_CNTRL_MOD_OFFSET   0x1000
+#define DM644X_EMAC_CNTRL_RAM_OFFSET   0x2000
+#define DM644X_EMAC_CNTRL_RAM_SIZE     0x2000
+
 static struct pll_data pll1_data = {
        .num       = 1,
        .phys_base = DAVINCI_PLL1_BASE,
@@ -587,13 +594,15 @@ static struct platform_device dm644x_asp_device = {
        .resource       = dm644x_asp_resources,
 };
 
+#define DM644X_VPSS_BASE       0x01c73400
+
 static struct resource dm644x_vpss_resources[] = {
        {
                /* VPSS Base address */
                .name           = "vpss",
-               .start          = 0x01c73400,
-               .end            = 0x01c73400 + 0xff,
-               .flags          = IORESOURCE_MEM,
+               .start          = DM644X_VPSS_BASE,
+               .end            = DM644X_VPSS_BASE + 0xff,
+               .flags          = IORESOURCE_MEM,
        },
 };
 
@@ -605,7 +614,7 @@ static struct platform_device dm644x_vpss_device = {
        .resource               = dm644x_vpss_resources,
 };
 
-static struct resource vpfe_resources[] = {
+static struct resource dm644x_vpfe_resources[] = {
        {
                .start          = IRQ_VDINT0,
                .end            = IRQ_VDINT0,
@@ -618,7 +627,7 @@ static struct resource vpfe_resources[] = {
        },
 };
 
-static u64 vpfe_capture_dma_mask = DMA_BIT_MASK(32);
+static u64 dm644x_video_dma_mask = DMA_BIT_MASK(32);
 static struct resource dm644x_ccdc_resource[] = {
        /* CCDC Base address */
        {
@@ -634,27 +643,149 @@ static struct platform_device dm644x_ccdc_dev = {
        .num_resources  = ARRAY_SIZE(dm644x_ccdc_resource),
        .resource       = dm644x_ccdc_resource,
        .dev = {
-               .dma_mask               = &vpfe_capture_dma_mask,
+               .dma_mask               = &dm644x_video_dma_mask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
        },
 };
 
-static struct platform_device vpfe_capture_dev = {
+static struct platform_device dm644x_vpfe_dev = {
        .name           = CAPTURE_DRV_NAME,
        .id             = -1,
-       .num_resources  = ARRAY_SIZE(vpfe_resources),
-       .resource       = vpfe_resources,
+       .num_resources  = ARRAY_SIZE(dm644x_vpfe_resources),
+       .resource       = dm644x_vpfe_resources,
        .dev = {
-               .dma_mask               = &vpfe_capture_dma_mask,
+               .dma_mask               = &dm644x_video_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+
+#define DM644X_OSD_BASE                0x01c72600
+
+static struct resource dm644x_osd_resources[] = {
+       {
+               .start  = DM644X_OSD_BASE,
+               .end    = DM644X_OSD_BASE + 0x1ff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct osd_platform_data dm644x_osd_data = {
+       .vpbe_type     = VPBE_VERSION_1,
+};
+
+static struct platform_device dm644x_osd_dev = {
+       .name           = VPBE_OSD_SUBDEV_NAME,
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(dm644x_osd_resources),
+       .resource       = dm644x_osd_resources,
+       .dev            = {
+               .dma_mask               = &dm644x_video_dma_mask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &dm644x_osd_data,
        },
 };
 
-void dm644x_set_vpfe_config(struct vpfe_config *cfg)
+#define DM644X_VENC_BASE               0x01c72400
+
+static struct resource dm644x_venc_resources[] = {
+       {
+               .start  = DM644X_VENC_BASE,
+               .end    = DM644X_VENC_BASE + 0x17f,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+#define DM644X_VPSS_MUXSEL_PLL2_MODE          BIT(0)
+#define DM644X_VPSS_MUXSEL_VPBECLK_MODE       BIT(1)
+#define DM644X_VPSS_VENCLKEN                  BIT(3)
+#define DM644X_VPSS_DACCLKEN                  BIT(4)
+
+static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type,
+                                  unsigned int mode)
 {
-       vpfe_capture_dev.dev.platform_data = cfg;
+       int ret = 0;
+       u32 v = DM644X_VPSS_VENCLKEN;
+
+       switch (type) {
+       case VPBE_ENC_STD:
+               v |= DM644X_VPSS_DACCLKEN;
+               writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
+               break;
+       case VPBE_ENC_DV_PRESET:
+               switch (mode) {
+               case V4L2_DV_480P59_94:
+               case V4L2_DV_576P50:
+                       v |= DM644X_VPSS_MUXSEL_PLL2_MODE |
+                            DM644X_VPSS_DACCLKEN;
+                       writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
+                       break;
+               case V4L2_DV_720P60:
+               case V4L2_DV_1080I60:
+               case V4L2_DV_1080P30:
+                       /*
+                        * For HD, use external clock source since
+                        * HD requires higher clock rate
+                        */
+                       v |= DM644X_VPSS_MUXSEL_VPBECLK_MODE;
+                       writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+               break;
+       default:
+               ret  = -EINVAL;
+       }
+
+       return ret;
 }
 
+static struct resource dm644x_v4l2_disp_resources[] = {
+       {
+               .start  = IRQ_VENCINT,
+               .end    = IRQ_VENCINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dm644x_vpbe_display = {
+       .name           = "vpbe-v4l2",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(dm644x_v4l2_disp_resources),
+       .resource       = dm644x_v4l2_disp_resources,
+       .dev            = {
+               .dma_mask               = &dm644x_video_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+
+static struct venc_platform_data dm644x_venc_pdata = {
+       .venc_type      = VPBE_VERSION_1,
+       .setup_clock    = dm644x_venc_setup_clock,
+};
+
+static struct platform_device dm644x_venc_dev = {
+       .name           = VPBE_VENC_SUBDEV_NAME,
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(dm644x_venc_resources),
+       .resource       = dm644x_venc_resources,
+       .dev            = {
+               .dma_mask               = &dm644x_video_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &dm644x_venc_pdata,
+       },
+};
+
+static struct platform_device dm644x_vpbe_dev = {
+       .name           = "vpbe_controller",
+       .id             = -1,
+       .dev            = {
+               .dma_mask               = &dm644x_video_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+
 /*----------------------------------------------------------------------*/
 
 static struct map_desc dm644x_io_desc[] = {
@@ -779,6 +910,35 @@ void __init dm644x_init_asp(struct snd_platform_data *pdata)
 void __init dm644x_init(void)
 {
        davinci_common_init(&davinci_soc_info_dm644x);
+       davinci_map_sysmod();
+}
+
+int __init dm644x_init_video(struct vpfe_config *vpfe_cfg,
+                               struct vpbe_config *vpbe_cfg)
+{
+       if (vpfe_cfg || vpbe_cfg)
+               platform_device_register(&dm644x_vpss_device);
+
+       if (vpfe_cfg) {
+               dm644x_vpfe_dev.dev.platform_data = vpfe_cfg;
+               platform_device_register(&dm644x_ccdc_dev);
+               platform_device_register(&dm644x_vpfe_dev);
+               /* Add ccdc clock aliases */
+               clk_add_alias("master", dm644x_ccdc_dev.name,
+                             "vpss_master", NULL);
+               clk_add_alias("slave", dm644x_ccdc_dev.name,
+                             "vpss_slave", NULL);
+       }
+
+       if (vpbe_cfg) {
+               dm644x_vpbe_dev.dev.platform_data = vpbe_cfg;
+               platform_device_register(&dm644x_osd_dev);
+               platform_device_register(&dm644x_venc_dev);
+               platform_device_register(&dm644x_vpbe_dev);
+               platform_device_register(&dm644x_vpbe_display);
+       }
+
+       return 0;
 }
 
 static int __init dm644x_init_devices(void)
@@ -786,9 +946,6 @@ static int __init dm644x_init_devices(void)
        if (!cpu_is_davinci_dm644x())
                return 0;
 
-       /* Add ccdc clock aliases */
-       clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL);
-       clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL);
        platform_device_register(&dm644x_edma_device);
 
        platform_device_register(&dm644x_mdio_device);
@@ -796,10 +953,6 @@ static int __init dm644x_init_devices(void)
        clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev),
                      NULL, &dm644x_emac_device.dev);
 
-       platform_device_register(&dm644x_vpss_device);
-       platform_device_register(&dm644x_ccdc_dev);
-       platform_device_register(&vpfe_capture_dev);
-
        return 0;
 }
 postcore_initcall(dm644x_init_devices);
index 00f7743..9eb87c1 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <asm/mach/map.h>
 
-#include <mach/dm646x.h>
 #include <mach/cputype.h>
 #include <mach/edma.h>
 #include <mach/irqs.h>
 #include <mach/asp.h>
 #include <mach/gpio-davinci.h>
 
+#include "davinci.h"
 #include "clock.h"
 #include "mux.h"
 
 #define DAVINCI_VPIF_BASE       (0x01C12000)
-#define VDD3P3V_PWDN_OFFSET    (0x48)
-#define VSCLKDIS_OFFSET                (0x6C)
 
 #define VDD3P3V_VID_MASK       (BIT_MASK(3) | BIT_MASK(2) | BIT_MASK(1) |\
                                        BIT_MASK(0))
 #define DM646X_REF_FREQ                27000000
 #define DM646X_AUX_FREQ                24000000
 
+#define DM646X_EMAC_BASE               0x01c80000
+#define DM646X_EMAC_MDIO_BASE          (DM646X_EMAC_BASE + 0x4000)
+#define DM646X_EMAC_CNTRL_OFFSET       0x0000
+#define DM646X_EMAC_CNTRL_MOD_OFFSET   0x1000
+#define DM646X_EMAC_CNTRL_RAM_OFFSET   0x2000
+#define DM646X_EMAC_CNTRL_RAM_SIZE     0x2000
+
 static struct pll_data pll1_data = {
        .num       = 1,
        .phys_base = DAVINCI_PLL1_BASE,
@@ -873,15 +878,14 @@ void dm646x_setup_vpif(struct vpif_display_config *display_config,
                       struct vpif_capture_config *capture_config)
 {
        unsigned int value;
-       void __iomem *base = IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE);
 
-       value = __raw_readl(base + VSCLKDIS_OFFSET);
+       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
        value &= ~VSCLKDIS_MASK;
-       __raw_writel(value, base + VSCLKDIS_OFFSET);
+       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VSCLKDIS));
 
-       value = __raw_readl(base + VDD3P3V_PWDN_OFFSET);
+       value = __raw_readl(DAVINCI_SYSMOD_VIRT(SYSMOD_VDD3P3VPWDN));
        value &= ~VDD3P3V_VID_MASK;
-       __raw_writel(value, base + VDD3P3V_PWDN_OFFSET);
+       __raw_writel(value, DAVINCI_SYSMOD_VIRT(SYSMOD_VDD3P3VPWDN));
 
        davinci_cfg_reg(DM646X_STSOMUX_DISABLE);
        davinci_cfg_reg(DM646X_STSIMUX_DISABLE);
@@ -905,6 +909,7 @@ int __init dm646x_init_edma(struct edma_rsv_info *rsv)
 void __init dm646x_init(void)
 {
        davinci_common_init(&davinci_soc_info_dm646x);
+       davinci_map_sysmod();
 }
 
 static int __init dm646x_init_devices(void)
index da90103..fd33919 100644 (file)
@@ -1508,12 +1508,8 @@ static int __init edma_probe(struct platform_device *pdev)
                        goto fail;
                }
 
-               /* Everything lives on transfer controller 1 until otherwise
-                * specified. This way, long transfers on the low priority queue
-                * started by the codec engine will not cause audio defects.
-                */
                for (i = 0; i < edma_cc[j]->num_channels; i++)
-                       map_dmach_queue(j, i, EVENTQ_1);
+                       map_dmach_queue(j, i, info[j]->default_queue);
 
                queue_tc_mapping = info[j]->queue_tc_mapping;
                queue_priority_mapping = info[j]->queue_priority_mapping;
diff --git a/arch/arm/mach-davinci/include/mach/dm355.h b/arch/arm/mach-davinci/include/mach/dm355.h
deleted file mode 100644 (file)
index 36dff4a..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Chip specific defines for DM355 SoC
- *
- * Author: Kevin Hilman, Deep Root Systems, LLC
- *
- * 2007 (c) Deep Root Systems, LLC. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __ASM_ARCH_DM355_H
-#define __ASM_ARCH_DM355_H
-
-#include <mach/hardware.h>
-#include <mach/asp.h>
-#include <media/davinci/vpfe_capture.h>
-
-#define DM355_ASYNC_EMIF_CONTROL_BASE  0x01E10000
-#define DM355_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
-
-#define ASP1_TX_EVT_EN 1
-#define ASP1_RX_EVT_EN 2
-
-struct spi_board_info;
-
-void __init dm355_init(void);
-void dm355_init_spi0(unsigned chipselect_mask,
-               struct spi_board_info *info, unsigned len);
-void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata);
-void dm355_set_vpfe_config(struct vpfe_config *cfg);
-
-#endif /* __ASM_ARCH_DM355_H */
index 2563bf4..b9bf3d6 100644 (file)
@@ -1,52 +1 @@
-/*
- * Copyright (C) 2009 Texas Instruments Incorporated
- *
- * 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 __ASM_ARCH_DM365_H
-#define __ASM_ARCH_DM665_H
-
-#include <linux/platform_device.h>
-#include <linux/davinci_emac.h>
-#include <mach/hardware.h>
-#include <mach/asp.h>
-#include <mach/keyscan.h>
-#include <media/davinci/vpfe_capture.h>
-
-#define DM365_EMAC_BASE                        (0x01D07000)
-#define DM365_EMAC_MDIO_BASE           (DM365_EMAC_BASE + 0x4000)
-#define DM365_EMAC_CNTRL_OFFSET                (0x0000)
-#define DM365_EMAC_CNTRL_MOD_OFFSET    (0x3000)
-#define DM365_EMAC_CNTRL_RAM_OFFSET    (0x1000)
-#define DM365_EMAC_CNTRL_RAM_SIZE      (0x2000)
-
-/* Base of key scan register bank */
-#define DM365_KEYSCAN_BASE             (0x01C69400)
-
-#define DM365_RTC_BASE                 (0x01C69000)
-
-#define DAVINCI_DM365_VC_BASE          (0x01D0C000)
-#define DAVINCI_DMA_VC_TX              2
-#define DAVINCI_DMA_VC_RX              3
-
-#define DM365_ASYNC_EMIF_CONTROL_BASE  0x01D10000
-#define DM365_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
-#define DM365_ASYNC_EMIF_DATA_CE1_BASE 0x04000000
-
-void __init dm365_init(void);
-void __init dm365_init_asp(struct snd_platform_data *pdata);
-void __init dm365_init_vc(struct snd_platform_data *pdata);
-void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
-void __init dm365_init_rtc(void);
-void dm365_init_spi0(unsigned chipselect_mask,
-                       struct spi_board_info *info, unsigned len);
-
-void dm365_set_vpfe_config(struct vpfe_config *cfg);
-#endif /* __ASM_ARCH_DM365_H */
+/* empty, remove once unused */
diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h
deleted file mode 100644 (file)
index 5a1b26d..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * This file contains the processor specific definitions
- * of the TI DM644x.
- *
- * Copyright (C) 2008 Texas Instruments.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-#ifndef __ASM_ARCH_DM644X_H
-#define __ASM_ARCH_DM644X_H
-
-#include <linux/davinci_emac.h>
-#include <mach/hardware.h>
-#include <mach/asp.h>
-#include <media/davinci/vpfe_capture.h>
-
-#define DM644X_EMAC_BASE               (0x01C80000)
-#define DM644X_EMAC_MDIO_BASE          (DM644X_EMAC_BASE + 0x4000)
-#define DM644X_EMAC_CNTRL_OFFSET       (0x0000)
-#define DM644X_EMAC_CNTRL_MOD_OFFSET   (0x1000)
-#define DM644X_EMAC_CNTRL_RAM_OFFSET   (0x2000)
-#define DM644X_EMAC_CNTRL_RAM_SIZE     (0x2000)
-
-#define DM644X_ASYNC_EMIF_CONTROL_BASE 0x01E00000
-#define DM644X_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
-#define DM644X_ASYNC_EMIF_DATA_CE1_BASE 0x04000000
-#define DM644X_ASYNC_EMIF_DATA_CE2_BASE 0x06000000
-#define DM644X_ASYNC_EMIF_DATA_CE3_BASE 0x08000000
-
-void __init dm644x_init(void);
-void __init dm644x_init_asp(struct snd_platform_data *pdata);
-void dm644x_set_vpfe_config(struct vpfe_config *cfg);
-
-#endif /* __ASM_ARCH_DM644X_H */
index a8ee6c9..b9bf3d6 100644 (file)
@@ -1,41 +1 @@
-/*
- * Chip specific defines for DM646x SoC
- *
- * Author: Kevin Hilman, Deep Root Systems, LLC
- *
- * 2007 (c) Deep Root Systems, LLC. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __ASM_ARCH_DM646X_H
-#define __ASM_ARCH_DM646X_H
-
-#include <mach/hardware.h>
-#include <mach/asp.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/davinci_emac.h>
-#include <media/davinci/vpif_types.h>
-
-#define DM646X_EMAC_BASE               (0x01C80000)
-#define DM646X_EMAC_MDIO_BASE          (DM646X_EMAC_BASE + 0x4000)
-#define DM646X_EMAC_CNTRL_OFFSET       (0x0000)
-#define DM646X_EMAC_CNTRL_MOD_OFFSET   (0x1000)
-#define DM646X_EMAC_CNTRL_RAM_OFFSET   (0x2000)
-#define DM646X_EMAC_CNTRL_RAM_SIZE     (0x2000)
-
-#define DM646X_ASYNC_EMIF_CONTROL_BASE 0x20008000
-#define DM646X_ASYNC_EMIF_CS2_SPACE_BASE 0x42000000
-
-void __init dm646x_init(void);
-void __init dm646x_init_mcasp0(struct snd_platform_data *pdata);
-void __init dm646x_init_mcasp1(struct snd_platform_data *pdata);
-int __init dm646x_init_edma(struct edma_rsv_info *rsv);
-
-void dm646x_video_init(void);
-
-void dm646x_setup_vpif(struct vpif_display_config *,
-                      struct vpif_capture_config *);
-
-#endif /* __ASM_ARCH_DM646X_H */
+/* empty, remove once unused */
index 20c77f2..7e84c90 100644 (file)
@@ -250,6 +250,11 @@ struct edma_soc_info {
        unsigned        n_slot;
        unsigned        n_tc;
        unsigned        n_cc;
+       /*
+        * Default queue is expected to be a low-priority queue.
+        * This way, long transfers on the default queue started
+        * by the codec engine will not cause audio defects.
+        */
        enum dma_event_q        default_queue;
 
        /* Resource reservation for other cores */
index e14c0dc..c1661d2 100644 (file)
 #include <mach/io.h>
 #include <mach/irqs.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                ldr \base, =davinci_intc_base
                ldr \base, [\base]
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 #if defined(CONFIG_AINTC) && defined(CONFIG_CP_INTC)
                ldr \tmp, =davinci_intc_type
index 414e0b9..0209b1f 100644 (file)
@@ -19,8 +19,6 @@
  * and the chip/board init code should then explicitly include
  * <chipname>.h
  */
-#define DAVINCI_SYSTEM_MODULE_BASE        0x01C40000
-
 /*
  * I/O mapping
  */
diff --git a/arch/arm/mach-davinci/include/mach/system.h b/arch/arm/mach-davinci/include/mach/system.h
deleted file mode 100644 (file)
index fcb7a01..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * DaVinci system defines
- *
- * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
- *
- * 2007 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <mach/common.h>
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif /* __ASM_ARCH_SYSTEM_H */
index e84c78c..72d622b 100644 (file)
 
 #include <mach/bridge-regs.h>
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =IRQ_VIRT_BASE
        .endm
diff --git a/arch/arm/mach-dove/include/mach/system.h b/arch/arm/mach-dove/include/mach/system.h
deleted file mode 100644 (file)
index 3027954..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-dove/include/mach/system.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
index 52e96d3..48a0320 100644 (file)
@@ -69,7 +69,7 @@ static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
        pp->res[0].flags = IORESOURCE_IO;
        if (request_resource(&ioport_resource, &pp->res[0]))
                panic("Request PCIe IO resource failed\n");
-       pci_add_resource(&sys->resources, &pp->res[0]);
+       pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
 
        /*
         * IORESOURCE_MEM
@@ -88,7 +88,7 @@ static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
        pp->res[1].flags = IORESOURCE_MEM;
        if (request_resource(&iomem_resource, &pp->res[1]))
                panic("Request PCIe Memory resource failed\n");
-       pci_add_resource(&sys->resources, &pp->res[1]);
+       pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
        return 1;
 }
index 0c40e59..8c9f56a 100644 (file)
 
 #include <asm/mach/time.h>
 
-#define IRQ_MASK               0xfe000000      /* read */
-#define IRQ_MSET               0xfe000000      /* write */
-#define IRQ_STAT               0xff000000      /* read */
-#define IRQ_MCLR               0xff000000      /* write */
+#include "core.h"
 
 static void ebsa110_mask_irq(struct irq_data *d)
 {
@@ -79,22 +76,22 @@ static struct map_desc ebsa110_io_desc[] __initdata = {
        {       /* IRQ_STAT/IRQ_MCLR */
                .virtual        = IRQ_STAT,
                .pfn            = __phys_to_pfn(TRICK4_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK4_SIZE,
                .type           = MT_DEVICE
        }, {    /* IRQ_MASK/IRQ_MSET */
                .virtual        = IRQ_MASK,
                .pfn            = __phys_to_pfn(TRICK3_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK3_SIZE,
                .type           = MT_DEVICE
        }, {    /* SOFT_BASE */
                .virtual        = SOFT_BASE,
                .pfn            = __phys_to_pfn(TRICK1_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK1_SIZE,
                .type           = MT_DEVICE
        }, {    /* PIT_BASE */
                .virtual        = PIT_BASE,
                .pfn            = __phys_to_pfn(TRICK0_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK0_SIZE,
                .type           = MT_DEVICE
        },
 
@@ -271,8 +268,33 @@ static struct platform_device *ebsa110_devices[] = {
        &am79c961_device,
 };
 
+/*
+ * EBSA110 idling methodology:
+ *
+ * We can not execute the "wait for interrupt" instruction since that
+ * will stop our MCLK signal (which provides the clock for the glue
+ * logic, and therefore the timer interrupt).
+ *
+ * Instead, we spin, polling the IRQ_STAT register for the occurrence
+ * of any interrupt with core clock down to the memory clock.
+ */
+static void ebsa110_idle(void)
+{
+       const char *irq_stat = (char *)0xff000000;
+
+       /* disable clock switching */
+       asm volatile ("mcr p15, 0, ip, c15, c2, 2" : : : "cc");
+
+       /* wait for an interrupt to occur */
+       while (!*irq_stat);
+
+       /* enable clock switching */
+       asm volatile ("mcr p15, 0, ip, c15, c1, 2" : : : "cc");
+}
+
 static int __init ebsa110_init(void)
 {
+       arm_pm_idle = ebsa110_idle;
        return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices));
 }
 
diff --git a/arch/arm/mach-ebsa110/core.h b/arch/arm/mach-ebsa110/core.h
new file mode 100644 (file)
index 0000000..c93c9e4
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (C) 1996-2000 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains the core hardware definitions of the EBSA-110.
+ */
+#ifndef CORE_H
+#define CORE_H
+
+/* Physical addresses/sizes */
+#define ISAMEM_PHYS            0xe0000000
+#define ISAMEM_SIZE            0x10000000
+
+#define ISAIO_PHYS             0xf0000000
+#define ISAIO_SIZE             PGDIR_SIZE
+
+#define TRICK0_PHYS            0xf2000000
+#define TRICK0_SIZE            PGDIR_SIZE
+#define TRICK1_PHYS            0xf2400000
+#define TRICK1_SIZE            PGDIR_SIZE
+#define TRICK2_PHYS            0xf2800000
+#define TRICK3_PHYS            0xf2c00000
+#define TRICK3_SIZE            PGDIR_SIZE
+#define TRICK4_PHYS            0xf3000000
+#define TRICK4_SIZE            PGDIR_SIZE
+#define TRICK5_PHYS            0xf3400000
+#define TRICK6_PHYS            0xf3800000
+#define TRICK7_PHYS            0xf3c00000
+
+/* Virtual addresses */
+#define PIT_BASE               0xfc000000      /* trick 0 */
+#define SOFT_BASE              0xfd000000      /* trick 1 */
+#define IRQ_MASK               0xfe000000      /* trick 3 - read */
+#define IRQ_MSET               0xfe000000      /* trick 3 - write */
+#define IRQ_STAT               0xff000000      /* trick 4 - read */
+#define IRQ_MCLR               0xff000000      /* trick 4 - write */
+
+#endif
index cc3e599..14b110d 100644 (file)
 
 #define IRQ_STAT               0xff000000      /* read */
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        mov     \base, #IRQ_STAT
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, stat, base, tmp
        ldrb    \stat, [\base]                  @ get interrupts
        mov     \irqnr, #0
index 4b2fb77..f4e5407 100644 (file)
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-/*
- * The EBSA110 has a weird "ISA IO" region:
- *
- * Region 0 (addr = 0xf0000000 + io << 2)
- * --------------------------------------------------------
- * Physical region     IO region
- * f0000fe0 - f0000ffc 3f8 - 3ff  ttyS0
- * f0000e60 - f0000e64 398 - 399
- * f0000de0 - f0000dfc 378 - 37f  lp0
- * f0000be0 - f0000bfc 2f8 - 2ff  ttyS1
- *
- * Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1))
- * --------------------------------------------------------
- * Physical region     IO region
- * f00014f1             a79        pnp write data
- * f00007c0 - f00007c1 3e0 - 3e1  pcmcia
- * f00004f1            279        pnp address
- * f0000440 - f000046c  220 - 236  eth0
- * f0000405            203        pnp read data
- */
-
-#define ISAMEM_PHYS            0xe0000000
-#define ISAMEM_SIZE            0x10000000
-
-#define ISAIO_PHYS             0xf0000000
-#define ISAIO_SIZE             PGDIR_SIZE
-
-#define TRICK0_PHYS            0xf2000000
-#define TRICK1_PHYS            0xf2400000
-#define TRICK2_PHYS            0xf2800000
-#define TRICK3_PHYS            0xf2c00000
-#define TRICK4_PHYS            0xf3000000
-#define TRICK5_PHYS            0xf3400000
-#define TRICK6_PHYS            0xf3800000
-#define TRICK7_PHYS            0xf3c00000
-
 #define ISAMEM_BASE            0xe0000000
 #define ISAIO_BASE             0xf0000000
 
-#define PIT_BASE               0xfc000000
-#define SOFT_BASE              0xfd000000
-
 /*
  * RAM definitions
  */
diff --git a/arch/arm/mach-ebsa110/include/mach/system.h b/arch/arm/mach-ebsa110/include/mach/system.h
deleted file mode 100644 (file)
index 2e4af65..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  arch/arm/mach-ebsa110/include/mach/system.h
- *
- *  Copyright (C) 1996-2000 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-/*
- * EBSA110 idling methodology:
- *
- * We can not execute the "wait for interrupt" instruction since that
- * will stop our MCLK signal (which provides the clock for the glue
- * logic, and therefore the timer interrupt).
- *
- * Instead, we spin, polling the IRQ_STAT register for the occurrence
- * of any interrupt with core clock down to the memory clock.
- */
-static inline void arch_idle(void)
-{
-       const char *irq_stat = (char *)0xff000000;
-
-       /* disable clock switching */
-       asm volatile ("mcr p15, 0, ip, c15, c2, 2" : : : "cc");
-
-       /* wait for an interrupt to occur */
-       while (!*irq_stat);
-
-       /* enable clock switching */
-       asm volatile ("mcr p15, 0, ip, c15, c1, 2" : : : "cc");
-}
-
-#endif
index c52e304..756cc37 100644 (file)
@@ -177,6 +177,26 @@ void writesl(void __iomem *addr, const void *data, int len)
 }
 EXPORT_SYMBOL(writesl);
 
+/*
+ * The EBSA110 has a weird "ISA IO" region:
+ *
+ * Region 0 (addr = 0xf0000000 + io << 2)
+ * --------------------------------------------------------
+ * Physical region     IO region
+ * f0000fe0 - f0000ffc 3f8 - 3ff  ttyS0
+ * f0000e60 - f0000e64 398 - 399
+ * f0000de0 - f0000dfc 378 - 37f  lp0
+ * f0000be0 - f0000bfc 2f8 - 2ff  ttyS1
+ *
+ * Region 1 (addr = 0xf0000000 + (io & ~1) << 1 + (io & 1))
+ * --------------------------------------------------------
+ * Physical region     IO region
+ * f00014f1             a79        pnp write data
+ * f00007c0 - f00007c1 3e0 - 3e1  pcmcia
+ * f00004f1            279        pnp address
+ * f0000440 - f000046c  220 - 236  eth0
+ * f0000405            203        pnp read data
+ */
 #define SUPERIO_PORT(p) \
        (((p) >> 3) == (0x3f8 >> 3) || \
         ((p) >> 3) == (0x2f8 >> 3) || \
index 101a320..99e14e3 100644 (file)
@@ -19,6 +19,8 @@
 #include <asm/leds.h>
 #include <asm/mach-types.h>
 
+#include "core.h"
+
 static spinlock_t leds_lock;
 
 static void ebsa110_leds_event(led_event_t ledevt)
index 574209d..0dc51f9 100644 (file)
@@ -8,6 +8,9 @@ obj-                    :=
 
 obj-$(CONFIG_EP93XX_DMA)       += dma.o
 
+obj-$(CONFIG_CRUNCH)           += crunch.o crunch-bits.o
+AFLAGS_crunch-bits.o           := -Wa,-mcpu=ep9312
+
 obj-$(CONFIG_MACH_ADSSPHERE)   += adssphere.o
 obj-$(CONFIG_MACH_EDB93XX)     += edb93xx.o
 obj-$(CONFIG_MACH_GESBC9312)   += gesbc9312.o
index 681e939..2d45947 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
 
 static struct ep93xx_eth_data __initdata adssphere_eth_data = {
        .phy_id         = 1,
index ca4de71..c95dbce 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <asm/div64.h>
 
+#include "soc.h"
 
 struct clk {
        struct clk      *parent;
index b5c1dae..8d25895 100644 (file)
@@ -46,6 +46,7 @@
 
 #include <asm/hardware/vic.h>
 
+#include "soc.h"
 
 /*************************************************************************
  * Static I/O mappings that are needed for all EP93xx platforms
@@ -204,7 +205,6 @@ void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg)
 
        spin_unlock_irqrestore(&syscon_swlock, flags);
 }
-EXPORT_SYMBOL(ep93xx_syscon_swlocked_write);
 
 void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits)
 {
@@ -221,7 +221,6 @@ void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits)
 
        spin_unlock_irqrestore(&syscon_swlock, flags);
 }
-EXPORT_SYMBOL(ep93xx_devcfg_set_clear);
 
 /**
  * ep93xx_chip_revision() - returns the EP93xx chip revision
@@ -279,48 +278,14 @@ static struct amba_pl010_data ep93xx_uart_data = {
        .set_mctrl      = ep93xx_uart_set_mctrl,
 };
 
-static struct amba_device uart1_device = {
-       .dev            = {
-               .init_name      = "apb:uart1",
-               .platform_data  = &ep93xx_uart_data,
-       },
-       .res            = {
-               .start  = EP93XX_UART1_PHYS_BASE,
-               .end    = EP93XX_UART1_PHYS_BASE + 0x0fff,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { IRQ_EP93XX_UART1, NO_IRQ },
-       .periphid       = 0x00041010,
-};
-
-static struct amba_device uart2_device = {
-       .dev            = {
-               .init_name      = "apb:uart2",
-               .platform_data  = &ep93xx_uart_data,
-       },
-       .res            = {
-               .start  = EP93XX_UART2_PHYS_BASE,
-               .end    = EP93XX_UART2_PHYS_BASE + 0x0fff,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { IRQ_EP93XX_UART2, NO_IRQ },
-       .periphid       = 0x00041010,
-};
+static AMBA_APB_DEVICE(uart1, "apb:uart1", 0x00041010, EP93XX_UART1_PHYS_BASE,
+       { IRQ_EP93XX_UART1 }, &ep93xx_uart_data);
 
-static struct amba_device uart3_device = {
-       .dev            = {
-               .init_name      = "apb:uart3",
-               .platform_data  = &ep93xx_uart_data,
-       },
-       .res            = {
-               .start  = EP93XX_UART3_PHYS_BASE,
-               .end    = EP93XX_UART3_PHYS_BASE + 0x0fff,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { IRQ_EP93XX_UART3, NO_IRQ },
-       .periphid       = 0x00041010,
-};
+static AMBA_APB_DEVICE(uart2, "apb:uart2", 0x00041010, EP93XX_UART2_PHYS_BASE,
+       { IRQ_EP93XX_UART2 }, &ep93xx_uart_data);
 
+static AMBA_APB_DEVICE(uart3, "apb:uart3", 0x00041010, EP93XX_UART3_PHYS_BASE,
+       { IRQ_EP93XX_UART3 }, &ep93xx_uart_data);
 
 static struct resource ep93xx_rtc_resource[] = {
        {
@@ -682,9 +647,19 @@ static struct platform_device ep93xx_fb_device = {
        .resource               = ep93xx_fb_resource,
 };
 
+/* The backlight use a single register in the framebuffer's register space */
+#define EP93XX_RASTER_REG_BRIGHTNESS 0x20
+
+static struct resource ep93xx_bl_resources[] = {
+       DEFINE_RES_MEM(EP93XX_RASTER_PHYS_BASE +
+                      EP93XX_RASTER_REG_BRIGHTNESS, 0x04),
+};
+
 static struct platform_device ep93xx_bl_device = {
        .name           = "ep93xx-bl",
        .id             = -1,
+       .num_resources  = ARRAY_SIZE(ep93xx_bl_resources),
+       .resource       = ep93xx_bl_resources,
 };
 
 /**
@@ -879,11 +854,32 @@ void __init ep93xx_register_ac97(void)
        platform_device_register(&ep93xx_pcm_device);
 }
 
+/*************************************************************************
+ * EP93xx Watchdog
+ *************************************************************************/
+static struct resource ep93xx_wdt_resources[] = {
+       DEFINE_RES_MEM(EP93XX_WATCHDOG_PHYS_BASE, 0x08),
+};
+
+static struct platform_device ep93xx_wdt_device = {
+       .name           = "ep93xx-wdt",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ep93xx_wdt_resources),
+       .resource       = ep93xx_wdt_resources,
+};
+
 void __init ep93xx_init_devices(void)
 {
        /* Disallow access to MaverickCrunch initially */
        ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_CPENA);
 
+       /* Default all ports to GPIO */
+       ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS |
+                              EP93XX_SYSCON_DEVCFG_GONK |
+                              EP93XX_SYSCON_DEVCFG_EONIDE |
+                              EP93XX_SYSCON_DEVCFG_GONIDE |
+                              EP93XX_SYSCON_DEVCFG_HONIDE);
+
        /* Get the GPIO working early, other devices need it */
        platform_device_register(&ep93xx_gpio_device);
 
@@ -894,6 +890,7 @@ void __init ep93xx_init_devices(void)
        platform_device_register(&ep93xx_rtc_device);
        platform_device_register(&ep93xx_ohci_device);
        platform_device_register(&ep93xx_leds);
+       platform_device_register(&ep93xx_wdt_device);
 }
 
 void ep93xx_restart(char mode, const char *cmd)
diff --git a/arch/arm/mach-ep93xx/crunch-bits.S b/arch/arm/mach-ep93xx/crunch-bits.S
new file mode 100644 (file)
index 0000000..0ec9bb4
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * arch/arm/kernel/crunch-bits.S
+ * Cirrus MaverickCrunch context switching and handling
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * Shamelessly stolen from the iWMMXt code by Nicolas Pitre, which is
+ * Copyright (c) 2003-2004, MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <mach/ep93xx-regs.h>
+
+/*
+ * We can't use hex constants here due to a bug in gas.
+ */
+#define CRUNCH_MVDX0           0
+#define CRUNCH_MVDX1           8
+#define CRUNCH_MVDX2           16
+#define CRUNCH_MVDX3           24
+#define CRUNCH_MVDX4           32
+#define CRUNCH_MVDX5           40
+#define CRUNCH_MVDX6           48
+#define CRUNCH_MVDX7           56
+#define CRUNCH_MVDX8           64
+#define CRUNCH_MVDX9           72
+#define CRUNCH_MVDX10          80
+#define CRUNCH_MVDX11          88
+#define CRUNCH_MVDX12          96
+#define CRUNCH_MVDX13          104
+#define CRUNCH_MVDX14          112
+#define CRUNCH_MVDX15          120
+#define CRUNCH_MVAX0L          128
+#define CRUNCH_MVAX0M          132
+#define CRUNCH_MVAX0H          136
+#define CRUNCH_MVAX1L          140
+#define CRUNCH_MVAX1M          144
+#define CRUNCH_MVAX1H          148
+#define CRUNCH_MVAX2L          152
+#define CRUNCH_MVAX2M          156
+#define CRUNCH_MVAX2H          160
+#define CRUNCH_MVAX3L          164
+#define CRUNCH_MVAX3M          168
+#define CRUNCH_MVAX3H          172
+#define CRUNCH_DSPSC           176
+
+#define CRUNCH_SIZE            184
+
+       .text
+
+/*
+ * Lazy switching of crunch coprocessor context
+ *
+ * r10 = struct thread_info pointer
+ * r9  = ret_from_exception
+ * lr  = undefined instr exit
+ *
+ * called from prefetch exception handler with interrupts disabled
+ */
+ENTRY(crunch_task_enable)
+       ldr     r8, =(EP93XX_APB_VIRT_BASE + 0x00130000)        @ syscon addr
+
+       ldr     r1, [r8, #0x80]
+       tst     r1, #0x00800000                 @ access to crunch enabled?
+       movne   pc, lr                          @ if so no business here
+       mov     r3, #0xaa                       @ unlock syscon swlock
+       str     r3, [r8, #0xc0]
+       orr     r1, r1, #0x00800000             @ enable access to crunch
+       str     r1, [r8, #0x80]
+
+       ldr     r3, =crunch_owner
+       add     r0, r10, #TI_CRUNCH_STATE       @ get task crunch save area
+       ldr     r2, [sp, #60]                   @ current task pc value
+       ldr     r1, [r3]                        @ get current crunch owner
+       str     r0, [r3]                        @ this task now owns crunch
+       sub     r2, r2, #4                      @ adjust pc back
+       str     r2, [sp, #60]
+
+       ldr     r2, [r8, #0x80]
+       mov     r2, r2                          @ flush out enable (@@@)
+
+       teq     r1, #0                          @ test for last ownership
+       mov     lr, r9                          @ normal exit from exception
+       beq     crunch_load                     @ no owner, skip save
+
+crunch_save:
+       cfstr64         mvdx0, [r1, #CRUNCH_MVDX0]      @ save 64b registers
+       cfstr64         mvdx1, [r1, #CRUNCH_MVDX1]
+       cfstr64         mvdx2, [r1, #CRUNCH_MVDX2]
+       cfstr64         mvdx3, [r1, #CRUNCH_MVDX3]
+       cfstr64         mvdx4, [r1, #CRUNCH_MVDX4]
+       cfstr64         mvdx5, [r1, #CRUNCH_MVDX5]
+       cfstr64         mvdx6, [r1, #CRUNCH_MVDX6]
+       cfstr64         mvdx7, [r1, #CRUNCH_MVDX7]
+       cfstr64         mvdx8, [r1, #CRUNCH_MVDX8]
+       cfstr64         mvdx9, [r1, #CRUNCH_MVDX9]
+       cfstr64         mvdx10, [r1, #CRUNCH_MVDX10]
+       cfstr64         mvdx11, [r1, #CRUNCH_MVDX11]
+       cfstr64         mvdx12, [r1, #CRUNCH_MVDX12]
+       cfstr64         mvdx13, [r1, #CRUNCH_MVDX13]
+       cfstr64         mvdx14, [r1, #CRUNCH_MVDX14]
+       cfstr64         mvdx15, [r1, #CRUNCH_MVDX15]
+
+#ifdef __ARMEB__
+#error fix me for ARMEB
+#endif
+
+       cfmv32al        mvfx0, mvax0                    @ save 72b accumulators
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0L]
+       cfmv32am        mvfx0, mvax0
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0M]
+       cfmv32ah        mvfx0, mvax0
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX0H]
+       cfmv32al        mvfx0, mvax1
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1L]
+       cfmv32am        mvfx0, mvax1
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1M]
+       cfmv32ah        mvfx0, mvax1
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX1H]
+       cfmv32al        mvfx0, mvax2
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2L]
+       cfmv32am        mvfx0, mvax2
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2M]
+       cfmv32ah        mvfx0, mvax2
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX2H]
+       cfmv32al        mvfx0, mvax3
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3L]
+       cfmv32am        mvfx0, mvax3
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3M]
+       cfmv32ah        mvfx0, mvax3
+       cfstr32         mvfx0, [r1, #CRUNCH_MVAX3H]
+
+       cfmv32sc        mvdx0, dspsc                    @ save status word
+       cfstr64         mvdx0, [r1, #CRUNCH_DSPSC]
+
+       teq             r0, #0                          @ anything to load?
+       cfldr64eq       mvdx0, [r1, #CRUNCH_MVDX0]      @ mvdx0 was clobbered
+       moveq           pc, lr
+
+crunch_load:
+       cfldr64         mvdx0, [r0, #CRUNCH_DSPSC]      @ load status word
+       cfmvsc32        dspsc, mvdx0
+
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0L]     @ load 72b accumulators
+       cfmval32        mvax0, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0M]
+       cfmvam32        mvax0, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX0H]
+       cfmvah32        mvax0, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1L]
+       cfmval32        mvax1, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1M]
+       cfmvam32        mvax1, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX1H]
+       cfmvah32        mvax1, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2L]
+       cfmval32        mvax2, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2M]
+       cfmvam32        mvax2, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX2H]
+       cfmvah32        mvax2, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3L]
+       cfmval32        mvax3, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3M]
+       cfmvam32        mvax3, mvfx0
+       cfldr32         mvfx0, [r0, #CRUNCH_MVAX3H]
+       cfmvah32        mvax3, mvfx0
+
+       cfldr64         mvdx0, [r0, #CRUNCH_MVDX0]      @ load 64b registers
+       cfldr64         mvdx1, [r0, #CRUNCH_MVDX1]
+       cfldr64         mvdx2, [r0, #CRUNCH_MVDX2]
+       cfldr64         mvdx3, [r0, #CRUNCH_MVDX3]
+       cfldr64         mvdx4, [r0, #CRUNCH_MVDX4]
+       cfldr64         mvdx5, [r0, #CRUNCH_MVDX5]
+       cfldr64         mvdx6, [r0, #CRUNCH_MVDX6]
+       cfldr64         mvdx7, [r0, #CRUNCH_MVDX7]
+       cfldr64         mvdx8, [r0, #CRUNCH_MVDX8]
+       cfldr64         mvdx9, [r0, #CRUNCH_MVDX9]
+       cfldr64         mvdx10, [r0, #CRUNCH_MVDX10]
+       cfldr64         mvdx11, [r0, #CRUNCH_MVDX11]
+       cfldr64         mvdx12, [r0, #CRUNCH_MVDX12]
+       cfldr64         mvdx13, [r0, #CRUNCH_MVDX13]
+       cfldr64         mvdx14, [r0, #CRUNCH_MVDX14]
+       cfldr64         mvdx15, [r0, #CRUNCH_MVDX15]
+
+       mov     pc, lr
+
+/*
+ * Back up crunch regs to save area and disable access to them
+ * (mainly for gdb or sleep mode usage)
+ *
+ * r0 = struct thread_info pointer of target task or NULL for any
+ */
+ENTRY(crunch_task_disable)
+       stmfd   sp!, {r4, r5, lr}
+
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r4, =(EP93XX_APB_VIRT_BASE + 0x00130000)        @ syscon addr
+
+       ldr     r3, =crunch_owner
+       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
+       ldr     r1, [r3]                        @ get current crunch owner
+       teq     r1, #0                          @ any current owner?
+       beq     1f                              @ no: quit
+       teq     r0, #0                          @ any owner?
+       teqne   r1, r2                          @ or specified one?
+       bne     1f                              @ no: quit
+
+       ldr     r5, [r4, #0x80]                 @ enable access to crunch
+       mov     r2, #0xaa
+       str     r2, [r4, #0xc0]
+       orr     r5, r5, #0x00800000
+       str     r5, [r4, #0x80]
+
+       mov     r0, #0                          @ nothing to load
+       str     r0, [r3]                        @ no more current owner
+       ldr     r2, [r4, #0x80]                 @ flush out enable (@@@)
+       mov     r2, r2
+       bl      crunch_save
+
+       mov     r2, #0xaa                       @ disable access to crunch
+       str     r2, [r4, #0xc0]
+       bic     r5, r5, #0x00800000
+       str     r5, [r4, #0x80]
+       ldr     r5, [r4, #0x80]                 @ flush out enable (@@@)
+       mov     r5, r5
+
+1:     msr     cpsr_c, ip                      @ restore interrupt mode
+       ldmfd   sp!, {r4, r5, pc}
+
+/*
+ * Copy crunch state to given memory address
+ *
+ * r0 = struct thread_info pointer of target task
+ * r1 = memory address where to store crunch state
+ *
+ * this is called mainly in the creation of signal stack frames
+ */
+ENTRY(crunch_task_copy)
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r3, =crunch_owner
+       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
+       ldr     r3, [r3]                        @ get current crunch owner
+       teq     r2, r3                          @ does this task own it...
+       beq     1f
+
+       @ current crunch values are in the task save area
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     r0, r1
+       mov     r1, r2
+       mov     r2, #CRUNCH_SIZE
+       b       memcpy
+
+1:     @ this task owns crunch regs -- grab a copy from there
+       mov     r0, #0                          @ nothing to load
+       mov     r3, lr                          @ preserve return address
+       bl      crunch_save
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     pc, r3
+
+/*
+ * Restore crunch state from given memory address
+ *
+ * r0 = struct thread_info pointer of target task
+ * r1 = memory address where to get crunch state from
+ *
+ * this is used to restore crunch state when unwinding a signal stack frame
+ */
+ENTRY(crunch_task_restore)
+       mrs     ip, cpsr
+       orr     r2, ip, #PSR_I_BIT              @ disable interrupts
+       msr     cpsr_c, r2
+
+       ldr     r3, =crunch_owner
+       add     r2, r0, #TI_CRUNCH_STATE        @ get task crunch save area
+       ldr     r3, [r3]                        @ get current crunch owner
+       teq     r2, r3                          @ does this task own it...
+       beq     1f
+
+       @ this task doesn't own crunch regs -- use its save area
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     r0, r2
+       mov     r2, #CRUNCH_SIZE
+       b       memcpy
+
+1:     @ this task owns crunch regs -- load them directly
+       mov     r0, r1
+       mov     r1, #0                          @ nothing to save
+       mov     r3, lr                          @ preserve return address
+       bl      crunch_load
+       msr     cpsr_c, ip                      @ restore interrupt mode
+       mov     pc, r3
diff --git a/arch/arm/mach-ep93xx/crunch.c b/arch/arm/mach-ep93xx/crunch.c
new file mode 100644 (file)
index 0000000..74753e2
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * arch/arm/kernel/crunch.c
+ * Cirrus MaverickCrunch context switching and handling
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <asm/thread_notify.h>
+
+#include "soc.h"
+
+struct crunch_state *crunch_owner;
+
+void crunch_task_release(struct thread_info *thread)
+{
+       local_irq_disable();
+       if (crunch_owner == &thread->crunchstate)
+               crunch_owner = NULL;
+       local_irq_enable();
+}
+
+static int crunch_enabled(u32 devcfg)
+{
+       return !!(devcfg & EP93XX_SYSCON_DEVCFG_CPENA);
+}
+
+static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
+{
+       struct thread_info *thread = (struct thread_info *)t;
+       struct crunch_state *crunch_state;
+       u32 devcfg;
+
+       crunch_state = &thread->crunchstate;
+
+       switch (cmd) {
+       case THREAD_NOTIFY_FLUSH:
+               memset(crunch_state, 0, sizeof(*crunch_state));
+
+               /*
+                * FALLTHROUGH: Ensure we don't try to overwrite our newly
+                * initialised state information on the first fault.
+                */
+
+       case THREAD_NOTIFY_EXIT:
+               crunch_task_release(thread);
+               break;
+
+       case THREAD_NOTIFY_SWITCH:
+               devcfg = __raw_readl(EP93XX_SYSCON_DEVCFG);
+               if (crunch_enabled(devcfg) || crunch_owner == crunch_state) {
+                       /*
+                        * We don't use ep93xx_syscon_swlocked_write() here
+                        * because we are on the context switch path and
+                        * preemption is already disabled.
+                        */
+                       devcfg ^= EP93XX_SYSCON_DEVCFG_CPENA;
+                       __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
+                       __raw_writel(devcfg, EP93XX_SYSCON_DEVCFG);
+               }
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block crunch_notifier_block = {
+       .notifier_call  = crunch_do,
+};
+
+static int __init crunch_init(void)
+{
+       thread_register_notifier(&crunch_notifier_block);
+       elf_hwcap |= HWCAP_CRUNCH;
+
+       return 0;
+}
+
+late_initcall(crunch_init);
index 5a25708..16976d7 100644 (file)
@@ -28,6 +28,8 @@
 #include <mach/dma.h>
 #include <mach/hardware.h>
 
+#include "soc.h"
+
 #define DMA_CHANNEL(_name, _base, _irq) \
        { .name = (_name), .base = (_base), .irq = (_irq) }
 
index d115653..da9047d 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
 
 static void __init edb93xx_register_flash(void)
 {
index af46970..fcdffbe 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
 
 static struct ep93xx_eth_data __initdata gesbc9312_eth_data = {
        .phy_id         = 1,
diff --git a/arch/arm/mach-ep93xx/include/mach/entry-macro.S b/arch/arm/mach-ep93xx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 9be6edc..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/entry-macro.S
- * IRQ demultiplexing for EP93xx
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.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.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index c4a7b84..c64d742 100644 (file)
@@ -6,40 +6,6 @@
 #define __ASM_ARCH_EP93XX_REGS_H
 
 /*
- * EP93xx Physical Memory Map:
- *
- * The ASDO pin is sampled at system reset to select a synchronous or
- * asynchronous boot configuration.  When ASDO is "1" (i.e. pulled-up)
- * the synchronous boot mode is selected.  When ASDO is "0" (i.e
- * pulled-down) the asynchronous boot mode is selected.
- *
- * In synchronous boot mode nSDCE3 is decoded starting at physical address
- * 0x00000000 and nCS0 is decoded starting at 0xf0000000.  For asynchronous
- * boot mode they are swapped with nCS0 decoded at 0x00000000 ann nSDCE3
- * decoded at 0xf0000000.
- *
- * There is known errata for the EP93xx dealing with External Memory
- * Configurations.  Please refer to "AN273: EP93xx Silicon Rev E Design
- * Guidelines" for more information.  This document can be found at:
- *
- *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
- */
-
-#define EP93XX_CS0_PHYS_BASE_ASYNC     0x00000000      /* ASDO Pin = 0 */
-#define EP93XX_SDCE3_PHYS_BASE_SYNC    0x00000000      /* ASDO Pin = 1 */
-#define EP93XX_CS1_PHYS_BASE           0x10000000
-#define EP93XX_CS2_PHYS_BASE           0x20000000
-#define EP93XX_CS3_PHYS_BASE           0x30000000
-#define EP93XX_PCMCIA_PHYS_BASE                0x40000000
-#define EP93XX_CS6_PHYS_BASE           0x60000000
-#define EP93XX_CS7_PHYS_BASE           0x70000000
-#define EP93XX_SDCE0_PHYS_BASE         0xc0000000
-#define EP93XX_SDCE1_PHYS_BASE         0xd0000000
-#define EP93XX_SDCE2_PHYS_BASE         0xe0000000
-#define EP93XX_SDCE3_PHYS_BASE_ASYNC   0xf0000000      /* ASDO Pin = 0 */
-#define EP93XX_CS0_PHYS_BASE_SYNC      0xf0000000      /* ASDO Pin = 1 */
-
-/*
  * EP93xx linux memory map:
  *
  * virt                phys            size
 #define EP93XX_APB_PHYS(x)             (EP93XX_APB_PHYS_BASE + (x))
 #define EP93XX_APB_IOMEM(x)            IOMEM(EP93XX_APB_VIRT_BASE + (x))
 
-
-/* AHB peripherals */
-#define EP93XX_DMA_BASE                        EP93XX_AHB_IOMEM(0x00000000)
-
-#define EP93XX_ETHERNET_PHYS_BASE      EP93XX_AHB_PHYS(0x00010000)
-#define EP93XX_ETHERNET_BASE           EP93XX_AHB_IOMEM(0x00010000)
-
-#define EP93XX_USB_PHYS_BASE           EP93XX_AHB_PHYS(0x00020000)
-#define EP93XX_USB_BASE                        EP93XX_AHB_IOMEM(0x00020000)
-
-#define EP93XX_RASTER_PHYS_BASE                EP93XX_AHB_PHYS(0x00030000)
-#define EP93XX_RASTER_BASE             EP93XX_AHB_IOMEM(0x00030000)
-
-#define EP93XX_GRAPHICS_ACCEL_BASE     EP93XX_AHB_IOMEM(0x00040000)
-
-#define EP93XX_SDRAM_CONTROLLER_BASE   EP93XX_AHB_IOMEM(0x00060000)
-
-#define EP93XX_PCMCIA_CONTROLLER_BASE  EP93XX_AHB_IOMEM(0x00080000)
-
-#define EP93XX_BOOT_ROM_BASE           EP93XX_AHB_IOMEM(0x00090000)
-
-#define EP93XX_IDE_BASE                        EP93XX_AHB_IOMEM(0x000a0000)
-
-#define EP93XX_VIC1_BASE               EP93XX_AHB_IOMEM(0x000b0000)
-
-#define EP93XX_VIC2_BASE               EP93XX_AHB_IOMEM(0x000c0000)
-
-
-/* APB peripherals */
-#define EP93XX_TIMER_BASE              EP93XX_APB_IOMEM(0x00010000)
-
-#define EP93XX_I2S_PHYS_BASE           EP93XX_APB_PHYS(0x00020000)
-#define EP93XX_I2S_BASE                        EP93XX_APB_IOMEM(0x00020000)
-
-#define EP93XX_SECURITY_BASE           EP93XX_APB_IOMEM(0x00030000)
-
-#define EP93XX_GPIO_PHYS_BASE          EP93XX_APB_PHYS(0x00040000)
-#define EP93XX_GPIO_BASE               EP93XX_APB_IOMEM(0x00040000)
-#define EP93XX_GPIO_REG(x)             (EP93XX_GPIO_BASE + (x))
-#define EP93XX_GPIO_F_INT_STATUS       EP93XX_GPIO_REG(0x5c)
-#define EP93XX_GPIO_A_INT_STATUS       EP93XX_GPIO_REG(0xa0)
-#define EP93XX_GPIO_B_INT_STATUS       EP93XX_GPIO_REG(0xbc)
-#define EP93XX_GPIO_EEDRIVE            EP93XX_GPIO_REG(0xc8)
-
-#define EP93XX_AAC_PHYS_BASE           EP93XX_APB_PHYS(0x00080000)
-#define EP93XX_AAC_BASE                        EP93XX_APB_IOMEM(0x00080000)
-
-#define EP93XX_SPI_PHYS_BASE           EP93XX_APB_PHYS(0x000a0000)
-#define EP93XX_SPI_BASE                        EP93XX_APB_IOMEM(0x000a0000)
-
-#define EP93XX_IRDA_BASE               EP93XX_APB_IOMEM(0x000b0000)
-
+/* APB UARTs */
 #define EP93XX_UART1_PHYS_BASE         EP93XX_APB_PHYS(0x000c0000)
 #define EP93XX_UART1_BASE              EP93XX_APB_IOMEM(0x000c0000)
 
 #define EP93XX_UART3_PHYS_BASE         EP93XX_APB_PHYS(0x000e0000)
 #define EP93XX_UART3_BASE              EP93XX_APB_IOMEM(0x000e0000)
 
-#define EP93XX_KEY_MATRIX_PHYS_BASE    EP93XX_APB_PHYS(0x000f0000)
-#define EP93XX_KEY_MATRIX_BASE         EP93XX_APB_IOMEM(0x000f0000)
-
-#define EP93XX_ADC_BASE                        EP93XX_APB_IOMEM(0x00100000)
-#define EP93XX_TOUCHSCREEN_BASE                EP93XX_APB_IOMEM(0x00100000)
-
-#define EP93XX_PWM_PHYS_BASE           EP93XX_APB_PHYS(0x00110000)
-#define EP93XX_PWM_BASE                        EP93XX_APB_IOMEM(0x00110000)
-
-#define EP93XX_RTC_PHYS_BASE           EP93XX_APB_PHYS(0x00120000)
-#define EP93XX_RTC_BASE                        EP93XX_APB_IOMEM(0x00120000)
-
-#define EP93XX_SYSCON_BASE             EP93XX_APB_IOMEM(0x00130000)
-#define EP93XX_SYSCON_REG(x)           (EP93XX_SYSCON_BASE + (x))
-#define EP93XX_SYSCON_POWER_STATE      EP93XX_SYSCON_REG(0x00)
-#define EP93XX_SYSCON_PWRCNT           EP93XX_SYSCON_REG(0x04)
-#define EP93XX_SYSCON_PWRCNT_FIR_EN    (1<<31)
-#define EP93XX_SYSCON_PWRCNT_UARTBAUD  (1<<29)
-#define EP93XX_SYSCON_PWRCNT_USH_EN    (1<<28)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2M1  (1<<27)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2M0  (1<<26)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P8  (1<<25)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P9  (1<<24)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P6  (1<<23)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P7  (1<<22)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P4  (1<<21)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P5  (1<<20)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P2  (1<<19)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P3  (1<<18)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P0  (1<<17)
-#define EP93XX_SYSCON_PWRCNT_DMA_M2P1  (1<<16)
-#define EP93XX_SYSCON_HALT             EP93XX_SYSCON_REG(0x08)
-#define EP93XX_SYSCON_STANDBY          EP93XX_SYSCON_REG(0x0c)
-#define EP93XX_SYSCON_CLKSET1          EP93XX_SYSCON_REG(0x20)
-#define EP93XX_SYSCON_CLKSET1_NBYP1    (1<<23)
-#define EP93XX_SYSCON_CLKSET2          EP93XX_SYSCON_REG(0x24)
-#define EP93XX_SYSCON_CLKSET2_NBYP2    (1<<19)
-#define EP93XX_SYSCON_CLKSET2_PLL2_EN  (1<<18)
-#define EP93XX_SYSCON_DEVCFG           EP93XX_SYSCON_REG(0x80)
-#define EP93XX_SYSCON_DEVCFG_SWRST     (1<<31)
-#define EP93XX_SYSCON_DEVCFG_D1ONG     (1<<30)
-#define EP93XX_SYSCON_DEVCFG_D0ONG     (1<<29)
-#define EP93XX_SYSCON_DEVCFG_IONU2     (1<<28)
-#define EP93XX_SYSCON_DEVCFG_GONK      (1<<27)
-#define EP93XX_SYSCON_DEVCFG_TONG      (1<<26)
-#define EP93XX_SYSCON_DEVCFG_MONG      (1<<25)
-#define EP93XX_SYSCON_DEVCFG_U3EN      (1<<24)
-#define EP93XX_SYSCON_DEVCFG_CPENA     (1<<23)
-#define EP93XX_SYSCON_DEVCFG_A2ONG     (1<<22)
-#define EP93XX_SYSCON_DEVCFG_A1ONG     (1<<21)
-#define EP93XX_SYSCON_DEVCFG_U2EN      (1<<20)
-#define EP93XX_SYSCON_DEVCFG_EXVC      (1<<19)
-#define EP93XX_SYSCON_DEVCFG_U1EN      (1<<18)
-#define EP93XX_SYSCON_DEVCFG_TIN       (1<<17)
-#define EP93XX_SYSCON_DEVCFG_HC3IN     (1<<15)
-#define EP93XX_SYSCON_DEVCFG_HC3EN     (1<<14)
-#define EP93XX_SYSCON_DEVCFG_HC1IN     (1<<13)
-#define EP93XX_SYSCON_DEVCFG_HC1EN     (1<<12)
-#define EP93XX_SYSCON_DEVCFG_HONIDE    (1<<11)
-#define EP93XX_SYSCON_DEVCFG_GONIDE    (1<<10)
-#define EP93XX_SYSCON_DEVCFG_PONG      (1<<9)
-#define EP93XX_SYSCON_DEVCFG_EONIDE    (1<<8)
-#define EP93XX_SYSCON_DEVCFG_I2SONSSP  (1<<7)
-#define EP93XX_SYSCON_DEVCFG_I2SONAC97 (1<<6)
-#define EP93XX_SYSCON_DEVCFG_RASONP3   (1<<4)
-#define EP93XX_SYSCON_DEVCFG_RAS       (1<<3)
-#define EP93XX_SYSCON_DEVCFG_ADCPD     (1<<2)
-#define EP93XX_SYSCON_DEVCFG_KEYS      (1<<1)
-#define EP93XX_SYSCON_DEVCFG_SHENA     (1<<0)
-#define EP93XX_SYSCON_VIDCLKDIV                EP93XX_SYSCON_REG(0x84)
-#define EP93XX_SYSCON_CLKDIV_ENABLE    (1<<15)
-#define EP93XX_SYSCON_CLKDIV_ESEL      (1<<14)
-#define EP93XX_SYSCON_CLKDIV_PSEL      (1<<13)
-#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT        8
-#define EP93XX_SYSCON_I2SCLKDIV                EP93XX_SYSCON_REG(0x8c)
-#define EP93XX_SYSCON_I2SCLKDIV_SENA   (1<<31)
-#define EP93XX_SYSCON_I2SCLKDIV_ORIDE   (1<<29)
-#define EP93XX_SYSCON_I2SCLKDIV_SPOL   (1<<19)
-#define EP93XX_I2SCLKDIV_SDIV          (1 << 16)
-#define EP93XX_I2SCLKDIV_LRDIV32       (0 << 17)
-#define EP93XX_I2SCLKDIV_LRDIV64       (1 << 17)
-#define EP93XX_I2SCLKDIV_LRDIV128      (2 << 17)
-#define EP93XX_I2SCLKDIV_LRDIV_MASK    (3 << 17)
-#define EP93XX_SYSCON_KEYTCHCLKDIV     EP93XX_SYSCON_REG(0x90)
-#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN        (1<<31)
-#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV        (1<<16)
-#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN (1<<15)
-#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV        (1<<0)
-#define EP93XX_SYSCON_SYSCFG           EP93XX_SYSCON_REG(0x9c)
-#define EP93XX_SYSCON_SYSCFG_REV_MASK  (0xf0000000)
-#define EP93XX_SYSCON_SYSCFG_REV_SHIFT (28)
-#define EP93XX_SYSCON_SYSCFG_SBOOT     (1<<8)
-#define EP93XX_SYSCON_SYSCFG_LCSN7     (1<<7)
-#define EP93XX_SYSCON_SYSCFG_LCSN6     (1<<6)
-#define EP93XX_SYSCON_SYSCFG_LASDO     (1<<5)
-#define EP93XX_SYSCON_SYSCFG_LEEDA     (1<<4)
-#define EP93XX_SYSCON_SYSCFG_LEECLK    (1<<3)
-#define EP93XX_SYSCON_SYSCFG_LCSN2     (1<<1)
-#define EP93XX_SYSCON_SYSCFG_LCSN1     (1<<0)
-#define EP93XX_SYSCON_SWLOCK           EP93XX_SYSCON_REG(0xc0)
-
-#define EP93XX_WATCHDOG_BASE           EP93XX_APB_IOMEM(0x00140000)
-
-
 #endif
index 8aff2ea..6d7c571 100644 (file)
@@ -3,6 +3,16 @@
 #ifndef __GPIO_EP93XX_H
 #define __GPIO_EP93XX_H
 
+#include <mach/ep93xx-regs.h>
+
+#define EP93XX_GPIO_PHYS_BASE          EP93XX_APB_PHYS(0x00040000)
+#define EP93XX_GPIO_BASE               EP93XX_APB_IOMEM(0x00040000)
+#define EP93XX_GPIO_REG(x)             (EP93XX_GPIO_BASE + (x))
+#define EP93XX_GPIO_F_INT_STATUS       EP93XX_GPIO_REG(0x5c)
+#define EP93XX_GPIO_A_INT_STATUS       EP93XX_GPIO_REG(0xa0)
+#define EP93XX_GPIO_B_INT_STATUS       EP93XX_GPIO_REG(0xbc)
+#define EP93XX_GPIO_EEDRIVE            EP93XX_GPIO_REG(0xc8)
+
 /* GPIO port A.  */
 #define EP93XX_GPIO_LINE_A(x)          ((x) + 0)
 #define EP93XX_GPIO_LINE_EGPIO0                EP93XX_GPIO_LINE_A(0)
index 4df8428..efcd478 100644 (file)
@@ -5,7 +5,6 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-#include <mach/ep93xx-regs.h>
 #include <mach/platform.h>
 
 /*
index ad63d4b..602bd87 100644 (file)
@@ -21,20 +21,6 @@ struct ep93xx_eth_data
 void ep93xx_map_io(void);
 void ep93xx_init_irq(void);
 
-/* EP93xx System Controller software locked register write */
-void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg);
-void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits);
-
-static inline void ep93xx_devcfg_set_bits(unsigned int bits)
-{
-       ep93xx_devcfg_set_clear(bits, 0x00);
-}
-
-static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
-{
-       ep93xx_devcfg_set_clear(0x00, bits);
-}
-
 #define EP93XX_CHIP_REV_D0     3
 #define EP93XX_CHIP_REV_D1     4
 #define EP93XX_CHIP_REV_E0     5
diff --git a/arch/arm/mach-ep93xx/include/mach/system.h b/arch/arm/mach-ep93xx/include/mach/system.h
deleted file mode 100644 (file)
index b5bec7c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/system.h
- */
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
index 7b98084..dc431c5 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
 
 /*************************************************************************
  * Micro9 NOR Flash
index f4e553e..f40c298 100644 (file)
@@ -29,6 +29,8 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
+
 static struct ep93xx_eth_data __initdata simone_eth_data = {
        .phy_id         = 1,
 };
index fd84633..0c00852 100644 (file)
@@ -35,6 +35,8 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
+
 #define SNAPPERCL15_NAND_BASE  (EP93XX_CS7_PHYS_BASE + SZ_16M)
 
 #define SNAPPERCL15_NAND_WPN   (1 << 8)  /* Write protect (active low) */
diff --git a/arch/arm/mach-ep93xx/soc.h b/arch/arm/mach-ep93xx/soc.h
new file mode 100644 (file)
index 0000000..979fba7
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * arch/arm/mach-ep93xx/soc.h
+ *
+ * Copyright (C) 2012 Open Kernel Labs <www.ok-labs.com>
+ * Copyright (C) 2012 Ryan Mallon <rmallon@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 _EP93XX_SOC_H
+#define _EP93XX_SOC_H
+
+#include <mach/ep93xx-regs.h>
+
+/*
+ * EP93xx Physical Memory Map:
+ *
+ * The ASDO pin is sampled at system reset to select a synchronous or
+ * asynchronous boot configuration.  When ASDO is "1" (i.e. pulled-up)
+ * the synchronous boot mode is selected.  When ASDO is "0" (i.e
+ * pulled-down) the asynchronous boot mode is selected.
+ *
+ * In synchronous boot mode nSDCE3 is decoded starting at physical address
+ * 0x00000000 and nCS0 is decoded starting at 0xf0000000.  For asynchronous
+ * boot mode they are swapped with nCS0 decoded at 0x00000000 ann nSDCE3
+ * decoded at 0xf0000000.
+ *
+ * There is known errata for the EP93xx dealing with External Memory
+ * Configurations.  Please refer to "AN273: EP93xx Silicon Rev E Design
+ * Guidelines" for more information.  This document can be found at:
+ *
+ *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
+ */
+
+#define EP93XX_CS0_PHYS_BASE_ASYNC     0x00000000      /* ASDO Pin = 0 */
+#define EP93XX_SDCE3_PHYS_BASE_SYNC    0x00000000      /* ASDO Pin = 1 */
+#define EP93XX_CS1_PHYS_BASE           0x10000000
+#define EP93XX_CS2_PHYS_BASE           0x20000000
+#define EP93XX_CS3_PHYS_BASE           0x30000000
+#define EP93XX_PCMCIA_PHYS_BASE                0x40000000
+#define EP93XX_CS6_PHYS_BASE           0x60000000
+#define EP93XX_CS7_PHYS_BASE           0x70000000
+#define EP93XX_SDCE0_PHYS_BASE         0xc0000000
+#define EP93XX_SDCE1_PHYS_BASE         0xd0000000
+#define EP93XX_SDCE2_PHYS_BASE         0xe0000000
+#define EP93XX_SDCE3_PHYS_BASE_ASYNC   0xf0000000      /* ASDO Pin = 0 */
+#define EP93XX_CS0_PHYS_BASE_SYNC      0xf0000000      /* ASDO Pin = 1 */
+
+/* AHB peripherals */
+#define EP93XX_DMA_BASE                        EP93XX_AHB_IOMEM(0x00000000)
+
+#define EP93XX_ETHERNET_PHYS_BASE      EP93XX_AHB_PHYS(0x00010000)
+#define EP93XX_ETHERNET_BASE           EP93XX_AHB_IOMEM(0x00010000)
+
+#define EP93XX_USB_PHYS_BASE           EP93XX_AHB_PHYS(0x00020000)
+#define EP93XX_USB_BASE                        EP93XX_AHB_IOMEM(0x00020000)
+
+#define EP93XX_RASTER_PHYS_BASE                EP93XX_AHB_PHYS(0x00030000)
+#define EP93XX_RASTER_BASE             EP93XX_AHB_IOMEM(0x00030000)
+
+#define EP93XX_GRAPHICS_ACCEL_BASE     EP93XX_AHB_IOMEM(0x00040000)
+
+#define EP93XX_SDRAM_CONTROLLER_BASE   EP93XX_AHB_IOMEM(0x00060000)
+
+#define EP93XX_PCMCIA_CONTROLLER_BASE  EP93XX_AHB_IOMEM(0x00080000)
+
+#define EP93XX_BOOT_ROM_BASE           EP93XX_AHB_IOMEM(0x00090000)
+
+#define EP93XX_IDE_BASE                        EP93XX_AHB_IOMEM(0x000a0000)
+
+#define EP93XX_VIC1_BASE               EP93XX_AHB_IOMEM(0x000b0000)
+
+#define EP93XX_VIC2_BASE               EP93XX_AHB_IOMEM(0x000c0000)
+
+/* APB peripherals */
+#define EP93XX_TIMER_BASE              EP93XX_APB_IOMEM(0x00010000)
+
+#define EP93XX_I2S_PHYS_BASE           EP93XX_APB_PHYS(0x00020000)
+#define EP93XX_I2S_BASE                        EP93XX_APB_IOMEM(0x00020000)
+
+#define EP93XX_SECURITY_BASE           EP93XX_APB_IOMEM(0x00030000)
+
+#define EP93XX_AAC_PHYS_BASE           EP93XX_APB_PHYS(0x00080000)
+#define EP93XX_AAC_BASE                        EP93XX_APB_IOMEM(0x00080000)
+
+#define EP93XX_SPI_PHYS_BASE           EP93XX_APB_PHYS(0x000a0000)
+#define EP93XX_SPI_BASE                        EP93XX_APB_IOMEM(0x000a0000)
+
+#define EP93XX_IRDA_BASE               EP93XX_APB_IOMEM(0x000b0000)
+
+#define EP93XX_KEY_MATRIX_PHYS_BASE    EP93XX_APB_PHYS(0x000f0000)
+#define EP93XX_KEY_MATRIX_BASE         EP93XX_APB_IOMEM(0x000f0000)
+
+#define EP93XX_ADC_BASE                        EP93XX_APB_IOMEM(0x00100000)
+#define EP93XX_TOUCHSCREEN_BASE                EP93XX_APB_IOMEM(0x00100000)
+
+#define EP93XX_PWM_PHYS_BASE           EP93XX_APB_PHYS(0x00110000)
+#define EP93XX_PWM_BASE                        EP93XX_APB_IOMEM(0x00110000)
+
+#define EP93XX_RTC_PHYS_BASE           EP93XX_APB_PHYS(0x00120000)
+#define EP93XX_RTC_BASE                        EP93XX_APB_IOMEM(0x00120000)
+
+#define EP93XX_WATCHDOG_PHYS_BASE      EP93XX_APB_PHYS(0x00140000)
+#define EP93XX_WATCHDOG_BASE           EP93XX_APB_IOMEM(0x00140000)
+
+/* System controller */
+#define EP93XX_SYSCON_BASE             EP93XX_APB_IOMEM(0x00130000)
+#define EP93XX_SYSCON_REG(x)           (EP93XX_SYSCON_BASE + (x))
+#define EP93XX_SYSCON_POWER_STATE      EP93XX_SYSCON_REG(0x00)
+#define EP93XX_SYSCON_PWRCNT           EP93XX_SYSCON_REG(0x04)
+#define EP93XX_SYSCON_PWRCNT_FIR_EN    (1<<31)
+#define EP93XX_SYSCON_PWRCNT_UARTBAUD  (1<<29)
+#define EP93XX_SYSCON_PWRCNT_USH_EN    (1<<28)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2M1  (1<<27)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2M0  (1<<26)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P8  (1<<25)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P9  (1<<24)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P6  (1<<23)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P7  (1<<22)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P4  (1<<21)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P5  (1<<20)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P2  (1<<19)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P3  (1<<18)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P0  (1<<17)
+#define EP93XX_SYSCON_PWRCNT_DMA_M2P1  (1<<16)
+#define EP93XX_SYSCON_HALT             EP93XX_SYSCON_REG(0x08)
+#define EP93XX_SYSCON_STANDBY          EP93XX_SYSCON_REG(0x0c)
+#define EP93XX_SYSCON_CLKSET1          EP93XX_SYSCON_REG(0x20)
+#define EP93XX_SYSCON_CLKSET1_NBYP1    (1<<23)
+#define EP93XX_SYSCON_CLKSET2          EP93XX_SYSCON_REG(0x24)
+#define EP93XX_SYSCON_CLKSET2_NBYP2    (1<<19)
+#define EP93XX_SYSCON_CLKSET2_PLL2_EN  (1<<18)
+#define EP93XX_SYSCON_DEVCFG           EP93XX_SYSCON_REG(0x80)
+#define EP93XX_SYSCON_DEVCFG_SWRST     (1<<31)
+#define EP93XX_SYSCON_DEVCFG_D1ONG     (1<<30)
+#define EP93XX_SYSCON_DEVCFG_D0ONG     (1<<29)
+#define EP93XX_SYSCON_DEVCFG_IONU2     (1<<28)
+#define EP93XX_SYSCON_DEVCFG_GONK      (1<<27)
+#define EP93XX_SYSCON_DEVCFG_TONG      (1<<26)
+#define EP93XX_SYSCON_DEVCFG_MONG      (1<<25)
+#define EP93XX_SYSCON_DEVCFG_U3EN      (1<<24)
+#define EP93XX_SYSCON_DEVCFG_CPENA     (1<<23)
+#define EP93XX_SYSCON_DEVCFG_A2ONG     (1<<22)
+#define EP93XX_SYSCON_DEVCFG_A1ONG     (1<<21)
+#define EP93XX_SYSCON_DEVCFG_U2EN      (1<<20)
+#define EP93XX_SYSCON_DEVCFG_EXVC      (1<<19)
+#define EP93XX_SYSCON_DEVCFG_U1EN      (1<<18)
+#define EP93XX_SYSCON_DEVCFG_TIN       (1<<17)
+#define EP93XX_SYSCON_DEVCFG_HC3IN     (1<<15)
+#define EP93XX_SYSCON_DEVCFG_HC3EN     (1<<14)
+#define EP93XX_SYSCON_DEVCFG_HC1IN     (1<<13)
+#define EP93XX_SYSCON_DEVCFG_HC1EN     (1<<12)
+#define EP93XX_SYSCON_DEVCFG_HONIDE    (1<<11)
+#define EP93XX_SYSCON_DEVCFG_GONIDE    (1<<10)
+#define EP93XX_SYSCON_DEVCFG_PONG      (1<<9)
+#define EP93XX_SYSCON_DEVCFG_EONIDE    (1<<8)
+#define EP93XX_SYSCON_DEVCFG_I2SONSSP  (1<<7)
+#define EP93XX_SYSCON_DEVCFG_I2SONAC97 (1<<6)
+#define EP93XX_SYSCON_DEVCFG_RASONP3   (1<<4)
+#define EP93XX_SYSCON_DEVCFG_RAS       (1<<3)
+#define EP93XX_SYSCON_DEVCFG_ADCPD     (1<<2)
+#define EP93XX_SYSCON_DEVCFG_KEYS      (1<<1)
+#define EP93XX_SYSCON_DEVCFG_SHENA     (1<<0)
+#define EP93XX_SYSCON_VIDCLKDIV                EP93XX_SYSCON_REG(0x84)
+#define EP93XX_SYSCON_CLKDIV_ENABLE    (1<<15)
+#define EP93XX_SYSCON_CLKDIV_ESEL      (1<<14)
+#define EP93XX_SYSCON_CLKDIV_PSEL      (1<<13)
+#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT        8
+#define EP93XX_SYSCON_I2SCLKDIV                EP93XX_SYSCON_REG(0x8c)
+#define EP93XX_SYSCON_I2SCLKDIV_SENA   (1<<31)
+#define EP93XX_SYSCON_I2SCLKDIV_ORIDE   (1<<29)
+#define EP93XX_SYSCON_I2SCLKDIV_SPOL   (1<<19)
+#define EP93XX_I2SCLKDIV_SDIV          (1 << 16)
+#define EP93XX_I2SCLKDIV_LRDIV32       (0 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV64       (1 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV128      (2 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV_MASK    (3 << 17)
+#define EP93XX_SYSCON_KEYTCHCLKDIV     EP93XX_SYSCON_REG(0x90)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN        (1<<31)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV        (1<<16)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN (1<<15)
+#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV        (1<<0)
+#define EP93XX_SYSCON_SYSCFG           EP93XX_SYSCON_REG(0x9c)
+#define EP93XX_SYSCON_SYSCFG_REV_MASK  (0xf0000000)
+#define EP93XX_SYSCON_SYSCFG_REV_SHIFT (28)
+#define EP93XX_SYSCON_SYSCFG_SBOOT     (1<<8)
+#define EP93XX_SYSCON_SYSCFG_LCSN7     (1<<7)
+#define EP93XX_SYSCON_SYSCFG_LCSN6     (1<<6)
+#define EP93XX_SYSCON_SYSCFG_LASDO     (1<<5)
+#define EP93XX_SYSCON_SYSCFG_LEEDA     (1<<4)
+#define EP93XX_SYSCON_SYSCFG_LEECLK    (1<<3)
+#define EP93XX_SYSCON_SYSCFG_LCSN2     (1<<1)
+#define EP93XX_SYSCON_SYSCFG_LCSN1     (1<<0)
+#define EP93XX_SYSCON_SWLOCK           EP93XX_SYSCON_REG(0xc0)
+
+/* EP93xx System Controller software locked register write */
+void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg);
+void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits);
+
+static inline void ep93xx_devcfg_set_bits(unsigned int bits)
+{
+       ep93xx_devcfg_set_clear(bits, 0x00);
+}
+
+static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
+{
+       ep93xx_devcfg_set_clear(0x00, bits);
+}
+
+#endif /* _EP93XX_SOC_H */
index 79f8ecf..5ea7909 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
 
 static struct map_desc ts72xx_io_desc[] __initdata = {
        {
index d67d0b4..ba156eb 100644 (file)
@@ -39,6 +39,8 @@
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
 
+#include "soc.h"
+
 /*************************************************************************
  * Static I/O mappings for the FPGA
  *************************************************************************/
index dfad653..0491cee 100644 (file)
@@ -11,18 +11,19 @@ if ARCH_EXYNOS
 
 menu "SAMSUNG EXYNOS SoCs Support"
 
-choice
-       prompt "EXYNOS System Type"
-       default ARCH_EXYNOS4
-
 config ARCH_EXYNOS4
        bool "SAMSUNG EXYNOS4"
+       default y
        select HAVE_SMP
        select MIGHT_HAVE_CACHE_L2X0
        help
          Samsung EXYNOS4 SoCs based systems
 
-endchoice
+config ARCH_EXYNOS5
+       bool "SAMSUNG EXYNOS5"
+       select HAVE_SMP
+       help
+         Samsung EXYNOS5 (Cortex-A15) SoC based systems
 
 comment "EXYNOS SoCs"
 
@@ -42,6 +43,7 @@ config SOC_EXYNOS4212
        bool "SAMSUNG EXYNOS4212"
        default y
        depends on ARCH_EXYNOS4
+       select SAMSUNG_DMADEV
        select S5P_PM if PM
        select S5P_SLEEP if PM
        help
@@ -51,9 +53,17 @@ config SOC_EXYNOS4412
        bool "SAMSUNG EXYNOS4412"
        default y
        depends on ARCH_EXYNOS4
+       select SAMSUNG_DMADEV
        help
          Enable EXYNOS4412 SoC support
 
+config SOC_EXYNOS5250
+       bool "SAMSUNG EXYNOS5250"
+       default y
+       depends on ARCH_EXYNOS5
+       help
+         Enable EXYNOS5250 SoC support
+
 config EXYNOS4_MCT
        bool
        default y
@@ -179,7 +189,9 @@ config MACH_SMDKV310
        select S5P_DEV_FIMC1
        select S5P_DEV_FIMC2
        select S5P_DEV_FIMC3
+       select S5P_DEV_G2D
        select S5P_DEV_I2C_HDMIPHY
+       select S5P_DEV_JPEG
        select S5P_DEV_MFC
        select S5P_DEV_TV
        select S5P_DEV_USB_EHCI
@@ -225,7 +237,9 @@ config MACH_UNIVERSAL_C210
        select S5P_DEV_FIMC1
        select S5P_DEV_FIMC2
        select S5P_DEV_FIMC3
+       select S5P_DEV_G2D
        select S5P_DEV_CSIS0
+       select S5P_DEV_JPEG
        select S5P_DEV_FIMD0
        select S3C_DEV_HSMMC
        select S3C_DEV_HSMMC2
@@ -262,11 +276,14 @@ config MACH_NURI
        select S3C_DEV_I2C1
        select S3C_DEV_I2C3
        select S3C_DEV_I2C5
+       select S3C_DEV_I2C6
        select S5P_DEV_CSIS0
+       select S5P_DEV_JPEG
        select S5P_DEV_FIMC0
        select S5P_DEV_FIMC1
        select S5P_DEV_FIMC2
        select S5P_DEV_FIMC3
+       select S5P_DEV_G2D
        select S5P_DEV_MFC
        select S5P_DEV_USB_EHCI
        select S5P_SETUP_MIPIPHY
@@ -276,6 +293,7 @@ config MACH_NURI
        select EXYNOS4_SETUP_I2C1
        select EXYNOS4_SETUP_I2C3
        select EXYNOS4_SETUP_I2C5
+       select EXYNOS4_SETUP_I2C6
        select EXYNOS4_SETUP_SDHCI
        select EXYNOS4_SETUP_USB_PHY
        select S5P_SETUP_MIPIPHY
@@ -296,7 +314,9 @@ config MACH_ORIGEN
        select S5P_DEV_FIMC2
        select S5P_DEV_FIMC3
        select S5P_DEV_FIMD0
+       select S5P_DEV_G2D
        select S5P_DEV_I2C_HDMIPHY
+       select S5P_DEV_JPEG
        select S5P_DEV_MFC
        select S5P_DEV_TV
        select S5P_DEV_USB_EHCI
@@ -325,6 +345,7 @@ config MACH_SMDK4212
        select SAMSUNG_DEV_BACKLIGHT
        select SAMSUNG_DEV_KEYPAD
        select SAMSUNG_DEV_PWM
+       select EXYNOS4_DEV_DMA
        select EXYNOS4_SETUP_I2C1
        select EXYNOS4_SETUP_I2C3
        select EXYNOS4_SETUP_I2C7
@@ -343,7 +364,7 @@ config MACH_SMDK4412
          Machine support for Samsung SMDK4412
 endif
 
-comment "Flattened Device Tree based board for Exynos4 based SoC"
+comment "Flattened Device Tree based board for EXYNOS SoCs"
 
 config MACH_EXYNOS4_DT
        bool "Samsung Exynos4 Machine using device tree"
@@ -357,6 +378,15 @@ config MACH_EXYNOS4_DT
          Note: This is under development and not all peripherals can be supported
          with this machine file.
 
+config MACH_EXYNOS5_DT
+       bool "SAMSUNG EXYNOS5 Machine using device tree"
+       select SOC_EXYNOS5250
+       select USE_OF
+       select ARM_AMBA
+       help
+         Machine support for Samsung Exynos4 machine with device tree enabled.
+         Select this if a fdt blob is available for the EXYNOS4 SoC based board.
+
 if ARCH_EXYNOS4
 
 comment "Configuration for HSMMC 8-bit bus width"
index d9191f9..8631840 100644 (file)
@@ -12,7 +12,9 @@ obj-                          :=
 
 # Core
 
-obj-$(CONFIG_ARCH_EXYNOS4)     += common.o clock.o
+obj-$(CONFIG_ARCH_EXYNOS)      += common.o
+obj-$(CONFIG_ARCH_EXYNOS4)     += clock-exynos4.o
+obj-$(CONFIG_ARCH_EXYNOS5)     += clock-exynos5.o
 obj-$(CONFIG_CPU_EXYNOS4210)   += clock-exynos4210.o
 obj-$(CONFIG_SOC_EXYNOS4212)   += clock-exynos4212.o
 
@@ -41,9 +43,11 @@ obj-$(CONFIG_MACH_SMDK4212)          += mach-smdk4x12.o
 obj-$(CONFIG_MACH_SMDK4412)            += mach-smdk4x12.o
 
 obj-$(CONFIG_MACH_EXYNOS4_DT)          += mach-exynos4-dt.o
+obj-$(CONFIG_MACH_EXYNOS5_DT)          += mach-exynos5-dt.o
 
 # device support
 
+obj-y                                  += dev-uart.o
 obj-$(CONFIG_ARCH_EXYNOS4)             += dev-audio.o
 obj-$(CONFIG_EXYNOS4_DEV_AHCI)         += dev-ahci.o
 obj-$(CONFIG_EXYNOS4_DEV_SYSMMU)       += dev-sysmmu.o
@@ -51,7 +55,7 @@ obj-$(CONFIG_EXYNOS4_DEV_DWMCI)               += dev-dwmci.o
 obj-$(CONFIG_EXYNOS4_DEV_DMA)          += dma.o
 obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI)     += dev-ohci.o
 
-obj-$(CONFIG_ARCH_EXYNOS4)             += setup-i2c0.o
+obj-$(CONFIG_ARCH_EXYNOS)              += setup-i2c0.o
 obj-$(CONFIG_EXYNOS4_SETUP_FIMC)       += setup-fimc.o
 obj-$(CONFIG_EXYNOS4_SETUP_FIMD0)      += setup-fimd0.o
 obj-$(CONFIG_EXYNOS4_SETUP_I2C1)       += setup-i2c1.o
diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c
new file mode 100644 (file)
index 0000000..df54c2a
--- /dev/null
@@ -0,0 +1,1581 @@
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * EXYNOS4 - Clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/syscore_ops.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/pm.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/sysmmu.h>
+
+#include "common.h"
+#include "clock-exynos4.h"
+
+#ifdef CONFIG_PM_SLEEP
+static struct sleep_save exynos4_clock_save[] = {
+       SAVE_ITEM(EXYNOS4_CLKDIV_LEFTBUS),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_LEFTBUS),
+       SAVE_ITEM(EXYNOS4_CLKDIV_RIGHTBUS),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_RIGHTBUS),
+       SAVE_ITEM(EXYNOS4_CLKSRC_TOP0),
+       SAVE_ITEM(EXYNOS4_CLKSRC_TOP1),
+       SAVE_ITEM(EXYNOS4_CLKSRC_CAM),
+       SAVE_ITEM(EXYNOS4_CLKSRC_TV),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MFC),
+       SAVE_ITEM(EXYNOS4_CLKSRC_G3D),
+       SAVE_ITEM(EXYNOS4_CLKSRC_LCD0),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MAUDIO),
+       SAVE_ITEM(EXYNOS4_CLKSRC_FSYS),
+       SAVE_ITEM(EXYNOS4_CLKSRC_PERIL0),
+       SAVE_ITEM(EXYNOS4_CLKSRC_PERIL1),
+       SAVE_ITEM(EXYNOS4_CLKDIV_CAM),
+       SAVE_ITEM(EXYNOS4_CLKDIV_TV),
+       SAVE_ITEM(EXYNOS4_CLKDIV_MFC),
+       SAVE_ITEM(EXYNOS4_CLKDIV_G3D),
+       SAVE_ITEM(EXYNOS4_CLKDIV_LCD0),
+       SAVE_ITEM(EXYNOS4_CLKDIV_MAUDIO),
+       SAVE_ITEM(EXYNOS4_CLKDIV_FSYS0),
+       SAVE_ITEM(EXYNOS4_CLKDIV_FSYS1),
+       SAVE_ITEM(EXYNOS4_CLKDIV_FSYS2),
+       SAVE_ITEM(EXYNOS4_CLKDIV_FSYS3),
+       SAVE_ITEM(EXYNOS4_CLKDIV_PERIL0),
+       SAVE_ITEM(EXYNOS4_CLKDIV_PERIL1),
+       SAVE_ITEM(EXYNOS4_CLKDIV_PERIL2),
+       SAVE_ITEM(EXYNOS4_CLKDIV_PERIL3),
+       SAVE_ITEM(EXYNOS4_CLKDIV_PERIL4),
+       SAVE_ITEM(EXYNOS4_CLKDIV_PERIL5),
+       SAVE_ITEM(EXYNOS4_CLKDIV_TOP),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MASK_TOP),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MASK_CAM),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MASK_TV),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MASK_LCD0),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MASK_MAUDIO),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MASK_FSYS),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MASK_PERIL0),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MASK_PERIL1),
+       SAVE_ITEM(EXYNOS4_CLKDIV2_RATIO),
+       SAVE_ITEM(EXYNOS4_CLKGATE_SCLKCAM),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_CAM),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_TV),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_MFC),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_G3D),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_LCD0),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_FSYS),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_GPS),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_PERIL),
+       SAVE_ITEM(EXYNOS4_CLKGATE_BLOCK),
+       SAVE_ITEM(EXYNOS4_CLKSRC_MASK_DMC),
+       SAVE_ITEM(EXYNOS4_CLKSRC_DMC),
+       SAVE_ITEM(EXYNOS4_CLKDIV_DMC0),
+       SAVE_ITEM(EXYNOS4_CLKDIV_DMC1),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_DMC),
+       SAVE_ITEM(EXYNOS4_CLKSRC_CPU),
+       SAVE_ITEM(EXYNOS4_CLKDIV_CPU),
+       SAVE_ITEM(EXYNOS4_CLKDIV_CPU + 0x4),
+       SAVE_ITEM(EXYNOS4_CLKGATE_SCLKCPU),
+       SAVE_ITEM(EXYNOS4_CLKGATE_IP_CPU),
+};
+#endif
+
+static struct clk exynos4_clk_sclk_hdmi27m = {
+       .name           = "sclk_hdmi27m",
+       .rate           = 27000000,
+};
+
+static struct clk exynos4_clk_sclk_hdmiphy = {
+       .name           = "sclk_hdmiphy",
+};
+
+static struct clk exynos4_clk_sclk_usbphy0 = {
+       .name           = "sclk_usbphy0",
+       .rate           = 27000000,
+};
+
+static struct clk exynos4_clk_sclk_usbphy1 = {
+       .name           = "sclk_usbphy1",
+};
+
+static struct clk dummy_apb_pclk = {
+       .name           = "apb_pclk",
+       .id             = -1,
+};
+
+static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_TOP, clk, enable);
+}
+
+static int exynos4_clksrc_mask_cam_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_CAM, clk, enable);
+}
+
+static int exynos4_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_LCD0, clk, enable);
+}
+
+int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_FSYS, clk, enable);
+}
+
+static int exynos4_clksrc_mask_peril0_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_PERIL0, clk, enable);
+}
+
+static int exynos4_clksrc_mask_peril1_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_PERIL1, clk, enable);
+}
+
+static int exynos4_clk_ip_mfc_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKGATE_IP_MFC, clk, enable);
+}
+
+static int exynos4_clksrc_mask_tv_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_TV, clk, enable);
+}
+
+static int exynos4_clk_ip_cam_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKGATE_IP_CAM, clk, enable);
+}
+
+static int exynos4_clk_ip_tv_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKGATE_IP_TV, clk, enable);
+}
+
+static int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKGATE_IP_IMAGE, clk, enable);
+}
+
+static int exynos4_clk_ip_lcd0_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKGATE_IP_LCD0, clk, enable);
+}
+
+int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4210_CLKGATE_IP_LCD1, clk, enable);
+}
+
+int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKGATE_IP_FSYS, clk, enable);
+}
+
+static int exynos4_clk_ip_peril_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKGATE_IP_PERIL, clk, enable);
+}
+
+static int exynos4_clk_ip_perir_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS4_CLKGATE_IP_PERIR, clk, enable);
+}
+
+static int exynos4_clk_hdmiphy_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable);
+}
+
+static int exynos4_clk_dac_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(S5P_DAC_PHY_CONTROL, clk, enable);
+}
+
+/* Core list of CMU_CPU side */
+
+static struct clksrc_clk exynos4_clk_mout_apll = {
+       .clk    = {
+               .name           = "mout_apll",
+       },
+       .sources = &clk_src_apll,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_CPU, .shift = 0, .size = 1 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_apll = {
+       .clk    = {
+               .name           = "sclk_apll",
+               .parent         = &exynos4_clk_mout_apll.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 24, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_mout_epll = {
+       .clk    = {
+               .name           = "mout_epll",
+       },
+       .sources = &clk_src_epll,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 4, .size = 1 },
+};
+
+struct clksrc_clk exynos4_clk_mout_mpll = {
+       .clk    = {
+               .name           = "mout_mpll",
+       },
+       .sources = &clk_src_mpll,
+
+       /* reg_src will be added in each SoCs' clock */
+};
+
+static struct clk *exynos4_clkset_moutcore_list[] = {
+       [0] = &exynos4_clk_mout_apll.clk,
+       [1] = &exynos4_clk_mout_mpll.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_moutcore = {
+       .sources        = exynos4_clkset_moutcore_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_moutcore_list),
+};
+
+static struct clksrc_clk exynos4_clk_moutcore = {
+       .clk    = {
+               .name           = "moutcore",
+       },
+       .sources = &exynos4_clkset_moutcore,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_CPU, .shift = 16, .size = 1 },
+};
+
+static struct clksrc_clk exynos4_clk_coreclk = {
+       .clk    = {
+               .name           = "core_clk",
+               .parent         = &exynos4_clk_moutcore.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_armclk = {
+       .clk    = {
+               .name           = "armclk",
+               .parent         = &exynos4_clk_coreclk.clk,
+       },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_corem0 = {
+       .clk    = {
+               .name           = "aclk_corem0",
+               .parent         = &exynos4_clk_coreclk.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 4, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_cores = {
+       .clk    = {
+               .name           = "aclk_cores",
+               .parent         = &exynos4_clk_coreclk.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 4, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_corem1 = {
+       .clk    = {
+               .name           = "aclk_corem1",
+               .parent         = &exynos4_clk_coreclk.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 8, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_periphclk = {
+       .clk    = {
+               .name           = "periphclk",
+               .parent         = &exynos4_clk_coreclk.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_CPU, .shift = 12, .size = 3 },
+};
+
+/* Core list of CMU_CORE side */
+
+static struct clk *exynos4_clkset_corebus_list[] = {
+       [0] = &exynos4_clk_mout_mpll.clk,
+       [1] = &exynos4_clk_sclk_apll.clk,
+};
+
+struct clksrc_sources exynos4_clkset_mout_corebus = {
+       .sources        = exynos4_clkset_corebus_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_corebus_list),
+};
+
+static struct clksrc_clk exynos4_clk_mout_corebus = {
+       .clk    = {
+               .name           = "mout_corebus",
+       },
+       .sources = &exynos4_clkset_mout_corebus,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_DMC, .shift = 4, .size = 1 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_dmc = {
+       .clk    = {
+               .name           = "sclk_dmc",
+               .parent         = &exynos4_clk_mout_corebus.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 12, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_cored = {
+       .clk    = {
+               .name           = "aclk_cored",
+               .parent         = &exynos4_clk_sclk_dmc.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 16, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_corep = {
+       .clk    = {
+               .name           = "aclk_corep",
+               .parent         = &exynos4_clk_aclk_cored.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 20, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_acp = {
+       .clk    = {
+               .name           = "aclk_acp",
+               .parent         = &exynos4_clk_mout_corebus.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_pclk_acp = {
+       .clk    = {
+               .name           = "pclk_acp",
+               .parent         = &exynos4_clk_aclk_acp.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_DMC0, .shift = 4, .size = 3 },
+};
+
+/* Core list of CMU_TOP side */
+
+struct clk *exynos4_clkset_aclk_top_list[] = {
+       [0] = &exynos4_clk_mout_mpll.clk,
+       [1] = &exynos4_clk_sclk_apll.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_aclk = {
+       .sources        = exynos4_clkset_aclk_top_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_aclk_top_list),
+};
+
+static struct clksrc_clk exynos4_clk_aclk_200 = {
+       .clk    = {
+               .name           = "aclk_200",
+       },
+       .sources = &exynos4_clkset_aclk,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 12, .size = 1 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_100 = {
+       .clk    = {
+               .name           = "aclk_100",
+       },
+       .sources = &exynos4_clkset_aclk,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 16, .size = 1 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 4, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_aclk_160 = {
+       .clk    = {
+               .name           = "aclk_160",
+       },
+       .sources = &exynos4_clkset_aclk,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 20, .size = 1 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 8, .size = 3 },
+};
+
+struct clksrc_clk exynos4_clk_aclk_133 = {
+       .clk    = {
+               .name           = "aclk_133",
+       },
+       .sources = &exynos4_clkset_aclk,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 24, .size = 1 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_TOP, .shift = 12, .size = 3 },
+};
+
+static struct clk *exynos4_clkset_vpllsrc_list[] = {
+       [0] = &clk_fin_vpll,
+       [1] = &exynos4_clk_sclk_hdmi27m,
+};
+
+static struct clksrc_sources exynos4_clkset_vpllsrc = {
+       .sources        = exynos4_clkset_vpllsrc_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_vpllsrc_list),
+};
+
+static struct clksrc_clk exynos4_clk_vpllsrc = {
+       .clk    = {
+               .name           = "vpll_src",
+               .enable         = exynos4_clksrc_mask_top_ctrl,
+               .ctrlbit        = (1 << 0),
+       },
+       .sources = &exynos4_clkset_vpllsrc,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_TOP1, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos4_clkset_sclk_vpll_list[] = {
+       [0] = &exynos4_clk_vpllsrc.clk,
+       [1] = &clk_fout_vpll,
+};
+
+static struct clksrc_sources exynos4_clkset_sclk_vpll = {
+       .sources        = exynos4_clkset_sclk_vpll_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_sclk_vpll_list),
+};
+
+static struct clksrc_clk exynos4_clk_sclk_vpll = {
+       .clk    = {
+               .name           = "sclk_vpll",
+       },
+       .sources = &exynos4_clkset_sclk_vpll,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_TOP0, .shift = 8, .size = 1 },
+};
+
+static struct clk exynos4_init_clocks_off[] = {
+       {
+               .name           = "timers",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1<<24),
+       }, {
+               .name           = "csis",
+               .devname        = "s5p-mipi-csis.0",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 4),
+       }, {
+               .name           = "csis",
+               .devname        = "s5p-mipi-csis.1",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 5),
+       }, {
+               .name           = "jpeg",
+               .id             = 0,
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 6),
+       }, {
+               .name           = "fimc",
+               .devname        = "exynos4-fimc.0",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 0),
+       }, {
+               .name           = "fimc",
+               .devname        = "exynos4-fimc.1",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "fimc",
+               .devname        = "exynos4-fimc.2",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 2),
+       }, {
+               .name           = "fimc",
+               .devname        = "exynos4-fimc.3",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 3),
+       }, {
+               .name           = "hsmmc",
+               .devname        = "s3c-sdhci.0",
+               .parent         = &exynos4_clk_aclk_133.clk,
+               .enable         = exynos4_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 5),
+       }, {
+               .name           = "hsmmc",
+               .devname        = "s3c-sdhci.1",
+               .parent         = &exynos4_clk_aclk_133.clk,
+               .enable         = exynos4_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 6),
+       }, {
+               .name           = "hsmmc",
+               .devname        = "s3c-sdhci.2",
+               .parent         = &exynos4_clk_aclk_133.clk,
+               .enable         = exynos4_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 7),
+       }, {
+               .name           = "hsmmc",
+               .devname        = "s3c-sdhci.3",
+               .parent         = &exynos4_clk_aclk_133.clk,
+               .enable         = exynos4_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 8),
+       }, {
+               .name           = "dwmmc",
+               .parent         = &exynos4_clk_aclk_133.clk,
+               .enable         = exynos4_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 9),
+       }, {
+               .name           = "dac",
+               .devname        = "s5p-sdo",
+               .enable         = exynos4_clk_ip_tv_ctrl,
+               .ctrlbit        = (1 << 2),
+       }, {
+               .name           = "mixer",
+               .devname        = "s5p-mixer",
+               .enable         = exynos4_clk_ip_tv_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "vp",
+               .devname        = "s5p-mixer",
+               .enable         = exynos4_clk_ip_tv_ctrl,
+               .ctrlbit        = (1 << 0),
+       }, {
+               .name           = "hdmi",
+               .devname        = "exynos4-hdmi",
+               .enable         = exynos4_clk_ip_tv_ctrl,
+               .ctrlbit        = (1 << 3),
+       }, {
+               .name           = "hdmiphy",
+               .devname        = "exynos4-hdmi",
+               .enable         = exynos4_clk_hdmiphy_ctrl,
+               .ctrlbit        = (1 << 0),
+       }, {
+               .name           = "dacphy",
+               .devname        = "s5p-sdo",
+               .enable         = exynos4_clk_dac_ctrl,
+               .ctrlbit        = (1 << 0),
+       }, {
+               .name           = "adc",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 15),
+       }, {
+               .name           = "keypad",
+               .enable         = exynos4_clk_ip_perir_ctrl,
+               .ctrlbit        = (1 << 16),
+       }, {
+               .name           = "rtc",
+               .enable         = exynos4_clk_ip_perir_ctrl,
+               .ctrlbit        = (1 << 15),
+       }, {
+               .name           = "watchdog",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_perir_ctrl,
+               .ctrlbit        = (1 << 14),
+       }, {
+               .name           = "usbhost",
+               .enable         = exynos4_clk_ip_fsys_ctrl ,
+               .ctrlbit        = (1 << 12),
+       }, {
+               .name           = "otg",
+               .enable         = exynos4_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 13),
+       }, {
+               .name           = "spi",
+               .devname        = "s3c64xx-spi.0",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 16),
+       }, {
+               .name           = "spi",
+               .devname        = "s3c64xx-spi.1",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 17),
+       }, {
+               .name           = "spi",
+               .devname        = "s3c64xx-spi.2",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 18),
+       }, {
+               .name           = "iis",
+               .devname        = "samsung-i2s.0",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 19),
+       }, {
+               .name           = "iis",
+               .devname        = "samsung-i2s.1",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 20),
+       }, {
+               .name           = "iis",
+               .devname        = "samsung-i2s.2",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 21),
+       }, {
+               .name           = "ac97",
+               .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",
+               .enable         = exynos4_clk_ip_mfc_ctrl,
+               .ctrlbit        = (1 << 0),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.0",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 6),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.1",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 7),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.2",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 8),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.3",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 9),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.4",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 10),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.5",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 11),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.6",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 12),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.7",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 13),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-hdmiphy-i2c",
+               .parent         = &exynos4_clk_aclk_100.clk,
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 14),
+       }, {
+               .name           = "SYSMMU_MDMA",
+               .enable         = exynos4_clk_ip_image_ctrl,
+               .ctrlbit        = (1 << 5),
+       }, {
+               .name           = "SYSMMU_FIMC0",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 7),
+       }, {
+               .name           = "SYSMMU_FIMC1",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 8),
+       }, {
+               .name           = "SYSMMU_FIMC2",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 9),
+       }, {
+               .name           = "SYSMMU_FIMC3",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 10),
+       }, {
+               .name           = "SYSMMU_JPEG",
+               .enable         = exynos4_clk_ip_cam_ctrl,
+               .ctrlbit        = (1 << 11),
+       }, {
+               .name           = "SYSMMU_FIMD0",
+               .enable         = exynos4_clk_ip_lcd0_ctrl,
+               .ctrlbit        = (1 << 4),
+       }, {
+               .name           = "SYSMMU_FIMD1",
+               .enable         = exynos4_clk_ip_lcd1_ctrl,
+               .ctrlbit        = (1 << 4),
+       }, {
+               .name           = "SYSMMU_PCIe",
+               .enable         = exynos4_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 18),
+       }, {
+               .name           = "SYSMMU_G2D",
+               .enable         = exynos4_clk_ip_image_ctrl,
+               .ctrlbit        = (1 << 3),
+       }, {
+               .name           = "SYSMMU_ROTATOR",
+               .enable         = exynos4_clk_ip_image_ctrl,
+               .ctrlbit        = (1 << 4),
+       }, {
+               .name           = "SYSMMU_TV",
+               .enable         = exynos4_clk_ip_tv_ctrl,
+               .ctrlbit        = (1 << 4),
+       }, {
+               .name           = "SYSMMU_MFC_L",
+               .enable         = exynos4_clk_ip_mfc_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "SYSMMU_MFC_R",
+               .enable         = exynos4_clk_ip_mfc_ctrl,
+               .ctrlbit        = (1 << 2),
+       }
+};
+
+static struct clk exynos4_init_clocks_on[] = {
+       {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.0",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 0),
+       }, {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.1",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.2",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 2),
+       }, {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.3",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 3),
+       }, {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.4",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 4),
+       }, {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.5",
+               .enable         = exynos4_clk_ip_peril_ctrl,
+               .ctrlbit        = (1 << 5),
+       }
+};
+
+static struct clk exynos4_clk_pdma0 = {
+       .name           = "dma",
+       .devname        = "dma-pl330.0",
+       .enable         = exynos4_clk_ip_fsys_ctrl,
+       .ctrlbit        = (1 << 0),
+};
+
+static struct clk exynos4_clk_pdma1 = {
+       .name           = "dma",
+       .devname        = "dma-pl330.1",
+       .enable         = exynos4_clk_ip_fsys_ctrl,
+       .ctrlbit        = (1 << 1),
+};
+
+static struct clk exynos4_clk_mdma1 = {
+       .name           = "dma",
+       .devname        = "dma-pl330.2",
+       .enable         = exynos4_clk_ip_image_ctrl,
+       .ctrlbit        = ((1 << 8) | (1 << 5) | (1 << 2)),
+};
+
+static struct clk exynos4_clk_fimd0 = {
+       .name           = "fimd",
+       .devname        = "exynos4-fb.0",
+       .enable         = exynos4_clk_ip_lcd0_ctrl,
+       .ctrlbit        = (1 << 0),
+};
+
+struct clk *exynos4_clkset_group_list[] = {
+       [0] = &clk_ext_xtal_mux,
+       [1] = &clk_xusbxti,
+       [2] = &exynos4_clk_sclk_hdmi27m,
+       [3] = &exynos4_clk_sclk_usbphy0,
+       [4] = &exynos4_clk_sclk_usbphy1,
+       [5] = &exynos4_clk_sclk_hdmiphy,
+       [6] = &exynos4_clk_mout_mpll.clk,
+       [7] = &exynos4_clk_mout_epll.clk,
+       [8] = &exynos4_clk_sclk_vpll.clk,
+};
+
+struct clksrc_sources exynos4_clkset_group = {
+       .sources        = exynos4_clkset_group_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_group_list),
+};
+
+static struct clk *exynos4_clkset_mout_g2d0_list[] = {
+       [0] = &exynos4_clk_mout_mpll.clk,
+       [1] = &exynos4_clk_sclk_apll.clk,
+};
+
+static 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 = {
+       .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,
+};
+
+static struct clksrc_sources exynos4_clkset_mout_mfc0 = {
+       .sources        = exynos4_clkset_mout_mfc0_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_mout_mfc0_list),
+};
+
+static struct clksrc_clk exynos4_clk_mout_mfc0 = {
+       .clk    = {
+               .name           = "mout_mfc0",
+       },
+       .sources = &exynos4_clkset_mout_mfc0,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_MFC, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos4_clkset_mout_mfc1_list[] = {
+       [0] = &exynos4_clk_mout_epll.clk,
+       [1] = &exynos4_clk_sclk_vpll.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_mout_mfc1 = {
+       .sources        = exynos4_clkset_mout_mfc1_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_mout_mfc1_list),
+};
+
+static struct clksrc_clk exynos4_clk_mout_mfc1 = {
+       .clk    = {
+               .name           = "mout_mfc1",
+       },
+       .sources = &exynos4_clkset_mout_mfc1,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_MFC, .shift = 4, .size = 1 },
+};
+
+static struct clk *exynos4_clkset_mout_mfc_list[] = {
+       [0] = &exynos4_clk_mout_mfc0.clk,
+       [1] = &exynos4_clk_mout_mfc1.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_mout_mfc = {
+       .sources        = exynos4_clkset_mout_mfc_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_mout_mfc_list),
+};
+
+static struct clk *exynos4_clkset_sclk_dac_list[] = {
+       [0] = &exynos4_clk_sclk_vpll.clk,
+       [1] = &exynos4_clk_sclk_hdmiphy,
+};
+
+static struct clksrc_sources exynos4_clkset_sclk_dac = {
+       .sources        = exynos4_clkset_sclk_dac_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_sclk_dac_list),
+};
+
+static struct clksrc_clk exynos4_clk_sclk_dac = {
+       .clk            = {
+               .name           = "sclk_dac",
+               .enable         = exynos4_clksrc_mask_tv_ctrl,
+               .ctrlbit        = (1 << 8),
+       },
+       .sources = &exynos4_clkset_sclk_dac,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_TV, .shift = 8, .size = 1 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_pixel = {
+       .clk            = {
+               .name           = "sclk_pixel",
+               .parent         = &exynos4_clk_sclk_vpll.clk,
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_TV, .shift = 0, .size = 4 },
+};
+
+static struct clk *exynos4_clkset_sclk_hdmi_list[] = {
+       [0] = &exynos4_clk_sclk_pixel.clk,
+       [1] = &exynos4_clk_sclk_hdmiphy,
+};
+
+static struct clksrc_sources exynos4_clkset_sclk_hdmi = {
+       .sources        = exynos4_clkset_sclk_hdmi_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_sclk_hdmi_list),
+};
+
+static struct clksrc_clk exynos4_clk_sclk_hdmi = {
+       .clk            = {
+               .name           = "sclk_hdmi",
+               .enable         = exynos4_clksrc_mask_tv_ctrl,
+               .ctrlbit        = (1 << 0),
+       },
+       .sources = &exynos4_clkset_sclk_hdmi,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_TV, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos4_clkset_sclk_mixer_list[] = {
+       [0] = &exynos4_clk_sclk_dac.clk,
+       [1] = &exynos4_clk_sclk_hdmi.clk,
+};
+
+static struct clksrc_sources exynos4_clkset_sclk_mixer = {
+       .sources        = exynos4_clkset_sclk_mixer_list,
+       .nr_sources     = ARRAY_SIZE(exynos4_clkset_sclk_mixer_list),
+};
+
+static struct clksrc_clk exynos4_clk_sclk_mixer = {
+       .clk    = {
+               .name           = "sclk_mixer",
+               .enable         = exynos4_clksrc_mask_tv_ctrl,
+               .ctrlbit        = (1 << 4),
+       },
+       .sources = &exynos4_clkset_sclk_mixer,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_TV, .shift = 4, .size = 1 },
+};
+
+static struct clksrc_clk *exynos4_sclk_tv[] = {
+       &exynos4_clk_sclk_dac,
+       &exynos4_clk_sclk_pixel,
+       &exynos4_clk_sclk_hdmi,
+       &exynos4_clk_sclk_mixer,
+};
+
+static struct clksrc_clk exynos4_clk_dout_mmc0 = {
+       .clk    = {
+               .name           = "dout_mmc0",
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 0, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_dout_mmc1 = {
+       .clk    = {
+               .name           = "dout_mmc1",
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 4, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_dout_mmc2 = {
+       .clk    = {
+               .name           = "dout_mmc2",
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 8, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_dout_mmc3 = {
+       .clk    = {
+               .name           = "dout_mmc3",
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 12, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_dout_mmc4 = {
+       .clk            = {
+               .name           = "dout_mmc4",
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 16, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS3, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clksrcs[] = {
+       {
+               .clk    = {
+                       .name           = "sclk_pwm",
+                       .enable         = exynos4_clksrc_mask_peril0_ctrl,
+                       .ctrlbit        = (1 << 24),
+               },
+               .sources = &exynos4_clkset_group,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 24, .size = 4 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL3, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_csis",
+                       .devname        = "s5p-mipi-csis.0",
+                       .enable         = exynos4_clksrc_mask_cam_ctrl,
+                       .ctrlbit        = (1 << 24),
+               },
+               .sources = &exynos4_clkset_group,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 24, .size = 4 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 24, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_csis",
+                       .devname        = "s5p-mipi-csis.1",
+                       .enable         = exynos4_clksrc_mask_cam_ctrl,
+                       .ctrlbit        = (1 << 28),
+               },
+               .sources = &exynos4_clkset_group,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 28, .size = 4 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 28, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_cam0",
+                       .enable         = exynos4_clksrc_mask_cam_ctrl,
+                       .ctrlbit        = (1 << 16),
+               },
+               .sources = &exynos4_clkset_group,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 16, .size = 4 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 16, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_cam1",
+                       .enable         = exynos4_clksrc_mask_cam_ctrl,
+                       .ctrlbit        = (1 << 20),
+               },
+               .sources = &exynos4_clkset_group,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 20, .size = 4 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 20, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_fimc",
+                       .devname        = "exynos4-fimc.0",
+                       .enable         = exynos4_clksrc_mask_cam_ctrl,
+                       .ctrlbit        = (1 << 0),
+               },
+               .sources = &exynos4_clkset_group,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 0, .size = 4 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_fimc",
+                       .devname        = "exynos4-fimc.1",
+                       .enable         = exynos4_clksrc_mask_cam_ctrl,
+                       .ctrlbit        = (1 << 4),
+               },
+               .sources = &exynos4_clkset_group,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 4, .size = 4 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 4, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_fimc",
+                       .devname        = "exynos4-fimc.2",
+                       .enable         = exynos4_clksrc_mask_cam_ctrl,
+                       .ctrlbit        = (1 << 8),
+               },
+               .sources = &exynos4_clkset_group,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 8, .size = 4 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 8, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_fimc",
+                       .devname        = "exynos4-fimc.3",
+                       .enable         = exynos4_clksrc_mask_cam_ctrl,
+                       .ctrlbit        = (1 << 12),
+               },
+               .sources = &exynos4_clkset_group,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_CAM, .shift = 12, .size = 4 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_CAM, .shift = 12, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_fimd",
+                       .devname        = "exynos4-fb.0",
+                       .enable         = exynos4_clksrc_mask_lcd0_ctrl,
+                       .ctrlbit        = (1 << 0),
+               },
+               .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",
+                       .devname        = "s5p-mfc",
+               },
+               .sources = &exynos4_clkset_mout_mfc,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_MFC, .shift = 8, .size = 1 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_MFC, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_dwmmc",
+                       .parent         = &exynos4_clk_dout_mmc4.clk,
+                       .enable         = exynos4_clksrc_mask_fsys_ctrl,
+                       .ctrlbit        = (1 << 16),
+               },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS3, .shift = 8, .size = 8 },
+       }
+};
+
+static struct clksrc_clk exynos4_clk_sclk_uart0 = {
+       .clk    = {
+               .name           = "uclk1",
+               .devname        = "exynos4210-uart.0",
+               .enable         = exynos4_clksrc_mask_peril0_ctrl,
+               .ctrlbit        = (1 << 0),
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 0, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_uart1 = {
+       .clk    = {
+               .name           = "uclk1",
+               .devname        = "exynos4210-uart.1",
+               .enable         = exynos4_clksrc_mask_peril0_ctrl,
+               .ctrlbit        = (1 << 4),
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 4, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 4, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_uart2 = {
+       .clk    = {
+               .name           = "uclk1",
+               .devname        = "exynos4210-uart.2",
+               .enable         = exynos4_clksrc_mask_peril0_ctrl,
+               .ctrlbit        = (1 << 8),
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 8, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_uart3 = {
+       .clk    = {
+               .name           = "uclk1",
+               .devname        = "exynos4210-uart.3",
+               .enable         = exynos4_clksrc_mask_peril0_ctrl,
+               .ctrlbit        = (1 << 12),
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL0, .shift = 12, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL0, .shift = 12, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_mmc0 = {
+       .clk    = {
+               .name           = "sclk_mmc",
+               .devname        = "s3c-sdhci.0",
+               .parent         = &exynos4_clk_dout_mmc0.clk,
+               .enable         = exynos4_clksrc_mask_fsys_ctrl,
+               .ctrlbit        = (1 << 0),
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_mmc1 = {
+       .clk    = {
+               .name           = "sclk_mmc",
+               .devname        = "s3c-sdhci.1",
+               .parent         = &exynos4_clk_dout_mmc1.clk,
+               .enable         = exynos4_clksrc_mask_fsys_ctrl,
+               .ctrlbit        = (1 << 4),
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS1, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_mmc2 = {
+       .clk    = {
+               .name           = "sclk_mmc",
+               .devname        = "s3c-sdhci.2",
+               .parent         = &exynos4_clk_dout_mmc2.clk,
+               .enable         = exynos4_clksrc_mask_fsys_ctrl,
+               .ctrlbit        = (1 << 8),
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_mmc3 = {
+       .clk    = {
+               .name           = "sclk_mmc",
+               .devname        = "s3c-sdhci.3",
+               .parent         = &exynos4_clk_dout_mmc3.clk,
+               .enable         = exynos4_clksrc_mask_fsys_ctrl,
+               .ctrlbit        = (1 << 12),
+       },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_spi0 = {
+       .clk    = {
+               .name           = "sclk_spi",
+               .devname        = "s3c64xx-spi.0",
+               .enable         = exynos4_clksrc_mask_peril1_ctrl,
+               .ctrlbit        = (1 << 16),
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 16, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_spi1 = {
+       .clk    = {
+               .name           = "sclk_spi",
+               .devname        = "s3c64xx-spi.1",
+               .enable         = exynos4_clksrc_mask_peril1_ctrl,
+               .ctrlbit        = (1 << 20),
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 20, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_sclk_spi2 = {
+       .clk    = {
+               .name           = "sclk_spi",
+               .devname        = "s3c64xx-spi.2",
+               .enable         = exynos4_clksrc_mask_peril1_ctrl,
+               .ctrlbit        = (1 << 24),
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 24, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL2, .shift = 0, .size = 4 },
+};
+
+/* Clock initialization code */
+static struct clksrc_clk *exynos4_sysclks[] = {
+       &exynos4_clk_mout_apll,
+       &exynos4_clk_sclk_apll,
+       &exynos4_clk_mout_epll,
+       &exynos4_clk_mout_mpll,
+       &exynos4_clk_moutcore,
+       &exynos4_clk_coreclk,
+       &exynos4_clk_armclk,
+       &exynos4_clk_aclk_corem0,
+       &exynos4_clk_aclk_cores,
+       &exynos4_clk_aclk_corem1,
+       &exynos4_clk_periphclk,
+       &exynos4_clk_mout_corebus,
+       &exynos4_clk_sclk_dmc,
+       &exynos4_clk_aclk_cored,
+       &exynos4_clk_aclk_corep,
+       &exynos4_clk_aclk_acp,
+       &exynos4_clk_pclk_acp,
+       &exynos4_clk_vpllsrc,
+       &exynos4_clk_sclk_vpll,
+       &exynos4_clk_aclk_200,
+       &exynos4_clk_aclk_100,
+       &exynos4_clk_aclk_160,
+       &exynos4_clk_aclk_133,
+       &exynos4_clk_dout_mmc0,
+       &exynos4_clk_dout_mmc1,
+       &exynos4_clk_dout_mmc2,
+       &exynos4_clk_dout_mmc3,
+       &exynos4_clk_dout_mmc4,
+       &exynos4_clk_mout_mfc0,
+       &exynos4_clk_mout_mfc1,
+};
+
+static struct clk *exynos4_clk_cdev[] = {
+       &exynos4_clk_pdma0,
+       &exynos4_clk_pdma1,
+       &exynos4_clk_mdma1,
+       &exynos4_clk_fimd0,
+};
+
+static struct clksrc_clk *exynos4_clksrc_cdev[] = {
+       &exynos4_clk_sclk_uart0,
+       &exynos4_clk_sclk_uart1,
+       &exynos4_clk_sclk_uart2,
+       &exynos4_clk_sclk_uart3,
+       &exynos4_clk_sclk_mmc0,
+       &exynos4_clk_sclk_mmc1,
+       &exynos4_clk_sclk_mmc2,
+       &exynos4_clk_sclk_mmc3,
+       &exynos4_clk_sclk_spi0,
+       &exynos4_clk_sclk_spi1,
+       &exynos4_clk_sclk_spi2,
+
+};
+
+static struct clk_lookup exynos4_clk_lookup[] = {
+       CLKDEV_INIT("exynos4210-uart.0", "clk_uart_baud0", &exynos4_clk_sclk_uart0.clk),
+       CLKDEV_INIT("exynos4210-uart.1", "clk_uart_baud0", &exynos4_clk_sclk_uart1.clk),
+       CLKDEV_INIT("exynos4210-uart.2", "clk_uart_baud0", &exynos4_clk_sclk_uart2.clk),
+       CLKDEV_INIT("exynos4210-uart.3", "clk_uart_baud0", &exynos4_clk_sclk_uart3.clk),
+       CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &exynos4_clk_sclk_mmc0.clk),
+       CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &exynos4_clk_sclk_mmc1.clk),
+       CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &exynos4_clk_sclk_mmc2.clk),
+       CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &exynos4_clk_sclk_mmc3.clk),
+       CLKDEV_INIT("exynos4-fb.0", "lcd", &exynos4_clk_fimd0),
+       CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos4_clk_pdma0),
+       CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos4_clk_pdma1),
+       CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos4_clk_mdma1),
+       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk0", &exynos4_clk_sclk_spi0.clk),
+       CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk0", &exynos4_clk_sclk_spi1.clk),
+       CLKDEV_INIT("s3c64xx-spi.2", "spi_busclk0", &exynos4_clk_sclk_spi2.clk),
+};
+
+static int xtal_rate;
+
+static unsigned long exynos4_fout_apll_get_rate(struct clk *clk)
+{
+       if (soc_is_exynos4210())
+               return s5p_get_pll45xx(xtal_rate, __raw_readl(EXYNOS4_APLL_CON0),
+                                       pll_4508);
+       else if (soc_is_exynos4212() || soc_is_exynos4412())
+               return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS4_APLL_CON0));
+       else
+               return 0;
+}
+
+static struct clk_ops exynos4_fout_apll_ops = {
+       .get_rate = exynos4_fout_apll_get_rate,
+};
+
+static u32 exynos4_vpll_div[][8] = {
+       {  54000000, 3, 53, 3, 1024, 0, 17, 0 },
+       { 108000000, 3, 53, 2, 1024, 0, 17, 0 },
+};
+
+static unsigned long exynos4_vpll_get_rate(struct clk *clk)
+{
+       return clk->rate;
+}
+
+static int exynos4_vpll_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned int vpll_con0, vpll_con1 = 0;
+       unsigned int i;
+
+       /* Return if nothing changed */
+       if (clk->rate == rate)
+               return 0;
+
+       vpll_con0 = __raw_readl(EXYNOS4_VPLL_CON0);
+       vpll_con0 &= ~(0x1 << 27 |                                      \
+                       PLL90XX_MDIV_MASK << PLL46XX_MDIV_SHIFT |       \
+                       PLL90XX_PDIV_MASK << PLL46XX_PDIV_SHIFT |       \
+                       PLL90XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
+
+       vpll_con1 = __raw_readl(EXYNOS4_VPLL_CON1);
+       vpll_con1 &= ~(PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT |  \
+                       PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT | \
+                       PLL4650C_KDIV_MASK << PLL46XX_KDIV_SHIFT);
+
+       for (i = 0; i < ARRAY_SIZE(exynos4_vpll_div); i++) {
+               if (exynos4_vpll_div[i][0] == rate) {
+                       vpll_con0 |= exynos4_vpll_div[i][1] << PLL46XX_PDIV_SHIFT;
+                       vpll_con0 |= exynos4_vpll_div[i][2] << PLL46XX_MDIV_SHIFT;
+                       vpll_con0 |= exynos4_vpll_div[i][3] << PLL46XX_SDIV_SHIFT;
+                       vpll_con1 |= exynos4_vpll_div[i][4] << PLL46XX_KDIV_SHIFT;
+                       vpll_con1 |= exynos4_vpll_div[i][5] << PLL46XX_MFR_SHIFT;
+                       vpll_con1 |= exynos4_vpll_div[i][6] << PLL46XX_MRR_SHIFT;
+                       vpll_con0 |= exynos4_vpll_div[i][7] << 27;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(exynos4_vpll_div)) {
+               printk(KERN_ERR "%s: Invalid Clock VPLL Frequency\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       __raw_writel(vpll_con0, EXYNOS4_VPLL_CON0);
+       __raw_writel(vpll_con1, EXYNOS4_VPLL_CON1);
+
+       /* Wait for VPLL lock */
+       while (!(__raw_readl(EXYNOS4_VPLL_CON0) & (1 << PLL46XX_LOCKED_SHIFT)))
+               continue;
+
+       clk->rate = rate;
+       return 0;
+}
+
+static struct clk_ops exynos4_vpll_ops = {
+       .get_rate = exynos4_vpll_get_rate,
+       .set_rate = exynos4_vpll_set_rate,
+};
+
+void __init_or_cpufreq exynos4_setup_clocks(void)
+{
+       struct clk *xtal_clk;
+       unsigned long apll = 0;
+       unsigned long mpll = 0;
+       unsigned long epll = 0;
+       unsigned long vpll = 0;
+       unsigned long vpllsrc;
+       unsigned long xtal;
+       unsigned long armclk;
+       unsigned long sclk_dmc;
+       unsigned long aclk_200;
+       unsigned long aclk_100;
+       unsigned long aclk_160;
+       unsigned long aclk_133;
+       unsigned int ptr;
+
+       printk(KERN_DEBUG "%s: registering clocks\n", __func__);
+
+       xtal_clk = clk_get(NULL, "xtal");
+       BUG_ON(IS_ERR(xtal_clk));
+
+       xtal = clk_get_rate(xtal_clk);
+
+       xtal_rate = xtal;
+
+       clk_put(xtal_clk);
+
+       printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
+
+       if (soc_is_exynos4210()) {
+               apll = s5p_get_pll45xx(xtal, __raw_readl(EXYNOS4_APLL_CON0),
+                                       pll_4508);
+               mpll = s5p_get_pll45xx(xtal, __raw_readl(EXYNOS4_MPLL_CON0),
+                                       pll_4508);
+               epll = s5p_get_pll46xx(xtal, __raw_readl(EXYNOS4_EPLL_CON0),
+                                       __raw_readl(EXYNOS4_EPLL_CON1), pll_4600);
+
+               vpllsrc = clk_get_rate(&exynos4_clk_vpllsrc.clk);
+               vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(EXYNOS4_VPLL_CON0),
+                                       __raw_readl(EXYNOS4_VPLL_CON1), pll_4650c);
+       } else if (soc_is_exynos4212() || soc_is_exynos4412()) {
+               apll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS4_APLL_CON0));
+               mpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS4_MPLL_CON0));
+               epll = s5p_get_pll36xx(xtal, __raw_readl(EXYNOS4_EPLL_CON0),
+                                       __raw_readl(EXYNOS4_EPLL_CON1));
+
+               vpllsrc = clk_get_rate(&exynos4_clk_vpllsrc.clk);
+               vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(EXYNOS4_VPLL_CON0),
+                                       __raw_readl(EXYNOS4_VPLL_CON1));
+       } else {
+               /* nothing */
+       }
+
+       clk_fout_apll.ops = &exynos4_fout_apll_ops;
+       clk_fout_mpll.rate = mpll;
+       clk_fout_epll.rate = epll;
+       clk_fout_vpll.ops = &exynos4_vpll_ops;
+       clk_fout_vpll.rate = vpll;
+
+       printk(KERN_INFO "EXYNOS4: PLL settings, A=%ld, M=%ld, E=%ld V=%ld",
+                       apll, mpll, epll, vpll);
+
+       armclk = clk_get_rate(&exynos4_clk_armclk.clk);
+       sclk_dmc = clk_get_rate(&exynos4_clk_sclk_dmc.clk);
+
+       aclk_200 = clk_get_rate(&exynos4_clk_aclk_200.clk);
+       aclk_100 = clk_get_rate(&exynos4_clk_aclk_100.clk);
+       aclk_160 = clk_get_rate(&exynos4_clk_aclk_160.clk);
+       aclk_133 = clk_get_rate(&exynos4_clk_aclk_133.clk);
+
+       printk(KERN_INFO "EXYNOS4: ARMCLK=%ld, DMC=%ld, ACLK200=%ld\n"
+                        "ACLK100=%ld, ACLK160=%ld, ACLK133=%ld\n",
+                       armclk, sclk_dmc, aclk_200,
+                       aclk_100, aclk_160, aclk_133);
+
+       clk_f.rate = armclk;
+       clk_h.rate = sclk_dmc;
+       clk_p.rate = aclk_100;
+
+       for (ptr = 0; ptr < ARRAY_SIZE(exynos4_clksrcs); ptr++)
+               s3c_set_clksrc(&exynos4_clksrcs[ptr], true);
+}
+
+static struct clk *exynos4_clks[] __initdata = {
+       &exynos4_clk_sclk_hdmi27m,
+       &exynos4_clk_sclk_hdmiphy,
+       &exynos4_clk_sclk_usbphy0,
+       &exynos4_clk_sclk_usbphy1,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos4_clock_suspend(void)
+{
+       s3c_pm_do_save(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save));
+       return 0;
+}
+
+static void exynos4_clock_resume(void)
+{
+       s3c_pm_do_restore_core(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save));
+}
+
+#else
+#define exynos4_clock_suspend NULL
+#define exynos4_clock_resume NULL
+#endif
+
+static struct syscore_ops exynos4_clock_syscore_ops = {
+       .suspend        = exynos4_clock_suspend,
+       .resume         = exynos4_clock_resume,
+};
+
+void __init exynos4_register_clocks(void)
+{
+       int ptr;
+
+       s3c24xx_register_clocks(exynos4_clks, ARRAY_SIZE(exynos4_clks));
+
+       for (ptr = 0; ptr < ARRAY_SIZE(exynos4_sysclks); ptr++)
+               s3c_register_clksrc(exynos4_sysclks[ptr], 1);
+
+       for (ptr = 0; ptr < ARRAY_SIZE(exynos4_sclk_tv); ptr++)
+               s3c_register_clksrc(exynos4_sclk_tv[ptr], 1);
+
+       for (ptr = 0; ptr < ARRAY_SIZE(exynos4_clksrc_cdev); ptr++)
+               s3c_register_clksrc(exynos4_clksrc_cdev[ptr], 1);
+
+       s3c_register_clksrc(exynos4_clksrcs, ARRAY_SIZE(exynos4_clksrcs));
+       s3c_register_clocks(exynos4_init_clocks_on, ARRAY_SIZE(exynos4_init_clocks_on));
+
+       s3c24xx_register_clocks(exynos4_clk_cdev, ARRAY_SIZE(exynos4_clk_cdev));
+       for (ptr = 0; ptr < ARRAY_SIZE(exynos4_clk_cdev); ptr++)
+               s3c_disable_clocks(exynos4_clk_cdev[ptr], 1);
+
+       s3c_register_clocks(exynos4_init_clocks_off, ARRAY_SIZE(exynos4_init_clocks_off));
+       s3c_disable_clocks(exynos4_init_clocks_off, ARRAY_SIZE(exynos4_init_clocks_off));
+       clkdev_add_table(exynos4_clk_lookup, ARRAY_SIZE(exynos4_clk_lookup));
+
+       register_syscore_ops(&exynos4_clock_syscore_ops);
+       s3c24xx_register_clock(&dummy_apb_pclk);
+
+       s3c_pwmclk_init();
+}
diff --git a/arch/arm/mach-exynos/clock-exynos4.h b/arch/arm/mach-exynos/clock-exynos4.h
new file mode 100644 (file)
index 0000000..cb71c29
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Header file for exynos4 clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_CLOCK_H
+#define __ASM_ARCH_CLOCK_H __FILE__
+
+#include <linux/clk.h>
+
+extern struct clksrc_clk exynos4_clk_aclk_133;
+extern struct clksrc_clk exynos4_clk_mout_mpll;
+
+extern struct clksrc_sources exynos4_clkset_mout_corebus;
+extern struct clksrc_sources exynos4_clkset_group;
+
+extern struct clk *exynos4_clkset_aclk_top_list[];
+extern struct clk *exynos4_clkset_group_list[];
+
+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);
+
+#endif /* __ASM_ARCH_CLOCK_H */
index 13312cc..3b131e4 100644 (file)
@@ -1,7 +1,5 @@
 /*
- * linux/arch/arm/mach-exynos4/clock-exynos4210.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
  * EXYNOS4210 - Clock support
 #include <mach/hardware.h>
 #include <mach/map.h>
 #include <mach/regs-clock.h>
-#include <mach/exynos4-clock.h>
 
 #include "common.h"
+#include "clock-exynos4.h"
 
 #ifdef CONFIG_PM_SLEEP
 static struct sleep_save exynos4210_clock_save[] = {
-       SAVE_ITEM(S5P_CLKSRC_IMAGE),
-       SAVE_ITEM(S5P_CLKSRC_LCD1),
-       SAVE_ITEM(S5P_CLKDIV_IMAGE),
-       SAVE_ITEM(S5P_CLKDIV_LCD1),
-       SAVE_ITEM(S5P_CLKSRC_MASK_LCD1),
-       SAVE_ITEM(S5P_CLKGATE_IP_IMAGE_4210),
-       SAVE_ITEM(S5P_CLKGATE_IP_LCD1),
-       SAVE_ITEM(S5P_CLKGATE_IP_PERIR_4210),
+       SAVE_ITEM(EXYNOS4_CLKSRC_IMAGE),
+       SAVE_ITEM(EXYNOS4_CLKDIV_IMAGE),
+       SAVE_ITEM(EXYNOS4210_CLKSRC_LCD1),
+       SAVE_ITEM(EXYNOS4210_CLKDIV_LCD1),
+       SAVE_ITEM(EXYNOS4210_CLKSRC_MASK_LCD1),
+       SAVE_ITEM(EXYNOS4210_CLKGATE_IP_IMAGE),
+       SAVE_ITEM(EXYNOS4210_CLKGATE_IP_LCD1),
+       SAVE_ITEM(EXYNOS4210_CLKGATE_IP_PERIR),
 };
 #endif
 
@@ -51,7 +49,7 @@ static struct clksrc_clk *sysclks[] = {
 
 static int exynos4_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable)
 {
-       return s5p_gatectrl(S5P_CLKSRC_MASK_LCD1, clk, enable);
+       return s5p_gatectrl(EXYNOS4210_CLKSRC_MASK_LCD1, clk, enable);
 }
 
 static struct clksrc_clk clksrcs[] = {
@@ -62,9 +60,9 @@ static struct clksrc_clk clksrcs[] = {
                        .enable         = exynos4_clksrc_mask_fsys_ctrl,
                        .ctrlbit        = (1 << 24),
                },
-               .sources = &clkset_mout_corebus,
-               .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 24, .size = 1 },
-               .reg_div = { .reg = S5P_CLKDIV_FSYS0, .shift = 20, .size = 4 },
+               .sources = &exynos4_clkset_mout_corebus,
+               .reg_src = { .reg = EXYNOS4_CLKSRC_FSYS, .shift = 24, .size = 1 },
+               .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS0, .shift = 20, .size = 4 },
        }, {
                .clk            = {
                        .name           = "sclk_fimd",
@@ -72,9 +70,9 @@ static struct clksrc_clk clksrcs[] = {
                        .enable         = exynos4_clksrc_mask_lcd1_ctrl,
                        .ctrlbit        = (1 << 0),
                },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_LCD1, .shift = 0, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_LCD1, .shift = 0, .size = 4 },
+               .sources = &exynos4_clkset_group,
+               .reg_src = { .reg = EXYNOS4210_CLKSRC_LCD1, .shift = 0, .size = 4 },
+               .reg_div = { .reg = EXYNOS4210_CLKDIV_LCD1, .shift = 0, .size = 4 },
        },
 };
 
@@ -82,13 +80,13 @@ static struct clk init_clocks_off[] = {
        {
                .name           = "sataphy",
                .id             = -1,
-               .parent         = &clk_aclk_133.clk,
+               .parent         = &exynos4_clk_aclk_133.clk,
                .enable         = exynos4_clk_ip_fsys_ctrl,
                .ctrlbit        = (1 << 3),
        }, {
                .name           = "sata",
                .id             = -1,
-               .parent         = &clk_aclk_133.clk,
+               .parent         = &exynos4_clk_aclk_133.clk,
                .enable         = exynos4_clk_ip_fsys_ctrl,
                .ctrlbit        = (1 << 10),
        }, {
@@ -117,7 +115,7 @@ static void exynos4210_clock_resume(void)
 #define exynos4210_clock_resume NULL
 #endif
 
-struct syscore_ops exynos4210_clock_syscore_ops = {
+static struct syscore_ops exynos4210_clock_syscore_ops = {
        .suspend        = exynos4210_clock_suspend,
        .resume         = exynos4210_clock_resume,
 };
@@ -126,9 +124,9 @@ void __init exynos4210_register_clocks(void)
 {
        int ptr;
 
-       clk_mout_mpll.reg_src.reg = S5P_CLKSRC_CPU;
-       clk_mout_mpll.reg_src.shift = 8;
-       clk_mout_mpll.reg_src.size = 1;
+       exynos4_clk_mout_mpll.reg_src.reg = EXYNOS4_CLKSRC_CPU;
+       exynos4_clk_mout_mpll.reg_src.shift = 8;
+       exynos4_clk_mout_mpll.reg_src.size = 1;
 
        for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
                s3c_register_clksrc(sysclks[ptr], 1);
index 48af285..3ecc01e 100644 (file)
@@ -1,7 +1,5 @@
 /*
- * linux/arch/arm/mach-exynos4/clock-exynos4212.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
  * EXYNOS4212 - Clock support
 #include <mach/hardware.h>
 #include <mach/map.h>
 #include <mach/regs-clock.h>
-#include <mach/exynos4-clock.h>
 
 #include "common.h"
+#include "clock-exynos4.h"
 
 #ifdef CONFIG_PM_SLEEP
 static struct sleep_save exynos4212_clock_save[] = {
-       SAVE_ITEM(S5P_CLKSRC_IMAGE),
-       SAVE_ITEM(S5P_CLKDIV_IMAGE),
-       SAVE_ITEM(S5P_CLKGATE_IP_IMAGE_4212),
-       SAVE_ITEM(S5P_CLKGATE_IP_PERIR_4212),
+       SAVE_ITEM(EXYNOS4_CLKSRC_IMAGE),
+       SAVE_ITEM(EXYNOS4_CLKDIV_IMAGE),
+       SAVE_ITEM(EXYNOS4212_CLKGATE_IP_IMAGE),
+       SAVE_ITEM(EXYNOS4212_CLKGATE_IP_PERIR),
 };
 #endif
 
 static struct clk *clk_src_mpll_user_list[] = {
        [0] = &clk_fin_mpll,
-       [1] = &clk_mout_mpll.clk,
+       [1] = &exynos4_clk_mout_mpll.clk,
 };
 
 static struct clksrc_sources clk_src_mpll_user = {
@@ -56,7 +54,7 @@ static struct clksrc_clk clk_mout_mpll_user = {
                .name           = "mout_mpll_user",
        },
        .sources        = &clk_src_mpll_user,
-       .reg_src        = { .reg = S5P_CLKSRC_CPU, .shift = 24, .size = 1 },
+       .reg_src        = { .reg = EXYNOS4_CLKSRC_CPU, .shift = 24, .size = 1 },
 };
 
 static struct clksrc_clk *sysclks[] = {
@@ -89,7 +87,7 @@ static void exynos4212_clock_resume(void)
 #define exynos4212_clock_resume NULL
 #endif
 
-struct syscore_ops exynos4212_clock_syscore_ops = {
+static struct syscore_ops exynos4212_clock_syscore_ops = {
        .suspend        = exynos4212_clock_suspend,
        .resume         = exynos4212_clock_resume,
 };
@@ -99,15 +97,15 @@ void __init exynos4212_register_clocks(void)
        int ptr;
 
        /* usbphy1 is removed */
-       clkset_group_list[4] = NULL;
+       exynos4_clkset_group_list[4] = NULL;
 
        /* mout_mpll_user is used */
-       clkset_group_list[6] = &clk_mout_mpll_user.clk;
-       clkset_aclk_top_list[0] = &clk_mout_mpll_user.clk;
+       exynos4_clkset_group_list[6] = &clk_mout_mpll_user.clk;
+       exynos4_clkset_aclk_top_list[0] = &clk_mout_mpll_user.clk;
 
-       clk_mout_mpll.reg_src.reg = S5P_CLKSRC_DMC;
-       clk_mout_mpll.reg_src.shift = 12;
-       clk_mout_mpll.reg_src.size = 1;
+       exynos4_clk_mout_mpll.reg_src.reg = EXYNOS4_CLKSRC_DMC;
+       exynos4_clk_mout_mpll.reg_src.shift = 12;
+       exynos4_clk_mout_mpll.reg_src.size = 1;
 
        for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
                s3c_register_clksrc(sysclks[ptr], 1);
diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c
new file mode 100644 (file)
index 0000000..d013982
--- /dev/null
@@ -0,0 +1,1247 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Clock support for EXYNOS5 SoCs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/syscore_ops.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/pm.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/sysmmu.h>
+
+#include "common.h"
+
+#ifdef CONFIG_PM_SLEEP
+static struct sleep_save exynos5_clock_save[] = {
+       /* will be implemented */
+};
+#endif
+
+static struct clk exynos5_clk_sclk_dptxphy = {
+       .name           = "sclk_dptx",
+};
+
+static struct clk exynos5_clk_sclk_hdmi24m = {
+       .name           = "sclk_hdmi24m",
+       .rate           = 24000000,
+};
+
+static struct clk exynos5_clk_sclk_hdmi27m = {
+       .name           = "sclk_hdmi27m",
+       .rate           = 27000000,
+};
+
+static struct clk exynos5_clk_sclk_hdmiphy = {
+       .name           = "sclk_hdmiphy",
+};
+
+static struct clk exynos5_clk_sclk_usbphy = {
+       .name           = "sclk_usbphy",
+       .rate           = 48000000,
+};
+
+static int exynos5_clksrc_mask_top_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_TOP, clk, enable);
+}
+
+static int exynos5_clksrc_mask_disp1_0_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_DISP1_0, clk, enable);
+}
+
+static int exynos5_clksrc_mask_fsys_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_FSYS, clk, enable);
+}
+
+static int exynos5_clksrc_mask_gscl_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_GSCL, clk, enable);
+}
+
+static int exynos5_clksrc_mask_peric0_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC0, clk, enable);
+}
+
+static int exynos5_clk_ip_core_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKGATE_IP_CORE, clk, enable);
+}
+
+static int exynos5_clk_ip_disp1_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKGATE_IP_DISP1, clk, enable);
+}
+
+static int exynos5_clk_ip_fsys_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKGATE_IP_FSYS, clk, enable);
+}
+
+static int exynos5_clk_block_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKGATE_BLOCK, clk, enable);
+}
+
+static int exynos5_clk_ip_gen_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GEN, clk, enable);
+}
+
+static int exynos5_clk_ip_gps_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GPS, clk, enable);
+}
+
+static int exynos5_clk_ip_mfc_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKGATE_IP_MFC, clk, enable);
+}
+
+static int exynos5_clk_ip_peric_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIC, clk, enable);
+}
+
+static int exynos5_clk_ip_peris_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIS, clk, enable);
+}
+
+/* Core list of CMU_CPU side */
+
+static struct clksrc_clk exynos5_clk_mout_apll = {
+       .clk    = {
+               .name           = "mout_apll",
+       },
+       .sources = &clk_src_apll,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_CPU, .shift = 0, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_apll = {
+       .clk    = {
+               .name           = "sclk_apll",
+               .parent         = &exynos5_clk_mout_apll.clk,
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 24, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_mout_bpll = {
+       .clk    = {
+               .name           = "mout_bpll",
+       },
+       .sources = &clk_src_bpll,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_CDREX, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos5_clk_src_bpll_user_list[] = {
+       [0] = &clk_fin_mpll,
+       [1] = &exynos5_clk_mout_bpll.clk,
+};
+
+static struct clksrc_sources exynos5_clk_src_bpll_user = {
+       .sources        = exynos5_clk_src_bpll_user_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clk_src_bpll_user_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_bpll_user = {
+       .clk    = {
+               .name           = "mout_bpll_user",
+       },
+       .sources = &exynos5_clk_src_bpll_user,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 24, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_mout_cpll = {
+       .clk    = {
+               .name           = "mout_cpll",
+       },
+       .sources = &clk_src_cpll,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 8, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_mout_epll = {
+       .clk    = {
+               .name           = "mout_epll",
+       },
+       .sources = &clk_src_epll,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 12, .size = 1 },
+};
+
+struct clksrc_clk exynos5_clk_mout_mpll = {
+       .clk = {
+               .name           = "mout_mpll",
+       },
+       .sources = &clk_src_mpll,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_CORE1, .shift = 8, .size = 1 },
+};
+
+static struct clk *exynos_clkset_vpllsrc_list[] = {
+       [0] = &clk_fin_vpll,
+       [1] = &exynos5_clk_sclk_hdmi27m,
+};
+
+static struct clksrc_sources exynos5_clkset_vpllsrc = {
+       .sources        = exynos_clkset_vpllsrc_list,
+       .nr_sources     = ARRAY_SIZE(exynos_clkset_vpllsrc_list),
+};
+
+static struct clksrc_clk exynos5_clk_vpllsrc = {
+       .clk    = {
+               .name           = "vpll_src",
+               .enable         = exynos5_clksrc_mask_top_ctrl,
+               .ctrlbit        = (1 << 0),
+       },
+       .sources = &exynos5_clkset_vpllsrc,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 0, .size = 1 },
+};
+
+static struct clk *exynos5_clkset_sclk_vpll_list[] = {
+       [0] = &exynos5_clk_vpllsrc.clk,
+       [1] = &clk_fout_vpll,
+};
+
+static struct clksrc_sources exynos5_clkset_sclk_vpll = {
+       .sources        = exynos5_clkset_sclk_vpll_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clkset_sclk_vpll_list),
+};
+
+static struct clksrc_clk exynos5_clk_sclk_vpll = {
+       .clk    = {
+               .name           = "sclk_vpll",
+       },
+       .sources = &exynos5_clkset_sclk_vpll,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 16, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_pixel = {
+       .clk    = {
+               .name           = "sclk_pixel",
+               .parent         = &exynos5_clk_sclk_vpll.clk,
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_DISP1_0, .shift = 28, .size = 4 },
+};
+
+static struct clk *exynos5_clkset_sclk_hdmi_list[] = {
+       [0] = &exynos5_clk_sclk_pixel.clk,
+       [1] = &exynos5_clk_sclk_hdmiphy,
+};
+
+static struct clksrc_sources exynos5_clkset_sclk_hdmi = {
+       .sources        = exynos5_clkset_sclk_hdmi_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clkset_sclk_hdmi_list),
+};
+
+static struct clksrc_clk exynos5_clk_sclk_hdmi = {
+       .clk    = {
+               .name           = "sclk_hdmi",
+               .enable         = exynos5_clksrc_mask_disp1_0_ctrl,
+               .ctrlbit        = (1 << 20),
+       },
+       .sources = &exynos5_clkset_sclk_hdmi,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 20, .size = 1 },
+};
+
+static struct clksrc_clk *exynos5_sclk_tv[] = {
+       &exynos5_clk_sclk_pixel,
+       &exynos5_clk_sclk_hdmi,
+};
+
+static struct clk *exynos5_clk_src_mpll_user_list[] = {
+       [0] = &clk_fin_mpll,
+       [1] = &exynos5_clk_mout_mpll.clk,
+};
+
+static struct clksrc_sources exynos5_clk_src_mpll_user = {
+       .sources        = exynos5_clk_src_mpll_user_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clk_src_mpll_user_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_mpll_user = {
+       .clk    = {
+               .name           = "mout_mpll_user",
+       },
+       .sources = &exynos5_clk_src_mpll_user,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 20, .size = 1 },
+};
+
+static struct clk *exynos5_clkset_mout_cpu_list[] = {
+       [0] = &exynos5_clk_mout_apll.clk,
+       [1] = &exynos5_clk_mout_mpll.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_mout_cpu = {
+       .sources        = exynos5_clkset_mout_cpu_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clkset_mout_cpu_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_cpu = {
+       .clk    = {
+               .name           = "mout_cpu",
+       },
+       .sources = &exynos5_clkset_mout_cpu,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_CPU, .shift = 16, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_armclk = {
+       .clk    = {
+               .name           = "dout_armclk",
+               .parent         = &exynos5_clk_mout_cpu.clk,
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_arm2clk = {
+       .clk    = {
+               .name           = "dout_arm2clk",
+               .parent         = &exynos5_clk_dout_armclk.clk,
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 28, .size = 3 },
+};
+
+static struct clk exynos5_clk_armclk = {
+       .name           = "armclk",
+       .parent         = &exynos5_clk_dout_arm2clk.clk,
+};
+
+/* Core list of CMU_CDREX side */
+
+static struct clk *exynos5_clkset_cdrex_list[] = {
+       [0] = &exynos5_clk_mout_mpll.clk,
+       [1] = &exynos5_clk_mout_bpll.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_cdrex = {
+       .sources        = exynos5_clkset_cdrex_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clkset_cdrex_list),
+};
+
+static struct clksrc_clk exynos5_clk_cdrex = {
+       .clk    = {
+               .name           = "clk_cdrex",
+       },
+       .sources = &exynos5_clkset_cdrex,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_CDREX, .shift = 4, .size = 1 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_CDREX, .shift = 16, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_acp = {
+       .clk    = {
+               .name           = "aclk_acp",
+               .parent         = &exynos5_clk_mout_mpll.clk,
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_ACP, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_pclk_acp = {
+       .clk    = {
+               .name           = "pclk_acp",
+               .parent         = &exynos5_clk_aclk_acp.clk,
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_ACP, .shift = 4, .size = 3 },
+};
+
+/* Core list of CMU_TOP side */
+
+struct clk *exynos5_clkset_aclk_top_list[] = {
+       [0] = &exynos5_clk_mout_mpll_user.clk,
+       [1] = &exynos5_clk_mout_bpll_user.clk,
+};
+
+struct clksrc_sources exynos5_clkset_aclk = {
+       .sources        = exynos5_clkset_aclk_top_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clkset_aclk_top_list),
+};
+
+static struct clksrc_clk exynos5_clk_aclk_400 = {
+       .clk    = {
+               .name           = "aclk_400",
+       },
+       .sources = &exynos5_clkset_aclk,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 20, .size = 1 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 24, .size = 3 },
+};
+
+struct clk *exynos5_clkset_aclk_333_166_list[] = {
+       [0] = &exynos5_clk_mout_cpll.clk,
+       [1] = &exynos5_clk_mout_mpll_user.clk,
+};
+
+struct clksrc_sources exynos5_clkset_aclk_333_166 = {
+       .sources        = exynos5_clkset_aclk_333_166_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clkset_aclk_333_166_list),
+};
+
+static struct clksrc_clk exynos5_clk_aclk_333 = {
+       .clk    = {
+               .name           = "aclk_333",
+       },
+       .sources = &exynos5_clkset_aclk_333_166,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 16, .size = 1 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 20, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_166 = {
+       .clk    = {
+               .name           = "aclk_166",
+       },
+       .sources = &exynos5_clkset_aclk_333_166,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 8, .size = 1 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 8, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_266 = {
+       .clk    = {
+               .name           = "aclk_266",
+               .parent         = &exynos5_clk_mout_mpll_user.clk,
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 16, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_200 = {
+       .clk    = {
+               .name           = "aclk_200",
+       },
+       .sources = &exynos5_clkset_aclk,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 12, .size = 1 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 12, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_66_pre = {
+       .clk    = {
+               .name           = "aclk_66_pre",
+               .parent         = &exynos5_clk_mout_mpll_user.clk,
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_TOP1, .shift = 24, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_66 = {
+       .clk    = {
+               .name           = "aclk_66",
+               .parent         = &exynos5_clk_aclk_66_pre.clk,
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 0, .size = 3 },
+};
+
+static struct clk exynos5_init_clocks_off[] = {
+       {
+               .name           = "timers",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 24),
+       }, {
+               .name           = "rtc",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peris_ctrl,
+               .ctrlbit        = (1 << 20),
+       }, {
+               .name           = "hsmmc",
+               .devname        = "s3c-sdhci.0",
+               .parent         = &exynos5_clk_aclk_200.clk,
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 12),
+       }, {
+               .name           = "hsmmc",
+               .devname        = "s3c-sdhci.1",
+               .parent         = &exynos5_clk_aclk_200.clk,
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 13),
+       }, {
+               .name           = "hsmmc",
+               .devname        = "s3c-sdhci.2",
+               .parent         = &exynos5_clk_aclk_200.clk,
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 14),
+       }, {
+               .name           = "hsmmc",
+               .devname        = "s3c-sdhci.3",
+               .parent         = &exynos5_clk_aclk_200.clk,
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 15),
+       }, {
+               .name           = "dwmci",
+               .parent         = &exynos5_clk_aclk_200.clk,
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 16),
+       }, {
+               .name           = "sata",
+               .devname        = "ahci",
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 6),
+       }, {
+               .name           = "sata_phy",
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 24),
+       }, {
+               .name           = "sata_phy_i2c",
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 25),
+       }, {
+               .name           = "mfc",
+               .devname        = "s5p-mfc",
+               .enable         = exynos5_clk_ip_mfc_ctrl,
+               .ctrlbit        = (1 << 0),
+       }, {
+               .name           = "hdmi",
+               .devname        = "exynos4-hdmi",
+               .enable         = exynos5_clk_ip_disp1_ctrl,
+               .ctrlbit        = (1 << 6),
+       }, {
+               .name           = "mixer",
+               .devname        = "s5p-mixer",
+               .enable         = exynos5_clk_ip_disp1_ctrl,
+               .ctrlbit        = (1 << 5),
+       }, {
+               .name           = "jpeg",
+               .enable         = exynos5_clk_ip_gen_ctrl,
+               .ctrlbit        = (1 << 2),
+       }, {
+               .name           = "dsim0",
+               .enable         = exynos5_clk_ip_disp1_ctrl,
+               .ctrlbit        = (1 << 3),
+       }, {
+               .name           = "iis",
+               .devname        = "samsung-i2s.1",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 20),
+       }, {
+               .name           = "iis",
+               .devname        = "samsung-i2s.2",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 21),
+       }, {
+               .name           = "pcm",
+               .devname        = "samsung-pcm.1",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 22),
+       }, {
+               .name           = "pcm",
+               .devname        = "samsung-pcm.2",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 23),
+       }, {
+               .name           = "spdif",
+               .devname        = "samsung-spdif",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 26),
+       }, {
+               .name           = "ac97",
+               .devname        = "samsung-ac97",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 27),
+       }, {
+               .name           = "usbhost",
+               .enable         = exynos5_clk_ip_fsys_ctrl ,
+               .ctrlbit        = (1 << 18),
+       }, {
+               .name           = "usbotg",
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 7),
+       }, {
+               .name           = "gps",
+               .enable         = exynos5_clk_ip_gps_ctrl,
+               .ctrlbit        = ((1 << 3) | (1 << 2) | (1 << 0)),
+       }, {
+               .name           = "nfcon",
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 22),
+       }, {
+               .name           = "iop",
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = ((1 << 30) | (1 << 26) | (1 << 23)),
+       }, {
+               .name           = "core_iop",
+               .enable         = exynos5_clk_ip_core_ctrl,
+               .ctrlbit        = ((1 << 21) | (1 << 3)),
+       }, {
+               .name           = "mcu_iop",
+               .enable         = exynos5_clk_ip_fsys_ctrl,
+               .ctrlbit        = (1 << 0),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.0",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 6),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.1",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 7),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.2",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 8),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.3",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 9),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.4",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 10),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.5",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 11),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.6",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 12),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-i2c.7",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 13),
+       }, {
+               .name           = "i2c",
+               .devname        = "s3c2440-hdmiphy-i2c",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 14),
+       }
+};
+
+static struct clk exynos5_init_clocks_on[] = {
+       {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.0",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 0),
+       }, {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.1",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.2",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 2),
+       }, {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.3",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 3),
+       }, {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.4",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 4),
+       }, {
+               .name           = "uart",
+               .devname        = "s5pv210-uart.5",
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 5),
+       }
+};
+
+static struct clk exynos5_clk_pdma0 = {
+       .name           = "dma",
+       .devname        = "dma-pl330.0",
+       .enable         = exynos5_clk_ip_fsys_ctrl,
+       .ctrlbit        = (1 << 1),
+};
+
+static struct clk exynos5_clk_pdma1 = {
+       .name           = "dma",
+       .devname        = "dma-pl330.1",
+       .enable         = exynos5_clk_ip_fsys_ctrl,
+       .ctrlbit        = (1 << 1),
+};
+
+static struct clk exynos5_clk_mdma1 = {
+       .name           = "dma",
+       .devname        = "dma-pl330.2",
+       .enable         = exynos5_clk_ip_gen_ctrl,
+       .ctrlbit        = (1 << 4),
+};
+
+struct clk *exynos5_clkset_group_list[] = {
+       [0] = &clk_ext_xtal_mux,
+       [1] = NULL,
+       [2] = &exynos5_clk_sclk_hdmi24m,
+       [3] = &exynos5_clk_sclk_dptxphy,
+       [4] = &exynos5_clk_sclk_usbphy,
+       [5] = &exynos5_clk_sclk_hdmiphy,
+       [6] = &exynos5_clk_mout_mpll_user.clk,
+       [7] = &exynos5_clk_mout_epll.clk,
+       [8] = &exynos5_clk_sclk_vpll.clk,
+       [9] = &exynos5_clk_mout_cpll.clk,
+};
+
+struct clksrc_sources exynos5_clkset_group = {
+       .sources        = exynos5_clkset_group_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clkset_group_list),
+};
+
+/* Possible clock sources for aclk_266_gscl_sub Mux */
+static struct clk *clk_src_gscl_266_list[] = {
+       [0] = &clk_ext_xtal_mux,
+       [1] = &exynos5_clk_aclk_266.clk,
+};
+
+static struct clksrc_sources clk_src_gscl_266 = {
+       .sources        = clk_src_gscl_266_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_gscl_266_list),
+};
+
+static struct clksrc_clk exynos5_clk_dout_mmc0 = {
+       .clk            = {
+               .name           = "dout_mmc0",
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 0, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_mmc1 = {
+       .clk            = {
+               .name           = "dout_mmc1",
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 4, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_mmc2 = {
+       .clk            = {
+               .name           = "dout_mmc2",
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 8, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_mmc3 = {
+       .clk            = {
+               .name           = "dout_mmc3",
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 12, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_mmc4 = {
+       .clk            = {
+               .name           = "dout_mmc4",
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 16, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS3, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_uart0 = {
+       .clk    = {
+               .name           = "uclk1",
+               .devname        = "exynos4210-uart.0",
+               .enable         = exynos5_clksrc_mask_peric0_ctrl,
+               .ctrlbit        = (1 << 0),
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 0, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_uart1 = {
+       .clk    = {
+               .name           = "uclk1",
+               .devname        = "exynos4210-uart.1",
+               .enable         = exynos5_clksrc_mask_peric0_ctrl,
+               .ctrlbit        = (1 << 4),
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 4, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 4, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_uart2 = {
+       .clk    = {
+               .name           = "uclk1",
+               .devname        = "exynos4210-uart.2",
+               .enable         = exynos5_clksrc_mask_peric0_ctrl,
+               .ctrlbit        = (1 << 8),
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 8, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_uart3 = {
+       .clk    = {
+               .name           = "uclk1",
+               .devname        = "exynos4210-uart.3",
+               .enable         = exynos5_clksrc_mask_peric0_ctrl,
+               .ctrlbit        = (1 << 12),
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC0, .shift = 12, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC0, .shift = 12, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_mmc0 = {
+       .clk    = {
+               .name           = "sclk_mmc",
+               .devname        = "s3c-sdhci.0",
+               .parent         = &exynos5_clk_dout_mmc0.clk,
+               .enable         = exynos5_clksrc_mask_fsys_ctrl,
+               .ctrlbit        = (1 << 0),
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_mmc1 = {
+       .clk    = {
+               .name           = "sclk_mmc",
+               .devname        = "s3c-sdhci.1",
+               .parent         = &exynos5_clk_dout_mmc1.clk,
+               .enable         = exynos5_clksrc_mask_fsys_ctrl,
+               .ctrlbit        = (1 << 4),
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS1, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_mmc2 = {
+       .clk    = {
+               .name           = "sclk_mmc",
+               .devname        = "s3c-sdhci.2",
+               .parent         = &exynos5_clk_dout_mmc2.clk,
+               .enable         = exynos5_clksrc_mask_fsys_ctrl,
+               .ctrlbit        = (1 << 8),
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_mmc3 = {
+       .clk    = {
+               .name           = "sclk_mmc",
+               .devname        = "s3c-sdhci.3",
+               .parent         = &exynos5_clk_dout_mmc3.clk,
+               .enable         = exynos5_clksrc_mask_fsys_ctrl,
+               .ctrlbit        = (1 << 12),
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clksrcs[] = {
+       {
+               .clk    = {
+                       .name           = "sclk_dwmci",
+                       .parent         = &exynos5_clk_dout_mmc4.clk,
+                       .enable         = exynos5_clksrc_mask_fsys_ctrl,
+                       .ctrlbit        = (1 << 16),
+               },
+               .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS3, .shift = 8, .size = 8 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_fimd",
+                       .devname        = "s3cfb.1",
+                       .enable         = exynos5_clksrc_mask_disp1_0_ctrl,
+                       .ctrlbit        = (1 << 0),
+               },
+               .sources = &exynos5_clkset_group,
+               .reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 0, .size = 4 },
+               .reg_div = { .reg = EXYNOS5_CLKDIV_DISP1_0, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "aclk_266_gscl",
+               },
+               .sources = &clk_src_gscl_266,
+               .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 8, .size = 1 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_g3d",
+                       .devname        = "mali-t604.0",
+                       .enable         = exynos5_clk_block_ctrl,
+                       .ctrlbit        = (1 << 1),
+               },
+               .sources = &exynos5_clkset_aclk,
+               .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 20, .size = 1 },
+               .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 24, .size = 3 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_gscl_wrap",
+                       .devname        = "s5p-mipi-csis.0",
+                       .enable         = exynos5_clksrc_mask_gscl_ctrl,
+                       .ctrlbit        = (1 << 24),
+               },
+               .sources = &exynos5_clkset_group,
+               .reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 24, .size = 4 },
+               .reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 24, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_gscl_wrap",
+                       .devname        = "s5p-mipi-csis.1",
+                       .enable         = exynos5_clksrc_mask_gscl_ctrl,
+                       .ctrlbit        = (1 << 28),
+               },
+               .sources = &exynos5_clkset_group,
+               .reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 28, .size = 4 },
+               .reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 28, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_cam0",
+                       .enable         = exynos5_clksrc_mask_gscl_ctrl,
+                       .ctrlbit        = (1 << 16),
+               },
+               .sources = &exynos5_clkset_group,
+               .reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 16, .size = 4 },
+               .reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 16, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_cam1",
+                       .enable         = exynos5_clksrc_mask_gscl_ctrl,
+                       .ctrlbit        = (1 << 20),
+               },
+               .sources = &exynos5_clkset_group,
+               .reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 20, .size = 4 },
+               .reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 20, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_jpeg",
+                       .parent         = &exynos5_clk_mout_cpll.clk,
+               },
+               .reg_div = { .reg = EXYNOS5_CLKDIV_GEN, .shift = 4, .size = 3 },
+       },
+};
+
+/* Clock initialization code */
+static struct clksrc_clk *exynos5_sysclks[] = {
+       &exynos5_clk_mout_apll,
+       &exynos5_clk_sclk_apll,
+       &exynos5_clk_mout_bpll,
+       &exynos5_clk_mout_bpll_user,
+       &exynos5_clk_mout_cpll,
+       &exynos5_clk_mout_epll,
+       &exynos5_clk_mout_mpll,
+       &exynos5_clk_mout_mpll_user,
+       &exynos5_clk_vpllsrc,
+       &exynos5_clk_sclk_vpll,
+       &exynos5_clk_mout_cpu,
+       &exynos5_clk_dout_armclk,
+       &exynos5_clk_dout_arm2clk,
+       &exynos5_clk_cdrex,
+       &exynos5_clk_aclk_400,
+       &exynos5_clk_aclk_333,
+       &exynos5_clk_aclk_266,
+       &exynos5_clk_aclk_200,
+       &exynos5_clk_aclk_166,
+       &exynos5_clk_aclk_66_pre,
+       &exynos5_clk_aclk_66,
+       &exynos5_clk_dout_mmc0,
+       &exynos5_clk_dout_mmc1,
+       &exynos5_clk_dout_mmc2,
+       &exynos5_clk_dout_mmc3,
+       &exynos5_clk_dout_mmc4,
+       &exynos5_clk_aclk_acp,
+       &exynos5_clk_pclk_acp,
+};
+
+static struct clk *exynos5_clk_cdev[] = {
+       &exynos5_clk_pdma0,
+       &exynos5_clk_pdma1,
+       &exynos5_clk_mdma1,
+};
+
+static struct clksrc_clk *exynos5_clksrc_cdev[] = {
+       &exynos5_clk_sclk_uart0,
+       &exynos5_clk_sclk_uart1,
+       &exynos5_clk_sclk_uart2,
+       &exynos5_clk_sclk_uart3,
+       &exynos5_clk_sclk_mmc0,
+       &exynos5_clk_sclk_mmc1,
+       &exynos5_clk_sclk_mmc2,
+       &exynos5_clk_sclk_mmc3,
+};
+
+static struct clk_lookup exynos5_clk_lookup[] = {
+       CLKDEV_INIT("exynos4210-uart.0", "clk_uart_baud0", &exynos5_clk_sclk_uart0.clk),
+       CLKDEV_INIT("exynos4210-uart.1", "clk_uart_baud0", &exynos5_clk_sclk_uart1.clk),
+       CLKDEV_INIT("exynos4210-uart.2", "clk_uart_baud0", &exynos5_clk_sclk_uart2.clk),
+       CLKDEV_INIT("exynos4210-uart.3", "clk_uart_baud0", &exynos5_clk_sclk_uart3.clk),
+       CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &exynos5_clk_sclk_mmc0.clk),
+       CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &exynos5_clk_sclk_mmc1.clk),
+       CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &exynos5_clk_sclk_mmc2.clk),
+       CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &exynos5_clk_sclk_mmc3.clk),
+       CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos5_clk_pdma0),
+       CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos5_clk_pdma1),
+       CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos5_clk_mdma1),
+};
+
+static unsigned long exynos5_epll_get_rate(struct clk *clk)
+{
+       return clk->rate;
+}
+
+static struct clk *exynos5_clks[] __initdata = {
+       &exynos5_clk_sclk_hdmi27m,
+       &exynos5_clk_sclk_hdmiphy,
+       &clk_fout_bpll,
+       &clk_fout_cpll,
+       &exynos5_clk_armclk,
+};
+
+static u32 epll_div[][6] = {
+       { 192000000, 0, 48, 3, 1, 0 },
+       { 180000000, 0, 45, 3, 1, 0 },
+       {  73728000, 1, 73, 3, 3, 47710 },
+       {  67737600, 1, 90, 4, 3, 20762 },
+       {  49152000, 0, 49, 3, 3, 9961 },
+       {  45158400, 0, 45, 3, 3, 10381 },
+       { 180633600, 0, 45, 3, 1, 10381 },
+};
+
+static int exynos5_epll_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned int epll_con, epll_con_k;
+       unsigned int i;
+       unsigned int tmp;
+       unsigned int epll_rate;
+       unsigned int locktime;
+       unsigned int lockcnt;
+
+       /* Return if nothing changed */
+       if (clk->rate == rate)
+               return 0;
+
+       if (clk->parent)
+               epll_rate = clk_get_rate(clk->parent);
+       else
+               epll_rate = clk_ext_xtal_mux.rate;
+
+       if (epll_rate != 24000000) {
+               pr_err("Invalid Clock : recommended clock is 24MHz.\n");
+               return -EINVAL;
+       }
+
+       epll_con = __raw_readl(EXYNOS5_EPLL_CON0);
+       epll_con &= ~(0x1 << 27 | \
+                       PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT |   \
+                       PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT | \
+                       PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
+
+       for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+               if (epll_div[i][0] == rate) {
+                       epll_con_k = epll_div[i][5] << 0;
+                       epll_con |= epll_div[i][1] << 27;
+                       epll_con |= epll_div[i][2] << PLL46XX_MDIV_SHIFT;
+                       epll_con |= epll_div[i][3] << PLL46XX_PDIV_SHIFT;
+                       epll_con |= epll_div[i][4] << PLL46XX_SDIV_SHIFT;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(epll_div)) {
+               printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       epll_rate /= 1000000;
+
+       /* 3000 max_cycls : specification data */
+       locktime = 3000 / epll_rate * epll_div[i][3];
+       lockcnt = locktime * 10000 / (10000 / epll_rate);
+
+       __raw_writel(lockcnt, EXYNOS5_EPLL_LOCK);
+
+       __raw_writel(epll_con, EXYNOS5_EPLL_CON0);
+       __raw_writel(epll_con_k, EXYNOS5_EPLL_CON1);
+
+       do {
+               tmp = __raw_readl(EXYNOS5_EPLL_CON0);
+       } while (!(tmp & 0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT));
+
+       clk->rate = rate;
+
+       return 0;
+}
+
+static struct clk_ops exynos5_epll_ops = {
+       .get_rate = exynos5_epll_get_rate,
+       .set_rate = exynos5_epll_set_rate,
+};
+
+static int xtal_rate;
+
+static unsigned long exynos5_fout_apll_get_rate(struct clk *clk)
+{
+       return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS5_APLL_CON0));
+}
+
+static struct clk_ops exynos5_fout_apll_ops = {
+       .get_rate = exynos5_fout_apll_get_rate,
+};
+
+#ifdef CONFIG_PM
+static int exynos5_clock_suspend(void)
+{
+       s3c_pm_do_save(exynos5_clock_save, ARRAY_SIZE(exynos5_clock_save));
+
+       return 0;
+}
+
+static void exynos5_clock_resume(void)
+{
+       s3c_pm_do_restore_core(exynos5_clock_save, ARRAY_SIZE(exynos5_clock_save));
+}
+#else
+#define exynos5_clock_suspend NULL
+#define exynos5_clock_resume NULL
+#endif
+
+struct syscore_ops exynos5_clock_syscore_ops = {
+       .suspend        = exynos5_clock_suspend,
+       .resume         = exynos5_clock_resume,
+};
+
+void __init_or_cpufreq exynos5_setup_clocks(void)
+{
+       struct clk *xtal_clk;
+       unsigned long apll;
+       unsigned long bpll;
+       unsigned long cpll;
+       unsigned long mpll;
+       unsigned long epll;
+       unsigned long vpll;
+       unsigned long vpllsrc;
+       unsigned long xtal;
+       unsigned long armclk;
+       unsigned long mout_cdrex;
+       unsigned long aclk_400;
+       unsigned long aclk_333;
+       unsigned long aclk_266;
+       unsigned long aclk_200;
+       unsigned long aclk_166;
+       unsigned long aclk_66;
+       unsigned int ptr;
+
+       printk(KERN_DEBUG "%s: registering clocks\n", __func__);
+
+       xtal_clk = clk_get(NULL, "xtal");
+       BUG_ON(IS_ERR(xtal_clk));
+
+       xtal = clk_get_rate(xtal_clk);
+
+       xtal_rate = xtal;
+
+       clk_put(xtal_clk);
+
+       printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
+
+       apll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_APLL_CON0));
+       bpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_BPLL_CON0));
+       cpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_CPLL_CON0));
+       mpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_MPLL_CON0));
+       epll = s5p_get_pll36xx(xtal, __raw_readl(EXYNOS5_EPLL_CON0),
+                       __raw_readl(EXYNOS5_EPLL_CON1));
+
+       vpllsrc = clk_get_rate(&exynos5_clk_vpllsrc.clk);
+       vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(EXYNOS5_VPLL_CON0),
+                       __raw_readl(EXYNOS5_VPLL_CON1));
+
+       clk_fout_apll.ops = &exynos5_fout_apll_ops;
+       clk_fout_bpll.rate = bpll;
+       clk_fout_cpll.rate = cpll;
+       clk_fout_mpll.rate = mpll;
+       clk_fout_epll.rate = epll;
+       clk_fout_vpll.rate = vpll;
+
+       printk(KERN_INFO "EXYNOS5: PLL settings, A=%ld, B=%ld, C=%ld\n"
+                       "M=%ld, E=%ld V=%ld",
+                       apll, bpll, cpll, mpll, epll, vpll);
+
+       armclk = clk_get_rate(&exynos5_clk_armclk);
+       mout_cdrex = clk_get_rate(&exynos5_clk_cdrex.clk);
+
+       aclk_400 = clk_get_rate(&exynos5_clk_aclk_400.clk);
+       aclk_333 = clk_get_rate(&exynos5_clk_aclk_333.clk);
+       aclk_266 = clk_get_rate(&exynos5_clk_aclk_266.clk);
+       aclk_200 = clk_get_rate(&exynos5_clk_aclk_200.clk);
+       aclk_166 = clk_get_rate(&exynos5_clk_aclk_166.clk);
+       aclk_66 = clk_get_rate(&exynos5_clk_aclk_66.clk);
+
+       printk(KERN_INFO "EXYNOS5: ARMCLK=%ld, CDREX=%ld, ACLK400=%ld\n"
+                       "ACLK333=%ld, ACLK266=%ld, ACLK200=%ld\n"
+                       "ACLK166=%ld, ACLK66=%ld\n",
+                       armclk, mout_cdrex, aclk_400,
+                       aclk_333, aclk_266, aclk_200,
+                       aclk_166, aclk_66);
+
+
+       clk_fout_epll.ops = &exynos5_epll_ops;
+
+       if (clk_set_parent(&exynos5_clk_mout_epll.clk, &clk_fout_epll))
+               printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+                               clk_fout_epll.name, exynos5_clk_mout_epll.clk.name);
+
+       clk_set_rate(&exynos5_clk_sclk_apll.clk, 100000000);
+       clk_set_rate(&exynos5_clk_aclk_266.clk, 300000000);
+
+       clk_set_rate(&exynos5_clk_aclk_acp.clk, 267000000);
+       clk_set_rate(&exynos5_clk_pclk_acp.clk, 134000000);
+
+       for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clksrcs); ptr++)
+               s3c_set_clksrc(&exynos5_clksrcs[ptr], true);
+}
+
+void __init exynos5_register_clocks(void)
+{
+       int ptr;
+
+       s3c24xx_register_clocks(exynos5_clks, ARRAY_SIZE(exynos5_clks));
+
+       for (ptr = 0; ptr < ARRAY_SIZE(exynos5_sysclks); ptr++)
+               s3c_register_clksrc(exynos5_sysclks[ptr], 1);
+
+       for (ptr = 0; ptr < ARRAY_SIZE(exynos5_sclk_tv); ptr++)
+               s3c_register_clksrc(exynos5_sclk_tv[ptr], 1);
+
+       for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clksrc_cdev); ptr++)
+               s3c_register_clksrc(exynos5_clksrc_cdev[ptr], 1);
+
+       s3c_register_clksrc(exynos5_clksrcs, ARRAY_SIZE(exynos5_clksrcs));
+       s3c_register_clocks(exynos5_init_clocks_on, ARRAY_SIZE(exynos5_init_clocks_on));
+
+       s3c24xx_register_clocks(exynos5_clk_cdev, ARRAY_SIZE(exynos5_clk_cdev));
+       for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clk_cdev); ptr++)
+               s3c_disable_clocks(exynos5_clk_cdev[ptr], 1);
+
+       s3c_register_clocks(exynos5_init_clocks_off, ARRAY_SIZE(exynos5_init_clocks_off));
+       s3c_disable_clocks(exynos5_init_clocks_off, ARRAY_SIZE(exynos5_init_clocks_off));
+       clkdev_add_table(exynos5_clk_lookup, ARRAY_SIZE(exynos5_clk_lookup));
+
+       register_syscore_ops(&exynos5_clock_syscore_ops);
+       s3c_pwmclk_init();
+}
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c
deleted file mode 100644 (file)
index 187287a..0000000
+++ /dev/null
@@ -1,1564 +0,0 @@
-/* linux/arch/arm/mach-exynos4/clock.c
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * EXYNOS4 - Clock support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/syscore_ops.h>
-
-#include <plat/cpu-freq.h>
-#include <plat/clock.h>
-#include <plat/cpu.h>
-#include <plat/pll.h>
-#include <plat/s5p-clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/pm.h>
-
-#include <mach/map.h>
-#include <mach/regs-clock.h>
-#include <mach/sysmmu.h>
-#include <mach/exynos4-clock.h>
-
-#include "common.h"
-
-#ifdef CONFIG_PM_SLEEP
-static struct sleep_save exynos4_clock_save[] = {
-       SAVE_ITEM(S5P_CLKDIV_LEFTBUS),
-       SAVE_ITEM(S5P_CLKGATE_IP_LEFTBUS),
-       SAVE_ITEM(S5P_CLKDIV_RIGHTBUS),
-       SAVE_ITEM(S5P_CLKGATE_IP_RIGHTBUS),
-       SAVE_ITEM(S5P_CLKSRC_TOP0),
-       SAVE_ITEM(S5P_CLKSRC_TOP1),
-       SAVE_ITEM(S5P_CLKSRC_CAM),
-       SAVE_ITEM(S5P_CLKSRC_TV),
-       SAVE_ITEM(S5P_CLKSRC_MFC),
-       SAVE_ITEM(S5P_CLKSRC_G3D),
-       SAVE_ITEM(S5P_CLKSRC_LCD0),
-       SAVE_ITEM(S5P_CLKSRC_MAUDIO),
-       SAVE_ITEM(S5P_CLKSRC_FSYS),
-       SAVE_ITEM(S5P_CLKSRC_PERIL0),
-       SAVE_ITEM(S5P_CLKSRC_PERIL1),
-       SAVE_ITEM(S5P_CLKDIV_CAM),
-       SAVE_ITEM(S5P_CLKDIV_TV),
-       SAVE_ITEM(S5P_CLKDIV_MFC),
-       SAVE_ITEM(S5P_CLKDIV_G3D),
-       SAVE_ITEM(S5P_CLKDIV_LCD0),
-       SAVE_ITEM(S5P_CLKDIV_MAUDIO),
-       SAVE_ITEM(S5P_CLKDIV_FSYS0),
-       SAVE_ITEM(S5P_CLKDIV_FSYS1),
-       SAVE_ITEM(S5P_CLKDIV_FSYS2),
-       SAVE_ITEM(S5P_CLKDIV_FSYS3),
-       SAVE_ITEM(S5P_CLKDIV_PERIL0),
-       SAVE_ITEM(S5P_CLKDIV_PERIL1),
-       SAVE_ITEM(S5P_CLKDIV_PERIL2),
-       SAVE_ITEM(S5P_CLKDIV_PERIL3),
-       SAVE_ITEM(S5P_CLKDIV_PERIL4),
-       SAVE_ITEM(S5P_CLKDIV_PERIL5),
-       SAVE_ITEM(S5P_CLKDIV_TOP),
-       SAVE_ITEM(S5P_CLKSRC_MASK_TOP),
-       SAVE_ITEM(S5P_CLKSRC_MASK_CAM),
-       SAVE_ITEM(S5P_CLKSRC_MASK_TV),
-       SAVE_ITEM(S5P_CLKSRC_MASK_LCD0),
-       SAVE_ITEM(S5P_CLKSRC_MASK_MAUDIO),
-       SAVE_ITEM(S5P_CLKSRC_MASK_FSYS),
-       SAVE_ITEM(S5P_CLKSRC_MASK_PERIL0),
-       SAVE_ITEM(S5P_CLKSRC_MASK_PERIL1),
-       SAVE_ITEM(S5P_CLKDIV2_RATIO),
-       SAVE_ITEM(S5P_CLKGATE_SCLKCAM),
-       SAVE_ITEM(S5P_CLKGATE_IP_CAM),
-       SAVE_ITEM(S5P_CLKGATE_IP_TV),
-       SAVE_ITEM(S5P_CLKGATE_IP_MFC),
-       SAVE_ITEM(S5P_CLKGATE_IP_G3D),
-       SAVE_ITEM(S5P_CLKGATE_IP_LCD0),
-       SAVE_ITEM(S5P_CLKGATE_IP_FSYS),
-       SAVE_ITEM(S5P_CLKGATE_IP_GPS),
-       SAVE_ITEM(S5P_CLKGATE_IP_PERIL),
-       SAVE_ITEM(S5P_CLKGATE_BLOCK),
-       SAVE_ITEM(S5P_CLKSRC_MASK_DMC),
-       SAVE_ITEM(S5P_CLKSRC_DMC),
-       SAVE_ITEM(S5P_CLKDIV_DMC0),
-       SAVE_ITEM(S5P_CLKDIV_DMC1),
-       SAVE_ITEM(S5P_CLKGATE_IP_DMC),
-       SAVE_ITEM(S5P_CLKSRC_CPU),
-       SAVE_ITEM(S5P_CLKDIV_CPU),
-       SAVE_ITEM(S5P_CLKDIV_CPU + 0x4),
-       SAVE_ITEM(S5P_CLKGATE_SCLKCPU),
-       SAVE_ITEM(S5P_CLKGATE_IP_CPU),
-};
-#endif
-
-struct clk clk_sclk_hdmi27m = {
-       .name           = "sclk_hdmi27m",
-       .rate           = 27000000,
-};
-
-struct clk clk_sclk_hdmiphy = {
-       .name           = "sclk_hdmiphy",
-};
-
-struct clk clk_sclk_usbphy0 = {
-       .name           = "sclk_usbphy0",
-       .rate           = 27000000,
-};
-
-struct clk clk_sclk_usbphy1 = {
-       .name           = "sclk_usbphy1",
-};
-
-static struct clk dummy_apb_pclk = {
-       .name           = "apb_pclk",
-       .id             = -1,
-};
-
-static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable);
-}
-
-static int exynos4_clksrc_mask_cam_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKSRC_MASK_CAM, clk, enable);
-}
-
-static int exynos4_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKSRC_MASK_LCD0, clk, enable);
-}
-
-int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKSRC_MASK_FSYS, clk, enable);
-}
-
-static int exynos4_clksrc_mask_peril0_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0, clk, enable);
-}
-
-static int exynos4_clksrc_mask_peril1_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL1, clk, enable);
-}
-
-static int exynos4_clk_ip_mfc_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP_MFC, clk, enable);
-}
-
-static int exynos4_clksrc_mask_tv_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKSRC_MASK_TV, clk, enable);
-}
-
-static int exynos4_clk_ip_cam_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP_CAM, clk, enable);
-}
-
-static int exynos4_clk_ip_tv_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP_TV, clk, enable);
-}
-
-static int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP_IMAGE, clk, enable);
-}
-
-static int exynos4_clk_ip_lcd0_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP_LCD0, clk, enable);
-}
-
-int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP_LCD1, clk, enable);
-}
-
-int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP_FSYS, clk, enable);
-}
-
-static int exynos4_clk_ip_peril_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable);
-}
-
-static int exynos4_clk_ip_perir_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLKGATE_IP_PERIR, clk, enable);
-}
-
-static int exynos4_clk_hdmiphy_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable);
-}
-
-static int exynos4_clk_dac_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_DAC_PHY_CONTROL, clk, enable);
-}
-
-/* Core list of CMU_CPU side */
-
-static struct clksrc_clk clk_mout_apll = {
-       .clk    = {
-               .name           = "mout_apll",
-       },
-       .sources        = &clk_src_apll,
-       .reg_src        = { .reg = S5P_CLKSRC_CPU, .shift = 0, .size = 1 },
-};
-
-struct clksrc_clk clk_sclk_apll = {
-       .clk    = {
-               .name           = "sclk_apll",
-               .parent         = &clk_mout_apll.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 24, .size = 3 },
-};
-
-struct clksrc_clk clk_mout_epll = {
-       .clk    = {
-               .name           = "mout_epll",
-       },
-       .sources        = &clk_src_epll,
-       .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 4, .size = 1 },
-};
-
-struct clksrc_clk clk_mout_mpll = {
-       .clk = {
-               .name           = "mout_mpll",
-       },
-       .sources        = &clk_src_mpll,
-
-       /* reg_src will be added in each SoCs' clock */
-};
-
-static struct clk *clkset_moutcore_list[] = {
-       [0] = &clk_mout_apll.clk,
-       [1] = &clk_mout_mpll.clk,
-};
-
-static struct clksrc_sources clkset_moutcore = {
-       .sources        = clkset_moutcore_list,
-       .nr_sources     = ARRAY_SIZE(clkset_moutcore_list),
-};
-
-static struct clksrc_clk clk_moutcore = {
-       .clk    = {
-               .name           = "moutcore",
-       },
-       .sources        = &clkset_moutcore,
-       .reg_src        = { .reg = S5P_CLKSRC_CPU, .shift = 16, .size = 1 },
-};
-
-static struct clksrc_clk clk_coreclk = {
-       .clk    = {
-               .name           = "core_clk",
-               .parent         = &clk_moutcore.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 0, .size = 3 },
-};
-
-static struct clksrc_clk clk_armclk = {
-       .clk    = {
-               .name           = "armclk",
-               .parent         = &clk_coreclk.clk,
-       },
-};
-
-static struct clksrc_clk clk_aclk_corem0 = {
-       .clk    = {
-               .name           = "aclk_corem0",
-               .parent         = &clk_coreclk.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 4, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_cores = {
-       .clk    = {
-               .name           = "aclk_cores",
-               .parent         = &clk_coreclk.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 4, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_corem1 = {
-       .clk    = {
-               .name           = "aclk_corem1",
-               .parent         = &clk_coreclk.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 8, .size = 3 },
-};
-
-static struct clksrc_clk clk_periphclk = {
-       .clk    = {
-               .name           = "periphclk",
-               .parent         = &clk_coreclk.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 12, .size = 3 },
-};
-
-/* Core list of CMU_CORE side */
-
-struct clk *clkset_corebus_list[] = {
-       [0] = &clk_mout_mpll.clk,
-       [1] = &clk_sclk_apll.clk,
-};
-
-struct clksrc_sources clkset_mout_corebus = {
-       .sources        = clkset_corebus_list,
-       .nr_sources     = ARRAY_SIZE(clkset_corebus_list),
-};
-
-static struct clksrc_clk clk_mout_corebus = {
-       .clk    = {
-               .name           = "mout_corebus",
-       },
-       .sources        = &clkset_mout_corebus,
-       .reg_src        = { .reg = S5P_CLKSRC_DMC, .shift = 4, .size = 1 },
-};
-
-static struct clksrc_clk clk_sclk_dmc = {
-       .clk    = {
-               .name           = "sclk_dmc",
-               .parent         = &clk_mout_corebus.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_DMC0, .shift = 12, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_cored = {
-       .clk    = {
-               .name           = "aclk_cored",
-               .parent         = &clk_sclk_dmc.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_DMC0, .shift = 16, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_corep = {
-       .clk    = {
-               .name           = "aclk_corep",
-               .parent         = &clk_aclk_cored.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_DMC0, .shift = 20, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_acp = {
-       .clk    = {
-               .name           = "aclk_acp",
-               .parent         = &clk_mout_corebus.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_DMC0, .shift = 0, .size = 3 },
-};
-
-static struct clksrc_clk clk_pclk_acp = {
-       .clk    = {
-               .name           = "pclk_acp",
-               .parent         = &clk_aclk_acp.clk,
-       },
-       .reg_div        = { .reg = S5P_CLKDIV_DMC0, .shift = 4, .size = 3 },
-};
-
-/* Core list of CMU_TOP side */
-
-struct clk *clkset_aclk_top_list[] = {
-       [0] = &clk_mout_mpll.clk,
-       [1] = &clk_sclk_apll.clk,
-};
-
-struct clksrc_sources clkset_aclk = {
-       .sources        = clkset_aclk_top_list,
-       .nr_sources     = ARRAY_SIZE(clkset_aclk_top_list),
-};
-
-static struct clksrc_clk clk_aclk_200 = {
-       .clk    = {
-               .name           = "aclk_200",
-       },
-       .sources        = &clkset_aclk,
-       .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 12, .size = 1 },
-       .reg_div        = { .reg = S5P_CLKDIV_TOP, .shift = 0, .size = 3 },
-};
-
-static struct clksrc_clk clk_aclk_100 = {
-       .clk    = {
-               .name           = "aclk_100",
-       },
-       .sources        = &clkset_aclk,
-       .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 16, .size = 1 },
-       .reg_div        = { .reg = S5P_CLKDIV_TOP, .shift = 4, .size = 4 },
-};
-
-static struct clksrc_clk clk_aclk_160 = {
-       .clk    = {
-               .name           = "aclk_160",
-       },
-       .sources        = &clkset_aclk,
-       .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 20, .size = 1 },
-       .reg_div        = { .reg = S5P_CLKDIV_TOP, .shift = 8, .size = 3 },
-};
-
-struct clksrc_clk clk_aclk_133 = {
-       .clk    = {
-               .name           = "aclk_133",
-       },
-       .sources        = &clkset_aclk,
-       .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 24, .size = 1 },
-       .reg_div        = { .reg = S5P_CLKDIV_TOP, .shift = 12, .size = 3 },
-};
-
-static struct clk *clkset_vpllsrc_list[] = {
-       [0] = &clk_fin_vpll,
-       [1] = &clk_sclk_hdmi27m,
-};
-
-static struct clksrc_sources clkset_vpllsrc = {
-       .sources        = clkset_vpllsrc_list,
-       .nr_sources     = ARRAY_SIZE(clkset_vpllsrc_list),
-};
-
-static struct clksrc_clk clk_vpllsrc = {
-       .clk    = {
-               .name           = "vpll_src",
-               .enable         = exynos4_clksrc_mask_top_ctrl,
-               .ctrlbit        = (1 << 0),
-       },
-       .sources        = &clkset_vpllsrc,
-       .reg_src        = { .reg = S5P_CLKSRC_TOP1, .shift = 0, .size = 1 },
-};
-
-static struct clk *clkset_sclk_vpll_list[] = {
-       [0] = &clk_vpllsrc.clk,
-       [1] = &clk_fout_vpll,
-};
-
-static struct clksrc_sources clkset_sclk_vpll = {
-       .sources        = clkset_sclk_vpll_list,
-       .nr_sources     = ARRAY_SIZE(clkset_sclk_vpll_list),
-};
-
-struct clksrc_clk clk_sclk_vpll = {
-       .clk    = {
-               .name           = "sclk_vpll",
-       },
-       .sources        = &clkset_sclk_vpll,
-       .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 8, .size = 1 },
-};
-
-static struct clk init_clocks_off[] = {
-       {
-               .name           = "timers",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1<<24),
-       }, {
-               .name           = "csis",
-               .devname        = "s5p-mipi-csis.0",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 4),
-       }, {
-               .name           = "csis",
-               .devname        = "s5p-mipi-csis.1",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 5),
-       }, {
-               .name           = "fimc",
-               .devname        = "exynos4-fimc.0",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 0),
-       }, {
-               .name           = "fimc",
-               .devname        = "exynos4-fimc.1",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 1),
-       }, {
-               .name           = "fimc",
-               .devname        = "exynos4-fimc.2",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 2),
-       }, {
-               .name           = "fimc",
-               .devname        = "exynos4-fimc.3",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 3),
-       }, {
-               .name           = "fimd",
-               .devname        = "exynos4-fb.0",
-               .enable         = exynos4_clk_ip_lcd0_ctrl,
-               .ctrlbit        = (1 << 0),
-       }, {
-               .name           = "hsmmc",
-               .devname        = "s3c-sdhci.0",
-               .parent         = &clk_aclk_133.clk,
-               .enable         = exynos4_clk_ip_fsys_ctrl,
-               .ctrlbit        = (1 << 5),
-       }, {
-               .name           = "hsmmc",
-               .devname        = "s3c-sdhci.1",
-               .parent         = &clk_aclk_133.clk,
-               .enable         = exynos4_clk_ip_fsys_ctrl,
-               .ctrlbit        = (1 << 6),
-       }, {
-               .name           = "hsmmc",
-               .devname        = "s3c-sdhci.2",
-               .parent         = &clk_aclk_133.clk,
-               .enable         = exynos4_clk_ip_fsys_ctrl,
-               .ctrlbit        = (1 << 7),
-       }, {
-               .name           = "hsmmc",
-               .devname        = "s3c-sdhci.3",
-               .parent         = &clk_aclk_133.clk,
-               .enable         = exynos4_clk_ip_fsys_ctrl,
-               .ctrlbit        = (1 << 8),
-       }, {
-               .name           = "dwmmc",
-               .parent         = &clk_aclk_133.clk,
-               .enable         = exynos4_clk_ip_fsys_ctrl,
-               .ctrlbit        = (1 << 9),
-       }, {
-               .name           = "dac",
-               .devname        = "s5p-sdo",
-               .enable         = exynos4_clk_ip_tv_ctrl,
-               .ctrlbit        = (1 << 2),
-       }, {
-               .name           = "mixer",
-               .devname        = "s5p-mixer",
-               .enable         = exynos4_clk_ip_tv_ctrl,
-               .ctrlbit        = (1 << 1),
-       }, {
-               .name           = "vp",
-               .devname        = "s5p-mixer",
-               .enable         = exynos4_clk_ip_tv_ctrl,
-               .ctrlbit        = (1 << 0),
-       }, {
-               .name           = "hdmi",
-               .devname        = "exynos4-hdmi",
-               .enable         = exynos4_clk_ip_tv_ctrl,
-               .ctrlbit        = (1 << 3),
-       }, {
-               .name           = "hdmiphy",
-               .devname        = "exynos4-hdmi",
-               .enable         = exynos4_clk_hdmiphy_ctrl,
-               .ctrlbit        = (1 << 0),
-       }, {
-               .name           = "dacphy",
-               .devname        = "s5p-sdo",
-               .enable         = exynos4_clk_dac_ctrl,
-               .ctrlbit        = (1 << 0),
-       }, {
-               .name           = "adc",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 15),
-       }, {
-               .name           = "keypad",
-               .enable         = exynos4_clk_ip_perir_ctrl,
-               .ctrlbit        = (1 << 16),
-       }, {
-               .name           = "rtc",
-               .enable         = exynos4_clk_ip_perir_ctrl,
-               .ctrlbit        = (1 << 15),
-       }, {
-               .name           = "watchdog",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_perir_ctrl,
-               .ctrlbit        = (1 << 14),
-       }, {
-               .name           = "usbhost",
-               .enable         = exynos4_clk_ip_fsys_ctrl ,
-               .ctrlbit        = (1 << 12),
-       }, {
-               .name           = "otg",
-               .enable         = exynos4_clk_ip_fsys_ctrl,
-               .ctrlbit        = (1 << 13),
-       }, {
-               .name           = "spi",
-               .devname        = "s3c64xx-spi.0",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 16),
-       }, {
-               .name           = "spi",
-               .devname        = "s3c64xx-spi.1",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 17),
-       }, {
-               .name           = "spi",
-               .devname        = "s3c64xx-spi.2",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 18),
-       }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.0",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 19),
-       }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.1",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 20),
-       }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.2",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 21),
-       }, {
-               .name           = "ac97",
-               .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",
-               .enable         = exynos4_clk_ip_mfc_ctrl,
-               .ctrlbit        = (1 << 0),
-       }, {
-               .name           = "i2c",
-               .devname        = "s3c2440-i2c.0",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 6),
-       }, {
-               .name           = "i2c",
-               .devname        = "s3c2440-i2c.1",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 7),
-       }, {
-               .name           = "i2c",
-               .devname        = "s3c2440-i2c.2",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 8),
-       }, {
-               .name           = "i2c",
-               .devname        = "s3c2440-i2c.3",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 9),
-       }, {
-               .name           = "i2c",
-               .devname        = "s3c2440-i2c.4",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 10),
-       }, {
-               .name           = "i2c",
-               .devname        = "s3c2440-i2c.5",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 11),
-       }, {
-               .name           = "i2c",
-               .devname        = "s3c2440-i2c.6",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 12),
-       }, {
-               .name           = "i2c",
-               .devname        = "s3c2440-i2c.7",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 13),
-       }, {
-               .name           = "i2c",
-               .devname        = "s3c2440-hdmiphy-i2c",
-               .parent         = &clk_aclk_100.clk,
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 14),
-       }, {
-               .name           = "SYSMMU_MDMA",
-               .enable         = exynos4_clk_ip_image_ctrl,
-               .ctrlbit        = (1 << 5),
-       }, {
-               .name           = "SYSMMU_FIMC0",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 7),
-       }, {
-               .name           = "SYSMMU_FIMC1",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 8),
-       }, {
-               .name           = "SYSMMU_FIMC2",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 9),
-       }, {
-               .name           = "SYSMMU_FIMC3",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 10),
-       }, {
-               .name           = "SYSMMU_JPEG",
-               .enable         = exynos4_clk_ip_cam_ctrl,
-               .ctrlbit        = (1 << 11),
-       }, {
-               .name           = "SYSMMU_FIMD0",
-               .enable         = exynos4_clk_ip_lcd0_ctrl,
-               .ctrlbit        = (1 << 4),
-       }, {
-               .name           = "SYSMMU_FIMD1",
-               .enable         = exynos4_clk_ip_lcd1_ctrl,
-               .ctrlbit        = (1 << 4),
-       }, {
-               .name           = "SYSMMU_PCIe",
-               .enable         = exynos4_clk_ip_fsys_ctrl,
-               .ctrlbit        = (1 << 18),
-       }, {
-               .name           = "SYSMMU_G2D",
-               .enable         = exynos4_clk_ip_image_ctrl,
-               .ctrlbit        = (1 << 3),
-       }, {
-               .name           = "SYSMMU_ROTATOR",
-               .enable         = exynos4_clk_ip_image_ctrl,
-               .ctrlbit        = (1 << 4),
-       }, {
-               .name           = "SYSMMU_TV",
-               .enable         = exynos4_clk_ip_tv_ctrl,
-               .ctrlbit        = (1 << 4),
-       }, {
-               .name           = "SYSMMU_MFC_L",
-               .enable         = exynos4_clk_ip_mfc_ctrl,
-               .ctrlbit        = (1 << 1),
-       }, {
-               .name           = "SYSMMU_MFC_R",
-               .enable         = exynos4_clk_ip_mfc_ctrl,
-               .ctrlbit        = (1 << 2),
-       }
-};
-
-static struct clk init_clocks[] = {
-       {
-               .name           = "uart",
-               .devname        = "s5pv210-uart.0",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 0),
-       }, {
-               .name           = "uart",
-               .devname        = "s5pv210-uart.1",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 1),
-       }, {
-               .name           = "uart",
-               .devname        = "s5pv210-uart.2",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 2),
-       }, {
-               .name           = "uart",
-               .devname        = "s5pv210-uart.3",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 3),
-       }, {
-               .name           = "uart",
-               .devname        = "s5pv210-uart.4",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 4),
-       }, {
-               .name           = "uart",
-               .devname        = "s5pv210-uart.5",
-               .enable         = exynos4_clk_ip_peril_ctrl,
-               .ctrlbit        = (1 << 5),
-       }
-};
-
-static struct clk clk_pdma0 = {
-       .name           = "dma",
-       .devname        = "dma-pl330.0",
-       .enable         = exynos4_clk_ip_fsys_ctrl,
-       .ctrlbit        = (1 << 0),
-};
-
-static struct clk clk_pdma1 = {
-       .name           = "dma",
-       .devname        = "dma-pl330.1",
-       .enable         = exynos4_clk_ip_fsys_ctrl,
-       .ctrlbit        = (1 << 1),
-};
-
-struct clk *clkset_group_list[] = {
-       [0] = &clk_ext_xtal_mux,
-       [1] = &clk_xusbxti,
-       [2] = &clk_sclk_hdmi27m,
-       [3] = &clk_sclk_usbphy0,
-       [4] = &clk_sclk_usbphy1,
-       [5] = &clk_sclk_hdmiphy,
-       [6] = &clk_mout_mpll.clk,
-       [7] = &clk_mout_epll.clk,
-       [8] = &clk_sclk_vpll.clk,
-};
-
-struct clksrc_sources clkset_group = {
-       .sources        = clkset_group_list,
-       .nr_sources     = ARRAY_SIZE(clkset_group_list),
-};
-
-static struct clk *clkset_mout_g2d0_list[] = {
-       [0] = &clk_mout_mpll.clk,
-       [1] = &clk_sclk_apll.clk,
-};
-
-static struct clksrc_sources clkset_mout_g2d0 = {
-       .sources        = clkset_mout_g2d0_list,
-       .nr_sources     = ARRAY_SIZE(clkset_mout_g2d0_list),
-};
-
-static struct clksrc_clk clk_mout_g2d0 = {
-       .clk    = {
-               .name           = "mout_g2d0",
-       },
-       .sources        = &clkset_mout_g2d0,
-       .reg_src        = { .reg = S5P_CLKSRC_IMAGE, .shift = 0, .size = 1 },
-};
-
-static struct clk *clkset_mout_g2d1_list[] = {
-       [0] = &clk_mout_epll.clk,
-       [1] = &clk_sclk_vpll.clk,
-};
-
-static struct clksrc_sources clkset_mout_g2d1 = {
-       .sources        = clkset_mout_g2d1_list,
-       .nr_sources     = ARRAY_SIZE(clkset_mout_g2d1_list),
-};
-
-static struct clksrc_clk clk_mout_g2d1 = {
-       .clk    = {
-               .name           = "mout_g2d1",
-       },
-       .sources        = &clkset_mout_g2d1,
-       .reg_src        = { .reg = S5P_CLKSRC_IMAGE, .shift = 4, .size = 1 },
-};
-
-static struct clk *clkset_mout_g2d_list[] = {
-       [0] = &clk_mout_g2d0.clk,
-       [1] = &clk_mout_g2d1.clk,
-};
-
-static struct clksrc_sources clkset_mout_g2d = {
-       .sources        = clkset_mout_g2d_list,
-       .nr_sources     = ARRAY_SIZE(clkset_mout_g2d_list),
-};
-
-static struct clk *clkset_mout_mfc0_list[] = {
-       [0] = &clk_mout_mpll.clk,
-       [1] = &clk_sclk_apll.clk,
-};
-
-static struct clksrc_sources clkset_mout_mfc0 = {
-       .sources        = clkset_mout_mfc0_list,
-       .nr_sources     = ARRAY_SIZE(clkset_mout_mfc0_list),
-};
-
-static struct clksrc_clk clk_mout_mfc0 = {
-       .clk    = {
-               .name           = "mout_mfc0",
-       },
-       .sources        = &clkset_mout_mfc0,
-       .reg_src        = { .reg = S5P_CLKSRC_MFC, .shift = 0, .size = 1 },
-};
-
-static struct clk *clkset_mout_mfc1_list[] = {
-       [0] = &clk_mout_epll.clk,
-       [1] = &clk_sclk_vpll.clk,
-};
-
-static struct clksrc_sources clkset_mout_mfc1 = {
-       .sources        = clkset_mout_mfc1_list,
-       .nr_sources     = ARRAY_SIZE(clkset_mout_mfc1_list),
-};
-
-static struct clksrc_clk clk_mout_mfc1 = {
-       .clk    = {
-               .name           = "mout_mfc1",
-       },
-       .sources        = &clkset_mout_mfc1,
-       .reg_src        = { .reg = S5P_CLKSRC_MFC, .shift = 4, .size = 1 },
-};
-
-static struct clk *clkset_mout_mfc_list[] = {
-       [0] = &clk_mout_mfc0.clk,
-       [1] = &clk_mout_mfc1.clk,
-};
-
-static struct clksrc_sources clkset_mout_mfc = {
-       .sources        = clkset_mout_mfc_list,
-       .nr_sources     = ARRAY_SIZE(clkset_mout_mfc_list),
-};
-
-static struct clk *clkset_sclk_dac_list[] = {
-       [0] = &clk_sclk_vpll.clk,
-       [1] = &clk_sclk_hdmiphy,
-};
-
-static struct clksrc_sources clkset_sclk_dac = {
-       .sources        = clkset_sclk_dac_list,
-       .nr_sources     = ARRAY_SIZE(clkset_sclk_dac_list),
-};
-
-static struct clksrc_clk clk_sclk_dac = {
-       .clk            = {
-               .name           = "sclk_dac",
-               .enable         = exynos4_clksrc_mask_tv_ctrl,
-               .ctrlbit        = (1 << 8),
-       },
-       .sources = &clkset_sclk_dac,
-       .reg_src = { .reg = S5P_CLKSRC_TV, .shift = 8, .size = 1 },
-};
-
-static struct clksrc_clk clk_sclk_pixel = {
-       .clk            = {
-               .name           = "sclk_pixel",
-               .parent = &clk_sclk_vpll.clk,
-       },
-       .reg_div = { .reg = S5P_CLKDIV_TV, .shift = 0, .size = 4 },
-};
-
-static struct clk *clkset_sclk_hdmi_list[] = {
-       [0] = &clk_sclk_pixel.clk,
-       [1] = &clk_sclk_hdmiphy,
-};
-
-static struct clksrc_sources clkset_sclk_hdmi = {
-       .sources        = clkset_sclk_hdmi_list,
-       .nr_sources     = ARRAY_SIZE(clkset_sclk_hdmi_list),
-};
-
-static struct clksrc_clk clk_sclk_hdmi = {
-       .clk            = {
-               .name           = "sclk_hdmi",
-               .enable         = exynos4_clksrc_mask_tv_ctrl,
-               .ctrlbit        = (1 << 0),
-       },
-       .sources = &clkset_sclk_hdmi,
-       .reg_src = { .reg = S5P_CLKSRC_TV, .shift = 0, .size = 1 },
-};
-
-static struct clk *clkset_sclk_mixer_list[] = {
-       [0] = &clk_sclk_dac.clk,
-       [1] = &clk_sclk_hdmi.clk,
-};
-
-static struct clksrc_sources clkset_sclk_mixer = {
-       .sources        = clkset_sclk_mixer_list,
-       .nr_sources     = ARRAY_SIZE(clkset_sclk_mixer_list),
-};
-
-static struct clksrc_clk clk_sclk_mixer = {
-       .clk            = {
-               .name           = "sclk_mixer",
-               .enable         = exynos4_clksrc_mask_tv_ctrl,
-               .ctrlbit        = (1 << 4),
-       },
-       .sources = &clkset_sclk_mixer,
-       .reg_src = { .reg = S5P_CLKSRC_TV, .shift = 4, .size = 1 },
-};
-
-static struct clksrc_clk *sclk_tv[] = {
-       &clk_sclk_dac,
-       &clk_sclk_pixel,
-       &clk_sclk_hdmi,
-       &clk_sclk_mixer,
-};
-
-static struct clksrc_clk clk_dout_mmc0 = {
-       .clk            = {
-               .name           = "dout_mmc0",
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 0, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clk_dout_mmc1 = {
-       .clk            = {
-               .name           = "dout_mmc1",
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 4, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 16, .size = 4 },
-};
-
-static struct clksrc_clk clk_dout_mmc2 = {
-       .clk            = {
-               .name           = "dout_mmc2",
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 8, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clk_dout_mmc3 = {
-       .clk            = {
-               .name           = "dout_mmc3",
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 12, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 16, .size = 4 },
-};
-
-static struct clksrc_clk clk_dout_mmc4 = {
-       .clk            = {
-               .name           = "dout_mmc4",
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 16, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clksrcs[] = {
-       {
-               .clk            = {
-                       .name           = "sclk_pwm",
-                       .enable         = exynos4_clksrc_mask_peril0_ctrl,
-                       .ctrlbit        = (1 << 24),
-               },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 24, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_PERIL3, .shift = 0, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_csis",
-                       .devname        = "s5p-mipi-csis.0",
-                       .enable         = exynos4_clksrc_mask_cam_ctrl,
-                       .ctrlbit        = (1 << 24),
-               },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 24, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 24, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_csis",
-                       .devname        = "s5p-mipi-csis.1",
-                       .enable         = exynos4_clksrc_mask_cam_ctrl,
-                       .ctrlbit        = (1 << 28),
-               },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 28, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 28, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_cam0",
-                       .enable         = exynos4_clksrc_mask_cam_ctrl,
-                       .ctrlbit        = (1 << 16),
-               },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 16, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 16, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_cam1",
-                       .enable         = exynos4_clksrc_mask_cam_ctrl,
-                       .ctrlbit        = (1 << 20),
-               },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 20, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 20, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_fimc",
-                       .devname        = "exynos4-fimc.0",
-                       .enable         = exynos4_clksrc_mask_cam_ctrl,
-                       .ctrlbit        = (1 << 0),
-               },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 0, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 0, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_fimc",
-                       .devname        = "exynos4-fimc.1",
-                       .enable         = exynos4_clksrc_mask_cam_ctrl,
-                       .ctrlbit        = (1 << 4),
-               },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 4, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 4, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_fimc",
-                       .devname        = "exynos4-fimc.2",
-                       .enable         = exynos4_clksrc_mask_cam_ctrl,
-                       .ctrlbit        = (1 << 8),
-               },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 8, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 8, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_fimc",
-                       .devname        = "exynos4-fimc.3",
-                       .enable         = exynos4_clksrc_mask_cam_ctrl,
-                       .ctrlbit        = (1 << 12),
-               },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 12, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 12, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_fimd",
-                       .devname        = "exynos4-fb.0",
-                       .enable         = exynos4_clksrc_mask_lcd0_ctrl,
-                       .ctrlbit        = (1 << 0),
-               },
-               .sources = &clkset_group,
-               .reg_src = { .reg = S5P_CLKSRC_LCD0, .shift = 0, .size = 4 },
-               .reg_div = { .reg = S5P_CLKDIV_LCD0, .shift = 0, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_fimg2d",
-               },
-               .sources = &clkset_mout_g2d,
-               .reg_src = { .reg = S5P_CLKSRC_IMAGE, .shift = 8, .size = 1 },
-               .reg_div = { .reg = S5P_CLKDIV_IMAGE, .shift = 0, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_mfc",
-                       .devname        = "s5p-mfc",
-               },
-               .sources = &clkset_mout_mfc,
-               .reg_src = { .reg = S5P_CLKSRC_MFC, .shift = 8, .size = 1 },
-               .reg_div = { .reg = S5P_CLKDIV_MFC, .shift = 0, .size = 4 },
-       }, {
-               .clk            = {
-                       .name           = "sclk_dwmmc",
-                       .parent         = &clk_dout_mmc4.clk,
-                       .enable         = exynos4_clksrc_mask_fsys_ctrl,
-                       .ctrlbit        = (1 << 16),
-               },
-               .reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 8, .size = 8 },
-       }
-};
-
-static struct clksrc_clk clk_sclk_uart0 = {
-       .clk    = {
-               .name           = "uclk1",
-               .devname        = "exynos4210-uart.0",
-               .enable         = exynos4_clksrc_mask_peril0_ctrl,
-               .ctrlbit        = (1 << 0),
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 0, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_uart1 = {
-       .clk            = {
-               .name           = "uclk1",
-               .devname        = "exynos4210-uart.1",
-               .enable         = exynos4_clksrc_mask_peril0_ctrl,
-               .ctrlbit        = (1 << 4),
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 4, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 4, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_uart2 = {
-       .clk            = {
-               .name           = "uclk1",
-               .devname        = "exynos4210-uart.2",
-               .enable         = exynos4_clksrc_mask_peril0_ctrl,
-               .ctrlbit        = (1 << 8),
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 8, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 8, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_uart3 = {
-       .clk            = {
-               .name           = "uclk1",
-               .devname        = "exynos4210-uart.3",
-               .enable         = exynos4_clksrc_mask_peril0_ctrl,
-               .ctrlbit        = (1 << 12),
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 12, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 12, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_mmc0 = {
-       .clk            = {
-               .name           = "sclk_mmc",
-               .devname        = "s3c-sdhci.0",
-               .parent         = &clk_dout_mmc0.clk,
-               .enable         = exynos4_clksrc_mask_fsys_ctrl,
-               .ctrlbit        = (1 << 0),
-       },
-       .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 8, .size = 8 },
-};
-
-static struct clksrc_clk clk_sclk_mmc1 = {
-       .clk            = {
-               .name           = "sclk_mmc",
-               .devname        = "s3c-sdhci.1",
-               .parent         = &clk_dout_mmc1.clk,
-               .enable         = exynos4_clksrc_mask_fsys_ctrl,
-               .ctrlbit        = (1 << 4),
-       },
-       .reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 24, .size = 8 },
-};
-
-static struct clksrc_clk clk_sclk_mmc2 = {
-       .clk            = {
-               .name           = "sclk_mmc",
-               .devname        = "s3c-sdhci.2",
-               .parent         = &clk_dout_mmc2.clk,
-               .enable         = exynos4_clksrc_mask_fsys_ctrl,
-               .ctrlbit        = (1 << 8),
-       },
-       .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 8, .size = 8 },
-};
-
-static struct clksrc_clk clk_sclk_mmc3 = {
-       .clk            = {
-               .name           = "sclk_mmc",
-               .devname        = "s3c-sdhci.3",
-               .parent         = &clk_dout_mmc3.clk,
-               .enable         = exynos4_clksrc_mask_fsys_ctrl,
-               .ctrlbit        = (1 << 12),
-       },
-       .reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 24, .size = 8 },
-};
-
-static struct clksrc_clk clk_sclk_spi0 = {
-       .clk            = {
-               .name           = "sclk_spi",
-               .devname                = "s3c64xx-spi.0",
-               .enable         = exynos4_clksrc_mask_peril1_ctrl,
-               .ctrlbit                = (1 << 16),
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 16, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_PERIL1, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_spi1 = {
-       .clk            = {
-               .name           = "sclk_spi",
-               .devname                = "s3c64xx-spi.1",
-               .enable         = exynos4_clksrc_mask_peril1_ctrl,
-               .ctrlbit                = (1 << 20),
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 20, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_PERIL1, .shift = 16, .size = 4 },
-};
-
-static struct clksrc_clk clk_sclk_spi2 = {
-       .clk            = {
-               .name           = "sclk_spi",
-               .devname                = "s3c64xx-spi.2",
-               .enable         = exynos4_clksrc_mask_peril1_ctrl,
-               .ctrlbit                = (1 << 24),
-       },
-       .sources = &clkset_group,
-       .reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 24, .size = 4 },
-       .reg_div = { .reg = S5P_CLKDIV_PERIL2, .shift = 0, .size = 4 },
-};
-
-/* Clock initialization code */
-static struct clksrc_clk *sysclks[] = {
-       &clk_mout_apll,
-       &clk_sclk_apll,
-       &clk_mout_epll,
-       &clk_mout_mpll,
-       &clk_moutcore,
-       &clk_coreclk,
-       &clk_armclk,
-       &clk_aclk_corem0,
-       &clk_aclk_cores,
-       &clk_aclk_corem1,
-       &clk_periphclk,
-       &clk_mout_corebus,
-       &clk_sclk_dmc,
-       &clk_aclk_cored,
-       &clk_aclk_corep,
-       &clk_aclk_acp,
-       &clk_pclk_acp,
-       &clk_vpllsrc,
-       &clk_sclk_vpll,
-       &clk_aclk_200,
-       &clk_aclk_100,
-       &clk_aclk_160,
-       &clk_aclk_133,
-       &clk_dout_mmc0,
-       &clk_dout_mmc1,
-       &clk_dout_mmc2,
-       &clk_dout_mmc3,
-       &clk_dout_mmc4,
-       &clk_mout_mfc0,
-       &clk_mout_mfc1,
-};
-
-static struct clk *clk_cdev[] = {
-       &clk_pdma0,
-       &clk_pdma1,
-};
-
-static struct clksrc_clk *clksrc_cdev[] = {
-       &clk_sclk_uart0,
-       &clk_sclk_uart1,
-       &clk_sclk_uart2,
-       &clk_sclk_uart3,
-       &clk_sclk_mmc0,
-       &clk_sclk_mmc1,
-       &clk_sclk_mmc2,
-       &clk_sclk_mmc3,
-       &clk_sclk_spi0,
-       &clk_sclk_spi1,
-       &clk_sclk_spi2,
-
-};
-
-static struct clk_lookup exynos4_clk_lookup[] = {
-       CLKDEV_INIT("exynos4210-uart.0", "clk_uart_baud0", &clk_sclk_uart0.clk),
-       CLKDEV_INIT("exynos4210-uart.1", "clk_uart_baud0", &clk_sclk_uart1.clk),
-       CLKDEV_INIT("exynos4210-uart.2", "clk_uart_baud0", &clk_sclk_uart2.clk),
-       CLKDEV_INIT("exynos4210-uart.3", "clk_uart_baud0", &clk_sclk_uart3.clk),
-       CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
-       CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
-       CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
-       CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &clk_sclk_mmc3.clk),
-       CLKDEV_INIT("dma-pl330.0", "apb_pclk", &clk_pdma0),
-       CLKDEV_INIT("dma-pl330.1", "apb_pclk", &clk_pdma1),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk0", &clk_sclk_spi0.clk),
-       CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk0", &clk_sclk_spi1.clk),
-       CLKDEV_INIT("s3c64xx-spi.2", "spi_busclk0", &clk_sclk_spi2.clk),
-};
-
-static int xtal_rate;
-
-static unsigned long exynos4_fout_apll_get_rate(struct clk *clk)
-{
-       if (soc_is_exynos4210())
-               return s5p_get_pll45xx(xtal_rate, __raw_readl(S5P_APLL_CON0),
-                                       pll_4508);
-       else if (soc_is_exynos4212() || soc_is_exynos4412())
-               return s5p_get_pll35xx(xtal_rate, __raw_readl(S5P_APLL_CON0));
-       else
-               return 0;
-}
-
-static struct clk_ops exynos4_fout_apll_ops = {
-       .get_rate = exynos4_fout_apll_get_rate,
-};
-
-static u32 vpll_div[][8] = {
-       {  54000000, 3, 53, 3, 1024, 0, 17, 0 },
-       { 108000000, 3, 53, 2, 1024, 0, 17, 0 },
-};
-
-static unsigned long exynos4_vpll_get_rate(struct clk *clk)
-{
-       return clk->rate;
-}
-
-static int exynos4_vpll_set_rate(struct clk *clk, unsigned long rate)
-{
-       unsigned int vpll_con0, vpll_con1 = 0;
-       unsigned int i;
-
-       /* Return if nothing changed */
-       if (clk->rate == rate)
-               return 0;
-
-       vpll_con0 = __raw_readl(S5P_VPLL_CON0);
-       vpll_con0 &= ~(0x1 << 27 |                                      \
-                       PLL90XX_MDIV_MASK << PLL46XX_MDIV_SHIFT |       \
-                       PLL90XX_PDIV_MASK << PLL46XX_PDIV_SHIFT |       \
-                       PLL90XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
-
-       vpll_con1 = __raw_readl(S5P_VPLL_CON1);
-       vpll_con1 &= ~(PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT |  \
-                       PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT | \
-                       PLL4650C_KDIV_MASK << PLL46XX_KDIV_SHIFT);
-
-       for (i = 0; i < ARRAY_SIZE(vpll_div); i++) {
-               if (vpll_div[i][0] == rate) {
-                       vpll_con0 |= vpll_div[i][1] << PLL46XX_PDIV_SHIFT;
-                       vpll_con0 |= vpll_div[i][2] << PLL46XX_MDIV_SHIFT;
-                       vpll_con0 |= vpll_div[i][3] << PLL46XX_SDIV_SHIFT;
-                       vpll_con1 |= vpll_div[i][4] << PLL46XX_KDIV_SHIFT;
-                       vpll_con1 |= vpll_div[i][5] << PLL46XX_MFR_SHIFT;
-                       vpll_con1 |= vpll_div[i][6] << PLL46XX_MRR_SHIFT;
-                       vpll_con0 |= vpll_div[i][7] << 27;
-                       break;
-               }
-       }
-
-       if (i == ARRAY_SIZE(vpll_div)) {
-               printk(KERN_ERR "%s: Invalid Clock VPLL Frequency\n",
-                               __func__);
-               return -EINVAL;
-       }
-
-       __raw_writel(vpll_con0, S5P_VPLL_CON0);
-       __raw_writel(vpll_con1, S5P_VPLL_CON1);
-
-       /* Wait for VPLL lock */
-       while (!(__raw_readl(S5P_VPLL_CON0) & (1 << PLL46XX_LOCKED_SHIFT)))
-               continue;
-
-       clk->rate = rate;
-       return 0;
-}
-
-static struct clk_ops exynos4_vpll_ops = {
-       .get_rate = exynos4_vpll_get_rate,
-       .set_rate = exynos4_vpll_set_rate,
-};
-
-void __init_or_cpufreq exynos4_setup_clocks(void)
-{
-       struct clk *xtal_clk;
-       unsigned long apll = 0;
-       unsigned long mpll = 0;
-       unsigned long epll = 0;
-       unsigned long vpll = 0;
-       unsigned long vpllsrc;
-       unsigned long xtal;
-       unsigned long armclk;
-       unsigned long sclk_dmc;
-       unsigned long aclk_200;
-       unsigned long aclk_100;
-       unsigned long aclk_160;
-       unsigned long aclk_133;
-       unsigned int ptr;
-
-       printk(KERN_DEBUG "%s: registering clocks\n", __func__);
-
-       xtal_clk = clk_get(NULL, "xtal");
-       BUG_ON(IS_ERR(xtal_clk));
-
-       xtal = clk_get_rate(xtal_clk);
-
-       xtal_rate = xtal;
-
-       clk_put(xtal_clk);
-
-       printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
-
-       if (soc_is_exynos4210()) {
-               apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON0),
-                                       pll_4508);
-               mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON0),
-                                       pll_4508);
-               epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON0),
-                                       __raw_readl(S5P_EPLL_CON1), pll_4600);
-
-               vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
-               vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0),
-                                       __raw_readl(S5P_VPLL_CON1), pll_4650c);
-       } else if (soc_is_exynos4212() || soc_is_exynos4412()) {
-               apll = s5p_get_pll35xx(xtal, __raw_readl(S5P_APLL_CON0));
-               mpll = s5p_get_pll35xx(xtal, __raw_readl(S5P_MPLL_CON0));
-               epll = s5p_get_pll36xx(xtal, __raw_readl(S5P_EPLL_CON0),
-                                       __raw_readl(S5P_EPLL_CON1));
-
-               vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
-               vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(S5P_VPLL_CON0),
-                                       __raw_readl(S5P_VPLL_CON1));
-       } else {
-               /* nothing */
-       }
-
-       clk_fout_apll.ops = &exynos4_fout_apll_ops;
-       clk_fout_mpll.rate = mpll;
-       clk_fout_epll.rate = epll;
-       clk_fout_vpll.ops = &exynos4_vpll_ops;
-       clk_fout_vpll.rate = vpll;
-
-       printk(KERN_INFO "EXYNOS4: PLL settings, A=%ld, M=%ld, E=%ld V=%ld",
-                       apll, mpll, epll, vpll);
-
-       armclk = clk_get_rate(&clk_armclk.clk);
-       sclk_dmc = clk_get_rate(&clk_sclk_dmc.clk);
-
-       aclk_200 = clk_get_rate(&clk_aclk_200.clk);
-       aclk_100 = clk_get_rate(&clk_aclk_100.clk);
-       aclk_160 = clk_get_rate(&clk_aclk_160.clk);
-       aclk_133 = clk_get_rate(&clk_aclk_133.clk);
-
-       printk(KERN_INFO "EXYNOS4: ARMCLK=%ld, DMC=%ld, ACLK200=%ld\n"
-                        "ACLK100=%ld, ACLK160=%ld, ACLK133=%ld\n",
-                       armclk, sclk_dmc, aclk_200,
-                       aclk_100, aclk_160, aclk_133);
-
-       clk_f.rate = armclk;
-       clk_h.rate = sclk_dmc;
-       clk_p.rate = aclk_100;
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-               s3c_set_clksrc(&clksrcs[ptr], true);
-}
-
-static struct clk *clks[] __initdata = {
-       &clk_sclk_hdmi27m,
-       &clk_sclk_hdmiphy,
-       &clk_sclk_usbphy0,
-       &clk_sclk_usbphy1,
-};
-
-#ifdef CONFIG_PM_SLEEP
-static int exynos4_clock_suspend(void)
-{
-       s3c_pm_do_save(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save));
-       return 0;
-}
-
-static void exynos4_clock_resume(void)
-{
-       s3c_pm_do_restore_core(exynos4_clock_save, ARRAY_SIZE(exynos4_clock_save));
-}
-
-#else
-#define exynos4_clock_suspend NULL
-#define exynos4_clock_resume NULL
-#endif
-
-struct syscore_ops exynos4_clock_syscore_ops = {
-       .suspend        = exynos4_clock_suspend,
-       .resume         = exynos4_clock_resume,
-};
-
-void __init exynos4_register_clocks(void)
-{
-       int ptr;
-
-       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
-       for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
-               s3c_register_clksrc(sysclks[ptr], 1);
-
-       for (ptr = 0; ptr < ARRAY_SIZE(sclk_tv); ptr++)
-               s3c_register_clksrc(sclk_tv[ptr], 1);
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrc_cdev); ptr++)
-               s3c_register_clksrc(clksrc_cdev[ptr], 1);
-
-       s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
-       s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
-
-       s3c24xx_register_clocks(clk_cdev, ARRAY_SIZE(clk_cdev));
-       for (ptr = 0; ptr < ARRAY_SIZE(clk_cdev); ptr++)
-               s3c_disable_clocks(clk_cdev[ptr], 1);
-
-       s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-       s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-       clkdev_add_table(exynos4_clk_lookup, ARRAY_SIZE(exynos4_clk_lookup));
-
-       register_syscore_ops(&exynos4_clock_syscore_ops);
-       s3c24xx_register_clock(&dummy_apb_pclk);
-
-       s3c_pwmclk_init();
-}
index 6de298c..e6cc50e 100644 (file)
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
+#include <asm/cacheflush.h>
 
 #include <mach/regs-irq.h>
 #include <mach/regs-pmu.h>
 #include <mach/regs-gpio.h>
+#include <mach/pmu.h>
 
 #include <plat/cpu.h>
 #include <plat/clock.h>
 #include <plat/regs-serial.h>
 
 #include "common.h"
+#define L2_AUX_VAL 0x7C470001
+#define L2_AUX_MASK 0xC200ffff
 
 static const char name_exynos4210[] = "EXYNOS4210";
 static const char name_exynos4212[] = "EXYNOS4212";
 static const char name_exynos4412[] = "EXYNOS4412";
+static const char name_exynos5250[] = "EXYNOS5250";
+
+static void exynos4_map_io(void);
+static void exynos5_map_io(void);
+static void exynos4_init_clocks(int xtal);
+static void exynos5_init_clocks(int xtal);
+static void exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+static int exynos_init(void);
 
 static struct cpu_table cpu_ids[] __initdata = {
        {
@@ -56,7 +68,7 @@ static struct cpu_table cpu_ids[] __initdata = {
                .idmask         = EXYNOS4_CPU_MASK,
                .map_io         = exynos4_map_io,
                .init_clocks    = exynos4_init_clocks,
-               .init_uarts     = exynos4_init_uarts,
+               .init_uarts     = exynos_init_uarts,
                .init           = exynos_init,
                .name           = name_exynos4210,
        }, {
@@ -64,7 +76,7 @@ static struct cpu_table cpu_ids[] __initdata = {
                .idmask         = EXYNOS4_CPU_MASK,
                .map_io         = exynos4_map_io,
                .init_clocks    = exynos4_init_clocks,
-               .init_uarts     = exynos4_init_uarts,
+               .init_uarts     = exynos_init_uarts,
                .init           = exynos_init,
                .name           = name_exynos4212,
        }, {
@@ -72,9 +84,17 @@ static struct cpu_table cpu_ids[] __initdata = {
                .idmask         = EXYNOS4_CPU_MASK,
                .map_io         = exynos4_map_io,
                .init_clocks    = exynos4_init_clocks,
-               .init_uarts     = exynos4_init_uarts,
+               .init_uarts     = exynos_init_uarts,
                .init           = exynos_init,
                .name           = name_exynos4412,
+       }, {
+               .idcode         = EXYNOS5250_SOC_ID,
+               .idmask         = EXYNOS5_SOC_MASK,
+               .map_io         = exynos5_map_io,
+               .init_clocks    = exynos5_init_clocks,
+               .init_uarts     = exynos_init_uarts,
+               .init           = exynos_init,
+               .name           = name_exynos5250,
        },
 };
 
@@ -83,10 +103,14 @@ static struct cpu_table cpu_ids[] __initdata = {
 static struct map_desc exynos_iodesc[] __initdata = {
        {
                .virtual        = (unsigned long)S5P_VA_CHIPID,
-               .pfn            = __phys_to_pfn(EXYNOS4_PA_CHIPID),
+               .pfn            = __phys_to_pfn(EXYNOS_PA_CHIPID),
                .length         = SZ_4K,
                .type           = MT_DEVICE,
-       }, {
+       },
+};
+
+static struct map_desc exynos4_iodesc[] __initdata = {
+       {
                .virtual        = (unsigned long)S3C_VA_SYS,
                .pfn            = __phys_to_pfn(EXYNOS4_PA_SYSCON),
                .length         = SZ_64K,
@@ -136,11 +160,7 @@ static struct map_desc exynos_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(EXYNOS4_PA_UART),
                .length         = SZ_512K,
                .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc exynos4_iodesc[] __initdata = {
-       {
+       }, {
                .virtual        = (unsigned long)S5P_VA_CMU,
                .pfn            = __phys_to_pfn(EXYNOS4_PA_CMU),
                .length         = SZ_128K,
@@ -156,24 +176,14 @@ static struct map_desc exynos4_iodesc[] __initdata = {
                .length         = SZ_4K,
                .type           = MT_DEVICE,
        }, {
-               .virtual        = (unsigned long)S5P_VA_GPIO1,
-               .pfn            = __phys_to_pfn(EXYNOS4_PA_GPIO1),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5P_VA_GPIO2,
-               .pfn            = __phys_to_pfn(EXYNOS4_PA_GPIO2),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5P_VA_GPIO3,
-               .pfn            = __phys_to_pfn(EXYNOS4_PA_GPIO3),
-               .length         = SZ_256,
-               .type           = MT_DEVICE,
-       }, {
                .virtual        = (unsigned long)S5P_VA_DMC0,
                .pfn            = __phys_to_pfn(EXYNOS4_PA_DMC0),
-               .length         = SZ_4K,
+               .length         = SZ_64K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_DMC1,
+               .pfn            = __phys_to_pfn(EXYNOS4_PA_DMC1),
+               .length         = SZ_64K,
                .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)S3C_VA_USB_HSPHY,
@@ -201,19 +211,80 @@ static struct map_desc exynos4_iodesc1[] __initdata = {
        },
 };
 
-static void exynos_idle(void)
-{
-       if (!need_resched())
-               cpu_do_idle();
-
-       local_irq_enable();
-}
+static struct map_desc exynos5_iodesc[] __initdata = {
+       {
+               .virtual        = (unsigned long)S3C_VA_SYS,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_SYSCON),
+               .length         = SZ_64K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_TIMER,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_TIMER),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_WATCHDOG,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_WATCHDOG),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_SROMC,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_SROMC),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_SYSTIMER,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_SYSTIMER),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_SYSRAM,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_SYSRAM),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_CMU,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_CMU),
+               .length         = 144 * SZ_1K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_PMU,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_PMU),
+               .length         = SZ_64K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_COMBINER_BASE,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_COMBINER),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_UART,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_UART),
+               .length         = SZ_512K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_GIC_CPU,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_GIC_CPU),
+               .length         = SZ_64K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_GIC_DIST,
+               .pfn            = __phys_to_pfn(EXYNOS5_PA_GIC_DIST),
+               .length         = SZ_64K,
+               .type           = MT_DEVICE,
+       },
+};
 
 void exynos4_restart(char mode, const char *cmd)
 {
        __raw_writel(0x1, S5P_SWRESET);
 }
 
+void exynos5_restart(char mode, const char *cmd)
+{
+       __raw_writel(0x1, EXYNOS_SWRESET);
+}
+
 /*
  * exynos_map_io
  *
@@ -233,7 +304,7 @@ void __init exynos_init_io(struct map_desc *mach_desc, int size)
        s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
 }
 
-void __init exynos4_map_io(void)
+static void __init exynos4_map_io(void)
 {
        iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc));
 
@@ -264,7 +335,22 @@ void __init exynos4_map_io(void)
        s5p_hdmi_setname("exynos4-hdmi");
 }
 
-void __init exynos4_init_clocks(int xtal)
+static void __init exynos5_map_io(void)
+{
+       iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc));
+
+       s3c_device_i2c0.resource[0].start = EXYNOS5_PA_IIC(0);
+       s3c_device_i2c0.resource[0].end   = EXYNOS5_PA_IIC(0) + SZ_4K - 1;
+       s3c_device_i2c0.resource[1].start = EXYNOS5_IRQ_IIC;
+       s3c_device_i2c0.resource[1].end   = EXYNOS5_IRQ_IIC;
+
+       /* The I2C bus controllers are directly compatible with s3c2440 */
+       s3c_i2c0_setname("s3c2440-i2c");
+       s3c_i2c1_setname("s3c2440-i2c");
+       s3c_i2c2_setname("s3c2440-i2c");
+}
+
+static void __init exynos4_init_clocks(int xtal)
 {
        printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
 
@@ -280,6 +366,17 @@ void __init exynos4_init_clocks(int xtal)
        exynos4_setup_clocks();
 }
 
+static void __init exynos5_init_clocks(int xtal)
+{
+       printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
+
+       s3c24xx_register_baseclocks(xtal);
+       s5p_register_clocks(xtal);
+
+       exynos5_register_clocks();
+       exynos5_setup_clocks();
+}
+
 #define COMBINER_ENABLE_SET    0x0
 #define COMBINER_ENABLE_CLEAR  0x4
 #define COMBINER_INT_STATUS    0xC
@@ -353,7 +450,14 @@ static struct irq_chip combiner_chip = {
 
 static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
 {
-       if (combiner_nr >= MAX_COMBINER_NR)
+       unsigned int max_nr;
+
+       if (soc_is_exynos5250())
+               max_nr = EXYNOS5_MAX_COMBINER_NR;
+       else
+               max_nr = EXYNOS4_MAX_COMBINER_NR;
+
+       if (combiner_nr >= max_nr)
                BUG();
        if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
                BUG();
@@ -364,8 +468,14 @@ static void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
                          unsigned int irq_start)
 {
        unsigned int i;
+       unsigned int max_nr;
 
-       if (combiner_nr >= MAX_COMBINER_NR)
+       if (soc_is_exynos5250())
+               max_nr = EXYNOS5_MAX_COMBINER_NR;
+       else
+               max_nr = EXYNOS4_MAX_COMBINER_NR;
+
+       if (combiner_nr >= max_nr)
                BUG();
 
        combiner_data[combiner_nr].base = base;
@@ -408,7 +518,7 @@ void __init exynos4_init_irq(void)
                of_irq_init(exynos4_dt_irq_match);
 #endif
 
-       for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
+       for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) {
 
                combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
                                COMBINER_IRQ(irq, 0));
@@ -423,60 +533,144 @@ void __init exynos4_init_irq(void)
        s5p_init_irq(NULL, 0);
 }
 
+void __init exynos5_init_irq(void)
+{
+       int irq;
+
+       gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
+
+       for (irq = 0; irq < EXYNOS5_MAX_COMBINER_NR; irq++) {
+               combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
+                               COMBINER_IRQ(irq, 0));
+               combiner_cascade_irq(irq, IRQ_SPI(irq));
+       }
+
+       /*
+        * The parameters of s5p_init_irq() are for VIC init.
+        * Theses parameters should be NULL and 0 because EXYNOS4
+        * uses GIC instead of VIC.
+        */
+       s5p_init_irq(NULL, 0);
+}
+
 struct bus_type exynos4_subsys = {
        .name           = "exynos4-core",
        .dev_name       = "exynos4-core",
 };
 
+struct bus_type exynos5_subsys = {
+       .name           = "exynos5-core",
+       .dev_name       = "exynos5-core",
+};
+
 static struct device exynos4_dev = {
        .bus    = &exynos4_subsys,
 };
 
-static int __init exynos4_core_init(void)
+static struct device exynos5_dev = {
+       .bus    = &exynos5_subsys,
+};
+
+static int __init exynos_core_init(void)
 {
-       return subsys_system_register(&exynos4_subsys, NULL);
+       if (soc_is_exynos5250())
+               return subsys_system_register(&exynos5_subsys, NULL);
+       else
+               return subsys_system_register(&exynos4_subsys, NULL);
 }
-core_initcall(exynos4_core_init);
+core_initcall(exynos_core_init);
 
 #ifdef CONFIG_CACHE_L2X0
 static int __init exynos4_l2x0_cache_init(void)
 {
-       /* TAG, Data Latency Control: 2cycle */
-       __raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
+       if (soc_is_exynos5250())
+               return 0;
+
+       int ret;
+       ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK);
+       if (!ret) {
+               l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
+               clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
+               return 0;
+       }
 
-       if (soc_is_exynos4210())
-               __raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
-       else if (soc_is_exynos4212() || soc_is_exynos4412())
-               __raw_writel(0x120, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
+       if (!(__raw_readl(S5P_VA_L2CC + L2X0_CTRL) & 0x1)) {
+               l2x0_saved_regs.phy_base = EXYNOS4_PA_L2CC;
+               /* TAG, Data Latency Control: 2 cycles */
+               l2x0_saved_regs.tag_latency = 0x110;
+
+               if (soc_is_exynos4212() || soc_is_exynos4412())
+                       l2x0_saved_regs.data_latency = 0x120;
+               else
+                       l2x0_saved_regs.data_latency = 0x110;
 
-       /* L2X0 Prefetch Control */
-       __raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
+               l2x0_saved_regs.prefetch_ctrl = 0x30000007;
+               l2x0_saved_regs.pwr_ctrl =
+                       (L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN);
 
-       /* L2X0 Power Control */
-       __raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN,
-                    S5P_VA_L2CC + L2X0_POWER_CTRL);
+               l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
 
-       l2x0_init(S5P_VA_L2CC, 0x7C470001, 0xC200ffff);
+               __raw_writel(l2x0_saved_regs.tag_latency,
+                               S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
+               __raw_writel(l2x0_saved_regs.data_latency,
+                               S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
 
+               /* L2X0 Prefetch Control */
+               __raw_writel(l2x0_saved_regs.prefetch_ctrl,
+                               S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
+
+               /* L2X0 Power Control */
+               __raw_writel(l2x0_saved_regs.pwr_ctrl,
+                               S5P_VA_L2CC + L2X0_POWER_CTRL);
+
+               clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
+               clean_dcache_area(&l2x0_saved_regs, sizeof(struct l2x0_regs));
+       }
+
+       l2x0_init(S5P_VA_L2CC, L2_AUX_VAL, L2_AUX_MASK);
        return 0;
 }
-
 early_initcall(exynos4_l2x0_cache_init);
 #endif
 
-int __init exynos_init(void)
+static int __init exynos5_l2_cache_init(void)
 {
-       printk(KERN_INFO "EXYNOS: Initializing architecture\n");
+       unsigned int val;
+
+       if (!soc_is_exynos5250())
+               return 0;
+
+       asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
+                    "bic %0, %0, #(1 << 2)\n"  /* cache disable */
+                    "mcr p15, 0, %0, c1, c0, 0\n"
+                    "mrc p15, 1, %0, c9, c0, 2\n"
+                    : "=r"(val));
+
+       val |= (1 << 9) | (1 << 5) | (2 << 6) | (2 << 0);
+
+       asm volatile("mcr p15, 1, %0, c9, c0, 2\n" : : "r"(val));
+       asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
+                    "orr %0, %0, #(1 << 2)\n"  /* cache enable */
+                    "mcr p15, 0, %0, c1, c0, 0\n"
+                    : : "r"(val));
+
+       return 0;
+}
+early_initcall(exynos5_l2_cache_init);
 
-       /* set idle function */
-       pm_idle = exynos_idle;
+static int __init exynos_init(void)
+{
+       printk(KERN_INFO "EXYNOS: Initializing architecture\n");
 
-       return device_register(&exynos4_dev);
+       if (soc_is_exynos5250())
+               return device_register(&exynos5_dev);
+       else
+               return device_register(&exynos4_dev);
 }
 
 /* uart registration process */
 
-void __init exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+static void __init exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no)
 {
        struct s3c2410_uartcfg *tcfg = cfg;
        u32 ucnt;
@@ -484,69 +678,138 @@ void __init exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no)
        for (ucnt = 0; ucnt < no; ucnt++, tcfg++)
                tcfg->has_fracval = 1;
 
-       s3c24xx_init_uartdevs("exynos4210-uart", s5p_uart_resources, cfg, no);
+       if (soc_is_exynos5250())
+               s3c24xx_init_uartdevs("exynos4210-uart", exynos5_uart_resources, cfg, no);
+       else
+               s3c24xx_init_uartdevs("exynos4210-uart", exynos4_uart_resources, cfg, no);
 }
 
+static void __iomem *exynos_eint_base;
+
 static DEFINE_SPINLOCK(eint_lock);
 
 static unsigned int eint0_15_data[16];
 
-static unsigned int exynos4_get_irq_nr(unsigned int number)
+static inline int exynos4_irq_to_gpio(unsigned int irq)
 {
-       u32 ret = 0;
+       if (irq < IRQ_EINT(0))
+               return -EINVAL;
 
-       switch (number) {
-       case 0 ... 3:
-               ret = (number + IRQ_EINT0);
-               break;
-       case 4 ... 7:
-               ret = (number + (IRQ_EINT4 - 4));
-               break;
-       case 8 ... 15:
-               ret = (number + (IRQ_EINT8 - 8));
-               break;
-       default:
-               printk(KERN_ERR "number available : %d\n", number);
-       }
+       irq -= IRQ_EINT(0);
+       if (irq < 8)
+               return EXYNOS4_GPX0(irq);
+
+       irq -= 8;
+       if (irq < 8)
+               return EXYNOS4_GPX1(irq);
+
+       irq -= 8;
+       if (irq < 8)
+               return EXYNOS4_GPX2(irq);
 
-       return ret;
+       irq -= 8;
+       if (irq < 8)
+               return EXYNOS4_GPX3(irq);
+
+       return -EINVAL;
 }
 
-static inline void exynos4_irq_eint_mask(struct irq_data *data)
+static inline int exynos5_irq_to_gpio(unsigned int irq)
+{
+       if (irq < IRQ_EINT(0))
+               return -EINVAL;
+
+       irq -= IRQ_EINT(0);
+       if (irq < 8)
+               return EXYNOS5_GPX0(irq);
+
+       irq -= 8;
+       if (irq < 8)
+               return EXYNOS5_GPX1(irq);
+
+       irq -= 8;
+       if (irq < 8)
+               return EXYNOS5_GPX2(irq);
+
+       irq -= 8;
+       if (irq < 8)
+               return EXYNOS5_GPX3(irq);
+
+       return -EINVAL;
+}
+
+static unsigned int exynos4_eint0_15_src_int[16] = {
+       EXYNOS4_IRQ_EINT0,
+       EXYNOS4_IRQ_EINT1,
+       EXYNOS4_IRQ_EINT2,
+       EXYNOS4_IRQ_EINT3,
+       EXYNOS4_IRQ_EINT4,
+       EXYNOS4_IRQ_EINT5,
+       EXYNOS4_IRQ_EINT6,
+       EXYNOS4_IRQ_EINT7,
+       EXYNOS4_IRQ_EINT8,
+       EXYNOS4_IRQ_EINT9,
+       EXYNOS4_IRQ_EINT10,
+       EXYNOS4_IRQ_EINT11,
+       EXYNOS4_IRQ_EINT12,
+       EXYNOS4_IRQ_EINT13,
+       EXYNOS4_IRQ_EINT14,
+       EXYNOS4_IRQ_EINT15,
+};
+
+static unsigned int exynos5_eint0_15_src_int[16] = {
+       EXYNOS5_IRQ_EINT0,
+       EXYNOS5_IRQ_EINT1,
+       EXYNOS5_IRQ_EINT2,
+       EXYNOS5_IRQ_EINT3,
+       EXYNOS5_IRQ_EINT4,
+       EXYNOS5_IRQ_EINT5,
+       EXYNOS5_IRQ_EINT6,
+       EXYNOS5_IRQ_EINT7,
+       EXYNOS5_IRQ_EINT8,
+       EXYNOS5_IRQ_EINT9,
+       EXYNOS5_IRQ_EINT10,
+       EXYNOS5_IRQ_EINT11,
+       EXYNOS5_IRQ_EINT12,
+       EXYNOS5_IRQ_EINT13,
+       EXYNOS5_IRQ_EINT14,
+       EXYNOS5_IRQ_EINT15,
+};
+static inline void exynos_irq_eint_mask(struct irq_data *data)
 {
        u32 mask;
 
        spin_lock(&eint_lock);
-       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
-       mask |= eint_irq_to_bit(data->irq);
-       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+       mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
+       mask |= EINT_OFFSET_BIT(data->irq);
+       __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
        spin_unlock(&eint_lock);
 }
 
-static void exynos4_irq_eint_unmask(struct irq_data *data)
+static void exynos_irq_eint_unmask(struct irq_data *data)
 {
        u32 mask;
 
        spin_lock(&eint_lock);
-       mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
-       mask &= ~(eint_irq_to_bit(data->irq));
-       __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+       mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
+       mask &= ~(EINT_OFFSET_BIT(data->irq));
+       __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
        spin_unlock(&eint_lock);
 }
 
-static inline void exynos4_irq_eint_ack(struct irq_data *data)
+static inline void exynos_irq_eint_ack(struct irq_data *data)
 {
-       __raw_writel(eint_irq_to_bit(data->irq),
-                    S5P_EINT_PEND(EINT_REG_NR(data->irq)));
+       __raw_writel(EINT_OFFSET_BIT(data->irq),
+                    EINT_PEND(exynos_eint_base, data->irq));
 }
 
-static void exynos4_irq_eint_maskack(struct irq_data *data)
+static void exynos_irq_eint_maskack(struct irq_data *data)
 {
-       exynos4_irq_eint_mask(data);
-       exynos4_irq_eint_ack(data);
+       exynos_irq_eint_mask(data);
+       exynos_irq_eint_ack(data);
 }
 
-static int exynos4_irq_eint_set_type(struct irq_data *data, unsigned int type)
+static int exynos_irq_eint_set_type(struct irq_data *data, unsigned int type)
 {
        int offs = EINT_OFFSET(data->irq);
        int shift;
@@ -583,39 +846,27 @@ static int exynos4_irq_eint_set_type(struct irq_data *data, unsigned int type)
        mask = 0x7 << shift;
 
        spin_lock(&eint_lock);
-       ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
+       ctrl = __raw_readl(EINT_CON(exynos_eint_base, data->irq));
        ctrl &= ~mask;
        ctrl |= newvalue << shift;
-       __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
+       __raw_writel(ctrl, EINT_CON(exynos_eint_base, data->irq));
        spin_unlock(&eint_lock);
 
-       switch (offs) {
-       case 0 ... 7:
-               s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
-               break;
-       case 8 ... 15:
-               s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
-               break;
-       case 16 ... 23:
-               s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
-               break;
-       case 24 ... 31:
-               s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
-               break;
-       default:
-               printk(KERN_ERR "No such irq number %d", offs);
-       }
+       if (soc_is_exynos5250())
+               s3c_gpio_cfgpin(exynos5_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
+       else
+               s3c_gpio_cfgpin(exynos4_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
 
        return 0;
 }
 
-static struct irq_chip exynos4_irq_eint = {
-       .name           = "exynos4-eint",
-       .irq_mask       = exynos4_irq_eint_mask,
-       .irq_unmask     = exynos4_irq_eint_unmask,
-       .irq_mask_ack   = exynos4_irq_eint_maskack,
-       .irq_ack        = exynos4_irq_eint_ack,
-       .irq_set_type   = exynos4_irq_eint_set_type,
+static struct irq_chip exynos_irq_eint = {
+       .name           = "exynos-eint",
+       .irq_mask       = exynos_irq_eint_mask,
+       .irq_unmask     = exynos_irq_eint_unmask,
+       .irq_mask_ack   = exynos_irq_eint_maskack,
+       .irq_ack        = exynos_irq_eint_ack,
+       .irq_set_type   = exynos_irq_eint_set_type,
 #ifdef CONFIG_PM
        .irq_set_wake   = s3c_irqext_wake,
 #endif
@@ -630,12 +881,12 @@ static struct irq_chip exynos4_irq_eint = {
  *
  * Each EINT pend/mask registers handle eight of them.
  */
-static inline void exynos4_irq_demux_eint(unsigned int start)
+static inline void exynos_irq_demux_eint(unsigned int start)
 {
        unsigned int irq;
 
-       u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
-       u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
+       u32 status = __raw_readl(EINT_PEND(exynos_eint_base, start));
+       u32 mask = __raw_readl(EINT_MASK(exynos_eint_base, start));
 
        status &= ~mask;
        status &= 0xff;
@@ -647,16 +898,16 @@ static inline void exynos4_irq_demux_eint(unsigned int start)
        }
 }
 
-static void exynos4_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
+static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_get_chip(irq);
        chained_irq_enter(chip, desc);
-       exynos4_irq_demux_eint(IRQ_EINT(16));
-       exynos4_irq_demux_eint(IRQ_EINT(24));
+       exynos_irq_demux_eint(IRQ_EINT(16));
+       exynos_irq_demux_eint(IRQ_EINT(24));
        chained_irq_exit(chip, desc);
 }
 
-static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
+static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
 {
        u32 *irq_data = irq_get_handler_data(irq);
        struct irq_chip *chip = irq_get_chip(irq);
@@ -673,27 +924,44 @@ static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
-int __init exynos4_init_irq_eint(void)
+static int __init exynos_init_irq_eint(void)
 {
        int irq;
 
+       if (soc_is_exynos5250())
+               exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
+       else
+               exynos_eint_base = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
+
+       if (exynos_eint_base == NULL) {
+               pr_err("unable to ioremap for EINT base address\n");
+               return -ENOMEM;
+       }
+
        for (irq = 0 ; irq <= 31 ; irq++) {
-               irq_set_chip_and_handler(IRQ_EINT(irq), &exynos4_irq_eint,
+               irq_set_chip_and_handler(IRQ_EINT(irq), &exynos_irq_eint,
                                         handle_level_irq);
                set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
        }
 
-       irq_set_chained_handler(IRQ_EINT16_31, exynos4_irq_demux_eint16_31);
+       irq_set_chained_handler(EXYNOS_IRQ_EINT16_31, exynos_irq_demux_eint16_31);
 
        for (irq = 0 ; irq <= 15 ; irq++) {
                eint0_15_data[irq] = IRQ_EINT(irq);
 
-               irq_set_handler_data(exynos4_get_irq_nr(irq),
-                                    &eint0_15_data[irq]);
-               irq_set_chained_handler(exynos4_get_irq_nr(irq),
-                                       exynos4_irq_eint0_15);
+               if (soc_is_exynos5250()) {
+                       irq_set_handler_data(exynos5_eint0_15_src_int[irq],
+                                            &eint0_15_data[irq]);
+                       irq_set_chained_handler(exynos5_eint0_15_src_int[irq],
+                                               exynos_irq_eint0_15);
+               } else {
+                       irq_set_handler_data(exynos4_eint0_15_src_int[irq],
+                                            &eint0_15_data[irq]);
+                       irq_set_chained_handler(exynos4_eint0_15_src_int[irq],
+                                               exynos_irq_eint0_15);
+               }
        }
 
        return 0;
 }
-arch_initcall(exynos4_init_irq_eint);
+arch_initcall(exynos_init_irq_eint);
index 1ac49de..677b546 100644 (file)
 #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
 #define __ARCH_ARM_MACH_EXYNOS_COMMON_H
 
+extern struct sys_timer exynos4_timer;
+
 void exynos_init_io(struct map_desc *mach_desc, int size);
 void exynos4_init_irq(void);
+void exynos5_init_irq(void);
+void exynos4_restart(char mode, const char *cmd);
+void exynos5_restart(char mode, const char *cmd);
 
+#ifdef CONFIG_ARCH_EXYNOS4
 void exynos4_register_clocks(void);
 void exynos4_setup_clocks(void);
 
-void exynos4210_register_clocks(void);
-void exynos4212_register_clocks(void);
+#else
+#define exynos4_register_clocks()
+#define exynos4_setup_clocks()
+#endif
 
-void exynos4_restart(char mode, const char *cmd);
+#ifdef CONFIG_ARCH_EXYNOS5
+void exynos5_register_clocks(void);
+void exynos5_setup_clocks(void);
 
-extern struct sys_timer exynos4_timer;
+#else
+#define exynos5_register_clocks()
+#define exynos5_setup_clocks()
+#endif
+
+#ifdef CONFIG_CPU_EXYNOS4210
+void exynos4210_register_clocks(void);
 
-#ifdef CONFIG_ARCH_EXYNOS
-extern  int exynos_init(void);
-extern void exynos4_map_io(void);
-extern void exynos4_init_clocks(int xtal);
-extern void exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+#else
+#define exynos4210_register_clocks()
+#endif
+
+#ifdef CONFIG_SOC_EXYNOS4212
+void exynos4212_register_clocks(void);
 
 #else
-#define exynos4_init_clocks NULL
-#define exynos4_init_uarts NULL
-#define exynos4_map_io NULL
-#define exynos_init NULL
+#define exynos4212_register_clocks()
 #endif
 
 #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */
index 4ebb382..33ab4e7 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
 #include <linux/io.h>
 #include <linux/export.h>
 #include <linux/time.h>
 
 #include <asm/proc-fns.h>
+#include <asm/smp_scu.h>
+#include <asm/suspend.h>
+#include <asm/unified.h>
+#include <mach/regs-pmu.h>
+#include <mach/pmu.h>
+
+#include <plat/cpu.h>
+
+#define REG_DIRECTGO_ADDR      (samsung_rev() == EXYNOS4210_REV_1_1 ? \
+                       S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
+                       (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0))
+#define REG_DIRECTGO_FLAG      (samsung_rev() == EXYNOS4210_REV_1_1 ? \
+                       S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
+                       (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1))
+
+#define S5P_CHECK_AFTR         0xFCBA0D10
 
 static int exynos4_enter_idle(struct cpuidle_device *dev,
                        struct cpuidle_driver *drv,
                              int index);
+static int exynos4_enter_lowpower(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv,
+                               int index);
 
-static struct cpuidle_state exynos4_cpuidle_set[] = {
+static struct cpuidle_state exynos4_cpuidle_set[] __initdata = {
        [0] = {
                .enter                  = exynos4_enter_idle,
                .exit_latency           = 1,
                .target_residency       = 100000,
                .flags                  = CPUIDLE_FLAG_TIME_VALID,
-               .name                   = "IDLE",
+               .name                   = "C0",
                .desc                   = "ARM clock gating(WFI)",
        },
+       [1] = {
+               .enter                  = exynos4_enter_lowpower,
+               .exit_latency           = 300,
+               .target_residency       = 100000,
+               .flags                  = CPUIDLE_FLAG_TIME_VALID,
+               .name                   = "C1",
+               .desc                   = "ARM power down",
+       },
 };
 
 static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
@@ -39,9 +67,102 @@ static struct cpuidle_driver exynos4_idle_driver = {
        .owner          = THIS_MODULE,
 };
 
+/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
+static void exynos4_set_wakeupmask(void)
+{
+       __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK);
+}
+
+static unsigned int g_pwr_ctrl, g_diag_reg;
+
+static void save_cpu_arch_register(void)
+{
+       /*read power control register*/
+       asm("mrc p15, 0, %0, c15, c0, 0" : "=r"(g_pwr_ctrl) : : "cc");
+       /*read diagnostic register*/
+       asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
+       return;
+}
+
+static void restore_cpu_arch_register(void)
+{
+       /*write power control register*/
+       asm("mcr p15, 0, %0, c15, c0, 0" : : "r"(g_pwr_ctrl) : "cc");
+       /*write diagnostic register*/
+       asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
+       return;
+}
+
+static int idle_finisher(unsigned long flags)
+{
+       cpu_do_idle();
+       return 1;
+}
+
+static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv,
+                               int index)
+{
+       struct timeval before, after;
+       int idle_time;
+       unsigned long tmp;
+
+       local_irq_disable();
+       do_gettimeofday(&before);
+
+       exynos4_set_wakeupmask();
+
+       /* Set value of power down register for aftr mode */
+       exynos4_sys_powerdown_conf(SYS_AFTR);
+
+       __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR);
+       __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG);
+
+       save_cpu_arch_register();
+
+       /* Setting Central Sequence Register for power down mode */
+       tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
+       tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
+       __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+
+       cpu_pm_enter();
+       cpu_suspend(0, idle_finisher);
+
+#ifdef CONFIG_SMP
+       scu_enable(S5P_VA_SCU);
+#endif
+       cpu_pm_exit();
+
+       restore_cpu_arch_register();
+
+       /*
+        * If PMU failed while entering sleep mode, WFI will be
+        * ignored by PMU and then exiting cpu_do_idle().
+        * S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically
+        * in this situation.
+        */
+       tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
+       if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) {
+               tmp |= S5P_CENTRAL_LOWPWR_CFG;
+               __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+       }
+
+       /* Clear wakeup state register */
+       __raw_writel(0x0, S5P_WAKEUP_STAT);
+
+       do_gettimeofday(&after);
+
+       local_irq_enable();
+       idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+                   (after.tv_usec - before.tv_usec);
+
+       dev->last_residency = idle_time;
+       return index;
+}
+
 static int exynos4_enter_idle(struct cpuidle_device *dev,
                                struct cpuidle_driver *drv,
-                             int index)
+                               int index)
 {
        struct timeval before, after;
        int idle_time;
@@ -60,6 +181,22 @@ static int exynos4_enter_idle(struct cpuidle_device *dev,
        return index;
 }
 
+static int exynos4_enter_lowpower(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv,
+                               int index)
+{
+       int new_index = index;
+
+       /* This mode only can be entered when other core's are offline */
+       if (num_online_cpus() > 1)
+               new_index = drv->safe_state_index;
+
+       if (new_index == 0)
+               return exynos4_enter_idle(dev, drv, new_index);
+       else
+               return exynos4_enter_core0_aftr(dev, drv, new_index);
+}
+
 static int __init exynos4_init_cpuidle(void)
 {
        int i, max_cpuidle_state, cpu_id;
@@ -74,19 +211,25 @@ static int __init exynos4_init_cpuidle(void)
                memcpy(&drv->states[i], &exynos4_cpuidle_set[i],
                                sizeof(struct cpuidle_state));
        }
+       drv->safe_state_index = 0;
        cpuidle_register_driver(&exynos4_idle_driver);
 
        for_each_cpu(cpu_id, cpu_online_mask) {
                device = &per_cpu(exynos4_cpuidle_device, cpu_id);
                device->cpu = cpu_id;
 
-               device->state_count = drv->state_count;
+               if (cpu_id == 0)
+                       device->state_count = (sizeof(exynos4_cpuidle_set) /
+                                              sizeof(struct cpuidle_state));
+               else
+                       device->state_count = 1;        /* Support IDLE only */
 
                if (cpuidle_register_device(device)) {
                        printk(KERN_ERR "CPUidle register device failed\n,");
                        return -EIO;
                }
        }
+
        return 0;
 }
 device_initcall(exynos4_init_cpuidle);
index f57a3de..50ce5b0 100644 (file)
@@ -242,8 +242,8 @@ static struct resource exynos4_ahci_resource[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_SATA,
-               .end    = IRQ_SATA,
+               .start  = EXYNOS4_IRQ_SATA,
+               .end    = EXYNOS4_IRQ_SATA,
                .flags  = IORESOURCE_IRQ,
        },
 };
index 5a9f9c2..7199e1a 100644 (file)
@@ -304,8 +304,8 @@ static struct resource exynos4_ac97_resource[] = {
                .flags  = IORESOURCE_DMA,
        },
        [4] = {
-               .start  = IRQ_AC97,
-               .end    = IRQ_AC97,
+               .start  = EXYNOS4_IRQ_AC97,
+               .end    = EXYNOS4_IRQ_AC97,
                .flags  = IORESOURCE_IRQ,
        },
 };
diff --git a/arch/arm/mach-exynos/dev-uart.c b/arch/arm/mach-exynos/dev-uart.c
new file mode 100644 (file)
index 0000000..2e85c02
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Base EXYNOS UART resource and device definitions
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <plat/devs.h>
+
+#define EXYNOS_UART_RESOURCE(_series, _nr)     \
+static struct resource exynos##_series##_uart##_nr##_resource[] = {    \
+       [0] = DEFINE_RES_MEM(EXYNOS##_series##_PA_UART##_nr, EXYNOS##_series##_SZ_UART),        \
+       [1] = DEFINE_RES_IRQ(EXYNOS##_series##_IRQ_UART##_nr),  \
+};
+
+EXYNOS_UART_RESOURCE(4, 0)
+EXYNOS_UART_RESOURCE(4, 1)
+EXYNOS_UART_RESOURCE(4, 2)
+EXYNOS_UART_RESOURCE(4, 3)
+
+struct s3c24xx_uart_resources exynos4_uart_resources[] __initdata = {
+       [0] = {
+               .resources      = exynos4_uart0_resource,
+               .nr_resources   = ARRAY_SIZE(exynos4_uart0_resource),
+       },
+       [1] = {
+               .resources      = exynos4_uart1_resource,
+               .nr_resources   = ARRAY_SIZE(exynos4_uart1_resource),
+       },
+       [2] = {
+               .resources      = exynos4_uart2_resource,
+               .nr_resources   = ARRAY_SIZE(exynos4_uart2_resource),
+       },
+       [3] = {
+               .resources      = exynos4_uart3_resource,
+               .nr_resources   = ARRAY_SIZE(exynos4_uart3_resource),
+       },
+};
+
+EXYNOS_UART_RESOURCE(5, 0)
+EXYNOS_UART_RESOURCE(5, 1)
+EXYNOS_UART_RESOURCE(5, 2)
+EXYNOS_UART_RESOURCE(5, 3)
+
+struct s3c24xx_uart_resources exynos5_uart_resources[] __initdata = {
+       [0] = {
+               .resources      = exynos5_uart0_resource,
+               .nr_resources   = ARRAY_SIZE(exynos5_uart0_resource),
+       },
+       [1] = {
+               .resources      = exynos5_uart1_resource,
+               .nr_resources   = ARRAY_SIZE(exynos5_uart0_resource),
+       },
+       [2] = {
+               .resources      = exynos5_uart2_resource,
+               .nr_resources   = ARRAY_SIZE(exynos5_uart2_resource),
+       },
+       [3] = {
+               .resources      = exynos5_uart3_resource,
+               .nr_resources   = ARRAY_SIZE(exynos5_uart3_resource),
+       },
+};
index b10fcd2..3983abe 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/irq.h>
 #include <plat/devs.h>
 #include <plat/irqs.h>
+#include <plat/cpu.h>
 
 #include <mach/map.h>
 #include <mach/irqs.h>
@@ -36,7 +37,7 @@
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-u8 pdma0_peri[] = {
+static u8 exynos4210_pdma0_peri[] = {
        DMACH_PCM0_RX,
        DMACH_PCM0_TX,
        DMACH_PCM2_RX,
@@ -69,28 +70,47 @@ u8 pdma0_peri[] = {
        DMACH_AC97_PCMOUT,
 };
 
-struct dma_pl330_platdata exynos4_pdma0_pdata = {
-       .nr_valid_peri = ARRAY_SIZE(pdma0_peri),
-       .peri_id = pdma0_peri,
+static u8 exynos4212_pdma0_peri[] = {
+       DMACH_PCM0_RX,
+       DMACH_PCM0_TX,
+       DMACH_PCM2_RX,
+       DMACH_PCM2_TX,
+       DMACH_MIPI_HSI0,
+       DMACH_MIPI_HSI1,
+       DMACH_SPI0_RX,
+       DMACH_SPI0_TX,
+       DMACH_SPI2_RX,
+       DMACH_SPI2_TX,
+       DMACH_I2S0S_TX,
+       DMACH_I2S0_RX,
+       DMACH_I2S0_TX,
+       DMACH_I2S2_RX,
+       DMACH_I2S2_TX,
+       DMACH_UART0_RX,
+       DMACH_UART0_TX,
+       DMACH_UART2_RX,
+       DMACH_UART2_TX,
+       DMACH_UART4_RX,
+       DMACH_UART4_TX,
+       DMACH_SLIMBUS0_RX,
+       DMACH_SLIMBUS0_TX,
+       DMACH_SLIMBUS2_RX,
+       DMACH_SLIMBUS2_TX,
+       DMACH_SLIMBUS4_RX,
+       DMACH_SLIMBUS4_TX,
+       DMACH_AC97_MICIN,
+       DMACH_AC97_PCMIN,
+       DMACH_AC97_PCMOUT,
+       DMACH_MIPI_HSI4,
+       DMACH_MIPI_HSI5,
 };
 
-struct amba_device exynos4_device_pdma0 = {
-       .dev = {
-               .init_name = "dma-pl330.0",
-               .dma_mask = &dma_dmamask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
-               .platform_data = &exynos4_pdma0_pdata,
-       },
-       .res = {
-               .start = EXYNOS4_PA_PDMA0,
-               .end = EXYNOS4_PA_PDMA0 + SZ_4K,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {IRQ_PDMA0, NO_IRQ},
-       .periphid = 0x00041330,
-};
+struct dma_pl330_platdata exynos4_pdma0_pdata;
+
+static AMBA_AHB_DEVICE(exynos4_pdma0, "dma-pl330.0", 0x00041330,
+       EXYNOS4_PA_PDMA0, {EXYNOS4_IRQ_PDMA0}, &exynos4_pdma0_pdata);
 
-u8 pdma1_peri[] = {
+static u8 exynos4210_pdma1_peri[] = {
        DMACH_PCM0_RX,
        DMACH_PCM0_TX,
        DMACH_PCM1_RX,
@@ -118,39 +138,94 @@ u8 pdma1_peri[] = {
        DMACH_SLIMBUS5_TX,
 };
 
-struct dma_pl330_platdata exynos4_pdma1_pdata = {
-       .nr_valid_peri = ARRAY_SIZE(pdma1_peri),
-       .peri_id = pdma1_peri,
+static u8 exynos4212_pdma1_peri[] = {
+       DMACH_PCM0_RX,
+       DMACH_PCM0_TX,
+       DMACH_PCM1_RX,
+       DMACH_PCM1_TX,
+       DMACH_MIPI_HSI2,
+       DMACH_MIPI_HSI3,
+       DMACH_SPI1_RX,
+       DMACH_SPI1_TX,
+       DMACH_I2S0S_TX,
+       DMACH_I2S0_RX,
+       DMACH_I2S0_TX,
+       DMACH_I2S1_RX,
+       DMACH_I2S1_TX,
+       DMACH_UART0_RX,
+       DMACH_UART0_TX,
+       DMACH_UART1_RX,
+       DMACH_UART1_TX,
+       DMACH_UART3_RX,
+       DMACH_UART3_TX,
+       DMACH_SLIMBUS1_RX,
+       DMACH_SLIMBUS1_TX,
+       DMACH_SLIMBUS3_RX,
+       DMACH_SLIMBUS3_TX,
+       DMACH_SLIMBUS5_RX,
+       DMACH_SLIMBUS5_TX,
+       DMACH_SLIMBUS0AUX_RX,
+       DMACH_SLIMBUS0AUX_TX,
+       DMACH_SPDIF,
+       DMACH_MIPI_HSI6,
+       DMACH_MIPI_HSI7,
 };
 
-struct amba_device exynos4_device_pdma1 = {
-       .dev = {
-               .init_name = "dma-pl330.1",
-               .dma_mask = &dma_dmamask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
-               .platform_data = &exynos4_pdma1_pdata,
-       },
-       .res = {
-               .start = EXYNOS4_PA_PDMA1,
-               .end = EXYNOS4_PA_PDMA1 + SZ_4K,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {IRQ_PDMA1, NO_IRQ},
-       .periphid = 0x00041330,
+static struct dma_pl330_platdata exynos4_pdma1_pdata;
+
+static AMBA_AHB_DEVICE(exynos4_pdma1,  "dma-pl330.1", 0x00041330,
+       EXYNOS4_PA_PDMA1, {EXYNOS4_IRQ_PDMA1}, &exynos4_pdma1_pdata);
+
+static u8 mdma_peri[] = {
+       DMACH_MTOM_0,
+       DMACH_MTOM_1,
+       DMACH_MTOM_2,
+       DMACH_MTOM_3,
+       DMACH_MTOM_4,
+       DMACH_MTOM_5,
+       DMACH_MTOM_6,
+       DMACH_MTOM_7,
+};
+
+static struct dma_pl330_platdata exynos4_mdma1_pdata = {
+       .nr_valid_peri = ARRAY_SIZE(mdma_peri),
+       .peri_id = mdma_peri,
 };
 
+static AMBA_AHB_DEVICE(exynos4_mdma1,  "dma-pl330.2", 0x00041330,
+       EXYNOS4_PA_MDMA1, {EXYNOS4_IRQ_MDMA1}, &exynos4_mdma1_pdata);
+
 static int __init exynos4_dma_init(void)
 {
        if (of_have_populated_dt())
                return 0;
 
+       if (soc_is_exynos4210()) {
+               exynos4_pdma0_pdata.nr_valid_peri =
+                       ARRAY_SIZE(exynos4210_pdma0_peri);
+               exynos4_pdma0_pdata.peri_id = exynos4210_pdma0_peri;
+               exynos4_pdma1_pdata.nr_valid_peri =
+                       ARRAY_SIZE(exynos4210_pdma1_peri);
+               exynos4_pdma1_pdata.peri_id = exynos4210_pdma1_peri;
+       } else if (soc_is_exynos4212() || soc_is_exynos4412()) {
+               exynos4_pdma0_pdata.nr_valid_peri =
+                       ARRAY_SIZE(exynos4212_pdma0_peri);
+               exynos4_pdma0_pdata.peri_id = exynos4212_pdma0_peri;
+               exynos4_pdma1_pdata.nr_valid_peri =
+                       ARRAY_SIZE(exynos4212_pdma1_peri);
+               exynos4_pdma1_pdata.peri_id = exynos4212_pdma1_peri;
+       }
+
        dma_cap_set(DMA_SLAVE, exynos4_pdma0_pdata.cap_mask);
        dma_cap_set(DMA_CYCLIC, exynos4_pdma0_pdata.cap_mask);
-       amba_device_register(&exynos4_device_pdma0, &iomem_resource);
+       amba_device_register(&exynos4_pdma0_device, &iomem_resource);
 
        dma_cap_set(DMA_SLAVE, exynos4_pdma1_pdata.cap_mask);
        dma_cap_set(DMA_CYCLIC, exynos4_pdma1_pdata.cap_mask);
-       amba_device_register(&exynos4_device_pdma1, &iomem_resource);
+       amba_device_register(&exynos4_pdma1_device, &iomem_resource);
+
+       dma_cap_set(DMA_MEMCPY, exynos4_mdma1_pdata.cap_mask);
+       amba_device_register(&exynos4_mdma1_device, &iomem_resource);
 
        return 0;
 }
index 3df27f2..7517c3f 100644 (file)
@@ -32,3 +32,5 @@ struct exynos_dvfs_info {
 };
 
 extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
+extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
+extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
index 6cacf16..6c857ff 100644 (file)
         */
 
        .macro addruart, rp, rv, tmp
-               ldr     \rp, = S3C_PA_UART
-               ldr     \rv, = S3C_VA_UART
+               mov     \rp, #0x10000000
+               ldr     \rp, [\rp, #0x0]
+               and     \rp, \rp, #0xf00000
+               teq     \rp, #0x500000          @@ EXYNOS5
+               ldreq   \rp, =EXYNOS5_PA_UART
+               movne   \rp, #EXYNOS4_PA_UART   @@ EXYNOS4
+               ldr     \rv, =S3C_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
                add     \rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART)
                add     \rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART)
diff --git a/arch/arm/mach-exynos/include/mach/entry-macro.S b/arch/arm/mach-exynos/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 3ba4f54..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* arch/arm/mach-exynos4/include/mach/entry-macro.S
- *
- * Cloned from arch/arm/mach-realview/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for EXYNOS4 platforms
- *
- * 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.
-*/
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-exynos/include/mach/exynos4-clock.h b/arch/arm/mach-exynos/include/mach/exynos4-clock.h
deleted file mode 100644 (file)
index a07fcbf..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * linux/arch/arm/mach-exynos4/include/mach/exynos4-clock.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Header file for exynos4 clock support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_CLOCK_H
-#define __ASM_ARCH_CLOCK_H __FILE__
-
-#include <linux/clk.h>
-
-extern struct clk clk_sclk_hdmi27m;
-extern struct clk clk_sclk_usbphy0;
-extern struct clk clk_sclk_usbphy1;
-extern struct clk clk_sclk_hdmiphy;
-
-extern struct clksrc_clk clk_sclk_apll;
-extern struct clksrc_clk clk_mout_mpll;
-extern struct clksrc_clk clk_aclk_133;
-extern struct clksrc_clk clk_mout_epll;
-extern struct clksrc_clk clk_sclk_vpll;
-
-extern struct clk *clkset_corebus_list[];
-extern struct clksrc_sources clkset_mout_corebus;
-
-extern struct clk *clkset_aclk_top_list[];
-extern struct clksrc_sources clkset_aclk;
-
-extern struct clk *clkset_group_list[];
-extern struct clksrc_sources clkset_group;
-
-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);
-
-#endif /* __ASM_ARCH_CLOCK_H */
index 80523ca..d7498af 100644 (file)
@@ -1,9 +1,8 @@
-/* linux/arch/arm/mach-exynos4/include/mach/gpio.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
- * EXYNOS4 - GPIO lib support
+ * EXYNOS - GPIO lib support
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #ifndef __ASM_ARCH_GPIO_H
 #define __ASM_ARCH_GPIO_H __FILE__
 
-/* Practically, GPIO banks up to GPZ are the configurable gpio banks */
+/* Macro for EXYNOS GPIO numbering */
+
+#define EXYNOS_GPIO_NEXT(__gpio) \
+       ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
+
+/* EXYNOS4 GPIO bank sizes */
 
-/* GPIO bank sizes */
 #define EXYNOS4_GPIO_A0_NR     (8)
 #define EXYNOS4_GPIO_A1_NR     (6)
 #define EXYNOS4_GPIO_B_NR      (8)
 #define EXYNOS4_GPIO_Y6_NR     (8)
 #define EXYNOS4_GPIO_Z_NR      (7)
 
-/* GPIO bank numbers */
-
-#define EXYNOS4_GPIO_NEXT(__gpio) \
-       ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
+/* EXYNOS4 GPIO bank numbers */
 
-enum s5p_gpio_number {
+enum exynos4_gpio_number {
        EXYNOS4_GPIO_A0_START   = 0,
-       EXYNOS4_GPIO_A1_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_A0),
-       EXYNOS4_GPIO_B_START    = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_A1),
-       EXYNOS4_GPIO_C0_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_B),
-       EXYNOS4_GPIO_C1_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_C0),
-       EXYNOS4_GPIO_D0_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_C1),
-       EXYNOS4_GPIO_D1_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_D0),
-       EXYNOS4_GPIO_E0_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_D1),
-       EXYNOS4_GPIO_E1_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E0),
-       EXYNOS4_GPIO_E2_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E1),
-       EXYNOS4_GPIO_E3_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E2),
-       EXYNOS4_GPIO_E4_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E3),
-       EXYNOS4_GPIO_F0_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E4),
-       EXYNOS4_GPIO_F1_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F0),
-       EXYNOS4_GPIO_F2_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F1),
-       EXYNOS4_GPIO_F3_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F2),
-       EXYNOS4_GPIO_J0_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F3),
-       EXYNOS4_GPIO_J1_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_J0),
-       EXYNOS4_GPIO_K0_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_J1),
-       EXYNOS4_GPIO_K1_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K0),
-       EXYNOS4_GPIO_K2_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K1),
-       EXYNOS4_GPIO_K3_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K2),
-       EXYNOS4_GPIO_L0_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K3),
-       EXYNOS4_GPIO_L1_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L0),
-       EXYNOS4_GPIO_L2_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L1),
-       EXYNOS4_GPIO_X0_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L2),
-       EXYNOS4_GPIO_X1_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X0),
-       EXYNOS4_GPIO_X2_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X1),
-       EXYNOS4_GPIO_X3_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X2),
-       EXYNOS4_GPIO_Y0_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X3),
-       EXYNOS4_GPIO_Y1_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y0),
-       EXYNOS4_GPIO_Y2_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y1),
-       EXYNOS4_GPIO_Y3_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y2),
-       EXYNOS4_GPIO_Y4_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y3),
-       EXYNOS4_GPIO_Y5_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y4),
-       EXYNOS4_GPIO_Y6_START   = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y5),
-       EXYNOS4_GPIO_Z_START    = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y6),
+       EXYNOS4_GPIO_A1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A0),
+       EXYNOS4_GPIO_B_START    = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_A1),
+       EXYNOS4_GPIO_C0_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_B),
+       EXYNOS4_GPIO_C1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_C0),
+       EXYNOS4_GPIO_D0_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_C1),
+       EXYNOS4_GPIO_D1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_D0),
+       EXYNOS4_GPIO_E0_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_D1),
+       EXYNOS4_GPIO_E1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_E0),
+       EXYNOS4_GPIO_E2_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_E1),
+       EXYNOS4_GPIO_E3_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_E2),
+       EXYNOS4_GPIO_E4_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_E3),
+       EXYNOS4_GPIO_F0_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_E4),
+       EXYNOS4_GPIO_F1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_F0),
+       EXYNOS4_GPIO_F2_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_F1),
+       EXYNOS4_GPIO_F3_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_F2),
+       EXYNOS4_GPIO_J0_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_F3),
+       EXYNOS4_GPIO_J1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_J0),
+       EXYNOS4_GPIO_K0_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_J1),
+       EXYNOS4_GPIO_K1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_K0),
+       EXYNOS4_GPIO_K2_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_K1),
+       EXYNOS4_GPIO_K3_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_K2),
+       EXYNOS4_GPIO_L0_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_K3),
+       EXYNOS4_GPIO_L1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_L0),
+       EXYNOS4_GPIO_L2_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_L1),
+       EXYNOS4_GPIO_X0_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_L2),
+       EXYNOS4_GPIO_X1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_X0),
+       EXYNOS4_GPIO_X2_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_X1),
+       EXYNOS4_GPIO_X3_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_X2),
+       EXYNOS4_GPIO_Y0_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_X3),
+       EXYNOS4_GPIO_Y1_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y0),
+       EXYNOS4_GPIO_Y2_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y1),
+       EXYNOS4_GPIO_Y3_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y2),
+       EXYNOS4_GPIO_Y4_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y3),
+       EXYNOS4_GPIO_Y5_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y4),
+       EXYNOS4_GPIO_Y6_START   = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y5),
+       EXYNOS4_GPIO_Z_START    = EXYNOS_GPIO_NEXT(EXYNOS4_GPIO_Y6),
 };
 
 /* EXYNOS4 GPIO number definitions */
+
 #define EXYNOS4_GPA0(_nr)      (EXYNOS4_GPIO_A0_START + (_nr))
 #define EXYNOS4_GPA1(_nr)      (EXYNOS4_GPIO_A1_START + (_nr))
 #define EXYNOS4_GPB(_nr)       (EXYNOS4_GPIO_B_START + (_nr))
@@ -139,11 +140,147 @@ enum s5p_gpio_number {
 #define EXYNOS4_GPZ(_nr)       (EXYNOS4_GPIO_Z_START + (_nr))
 
 /* the end of the EXYNOS4 specific gpios */
+
 #define EXYNOS4_GPIO_END       (EXYNOS4_GPZ(EXYNOS4_GPIO_Z_NR) + 1)
-#define S3C_GPIO_END           EXYNOS4_GPIO_END
 
-/* define the number of gpios we need to the one after the GPZ() range */
-#define ARCH_NR_GPIOS          (EXYNOS4_GPZ(EXYNOS4_GPIO_Z_NR) +       \
-                                CONFIG_SAMSUNG_GPIO_EXTRA + 1)
+/* EXYNOS5 GPIO bank sizes */
+
+#define EXYNOS5_GPIO_A0_NR     (8)
+#define EXYNOS5_GPIO_A1_NR     (6)
+#define EXYNOS5_GPIO_A2_NR     (8)
+#define EXYNOS5_GPIO_B0_NR     (5)
+#define EXYNOS5_GPIO_B1_NR     (5)
+#define EXYNOS5_GPIO_B2_NR     (4)
+#define EXYNOS5_GPIO_B3_NR     (4)
+#define EXYNOS5_GPIO_C0_NR     (7)
+#define EXYNOS5_GPIO_C1_NR     (7)
+#define EXYNOS5_GPIO_C2_NR     (7)
+#define EXYNOS5_GPIO_C3_NR     (7)
+#define EXYNOS5_GPIO_D0_NR     (8)
+#define EXYNOS5_GPIO_D1_NR     (8)
+#define EXYNOS5_GPIO_Y0_NR     (6)
+#define EXYNOS5_GPIO_Y1_NR     (4)
+#define EXYNOS5_GPIO_Y2_NR     (6)
+#define EXYNOS5_GPIO_Y3_NR     (8)
+#define EXYNOS5_GPIO_Y4_NR     (8)
+#define EXYNOS5_GPIO_Y5_NR     (8)
+#define EXYNOS5_GPIO_Y6_NR     (8)
+#define EXYNOS5_GPIO_X0_NR     (8)
+#define EXYNOS5_GPIO_X1_NR     (8)
+#define EXYNOS5_GPIO_X2_NR     (8)
+#define EXYNOS5_GPIO_X3_NR     (8)
+#define EXYNOS5_GPIO_E0_NR     (8)
+#define EXYNOS5_GPIO_E1_NR     (2)
+#define EXYNOS5_GPIO_F0_NR     (4)
+#define EXYNOS5_GPIO_F1_NR     (4)
+#define EXYNOS5_GPIO_G0_NR     (8)
+#define EXYNOS5_GPIO_G1_NR     (8)
+#define EXYNOS5_GPIO_G2_NR     (2)
+#define EXYNOS5_GPIO_H0_NR     (4)
+#define EXYNOS5_GPIO_H1_NR     (8)
+#define EXYNOS5_GPIO_V0_NR     (8)
+#define EXYNOS5_GPIO_V1_NR     (8)
+#define EXYNOS5_GPIO_V2_NR     (8)
+#define EXYNOS5_GPIO_V3_NR     (8)
+#define EXYNOS5_GPIO_V4_NR     (2)
+#define EXYNOS5_GPIO_Z_NR      (7)
+
+/* EXYNOS5 GPIO bank numbers */
+
+enum exynos5_gpio_number {
+       EXYNOS5_GPIO_A0_START           = 0,
+       EXYNOS5_GPIO_A1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_A0),
+       EXYNOS5_GPIO_A2_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_A1),
+       EXYNOS5_GPIO_B0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_A2),
+       EXYNOS5_GPIO_B1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_B0),
+       EXYNOS5_GPIO_B2_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_B1),
+       EXYNOS5_GPIO_B3_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_B2),
+       EXYNOS5_GPIO_C0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_B3),
+       EXYNOS5_GPIO_C1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C0),
+       EXYNOS5_GPIO_C2_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C1),
+       EXYNOS5_GPIO_C3_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C2),
+       EXYNOS5_GPIO_D0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C3),
+       EXYNOS5_GPIO_D1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_D0),
+       EXYNOS5_GPIO_Y0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_D1),
+       EXYNOS5_GPIO_Y1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y0),
+       EXYNOS5_GPIO_Y2_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y1),
+       EXYNOS5_GPIO_Y3_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y2),
+       EXYNOS5_GPIO_Y4_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y3),
+       EXYNOS5_GPIO_Y5_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y4),
+       EXYNOS5_GPIO_Y6_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y5),
+       EXYNOS5_GPIO_X0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y6),
+       EXYNOS5_GPIO_X1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X0),
+       EXYNOS5_GPIO_X2_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X1),
+       EXYNOS5_GPIO_X3_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X2),
+       EXYNOS5_GPIO_E0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X3),
+       EXYNOS5_GPIO_E1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_E0),
+       EXYNOS5_GPIO_F0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_E1),
+       EXYNOS5_GPIO_F1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_F0),
+       EXYNOS5_GPIO_G0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_F1),
+       EXYNOS5_GPIO_G1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_G0),
+       EXYNOS5_GPIO_G2_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_G1),
+       EXYNOS5_GPIO_H0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_G2),
+       EXYNOS5_GPIO_H1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_H0),
+       EXYNOS5_GPIO_V0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_H1),
+       EXYNOS5_GPIO_V1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_V0),
+       EXYNOS5_GPIO_V2_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_V1),
+       EXYNOS5_GPIO_V3_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_V2),
+       EXYNOS5_GPIO_V4_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_V3),
+       EXYNOS5_GPIO_Z_START            = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_V4),
+};
+
+/* EXYNOS5 GPIO number definitions */
+
+#define EXYNOS5_GPA0(_nr)      (EXYNOS5_GPIO_A0_START + (_nr))
+#define EXYNOS5_GPA1(_nr)      (EXYNOS5_GPIO_A1_START + (_nr))
+#define EXYNOS5_GPA2(_nr)      (EXYNOS5_GPIO_A2_START + (_nr))
+#define EXYNOS5_GPB0(_nr)      (EXYNOS5_GPIO_B0_START + (_nr))
+#define EXYNOS5_GPB1(_nr)      (EXYNOS5_GPIO_B1_START + (_nr))
+#define EXYNOS5_GPB2(_nr)      (EXYNOS5_GPIO_B2_START + (_nr))
+#define EXYNOS5_GPB3(_nr)      (EXYNOS5_GPIO_B3_START + (_nr))
+#define EXYNOS5_GPC0(_nr)      (EXYNOS5_GPIO_C0_START + (_nr))
+#define EXYNOS5_GPC1(_nr)      (EXYNOS5_GPIO_C1_START + (_nr))
+#define EXYNOS5_GPC2(_nr)      (EXYNOS5_GPIO_C2_START + (_nr))
+#define EXYNOS5_GPC3(_nr)      (EXYNOS5_GPIO_C3_START + (_nr))
+#define EXYNOS5_GPD0(_nr)      (EXYNOS5_GPIO_D0_START + (_nr))
+#define EXYNOS5_GPD1(_nr)      (EXYNOS5_GPIO_D1_START + (_nr))
+#define EXYNOS5_GPY0(_nr)      (EXYNOS5_GPIO_Y0_START + (_nr))
+#define EXYNOS5_GPY1(_nr)      (EXYNOS5_GPIO_Y1_START + (_nr))
+#define EXYNOS5_GPY2(_nr)      (EXYNOS5_GPIO_Y2_START + (_nr))
+#define EXYNOS5_GPY3(_nr)      (EXYNOS5_GPIO_Y3_START + (_nr))
+#define EXYNOS5_GPY4(_nr)      (EXYNOS5_GPIO_Y4_START + (_nr))
+#define EXYNOS5_GPY5(_nr)      (EXYNOS5_GPIO_Y5_START + (_nr))
+#define EXYNOS5_GPY6(_nr)      (EXYNOS5_GPIO_Y6_START + (_nr))
+#define EXYNOS5_GPX0(_nr)      (EXYNOS5_GPIO_X0_START + (_nr))
+#define EXYNOS5_GPX1(_nr)      (EXYNOS5_GPIO_X1_START + (_nr))
+#define EXYNOS5_GPX2(_nr)      (EXYNOS5_GPIO_X2_START + (_nr))
+#define EXYNOS5_GPX3(_nr)      (EXYNOS5_GPIO_X3_START + (_nr))
+#define EXYNOS5_GPE0(_nr)      (EXYNOS5_GPIO_E0_START + (_nr))
+#define EXYNOS5_GPE1(_nr)      (EXYNOS5_GPIO_E1_START + (_nr))
+#define EXYNOS5_GPF0(_nr)      (EXYNOS5_GPIO_F0_START + (_nr))
+#define EXYNOS5_GPF1(_nr)      (EXYNOS5_GPIO_F1_START + (_nr))
+#define EXYNOS5_GPG0(_nr)      (EXYNOS5_GPIO_G0_START + (_nr))
+#define EXYNOS5_GPG1(_nr)      (EXYNOS5_GPIO_G1_START + (_nr))
+#define EXYNOS5_GPG2(_nr)      (EXYNOS5_GPIO_G2_START + (_nr))
+#define EXYNOS5_GPH0(_nr)      (EXYNOS5_GPIO_H0_START + (_nr))
+#define EXYNOS5_GPH1(_nr)      (EXYNOS5_GPIO_H1_START + (_nr))
+#define EXYNOS5_GPV0(_nr)      (EXYNOS5_GPIO_V0_START + (_nr))
+#define EXYNOS5_GPV1(_nr)      (EXYNOS5_GPIO_V1_START + (_nr))
+#define EXYNOS5_GPV2(_nr)      (EXYNOS5_GPIO_V2_START + (_nr))
+#define EXYNOS5_GPV3(_nr)      (EXYNOS5_GPIO_V3_START + (_nr))
+#define EXYNOS5_GPV4(_nr)      (EXYNOS5_GPIO_V4_START + (_nr))
+#define EXYNOS5_GPZ(_nr)       (EXYNOS5_GPIO_Z_START + (_nr))
+
+/* the end of the EXYNOS5 specific gpios */
+
+#define EXYNOS5_GPIO_END       (EXYNOS5_GPZ(EXYNOS5_GPIO_Z_NR) + 1)
+
+/* actually, EXYNOS5_GPIO_END is bigger than EXYNOS4 */
+
+#define S3C_GPIO_END           (EXYNOS5_GPIO_END)
+
+/* define the number of gpios */
+
+#define ARCH_NR_GPIOS          (CONFIG_SAMSUNG_GPIO_EXTRA + S3C_GPIO_END)
 
 #endif /* __ASM_ARCH_GPIO_H */
index f77bce0..9bee853 100644 (file)
@@ -1,9 +1,8 @@
-/* linux/arch/arm/mach-exynos4/include/mach/irqs.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
- * EXYNOS4 - IRQ definitions
+ * EXYNOS - IRQ definitions
  *
  * 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
 
 /* PPI: Private Peripheral Interrupt */
 
-#define IRQ_PPI(x)             (x+16)
-
-#define IRQ_MCT_LOCALTIMER     IRQ_PPI(12)
+#define IRQ_PPI(x)                     (x + 16)
 
 /* SPI: Shared Peripheral Interrupt */
 
-#define IRQ_SPI(x)             (x+32)
-
-#define IRQ_EINT0              IRQ_SPI(16)
-#define IRQ_EINT1              IRQ_SPI(17)
-#define IRQ_EINT2              IRQ_SPI(18)
-#define IRQ_EINT3              IRQ_SPI(19)
-#define IRQ_EINT4              IRQ_SPI(20)
-#define IRQ_EINT5              IRQ_SPI(21)
-#define IRQ_EINT6              IRQ_SPI(22)
-#define IRQ_EINT7              IRQ_SPI(23)
-#define IRQ_EINT8              IRQ_SPI(24)
-#define IRQ_EINT9              IRQ_SPI(25)
-#define IRQ_EINT10             IRQ_SPI(26)
-#define IRQ_EINT11             IRQ_SPI(27)
-#define IRQ_EINT12             IRQ_SPI(28)
-#define IRQ_EINT13             IRQ_SPI(29)
-#define IRQ_EINT14             IRQ_SPI(30)
-#define IRQ_EINT15             IRQ_SPI(31)
-#define IRQ_EINT16_31          IRQ_SPI(32)
-
-#define IRQ_PDMA0              IRQ_SPI(35)
-#define IRQ_PDMA1              IRQ_SPI(36)
-#define IRQ_TIMER0_VIC         IRQ_SPI(37)
-#define IRQ_TIMER1_VIC         IRQ_SPI(38)
-#define IRQ_TIMER2_VIC         IRQ_SPI(39)
-#define IRQ_TIMER3_VIC         IRQ_SPI(40)
-#define IRQ_TIMER4_VIC         IRQ_SPI(41)
-#define IRQ_MCT_L0             IRQ_SPI(42)
-#define IRQ_WDT                        IRQ_SPI(43)
-#define IRQ_RTC_ALARM          IRQ_SPI(44)
-#define IRQ_RTC_TIC            IRQ_SPI(45)
-#define IRQ_GPIO_XB            IRQ_SPI(46)
-#define IRQ_GPIO_XA            IRQ_SPI(47)
-#define IRQ_MCT_L1             IRQ_SPI(48)
-
-#define IRQ_UART0              IRQ_SPI(52)
-#define IRQ_UART1              IRQ_SPI(53)
-#define IRQ_UART2              IRQ_SPI(54)
-#define IRQ_UART3              IRQ_SPI(55)
-#define IRQ_UART4              IRQ_SPI(56)
-#define IRQ_MCT_G0             IRQ_SPI(57)
-#define IRQ_IIC                        IRQ_SPI(58)
-#define IRQ_IIC1               IRQ_SPI(59)
-#define IRQ_IIC2               IRQ_SPI(60)
-#define IRQ_IIC3               IRQ_SPI(61)
-#define IRQ_IIC4               IRQ_SPI(62)
-#define IRQ_IIC5               IRQ_SPI(63)
-#define IRQ_IIC6               IRQ_SPI(64)
-#define IRQ_IIC7               IRQ_SPI(65)
-#define IRQ_SPI0               IRQ_SPI(66)
-#define IRQ_SPI1               IRQ_SPI(67)
-#define IRQ_SPI2               IRQ_SPI(68)
-
-#define IRQ_USB_HOST           IRQ_SPI(70)
-#define IRQ_USB_HSOTG          IRQ_SPI(71)
-#define IRQ_MODEM_IF           IRQ_SPI(72)
-#define IRQ_HSMMC0             IRQ_SPI(73)
-#define IRQ_HSMMC1             IRQ_SPI(74)
-#define IRQ_HSMMC2             IRQ_SPI(75)
-#define IRQ_HSMMC3             IRQ_SPI(76)
-#define IRQ_DWMCI              IRQ_SPI(77)
-
-#define IRQ_MIPI_CSIS0         IRQ_SPI(78)
-#define IRQ_MIPI_CSIS1         IRQ_SPI(80)
-
-#define IRQ_ONENAND_AUDI       IRQ_SPI(82)
-#define IRQ_ROTATOR            IRQ_SPI(83)
-#define IRQ_FIMC0              IRQ_SPI(84)
-#define IRQ_FIMC1              IRQ_SPI(85)
-#define IRQ_FIMC2              IRQ_SPI(86)
-#define IRQ_FIMC3              IRQ_SPI(87)
-#define IRQ_JPEG               IRQ_SPI(88)
-#define IRQ_2D                 IRQ_SPI(89)
-#define IRQ_PCIE               IRQ_SPI(90)
-
-#define IRQ_MIXER              IRQ_SPI(91)
-#define IRQ_HDMI               IRQ_SPI(92)
-#define IRQ_IIC_HDMIPHY                IRQ_SPI(93)
-#define IRQ_MFC                        IRQ_SPI(94)
-#define IRQ_SDO                        IRQ_SPI(95)
-
-#define IRQ_AUDIO_SS           IRQ_SPI(96)
-#define IRQ_I2S0               IRQ_SPI(97)
-#define IRQ_I2S1               IRQ_SPI(98)
-#define IRQ_I2S2               IRQ_SPI(99)
-#define IRQ_AC97               IRQ_SPI(100)
-
-#define IRQ_SPDIF              IRQ_SPI(104)
-#define IRQ_ADC0               IRQ_SPI(105)
-#define IRQ_PEN0               IRQ_SPI(106)
-#define IRQ_ADC1               IRQ_SPI(107)
-#define IRQ_PEN1               IRQ_SPI(108)
-#define IRQ_KEYPAD             IRQ_SPI(109)
-#define IRQ_PMU                        IRQ_SPI(110)
-#define IRQ_GPS                        IRQ_SPI(111)
-#define IRQ_INTFEEDCTRL_SSS    IRQ_SPI(112)
-#define IRQ_SLIMBUS            IRQ_SPI(113)
-
-#define IRQ_TSI                        IRQ_SPI(115)
-#define IRQ_SATA               IRQ_SPI(116)
-
-#define MAX_IRQ_IN_COMBINER    8
-#define COMBINER_GROUP(x)      ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(128))
-#define COMBINER_IRQ(x, y)     (COMBINER_GROUP(x) + y)
-
-#define IRQ_SYSMMU_MDMA0_0     COMBINER_IRQ(4, 0)
-#define IRQ_SYSMMU_SSS_0       COMBINER_IRQ(4, 1)
-#define IRQ_SYSMMU_FIMC0_0     COMBINER_IRQ(4, 2)
-#define IRQ_SYSMMU_FIMC1_0     COMBINER_IRQ(4, 3)
-#define IRQ_SYSMMU_FIMC2_0     COMBINER_IRQ(4, 4)
-#define IRQ_SYSMMU_FIMC3_0     COMBINER_IRQ(4, 5)
-#define IRQ_SYSMMU_JPEG_0      COMBINER_IRQ(4, 6)
-#define IRQ_SYSMMU_2D_0                COMBINER_IRQ(4, 7)
-
-#define IRQ_SYSMMU_ROTATOR_0   COMBINER_IRQ(5, 0)
-#define IRQ_SYSMMU_MDMA1_0     COMBINER_IRQ(5, 1)
-#define IRQ_SYSMMU_LCD0_M0_0   COMBINER_IRQ(5, 2)
-#define IRQ_SYSMMU_LCD1_M1_0   COMBINER_IRQ(5, 3)
-#define IRQ_SYSMMU_TV_M0_0     COMBINER_IRQ(5, 4)
-#define IRQ_SYSMMU_MFC_M0_0    COMBINER_IRQ(5, 5)
-#define IRQ_SYSMMU_MFC_M1_0    COMBINER_IRQ(5, 6)
-#define IRQ_SYSMMU_PCIE_0      COMBINER_IRQ(5, 7)
-
-#define IRQ_FIMD0_FIFO         COMBINER_IRQ(11, 0)
-#define IRQ_FIMD0_VSYNC                COMBINER_IRQ(11, 1)
-#define IRQ_FIMD0_SYSTEM       COMBINER_IRQ(11, 2)
-
-#define MAX_COMBINER_NR                16
-
-#define IRQ_ADC                        IRQ_ADC0
-#define IRQ_TC                 IRQ_PEN0
-
-#define S5P_IRQ_EINT_BASE      COMBINER_IRQ(MAX_COMBINER_NR, 0)
-
-#define S5P_EINT_BASE1         (S5P_IRQ_EINT_BASE + 0)
-#define S5P_EINT_BASE2         (S5P_IRQ_EINT_BASE + 16)
-
-/* optional GPIO interrupts */
-#define S5P_GPIOINT_BASE       (S5P_IRQ_EINT_BASE + 32)
-#define IRQ_GPIO1_NR_GROUPS    16
-#define IRQ_GPIO2_NR_GROUPS    9
-#define IRQ_GPIO_END           (S5P_GPIOINT_BASE + S5P_GPIOINT_COUNT)
-
-#define IRQ_TIMER_BASE         (IRQ_GPIO_END + 64)
+#define IRQ_SPI(x)                     (x + 32)
+
+/* COMBINER */
+
+#define MAX_IRQ_IN_COMBINER            8
+#define COMBINER_GROUP(x)              ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(128))
+#define COMBINER_IRQ(x, y)             (COMBINER_GROUP(x) + y)
+
+/* For EXYNOS4 and EXYNOS5 */
+
+#define EXYNOS_IRQ_MCT_LOCALTIMER      IRQ_PPI(12)
+
+#define EXYNOS_IRQ_EINT16_31           IRQ_SPI(32)
+
+/* For EXYNOS4 SoCs */
+
+#define EXYNOS4_IRQ_EINT0              IRQ_SPI(16)
+#define EXYNOS4_IRQ_EINT1              IRQ_SPI(17)
+#define EXYNOS4_IRQ_EINT2              IRQ_SPI(18)
+#define EXYNOS4_IRQ_EINT3              IRQ_SPI(19)
+#define EXYNOS4_IRQ_EINT4              IRQ_SPI(20)
+#define EXYNOS4_IRQ_EINT5              IRQ_SPI(21)
+#define EXYNOS4_IRQ_EINT6              IRQ_SPI(22)
+#define EXYNOS4_IRQ_EINT7              IRQ_SPI(23)
+#define EXYNOS4_IRQ_EINT8              IRQ_SPI(24)
+#define EXYNOS4_IRQ_EINT9              IRQ_SPI(25)
+#define EXYNOS4_IRQ_EINT10             IRQ_SPI(26)
+#define EXYNOS4_IRQ_EINT11             IRQ_SPI(27)
+#define EXYNOS4_IRQ_EINT12             IRQ_SPI(28)
+#define EXYNOS4_IRQ_EINT13             IRQ_SPI(29)
+#define EXYNOS4_IRQ_EINT14             IRQ_SPI(30)
+#define EXYNOS4_IRQ_EINT15             IRQ_SPI(31)
+
+#define EXYNOS4_IRQ_MDMA0              IRQ_SPI(33)
+#define EXYNOS4_IRQ_MDMA1              IRQ_SPI(34)
+#define EXYNOS4_IRQ_PDMA0              IRQ_SPI(35)
+#define EXYNOS4_IRQ_PDMA1              IRQ_SPI(36)
+#define EXYNOS4_IRQ_TIMER0_VIC         IRQ_SPI(37)
+#define EXYNOS4_IRQ_TIMER1_VIC         IRQ_SPI(38)
+#define EXYNOS4_IRQ_TIMER2_VIC         IRQ_SPI(39)
+#define EXYNOS4_IRQ_TIMER3_VIC         IRQ_SPI(40)
+#define EXYNOS4_IRQ_TIMER4_VIC         IRQ_SPI(41)
+#define EXYNOS4_IRQ_MCT_L0             IRQ_SPI(42)
+#define EXYNOS4_IRQ_WDT                        IRQ_SPI(43)
+#define EXYNOS4_IRQ_RTC_ALARM          IRQ_SPI(44)
+#define EXYNOS4_IRQ_RTC_TIC            IRQ_SPI(45)
+#define EXYNOS4_IRQ_GPIO_XB            IRQ_SPI(46)
+#define EXYNOS4_IRQ_GPIO_XA            IRQ_SPI(47)
+#define EXYNOS4_IRQ_MCT_L1             IRQ_SPI(48)
+
+#define EXYNOS4_IRQ_UART0              IRQ_SPI(52)
+#define EXYNOS4_IRQ_UART1              IRQ_SPI(53)
+#define EXYNOS4_IRQ_UART2              IRQ_SPI(54)
+#define EXYNOS4_IRQ_UART3              IRQ_SPI(55)
+#define EXYNOS4_IRQ_UART4              IRQ_SPI(56)
+#define EXYNOS4_IRQ_MCT_G0             IRQ_SPI(57)
+#define EXYNOS4_IRQ_IIC                        IRQ_SPI(58)
+#define EXYNOS4_IRQ_IIC1               IRQ_SPI(59)
+#define EXYNOS4_IRQ_IIC2               IRQ_SPI(60)
+#define EXYNOS4_IRQ_IIC3               IRQ_SPI(61)
+#define EXYNOS4_IRQ_IIC4               IRQ_SPI(62)
+#define EXYNOS4_IRQ_IIC5               IRQ_SPI(63)
+#define EXYNOS4_IRQ_IIC6               IRQ_SPI(64)
+#define EXYNOS4_IRQ_IIC7               IRQ_SPI(65)
+#define EXYNOS4_IRQ_SPI0               IRQ_SPI(66)
+#define EXYNOS4_IRQ_SPI1               IRQ_SPI(67)
+#define EXYNOS4_IRQ_SPI2               IRQ_SPI(68)
+
+#define EXYNOS4_IRQ_USB_HOST           IRQ_SPI(70)
+#define EXYNOS4_IRQ_USB_HSOTG          IRQ_SPI(71)
+#define EXYNOS4_IRQ_MODEM_IF           IRQ_SPI(72)
+#define EXYNOS4_IRQ_HSMMC0             IRQ_SPI(73)
+#define EXYNOS4_IRQ_HSMMC1             IRQ_SPI(74)
+#define EXYNOS4_IRQ_HSMMC2             IRQ_SPI(75)
+#define EXYNOS4_IRQ_HSMMC3             IRQ_SPI(76)
+#define EXYNOS4_IRQ_DWMCI              IRQ_SPI(77)
+
+#define EXYNOS4_IRQ_MIPI_CSIS0         IRQ_SPI(78)
+#define EXYNOS4_IRQ_MIPI_CSIS1         IRQ_SPI(80)
+
+#define EXYNOS4_IRQ_ONENAND_AUDI       IRQ_SPI(82)
+#define EXYNOS4_IRQ_ROTATOR            IRQ_SPI(83)
+#define EXYNOS4_IRQ_FIMC0              IRQ_SPI(84)
+#define EXYNOS4_IRQ_FIMC1              IRQ_SPI(85)
+#define EXYNOS4_IRQ_FIMC2              IRQ_SPI(86)
+#define EXYNOS4_IRQ_FIMC3              IRQ_SPI(87)
+#define EXYNOS4_IRQ_JPEG               IRQ_SPI(88)
+#define EXYNOS4_IRQ_2D                 IRQ_SPI(89)
+#define EXYNOS4_IRQ_PCIE               IRQ_SPI(90)
+
+#define EXYNOS4_IRQ_MIXER              IRQ_SPI(91)
+#define EXYNOS4_IRQ_HDMI               IRQ_SPI(92)
+#define EXYNOS4_IRQ_IIC_HDMIPHY                IRQ_SPI(93)
+#define EXYNOS4_IRQ_MFC                        IRQ_SPI(94)
+#define EXYNOS4_IRQ_SDO                        IRQ_SPI(95)
+
+#define EXYNOS4_IRQ_AUDIO_SS           IRQ_SPI(96)
+#define EXYNOS4_IRQ_I2S0               IRQ_SPI(97)
+#define EXYNOS4_IRQ_I2S1               IRQ_SPI(98)
+#define EXYNOS4_IRQ_I2S2               IRQ_SPI(99)
+#define EXYNOS4_IRQ_AC97               IRQ_SPI(100)
+
+#define EXYNOS4_IRQ_SPDIF              IRQ_SPI(104)
+#define EXYNOS4_IRQ_ADC0               IRQ_SPI(105)
+#define EXYNOS4_IRQ_PEN0               IRQ_SPI(106)
+#define EXYNOS4_IRQ_ADC1               IRQ_SPI(107)
+#define EXYNOS4_IRQ_PEN1               IRQ_SPI(108)
+#define EXYNOS4_IRQ_KEYPAD             IRQ_SPI(109)
+#define EXYNOS4_IRQ_PMU                        IRQ_SPI(110)
+#define EXYNOS4_IRQ_GPS                        IRQ_SPI(111)
+#define EXYNOS4_IRQ_INTFEEDCTRL_SSS    IRQ_SPI(112)
+#define EXYNOS4_IRQ_SLIMBUS            IRQ_SPI(113)
+
+#define EXYNOS4_IRQ_TSI                        IRQ_SPI(115)
+#define EXYNOS4_IRQ_SATA               IRQ_SPI(116)
+
+#define EXYNOS4_IRQ_SYSMMU_MDMA0_0     COMBINER_IRQ(4, 0)
+#define EXYNOS4_IRQ_SYSMMU_SSS_0       COMBINER_IRQ(4, 1)
+#define EXYNOS4_IRQ_SYSMMU_FIMC0_0     COMBINER_IRQ(4, 2)
+#define EXYNOS4_IRQ_SYSMMU_FIMC1_0     COMBINER_IRQ(4, 3)
+#define EXYNOS4_IRQ_SYSMMU_FIMC2_0     COMBINER_IRQ(4, 4)
+#define EXYNOS4_IRQ_SYSMMU_FIMC3_0     COMBINER_IRQ(4, 5)
+#define EXYNOS4_IRQ_SYSMMU_JPEG_0      COMBINER_IRQ(4, 6)
+#define EXYNOS4_IRQ_SYSMMU_2D_0                COMBINER_IRQ(4, 7)
+
+#define EXYNOS4_IRQ_SYSMMU_ROTATOR_0   COMBINER_IRQ(5, 0)
+#define EXYNOS4_IRQ_SYSMMU_MDMA1_0     COMBINER_IRQ(5, 1)
+#define EXYNOS4_IRQ_SYSMMU_LCD0_M0_0   COMBINER_IRQ(5, 2)
+#define EXYNOS4_IRQ_SYSMMU_LCD1_M1_0   COMBINER_IRQ(5, 3)
+#define EXYNOS4_IRQ_SYSMMU_TV_M0_0     COMBINER_IRQ(5, 4)
+#define EXYNOS4_IRQ_SYSMMU_MFC_M0_0    COMBINER_IRQ(5, 5)
+#define EXYNOS4_IRQ_SYSMMU_MFC_M1_0    COMBINER_IRQ(5, 6)
+#define EXYNOS4_IRQ_SYSMMU_PCIE_0      COMBINER_IRQ(5, 7)
+
+#define EXYNOS4_IRQ_FIMD0_FIFO         COMBINER_IRQ(11, 0)
+#define EXYNOS4_IRQ_FIMD0_VSYNC                COMBINER_IRQ(11, 1)
+#define EXYNOS4_IRQ_FIMD0_SYSTEM       COMBINER_IRQ(11, 2)
+
+#define EXYNOS4_MAX_COMBINER_NR                16
+
+#define EXYNOS4_IRQ_GPIO1_NR_GROUPS    16
+#define EXYNOS4_IRQ_GPIO2_NR_GROUPS    9
+
+/*
+ * For Compatibility:
+ * the default is for EXYNOS4, and
+ * for exynos5, should be re-mapped at function
+ */
+
+#define IRQ_TIMER0_VIC                 EXYNOS4_IRQ_TIMER0_VIC
+#define IRQ_TIMER1_VIC                 EXYNOS4_IRQ_TIMER1_VIC
+#define IRQ_TIMER2_VIC                 EXYNOS4_IRQ_TIMER2_VIC
+#define IRQ_TIMER3_VIC                 EXYNOS4_IRQ_TIMER3_VIC
+#define IRQ_TIMER4_VIC                 EXYNOS4_IRQ_TIMER4_VIC
+
+#define IRQ_WDT                                EXYNOS4_IRQ_WDT
+#define IRQ_RTC_ALARM                  EXYNOS4_IRQ_RTC_ALARM
+#define IRQ_RTC_TIC                    EXYNOS4_IRQ_RTC_TIC
+#define IRQ_GPIO_XB                    EXYNOS4_IRQ_GPIO_XB
+#define IRQ_GPIO_XA                    EXYNOS4_IRQ_GPIO_XA
+
+#define IRQ_IIC                                EXYNOS4_IRQ_IIC
+#define IRQ_IIC1                       EXYNOS4_IRQ_IIC1
+#define IRQ_IIC3                       EXYNOS4_IRQ_IIC3
+#define IRQ_IIC5                       EXYNOS4_IRQ_IIC5
+#define IRQ_IIC6                       EXYNOS4_IRQ_IIC6
+#define IRQ_IIC7                       EXYNOS4_IRQ_IIC7
+
+#define IRQ_USB_HOST                   EXYNOS4_IRQ_USB_HOST
+
+#define IRQ_HSMMC0                     EXYNOS4_IRQ_HSMMC0
+#define IRQ_HSMMC1                     EXYNOS4_IRQ_HSMMC1
+#define IRQ_HSMMC2                     EXYNOS4_IRQ_HSMMC2
+#define IRQ_HSMMC3                     EXYNOS4_IRQ_HSMMC3
+
+#define IRQ_MIPI_CSIS0                 EXYNOS4_IRQ_MIPI_CSIS0
+
+#define IRQ_ONENAND_AUDI               EXYNOS4_IRQ_ONENAND_AUDI
+
+#define IRQ_FIMC0                      EXYNOS4_IRQ_FIMC0
+#define IRQ_FIMC1                      EXYNOS4_IRQ_FIMC1
+#define IRQ_FIMC2                      EXYNOS4_IRQ_FIMC2
+#define IRQ_FIMC3                      EXYNOS4_IRQ_FIMC3
+#define IRQ_JPEG                       EXYNOS4_IRQ_JPEG
+#define IRQ_2D                         EXYNOS4_IRQ_2D
+
+#define IRQ_MIXER                      EXYNOS4_IRQ_MIXER
+#define IRQ_HDMI                       EXYNOS4_IRQ_HDMI
+#define IRQ_IIC_HDMIPHY                        EXYNOS4_IRQ_IIC_HDMIPHY
+#define IRQ_MFC                                EXYNOS4_IRQ_MFC
+#define IRQ_SDO                                EXYNOS4_IRQ_SDO
+
+#define IRQ_ADC                                EXYNOS4_IRQ_ADC0
+#define IRQ_TC                         EXYNOS4_IRQ_PEN0
+
+#define IRQ_KEYPAD                     EXYNOS4_IRQ_KEYPAD
+#define IRQ_PMU                                EXYNOS4_IRQ_PMU
+
+#define IRQ_SYSMMU_MDMA0_0             EXYNOS4_IRQ_SYSMMU_MDMA0_0
+#define IRQ_SYSMMU_SSS_0                EXYNOS4_IRQ_SYSMMU_SSS_0
+#define IRQ_SYSMMU_FIMC0_0              EXYNOS4_IRQ_SYSMMU_FIMC0_0
+#define IRQ_SYSMMU_FIMC1_0              EXYNOS4_IRQ_SYSMMU_FIMC1_0
+#define IRQ_SYSMMU_FIMC2_0              EXYNOS4_IRQ_SYSMMU_FIMC2_0
+#define IRQ_SYSMMU_FIMC3_0              EXYNOS4_IRQ_SYSMMU_FIMC3_0
+#define IRQ_SYSMMU_JPEG_0               EXYNOS4_IRQ_SYSMMU_JPEG_0
+#define IRQ_SYSMMU_2D_0                 EXYNOS4_IRQ_SYSMMU_2D_0
+
+#define IRQ_SYSMMU_ROTATOR_0            EXYNOS4_IRQ_SYSMMU_ROTATOR_0
+#define IRQ_SYSMMU_MDMA1_0              EXYNOS4_IRQ_SYSMMU_MDMA1_0
+#define IRQ_SYSMMU_LCD0_M0_0            EXYNOS4_IRQ_SYSMMU_LCD0_M0_0
+#define IRQ_SYSMMU_LCD1_M1_0            EXYNOS4_IRQ_SYSMMU_LCD1_M1_0
+#define IRQ_SYSMMU_TV_M0_0              EXYNOS4_IRQ_SYSMMU_TV_M0_0
+#define IRQ_SYSMMU_MFC_M0_0             EXYNOS4_IRQ_SYSMMU_MFC_M0_0
+#define IRQ_SYSMMU_MFC_M1_0             EXYNOS4_IRQ_SYSMMU_MFC_M1_0
+#define IRQ_SYSMMU_PCIE_0               EXYNOS4_IRQ_SYSMMU_PCIE_0
+
+#define IRQ_FIMD0_FIFO                 EXYNOS4_IRQ_FIMD0_FIFO
+#define IRQ_FIMD0_VSYNC                        EXYNOS4_IRQ_FIMD0_VSYNC
+#define IRQ_FIMD0_SYSTEM               EXYNOS4_IRQ_FIMD0_SYSTEM
+
+#define IRQ_GPIO1_NR_GROUPS            EXYNOS4_IRQ_GPIO1_NR_GROUPS
+#define IRQ_GPIO2_NR_GROUPS            EXYNOS4_IRQ_GPIO2_NR_GROUPS
+
+/* For EXYNOS5 SoCs */
+
+#define EXYNOS5_IRQ_MDMA0              IRQ_SPI(33)
+#define EXYNOS5_IRQ_PDMA0              IRQ_SPI(34)
+#define EXYNOS5_IRQ_PDMA1              IRQ_SPI(35)
+#define EXYNOS5_IRQ_TIMER0_VIC         IRQ_SPI(36)
+#define EXYNOS5_IRQ_TIMER1_VIC         IRQ_SPI(37)
+#define EXYNOS5_IRQ_TIMER2_VIC         IRQ_SPI(38)
+#define EXYNOS5_IRQ_TIMER3_VIC         IRQ_SPI(39)
+#define EXYNOS5_IRQ_TIMER4_VIC         IRQ_SPI(40)
+#define EXYNOS5_IRQ_RTIC               IRQ_SPI(41)
+#define EXYNOS5_IRQ_WDT                        IRQ_SPI(42)
+#define EXYNOS5_IRQ_RTC_ALARM          IRQ_SPI(43)
+#define EXYNOS5_IRQ_RTC_TIC            IRQ_SPI(44)
+#define EXYNOS5_IRQ_GPIO_XB            IRQ_SPI(45)
+#define EXYNOS5_IRQ_GPIO_XA            IRQ_SPI(46)
+#define EXYNOS5_IRQ_GPIO               IRQ_SPI(47)
+#define EXYNOS5_IRQ_IEM_IEC            IRQ_SPI(48)
+#define EXYNOS5_IRQ_IEM_APC            IRQ_SPI(49)
+#define EXYNOS5_IRQ_GPIO_C2C           IRQ_SPI(50)
+#define EXYNOS5_IRQ_UART0              IRQ_SPI(51)
+#define EXYNOS5_IRQ_UART1              IRQ_SPI(52)
+#define EXYNOS5_IRQ_UART2              IRQ_SPI(53)
+#define EXYNOS5_IRQ_UART3              IRQ_SPI(54)
+#define EXYNOS5_IRQ_UART4              IRQ_SPI(55)
+#define EXYNOS5_IRQ_IIC                        IRQ_SPI(56)
+#define EXYNOS5_IRQ_IIC1               IRQ_SPI(57)
+#define EXYNOS5_IRQ_IIC2               IRQ_SPI(58)
+#define EXYNOS5_IRQ_IIC3               IRQ_SPI(59)
+#define EXYNOS5_IRQ_IIC4               IRQ_SPI(60)
+#define EXYNOS5_IRQ_IIC5               IRQ_SPI(61)
+#define EXYNOS5_IRQ_IIC6               IRQ_SPI(62)
+#define EXYNOS5_IRQ_IIC7               IRQ_SPI(63)
+#define EXYNOS5_IRQ_IIC_HDMIPHY                IRQ_SPI(64)
+#define EXYNOS5_IRQ_TMU                        IRQ_SPI(65)
+#define EXYNOS5_IRQ_FIQ_0              IRQ_SPI(66)
+#define EXYNOS5_IRQ_FIQ_1              IRQ_SPI(67)
+#define EXYNOS5_IRQ_SPI0               IRQ_SPI(68)
+#define EXYNOS5_IRQ_SPI1               IRQ_SPI(69)
+#define EXYNOS5_IRQ_SPI2               IRQ_SPI(70)
+#define EXYNOS5_IRQ_USB_HOST           IRQ_SPI(71)
+#define EXYNOS5_IRQ_USB3_DRD           IRQ_SPI(72)
+#define EXYNOS5_IRQ_MIPI_HSI           IRQ_SPI(73)
+#define EXYNOS5_IRQ_USB_HSOTG          IRQ_SPI(74)
+#define EXYNOS5_IRQ_HSMMC0             IRQ_SPI(75)
+#define EXYNOS5_IRQ_HSMMC1             IRQ_SPI(76)
+#define EXYNOS5_IRQ_HSMMC2             IRQ_SPI(77)
+#define EXYNOS5_IRQ_HSMMC3             IRQ_SPI(78)
+#define EXYNOS5_IRQ_MIPICSI0           IRQ_SPI(79)
+#define EXYNOS5_IRQ_MIPICSI1           IRQ_SPI(80)
+#define EXYNOS5_IRQ_EFNFCON_DMA_ABORT  IRQ_SPI(81)
+#define EXYNOS5_IRQ_MIPIDSI0           IRQ_SPI(82)
+#define EXYNOS5_IRQ_ROTATOR            IRQ_SPI(84)
+#define EXYNOS5_IRQ_GSC0               IRQ_SPI(85)
+#define EXYNOS5_IRQ_GSC1               IRQ_SPI(86)
+#define EXYNOS5_IRQ_GSC2               IRQ_SPI(87)
+#define EXYNOS5_IRQ_GSC3               IRQ_SPI(88)
+#define EXYNOS5_IRQ_JPEG               IRQ_SPI(89)
+#define EXYNOS5_IRQ_EFNFCON_DMA                IRQ_SPI(90)
+#define EXYNOS5_IRQ_2D                 IRQ_SPI(91)
+#define EXYNOS5_IRQ_SFMC0              IRQ_SPI(92)
+#define EXYNOS5_IRQ_SFMC1              IRQ_SPI(93)
+#define EXYNOS5_IRQ_MIXER              IRQ_SPI(94)
+#define EXYNOS5_IRQ_HDMI               IRQ_SPI(95)
+#define EXYNOS5_IRQ_MFC                        IRQ_SPI(96)
+#define EXYNOS5_IRQ_AUDIO_SS           IRQ_SPI(97)
+#define EXYNOS5_IRQ_I2S0               IRQ_SPI(98)
+#define EXYNOS5_IRQ_I2S1               IRQ_SPI(99)
+#define EXYNOS5_IRQ_I2S2               IRQ_SPI(100)
+#define EXYNOS5_IRQ_AC97               IRQ_SPI(101)
+#define EXYNOS5_IRQ_PCM0               IRQ_SPI(102)
+#define EXYNOS5_IRQ_PCM1               IRQ_SPI(103)
+#define EXYNOS5_IRQ_PCM2               IRQ_SPI(104)
+#define EXYNOS5_IRQ_SPDIF              IRQ_SPI(105)
+#define EXYNOS5_IRQ_ADC0               IRQ_SPI(106)
+
+#define EXYNOS5_IRQ_SATA_PHY           IRQ_SPI(108)
+#define EXYNOS5_IRQ_SATA_PMEMREQ       IRQ_SPI(109)
+#define EXYNOS5_IRQ_CAM_C              IRQ_SPI(110)
+#define EXYNOS5_IRQ_EAGLE_PMU          IRQ_SPI(111)
+#define EXYNOS5_IRQ_INTFEEDCTRL_SSS    IRQ_SPI(112)
+#define EXYNOS5_IRQ_DP1_INTP1          IRQ_SPI(113)
+#define EXYNOS5_IRQ_CEC                        IRQ_SPI(114)
+#define EXYNOS5_IRQ_SATA               IRQ_SPI(115)
+#define EXYNOS5_IRQ_NFCON              IRQ_SPI(116)
+
+#define EXYNOS5_IRQ_MMC44              IRQ_SPI(123)
+#define EXYNOS5_IRQ_MDMA1              IRQ_SPI(124)
+#define EXYNOS5_IRQ_FIMC_LITE0         IRQ_SPI(125)
+#define EXYNOS5_IRQ_FIMC_LITE1         IRQ_SPI(126)
+#define EXYNOS5_IRQ_RP_TIMER           IRQ_SPI(127)
+
+#define EXYNOS5_IRQ_PMU                        COMBINER_IRQ(1, 2)
+#define EXYNOS5_IRQ_PMU_CPU1           COMBINER_IRQ(1, 6)
+
+#define EXYNOS5_IRQ_SYSMMU_GSC0_0      COMBINER_IRQ(2, 0)
+#define EXYNOS5_IRQ_SYSMMU_GSC0_1      COMBINER_IRQ(2, 1)
+#define EXYNOS5_IRQ_SYSMMU_GSC1_0      COMBINER_IRQ(2, 2)
+#define EXYNOS5_IRQ_SYSMMU_GSC1_1      COMBINER_IRQ(2, 3)
+#define EXYNOS5_IRQ_SYSMMU_GSC2_0      COMBINER_IRQ(2, 4)
+#define EXYNOS5_IRQ_SYSMMU_GSC2_1      COMBINER_IRQ(2, 5)
+#define EXYNOS5_IRQ_SYSMMU_GSC3_0      COMBINER_IRQ(2, 6)
+#define EXYNOS5_IRQ_SYSMMU_GSC3_1      COMBINER_IRQ(2, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_FIMD1_0     COMBINER_IRQ(3, 2)
+#define EXYNOS5_IRQ_SYSMMU_FIMD1_1     COMBINER_IRQ(3, 3)
+#define EXYNOS5_IRQ_SYSMMU_LITE0_0     COMBINER_IRQ(3, 4)
+#define EXYNOS5_IRQ_SYSMMU_LITE0_1     COMBINER_IRQ(3, 5)
+#define EXYNOS5_IRQ_SYSMMU_SCALERPISP_0        COMBINER_IRQ(3, 6)
+#define EXYNOS5_IRQ_SYSMMU_SCALERPISP_1        COMBINER_IRQ(3, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_ROTATOR_0   COMBINER_IRQ(4, 0)
+#define EXYNOS5_IRQ_SYSMMU_ROTATOR_1   COMBINER_IRQ(4, 1)
+#define EXYNOS5_IRQ_SYSMMU_JPEG_0      COMBINER_IRQ(4, 2)
+#define EXYNOS5_IRQ_SYSMMU_JPEG_1      COMBINER_IRQ(4, 3)
+
+#define EXYNOS5_IRQ_SYSMMU_FD_0                COMBINER_IRQ(5, 0)
+#define EXYNOS5_IRQ_SYSMMU_FD_1                COMBINER_IRQ(5, 1)
+#define EXYNOS5_IRQ_SYSMMU_SCALERCISP_0        COMBINER_IRQ(5, 2)
+#define EXYNOS5_IRQ_SYSMMU_SCALERCISP_1        COMBINER_IRQ(5, 3)
+#define EXYNOS5_IRQ_SYSMMU_MCUISP_0    COMBINER_IRQ(5, 4)
+#define EXYNOS5_IRQ_SYSMMU_MCUISP_1    COMBINER_IRQ(5, 5)
+#define EXYNOS5_IRQ_SYSMMU_3DNR_0      COMBINER_IRQ(5, 6)
+#define EXYNOS5_IRQ_SYSMMU_3DNR_1      COMBINER_IRQ(5, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_ARM_0       COMBINER_IRQ(6, 0)
+#define EXYNOS5_IRQ_SYSMMU_ARM_1       COMBINER_IRQ(6, 1)
+#define EXYNOS5_IRQ_SYSMMU_MFC_L_0     COMBINER_IRQ(6, 2)
+#define EXYNOS5_IRQ_SYSMMU_MFC_L_1     COMBINER_IRQ(6, 3)
+#define EXYNOS5_IRQ_SYSMMU_RTIC_0      COMBINER_IRQ(6, 4)
+#define EXYNOS5_IRQ_SYSMMU_RTIC_1      COMBINER_IRQ(6, 5)
+#define EXYNOS5_IRQ_SYSMMU_SSS_0       COMBINER_IRQ(6, 6)
+#define EXYNOS5_IRQ_SYSMMU_SSS_1       COMBINER_IRQ(6, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_MDMA0_0     COMBINER_IRQ(7, 0)
+#define EXYNOS5_IRQ_SYSMMU_MDMA0_1     COMBINER_IRQ(7, 1)
+#define EXYNOS5_IRQ_SYSMMU_MDMA1_0     COMBINER_IRQ(7, 2)
+#define EXYNOS5_IRQ_SYSMMU_MDMA1_1     COMBINER_IRQ(7, 3)
+#define EXYNOS5_IRQ_SYSMMU_TV_0                COMBINER_IRQ(7, 4)
+#define EXYNOS5_IRQ_SYSMMU_TV_1                COMBINER_IRQ(7, 5)
+#define EXYNOS5_IRQ_SYSMMU_GPSX_0      COMBINER_IRQ(7, 6)
+#define EXYNOS5_IRQ_SYSMMU_GPSX_1      COMBINER_IRQ(7, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_MFC_R_0     COMBINER_IRQ(8, 5)
+#define EXYNOS5_IRQ_SYSMMU_MFC_R_1     COMBINER_IRQ(8, 6)
+
+#define EXYNOS5_IRQ_SYSMMU_DIS1_0      COMBINER_IRQ(9, 4)
+#define EXYNOS5_IRQ_SYSMMU_DIS1_1      COMBINER_IRQ(9, 5)
+
+#define EXYNOS5_IRQ_DP                 COMBINER_IRQ(10, 3)
+#define EXYNOS5_IRQ_SYSMMU_DIS0_0      COMBINER_IRQ(10, 4)
+#define EXYNOS5_IRQ_SYSMMU_DIS0_1      COMBINER_IRQ(10, 5)
+#define EXYNOS5_IRQ_SYSMMU_ISP_0       COMBINER_IRQ(10, 6)
+#define EXYNOS5_IRQ_SYSMMU_ISP_1       COMBINER_IRQ(10, 7)
+
+#define EXYNOS5_IRQ_SYSMMU_ODC_0       COMBINER_IRQ(11, 0)
+#define EXYNOS5_IRQ_SYSMMU_ODC_1       COMBINER_IRQ(11, 1)
+#define EXYNOS5_IRQ_SYSMMU_DRC_0       COMBINER_IRQ(11, 6)
+#define EXYNOS5_IRQ_SYSMMU_DRC_1       COMBINER_IRQ(11, 7)
+
+#define EXYNOS5_IRQ_FIMD1_FIFO         COMBINER_IRQ(18, 4)
+#define EXYNOS5_IRQ_FIMD1_VSYNC                COMBINER_IRQ(18, 5)
+#define EXYNOS5_IRQ_FIMD1_SYSTEM       COMBINER_IRQ(18, 6)
+
+#define EXYNOS5_IRQ_EINT0              COMBINER_IRQ(23, 0)
+#define EXYNOS5_IRQ_MCT_L0             COMBINER_IRQ(23, 1)
+#define EXYNOS5_IRQ_MCT_L1             COMBINER_IRQ(23, 2)
+#define EXYNOS5_IRQ_MCT_G0             COMBINER_IRQ(23, 3)
+#define EXYNOS5_IRQ_MCT_G1             COMBINER_IRQ(23, 4)
+#define EXYNOS5_IRQ_MCT_G2             COMBINER_IRQ(23, 5)
+#define EXYNOS5_IRQ_MCT_G3             COMBINER_IRQ(23, 6)
+
+#define EXYNOS5_IRQ_EINT1              COMBINER_IRQ(24, 0)
+#define EXYNOS5_IRQ_SYSMMU_LITE1_0     COMBINER_IRQ(24, 1)
+#define EXYNOS5_IRQ_SYSMMU_LITE1_1     COMBINER_IRQ(24, 2)
+#define EXYNOS5_IRQ_SYSMMU_2D_0                COMBINER_IRQ(24, 5)
+#define EXYNOS5_IRQ_SYSMMU_2D_1                COMBINER_IRQ(24, 6)
+
+#define EXYNOS5_IRQ_EINT2              COMBINER_IRQ(25, 0)
+#define EXYNOS5_IRQ_EINT3              COMBINER_IRQ(25, 1)
+
+#define EXYNOS5_IRQ_EINT4              COMBINER_IRQ(26, 0)
+#define EXYNOS5_IRQ_EINT5              COMBINER_IRQ(26, 1)
+
+#define EXYNOS5_IRQ_EINT6              COMBINER_IRQ(27, 0)
+#define EXYNOS5_IRQ_EINT7              COMBINER_IRQ(27, 1)
+
+#define EXYNOS5_IRQ_EINT8              COMBINER_IRQ(28, 0)
+#define EXYNOS5_IRQ_EINT9              COMBINER_IRQ(28, 1)
+
+#define EXYNOS5_IRQ_EINT10             COMBINER_IRQ(29, 0)
+#define EXYNOS5_IRQ_EINT11             COMBINER_IRQ(29, 1)
+
+#define EXYNOS5_IRQ_EINT12             COMBINER_IRQ(30, 0)
+#define EXYNOS5_IRQ_EINT13             COMBINER_IRQ(30, 1)
+
+#define EXYNOS5_IRQ_EINT14             COMBINER_IRQ(31, 0)
+#define EXYNOS5_IRQ_EINT15             COMBINER_IRQ(31, 1)
+
+#define EXYNOS5_MAX_COMBINER_NR                32
+
+#define EXYNOS5_IRQ_GPIO1_NR_GROUPS    13
+#define EXYNOS5_IRQ_GPIO2_NR_GROUPS    9
+#define EXYNOS5_IRQ_GPIO3_NR_GROUPS    5
+#define EXYNOS5_IRQ_GPIO4_NR_GROUPS    1
+
+#define MAX_COMBINER_NR                        (EXYNOS4_MAX_COMBINER_NR > EXYNOS5_MAX_COMBINER_NR ? \
+                                       EXYNOS4_MAX_COMBINER_NR : EXYNOS5_MAX_COMBINER_NR)
+
+#define S5P_EINT_BASE1                 COMBINER_IRQ(MAX_COMBINER_NR, 0)
+#define S5P_EINT_BASE2                 (S5P_EINT_BASE1 + 16)
+#define S5P_GPIOINT_BASE               (S5P_EINT_BASE1 + 32)
+#define IRQ_GPIO_END                   (S5P_GPIOINT_BASE + S5P_GPIOINT_COUNT)
+#define IRQ_TIMER_BASE                 (IRQ_GPIO_END + 64)
 
 /* Set the default NR_IRQS */
-#define NR_IRQS                        (IRQ_TIMER_BASE + IRQ_TIMER_COUNT)
+
+#define NR_IRQS                                (IRQ_TIMER_BASE + IRQ_TIMER_COUNT)
 
 #endif /* __ASM_ARCH_IRQS_H */
index c754a22..024d38f 100644 (file)
 
 #define EXYNOS4_PA_SYSRAM0             0x02025000
 #define EXYNOS4_PA_SYSRAM1             0x02020000
+#define EXYNOS5_PA_SYSRAM              0x02020000
 
 #define EXYNOS4_PA_FIMC0               0x11800000
 #define EXYNOS4_PA_FIMC1               0x11810000
 #define EXYNOS4_PA_FIMC2               0x11820000
 #define EXYNOS4_PA_FIMC3               0x11830000
 
+#define EXYNOS4_PA_JPEG                        0x11840000
+
+#define EXYNOS4_PA_G2D                 0x12800000
+
 #define EXYNOS4_PA_I2S0                        0x03830000
 #define EXYNOS4_PA_I2S1                        0xE3100000
 #define EXYNOS4_PA_I2S2                        0xE2A00000
 #define EXYNOS4_PA_ONENAND             0x0C000000
 #define EXYNOS4_PA_ONENAND_DMA         0x0C600000
 
-#define EXYNOS4_PA_CHIPID              0x10000000
+#define EXYNOS_PA_CHIPID               0x10000000
 
 #define EXYNOS4_PA_SYSCON              0x10010000
+#define EXYNOS5_PA_SYSCON              0x10050100
+
 #define EXYNOS4_PA_PMU                 0x10020000
+#define EXYNOS5_PA_PMU                 0x10040000
+
 #define EXYNOS4_PA_CMU                 0x10030000
+#define EXYNOS5_PA_CMU                 0x10010000
 
 #define EXYNOS4_PA_SYSTIMER            0x10050000
+#define EXYNOS5_PA_SYSTIMER            0x101C0000
+
 #define EXYNOS4_PA_WATCHDOG            0x10060000
+#define EXYNOS5_PA_WATCHDOG            0x101D0000
+
 #define EXYNOS4_PA_RTC                 0x10070000
 
 #define EXYNOS4_PA_KEYPAD              0x100A0000
 
 #define EXYNOS4_PA_DMC0                        0x10400000
+#define EXYNOS4_PA_DMC1                        0x10410000
 
 #define EXYNOS4_PA_COMBINER            0x10440000
+#define EXYNOS5_PA_COMBINER            0x10440000
 
 #define EXYNOS4_PA_GIC_CPU             0x10480000
 #define EXYNOS4_PA_GIC_DIST            0x10490000
+#define EXYNOS5_PA_GIC_CPU             0x10480000
+#define EXYNOS5_PA_GIC_DIST            0x10490000
 
 #define EXYNOS4_PA_COREPERI            0x10500000
 #define EXYNOS4_PA_TWD                 0x10500600
 #define EXYNOS4_PA_L2CC                        0x10502000
 
-#define EXYNOS4_PA_MDMA                        0x10810000
+#define EXYNOS4_PA_MDMA0               0x10810000
+#define EXYNOS4_PA_MDMA1               0x12840000
 #define EXYNOS4_PA_PDMA0               0x12680000
 #define EXYNOS4_PA_PDMA1               0x12690000
 
 #define EXYNOS4_PA_SPI1                        0x13930000
 #define EXYNOS4_PA_SPI2                        0x13940000
 
-
 #define EXYNOS4_PA_GPIO1               0x11400000
 #define EXYNOS4_PA_GPIO2               0x11000000
 #define EXYNOS4_PA_GPIO3               0x03860000
+#define EXYNOS5_PA_GPIO1               0x11400000
+#define EXYNOS5_PA_GPIO2               0x13400000
+#define EXYNOS5_PA_GPIO3               0x10D10000
+#define EXYNOS5_PA_GPIO4               0x03860000
 
 #define EXYNOS4_PA_MIPI_CSIS0          0x11880000
 #define EXYNOS4_PA_MIPI_CSIS1          0x11890000
 #define EXYNOS4_PA_SATAPHY_CTRL                0x126B0000
 
 #define EXYNOS4_PA_SROMC               0x12570000
+#define EXYNOS5_PA_SROMC               0x12250000
 
 #define EXYNOS4_PA_EHCI                        0x12580000
 #define EXYNOS4_PA_OHCI                        0x12590000
 #define EXYNOS4_PA_MFC                 0x13400000
 
 #define EXYNOS4_PA_UART                        0x13800000
+#define EXYNOS5_PA_UART                        0x12C00000
 
 #define EXYNOS4_PA_VP                  0x12C00000
 #define EXYNOS4_PA_MIXER               0x12C10000
 #define EXYNOS4_PA_IIC_HDMIPHY         0x138E0000
 
 #define EXYNOS4_PA_IIC(x)              (0x13860000 + ((x) * 0x10000))
+#define EXYNOS5_PA_IIC(x)              (0x12C60000 + ((x) * 0x10000))
 
 #define EXYNOS4_PA_ADC                 0x13910000
 #define EXYNOS4_PA_ADC1                        0x13911000
 #define EXYNOS4_PA_SPDIF               0x139B0000
 
 #define EXYNOS4_PA_TIMER               0x139D0000
+#define EXYNOS5_PA_TIMER               0x12DD0000
 
 #define EXYNOS4_PA_SDRAM               0x40000000
+#define EXYNOS5_PA_SDRAM               0x40000000
 
 /* Compatibiltiy Defines */
 
 #define S3C_PA_IIC7                    EXYNOS4_PA_IIC(7)
 #define S3C_PA_RTC                     EXYNOS4_PA_RTC
 #define S3C_PA_WDT                     EXYNOS4_PA_WATCHDOG
-#define S3C_PA_UART                    EXYNOS4_PA_UART
 #define S3C_PA_SPI0                    EXYNOS4_PA_SPI0
 #define S3C_PA_SPI1                    EXYNOS4_PA_SPI1
 #define S3C_PA_SPI2                    EXYNOS4_PA_SPI2
 #define S5P_PA_FIMC1                   EXYNOS4_PA_FIMC1
 #define S5P_PA_FIMC2                   EXYNOS4_PA_FIMC2
 #define S5P_PA_FIMC3                   EXYNOS4_PA_FIMC3
+#define S5P_PA_JPEG                    EXYNOS4_PA_JPEG
+#define S5P_PA_G2D                     EXYNOS4_PA_G2D
 #define S5P_PA_FIMD0                   EXYNOS4_PA_FIMD0
 #define S5P_PA_HDMI                    EXYNOS4_PA_HDMI
 #define S5P_PA_IIC_HDMIPHY             EXYNOS4_PA_IIC_HDMIPHY
 
 /* Compatibility UART */
 
-#define S3C_VA_UARTx(x)                        (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
+#define EXYNOS4_PA_UART0               0x13800000
+#define EXYNOS4_PA_UART1               0x13810000
+#define EXYNOS4_PA_UART2               0x13820000
+#define EXYNOS4_PA_UART3               0x13830000
+#define EXYNOS4_SZ_UART                        SZ_256
 
-#define S5P_PA_UART(x)                 (EXYNOS4_PA_UART + ((x) * S3C_UART_OFFSET))
-#define S5P_PA_UART0                   S5P_PA_UART(0)
-#define S5P_PA_UART1                   S5P_PA_UART(1)
-#define S5P_PA_UART2                   S5P_PA_UART(2)
-#define S5P_PA_UART3                   S5P_PA_UART(3)
-#define S5P_PA_UART4                   S5P_PA_UART(4)
+#define EXYNOS5_PA_UART0               0x12C00000
+#define EXYNOS5_PA_UART1               0x12C10000
+#define EXYNOS5_PA_UART2               0x12C20000
+#define EXYNOS5_PA_UART3               0x12C30000
+#define EXYNOS5_SZ_UART                        SZ_256
 
-#define S5P_SZ_UART                    SZ_256
+#define S3C_VA_UARTx(x)                        (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
 
 #endif /* __ASM_ARCH_MAP_H */
index 632dd56..e76b7fa 100644 (file)
@@ -22,11 +22,13 @@ enum sys_powerdown {
        NUM_SYS_POWERDOWN,
 };
 
+extern unsigned long l2x0_regs_phys;
 struct exynos4_pmu_conf {
        void __iomem *reg;
        unsigned int val[NUM_SYS_POWERDOWN];
 };
 
 extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode);
+extern void s3c_cpu_resume(void);
 
 #endif /* __ASM_ARCH_PMU_H */
index 6c37ebe..e141c1f 100644 (file)
 #include <plat/cpu.h>
 #include <mach/map.h>
 
-#define S5P_CLKREG(x)                  (S5P_VA_CMU + (x))
-
-#define S5P_CLKDIV_LEFTBUS             S5P_CLKREG(0x04500)
-#define S5P_CLKDIV_STAT_LEFTBUS                S5P_CLKREG(0x04600)
-#define S5P_CLKGATE_IP_LEFTBUS         S5P_CLKREG(0x04800)
-
-#define S5P_CLKDIV_RIGHTBUS            S5P_CLKREG(0x08500)
-#define S5P_CLKDIV_STAT_RIGHTBUS       S5P_CLKREG(0x08600)
-#define S5P_CLKGATE_IP_RIGHTBUS                S5P_CLKREG(0x08800)
-
-#define S5P_EPLL_LOCK                  S5P_CLKREG(0x0C010)
-#define S5P_VPLL_LOCK                  S5P_CLKREG(0x0C020)
-
-#define S5P_EPLL_CON0                  S5P_CLKREG(0x0C110)
-#define S5P_EPLL_CON1                  S5P_CLKREG(0x0C114)
-#define S5P_VPLL_CON0                  S5P_CLKREG(0x0C120)
-#define S5P_VPLL_CON1                  S5P_CLKREG(0x0C124)
-
-#define S5P_CLKSRC_TOP0                        S5P_CLKREG(0x0C210)
-#define S5P_CLKSRC_TOP1                        S5P_CLKREG(0x0C214)
-#define S5P_CLKSRC_CAM                 S5P_CLKREG(0x0C220)
-#define S5P_CLKSRC_TV                  S5P_CLKREG(0x0C224)
-#define S5P_CLKSRC_MFC                 S5P_CLKREG(0x0C228)
-#define S5P_CLKSRC_G3D                 S5P_CLKREG(0x0C22C)
-#define S5P_CLKSRC_IMAGE               S5P_CLKREG(0x0C230)
-#define S5P_CLKSRC_LCD0                        S5P_CLKREG(0x0C234)
-#define S5P_CLKSRC_MAUDIO              S5P_CLKREG(0x0C23C)
-#define S5P_CLKSRC_FSYS                        S5P_CLKREG(0x0C240)
-#define S5P_CLKSRC_PERIL0              S5P_CLKREG(0x0C250)
-#define S5P_CLKSRC_PERIL1              S5P_CLKREG(0x0C254)
-
-#define S5P_CLKSRC_MASK_TOP            S5P_CLKREG(0x0C310)
-#define S5P_CLKSRC_MASK_CAM            S5P_CLKREG(0x0C320)
-#define S5P_CLKSRC_MASK_TV             S5P_CLKREG(0x0C324)
-#define S5P_CLKSRC_MASK_LCD0           S5P_CLKREG(0x0C334)
-#define S5P_CLKSRC_MASK_MAUDIO         S5P_CLKREG(0x0C33C)
-#define S5P_CLKSRC_MASK_FSYS           S5P_CLKREG(0x0C340)
-#define S5P_CLKSRC_MASK_PERIL0         S5P_CLKREG(0x0C350)
-#define S5P_CLKSRC_MASK_PERIL1         S5P_CLKREG(0x0C354)
-
-#define S5P_CLKDIV_TOP                 S5P_CLKREG(0x0C510)
-#define S5P_CLKDIV_CAM                 S5P_CLKREG(0x0C520)
-#define S5P_CLKDIV_TV                  S5P_CLKREG(0x0C524)
-#define S5P_CLKDIV_MFC                 S5P_CLKREG(0x0C528)
-#define S5P_CLKDIV_G3D                 S5P_CLKREG(0x0C52C)
-#define S5P_CLKDIV_IMAGE               S5P_CLKREG(0x0C530)
-#define S5P_CLKDIV_LCD0                        S5P_CLKREG(0x0C534)
-#define S5P_CLKDIV_MAUDIO              S5P_CLKREG(0x0C53C)
-#define S5P_CLKDIV_FSYS0               S5P_CLKREG(0x0C540)
-#define S5P_CLKDIV_FSYS1               S5P_CLKREG(0x0C544)
-#define S5P_CLKDIV_FSYS2               S5P_CLKREG(0x0C548)
-#define S5P_CLKDIV_FSYS3               S5P_CLKREG(0x0C54C)
-#define S5P_CLKDIV_PERIL0              S5P_CLKREG(0x0C550)
-#define S5P_CLKDIV_PERIL1              S5P_CLKREG(0x0C554)
-#define S5P_CLKDIV_PERIL2              S5P_CLKREG(0x0C558)
-#define S5P_CLKDIV_PERIL3              S5P_CLKREG(0x0C55C)
-#define S5P_CLKDIV_PERIL4              S5P_CLKREG(0x0C560)
-#define S5P_CLKDIV_PERIL5              S5P_CLKREG(0x0C564)
-#define S5P_CLKDIV2_RATIO              S5P_CLKREG(0x0C580)
-
-#define S5P_CLKDIV_STAT_TOP            S5P_CLKREG(0x0C610)
-
-#define S5P_CLKGATE_SCLKCAM            S5P_CLKREG(0x0C820)
-#define S5P_CLKGATE_IP_CAM             S5P_CLKREG(0x0C920)
-#define S5P_CLKGATE_IP_TV              S5P_CLKREG(0x0C924)
-#define S5P_CLKGATE_IP_MFC             S5P_CLKREG(0x0C928)
-#define S5P_CLKGATE_IP_G3D             S5P_CLKREG(0x0C92C)
-#define S5P_CLKGATE_IP_IMAGE           (soc_is_exynos4210() ? \
-                                       S5P_CLKREG(0x0C930) : \
-                                       S5P_CLKREG(0x04930))
-#define S5P_CLKGATE_IP_IMAGE_4210      S5P_CLKREG(0x0C930)
-#define S5P_CLKGATE_IP_IMAGE_4212      S5P_CLKREG(0x04930)
-#define S5P_CLKGATE_IP_LCD0            S5P_CLKREG(0x0C934)
-#define S5P_CLKGATE_IP_FSYS            S5P_CLKREG(0x0C940)
-#define S5P_CLKGATE_IP_GPS             S5P_CLKREG(0x0C94C)
-#define S5P_CLKGATE_IP_PERIL           S5P_CLKREG(0x0C950)
-#define S5P_CLKGATE_IP_PERIR           (soc_is_exynos4210() ? \
-                                       S5P_CLKREG(0x0C960) : \
-                                       S5P_CLKREG(0x08960))
-#define S5P_CLKGATE_IP_PERIR_4210      S5P_CLKREG(0x0C960)
-#define S5P_CLKGATE_IP_PERIR_4212      S5P_CLKREG(0x08960)
-#define S5P_CLKGATE_BLOCK              S5P_CLKREG(0x0C970)
-
-#define S5P_CLKSRC_MASK_DMC            S5P_CLKREG(0x10300)
-#define S5P_CLKSRC_DMC                 S5P_CLKREG(0x10200)
-#define S5P_CLKDIV_DMC0                        S5P_CLKREG(0x10500)
-#define S5P_CLKDIV_DMC1                        S5P_CLKREG(0x10504)
-#define S5P_CLKDIV_STAT_DMC0           S5P_CLKREG(0x10600)
-#define S5P_CLKGATE_IP_DMC             S5P_CLKREG(0x10900)
-
-#define S5P_APLL_LOCK                  S5P_CLKREG(0x14000)
-#define S5P_MPLL_LOCK                  (soc_is_exynos4210() ? \
-                                       S5P_CLKREG(0x14004) :  \
-                                       S5P_CLKREG(0x10008))
-#define S5P_APLL_CON0                  S5P_CLKREG(0x14100)
-#define S5P_APLL_CON1                  S5P_CLKREG(0x14104)
-#define S5P_MPLL_CON0                  (soc_is_exynos4210() ? \
-                                       S5P_CLKREG(0x14108) : \
-                                       S5P_CLKREG(0x10108))
-#define S5P_MPLL_CON1                  (soc_is_exynos4210() ? \
-                                       S5P_CLKREG(0x1410C) : \
-                                       S5P_CLKREG(0x1010C))
-
-#define S5P_CLKSRC_CPU                 S5P_CLKREG(0x14200)
-#define S5P_CLKMUX_STATCPU             S5P_CLKREG(0x14400)
-
-#define S5P_CLKDIV_CPU                 S5P_CLKREG(0x14500)
-#define S5P_CLKDIV_CPU1                        S5P_CLKREG(0x14504)
-#define S5P_CLKDIV_STATCPU             S5P_CLKREG(0x14600)
-#define S5P_CLKDIV_STATCPU1            S5P_CLKREG(0x14604)
-
-#define S5P_CLKGATE_SCLKCPU            S5P_CLKREG(0x14800)
-#define S5P_CLKGATE_IP_CPU             S5P_CLKREG(0x14900)
-
-#define S5P_APLL_LOCKTIME              (0x1C20)        /* 300us */
-
-#define S5P_APLLCON0_ENABLE_SHIFT      (31)
-#define S5P_APLLCON0_LOCKED_SHIFT      (29)
-#define S5P_APLL_VAL_1000              ((250 << 16) | (6 << 8) | 1)
-#define S5P_APLL_VAL_800               ((200 << 16) | (6 << 8) | 1)
-
-#define S5P_EPLLCON0_ENABLE_SHIFT      (31)
-#define S5P_EPLLCON0_LOCKED_SHIFT      (29)
-
-#define S5P_VPLLCON0_ENABLE_SHIFT      (31)
-#define S5P_VPLLCON0_LOCKED_SHIFT      (29)
-
-#define S5P_CLKSRC_CPU_MUXCORE_SHIFT   (16)
-#define S5P_CLKMUX_STATCPU_MUXCORE_MASK        (0x7 << S5P_CLKSRC_CPU_MUXCORE_SHIFT)
-
-#define S5P_CLKDIV_CPU0_CORE_SHIFT     (0)
-#define S5P_CLKDIV_CPU0_CORE_MASK      (0x7 << S5P_CLKDIV_CPU0_CORE_SHIFT)
-#define S5P_CLKDIV_CPU0_COREM0_SHIFT   (4)
-#define S5P_CLKDIV_CPU0_COREM0_MASK    (0x7 << S5P_CLKDIV_CPU0_COREM0_SHIFT)
-#define S5P_CLKDIV_CPU0_COREM1_SHIFT   (8)
-#define S5P_CLKDIV_CPU0_COREM1_MASK    (0x7 << S5P_CLKDIV_CPU0_COREM1_SHIFT)
-#define S5P_CLKDIV_CPU0_PERIPH_SHIFT   (12)
-#define S5P_CLKDIV_CPU0_PERIPH_MASK    (0x7 << S5P_CLKDIV_CPU0_PERIPH_SHIFT)
-#define S5P_CLKDIV_CPU0_ATB_SHIFT      (16)
-#define S5P_CLKDIV_CPU0_ATB_MASK       (0x7 << S5P_CLKDIV_CPU0_ATB_SHIFT)
-#define S5P_CLKDIV_CPU0_PCLKDBG_SHIFT  (20)
-#define S5P_CLKDIV_CPU0_PCLKDBG_MASK   (0x7 << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT)
-#define S5P_CLKDIV_CPU0_APLL_SHIFT     (24)
-#define S5P_CLKDIV_CPU0_APLL_MASK      (0x7 << S5P_CLKDIV_CPU0_APLL_SHIFT)
-
-#define S5P_CLKDIV_DMC0_ACP_SHIFT      (0)
-#define S5P_CLKDIV_DMC0_ACP_MASK       (0x7 << S5P_CLKDIV_DMC0_ACP_SHIFT)
-#define S5P_CLKDIV_DMC0_ACPPCLK_SHIFT  (4)
-#define S5P_CLKDIV_DMC0_ACPPCLK_MASK   (0x7 << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT)
-#define S5P_CLKDIV_DMC0_DPHY_SHIFT     (8)
-#define S5P_CLKDIV_DMC0_DPHY_MASK      (0x7 << S5P_CLKDIV_DMC0_DPHY_SHIFT)
-#define S5P_CLKDIV_DMC0_DMC_SHIFT      (12)
-#define S5P_CLKDIV_DMC0_DMC_MASK       (0x7 << S5P_CLKDIV_DMC0_DMC_SHIFT)
-#define S5P_CLKDIV_DMC0_DMCD_SHIFT     (16)
-#define S5P_CLKDIV_DMC0_DMCD_MASK      (0x7 << S5P_CLKDIV_DMC0_DMCD_SHIFT)
-#define S5P_CLKDIV_DMC0_DMCP_SHIFT     (20)
-#define S5P_CLKDIV_DMC0_DMCP_MASK      (0x7 << S5P_CLKDIV_DMC0_DMCP_SHIFT)
-#define S5P_CLKDIV_DMC0_COPY2_SHIFT    (24)
-#define S5P_CLKDIV_DMC0_COPY2_MASK     (0x7 << S5P_CLKDIV_DMC0_COPY2_SHIFT)
-#define S5P_CLKDIV_DMC0_CORETI_SHIFT   (28)
-#define S5P_CLKDIV_DMC0_CORETI_MASK    (0x7 << S5P_CLKDIV_DMC0_CORETI_SHIFT)
-
-#define S5P_CLKDIV_TOP_ACLK200_SHIFT   (0)
-#define S5P_CLKDIV_TOP_ACLK200_MASK    (0x7 << S5P_CLKDIV_TOP_ACLK200_SHIFT)
-#define S5P_CLKDIV_TOP_ACLK100_SHIFT   (4)
-#define S5P_CLKDIV_TOP_ACLK100_MASK    (0xf << S5P_CLKDIV_TOP_ACLK100_SHIFT)
-#define S5P_CLKDIV_TOP_ACLK160_SHIFT   (8)
-#define S5P_CLKDIV_TOP_ACLK160_MASK    (0x7 << S5P_CLKDIV_TOP_ACLK160_SHIFT)
-#define S5P_CLKDIV_TOP_ACLK133_SHIFT   (12)
-#define S5P_CLKDIV_TOP_ACLK133_MASK    (0x7 << S5P_CLKDIV_TOP_ACLK133_SHIFT)
-#define S5P_CLKDIV_TOP_ONENAND_SHIFT   (16)
-#define S5P_CLKDIV_TOP_ONENAND_MASK    (0x7 << S5P_CLKDIV_TOP_ONENAND_SHIFT)
-
-#define S5P_CLKDIV_BUS_GDLR_SHIFT      (0)
-#define S5P_CLKDIV_BUS_GDLR_MASK       (0x7 << S5P_CLKDIV_BUS_GDLR_SHIFT)
-#define S5P_CLKDIV_BUS_GPLR_SHIFT      (4)
-#define S5P_CLKDIV_BUS_GPLR_MASK       (0x7 << S5P_CLKDIV_BUS_GPLR_SHIFT)
+#define EXYNOS_CLKREG(x)                       (S5P_VA_CMU + (x))
+
+#define EXYNOS4_CLKDIV_LEFTBUS                 EXYNOS_CLKREG(0x04500)
+#define EXYNOS4_CLKDIV_STAT_LEFTBUS            EXYNOS_CLKREG(0x04600)
+#define EXYNOS4_CLKGATE_IP_LEFTBUS             EXYNOS_CLKREG(0x04800)
+
+#define EXYNOS4_CLKDIV_RIGHTBUS                        EXYNOS_CLKREG(0x08500)
+#define EXYNOS4_CLKDIV_STAT_RIGHTBUS           EXYNOS_CLKREG(0x08600)
+#define EXYNOS4_CLKGATE_IP_RIGHTBUS            EXYNOS_CLKREG(0x08800)
+
+#define EXYNOS4_EPLL_LOCK                      EXYNOS_CLKREG(0x0C010)
+#define EXYNOS4_VPLL_LOCK                      EXYNOS_CLKREG(0x0C020)
+
+#define EXYNOS4_EPLL_CON0                      EXYNOS_CLKREG(0x0C110)
+#define EXYNOS4_EPLL_CON1                      EXYNOS_CLKREG(0x0C114)
+#define EXYNOS4_VPLL_CON0                      EXYNOS_CLKREG(0x0C120)
+#define EXYNOS4_VPLL_CON1                      EXYNOS_CLKREG(0x0C124)
+
+#define EXYNOS4_CLKSRC_TOP0                    EXYNOS_CLKREG(0x0C210)
+#define EXYNOS4_CLKSRC_TOP1                    EXYNOS_CLKREG(0x0C214)
+#define EXYNOS4_CLKSRC_CAM                     EXYNOS_CLKREG(0x0C220)
+#define EXYNOS4_CLKSRC_TV                      EXYNOS_CLKREG(0x0C224)
+#define EXYNOS4_CLKSRC_MFC                     EXYNOS_CLKREG(0x0C228)
+#define EXYNOS4_CLKSRC_G3D                     EXYNOS_CLKREG(0x0C22C)
+#define EXYNOS4_CLKSRC_IMAGE                   EXYNOS_CLKREG(0x0C230)
+#define EXYNOS4_CLKSRC_LCD0                    EXYNOS_CLKREG(0x0C234)
+#define EXYNOS4_CLKSRC_MAUDIO                  EXYNOS_CLKREG(0x0C23C)
+#define EXYNOS4_CLKSRC_FSYS                    EXYNOS_CLKREG(0x0C240)
+#define EXYNOS4_CLKSRC_PERIL0                  EXYNOS_CLKREG(0x0C250)
+#define EXYNOS4_CLKSRC_PERIL1                  EXYNOS_CLKREG(0x0C254)
+
+#define EXYNOS4_CLKSRC_MASK_TOP                        EXYNOS_CLKREG(0x0C310)
+#define EXYNOS4_CLKSRC_MASK_CAM                        EXYNOS_CLKREG(0x0C320)
+#define EXYNOS4_CLKSRC_MASK_TV                 EXYNOS_CLKREG(0x0C324)
+#define EXYNOS4_CLKSRC_MASK_LCD0               EXYNOS_CLKREG(0x0C334)
+#define EXYNOS4_CLKSRC_MASK_MAUDIO             EXYNOS_CLKREG(0x0C33C)
+#define EXYNOS4_CLKSRC_MASK_FSYS               EXYNOS_CLKREG(0x0C340)
+#define EXYNOS4_CLKSRC_MASK_PERIL0             EXYNOS_CLKREG(0x0C350)
+#define EXYNOS4_CLKSRC_MASK_PERIL1             EXYNOS_CLKREG(0x0C354)
+
+#define EXYNOS4_CLKDIV_TOP                     EXYNOS_CLKREG(0x0C510)
+#define EXYNOS4_CLKDIV_CAM                     EXYNOS_CLKREG(0x0C520)
+#define EXYNOS4_CLKDIV_TV                      EXYNOS_CLKREG(0x0C524)
+#define EXYNOS4_CLKDIV_MFC                     EXYNOS_CLKREG(0x0C528)
+#define EXYNOS4_CLKDIV_G3D                     EXYNOS_CLKREG(0x0C52C)
+#define EXYNOS4_CLKDIV_IMAGE                   EXYNOS_CLKREG(0x0C530)
+#define EXYNOS4_CLKDIV_LCD0                    EXYNOS_CLKREG(0x0C534)
+#define EXYNOS4_CLKDIV_MAUDIO                  EXYNOS_CLKREG(0x0C53C)
+#define EXYNOS4_CLKDIV_FSYS0                   EXYNOS_CLKREG(0x0C540)
+#define EXYNOS4_CLKDIV_FSYS1                   EXYNOS_CLKREG(0x0C544)
+#define EXYNOS4_CLKDIV_FSYS2                   EXYNOS_CLKREG(0x0C548)
+#define EXYNOS4_CLKDIV_FSYS3                   EXYNOS_CLKREG(0x0C54C)
+#define EXYNOS4_CLKDIV_PERIL0                  EXYNOS_CLKREG(0x0C550)
+#define EXYNOS4_CLKDIV_PERIL1                  EXYNOS_CLKREG(0x0C554)
+#define EXYNOS4_CLKDIV_PERIL2                  EXYNOS_CLKREG(0x0C558)
+#define EXYNOS4_CLKDIV_PERIL3                  EXYNOS_CLKREG(0x0C55C)
+#define EXYNOS4_CLKDIV_PERIL4                  EXYNOS_CLKREG(0x0C560)
+#define EXYNOS4_CLKDIV_PERIL5                  EXYNOS_CLKREG(0x0C564)
+#define EXYNOS4_CLKDIV2_RATIO                  EXYNOS_CLKREG(0x0C580)
+
+#define EXYNOS4_CLKDIV_STAT_TOP                        EXYNOS_CLKREG(0x0C610)
+#define EXYNOS4_CLKDIV_STAT_MFC                        EXYNOS_CLKREG(0x0C628)
+
+#define EXYNOS4_CLKGATE_SCLKCAM                        EXYNOS_CLKREG(0x0C820)
+#define EXYNOS4_CLKGATE_IP_CAM                 EXYNOS_CLKREG(0x0C920)
+#define EXYNOS4_CLKGATE_IP_TV                  EXYNOS_CLKREG(0x0C924)
+#define EXYNOS4_CLKGATE_IP_MFC                 EXYNOS_CLKREG(0x0C928)
+#define EXYNOS4_CLKGATE_IP_G3D                 EXYNOS_CLKREG(0x0C92C)
+#define EXYNOS4_CLKGATE_IP_IMAGE               (soc_is_exynos4210() ? \
+                                               EXYNOS_CLKREG(0x0C930) : \
+                                               EXYNOS_CLKREG(0x04930))
+#define EXYNOS4210_CLKGATE_IP_IMAGE            EXYNOS_CLKREG(0x0C930)
+#define EXYNOS4212_CLKGATE_IP_IMAGE            EXYNOS_CLKREG(0x04930)
+#define EXYNOS4_CLKGATE_IP_LCD0                        EXYNOS_CLKREG(0x0C934)
+#define EXYNOS4_CLKGATE_IP_FSYS                        EXYNOS_CLKREG(0x0C940)
+#define EXYNOS4_CLKGATE_IP_GPS                 EXYNOS_CLKREG(0x0C94C)
+#define EXYNOS4_CLKGATE_IP_PERIL               EXYNOS_CLKREG(0x0C950)
+#define EXYNOS4_CLKGATE_IP_PERIR               (soc_is_exynos4210() ? \
+                                               EXYNOS_CLKREG(0x0C960) : \
+                                               EXYNOS_CLKREG(0x08960))
+#define EXYNOS4210_CLKGATE_IP_PERIR            EXYNOS_CLKREG(0x0C960)
+#define EXYNOS4212_CLKGATE_IP_PERIR            EXYNOS_CLKREG(0x08960)
+#define EXYNOS4_CLKGATE_BLOCK                  EXYNOS_CLKREG(0x0C970)
+
+#define EXYNOS4_CLKSRC_MASK_DMC                        EXYNOS_CLKREG(0x10300)
+#define EXYNOS4_CLKSRC_DMC                     EXYNOS_CLKREG(0x10200)
+#define EXYNOS4_CLKDIV_DMC0                    EXYNOS_CLKREG(0x10500)
+#define EXYNOS4_CLKDIV_DMC1                    EXYNOS_CLKREG(0x10504)
+#define EXYNOS4_CLKDIV_STAT_DMC0               EXYNOS_CLKREG(0x10600)
+#define EXYNOS4_CLKDIV_STAT_DMC1               EXYNOS_CLKREG(0x10604)
+#define EXYNOS4_CLKGATE_IP_DMC                 EXYNOS_CLKREG(0x10900)
+
+#define EXYNOS4_DMC_PAUSE_CTRL                 EXYNOS_CLKREG(0x11094)
+#define EXYNOS4_DMC_PAUSE_ENABLE               (1 << 0)
+
+#define EXYNOS4_APLL_LOCK                      EXYNOS_CLKREG(0x14000)
+#define EXYNOS4_MPLL_LOCK                      (soc_is_exynos4210() ? \
+                                               EXYNOS_CLKREG(0x14004) :  \
+                                               EXYNOS_CLKREG(0x10008))
+#define EXYNOS4_APLL_CON0                      EXYNOS_CLKREG(0x14100)
+#define EXYNOS4_APLL_CON1                      EXYNOS_CLKREG(0x14104)
+#define EXYNOS4_MPLL_CON0                      (soc_is_exynos4210() ? \
+                                               EXYNOS_CLKREG(0x14108) : \
+                                               EXYNOS_CLKREG(0x10108))
+#define EXYNOS4_MPLL_CON1                      (soc_is_exynos4210() ? \
+                                               EXYNOS_CLKREG(0x1410C) : \
+                                               EXYNOS_CLKREG(0x1010C))
+
+#define EXYNOS4_CLKSRC_CPU                     EXYNOS_CLKREG(0x14200)
+#define EXYNOS4_CLKMUX_STATCPU                 EXYNOS_CLKREG(0x14400)
+
+#define EXYNOS4_CLKDIV_CPU                     EXYNOS_CLKREG(0x14500)
+#define EXYNOS4_CLKDIV_CPU1                    EXYNOS_CLKREG(0x14504)
+#define EXYNOS4_CLKDIV_STATCPU                 EXYNOS_CLKREG(0x14600)
+#define EXYNOS4_CLKDIV_STATCPU1                        EXYNOS_CLKREG(0x14604)
+
+#define EXYNOS4_CLKGATE_SCLKCPU                        EXYNOS_CLKREG(0x14800)
+#define EXYNOS4_CLKGATE_IP_CPU                 EXYNOS_CLKREG(0x14900)
+
+#define EXYNOS4_APLL_LOCKTIME                  (0x1C20)        /* 300us */
+
+#define EXYNOS4_APLLCON0_ENABLE_SHIFT          (31)
+#define EXYNOS4_APLLCON0_LOCKED_SHIFT          (29)
+#define EXYNOS4_APLL_VAL_1000                  ((250 << 16) | (6 << 8) | 1)
+#define EXYNOS4_APLL_VAL_800                   ((200 << 16) | (6 << 8) | 1)
+
+#define EXYNOS4_EPLLCON0_ENABLE_SHIFT          (31)
+#define EXYNOS4_EPLLCON0_LOCKED_SHIFT          (29)
+
+#define EXYNOS4_VPLLCON0_ENABLE_SHIFT          (31)
+#define EXYNOS4_VPLLCON0_LOCKED_SHIFT          (29)
+
+#define EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT       (16)
+#define EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK    (0x7 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT)
+
+#define EXYNOS4_CLKDIV_CPU0_CORE_SHIFT         (0)
+#define EXYNOS4_CLKDIV_CPU0_CORE_MASK          (0x7 << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT       (4)
+#define EXYNOS4_CLKDIV_CPU0_COREM0_MASK                (0x7 << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT       (8)
+#define EXYNOS4_CLKDIV_CPU0_COREM1_MASK                (0x7 << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT       (12)
+#define EXYNOS4_CLKDIV_CPU0_PERIPH_MASK                (0x7 << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_ATB_SHIFT          (16)
+#define EXYNOS4_CLKDIV_CPU0_ATB_MASK           (0x7 << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT      (20)
+#define EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK       (0x7 << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_APLL_SHIFT         (24)
+#define EXYNOS4_CLKDIV_CPU0_APLL_MASK          (0x7 << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT)
+#define EXYNOS4_CLKDIV_CPU0_CORE2_SHIFT                28
+#define EXYNOS4_CLKDIV_CPU0_CORE2_MASK         (0x7 << EXYNOS4_CLKDIV_CPU0_CORE2_SHIFT)
+
+#define EXYNOS4_CLKDIV_CPU1_COPY_SHIFT         0
+#define EXYNOS4_CLKDIV_CPU1_COPY_MASK          (0x7 << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT)
+#define EXYNOS4_CLKDIV_CPU1_HPM_SHIFT          4
+#define EXYNOS4_CLKDIV_CPU1_HPM_MASK           (0x7 << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT)
+#define EXYNOS4_CLKDIV_CPU1_CORES_SHIFT                8
+#define EXYNOS4_CLKDIV_CPU1_CORES_MASK         (0x7 << EXYNOS4_CLKDIV_CPU1_CORES_SHIFT)
+
+#define EXYNOS4_CLKDIV_DMC0_ACP_SHIFT          (0)
+#define EXYNOS4_CLKDIV_DMC0_ACP_MASK           (0x7 << EXYNOS4_CLKDIV_DMC0_ACP_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT      (4)
+#define EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK       (0x7 << EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT         (8)
+#define EXYNOS4_CLKDIV_DMC0_DPHY_MASK          (0x7 << EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_DMC_SHIFT          (12)
+#define EXYNOS4_CLKDIV_DMC0_DMC_MASK           (0x7 << EXYNOS4_CLKDIV_DMC0_DMC_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT         (16)
+#define EXYNOS4_CLKDIV_DMC0_DMCD_MASK          (0x7 << EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT         (20)
+#define EXYNOS4_CLKDIV_DMC0_DMCP_MASK          (0x7 << EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT                (24)
+#define EXYNOS4_CLKDIV_DMC0_COPY2_MASK         (0x7 << EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT)
+#define EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT       (28)
+#define EXYNOS4_CLKDIV_DMC0_CORETI_MASK                (0x7 << EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT)
+
+#define EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT      (0)
+#define EXYNOS4_CLKDIV_DMC1_G2D_ACP_MASK       (0xf << EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT)
+#define EXYNOS4_CLKDIV_DMC1_C2C_SHIFT          (4)
+#define EXYNOS4_CLKDIV_DMC1_C2C_MASK           (0x7 << EXYNOS4_CLKDIV_DMC1_C2C_SHIFT)
+#define EXYNOS4_CLKDIV_DMC1_PWI_SHIFT          (8)
+#define EXYNOS4_CLKDIV_DMC1_PWI_MASK           (0xf << EXYNOS4_CLKDIV_DMC1_PWI_SHIFT)
+#define EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT      (12)
+#define EXYNOS4_CLKDIV_DMC1_C2CACLK_MASK       (0x7 << EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT)
+#define EXYNOS4_CLKDIV_DMC1_DVSEM_SHIFT                (16)
+#define EXYNOS4_CLKDIV_DMC1_DVSEM_MASK         (0x7f << EXYNOS4_CLKDIV_DMC1_DVSEM_SHIFT)
+#define EXYNOS4_CLKDIV_DMC1_DPM_SHIFT          (24)
+#define EXYNOS4_CLKDIV_DMC1_DPM_MASK           (0x7f << EXYNOS4_CLKDIV_DMC1_DPM_SHIFT)
+
+#define EXYNOS4_CLKDIV_MFC_SHIFT               (0)
+#define EXYNOS4_CLKDIV_MFC_MASK                        (0x7 << EXYNOS4_CLKDIV_MFC_SHIFT)
+
+#define EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT       (0)
+#define EXYNOS4_CLKDIV_TOP_ACLK200_MASK                (0x7 << EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT       (4)
+#define EXYNOS4_CLKDIV_TOP_ACLK100_MASK                (0xF << EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT       (8)
+#define EXYNOS4_CLKDIV_TOP_ACLK160_MASK                (0x7 << EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT       (12)
+#define EXYNOS4_CLKDIV_TOP_ACLK133_MASK                (0x7 << EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT       (16)
+#define EXYNOS4_CLKDIV_TOP_ONENAND_MASK                (0x7 << EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT   (20)
+#define EXYNOS4_CLKDIV_TOP_ACLK266_GPS_MASK    (0x7 << EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT)
+#define EXYNOS4_CLKDIV_TOP_ACLK400_MCUISP_SHIFT        (24)
+#define EXYNOS4_CLKDIV_TOP_ACLK400_MCUISP_MASK (0x7 << EXYNOS4_CLKDIV_TOP_ACLK400_MCUISP_SHIFT)
+
+#define EXYNOS4_CLKDIV_BUS_GDLR_SHIFT          (0)
+#define EXYNOS4_CLKDIV_BUS_GDLR_MASK           (0x7 << EXYNOS4_CLKDIV_BUS_GDLR_SHIFT)
+#define EXYNOS4_CLKDIV_BUS_GPLR_SHIFT          (4)
+#define EXYNOS4_CLKDIV_BUS_GPLR_MASK           (0x7 << EXYNOS4_CLKDIV_BUS_GPLR_SHIFT)
+
+#define EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT         (0)
+#define EXYNOS4_CLKDIV_CAM_FIMC0_MASK          (0xf << EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT)
+#define EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT         (4)
+#define EXYNOS4_CLKDIV_CAM_FIMC1_MASK          (0xf << EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT)
+#define EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT         (8)
+#define EXYNOS4_CLKDIV_CAM_FIMC2_MASK          (0xf << EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT)
+#define EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT         (12)
+#define EXYNOS4_CLKDIV_CAM_FIMC3_MASK          (0xf << EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT)
 
 /* Only for EXYNOS4210 */
 
-#define S5P_CLKSRC_LCD1                        S5P_CLKREG(0x0C238)
-#define S5P_CLKSRC_MASK_LCD1           S5P_CLKREG(0x0C338)
-#define S5P_CLKDIV_LCD1                        S5P_CLKREG(0x0C538)
-#define S5P_CLKGATE_IP_LCD1            S5P_CLKREG(0x0C938)
+#define EXYNOS4210_CLKSRC_LCD1                 EXYNOS_CLKREG(0x0C238)
+#define EXYNOS4210_CLKSRC_MASK_LCD1            EXYNOS_CLKREG(0x0C338)
+#define EXYNOS4210_CLKDIV_LCD1                 EXYNOS_CLKREG(0x0C538)
+#define EXYNOS4210_CLKGATE_IP_LCD1             EXYNOS_CLKREG(0x0C938)
+
+/* Only for EXYNOS4212 */
+
+#define EXYNOS4_CLKDIV_CAM1                    EXYNOS_CLKREG(0x0C568)
+
+#define EXYNOS4_CLKDIV_STAT_CAM1               EXYNOS_CLKREG(0x0C668)
+
+#define EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT         (0)
+#define EXYNOS4_CLKDIV_CAM1_JPEG_MASK          (0xf << EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT)
+
+/* For EXYNOS5250 */
+
+#define EXYNOS5_APLL_CON0                      EXYNOS_CLKREG(0x00100)
+#define EXYNOS5_CLKSRC_CPU                     EXYNOS_CLKREG(0x00200)
+#define EXYNOS5_CLKDIV_CPU0                    EXYNOS_CLKREG(0x00500)
+#define EXYNOS5_MPLL_CON0                      EXYNOS_CLKREG(0x04100)
+#define EXYNOS5_CLKSRC_CORE1                   EXYNOS_CLKREG(0x04204)
+
+#define EXYNOS5_CLKGATE_IP_CORE                        EXYNOS_CLKREG(0x04900)
+
+#define EXYNOS5_CLKDIV_ACP                     EXYNOS_CLKREG(0x08500)
+
+#define EXYNOS5_CLKSRC_TOP2                    EXYNOS_CLKREG(0x10218)
+#define EXYNOS5_EPLL_CON0                      EXYNOS_CLKREG(0x10130)
+#define EXYNOS5_EPLL_CON1                      EXYNOS_CLKREG(0x10134)
+#define EXYNOS5_VPLL_CON0                      EXYNOS_CLKREG(0x10140)
+#define EXYNOS5_VPLL_CON1                      EXYNOS_CLKREG(0x10144)
+#define EXYNOS5_CPLL_CON0                      EXYNOS_CLKREG(0x10120)
+
+#define EXYNOS5_CLKSRC_TOP0                    EXYNOS_CLKREG(0x10210)
+#define EXYNOS5_CLKSRC_TOP3                    EXYNOS_CLKREG(0x1021C)
+#define EXYNOS5_CLKSRC_GSCL                    EXYNOS_CLKREG(0x10220)
+#define EXYNOS5_CLKSRC_DISP1_0                 EXYNOS_CLKREG(0x1022C)
+#define EXYNOS5_CLKSRC_FSYS                    EXYNOS_CLKREG(0x10244)
+#define EXYNOS5_CLKSRC_PERIC0                  EXYNOS_CLKREG(0x10250)
+
+#define EXYNOS5_CLKSRC_MASK_TOP                        EXYNOS_CLKREG(0x10310)
+#define EXYNOS5_CLKSRC_MASK_GSCL               EXYNOS_CLKREG(0x10320)
+#define EXYNOS5_CLKSRC_MASK_DISP1_0            EXYNOS_CLKREG(0x1032C)
+#define EXYNOS5_CLKSRC_MASK_FSYS               EXYNOS_CLKREG(0x10340)
+#define EXYNOS5_CLKSRC_MASK_PERIC0             EXYNOS_CLKREG(0x10350)
+
+#define EXYNOS5_CLKDIV_TOP0                    EXYNOS_CLKREG(0x10510)
+#define EXYNOS5_CLKDIV_TOP1                    EXYNOS_CLKREG(0x10514)
+#define EXYNOS5_CLKDIV_GSCL                    EXYNOS_CLKREG(0x10520)
+#define EXYNOS5_CLKDIV_DISP1_0                 EXYNOS_CLKREG(0x1052C)
+#define EXYNOS5_CLKDIV_GEN                     EXYNOS_CLKREG(0x1053C)
+#define EXYNOS5_CLKDIV_FSYS0                   EXYNOS_CLKREG(0x10548)
+#define EXYNOS5_CLKDIV_FSYS1                   EXYNOS_CLKREG(0x1054C)
+#define EXYNOS5_CLKDIV_FSYS2                   EXYNOS_CLKREG(0x10550)
+#define EXYNOS5_CLKDIV_FSYS3                   EXYNOS_CLKREG(0x10554)
+#define EXYNOS5_CLKDIV_PERIC0                  EXYNOS_CLKREG(0x10558)
+
+#define EXYNOS5_CLKGATE_IP_ACP                 EXYNOS_CLKREG(0x08800)
+#define EXYNOS5_CLKGATE_IP_GSCL                        EXYNOS_CLKREG(0x10920)
+#define EXYNOS5_CLKGATE_IP_DISP1               EXYNOS_CLKREG(0x10928)
+#define EXYNOS5_CLKGATE_IP_MFC                 EXYNOS_CLKREG(0x1092C)
+#define EXYNOS5_CLKGATE_IP_GEN                 EXYNOS_CLKREG(0x10934)
+#define EXYNOS5_CLKGATE_IP_FSYS                        EXYNOS_CLKREG(0x10944)
+#define EXYNOS5_CLKGATE_IP_GPS                 EXYNOS_CLKREG(0x1094C)
+#define EXYNOS5_CLKGATE_IP_PERIC               EXYNOS_CLKREG(0x10950)
+#define EXYNOS5_CLKGATE_IP_PERIS               EXYNOS_CLKREG(0x10960)
+#define EXYNOS5_CLKGATE_BLOCK                  EXYNOS_CLKREG(0x10980)
+
+#define EXYNOS5_BPLL_CON0                      EXYNOS_CLKREG(0x20110)
+#define EXYNOS5_CLKSRC_CDREX                   EXYNOS_CLKREG(0x20200)
+#define EXYNOS5_CLKDIV_CDREX                   EXYNOS_CLKREG(0x20500)
+
+#define EXYNOS5_EPLL_LOCK                      EXYNOS_CLKREG(0x10030)
+
+#define EXYNOS5_EPLLCON0_LOCKED_SHIFT          (29)
 
 /* Compatibility defines and inclusion */
 
 #include <mach/regs-pmu.h>
 
-#define S5P_EPLL_CON                   S5P_EPLL_CON0
+#define S5P_EPLL_CON                           EXYNOS4_EPLL_CON0
 
 #endif /* __ASM_ARCH_REGS_CLOCK_H */
index 1401b21..e4b5b60 100644 (file)
 #include <mach/map.h>
 #include <mach/irqs.h>
 
+#define EINT_REG_NR(x)                 (EINT_OFFSET(x) >> 3)
+#define EINT_CON(b, x)                 (b + 0xE00 + (EINT_REG_NR(x) * 4))
+#define EINT_FLTCON(b, x)              (b + 0xE80 + (EINT_REG_NR(x) * 4))
+#define EINT_MASK(b, x)                        (b + 0xF00 + (EINT_REG_NR(x) * 4))
+#define EINT_PEND(b, x)                        (b + 0xF40 + (EINT_REG_NR(x) * 4))
+
+#define EINT_OFFSET_BIT(x)             (1 << (EINT_OFFSET(x) & 0x7))
+
+/* compatibility for plat-s5p/irq-pm.c */
 #define EXYNOS4_EINT40CON              (S5P_VA_GPIO2 + 0xE00)
 #define S5P_EINT_CON(x)                        (EXYNOS4_EINT40CON + ((x) * 0x4))
 
 #define EXYNOS4_EINT40PEND             (S5P_VA_GPIO2 + 0xF40)
 #define S5P_EINT_PEND(x)               (EXYNOS4_EINT40PEND + ((x) * 0x4))
 
-#define EINT_REG_NR(x)                 (EINT_OFFSET(x) >> 3)
-
-#define eint_irq_to_bit(irq)           (1 << (EINT_OFFSET(irq) & 0x7))
-
-#define EINT_MODE                      S3C_GPIO_SFN(0xf)
-
-#define EINT_GPIO_0(x)                 EXYNOS4_GPX0(x)
-#define EINT_GPIO_1(x)                 EXYNOS4_GPX1(x)
-#define EINT_GPIO_2(x)                 EXYNOS4_GPX2(x)
-#define EINT_GPIO_3(x)                 EXYNOS4_GPX3(x)
-
 #endif /* __ASM_ARCH_REGS_GPIO_H */
index 4fff8e9..4c53f38 100644 (file)
@@ -31,6 +31,7 @@
 #define S5P_USE_STANDBYWFE_ISP_ARM             (1 << 26)
 
 #define S5P_SWRESET                            S5P_PMUREG(0x0400)
+#define EXYNOS_SWRESET                         S5P_PMUREG(0x0400)
 
 #define S5P_WAKEUP_STAT                                S5P_PMUREG(0x0600)
 #define S5P_EINT_WAKEUP_MASK                   S5P_PMUREG(0x0604)
diff --git a/arch/arm/mach-exynos/include/mach/system.h b/arch/arm/mach-exynos/include/mach/system.h
deleted file mode 100644 (file)
index 0063a6d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* linux/arch/arm/mach-exynos4/include/mach/system.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * EXYNOS4 - system support header
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-static void arch_idle(void)
-{
-       /* nothing here yet */
-}
-#endif /* __ASM_ARCH_SYSTEM_H */
index 21d97bc..493f4f3 100644 (file)
@@ -1,9 +1,8 @@
-/* linux/arch/arm/mach-exynos4/include/mach/uncompress.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
- * EXYNOS4 - uncompress code
+ * EXYNOS - uncompress code
  *
  * 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
 #ifndef __ASM_ARCH_UNCOMPRESS_H
 #define __ASM_ARCH_UNCOMPRESS_H __FILE__
 
+#include <asm/mach-types.h>
+
 #include <mach/map.h>
+
+volatile u8 *uart_base;
+
 #include <plat/uncompress.h>
 
 static void arch_detect_cpu(void)
 {
-       /* we do not need to do any cpu detection here at the moment. */
+       if (machine_is_smdk5250())
+               uart_base = (volatile u8 *)EXYNOS5_PA_UART + (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT);
+       else
+               uart_base = (volatile u8 *)EXYNOS4_PA_UART + (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT);
 
        /*
         * For preventing FIFO overrun or infinite loop of UART console,
index e6b02fd..8245f1c 100644 (file)
  * data from the device tree.
  */
 static const struct of_dev_auxdata exynos4210_auxdata_lookup[] __initconst = {
-       OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART0,
+       OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART0,
                                "exynos4210-uart.0", NULL),
-       OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART1,
+       OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART1,
                                "exynos4210-uart.1", NULL),
-       OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART2,
+       OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART2,
                                "exynos4210-uart.2", NULL),
-       OF_DEV_AUXDATA("samsung,exynos4210-uart", S5P_PA_UART3,
+       OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS4_PA_UART3,
                                "exynos4210-uart.3", NULL),
        OF_DEV_AUXDATA("samsung,exynos4210-sdhci", EXYNOS4_PA_HSMMC(0),
                                "exynos4-sdhci.0", NULL),
diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c
new file mode 100644 (file)
index 0000000..0d26f50
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * SAMSUNG EXYNOS5250 Flattened Device Tree enabled machine
+ *
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/of_platform.h>
+#include <linux/serial_core.h>
+
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+#include <mach/map.h>
+
+#include <plat/cpu.h>
+#include <plat/regs-serial.h>
+
+#include "common.h"
+
+/*
+ * The following lookup table is used to override device names when devices
+ * are registered from device tree. This is temporarily added to enable
+ * device tree support addition for the EXYNOS5 architecture.
+ *
+ * For drivers that require platform data to be provided from the machine
+ * file, a platform data pointer can also be supplied along with the
+ * devices names. Usually, the platform data elements that cannot be parsed
+ * from the device tree by the drivers (example: function pointers) are
+ * supplied. But it should be noted that this is a temporary mechanism and
+ * at some point, the drivers should be capable of parsing all the platform
+ * data from the device tree.
+ */
+static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = {
+       OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART0,
+                               "exynos4210-uart.0", NULL),
+       OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART1,
+                               "exynos4210-uart.1", NULL),
+       OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART2,
+                               "exynos4210-uart.2", NULL),
+       OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART3,
+                               "exynos4210-uart.3", NULL),
+       OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA0, "dma-pl330.0", NULL),
+       OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.1", NULL),
+       OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.2", NULL),
+       {},
+};
+
+static void __init exynos5250_dt_map_io(void)
+{
+       exynos_init_io(NULL, 0);
+       s3c24xx_init_clocks(24000000);
+}
+
+static void __init exynos5250_dt_machine_init(void)
+{
+       of_platform_populate(NULL, of_default_bus_match_table,
+                               exynos5250_auxdata_lookup, NULL);
+}
+
+static char const *exynos5250_dt_compat[] __initdata = {
+       "samsung,exynos5250",
+       NULL
+};
+
+DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)")
+       /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
+       .init_irq       = exynos5_init_irq,
+       .map_io         = exynos5250_dt_map_io,
+       .handle_irq     = gic_handle_irq,
+       .init_machine   = exynos5250_dt_machine_init,
+       .timer          = &exynos4_timer,
+       .dt_compat      = exynos5250_dt_compat,
+       .restart        = exynos5_restart,
+MACHINE_END
index aa37179..82ea6fc 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <video/platform_lcd.h>
 #include <media/m5mols.h>
+#include <media/s5k6aa.h>
 #include <media/s5p_fimc.h>
 #include <media/v4l2-mediabus.h>
 
@@ -75,6 +76,7 @@ enum fixed_regulator_id {
        FIXED_REG_ID_MAX8903,
        FIXED_REG_ID_CAM_A28V,
        FIXED_REG_ID_CAM_12V,
+       FIXED_REG_ID_CAM_VT_15V,
 };
 
 static struct s3c2410_uartcfg nuri_uartcfgs[] __initdata = {
@@ -115,7 +117,7 @@ static struct s3c_sdhci_platdata nuri_hsmmc0_data __initdata = {
 };
 
 static struct regulator_consumer_supply emmc_supplies[] = {
-       REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
+       REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.0"),
        REGULATOR_SUPPLY("vmmc", "dw_mmc"),
 };
 
@@ -399,6 +401,9 @@ static struct regulator_consumer_supply __initdata max8997_ldo4_[] = {
 static struct regulator_consumer_supply __initdata max8997_ldo5_[] = {
        REGULATOR_SUPPLY("vhsic", "modemctl"), /* MODEM */
 };
+static struct regulator_consumer_supply nuri_max8997_ldo6_consumer[] = {
+       REGULATOR_SUPPLY("vdd_reg", "6-003c"), /* S5K6AA camera */
+};
 static struct regulator_consumer_supply __initdata max8997_ldo7_[] = {
        REGULATOR_SUPPLY("dig_18", "0-001f"), /* HCD803 */
 };
@@ -413,7 +418,7 @@ static struct regulator_consumer_supply __initdata max8997_ldo12_[] = {
        REGULATOR_SUPPLY("vddio", "6-003c"), /* HDC802 */
 };
 static struct regulator_consumer_supply __initdata max8997_ldo13_[] = {
-       REGULATOR_SUPPLY("vmmc", "s3c-sdhci.2"), /* TFLASH */
+       REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.2"), /* TFLASH */
 };
 static struct regulator_consumer_supply __initdata max8997_ldo14_[] = {
        REGULATOR_SUPPLY("inmotor", "max8997-haptic"),
@@ -431,7 +436,7 @@ static struct regulator_consumer_supply __initdata max8997_buck1_[] = {
        REGULATOR_SUPPLY("vdd_arm", NULL), /* CPUFREQ */
 };
 static struct regulator_consumer_supply __initdata max8997_buck2_[] = {
-       REGULATOR_SUPPLY("vdd_int", NULL), /* CPUFREQ */
+       REGULATOR_SUPPLY("vdd_int", "exynos4210-busfreq.0"), /* CPUFREQ */
 };
 static struct regulator_consumer_supply __initdata max8997_buck3_[] = {
        REGULATOR_SUPPLY("vdd", "mali_dev.0"), /* G3D of Exynos 4 */
@@ -546,6 +551,8 @@ static struct regulator_init_data __initdata max8997_ldo6_data = {
                        .enabled        = 1,
                },
        },
+       .num_consumer_supplies  = ARRAY_SIZE(nuri_max8997_ldo6_consumer),
+       .consumer_supplies      = nuri_max8997_ldo6_consumer,
 };
 
 static struct regulator_init_data __initdata max8997_ldo7_data = {
@@ -742,7 +749,7 @@ static struct regulator_init_data __initdata max8997_buck2_data = {
        .constraints    = {
                .name           = "VINT_1.1V_C210",
                .min_uV         = 900000,
-               .max_uV         = 1100000,
+               .max_uV         = 1200000,
                .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
                .always_on      = 1,
                .state_mem      = {
@@ -957,7 +964,6 @@ static struct max8997_platform_data __initdata nuri_max8997_pdata = {
        .regulators             = nuri_max8997_regulators,
 
        .buck125_gpios = { EXYNOS4_GPX0(5), EXYNOS4_GPX0(6), EXYNOS4_GPL0(0) },
-       .buck2_gpiodvs = true,
 
        .buck1_voltage[0] = 1350000, /* 1.35V */
        .buck1_voltage[1] = 1300000, /* 1.3V */
@@ -1116,7 +1122,30 @@ static void __init nuri_ehci_init(void)
 }
 
 /* CAMERA */
+static struct regulator_consumer_supply cam_vt_cam15_supply =
+       REGULATOR_SUPPLY("vdd_core", "6-003c");
+
+static struct regulator_init_data cam_vt_cam15_reg_init_data = {
+       .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS },
+       .num_consumer_supplies = 1,
+       .consumer_supplies = &cam_vt_cam15_supply,
+};
+
+static struct fixed_voltage_config cam_vt_cam15_fixed_voltage_cfg = {
+       .supply_name    = "VT_CAM_1.5V",
+       .microvolts     = 1500000,
+       .gpio           = EXYNOS4_GPE2(2), /* VT_CAM_1.5V_EN */
+       .enable_high    = 1,
+       .init_data      = &cam_vt_cam15_reg_init_data,
+};
+
+static struct platform_device cam_vt_cam15_fixed_rdev = {
+       .name = "reg-fixed-voltage", .id = FIXED_REG_ID_CAM_VT_15V,
+       .dev = { .platform_data = &cam_vt_cam15_fixed_voltage_cfg },
+};
+
 static struct regulator_consumer_supply cam_vdda_supply[] = {
+       REGULATOR_SUPPLY("vdda", "6-003c"),
        REGULATOR_SUPPLY("a_sensor", "0-001f"),
 };
 
@@ -1173,6 +1202,21 @@ static struct s5p_platform_mipi_csis mipi_csis_platdata = {
 
 #define GPIO_CAM_MEGA_RST      EXYNOS4_GPY3(7) /* ISP_RESET */
 #define GPIO_CAM_8M_ISP_INT    EXYNOS4_GPL2(5)
+#define GPIO_CAM_VT_NSTBY      EXYNOS4_GPL2(0)
+#define GPIO_CAM_VT_NRST       EXYNOS4_GPL2(1)
+
+static struct s5k6aa_platform_data s5k6aa_pldata = {
+       .mclk_frequency = 24000000UL,
+       .gpio_reset     = { GPIO_CAM_VT_NRST, 0 },
+       .gpio_stby      = { GPIO_CAM_VT_NSTBY, 0 },
+       .bus_type       = V4L2_MBUS_PARALLEL,
+       .horiz_flip     = 1,
+};
+
+static struct i2c_board_info s5k6aa_board_info = {
+       I2C_BOARD_INFO("S5K6AA", 0x3c),
+       .platform_data = &s5k6aa_pldata,
+};
 
 static struct m5mols_platform_data m5mols_platdata = {
        .gpio_reset = GPIO_CAM_MEGA_RST,
@@ -1185,6 +1229,13 @@ static struct i2c_board_info m5mols_board_info = {
 
 static struct s5p_fimc_isp_info nuri_camera_sensors[] = {
        {
+               .flags          = V4L2_MBUS_PCLK_SAMPLE_RISING |
+                                 V4L2_MBUS_VSYNC_ACTIVE_LOW,
+               .bus_type       = FIMC_ITU_601,
+               .board_info     = &s5k6aa_board_info,
+               .clk_frequency  = 24000000UL,
+               .i2c_bus_num    = 6,
+       }, {
                .flags          = V4L2_MBUS_PCLK_SAMPLE_FALLING |
                                  V4L2_MBUS_VSYNC_ACTIVE_LOW,
                .bus_type       = FIMC_MIPI_CSI2,
@@ -1200,11 +1251,13 @@ static struct s5p_platform_fimc fimc_md_platdata = {
 };
 
 static struct gpio nuri_camera_gpios[] = {
+       { GPIO_CAM_VT_NSTBY,    GPIOF_OUT_INIT_LOW, "CAM_VGA_NSTBY" },
+       { GPIO_CAM_VT_NRST,     GPIOF_OUT_INIT_LOW, "CAM_VGA_NRST"  },
        { GPIO_CAM_8M_ISP_INT,  GPIOF_IN,           "8M_ISP_INT"  },
        { GPIO_CAM_MEGA_RST,    GPIOF_OUT_INIT_LOW, "CAM_8M_NRST" },
 };
 
-static void nuri_camera_init(void)
+static void __init nuri_camera_init(void)
 {
        s3c_set_platdata(&mipi_csis_platdata, sizeof(mipi_csis_platdata),
                         &s5p_device_mipi_csis0);
@@ -1224,6 +1277,8 @@ static void nuri_camera_init(void)
                pr_err("%s: Failed to configure 8M_ISP_INT GPIO\n", __func__);
 
        /* Free GPIOs controlled directly by the sensor drivers. */
+       gpio_free(GPIO_CAM_VT_NRST);
+       gpio_free(GPIO_CAM_VT_NSTBY);
        gpio_free(GPIO_CAM_MEGA_RST);
 
        if (exynos4_fimc_setup_gpio(S5P_CAMPORT_A)) {
@@ -1234,15 +1289,27 @@ static void nuri_camera_init(void)
        s5p_gpio_set_drvstr(EXYNOS4_GPJ1(3), S5P_GPIO_DRVSTR_LV4);
 }
 
+static struct s3c2410_platform_i2c nuri_i2c6_platdata __initdata = {
+       .frequency      = 400000U,
+       .sda_delay      = 200,
+       .bus_num        = 6,
+};
+
 static struct s3c2410_platform_i2c nuri_i2c0_platdata __initdata = {
        .frequency      = 400000U,
        .sda_delay      = 200,
 };
 
+/* DEVFREQ controlling memory/bus */
+static struct platform_device exynos4_bus_devfreq = {
+       .name                   = "exynos4210-busfreq",
+};
+
 static struct platform_device *nuri_devices[] __initdata = {
        /* Samsung Platform Devices */
        &s3c_device_i2c5, /* PMIC should initialize first */
        &s3c_device_i2c0,
+       &s3c_device_i2c6,
        &emmc_fixed_voltage,
        &s5p_device_mipi_csis0,
        &s5p_device_fimc0,
@@ -1259,6 +1326,8 @@ static struct platform_device *nuri_devices[] __initdata = {
        &s3c_device_i2c3,
        &i2c9_gpio,
        &s3c_device_adc,
+       &s5p_device_g2d,
+       &s5p_device_jpeg,
        &s3c_device_rtc,
        &s5p_device_mfc,
        &s5p_device_mfc_l,
@@ -1271,8 +1340,10 @@ static struct platform_device *nuri_devices[] __initdata = {
        &nuri_backlight_device,
        &max8903_fixed_reg_dev,
        &nuri_max8903_device,
+       &cam_vt_cam15_fixed_rdev,
        &cam_vdda_fixed_rdev,
        &cam_8m_12v_fixed_rdev,
+       &exynos4_bus_devfreq,
 };
 
 static void __init nuri_map_io(void)
@@ -1302,6 +1373,7 @@ static void __init nuri_machine_init(void)
        i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
        i2c9_devs[I2C9_MAX17042].irq = gpio_to_irq(EXYNOS4_GPX2(3));
        i2c_register_board_info(9, i2c9_devs, ARRAY_SIZE(i2c9_devs));
+       s3c_i2c6_set_platdata(&nuri_i2c6_platdata);
 
        s5p_fimd0_set_platdata(&nuri_fb_pdata);
 
index fa5c4a5..878d4c9 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/mfd/max8997.h>
 #include <linux/lcd.h>
+#include <linux/rfkill-gpio.h>
 
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
@@ -235,6 +236,7 @@ static struct regulator_init_data __initdata max8997_ldo9_data = {
                .min_uV         = 2800000,
                .max_uV         = 2800000,
                .apply_uV       = 1,
+               .always_on      = 1,
                .valid_ops_mask = REGULATOR_CHANGE_STATUS,
                .state_mem      = {
                        .disabled       = 1,
@@ -278,6 +280,7 @@ static struct regulator_init_data __initdata max8997_ldo14_data = {
                .min_uV         = 1800000,
                .max_uV         = 1800000,
                .apply_uV       = 1,
+               .always_on      = 1,
                .valid_ops_mask = REGULATOR_CHANGE_STATUS,
                .state_mem      = {
                        .disabled       = 1,
@@ -293,6 +296,7 @@ static struct regulator_init_data __initdata max8997_ldo17_data = {
                .min_uV         = 3300000,
                .max_uV         = 3300000,
                .apply_uV       = 1,
+               .always_on      = 1,
                .valid_ops_mask = REGULATOR_CHANGE_STATUS,
                .state_mem      = {
                        .disabled       = 1,
@@ -412,7 +416,7 @@ static struct max8997_regulator_data __initdata origen_max8997_regulators[] = {
        { MAX8997_BUCK7,        &max8997_buck7_data },
 };
 
-struct max8997_platform_data __initdata origen_max8997_pdata = {
+static struct max8997_platform_data __initdata origen_max8997_pdata = {
        .num_regulators = ARRAY_SIZE(origen_max8997_regulators),
        .regulators     = origen_max8997_regulators,
 
@@ -602,6 +606,23 @@ static struct s3c_fb_platdata origen_lcd_pdata __initdata = {
        .setup_gpio     = exynos4_fimd0_gpio_setup_24bpp,
 };
 
+/* Bluetooth rfkill gpio platform data */
+struct rfkill_gpio_platform_data origen_bt_pdata = {
+       .reset_gpio     = EXYNOS4_GPX2(2),
+       .shutdown_gpio  = -1,
+       .type           = RFKILL_TYPE_BLUETOOTH,
+       .name           = "origen-bt",
+};
+
+/* Bluetooth Platform device */
+static struct platform_device origen_device_bluetooth = {
+       .name           = "rfkill_gpio",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &origen_bt_pdata,
+       },
+};
+
 static struct platform_device *origen_devices[] __initdata = {
        &s3c_device_hsmmc2,
        &s3c_device_hsmmc0,
@@ -613,9 +634,12 @@ static struct platform_device *origen_devices[] __initdata = {
        &s5p_device_fimc1,
        &s5p_device_fimc2,
        &s5p_device_fimc3,
+       &s5p_device_fimc_md,
        &s5p_device_fimd0,
+       &s5p_device_g2d,
        &s5p_device_hdmi,
        &s5p_device_i2c_hdmiphy,
+       &s5p_device_jpeg,
        &s5p_device_mfc,
        &s5p_device_mfc_l,
        &s5p_device_mfc_r,
@@ -623,6 +647,7 @@ static struct platform_device *origen_devices[] __initdata = {
        &exynos4_device_ohci,
        &origen_device_gpiokeys,
        &origen_lcd_hv070wsa,
+       &origen_device_bluetooth,
 };
 
 /* LCD Backlight data */
@@ -636,6 +661,16 @@ static struct platform_pwm_backlight_data origen_bl_data = {
        .pwm_period_ns  = 1000,
 };
 
+static void __init origen_bt_setup(void)
+{
+       gpio_request(EXYNOS4_GPA0(0), "GPIO BT_UART");
+       /* 4 UART Pins configuration */
+       s3c_gpio_cfgrange_nopull(EXYNOS4_GPA0(0), 4, S3C_GPIO_SFN(2));
+       /* Setup BT Reset, this gpio will be requesed by rfkill-gpio */
+       s3c_gpio_cfgpin(EXYNOS4_GPX2(2), S3C_GPIO_OUTPUT);
+       s3c_gpio_setpull(EXYNOS4_GPX2(2), S3C_GPIO_PULL_NONE);
+}
+
 static void s5p_tv_setup(void)
 {
        /* Direct HPD to HDMI chip */
@@ -689,6 +724,8 @@ static void __init origen_machine_init(void)
        platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices));
 
        samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data);
+
+       origen_bt_setup();
 }
 
 MACHINE_START(ORIGEN, "ORIGEN")
index 5258b85..83b91fa 100644 (file)
@@ -270,6 +270,9 @@ static struct platform_device *smdkv310_devices[] __initdata = {
        &s5p_device_fimc1,
        &s5p_device_fimc2,
        &s5p_device_fimc3,
+       &s5p_device_fimc_md,
+       &s5p_device_g2d,
+       &s5p_device_jpeg,
        &exynos4_device_ac97,
        &exynos4_device_i2s0,
        &exynos4_device_ohci,
index b2d495b..28658da 100644 (file)
@@ -47,6 +47,7 @@
 #include <media/v4l2-mediabus.h>
 #include <media/s5p_fimc.h>
 #include <media/m5mols.h>
+#include <media/s5k6aa.h>
 
 #include "common.h"
 
@@ -123,8 +124,10 @@ static struct regulator_consumer_supply lp3974_buck1_consumer =
 static struct regulator_consumer_supply lp3974_buck2_consumer =
        REGULATOR_SUPPLY("vddg3d", NULL);
 
-static struct regulator_consumer_supply lp3974_buck3_consumer =
-       REGULATOR_SUPPLY("vdet", "s5p-sdo");
+static struct regulator_consumer_supply lp3974_buck3_consumer[] = {
+       REGULATOR_SUPPLY("vdet", "s5p-sdo"),
+       REGULATOR_SUPPLY("vdd_reg", "0-003c"),
+};
 
 static struct regulator_init_data lp3974_buck1_data = {
        .constraints    = {
@@ -169,8 +172,8 @@ static struct regulator_init_data lp3974_buck3_data = {
                        .enabled        = 1,
                },
        },
-       .num_consumer_supplies = 1,
-       .consumer_supplies = &lp3974_buck3_consumer,
+       .num_consumer_supplies = ARRAY_SIZE(lp3974_buck3_consumer),
+       .consumer_supplies = lp3974_buck3_consumer,
 };
 
 static struct regulator_init_data lp3974_buck4_data = {
@@ -303,6 +306,9 @@ static struct regulator_init_data lp3974_ldo8_data = {
        .consumer_supplies = lp3974_ldo8_consumer,
 };
 
+static struct regulator_consumer_supply lp3974_ldo9_consumer =
+       REGULATOR_SUPPLY("vddio", "0-003c");
+
 static struct regulator_init_data lp3974_ldo9_data = {
        .constraints    = {
                .name           = "VCC_2.8V",
@@ -314,6 +320,8 @@ static struct regulator_init_data lp3974_ldo9_data = {
                        .enabled        = 1,
                },
        },
+       .num_consumer_supplies  = 1,
+       .consumer_supplies      = &lp3974_ldo9_consumer,
 };
 
 static struct regulator_init_data lp3974_ldo10_data = {
@@ -412,6 +420,7 @@ static struct regulator_init_data lp3974_ldo15_data = {
 };
 
 static struct regulator_consumer_supply lp3974_ldo16_consumer[] = {
+       REGULATOR_SUPPLY("vdda", "0-003c"),
        REGULATOR_SUPPLY("a_sensor", "0-001f"),
 };
 
@@ -743,7 +752,7 @@ static struct s3c_sdhci_platdata universal_hsmmc0_data __initdata = {
 };
 
 static struct regulator_consumer_supply mmc0_supplies[] = {
-       REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
+       REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.0"),
 };
 
 static struct regulator_init_data mmc0_fixed_voltage_init_data = {
@@ -819,6 +828,8 @@ static struct s3c_fb_pd_win universal_fb_win0 = {
        },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .virtual_x      = 480,
+       .virtual_y      = 2 * 800,
 };
 
 static struct s3c_fb_platdata universal_lcd_pdata __initdata = {
@@ -830,6 +841,28 @@ static struct s3c_fb_platdata universal_lcd_pdata __initdata = {
        .setup_gpio     = exynos4_fimd0_gpio_setup_24bpp,
 };
 
+static struct regulator_consumer_supply cam_vt_dio_supply =
+       REGULATOR_SUPPLY("vdd_core", "0-003c");
+
+static struct regulator_init_data cam_vt_dio_reg_init_data = {
+       .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS },
+       .num_consumer_supplies = 1,
+       .consumer_supplies = &cam_vt_dio_supply,
+};
+
+static struct fixed_voltage_config cam_vt_dio_fixed_voltage_cfg = {
+       .supply_name    = "CAM_VT_D_IO",
+       .microvolts     = 2800000,
+       .gpio           = EXYNOS4_GPE2(1), /* CAM_PWR_EN2 */
+       .enable_high    = 1,
+       .init_data      = &cam_vt_dio_reg_init_data,
+};
+
+static struct platform_device cam_vt_dio_fixed_reg_dev = {
+       .name = "reg-fixed-voltage", .id = FIXED_REG_ID_CAM_VT_DIO,
+       .dev = { .platform_data = &cam_vt_dio_fixed_voltage_cfg },
+};
+
 static struct regulator_consumer_supply cam_i_core_supply =
        REGULATOR_SUPPLY("core", "0-001f");
 
@@ -885,6 +918,28 @@ static struct s5p_platform_mipi_csis mipi_csis_platdata = {
 #define GPIO_CAM_LEVEL_EN(n)   EXYNOS4_GPE4(n + 3)
 #define GPIO_CAM_8M_ISP_INT    EXYNOS4_GPX1(5) /* XEINT_13 */
 #define GPIO_CAM_MEGA_nRST     EXYNOS4_GPE2(5)
+#define GPIO_CAM_VGA_NRST      EXYNOS4_GPE4(7)
+#define GPIO_CAM_VGA_NSTBY     EXYNOS4_GPE4(6)
+
+static int s5k6aa_set_power(int on)
+{
+       gpio_set_value(GPIO_CAM_LEVEL_EN(2), !!on);
+       return 0;
+}
+
+static struct s5k6aa_platform_data s5k6aa_platdata = {
+       .mclk_frequency = 21600000UL,
+       .gpio_reset     = { GPIO_CAM_VGA_NRST, 0 },
+       .gpio_stby      = { GPIO_CAM_VGA_NSTBY, 0 },
+       .bus_type       = V4L2_MBUS_PARALLEL,
+       .horiz_flip     = 1,
+       .set_power      = s5k6aa_set_power,
+};
+
+static struct i2c_board_info s5k6aa_board_info = {
+       I2C_BOARD_INFO("S5K6AA", 0x3C),
+       .platform_data = &s5k6aa_platdata,
+};
 
 static int m5mols_set_power(struct device *dev, int on)
 {
@@ -909,6 +964,14 @@ static struct s5p_fimc_isp_info universal_camera_sensors[] = {
                .mux_id         = 0,
                .flags          = V4L2_MBUS_PCLK_SAMPLE_FALLING |
                                  V4L2_MBUS_VSYNC_ACTIVE_LOW,
+               .bus_type       = FIMC_ITU_601,
+               .board_info     = &s5k6aa_board_info,
+               .i2c_bus_num    = 0,
+               .clk_frequency  = 24000000UL,
+       }, {
+               .mux_id         = 0,
+               .flags          = V4L2_MBUS_PCLK_SAMPLE_FALLING |
+                                 V4L2_MBUS_VSYNC_ACTIVE_LOW,
                .bus_type       = FIMC_MIPI_CSI2,
                .board_info     = &m5mols_board_info,
                .i2c_bus_num    = 0,
@@ -927,9 +990,11 @@ static struct gpio universal_camera_gpios[] = {
        { GPIO_CAM_LEVEL_EN(2), GPIOF_OUT_INIT_LOW,  "CAM_LVL_EN2" },
        { GPIO_CAM_8M_ISP_INT,  GPIOF_IN,            "8M_ISP_INT"  },
        { GPIO_CAM_MEGA_nRST,   GPIOF_OUT_INIT_LOW,  "CAM_8M_NRST" },
+       { GPIO_CAM_VGA_NRST,    GPIOF_OUT_INIT_LOW,  "CAM_VGA_NRST"  },
+       { GPIO_CAM_VGA_NSTBY,   GPIOF_OUT_INIT_LOW,  "CAM_VGA_NSTBY" },
 };
 
-static void universal_camera_init(void)
+static void __init universal_camera_init(void)
 {
        s3c_set_platdata(&mipi_csis_platdata, sizeof(mipi_csis_platdata),
                         &s5p_device_mipi_csis0);
@@ -950,6 +1015,8 @@ static void universal_camera_init(void)
        /* Free GPIOs controlled directly by the sensor drivers. */
        gpio_free(GPIO_CAM_MEGA_nRST);
        gpio_free(GPIO_CAM_8M_ISP_INT);
+       gpio_free(GPIO_CAM_VGA_NRST);
+       gpio_free(GPIO_CAM_VGA_NSTBY);
 
        if (exynos4_fimc_setup_gpio(S5P_CAMPORT_A))
                pr_err("Camera port A setup failed\n");
@@ -962,6 +1029,7 @@ static struct platform_device *universal_devices[] __initdata = {
        &s5p_device_fimc1,
        &s5p_device_fimc2,
        &s5p_device_fimc3,
+       &s5p_device_g2d,
        &mmc0_fixed_voltage,
        &s3c_device_hsmmc0,
        &s3c_device_hsmmc2,
@@ -980,9 +1048,11 @@ static struct platform_device *universal_devices[] __initdata = {
        &universal_gpio_keys,
        &s5p_device_onenand,
        &s5p_device_fimd0,
+       &s5p_device_jpeg,
        &s5p_device_mfc,
        &s5p_device_mfc_l,
        &s5p_device_mfc_r,
+       &cam_vt_dio_fixed_reg_dev,
        &cam_i_core_fixed_reg_dev,
        &cam_s_if_fixed_reg_dev,
        &s5p_device_fimc_md,
@@ -995,7 +1065,7 @@ static void __init universal_map_io(void)
        s3c24xx_init_uarts(universal_uartcfgs, ARRAY_SIZE(universal_uartcfgs));
 }
 
-void s5p_tv_setup(void)
+static void s5p_tv_setup(void)
 {
        /* direct HPD to HDMI chip */
        gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug");
index 85b5527..897d9a9 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/percpu.h>
 
 #include <asm/hardware/gic.h>
+#include <asm/localtimer.h>
 
 #include <plat/cpu.h>
 
 #include <mach/regs-mct.h>
 #include <asm/mach/time.h>
 
+#define TICK_BASE_CNT  1
+
 enum {
        MCT_INT_SPI,
        MCT_INT_PPI
 };
 
-static unsigned long clk_cnt_per_tick;
 static unsigned long clk_rate;
 static unsigned int mct_int_type;
 
@@ -205,11 +207,14 @@ static int exynos4_comp_set_next_event(unsigned long cycles,
 static void exynos4_comp_set_mode(enum clock_event_mode mode,
                                  struct clock_event_device *evt)
 {
+       unsigned long cycles_per_jiffy;
        exynos4_mct_comp0_stop();
 
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
-               exynos4_mct_comp0_start(mode, clk_cnt_per_tick);
+               cycles_per_jiffy =
+                       (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
+               exynos4_mct_comp0_start(mode, cycles_per_jiffy);
                break;
 
        case CLOCK_EVT_MODE_ONESHOT:
@@ -248,9 +253,7 @@ static struct irqaction mct_comp_event_irq = {
 
 static void exynos4_clockevent_init(void)
 {
-       clk_cnt_per_tick = clk_rate / 2 / HZ;
-
-       clockevents_calc_mult_shift(&mct_comp_device, clk_rate / 2, 5);
+       clockevents_calc_mult_shift(&mct_comp_device, clk_rate, 5);
        mct_comp_device.max_delta_ns =
                clockevent_delta2ns(0xffffffff, &mct_comp_device);
        mct_comp_device.min_delta_ns =
@@ -258,7 +261,10 @@ static void exynos4_clockevent_init(void)
        mct_comp_device.cpumask = cpumask_of(0);
        clockevents_register_device(&mct_comp_device);
 
-       setup_irq(IRQ_MCT_G0, &mct_comp_event_irq);
+       if (soc_is_exynos5250())
+               setup_irq(EXYNOS5_IRQ_MCT_G0, &mct_comp_event_irq);
+       else
+               setup_irq(EXYNOS4_IRQ_MCT_G0, &mct_comp_event_irq);
 }
 
 #ifdef CONFIG_LOCAL_TIMERS
@@ -314,12 +320,15 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
                                         struct clock_event_device *evt)
 {
        struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
+       unsigned long cycles_per_jiffy;
 
        exynos4_mct_tick_stop(mevt);
 
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
-               exynos4_mct_tick_start(clk_cnt_per_tick, mevt);
+               cycles_per_jiffy =
+                       (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
+               exynos4_mct_tick_start(cycles_per_jiffy, mevt);
                break;
 
        case CLOCK_EVT_MODE_ONESHOT:
@@ -375,7 +384,7 @@ static struct irqaction mct_tick1_event_irq = {
        .handler        = exynos4_mct_tick_isr,
 };
 
-static void exynos4_mct_tick_init(struct clock_event_device *evt)
+static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
 {
        struct mct_clock_event_device *mevt;
        unsigned int cpu = smp_processor_id();
@@ -393,7 +402,7 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt)
        evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
        evt->rating = 450;
 
-       clockevents_calc_mult_shift(evt, clk_rate / 2, 5);
+       clockevents_calc_mult_shift(evt, clk_rate / (TICK_BASE_CNT + 1), 5);
        evt->max_delta_ns =
                clockevent_delta2ns(0x7fffffff, evt);
        evt->min_delta_ns =
@@ -401,33 +410,27 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt)
 
        clockevents_register_device(evt);
 
-       exynos4_mct_write(0x1, mevt->base + MCT_L_TCNTB_OFFSET);
+       exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
 
        if (mct_int_type == MCT_INT_SPI) {
                if (cpu == 0) {
                        mct_tick0_event_irq.dev_id = mevt;
-                       evt->irq = IRQ_MCT_L0;
-                       setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq);
+                       evt->irq = EXYNOS4_IRQ_MCT_L0;
+                       setup_irq(EXYNOS4_IRQ_MCT_L0, &mct_tick0_event_irq);
                } else {
                        mct_tick1_event_irq.dev_id = mevt;
-                       evt->irq = IRQ_MCT_L1;
-                       setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq);
-                       irq_set_affinity(IRQ_MCT_L1, cpumask_of(1));
+                       evt->irq = EXYNOS4_IRQ_MCT_L1;
+                       setup_irq(EXYNOS4_IRQ_MCT_L1, &mct_tick1_event_irq);
+                       irq_set_affinity(EXYNOS4_IRQ_MCT_L1, cpumask_of(1));
                }
        } else {
-               enable_percpu_irq(IRQ_MCT_LOCALTIMER, 0);
+               enable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, 0);
        }
-}
-
-/* Setup the local clock events for a CPU */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       exynos4_mct_tick_init(evt);
 
        return 0;
 }
 
-void local_timer_stop(struct clock_event_device *evt)
+static void exynos4_local_timer_stop(struct clock_event_device *evt)
 {
        unsigned int cpu = smp_processor_id();
        evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
@@ -437,8 +440,13 @@ void local_timer_stop(struct clock_event_device *evt)
                else
                        remove_irq(evt->irq, &mct_tick1_event_irq);
        else
-               disable_percpu_irq(IRQ_MCT_LOCALTIMER);
+               disable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER);
 }
+
+static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = {
+       .setup  = exynos4_local_timer_setup,
+       .stop   = exynos4_local_timer_stop,
+};
 #endif /* CONFIG_LOCAL_TIMERS */
 
 static void __init exynos4_timer_resources(void)
@@ -452,12 +460,14 @@ static void __init exynos4_timer_resources(void)
        if (mct_int_type == MCT_INT_PPI) {
                int err;
 
-               err = request_percpu_irq(IRQ_MCT_LOCALTIMER,
+               err = request_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER,
                                         exynos4_mct_tick_isr, "MCT",
                                         &percpu_mct_tick);
                WARN(err, "MCT: can't request IRQ %d (%d)\n",
-                    IRQ_MCT_LOCALTIMER, err);
+                    EXYNOS_IRQ_MCT_LOCALTIMER, err);
        }
+
+       local_timer_register(&exynos4_mct_tick_ops);
 #endif /* CONFIG_LOCAL_TIMERS */
 }
 
index 0f2035a..36c3984 100644 (file)
@@ -166,7 +166,10 @@ void __init smp_init_cpus(void)
        void __iomem *scu_base = scu_base_addr();
        unsigned int i, ncores;
 
-       ncores = scu_base ? scu_get_core_count(scu_base) : 1;
+       if (soc_is_exynos5250())
+               ncores = 2;
+       else
+               ncores = scu_base ? scu_get_core_count(scu_base) : 1;
 
        /* sanity check */
        if (ncores > nr_cpu_ids) {
@@ -183,8 +186,8 @@ void __init smp_init_cpus(void)
 
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
 {
-
-       scu_enable(scu_base_addr());
+       if (!soc_is_exynos5250())
+               scu_enable(scu_base_addr());
 
        /*
         * Write the address of secondary startup into the
index e190130..428cfeb 100644 (file)
 #include <mach/pmu.h>
 
 static struct sleep_save exynos4_set_clksrc[] = {
-       { .reg = S5P_CLKSRC_MASK_TOP                    , .val = 0x00000001, },
-       { .reg = S5P_CLKSRC_MASK_CAM                    , .val = 0x11111111, },
-       { .reg = S5P_CLKSRC_MASK_TV                     , .val = 0x00000111, },
-       { .reg = S5P_CLKSRC_MASK_LCD0                   , .val = 0x00001111, },
-       { .reg = S5P_CLKSRC_MASK_MAUDIO                 , .val = 0x00000001, },
-       { .reg = S5P_CLKSRC_MASK_FSYS                   , .val = 0x01011111, },
-       { .reg = S5P_CLKSRC_MASK_PERIL0                 , .val = 0x01111111, },
-       { .reg = S5P_CLKSRC_MASK_PERIL1                 , .val = 0x01110111, },
-       { .reg = S5P_CLKSRC_MASK_DMC                    , .val = 0x00010000, },
+       { .reg = EXYNOS4_CLKSRC_MASK_TOP                , .val = 0x00000001, },
+       { .reg = EXYNOS4_CLKSRC_MASK_CAM                , .val = 0x11111111, },
+       { .reg = EXYNOS4_CLKSRC_MASK_TV                 , .val = 0x00000111, },
+       { .reg = EXYNOS4_CLKSRC_MASK_LCD0               , .val = 0x00001111, },
+       { .reg = EXYNOS4_CLKSRC_MASK_MAUDIO             , .val = 0x00000001, },
+       { .reg = EXYNOS4_CLKSRC_MASK_FSYS               , .val = 0x01011111, },
+       { .reg = EXYNOS4_CLKSRC_MASK_PERIL0             , .val = 0x01111111, },
+       { .reg = EXYNOS4_CLKSRC_MASK_PERIL1             , .val = 0x01110111, },
+       { .reg = EXYNOS4_CLKSRC_MASK_DMC                , .val = 0x00010000, },
 };
 
 static struct sleep_save exynos4210_set_clksrc[] = {
-       { .reg = S5P_CLKSRC_MASK_LCD1                   , .val = 0x00001111, },
+       { .reg = EXYNOS4210_CLKSRC_MASK_LCD1            , .val = 0x00001111, },
 };
 
 static struct sleep_save exynos4_epll_save[] = {
-       SAVE_ITEM(S5P_EPLL_CON0),
-       SAVE_ITEM(S5P_EPLL_CON1),
+       SAVE_ITEM(EXYNOS4_EPLL_CON0),
+       SAVE_ITEM(EXYNOS4_EPLL_CON1),
 };
 
 static struct sleep_save exynos4_vpll_save[] = {
-       SAVE_ITEM(S5P_VPLL_CON0),
-       SAVE_ITEM(S5P_VPLL_CON1),
+       SAVE_ITEM(EXYNOS4_VPLL_CON0),
+       SAVE_ITEM(EXYNOS4_VPLL_CON1),
 };
 
 static struct sleep_save exynos4_core_save[] = {
@@ -155,13 +155,6 @@ static struct sleep_save exynos4_core_save[] = {
        SAVE_ITEM(S5P_SROM_BC3),
 };
 
-static struct sleep_save exynos4_l2cc_save[] = {
-       SAVE_ITEM(S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL),
-       SAVE_ITEM(S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL),
-       SAVE_ITEM(S5P_VA_L2CC + L2X0_PREFETCH_CTRL),
-       SAVE_ITEM(S5P_VA_L2CC + L2X0_POWER_CTRL),
-       SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL),
-};
 
 /* For Cortex-A9 Diagnostic and Power control register */
 static unsigned int save_arm_register[2];
@@ -182,7 +175,6 @@ static void exynos4_pm_prepare(void)
        u32 tmp;
 
        s3c_pm_do_save(exynos4_core_save, ARRAY_SIZE(exynos4_core_save));
-       s3c_pm_do_save(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save));
        s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save));
        s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save));
 
@@ -239,7 +231,7 @@ static void exynos4_restore_pll(void)
                locktime = (3000 / pll_in_rate) * p_div;
                lockcnt = locktime * 10000 / (10000 / pll_in_rate);
 
-               __raw_writel(lockcnt, S5P_EPLL_LOCK);
+               __raw_writel(lockcnt, EXYNOS4_EPLL_LOCK);
 
                s3c_pm_do_restore_core(exynos4_epll_save,
                                        ARRAY_SIZE(exynos4_epll_save));
@@ -257,7 +249,7 @@ static void exynos4_restore_pll(void)
                locktime = 750;
                lockcnt = locktime * 10000 / (10000 / pll_in_rate);
 
-               __raw_writel(lockcnt, S5P_VPLL_LOCK);
+               __raw_writel(lockcnt, EXYNOS4_VPLL_LOCK);
 
                s3c_pm_do_restore_core(exynos4_vpll_save,
                                        ARRAY_SIZE(exynos4_vpll_save));
@@ -268,14 +260,14 @@ static void exynos4_restore_pll(void)
 
        do {
                if (epll_wait) {
-                       pll_con = __raw_readl(S5P_EPLL_CON0);
-                       if (pll_con & (1 << S5P_EPLLCON0_LOCKED_SHIFT))
+                       pll_con = __raw_readl(EXYNOS4_EPLL_CON0);
+                       if (pll_con & (1 << EXYNOS4_EPLLCON0_LOCKED_SHIFT))
                                epll_wait = 0;
                }
 
                if (vpll_wait) {
-                       pll_con = __raw_readl(S5P_VPLL_CON0);
-                       if (pll_con & (1 << S5P_VPLLCON0_LOCKED_SHIFT))
+                       pll_con = __raw_readl(EXYNOS4_VPLL_CON0);
+                       if (pll_con & (1 << EXYNOS4_VPLLCON0_LOCKED_SHIFT))
                                vpll_wait = 0;
                }
        } while (epll_wait || vpll_wait);
@@ -388,13 +380,6 @@ static void exynos4_pm_resume(void)
        scu_enable(S5P_VA_SCU);
 #endif
 
-#ifdef CONFIG_CACHE_L2X0
-       s3c_pm_do_restore_core(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save));
-       outer_inv_all();
-       /* enable L2X0*/
-       writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL);
-#endif
-
 early_wakeup:
        return;
 }
index 0b04af2..13b3068 100644 (file)
@@ -183,6 +183,12 @@ static __init int exynos4_pm_init_power_domain(void)
 #ifdef CONFIG_S5P_DEV_CSIS1
        exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis1, &exynos4_pd_cam);
 #endif
+#ifdef CONFIG_S5P_DEV_G2D
+       exynos_pm_add_dev_to_genpd(&s5p_device_g2d, &exynos4_pd_lcd0);
+#endif
+#ifdef CONFIG_S5P_DEV_JPEG
+       exynos_pm_add_dev_to_genpd(&s5p_device_jpeg, &exynos4_pd_cam);
+#endif
        return 0;
 }
 arch_initcall(exynos4_pm_init_power_domain);
index d395bd1..b90d94c 100644 (file)
@@ -1,7 +1,5 @@
 /*
- * linux/arch/arm/mach-exynos4/setup-i2c0.c
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2009-2012 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  *
  * I2C0 GPIO configuration.
@@ -18,9 +16,14 @@ struct platform_device; /* don't need the contents */
 #include <linux/gpio.h>
 #include <plat/iic.h>
 #include <plat/gpio-cfg.h>
+#include <plat/cpu.h>
 
 void s3c_i2c0_cfg_gpio(struct platform_device *dev)
 {
+       if (soc_is_exynos5250())
+               /* will be implemented with gpio function */
+               return;
+
        s3c_gpio_cfgall_range(EXYNOS4_GPD1(0), 2,
                              S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 }
index 94a7087..e17e11d 100644 (file)
@@ -274,11 +274,13 @@ int __init dc21285_setup(int nr, struct pci_sys_data *sys)
        allocate_resource(&iomem_resource, &res[0], 0x40000000,
                          0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
 
-       pci_add_resource(&sys->resources, &ioport_resource);
-       pci_add_resource(&sys->resources, &res[0]);
-       pci_add_resource(&sys->resources, &res[1]);
        sys->mem_offset  = DC21285_PCI_MEM;
 
+       pci_add_resource_offset(&sys->resources,
+                               &ioport_resource, sys->io_offset);
+       pci_add_resource_offset(&sys->resources, &res[0], sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+
        return 1;
 }
 
index d3847be..dabbd5c 100644 (file)
@@ -14,9 +14,6 @@
                .equ    dc21285_high, ARMCSR_BASE & 0xff000000
                .equ    dc21285_low, ARMCSR_BASE & 0x00ffffff
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                mov     \base, #dc21285_high
                .if     dc21285_low
@@ -24,9 +21,6 @@
                .endif
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \irqstat, [\base, #0x180]       @ get interrupts
 
diff --git a/arch/arm/mach-footbridge/include/mach/system.h b/arch/arm/mach-footbridge/include/mach/system.h
deleted file mode 100644 (file)
index a174a58..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- *  arch/arm/mach-footbridge/include/mach/system.h
- *
- *  Copyright (C) 1996-1999 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
index c5b24b9..7355c0b 100644 (file)
@@ -4,7 +4,7 @@
 
 # Object file lists.
 
-obj-y                  := irq.o mm.o time.o devices.o gpio.o
+obj-y                  := irq.o mm.o time.o devices.o gpio.o idle.o
 
 # Board-specific support
 obj-$(CONFIG_MACH_NAS4220B)    += board-nas4220b.o
diff --git a/arch/arm/mach-gemini/idle.c b/arch/arm/mach-gemini/idle.c
new file mode 100644 (file)
index 0000000..92bbd6b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-gemini/idle.c
+ */
+
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/proc-fns.h>
+
+static void gemini_idle(void)
+{
+       /*
+        * Because of broken hardware we have to enable interrupts or the CPU
+        * will never wakeup... Acctualy it is not very good to enable
+        * interrupts first since scheduler can miss a tick, but there is
+        * no other way around this. Platforms that needs it for power saving
+        * should call enable_hlt() in init code, since by default it is
+        * disabled.
+        */
+       local_irq_enable();
+       cpu_do_idle();
+}
+
+static int __init gemini_idle_init(void)
+{
+       arm_pm_idle = gemini_idle;
+       return 0;
+}
+
+arch_initcall(gemini_idle_init);
index 1624f91..f044e43 100644 (file)
 
 #define IRQ_STATUS     0x14
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
        ldr     \irqstat, =IO_ADDRESS(GEMINI_INTERRUPT_BASE + IRQ_STATUS)
        ldr     \irqnr, [\irqstat]
index 4d9c1f8..a33b5a1 100644 (file)
 #include <mach/hardware.h>
 #include <mach/global_reg.h>
 
-static inline void arch_idle(void)
-{
-       /*
-        * Because of broken hardware we have to enable interrupts or the CPU
-        * will never wakeup... Acctualy it is not very good to enable
-        * interrupts here since scheduler can miss a tick, but there is
-        * no other way around this. Platforms that needs it for power saving
-        * should call enable_hlt() in init code, since by default it is
-        * disabled.
-        */
-       local_irq_enable();
-       cpu_do_idle();
-}
-
 static inline void arch_reset(char mode, const char *cmd)
 {
        __raw_writel(RESET_GLOBAL | RESET_CPU1,
index 9485a8f..ca70e5f 100644 (file)
@@ -73,8 +73,8 @@ void __init gemini_init_irq(void)
        unsigned int i, mode = 0, level = 0;
 
        /*
-        * Disable arch_idle() by default since it is buggy
-        * For more info see arch/arm/mach-gemini/include/mach/system.h
+        * Disable the idle handler by default since it is buggy
+        * For more info see arch/arm/mach-gemini/idle.c
         */
        disable_hlt();
 
index f8a2f6b..e756d1a 100644 (file)
@@ -247,3 +247,21 @@ void h720x_restart(char mode, const char *cmd)
 {
        CPU_REG (PMU_BASE, PMU_STAT) |= PMU_WARMRESET;
 }
+
+static void h720x__idle(void)
+{
+       CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_IDLE;
+       nop();
+       nop();
+       CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_RUN;
+       nop();
+       nop();
+}
+
+static int __init h720x_idle_init(void)
+{
+       arm_pm_idle = h720x__idle;
+       return 0;
+}
+
+arch_initcall(h720x_idle_init);
index c3948e5..75267fa 100644 (file)
@@ -8,15 +8,9 @@
  * warranty of any kind, whether express or implied.
  */
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 #if defined (CONFIG_CPU_H7201) || defined (CONFIG_CPU_H7202)
                @ we could use the id register on H7202, but this is not
diff --git a/arch/arm/mach-h720x/include/mach/system.h b/arch/arm/mach-h720x/include/mach/system.h
deleted file mode 100644 (file)
index 16ac46e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-h720x/include/mach/system.h
- *
- * Copyright (C) 2001-2002 Jungjun Kim, Hynix Semiconductor Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- * arch/arm/mach-h720x/include/mach/system.h
- *
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-#include <mach/hardware.h>
-
-static void arch_idle(void)
-{
-       CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_IDLE;
-       nop();
-       nop();
-       CPU_REG (PMU_BASE, PMU_MODE) = PMU_MODE_RUN;
-       nop();
-       nop();
-}
-
-#endif
index 986958a..f8437dd 100644 (file)
@@ -1,6 +1,5 @@
 obj-y                                  := clock.o highbank.o system.o
 obj-$(CONFIG_DEBUG_HIGHBANK_UART)      += lluart.o
 obj-$(CONFIG_SMP)                      += platsmp.o
-obj-$(CONFIG_LOCAL_TIMERS)             += localtimer.o
 obj-$(CONFIG_HOTPLUG_CPU)              += hotplug.o
 obj-$(CONFIG_PM_SLEEP)                 += pm.o
index 8394d51..808b055 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/cacheflush.h>
 #include <asm/smp_plat.h>
 #include <asm/smp_scu.h>
+#include <asm/smp_twd.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/timer-sp.h>
 #include <asm/hardware/gic.h>
@@ -109,8 +110,10 @@ static void __init highbank_timer_init(void)
 
        highbank_clocks_init();
 
-       sp804_clocksource_init(timer_base + 0x20, "timer1");
+       sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1");
        sp804_clockevents_init(timer_base, irq, "timer0");
+
+       twd_local_timer_of_register();
 }
 
 static struct sys_timer highbank_timer = {
diff --git a/arch/arm/mach-highbank/include/mach/entry-macro.S b/arch/arm/mach-highbank/include/mach/entry-macro.S
deleted file mode 100644 (file)
index a14f9e6..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
diff --git a/arch/arm/mach-highbank/include/mach/memory.h b/arch/arm/mach-highbank/include/mach/memory.h
deleted file mode 100644 (file)
index 40a8c17..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
diff --git a/arch/arm/mach-highbank/include/mach/system.h b/arch/arm/mach-highbank/include/mach/system.h
deleted file mode 100644 (file)
index b1d8b5f..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2010-2011 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/>.
- */
-#ifndef __MACH_SYSTEM_H
-#define __MACH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
diff --git a/arch/arm/mach-highbank/localtimer.c b/arch/arm/mach-highbank/localtimer.c
deleted file mode 100644 (file)
index 5a00e79..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2010-2011 Calxeda, Inc.
- * Based on localtimer.c, Copyright (C) 2002 ARM Ltd.
- *
- * 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/init.h>
-#include <linux/clockchips.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-#include <asm/smp_twd.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       struct device_node *np;
-
-       np = of_find_compatible_node(NULL, NULL, "arm,smp-twd");
-       if (!twd_base) {
-               twd_base = of_iomap(np, 0);
-               WARN_ON(!twd_base);
-       }
-       evt->irq = irq_of_parse_and_map(np, 0);
-       twd_timer_setup(evt);
-       return 0;
-}
index 3919fba..52359f8 100644 (file)
@@ -298,6 +298,7 @@ config MACH_MX27_3DS
        select IMX_HAVE_PLATFORM_IMX_I2C
        select IMX_HAVE_PLATFORM_IMX_KEYPAD
        select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MX2_CAMERA
        select IMX_HAVE_PLATFORM_MXC_EHCI
        select IMX_HAVE_PLATFORM_MXC_MMC
        select IMX_HAVE_PLATFORM_SPI_IMX
@@ -314,8 +315,10 @@ config MACH_IMX27_VISSTRIM_M10
        select IMX_HAVE_PLATFORM_IMX_I2C
        select IMX_HAVE_PLATFORM_IMX_SSI
        select IMX_HAVE_PLATFORM_IMX_UART
-       select IMX_HAVE_PLATFORM_MXC_MMC
+       select IMX_HAVE_PLATFORM_MX2_CAMERA
        select IMX_HAVE_PLATFORM_MXC_EHCI
+       select IMX_HAVE_PLATFORM_MXC_MMC
+       select LEDS_GPIO_REGISTER
        help
          Include support for Visstrim_m10 platform and its different variants.
          This includes specific configurations for the board and its
@@ -370,6 +373,14 @@ config MACH_IMX27IPCAM
          Include support for IMX27 IPCAM platform. This includes specific
          configurations for the board and its peripherals.
 
+config MACH_IMX27_DT
+       bool "Support i.MX27 platforms from device tree"
+       select SOC_IMX27
+       select USE_OF
+       help
+         Include support for Freescale i.MX27 based platforms
+         using the device tree for discovery
+
 endif
 
 if ARCH_IMX_V6_V7
@@ -486,6 +497,7 @@ config MACH_MX31MOBOARD
        bool "Support mx31moboard platforms (EPFL Mobots group)"
        select SOC_IMX31
        select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+       select IMX_HAVE_PLATFORM_IMX2_WDT
        select IMX_HAVE_PLATFORM_IMX_I2C
        select IMX_HAVE_PLATFORM_IMX_UART
        select IMX_HAVE_PLATFORM_IPU_CORE
index 55db9c4..35fc450 100644 (file)
@@ -8,8 +8,8 @@ obj-$(CONFIG_SOC_IMX25) += clock-imx25.o mm-imx25.o ehci-imx25.o cpu-imx25.o
 obj-$(CONFIG_SOC_IMX27) += cpu-imx27.o pm-imx27.o
 obj-$(CONFIG_SOC_IMX27) += clock-imx27.o mm-imx27.o ehci-imx27.o
 
-obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o
-obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o
+obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o
+obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o pm-imx3.o
 
 obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o
 
@@ -41,6 +41,7 @@ obj-$(CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD) += eukrea_mbimx27-baseboard.o
 obj-$(CONFIG_MACH_PCA100) += mach-pca100.o
 obj-$(CONFIG_MACH_MXT_TD60) += mach-mxt_td60.o
 obj-$(CONFIG_MACH_IMX27IPCAM) += mach-imx27ipcam.o
+obj-$(CONFIG_MACH_IMX27_DT) += imx27-dt.o
 
 # i.MX31 based machines
 obj-$(CONFIG_MACH_MX31ADS) += mach-mx31ads.o
@@ -71,7 +72,6 @@ obj-$(CONFIG_CPU_V7) += head-v7.o
 AFLAGS_head-v7.o :=-Wa,-march=armv7-a
 obj-$(CONFIG_SMP) += platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
 obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o
 
 ifeq ($(CONFIG_PM),y)
index 6dfdbcc..3851d8a 100644 (file)
@@ -38,5 +38,8 @@ zreladdr-$(CONFIG_SOC_IMX6Q)  += 0x10008000
 params_phys-$(CONFIG_SOC_IMX6Q)        := 0x10000100
 initrd_phys-$(CONFIG_SOC_IMX6Q)        := 0x10800000
 
+dtb-$(CONFIG_MACH_IMX51_DT) += imx51-babbage.dtb
+dtb-$(CONFIG_MACH_IMX53_DT) += imx53-ard.dtb imx53-evk.dtb \
+                              imx53-qsb.dtb imx53-smd.dtb
 dtb-$(CONFIG_SOC_IMX6Q)        += imx6q-arm2.dtb \
                           imx6q-sabrelite.dtb
index 88fe00a..b9a95ed 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/clkdev.h>
+#include <linux/of.h>
 
 #include <asm/div64.h>
 
@@ -661,7 +662,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "dma", dma_clk)
        _REGISTER_CLOCK(NULL, "rtic", rtic_clk)
        _REGISTER_CLOCK(NULL, "brom", brom_clk)
-       _REGISTER_CLOCK(NULL, "emma", emma_clk)
+       _REGISTER_CLOCK("m2m-emmaprp.0", NULL, emma_clk)
        _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk)
        _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK(NULL, "emi", emi_clk)
@@ -764,3 +765,20 @@ int __init mx27_clocks_init(unsigned long fref)
        return 0;
 }
 
+#ifdef CONFIG_OF
+int __init mx27_clocks_init_dt(void)
+{
+       struct device_node *np;
+       u32 fref = 26000000; /* default */
+
+       for_each_compatible_node(np, NULL, "fixed-clock") {
+               if (!of_device_is_compatible(np, "fsl,imx-osc26m"))
+                       continue;
+
+               if (!of_property_read_u32(np, "clock-frequency", &fref))
+                       break;
+       }
+
+       return mx27_clocks_init(fref);
+}
+#endif
index 988a281..3a943cd 100644 (file)
@@ -32,7 +32,7 @@
 #include <mach/mx31.h>
 #include <mach/common.h>
 
-#include "crmregs-imx31.h"
+#include "crmregs-imx3.h"
 
 #define PRE_DIV_MIN_FREQ    10000000 /* Minimum Frequency after Predivider */
 
index ac8238c..1e279af 100644 (file)
 #include <mach/hardware.h>
 #include <mach/common.h>
 
-#define CCM_BASE       MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR)
-
-#define CCM_CCMR        0x00
-#define CCM_PDR0        0x04
-#define CCM_PDR1        0x08
-#define CCM_PDR2        0x0C
-#define CCM_PDR3        0x10
-#define CCM_PDR4        0x14
-#define CCM_RCSR        0x18
-#define CCM_MPCTL       0x1C
-#define CCM_PPCTL       0x20
-#define CCM_ACMR        0x24
-#define CCM_COSR        0x28
-#define CCM_CGR0        0x2C
-#define CCM_CGR1        0x30
-#define CCM_CGR2        0x34
-#define CCM_CGR3        0x38
+#include "crmregs-imx3.h"
 
 #ifdef HAVE_SET_RATE_SUPPORT
 static void calc_dividers(u32 div, u32 *pre, u32 *post, u32 maxpost)
@@ -111,14 +95,14 @@ static void calc_dividers_3_3(u32 div, u32 *pre, u32 *post)
 
 static unsigned long get_rate_mpll(void)
 {
-       ulong mpctl = __raw_readl(CCM_BASE + CCM_MPCTL);
+       ulong mpctl = __raw_readl(MX35_CCM_MPCTL);
 
        return mxc_decode_pll(mpctl, 24000000);
 }
 
 static unsigned long get_rate_ppll(void)
 {
-       ulong ppctl = __raw_readl(CCM_BASE + CCM_PPCTL);
+       ulong ppctl = __raw_readl(MX35_CCM_PPCTL);
 
        return mxc_decode_pll(ppctl, 24000000);
 }
@@ -148,7 +132,7 @@ static struct arm_ahb_div clk_consumer[] = {
 
 static unsigned long get_rate_arm(void)
 {
-       unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0);
+       unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0);
        struct arm_ahb_div *aad;
        unsigned long fref = get_rate_mpll();
 
@@ -161,7 +145,7 @@ static unsigned long get_rate_arm(void)
 
 static unsigned long get_rate_ahb(struct clk *clk)
 {
-       unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0);
+       unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0);
        struct arm_ahb_div *aad;
        unsigned long fref = get_rate_arm();
 
@@ -177,8 +161,8 @@ static unsigned long get_rate_ipg(struct clk *clk)
 
 static unsigned long get_rate_uart(struct clk *clk)
 {
-       unsigned long pdr3 = __raw_readl(CCM_BASE + CCM_PDR3);
-       unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4);
+       unsigned long pdr3 = __raw_readl(MX35_CCM_PDR3);
+       unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4);
        unsigned long div = ((pdr4 >> 10) & 0x3f) + 1;
 
        if (pdr3 & (1 << 14))
@@ -189,7 +173,7 @@ static unsigned long get_rate_uart(struct clk *clk)
 
 static unsigned long get_rate_sdhc(struct clk *clk)
 {
-       unsigned long pdr3 = __raw_readl(CCM_BASE + CCM_PDR3);
+       unsigned long pdr3 = __raw_readl(MX35_CCM_PDR3);
        unsigned long div, rate;
 
        if (pdr3 & (1 << 6))
@@ -215,7 +199,7 @@ static unsigned long get_rate_sdhc(struct clk *clk)
 
 static unsigned long get_rate_mshc(struct clk *clk)
 {
-       unsigned long pdr1 = __raw_readl(CCM_BASE + CCM_PDR1);
+       unsigned long pdr1 = __raw_readl(MXC_CCM_PDR1);
        unsigned long div1, div2, rate;
 
        if (pdr1 & (1 << 7))
@@ -231,7 +215,7 @@ static unsigned long get_rate_mshc(struct clk *clk)
 
 static unsigned long get_rate_ssi(struct clk *clk)
 {
-       unsigned long pdr2 = __raw_readl(CCM_BASE + CCM_PDR2);
+       unsigned long pdr2 = __raw_readl(MX35_CCM_PDR2);
        unsigned long div1, div2, rate;
 
        if (pdr2 & (1 << 6))
@@ -256,7 +240,7 @@ static unsigned long get_rate_ssi(struct clk *clk)
 
 static unsigned long get_rate_csi(struct clk *clk)
 {
-       unsigned long pdr2 = __raw_readl(CCM_BASE + CCM_PDR2);
+       unsigned long pdr2 = __raw_readl(MX35_CCM_PDR2);
        unsigned long rate;
 
        if (pdr2 & (1 << 7))
@@ -269,7 +253,7 @@ static unsigned long get_rate_csi(struct clk *clk)
 
 static unsigned long get_rate_otg(struct clk *clk)
 {
-       unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4);
+       unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4);
        unsigned long rate;
 
        if (pdr4 & (1 << 9))
@@ -282,8 +266,8 @@ static unsigned long get_rate_otg(struct clk *clk)
 
 static unsigned long get_rate_ipg_per(struct clk *clk)
 {
-       unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0);
-       unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4);
+       unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0);
+       unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4);
        unsigned long div;
 
        if (pdr0 & (1 << 26)) {
@@ -297,7 +281,7 @@ static unsigned long get_rate_ipg_per(struct clk *clk)
 
 static unsigned long get_rate_hsp(struct clk *clk)
 {
-       unsigned long hsp_podf = (__raw_readl(CCM_BASE + CCM_PDR0) >> 20) & 0x03;
+       unsigned long hsp_podf = (__raw_readl(MXC_CCM_PDR0) >> 20) & 0x03;
        unsigned long fref = get_rate_mpll();
 
        if (fref > 400 * 1000 * 1000) {
@@ -345,7 +329,7 @@ static void clk_cgr_disable(struct clk *clk)
 #define DEFINE_CLOCK(name, i, er, es, gr, sr)          \
        static struct clk name = {                      \
                .id             = i,                    \
-               .enable_reg     = CCM_BASE + er,        \
+               .enable_reg     = er,                   \
                .enable_shift   = es,                   \
                .get_rate       = gr,                   \
                .set_rate       = sr,                   \
@@ -353,59 +337,59 @@ static void clk_cgr_disable(struct clk *clk)
                .disable        = clk_cgr_disable,      \
        }
 
-DEFINE_CLOCK(asrc_clk,   0, CCM_CGR0,  0, NULL, NULL);
-DEFINE_CLOCK(pata_clk,    0, CCM_CGR0,  2, get_rate_ipg, NULL);
-/* DEFINE_CLOCK(audmux_clk, 0, CCM_CGR0,  4, NULL, NULL); */
-DEFINE_CLOCK(can1_clk,   0, CCM_CGR0,  6, get_rate_ipg, NULL);
-DEFINE_CLOCK(can2_clk,   1, CCM_CGR0,  8, get_rate_ipg, NULL);
-DEFINE_CLOCK(cspi1_clk,  0, CCM_CGR0, 10, get_rate_ipg, NULL);
-DEFINE_CLOCK(cspi2_clk,  1, CCM_CGR0, 12, get_rate_ipg, NULL);
-DEFINE_CLOCK(ect_clk,    0, CCM_CGR0, 14, get_rate_ipg, NULL);
-DEFINE_CLOCK(edio_clk,   0, CCM_CGR0, 16, NULL, NULL);
-DEFINE_CLOCK(emi_clk,    0, CCM_CGR0, 18, get_rate_ipg, NULL);
-DEFINE_CLOCK(epit1_clk,  0, CCM_CGR0, 20, get_rate_ipg, NULL);
-DEFINE_CLOCK(epit2_clk,  1, CCM_CGR0, 22, get_rate_ipg, NULL);
-DEFINE_CLOCK(esai_clk,   0, CCM_CGR0, 24, NULL, NULL);
-DEFINE_CLOCK(esdhc1_clk, 0, CCM_CGR0, 26, get_rate_sdhc, NULL);
-DEFINE_CLOCK(esdhc2_clk, 1, CCM_CGR0, 28, get_rate_sdhc, NULL);
-DEFINE_CLOCK(esdhc3_clk, 2, CCM_CGR0, 30, get_rate_sdhc, NULL);
-
-DEFINE_CLOCK(fec_clk,    0, CCM_CGR1,  0, get_rate_ipg, NULL);
-DEFINE_CLOCK(gpio1_clk,  0, CCM_CGR1,  2, NULL, NULL);
-DEFINE_CLOCK(gpio2_clk,  1, CCM_CGR1,  4, NULL, NULL);
-DEFINE_CLOCK(gpio3_clk,  2, CCM_CGR1,  6, NULL, NULL);
-DEFINE_CLOCK(gpt_clk,    0, CCM_CGR1,  8, get_rate_ipg, NULL);
-DEFINE_CLOCK(i2c1_clk,   0, CCM_CGR1, 10, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(i2c2_clk,   1, CCM_CGR1, 12, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(i2c3_clk,   2, CCM_CGR1, 14, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(iomuxc_clk, 0, CCM_CGR1, 16, NULL, NULL);
-DEFINE_CLOCK(ipu_clk,    0, CCM_CGR1, 18, get_rate_hsp, NULL);
-DEFINE_CLOCK(kpp_clk,    0, CCM_CGR1, 20, get_rate_ipg, NULL);
-DEFINE_CLOCK(mlb_clk,    0, CCM_CGR1, 22, get_rate_ahb, NULL);
-DEFINE_CLOCK(mshc_clk,   0, CCM_CGR1, 24, get_rate_mshc, NULL);
-DEFINE_CLOCK(owire_clk,  0, CCM_CGR1, 26, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(pwm_clk,    0, CCM_CGR1, 28, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(rngc_clk,   0, CCM_CGR1, 30, get_rate_ipg, NULL);
-
-DEFINE_CLOCK(rtc_clk,    0, CCM_CGR2,  0, get_rate_ipg, NULL);
-DEFINE_CLOCK(rtic_clk,   0, CCM_CGR2,  2, get_rate_ahb, NULL);
-DEFINE_CLOCK(scc_clk,    0, CCM_CGR2,  4, get_rate_ipg, NULL);
-DEFINE_CLOCK(sdma_clk,   0, CCM_CGR2,  6, NULL, NULL);
-DEFINE_CLOCK(spba_clk,   0, CCM_CGR2,  8, get_rate_ipg, NULL);
-DEFINE_CLOCK(spdif_clk,  0, CCM_CGR2, 10, NULL, NULL);
-DEFINE_CLOCK(ssi1_clk,   0, CCM_CGR2, 12, get_rate_ssi, NULL);
-DEFINE_CLOCK(ssi2_clk,   1, CCM_CGR2, 14, get_rate_ssi, NULL);
-DEFINE_CLOCK(uart1_clk,  0, CCM_CGR2, 16, get_rate_uart, NULL);
-DEFINE_CLOCK(uart2_clk,  1, CCM_CGR2, 18, get_rate_uart, NULL);
-DEFINE_CLOCK(uart3_clk,  2, CCM_CGR2, 20, get_rate_uart, NULL);
-DEFINE_CLOCK(usbotg_clk, 0, CCM_CGR2, 22, get_rate_otg, NULL);
-DEFINE_CLOCK(wdog_clk,   0, CCM_CGR2, 24, NULL, NULL);
-DEFINE_CLOCK(max_clk,    0, CCM_CGR2, 26, NULL, NULL);
-DEFINE_CLOCK(audmux_clk, 0, CCM_CGR2, 30, NULL, NULL);
-
-DEFINE_CLOCK(csi_clk,    0, CCM_CGR3,  0, get_rate_csi, NULL);
-DEFINE_CLOCK(iim_clk,    0, CCM_CGR3,  2, NULL, NULL);
-DEFINE_CLOCK(gpu2d_clk,  0, CCM_CGR3,  4, NULL, NULL);
+DEFINE_CLOCK(asrc_clk,   0, MX35_CCM_CGR0,  0, NULL, NULL);
+DEFINE_CLOCK(pata_clk,    0, MX35_CCM_CGR0,  2, get_rate_ipg, NULL);
+/* DEFINE_CLOCK(audmux_clk, 0, MX35_CCM_CGR0,  4, NULL, NULL); */
+DEFINE_CLOCK(can1_clk,   0, MX35_CCM_CGR0,  6, get_rate_ipg, NULL);
+DEFINE_CLOCK(can2_clk,   1, MX35_CCM_CGR0,  8, get_rate_ipg, NULL);
+DEFINE_CLOCK(cspi1_clk,  0, MX35_CCM_CGR0, 10, get_rate_ipg, NULL);
+DEFINE_CLOCK(cspi2_clk,  1, MX35_CCM_CGR0, 12, get_rate_ipg, NULL);
+DEFINE_CLOCK(ect_clk,    0, MX35_CCM_CGR0, 14, get_rate_ipg, NULL);
+DEFINE_CLOCK(edio_clk,   0, MX35_CCM_CGR0, 16, NULL, NULL);
+DEFINE_CLOCK(emi_clk,    0, MX35_CCM_CGR0, 18, get_rate_ipg, NULL);
+DEFINE_CLOCK(epit1_clk,  0, MX35_CCM_CGR0, 20, get_rate_ipg, NULL);
+DEFINE_CLOCK(epit2_clk,  1, MX35_CCM_CGR0, 22, get_rate_ipg, NULL);
+DEFINE_CLOCK(esai_clk,   0, MX35_CCM_CGR0, 24, NULL, NULL);
+DEFINE_CLOCK(esdhc1_clk, 0, MX35_CCM_CGR0, 26, get_rate_sdhc, NULL);
+DEFINE_CLOCK(esdhc2_clk, 1, MX35_CCM_CGR0, 28, get_rate_sdhc, NULL);
+DEFINE_CLOCK(esdhc3_clk, 2, MX35_CCM_CGR0, 30, get_rate_sdhc, NULL);
+
+DEFINE_CLOCK(fec_clk,    0, MX35_CCM_CGR1,  0, get_rate_ipg, NULL);
+DEFINE_CLOCK(gpio1_clk,  0, MX35_CCM_CGR1,  2, NULL, NULL);
+DEFINE_CLOCK(gpio2_clk,  1, MX35_CCM_CGR1,  4, NULL, NULL);
+DEFINE_CLOCK(gpio3_clk,  2, MX35_CCM_CGR1,  6, NULL, NULL);
+DEFINE_CLOCK(gpt_clk,    0, MX35_CCM_CGR1,  8, get_rate_ipg, NULL);
+DEFINE_CLOCK(i2c1_clk,   0, MX35_CCM_CGR1, 10, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(i2c2_clk,   1, MX35_CCM_CGR1, 12, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(i2c3_clk,   2, MX35_CCM_CGR1, 14, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(iomuxc_clk, 0, MX35_CCM_CGR1, 16, NULL, NULL);
+DEFINE_CLOCK(ipu_clk,    0, MX35_CCM_CGR1, 18, get_rate_hsp, NULL);
+DEFINE_CLOCK(kpp_clk,    0, MX35_CCM_CGR1, 20, get_rate_ipg, NULL);
+DEFINE_CLOCK(mlb_clk,    0, MX35_CCM_CGR1, 22, get_rate_ahb, NULL);
+DEFINE_CLOCK(mshc_clk,   0, MX35_CCM_CGR1, 24, get_rate_mshc, NULL);
+DEFINE_CLOCK(owire_clk,  0, MX35_CCM_CGR1, 26, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(pwm_clk,    0, MX35_CCM_CGR1, 28, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(rngc_clk,   0, MX35_CCM_CGR1, 30, get_rate_ipg, NULL);
+
+DEFINE_CLOCK(rtc_clk,    0, MX35_CCM_CGR2,  0, get_rate_ipg, NULL);
+DEFINE_CLOCK(rtic_clk,   0, MX35_CCM_CGR2,  2, get_rate_ahb, NULL);
+DEFINE_CLOCK(scc_clk,    0, MX35_CCM_CGR2,  4, get_rate_ipg, NULL);
+DEFINE_CLOCK(sdma_clk,   0, MX35_CCM_CGR2,  6, NULL, NULL);
+DEFINE_CLOCK(spba_clk,   0, MX35_CCM_CGR2,  8, get_rate_ipg, NULL);
+DEFINE_CLOCK(spdif_clk,  0, MX35_CCM_CGR2, 10, NULL, NULL);
+DEFINE_CLOCK(ssi1_clk,   0, MX35_CCM_CGR2, 12, get_rate_ssi, NULL);
+DEFINE_CLOCK(ssi2_clk,   1, MX35_CCM_CGR2, 14, get_rate_ssi, NULL);
+DEFINE_CLOCK(uart1_clk,  0, MX35_CCM_CGR2, 16, get_rate_uart, NULL);
+DEFINE_CLOCK(uart2_clk,  1, MX35_CCM_CGR2, 18, get_rate_uart, NULL);
+DEFINE_CLOCK(uart3_clk,  2, MX35_CCM_CGR2, 20, get_rate_uart, NULL);
+DEFINE_CLOCK(usbotg_clk, 0, MX35_CCM_CGR2, 22, get_rate_otg, NULL);
+DEFINE_CLOCK(wdog_clk,   0, MX35_CCM_CGR2, 24, NULL, NULL);
+DEFINE_CLOCK(max_clk,    0, MX35_CCM_CGR2, 26, NULL, NULL);
+DEFINE_CLOCK(audmux_clk, 0, MX35_CCM_CGR2, 30, NULL, NULL);
+
+DEFINE_CLOCK(csi_clk,    0, MX35_CCM_CGR3,  0, get_rate_csi, NULL);
+DEFINE_CLOCK(iim_clk,    0, MX35_CCM_CGR3,  2, NULL, NULL);
+DEFINE_CLOCK(gpu2d_clk,  0, MX35_CCM_CGR3,  4, NULL, NULL);
 
 DEFINE_CLOCK(usbahb_clk, 0, 0,         0, get_rate_ahb, NULL);
 
@@ -422,7 +406,7 @@ static unsigned long get_rate_nfc(struct clk *clk)
 {
        unsigned long div1;
 
-       div1 = (__raw_readl(CCM_BASE + CCM_PDR4) >> 28) + 1;
+       div1 = (__raw_readl(MX35_CCM_PDR4) >> 28) + 1;
 
        return get_rate_ahb(NULL) / div1;
 }
@@ -518,11 +502,11 @@ int __init mx35_clocks_init()
        /* Turn off all clocks except the ones we need to survive, namely:
         * EMI, GPIO1/2/3, GPT, IOMUX, MAX and eventually uart
         */
-       __raw_writel((3 << 18), CCM_BASE + CCM_CGR0);
+       __raw_writel((3 << 18), MX35_CCM_CGR0);
        __raw_writel((3 << 2) | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 16),
-                       CCM_BASE + CCM_CGR1);
-       __raw_writel(cgr2, CCM_BASE + CCM_CGR2);
-       __raw_writel(0, CCM_BASE + CCM_CGR3);
+                       MX35_CCM_CGR1);
+       __raw_writel(cgr2, MX35_CCM_CGR2);
+       __raw_writel(0, MX35_CCM_CGR3);
 
        clk_enable(&iim_clk);
        imx_print_silicon_rev("i.MX35", mx35_revision());
@@ -533,7 +517,7 @@ int __init mx35_clocks_init()
         * extra clocks turned on, otherwise the MX35 boot ROM code will
         * hang after a watchdog reset.
         */
-       if (!(__raw_readl(CCM_BASE + CCM_RCSR) & (3 << 10))) {
+       if (!(__raw_readl(MX35_CCM_RCSR) & (3 << 10))) {
                /* Additionally turn on UART1, SCC, and IIM clocks */
                clk_enable(&iim_clk);
                clk_enable(&uart1_clk);
index 2d88f8b..111c328 100644 (file)
 #define BM_CLPCR_MASK_SCU_IDLE         (0x1 << 26)
 #define BM_CLPCR_MASK_L2CC_IDLE                (0x1 << 27)
 
+#define BP_CCOSR_CKO1_EN               7
+#define BP_CCOSR_CKO1_PODF             4
+#define BM_CCOSR_CKO1_PODF             (0x7 << 4)
+#define BP_CCOSR_CKO1_SEL              0
+#define BM_CCOSR_CKO1_SEL              (0xf << 0)
+
 #define FREQ_480M      480000000
 #define FREQ_528M      528000000
 #define FREQ_594M      594000000
@@ -393,6 +399,7 @@ static struct clk ipu1_di1_clk;
 static struct clk ipu2_di0_clk;
 static struct clk ipu2_di1_clk;
 static struct clk enfc_clk;
+static struct clk cko1_clk;
 static struct clk dummy_clk = {};
 
 static unsigned long external_high_reference;
@@ -938,6 +945,24 @@ static void _clk_disable(struct clk *clk)
        writel_relaxed(reg, clk->enable_reg);
 }
 
+static int _clk_enable_1b(struct clk *clk)
+{
+       u32 reg;
+       reg = readl_relaxed(clk->enable_reg);
+       reg |= 0x1 << clk->enable_shift;
+       writel_relaxed(reg, clk->enable_reg);
+
+       return 0;
+}
+
+static void _clk_disable_1b(struct clk *clk)
+{
+       u32 reg;
+       reg = readl_relaxed(clk->enable_reg);
+       reg &= ~(0x1 << clk->enable_shift);
+       writel_relaxed(reg, clk->enable_reg);
+}
+
 struct divider {
        struct clk *clk;
        void __iomem *reg;
@@ -983,6 +1008,7 @@ DEF_CLK_DIV1(ipu2_di0_pre_div,     &ipu2_di0_pre_clk,      CSCDR2, IPU2_DI0_PRE);
 DEF_CLK_DIV1(ipu2_di1_pre_div, &ipu2_di1_pre_clk,      CSCDR2, IPU2_DI1_PRE);
 DEF_CLK_DIV1(ipu1_div,         &ipu1_clk,              CSCDR3, IPU1_HSP);
 DEF_CLK_DIV1(ipu2_div,         &ipu2_clk,              CSCDR3, IPU2_HSP);
+DEF_CLK_DIV1(cko1_div,         &cko1_clk,              CCOSR, CKO1);
 
 #define DEF_CLK_DIV2(d, c, r, b)                               \
        static struct divider d = {                             \
@@ -1038,6 +1064,7 @@ static struct divider *dividers[] = {
        &enfc_div,
        &spdif_div,
        &asrc_serial_div,
+       &cko1_div,
 };
 
 static unsigned long ldb_di_clk_get_rate(struct clk *clk)
@@ -1625,6 +1652,32 @@ DEF_IPU_DI_MUX(CSCDR2, 2, 1);
 DEF_IPU_MUX(1);
 DEF_IPU_MUX(2);
 
+static struct multiplexer cko1_mux = {
+       .clk = &cko1_clk,
+       .reg = CCOSR,
+       .bp = BP_CCOSR_CKO1_SEL,
+       .bm = BM_CCOSR_CKO1_SEL,
+       .parents = {
+               &pll3_usb_otg,
+               &pll2_bus,
+               &pll1_sys,
+               &pll5_video,
+               &dummy_clk,
+               &axi_clk,
+               &enfc_clk,
+               &ipu1_di0_clk,
+               &ipu1_di1_clk,
+               &ipu2_di0_clk,
+               &ipu2_di1_clk,
+               &ahb_clk,
+               &ipg_clk,
+               &ipg_perclk,
+               &ckil_clk,
+               &pll4_audio,
+               NULL
+       },
+};
+
 static struct multiplexer *multiplexers[] = {
        &axi_mux,
        &periph_mux,
@@ -1667,6 +1720,7 @@ static struct multiplexer *multiplexers[] = {
        &ipu2_di1_mux,
        &ipu1_mux,
        &ipu2_mux,
+       &cko1_mux,
 };
 
 static int _clk_set_parent(struct clk *clk, struct clk *parent)
@@ -1690,7 +1744,7 @@ static int _clk_set_parent(struct clk *clk, struct clk *parent)
                        break;
                i++;
        }
-       if (!m->parents[i])
+       if (!m->parents[i] || m->parents[i] == &dummy_clk)
                return -EINVAL;
 
        val = readl_relaxed(m->reg);
@@ -1745,6 +1799,20 @@ DEF_NG_CLK(asrc_serial_clk,      &pll3_usb_otg);
                .secondary      = s,                    \
        }
 
+#define DEF_CLK_1B(name, er, es, p, s)                 \
+       static struct clk name = {                      \
+               .enable_reg     = er,                   \
+               .enable_shift   = es,                   \
+               .enable         = _clk_enable_1b,       \
+               .disable        = _clk_disable_1b,      \
+               .get_rate       = _clk_get_rate,        \
+               .set_rate       = _clk_set_rate,        \
+               .round_rate     = _clk_round_rate,      \
+               .set_parent     = _clk_set_parent,      \
+               .parent         = p,                    \
+               .secondary      = s,                    \
+       }
+
 DEF_CLK(aips_tz1_clk,    CCGR0, CG0,  &ahb_clk,          NULL);
 DEF_CLK(aips_tz2_clk,    CCGR0, CG1,  &ahb_clk,          NULL);
 DEF_CLK(apbh_dma_clk,    CCGR0, CG2,  &ahb_clk,          NULL);
@@ -1811,6 +1879,7 @@ DEF_CLK(usdhc4_clk,         CCGR6, CG4,  &pll2_pfd_400m,    NULL);
 DEF_CLK(emi_slow_clk,    CCGR6, CG5,  &axi_clk,          NULL);
 DEF_CLK(vdo_axi_clk,     CCGR6, CG6,  &axi_clk,          NULL);
 DEF_CLK(vpu_clk,         CCGR6, CG7,  &axi_clk,          NULL);
+DEF_CLK_1B(cko1_clk,     CCOSR, BP_CCOSR_CKO1_EN, &pll2_bus, NULL);
 
 static int pcie_clk_enable(struct clk *clk)
 {
@@ -1922,6 +1991,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "gpmi_io_clk", gpmi_io_clk),
        _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk),
        _REGISTER_CLOCK(NULL, "sata_clk", sata_clk),
+       _REGISTER_CLOCK(NULL, "cko1_clk", cko1_clk),
 };
 
 int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
@@ -2029,6 +2099,8 @@ int __init mx6q_clocks_init(void)
        clk_set_rate(&usdhc3_clk, 49500000);
        clk_set_rate(&usdhc4_clk, 49500000);
 
+       clk_set_parent(&cko1_clk, &ahb_clk);
+
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
        base = of_iomap(np, 0);
        WARN_ON(!base);
index 5e2e7a8..aa15c51 100644 (file)
@@ -149,39 +149,3 @@ int mx50_revision(void)
        return mx5_cpu_rev;
 }
 EXPORT_SYMBOL(mx50_revision);
-
-static int __init post_cpu_init(void)
-{
-       unsigned int reg;
-       void __iomem *base;
-
-       if (cpu_is_mx51() || cpu_is_mx53()) {
-               if (cpu_is_mx51())
-                       base = MX51_IO_ADDRESS(MX51_AIPS1_BASE_ADDR);
-               else
-                       base = MX53_IO_ADDRESS(MX53_AIPS1_BASE_ADDR);
-
-               __raw_writel(0x0, base + 0x40);
-               __raw_writel(0x0, base + 0x44);
-               __raw_writel(0x0, base + 0x48);
-               __raw_writel(0x0, base + 0x4C);
-               reg = __raw_readl(base + 0x50) & 0x00FFFFFF;
-               __raw_writel(reg, base + 0x50);
-
-               if (cpu_is_mx51())
-                       base = MX51_IO_ADDRESS(MX51_AIPS2_BASE_ADDR);
-               else
-                       base = MX53_IO_ADDRESS(MX53_AIPS2_BASE_ADDR);
-
-               __raw_writel(0x0, base + 0x40);
-               __raw_writel(0x0, base + 0x44);
-               __raw_writel(0x0, base + 0x48);
-               __raw_writel(0x0, base + 0x4C);
-               reg = __raw_readl(base + 0x50) & 0x00FFFFFF;
-               __raw_writel(reg, base + 0x50);
-       }
-
-       return 0;
-}
-
-postcore_initcall(post_cpu_init);
index 9d34c3d..7b92cd6 100644 (file)
@@ -11,6 +11,7 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
+#include <linux/bug.h>
 #include <linux/types.h>
 #include <mach/hardware.h>
 #include <linux/kernel.h>
diff --git a/arch/arm/mach-imx/crmregs-imx3.h b/arch/arm/mach-imx/crmregs-imx3.h
new file mode 100644 (file)
index 0000000..5314127
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 by Sascha Hauer <kernel@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.
+ */
+
+#ifndef __ARCH_ARM_MACH_MX3_CRM_REGS_H__
+#define __ARCH_ARM_MACH_MX3_CRM_REGS_H__
+
+#define CKIH_CLK_FREQ           26000000
+#define CKIH_CLK_FREQ_27MHZ     27000000
+#define CKIL_CLK_FREQ           32768
+
+#define MXC_CCM_BASE           (cpu_is_mx31() ? \
+MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR) : MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR))
+
+/* Register addresses */
+#define MXC_CCM_CCMR           (MXC_CCM_BASE + 0x00)
+#define MXC_CCM_PDR0           (MXC_CCM_BASE + 0x04)
+#define MXC_CCM_PDR1           (MXC_CCM_BASE + 0x08)
+#define MX35_CCM_PDR2          (MXC_CCM_BASE + 0x0C)
+#define MXC_CCM_RCSR           (MXC_CCM_BASE + 0x0C)
+#define MX35_CCM_PDR3          (MXC_CCM_BASE + 0x10)
+#define MXC_CCM_MPCTL          (MXC_CCM_BASE + 0x10)
+#define MX35_CCM_PDR4          (MXC_CCM_BASE + 0x14)
+#define MXC_CCM_UPCTL          (MXC_CCM_BASE + 0x14)
+#define MX35_CCM_RCSR          (MXC_CCM_BASE + 0x18)
+#define MXC_CCM_SRPCTL         (MXC_CCM_BASE + 0x18)
+#define MX35_CCM_MPCTL         (MXC_CCM_BASE + 0x1C)
+#define MXC_CCM_COSR           (MXC_CCM_BASE + 0x1C)
+#define MX35_CCM_PPCTL         (MXC_CCM_BASE + 0x20)
+#define MXC_CCM_CGR0           (MXC_CCM_BASE + 0x20)
+#define MX35_CCM_ACMR          (MXC_CCM_BASE + 0x24)
+#define MXC_CCM_CGR1           (MXC_CCM_BASE + 0x24)
+#define MX35_CCM_COSR          (MXC_CCM_BASE + 0x28)
+#define MXC_CCM_CGR2           (MXC_CCM_BASE + 0x28)
+#define MX35_CCM_CGR0          (MXC_CCM_BASE + 0x2C)
+#define MXC_CCM_WIMR           (MXC_CCM_BASE + 0x2C)
+#define MX35_CCM_CGR1          (MXC_CCM_BASE + 0x30)
+#define MXC_CCM_LDC            (MXC_CCM_BASE + 0x30)
+#define MX35_CCM_CGR2          (MXC_CCM_BASE + 0x34)
+#define MXC_CCM_DCVR0          (MXC_CCM_BASE + 0x34)
+#define MX35_CCM_CGR3          (MXC_CCM_BASE + 0x38)
+#define MXC_CCM_DCVR1          (MXC_CCM_BASE + 0x38)
+#define MXC_CCM_DCVR2          (MXC_CCM_BASE + 0x3C)
+#define MXC_CCM_DCVR3          (MXC_CCM_BASE + 0x40)
+#define MXC_CCM_LTR0           (MXC_CCM_BASE + 0x44)
+#define MXC_CCM_LTR1           (MXC_CCM_BASE + 0x48)
+#define MXC_CCM_LTR2           (MXC_CCM_BASE + 0x4C)
+#define MXC_CCM_LTR3           (MXC_CCM_BASE + 0x50)
+#define MXC_CCM_LTBR0          (MXC_CCM_BASE + 0x54)
+#define MXC_CCM_LTBR1          (MXC_CCM_BASE + 0x58)
+#define MXC_CCM_PMCR0          (MXC_CCM_BASE + 0x5C)
+#define MXC_CCM_PMCR1          (MXC_CCM_BASE + 0x60)
+#define MXC_CCM_PDR2           (MXC_CCM_BASE + 0x64)
+
+/* Register bit definitions */
+#define MXC_CCM_CCMR_WBEN                       (1 << 27)
+#define MXC_CCM_CCMR_CSCS                       (1 << 25)
+#define MXC_CCM_CCMR_PERCS                      (1 << 24)
+#define MXC_CCM_CCMR_SSI1S_OFFSET               18
+#define MXC_CCM_CCMR_SSI1S_MASK                 (0x3 << 18)
+#define MXC_CCM_CCMR_SSI2S_OFFSET               21
+#define MXC_CCM_CCMR_SSI2S_MASK                 (0x3 << 21)
+#define MXC_CCM_CCMR_LPM_OFFSET                 14
+#define MXC_CCM_CCMR_LPM_MASK                   (0x3 << 14)
+#define MXC_CCM_CCMR_LPM_WAIT_MX35             (0x1 << 14)
+#define MXC_CCM_CCMR_FIRS_OFFSET                11
+#define MXC_CCM_CCMR_FIRS_MASK                  (0x3 << 11)
+#define MXC_CCM_CCMR_UPE                        (1 << 9)
+#define MXC_CCM_CCMR_SPE                        (1 << 8)
+#define MXC_CCM_CCMR_MDS                        (1 << 7)
+#define MXC_CCM_CCMR_SBYCS                      (1 << 4)
+#define MXC_CCM_CCMR_MPE                        (1 << 3)
+#define MXC_CCM_CCMR_PRCS_OFFSET                1
+#define MXC_CCM_CCMR_PRCS_MASK                  (0x3 << 1)
+
+#define MXC_CCM_PDR0_CSI_PODF_OFFSET            26
+#define MXC_CCM_PDR0_CSI_PODF_MASK              (0x3F << 26)
+#define MXC_CCM_PDR0_CSI_PRDF_OFFSET            23
+#define MXC_CCM_PDR0_CSI_PRDF_MASK              (0x7 << 23)
+#define MXC_CCM_PDR0_PER_PODF_OFFSET            16
+#define MXC_CCM_PDR0_PER_PODF_MASK              (0x1F << 16)
+#define MXC_CCM_PDR0_HSP_PODF_OFFSET            11
+#define MXC_CCM_PDR0_HSP_PODF_MASK              (0x7 << 11)
+#define MXC_CCM_PDR0_NFC_PODF_OFFSET            8
+#define MXC_CCM_PDR0_NFC_PODF_MASK              (0x7 << 8)
+#define MXC_CCM_PDR0_IPG_PODF_OFFSET            6
+#define MXC_CCM_PDR0_IPG_PODF_MASK              (0x3 << 6)
+#define MXC_CCM_PDR0_MAX_PODF_OFFSET            3
+#define MXC_CCM_PDR0_MAX_PODF_MASK              (0x7 << 3)
+#define MXC_CCM_PDR0_MCU_PODF_OFFSET            0
+#define MXC_CCM_PDR0_MCU_PODF_MASK              0x7
+
+#define MXC_CCM_PDR1_USB_PRDF_OFFSET            30
+#define MXC_CCM_PDR1_USB_PRDF_MASK              (0x3 << 30)
+#define MXC_CCM_PDR1_USB_PODF_OFFSET            27
+#define MXC_CCM_PDR1_USB_PODF_MASK              (0x7 << 27)
+#define MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET       24
+#define MXC_CCM_PDR1_FIRI_PRE_PODF_MASK         (0x7 << 24)
+#define MXC_CCM_PDR1_FIRI_PODF_OFFSET           18
+#define MXC_CCM_PDR1_FIRI_PODF_MASK             (0x3F << 18)
+#define MXC_CCM_PDR1_SSI2_PRE_PODF_OFFSET       15
+#define MXC_CCM_PDR1_SSI2_PRE_PODF_MASK         (0x7 << 15)
+#define MXC_CCM_PDR1_SSI2_PODF_OFFSET           9
+#define MXC_CCM_PDR1_SSI2_PODF_MASK             (0x3F << 9)
+#define MXC_CCM_PDR1_SSI1_PRE_PODF_OFFSET       6
+#define MXC_CCM_PDR1_SSI1_PRE_PODF_MASK         (0x7 << 6)
+#define MXC_CCM_PDR1_SSI1_PODF_OFFSET           0
+#define MXC_CCM_PDR1_SSI1_PODF_MASK             0x3F
+
+/* Bit definitions for RCSR */
+#define MXC_CCM_RCSR_NF16B                     0x80000000
+
+/*
+ * LTR0 register offsets
+ */
+#define MXC_CCM_LTR0_DIV3CK_OFFSET              1
+#define MXC_CCM_LTR0_DIV3CK_MASK                (0x3 << 1)
+#define MXC_CCM_LTR0_DNTHR_OFFSET               16
+#define MXC_CCM_LTR0_DNTHR_MASK                 (0x3F << 16)
+#define MXC_CCM_LTR0_UPTHR_OFFSET               22
+#define MXC_CCM_LTR0_UPTHR_MASK                 (0x3F << 22)
+
+/*
+ * LTR1 register offsets
+ */
+#define MXC_CCM_LTR1_PNCTHR_OFFSET              0
+#define MXC_CCM_LTR1_PNCTHR_MASK                0x3F
+#define MXC_CCM_LTR1_UPCNT_OFFSET               6
+#define MXC_CCM_LTR1_UPCNT_MASK                 (0xFF << 6)
+#define MXC_CCM_LTR1_DNCNT_OFFSET               14
+#define MXC_CCM_LTR1_DNCNT_MASK                 (0xFF << 14)
+#define MXC_CCM_LTR1_LTBRSR_MASK                0x400000
+#define MXC_CCM_LTR1_LTBRSR_OFFSET              22
+#define MXC_CCM_LTR1_LTBRSR                     0x400000
+#define MXC_CCM_LTR1_LTBRSH                     0x800000
+
+/*
+ * LTR2 bit definitions. x ranges from 0 for WSW9 to 6 for WSW15
+ */
+#define MXC_CCM_LTR2_WSW_OFFSET(x)              (11 + (x) * 3)
+#define MXC_CCM_LTR2_WSW_MASK(x)                (0x7 << \
+                                       MXC_CCM_LTR2_WSW_OFFSET((x)))
+#define MXC_CCM_LTR2_EMAC_OFFSET                0
+#define MXC_CCM_LTR2_EMAC_MASK                  0x1FF
+
+/*
+ * LTR3 bit definitions. x ranges from 0 for WSW0 to 8 for WSW8
+ */
+#define MXC_CCM_LTR3_WSW_OFFSET(x)              (5 + (x) * 3)
+#define MXC_CCM_LTR3_WSW_MASK(x)                (0x7 << \
+                                       MXC_CCM_LTR3_WSW_OFFSET((x)))
+
+#define MXC_CCM_PMCR0_DFSUP1                    0x80000000
+#define MXC_CCM_PMCR0_DFSUP1_SPLL               (0 << 31)
+#define MXC_CCM_PMCR0_DFSUP1_MPLL               (1 << 31)
+#define MXC_CCM_PMCR0_DFSUP0                    0x40000000
+#define MXC_CCM_PMCR0_DFSUP0_PLL                (0 << 30)
+#define MXC_CCM_PMCR0_DFSUP0_PDR                (1 << 30)
+#define MXC_CCM_PMCR0_DFSUP_MASK                (0x3 << 30)
+
+#define DVSUP_TURBO                            0
+#define DVSUP_HIGH                             1
+#define DVSUP_MEDIUM                           2
+#define DVSUP_LOW                              3
+#define MXC_CCM_PMCR0_DVSUP_TURBO               (DVSUP_TURBO << 28)
+#define MXC_CCM_PMCR0_DVSUP_HIGH                (DVSUP_HIGH << 28)
+#define MXC_CCM_PMCR0_DVSUP_MEDIUM              (DVSUP_MEDIUM << 28)
+#define MXC_CCM_PMCR0_DVSUP_LOW                 (DVSUP_LOW << 28)
+#define MXC_CCM_PMCR0_DVSUP_OFFSET              28
+#define MXC_CCM_PMCR0_DVSUP_MASK                (0x3 << 28)
+#define MXC_CCM_PMCR0_UDSC                      0x08000000
+#define MXC_CCM_PMCR0_UDSC_MASK                 (1 << 27)
+#define MXC_CCM_PMCR0_UDSC_UP                   (1 << 27)
+#define MXC_CCM_PMCR0_UDSC_DOWN                 (0 << 27)
+
+#define MXC_CCM_PMCR0_VSCNT_1                   (0x0 << 24)
+#define MXC_CCM_PMCR0_VSCNT_2                   (0x1 << 24)
+#define MXC_CCM_PMCR0_VSCNT_3                   (0x2 << 24)
+#define MXC_CCM_PMCR0_VSCNT_4                   (0x3 << 24)
+#define MXC_CCM_PMCR0_VSCNT_5                   (0x4 << 24)
+#define MXC_CCM_PMCR0_VSCNT_6                   (0x5 << 24)
+#define MXC_CCM_PMCR0_VSCNT_7                   (0x6 << 24)
+#define MXC_CCM_PMCR0_VSCNT_8                   (0x7 << 24)
+#define MXC_CCM_PMCR0_VSCNT_OFFSET              24
+#define MXC_CCM_PMCR0_VSCNT_MASK                (0x7 << 24)
+#define MXC_CCM_PMCR0_DVFEV                     0x00800000
+#define MXC_CCM_PMCR0_DVFIS                     0x00400000
+#define MXC_CCM_PMCR0_LBMI                      0x00200000
+#define MXC_CCM_PMCR0_LBFL                      0x00100000
+#define MXC_CCM_PMCR0_LBCF_4                    (0x0 << 18)
+#define MXC_CCM_PMCR0_LBCF_8                    (0x1 << 18)
+#define MXC_CCM_PMCR0_LBCF_12                   (0x2 << 18)
+#define MXC_CCM_PMCR0_LBCF_16                   (0x3 << 18)
+#define MXC_CCM_PMCR0_LBCF_OFFSET               18
+#define MXC_CCM_PMCR0_LBCF_MASK                 (0x3 << 18)
+#define MXC_CCM_PMCR0_PTVIS                     0x00020000
+#define MXC_CCM_PMCR0_UPDTEN                    0x00010000
+#define MXC_CCM_PMCR0_UPDTEN_MASK               (0x1 << 16)
+#define MXC_CCM_PMCR0_FSVAIM                    0x00008000
+#define MXC_CCM_PMCR0_FSVAI_OFFSET              13
+#define MXC_CCM_PMCR0_FSVAI_MASK                (0x3 << 13)
+#define MXC_CCM_PMCR0_DPVCR                     0x00001000
+#define MXC_CCM_PMCR0_DPVV                      0x00000800
+#define MXC_CCM_PMCR0_WFIM                      0x00000400
+#define MXC_CCM_PMCR0_DRCE3                     0x00000200
+#define MXC_CCM_PMCR0_DRCE2                     0x00000100
+#define MXC_CCM_PMCR0_DRCE1                     0x00000080
+#define MXC_CCM_PMCR0_DRCE0                     0x00000040
+#define MXC_CCM_PMCR0_DCR                       0x00000020
+#define MXC_CCM_PMCR0_DVFEN                     0x00000010
+#define MXC_CCM_PMCR0_PTVAIM                    0x00000008
+#define MXC_CCM_PMCR0_PTVAI_OFFSET              1
+#define MXC_CCM_PMCR0_PTVAI_MASK                (0x3 << 1)
+#define MXC_CCM_PMCR0_DPTEN                     0x00000001
+
+#define MXC_CCM_PMCR1_DVGP_OFFSET               0
+#define MXC_CCM_PMCR1_DVGP_MASK                 (0xF)
+
+#define MXC_CCM_PMCR1_PLLRDIS                      (0x1 << 7)
+#define MXC_CCM_PMCR1_EMIRQ_EN                      (0x1 << 8)
+
+#define MXC_CCM_DCVR_ULV_MASK                   (0x3FF << 22)
+#define MXC_CCM_DCVR_ULV_OFFSET                 22
+#define MXC_CCM_DCVR_LLV_MASK                   (0x3FF << 12)
+#define MXC_CCM_DCVR_LLV_OFFSET                 12
+#define MXC_CCM_DCVR_ELV_MASK                   (0x3FF << 2)
+#define MXC_CCM_DCVR_ELV_OFFSET                 2
+
+#define MXC_CCM_PDR2_MST2_PDF_MASK              (0x3F << 7)
+#define MXC_CCM_PDR2_MST2_PDF_OFFSET            7
+#define MXC_CCM_PDR2_MST1_PDF_MASK              0x3F
+#define MXC_CCM_PDR2_MST1_PDF_OFFSET            0
+
+#define MXC_CCM_COSR_CLKOSEL_MASK               0x0F
+#define MXC_CCM_COSR_CLKOSEL_OFFSET             0
+#define MXC_CCM_COSR_CLKOUTDIV_MASK             (0x07 << 6)
+#define MXC_CCM_COSR_CLKOUTDIV_OFFSET           6
+#define MXC_CCM_COSR_CLKOEN                     (1 << 9)
+
+/*
+ * PMCR0 register offsets
+ */
+#define MXC_CCM_PMCR0_LBFL_OFFSET   20
+#define MXC_CCM_PMCR0_DFSUP0_OFFSET 30
+#define MXC_CCM_PMCR0_DFSUP1_OFFSET 31
+
+#endif                         /* __ARCH_ARM_MACH_MX3_CRM_REGS_H__ */
diff --git a/arch/arm/mach-imx/crmregs-imx31.h b/arch/arm/mach-imx/crmregs-imx31.h
deleted file mode 100644 (file)
index 37a8a07..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2008 by Sascha Hauer <kernel@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.
- */
-
-#ifndef __ARCH_ARM_MACH_MX3_CRM_REGS_H__
-#define __ARCH_ARM_MACH_MX3_CRM_REGS_H__
-
-#define CKIH_CLK_FREQ           26000000
-#define CKIH_CLK_FREQ_27MHZ     27000000
-#define CKIL_CLK_FREQ           32768
-
-#define MXC_CCM_BASE           MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR)
-
-/* Register addresses */
-#define MXC_CCM_CCMR           (MXC_CCM_BASE + 0x00)
-#define MXC_CCM_PDR0           (MXC_CCM_BASE + 0x04)
-#define MXC_CCM_PDR1           (MXC_CCM_BASE + 0x08)
-#define MXC_CCM_RCSR           (MXC_CCM_BASE + 0x0C)
-#define MXC_CCM_MPCTL          (MXC_CCM_BASE + 0x10)
-#define MXC_CCM_UPCTL          (MXC_CCM_BASE + 0x14)
-#define MXC_CCM_SRPCTL         (MXC_CCM_BASE + 0x18)
-#define MXC_CCM_COSR           (MXC_CCM_BASE + 0x1C)
-#define MXC_CCM_CGR0           (MXC_CCM_BASE + 0x20)
-#define MXC_CCM_CGR1           (MXC_CCM_BASE + 0x24)
-#define MXC_CCM_CGR2           (MXC_CCM_BASE + 0x28)
-#define MXC_CCM_WIMR           (MXC_CCM_BASE + 0x2C)
-#define MXC_CCM_LDC            (MXC_CCM_BASE + 0x30)
-#define MXC_CCM_DCVR0          (MXC_CCM_BASE + 0x34)
-#define MXC_CCM_DCVR1          (MXC_CCM_BASE + 0x38)
-#define MXC_CCM_DCVR2          (MXC_CCM_BASE + 0x3C)
-#define MXC_CCM_DCVR3          (MXC_CCM_BASE + 0x40)
-#define MXC_CCM_LTR0           (MXC_CCM_BASE + 0x44)
-#define MXC_CCM_LTR1           (MXC_CCM_BASE + 0x48)
-#define MXC_CCM_LTR2           (MXC_CCM_BASE + 0x4C)
-#define MXC_CCM_LTR3           (MXC_CCM_BASE + 0x50)
-#define MXC_CCM_LTBR0          (MXC_CCM_BASE + 0x54)
-#define MXC_CCM_LTBR1          (MXC_CCM_BASE + 0x58)
-#define MXC_CCM_PMCR0          (MXC_CCM_BASE + 0x5C)
-#define MXC_CCM_PMCR1          (MXC_CCM_BASE + 0x60)
-#define MXC_CCM_PDR2           (MXC_CCM_BASE + 0x64)
-
-/* Register bit definitions */
-#define MXC_CCM_CCMR_WBEN                       (1 << 27)
-#define MXC_CCM_CCMR_CSCS                       (1 << 25)
-#define MXC_CCM_CCMR_PERCS                      (1 << 24)
-#define MXC_CCM_CCMR_SSI1S_OFFSET               18
-#define MXC_CCM_CCMR_SSI1S_MASK                 (0x3 << 18)
-#define MXC_CCM_CCMR_SSI2S_OFFSET               21
-#define MXC_CCM_CCMR_SSI2S_MASK                 (0x3 << 21)
-#define MXC_CCM_CCMR_LPM_OFFSET                 14
-#define MXC_CCM_CCMR_LPM_MASK                   (0x3 << 14)
-#define MXC_CCM_CCMR_FIRS_OFFSET                11
-#define MXC_CCM_CCMR_FIRS_MASK                  (0x3 << 11)
-#define MXC_CCM_CCMR_UPE                        (1 << 9)
-#define MXC_CCM_CCMR_SPE                        (1 << 8)
-#define MXC_CCM_CCMR_MDS                        (1 << 7)
-#define MXC_CCM_CCMR_SBYCS                      (1 << 4)
-#define MXC_CCM_CCMR_MPE                        (1 << 3)
-#define MXC_CCM_CCMR_PRCS_OFFSET                1
-#define MXC_CCM_CCMR_PRCS_MASK                  (0x3 << 1)
-
-#define MXC_CCM_PDR0_CSI_PODF_OFFSET            26
-#define MXC_CCM_PDR0_CSI_PODF_MASK              (0x3F << 26)
-#define MXC_CCM_PDR0_CSI_PRDF_OFFSET            23
-#define MXC_CCM_PDR0_CSI_PRDF_MASK              (0x7 << 23)
-#define MXC_CCM_PDR0_PER_PODF_OFFSET            16
-#define MXC_CCM_PDR0_PER_PODF_MASK              (0x1F << 16)
-#define MXC_CCM_PDR0_HSP_PODF_OFFSET            11
-#define MXC_CCM_PDR0_HSP_PODF_MASK              (0x7 << 11)
-#define MXC_CCM_PDR0_NFC_PODF_OFFSET            8
-#define MXC_CCM_PDR0_NFC_PODF_MASK              (0x7 << 8)
-#define MXC_CCM_PDR0_IPG_PODF_OFFSET            6
-#define MXC_CCM_PDR0_IPG_PODF_MASK              (0x3 << 6)
-#define MXC_CCM_PDR0_MAX_PODF_OFFSET            3
-#define MXC_CCM_PDR0_MAX_PODF_MASK              (0x7 << 3)
-#define MXC_CCM_PDR0_MCU_PODF_OFFSET            0
-#define MXC_CCM_PDR0_MCU_PODF_MASK              0x7
-
-#define MXC_CCM_PDR1_USB_PRDF_OFFSET            30
-#define MXC_CCM_PDR1_USB_PRDF_MASK              (0x3 << 30)
-#define MXC_CCM_PDR1_USB_PODF_OFFSET            27
-#define MXC_CCM_PDR1_USB_PODF_MASK              (0x7 << 27)
-#define MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET       24
-#define MXC_CCM_PDR1_FIRI_PRE_PODF_MASK         (0x7 << 24)
-#define MXC_CCM_PDR1_FIRI_PODF_OFFSET           18
-#define MXC_CCM_PDR1_FIRI_PODF_MASK             (0x3F << 18)
-#define MXC_CCM_PDR1_SSI2_PRE_PODF_OFFSET       15
-#define MXC_CCM_PDR1_SSI2_PRE_PODF_MASK         (0x7 << 15)
-#define MXC_CCM_PDR1_SSI2_PODF_OFFSET           9
-#define MXC_CCM_PDR1_SSI2_PODF_MASK             (0x3F << 9)
-#define MXC_CCM_PDR1_SSI1_PRE_PODF_OFFSET       6
-#define MXC_CCM_PDR1_SSI1_PRE_PODF_MASK         (0x7 << 6)
-#define MXC_CCM_PDR1_SSI1_PODF_OFFSET           0
-#define MXC_CCM_PDR1_SSI1_PODF_MASK             0x3F
-
-/* Bit definitions for RCSR */
-#define MXC_CCM_RCSR_NF16B                     0x80000000
-
-/*
- * LTR0 register offsets
- */
-#define MXC_CCM_LTR0_DIV3CK_OFFSET              1
-#define MXC_CCM_LTR0_DIV3CK_MASK                (0x3 << 1)
-#define MXC_CCM_LTR0_DNTHR_OFFSET               16
-#define MXC_CCM_LTR0_DNTHR_MASK                 (0x3F << 16)
-#define MXC_CCM_LTR0_UPTHR_OFFSET               22
-#define MXC_CCM_LTR0_UPTHR_MASK                 (0x3F << 22)
-
-/*
- * LTR1 register offsets
- */
-#define MXC_CCM_LTR1_PNCTHR_OFFSET              0
-#define MXC_CCM_LTR1_PNCTHR_MASK                0x3F
-#define MXC_CCM_LTR1_UPCNT_OFFSET               6
-#define MXC_CCM_LTR1_UPCNT_MASK                 (0xFF << 6)
-#define MXC_CCM_LTR1_DNCNT_OFFSET               14
-#define MXC_CCM_LTR1_DNCNT_MASK                 (0xFF << 14)
-#define MXC_CCM_LTR1_LTBRSR_MASK                0x400000
-#define MXC_CCM_LTR1_LTBRSR_OFFSET              22
-#define MXC_CCM_LTR1_LTBRSR                     0x400000
-#define MXC_CCM_LTR1_LTBRSH                     0x800000
-
-/*
- * LTR2 bit definitions. x ranges from 0 for WSW9 to 6 for WSW15
- */
-#define MXC_CCM_LTR2_WSW_OFFSET(x)              (11 + (x) * 3)
-#define MXC_CCM_LTR2_WSW_MASK(x)                (0x7 << \
-                                       MXC_CCM_LTR2_WSW_OFFSET((x)))
-#define MXC_CCM_LTR2_EMAC_OFFSET                0
-#define MXC_CCM_LTR2_EMAC_MASK                  0x1FF
-
-/*
- * LTR3 bit definitions. x ranges from 0 for WSW0 to 8 for WSW8
- */
-#define MXC_CCM_LTR3_WSW_OFFSET(x)              (5 + (x) * 3)
-#define MXC_CCM_LTR3_WSW_MASK(x)                (0x7 << \
-                                       MXC_CCM_LTR3_WSW_OFFSET((x)))
-
-#define MXC_CCM_PMCR0_DFSUP1                    0x80000000
-#define MXC_CCM_PMCR0_DFSUP1_SPLL               (0 << 31)
-#define MXC_CCM_PMCR0_DFSUP1_MPLL               (1 << 31)
-#define MXC_CCM_PMCR0_DFSUP0                    0x40000000
-#define MXC_CCM_PMCR0_DFSUP0_PLL                (0 << 30)
-#define MXC_CCM_PMCR0_DFSUP0_PDR                (1 << 30)
-#define MXC_CCM_PMCR0_DFSUP_MASK                (0x3 << 30)
-
-#define DVSUP_TURBO                            0
-#define DVSUP_HIGH                             1
-#define DVSUP_MEDIUM                           2
-#define DVSUP_LOW                              3
-#define MXC_CCM_PMCR0_DVSUP_TURBO               (DVSUP_TURBO << 28)
-#define MXC_CCM_PMCR0_DVSUP_HIGH                (DVSUP_HIGH << 28)
-#define MXC_CCM_PMCR0_DVSUP_MEDIUM              (DVSUP_MEDIUM << 28)
-#define MXC_CCM_PMCR0_DVSUP_LOW                 (DVSUP_LOW << 28)
-#define MXC_CCM_PMCR0_DVSUP_OFFSET              28
-#define MXC_CCM_PMCR0_DVSUP_MASK                (0x3 << 28)
-#define MXC_CCM_PMCR0_UDSC                      0x08000000
-#define MXC_CCM_PMCR0_UDSC_MASK                 (1 << 27)
-#define MXC_CCM_PMCR0_UDSC_UP                   (1 << 27)
-#define MXC_CCM_PMCR0_UDSC_DOWN                 (0 << 27)
-
-#define MXC_CCM_PMCR0_VSCNT_1                   (0x0 << 24)
-#define MXC_CCM_PMCR0_VSCNT_2                   (0x1 << 24)
-#define MXC_CCM_PMCR0_VSCNT_3                   (0x2 << 24)
-#define MXC_CCM_PMCR0_VSCNT_4                   (0x3 << 24)
-#define MXC_CCM_PMCR0_VSCNT_5                   (0x4 << 24)
-#define MXC_CCM_PMCR0_VSCNT_6                   (0x5 << 24)
-#define MXC_CCM_PMCR0_VSCNT_7                   (0x6 << 24)
-#define MXC_CCM_PMCR0_VSCNT_8                   (0x7 << 24)
-#define MXC_CCM_PMCR0_VSCNT_OFFSET              24
-#define MXC_CCM_PMCR0_VSCNT_MASK                (0x7 << 24)
-#define MXC_CCM_PMCR0_DVFEV                     0x00800000
-#define MXC_CCM_PMCR0_DVFIS                     0x00400000
-#define MXC_CCM_PMCR0_LBMI                      0x00200000
-#define MXC_CCM_PMCR0_LBFL                      0x00100000
-#define MXC_CCM_PMCR0_LBCF_4                    (0x0 << 18)
-#define MXC_CCM_PMCR0_LBCF_8                    (0x1 << 18)
-#define MXC_CCM_PMCR0_LBCF_12                   (0x2 << 18)
-#define MXC_CCM_PMCR0_LBCF_16                   (0x3 << 18)
-#define MXC_CCM_PMCR0_LBCF_OFFSET               18
-#define MXC_CCM_PMCR0_LBCF_MASK                 (0x3 << 18)
-#define MXC_CCM_PMCR0_PTVIS                     0x00020000
-#define MXC_CCM_PMCR0_UPDTEN                    0x00010000
-#define MXC_CCM_PMCR0_UPDTEN_MASK               (0x1 << 16)
-#define MXC_CCM_PMCR0_FSVAIM                    0x00008000
-#define MXC_CCM_PMCR0_FSVAI_OFFSET              13
-#define MXC_CCM_PMCR0_FSVAI_MASK                (0x3 << 13)
-#define MXC_CCM_PMCR0_DPVCR                     0x00001000
-#define MXC_CCM_PMCR0_DPVV                      0x00000800
-#define MXC_CCM_PMCR0_WFIM                      0x00000400
-#define MXC_CCM_PMCR0_DRCE3                     0x00000200
-#define MXC_CCM_PMCR0_DRCE2                     0x00000100
-#define MXC_CCM_PMCR0_DRCE1                     0x00000080
-#define MXC_CCM_PMCR0_DRCE0                     0x00000040
-#define MXC_CCM_PMCR0_DCR                       0x00000020
-#define MXC_CCM_PMCR0_DVFEN                     0x00000010
-#define MXC_CCM_PMCR0_PTVAIM                    0x00000008
-#define MXC_CCM_PMCR0_PTVAI_OFFSET              1
-#define MXC_CCM_PMCR0_PTVAI_MASK                (0x3 << 1)
-#define MXC_CCM_PMCR0_DPTEN                     0x00000001
-
-#define MXC_CCM_PMCR1_DVGP_OFFSET               0
-#define MXC_CCM_PMCR1_DVGP_MASK                 (0xF)
-
-#define MXC_CCM_PMCR1_PLLRDIS                      (0x1 << 7)
-#define MXC_CCM_PMCR1_EMIRQ_EN                      (0x1 << 8)
-
-#define MXC_CCM_DCVR_ULV_MASK                   (0x3FF << 22)
-#define MXC_CCM_DCVR_ULV_OFFSET                 22
-#define MXC_CCM_DCVR_LLV_MASK                   (0x3FF << 12)
-#define MXC_CCM_DCVR_LLV_OFFSET                 12
-#define MXC_CCM_DCVR_ELV_MASK                   (0x3FF << 2)
-#define MXC_CCM_DCVR_ELV_OFFSET                 2
-
-#define MXC_CCM_PDR2_MST2_PDF_MASK              (0x3F << 7)
-#define MXC_CCM_PDR2_MST2_PDF_OFFSET            7
-#define MXC_CCM_PDR2_MST1_PDF_MASK              0x3F
-#define MXC_CCM_PDR2_MST1_PDF_OFFSET            0
-
-#define MXC_CCM_COSR_CLKOSEL_MASK               0x0F
-#define MXC_CCM_COSR_CLKOSEL_OFFSET             0
-#define MXC_CCM_COSR_CLKOUTDIV_MASK             (0x07 << 6)
-#define MXC_CCM_COSR_CLKOUTDIV_OFFSET           6
-#define MXC_CCM_COSR_CLKOEN                     (1 << 9)
-
-/*
- * PMCR0 register offsets
- */
-#define MXC_CCM_PMCR0_LBFL_OFFSET   20
-#define MXC_CCM_PMCR0_DFSUP0_OFFSET 30
-#define MXC_CCM_PMCR0_DFSUP1_OFFSET 31
-
-#endif                         /* __ARCH_ARM_MACH_MX3_CRM_REGS_H__ */
index 2f727d7..28537a5 100644 (file)
@@ -50,6 +50,8 @@ extern const struct imx_imx_uart_1irq_data imx27_imx_uart_data[];
 extern const struct imx_mx2_camera_data imx27_mx2_camera_data;
 #define imx27_add_mx2_camera(pdata)    \
        imx_add_mx2_camera(&imx27_mx2_camera_data, pdata)
+#define imx27_add_mx2_emmaprp(pdata)   \
+       imx_add_mx2_emmaprp(&imx27_mx2_camera_data)
 
 extern const struct imx_mxc_ehci_data imx27_mxc_ehci_otg_data;
 #define imx27_add_mxc_ehci_otg(pdata)  \
diff --git a/arch/arm/mach-imx/imx27-dt.c b/arch/arm/mach-imx/imx27-dt.c
new file mode 100644 (file)
index 0000000..861ceb8
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012 Sascha Hauer, Pengutronix
+ *
+ * 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/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/common.h>
+#include <mach/mx27.h>
+
+static const struct of_dev_auxdata imx27_auxdata_lookup[] __initconst = {
+       OF_DEV_AUXDATA("fsl,imx27-uart", MX27_UART1_BASE_ADDR, "imx21-uart.0", NULL),
+       OF_DEV_AUXDATA("fsl,imx27-uart", MX27_UART2_BASE_ADDR, "imx21-uart.1", NULL),
+       OF_DEV_AUXDATA("fsl,imx27-uart", MX27_UART3_BASE_ADDR, "imx21-uart.2", NULL),
+       OF_DEV_AUXDATA("fsl,imx27-fec", MX27_FEC_BASE_ADDR, "imx27-fec.0", NULL),
+       OF_DEV_AUXDATA("fsl,imx27-i2c", MX27_I2C1_BASE_ADDR, "imx-i2c.0", NULL),
+       OF_DEV_AUXDATA("fsl,imx27-i2c", MX27_I2C2_BASE_ADDR, "imx-i2c.1", NULL),
+       OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI1_BASE_ADDR, "imx27-cspi.0", NULL),
+       OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI2_BASE_ADDR, "imx27-cspi.1", NULL),
+       OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI3_BASE_ADDR, "imx27-cspi.2", NULL),
+       OF_DEV_AUXDATA("fsl,imx27-wdt", MX27_WDOG_BASE_ADDR, "imx2-wdt.0", NULL),
+       { /* sentinel */ }
+};
+
+static int __init imx27_avic_add_irq_domain(struct device_node *np,
+                               struct device_node *interrupt_parent)
+{
+       irq_domain_add_simple(np, 0);
+       return 0;
+}
+
+static int __init imx27_gpio_add_irq_domain(struct device_node *np,
+                               struct device_node *interrupt_parent)
+{
+       static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;
+
+       irq_domain_add_simple(np, gpio_irq_base);
+
+       return 0;
+}
+
+static const struct of_device_id imx27_irq_match[] __initconst = {
+       { .compatible = "fsl,imx27-avic", .data = imx27_avic_add_irq_domain, },
+       { .compatible = "fsl,imx27-gpio", .data = imx27_gpio_add_irq_domain, },
+       { /* sentinel */ }
+};
+
+static void __init imx27_dt_init(void)
+{
+       of_irq_init(imx27_irq_match);
+
+       of_platform_populate(NULL, of_default_bus_match_table,
+                            imx27_auxdata_lookup, NULL);
+}
+
+static void __init imx27_timer_init(void)
+{
+       mx27_clocks_init_dt();
+}
+
+static struct sys_timer imx27_timer = {
+       .init = imx27_timer_init,
+};
+
+static const char *imx27_dt_board_compat[] __initdata = {
+       "fsl,imx27",
+       NULL
+};
+
+DT_MACHINE_START(IMX27_DT, "Freescale i.MX27 (Device Tree Support)")
+       .map_io         = mx27_map_io,
+       .init_early     = imx27_init_early,
+       .init_irq       = mx27_init_irq,
+       .handle_irq     = imx27_handle_irq,
+       .timer          = &imx27_timer,
+       .init_machine   = imx27_dt_init,
+       .dt_compat      = imx27_dt_board_compat,
+       .restart        = mxc_restart,
+MACHINE_END
index 1e03ef4..5cca573 100644 (file)
@@ -104,6 +104,7 @@ static struct sys_timer imx51_timer = {
 
 static const char *imx51_dt_board_compat[] __initdata = {
        "fsl,imx51-babbage",
+       "fsl,imx51",
        NULL
 };
 
index fd5be0f..4172279 100644 (file)
@@ -114,6 +114,7 @@ static const char *imx53_dt_board_compat[] __initdata = {
        "fsl,imx53-evk",
        "fsl,imx53-qsb",
        "fsl,imx53-smd",
+       "fsl,imx53",
        NULL
 };
 
index d4ab6f2..0213f8d 100644 (file)
@@ -17,7 +17,7 @@
 #include <mach/hardware.h>
 
 static struct map_desc imx_lluart_desc = {
-#ifdef CONFIG_DEBUG_IMX6Q_UART
+#ifdef CONFIG_DEBUG_IMX6Q_UART4
        .virtual        = MX6Q_IO_P2V(MX6Q_UART4_BASE_ADDR),
        .pfn            = __phys_to_pfn(MX6Q_UART4_BASE_ADDR),
        .length         = MX6Q_UART4_SIZE,
diff --git a/arch/arm/mach-imx/localtimer.c b/arch/arm/mach-imx/localtimer.c
deleted file mode 100644 (file)
index 3a16351..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2011 Freescale Semiconductor, Inc.
- * Copyright 2011 Linaro Ltd.
- *
- * 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/init.h>
-#include <linux/clockchips.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <asm/smp_twd.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       struct device_node *np;
-
-       np = of_find_compatible_node(NULL, NULL, "arm,smp-twd");
-       if (!twd_base) {
-               twd_base = of_iomap(np, 0);
-               WARN_ON(!twd_base);
-       }
-       evt->irq = irq_of_parse_and_map(np, 0);
-       twd_timer_setup(evt);
-
-       return 0;
-}
index e4f426a..27bc27e 100644 (file)
@@ -51,7 +51,7 @@
 #include <mach/ulpi.h>
 
 #include "devices-imx31.h"
-#include "crmregs-imx31.h"
+#include "crmregs-imx3.h"
 
 static int armadillo5x0_pins[] = {
        /* UART1 */
index 428459f..f7b074f 100644 (file)
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/leds.h>
+#include <linux/memblock.h>
+#include <media/soc_camera.h>
 #include <sound/tlv320aic32x4.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -39,6 +43,8 @@
 
 #include "devices-imx27.h"
 
+#define TVP5150_RSTN (GPIO_PORTC + 18)
+#define TVP5150_PWDN (GPIO_PORTC + 19)
 #define OTG_PHY_CS_GPIO (GPIO_PORTF + 17)
 #define SDHC1_IRQ IRQ_GPIOB(25)
 
@@ -100,8 +106,99 @@ static const int visstrim_m10_pins[] __initconst = {
        PE1_PF_USBOTG_STP,
        PB23_PF_USB_PWR,
        PB24_PF_USB_OC,
+       /* CSI */
+       PB10_PF_CSI_D0,
+       PB11_PF_CSI_D1,
+       PB12_PF_CSI_D2,
+       PB13_PF_CSI_D3,
+       PB14_PF_CSI_D4,
+       PB15_PF_CSI_MCLK,
+       PB16_PF_CSI_PIXCLK,
+       PB17_PF_CSI_D5,
+       PB18_PF_CSI_D6,
+       PB19_PF_CSI_D7,
+       PB20_PF_CSI_VSYNC,
+       PB21_PF_CSI_HSYNC,
 };
 
+/* Camera */
+static int visstrim_camera_power(struct device *dev, int on)
+{
+       gpio_set_value(TVP5150_PWDN, on);
+
+       return 0;
+};
+
+static int visstrim_camera_reset(struct device *dev)
+{
+       gpio_set_value(TVP5150_RSTN, 0);
+       ndelay(500);
+       gpio_set_value(TVP5150_RSTN, 1);
+
+       return 0;
+};
+
+static struct i2c_board_info visstrim_i2c_camera =  {
+       I2C_BOARD_INFO("tvp5150", 0x5d),
+};
+
+static struct soc_camera_link iclink_tvp5150 = {
+       .bus_id         = 0,
+       .board_info     = &visstrim_i2c_camera,
+       .i2c_adapter_id = 0,
+       .power = visstrim_camera_power,
+       .reset = visstrim_camera_reset,
+};
+
+static struct mx2_camera_platform_data visstrim_camera = {
+       .flags = MX2_CAMERA_CCIR | MX2_CAMERA_CCIR_INTERLACE |
+                       MX2_CAMERA_SWAP16 | MX2_CAMERA_PCLK_SAMPLE_RISING,
+       .clk = 100000,
+};
+
+static phys_addr_t mx2_camera_base __initdata;
+#define MX2_CAMERA_BUF_SIZE SZ_8M
+
+static void __init visstrim_camera_init(void)
+{
+       struct platform_device *pdev;
+       int dma;
+
+       /* Initialize tvp5150 gpios */
+       mxc_gpio_mode(TVP5150_RSTN | GPIO_GPIO | GPIO_OUT);
+       mxc_gpio_mode(TVP5150_PWDN | GPIO_GPIO | GPIO_OUT);
+       gpio_set_value(TVP5150_RSTN, 1);
+       gpio_set_value(TVP5150_PWDN, 0);
+       ndelay(1);
+
+       gpio_set_value(TVP5150_PWDN, 1);
+       ndelay(1);
+       gpio_set_value(TVP5150_RSTN, 0);
+       ndelay(500);
+       gpio_set_value(TVP5150_RSTN, 1);
+       ndelay(200000);
+
+       pdev = imx27_add_mx2_camera(&visstrim_camera);
+       if (IS_ERR(pdev))
+               return;
+
+       dma = dma_declare_coherent_memory(&pdev->dev,
+                               mx2_camera_base, mx2_camera_base,
+                               MX2_CAMERA_BUF_SIZE,
+                               DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+       if (!(dma & DMA_MEMORY_MAP))
+               return;
+}
+
+static void __init visstrim_reserve(void)
+{
+       /* reserve 4 MiB for mx2-camera */
+       mx2_camera_base = memblock_alloc(MX2_CAMERA_BUF_SIZE,
+                       MX2_CAMERA_BUF_SIZE);
+       memblock_free(mx2_camera_base, MX2_CAMERA_BUF_SIZE);
+       memblock_remove(mx2_camera_base, MX2_CAMERA_BUF_SIZE);
+}
+
 /* GPIOs used as events for applications */
 static struct gpio_keys_button visstrim_gpio_keys[] = {
        {
@@ -136,6 +233,35 @@ static const struct gpio_keys_platform_data
        .nbuttons       = ARRAY_SIZE(visstrim_gpio_keys),
 };
 
+/* led */
+static const struct gpio_led visstrim_m10_leds[] __initconst = {
+       {
+               .name = "visstrim:ld0",
+               .default_trigger = "nand-disk",
+               .gpio = (GPIO_PORTC + 29),
+       },
+       {
+               .name = "visstrim:ld1",
+               .default_trigger = "nand-disk",
+               .gpio = (GPIO_PORTC + 24),
+       },
+       {
+               .name = "visstrim:ld2",
+               .default_trigger = "nand-disk",
+               .gpio = (GPIO_PORTC + 28),
+       },
+       {
+               .name = "visstrim:ld3",
+               .default_trigger = "nand-disk",
+               .gpio = (GPIO_PORTC + 25),
+       },
+};
+
+static const struct gpio_led_platform_data visstrim_m10_led_data __initconst = {
+       .leds = visstrim_m10_leds,
+       .num_leds = ARRAY_SIZE(visstrim_m10_leds),
+};
+
 /* Visstrim_SM10 has a microSD slot connected to sdhc1 */
 static int visstrim_m10_sdhc1_init(struct device *dev,
                irq_handler_t detect_irq, void *data)
@@ -216,6 +342,9 @@ static struct i2c_board_info visstrim_m10_i2c_devices[] = {
        {
                I2C_BOARD_INFO("tlv320aic32x4", 0x18),
                .platform_data = &visstrim_m10_aic32x4_pdata,
+       },
+       {
+                I2C_BOARD_INFO("m41t00", 0x68),
        }
 };
 
@@ -254,16 +383,21 @@ static void __init visstrim_m10_board_init(void)
        imx27_add_imx_ssi(0, &visstrim_m10_ssi_pdata);
        imx27_add_imx_uart0(&uart_pdata);
 
-       i2c_register_board_info(0, visstrim_m10_i2c_devices,
-                               ARRAY_SIZE(visstrim_m10_i2c_devices));
        imx27_add_imx_i2c(0, &visstrim_m10_i2c_data);
        imx27_add_imx_i2c(1, &visstrim_m10_i2c_data);
+       i2c_register_board_info(0, visstrim_m10_i2c_devices,
+                               ARRAY_SIZE(visstrim_m10_i2c_devices));
+
        imx27_add_mxc_mmc(0, &visstrim_m10_sdhc_pdata);
        imx27_add_mxc_ehci_otg(&visstrim_m10_usbotg_pdata);
        imx27_add_fec(NULL);
        imx_add_gpio_keys(&visstrim_gpio_keys_platform_data);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
        imx_add_platform_device("mx27vis", 0, NULL, 0, NULL, 0);
+       platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
+                                     &iclink_tvp5150, sizeof(iclink_tvp5150));
+       gpio_led_register_device(0, &visstrim_m10_led_data);
+       visstrim_camera_init();
 }
 
 static void __init visstrim_m10_timer_init(void)
@@ -277,6 +411,7 @@ static struct sys_timer visstrim_m10_timer = {
 
 MACHINE_START(IMX27_VISSTRIM_M10, "Vista Silicon Visstrim_M10")
        .atag_offset = 0x100,
+       .reserve = visstrim_reserve,
        .map_io = mx27_map_io,
        .init_early = imx27_init_early,
        .init_irq = mx27_init_irq,
index e4bbd4f..da6c1d9 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/of_platform.h>
 #include <linux/phy.h>
 #include <linux/micrel_phy.h>
+#include <asm/smp_twd.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/arch.h>
@@ -121,6 +122,7 @@ static void __init imx6q_init_irq(void)
 static void __init imx6q_timer_init(void)
 {
        mx6q_clocks_init();
+       twd_local_timer_of_register();
 }
 
 static struct sys_timer imx6q_timer = {
@@ -130,6 +132,7 @@ static struct sys_timer imx6q_timer = {
 static const char *imx6q_dt_compat[] __initdata = {
        "fsl,imx6q-arm2",
        "fsl,imx6q-sabrelite",
+       "fsl,imx6q",
        NULL,
 };
 
index 8d9f955..e432d4a 100644 (file)
@@ -37,8 +37,8 @@
 #define MX21ADS_REG_ADDR(offset)    (void __force __iomem *) \
                (MX21ADS_MMIO_BASE_ADDR + (offset))
 
+#define MX21ADS_CS8900A_MMIO_SIZE   0x200000
 #define MX21ADS_CS8900A_IRQ         IRQ_GPIOE(11)
-#define MX21ADS_CS8900A_IOBASE_REG  MX21ADS_REG_ADDR(0x000000)
 #define MX21ADS_ST16C255_IOBASE_REG MX21ADS_REG_ADDR(0x200000)
 #define MX21ADS_VERSION_REG         MX21ADS_REG_ADDR(0x400000)
 #define MX21ADS_IO_REG              MX21ADS_REG_ADDR(0x800000)
@@ -159,6 +159,18 @@ static struct platform_device mx21ads_nor_mtd_device = {
        .resource = &mx21ads_flash_resource,
 };
 
+static const struct resource mx21ads_cs8900_resources[] __initconst = {
+       DEFINE_RES_MEM(MX21_CS1_BASE_ADDR, MX21ADS_CS8900A_MMIO_SIZE),
+       DEFINE_RES_IRQ(MX21ADS_CS8900A_IRQ),
+};
+
+static const struct platform_device_info mx21ads_cs8900_devinfo __initconst = {
+       .name = "cs89x0",
+       .id = 0,
+       .res = mx21ads_cs8900_resources,
+       .num_res = ARRAY_SIZE(mx21ads_cs8900_resources),
+};
+
 static const struct imxuart_platform_data uart_pdata_rts __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
@@ -292,6 +304,8 @@ static void __init mx21ads_board_init(void)
        imx21_add_mxc_nand(&mx21ads_nand_board_info);
 
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+       platform_device_register_full(
+                       (struct platform_device_info *)&mx21ads_cs8900_devinfo);
 }
 
 static void __init mx21ads_timer_init(void)
index 18f3581..c6d385c 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/regulator/machine.h>
 #include <linux/spi/l4f00242t03.h>
 
+#include <media/soc_camera.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
@@ -52,6 +54,8 @@
 #define SD1_CD                 IMX_GPIO_NR(2, 26)
 #define LCD_RESET              IMX_GPIO_NR(1, 3)
 #define LCD_ENABLE             IMX_GPIO_NR(1, 31)
+#define CSI_PWRDWN             IMX_GPIO_NR(4, 19)
+#define CSI_RESET              IMX_GPIO_NR(3, 6)
 
 static const int mx27pdk_pins[] __initconst = {
        /* UART1 */
@@ -141,6 +145,26 @@ static const int mx27pdk_pins[] __initconst = {
        PA30_PF_CONTRAST,
        LCD_ENABLE | GPIO_GPIO | GPIO_OUT,
        LCD_RESET | GPIO_GPIO | GPIO_OUT,
+       /* CSI */
+       PB10_PF_CSI_D0,
+       PB11_PF_CSI_D1,
+       PB12_PF_CSI_D2,
+       PB13_PF_CSI_D3,
+       PB14_PF_CSI_D4,
+       PB15_PF_CSI_MCLK,
+       PB16_PF_CSI_PIXCLK,
+       PB17_PF_CSI_D5,
+       PB18_PF_CSI_D6,
+       PB19_PF_CSI_D7,
+       PB20_PF_CSI_VSYNC,
+       PB21_PF_CSI_HSYNC,
+       CSI_PWRDWN | GPIO_GPIO | GPIO_OUT,
+       CSI_RESET | GPIO_GPIO | GPIO_OUT,
+};
+
+static struct gpio mx27_3ds_camera_gpios[] = {
+       { CSI_PWRDWN, GPIOF_OUT_INIT_HIGH, "camera-power" },
+       { CSI_RESET, GPIOF_OUT_INIT_HIGH, "camera-reset" },
 };
 
 static const struct imxuart_platform_data uart_pdata __initconst = {
@@ -242,6 +266,7 @@ static struct regulator_init_data gpo_init = {
 
 static struct regulator_consumer_supply vmmc1_consumers[] = {
        REGULATOR_SUPPLY("vcore", "spi0.0"),
+       REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
 };
 
 static struct regulator_init_data vmmc1_init = {
@@ -270,6 +295,22 @@ static struct regulator_init_data vgen_init = {
        .consumer_supplies = vgen_consumers,
 };
 
+static struct regulator_consumer_supply vvib_consumers[] = {
+       REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"),
+};
+
+static struct regulator_init_data vvib_init = {
+       .constraints = {
+               .min_uV = 1300000,
+               .max_uV = 1300000,
+               .apply_uV = 1,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+                                 REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(vvib_consumers),
+       .consumer_supplies = vvib_consumers,
+};
+
 static struct mc13xxx_regulator_init_data mx27_3ds_regulators[] = {
        {
                .id = MC13783_REG_VMMC1,
@@ -283,6 +324,9 @@ static struct mc13xxx_regulator_init_data mx27_3ds_regulators[] = {
        }, {
                .id = MC13783_REG_GPO3, /* Turn on 3.3V */
                .init_data = &gpo_init,
+       }, {
+               .id = MC13783_REG_VVIB,  /* Power OV2640 */
+               .init_data = &vvib_init,
        },
 };
 
@@ -311,6 +355,51 @@ static const struct spi_imx_master spi2_pdata __initconst = {
        .num_chipselect = ARRAY_SIZE(spi2_chipselect),
 };
 
+static int mx27_3ds_camera_power(struct device *dev, int on)
+{
+       /* enable or disable the camera */
+       pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
+       gpio_set_value(CSI_PWRDWN, on ? 0 : 1);
+
+       if (!on)
+               goto out;
+
+       /* If enabled, give a reset impulse */
+       gpio_set_value(CSI_RESET, 0);
+       msleep(20);
+       gpio_set_value(CSI_RESET, 1);
+       msleep(100);
+
+out:
+       return 0;
+}
+
+static struct i2c_board_info mx27_3ds_i2c_camera = {
+       I2C_BOARD_INFO("ov2640", 0x30),
+};
+
+static struct regulator_bulk_data mx27_3ds_camera_regs[] = {
+       { .supply = "cmos_vcore" },
+       { .supply = "cmos_2v8" },
+};
+
+static struct soc_camera_link iclink_ov2640 = {
+       .bus_id         = 0,
+       .board_info     = &mx27_3ds_i2c_camera,
+       .i2c_adapter_id = 0,
+       .power          = mx27_3ds_camera_power,
+       .regulators     = mx27_3ds_camera_regs,
+       .num_regulators = ARRAY_SIZE(mx27_3ds_camera_regs),
+};
+
+static struct platform_device mx27_3ds_ov2640 = {
+       .name   = "soc-camera-pdrv",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &iclink_ov2640,
+       },
+};
+
 static struct imx_fb_videomode mx27_3ds_modes[] = {
        {       /* 480x640 @ 60 Hz */
                .mode = {
@@ -367,12 +456,21 @@ static struct spi_board_info mx27_3ds_spi_devs[] __initdata = {
        },
 };
 
+static struct platform_device *devices[] __initdata = {
+       &mx27_3ds_ov2640,
+};
+
+static const struct mx2_camera_platform_data mx27_3ds_cam_pdata __initconst = {
+       .clk = 26000000,
+};
+
 static const struct imxi2c_platform_data mx27_3ds_i2c0_data __initconst = {
        .bitrate = 100000,
 };
 
 static void __init mx27pdk_init(void)
 {
+       int ret;
        imx27_soc_init();
 
        mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins),
@@ -404,7 +502,17 @@ static void __init mx27pdk_init(void)
        if (mxc_expio_init(MX27_CS5_BASE_ADDR, EXPIO_PARENT_INT))
                pr_warn("Init of the debugboard failed, all devices on the debugboard are unusable.\n");
        imx27_add_imx_i2c(0, &mx27_3ds_i2c0_data);
+       platform_add_devices(devices, ARRAY_SIZE(devices));
        imx27_add_imx_fb(&mx27_3ds_fb_data);
+
+       ret = gpio_request_array(mx27_3ds_camera_gpios,
+                                ARRAY_SIZE(mx27_3ds_camera_gpios));
+       if (ret) {
+               pr_err("Failed to request camera gpios");
+               iclink_ov2640.power = NULL;
+       }
+
+       imx27_add_mx2_camera(&mx27_3ds_cam_pdata);
 }
 
 static void __init mx27pdk_timer_init(void)
index 4917aab..4518e54 100644 (file)
@@ -28,7 +28,6 @@
 #include <asm/memory.h>
 #include <asm/mach/map.h>
 #include <mach/common.h>
-#include <mach/board-mx31ads.h>
 #include <mach/iomux-mx3.h>
 
 #ifdef CONFIG_MACH_MX31ADS_WM1133_EV1
@@ -39,6 +38,9 @@
 
 #include "devices-imx31.h"
 
+/* Base address of PBC controller */
+#define PBC_BASE_ADDRESS       MX31_CS4_BASE_ADDR_VIRT
+
 /* PBC Board interrupt status register */
 #define PBC_INTSTATUS           0x000016
 
@@ -62,6 +64,7 @@
 #define PBC_INTMASK_CLEAR_REG  (PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS)
 #define EXPIO_PARENT_INT       IOMUX_TO_IRQ(MX31_PIN_GPIO1_4)
 
+#define MXC_EXP_IO_BASE                MXC_BOARD_IRQ_START
 #define MXC_IRQ_TO_EXPIO(irq)  ((irq) - MXC_EXP_IO_BASE)
 
 #define EXPIO_INT_XUART_INTA   (MXC_EXP_IO_BASE + 10)
 
 #define MXC_MAX_EXP_IO_LINES   16
 
+/* CS8900 */
+#define EXPIO_INT_ENET_INT     (MXC_EXP_IO_BASE + 8)
+#define CS4_CS8900_MMIO_START  0x20000
+
 /*
  * The serial port definition structure.
  */
@@ -101,11 +108,29 @@ static struct platform_device serial_device = {
        },
 };
 
+static const struct resource mx31ads_cs8900_resources[] __initconst = {
+       DEFINE_RES_MEM(MX31_CS4_BASE_ADDR + CS4_CS8900_MMIO_START, SZ_64K),
+       DEFINE_RES_IRQ(EXPIO_INT_ENET_INT),
+};
+
+static const struct platform_device_info mx31ads_cs8900_devinfo __initconst = {
+       .name = "cs89x0",
+       .id = 0,
+       .res = mx31ads_cs8900_resources,
+       .num_res = ARRAY_SIZE(mx31ads_cs8900_resources),
+};
+
 static int __init mxc_init_extuart(void)
 {
        return platform_device_register(&serial_device);
 }
 
+static void __init mxc_init_ext_ethernet(void)
+{
+       platform_device_register_full(
+               (struct platform_device_info *)&mx31ads_cs8900_devinfo);
+}
+
 static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
@@ -492,12 +517,15 @@ static void __init mxc_init_audio(void)
        mxc_iomux_setup_multiple_pins(ssi_pins, ARRAY_SIZE(ssi_pins), "ssi");
 }
 
-/* static mappings */
+/*
+ * Static mappings, starting from the CS4 start address up to the start address
+ * of the CS8900.
+ */
 static struct map_desc mx31ads_io_desc[] __initdata = {
        {
                .virtual        = MX31_CS4_BASE_ADDR_VIRT,
                .pfn            = __phys_to_pfn(MX31_CS4_BASE_ADDR),
-               .length         = MX31_CS4_SIZE / 2,
+               .length         = CS4_CS8900_MMIO_START,
                .type           = MT_DEVICE
        },
 };
@@ -522,6 +550,7 @@ static void __init mx31ads_init(void)
        mxc_init_imx_uart();
        mxc_init_i2c();
        mxc_init_audio();
+       mxc_init_ext_ethernet();
 }
 
 static void __init mx31ads_timer_init(void)
index f225262..f17a15f 100644 (file)
@@ -507,7 +507,7 @@ static void mx31moboard_poweroff(void)
        struct clk *clk = clk_get_sys("imx2-wdt.0", NULL);
 
        if (!IS_ERR(clk))
-               clk_enable(clk);
+               clk_prepare_enable(clk);
 
        mxc_iomux_mode(MX31_PIN_WATCHDOG_RST__WATCHDOG_RST);
 
@@ -530,6 +530,8 @@ static void __init mx31moboard_init(void)
        platform_add_devices(devices, ARRAY_SIZE(devices));
        gpio_led_register_device(-1, &mx31moboard_led_pdata);
 
+       imx31_add_imx2_wdt(NULL);
+
        imx31_add_imx_uart0(&uart0_pdata);
        imx31_add_imx_uart4(&uart4_pdata);
 
@@ -590,7 +592,7 @@ static void __init mx31moboard_reserve(void)
 }
 
 MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
-       /* Maintainer: Valentin Longchamp, EPFL Mobots group */
+       /* Maintainer: Philippe Retornaz, EPFL Mobots group */
        .atag_offset = 0x100,
        .reserve = mx31moboard_reserve,
        .map_io = mx31_map_io,
index 0af6c9c..e14291d 100644 (file)
@@ -4,6 +4,11 @@
  *
  * Author: Fabio Estevam <fabio.estevam@freescale.com>
  *
+ * Copyright (C) 2011 Meprolight, Ltd.
+ * Alex Gershgorin <alexg@meprolight.com>
+ *
+ * Modified from i.MX31 3-Stack Development System
+ *
  * 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
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
+#include <asm/memblock.h>
 
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/iomux-mx35.h>
 #include <mach/irqs.h>
 #include <mach/3ds_debugboard.h>
+#include <video/platform_lcd.h>
+
+#include <media/soc_camera.h>
 
 #include "devices-imx35.h"
 
+#define GPIO_MC9S08DZ60_GPS_ENABLE 0
+#define GPIO_MC9S08DZ60_HDD_ENABLE 4
+#define GPIO_MC9S08DZ60_WIFI_ENABLE 5
+#define GPIO_MC9S08DZ60_LCD_ENABLE 6
+#define GPIO_MC9S08DZ60_SPEAKER_ENABLE 8
+
+static const struct fb_videomode fb_modedb[] = {
+       {
+                /* 800x480 @ 55 Hz */
+               .name = "Ceramate-CLAA070VC01",
+               .refresh = 55,
+               .xres = 800,
+               .yres = 480,
+               .pixclock = 40000,
+               .left_margin = 40,
+               .right_margin = 40,
+               .upper_margin = 5,
+               .lower_margin = 5,
+               .hsync_len = 20,
+               .vsync_len = 10,
+               .sync = FB_SYNC_OE_ACT_HIGH,
+               .vmode = FB_VMODE_NONINTERLACED,
+               .flag = 0,
+        },
+};
+
+static const struct ipu_platform_data mx3_ipu_data __initconst = {
+       .irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct mx3fb_platform_data mx3fb_pdata __initdata = {
+       .name = "Ceramate-CLAA070VC01",
+       .mode = fb_modedb,
+       .num_modes = ARRAY_SIZE(fb_modedb),
+};
+
+static struct i2c_board_info __initdata i2c_devices_3ds[] = {
+       {
+               I2C_BOARD_INFO("mc9s08dz60", 0x69),
+       },
+};
+
+static int lcd_power_gpio = -ENXIO;
+
+static int mc9s08dz60_gpiochip_match(struct gpio_chip *chip,
+                                                    void *data)
+{
+       return !strcmp(chip->label, data);
+}
+
+static void mx35_3ds_lcd_set_power(
+                               struct plat_lcd_data *pd, unsigned int power)
+{
+       struct gpio_chip *chip;
+
+       if (!gpio_is_valid(lcd_power_gpio)) {
+               chip = gpiochip_find(
+                               "mc9s08dz60", mc9s08dz60_gpiochip_match);
+               if (chip) {
+                       lcd_power_gpio =
+                               chip->base + GPIO_MC9S08DZ60_LCD_ENABLE;
+                       if (gpio_request(lcd_power_gpio, "lcd_power") < 0) {
+                               pr_err("error: gpio already requested!\n");
+                               lcd_power_gpio = -ENXIO;
+                       }
+               } else {
+                       pr_err("error: didn't find mc9s08dz60 gpio chip\n");
+               }
+       }
+
+       if (gpio_is_valid(lcd_power_gpio))
+               gpio_set_value_cansleep(lcd_power_gpio, power);
+}
+
+static struct plat_lcd_data mx35_3ds_lcd_data = {
+       .set_power = mx35_3ds_lcd_set_power,
+};
+
+static struct platform_device mx35_3ds_lcd = {
+       .name = "platform-lcd",
+       .dev.platform_data = &mx35_3ds_lcd_data,
+};
+
 #define EXPIO_PARENT_INT       gpio_to_irq(IMX_GPIO_NR(1, 1))
 
 static const struct imxuart_platform_data uart_pdata __initconst = {
@@ -120,6 +212,109 @@ static iomux_v3_cfg_t mx35pdk_pads[] = {
        /* I2C1 */
        MX35_PAD_I2C1_CLK__I2C1_SCL,
        MX35_PAD_I2C1_DAT__I2C1_SDA,
+       /* Display */
+       MX35_PAD_LD0__IPU_DISPB_DAT_0,
+       MX35_PAD_LD1__IPU_DISPB_DAT_1,
+       MX35_PAD_LD2__IPU_DISPB_DAT_2,
+       MX35_PAD_LD3__IPU_DISPB_DAT_3,
+       MX35_PAD_LD4__IPU_DISPB_DAT_4,
+       MX35_PAD_LD5__IPU_DISPB_DAT_5,
+       MX35_PAD_LD6__IPU_DISPB_DAT_6,
+       MX35_PAD_LD7__IPU_DISPB_DAT_7,
+       MX35_PAD_LD8__IPU_DISPB_DAT_8,
+       MX35_PAD_LD9__IPU_DISPB_DAT_9,
+       MX35_PAD_LD10__IPU_DISPB_DAT_10,
+       MX35_PAD_LD11__IPU_DISPB_DAT_11,
+       MX35_PAD_LD12__IPU_DISPB_DAT_12,
+       MX35_PAD_LD13__IPU_DISPB_DAT_13,
+       MX35_PAD_LD14__IPU_DISPB_DAT_14,
+       MX35_PAD_LD15__IPU_DISPB_DAT_15,
+       MX35_PAD_LD16__IPU_DISPB_DAT_16,
+       MX35_PAD_LD17__IPU_DISPB_DAT_17,
+       MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC,
+       MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK,
+       MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY,
+       MX35_PAD_CONTRAST__IPU_DISPB_CONTR,
+       MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC,
+       MX35_PAD_D3_REV__IPU_DISPB_D3_REV,
+       MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS,
+       /* CSI */
+       MX35_PAD_TX1__IPU_CSI_D_6,
+       MX35_PAD_TX0__IPU_CSI_D_7,
+       MX35_PAD_CSI_D8__IPU_CSI_D_8,
+       MX35_PAD_CSI_D9__IPU_CSI_D_9,
+       MX35_PAD_CSI_D10__IPU_CSI_D_10,
+       MX35_PAD_CSI_D11__IPU_CSI_D_11,
+       MX35_PAD_CSI_D12__IPU_CSI_D_12,
+       MX35_PAD_CSI_D13__IPU_CSI_D_13,
+       MX35_PAD_CSI_D14__IPU_CSI_D_14,
+       MX35_PAD_CSI_D15__IPU_CSI_D_15,
+       MX35_PAD_CSI_HSYNC__IPU_CSI_HSYNC,
+       MX35_PAD_CSI_MCLK__IPU_CSI_MCLK,
+       MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK,
+       MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC,
+};
+
+/*
+ * Camera support
+*/
+static phys_addr_t mx3_camera_base __initdata;
+#define MX35_3DS_CAMERA_BUF_SIZE SZ_8M
+
+static const struct mx3_camera_pdata mx35_3ds_camera_pdata __initconst = {
+       .flags = MX3_CAMERA_DATAWIDTH_8,
+       .mclk_10khz = 2000,
+};
+
+static int __init imx35_3ds_init_camera(void)
+{
+       int dma, ret = -ENOMEM;
+       struct platform_device *pdev =
+               imx35_alloc_mx3_camera(&mx35_3ds_camera_pdata);
+
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       if (!mx3_camera_base)
+               goto err;
+
+       dma = dma_declare_coherent_memory(&pdev->dev,
+                                       mx3_camera_base, mx3_camera_base,
+                                       MX35_3DS_CAMERA_BUF_SIZE,
+                                       DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+
+       if (!(dma & DMA_MEMORY_MAP))
+               goto err;
+
+       ret = platform_device_add(pdev);
+       if (ret)
+err:
+               platform_device_put(pdev);
+
+       return ret;
+}
+
+static const struct ipu_platform_data mx35_3ds_ipu_data __initconst = {
+       .irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct i2c_board_info mx35_3ds_i2c_camera = {
+       I2C_BOARD_INFO("ov2640", 0x30),
+};
+
+static struct soc_camera_link iclink_ov2640 = {
+       .bus_id         = 0,
+       .board_info     = &mx35_3ds_i2c_camera,
+       .i2c_adapter_id = 0,
+       .power          = NULL,
+};
+
+static struct platform_device mx35_3ds_ov2640 = {
+       .name   = "soc-camera-pdrv",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &iclink_ov2640,
+       },
 };
 
 static int mx35_3ds_otg_init(struct platform_device *pdev)
@@ -179,6 +374,8 @@ static const struct imxi2c_platform_data mx35_3ds_i2c0_data __initconst = {
  */
 static void __init mx35_3ds_init(void)
 {
+       struct platform_device *imx35_fb_pdev;
+
        imx35_soc_init();
 
        mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads));
@@ -204,6 +401,17 @@ static void __init mx35_3ds_init(void)
                pr_warn("Init of the debugboard failed, all "
                                "devices on the debugboard are unusable.\n");
        imx35_add_imx_i2c0(&mx35_3ds_i2c0_data);
+
+       i2c_register_board_info(
+               0, i2c_devices_3ds, ARRAY_SIZE(i2c_devices_3ds));
+
+       imx35_add_ipu_core(&mx35_3ds_ipu_data);
+       platform_device_register(&mx35_3ds_ov2640);
+       imx35_3ds_init_camera();
+
+       imx35_fb_pdev = imx35_add_mx3_sdc_fb(&mx3fb_pdata);
+       mx35_3ds_lcd.dev.parent = &imx35_fb_pdev->dev;
+       platform_device_register(&mx35_3ds_lcd);
 }
 
 static void __init mx35pdk_timer_init(void)
@@ -215,6 +423,13 @@ struct sys_timer mx35pdk_timer = {
        .init   = mx35pdk_timer_init,
 };
 
+static void __init mx35_3ds_reserve(void)
+{
+       /* reserve MX35_3DS_CAMERA_BUF_SIZE bytes for mx3-camera */
+       mx3_camera_base = arm_memblock_steal(MX35_3DS_CAMERA_BUF_SIZE,
+                                        MX35_3DS_CAMERA_BUF_SIZE);
+}
+
 MACHINE_START(MX35_3DS, "Freescale MX35PDK")
        /* Maintainer: Freescale Semiconductor, Inc */
        .atag_offset = 0x100,
@@ -224,5 +439,6 @@ MACHINE_START(MX35_3DS, "Freescale MX35PDK")
        .handle_irq = imx35_handle_irq,
        .timer = &mx35pdk_timer,
        .init_machine = mx35_3ds_init,
+       .reserve = mx35_3ds_reserve,
        .restart        = mxc_restart,
 MACHINE_END
index 16f126d..2f3debe 100644 (file)
@@ -233,7 +233,7 @@ static struct regulator_init_data sdhc1_data = {
 
 static struct regulator_consumer_supply cam_consumers[] = {
        {
-               .dev    = NULL,
+               .dev_name = NULL,
                .supply = "imx_cam_vcc",
        },
 };
index 2530c15..f8ca96c 100644 (file)
@@ -34,31 +34,31 @@ static void imx3_idle(void)
 {
        unsigned long reg = 0;
 
-       if (!need_resched())
-               __asm__ __volatile__(
-                       /* disable I and D cache */
-                       "mrc p15, 0, %0, c1, c0, 0\n"
-                       "bic %0, %0, #0x00001000\n"
-                       "bic %0, %0, #0x00000004\n"
-                       "mcr p15, 0, %0, c1, c0, 0\n"
-                       /* invalidate I cache */
-                       "mov %0, #0\n"
-                       "mcr p15, 0, %0, c7, c5, 0\n"
-                       /* clear and invalidate D cache */
-                       "mov %0, #0\n"
-                       "mcr p15, 0, %0, c7, c14, 0\n"
-                       /* WFI */
-                       "mov %0, #0\n"
-                       "mcr p15, 0, %0, c7, c0, 4\n"
-                       "nop\n" "nop\n" "nop\n" "nop\n"
-                       "nop\n" "nop\n" "nop\n"
-                       /* enable I and D cache */
-                       "mrc p15, 0, %0, c1, c0, 0\n"
-                       "orr %0, %0, #0x00001000\n"
-                       "orr %0, %0, #0x00000004\n"
-                       "mcr p15, 0, %0, c1, c0, 0\n"
-                       : "=r" (reg));
-       local_irq_enable();
+       mx3_cpu_lp_set(MX3_WAIT);
+
+       __asm__ __volatile__(
+               /* disable I and D cache */
+               "mrc p15, 0, %0, c1, c0, 0\n"
+               "bic %0, %0, #0x00001000\n"
+               "bic %0, %0, #0x00000004\n"
+               "mcr p15, 0, %0, c1, c0, 0\n"
+               /* invalidate I cache */
+               "mov %0, #0\n"
+               "mcr p15, 0, %0, c7, c5, 0\n"
+               /* clear and invalidate D cache */
+               "mov %0, #0\n"
+               "mcr p15, 0, %0, c7, c14, 0\n"
+               /* WFI */
+               "mov %0, #0\n"
+               "mcr p15, 0, %0, c7, c0, 4\n"
+               "nop\n" "nop\n" "nop\n" "nop\n"
+               "nop\n" "nop\n" "nop\n"
+               /* enable I and D cache */
+               "mrc p15, 0, %0, c1, c0, 0\n"
+               "orr %0, %0, #0x00001000\n"
+               "orr %0, %0, #0x00000004\n"
+               "mcr p15, 0, %0, c1, c0, 0\n"
+               : "=r" (reg));
 }
 
 static void __iomem *imx3_ioremap(unsigned long phys_addr, size_t size,
@@ -78,7 +78,7 @@ static void __iomem *imx3_ioremap(unsigned long phys_addr, size_t size,
        return __arm_ioremap(phys_addr, size, mtype);
 }
 
-void imx3_init_l2x0(void)
+void __init imx3_init_l2x0(void)
 {
        void __iomem *l2x0_base;
        void __iomem *clkctl_base;
@@ -134,8 +134,8 @@ void __init imx31_init_early(void)
 {
        mxc_set_cpu_type(MXC_CPU_MX31);
        mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR));
-       pm_idle = imx3_idle;
        imx_ioremap = imx3_ioremap;
+       arm_pm_idle = imx3_idle;
 }
 
 void __init mx31_init_irq(void)
@@ -179,6 +179,10 @@ void __init imx31_soc_init(void)
        }
 
        imx_add_imx_sdma("imx31-sdma", MX31_SDMA_BASE_ADDR, MX31_INT_SDMA, &imx31_sdma_pdata);
+
+       imx_set_aips(MX31_IO_ADDRESS(MX31_AIPS1_BASE_ADDR));
+       imx_set_aips(MX31_IO_ADDRESS(MX31_AIPS2_BASE_ADDR));
+
        platform_device_register_simple("imx31-audmux", 0, imx31_audmux_res,
                                        ARRAY_SIZE(imx31_audmux_res));
 }
@@ -203,7 +207,7 @@ void __init imx35_init_early(void)
        mxc_set_cpu_type(MXC_CPU_MX35);
        mxc_iomux_v3_init(MX35_IO_ADDRESS(MX35_IOMUXC_BASE_ADDR));
        mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR));
-       pm_idle = imx3_idle;
+       arm_pm_idle = imx3_idle;
        imx_ioremap = imx3_ioremap;
 }
 
@@ -269,6 +273,11 @@ void __init imx35_soc_init(void)
        }
 
        imx_add_imx_sdma("imx35-sdma", MX35_SDMA_BASE_ADDR, MX35_INT_SDMA, &imx35_sdma_pdata);
+
+       /* Setup AIPS registers */
+       imx_set_aips(MX35_IO_ADDRESS(MX35_AIPS1_BASE_ADDR));
+       imx_set_aips(MX35_IO_ADDRESS(MX35_AIPS2_BASE_ADDR));
+
        /* i.mx35 has the i.mx31 type audmux */
        platform_device_register_simple("imx31-audmux", 0, imx35_audmux_res,
                                        ARRAY_SIZE(imx35_audmux_res));
index 90d7880..51af9fa 100644 (file)
@@ -26,23 +26,17 @@ static struct clk *gpc_dvfs_clk;
 
 static void imx5_idle(void)
 {
-       if (!need_resched()) {
-               /* gpc clock is needed for SRPG */
-               if (gpc_dvfs_clk == NULL) {
-                       gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
-                       if (IS_ERR(gpc_dvfs_clk))
-                               goto err0;
-               }
-               clk_enable(gpc_dvfs_clk);
-               mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
-               if (tzic_enable_wake())
-                       goto err1;
-               cpu_do_idle();
-err1:
-               clk_disable(gpc_dvfs_clk);
+       /* gpc clock is needed for SRPG */
+       if (gpc_dvfs_clk == NULL) {
+               gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
+               if (IS_ERR(gpc_dvfs_clk))
+                       return;
        }
-err0:
-       local_irq_enable();
+       clk_enable(gpc_dvfs_clk);
+       mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
+       if (tzic_enable_wake() != 0)
+               cpu_do_idle();
+       clk_disable(gpc_dvfs_clk);
 }
 
 /*
@@ -108,7 +102,7 @@ void __init imx51_init_early(void)
        mxc_set_cpu_type(MXC_CPU_MX51);
        mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR));
        mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR));
-       pm_idle = imx5_idle;
+       arm_pm_idle = imx5_idle;
 }
 
 void __init imx53_init_early(void)
@@ -207,6 +201,11 @@ void __init imx51_soc_init(void)
 
        /* i.mx51 has the i.mx35 type sdma */
        imx_add_imx_sdma("imx35-sdma", MX51_SDMA_BASE_ADDR, MX51_INT_SDMA, &imx51_sdma_pdata);
+
+       /* Setup AIPS registers */
+       imx_set_aips(MX51_IO_ADDRESS(MX51_AIPS1_BASE_ADDR));
+       imx_set_aips(MX51_IO_ADDRESS(MX51_AIPS2_BASE_ADDR));
+
        /* i.mx51 has the i.mx31 type audmux */
        platform_device_register_simple("imx31-audmux", 0, imx51_audmux_res,
                                        ARRAY_SIZE(imx51_audmux_res));
@@ -225,6 +224,11 @@ void __init imx53_soc_init(void)
 
        /* i.mx53 has the i.mx35 type sdma */
        imx_add_imx_sdma("imx35-sdma", MX53_SDMA_BASE_ADDR, MX53_INT_SDMA, &imx53_sdma_pdata);
+
+       /* Setup AIPS registers */
+       imx_set_aips(MX53_IO_ADDRESS(MX53_AIPS1_BASE_ADDR));
+       imx_set_aips(MX53_IO_ADDRESS(MX53_AIPS2_BASE_ADDR));
+
        /* i.mx53 has the i.mx31 type audmux */
        platform_device_register_simple("imx31-audmux", 0, imx53_audmux_res,
                                        ARRAY_SIZE(imx53_audmux_res));
index e455d2f..6fcffa7 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/suspend.h>
 #include <linux/io.h>
-#include <mach/system.h>
 #include <mach/hardware.h>
 
 static int mx27_suspend_enter(suspend_state_t state)
@@ -23,7 +22,7 @@ static int mx27_suspend_enter(suspend_state_t state)
                cscr &= 0xFFFFFFFC;
                __raw_writel(cscr, MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR));
                /* Executes WFI */
-               arch_idle();
+               cpu_do_idle();
                break;
 
        default:
diff --git a/arch/arm/mach-imx/pm-imx3.c b/arch/arm/mach-imx/pm-imx3.c
new file mode 100644 (file)
index 0000000..b375243
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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/io.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+#include "crmregs-imx3.h"
+
+/*
+ * Set cpu low power mode before WFI instruction. This function is called
+ * mx3 because it can be used for mx31 and mx35.
+ * Currently only WAIT_MODE is supported.
+ */
+void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode)
+{
+       int reg = __raw_readl(MXC_CCM_CCMR);
+       reg &= ~MXC_CCM_CCMR_LPM_MASK;
+
+       switch (mode) {
+       case MX3_WAIT:
+               if (cpu_is_mx35())
+                       reg |= MXC_CCM_CCMR_LPM_WAIT_MX35;
+               __raw_writel(reg, MXC_CCM_CCMR);
+               break;
+       default:
+               pr_err("Unknown cpu power mode: %d\n", mode);
+               return;
+       }
+}
index 6dc0934..e26a9cb 100644 (file)
@@ -89,7 +89,7 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
 
 static int mx5_suspend_prepare(void)
 {
-       return clk_enable(gpc_dvfs_clk);
+       return clk_prepare_enable(gpc_dvfs_clk);
 }
 
 static int mx5_suspend_enter(suspend_state_t state)
@@ -119,7 +119,7 @@ static int mx5_suspend_enter(suspend_state_t state)
 
 static void mx5_suspend_finish(void)
 {
-       clk_disable(gpc_dvfs_clk);
+       clk_disable_unprepare(gpc_dvfs_clk);
 }
 
 static int mx5_pm_valid(suspend_state_t state)
index d2fd9f3..1a65d77 100644 (file)
 
 static struct amba_pl010_data integrator_uart_data;
 
-static struct amba_device rtc_device = {
-       .dev            = {
-               .init_name = "mb:15",
-       },
-       .res            = {
-               .start  = INTEGRATOR_RTC_BASE,
-               .end    = INTEGRATOR_RTC_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { IRQ_RTCINT, NO_IRQ },
-};
+#define INTEGRATOR_RTC_IRQ     { IRQ_RTCINT }
+#define INTEGRATOR_UART0_IRQ   { IRQ_UARTINT0 }
+#define INTEGRATOR_UART1_IRQ   { IRQ_UARTINT1 }
+#define KMI0_IRQ               { IRQ_KMIINT0 }
+#define KMI1_IRQ               { IRQ_KMIINT1 }
 
-static struct amba_device uart0_device = {
-       .dev            = {
-               .init_name = "mb:16",
-               .platform_data = &integrator_uart_data,
-       },
-       .res            = {
-               .start  = INTEGRATOR_UART0_BASE,
-               .end    = INTEGRATOR_UART0_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { IRQ_UARTINT0, NO_IRQ },
-};
+static AMBA_APB_DEVICE(rtc, "mb:15", 0,
+       INTEGRATOR_RTC_BASE, INTEGRATOR_RTC_IRQ, NULL);
 
-static struct amba_device uart1_device = {
-       .dev            = {
-               .init_name = "mb:17",
-               .platform_data = &integrator_uart_data,
-       },
-       .res            = {
-               .start  = INTEGRATOR_UART1_BASE,
-               .end    = INTEGRATOR_UART1_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { IRQ_UARTINT1, NO_IRQ },
-};
+static AMBA_APB_DEVICE(uart0, "mb:16", 0,
+       INTEGRATOR_UART0_BASE, INTEGRATOR_UART0_IRQ, &integrator_uart_data);
 
-static struct amba_device kmi0_device = {
-       .dev            = {
-               .init_name = "mb:18",
-       },
-       .res            = {
-               .start  = KMI0_BASE,
-               .end    = KMI0_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { IRQ_KMIINT0, NO_IRQ },
-};
+static AMBA_APB_DEVICE(uart1, "mb:17", 0,
+       INTEGRATOR_UART1_BASE, INTEGRATOR_UART1_IRQ, &integrator_uart_data);
 
-static struct amba_device kmi1_device = {
-       .dev            = {
-               .init_name = "mb:19",
-       },
-       .res            = {
-               .start  = KMI1_BASE,
-               .end    = KMI1_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { IRQ_KMIINT1, NO_IRQ },
-};
+static AMBA_APB_DEVICE(kmi0, "mb:18", 0, KMI0_BASE, KMI0_IRQ, NULL);
+static AMBA_APB_DEVICE(kmi1, "mb:19", 0, KMI1_BASE, KMI1_IRQ, NULL);
 
 static struct amba_device *amba_devs[] __initdata = {
        &rtc_device,
index 8cbb75a..3e538da 100644 (file)
@@ -401,24 +401,21 @@ static int impd1_probe(struct lm_device *dev)
 
                pc_base = dev->resource.start + idev->offset;
 
-               d = kzalloc(sizeof(struct amba_device), GFP_KERNEL);
+               d = amba_device_alloc(NULL, pc_base, SZ_4K);
                if (!d)
                        continue;
 
                dev_set_name(&d->dev, "lm%x:%5.5lx", dev->id, idev->offset >> 12);
                d->dev.parent   = &dev->dev;
-               d->res.start    = dev->resource.start + idev->offset;
-               d->res.end      = d->res.start + SZ_4K - 1;
-               d->res.flags    = IORESOURCE_MEM;
                d->irq[0]       = dev->irq;
                d->irq[1]       = dev->irq;
                d->periphid     = idev->id;
                d->dev.platform_data = idev->platform_data;
 
-               ret = amba_device_register(d, &dev->resource);
+               ret = amba_device_add(d, &dev->resource);
                if (ret) {
                        dev_err(&d->dev, "unable to register device: %d\n", ret);
-                       kfree(d);
+                       amba_device_put(d);
                }
        }
 
index 3d029c9..5cc7b85 100644 (file)
 #include <mach/platform.h>
 #include <mach/irqs.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 /* FIXME: should not be using soo many LDRs here */
                ldr     \base, =IO_ADDRESS(INTEGRATOR_IC_BASE)
diff --git a/arch/arm/mach-integrator/include/mach/system.h b/arch/arm/mach-integrator/include/mach/system.h
deleted file mode 100644 (file)
index 901514e..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-integrator/include/mach/system.h
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       /*
-        * This should do all the clock switching
-        * and wait for interrupt tricks
-        */
-       cpu_do_idle();
-}
-
-#endif
index a8b6aa6..be9ead4 100644 (file)
@@ -347,32 +347,14 @@ static struct mmci_platform_data mmc_data = {
        .gpio_cd        = -1,
 };
 
-static struct amba_device mmc_device = {
-       .dev            = {
-               .init_name = "mb:1c",
-               .platform_data = &mmc_data,
-       },
-       .res            = {
-               .start  = INTEGRATOR_CP_MMC_BASE,
-               .end    = INTEGRATOR_CP_MMC_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 },
-       .periphid       = 0,
-};
+#define INTEGRATOR_CP_MMC_IRQS { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 }
+#define INTEGRATOR_CP_AACI_IRQS        { IRQ_CP_AACIINT }
 
-static struct amba_device aaci_device = {
-       .dev            = {
-               .init_name = "mb:1d",
-       },
-       .res            = {
-               .start  = INTEGRATOR_CP_AACI_BASE,
-               .end    = INTEGRATOR_CP_AACI_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { IRQ_CP_AACIINT, NO_IRQ },
-       .periphid       = 0,
-};
+static AMBA_APB_DEVICE(mmc, "mb:1c", 0, INTEGRATOR_CP_MMC_BASE,
+       INTEGRATOR_CP_MMC_IRQS, &mmc_data);
+
+static AMBA_APB_DEVICE(aaci, "mb:1d", 0, INTEGRATOR_CP_AACI_BASE,
+       INTEGRATOR_CP_AACI_IRQS, NULL);
 
 
 /*
@@ -425,21 +407,8 @@ static struct clcd_board clcd_data = {
        .remove         = versatile_clcd_remove_dma,
 };
 
-static struct amba_device clcd_device = {
-       .dev            = {
-               .init_name = "mb:c0",
-               .coherent_dma_mask = ~0,
-               .platform_data = &clcd_data,
-       },
-       .res            = {
-               .start  = INTCP_PA_CLCD_BASE,
-               .end    = INTCP_PA_CLCD_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       .dma_mask       = ~0,
-       .irq            = { IRQ_CP_CLCDCINT, NO_IRQ },
-       .periphid       = 0,
-};
+static AMBA_AHB_DEVICE(clcd, "mb:c0", 0, INTCP_PA_CLCD_BASE,
+       { IRQ_CP_CLCDCINT }, &clcd_data);
 
 static struct amba_device *amba_devs[] __initdata = {
        &mmc_device,
index 9d47b4c..4be172c 100644 (file)
@@ -377,9 +377,10 @@ static int __init pci_v3_setup_resources(struct pci_sys_data *sys)
         * the mem resource for this bus
         * the prefetch mem resource for this bus
         */
-       pci_add_resource(&sys->resources, &ioport_resource);
-       pci_add_resource(&sys->resources, &non_mem);
-       pci_add_resource(&sys->resources, &pre_mem);
+       pci_add_resource_offset(&sys->resources,
+                               &ioport_resource, sys->io_offset);
+       pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
 
        return 1;
 }
index a624a78..1a2d603 100644 (file)
@@ -16,9 +16,6 @@
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  *
  */
-       .macro  disable_fiq
-       .endm
-
        .macro get_irqnr_preamble, base, tmp
        mrc     p15, 0, \tmp, c15, c1, 0
        orr     \tmp, \tmp, #(1 << 6)
diff --git a/arch/arm/mach-iop13xx/include/mach/system.h b/arch/arm/mach-iop13xx/include/mach/system.h
deleted file mode 100644 (file)
index 1f31ed3..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-iop13xx/include/mach/system.h
- *
- *  Copyright (C) 2004 Intel Corp.
- *
- * 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.
- */
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
index b8f5a87..861cb12 100644 (file)
@@ -1084,8 +1084,8 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
        request_resource(&ioport_resource, &res[0]);
        request_resource(&iomem_resource, &res[1]);
 
-       pci_add_resource(&sys->resources, &res[0]);
-       pci_add_resource(&sys->resources, &res[1]);
+       pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
+       pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
        return 1;
 }
index b02fb56..ea13ae0 100644 (file)
@@ -9,9 +9,6 @@
  */
 #include <mach/iop32x.h>
 
-       .macro  disable_fiq
-       .endm
-
        .macro get_irqnr_preamble, base, tmp
        mrc     p15, 0, \tmp, c15, c1, 0
        orr     \tmp, \tmp, #(1 << 6)
diff --git a/arch/arm/mach-iop32x/include/mach/system.h b/arch/arm/mach-iop32x/include/mach/system.h
deleted file mode 100644 (file)
index 4a88727..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-iop32x/include/mach/system.h
- *
- * Copyright (C) 2001 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
index 4e1f728..0a398fe 100644 (file)
@@ -9,9 +9,6 @@
  */
 #include <mach/iop33x.h>
 
-       .macro  disable_fiq
-       .endm
-
        .macro get_irqnr_preamble, base, tmp
        mrc     p15, 0, \tmp, c15, c1, 0
        orr     \tmp, \tmp, #(1 << 6)
diff --git a/arch/arm/mach-iop33x/include/mach/system.h b/arch/arm/mach-iop33x/include/mach/system.h
deleted file mode 100644 (file)
index 4f98e76..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-iop33x/include/mach/system.h
- *
- * Copyright (C) 2001 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
index 5850ffc..c4444df 100644 (file)
@@ -9,15 +9,9 @@
  */
 #include <mach/irqs.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 
                mov     \irqnr, #0x0              @clear out irqnr as default
diff --git a/arch/arm/mach-ixp2000/include/mach/system.h b/arch/arm/mach-ixp2000/include/mach/system.h
deleted file mode 100644 (file)
index a7fb08b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/system.h
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyricht (C) 2003-2005 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
index 558f5f8..915ad49 100644 (file)
@@ -133,11 +133,11 @@ static void ixdp2400_pci_postinit(void)
 
        if (ixdp2x00_master_npu()) {
                dev = pci_get_bus_and_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
-               pci_remove_bus_device(dev);
+               pci_stop_and_remove_bus_device(dev);
                pci_dev_put(dev);
        } else {
                dev = pci_get_bus_and_slot(1, IXDP2400_MASTER_ENET_DEVFN);
-               pci_remove_bus_device(dev);
+               pci_stop_and_remove_bus_device(dev);
                pci_dev_put(dev);
 
                ixdp2x00_slave_pci_postinit();
index 33c6d5f..a9f1819 100644 (file)
@@ -261,14 +261,14 @@ int __init ixdp2800_pci_init(void)
                pci_common_init(&ixdp2800_pci);
                if (ixdp2x00_master_npu()) {
                        dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
-                       pci_remove_bus_device(dev);
+                       pci_stop_and_remove_bus_device(dev);
                        pci_dev_put(dev);
 
                        ixdp2800_master_enable_slave();
                        ixdp2800_master_wait_for_slave_bus_scan();
                } else {
                        dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN);
-                       pci_remove_bus_device(dev);
+                       pci_stop_and_remove_bus_device(dev);
                        pci_dev_put(dev);
                }
        }
index 910426a..421e38d 100644 (file)
@@ -238,12 +238,12 @@ void ixdp2x00_slave_pci_postinit(void)
         * Remove PMC device is there is one
         */
        if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) {
-               pci_remove_bus_device(dev);
+               pci_stop_and_remove_bus_device(dev);
                pci_dev_put(dev);
        }
 
        dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN);
-       pci_remove_bus_device(dev);
+       pci_stop_and_remove_bus_device(dev);
        pci_dev_put(dev);
 }
 
index 7e9a1f3..9c02de9 100644 (file)
@@ -242,8 +242,10 @@ int ixp2000_pci_setup(int nr, struct pci_sys_data *sys)
        if (nr >= 1)
                return 0;
 
-       pci_add_resource(&sys->resources, &ixp2000_pci_io_space);
-       pci_add_resource(&sys->resources, &ixp2000_pci_mem_space);
+       pci_add_resource_offset(&sys->resources,
+                               &ixp2000_pci_io_space, sys->io_offset);
+       pci_add_resource_offset(&sys->resources,
+                               &ixp2000_pci_mem_space, sys->mem_offset);
 
        return 1;
 }
index ccdec42..d2c2dc3 100644 (file)
@@ -440,6 +440,9 @@ static struct platform_device *ixp23xx_devices[] __initdata = {
 
 void __init ixp23xx_sys_init(void)
 {
+       /* by default, the idle code is disabled */
+       disable_hlt();
+
        *IXP23XX_EXP_UNIT_FUSE |= 0xf;
        platform_add_devices(ixp23xx_devices, ARRAY_SIZE(ixp23xx_devices));
 }
index 3f5338a..3fd2cb9 100644 (file)
@@ -2,15 +2,9 @@
  * arch/arm/mach-ixp23xx/include/mach/entry-macro.S
  */
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \irqnr, =(IXP23XX_INTC_VIRT + IXP23XX_INTR_IRQ_ENC_ST_OFFSET)
                ldr     \irqnr, [\irqnr]        @ get interrupt number
diff --git a/arch/arm/mach-ixp23xx/include/mach/system.h b/arch/arm/mach-ixp23xx/include/mach/system.h
deleted file mode 100644 (file)
index 277dda7..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/system.h
- *
- * Copyright (C) 2003 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-static inline void arch_idle(void)
-{
-#if 0
-       if (!hlt_counter)
-               cpu_do_idle();
-#endif
-}
index bdf2866..911f5a5 100644 (file)
@@ -280,8 +280,10 @@ int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys)
        if (nr >= 1)
                return 0;
 
-       pci_add_resource(&sys->resources, &ixp23xx_pci_io_space);
-       pci_add_resource(&sys->resources, &ixp23xx_pci_mem_space);
+       pci_add_resource_offset(&sys->resources,
+                               &ixp23xx_pci_io_space, sys->io_offset);
+       pci_add_resource_offset(&sys->resources,
+                               &ixp23xx_pci_mem_space, sys->mem_offset);
 
        return 1;
 }
index 0f445d3..d5719eb 100644 (file)
@@ -471,8 +471,8 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys)
        request_resource(&ioport_resource, &res[0]);
        request_resource(&iomem_resource, &res[1]);
 
-       pci_add_resource(&sys->resources, &res[0]);
-       pci_add_resource(&sys->resources, &res[1]);
+       pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
+       pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
        platform_notify = ixp4xx_pci_platform_notify;
        platform_notify_remove = ixp4xx_pci_platform_notify_remove;
index 3841ab4..a6329a0 100644 (file)
@@ -236,6 +236,12 @@ void __init ixp4xx_init_irq(void)
 {
        int i = 0;
 
+       /*
+        * ixp4xx does not implement the XScale PWRMODE register
+        * so it must not call cpu_do_idle().
+        */
+       disable_hlt();
+
        /* Route all sources to IRQ instead of FIQ */
        *IXP4XX_ICLR = 0x0;
 
index f2e14e9..79adf83 100644 (file)
@@ -9,15 +9,9 @@
  */
 #include <mach/hardware.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \irqstat, =(IXP4XX_INTC_BASE_VIRT+IXP4XX_ICIP_OFFSET)
                ldr     \irqstat, [\irqstat]            @ get interrupts
diff --git a/arch/arm/mach-ixp4xx/include/mach/system.h b/arch/arm/mach-ixp4xx/include/mach/system.h
deleted file mode 100644 (file)
index 140a9be..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/include/mach/system.h
- *
- * Copyright (C) 2002 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-static inline void arch_idle(void)
-{
-       /* ixp4xx does not implement the XScale PWRMODE register,
-        * so it must not call cpu_do_idle() here.
-        */
-#if 0
-       cpu_do_idle();
-#endif
-}
index 7fc603b..90ceab7 100644 (file)
@@ -44,6 +44,20 @@ config MACH_GURUPLUG
          Say 'Y' here if you want your kernel to support the
          Marvell GuruPlug Reference Board.
 
+config ARCH_KIRKWOOD_DT
+       bool "Marvell Kirkwood Flattened Device Tree"
+       select USE_OF
+       help
+         Say 'Y' here if you want your kernel to support the
+         Marvell Kirkwood using flattened device tree.
+
+config MACH_DREAMPLUG_DT
+       bool "Marvell DreamPlug (Flattened Device Tree)"
+       select ARCH_KIRKWOOD_DT
+       help
+         Say 'Y' here if you want your kernel to support the
+         Marvell DreamPlug (Flattened Device Tree).
+
 config MACH_TS219
        bool "QNAP TS-110, TS-119, TS-119P+, TS-210, TS-219, TS-219P and TS-219P+ Turbo NAS"
        help
index 5dcaa81..e299a95 100644 (file)
@@ -20,3 +20,5 @@ obj-$(CONFIG_MACH_NET5BIG_V2)         += netxbig_v2-setup.o lacie_v2-common.o
 obj-$(CONFIG_MACH_T5325)               += t5325-setup.o
 
 obj-$(CONFIG_CPU_IDLE)                 += cpuidle.o
+obj-$(CONFIG_ARCH_KIRKWOOD_DT)         += board-dt.o
+obj-$(CONFIG_MACH_DREAMPLUG_DT)                += board-dreamplug.o
index 760a0ef..16f9385 100644 (file)
@@ -1,3 +1,5 @@
    zreladdr-y  += 0x00008000
 params_phys-y  := 0x00000100
 initrd_phys-y  := 0x00800000
+
+dtb-$(CONFIG_MACH_DREAMPLUG_DT) += kirkwood-dreamplug.dtb
diff --git a/arch/arm/mach-kirkwood/board-dreamplug.c b/arch/arm/mach-kirkwood/board-dreamplug.c
new file mode 100644 (file)
index 0000000..9854539
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2012 (C), Jason Cooper <jason@lakedaemon.net>
+ *
+ * arch/arm/mach-kirkwood/board-dreamplug.c
+ *
+ * Marvell DreamPlug Reference Board Init for drivers not converted to
+ * flattened device tree yet.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/orion_spi.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/kirkwood.h>
+#include <mach/bridge-regs.h>
+#include <plat/mvsdio.h>
+#include "common.h"
+#include "mpp.h"
+
+struct mtd_partition dreamplug_partitions[] = {
+       {
+               .name   = "u-boot",
+               .size   = SZ_512K,
+               .offset = 0,
+       },
+       {
+               .name   = "u-boot env",
+               .size   = SZ_64K,
+               .offset = SZ_512K + SZ_512K,
+       },
+       {
+               .name   = "dtb",
+               .size   = SZ_64K,
+               .offset = SZ_512K + SZ_512K + SZ_512K,
+       },
+};
+
+static const struct flash_platform_data dreamplug_spi_slave_data = {
+       .type           = "mx25l1606e",
+       .name           = "spi_flash",
+       .parts          = dreamplug_partitions,
+       .nr_parts       = ARRAY_SIZE(dreamplug_partitions),
+};
+
+static struct spi_board_info __initdata dreamplug_spi_slave_info[] = {
+       {
+               .modalias       = "m25p80",
+               .platform_data  = &dreamplug_spi_slave_data,
+               .irq            = -1,
+               .max_speed_hz   = 50000000,
+               .bus_num        = 0,
+               .chip_select    = 0,
+       },
+};
+
+static struct mv643xx_eth_platform_data dreamplug_ge00_data = {
+       .phy_addr       = MV643XX_ETH_PHY_ADDR(0),
+};
+
+static struct mv643xx_eth_platform_data dreamplug_ge01_data = {
+       .phy_addr       = MV643XX_ETH_PHY_ADDR(1),
+};
+
+static struct mv_sata_platform_data dreamplug_sata_data = {
+       .n_ports        = 1,
+};
+
+static struct mvsdio_platform_data dreamplug_mvsdio_data = {
+       /* unfortunately the CD signal has not been connected */
+};
+
+static struct gpio_led dreamplug_led_pins[] = {
+       {
+               .name                   = "dreamplug:blue:bluetooth",
+               .gpio                   = 47,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "dreamplug:green:wifi",
+               .gpio                   = 48,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "dreamplug:green:wifi_ap",
+               .gpio                   = 49,
+               .active_low             = 1,
+       },
+};
+
+static struct gpio_led_platform_data dreamplug_led_data = {
+       .leds           = dreamplug_led_pins,
+       .num_leds       = ARRAY_SIZE(dreamplug_led_pins),
+};
+
+static struct platform_device dreamplug_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &dreamplug_led_data,
+       }
+};
+
+static unsigned int dreamplug_mpp_config[] __initdata = {
+       MPP0_SPI_SCn,
+       MPP1_SPI_MOSI,
+       MPP2_SPI_SCK,
+       MPP3_SPI_MISO,
+       MPP47_GPIO,     /* Bluetooth LED */
+       MPP48_GPIO,     /* Wifi LED */
+       MPP49_GPIO,     /* Wifi AP LED */
+       0
+};
+
+void __init dreamplug_init(void)
+{
+       /*
+        * Basic setup. Needs to be called early.
+        */
+       kirkwood_mpp_conf(dreamplug_mpp_config);
+
+       spi_register_board_info(dreamplug_spi_slave_info,
+                               ARRAY_SIZE(dreamplug_spi_slave_info));
+       kirkwood_spi_init();
+
+       kirkwood_ehci_init();
+       kirkwood_ge00_init(&dreamplug_ge00_data);
+       kirkwood_ge01_init(&dreamplug_ge01_data);
+       kirkwood_sata_init(&dreamplug_sata_data);
+       kirkwood_sdio_init(&dreamplug_mvsdio_data);
+
+       platform_device_register(&dreamplug_leds);
+}
diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c
new file mode 100644 (file)
index 0000000..1c672d9
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012 (C), Jason Cooper <jason@lakedaemon.net>
+ *
+ * arch/arm/mach-kirkwood/board-dt.c
+ *
+ * Flattened Device Tree board initialization
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/bridge-regs.h>
+#include "common.h"
+
+static struct of_device_id kirkwood_dt_match_table[] __initdata = {
+       { .compatible = "simple-bus", },
+       { }
+};
+
+static void __init kirkwood_dt_init(void)
+{
+       pr_info("Kirkwood: %s, TCLK=%d.\n", kirkwood_id(), kirkwood_tclk);
+
+       /*
+        * Disable propagation of mbus errors to the CPU local bus,
+        * as this causes mbus errors (which can occur for example
+        * for PCI aborts) to throw CPU aborts, which we're not set
+        * up to deal with.
+        */
+       writel(readl(CPU_CONFIG) & ~CPU_CONFIG_ERROR_PROP, CPU_CONFIG);
+
+       kirkwood_setup_cpu_mbus();
+
+#ifdef CONFIG_CACHE_FEROCEON_L2
+       kirkwood_l2_init();
+#endif
+
+       /* internal devices that every board has */
+       kirkwood_wdt_init();
+       kirkwood_xor0_init();
+       kirkwood_xor1_init();
+       kirkwood_crypto_init();
+
+#ifdef CONFIG_KEXEC
+       kexec_reinit = kirkwood_enable_pcie;
+#endif
+
+       if (of_machine_is_compatible("globalscale,dreamplug"))
+               dreamplug_init();
+
+       of_platform_populate(NULL, kirkwood_dt_match_table, NULL, NULL);
+}
+
+static const char *kirkwood_dt_board_compat[] = {
+       "globalscale,dreamplug",
+       NULL
+};
+
+DT_MACHINE_START(KIRKWOOD_DT, "Marvell Kirkwood (Flattened Device Tree)")
+       /* Maintainer: Jason Cooper <jason@lakedaemon.net> */
+       .map_io         = kirkwood_map_io,
+       .init_early     = kirkwood_init_early,
+       .init_irq       = kirkwood_init_irq,
+       .timer          = &kirkwood_timer,
+       .init_machine   = kirkwood_dt_init,
+       .restart        = kirkwood_restart,
+       .dt_compat      = kirkwood_dt_board_compat,
+MACHINE_END
index 77d4852..a02cae8 100644 (file)
@@ -279,7 +279,7 @@ void __init kirkwood_crypto_init(void)
 /*****************************************************************************
  * XOR0
  ****************************************************************************/
-static void __init kirkwood_xor0_init(void)
+void __init kirkwood_xor0_init(void)
 {
        kirkwood_clk_ctrl |= CGC_XOR0;
 
@@ -291,7 +291,7 @@ static void __init kirkwood_xor0_init(void)
 /*****************************************************************************
  * XOR1
  ****************************************************************************/
-static void __init kirkwood_xor1_init(void)
+void __init kirkwood_xor1_init(void)
 {
        kirkwood_clk_ctrl |= CGC_XOR1;
 
@@ -303,7 +303,7 @@ static void __init kirkwood_xor1_init(void)
 /*****************************************************************************
  * Watchdog
  ****************************************************************************/
-static void __init kirkwood_wdt_init(void)
+void __init kirkwood_wdt_init(void)
 {
        orion_wdt_init(kirkwood_tclk);
 }
@@ -392,7 +392,7 @@ void __init kirkwood_audio_init(void)
 /*
  * Identify device ID and revision.
  */
-static char * __init kirkwood_id(void)
+char * __init kirkwood_id(void)
 {
        u32 dev, rev;
 
@@ -435,7 +435,7 @@ static char * __init kirkwood_id(void)
        }
 }
 
-static void __init kirkwood_l2_init(void)
+void __init kirkwood_l2_init(void)
 {
 #ifdef CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH
        writel(readl(L2_CONFIG_REG) | L2_WRITETHROUGH, L2_CONFIG_REG);
@@ -450,7 +450,6 @@ void __init kirkwood_init(void)
 {
        printk(KERN_INFO "Kirkwood: %s, TCLK=%d.\n",
                kirkwood_id(), kirkwood_tclk);
-       kirkwood_i2s_data.tclk = kirkwood_tclk;
 
        /*
         * Disable propagation of mbus errors to the CPU local bus,
index 9071a39..fa8e768 100644 (file)
@@ -51,6 +51,21 @@ void kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev
 void kirkwood_audio_init(void);
 void kirkwood_restart(char, const char *);
 
+/* board init functions for boards not fully converted to fdt */
+#ifdef CONFIG_MACH_DREAMPLUG_DT
+void dreamplug_init(void);
+#else
+static inline void dreamplug_init(void) {};
+#endif
+
+/* early init functions not converted to fdt yet */
+char *kirkwood_id(void);
+void kirkwood_l2_init(void);
+void kirkwood_wdt_init(void);
+void kirkwood_xor0_init(void);
+void kirkwood_xor1_init(void);
+void kirkwood_crypto_init(void);
+
 extern int kirkwood_tclk;
 extern struct sys_timer kirkwood_timer;
 
index 8939d36..82db29f 100644 (file)
 
 #include <mach/bridge-regs.h>
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =IRQ_VIRT_BASE
        .endm
diff --git a/arch/arm/mach-kirkwood/include/mach/system.h b/arch/arm/mach-kirkwood/include/mach/system.h
deleted file mode 100644 (file)
index 5fddde0..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-kirkwood/include/mach/system.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
index a066a6d..f56a011 100644 (file)
@@ -198,9 +198,9 @@ static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
        if (request_resource(&iomem_resource, &pp->res[1]))
                panic("Request PCIe%d Memory resource failed\n", index);
 
-       pci_add_resource(&sys->resources, &pp->res[0]);
-       pci_add_resource(&sys->resources, &pp->res[1]);
        sys->io_offset = 0;
+       pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+       pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
        /*
         * Generic PCIe unit setup.
index b4fe0c1..8315b34 100644 (file)
 #include <mach/hardware.h>
 #include <mach/regs-irq.h>
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
                ldr     \base, =KS8695_IRQ_VA                   @ Base address of interrupt controller
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \irqstat, [\base, #KS8695_INTMS]        @ Mask Status register
 
diff --git a/arch/arm/mach-ks8695/include/mach/system.h b/arch/arm/mach-ks8695/include/mach/system.h
deleted file mode 100644 (file)
index 59fe992..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-s3c2410/include/mach/system.h
- *
- * Copyright (C) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * KS8695 - System function defines and includes
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static void arch_idle(void)
-{
-       /*
-        * This should do all the clock switching
-        * and wait for interrupt tricks,
-        */
-       cpu_do_idle();
-
-}
-
-#endif
index b26f992..acc7014 100644 (file)
@@ -169,8 +169,8 @@ static int __init ks8695_pci_setup(int nr, struct pci_sys_data *sys)
        request_resource(&iomem_resource, &pci_mem);
        request_resource(&ioport_resource, &pci_io);
 
-       pci_add_resource(&sys->resources, &pci_io);
-       pci_add_resource(&sys->resources, &pci_mem);
+       pci_add_resource_offset(&sys->resources, &pci_io, sys->io_offset);
+       pci_add_resource_offset(&sys->resources, &pci_mem, sys->mem_offset);
 
        /* Assign and enable processor bridge */
        ks8695_local_writeconfig(PCI_BASE_ADDRESS_0, KS8695_PCIMEM_PA);
index fde6635..75946ac 100644 (file)
@@ -29,5 +29,30 @@ config ARCH_LPC32XX_UART6_SELECT
 
 endmenu
 
+menu "LPC32XX chip components"
+
+config ARCH_LPC32XX_IRAM_FOR_NET
+       bool "Use IRAM for network buffers"
+       default y
+       help
+         Say Y here to use the LPC internal fast IRAM (i.e. 256KB SRAM) as
+         network buffer.  If the total combined required buffer sizes is
+         larger than the size of IRAM, then SDRAM will be used instead.
+
+         This can be enabled safely if the IRAM is not intended for other
+         uses.
+
+config ARCH_LPC32XX_MII_SUPPORT
+       bool "Check to enable MII support or leave disabled for RMII support"
+       help
+         Say Y here to enable MII support, or N for RMII support. Regardless of
+         which support is selected, the ethernet interface driver needs to be
+         selected in the device driver networking section.
+
+         The PHY3250 reference board uses RMII, so users of this board should
+         say N.
+
+endmenu
+
 endif
 
index 1e02751..b7ef511 100644 (file)
  *   will also impact the individual peripheral rates.
  */
 
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/device.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/amba/bus.h>
 #include "clock.h"
 #include "common.h"
 
+static DEFINE_SPINLOCK(global_clkregs_lock);
+
+static int usb_pll_enable, usb_pll_valid;
+
 static struct clk clk_armpll;
 static struct clk clk_usbpll;
-static DEFINE_MUTEX(clkm_lock);
 
 /*
  * Post divider values for PLLs based on selected register value
@@ -127,7 +132,7 @@ static struct clk osc_32KHz = {
 static int local_pll397_enable(struct clk *clk, int enable)
 {
        u32 reg;
-       unsigned long timeout = 1 + msecs_to_jiffies(10);
+       unsigned long timeout = jiffies + msecs_to_jiffies(10);
 
        reg = __raw_readl(LPC32XX_CLKPWR_PLL397_CTRL);
 
@@ -142,7 +147,7 @@ static int local_pll397_enable(struct clk *clk, int enable)
                /* Wait for PLL397 lock */
                while (((__raw_readl(LPC32XX_CLKPWR_PLL397_CTRL) &
                        LPC32XX_CLKPWR_SYSCTRL_PLL397_STS) == 0) &&
-                       (timeout > jiffies))
+                       time_before(jiffies, timeout))
                        cpu_relax();
 
                if ((__raw_readl(LPC32XX_CLKPWR_PLL397_CTRL) &
@@ -156,7 +161,7 @@ static int local_pll397_enable(struct clk *clk, int enable)
 static int local_oscmain_enable(struct clk *clk, int enable)
 {
        u32 reg;
-       unsigned long timeout = 1 + msecs_to_jiffies(10);
+       unsigned long timeout = jiffies + msecs_to_jiffies(10);
 
        reg = __raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL);
 
@@ -171,7 +176,7 @@ static int local_oscmain_enable(struct clk *clk, int enable)
                /* Wait for main oscillator to start */
                while (((__raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL) &
                        LPC32XX_CLKPWR_MOSC_DISABLE) != 0) &&
-                       (timeout > jiffies))
+                       time_before(jiffies, timeout))
                        cpu_relax();
 
                if ((__raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL) &
@@ -382,30 +387,62 @@ static u32 local_clk_usbpll_setup(struct clk_pll_setup *pHCLKPllSetup)
 static int local_usbpll_enable(struct clk *clk, int enable)
 {
        u32 reg;
-       int ret = -ENODEV;
-       unsigned long timeout = 1 + msecs_to_jiffies(10);
+       int ret = 0;
+       unsigned long timeout = jiffies + msecs_to_jiffies(20);
 
        reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
 
-       if (enable == 0) {
-               reg &= ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN1 |
-                       LPC32XX_CLKPWR_USBCTRL_CLK_EN2);
-               __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
-       } else if (reg & LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP) {
+       __raw_writel(reg & ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN2 |
+               LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP),
+               LPC32XX_CLKPWR_USB_CTRL);
+       __raw_writel(reg & ~LPC32XX_CLKPWR_USBCTRL_CLK_EN1,
+               LPC32XX_CLKPWR_USB_CTRL);
+
+       if (enable && usb_pll_valid && usb_pll_enable) {
+               ret = -ENODEV;
+               /*
+                * If the PLL rate has been previously set, then the rate
+                * in the PLL register is valid and can be enabled here.
+                * Otherwise, it needs to be enabled as part of setrate.
+                */
+
+               /*
+                * Gate clock into PLL
+                */
                reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN1;
                __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
 
-               /* Wait for PLL lock */
-               while ((timeout > jiffies) & (ret == -ENODEV)) {
+               /*
+                * Enable PLL
+                */
+               reg |= LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP;
+               __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+               /*
+                * Wait for PLL to lock
+                */
+               while (time_before(jiffies, timeout) && (ret == -ENODEV)) {
                        reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
                        if (reg & LPC32XX_CLKPWR_USBCTRL_PLL_STS)
                                ret = 0;
+                       else
+                               udelay(10);
                }
 
+               /*
+                * Gate clock from PLL if PLL is locked
+                */
                if (ret == 0) {
-                       reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN2;
-                       __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+                       __raw_writel(reg | LPC32XX_CLKPWR_USBCTRL_CLK_EN2,
+                               LPC32XX_CLKPWR_USB_CTRL);
+               } else {
+                       __raw_writel(reg & ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN1 |
+                               LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP),
+                               LPC32XX_CLKPWR_USB_CTRL);
                }
+       } else if ((enable == 0) && usb_pll_valid  && usb_pll_enable) {
+               usb_pll_valid = 0;
+               usb_pll_enable = 0;
        }
 
        return ret;
@@ -423,7 +460,7 @@ static unsigned long local_usbpll_round_rate(struct clk *clk,
         */
        rate = rate * 1000;
 
-       clkin = clk->parent->rate;
+       clkin = clk->get_rate(clk);
        usbdiv = (__raw_readl(LPC32XX_CLKPWR_USBCLK_PDIV) &
                LPC32XX_CLKPWR_USBPDIV_PLL_MASK) + 1;
        clkin = clkin / usbdiv;
@@ -437,7 +474,8 @@ static unsigned long local_usbpll_round_rate(struct clk *clk,
 
 static int local_usbpll_set_rate(struct clk *clk, unsigned long rate)
 {
-       u32 clkin, reg, usbdiv;
+       int ret = -ENODEV;
+       u32 clkin, usbdiv;
        struct clk_pll_setup pllsetup;
 
        /*
@@ -446,7 +484,7 @@ static int local_usbpll_set_rate(struct clk *clk, unsigned long rate)
         */
        rate = rate * 1000;
 
-       clkin = clk->get_rate(clk);
+       clkin = clk->get_rate(clk->parent);
        usbdiv = (__raw_readl(LPC32XX_CLKPWR_USBCLK_PDIV) &
                LPC32XX_CLKPWR_USBPDIV_PLL_MASK) + 1;
        clkin = clkin / usbdiv;
@@ -455,22 +493,25 @@ static int local_usbpll_set_rate(struct clk *clk, unsigned long rate)
        if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0)
                return -EINVAL;
 
+       /*
+        * Disable PLL clocks during PLL change
+        */
        local_usbpll_enable(clk, 0);
-
-       reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
-       reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN1;
-       __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
-
-       pllsetup.analog_on = 1;
+       pllsetup.analog_on = 0;
        local_clk_usbpll_setup(&pllsetup);
 
-       clk->rate = clk_check_pll_setup(clkin, &pllsetup);
+       /*
+        * Start USB PLL and check PLL status
+        */
+
+       usb_pll_valid = 1;
+       usb_pll_enable = 1;
 
-       reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
-       reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN2;
-       __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+       ret = local_usbpll_enable(clk, 1);
+       if (ret >= 0)
+               clk->rate = clk_check_pll_setup(clkin, &pllsetup);
 
-       return 0;
+       return ret;
 }
 
 static struct clk clk_usbpll = {
@@ -719,6 +760,41 @@ static struct clk clk_tsc = {
        .get_rate       = local_return_parent_rate,
 };
 
+static int adc_onoff_enable(struct clk *clk, int enable)
+{
+       u32 tmp;
+       u32 divider;
+
+       /* Use PERIPH_CLOCK */
+       tmp = __raw_readl(LPC32XX_CLKPWR_ADC_CLK_CTRL_1);
+       tmp |= LPC32XX_CLKPWR_ADCCTRL1_PCLK_SEL;
+       /*
+        * Set clock divider so that we have equal to or less than
+        * 4.5MHz clock at ADC
+        */
+       divider = clk->get_rate(clk) / 4500000 + 1;
+       tmp |= divider;
+       __raw_writel(tmp, LPC32XX_CLKPWR_ADC_CLK_CTRL_1);
+
+       /* synchronize rate of this clock w/ actual HW setting */
+       clk->rate = clk->get_rate(clk->parent) / divider;
+
+       if (enable == 0)
+               __raw_writel(0, clk->enable_reg);
+       else
+               __raw_writel(clk->enable_mask, clk->enable_reg);
+
+       return 0;
+}
+
+static struct clk clk_adc = {
+       .parent         = &clk_pclk,
+       .enable         = adc_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_ADC_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_ADC32CLKCTRL_CLK_EN,
+       .get_rate       = local_return_parent_rate,
+};
+
 static int mmc_onoff_enable(struct clk *clk, int enable)
 {
        u32 tmp;
@@ -891,20 +967,8 @@ static struct clk clk_lcd = {
        .enable_mask    = LPC32XX_CLKPWR_LCDCTRL_CLK_EN,
 };
 
-static inline void clk_lock(void)
-{
-       mutex_lock(&clkm_lock);
-}
-
-static inline void clk_unlock(void)
-{
-       mutex_unlock(&clkm_lock);
-}
-
 static void local_clk_disable(struct clk *clk)
 {
-       WARN_ON(clk->usecount == 0);
-
        /* Don't attempt to disable clock if it has no users */
        if (clk->usecount > 0) {
                clk->usecount--;
@@ -947,10 +1011,11 @@ static int local_clk_enable(struct clk *clk)
 int clk_enable(struct clk *clk)
 {
        int ret;
+       unsigned long flags;
 
-       clk_lock();
+       spin_lock_irqsave(&global_clkregs_lock, flags);
        ret = local_clk_enable(clk);
-       clk_unlock();
+       spin_unlock_irqrestore(&global_clkregs_lock, flags);
 
        return ret;
 }
@@ -961,9 +1026,11 @@ EXPORT_SYMBOL(clk_enable);
  */
 void clk_disable(struct clk *clk)
 {
-       clk_lock();
+       unsigned long flags;
+
+       spin_lock_irqsave(&global_clkregs_lock, flags);
        local_clk_disable(clk);
-       clk_unlock();
+       spin_unlock_irqrestore(&global_clkregs_lock, flags);
 }
 EXPORT_SYMBOL(clk_disable);
 
@@ -972,13 +1039,7 @@ EXPORT_SYMBOL(clk_disable);
  */
 unsigned long clk_get_rate(struct clk *clk)
 {
-       unsigned long rate;
-
-       clk_lock();
-       rate = clk->get_rate(clk);
-       clk_unlock();
-
-       return rate;
+       return clk->get_rate(clk);
 }
 EXPORT_SYMBOL(clk_get_rate);
 
@@ -994,11 +1055,8 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
         * the actual rate set as part of the peripheral dividers
         * instead of high level clock control
         */
-       if (clk->set_rate) {
-               clk_lock();
+       if (clk->set_rate)
                ret = clk->set_rate(clk, rate);
-               clk_unlock();
-       }
 
        return ret;
 }
@@ -1009,15 +1067,11 @@ EXPORT_SYMBOL(clk_set_rate);
  */
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-       clk_lock();
-
        if (clk->round_rate)
                rate = clk->round_rate(clk, rate);
        else
                rate = clk->get_rate(clk);
 
-       clk_unlock();
-
        return rate;
 }
 EXPORT_SYMBOL(clk_round_rate);
@@ -1075,10 +1129,11 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("dev:ssp1", NULL, clk_ssp1)
        _REGISTER_CLOCK("lpc32xx_keys.0", NULL, clk_kscan)
        _REGISTER_CLOCK("lpc32xx-nand.0", "nand_ck", clk_nand)
-       _REGISTER_CLOCK("tbd", "i2s0_ck", clk_i2s0)
-       _REGISTER_CLOCK("tbd", "i2s1_ck", clk_i2s1)
+       _REGISTER_CLOCK("lpc32xx-adc", NULL, clk_adc)
+       _REGISTER_CLOCK(NULL, "i2s0_ck", clk_i2s0)
+       _REGISTER_CLOCK(NULL, "i2s1_ck", clk_i2s1)
        _REGISTER_CLOCK("ts-lpc32xx", NULL, clk_tsc)
-       _REGISTER_CLOCK("dev:mmc0", "MCLK", clk_mmc)
+       _REGISTER_CLOCK("dev:mmc0", NULL, clk_mmc)
        _REGISTER_CLOCK("lpc-net.0", NULL, clk_net)
        _REGISTER_CLOCK("dev:clcd", NULL, clk_lcd)
        _REGISTER_CLOCK("lpc32xx_udc", "ck_usbd", clk_usbd)
index 369b152..bbbf063 100644 (file)
@@ -138,6 +138,75 @@ struct platform_device lpc32xx_rtc_device = {
 };
 
 /*
+ * ADC support
+ */
+static struct resource adc_resources[] = {
+       {
+               .start = LPC32XX_ADC_BASE,
+               .end = LPC32XX_ADC_BASE + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = IRQ_LPC32XX_TS_IRQ,
+               .end = IRQ_LPC32XX_TS_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device lpc32xx_adc_device = {
+       .name =  "lpc32xx-adc",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(adc_resources),
+       .resource = adc_resources,
+};
+
+/*
+ * USB support
+ */
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32) 0;
+static struct resource ohci_resources[] = {
+       {
+               .start = IO_ADDRESS(LPC32XX_USB_BASE),
+               .end = IO_ADDRESS(LPC32XX_USB_BASE + 0x100 - 1),
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = IRQ_LPC32XX_USB_HOST,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+struct platform_device lpc32xx_ohci_device = {
+       .name = "usb-ohci",
+       .id = -1,
+       .dev = {
+               .dma_mask = &ohci_dmamask,
+               .coherent_dma_mask = 0xFFFFFFFF,
+       },
+       .num_resources = ARRAY_SIZE(ohci_resources),
+       .resource = ohci_resources,
+};
+
+/*
+ * Network Support
+ */
+static struct resource net_resources[] = {
+       [0] = DEFINE_RES_MEM(LPC32XX_ETHERNET_BASE, SZ_4K),
+       [1] = DEFINE_RES_MEM(LPC32XX_IRAM_BASE, SZ_128K),
+       [2] = DEFINE_RES_IRQ(IRQ_LPC32XX_ETHERNET),
+};
+
+static u64 lpc32xx_mac_dma_mask = 0xffffffffUL;
+struct platform_device lpc32xx_net_device = {
+       .name = "lpc-eth",
+       .id = 0,
+       .dev = {
+               .dma_mask = &lpc32xx_mac_dma_mask,
+               .coherent_dma_mask = 0xffffffffUL,
+       },
+       .num_resources = ARRAY_SIZE(net_resources),
+       .resource = net_resources,
+};
+
+/*
  * Returns the unique ID for the device
  */
 void lpc32xx_get_uid(u32 devid[4])
index 4b4e700..68e45e8 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef __LPC32XX_COMMON_H
 #define __LPC32XX_COMMON_H
 
+#include <mach/board.h>
 #include <linux/platform_device.h>
 
 /*
@@ -29,7 +30,10 @@ extern struct platform_device lpc32xx_i2c0_device;
 extern struct platform_device lpc32xx_i2c1_device;
 extern struct platform_device lpc32xx_i2c2_device;
 extern struct platform_device lpc32xx_tsc_device;
+extern struct platform_device lpc32xx_adc_device;
 extern struct platform_device lpc32xx_rtc_device;
+extern struct platform_device lpc32xx_ohci_device;
+extern struct platform_device lpc32xx_net_device;
 
 /*
  * Other arch specific structures and functions
@@ -65,9 +69,7 @@ extern u32 clk_get_pclk_div(void);
  */
 extern void lpc32xx_get_uid(u32 devid[4]);
 
-extern void lpc32xx_watchdog_reset(void);
 extern u32 lpc32xx_return_iram_size(void);
-
 /*
  * Pointers used for sizing and copying suspend function data
  */
diff --git a/arch/arm/mach-lpc32xx/include/mach/board.h b/arch/arm/mach-lpc32xx/include/mach/board.h
new file mode 100644 (file)
index 0000000..52531ca
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * arm/arch/mach-lpc32xx/include/mach/board.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_BOARD_H
+#define __ASM_ARCH_BOARD_H
+
+extern u32 lpc32xx_return_iram_size(void);
+
+#endif  /* __ASM_ARCH_BOARD_H */
index b725f6c..24ca11b 100644 (file)
 
 #define LPC32XX_INTC_MASKED_STATUS_OFS 0x8
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =IO_ADDRESS(LPC32XX_MIC_BASE)
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
 /*
  * Return IRQ number in irqnr. Also return processor Z flag status in CPSR
  * as set if an interrupt is pending.
index 14ea8d1..c584f5b 100644 (file)
 /*
  * Timer/counter register offsets
  */
-#define LCP32XX_TIMER_IR(x)                    io_p2v((x) + 0x00)
-#define LCP32XX_TIMER_TCR(x)                   io_p2v((x) + 0x04)
-#define LCP32XX_TIMER_TC(x)                    io_p2v((x) + 0x08)
-#define LCP32XX_TIMER_PR(x)                    io_p2v((x) + 0x0C)
-#define LCP32XX_TIMER_PC(x)                    io_p2v((x) + 0x10)
-#define LCP32XX_TIMER_MCR(x)                   io_p2v((x) + 0x14)
-#define LCP32XX_TIMER_MR0(x)                   io_p2v((x) + 0x18)
-#define LCP32XX_TIMER_MR1(x)                   io_p2v((x) + 0x1C)
-#define LCP32XX_TIMER_MR2(x)                   io_p2v((x) + 0x20)
-#define LCP32XX_TIMER_MR3(x)                   io_p2v((x) + 0x24)
-#define LCP32XX_TIMER_CCR(x)                   io_p2v((x) + 0x28)
-#define LCP32XX_TIMER_CR0(x)                   io_p2v((x) + 0x2C)
-#define LCP32XX_TIMER_CR1(x)                   io_p2v((x) + 0x30)
-#define LCP32XX_TIMER_CR2(x)                   io_p2v((x) + 0x34)
-#define LCP32XX_TIMER_CR3(x)                   io_p2v((x) + 0x38)
-#define LCP32XX_TIMER_EMR(x)                   io_p2v((x) + 0x3C)
-#define LCP32XX_TIMER_CTCR(x)                  io_p2v((x) + 0x70)
+#define LPC32XX_TIMER_IR(x)                    io_p2v((x) + 0x00)
+#define LPC32XX_TIMER_TCR(x)                   io_p2v((x) + 0x04)
+#define LPC32XX_TIMER_TC(x)                    io_p2v((x) + 0x08)
+#define LPC32XX_TIMER_PR(x)                    io_p2v((x) + 0x0C)
+#define LPC32XX_TIMER_PC(x)                    io_p2v((x) + 0x10)
+#define LPC32XX_TIMER_MCR(x)                   io_p2v((x) + 0x14)
+#define LPC32XX_TIMER_MR0(x)                   io_p2v((x) + 0x18)
+#define LPC32XX_TIMER_MR1(x)                   io_p2v((x) + 0x1C)
+#define LPC32XX_TIMER_MR2(x)                   io_p2v((x) + 0x20)
+#define LPC32XX_TIMER_MR3(x)                   io_p2v((x) + 0x24)
+#define LPC32XX_TIMER_CCR(x)                   io_p2v((x) + 0x28)
+#define LPC32XX_TIMER_CR0(x)                   io_p2v((x) + 0x2C)
+#define LPC32XX_TIMER_CR1(x)                   io_p2v((x) + 0x30)
+#define LPC32XX_TIMER_CR2(x)                   io_p2v((x) + 0x34)
+#define LPC32XX_TIMER_CR3(x)                   io_p2v((x) + 0x38)
+#define LPC32XX_TIMER_EMR(x)                   io_p2v((x) + 0x3C)
+#define LPC32XX_TIMER_CTCR(x)                  io_p2v((x) + 0x70)
 
 /*
  * ir register definitions
  */
-#define LCP32XX_TIMER_CNTR_MTCH_BIT(n)         (1 << ((n) & 0x3))
-#define LCP32XX_TIMER_CNTR_CAPT_BIT(n)         (1 << (4 + ((n) & 0x3)))
+#define LPC32XX_TIMER_CNTR_MTCH_BIT(n)         (1 << ((n) & 0x3))
+#define LPC32XX_TIMER_CNTR_CAPT_BIT(n)         (1 << (4 + ((n) & 0x3)))
 
 /*
  * tcr register definitions
  */
-#define LCP32XX_TIMER_CNTR_TCR_EN              0x1
-#define LCP32XX_TIMER_CNTR_TCR_RESET           0x2
+#define LPC32XX_TIMER_CNTR_TCR_EN              0x1
+#define LPC32XX_TIMER_CNTR_TCR_RESET           0x2
 
 /*
  * mcr register definitions
  */
-#define LCP32XX_TIMER_CNTR_MCR_MTCH(n)         (0x1 << ((n) * 3))
-#define LCP32XX_TIMER_CNTR_MCR_RESET(n)                (0x1 << (((n) * 3) + 1))
-#define LCP32XX_TIMER_CNTR_MCR_STOP(n)         (0x1 << (((n) * 3) + 2))
+#define LPC32XX_TIMER_CNTR_MCR_MTCH(n)         (0x1 << ((n) * 3))
+#define LPC32XX_TIMER_CNTR_MCR_RESET(n)                (0x1 << (((n) * 3) + 1))
+#define LPC32XX_TIMER_CNTR_MCR_STOP(n)         (0x1 << (((n) * 3) + 2))
 
 /*
  * Standard UART register offsets
 #define LPC32XX_GPIO_P1_MUX_SET                        _GPREG(0x130)
 #define LPC32XX_GPIO_P1_MUX_CLR                        _GPREG(0x134)
 #define LPC32XX_GPIO_P1_MUX_STATE              _GPREG(0x138)
+#define LPC32XX_GPIO_P2_MUX_SET                        _GPREG(0x028)
+#define LPC32XX_GPIO_P2_MUX_CLR                        _GPREG(0x02C)
+#define LPC32XX_GPIO_P2_MUX_STATE              _GPREG(0x030)
 
 #endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/system.h b/arch/arm/mach-lpc32xx/include/mach/system.h
deleted file mode 100644 (file)
index bf176c9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-lpc32xx/include/mach/system.h
- *
- * Author: Kevin Wells <kevin.wells@nxp.com>
- *
- * Copyright (C) 2010 NXP Semiconductors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
index c74de01..d080cb1 100644 (file)
@@ -150,6 +150,10 @@ static const struct lpc32xx_event_info lpc32xx_events[NR_IRQS] = {
                .event_group = &lpc32xx_event_int_regs,
                .mask = LPC32XX_CLKPWR_INTSRC_KEY_BIT,
        },
+       [IRQ_LPC32XX_ETHERNET] = {
+               .event_group = &lpc32xx_event_int_regs,
+               .mask = LPC32XX_CLKPWR_INTSRC_MAC_BIT,
+       },
        [IRQ_LPC32XX_USB_OTG_ATX] = {
                .event_group = &lpc32xx_event_int_regs,
                .mask = LPC32XX_CLKPWR_INTSRC_USBATXINT_BIT,
index bfee5b4..7f7401e 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
+#include <mach/board.h>
 #include <mach/gpio-lpc32xx.h>
 #include "common.h"
 
@@ -149,20 +150,8 @@ static struct clcd_board lpc32xx_clcd_data = {
        .remove         = lpc32xx_clcd_remove,
 };
 
-static struct amba_device lpc32xx_clcd_device = {
-       .dev                            = {
-               .coherent_dma_mask      = ~0,
-               .init_name              = "dev:clcd",
-               .platform_data          = &lpc32xx_clcd_data,
-       },
-       .res                            = {
-               .start                  = LPC32XX_LCD_BASE,
-               .end                    = (LPC32XX_LCD_BASE + SZ_4K - 1),
-               .flags                  = IORESOURCE_MEM,
-       },
-       .dma_mask                       = ~0,
-       .irq                            = {IRQ_LPC32XX_LCD, NO_IRQ},
-};
+static AMBA_AHB_DEVICE(lpc32xx_clcd, "dev:clcd", 0,
+       LPC32XX_LCD_BASE, { IRQ_LPC32XX_LCD }, &lpc32xx_clcd_data);
 
 /*
  * AMBA SSP (SPI)
@@ -191,20 +180,8 @@ static struct pl022_ssp_controller lpc32xx_ssp0_data = {
        .enable_dma             = 0,
 };
 
-static struct amba_device lpc32xx_ssp0_device = {
-       .dev                            = {
-               .coherent_dma_mask      = ~0,
-               .init_name              = "dev:ssp0",
-               .platform_data          = &lpc32xx_ssp0_data,
-       },
-       .res                            = {
-               .start                  = LPC32XX_SSP0_BASE,
-               .end                    = (LPC32XX_SSP0_BASE + SZ_4K - 1),
-               .flags                  = IORESOURCE_MEM,
-       },
-       .dma_mask                       = ~0,
-       .irq                            = {IRQ_LPC32XX_SSP0, NO_IRQ},
-};
+static AMBA_APB_DEVICE(lpc32xx_ssp0, "dev:ssp0", 0,
+       LPC32XX_SSP0_BASE, { IRQ_LPC32XX_SSP0 }, &lpc32xx_ssp0_data);
 
 /* AT25 driver registration */
 static int __init phy3250_spi_board_register(void)
@@ -271,11 +248,16 @@ static struct platform_device lpc32xx_gpio_led_device = {
 };
 
 static struct platform_device *phy3250_devs[] __initdata = {
+       &lpc32xx_rtc_device,
+       &lpc32xx_tsc_device,
        &lpc32xx_i2c0_device,
        &lpc32xx_i2c1_device,
        &lpc32xx_i2c2_device,
        &lpc32xx_watchdog_device,
        &lpc32xx_gpio_led_device,
+       &lpc32xx_adc_device,
+       &lpc32xx_ohci_device,
+       &lpc32xx_net_device,
 };
 
 static struct amba_device *amba_devs[] __initdata = {
index b9c8059..207e812 100644 (file)
@@ -13,7 +13,7 @@
 /*
  * LPC32XX CPU and system power management
  *
- * The LCP32XX has three CPU modes for controlling system power: run,
+ * The LPC32XX has three CPU modes for controlling system power: run,
  * direct-run, and halt modes. When switching between halt and run modes,
  * the CPU transistions through direct-run mode. For Linux, direct-run
  * mode is not used in normal operation. Halt mode is used when the
index b42c909..c40667c 100644 (file)
 static int lpc32xx_clkevt_next_event(unsigned long delta,
     struct clock_event_device *dev)
 {
-       __raw_writel(LCP32XX_TIMER_CNTR_TCR_RESET,
-               LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
-       __raw_writel(delta, LCP32XX_TIMER_PR(LPC32XX_TIMER0_BASE));
-       __raw_writel(LCP32XX_TIMER_CNTR_TCR_EN,
-               LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+       __raw_writel(LPC32XX_TIMER_CNTR_TCR_RESET,
+               LPC32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+       __raw_writel(delta, LPC32XX_TIMER_PR(LPC32XX_TIMER0_BASE));
+       __raw_writel(LPC32XX_TIMER_CNTR_TCR_EN,
+               LPC32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
 
        return 0;
 }
@@ -58,7 +58,7 @@ static void lpc32xx_clkevt_mode(enum clock_event_mode mode,
                 * disable the timer to wait for the first call to
                 * set_next_event().
                 */
-               __raw_writel(0, LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+               __raw_writel(0, LPC32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
                break;
 
        case CLOCK_EVT_MODE_UNUSED:
@@ -81,8 +81,8 @@ static irqreturn_t lpc32xx_timer_interrupt(int irq, void *dev_id)
        struct clock_event_device *evt = &lpc32xx_clkevt;
 
        /* Clear match */
-       __raw_writel(LCP32XX_TIMER_CNTR_MTCH_BIT(0),
-               LCP32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
+       __raw_writel(LPC32XX_TIMER_CNTR_MTCH_BIT(0),
+               LPC32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
 
        evt->event_handler(evt);
 
@@ -128,14 +128,14 @@ static void __init lpc32xx_timer_init(void)
        clkrate = clkrate / clk_get_pclk_div();
 
        /* Initial timer setup */
-       __raw_writel(0, LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
-       __raw_writel(LCP32XX_TIMER_CNTR_MTCH_BIT(0),
-               LCP32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
-       __raw_writel(1, LCP32XX_TIMER_MR0(LPC32XX_TIMER0_BASE));
-       __raw_writel(LCP32XX_TIMER_CNTR_MCR_MTCH(0) |
-               LCP32XX_TIMER_CNTR_MCR_STOP(0) |
-               LCP32XX_TIMER_CNTR_MCR_RESET(0),
-               LCP32XX_TIMER_MCR(LPC32XX_TIMER0_BASE));
+       __raw_writel(0, LPC32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+       __raw_writel(LPC32XX_TIMER_CNTR_MTCH_BIT(0),
+               LPC32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
+       __raw_writel(1, LPC32XX_TIMER_MR0(LPC32XX_TIMER0_BASE));
+       __raw_writel(LPC32XX_TIMER_CNTR_MCR_MTCH(0) |
+               LPC32XX_TIMER_CNTR_MCR_STOP(0) |
+               LPC32XX_TIMER_CNTR_MCR_RESET(0),
+               LPC32XX_TIMER_MCR(LPC32XX_TIMER0_BASE));
 
        /* Setup tick interrupt */
        setup_irq(IRQ_LPC32XX_TIMER0, &lpc32xx_timer_irq);
@@ -151,14 +151,14 @@ static void __init lpc32xx_timer_init(void)
        clockevents_register_device(&lpc32xx_clkevt);
 
        /* Use timer1 as clock source. */
-       __raw_writel(LCP32XX_TIMER_CNTR_TCR_RESET,
-               LCP32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
-       __raw_writel(0, LCP32XX_TIMER_PR(LPC32XX_TIMER1_BASE));
-       __raw_writel(0, LCP32XX_TIMER_MCR(LPC32XX_TIMER1_BASE));
-       __raw_writel(LCP32XX_TIMER_CNTR_TCR_EN,
-               LCP32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
-
-       clocksource_mmio_init(LCP32XX_TIMER_TC(LPC32XX_TIMER1_BASE),
+       __raw_writel(LPC32XX_TIMER_CNTR_TCR_RESET,
+               LPC32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
+       __raw_writel(0, LPC32XX_TIMER_PR(LPC32XX_TIMER1_BASE));
+       __raw_writel(0, LPC32XX_TIMER_MCR(LPC32XX_TIMER1_BASE));
+       __raw_writel(LPC32XX_TIMER_CNTR_TCR_EN,
+               LPC32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
+
+       clocksource_mmio_init(LPC32XX_TIMER_TC(LPC32XX_TIMER1_BASE),
                "lpc32xx_clksrc", clkrate, 300, 32, clocksource_mmio_readl_up);
 }
 
index 323d4c9..5a90b9a 100644 (file)
@@ -2,6 +2,16 @@ if ARCH_MMP
 
 menu "Marvell PXA168/910/MMP2 Implmentations"
 
+config MACH_MMP_DT
+       bool "Support MMP2 platforms from device tree"
+       select CPU_PXA168
+       select CPU_PXA910
+       select USE_OF
+       help
+         Include support for Marvell MMP2 based platforms using
+         the device tree. Needn't select any other machine while
+         MACH_MMP_DT is enabled.
+
 config MACH_ASPENITE
        bool "Marvell's PXA168 Aspenite Development Board"
        select CPU_PXA168
index ba254a7..4fc0ff5 100644 (file)
@@ -18,5 +18,6 @@ obj-$(CONFIG_MACH_TTC_DKB)    += ttc_dkb.o
 obj-$(CONFIG_MACH_BROWNSTONE)  += brownstone.o
 obj-$(CONFIG_MACH_FLINT)       += flint.o
 obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o
+obj-$(CONFIG_MACH_MMP_DT)      += mmp-dt.o
 obj-$(CONFIG_MACH_TETON_BGA)   += teton_bga.o
 obj-$(CONFIG_MACH_GPLUGD)      += gplugd.o
index c42d9d4..9cff9e7 100644 (file)
@@ -8,12 +8,6 @@
 
 #include <mach/regs-icu.h>
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        mrc     p15, 0, \tmp, c0, c0, 0         @ CPUID
        and     \tmp, \tmp, #0xff00
index 4de13ab..e2e1f1e 100644 (file)
@@ -22,6 +22,7 @@ extern struct pxa_device_desc pxa910_device_pwm4;
 extern struct pxa_device_desc pxa910_device_nand;
 
 extern struct platform_device pxa910_device_gpio;
+extern struct platform_device pxa910_device_rtc;
 
 static inline int pxa910_add_uart(int id)
 {
index 1a96585..8a37fb0 100644 (file)
@@ -57,6 +57,7 @@
 #define APBC_PXA910_SSP1       APBC_REG(0x01c)
 #define APBC_PXA910_SSP2       APBC_REG(0x020)
 #define APBC_PXA910_IPC                APBC_REG(0x024)
+#define APBC_PXA910_RTC                APBC_REG(0x028)
 #define APBC_PXA910_TWSI0      APBC_REG(0x02c)
 #define APBC_PXA910_KPC                APBC_REG(0x030)
 #define APBC_PXA910_TIMERS     APBC_REG(0x034)
diff --git a/arch/arm/mach-mmp/include/mach/regs-rtc.h b/arch/arm/mach-mmp/include/mach/regs-rtc.h
new file mode 100644 (file)
index 0000000..5bff886
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __ASM_MACH_REGS_RTC_H
+#define __ASM_MACH_REGS_RTC_H
+
+#include <mach/addr-map.h>
+
+#define RTC_VIRT_BASE  (APB_VIRT_BASE + 0x10000)
+#define RTC_REG(x)     (*((volatile u32 __iomem *)(RTC_VIRT_BASE + (x))))
+
+/*
+ * Real Time Clock
+ */
+
+#define RCNR           RTC_REG(0x00)   /* RTC Count Register */
+#define RTAR           RTC_REG(0x04)   /* RTC Alarm Register */
+#define RTSR           RTC_REG(0x08)   /* RTC Status Register */
+#define RTTR           RTC_REG(0x0C)   /* RTC Timer Trim Register */
+
+#define RTSR_HZE       (1 << 3)        /* HZ interrupt enable */
+#define RTSR_ALE       (1 << 2)        /* RTC alarm interrupt enable */
+#define RTSR_HZ                (1 << 1)        /* HZ rising-edge detected */
+#define RTSR_AL                (1 << 0)        /* RTC alarm detected */
+
+#endif /* __ASM_MACH_REGS_RTC_H */
diff --git a/arch/arm/mach-mmp/include/mach/system.h b/arch/arm/mach-mmp/include/mach/system.h
deleted file mode 100644 (file)
index 1d001ea..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/include/mach/system.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_MACH_SYSTEM_H
-#define __ASM_MACH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-#endif /* __ASM_MACH_SYSTEM_H */
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
new file mode 100644 (file)
index 0000000..6707539
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *  linux/arch/arm/mach-mmp/mmp-dt.c
+ *
+ *  Copyright (C) 2012 Marvell Technology Group Ltd.
+ *  Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+extern struct sys_timer pxa168_timer;
+extern void __init icu_init_irq(void);
+
+static const struct of_dev_auxdata mmp_auxdata_lookup[] __initconst = {
+       OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
+       OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
+       OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4026000, "pxa2xx-uart.2", NULL),
+       OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
+       OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
+       OF_DEV_AUXDATA("mrvl,mmp-gpio", 0xd4019000, "pxa-gpio", NULL),
+       OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
+       {}
+};
+
+static int __init mmp_intc_add_irq_domain(struct device_node *np,
+                                          struct device_node *parent)
+{
+       irq_domain_add_simple(np, 0);
+       return 0;
+}
+
+static int __init mmp_gpio_add_irq_domain(struct device_node *np,
+                                          struct device_node *parent)
+{
+       irq_domain_add_simple(np, IRQ_GPIO_START);
+       return 0;
+}
+
+static const struct of_device_id mmp_irq_match[] __initconst = {
+       { .compatible = "mrvl,mmp-intc", .data = mmp_intc_add_irq_domain, },
+       { .compatible = "mrvl,mmp-gpio", .data = mmp_gpio_add_irq_domain, },
+       {}
+};
+
+static void __init mmp_dt_init(void)
+{
+
+       of_irq_init(mmp_irq_match);
+
+       of_platform_populate(NULL, of_default_bus_match_table,
+                            mmp_auxdata_lookup, NULL);
+}
+
+static const char *pxa168_dt_board_compat[] __initdata = {
+       "mrvl,pxa168-aspenite",
+       NULL,
+};
+
+DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
+       .map_io         = mmp_map_io,
+       .init_irq       = icu_init_irq,
+       .timer          = &pxa168_timer,
+       .init_machine   = mmp_dt_init,
+       .dt_compat      = pxa168_dt_board_compat,
+MACHINE_END
index 617c60a..c709a24 100644 (file)
@@ -223,6 +223,7 @@ struct resource mmp2_resource_gpio[] = {
        }, {
                .start  = IRQ_MMP2_GPIO,
                .end    = IRQ_MMP2_GPIO,
+               .name   = "gpio_mux",
                .flags  = IORESOURCE_IRQ,
        },
 };
index 520f39d..b24d2c3 100644 (file)
@@ -65,6 +65,7 @@ static APBC_CLK(ssp4, PXA168_SSP4, 4, 0);
 static APBC_CLK(ssp5, PXA168_SSP5, 4, 0);
 static APBC_CLK(gpio, PXA168_GPIO, 0, 13000000);
 static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
+static APBC_CLK(rtc, PXA168_RTC, 8, 32768);
 
 static APMU_CLK(nand, NAND, 0x19b, 156000000);
 static APMU_CLK(lcd, LCD, 0x7f, 312000000);
@@ -93,6 +94,7 @@ static struct clk_lookup pxa168_clkregs[] = {
        INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
        INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
        INIT_CLKREG(&clk_usb, "pxa168-ehci", "PXA168-USBCLK"),
+       INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
 };
 
 static int __init pxa168_init(void)
@@ -167,6 +169,7 @@ struct resource pxa168_resource_gpio[] = {
        }, {
                .start  = IRQ_PXA168_GPIOX,
                .end    = IRQ_PXA168_GPIOX,
+               .name   = "gpio_mux",
                .flags  = IORESOURCE_IRQ,
        },
 };
index 3241a25..43f8bcc 100644 (file)
@@ -92,6 +92,7 @@ static APBC_CLK(pwm2, PXA910_PWM2, 1, 13000000);
 static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000);
 static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000);
 static APBC_CLK(gpio, PXA910_GPIO, 0, 13000000);
+static APBC_CLK(rtc, PXA910_RTC, 8, 32768);
 
 static APMU_CLK(nand, NAND, 0x19b, 156000000);
 static APMU_CLK(u2o, USB, 0x1b, 480000000);
@@ -109,6 +110,7 @@ static struct clk_lookup pxa910_clkregs[] = {
        INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
        INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
        INIT_CLKREG(&clk_u2o, "pxa-u2o", "U2OCLK"),
+       INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
 };
 
 static int __init pxa910_init(void)
@@ -173,6 +175,7 @@ struct resource pxa910_resource_gpio[] = {
        }, {
                .start  = IRQ_PXA910_AP_GPIO,
                .end    = IRQ_PXA910_AP_GPIO,
+               .name   = "gpio_mux",
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -183,3 +186,28 @@ struct platform_device pxa910_device_gpio = {
        .num_resources  = ARRAY_SIZE(pxa910_resource_gpio),
        .resource       = pxa910_resource_gpio,
 };
+
+static struct resource pxa910_resource_rtc[] = {
+       {
+               .start  = 0xd4010000,
+               .end    = 0xd401003f,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_PXA910_RTC_INT,
+               .end    = IRQ_PXA910_RTC_INT,
+               .name   = "rtc 1Hz",
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = IRQ_PXA910_RTC_ALARM,
+               .end    = IRQ_PXA910_RTC_ALARM,
+               .name   = "rtc alarm",
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device pxa910_device_rtc = {
+       .name           = "sa1100-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(pxa910_resource_rtc),
+       .resource       = pxa910_resource_rtc,
+};
index 5ac5d58..e72c709 100644 (file)
@@ -124,6 +124,7 @@ static struct platform_device ttc_dkb_device_onenand = {
 
 static struct platform_device *ttc_dkb_devices[] = {
        &pxa910_device_gpio,
+       &pxa910_device_rtc,
        &ttc_dkb_device_onenand,
 };
 
diff --git a/arch/arm/mach-msm/idle.S b/arch/arm/mach-msm/idle.S
deleted file mode 100644 (file)
index 6a94f05..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* arch/arm/mach-msm/include/mach/idle.S
- *
- * Idle processing for MSM7K - work around bugs with SWFI.
- *
- * Copyright (c) 2007 QUALCOMM Incorporated.
- * Copyright (C) 2007 Google, Inc. 
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */ 
-               
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-
-ENTRY(arch_idle)
-#ifdef CONFIG_MSM7X00A_IDLE
-       mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */
-       bic     r0, r1, #(1 << 2)        /* clear dcache bit   */
-       bic     r0, r0, #(1 << 12)       /* clear icache bit   */
-       mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
-
-       mov     r0, #0                   /* prepare wfi value  */
-       mcr     p15, 0, r0, c7, c10, 0   /* flush the cache    */
-       mcr     p15, 0, r0, c7, c10, 4   /* memory barrier     */
-       mcr     p15, 0, r0, c7, c0, 4    /* wait for interrupt */
-
-       mcr     p15, 0, r1, c1, c0, 0    /* restore d/i cache  */
-#endif
-       mov     pc, lr
diff --git a/arch/arm/mach-msm/idle.c b/arch/arm/mach-msm/idle.c
new file mode 100644 (file)
index 0000000..0c9e13c
--- /dev/null
@@ -0,0 +1,49 @@
+/* arch/arm/mach-msm/idle.c
+ *
+ * Idle processing for MSM7K - work around bugs with SWFI.
+ *
+ * Copyright (c) 2007 QUALCOMM Incorporated.
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <asm/system.h>
+
+static void msm_idle(void)
+{
+#ifdef CONFIG_MSM7X00A_IDLE
+       asm volatile (
+
+       "mrc     p15, 0, r1, c1, c0, 0    /* read current CR    */ \n\t"
+       "bic     r0, r1, #(1 << 2)        /* clear dcache bit   */ \n\t"
+       "bic     r0, r0, #(1 << 12)       /* clear icache bit   */ \n\t"
+       "mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */ \n\t"
+
+       "mov     r0, #0                   /* prepare wfi value  */ \n\t"
+       "mcr     p15, 0, r0, c7, c10, 0   /* flush the cache    */ \n\t"
+       "mcr     p15, 0, r0, c7, c10, 4   /* memory barrier     */ \n\t"
+       "mcr     p15, 0, r0, c7, c0, 4    /* wait for interrupt */ \n\t"
+
+       "mcr     p15, 0, r1, c1, c0, 0    /* restore d/i cache  */ \n\t"
+
+       : : : "r0","r1" );
+#endif
+}
+
+static int __init msm_idle_init(void)
+{
+       arm_pm_idle = msm_idle;
+       return 0;
+}
+
+arch_initcall(msm_idle_init);
index 41f7003..f2ae908 100644 (file)
  *
  */
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
 #if !defined(CONFIG_ARM_GIC)
 #include <mach/msm_iomap.h>
 
index 311db2b..f5fb2ec 100644 (file)
@@ -12,7 +12,6 @@
  * GNU General Public License for more details.
  *
  */
-void arch_idle(void);
 
 /* low level hardware reset hook -- for example, hitting the
  * PSHOLD line on the PMIC to hard reset the system
index 11d0d8f..75f4be4 100644 (file)
@@ -127,6 +127,45 @@ static struct clocksource msm_clocksource = {
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+#ifdef CONFIG_LOCAL_TIMERS
+static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt)
+{
+       /* Use existing clock_event for cpu 0 */
+       if (!smp_processor_id())
+               return 0;
+
+       writel_relaxed(0, event_base + TIMER_ENABLE);
+       writel_relaxed(0, event_base + TIMER_CLEAR);
+       writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
+       evt->irq = msm_clockevent.irq;
+       evt->name = "local_timer";
+       evt->features = msm_clockevent.features;
+       evt->rating = msm_clockevent.rating;
+       evt->set_mode = msm_timer_set_mode;
+       evt->set_next_event = msm_timer_set_next_event;
+       evt->shift = msm_clockevent.shift;
+       evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift);
+       evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt);
+       evt->min_delta_ns = clockevent_delta2ns(4, evt);
+
+       *__this_cpu_ptr(msm_evt.percpu_evt) = evt;
+       clockevents_register_device(evt);
+       enable_percpu_irq(evt->irq, 0);
+       return 0;
+}
+
+static void msm_local_timer_stop(struct clock_event_device *evt)
+{
+       evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+       disable_percpu_irq(evt->irq);
+}
+
+static struct local_timer_ops msm_local_timer_ops __cpuinitdata = {
+       .setup  = msm_local_timer_setup,
+       .stop   = msm_local_timer_stop,
+};
+#endif /* CONFIG_LOCAL_TIMERS */
+
 static void __init msm_timer_init(void)
 {
        struct clock_event_device *ce = &msm_clockevent;
@@ -173,8 +212,12 @@ static void __init msm_timer_init(void)
                *__this_cpu_ptr(msm_evt.percpu_evt) = ce;
                res = request_percpu_irq(ce->irq, msm_timer_interrupt,
                                         ce->name, msm_evt.percpu_evt);
-               if (!res)
+               if (!res) {
                        enable_percpu_irq(ce->irq, 0);
+#ifdef CONFIG_LOCAL_TIMERS
+                       local_timer_register(&msm_local_timer_ops);
+#endif
+               }
        } else {
                msm_evt.evt = ce;
                res = request_irq(ce->irq, msm_timer_interrupt,
@@ -191,40 +234,6 @@ err:
                pr_err("clocksource_register failed\n");
 }
 
-#ifdef CONFIG_LOCAL_TIMERS
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       /* Use existing clock_event for cpu 0 */
-       if (!smp_processor_id())
-               return 0;
-
-       writel_relaxed(0, event_base + TIMER_ENABLE);
-       writel_relaxed(0, event_base + TIMER_CLEAR);
-       writel_relaxed(~0, event_base + TIMER_MATCH_VAL);
-       evt->irq = msm_clockevent.irq;
-       evt->name = "local_timer";
-       evt->features = msm_clockevent.features;
-       evt->rating = msm_clockevent.rating;
-       evt->set_mode = msm_timer_set_mode;
-       evt->set_next_event = msm_timer_set_next_event;
-       evt->shift = msm_clockevent.shift;
-       evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift);
-       evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt);
-       evt->min_delta_ns = clockevent_delta2ns(4, evt);
-
-       *__this_cpu_ptr(msm_evt.percpu_evt) = evt;
-       clockevents_register_device(evt);
-       enable_percpu_irq(evt->irq, 0);
-       return 0;
-}
-
-void local_timer_stop(struct clock_event_device *evt)
-{
-       evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
-       disable_percpu_irq(evt->irq);
-}
-#endif /* CONFIG_LOCAL_TIMERS */
-
 struct sys_timer msm_timer = {
        .init = msm_timer_init
 };
index 66ae2d2..6b1f088 100644 (file)
 
 #include <mach/bridge-regs.h>
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =IRQ_VIRT_BASE
        .endm
diff --git a/arch/arm/mach-mv78xx0/include/mach/system.h b/arch/arm/mach-mv78xx0/include/mach/system.h
deleted file mode 100644 (file)
index 8c3a538..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-mv78xx0/include/mach/system.h
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
index 8459f6d..df3e380 100644 (file)
@@ -155,8 +155,8 @@ static int __init mv78xx0_pcie_setup(int nr, struct pci_sys_data *sys)
        orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
        orion_pcie_setup(pp->base);
 
-       pci_add_resource(&sys->resources, &pp->res[0]);
-       pci_add_resource(&sys->resources, &pp->res[1]);
+       pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+       pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
        return 1;
 }
index cf00b3e..c57f996 100644 (file)
@@ -83,6 +83,18 @@ config MODULE_M28
        select MXS_HAVE_PLATFORM_MXSFB
        select MXS_OCOTP
 
+config MODULE_APX4
+       bool
+       select SOC_IMX28
+       select LEDS_GPIO_REGISTER
+       select MXS_HAVE_AMBA_DUART
+       select MXS_HAVE_PLATFORM_AUART
+       select MXS_HAVE_PLATFORM_FEC
+       select MXS_HAVE_PLATFORM_MXS_I2C
+       select MXS_HAVE_PLATFORM_MXS_MMC
+       select MXS_HAVE_PLATFORM_MXS_SAIF
+       select MXS_OCOTP
+
 config MACH_TX28
        bool "Ka-Ro TX28 module"
        select MODULE_TX28
@@ -91,4 +103,8 @@ config MACH_M28EVK
        bool "Support DENX M28EVK Platform"
        select MODULE_M28
 
+config MACH_APX4DEVKIT
+       bool "Support Bluegiga APX4 Development Kit"
+       select MODULE_APX4
+
 endif
index 8c93b24..908bf9a 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_MACH_STMP378X_DEVB) += mach-stmp378x_devb.o
 obj-$(CONFIG_MACH_MX23EVK) += mach-mx23evk.o
 obj-$(CONFIG_MACH_MX28EVK) += mach-mx28evk.o
 obj-$(CONFIG_MACH_M28EVK)    += mach-m28evk.o
+obj-$(CONFIG_MACH_APX4DEVKIT) += mach-apx4devkit.o
 obj-$(CONFIG_MODULE_TX28) += module-tx28.o
 obj-$(CONFIG_MACH_TX28)    += mach-tx28.o
 
index e12e112..e3ac52c 100644 (file)
@@ -223,7 +223,6 @@ static int cpu_clk_set_rate(struct clk *clk, unsigned long rate)
 {
        u32 reg, bm_busy, div_max, d, f, div, frac;
        unsigned long diff, parent_rate, calc_rate;
-       int i;
 
        parent_rate = clk_get_rate(clk->parent);
 
@@ -275,14 +274,7 @@ static int cpu_clk_set_rate(struct clk *clk, unsigned long rate)
        reg |= div << BP_CLKCTRL_CPU_DIV_CPU;
        __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);
 
-       for (i = 10000; i; i--)
-               if (!(__raw_readl(CLKCTRL_BASE_ADDR +
-                                       HW_CLKCTRL_CPU) & bm_busy))
-                       break;
-       if (!i) {
-               pr_err("%s: divider writing timeout\n", __func__);
-               return -ETIMEDOUT;
-       }
+       mxs_clkctrl_timeout(HW_CLKCTRL_CPU, bm_busy);
 
        return 0;
 }
@@ -292,7 +284,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)             \
 {                                                                      \
        u32 reg, div_max, div;                                          \
        unsigned long parent_rate;                                      \
-       int i;                                                          \
                                                                        \
        parent_rate = clk_get_rate(clk->parent);                        \
        div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV;       \
@@ -310,15 +301,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)            \
        }                                                               \
        __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);         \
                                                                        \
-       for (i = 10000; i; i--)                                         \
-               if (!(__raw_readl(CLKCTRL_BASE_ADDR +                   \
-                       HW_CLKCTRL_##dr) & BM_CLKCTRL_##dr##_BUSY))     \
-                       break;                                          \
-       if (!i) {                                                       \
-               pr_err("%s: divider writing timeout\n", __func__);      \
-               return -ETIMEDOUT;                                      \
-       }                                                               \
-                                                                       \
+       mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY);   \
        return 0;                                                       \
 }
 
@@ -456,12 +439,13 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("mxs-pwm.3", NULL, pwm_clk)
        _REGISTER_CLOCK("mxs-pwm.4", NULL, pwm_clk)
        _REGISTER_CLOCK("imx23-fb", NULL, lcdif_clk)
+       _REGISTER_CLOCK("imx23-gpmi-nand", NULL, gpmi_clk)
 };
 
 static int clk_misc_init(void)
 {
        u32 reg;
-       int i;
+       int ret;
 
        /* Fix up parent per register setting */
        reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ);
@@ -510,14 +494,7 @@ static int clk_misc_init(void)
        reg |= 3 << BP_CLKCTRL_HBUS_DIV;
        __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
 
-       for (i = 10000; i; i--)
-               if (!(__raw_readl(CLKCTRL_BASE_ADDR +
-                       HW_CLKCTRL_HBUS) & BM_CLKCTRL_HBUS_BUSY))
-                       break;
-       if (!i) {
-               pr_err("%s: divider writing timeout\n", __func__);
-               return -ETIMEDOUT;
-       }
+       ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_BUSY);
 
        /* Gate off cpu clock in WFI for power saving */
        __raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT,
@@ -532,7 +509,7 @@ static int clk_misc_init(void)
        reg |= 30 << BP_CLKCTRL_FRAC_IOFRAC;
        __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC);
 
-       return 0;
+       return ret;
 }
 
 int __init mx23_clocks_init(void)
index 5d68e41..cea29c9 100644 (file)
@@ -322,7 +322,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)             \
 {                                                                      \
        u32 reg, bm_busy, div_max, d, f, div, frac;                     \
        unsigned long diff, parent_rate, calc_rate;                     \
-       int i;                                                          \
                                                                        \
        div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV;       \
        bm_busy = BM_CLKCTRL_##dr##_BUSY;                               \
@@ -396,16 +395,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)            \
        }                                                               \
        __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);         \
                                                                        \
-       for (i = 10000; i; i--)                                         \
-               if (!(__raw_readl(CLKCTRL_BASE_ADDR +                   \
-                       HW_CLKCTRL_##dr) & bm_busy))                    \
-                       break;                                          \
-       if (!i) {                                                       \
-               pr_err("%s: divider writing timeout\n", __func__);      \
-               return -ETIMEDOUT;                                      \
-       }                                                               \
-                                                                       \
-       return 0;                                                       \
+       return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, bm_busy);           \
 }
 
 _CLK_SET_RATE(cpu_clk, CPU, FRAC0, CPU)
@@ -421,7 +411,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)             \
 {                                                                      \
        u32 reg, div_max, div;                                          \
        unsigned long parent_rate;                                      \
-       int i;                                                          \
                                                                        \
        parent_rate = clk_get_rate(clk->parent);                        \
        div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV;       \
@@ -439,16 +428,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)            \
        }                                                               \
        __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);         \
                                                                        \
-       for (i = 10000; i; i--)                                         \
-               if (!(__raw_readl(CLKCTRL_BASE_ADDR +                   \
-                       HW_CLKCTRL_##dr) & BM_CLKCTRL_##dr##_BUSY))     \
-                       break;                                          \
-       if (!i) {                                                       \
-               pr_err("%s: divider writing timeout\n", __func__);      \
-               return -ETIMEDOUT;                                      \
-       }                                                               \
-                                                                       \
-       return 0;                                                       \
+       return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY);\
 }
 
 _CLK_SET_RATE1(xbus_clk, XBUS)
@@ -461,7 +441,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)             \
        u32 reg;                                                        \
        u64 lrate;                                                      \
        unsigned long parent_rate;                                      \
-       int i;                                                          \
                                                                        \
        parent_rate = clk_get_rate(clk->parent);                        \
        if (rate > parent_rate)                                         \
@@ -477,18 +456,13 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)           \
        reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs);         \
        reg &= ~BM_CLKCTRL_##rs##_DIV;                                  \
        reg |= div << BP_CLKCTRL_##rs##_DIV;                            \
-       __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs);         \
-                                                                       \
-       for (i = 10000; i; i--)                                         \
-               if (!(__raw_readl(CLKCTRL_BASE_ADDR +                   \
-                       HW_CLKCTRL_##rs) & BM_CLKCTRL_##rs##_BUSY))     \
-                       break;                                          \
-       if (!i) {                                                       \
-               pr_err("%s: divider writing timeout\n", __func__);      \
-               return -ETIMEDOUT;                                      \
+       if (reg & (1 << clk->enable_shift)) {                           \
+               pr_err("%s: clock is gated\n", __func__);               \
+               return -EINVAL;                                         \
        }                                                               \
+       __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs);         \
                                                                        \
-       return 0;                                                       \
+       return mxs_clkctrl_timeout(HW_CLKCTRL_##rs, BM_CLKCTRL_##rs##_BUSY);\
 }
 
 _CLK_SET_RATE_SAIF(saif0_clk, SAIF0)
@@ -643,6 +617,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("duart", NULL, uart_clk)
        _REGISTER_CLOCK("imx28-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK("imx28-fec.1", NULL, fec_clk)
+       _REGISTER_CLOCK("imx28-gpmi-nand", NULL, gpmi_clk)
        _REGISTER_CLOCK("mxs-auart.0", NULL, uart_clk)
        _REGISTER_CLOCK("mxs-auart.1", NULL, uart_clk)
        _REGISTER_CLOCK("mxs-auart.2", NULL, uart_clk)
@@ -654,6 +629,8 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk)
        _REGISTER_CLOCK("mxs-mmc.0", NULL, ssp0_clk)
        _REGISTER_CLOCK("mxs-mmc.1", NULL, ssp1_clk)
+       _REGISTER_CLOCK("mxs-mmc.2", NULL, ssp2_clk)
+       _REGISTER_CLOCK("mxs-mmc.3", NULL, ssp3_clk)
        _REGISTER_CLOCK("flexcan.0", NULL, can0_clk)
        _REGISTER_CLOCK("flexcan.1", NULL, can1_clk)
        _REGISTER_CLOCK(NULL, "usb0", usb0_clk)
@@ -676,7 +653,7 @@ static struct clk_lookup lookups[] = {
 static int clk_misc_init(void)
 {
        u32 reg;
-       int i;
+       int ret;
 
        /* Fix up parent per register setting */
        reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ);
@@ -756,14 +733,7 @@ static int clk_misc_init(void)
        reg |= 3 << BP_CLKCTRL_HBUS_DIV;
        __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
 
-       for (i = 10000; i; i--)
-               if (!(__raw_readl(CLKCTRL_BASE_ADDR +
-                       HW_CLKCTRL_HBUS) & BM_CLKCTRL_HBUS_ASM_BUSY))
-                       break;
-       if (!i) {
-               pr_err("%s: divider writing timeout\n", __func__);
-               return -ETIMEDOUT;
-       }
+       ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_ASM_BUSY);
 
        /* Gate off cpu clock in WFI for power saving */
        __raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT,
@@ -790,7 +760,7 @@ static int clk_misc_init(void)
        reg |= 30 << BP_CLKCTRL_FRAC0_IO0FRAC;
        __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0);
 
-       return 0;
+       return ret;
 }
 
 int __init mx28_clocks_init(void)
@@ -803,6 +773,8 @@ int __init mx28_clocks_init(void)
         */
        clk_set_parent(&ssp0_clk, &ref_io0_clk);
        clk_set_parent(&ssp1_clk, &ref_io0_clk);
+       clk_set_parent(&ssp2_clk, &ref_io1_clk);
+       clk_set_parent(&ssp3_clk, &ref_io1_clk);
 
        clk_prepare_enable(&cpu_clk);
        clk_prepare_enable(&hbus_clk);
index 3fa651d..4d1329d 100644 (file)
@@ -21,6 +21,10 @@ extern const struct mxs_auart_data mx23_auart_data[] __initconst;
 #define mx23_add_auart0()              mx23_add_auart(0)
 #define mx23_add_auart1()              mx23_add_auart(1)
 
+extern const struct mxs_gpmi_nand_data mx23_gpmi_nand_data __initconst;
+#define mx23_add_gpmi_nand(pdata)      \
+       mxs_add_gpmi_nand(pdata, &mx23_gpmi_nand_data)
+
 extern const struct mxs_mxs_mmc_data mx23_mxs_mmc_data[] __initconst;
 #define mx23_add_mxs_mmc(id, pdata) \
        mxs_add_mxs_mmc(&mx23_mxs_mmc_data[id], pdata)
index 4f50094..9dbeae1 100644 (file)
@@ -34,6 +34,10 @@ extern const struct mxs_flexcan_data mx28_flexcan_data[] __initconst;
 #define mx28_add_flexcan0(pdata)       mx28_add_flexcan(0, pdata)
 #define mx28_add_flexcan1(pdata)       mx28_add_flexcan(1, pdata)
 
+extern const struct mxs_gpmi_nand_data mx28_gpmi_nand_data __initconst;
+#define mx28_add_gpmi_nand(pdata)      \
+       mxs_add_gpmi_nand(pdata, &mx28_gpmi_nand_data)
+
 extern const struct mxs_mxs_i2c_data mx28_mxs_i2c_data[] __initconst;
 #define mx28_add_mxs_i2c(id)           mxs_add_mxs_i2c(&mx28_mxs_i2c_data[id])
 
index fe3e847..01faffe 100644 (file)
@@ -77,16 +77,18 @@ err:
 
 int __init mxs_add_amba_device(const struct amba_device *dev)
 {
-       struct amba_device *adev = kmalloc(sizeof(*adev), GFP_KERNEL);
+       struct amba_device *adev = amba_device_alloc(dev->dev.init_name,
+               dev->res.start, resource_size(&dev->res));
 
        if (!adev) {
                pr_err("%s: failed to allocate memory", __func__);
                return -ENOMEM;
        }
 
-       *adev = *dev;
+       adev->irq[0] = dev->irq[0];
+       adev->irq[1] = dev->irq[1];
 
-       return amba_device_register(adev, &iomem_resource);
+       return amba_device_add(adev, &iomem_resource);
 }
 
 struct device mxs_apbh_bus = {
index 18b6bf5..b8913df 100644 (file)
@@ -12,6 +12,9 @@ config MXS_HAVE_PLATFORM_FLEXCAN
        select HAVE_CAN_FLEXCAN if CAN
        bool
 
+config MXS_HAVE_PLATFORM_GPMI_NAND
+       bool
+
 config MXS_HAVE_PLATFORM_MXS_I2C
        bool
 
index f52e3e5..c8f5c95 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_MXS_HAVE_PLATFORM_AUART) += platform-auart.o
 obj-y += platform-dma.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_FEC) += platform-fec.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o
+obj-$(CONFIG_MXS_HAVE_PLATFORM_GPMI_NAND) += platform-gpmi-nand.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_I2C) += platform-mxs-i2c.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_MMC) += platform-mxs-mmc.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_PWM) += platform-mxs-pwm.o
index a559db0..a5479f7 100644 (file)
@@ -23,7 +23,7 @@ const struct amba_device name##_device __initconst = {                \
                .end = (soc ## _DUART_BASE_ADDR) + SZ_8K - 1,   \
                .flags = IORESOURCE_MEM,                        \
        },                                                      \
-       .irq = {soc ## _INT_DUART, NO_IRQ},                     \
+       .irq = {soc ## _INT_DUART},                             \
 }
 
 #ifdef CONFIG_SOC_IMX23
diff --git a/arch/arm/mach-mxs/devices/platform-gpmi-nand.c b/arch/arm/mach-mxs/devices/platform-gpmi-nand.c
new file mode 100644 (file)
index 0000000..3e22df5
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 <asm/sizes.h>
+#include <mach/mx23.h>
+#include <mach/mx28.h>
+#include <mach/devices-common.h>
+#include <linux/dma-mapping.h>
+
+#ifdef CONFIG_SOC_IMX23
+const struct mxs_gpmi_nand_data mx23_gpmi_nand_data __initconst = {
+       .devid = "imx23-gpmi-nand",
+       .res = {
+               /* GPMI */
+               DEFINE_RES_MEM_NAMED(MX23_GPMI_BASE_ADDR, SZ_8K,
+                                       GPMI_NAND_GPMI_REGS_ADDR_RES_NAME),
+               DEFINE_RES_IRQ_NAMED(MX23_INT_GPMI_ATTENTION,
+                                       GPMI_NAND_GPMI_INTERRUPT_RES_NAME),
+               /* BCH */
+               DEFINE_RES_MEM_NAMED(MX23_BCH_BASE_ADDR, SZ_8K,
+                                       GPMI_NAND_BCH_REGS_ADDR_RES_NAME),
+               DEFINE_RES_IRQ_NAMED(MX23_INT_BCH,
+                                       GPMI_NAND_BCH_INTERRUPT_RES_NAME),
+               /* DMA */
+               DEFINE_RES_NAMED(MX23_DMA_GPMI0,
+                                       MX23_DMA_GPMI3 - MX23_DMA_GPMI0 + 1,
+                                       GPMI_NAND_DMA_CHANNELS_RES_NAME,
+                                       IORESOURCE_DMA),
+               DEFINE_RES_IRQ_NAMED(MX23_INT_GPMI_DMA,
+                                       GPMI_NAND_DMA_INTERRUPT_RES_NAME),
+       },
+};
+#endif
+
+#ifdef CONFIG_SOC_IMX28
+const struct mxs_gpmi_nand_data mx28_gpmi_nand_data __initconst = {
+       .devid = "imx28-gpmi-nand",
+       .res = {
+               /* GPMI */
+               DEFINE_RES_MEM_NAMED(MX28_GPMI_BASE_ADDR, SZ_8K,
+                                       GPMI_NAND_GPMI_REGS_ADDR_RES_NAME),
+               DEFINE_RES_IRQ_NAMED(MX28_INT_GPMI,
+                                       GPMI_NAND_GPMI_INTERRUPT_RES_NAME),
+               /* BCH */
+               DEFINE_RES_MEM_NAMED(MX28_BCH_BASE_ADDR, SZ_8K,
+                                       GPMI_NAND_BCH_REGS_ADDR_RES_NAME),
+               DEFINE_RES_IRQ_NAMED(MX28_INT_BCH,
+                                       GPMI_NAND_BCH_INTERRUPT_RES_NAME),
+               /* DMA */
+               DEFINE_RES_NAMED(MX28_DMA_GPMI0,
+                                       MX28_DMA_GPMI7 - MX28_DMA_GPMI0 + 1,
+                                       GPMI_NAND_DMA_CHANNELS_RES_NAME,
+                                       IORESOURCE_DMA),
+               DEFINE_RES_IRQ_NAMED(MX28_INT_GPMI_DMA,
+                                       GPMI_NAND_DMA_INTERRUPT_RES_NAME),
+       },
+};
+#endif
+
+struct platform_device *__init
+mxs_add_gpmi_nand(const struct gpmi_nand_platform_data *pdata,
+               const struct mxs_gpmi_nand_data *data)
+{
+       return mxs_add_platform_device_dmamask(data->devid, -1,
+                               data->res, GPMI_NAND_RES_SIZE,
+                               pdata, sizeof(*pdata), DMA_BIT_MASK(32));
+}
index 382dacb..bef9d92 100644 (file)
@@ -41,6 +41,8 @@ const struct mxs_mxs_mmc_data mx23_mxs_mmc_data[] __initconst = {
 const struct mxs_mxs_mmc_data mx28_mxs_mmc_data[] __initconst = {
        mxs_mxs_mmc_data_entry(MX28, 0, 0),
        mxs_mxs_mmc_data_entry(MX28, 1, 1),
+       mxs_mxs_mmc_data_entry(MX28, 2, 2),
+       mxs_mxs_mmc_data_entry(MX28, 3, 3),
 };
 #endif
 
index e1237ab..c50c3ea 100644 (file)
@@ -31,4 +31,6 @@ extern void mx28_init_irq(void);
 
 extern void icoll_init_irq(void);
 
+extern int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask);
+
 #endif /* __MACH_MXS_COMMON_H__ */
index dc369c1..f2e3839 100644 (file)
@@ -66,6 +66,16 @@ struct platform_device *__init mxs_add_flexcan(
                const struct mxs_flexcan_data *data,
                const struct flexcan_platform_data *pdata);
 
+/* gpmi-nand */
+#include <linux/mtd/gpmi-nand.h>
+struct mxs_gpmi_nand_data {
+       const char *devid;
+       const struct resource res[GPMI_NAND_RES_SIZE];
+};
+struct platform_device *__init
+mxs_add_gpmi_nand(const struct gpmi_nand_platform_data *pdata,
+               const struct mxs_gpmi_nand_data *data);
+
 /* i2c */
 struct mxs_mxs_i2c_data {
        int id;
index 49a888c..1796406 100644 (file)
@@ -18,4 +18,5 @@
 #define HW_DIGCTL_CTRL                 0x0
 #define  BP_DIGCTL_CTRL_SAIF_CLKMUX    10
 #define  BM_DIGCTL_CTRL_SAIF_CLKMUX    (0x3 << 10)
+#define HW_DIGCTL_CHIPID               0x310
 #endif
index 9f0da12..0c14259 100644 (file)
@@ -23,9 +23,6 @@
 #define MXS_ICOLL_VBASE                MXS_IO_ADDRESS(MXS_ICOLL_BASE_ADDR)
 #define HW_ICOLL_STAT_OFFSET   0x70
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
        ldr     \irqnr, [\base, #HW_ICOLL_STAT_OFFSET]
        cmp     \irqnr, #0x7F
@@ -36,6 +33,3 @@
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =MXS_ICOLL_VBASE
        .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
index bde5f66..7d4fb6d 100644 (file)
 #include <linux/io.h>
 #endif
 #include <asm/mach-types.h>
+#include <mach/digctl.h>
 #include <mach/hardware.h>
 
 /*
- * MXS CPU types
- */
-#define cpu_is_mx23()          (                                       \
-               machine_is_mx23evk() ||                                 \
-               machine_is_stmp378x() ||                                \
-               0)
-#define cpu_is_mx28()          (                                       \
-               machine_is_mx28evk() ||                                 \
-               machine_is_m28evk() ||                                  \
-               machine_is_tx28() ||                                    \
-               0)
-
-/*
  * IO addresses common to MXS-based
  */
 #define MXS_IO_BASE_ADDR               0x80000000
@@ -109,6 +97,21 @@ static inline void __mxs_togl(u32 mask, void __iomem *reg)
 {
        __raw_writel(mask, reg + MXS_TOG_ADDR);
 }
+
+/*
+ * MXS CPU types
+ */
+#define MXS_CHIPID (MXS_IO_ADDRESS(MXS_DIGCTL_BASE_ADDR) + HW_DIGCTL_CHIPID)
+
+static inline int cpu_is_mx23(void)
+{
+       return ((__raw_readl(MXS_CHIPID) >> 16) == 0x3780);
+}
+
+static inline int cpu_is_mx28(void)
+{
+       return ((__raw_readl(MXS_CHIPID) >> 16) == 0x2800);
+}
 #endif
 
 #endif /* __MACH_MXS_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/system.h b/arch/arm/mach-mxs/include/mach/system.h
deleted file mode 100644 (file)
index e7ad1bb..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *  Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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.
- */
-
-#ifndef __MACH_MXS_SYSTEM_H__
-#define __MACH_MXS_SYSTEM_H__
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif /* __MACH_MXS_SYSTEM_H__ */
index 6777674..ef28114 100644 (file)
@@ -18,8 +18,6 @@
 #ifndef __MACH_MXS_UNCOMPRESS_H__
 #define __MACH_MXS_UNCOMPRESS_H__
 
-#include <asm/mach-types.h>
-
 unsigned long mxs_duart_base;
 
 #define MXS_DUART(x)   (*(volatile unsigned long *)(mxs_duart_base + (x)))
@@ -55,16 +53,17 @@ static inline void flush(void)
 
 #define MX23_DUART_BASE_ADDR   0x80070000
 #define MX28_DUART_BASE_ADDR   0x80074000
+#define MXS_DIGCTL_CHIPID      0x8001c310
 
 static inline void __arch_decomp_setup(unsigned long arch_id)
 {
-       switch (arch_id) {
-       case MACH_TYPE_MX23EVK:
+       u16 chipid = (*(volatile unsigned long *) MXS_DIGCTL_CHIPID) >> 16;
+
+       switch (chipid) {
+       case 0x3780:
                mxs_duart_base = MX23_DUART_BASE_ADDR;
                break;
-       case MACH_TYPE_MX28EVK:
-       case MACH_TYPE_M28EVK:
-       case MACH_TYPE_TX28:
+       case 0x2800:
                mxs_duart_base = MX28_DUART_BASE_ADDR;
                break;
        default:
diff --git a/arch/arm/mach-mxs/mach-apx4devkit.c b/arch/arm/mach-mxs/mach-apx4devkit.c
new file mode 100644 (file)
index 0000000..48a7fab
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2011-2012
+ * Lauri Hintsala, Bluegiga, <lauri.hintsala@bluegiga.com>
+ * Veli-Pekka Peltola, Bluegiga, <veli-pekka.peltola@bluegiga.com>
+ *
+ * based on: mach-mx28evk.c
+ * Copyright 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/micrel_phy.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/common.h>
+#include <mach/digctl.h>
+#include <mach/iomux-mx28.h>
+
+#include "devices-mx28.h"
+
+#define APX4DEVKIT_GPIO_USERLED        MXS_GPIO_NR(3, 28)
+
+static const iomux_cfg_t apx4devkit_pads[] __initconst = {
+       /* duart */
+       MX28_PAD_PWM0__DUART_RX | MXS_PAD_CTRL,
+       MX28_PAD_PWM1__DUART_TX | MXS_PAD_CTRL,
+
+       /* auart0 */
+       MX28_PAD_AUART0_RX__AUART0_RX | MXS_PAD_CTRL,
+       MX28_PAD_AUART0_TX__AUART0_TX | MXS_PAD_CTRL,
+       MX28_PAD_AUART0_CTS__AUART0_CTS | MXS_PAD_CTRL,
+       MX28_PAD_AUART0_RTS__AUART0_RTS | MXS_PAD_CTRL,
+
+       /* auart1 */
+       MX28_PAD_AUART1_RX__AUART1_RX | MXS_PAD_CTRL,
+       MX28_PAD_AUART1_TX__AUART1_TX | MXS_PAD_CTRL,
+
+       /* auart2 */
+       MX28_PAD_SSP2_SCK__AUART2_RX | MXS_PAD_CTRL,
+       MX28_PAD_SSP2_MOSI__AUART2_TX | MXS_PAD_CTRL,
+
+       /* auart3 */
+       MX28_PAD_SSP2_MISO__AUART3_RX | MXS_PAD_CTRL,
+       MX28_PAD_SSP2_SS0__AUART3_TX | MXS_PAD_CTRL,
+
+#define MXS_PAD_FEC    (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP)
+       /* fec0 */
+       MX28_PAD_ENET0_MDC__ENET0_MDC | MXS_PAD_FEC,
+       MX28_PAD_ENET0_MDIO__ENET0_MDIO | MXS_PAD_FEC,
+       MX28_PAD_ENET0_RX_EN__ENET0_RX_EN | MXS_PAD_FEC,
+       MX28_PAD_ENET0_RXD0__ENET0_RXD0 | MXS_PAD_FEC,
+       MX28_PAD_ENET0_RXD1__ENET0_RXD1 | MXS_PAD_FEC,
+       MX28_PAD_ENET0_TX_EN__ENET0_TX_EN | MXS_PAD_FEC,
+       MX28_PAD_ENET0_TXD0__ENET0_TXD0 | MXS_PAD_FEC,
+       MX28_PAD_ENET0_TXD1__ENET0_TXD1 | MXS_PAD_FEC,
+       MX28_PAD_ENET_CLK__CLKCTRL_ENET | MXS_PAD_FEC,
+
+       /* i2c */
+       MX28_PAD_I2C0_SCL__I2C0_SCL,
+       MX28_PAD_I2C0_SDA__I2C0_SDA,
+
+       /* mmc0 */
+       MX28_PAD_SSP0_DATA0__SSP0_D0 |
+               (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SSP0_DATA1__SSP0_D1 |
+               (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SSP0_DATA2__SSP0_D2 |
+               (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SSP0_DATA3__SSP0_D3 |
+               (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SSP0_DATA4__SSP0_D4 |
+               (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SSP0_DATA5__SSP0_D5 |
+               (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SSP0_DATA6__SSP0_D6 |
+               (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SSP0_DATA7__SSP0_D7 |
+               (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SSP0_CMD__SSP0_CMD |
+               (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT |
+               (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+       MX28_PAD_SSP0_SCK__SSP0_SCK |
+               (MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+
+       /* led */
+       MX28_PAD_PWM3__GPIO_3_28 | MXS_PAD_CTRL,
+
+       /* saif0 & saif1 */
+       MX28_PAD_SAIF0_MCLK__SAIF0_MCLK |
+               (MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SAIF0_LRCLK__SAIF0_LRCLK |
+               (MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SAIF0_BITCLK__SAIF0_BITCLK |
+               (MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SAIF0_SDATA0__SAIF0_SDATA0 |
+               (MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+       MX28_PAD_SAIF1_SDATA0__SAIF1_SDATA0 |
+               (MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+};
+
+/* led */
+static const struct gpio_led apx4devkit_leds[] __initconst = {
+       {
+               .name = "user-led",
+               .default_trigger = "heartbeat",
+               .gpio = APX4DEVKIT_GPIO_USERLED,
+       },
+};
+
+static const struct gpio_led_platform_data apx4devkit_led_data __initconst = {
+       .leds = apx4devkit_leds,
+       .num_leds = ARRAY_SIZE(apx4devkit_leds),
+};
+
+static const struct fec_platform_data mx28_fec_pdata __initconst = {
+       .phy = PHY_INTERFACE_MODE_RMII,
+};
+
+static const struct mxs_mmc_platform_data apx4devkit_mmc_pdata __initconst = {
+       .wp_gpio = -EINVAL,
+       .flags = SLOTF_4_BIT_CAPABLE,
+};
+
+static const struct i2c_board_info apx4devkit_i2c_boardinfo[] __initconst = {
+       { I2C_BOARD_INFO("sgtl5000", 0x0a) }, /* ASoC */
+       { I2C_BOARD_INFO("pcf8563", 0x51) }, /* RTC */
+};
+
+#if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || \
+               defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
+static struct regulator_consumer_supply apx4devkit_audio_consumer_supplies[] = {
+       REGULATOR_SUPPLY("VDDA", "0-000a"),
+       REGULATOR_SUPPLY("VDDIO", "0-000a"),
+};
+
+static struct regulator_init_data apx4devkit_vdd_reg_init_data = {
+       .constraints    = {
+               .name   = "3V3",
+               .always_on = 1,
+       },
+       .consumer_supplies = apx4devkit_audio_consumer_supplies,
+       .num_consumer_supplies = ARRAY_SIZE(apx4devkit_audio_consumer_supplies),
+};
+
+static struct fixed_voltage_config apx4devkit_vdd_pdata = {
+       .supply_name    = "board-3V3",
+       .microvolts     = 3300000,
+       .gpio           = -EINVAL,
+       .enabled_at_boot = 1,
+       .init_data      = &apx4devkit_vdd_reg_init_data,
+};
+
+static struct platform_device apx4devkit_voltage_regulator = {
+       .name           = "reg-fixed-voltage",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &apx4devkit_vdd_pdata,
+       },
+};
+
+static void __init apx4devkit_add_regulators(void)
+{
+       platform_device_register(&apx4devkit_voltage_regulator);
+}
+#else
+static void __init apx4devkit_add_regulators(void) {}
+#endif
+
+static const struct mxs_saif_platform_data
+                       apx4devkit_mxs_saif_pdata[] __initconst = {
+       /* working on EXTMSTR0 mode (saif0 master, saif1 slave) */
+       {
+               .master_mode = 1,
+               .master_id = 0,
+       }, {
+               .master_mode = 0,
+               .master_id = 0,
+       },
+};
+
+static int apx4devkit_phy_fixup(struct phy_device *phy)
+{
+       phy->dev_flags |= MICREL_PHY_50MHZ_CLK;
+       return 0;
+}
+
+static void __init apx4devkit_init(void)
+{
+       mxs_iomux_setup_multiple_pads(apx4devkit_pads,
+                       ARRAY_SIZE(apx4devkit_pads));
+
+       mx28_add_duart();
+       mx28_add_auart0();
+       mx28_add_auart1();
+       mx28_add_auart2();
+       mx28_add_auart3();
+
+       /*
+        * Register fixup for the Micrel KS8031 PHY clock
+        * (shares same ID with KS8051)
+        */
+       phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK,
+                       apx4devkit_phy_fixup);
+
+       mx28_add_fec(0, &mx28_fec_pdata);
+
+       mx28_add_mxs_mmc(0, &apx4devkit_mmc_pdata);
+
+       gpio_led_register_device(0, &apx4devkit_led_data);
+
+       mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0);
+       mx28_add_saif(0, &apx4devkit_mxs_saif_pdata[0]);
+       mx28_add_saif(1, &apx4devkit_mxs_saif_pdata[1]);
+
+       apx4devkit_add_regulators();
+
+       mx28_add_mxs_i2c(0);
+       i2c_register_board_info(0, apx4devkit_i2c_boardinfo,
+                       ARRAY_SIZE(apx4devkit_i2c_boardinfo));
+
+       mxs_add_platform_device("mxs-sgtl5000", 0, NULL, 0, NULL, 0);
+}
+
+static void __init apx4devkit_timer_init(void)
+{
+       mx28_clocks_init();
+}
+
+static struct sys_timer apx4devkit_timer = {
+       .init   = apx4devkit_timer_init,
+};
+
+MACHINE_START(APX4DEVKIT, "Bluegiga APX4 Development Kit")
+       .map_io         = mx28_map_io,
+       .init_irq       = mx28_init_irq,
+       .timer          = &apx4devkit_timer,
+       .init_machine   = apx4devkit_init,
+       .restart        = mxs_restart,
+MACHINE_END
index 2f27582..06d7996 100644 (file)
@@ -247,18 +247,15 @@ static int __init m28evk_fec_get_mac(void)
        u32 val;
        const u32 *ocotp = mxs_get_ocotp();
 
-       if (!ocotp) {
-               pr_err("%s: timeout when reading fec mac from OCOTP\n",
-                       __func__);
+       if (!ocotp)
                return -ETIMEDOUT;
-       }
 
        /*
         * OCOTP only stores the last 4 octets for each mac address,
         * so hard-code DENX OUI (C0:E5:4E) here.
         */
        for (i = 0; i < 2; i++) {
-               val = ocotp[i * 4];
+               val = ocotp[i];
                mx28_fec_pdata[i].mac[0] = 0xC0;
                mx28_fec_pdata[i].mac[1] = 0xE5;
                mx28_fec_pdata[i].mac[2] = 0x4E;
index fdb0a56..e386c14 100644 (file)
@@ -223,7 +223,6 @@ static const struct gpio_led_platform_data mx28evk_led_data __initconst = {
 /* fec */
 static void __init mx28evk_fec_reset(void)
 {
-       int ret;
        struct clk *clk;
 
        /* Enable fec phy clock */
@@ -231,32 +230,7 @@ static void __init mx28evk_fec_reset(void)
        if (!IS_ERR(clk))
                clk_prepare_enable(clk);
 
-       /* Power up fec phy */
-       ret = gpio_request(MX28EVK_FEC_PHY_POWER, "fec-phy-power");
-       if (ret) {
-               pr_err("Failed to request gpio fec-phy-%s: %d\n", "power", ret);
-               return;
-       }
-
-       ret = gpio_direction_output(MX28EVK_FEC_PHY_POWER, 0);
-       if (ret) {
-               pr_err("Failed to drive gpio fec-phy-%s: %d\n", "power", ret);
-               return;
-       }
-
-       /* Reset fec phy */
-       ret = gpio_request(MX28EVK_FEC_PHY_RESET, "fec-phy-reset");
-       if (ret) {
-               pr_err("Failed to request gpio fec-phy-%s: %d\n", "reset", ret);
-               return;
-       }
-
-       gpio_direction_output(MX28EVK_FEC_PHY_RESET, 0);
-       if (ret) {
-               pr_err("Failed to drive gpio fec-phy-%s: %d\n", "reset", ret);
-               return;
-       }
-
+       gpio_set_value(MX28EVK_FEC_PHY_RESET, 0);
        mdelay(1);
        gpio_set_value(MX28EVK_FEC_PHY_RESET, 1);
 }
@@ -278,14 +252,14 @@ static int __init mx28evk_fec_get_mac(void)
        const u32 *ocotp = mxs_get_ocotp();
 
        if (!ocotp)
-               goto error;
+               return -ETIMEDOUT;
 
        /*
         * OCOTP only stores the last 4 octets for each mac address,
         * so hard-code Freescale OUI (00:04:9f) here.
         */
        for (i = 0; i < 2; i++) {
-               val = ocotp[i * 4];
+               val = ocotp[i];
                mx28_fec_pdata[i].mac[0] = 0x00;
                mx28_fec_pdata[i].mac[1] = 0x04;
                mx28_fec_pdata[i].mac[2] = 0x9f;
@@ -295,10 +269,6 @@ static int __init mx28evk_fec_get_mac(void)
        }
 
        return 0;
-
-error:
-       pr_err("%s: timeout when reading fec mac from OCOTP\n", __func__);
-       return -ETIMEDOUT;
 }
 
 /*
@@ -417,9 +387,14 @@ static void __init mx28evk_add_regulators(void)
 static void __init mx28evk_add_regulators(void) {}
 #endif
 
-static struct gpio mx28evk_lcd_gpios[] = {
+static const struct gpio mx28evk_gpios[] __initconst = {
        { MX28EVK_LCD_ENABLE, GPIOF_OUT_INIT_HIGH, "lcd-enable" },
        { MX28EVK_BL_ENABLE, GPIOF_OUT_INIT_HIGH, "bl-enable" },
+       { MX28EVK_FLEXCAN_SWITCH, GPIOF_DIR_OUT, "flexcan-switch" },
+       { MX28EVK_MMC0_SLOT_POWER, GPIOF_OUT_INIT_LOW, "mmc0-slot-power" },
+       { MX28EVK_MMC1_SLOT_POWER, GPIOF_OUT_INIT_LOW, "mmc1-slot-power" },
+       { MX28EVK_FEC_PHY_POWER, GPIOF_OUT_INIT_LOW, "fec-phy-power" },
+       { MX28EVK_FEC_PHY_RESET, GPIOF_DIR_OUT, "fec-phy-reset" },
 };
 
 static const struct mxs_saif_platform_data
@@ -447,25 +422,18 @@ static void __init mx28evk_init(void)
        if (mx28evk_fec_get_mac())
                pr_warn("%s: failed on fec mac setup\n", __func__);
 
+       ret = gpio_request_array(mx28evk_gpios, ARRAY_SIZE(mx28evk_gpios));
+       if (ret)
+               pr_err("One or more GPIOs failed to be requested: %d\n", ret);
+
        mx28evk_fec_reset();
        mx28_add_fec(0, &mx28_fec_pdata[0]);
        mx28_add_fec(1, &mx28_fec_pdata[1]);
 
-       ret = gpio_request_one(MX28EVK_FLEXCAN_SWITCH, GPIOF_DIR_OUT,
-                               "flexcan-switch");
-       if (ret) {
-               pr_err("failed to request gpio flexcan-switch: %d\n", ret);
-       } else {
-               mx28_add_flexcan(0, &mx28evk_flexcan_pdata[0]);
-               mx28_add_flexcan(1, &mx28evk_flexcan_pdata[1]);
-       }
+       mx28_add_flexcan(0, &mx28evk_flexcan_pdata[0]);
+       mx28_add_flexcan(1, &mx28evk_flexcan_pdata[1]);
 
-       ret = gpio_request_array(mx28evk_lcd_gpios,
-                                ARRAY_SIZE(mx28evk_lcd_gpios));
-       if (ret)
-               pr_warn("failed to request gpio pins for lcd: %d\n", ret);
-       else
-               mx28_add_mxsfb(&mx28evk_mxsfb_pdata);
+       mx28_add_mxsfb(&mx28evk_mxsfb_pdata);
 
        mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0);
        mx28_add_saif(0, &mx28evk_mxs_saif_pdata[0]);
@@ -480,20 +448,8 @@ static void __init mx28evk_init(void)
        mxs_add_platform_device("mxs-sgtl5000", 0, NULL, 0,
                        NULL, 0);
 
-       /* power on mmc slot by writing 0 to the gpio */
-       ret = gpio_request_one(MX28EVK_MMC0_SLOT_POWER, GPIOF_OUT_INIT_LOW,
-                              "mmc0-slot-power");
-       if (ret)
-               pr_warn("failed to request gpio mmc0-slot-power: %d\n", ret);
-       else
-               mx28_add_mxs_mmc(0, &mx28evk_mmc_pdata[0]);
-
-       ret = gpio_request_one(MX28EVK_MMC1_SLOT_POWER, GPIOF_OUT_INIT_LOW,
-                              "mmc1-slot-power");
-       if (ret)
-               pr_warn("failed to request gpio mmc1-slot-power: %d\n", ret);
-       else
-               mx28_add_mxs_mmc(1, &mx28evk_mmc_pdata[1]);
+       mx28_add_mxs_mmc(0, &mx28evk_mmc_pdata[0]);
+       mx28_add_mxs_mmc(1, &mx28evk_mmc_pdata[1]);
 
        mx28_add_rtc_stmp3xxx();
 
index fb042da..a9b4bbc 100644 (file)
 #include <linux/kernel.h>
 #include <linux/suspend.h>
 #include <linux/io.h>
-#include <mach/system.h>
 
 static int mxs_suspend_enter(suspend_state_t state)
 {
        switch (state) {
        case PM_SUSPEND_MEM:
-               arch_idle();
+               cpu_do_idle();
                break;
 
        default:
index 30042e2..80ac1fc 100644 (file)
@@ -37,6 +37,8 @@
 #define MXS_MODULE_CLKGATE             (1 << 30)
 #define MXS_MODULE_SFTRST              (1 << 31)
 
+#define CLKCTRL_TIMEOUT                10      /* 10 ms */
+
 static void __iomem *mxs_clkctrl_reset_addr;
 
 /*
@@ -137,3 +139,17 @@ error:
        return -ETIMEDOUT;
 }
 EXPORT_SYMBOL(mxs_reset_block);
+
+int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(CLKCTRL_TIMEOUT);
+       while (readl_relaxed(MXS_IO_ADDRESS(MXS_CLKCTRL_BASE_ADDR)
+                                               + reg_offset) & mask) {
+               if (time_after(jiffies, timeout)) {
+                       pr_err("Timeout at CLKCTRL + 0x%x\n", reg_offset);
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
index b991323..2cdf6ef 100644 (file)
@@ -92,18 +92,7 @@ void clk_put(struct clk *clk)
 {
 }
 
-static struct amba_device fb_device = {
-       .dev            = {
-               .init_name = "fb",
-               .coherent_dma_mask = ~0,
-       },
-       .res            = {
-               .start  = 0x00104000,
-               .end    = 0x00104fff,
-               .flags  = IORESOURCE_MEM,
-       },
-       .irq            = { NETX_IRQ_LCD, NO_IRQ },
-};
+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-netx/include/mach/entry-macro.S b/arch/arm/mach-netx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 6e9f1cb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * arch/arm/mach-netx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for Hilscher netX based platforms
- *
- * Copyright (C) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-netx/include/mach/system.h b/arch/arm/mach-netx/include/mach/system.h
deleted file mode 100644 (file)
index b38fa36..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * arch/arm/mach-netx/include/mach/system.h
- *
- * Copyright (C) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
-
index 7c878bf..58cacaf 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/flash.h>
+#include <asm/mach/time.h>
 
 #include <plat/gpio-nomadik.h>
 #include <plat/mtu.h>
 
-#include <mach/setup.h>
 #include <mach/nand.h>
 #include <mach/fsmc.h>
 
@@ -185,20 +185,11 @@ static void __init nhk8815_onenand_init(void)
 #endif
 }
 
-#define __MEM_4K_RESOURCE(x) \
-       .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
+static AMBA_APB_DEVICE(uart0, "uart0", 0, NOMADIK_UART0_BASE,
+       { IRQ_UART0 }, NULL);
 
-static struct amba_device uart0_device = {
-       .dev = { .init_name = "uart0" },
-       __MEM_4K_RESOURCE(NOMADIK_UART0_BASE),
-       .irq = {IRQ_UART0, NO_IRQ},
-};
-
-static struct amba_device uart1_device = {
-       .dev = { .init_name = "uart1" },
-       __MEM_4K_RESOURCE(NOMADIK_UART1_BASE),
-       .irq = {IRQ_UART1, NO_IRQ},
-};
+static AMBA_APB_DEVICE(uart1, "uart1", 0, NOMADIK_UART1_BASE,
+       { IRQ_UART1 }, NULL);
 
 static struct amba_device *amba_devs[] __initdata = {
        &uart0_device,
@@ -255,10 +246,7 @@ static void __init nomadik_timer_init(void)
        src_cr |= SRC_CR_INIT_VAL;
        writel(src_cr, io_p2v(NOMADIK_SRC_BASE));
 
-       /* Save global pointer to mtu, used by platform timer code */
-       mtu_base = io_p2v(NOMADIK_MTU0_BASE);
-
-       nmdk_timer_init();
+       nmdk_timer_init(io_p2v(NOMADIK_MTU0_BASE));
 }
 
 static struct sys_timer nomadik_timer = {
index 65df7b4..27f43a4 100644 (file)
@@ -97,12 +97,7 @@ static struct platform_device cpu8815_platform_gpio[] = {
        GPIO_DEVICE(3),
 };
 
-static struct amba_device cpu8815_amba_rng = {
-       .dev = {
-               .init_name = "rng",
-       },
-       __MEM_4K_RESOURCE(NOMADIK_RNG_BASE),
-};
+static AMBA_APB_DEVICE(cpu8815_amba_rng, "rng", 0, NOMADIK_RNG_BASE, { }, NULL);
 
 static struct platform_device *platform_devs[] __initdata = {
        cpu8815_platform_gpio + 0,
@@ -112,7 +107,7 @@ static struct platform_device *platform_devs[] __initdata = {
 };
 
 static struct amba_device *amba_devs[] __initdata = {
-       &cpu8815_amba_rng
+       &cpu8815_amba_rng_device
 };
 
 static int __init cpu8815_init(void)
diff --git a/arch/arm/mach-nomadik/include/mach/entry-macro.S b/arch/arm/mach-nomadik/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 98ea1c1..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Low-level IRQ helper macros for Nomadik platforms
- *
- * 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.
- */
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
diff --git a/arch/arm/mach-nomadik/include/mach/setup.h b/arch/arm/mach-nomadik/include/mach/setup.h
deleted file mode 100644 (file)
index bcaeaf4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-
-/*
- * These symbols are needed for board-specific files to call their
- * own cpu-specific files
- */
-
-#ifndef __ASM_ARCH_SETUP_H
-#define __ASM_ARCH_SETUP_H
-
-#include <asm/mach/time.h>
-#include <linux/init.h>
-
-#ifdef CONFIG_NOMADIK_8815
-
-extern void nmdk_timer_init(void);
-
-#endif /* NOMADIK_8815 */
-
-#endif /*  __ASM_ARCH_SETUP_H */
diff --git a/arch/arm/mach-nomadik/include/mach/system.h b/arch/arm/mach-nomadik/include/mach/system.h
deleted file mode 100644 (file)
index 25e198b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  mach-nomadik/include/mach/system.h
- *
- *  Copyright (C) 2008 STMicroelectronics
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       /*
-        * This should do all the clock switching
-        * and wait for interrupt tricks
-        */
-       cpu_do_idle();
-}
-
-#endif
index 922ab0d..dfab466 100644 (file)
@@ -152,6 +152,10 @@ config MACH_AMS_DELTA
        bool "Amstrad E3 (Delta)"
        depends on ARCH_OMAP1 && ARCH_OMAP15XX
        select FIQ
+       select GPIO_GENERIC_PLATFORM
+       select LEDS_GPIO_REGISTER
+       select REGULATOR
+       select REGULATOR_FIXED_VOLTAGE
        help
          Support for the Amstrad E3 (codename Delta) videophone. Say Y here
          if you have such a device.
index c1c5fb6..399c4c4 100644 (file)
 
 #include <linux/linkage.h>
 
-#include <plat/io.h>
 #include <plat/board-ams-delta.h>
 
 #include <mach/ams-delta-fiq.h>
 
+#include "iomap.h"
+
 /*
  * GPIO related definitions, copied from arch/arm/plat-omap/gpio.c.
  * Unfortunately, those were not placed in a separate header file.
index 152b32c..fcce7ff 100644 (file)
@@ -22,6 +22,7 @@
 #include <plat/board-ams-delta.h>
 
 #include <asm/fiq.h>
+
 #include <mach/ams-delta-fiq.h>
 
 static struct fiq_handler fh = {
index e0e8245..c1b681e 100644 (file)
@@ -11,6 +11,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/basic_mmio_gpio.h>
 #include <linux/gpio.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/leds.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 #include <linux/serial_8250.h>
 #include <linux/export.h>
 #include <linux/omapfb.h>
+#include <linux/io.h>
 
 #include <media/soc_camera.h>
 
 #include <asm/serial.h>
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/io.h>
 #include <plat/board-ams-delta.h>
 #include <plat/keypad.h>
 #include <plat/mux.h>
 #include <plat/usb.h>
 #include <plat/board.h>
-#include "common.h"
-#include <mach/camera.h>
 
+#include <mach/hardware.h>
 #include <mach/ams-delta-fiq.h>
+#include <mach/camera.h>
 
-static u8 ams_delta_latch1_reg;
-static u16 ams_delta_latch2_reg;
+#include "iomap.h"
+#include "common.h"
 
 static const unsigned int ams_delta_keymap[] = {
        KEY(0, 0, KEY_F1),              /* Advert    */
@@ -122,54 +125,188 @@ static const unsigned int ams_delta_keymap[] = {
        KEY(7, 3, KEY_LEFTCTRL),        /* Vol down  */
 };
 
-void ams_delta_latch1_write(u8 mask, u8 value)
-{
-       ams_delta_latch1_reg &= ~mask;
-       ams_delta_latch1_reg |= value;
-       *(volatile __u8 *) AMS_DELTA_LATCH1_VIRT = ams_delta_latch1_reg;
-}
-
-void ams_delta_latch2_write(u16 mask, u16 value)
-{
-       ams_delta_latch2_reg &= ~mask;
-       ams_delta_latch2_reg |= value;
-       *(volatile __u16 *) AMS_DELTA_LATCH2_VIRT = ams_delta_latch2_reg;
-}
+#define LATCH1_PHYS    0x01000000
+#define LATCH1_VIRT    0xEA000000
+#define MODEM_PHYS     0x04000000
+#define MODEM_VIRT     0xEB000000
+#define LATCH2_PHYS    0x08000000
+#define LATCH2_VIRT    0xEC000000
 
 static struct map_desc ams_delta_io_desc[] __initdata = {
        /* AMS_DELTA_LATCH1 */
        {
-               .virtual        = AMS_DELTA_LATCH1_VIRT,
-               .pfn            = __phys_to_pfn(AMS_DELTA_LATCH1_PHYS),
+               .virtual        = LATCH1_VIRT,
+               .pfn            = __phys_to_pfn(LATCH1_PHYS),
                .length         = 0x01000000,
                .type           = MT_DEVICE
        },
        /* AMS_DELTA_LATCH2 */
        {
-               .virtual        = AMS_DELTA_LATCH2_VIRT,
-               .pfn            = __phys_to_pfn(AMS_DELTA_LATCH2_PHYS),
+               .virtual        = LATCH2_VIRT,
+               .pfn            = __phys_to_pfn(LATCH2_PHYS),
                .length         = 0x01000000,
                .type           = MT_DEVICE
        },
        /* AMS_DELTA_MODEM */
        {
-               .virtual        = AMS_DELTA_MODEM_VIRT,
-               .pfn            = __phys_to_pfn(AMS_DELTA_MODEM_PHYS),
+               .virtual        = MODEM_VIRT,
+               .pfn            = __phys_to_pfn(MODEM_PHYS),
                .length         = 0x01000000,
                .type           = MT_DEVICE
        }
 };
 
-static struct omap_lcd_config ams_delta_lcd_config = {
+static struct omap_lcd_config ams_delta_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
 
-static struct omap_usb_config ams_delta_usb_config __initdata = {
+static struct omap_usb_config ams_delta_usb_config = {
        .register_host  = 1,
        .hmc_mode       = 16,
        .pins[0]        = 2,
 };
 
+#define LATCH1_GPIO_BASE       232
+#define LATCH1_NGPIO           8
+
+static struct resource latch1_resources[] = {
+       [0] = {
+               .name   = "dat",
+               .start  = LATCH1_PHYS,
+               .end    = LATCH1_PHYS + (LATCH1_NGPIO - 1) / 8,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct bgpio_pdata latch1_pdata = {
+       .base   = LATCH1_GPIO_BASE,
+       .ngpio  = LATCH1_NGPIO,
+};
+
+static struct platform_device latch1_gpio_device = {
+       .name           = "basic-mmio-gpio",
+       .id             = 0,
+       .resource       = latch1_resources,
+       .num_resources  = ARRAY_SIZE(latch1_resources),
+       .dev            = {
+               .platform_data  = &latch1_pdata,
+       },
+};
+
+static struct resource latch2_resources[] = {
+       [0] = {
+               .name   = "dat",
+               .start  = LATCH2_PHYS,
+               .end    = LATCH2_PHYS + (AMS_DELTA_LATCH2_NGPIO - 1) / 8,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct bgpio_pdata latch2_pdata = {
+       .base   = AMS_DELTA_LATCH2_GPIO_BASE,
+       .ngpio  = AMS_DELTA_LATCH2_NGPIO,
+};
+
+static struct platform_device latch2_gpio_device = {
+       .name           = "basic-mmio-gpio",
+       .id             = 1,
+       .resource       = latch2_resources,
+       .num_resources  = ARRAY_SIZE(latch2_resources),
+       .dev            = {
+               .platform_data  = &latch2_pdata,
+       },
+};
+
+static const struct gpio latch_gpios[] __initconst = {
+       {
+               .gpio   = LATCH1_GPIO_BASE + 6,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "dockit1",
+       },
+       {
+               .gpio   = LATCH1_GPIO_BASE + 7,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "dockit2",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_SCARD_RSTIN,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "scard_rstin",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_SCARD_CMDVCC,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "scard_cmdvcc",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_MODEM_CODEC,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "modem_codec",
+       },
+       {
+               .gpio   = AMS_DELTA_LATCH2_GPIO_BASE + 14,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "hookflash1",
+       },
+       {
+               .gpio   = AMS_DELTA_LATCH2_GPIO_BASE + 15,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "hookflash2",
+       },
+};
+
+static struct regulator_consumer_supply modem_nreset_consumers[] = {
+       REGULATOR_SUPPLY("RESET#", "serial8250.1"),
+       REGULATOR_SUPPLY("POR", "cx20442-codec"),
+};
+
+static struct regulator_init_data modem_nreset_data = {
+       .constraints            = {
+               .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
+               .boot_on                = 1,
+       },
+       .num_consumer_supplies  = ARRAY_SIZE(modem_nreset_consumers),
+       .consumer_supplies      = modem_nreset_consumers,
+};
+
+static struct fixed_voltage_config modem_nreset_config = {
+       .supply_name            = "modem_nreset",
+       .microvolts             = 3300000,
+       .gpio                   = AMS_DELTA_GPIO_PIN_MODEM_NRESET,
+       .startup_delay          = 25000,
+       .enable_high            = 1,
+       .enabled_at_boot        = 1,
+       .init_data              = &modem_nreset_data,
+};
+
+static struct platform_device modem_nreset_device = {
+       .name   = "reg-fixed-voltage",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &modem_nreset_config,
+       },
+};
+
+struct modem_private_data {
+       struct regulator *regulator;
+};
+
+static struct modem_private_data modem_priv;
+
+void ams_delta_latch_write(int base, int ngpio, u16 mask, u16 value)
+{
+       int bit = 0;
+       u16 bitpos = 1 << bit;
+
+       for (; bit < ngpio; bit++, bitpos = bitpos << 1) {
+               if (!(mask & bitpos))
+                       continue;
+               else
+                       gpio_set_value(base + bit, (value & bitpos) != 0);
+       }
+}
+EXPORT_SYMBOL(ams_delta_latch_write);
+
 static struct resource ams_delta_nand_resources[] = {
        [0] = {
                .start  = OMAP1_MPUIO_BASE,
@@ -199,7 +336,7 @@ static const struct matrix_keymap_data ams_delta_keymap_data = {
        .keymap_size    = ARRAY_SIZE(ams_delta_keymap),
 };
 
-static struct omap_kp_platform_data ams_delta_kp_data __initdata = {
+static struct omap_kp_platform_data ams_delta_kp_data = {
        .rows           = 8,
        .cols           = 8,
        .keymap_data    = &ams_delta_keymap_data,
@@ -221,9 +358,45 @@ static struct platform_device ams_delta_lcd_device = {
        .id     = -1,
 };
 
-static struct platform_device ams_delta_led_device = {
-       .name   = "ams-delta-led",
-       .id     = -1
+static const struct gpio_led gpio_leds[] __initconst = {
+       {
+               .name            = "camera",
+               .gpio            = LATCH1_GPIO_BASE + 0,
+               .default_state   = LEDS_GPIO_DEFSTATE_OFF,
+#ifdef CONFIG_LEDS_TRIGGERS
+               .default_trigger = "ams_delta_camera",
+#endif
+       },
+       {
+               .name            = "advert",
+               .gpio            = LATCH1_GPIO_BASE + 1,
+               .default_state   = LEDS_GPIO_DEFSTATE_OFF,
+       },
+       {
+               .name            = "email",
+               .gpio            = LATCH1_GPIO_BASE + 2,
+               .default_state   = LEDS_GPIO_DEFSTATE_OFF,
+       },
+       {
+               .name            = "handsfree",
+               .gpio            = LATCH1_GPIO_BASE + 3,
+               .default_state   = LEDS_GPIO_DEFSTATE_OFF,
+       },
+       {
+               .name            = "voicemail",
+               .gpio            = LATCH1_GPIO_BASE + 4,
+               .default_state   = LEDS_GPIO_DEFSTATE_OFF,
+       },
+       {
+               .name            = "voice",
+               .gpio            = LATCH1_GPIO_BASE + 5,
+               .default_state   = LEDS_GPIO_DEFSTATE_OFF,
+       },
+};
+
+static const struct gpio_led_platform_data leds_pdata __initconst = {
+       .leds           = gpio_leds,
+       .num_leds       = ARRAY_SIZE(gpio_leds),
 };
 
 static struct i2c_board_info ams_delta_camera_board_info[] = {
@@ -272,13 +445,17 @@ static struct omap1_cam_platform_data ams_delta_camera_platform_data = {
 };
 
 static struct platform_device *ams_delta_devices[] __initdata = {
-       &ams_delta_nand_device,
+       &latch1_gpio_device,
+       &latch2_gpio_device,
        &ams_delta_kp_device,
-       &ams_delta_lcd_device,
-       &ams_delta_led_device,
        &ams_delta_camera_device,
 };
 
+static struct platform_device *late_devices[] __initdata = {
+       &ams_delta_nand_device,
+       &ams_delta_lcd_device,
+};
+
 static void __init ams_delta_init(void)
 {
        /* mux pins for uarts */
@@ -302,15 +479,13 @@ static void __init ams_delta_init(void)
        omap_serial_init();
        omap_register_i2c_bus(1, 100, NULL, 0);
 
-       /* Clear latch2 (NAND, LCD, modem enable) */
-       ams_delta_latch2_write(~0, 0);
-
        omap1_usb_init(&ams_delta_usb_config);
        omap1_set_camera_info(&ams_delta_camera_platform_data);
 #ifdef CONFIG_LEDS_TRIGGERS
        led_trigger_register_simple("ams_delta_camera",
                        &ams_delta_camera_led_trigger);
 #endif
+       gpio_led_register_device(-1, &leds_pdata);
        platform_add_devices(ams_delta_devices, ARRAY_SIZE(ams_delta_devices));
 
        ams_delta_init_fiq();
@@ -320,16 +495,34 @@ static void __init ams_delta_init(void)
        omapfb_set_lcd_config(&ams_delta_lcd_config);
 }
 
+static void modem_pm(struct uart_port *port, unsigned int state, unsigned old)
+{
+       struct modem_private_data *priv = port->private_data;
+
+       if (IS_ERR(priv->regulator))
+               return;
+
+       if (state == old)
+               return;
+
+       if (state == 0)
+               regulator_enable(priv->regulator);
+       else if (old == 0)
+               regulator_disable(priv->regulator);
+}
+
 static struct plat_serial8250_port ams_delta_modem_ports[] = {
        {
-               .membase        = IOMEM(AMS_DELTA_MODEM_VIRT),
-               .mapbase        = AMS_DELTA_MODEM_PHYS,
+               .membase        = IOMEM(MODEM_VIRT),
+               .mapbase        = MODEM_PHYS,
                .irq            = -EINVAL, /* changed later */
                .flags          = UPF_BOOT_AUTOCONF,
                .irqflags       = IRQF_TRIGGER_RISING,
                .iotype         = UPIO_MEM,
                .regshift       = 1,
                .uartclk        = BASE_BAUD * 16,
+               .pm             = modem_pm,
+               .private_data   = &modem_priv,
        },
        { },
 };
@@ -342,13 +535,27 @@ static struct platform_device ams_delta_modem_device = {
        },
 };
 
-static int __init ams_delta_modem_init(void)
+static int __init late_init(void)
 {
        int err;
 
        if (!machine_is_ams_delta())
                return -ENODEV;
 
+       err = gpio_request_array(latch_gpios, ARRAY_SIZE(latch_gpios));
+       if (err) {
+               pr_err("Couldn't take over latch1/latch2 GPIO pins\n");
+               return err;
+       }
+
+       platform_add_devices(late_devices, ARRAY_SIZE(late_devices));
+
+       err = platform_device_register(&modem_nreset_device);
+       if (err) {
+               pr_err("Couldn't register the modem regulator device\n");
+               return err;
+       }
+
        omap_cfg_reg(M14_1510_GPIO2);
        ams_delta_modem_ports[0].irq =
                        gpio_to_irq(AMS_DELTA_GPIO_PIN_MODEM_IRQ);
@@ -360,13 +567,35 @@ static int __init ams_delta_modem_init(void)
        }
        gpio_direction_input(AMS_DELTA_GPIO_PIN_MODEM_IRQ);
 
-       ams_delta_latch2_write(
-               AMS_DELTA_LATCH2_MODEM_NRESET | AMS_DELTA_LATCH2_MODEM_CODEC,
-               AMS_DELTA_LATCH2_MODEM_NRESET | AMS_DELTA_LATCH2_MODEM_CODEC);
+       /* Initialize the modem_nreset regulator consumer before use */
+       modem_priv.regulator = ERR_PTR(-ENODEV);
+
+       ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC,
+                       AMS_DELTA_LATCH2_MODEM_CODEC);
 
-       return platform_device_register(&ams_delta_modem_device);
+       err = platform_device_register(&ams_delta_modem_device);
+       if (err)
+               goto gpio_free;
+
+       /*
+        * Once the modem device is registered, the modem_nreset
+        * regulator can be requested on behalf of that device.
+        */
+       modem_priv.regulator = regulator_get(&ams_delta_modem_device.dev,
+                       "RESET#");
+       if (IS_ERR(modem_priv.regulator)) {
+               err = PTR_ERR(modem_priv.regulator);
+               goto unregister;
+       }
+       return 0;
+
+unregister:
+       platform_device_unregister(&ams_delta_modem_device);
+gpio_free:
+       gpio_free(AMS_DELTA_GPIO_PIN_MODEM_IRQ);
+       return err;
 }
-arch_initcall(ams_delta_modem_init);
+late_initcall(late_init);
 
 static void __init ams_delta_map_io(void)
 {
@@ -385,6 +614,3 @@ MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)")
        .timer          = &omap1_timer,
        .restart        = omap1_restart,
 MACHINE_END
-
-EXPORT_SYMBOL(ams_delta_latch1_write);
-EXPORT_SYMBOL(ams_delta_latch2_write);
index 7afaf3c..80bd43c 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <plat/flash.h>
 #include <plat/fpga.h>
 #include <plat/keypad.h>
-#include "common.h"
 #include <plat/board.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
+#include "common.h"
+
 /* fsample is pretty close to p2-sample */
 
 #define fsample_cpld_read(reg) __raw_readb(reg)
index af2be8c..c306862 100644 (file)
@@ -32,8 +32,6 @@
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
 
-#include <mach/hardware.h>
-
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <plat/irda.h>
 #include <plat/usb.h>
 #include <plat/keypad.h>
-#include "common.h"
 #include <plat/flash.h>
 
+#include <mach/hardware.h>
+
+#include "common.h"
 #include "board-h2.h"
 
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
index 7cfd25b..64b8584 100644 (file)
 
 #include <asm/setup.h>
 #include <asm/page.h>
-#include <mach/hardware.h>
-
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/irqs.h>
 #include <plat/mux.h>
 #include <plat/tc.h>
 #include <plat/usb.h>
 #include <plat/keypad.h>
 #include <plat/dma.h>
-#include "common.h"
 #include <plat/flash.h>
 
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+#include "common.h"
 #include "board-h3.h"
 
 /* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
index af2afcf..827d83a 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
-#include <linux/io.h>
+#include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/i2c.h>
@@ -42,7 +42,6 @@
 #include <asm/mach/arch.h>
 
 #include <plat/omap7xx.h>
-#include "common.h"
 #include <plat/board.h>
 #include <plat/keypad.h>
 #include <plat/usb.h>
@@ -50,7 +49,7 @@
 
 #include <mach/irqs.h>
 
-#include <linux/delay.h>
+#include "common.h"
 
 /* LCD register definition */
 #define       OMAP_LCDC_CONTROL               (0xfffec000 + 0x00)
index 1d5ab66..6121918 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <plat/tc.h>
 #include <plat/usb.h>
 #include <plat/keypad.h>
-#include "common.h"
 #include <plat/mmc.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
+#include "common.h"
+
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
 #define INNOVATOR1610_ETHR_START       0x04000300
 
index 9b6332a..fe95ec5 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <plat/usb.h>
 #include <plat/board.h>
 #include <plat/keypad.h>
-#include "common.h"
 #include <plat/lcd_mipid.h>
 #include <plat/mmc.h>
 #include <plat/clock.h>
 
+#include <mach/hardware.h>
+
+#include "common.h"
+
 #define ADS7846_PENDOWN_GPIO   15
 
 static const unsigned int nokia770_keymap[] = {
index ef87465..1fe3473 100644 (file)
 #include <linux/leds.h>
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
-
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
-
 #include <linux/i2c/tps65010.h>
 
-#include <mach/hardware.h>
-
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -52,6 +48,9 @@
 #include <plat/usb.h>
 #include <plat/mux.h>
 #include <plat/tc.h>
+
+#include <mach/hardware.h>
+
 #include "common.h"
 
 /* At OMAP5912 OSK the Ethernet is directly connected to CS1 */
index 612342c..0863d8e 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/apm-emulation.h>
 #include <linux/omapfb.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -42,6 +41,9 @@
 #include <plat/board.h>
 #include <plat/irda.h>
 #include <plat/keypad.h>
+
+#include <mach/hardware.h>
+
 #include "common.h"
 
 #define PALMTE_USBDETECT_GPIO  0
index b63350b..4ff699c 100644 (file)
@@ -25,8 +25,9 @@
 #include <linux/mtd/physmap.h>
 #include <linux/leds.h>
 #include <linux/omapfb.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <plat/board.h>
 #include <plat/irda.h>
 #include <plat/keypad.h>
-#include "common.h"
 
-#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
+#include <mach/hardware.h>
+
+#include "common.h"
 
 #define PALMTT_USBDETECT_GPIO  0
 #define PALMTT_CABLE_GPIO      1
index 9924c70..abcbbd3 100644 (file)
@@ -28,8 +28,9 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/omapfb.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <plat/board.h>
 #include <plat/irda.h>
 #include <plat/keypad.h>
-#include "common.h"
 
-#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
+#include <mach/hardware.h>
+
+#include "common.h"
 
 #define PALMZ71_USBDETECT_GPIO 0
 #define PALMZ71_PENIRQ_GPIO    6
index 8e01534..76d4ee0 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <plat/fpga.h>
 #include <plat/flash.h>
 #include <plat/keypad.h>
-#include "common.h"
 #include <plat/board.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
+#include "common.h"
+
 static const unsigned int p2_keymap[] = {
        KEY(0, 0, KEY_UP),
        KEY(1, 0, KEY_RIGHT),
index 0c76e12..f34cb74 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/export.h>
 #include <linux/omapfb.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <plat/usb.h>
 #include <plat/tc.h>
 #include <plat/board.h>
-#include "common.h"
 #include <plat/keypad.h>
 #include <plat/board-sx1.h>
 
+#include <mach/hardware.h>
+
+#include "common.h"
+
 /* Write to I2C device */
 int sx1_i2c_write_byte(u8 devaddr, u8 regoffset, u8 value)
 {
index f83a502..659d0f7 100644 (file)
 #include <linux/smc91x.h>
 #include <linux/export.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
 #include <plat/board-voiceblue.h>
-#include "common.h"
 #include <plat/flash.h>
 #include <plat/mux.h>
 #include <plat/tc.h>
 #include <plat/usb.h>
 
+#include <mach/hardware.h>
+
+#include "common.h"
+
 static struct plat_serial8250_port voiceblue_ports[] = {
        {
                .mapbase        = (unsigned long)(OMAP_CS1_PHYS + 0x40000),
index 0c50df0..67382dd 100644 (file)
@@ -15,8 +15,8 @@
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/err.h>
-#include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/clk.h>
 #include <linux/clkdev.h>
 
 #include <asm/mach-types.h>
@@ -27,6 +27,9 @@
 #include <plat/sram.h>
 #include <plat/clkdev_omap.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
 #include "clock.h"
 #include "opp.h"
 
index 94699a8..c6ce93f 100644 (file)
  */
 
 #include <linux/kernel.h>
+#include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
 #include <linux/delay.h>
-#include <linux/io.h>
 
 #include <asm/mach-types.h>  /* for machine_is_* */
 
@@ -28,6 +28,9 @@
 #include <plat/sram.h> /* for omap_sram_reprogram_clock() */
 #include <plat/usb.h>   /* for OTG_BASE */
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
 #include "clock.h"
 
 /* Some ARM_IDLECT1 bit shifts - used in struct arm_idlect1_clk */
index a9a5146..af658ad 100644 (file)
@@ -58,5 +58,6 @@ void omap1_restart(char, const char *);
 
 extern struct sys_timer omap1_timer;
 extern bool omap_32k_timer_init(void);
+extern void __init omap_init_consistent_dma_size(void);
 
 #endif /* __ARCH_ARM_MACH_OMAP1_COMMON_H */
index 187b2fe..dcd8ddb 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/io.h>
 #include <linux/spi/spi.h>
 
-#include <mach/camera.h>
-#include <mach/hardware.h>
 #include <asm/mach/map.h>
 
-#include "common.h"
 #include <plat/tc.h>
 #include <plat/board.h>
 #include <plat/mux.h>
 #include <plat/mmc.h>
 #include <plat/omap7xx.h>
 
+#include <mach/camera.h>
+#include <mach/hardware.h>
+
+#include "common.h"
 #include "clock.h"
 
 /*-------------------------------------------------------------------------*/
index f5a5220..3ef7d52 100644 (file)
  */
 
 #include <linux/err.h>
-#include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/io.h>
 
 #include <plat/dma.h>
 #include <plat/tc.h>
index 1749cb3..f9bf78d 100644 (file)
@@ -6,13 +6,15 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 
-#include <plat/io.h>
 #include <plat/tc.h>
 #include <plat/flash.h>
 
+#include <mach/hardware.h>
+
 void omap1_set_vpp(struct platform_device *pdev, int enable)
 {
        static int count;
index 0a17a1a..76c67b3 100644 (file)
 #include <linux/errno.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 
 #include <plat/fpga.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
+
 static void fpga_mask_irq(struct irq_data *d)
 {
        unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE;
index 399da4c..634903e 100644 (file)
@@ -42,11 +42,12 @@ static struct omap_gpio_reg_offs omap15xx_mpuio_regs = {
        .irqstatus      = OMAP_MPUIO_GPIO_INT,
        .irqenable      = OMAP_MPUIO_GPIO_MASKIT,
        .irqenable_inv  = true,
+       .irqctrl        = OMAP_MPUIO_GPIO_INT_EDGE,
 };
 
 static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = {
        .virtual_irq_start      = IH_MPUIO_BASE,
-       .bank_type              = METHOD_MPUIO,
+       .is_mpuio               = true,
        .bank_width             = 16,
        .bank_stride            = 1,
        .regs                   = &omap15xx_mpuio_regs,
@@ -83,11 +84,12 @@ static struct omap_gpio_reg_offs omap15xx_gpio_regs = {
        .irqstatus      = OMAP1510_GPIO_INT_STATUS,
        .irqenable      = OMAP1510_GPIO_INT_MASK,
        .irqenable_inv  = true,
+       .irqctrl        = OMAP1510_GPIO_INT_CONTROL,
+       .pinctrl        = OMAP1510_GPIO_PIN_CONTROL,
 };
 
 static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {
        .virtual_irq_start      = IH_GPIO_BASE,
-       .bank_type              = METHOD_GPIO_1510,
        .bank_width             = 16,
        .regs                   = &omap15xx_gpio_regs,
 };
@@ -115,7 +117,6 @@ static int __init omap15xx_gpio_init(void)
        platform_device_register(&omap15xx_mpu_gpio);
        platform_device_register(&omap15xx_gpio);
 
-       gpio_bank_count = 2;
        return 0;
 }
 postcore_initcall(omap15xx_gpio_init);
index 0f399bd..1fb3b9a 100644 (file)
@@ -24,6 +24,9 @@
 #define OMAP1610_GPIO4_BASE            0xfffbbc00
 #define OMAP1_MPUIO_VBASE              OMAP1_MPUIO_BASE
 
+/* smart idle, enable wakeup */
+#define SYSCONFIG_WORD                 0x14
+
 /* mpu gpio */
 static struct __initdata resource omap16xx_mpu_gpio_resources[] = {
        {
@@ -45,11 +48,12 @@ static struct omap_gpio_reg_offs omap16xx_mpuio_regs = {
        .irqstatus      = OMAP_MPUIO_GPIO_INT,
        .irqenable      = OMAP_MPUIO_GPIO_MASKIT,
        .irqenable_inv  = true,
+       .irqctrl        = OMAP_MPUIO_GPIO_INT_EDGE,
 };
 
 static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = {
        .virtual_irq_start      = IH_MPUIO_BASE,
-       .bank_type              = METHOD_MPUIO,
+       .is_mpuio               = true,
        .bank_width             = 16,
        .bank_stride            = 1,
        .regs                   = &omap16xx_mpuio_regs,
@@ -89,11 +93,13 @@ static struct omap_gpio_reg_offs omap16xx_gpio_regs = {
        .irqenable      = OMAP1610_GPIO_IRQENABLE1,
        .set_irqenable  = OMAP1610_GPIO_SET_IRQENABLE1,
        .clr_irqenable  = OMAP1610_GPIO_CLEAR_IRQENABLE1,
+       .wkup_en        = OMAP1610_GPIO_WAKEUPENABLE,
+       .edgectrl1      = OMAP1610_GPIO_EDGE_CTRL1,
+       .edgectrl2      = OMAP1610_GPIO_EDGE_CTRL2,
 };
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {
        .virtual_irq_start      = IH_GPIO_BASE,
-       .bank_type              = METHOD_GPIO_1610,
        .bank_width             = 16,
        .regs                   = &omap16xx_gpio_regs,
 };
@@ -123,7 +129,6 @@ static struct __initdata resource omap16xx_gpio2_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 16,
-       .bank_type              = METHOD_GPIO_1610,
        .bank_width             = 16,
        .regs                   = &omap16xx_gpio_regs,
 };
@@ -153,7 +158,6 @@ static struct __initdata resource omap16xx_gpio3_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 32,
-       .bank_type              = METHOD_GPIO_1610,
        .bank_width             = 16,
        .regs                   = &omap16xx_gpio_regs,
 };
@@ -183,7 +187,6 @@ static struct __initdata resource omap16xx_gpio4_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 48,
-       .bank_type              = METHOD_GPIO_1610,
        .bank_width             = 16,
        .regs                   = &omap16xx_gpio_regs,
 };
@@ -214,14 +217,42 @@ static struct __initdata platform_device * omap16xx_gpio_dev[] = {
 static int __init omap16xx_gpio_init(void)
 {
        int i;
+       void __iomem *base;
+       struct resource *res;
+       struct platform_device *pdev;
+       struct omap_gpio_platform_data *pdata;
 
        if (!cpu_is_omap16xx())
                return -EINVAL;
 
-       for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++)
-               platform_device_register(omap16xx_gpio_dev[i]);
+       /*
+        * Enable system clock for GPIO module.
+        * The CAM_CLK_CTRL *is* really the right place.
+        */
+       omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04,
+                                       ULPD_CAM_CLK_CTRL);
+
+       for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++) {
+               pdev = omap16xx_gpio_dev[i];
+               pdata = pdev->dev.platform_data;
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (unlikely(!res)) {
+                       dev_err(&pdev->dev, "Invalid mem resource.\n");
+                       return -ENODEV;
+               }
 
-       gpio_bank_count = ARRAY_SIZE(omap16xx_gpio_dev);
+               base = ioremap(res->start, resource_size(res));
+               if (unlikely(!base)) {
+                       dev_err(&pdev->dev, "ioremap failed.\n");
+                       return -ENOMEM;
+               }
+
+               __raw_writel(SYSCONFIG_WORD, base + OMAP1610_GPIO_SYSCONFIG);
+               iounmap(base);
+
+               platform_device_register(omap16xx_gpio_dev[i]);
+       }
 
        return 0;
 }
index 5ab63ea..4771d6b 100644 (file)
@@ -47,12 +47,13 @@ static struct omap_gpio_reg_offs omap7xx_mpuio_regs = {
        .irqstatus      = OMAP_MPUIO_GPIO_INT / 2,
        .irqenable      = OMAP_MPUIO_GPIO_MASKIT / 2,
        .irqenable_inv  = true,
+       .irqctrl        = OMAP_MPUIO_GPIO_INT_EDGE >> 1,
 };
 
 static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {
        .virtual_irq_start      = IH_MPUIO_BASE,
-       .bank_type              = METHOD_MPUIO,
-       .bank_width             = 32,
+       .is_mpuio               = true,
+       .bank_width             = 16,
        .bank_stride            = 2,
        .regs                   = &omap7xx_mpuio_regs,
 };
@@ -88,11 +89,11 @@ static struct omap_gpio_reg_offs omap7xx_gpio_regs = {
        .irqstatus      = OMAP7XX_GPIO_INT_STATUS,
        .irqenable      = OMAP7XX_GPIO_INT_MASK,
        .irqenable_inv  = true,
+       .irqctrl        = OMAP7XX_GPIO_INT_CONTROL,
 };
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = {
        .virtual_irq_start      = IH_GPIO_BASE,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -122,7 +123,6 @@ static struct __initdata resource omap7xx_gpio2_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 32,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -152,7 +152,6 @@ static struct __initdata resource omap7xx_gpio3_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 64,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -182,7 +181,6 @@ static struct __initdata resource omap7xx_gpio4_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 96,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -212,7 +210,6 @@ static struct __initdata resource omap7xx_gpio5_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 128,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -242,7 +239,6 @@ static struct __initdata resource omap7xx_gpio6_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = {
        .virtual_irq_start      = IH_GPIO_BASE + 160,
-       .bank_type              = METHOD_GPIO_7XX,
        .bank_width             = 32,
        .regs                   = &omap7xx_gpio_regs,
 };
@@ -282,8 +278,6 @@ static int __init omap7xx_gpio_init(void)
        for (i = 0; i < ARRAY_SIZE(omap7xx_gpio_dev); i++)
                platform_device_register(omap7xx_gpio_dev[i]);
 
-       gpio_bank_count = ARRAY_SIZE(omap7xx_gpio_dev);
-
        return 0;
 }
 postcore_initcall(omap7xx_gpio_init);
index b3f3363..2b28e1d 100644 (file)
 #include <linux/init.h>
 #include <linux/io.h>
 #include <asm/system_info.h>
+
 #include <plat/cpu.h>
 
+#include <mach/hardware.h>
+
 #define OMAP_DIE_ID_0          0xfffe1800
 #define OMAP_DIE_ID_1          0xfffe1804
 #define OMAP_PRODUCTION_ID_0   0xfffe2000
index bfb4fb1..fa0f32a 100644 (file)
@@ -9,20 +9,16 @@
  * License version 2. This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  */
+
 #include <mach/hardware.h>
 #include <mach/io.h>
 #include <mach/irqs.h>
-#include <asm/hardware/gic.h>
 
-               .macro  disable_fiq
-               .endm
+#include "../../iomap.h"
 
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \base, =OMAP1_IO_ADDRESS(OMAP_IH1_BASE)
                ldr     \irqnr, [\base, #IRQ_ITR_REG_OFFSET]
index a3f6287..01e35fa 100644 (file)
@@ -2,4 +2,40 @@
  * arch/arm/mach-omap1/include/mach/hardware.h
  */
 
+#ifndef __MACH_HARDWARE_H
+#define __MACH_HARDWARE_H
+
+#ifndef __ASSEMBLER__
+/*
+ * NOTE: Please use ioremap + __raw_read/write where possible instead of these
+ */
+extern u8 omap_readb(u32 pa);
+extern u16 omap_readw(u32 pa);
+extern u32 omap_readl(u32 pa);
+extern void omap_writeb(u8 v, u32 pa);
+extern void omap_writew(u16 v, u32 pa);
+extern void omap_writel(u32 v, u32 pa);
+
+#include <plat/tc.h>
+
+/* Almost all documentation for chip and board memory maps assumes
+ * BM is clear.  Most devel boards have a switch to control booting
+ * from NOR flash (using external chipselect 3) rather than mask ROM,
+ * which uses BM to interchange the physical CS0 and CS3 addresses.
+ */
+static inline u32 omap_cs0m_phys(void)
+{
+       return (omap_readl(EMIFS_CONFIG) & OMAP_EMIFS_CONFIG_BM)
+                       ?  OMAP_CS3_PHYS : 0;
+}
+
+static inline u32 omap_cs3_phys(void)
+{
+       return (omap_readl(EMIFS_CONFIG) & OMAP_EMIFS_CONFIG_BM)
+                       ? 0 : OMAP_CS3_PHYS;
+}
+
+#endif
+#endif
+
 #include <plat/hardware.h>
index 57bdf74..37b12e1 100644 (file)
@@ -1,5 +1,46 @@
 /*
  * arch/arm/mach-omap1/include/mach/io.h
+ *
+ * IO definitions for TI OMAP processors and boards
+ *
+ * Copied from arch/arm/mach-sa1100/include/mach/io.h
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * 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.
+ *
+ * Modifications:
+ *  06-12-1997 RMK     Created.
+ *  07-04-1999 RMK     Major cleanup
  */
 
-#include <plat/io.h>
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We don't actually have real ISA nor PCI buses, but there is so many
+ * drivers out there that might just work if we fake them...
+ */
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
+
+#endif
index c633764..901082d 100644 (file)
@@ -18,7 +18,8 @@
  * Note that the is_lbus_device() test is not very efficient on 1510
  * because of the strncmp().
  */
-#ifdef CONFIG_ARCH_OMAP15XX
+#if defined(CONFIG_ARCH_OMAP15XX) && !defined(__ASSEMBLER__)
+#include <plat/cpu.h>
 
 /*
  * OMAP-1510 Local Bus address offset
diff --git a/arch/arm/mach-omap1/include/mach/system.h b/arch/arm/mach-omap1/include/mach/system.h
deleted file mode 100644 (file)
index a6c1b3a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * arch/arm/mach-omap1/include/mach/system.h
- */
-
-#include <plat/system.h>
index 8e55b6f..d969a72 100644 (file)
 
 #include <asm/tlb.h>
 #include <asm/mach/map.h>
+
 #include <plat/mux.h>
 #include <plat/tc.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "clock.h"
 
 extern void omap_check_revision(void);
@@ -118,7 +121,7 @@ void __init omap16xx_map_io(void)
 /*
  * Common low-level hardware init for omap1.
  */
-void omap1_init_early(void)
+void __init omap1_init_early(void)
 {
        omap_check_revision();
 
diff --git a/arch/arm/mach-omap1/iomap.h b/arch/arm/mach-omap1/iomap.h
new file mode 100644 (file)
index 0000000..d681757
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * IO mappings for OMAP1
+ *
+ * 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.
+ */
+
+#ifdef __ASSEMBLER__
+#define IOMEM(x)               (x)
+#else
+#define IOMEM(x)               ((void __force __iomem *)(x))
+#endif
+
+#define OMAP1_IO_OFFSET                0x01000000      /* Virtual IO = 0xfefb0000 */
+#define OMAP1_IO_ADDRESS(pa)   IOMEM((pa) - OMAP1_IO_OFFSET)
+
+/*
+ * ----------------------------------------------------------------------------
+ * Omap1 specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+
+#define OMAP1_IO_PHYS          0xFFFB0000
+#define OMAP1_IO_SIZE          0x40000
+#define OMAP1_IO_VIRT          (OMAP1_IO_PHYS - OMAP1_IO_OFFSET)
index e5b104b..4448114 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
+
 #include <plat/cpu.h>
 
+#include <mach/hardware.h>
+
 #define IRQ_BANK(irq) ((irq) >> 5)
 #define IRQ_BIT(irq)  ((irq) & 0x1f)
 
index 4c5ce7d..86ace9a 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 
+#include <plat/dma.h>
+
 #include <mach/hardware.h>
 #include <mach/lcdc.h>
-#include <plat/dma.h>
 
 int omap_lcd_dma_running(void)
 {
index 3e8410a..adf0097 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
-#include <mach/irqs.h>
 #include <plat/dma.h>
 #include <plat/mux.h>
 #include <plat/cpu.h>
 #include <plat/mcbsp.h>
 
+#include <mach/irqs.h>
+
+#include "iomap.h"
+
 #define DPS_RSTCT2_PER_EN      (1 << 0)
 #define DSP_RSTCT2_WD_PER_EN   (1 << 1)
 
index 89ea20c..306beac 100644 (file)
 #include <linux/sysfs.h>
 #include <linux/module.h>
 #include <linux/io.h>
+#include <linux/atomic.h>
 
 #include <asm/irq.h>
-#include <linux/atomic.h>
 #include <asm/mach/time.h>
 #include <asm/mach/irq.h>
 
 #include <plat/cpu.h>
-#include <mach/irqs.h>
 #include <plat/clock.h>
 #include <plat/sram.h>
 #include <plat/tc.h>
@@ -57,6 +56,9 @@
 #include <plat/dma.h>
 #include <plat/dmtimer.h>
 
+#include <mach/irqs.h>
+
+#include "iomap.h"
 #include "pm.h"
 
 static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
@@ -108,13 +110,7 @@ void omap1_pm_idle(void)
        __u32 use_idlect1 = arm_idlect1_mask;
        int do_sleep = 0;
 
-       local_irq_disable();
        local_fiq_disable();
-       if (need_resched()) {
-               local_fiq_enable();
-               local_irq_enable();
-               return;
-       }
 
 #if defined(CONFIG_OMAP_MPU_TIMER) && !defined(CONFIG_OMAP_DM_TIMER)
 #warning Enable 32kHz OS timer in order to allow sleep states in idle
@@ -157,14 +153,12 @@ void omap1_pm_idle(void)
                omap_writel(saved_idlect1, ARM_IDLECT1);
 
                local_fiq_enable();
-               local_irq_enable();
                return;
        }
        omap_sram_suspend(omap_readl(ARM_IDLECT1),
                          omap_readl(ARM_IDLECT2));
 
        local_fiq_enable();
-       local_irq_enable();
 }
 
 /*
@@ -583,8 +577,6 @@ static void omap_pm_init_proc(void)
 
 #endif /* DEBUG && CONFIG_PROC_FS */
 
-static void (*saved_idle)(void) = NULL;
-
 /*
  *     omap_pm_prepare - Do preliminary suspend work.
  *
@@ -592,8 +584,7 @@ static void (*saved_idle)(void) = NULL;
 static int omap_pm_prepare(void)
 {
        /* We cannot sleep in idle until we have resumed */
-       saved_idle = pm_idle;
-       pm_idle = NULL;
+       disable_hlt();
 
        return 0;
 }
@@ -630,7 +621,7 @@ static int omap_pm_enter(suspend_state_t state)
 
 static void omap_pm_finish(void)
 {
-       pm_idle = saved_idle;
+       enable_hlt();
 }
 
 
@@ -687,7 +678,7 @@ static int __init omap_pm_init(void)
                return -ENODEV;
        }
 
-       pm_idle = omap1_pm_idle;
+       arm_pm_idle = omap1_pm_idle;
 
        if (cpu_is_omap7xx())
                setup_irq(INT_7XX_WAKE_UP_REQ, &omap_wakeup_irq);
index 91d199b..f255b15 100644 (file)
@@ -4,9 +4,10 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
 #include <plat/prcm.h>
 
+#include <mach/hardware.h>
+
 void omap1_restart(char mode, const char *cmd)
 {
        /*
index c875bdc..0779db1 100644 (file)
  */
 
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
+
 #include <mach/io.h>
+
+#include "iomap.h"
 #include "pm.h"
 
                .text
index 692587d..2ce0b9a 100644 (file)
@@ -9,10 +9,14 @@
  */
 
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
+
 #include <mach/io.h>
 #include <mach/hardware.h>
 
+#include "iomap.h"
+
        .text
 
 /*
index 7595e0a..4d8dd9a 100644 (file)
 #include <linux/clockchips.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/sched_clock.h>
 
+#include <mach/hardware.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
+#include "iomap.h"
 #include "common.h"
 
 #ifdef CONFIG_OMAP_MPU_TIMER
index 10bcd13..325b9a0 100644 (file)
 #include <linux/clockchips.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
 #include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
-#include "common.h"
+
 #include <plat/dmtimer.h>
 
+#include <mach/hardware.h>
+
+#include "common.h"
+
 /*
  * ---------------------------------------------------------------------------
  * 32KHz OS timer
index e20c8ab..8141b76 100644 (file)
@@ -32,7 +32,7 @@ config ARCH_OMAP3
        depends on ARCH_OMAP2PLUS
        default y
        select CPU_V7
-       select USB_ARCH_HAS_EHCI
+       select USB_ARCH_HAS_EHCI if USB_SUPPORT
        select ARCH_HAS_OPP
        select PM_OPP if PM
        select ARM_CPU_SUSPEND if PM
@@ -52,7 +52,7 @@ config ARCH_OMAP4
        select ARM_ERRATA_720789
        select ARCH_HAS_OPP
        select PM_OPP if PM
-       select USB_ARCH_HAS_EHCI
+       select USB_ARCH_HAS_EHCI if USB_SUPPORT
        select ARM_CPU_SUSPEND if PM
 
 comment "OMAP Core Type"
@@ -117,7 +117,6 @@ comment "OMAP Board Type"
 config MACH_OMAP_GENERIC
        bool "Generic OMAP2+ board"
        depends on ARCH_OMAP2PLUS
-       select USE_OF
        default y
        help
          Support for generic TI OMAP2+ boards using Flattened Device Tree.
@@ -245,10 +244,11 @@ config MACH_NOKIA_N8X0
        select MACH_NOKIA_N810_WIMAX
 
 config MACH_NOKIA_RM680
-       bool "Nokia RM-680 board"
+       bool "Nokia RM-680/696 board"
        depends on ARCH_OMAP3
        default y
        select OMAP_PACKAGE_CBB
+       select MACH_NOKIA_RM696
 
 config MACH_NOKIA_RX51
        bool "Nokia RX-51 board"
index 06326a6..49f92bc 100644 (file)
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer.o pm.o \
-        common.o gpio.o dma.o wd_timer.o display.o
+        common.o gpio.o dma.o wd_timer.o display.o i2c.o
 
 omap-2-3-common                                = irq.o sdrc.o
 hwmod-common                           = omap_hwmod.o \
@@ -25,7 +25,6 @@ obj-$(CONFIG_TWL4030_CORE) += omap_twl.o
 
 # SMP support ONLY available for OMAP4
 obj-$(CONFIG_SMP)                      += omap-smp.o omap-headsmp.o
-obj-$(CONFIG_LOCAL_TIMERS)             += timer-mpu.o
 obj-$(CONFIG_HOTPLUG_CPU)              += omap-hotplug.o
 obj-$(CONFIG_ARCH_OMAP4)               += omap4-common.o omap-wakeupgen.o \
                                           sleep44xx.o
@@ -184,9 +183,6 @@ obj-$(CONFIG_OMAP_IOMMU)            += iommu2.o
 iommu-$(CONFIG_OMAP_IOMMU)             := omap-iommu.o
 obj-y                                  += $(iommu-m) $(iommu-y)
 
-i2c-omap-$(CONFIG_I2C_OMAP)            := i2c.o
-obj-y                                  += $(i2c-omap-m) $(i2c-omap-y)
-
 ifneq ($(CONFIG_TIDSPBRIDGE),)
 obj-y                                  += dsp.o
 endif
@@ -270,6 +266,11 @@ obj-y                                      += $(smc91x-m) $(smc91x-y)
 
 smsc911x-$(CONFIG_SMSC911X)            := gpmc-smsc911x.o
 obj-y                                  += $(smsc911x-m) $(smsc911x-y)
-obj-$(CONFIG_ARCH_OMAP4)               += hwspinlock.o
+ifneq ($(CONFIG_HWSPINLOCK_OMAP),)
+obj-y                                  += hwspinlock.o
+endif
+
+emac-$(CONFIG_TI_DAVINCI_EMAC)         := am35xx-emac.o
+obj-y                                  += $(emac-m) $(emac-y)
 
 obj-y                                  += common-board-devices.o twl-common.o
diff --git a/arch/arm/mach-omap2/am35xx-emac.c b/arch/arm/mach-omap2/am35xx-emac.c
new file mode 100644 (file)
index 0000000..1f97e74
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011 Ilya Yanok, Emcraft Systems
+ *
+ * Based on mach-omap2/board-am3517evm.c
+ * Copyright (C) 2009 Texas Instruments Incorporated
+ * Author: Ranjith Lohithakshan <ranjithl@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * published by the Free Software Foundation.
+ *
+ * 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/clk.h>
+#include <linux/davinci_emac.h>
+#include <linux/platform_device.h>
+#include <plat/irqs.h>
+#include <mach/am35xx.h>
+
+#include "control.h"
+
+static struct mdio_platform_data am35xx_emac_mdio_pdata;
+
+static struct resource am35xx_emac_mdio_resources[] = {
+       DEFINE_RES_MEM(AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET, SZ_4K),
+};
+
+static struct platform_device am35xx_emac_mdio_device = {
+       .name           = "davinci_mdio",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(am35xx_emac_mdio_resources),
+       .resource       = am35xx_emac_mdio_resources,
+       .dev.platform_data = &am35xx_emac_mdio_pdata,
+};
+
+static void am35xx_enable_emac_int(void)
+{
+       u32 regval;
+
+       regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+       regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
+                 AM35XX_CPGMAC_C0_TX_PULSE_CLR |
+                 AM35XX_CPGMAC_C0_MISC_PULSE_CLR |
+                 AM35XX_CPGMAC_C0_RX_THRESH_CLR);
+       omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
+       regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+}
+
+static void am35xx_disable_emac_int(void)
+{
+       u32 regval;
+
+       regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+       regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
+                 AM35XX_CPGMAC_C0_TX_PULSE_CLR);
+       omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
+       regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+}
+
+static struct emac_platform_data am35xx_emac_pdata = {
+       .ctrl_reg_offset        = AM35XX_EMAC_CNTRL_OFFSET,
+       .ctrl_mod_reg_offset    = AM35XX_EMAC_CNTRL_MOD_OFFSET,
+       .ctrl_ram_offset        = AM35XX_EMAC_CNTRL_RAM_OFFSET,
+       .ctrl_ram_size          = AM35XX_EMAC_CNTRL_RAM_SIZE,
+       .hw_ram_addr            = AM35XX_EMAC_HW_RAM_ADDR,
+       .version                = EMAC_VERSION_2,
+       .interrupt_enable       = am35xx_enable_emac_int,
+       .interrupt_disable      = am35xx_disable_emac_int,
+};
+
+static struct resource am35xx_emac_resources[] = {
+       DEFINE_RES_MEM(AM35XX_IPSS_EMAC_BASE, 0x30000),
+       DEFINE_RES_IRQ(INT_35XX_EMAC_C0_RXTHRESH_IRQ),
+       DEFINE_RES_IRQ(INT_35XX_EMAC_C0_RX_PULSE_IRQ),
+       DEFINE_RES_IRQ(INT_35XX_EMAC_C0_TX_PULSE_IRQ),
+       DEFINE_RES_IRQ(INT_35XX_EMAC_C0_MISC_PULSE_IRQ),
+};
+
+static struct platform_device am35xx_emac_device = {
+       .name           = "davinci_emac",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(am35xx_emac_resources),
+       .resource       = am35xx_emac_resources,
+       .dev            = {
+               .platform_data  = &am35xx_emac_pdata,
+       },
+};
+
+void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
+{
+       unsigned int regval;
+       int err;
+
+       am35xx_emac_pdata.rmii_en = rmii_en;
+       am35xx_emac_mdio_pdata.bus_freq = mdio_bus_freq;
+       err = platform_device_register(&am35xx_emac_device);
+       if (err) {
+               pr_err("AM35x: failed registering EMAC device: %d\n", err);
+               return;
+       }
+
+       err = platform_device_register(&am35xx_emac_mdio_device);
+       if (err) {
+               pr_err("AM35x: failed registering EMAC MDIO device: %d\n", err);
+               platform_device_unregister(&am35xx_emac_device);
+               return;
+       }
+
+       regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+       regval = regval & (~(AM35XX_CPGMACSS_SW_RST));
+       omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
+       regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+}
diff --git a/arch/arm/mach-omap2/am35xx-emac.h b/arch/arm/mach-omap2/am35xx-emac.h
new file mode 100644 (file)
index 0000000..15c6f9c
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2011 Ilya Yanok, Emcraft Systems
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define AM35XX_DEFAULT_MDIO_FREQUENCY  1000000
+
+#if defined(CONFIG_TI_DAVINCI_EMAC) || defined(CONFIG_TI_DAVINCI_EMAC_MODULE)
+void am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en);
+#else
+static inline void am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en) {}
+#endif
index 7370983..c8bda62 100644 (file)
@@ -279,7 +279,7 @@ static void __init omap_2430sdp_init(void)
        platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
        omap_serial_init();
        omap_sdrc_init(NULL, NULL);
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_init(mmc);
        omap2_usbfs_init(&sdp2430_usb_config);
 
        omap_mux_init_signal("usb0hs_stp", OMAP_PULL_ENA | OMAP_PULL_UP);
index 383717b..da75f23 100644 (file)
@@ -232,11 +232,13 @@ static struct omap2_hsmmc_info mmc[] = {
                 */
                .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = 4,
+               .deferred       = true,
        },
        {
                .mmc            = 2,
                .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = 7,
+               .deferred       = true,
        },
        {}      /* Terminator */
 };
@@ -249,7 +251,7 @@ static int sdp3430_twl_gpio_setup(struct device *dev,
         */
        mmc[0].gpio_cd = gpio + 0;
        mmc[1].gpio_cd = gpio + 1;
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_late_init(mmc);
 
        /* gpio + 7 is "sub_lcd_en_bkl" (output/PWM1) */
        gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "sub_lcd_en_bkl");
@@ -606,6 +608,7 @@ static void __init omap_3430sdp_init(void)
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
        omap_board_config = sdp3430_config;
        omap_board_config_size = ARRAY_SIZE(sdp3430_config);
+       omap_hsmmc_init(mmc);
        omap3430_i2c_init();
        omap_display_init(&sdp3430_dss_data);
        if (omap_rev() > OMAP3430_REV_ES1_0)
index 44cf189..37dcb1b 100644 (file)
@@ -324,7 +324,10 @@ static struct spi_board_info sdp4430_spi_board_info[] __initdata = {
                .bus_num                = 1,
                .chip_select            = 0,
                .max_speed_hz           = 24000000,
-               .irq                    = ETH_KS8851_IRQ,
+               /*
+                * .irq is set to gpio_to_irq(ETH_KS8851_IRQ)
+                * in omap_4430sdp_init
+                */
        },
 };
 
@@ -487,21 +490,22 @@ static struct platform_device omap_vwlan_device = {
 
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
-       int ret = 0;
+       int irq = 0;
        struct platform_device *pdev = container_of(dev,
                                struct platform_device, dev);
        struct omap_mmc_platform_data *pdata = dev->platform_data;
 
        /* Setting MMC1 Card detect Irq */
        if (pdev->id == 0) {
-               ret = twl6030_mmc_card_detect_config();
-               if (ret)
+               irq = twl6030_mmc_card_detect_config();
+               if (irq < 0) {
                        pr_err("Failed configuring MMC1 card detect\n");
-               pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE +
-                                               MMCDETECT_INTR_OFFSET;
+                       return irq;
+               }
+               pdata->slots[0].card_detect_irq = irq;
                pdata->slots[0].card_detect = twl6030_mmc_card_detect;
        }
-       return ret;
+       return 0;
 }
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
@@ -521,9 +525,9 @@ static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
 {
        struct omap2_hsmmc_info *c;
 
-       omap2_hsmmc_init(controllers);
+       omap_hsmmc_init(controllers);
        for (c = controllers; c->mmc; c++)
-               omap4_twl6030_hsmmc_set_late_init(c->dev);
+               omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
 
        return 0;
 }
index 4b1cfe3..3645285 100644 (file)
 #include <video/omap-panel-generic-dpi.h>
 #include <video/omap-panel-dvi.h>
 
+#include "am35xx-emac.h"
 #include "mux.h"
 #include "control.h"
 #include "hsmmc.h"
 
-#define AM35XX_EVM_MDIO_FREQUENCY      (1000000)
-
-static struct mdio_platform_data am3517_evm_mdio_pdata = {
-       .bus_freq       = AM35XX_EVM_MDIO_FREQUENCY,
-};
-
-static struct resource am3517_mdio_resources[] = {
-       {
-               .start  = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET,
-               .end    = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET +
-                         SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device am3517_mdio_device = {
-       .name           = "davinci_mdio",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(am3517_mdio_resources),
-       .resource       = am3517_mdio_resources,
-       .dev.platform_data = &am3517_evm_mdio_pdata,
-};
-
-static struct emac_platform_data am3517_evm_emac_pdata = {
-       .rmii_en        = 1,
-};
-
-static struct resource am3517_emac_resources[] = {
-       {
-               .start  = AM35XX_IPSS_EMAC_BASE,
-               .end    = AM35XX_IPSS_EMAC_BASE + 0x2FFFF,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = INT_35XX_EMAC_C0_RXTHRESH_IRQ,
-               .end    = INT_35XX_EMAC_C0_RXTHRESH_IRQ,
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = INT_35XX_EMAC_C0_RX_PULSE_IRQ,
-               .end    = INT_35XX_EMAC_C0_RX_PULSE_IRQ,
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = INT_35XX_EMAC_C0_TX_PULSE_IRQ,
-               .end    = INT_35XX_EMAC_C0_TX_PULSE_IRQ,
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = INT_35XX_EMAC_C0_MISC_PULSE_IRQ,
-               .end    = INT_35XX_EMAC_C0_MISC_PULSE_IRQ,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device am3517_emac_device = {
-       .name           = "davinci_emac",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(am3517_emac_resources),
-       .resource       = am3517_emac_resources,
-};
-
-static void am3517_enable_ethernet_int(void)
-{
-       u32 regval;
-
-       regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-       regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
-               AM35XX_CPGMAC_C0_TX_PULSE_CLR |
-               AM35XX_CPGMAC_C0_MISC_PULSE_CLR |
-               AM35XX_CPGMAC_C0_RX_THRESH_CLR);
-       omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
-       regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-}
-
-static void am3517_disable_ethernet_int(void)
-{
-       u32 regval;
-
-       regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-       regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
-               AM35XX_CPGMAC_C0_TX_PULSE_CLR);
-       omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
-       regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-}
-
-static void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
-{
-       unsigned int regval;
-
-       pdata->ctrl_reg_offset          = AM35XX_EMAC_CNTRL_OFFSET;
-       pdata->ctrl_mod_reg_offset      = AM35XX_EMAC_CNTRL_MOD_OFFSET;
-       pdata->ctrl_ram_offset          = AM35XX_EMAC_CNTRL_RAM_OFFSET;
-       pdata->ctrl_ram_size            = AM35XX_EMAC_CNTRL_RAM_SIZE;
-       pdata->version                  = EMAC_VERSION_2;
-       pdata->hw_ram_addr              = AM35XX_EMAC_HW_RAM_ADDR;
-       pdata->interrupt_enable         = am3517_enable_ethernet_int;
-       pdata->interrupt_disable        = am3517_disable_ethernet_int;
-       am3517_emac_device.dev.platform_data    = pdata;
-       platform_device_register(&am3517_emac_device);
-       platform_device_register(&am3517_mdio_device);
-       clk_add_alias(NULL, dev_name(&am3517_mdio_device.dev),
-                     NULL, &am3517_emac_device.dev);
-
-       regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
-       regval = regval & (~(AM35XX_CPGMACSS_SW_RST));
-       omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
-       regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
-
-       return ;
-}
-
-
-
 #define LCD_PANEL_PWR          176
 #define LCD_PANEL_BKLIGHT_PWR  182
 #define LCD_PANEL_PWM          181
@@ -498,13 +385,13 @@ static void __init am3517_evm_init(void)
        i2c_register_board_info(1, am3517evm_i2c1_boardinfo,
                                ARRAY_SIZE(am3517evm_i2c1_boardinfo));
        /*Ethernet*/
-       am3517_evm_ethernet_init(&am3517_evm_emac_pdata);
+       am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1);
 
        /* MUSB */
        am3517_evm_musb_init();
 
        /* MMC init function */
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_init(mmc);
 }
 
 MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
index d73316e..41b0a2f 100644 (file)
@@ -280,7 +280,6 @@ static struct omap_dss_board_info cm_t35_dss_data = {
 
 static struct omap2_mcspi_device_config tdo24m_mcspi_config = {
        .turbo_mode     = 0,
-       .single_channel = 1,    /* 0: slave, 1: master */
 };
 
 static struct tdo24m_platform_data tdo24m_config = {
@@ -413,7 +412,7 @@ static struct omap2_hsmmc_info mmc[] = {
                .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
-
+               .deferred       = true,
        },
        {
                .mmc            = 2,
@@ -471,7 +470,7 @@ static int cm_t35_twl_gpio_setup(struct device *dev, unsigned gpio,
 
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        mmc[0].gpio_cd = gpio + 0;
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_late_init(mmc);
 
        return 0;
 }
@@ -639,6 +638,7 @@ static void __init cm_t3x_common_init(void)
        omap_serial_init();
        omap_sdrc_init(mt46h32m32lf6_sdrc_params,
                             mt46h32m32lf6_sdrc_params);
+       omap_hsmmc_init(mmc);
        cm_t35_init_i2c();
        omap_ads7846_init(1, CM_T35_GPIO_PENDOWN, 0, NULL);
        cm_t35_init_ethernet();
index f36d694..9e66e16 100644 (file)
@@ -49,6 +49,7 @@
 #include "mux.h"
 #include "control.h"
 #include "common-board-devices.h"
+#include "am35xx-emac.h"
 
 #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
 static struct gpio_led cm_t3517_leds[] = {
@@ -291,6 +292,7 @@ static void __init cm_t3517_init(void)
        cm_t3517_init_rtc();
        cm_t3517_init_usbh();
        cm_t3517_init_hecc();
+       am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1);
 }
 
 MACHINE_START(CM_T3517, "Compulab CM-T3517")
index e873063..11cd2a8 100644 (file)
@@ -100,6 +100,7 @@ static struct omap2_hsmmc_info mmc[] = {
                .mmc            = 1,
                .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = 29,
+               .deferred       = true,
        },
        {}      /* Terminator */
 };
@@ -228,7 +229,7 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
 
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        mmc[0].gpio_cd = gpio + 0;
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_late_init(mmc);
 
        /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
        gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
@@ -636,6 +637,7 @@ static void __init devkit8000_init(void)
 
        omap_dm9000_init();
 
+       omap_hsmmc_init(mmc);
        devkit8000_i2c_init();
        platform_add_devices(devkit8000_devices,
                        ARRAY_SIZE(devkit8000_devices));
index 30a6f52..0349fd2 100644 (file)
@@ -189,7 +189,7 @@ unmap:
  *
  * @return - void.
  */
-void board_flash_init(struct flash_partitions partition_info[],
+void __init board_flash_init(struct flash_partitions partition_info[],
                        char chip_sel_board[][GPMC_CS_NUM], int nand_type)
 {
        u8              cs = 0;
index 45fdfe2..74e1687 100644 (file)
@@ -12,6 +12,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/io.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/irqdomain.h>
 #include <linux/i2c/twl.h>
 #include "common.h"
 #include "common-board-devices.h"
 
-/*
- * XXX: Still needed to boot until the i2c & twl driver is adapted to
- * device-tree
- */
-#ifdef CONFIG_ARCH_OMAP4
-static struct twl4030_platform_data sdp4430_twldata = {
-       .irq_base       = TWL6030_IRQ_BASE,
-       .irq_end        = TWL6030_IRQ_END,
-};
-
-static void __init omap4_i2c_init(void)
-{
-       omap4_pmic_init("twl6030", &sdp4430_twldata);
-}
+#if !(defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3))
+#define omap_intc_of_init      NULL
+#endif
+#ifndef CONFIG_ARCH_OMAP4
+#define gic_of_init            NULL
 #endif
 
-#ifdef CONFIG_ARCH_OMAP3
-static struct twl4030_platform_data beagle_twldata = {
-       .irq_base       = TWL4030_IRQ_BASE,
-       .irq_end        = TWL4030_IRQ_END,
+static struct of_device_id irq_match[] __initdata = {
+       { .compatible = "ti,omap2-intc", .data = omap_intc_of_init, },
+       { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+       { }
 };
 
-static void __init omap3_i2c_init(void)
+static void __init omap_init_irq(void)
 {
-       omap3_pmic_init("twl4030", &beagle_twldata);
+       of_irq_init(irq_match);
 }
-#endif
 
 static struct of_device_id omap_dt_match_table[] __initdata = {
        { .compatible = "simple-bus", },
@@ -58,51 +49,24 @@ static struct of_device_id omap_dt_match_table[] __initdata = {
        { }
 };
 
-static struct of_device_id intc_match[] __initdata = {
-       { .compatible = "ti,omap3-intc", },
-       { .compatible = "arm,cortex-a9-gic", },
-       { }
-};
-
 static void __init omap_generic_init(void)
 {
-       struct device_node *node = of_find_matching_node(NULL, intc_match);
-       if (node)
-               irq_domain_add_legacy(node, 32, 0, 0, &irq_domain_simple_ops, NULL);
-
        omap_sdrc_init(NULL, NULL);
 
        of_platform_populate(NULL, omap_dt_match_table, NULL, NULL);
 }
 
-#ifdef CONFIG_ARCH_OMAP4
-static void __init omap4_init(void)
-{
-       omap4_i2c_init();
-       omap_generic_init();
-}
-#endif
-
-#ifdef CONFIG_ARCH_OMAP3
-static void __init omap3_init(void)
-{
-       omap3_i2c_init();
-       omap_generic_init();
-}
-#endif
-
-#if defined(CONFIG_SOC_OMAP2420)
+#ifdef CONFIG_SOC_OMAP2420
 static const char *omap242x_boards_compat[] __initdata = {
        "ti,omap2420",
        NULL,
 };
 
 DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)")
-       .atag_offset    = 0x100,
        .reserve        = omap_reserve,
        .map_io         = omap242x_map_io,
        .init_early     = omap2420_init_early,
-       .init_irq       = omap2_init_irq,
+       .init_irq       = omap_init_irq,
        .handle_irq     = omap2_intc_handle_irq,
        .init_machine   = omap_generic_init,
        .timer          = &omap2_timer,
@@ -111,18 +75,17 @@ DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)")
 MACHINE_END
 #endif
 
-#if defined(CONFIG_SOC_OMAP2430)
+#ifdef CONFIG_SOC_OMAP2430
 static const char *omap243x_boards_compat[] __initdata = {
        "ti,omap2430",
        NULL,
 };
 
 DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)")
-       .atag_offset    = 0x100,
        .reserve        = omap_reserve,
        .map_io         = omap243x_map_io,
        .init_early     = omap2430_init_early,
-       .init_irq       = omap2_init_irq,
+       .init_irq       = omap_init_irq,
        .handle_irq     = omap2_intc_handle_irq,
        .init_machine   = omap_generic_init,
        .timer          = &omap2_timer,
@@ -131,18 +94,33 @@ DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)")
 MACHINE_END
 #endif
 
-#if defined(CONFIG_ARCH_OMAP3)
+#ifdef CONFIG_ARCH_OMAP3
+static struct twl4030_platform_data beagle_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+};
+
+static void __init omap3_i2c_init(void)
+{
+       omap3_pmic_init("twl4030", &beagle_twldata);
+}
+
+static void __init omap3_init(void)
+{
+       omap3_i2c_init();
+       omap_generic_init();
+}
+
 static const char *omap3_boards_compat[] __initdata = {
        "ti,omap3",
        NULL,
 };
 
 DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
-       .atag_offset    = 0x100,
        .reserve        = omap_reserve,
        .map_io         = omap3_map_io,
        .init_early     = omap3430_init_early,
-       .init_irq       = omap3_init_irq,
+       .init_irq       = omap_init_irq,
        .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap3_init,
        .timer          = &omap3_timer,
@@ -151,18 +129,33 @@ DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
 MACHINE_END
 #endif
 
-#if defined(CONFIG_ARCH_OMAP4)
+#ifdef CONFIG_ARCH_OMAP4
+static struct twl4030_platform_data sdp4430_twldata = {
+       .irq_base       = TWL6030_IRQ_BASE,
+       .irq_end        = TWL6030_IRQ_END,
+};
+
+static void __init omap4_i2c_init(void)
+{
+       omap4_pmic_init("twl6030", &sdp4430_twldata);
+}
+
+static void __init omap4_init(void)
+{
+       omap4_i2c_init();
+       omap_generic_init();
+}
+
 static const char *omap4_boards_compat[] __initdata = {
        "ti,omap4",
        NULL,
 };
 
 DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)")
-       .atag_offset    = 0x100,
        .reserve        = omap_reserve,
        .map_io         = omap4_map_io,
        .init_early     = omap4430_init_early,
-       .init_irq       = gic_init_irq,
+       .init_irq       = omap_init_irq,
        .handle_irq     = gic_handle_irq,
        .init_machine   = omap4_init,
        .timer          = &omap4_timer,
index a59ace0..e558800 100644 (file)
@@ -295,6 +295,7 @@ static struct omap2_hsmmc_info mmc[] = {
                .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = -EINVAL,
+               .deferred       = true,
        },
 #if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
        {
@@ -402,7 +403,7 @@ static int igep_twl_gpio_setup(struct device *dev,
 
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        mmc[0].gpio_cd = gpio + 0;
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_late_init(mmc);
 
        /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
 #if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
@@ -639,6 +640,9 @@ static void __init igep_init(void)
 
        /* Get IGEP2 hardware revision */
        igep2_get_revision();
+
+       omap_hsmmc_init(mmc);
+
        /* Register I2C busses and drivers */
        igep_i2c_init();
        platform_add_devices(igep_devices, ARRAY_SIZE(igep_devices));
index 2d2a61f..d50a562 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/io.h>
 #include <linux/smsc911x.h>
 #include <linux/mmc/host.h>
-#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -424,7 +423,7 @@ static void __init omap_ldp_init(void)
        board_nand_init(ldp_nand_partitions,
                ARRAY_SIZE(ldp_nand_partitions), ZOOM_NAND_CS, 0);
 
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_init(mmc);
        ldp_display_init();
 }
 
index 6722627..518091c 100644 (file)
 
 #include "mux.h"
 
-static int slot1_cover_open;
-static int slot2_cover_open;
-static struct device *mmc_device;
-
 #define TUSB6010_ASYNC_CS      1
 #define TUSB6010_SYNC_CS       4
 #define TUSB6010_GPIO_INT      58
@@ -137,7 +133,6 @@ static void __init n8x0_usb_init(void) {}
 
 static struct omap2_mcspi_device_config p54spi_mcspi_config = {
        .turbo_mode     = 0,
-       .single_channel = 1,
 };
 
 static struct spi_board_info n800_spi_board_info[] __initdata = {
@@ -211,6 +206,10 @@ static struct omap_onenand_platform_data board_onenand_data[] = {
 #define N810_EMMC_VSD_GPIO     23
 #define N810_EMMC_VIO_GPIO     9
 
+static int slot1_cover_open;
+static int slot2_cover_open;
+static struct device *mmc_device;
+
 static int n8x0_mmc_switch_slot(struct device *dev, int slot)
 {
 #ifdef CONFIG_MMC_DEBUG
index 7ffcd28..7be8d65 100644 (file)
@@ -253,6 +253,7 @@ static struct omap2_hsmmc_info mmc[] = {
                .mmc            = 1,
                .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = -EINVAL,
+               .deferred       = true,
        },
        {}      /* Terminator */
 };
@@ -272,12 +273,10 @@ static int beagle_twl_gpio_setup(struct device *dev,
 {
        int r;
 
-       if (beagle_config.mmc1_gpio_wp != -EINVAL)
-               omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT);
        mmc[0].gpio_wp = beagle_config.mmc1_gpio_wp;
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        mmc[0].gpio_cd = gpio + 0;
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_late_init(mmc);
 
        /*
         * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
@@ -521,6 +520,11 @@ static void __init omap3_beagle_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
        omap3_beagle_init_rev();
+
+       if (beagle_config.mmc1_gpio_wp != -EINVAL)
+               omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT);
+       omap_hsmmc_init(mmc);
+
        omap3_beagle_i2c_init();
 
        gpio_buttons[0].gpio = beagle_config.usr_button_gpio;
index c877236..a659e19 100644 (file)
@@ -317,6 +317,7 @@ static struct omap2_hsmmc_info mmc[] = {
                .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
                .gpio_wp        = 63,
+               .deferred       = true,
        },
 #ifdef CONFIG_WL12XX_PLATFORM_DATA
        {
@@ -361,9 +362,8 @@ static int omap3evm_twl_gpio_setup(struct device *dev,
        int r, lcd_bl_en;
 
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
-       omap_mux_init_gpio(63, OMAP_PIN_INPUT);
        mmc[0].gpio_cd = gpio + 0;
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_late_init(mmc);
 
        /*
         * Most GPIOs are for USB OTG.  Some are mostly sent to
@@ -644,6 +644,9 @@ static void __init omap3_evm_init(void)
        omap_board_config = omap3_evm_config;
        omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
 
+       omap_mux_init_gpio(63, OMAP_PIN_INPUT);
+       omap_hsmmc_init(mmc);
+
        omap3_evm_i2c_init();
 
        omap_display_init(&omap3_evm_dss_data);
index 4198dd0..4a7d8c8 100644 (file)
@@ -128,7 +128,7 @@ static void __init board_mmc_init(void)
                return;
        }
 
-       omap2_hsmmc_init(board_mmc_info);
+       omap_hsmmc_init(board_mmc_info);
 }
 
 static struct omap_smsc911x_platform_data __initdata board_smsc911x_data = {
@@ -205,6 +205,7 @@ static void __init omap3logic_init(void)
 
 MACHINE_START(OMAP3_TORPEDO, "Logic OMAP3 Torpedo board")
        .atag_offset    = 0x100,
+       .reserve        = omap_reserve,
        .map_io         = omap3_map_io,
        .init_early     = omap35xx_init_early,
        .init_irq       = omap3_init_irq,
@@ -216,6 +217,7 @@ MACHINE_END
 
 MACHINE_START(OMAP3530_LV_SOM, "OMAP Logic 3530 LV SOM board")
        .atag_offset    = 0x100,
+       .reserve        = omap_reserve,
        .map_io         = omap3_map_io,
        .init_early     = omap35xx_init_early,
        .init_irq       = omap3_init_irq,
index 1644b73..33d995d 100644 (file)
@@ -121,6 +121,11 @@ static struct platform_device pandora_leds_gpio = {
        },
 };
 
+static struct platform_device pandora_backlight = {
+       .name   = "pandora-backlight",
+       .id     = -1,
+};
+
 #define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr)        \
 {                                                              \
        .gpio           = gpio_num,                             \
@@ -273,6 +278,7 @@ static struct omap2_hsmmc_info omap3pandora_mmc[] = {
                .gpio_cd        = -EINVAL,
                .gpio_wp        = 126,
                .ext_clock      = 0,
+               .deferred       = true,
        },
        {
                .mmc            = 2,
@@ -281,6 +287,7 @@ static struct omap2_hsmmc_info omap3pandora_mmc[] = {
                .gpio_wp        = 127,
                .ext_clock      = 1,
                .transceiver    = true,
+               .deferred       = true,
        },
        {
                .mmc            = 3,
@@ -300,7 +307,7 @@ static int omap3pandora_twl_gpio_setup(struct device *dev,
        /* gpio + {0,1} is "mmc{0,1}_cd" (input/IRQ) */
        omap3pandora_mmc[0].gpio_cd = gpio + 0;
        omap3pandora_mmc[1].gpio_cd = gpio + 1;
-       omap2_hsmmc_init(omap3pandora_mmc);
+       omap_hsmmc_late_init(omap3pandora_mmc);
 
        /* gpio + 13 drives 32kHz buffer for wifi module */
        gpio_32khz = gpio + 13;
@@ -343,7 +350,7 @@ static struct regulator_consumer_supply pandora_vcc_lcd_supply[] = {
 };
 
 static struct regulator_consumer_supply pandora_usb_phy_supply[] = {
-       REGULATOR_SUPPLY("hsusb0", "ehci-omap.0"),
+       REGULATOR_SUPPLY("hsusb1", "ehci-omap.0"),
 };
 
 /* ads7846 on SPI and 2 nub controllers on I2C */
@@ -476,6 +483,10 @@ static struct platform_device pandora_vwlan_device = {
 
 static struct twl4030_bci_platform_data pandora_bci_data;
 
+static struct twl4030_power_data pandora_power_data = {
+       .use_poweroff   = true,
+};
+
 static struct twl4030_platform_data omap3pandora_twldata = {
        .gpio           = &omap3pandora_gpio_data,
        .vmmc1          = &pandora_vmmc1,
@@ -486,6 +497,7 @@ static struct twl4030_platform_data omap3pandora_twldata = {
        .vsim           = &pandora_vsim,
        .keypad         = &pandora_kp_data,
        .bci            = &pandora_bci_data,
+       .power          = &pandora_power_data,
 };
 
 static struct i2c_board_info __initdata omap3pandora_i2c3_boardinfo[] = {
@@ -557,17 +569,18 @@ static struct platform_device *omap3pandora_devices[] __initdata = {
        &pandora_leds_gpio,
        &pandora_keys_gpio,
        &pandora_vwlan_device,
+       &pandora_backlight,
 };
 
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
 
-       .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
-       .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
+       .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
+       .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
        .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
 
        .phy_reset  = true,
-       .reset_gpio_port[0]  = 16,
-       .reset_gpio_port[1]  = -EINVAL,
+       .reset_gpio_port[0]  = -EINVAL,
+       .reset_gpio_port[1]  = 16,
        .reset_gpio_port[2]  = -EINVAL
 };
 
@@ -580,6 +593,7 @@ static struct omap_board_mux board_mux[] __initdata = {
 static void __init omap3pandora_init(void)
 {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+       omap_hsmmc_init(omap3pandora_mmc);
        omap3pandora_i2c_init();
        pandora_wl1251_init();
        platform_add_devices(omap3pandora_devices,
index cb089a4..6410043 100644 (file)
@@ -209,10 +209,11 @@ static struct regulator_init_data omap3stalker_vsim = {
 
 static struct omap2_hsmmc_info mmc[] = {
        {
-        .mmc           = 1,
-        .caps          = MMC_CAP_4_BIT_DATA,
-        .gpio_cd       = -EINVAL,
-        .gpio_wp       = 23,
+               .mmc            = 1,
+               .caps           = MMC_CAP_4_BIT_DATA,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = 23,
+               .deferred       = true,
         },
        {}                      /* Terminator */
 };
@@ -282,9 +283,8 @@ omap3stalker_twl_gpio_setup(struct device *dev,
                            unsigned gpio, unsigned ngpio)
 {
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
-       omap_mux_init_gpio(23, OMAP_PIN_INPUT);
        mmc[0].gpio_cd = gpio + 0;
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_late_init(mmc);
 
        /*
         * Most GPIOs are for USB OTG.  Some are mostly sent to
@@ -425,6 +425,9 @@ static void __init omap3_stalker_init(void)
        omap_board_config = omap3_stalker_config;
        omap_board_config_size = ARRAY_SIZE(omap3_stalker_config);
 
+       omap_mux_init_gpio(23, OMAP_PIN_INPUT);
+       omap_hsmmc_init(mmc);
+
        omap3_stalker_i2c_init();
 
        platform_add_devices(omap3_stalker_devices,
index c4f55a8..ae2251f 100644 (file)
@@ -101,6 +101,7 @@ static struct omap2_hsmmc_info mmc[] = {
                .mmc            = 1,
                .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
                .gpio_wp        = 29,
+               .deferred       = true,
        },
        {}      /* Terminator */
 };
@@ -118,15 +119,9 @@ static struct gpio_led gpio_leds[];
 static int touchbook_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
-       if (system_rev >= 0x20 && system_rev <= 0x34301000) {
-               omap_mux_init_gpio(23, OMAP_PIN_INPUT);
-               mmc[0].gpio_wp = 23;
-       } else {
-               omap_mux_init_gpio(29, OMAP_PIN_INPUT);
-       }
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        mmc[0].gpio_cd = gpio + 0;
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_late_init(mmc);
 
        /* REVISIT: need ehci-omap hooks for external VBUS
         * power switch and overcurrent detect
@@ -352,6 +347,14 @@ static void __init omap3_touchbook_init(void)
 
        pm_power_off = omap3_touchbook_poweroff;
 
+       if (system_rev >= 0x20 && system_rev <= 0x34301000) {
+               omap_mux_init_gpio(23, OMAP_PIN_INPUT);
+               mmc[0].gpio_wp = 23;
+       } else {
+               omap_mux_init_gpio(29, OMAP_PIN_INPUT);
+       }
+       omap_hsmmc_init(mmc);
+
        omap3_touchbook_i2c_init();
        platform_add_devices(omap3_touchbook_devices,
                        ARRAY_SIZE(omap3_touchbook_devices));
index e441591..8bf8e99 100644 (file)
@@ -116,10 +116,16 @@ static struct platform_device panda_abe_audio = {
        },
 };
 
+static struct platform_device btwilink_device = {
+       .name   = "btwilink",
+       .id     = -1,
+};
+
 static struct platform_device *panda_devices[] __initdata = {
        &leds_gpio,
        &wl1271_device,
        &panda_abe_audio,
+       &btwilink_device,
 };
 
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
@@ -232,7 +238,7 @@ struct wl12xx_platform_data omap_panda_wlan_data  __initdata = {
 
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
 {
-       int ret = 0;
+       int irq = 0;
        struct platform_device *pdev = container_of(dev,
                                struct platform_device, dev);
        struct omap_mmc_platform_data *pdata = dev->platform_data;
@@ -243,14 +249,15 @@ static int omap4_twl6030_hsmmc_late_init(struct device *dev)
        }
        /* Setting MMC1 Card detect Irq */
        if (pdev->id == 0) {
-               ret = twl6030_mmc_card_detect_config();
-                if (ret)
+               irq = twl6030_mmc_card_detect_config();
+               if (irq < 0) {
                        dev_err(dev, "%s: Error card detect config(%d)\n",
-                               __func__, ret);
-                else
-                       pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+                               __func__, irq);
+                       return irq;
+               }
+               pdata->slots[0].card_detect = twl6030_mmc_card_detect;
        }
-       return ret;
+       return 0;
 }
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
@@ -271,9 +278,9 @@ static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
 {
        struct omap2_hsmmc_info *c;
 
-       omap2_hsmmc_init(controllers);
+       omap_hsmmc_init(controllers);
        for (c = controllers; c->mmc; c++)
-               omap4_twl6030_hsmmc_set_late_init(c->dev);
+               omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
 
        return 0;
 }
@@ -504,7 +511,7 @@ static struct omap_dss_board_info omap4_panda_dss_data = {
        .default_device = &omap4_panda_dvi_device,
 };
 
-void omap4_panda_display_init(void)
+void __init omap4_panda_display_init(void)
 {
        int r;
 
index 52c0cef..668533e 100644 (file)
@@ -407,8 +407,6 @@ static inline void __init overo_init_keys(void) { return; }
 static int overo_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
-       omap2_hsmmc_init(mmc);
-
 #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
        /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
        gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
@@ -505,6 +503,7 @@ static void __init overo_init(void)
        int ret;
 
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+       omap_hsmmc_init(mmc);
        overo_i2c_init();
        omap_display_init(&overo_dss_data);
        omap_serial_init();
index 8678b38..ae53d71 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Board support file for Nokia RM-680.
+ * Board support file for Nokia RM-680/696.
  *
  * Copyright (C) 2010 Nokia
  *
@@ -120,7 +120,7 @@ static void __init rm680_peripherals_init(void)
                                ARRAY_SIZE(rm680_peripherals_devices));
        rm680_i2c_init();
        gpmc_onenand_init(board_onenand_data);
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_init(mmc);
 }
 
 #ifdef CONFIG_OMAP_MUX
@@ -154,3 +154,15 @@ MACHINE_START(NOKIA_RM680, "Nokia RM-680 board")
        .timer          = &omap3_timer,
        .restart        = omap_prcm_restart,
 MACHINE_END
+
+MACHINE_START(NOKIA_RM696, "Nokia RM-696 board")
+       .atag_offset    = 0x100,
+       .reserve        = omap_reserve,
+       .map_io         = omap3_map_io,
+       .init_early     = omap3630_init_early,
+       .init_irq       = omap3_init_irq,
+       .handle_irq     = omap3_intc_handle_irq,
+       .init_machine   = rm680_init,
+       .timer          = &omap3_timer,
+       .restart        = omap_prcm_restart,
+MACHINE_END
index 2bf84fd..f120997 100644 (file)
@@ -139,17 +139,14 @@ static struct lp5523_platform_data rx51_lp5523_platform_data = {
 
 static struct omap2_mcspi_device_config wl1251_mcspi_config = {
        .turbo_mode     = 0,
-       .single_channel = 1,
 };
 
 static struct omap2_mcspi_device_config mipid_mcspi_config = {
        .turbo_mode     = 0,
-       .single_channel = 1,
 };
 
 static struct omap2_mcspi_device_config tsc2005_mcspi_config = {
        .turbo_mode     = 0,
-       .single_channel = 1,
 };
 
 static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
@@ -1106,6 +1103,11 @@ static struct tsc2005_platform_data tsc2005_pdata = {
        .esd_timeout_ms         = 8000,
 };
 
+static struct gpio rx51_tsc2005_gpios[] __initdata = {
+       { RX51_TSC2005_IRQ_GPIO,   GPIOF_IN,            "tsc2005 IRQ"   },
+       { RX51_TSC2005_RESET_GPIO, GPIOF_OUT_INIT_HIGH, "tsc2005 reset" },
+};
+
 static void rx51_tsc2005_set_reset(bool enable)
 {
        gpio_set_value(RX51_TSC2005_RESET_GPIO, enable);
@@ -1115,20 +1117,18 @@ static void __init rx51_init_tsc2005(void)
 {
        int r;
 
-       r = gpio_request_one(RX51_TSC2005_IRQ_GPIO, GPIOF_IN, "tsc2005 IRQ");
-       if (r < 0) {
-               printk(KERN_ERR "unable to get %s GPIO\n", "tsc2005 IRQ");
-               rx51_peripherals_spi_board_info[RX51_SPI_TSC2005].irq = 0;
-       }
+       omap_mux_init_gpio(RX51_TSC2005_RESET_GPIO, OMAP_PIN_OUTPUT);
+       omap_mux_init_gpio(RX51_TSC2005_IRQ_GPIO, OMAP_PIN_INPUT_PULLUP);
 
-       r = gpio_request_one(RX51_TSC2005_RESET_GPIO, GPIOF_OUT_INIT_HIGH,
-               "tsc2005 reset");
-       if (r >= 0) {
-               tsc2005_pdata.set_reset = rx51_tsc2005_set_reset;
-       } else {
-               printk(KERN_ERR "unable to get %s GPIO\n", "tsc2005 reset");
+       r = gpio_request_array(rx51_tsc2005_gpios,
+                              ARRAY_SIZE(rx51_tsc2005_gpios));
+       if (r < 0) {
+               printk(KERN_ERR "tsc2005 board initialization failed\n");
                tsc2005_pdata.esd_timeout_ms = 0;
+               return;
        }
+
+       tsc2005_pdata.set_reset = rx51_tsc2005_set_reset;
 }
 
 void __init rx51_peripherals_init(void)
@@ -1146,7 +1146,7 @@ void __init rx51_peripherals_init(void)
 
        partition = omap_mux_get("core");
        if (partition)
-               omap2_hsmmc_init(mmc);
+               omap_hsmmc_init(mmc);
 
        rx51_charger_init();
 }
index d4683ba..a43a765 100644 (file)
@@ -55,6 +55,7 @@ static void zoom_panel_disable_lcd(struct omap_dss_device *dssdev)
 
 static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
 {
+#ifdef CONFIG_TWL4030_CORE
        unsigned char c;
        u8 mux_pwm, enb_pwm;
 
@@ -90,6 +91,9 @@ static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
        c = ((50 * (100 - level)) / 100) + 1;
        twl_i2c_write_u8(TWL4030_MODULE_PWM1, 0x7F, TWL_LED_PWMOFF);
        twl_i2c_write_u8(TWL4030_MODULE_PWM1, c, TWL_LED_PWMON);
+#else
+       pr_warn("Backlight not enabled\n");
+#endif
 
        return 0;
 }
@@ -117,7 +121,6 @@ static struct omap_dss_board_info zoom_dss_data = {
 
 static struct omap2_mcspi_device_config dss_lcd_mcspi_config = {
        .turbo_mode             = 1,
-       .single_channel = 1,  /* 0: slave, 1: master */
 };
 
 static struct spi_board_info nec_8048_spi_board_info[] __initdata = {
index c126461..3d39cdb 100644 (file)
@@ -205,6 +205,7 @@ static struct omap2_hsmmc_info mmc[] = {
                .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_wp        = -EINVAL,
                .power_saving   = true,
+               .deferred       = true,
        },
        {
                .name           = "internal",
@@ -233,7 +234,7 @@ static int zoom_twl_gpio_setup(struct device *dev,
 
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        mmc[0].gpio_cd = gpio + 0;
-       omap2_hsmmc_init(mmc);
+       omap_hsmmc_late_init(mmc);
 
        ret = gpio_request_one(LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW,
                               "lcd enable");
@@ -301,6 +302,7 @@ void __init zoom_peripherals_init(void)
        if (ret)
                pr_err("error setting wl12xx data: %d\n", ret);
 
+       omap_hsmmc_init(mmc);
        omap_i2c_init();
        platform_device_register(&omap_vwlan_device);
        usb_musb_init(NULL);
index 39f9d5a..7072e0d 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
 
+#include <plat/cpu.h>
 #include <plat/clock.h>
 #include <plat/sram.h>
 #include <plat/sdrc.h>
index e25364d..04d551b 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/errno.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/bug.h>
 
 #include <plat/clock.h>
 
index e069a9b..cd7fd0f 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/div64.h>
 
 #include <plat/clock.h>
+#include <plat/cpu.h>
 
 #include "clock.h"
 #include "cm-regbits-24xx.h"
index 61ad385..bace930 100644 (file)
  */
 
 #include <linux/kernel.h>
+#include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/list.h>
 
+#include <plat/hardware.h>
 #include <plat/clkdev_omap.h>
 
+#include "iomap.h"
 #include "clock.h"
 #include "clock2xxx.h"
 #include "opp2xxx.h"
index d87bc9c..dfda9a3 100644 (file)
 #include <linux/clk.h>
 #include <linux/io.h>
 
+#include <plat/hardware.h>
 #include <plat/clock.h>
 
+#include "iomap.h"
 #include "clock.h"
 #include "clock2xxx.h"
 #include "cm2xxx_3xxx.h"
index 0cc1287..3b4d09a 100644 (file)
 #include <linux/clk.h>
 #include <linux/list.h>
 
+#include <plat/hardware.h>
 #include <plat/clkdev_omap.h>
 
+#include "iomap.h"
 #include "clock.h"
 #include "clock2xxx.h"
 #include "opp2xxx.h"
index 80bb0f0..1250009 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
+#include <plat/cpu.h>
 #include <plat/clock.h>
 
 #include "clock.h"
index 952c3e0..794d827 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 
+#include <plat/hardware.h>
 #include <plat/clock.h>
 
 #include "clock.h"
index d75e5f6..981b9f9 100644 (file)
 #include <linux/clk.h>
 #include <linux/list.h>
 
+#include <plat/hardware.h>
 #include <plat/clkdev_omap.h>
 
+#include "iomap.h"
 #include "clock.h"
 #include "clock3xxx.h"
 #include "clock34xx.h"
 #include "clock36xx.h"
 #include "clock3517.h"
-
 #include "cm2xxx_3xxx.h"
 #include "cm-regbits-34xx.h"
 #include "prm2xxx_3xxx.h"
index 08e86d7..79b98f2 100644 (file)
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/clk.h>
+
+#include <plat/hardware.h>
 #include <plat/clkdev_omap.h>
 
+#include "iomap.h"
 #include "clock.h"
 #include "clock44xx.h"
 #include "cm1_44xx.h"
index 04d39cd..389f9f8 100644 (file)
 #include <linux/err.h>
 #include <linux/io.h>
 
-#include "common.h"
+#include <plat/hardware.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "cm.h"
 #include "cm2xxx_3xxx.h"
 #include "cm-regbits-24xx.h"
index 6a83630..535d66e 100644 (file)
@@ -18,8 +18,8 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
+#include "iomap.h"
 #include "common.h"
-
 #include "cm.h"
 #include "cm1_44xx.h"
 #include "cm2_44xx.h"
index 6204dea..bd8810c 100644 (file)
@@ -20,8 +20,8 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
+#include "iomap.h"
 #include "common.h"
-
 #include "cm.h"
 #include "cm1_44xx.h"
 #include "cm2_44xx.h"
index bcb0c58..9498b0f 100644 (file)
@@ -33,7 +33,6 @@
        defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
 static struct omap2_mcspi_device_config ads7846_mcspi_config = {
        .turbo_mode     = 0,
-       .single_channel = 1,    /* 0: slave, 1: master */
 };
 
 static struct ads7846_platform_data ads7846_config = {
@@ -76,13 +75,15 @@ void __init omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
                        gpio_set_debounce(gpio_pendown, gpio_debounce);
        }
 
-       ads7846_config.gpio_pendown = gpio_pendown;
-
        spi_bi->bus_num = bus_num;
        spi_bi->irq     = OMAP_GPIO_IRQ(gpio_pendown);
 
-       if (board_pdata)
+       if (board_pdata) {
+               board_pdata->gpio_pendown = gpio_pendown;
                spi_bi->platform_data = board_pdata;
+       } else {
+               ads7846_config.gpio_pendown = gpio_pendown;
+       }
 
        spi_register_board_info(&ads7846_spi_board_info, 1);
 }
index aaf4211..1549c11 100644 (file)
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include "common.h"
+#include <plat/hardware.h>
 #include <plat/board.h>
 #include <plat/mux.h>
-
 #include <plat/clock.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "sdrc.h"
 #include "control.h"
 
index 7e9338e..57da7f4 100644 (file)
@@ -134,6 +134,8 @@ void omap4_map_io(void);
 void ti81xx_map_io(void);
 void omap_barriers_init(void);
 
+extern void __init omap_init_consistent_dma_size(void);
+
 /**
  * omap_test_timeout - busy-loop, testing a condition
  * @cond: condition to test until it evaluates to true
@@ -175,6 +177,18 @@ void omap3_intc_handle_irq(struct pt_regs *regs);
 extern void __iomem *omap4_get_l2cache_base(void);
 #endif
 
+struct device_node;
+#ifdef CONFIG_OF
+int __init omap_intc_of_init(struct device_node *node,
+                            struct device_node *parent);
+#else
+int __init omap_intc_of_init(struct device_node *node,
+                            struct device_node *parent)
+{
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_SMP
 extern void __iomem *omap4_get_scu_base(void);
 #else
@@ -236,5 +250,10 @@ static inline u32 omap4_mpuss_read_prev_context_state(void)
        return 0;
 }
 #endif
+
+struct omap_sdrc_params;
+extern void omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
+                                     struct omap_sdrc_params *sdrc_cs1);
+
 #endif /* __ASSEMBLER__ */
 #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */
index 114c037..08e674b 100644 (file)
 #include <linux/kernel.h>
 #include <linux/io.h>
 
-#include "common.h"
+#include <plat/hardware.h>
 #include <plat/sdrc.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "cm-regbits-34xx.h"
 #include "prm-regbits-34xx.h"
 #include "prm2xxx_3xxx.h"
index 0ba68d3..a406fd0 100644 (file)
@@ -16,7 +16,6 @@
 #ifndef __ARCH_ARM_MACH_OMAP2_CONTROL_H
 #define __ARCH_ARM_MACH_OMAP2_CONTROL_H
 
-#include <mach/io.h>
 #include <mach/ctrl_module_core_44xx.h>
 #include <mach/ctrl_module_wkup_44xx.h>
 #include <mach/ctrl_module_pad_core_44xx.h>
 #define AM35XX_VPFE_PCLK_SW_RST                BIT(4)
 
 /*
+ * CONTROL AM33XX STATUS register
+ */
+#define AM33XX_CONTROL_STATUS          0x040
+
+/*
  * CONTROL OMAP STATUS register to identify OMAP3 features
  */
 #define OMAP3_CONTROL_OMAP_STATUS      0x044c
index f713818..e433603 100644 (file)
@@ -25,7 +25,7 @@
 #include <asm/mach/map.h>
 #include <asm/pmu.h>
 
-#include <plat/tc.h>
+#include "iomap.h"
 #include <plat/board.h>
 #include <plat/mmc.h>
 #include <plat/dma.h>
@@ -276,7 +276,7 @@ int __init omap4_keyboard_init(struct omap4_keypad_platform_data
 }
 
 #if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
-static inline void omap_init_mbox(void)
+static inline void __init omap_init_mbox(void)
 {
        struct omap_hwmod *oh;
        struct platform_device *pdev;
@@ -316,7 +316,7 @@ static inline void omap_init_audio(void) {}
 #if defined(CONFIG_SND_OMAP_SOC_MCPDM) || \
                defined(CONFIG_SND_OMAP_SOC_MCPDM_MODULE)
 
-static void omap_init_mcpdm(void)
+static void __init omap_init_mcpdm(void)
 {
        struct omap_hwmod *oh;
        struct platform_device *pdev;
@@ -337,7 +337,7 @@ static inline void omap_init_mcpdm(void) {}
 #if defined(CONFIG_SND_OMAP_SOC_DMIC) || \
                defined(CONFIG_SND_OMAP_SOC_DMIC_MODULE)
 
-static void omap_init_dmic(void)
+static void __init omap_init_dmic(void)
 {
        struct omap_hwmod *oh;
        struct platform_device *pdev;
@@ -359,7 +359,7 @@ static inline void omap_init_dmic(void) {}
 
 #include <plat/mcspi.h>
 
-static int omap_mcspi_init(struct omap_hwmod *oh, void *unused)
+static int __init omap_mcspi_init(struct omap_hwmod *oh, void *unused)
 {
        struct platform_device *pdev;
        char *name = "omap2_mcspi";
@@ -633,9 +633,7 @@ void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data)
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE)
-#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430)
 #define OMAP_HDQ_BASE  0x480B2000
-#endif
 static struct resource omap_hdq_resources[] = {
        {
                .start          = OMAP_HDQ_BASE,
@@ -658,7 +656,10 @@ static struct platform_device omap_hdq_dev = {
 };
 static inline void omap_hdq_init(void)
 {
-       (void) platform_device_register(&omap_hdq_dev);
+       if (cpu_is_omap2420())
+               return;
+
+       platform_device_register(&omap_hdq_dev);
 }
 #else
 static inline void omap_hdq_init(void) {}
index 3677b1f..9706c64 100644 (file)
@@ -30,6 +30,7 @@
 #include <plat/omap-pm.h>
 #include "common.h"
 
+#include "iomap.h"
 #include "mux.h"
 #include "control.h"
 #include "display.h"
@@ -124,7 +125,7 @@ static void omap4_hdmi_mux_pads(enum omap_hdmi_flags flags)
        }
 }
 
-static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes)
+static int __init omap4_dsi_mux_pads(int dsi_id, unsigned lanes)
 {
        u32 enable_mask, enable_shift;
        u32 pipd_mask, pipd_shift;
@@ -157,7 +158,7 @@ static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes)
        return 0;
 }
 
-int omap_hdmi_init(enum omap_hdmi_flags flags)
+int __init omap_hdmi_init(enum omap_hdmi_flags flags)
 {
        if (cpu_is_omap44xx())
                omap4_hdmi_mux_pads(flags);
@@ -165,7 +166,7 @@ int omap_hdmi_init(enum omap_hdmi_flags flags)
        return 0;
 }
 
-static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask)
+static int __init omap_dsi_enable_pads(int dsi_id, unsigned lane_mask)
 {
        if (cpu_is_omap44xx())
                return omap4_dsi_mux_pads(dsi_id, lane_mask);
@@ -173,7 +174,7 @@ static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask)
        return 0;
 }
 
-static void omap_dsi_disable_pads(int dsi_id, unsigned lane_mask)
+static void __init omap_dsi_disable_pads(int dsi_id, unsigned lane_mask)
 {
        if (cpu_is_omap44xx())
                omap4_dsi_mux_pads(dsi_id, 0);
index a59a45a..b19d849 100644 (file)
@@ -227,7 +227,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
 
        dma_stride              = OMAP2_DMA_STRIDE;
        dma_common_ch_start     = CSDP;
-       if (cpu_is_omap3630() || cpu_is_omap4430())
+       if (cpu_is_omap3630() || cpu_is_omap44xx())
                dma_common_ch_end = CCDN;
        else
                dma_common_ch_end = CCFN;
index 9c442e2..e28e761 100644 (file)
 #include <linux/clk.h>
 #include <linux/err.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexander Shishkin");
 
@@ -30,29 +34,8 @@ MODULE_AUTHOR("Alexander Shishkin");
 #define ETB_BASE       (L4_EMU_34XX_PHYS + 0x1b000)
 #define DAPCTL         (L4_EMU_34XX_PHYS + 0x1d000)
 
-static struct amba_device omap3_etb_device = {
-       .dev            = {
-               .init_name = "etb",
-       },
-       .res            = {
-               .start  = ETB_BASE,
-               .end    = ETB_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       .periphid       = 0x000bb907,
-};
-
-static struct amba_device omap3_etm_device = {
-       .dev            = {
-               .init_name = "etm",
-       },
-       .res            = {
-               .start  = ETM_BASE,
-               .end    = ETM_BASE + SZ_4K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       .periphid       = 0x102bb921,
-};
+static AMBA_APB_DEVICE(omap3_etb, "etb", 0x000bb907, ETB_BASE, { }, NULL);
+static AMBA_APB_DEVICE(omap3_etm, "etm", 0x102bb921, ETM_BASE, { }, NULL);
 
 static int __init emu_init(void)
 {
@@ -66,4 +49,3 @@ static int __init emu_init(void)
 }
 
 subsys_initcall(emu_init);
-
index 8cbfbc2..2f994e5 100644 (file)
 
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
+#include <plat/omap-pm.h>
 
-static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
+#include "powerdomain.h"
+
+static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 {
        struct platform_device *pdev;
        struct omap_gpio_platform_data *pdata;
        struct omap_gpio_dev_attr *dev_attr;
        char *name = "omap_gpio";
        int id;
+       struct powerdomain *pwrdm;
 
        /*
         * extract the device id from name field available in the
@@ -52,7 +56,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
        pdata->bank_width = dev_attr->bank_width;
        pdata->dbck_flag = dev_attr->dbck_flag;
        pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1);
-
+       pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
        pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL);
        if (!pdata) {
                pr_err("gpio%d: Memory allocation failed\n", id);
@@ -61,8 +65,15 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 
        switch (oh->class->rev) {
        case 0:
+               if (id == 1)
+                       /* non-wakeup GPIO pins for OMAP2 Bank1 */
+                       pdata->non_wakeup_gpios = 0xe203ffc0;
+               else if (id == 2)
+                       /* non-wakeup GPIO pins for OMAP2 Bank2 */
+                       pdata->non_wakeup_gpios = 0x08700040;
+               /* fall through */
+
        case 1:
-               pdata->bank_type = METHOD_GPIO_24XX;
                pdata->regs->revision = OMAP24XX_GPIO_REVISION;
                pdata->regs->direction = OMAP24XX_GPIO_OE;
                pdata->regs->datain = OMAP24XX_GPIO_DATAIN;
@@ -72,13 +83,19 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
                pdata->regs->irqstatus = OMAP24XX_GPIO_IRQSTATUS1;
                pdata->regs->irqstatus2 = OMAP24XX_GPIO_IRQSTATUS2;
                pdata->regs->irqenable = OMAP24XX_GPIO_IRQENABLE1;
+               pdata->regs->irqenable2 = OMAP24XX_GPIO_IRQENABLE2;
                pdata->regs->set_irqenable = OMAP24XX_GPIO_SETIRQENABLE1;
                pdata->regs->clr_irqenable = OMAP24XX_GPIO_CLEARIRQENABLE1;
                pdata->regs->debounce = OMAP24XX_GPIO_DEBOUNCE_VAL;
                pdata->regs->debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN;
+               pdata->regs->ctrl = OMAP24XX_GPIO_CTRL;
+               pdata->regs->wkup_en = OMAP24XX_GPIO_WAKE_EN;
+               pdata->regs->leveldetect0 = OMAP24XX_GPIO_LEVELDETECT0;
+               pdata->regs->leveldetect1 = OMAP24XX_GPIO_LEVELDETECT1;
+               pdata->regs->risingdetect = OMAP24XX_GPIO_RISINGDETECT;
+               pdata->regs->fallingdetect = OMAP24XX_GPIO_FALLINGDETECT;
                break;
        case 2:
-               pdata->bank_type = METHOD_GPIO_44XX;
                pdata->regs->revision = OMAP4_GPIO_REVISION;
                pdata->regs->direction = OMAP4_GPIO_OE;
                pdata->regs->datain = OMAP4_GPIO_DATAIN;
@@ -88,10 +105,17 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
                pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0;
                pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1;
                pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0;
+               pdata->regs->irqenable2 = OMAP4_GPIO_IRQSTATUSSET1;
                pdata->regs->set_irqenable = OMAP4_GPIO_IRQSTATUSSET0;
                pdata->regs->clr_irqenable = OMAP4_GPIO_IRQSTATUSCLR0;
                pdata->regs->debounce = OMAP4_GPIO_DEBOUNCINGTIME;
                pdata->regs->debounce_en = OMAP4_GPIO_DEBOUNCENABLE;
+               pdata->regs->ctrl = OMAP4_GPIO_CTRL;
+               pdata->regs->wkup_en = OMAP4_GPIO_IRQWAKEN0;
+               pdata->regs->leveldetect0 = OMAP4_GPIO_LEVELDETECT0;
+               pdata->regs->leveldetect1 = OMAP4_GPIO_LEVELDETECT1;
+               pdata->regs->risingdetect = OMAP4_GPIO_RISINGDETECT;
+               pdata->regs->fallingdetect = OMAP4_GPIO_FALLINGDETECT;
                break;
        default:
                WARN(1, "Invalid gpio bank_type\n");
@@ -99,6 +123,9 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
                return -EINVAL;
        }
 
+       pwrdm = omap_hwmod_get_pwrdm(oh);
+       pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
+
        pdev = omap_device_build(name, id - 1, oh, pdata,
                                sizeof(*pdata), NULL, 0, false);
        kfree(pdata);
@@ -109,9 +136,6 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
                return PTR_ERR(pdev);
        }
 
-       omap_device_disable_idle_on_suspend(pdev);
-
-       gpio_bank_count++;
        return 0;
 }
 
index 8ad210b..386dec8 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <asm/mach/flash.h>
 
+#include <plat/cpu.h>
 #include <plat/nand.h>
 #include <plat/board.h>
 #include <plat/gpmc.h>
index 5cdce10..385b3e0 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <asm/mach/flash.h>
 
+#include <plat/cpu.h>
 #include <plat/onenand.h>
 #include <plat/board.h>
 #include <plat/gpmc.h>
index bbb870c..5e5880d 100644 (file)
@@ -101,10 +101,13 @@ void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *board_data)
 
        gpmc_cfg = board_data;
 
-       ret = platform_device_register(&gpmc_smsc911x_regulator);
-       if (ret < 0) {
-               pr_err("Unable to register smsc911x regulators: %d\n", ret);
-               return;
+       if (!gpmc_cfg->id) {
+               ret = platform_device_register(&gpmc_smsc911x_regulator);
+               if (ret < 0) {
+                       pr_err("Unable to register smsc911x regulators: %d\n",
+                              ret);
+                       return;
+               }
        }
 
        if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
index dfffbbf..00d5108 100644 (file)
@@ -888,6 +888,7 @@ int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size)
        gpmc_write_reg(GPMC_ECC_CONFIG, val);
        return 0;
 }
+EXPORT_SYMBOL_GPL(gpmc_enable_hwecc);
 
 /**
  * gpmc_calculate_ecc - generate non-inverted ecc bytes
@@ -918,3 +919,4 @@ int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
        gpmc_ecc_used = -EINVAL;
        return 0;
 }
+EXPORT_SYMBOL_GPL(gpmc_calculate_ecc);
index 19dd165..8121720 100644 (file)
@@ -293,8 +293,8 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
        }
 }
 
-static int omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
-                                struct omap_mmc_platform_data *mmc)
+static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
+                                       struct omap_mmc_platform_data *mmc)
 {
        char *hc_name;
 
@@ -429,66 +429,131 @@ static int omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
 }
 
 static int omap_hsmmc_done;
+
+void omap_hsmmc_late_init(struct omap2_hsmmc_info *c)
+{
+       struct platform_device *pdev;
+       struct omap_mmc_platform_data *mmc_pdata;
+       int res;
+
+       if (omap_hsmmc_done != 1)
+               return;
+
+       omap_hsmmc_done++;
+
+       for (; c->mmc; c++) {
+               if (!c->deferred)
+                       continue;
+
+               pdev = c->pdev;
+               if (!pdev)
+                       continue;
+
+               mmc_pdata = pdev->dev.platform_data;
+               if (!mmc_pdata)
+                       continue;
+
+               mmc_pdata->slots[0].switch_pin = c->gpio_cd;
+               mmc_pdata->slots[0].gpio_wp = c->gpio_wp;
+
+               res = omap_device_register(pdev);
+               if (res)
+                       pr_err("Could not late init MMC %s\n",
+                              c->name);
+       }
+}
+
 #define MAX_OMAP_MMC_HWMOD_NAME_LEN            16
 
-void omap_init_hsmmc(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr)
+static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo,
+                                       int ctrl_nr)
 {
        struct omap_hwmod *oh;
+       struct omap_hwmod *ohs[1];
+       struct omap_device *od;
        struct platform_device *pdev;
        char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN];
        struct omap_mmc_platform_data *mmc_data;
        struct omap_mmc_dev_attr *mmc_dev_attr;
        char *name;
-       int l;
+       int res;
 
        mmc_data = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL);
        if (!mmc_data) {
                pr_err("Cannot allocate memory for mmc device!\n");
-               goto done;
+               return;
        }
 
-       if (omap_hsmmc_pdata_init(hsmmcinfo, mmc_data) < 0) {
-               pr_err("%s fails!\n", __func__);
-               goto done;
-       }
+       res = omap_hsmmc_pdata_init(hsmmcinfo, mmc_data);
+       if (res < 0)
+               goto free_mmc;
+
        omap_hsmmc_mux(mmc_data, (ctrl_nr - 1));
 
        name = "omap_hsmmc";
-
-       l = snprintf(oh_name, MAX_OMAP_MMC_HWMOD_NAME_LEN,
+       res = snprintf(oh_name, MAX_OMAP_MMC_HWMOD_NAME_LEN,
                     "mmc%d", ctrl_nr);
-       WARN(l >= MAX_OMAP_MMC_HWMOD_NAME_LEN,
+       WARN(res >= MAX_OMAP_MMC_HWMOD_NAME_LEN,
             "String buffer overflow in MMC%d device setup\n", ctrl_nr);
+
        oh = omap_hwmod_lookup(oh_name);
        if (!oh) {
                pr_err("Could not look up %s\n", oh_name);
-               kfree(mmc_data->slots[0].name);
-               goto done;
+               goto free_name;
        }
-
+       ohs[0] = oh;
        if (oh->dev_attr != NULL) {
                mmc_dev_attr = oh->dev_attr;
                mmc_data->controller_flags = mmc_dev_attr->flags;
        }
 
-       pdev = omap_device_build(name, ctrl_nr - 1, oh, mmc_data,
-               sizeof(struct omap_mmc_platform_data), NULL, 0, false);
-       if (IS_ERR(pdev)) {
-               WARN(1, "Can't build omap_device for %s:%s.\n", name, oh->name);
-               kfree(mmc_data->slots[0].name);
-               goto done;
+       pdev = platform_device_alloc(name, ctrl_nr - 1);
+       if (!pdev) {
+               pr_err("Could not allocate pdev for %s\n", name);
+               goto free_name;
        }
-       /*
-        * return device handle to board setup code
-        * required to populate for regulator framework structure
-        */
-       hsmmcinfo->dev = &pdev->dev;
+       dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
+
+       od = omap_device_alloc(pdev, ohs, 1, NULL, 0);
+       if (!od) {
+               pr_err("Could not allocate od for %s\n", name);
+               goto put_pdev;
+       }
+
+       res = platform_device_add_data(pdev, mmc_data,
+                             sizeof(struct omap_mmc_platform_data));
+       if (res) {
+               pr_err("Could not add pdata for %s\n", name);
+               goto put_pdev;
+       }
+
+       hsmmcinfo->pdev = pdev;
+
+       if (hsmmcinfo->deferred)
+               goto free_mmc;
+
+       res = omap_device_register(pdev);
+       if (res) {
+               pr_err("Could not register od for %s\n", name);
+               goto free_od;
+       }
+
+       goto free_mmc;
+
+free_od:
+       omap_device_delete(od);
+
+put_pdev:
+       platform_device_put(pdev);
+
+free_name:
+       kfree(mmc_data->slots[0].name);
 
-done:
+free_mmc:
        kfree(mmc_data);
 }
 
-void omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
+void __init omap_hsmmc_init(struct omap2_hsmmc_info *controllers)
 {
        u32 reg;
 
@@ -521,7 +586,7 @@ void omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
        }
 
        for (; controllers->mmc; controllers++)
-               omap_init_hsmmc(controllers, controllers->mmc);
+               omap_hsmmc_init_one(controllers, controllers->mmc);
 
 }
 
index c440973..07831cc 100644 (file)
@@ -21,10 +21,11 @@ struct omap2_hsmmc_info {
        bool    no_off;         /* power_saving and power is not to go off */
        bool    no_off_init;    /* no power off when not in MMC sleep state */
        bool    vcc_aux_disable_is_sleep; /* Regulator off remapped to sleep */
+       bool    deferred;       /* mmc needs a deferred probe */
        int     gpio_cd;        /* or -EINVAL */
        int     gpio_wp;        /* or -EINVAL */
        char    *name;          /* or NULL for default */
-       struct device *dev;     /* returned: pointer to mmc adapter */
+       struct platform_device *pdev;   /* mmc controller instance */
        int     ocr_mask;       /* temporary HACK */
        /* Remux (pad configuration) when powering on/off */
        void (*remux)(struct device *dev, int slot, int power_on);
@@ -34,11 +35,16 @@ struct omap2_hsmmc_info {
 
 #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
 
-void omap2_hsmmc_init(struct omap2_hsmmc_info *);
+void omap_hsmmc_init(struct omap2_hsmmc_info *);
+void omap_hsmmc_late_init(struct omap2_hsmmc_info *);
 
 #else
 
-static inline void omap2_hsmmc_init(struct omap2_hsmmc_info *info)
+static inline void omap_hsmmc_init(struct omap2_hsmmc_info *info)
+{
+}
+
+static inline void omap_hsmmc_late_init(struct omap2_hsmmc_info *info)
 {
 }
 
index 719ee42..0e79b7b 100644 (file)
@@ -29,7 +29,7 @@
 #include "control.h"
 
 static unsigned int omap_revision;
-
+static const char *cpu_rev;
 u32 omap_features;
 
 unsigned int omap_rev(void)
@@ -44,6 +44,8 @@ int omap_type(void)
 
        if (cpu_is_omap24xx()) {
                val = omap_ctrl_readl(OMAP24XX_CONTROL_STATUS);
+       } else if (cpu_is_am33xx()) {
+               val = omap_ctrl_readl(AM33XX_CONTROL_STATUS);
        } else if (cpu_is_omap34xx()) {
                val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
        } else if (cpu_is_omap44xx()) {
@@ -112,7 +114,7 @@ void omap_get_die_id(struct omap_die_id *odi)
        odi->id_3 = read_tap_reg(OMAP_TAP_DIE_ID_3);
 }
 
-static void __init omap24xx_check_revision(void)
+void __init omap2xxx_check_revision(void)
 {
        int i, j;
        u32 idcode, prod_id;
@@ -166,13 +168,63 @@ static void __init omap24xx_check_revision(void)
        pr_info("\n");
 }
 
+#define OMAP3_SHOW_FEATURE(feat)               \
+       if (omap3_has_ ##feat())                \
+               printk(#feat" ");
+
+static void __init omap3_cpuinfo(void)
+{
+       const char *cpu_name;
+
+       /*
+        * OMAP3430 and OMAP3530 are assumed to be same.
+        *
+        * OMAP3525, OMAP3515 and OMAP3503 can be detected only based
+        * on available features. Upon detection, update the CPU id
+        * and CPU class bits.
+        */
+       if (cpu_is_omap3630()) {
+               cpu_name = "OMAP3630";
+       } else if (cpu_is_omap3517()) {
+               /* AM35xx devices */
+               cpu_name = (omap3_has_sgx()) ? "AM3517" : "AM3505";
+       } else if (cpu_is_ti816x()) {
+               cpu_name = "TI816X";
+       } else if (cpu_is_am335x()) {
+               cpu_name =  "AM335X";
+       } else if (cpu_is_ti814x()) {
+               cpu_name = "TI814X";
+       } else if (omap3_has_iva() && omap3_has_sgx()) {
+               /* OMAP3430, OMAP3525, OMAP3515, OMAP3503 devices */
+               cpu_name = "OMAP3430/3530";
+       } else if (omap3_has_iva()) {
+               cpu_name = "OMAP3525";
+       } else if (omap3_has_sgx()) {
+               cpu_name = "OMAP3515";
+       } else {
+               cpu_name = "OMAP3503";
+       }
+
+       /* Print verbose information */
+       pr_info("%s ES%s (", cpu_name, cpu_rev);
+
+       OMAP3_SHOW_FEATURE(l2cache);
+       OMAP3_SHOW_FEATURE(iva);
+       OMAP3_SHOW_FEATURE(sgx);
+       OMAP3_SHOW_FEATURE(neon);
+       OMAP3_SHOW_FEATURE(isp);
+       OMAP3_SHOW_FEATURE(192mhz_clk);
+
+       printk(")\n");
+}
+
 #define OMAP3_CHECK_FEATURE(status,feat)                               \
        if (((status & OMAP3_ ##feat## _MASK)                           \
                >> OMAP3_ ##feat## _SHIFT) != FEAT_ ##feat## _NONE) {   \
                omap_features |= OMAP3_HAS_ ##feat;                     \
        }
 
-static void __init omap3_check_features(void)
+void __init omap3xxx_check_features(void)
 {
        u32 status;
 
@@ -199,9 +251,11 @@ static void __init omap3_check_features(void)
         * TODO: Get additional info (where applicable)
         *       e.g. Size of L2 cache.
         */
+
+       omap3_cpuinfo();
 }
 
-static void __init omap4_check_features(void)
+void __init omap4xxx_check_features(void)
 {
        u32 si_type;
 
@@ -226,12 +280,13 @@ static void __init omap4_check_features(void)
        }
 }
 
-static void __init ti81xx_check_features(void)
+void __init ti81xx_check_features(void)
 {
        omap_features = OMAP3_HAS_NEON;
+       omap3_cpuinfo();
 }
 
-static void __init omap3_check_revision(const char **cpu_rev)
+void __init omap3xxx_check_revision(void)
 {
        u32 cpuid, idcode;
        u16 hawkeye;
@@ -245,7 +300,7 @@ static void __init omap3_check_revision(const char **cpu_rev)
        cpuid = read_cpuid(CPUID_ID);
        if ((((cpuid >> 4) & 0xfff) == 0xc08) && ((cpuid & 0xf) == 0x0)) {
                omap_revision = OMAP3430_REV_ES1_0;
-               *cpu_rev = "1.0";
+               cpu_rev = "1.0";
                return;
        }
 
@@ -266,26 +321,26 @@ static void __init omap3_check_revision(const char **cpu_rev)
                case 0: /* Take care of early samples */
                case 1:
                        omap_revision = OMAP3430_REV_ES2_0;
-                       *cpu_rev = "2.0";
+                       cpu_rev = "2.0";
                        break;
                case 2:
                        omap_revision = OMAP3430_REV_ES2_1;
-                       *cpu_rev = "2.1";
+                       cpu_rev = "2.1";
                        break;
                case 3:
                        omap_revision = OMAP3430_REV_ES3_0;
-                       *cpu_rev = "3.0";
+                       cpu_rev = "3.0";
                        break;
                case 4:
                        omap_revision = OMAP3430_REV_ES3_1;
-                       *cpu_rev = "3.1";
+                       cpu_rev = "3.1";
                        break;
                case 7:
                /* FALLTHROUGH */
                default:
                        /* Use the latest known revision as default */
                        omap_revision = OMAP3430_REV_ES3_1_2;
-                       *cpu_rev = "3.1.2";
+                       cpu_rev = "3.1.2";
                }
                break;
        case 0xb868:
@@ -298,13 +353,13 @@ static void __init omap3_check_revision(const char **cpu_rev)
                switch (rev) {
                case 0:
                        omap_revision = OMAP3517_REV_ES1_0;
-                       *cpu_rev = "1.0";
+                       cpu_rev = "1.0";
                        break;
                case 1:
                /* FALLTHROUGH */
                default:
                        omap_revision = OMAP3517_REV_ES1_1;
-                       *cpu_rev = "1.1";
+                       cpu_rev = "1.1";
                }
                break;
        case 0xb891:
@@ -313,36 +368,36 @@ static void __init omap3_check_revision(const char **cpu_rev)
                switch(rev) {
                case 0: /* Take care of early samples */
                        omap_revision = OMAP3630_REV_ES1_0;
-                       *cpu_rev = "1.0";
+                       cpu_rev = "1.0";
                        break;
                case 1:
                        omap_revision = OMAP3630_REV_ES1_1;
-                       *cpu_rev = "1.1";
+                       cpu_rev = "1.1";
                        break;
                case 2:
                /* FALLTHROUGH */
                default:
                        omap_revision = OMAP3630_REV_ES1_2;
-                       *cpu_rev = "1.2";
+                       cpu_rev = "1.2";
                }
                break;
        case 0xb81e:
                switch (rev) {
                case 0:
                        omap_revision = TI8168_REV_ES1_0;
-                       *cpu_rev = "1.0";
+                       cpu_rev = "1.0";
                        break;
                case 1:
                /* FALLTHROUGH */
                default:
                        omap_revision = TI8168_REV_ES1_1;
-                       *cpu_rev = "1.1";
+                       cpu_rev = "1.1";
                        break;
                }
                break;
        case 0xb944:
                omap_revision = AM335X_REV_ES1_0;
-               *cpu_rev = "1.0";
+               cpu_rev = "1.0";
                break;
        case 0xb8f2:
                switch (rev) {
@@ -350,29 +405,29 @@ static void __init omap3_check_revision(const char **cpu_rev)
                /* FALLTHROUGH */
                case 1:
                        omap_revision = TI8148_REV_ES1_0;
-                       *cpu_rev = "1.0";
+                       cpu_rev = "1.0";
                        break;
                case 2:
                        omap_revision = TI8148_REV_ES2_0;
-                       *cpu_rev = "2.0";
+                       cpu_rev = "2.0";
                        break;
                case 3:
                /* FALLTHROUGH */
                default:
                        omap_revision = TI8148_REV_ES2_1;
-                       *cpu_rev = "2.1";
+                       cpu_rev = "2.1";
                        break;
                }
                break;
        default:
                /* Unknown default to latest silicon rev as default */
                omap_revision = OMAP3630_REV_ES1_2;
-               *cpu_rev = "1.2";
+               cpu_rev = "1.2";
                pr_warn("Warning: unknown chip type; assuming OMAP3630ES1.2\n");
        }
 }
 
-static void __init omap4_check_revision(void)
+void __init omap4xxx_check_revision(void)
 {
        u32 idcode;
        u16 hawkeye;
@@ -445,89 +500,6 @@ static void __init omap4_check_revision(void)
                ((omap_rev() >> 12) & 0xf), ((omap_rev() >> 8) & 0xf));
 }
 
-#define OMAP3_SHOW_FEATURE(feat)               \
-       if (omap3_has_ ##feat())                \
-               printk(#feat" ");
-
-static void __init omap3_cpuinfo(const char *cpu_rev)
-{
-       const char *cpu_name;
-
-       /*
-        * OMAP3430 and OMAP3530 are assumed to be same.
-        *
-        * OMAP3525, OMAP3515 and OMAP3503 can be detected only based
-        * on available features. Upon detection, update the CPU id
-        * and CPU class bits.
-        */
-       if (cpu_is_omap3630()) {
-               cpu_name = "OMAP3630";
-       } else if (cpu_is_omap3517()) {
-               /* AM35xx devices */
-               cpu_name = (omap3_has_sgx()) ? "AM3517" : "AM3505";
-       } else if (cpu_is_ti816x()) {
-               cpu_name = "TI816X";
-       } else if (cpu_is_am335x()) {
-               cpu_name =  "AM335X";
-       } else if (cpu_is_ti814x()) {
-               cpu_name = "TI814X";
-       } else if (omap3_has_iva() && omap3_has_sgx()) {
-               /* OMAP3430, OMAP3525, OMAP3515, OMAP3503 devices */
-               cpu_name = "OMAP3430/3530";
-       } else if (omap3_has_iva()) {
-               cpu_name = "OMAP3525";
-       } else if (omap3_has_sgx()) {
-               cpu_name = "OMAP3515";
-       } else {
-               cpu_name = "OMAP3503";
-       }
-
-       /* Print verbose information */
-       pr_info("%s ES%s (", cpu_name, cpu_rev);
-
-       OMAP3_SHOW_FEATURE(l2cache);
-       OMAP3_SHOW_FEATURE(iva);
-       OMAP3_SHOW_FEATURE(sgx);
-       OMAP3_SHOW_FEATURE(neon);
-       OMAP3_SHOW_FEATURE(isp);
-       OMAP3_SHOW_FEATURE(192mhz_clk);
-
-       printk(")\n");
-}
-
-/*
- * Try to detect the exact revision of the omap we're running on
- */
-void __init omap2_check_revision(void)
-{
-       const char *cpu_rev;
-
-       /*
-        * At this point we have an idea about the processor revision set
-        * earlier with omap2_set_globals_tap().
-        */
-       if (cpu_is_omap24xx()) {
-               omap24xx_check_revision();
-       } else if (cpu_is_omap34xx()) {
-               omap3_check_revision(&cpu_rev);
-
-               /* TI81XX doesn't have feature register */
-               if (!cpu_is_ti81xx())
-                       omap3_check_features();
-               else
-                       ti81xx_check_features();
-
-               omap3_cpuinfo(cpu_rev);
-               return;
-       } else if (cpu_is_omap44xx()) {
-               omap4_check_revision();
-               omap4_check_features();
-               return;
-       } else {
-               pr_err("OMAP revision unknown, please fix!\n");
-       }
-}
-
 /*
  * Set up things for map_io and processor detection later on. Gets called
  * pretty much first thing from board init. For multi-omap, this gets
diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 56964a0..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for OMAP-based platforms
- *
- * Copyright (C) 2009 Texas Instruments
- * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index fd78f31..b8758c8 100644 (file)
@@ -1,5 +1,49 @@
 /*
  * arch/arm/mach-omap2/include/mach/io.h
+ *
+ * IO definitions for TI OMAP processors and boards
+ *
+ * Copied from arch/arm/mach-sa1100/include/mach/io.h
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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.
+ *
+ * Modifications:
+ *  06-12-1997 RMK     Created.
+ *  07-04-1999 RMK     Major cleanup
  */
 
-#include <plat/io.h>
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We don't actually have real ISA nor PCI buses, but there is so many
+ * drivers out there that might just work if we fake them...
+ */
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
+
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/system.h b/arch/arm/mach-omap2/include/mach/system.h
deleted file mode 100644 (file)
index d488721..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
- * arch/arm/mach-omap2/include/mach/system.h
- */
-
-#include <plat/system.h>
index e501b49..065bd76 100644 (file)
 #include <linux/clk.h>
 
 #include <asm/tlb.h>
-
 #include <asm/mach/map.h>
 
 #include <plat/sram.h>
 #include <plat/sdrc.h>
 #include <plat/serial.h>
-
-#include "clock2xxx.h"
-#include "clock3xxx.h"
-#include "clock44xx.h"
-
-#include "common.h"
 #include <plat/omap-pm.h>
+#include <plat/omap_hwmod.h>
+#include <plat/multi.h>
+
+#include "iomap.h"
 #include "voltage.h"
 #include "powerdomain.h"
-
 #include "clockdomain.h"
-#include <plat/omap_hwmod.h>
-#include <plat/multi.h>
 #include "common.h"
+#include "clock2xxx.h"
+#include "clock3xxx.h"
+#include "clock44xx.h"
 
 /*
  * The machine specific code may provide the extra mapping besides the
  * default mapping provided here.
  */
 
-#ifdef CONFIG_ARCH_OMAP2
+#if defined(CONFIG_SOC_OMAP2420) || defined(CONFIG_SOC_OMAP2430)
 static struct map_desc omap24xx_io_desc[] __initdata = {
        {
                .virtual        = L3_24XX_VIRT,
@@ -351,7 +348,6 @@ static int _set_hwmod_postsetup_state(struct omap_hwmod *oh, void *data)
 
 static void __init omap_common_init_early(void)
 {
-       omap2_check_revision();
        omap_init_consistent_dma_size();
 }
 
@@ -392,6 +388,7 @@ static void __init omap_hwmod_init_postsetup(void)
 void __init omap2420_init_early(void)
 {
        omap2_set_globals_242x();
+       omap2xxx_check_revision();
        omap_common_init_early();
        omap2xxx_voltagedomains_init();
        omap242x_powerdomains_init();
@@ -406,6 +403,7 @@ void __init omap2420_init_early(void)
 void __init omap2430_init_early(void)
 {
        omap2_set_globals_243x();
+       omap2xxx_check_revision();
        omap_common_init_early();
        omap2xxx_voltagedomains_init();
        omap243x_powerdomains_init();
@@ -424,6 +422,8 @@ void __init omap2430_init_early(void)
 void __init omap3_init_early(void)
 {
        omap2_set_globals_3xxx();
+       omap3xxx_check_revision();
+       omap3xxx_check_features();
        omap_common_init_early();
        omap3xxx_voltagedomains_init();
        omap3xxx_powerdomains_init();
@@ -456,6 +456,8 @@ void __init am35xx_init_early(void)
 void __init ti81xx_init_early(void)
 {
        omap2_set_globals_ti81xx();
+       omap3xxx_check_revision();
+       ti81xx_check_features();
        omap_common_init_early();
        omap3xxx_voltagedomains_init();
        omap3xxx_powerdomains_init();
@@ -470,6 +472,8 @@ void __init ti81xx_init_early(void)
 void __init omap4430_init_early(void)
 {
        omap2_set_globals_443x();
+       omap4xxx_check_revision();
+       omap4xxx_check_features();
        omap_common_init_early();
        omap44xx_voltagedomains_init();
        omap44xx_powerdomains_init();
@@ -490,43 +494,3 @@ void __init omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
                _omap2_init_reprogram_sdrc();
        }
 }
-
-/*
- * NOTE: Please use ioremap + __raw_read/write where possible instead of these
- */
-
-u8 omap_readb(u32 pa)
-{
-       return __raw_readb(OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_readb);
-
-u16 omap_readw(u32 pa)
-{
-       return __raw_readw(OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_readw);
-
-u32 omap_readl(u32 pa)
-{
-       return __raw_readl(OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_readl);
-
-void omap_writeb(u8 v, u32 pa)
-{
-       __raw_writeb(v, OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_writeb);
-
-void omap_writew(u16 v, u32 pa)
-{
-       __raw_writew(v, OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_writew);
-
-void omap_writel(u32 v, u32 pa)
-{
-       __raw_writel(v, OMAP2_L4_IO_ADDRESS(pa));
-}
-EXPORT_SYMBOL(omap_writel);
diff --git a/arch/arm/mach-omap2/iomap.h b/arch/arm/mach-omap2/iomap.h
new file mode 100644 (file)
index 0000000..e6f9581
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * IO mappings for OMAP2+
+ *
+ * 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.
+ */
+
+#ifdef __ASSEMBLER__
+#define IOMEM(x)               (x)
+#else
+#define IOMEM(x)               ((void __force __iomem *)(x))
+#endif
+
+#define OMAP2_L3_IO_OFFSET     0x90000000
+#define OMAP2_L3_IO_ADDRESS(pa)        IOMEM((pa) + OMAP2_L3_IO_OFFSET) /* L3 */
+
+#define OMAP2_L4_IO_OFFSET     0xb2000000
+#define OMAP2_L4_IO_ADDRESS(pa)        IOMEM((pa) + OMAP2_L4_IO_OFFSET) /* L4 */
+
+#define OMAP4_L3_IO_OFFSET     0xb4000000
+#define OMAP4_L3_IO_ADDRESS(pa)        IOMEM((pa) + OMAP4_L3_IO_OFFSET) /* L3 */
+
+#define AM33XX_L4_WK_IO_OFFSET 0xb5000000
+#define AM33XX_L4_WK_IO_ADDRESS(pa)    IOMEM((pa) + AM33XX_L4_WK_IO_OFFSET)
+
+#define OMAP4_L3_PER_IO_OFFSET 0xb1100000
+#define OMAP4_L3_PER_IO_ADDRESS(pa)    IOMEM((pa) + OMAP4_L3_PER_IO_OFFSET)
+
+#define OMAP4_GPMC_IO_OFFSET           0xa9000000
+#define OMAP4_GPMC_IO_ADDRESS(pa)      IOMEM((pa) + OMAP4_GPMC_IO_OFFSET)
+
+#define OMAP2_EMU_IO_OFFSET            0xaa800000      /* Emulation */
+#define OMAP2_EMU_IO_ADDRESS(pa)       IOMEM((pa) + OMAP2_EMU_IO_OFFSET)
+
+/*
+ * ----------------------------------------------------------------------------
+ * Omap2 specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+
+/* We map both L3 and L4 on OMAP2 */
+#define L3_24XX_PHYS   L3_24XX_BASE    /* 0x68000000 --> 0xf8000000*/
+#define L3_24XX_VIRT   (L3_24XX_PHYS + OMAP2_L3_IO_OFFSET)
+#define L3_24XX_SIZE   SZ_1M           /* 44kB of 128MB used, want 1MB sect */
+#define L4_24XX_PHYS   L4_24XX_BASE    /* 0x48000000 --> 0xfa000000 */
+#define L4_24XX_VIRT   (L4_24XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_24XX_SIZE   SZ_1M           /* 1MB of 128MB used, want 1MB sect */
+
+#define L4_WK_243X_PHYS                L4_WK_243X_BASE /* 0x49000000 --> 0xfb000000 */
+#define L4_WK_243X_VIRT                (L4_WK_243X_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_WK_243X_SIZE                SZ_1M
+#define OMAP243X_GPMC_PHYS     OMAP243X_GPMC_BASE
+#define OMAP243X_GPMC_VIRT     (OMAP243X_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
+                                               /* 0x6e000000 --> 0xfe000000 */
+#define OMAP243X_GPMC_SIZE     SZ_1M
+#define OMAP243X_SDRC_PHYS     OMAP243X_SDRC_BASE
+                                               /* 0x6D000000 --> 0xfd000000 */
+#define OMAP243X_SDRC_VIRT     (OMAP243X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
+#define OMAP243X_SDRC_SIZE     SZ_1M
+#define OMAP243X_SMS_PHYS      OMAP243X_SMS_BASE
+                                               /* 0x6c000000 --> 0xfc000000 */
+#define OMAP243X_SMS_VIRT      (OMAP243X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
+#define OMAP243X_SMS_SIZE      SZ_1M
+
+/* 2420 IVA */
+#define DSP_MEM_2420_PHYS      OMAP2420_DSP_MEM_BASE
+                                               /* 0x58000000 --> 0xfc100000 */
+#define DSP_MEM_2420_VIRT      0xfc100000
+#define DSP_MEM_2420_SIZE      0x28000
+#define DSP_IPI_2420_PHYS      OMAP2420_DSP_IPI_BASE
+                                               /* 0x59000000 --> 0xfc128000 */
+#define DSP_IPI_2420_VIRT      0xfc128000
+#define DSP_IPI_2420_SIZE      SZ_4K
+#define DSP_MMU_2420_PHYS      OMAP2420_DSP_MMU_BASE
+                                               /* 0x5a000000 --> 0xfc129000 */
+#define DSP_MMU_2420_VIRT      0xfc129000
+#define DSP_MMU_2420_SIZE      SZ_4K
+
+/* 2430 IVA2.1 - currently unmapped */
+
+/*
+ * ----------------------------------------------------------------------------
+ * Omap3 specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+
+/* We map both L3 and L4 on OMAP3 */
+#define L3_34XX_PHYS           L3_34XX_BASE    /* 0x68000000 --> 0xf8000000 */
+#define L3_34XX_VIRT           (L3_34XX_PHYS + OMAP2_L3_IO_OFFSET)
+#define L3_34XX_SIZE           SZ_1M   /* 44kB of 128MB used, want 1MB sect */
+
+#define L4_34XX_PHYS           L4_34XX_BASE    /* 0x48000000 --> 0xfa000000 */
+#define L4_34XX_VIRT           (L4_34XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_34XX_SIZE           SZ_4M   /* 1MB of 128MB used, want 1MB sect */
+
+/*
+ * ----------------------------------------------------------------------------
+ * AM33XX specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+#define L4_WK_AM33XX_PHYS      L4_WK_AM33XX_BASE
+#define L4_WK_AM33XX_VIRT      (L4_WK_AM33XX_PHYS + AM33XX_L4_WK_IO_OFFSET)
+#define L4_WK_AM33XX_SIZE      SZ_4M   /* 1MB of 128MB used, want 1MB sect */
+
+/*
+ * Need to look at the Size 4M for L4.
+ * VPOM3430 was not working for Int controller
+ */
+
+#define L4_PER_34XX_PHYS       L4_PER_34XX_BASE
+                                               /* 0x49000000 --> 0xfb000000 */
+#define L4_PER_34XX_VIRT       (L4_PER_34XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_PER_34XX_SIZE       SZ_1M
+
+#define L4_EMU_34XX_PHYS       L4_EMU_34XX_BASE
+                                               /* 0x54000000 --> 0xfe800000 */
+#define L4_EMU_34XX_VIRT       (L4_EMU_34XX_PHYS + OMAP2_EMU_IO_OFFSET)
+#define L4_EMU_34XX_SIZE       SZ_8M
+
+#define OMAP34XX_GPMC_PHYS     OMAP34XX_GPMC_BASE
+                                               /* 0x6e000000 --> 0xfe000000 */
+#define OMAP34XX_GPMC_VIRT     (OMAP34XX_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
+#define OMAP34XX_GPMC_SIZE     SZ_1M
+
+#define OMAP343X_SMS_PHYS      OMAP343X_SMS_BASE
+                                               /* 0x6c000000 --> 0xfc000000 */
+#define OMAP343X_SMS_VIRT      (OMAP343X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
+#define OMAP343X_SMS_SIZE      SZ_1M
+
+#define OMAP343X_SDRC_PHYS     OMAP343X_SDRC_BASE
+                                               /* 0x6D000000 --> 0xfd000000 */
+#define OMAP343X_SDRC_VIRT     (OMAP343X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
+#define OMAP343X_SDRC_SIZE     SZ_1M
+
+/* 3430 IVA - currently unmapped */
+
+/*
+ * ----------------------------------------------------------------------------
+ * Omap4 specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+
+/* We map both L3 and L4 on OMAP4 */
+#define L3_44XX_PHYS           L3_44XX_BASE    /* 0x44000000 --> 0xf8000000 */
+#define L3_44XX_VIRT           (L3_44XX_PHYS + OMAP4_L3_IO_OFFSET)
+#define L3_44XX_SIZE           SZ_1M
+
+#define L4_44XX_PHYS           L4_44XX_BASE    /* 0x4a000000 --> 0xfc000000 */
+#define L4_44XX_VIRT           (L4_44XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_44XX_SIZE           SZ_4M
+
+#define L4_PER_44XX_PHYS       L4_PER_44XX_BASE
+                                               /* 0x48000000 --> 0xfa000000 */
+#define L4_PER_44XX_VIRT       (L4_PER_44XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_PER_44XX_SIZE       SZ_4M
+
+#define L4_ABE_44XX_PHYS       L4_ABE_44XX_BASE
+                                               /* 0x49000000 --> 0xfb000000 */
+#define L4_ABE_44XX_VIRT       (L4_ABE_44XX_PHYS + OMAP2_L4_IO_OFFSET)
+#define L4_ABE_44XX_SIZE       SZ_1M
+
+#define L4_EMU_44XX_PHYS       L4_EMU_44XX_BASE
+                                               /* 0x54000000 --> 0xfe800000 */
+#define L4_EMU_44XX_VIRT       (L4_EMU_44XX_PHYS + OMAP2_EMU_IO_OFFSET)
+#define L4_EMU_44XX_SIZE       SZ_8M
+
+#define OMAP44XX_GPMC_PHYS     OMAP44XX_GPMC_BASE
+                                               /* 0x50000000 --> 0xf9000000 */
+#define OMAP44XX_GPMC_VIRT     (OMAP44XX_GPMC_PHYS + OMAP4_GPMC_IO_OFFSET)
+#define OMAP44XX_GPMC_SIZE     SZ_1M
+
+
+#define OMAP44XX_EMIF1_PHYS    OMAP44XX_EMIF1_BASE
+                                               /* 0x4c000000 --> 0xfd100000 */
+#define OMAP44XX_EMIF1_VIRT    (OMAP44XX_EMIF1_PHYS + OMAP4_L3_PER_IO_OFFSET)
+#define OMAP44XX_EMIF1_SIZE    SZ_1M
+
+#define OMAP44XX_EMIF2_PHYS    OMAP44XX_EMIF2_BASE
+                                               /* 0x4d000000 --> 0xfd200000 */
+#define OMAP44XX_EMIF2_SIZE    SZ_1M
+#define OMAP44XX_EMIF2_VIRT    (OMAP44XX_EMIF1_VIRT + OMAP44XX_EMIF1_SIZE)
+
+#define OMAP44XX_DMM_PHYS      OMAP44XX_DMM_BASE
+                                               /* 0x4e000000 --> 0xfd300000 */
+#define OMAP44XX_DMM_SIZE      SZ_1M
+#define OMAP44XX_DMM_VIRT      (OMAP44XX_EMIF2_VIRT + OMAP44XX_EMIF2_SIZE)
index 1fef061..65f0d25 100644 (file)
  * for more details.
  */
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <mach/hardware.h>
+
 #include <asm/exception.h>
 #include <asm/mach/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 
+#include <mach/hardware.h>
+
+#include "iomap.h"
 
 /* selected INTC register offsets */
 
@@ -57,6 +64,8 @@ static struct omap_irq_bank {
        },
 };
 
+static struct irq_domain *domain;
+
 /* Structure to save interrupt controller context */
 struct omap3_intc_regs {
        u32 sysconfig;
@@ -147,17 +156,27 @@ omap_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
                                IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 }
 
-static void __init omap_init_irq(u32 base, int nr_irqs)
+static void __init omap_init_irq(u32 base, int nr_irqs,
+                                struct device_node *node)
 {
        void __iomem *omap_irq_base;
        unsigned long nr_of_irqs = 0;
        unsigned int nr_banks = 0;
-       int i, j;
+       int i, j, irq_base;
 
        omap_irq_base = ioremap(base, SZ_4K);
        if (WARN_ON(!omap_irq_base))
                return;
 
+       irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+       if (irq_base < 0) {
+               pr_warn("Couldn't allocate IRQ numbers\n");
+               irq_base = 0;
+       }
+
+       domain = irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+                                      &irq_domain_simple_ops, NULL);
+
        for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
                struct omap_irq_bank *bank = irq_banks + i;
 
@@ -166,36 +185,36 @@ static void __init omap_init_irq(u32 base, int nr_irqs)
                /* Static mapping, never released */
                bank->base_reg = ioremap(base, SZ_4K);
                if (!bank->base_reg) {
-                       printk(KERN_ERR "Could not ioremap irq bank%i\n", i);
+                       pr_err("Could not ioremap irq bank%i\n", i);
                        continue;
                }
 
                omap_irq_bank_init_one(bank);
 
                for (j = 0; j < bank->nr_irqs; j += 32)
-                       omap_alloc_gc(bank->base_reg + j, j, 32);
+                       omap_alloc_gc(bank->base_reg + j, j + irq_base, 32);
 
                nr_of_irqs += bank->nr_irqs;
                nr_banks++;
        }
 
-       printk(KERN_INFO "Total of %ld interrupts on %d active controller%s\n",
-              nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : "");
+       pr_info("Total of %ld interrupts on %d active controller%s\n",
+               nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : "");
 }
 
 void __init omap2_init_irq(void)
 {
-       omap_init_irq(OMAP24XX_IC_BASE, 96);
+       omap_init_irq(OMAP24XX_IC_BASE, 96, NULL);
 }
 
 void __init omap3_init_irq(void)
 {
-       omap_init_irq(OMAP34XX_IC_BASE, 96);
+       omap_init_irq(OMAP34XX_IC_BASE, 96, NULL);
 }
 
 void __init ti81xx_init_irq(void)
 {
-       omap_init_irq(OMAP34XX_IC_BASE, 128);
+       omap_init_irq(OMAP34XX_IC_BASE, 128, NULL);
 }
 
 static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs *regs)
@@ -225,8 +244,10 @@ out:
                irqnr = readl_relaxed(base_addr + INTCPS_SIR_IRQ_OFFSET);
                irqnr &= ACTIVEIRQ_MASK;
 
-               if (irqnr)
+               if (irqnr) {
+                       irqnr = irq_find_mapping(domain, irqnr);
                        handle_IRQ(irqnr, regs);
+               }
        } while (irqnr);
 }
 
@@ -236,6 +257,28 @@ asmlinkage void __exception_irq_entry omap2_intc_handle_irq(struct pt_regs *regs
        omap_intc_handle_irq(base_addr, regs);
 }
 
+int __init omap_intc_of_init(struct device_node *node,
+                            struct device_node *parent)
+{
+       struct resource res;
+       u32 nr_irqs = 96;
+
+       if (WARN_ON(!node))
+               return -ENODEV;
+
+       if (of_address_to_resource(node, 0, &res)) {
+               WARN(1, "unable to get intc registers\n");
+               return -EINVAL;
+       }
+
+       if (of_property_read_u32(node, "ti,intc-size", &nr_irqs))
+               pr_warn("unable to get intc-size, default to %d\n", nr_irqs);
+
+       omap_init_irq(res.start, nr_irqs, of_node_get(node));
+
+       return 0;
+}
+
 #ifdef CONFIG_ARCH_OMAP3
 static struct omap3_intc_regs intc_context[ARRAY_SIZE(irq_banks)];
 
index ecc039e..577cb77 100644 (file)
@@ -158,7 +158,7 @@ static int omap3_enable_st_clock(unsigned int id, bool enable)
        return 0;
 }
 
-static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
+static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
 {
        int id, count = 1;
        char *name = "omap-mcbsp";
index e974d33..65c3391 100644 (file)
@@ -99,8 +99,8 @@ void omap_mux_write_array(struct omap_mux_partition *partition,
 
 static char *omap_mux_options;
 
-static int _omap_mux_init_gpio(struct omap_mux_partition *partition,
-                              int gpio, int val)
+static int __init _omap_mux_init_gpio(struct omap_mux_partition *partition,
+                                     int gpio, int val)
 {
        struct omap_mux_entry *e;
        struct omap_mux *gpio_mux = NULL;
@@ -144,7 +144,7 @@ static int _omap_mux_init_gpio(struct omap_mux_partition *partition,
        return 0;
 }
 
-int omap_mux_init_gpio(int gpio, int val)
+int __init omap_mux_init_gpio(int gpio, int val)
 {
        struct omap_mux_partition *partition;
        int ret;
@@ -158,9 +158,9 @@ int omap_mux_init_gpio(int gpio, int val)
        return -ENODEV;
 }
 
-static int _omap_mux_get_by_name(struct omap_mux_partition *partition,
-                                const char *muxname,
-                                struct omap_mux **found_mux)
+static int __init _omap_mux_get_by_name(struct omap_mux_partition *partition,
+                                       const char *muxname,
+                                       struct omap_mux **found_mux)
 {
        struct omap_mux *mux = NULL;
        struct omap_mux_entry *e;
@@ -217,7 +217,7 @@ static int _omap_mux_get_by_name(struct omap_mux_partition *partition,
        return -ENODEV;
 }
 
-static int
+static int __init
 omap_mux_get_by_name(const char *muxname,
                        struct omap_mux_partition **found_partition,
                        struct omap_mux **found_mux)
@@ -239,7 +239,7 @@ omap_mux_get_by_name(const char *muxname,
        return -ENODEV;
 }
 
-int omap_mux_init_signal(const char *muxname, int val)
+int __init omap_mux_init_signal(const char *muxname, int val)
 {
        struct omap_mux_partition *partition = NULL;
        struct omap_mux *mux = NULL;
index 2132308..69fe060 100644 (file)
@@ -246,7 +246,7 @@ static inline void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
 {
 }
 
-static struct omap_board_mux *board_mux __initdata __maybe_unused;
+static struct omap_board_mux *board_mux __maybe_unused;
 
 #endif
 
index adbe4d8..56c345b 100644 (file)
@@ -33,7 +33,7 @@ int platform_cpu_kill(unsigned int cpu)
  * platform-specific code to shutdown a CPU
  * Called with IRQs disabled
  */
-void platform_cpu_die(unsigned int cpu)
+void __ref platform_cpu_die(unsigned int cpu)
 {
        unsigned int this_cpu;
 
index 069f8fc..13670aa 100644 (file)
@@ -262,12 +262,10 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
         * In MPUSS OSWR or device OFF, interrupt controller  contest is lost.
         */
        mpuss_clear_prev_logic_pwrst();
-       pwrdm_clear_all_prev_pwrst(mpuss_pd);
        if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
                (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
                save_state = 2;
 
-       clear_cpu_prev_pwrst(cpu);
        cpu_clear_prev_logic_pwrst(cpu);
        set_cpu_next_pwrst(cpu, power_state);
        set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume));
@@ -299,7 +297,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
  * @cpu : CPU ID
  * @power_state: CPU low power state.
  */
-int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
+int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
 {
        unsigned int cpu_state = 0;
 
index c1bf3ef..deffbf1 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/hardware/gic.h>
 #include <asm/smp_scu.h>
+
 #include <mach/hardware.h>
 #include <mach/omap-secure.h>
 
+#include "iomap.h"
 #include "common.h"
-
 #include "clockdomain.h"
 
 /* SCU base address */
index d3d8971..42cd7fb 100644 (file)
@@ -43,7 +43,6 @@
 
 static void __iomem *wakeupgen_base;
 static void __iomem *sar_base;
-static DEFINE_PER_CPU(u32 [NR_REG_BANKS], irqmasks);
 static DEFINE_SPINLOCK(wakeupgen_lock);
 static unsigned int irq_target_cpu[NR_IRQS];
 
@@ -67,14 +66,6 @@ static inline void sar_writel(u32 val, u32 offset, u8 idx)
        __raw_writel(val, sar_base + offset + (idx * 4));
 }
 
-static void _wakeupgen_set_all(unsigned int cpu, unsigned int reg)
-{
-       u8 i;
-
-       for (i = 0; i < NR_REG_BANKS; i++)
-               wakeupgen_writel(reg, i, cpu);
-}
-
 static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index)
 {
        unsigned int spi_irq;
@@ -130,22 +121,6 @@ static void _wakeupgen_set(unsigned int irq, unsigned int cpu)
        wakeupgen_writel(val, i, cpu);
 }
 
-static void _wakeupgen_save_masks(unsigned int cpu)
-{
-       u8 i;
-
-       for (i = 0; i < NR_REG_BANKS; i++)
-               per_cpu(irqmasks, cpu)[i] = wakeupgen_readl(i, cpu);
-}
-
-static void _wakeupgen_restore_masks(unsigned int cpu)
-{
-       u8 i;
-
-       for (i = 0; i < NR_REG_BANKS; i++)
-               wakeupgen_writel(per_cpu(irqmasks, cpu)[i], i, cpu);
-}
-
 /*
  * Architecture specific Mask extension
  */
@@ -170,6 +145,33 @@ static void wakeupgen_unmask(struct irq_data *d)
        spin_unlock_irqrestore(&wakeupgen_lock, flags);
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static DEFINE_PER_CPU(u32 [NR_REG_BANKS], irqmasks);
+
+static void _wakeupgen_save_masks(unsigned int cpu)
+{
+       u8 i;
+
+       for (i = 0; i < NR_REG_BANKS; i++)
+               per_cpu(irqmasks, cpu)[i] = wakeupgen_readl(i, cpu);
+}
+
+static void _wakeupgen_restore_masks(unsigned int cpu)
+{
+       u8 i;
+
+       for (i = 0; i < NR_REG_BANKS; i++)
+               wakeupgen_writel(per_cpu(irqmasks, cpu)[i], i, cpu);
+}
+
+static void _wakeupgen_set_all(unsigned int cpu, unsigned int reg)
+{
+       u8 i;
+
+       for (i = 0; i < NR_REG_BANKS; i++)
+               wakeupgen_writel(reg, i, cpu);
+}
+
 /*
  * Mask or unmask all interrupts on given CPU.
  *     0 = Mask all interrupts on the 'cpu'
@@ -191,6 +193,7 @@ static void wakeupgen_irqmask_all(unsigned int cpu, unsigned int set)
        }
        spin_unlock_irqrestore(&wakeupgen_lock, flags);
 }
+#endif
 
 #ifdef CONFIG_CPU_PM
 /*
index 3c8dd92..34b9766 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "omap_hwmod_common_data.h"
 
+#include "smartreflex.h"
 #include "prm-regbits-34xx.h"
 #include "cm-regbits-34xx.h"
 #include "wd_timer.h"
@@ -376,6 +377,16 @@ static struct omap_hwmod_ocp_if omap3_l4_core__i2c3 = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = {
+       { .irq = 18},
+       { .irq = -1 }
+};
+
+static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = {
+       { .irq = 19},
+       { .irq = -1 }
+};
+
 /* L4 CORE -> SR1 interface */
 static struct omap_hwmod_addr_space omap3_sr1_addr_space[] = {
        {
@@ -2664,6 +2675,10 @@ static struct omap_hwmod_class omap36xx_smartreflex_hwmod_class = {
 };
 
 /* SR1 */
+static struct omap_smartreflex_dev_attr sr1_dev_attr = {
+       .sensor_voltdm_name   = "mpu_iva",
+};
+
 static struct omap_hwmod_ocp_if *omap3_sr1_slaves[] = {
        &omap3_l4_core__sr1,
 };
@@ -2672,7 +2687,6 @@ static struct omap_hwmod omap34xx_sr1_hwmod = {
        .name           = "sr1_hwmod",
        .class          = &omap34xx_smartreflex_hwmod_class,
        .main_clk       = "sr1_fck",
-       .vdd_name       = "mpu_iva",
        .prcm           = {
                .omap2 = {
                        .prcm_reg_id = 1,
@@ -2684,6 +2698,8 @@ static struct omap_hwmod omap34xx_sr1_hwmod = {
        },
        .slaves         = omap3_sr1_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3_sr1_slaves),
+       .dev_attr       = &sr1_dev_attr,
+       .mpu_irqs       = omap3_smartreflex_mpu_irqs,
        .flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
@@ -2691,7 +2707,6 @@ static struct omap_hwmod omap36xx_sr1_hwmod = {
        .name           = "sr1_hwmod",
        .class          = &omap36xx_smartreflex_hwmod_class,
        .main_clk       = "sr1_fck",
-       .vdd_name       = "mpu_iva",
        .prcm           = {
                .omap2 = {
                        .prcm_reg_id = 1,
@@ -2703,9 +2718,15 @@ static struct omap_hwmod omap36xx_sr1_hwmod = {
        },
        .slaves         = omap3_sr1_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3_sr1_slaves),
+       .dev_attr       = &sr1_dev_attr,
+       .mpu_irqs       = omap3_smartreflex_mpu_irqs,
 };
 
 /* SR2 */
+static struct omap_smartreflex_dev_attr sr2_dev_attr = {
+       .sensor_voltdm_name     = "core",
+};
+
 static struct omap_hwmod_ocp_if *omap3_sr2_slaves[] = {
        &omap3_l4_core__sr2,
 };
@@ -2714,7 +2735,6 @@ static struct omap_hwmod omap34xx_sr2_hwmod = {
        .name           = "sr2_hwmod",
        .class          = &omap34xx_smartreflex_hwmod_class,
        .main_clk       = "sr2_fck",
-       .vdd_name       = "core",
        .prcm           = {
                .omap2 = {
                        .prcm_reg_id = 1,
@@ -2726,6 +2746,8 @@ static struct omap_hwmod omap34xx_sr2_hwmod = {
        },
        .slaves         = omap3_sr2_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3_sr2_slaves),
+       .dev_attr       = &sr2_dev_attr,
+       .mpu_irqs       = omap3_smartreflex_core_irqs,
        .flags          = HWMOD_SET_DEFAULT_CLOCKACT,
 };
 
@@ -2733,7 +2755,6 @@ static struct omap_hwmod omap36xx_sr2_hwmod = {
        .name           = "sr2_hwmod",
        .class          = &omap36xx_smartreflex_hwmod_class,
        .main_clk       = "sr2_fck",
-       .vdd_name       = "core",
        .prcm           = {
                .omap2 = {
                        .prcm_reg_id = 1,
@@ -2745,6 +2766,8 @@ static struct omap_hwmod omap36xx_sr2_hwmod = {
        },
        .slaves         = omap3_sr2_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap3_sr2_slaves),
+       .dev_attr       = &sr2_dev_attr,
+       .mpu_irqs       = omap3_smartreflex_core_irqs,
 };
 
 /*
index ef0524c..08daa5e 100644 (file)
 #include <plat/mcspi.h>
 #include <plat/mcbsp.h>
 #include <plat/mmc.h>
-#include <plat/i2c.h>
 #include <plat/dmtimer.h>
 #include <plat/common.h>
 
 #include "omap_hwmod_common_data.h"
 
+#include "smartreflex.h"
 #include "cm1_44xx.h"
 #include "cm2_44xx.h"
 #include "prm44xx.h"
@@ -3963,6 +3963,10 @@ static struct omap_hwmod_class omap44xx_smartreflex_hwmod_class = {
 };
 
 /* smartreflex_core */
+static struct omap_smartreflex_dev_attr smartreflex_core_dev_attr = {
+       .sensor_voltdm_name   = "core",
+};
+
 static struct omap_hwmod omap44xx_smartreflex_core_hwmod;
 static struct omap_hwmod_irq_info omap44xx_smartreflex_core_irqs[] = {
        { .irq = 19 + OMAP44XX_IRQ_GIC_START },
@@ -3999,7 +4003,6 @@ static struct omap_hwmod omap44xx_smartreflex_core_hwmod = {
        .mpu_irqs       = omap44xx_smartreflex_core_irqs,
 
        .main_clk       = "smartreflex_core_fck",
-       .vdd_name       = "core",
        .prcm = {
                .omap4 = {
                        .clkctrl_offs = OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET,
@@ -4009,9 +4012,14 @@ static struct omap_hwmod omap44xx_smartreflex_core_hwmod = {
        },
        .slaves         = omap44xx_smartreflex_core_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_smartreflex_core_slaves),
+       .dev_attr       = &smartreflex_core_dev_attr,
 };
 
 /* smartreflex_iva */
+static struct omap_smartreflex_dev_attr smartreflex_iva_dev_attr = {
+       .sensor_voltdm_name     = "iva",
+};
+
 static struct omap_hwmod omap44xx_smartreflex_iva_hwmod;
 static struct omap_hwmod_irq_info omap44xx_smartreflex_iva_irqs[] = {
        { .irq = 102 + OMAP44XX_IRQ_GIC_START },
@@ -4047,7 +4055,6 @@ static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = {
        .clkdm_name     = "l4_ao_clkdm",
        .mpu_irqs       = omap44xx_smartreflex_iva_irqs,
        .main_clk       = "smartreflex_iva_fck",
-       .vdd_name       = "iva",
        .prcm = {
                .omap4 = {
                        .clkctrl_offs = OMAP4_CM_ALWON_SR_IVA_CLKCTRL_OFFSET,
@@ -4057,9 +4064,14 @@ static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = {
        },
        .slaves         = omap44xx_smartreflex_iva_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_smartreflex_iva_slaves),
+       .dev_attr       = &smartreflex_iva_dev_attr,
 };
 
 /* smartreflex_mpu */
+static struct omap_smartreflex_dev_attr smartreflex_mpu_dev_attr = {
+       .sensor_voltdm_name     = "mpu",
+};
+
 static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod;
 static struct omap_hwmod_irq_info omap44xx_smartreflex_mpu_irqs[] = {
        { .irq = 18 + OMAP44XX_IRQ_GIC_START },
@@ -4095,7 +4107,6 @@ static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = {
        .clkdm_name     = "l4_ao_clkdm",
        .mpu_irqs       = omap44xx_smartreflex_mpu_irqs,
        .main_clk       = "smartreflex_mpu_fck",
-       .vdd_name       = "mpu",
        .prcm = {
                .omap4 = {
                        .clkctrl_offs = OMAP4_CM_ALWON_SR_MPU_CLKCTRL_OFFSET,
@@ -4105,6 +4116,7 @@ static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = {
        },
        .slaves         = omap44xx_smartreflex_mpu_slaves,
        .slaves_cnt     = ARRAY_SIZE(omap44xx_smartreflex_mpu_slaves),
+       .dev_attr       = &smartreflex_mpu_dev_attr,
 };
 
 /*
index e6dda69..5037e76 100644 (file)
@@ -28,6 +28,8 @@
  *     http://repository.maemo.org/pool/diablo/free/k/kernel-source-diablo/
  */
 
+#include <plat/hardware.h>
+
 #include "opp2xxx.h"
 #include "sdrc.h"
 #include "clock.h"
index 1b9596a..750805c 100644 (file)
@@ -26,6 +26,8 @@
  * This is technically part of the OMAP2xxx clock code.
  */
 
+#include <plat/hardware.h>
+
 #include "opp2xxx.h"
 #include "sdrc.h"
 #include "clock.h"
index 4411163..814bcd9 100644 (file)
@@ -220,8 +220,8 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
                return 0;
 
        d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir);
-
-       (void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d,
+       if (!(IS_ERR_OR_NULL(d)))
+               (void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d,
                        (void *)pwrdm, &pwrdm_suspend_fops);
 
        return 0;
@@ -264,7 +264,7 @@ static int __init pm_dbg_init(void)
                return 0;
 
        d = debugfs_create_dir("pm_debug", NULL);
-       if (IS_ERR(d))
+       if (IS_ERR_OR_NULL(d))
                return PTR_ERR(d);
 
        (void) debugfs_create_file("count", S_IRUGO,
index 5a65dd0..a7bdec6 100644 (file)
 #include <linux/err.h>
 #include <linux/opp.h>
 #include <linux/export.h>
+#include <linux/suspend.h>
 
 #include <plat/omap-pm.h>
 #include <plat/omap_device.h>
 #include "common.h"
 
+#include "prcm-common.h"
 #include "voltage.h"
 #include "powerdomain.h"
 #include "clockdomain.h"
 
 static struct omap_device_pm_latency *pm_lats;
 
-static int _init_omap_device(char *name)
+/*
+ * omap_pm_suspend: points to a function that does the SoC-specific
+ * suspend work
+ */
+int (*omap_pm_suspend)(void);
+
+static int __init _init_omap_device(char *name)
 {
        struct omap_hwmod *oh;
        struct platform_device *pdev;
@@ -49,7 +57,7 @@ static int _init_omap_device(char *name)
 /*
  * Build omap_devices for processors and bus.
  */
-static void omap2_init_processor_devices(void)
+static void __init omap2_init_processor_devices(void)
 {
        _init_omap_device("mpu");
        if (omap3_has_iva())
@@ -68,32 +76,41 @@ static void omap2_init_processor_devices(void)
 #define FORCEWAKEUP_SWITCH     0
 #define LOWPOWERSTATE_SWITCH   1
 
+int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
+{
+       if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
+               clkdm_allow_idle(clkdm);
+       else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
+                atomic_read(&clkdm->usecount) == 0)
+               clkdm_sleep(clkdm);
+       return 0;
+}
+
 /*
  * This sets pwrdm state (other than mpu & core. Currently only ON &
  * RET are supported.
  */
-int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
 {
-       u32 cur_state;
-       int sleep_switch = -1;
-       int ret = 0;
-       int hwsup = 0;
+       u8 curr_pwrst, next_pwrst;
+       int sleep_switch = -1, ret = 0, hwsup = 0;
 
-       if (pwrdm == NULL || IS_ERR(pwrdm))
+       if (!pwrdm || IS_ERR(pwrdm))
                return -EINVAL;
 
-       while (!(pwrdm->pwrsts & (1 << state))) {
-               if (state == PWRDM_POWER_OFF)
+       while (!(pwrdm->pwrsts & (1 << pwrst))) {
+               if (pwrst == PWRDM_POWER_OFF)
                        return ret;
-               state--;
+               pwrst--;
        }
 
-       cur_state = pwrdm_read_next_pwrst(pwrdm);
-       if (cur_state == state)
+       next_pwrst = pwrdm_read_next_pwrst(pwrdm);
+       if (next_pwrst == pwrst)
                return ret;
 
-       if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
-               if ((pwrdm_read_pwrst(pwrdm) > state) &&
+       curr_pwrst = pwrdm_read_pwrst(pwrdm);
+       if (curr_pwrst < PWRDM_POWER_ON) {
+               if ((curr_pwrst > pwrst) &&
                        (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
                        sleep_switch = LOWPOWERSTATE_SWITCH;
                } else {
@@ -103,12 +120,10 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
                }
        }
 
-       ret = pwrdm_set_next_pwrst(pwrdm, state);
-       if (ret) {
-               pr_err("%s: unable to set state of powerdomain: %s\n",
+       ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+       if (ret)
+               pr_err("%s: unable to set power state of powerdomain: %s\n",
                       __func__, pwrdm->name);
-               goto err;
-       }
 
        switch (sleep_switch) {
        case FORCEWAKEUP_SWITCH:
@@ -119,16 +134,16 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
                break;
        case LOWPOWERSTATE_SWITCH:
                pwrdm_set_lowpwrstchange(pwrdm);
+               pwrdm_wait_transition(pwrdm);
+               pwrdm_state_switch(pwrdm);
                break;
-       default:
-               return ret;
        }
 
-       pwrdm_state_switch(pwrdm);
-err:
        return ret;
 }
 
+
+
 /*
  * This API is to be called during init to set the various voltage
  * domains to the voltage as per the opp table. Typically we boot up
@@ -199,6 +214,56 @@ exit:
        return -EINVAL;
 }
 
+#ifdef CONFIG_SUSPEND
+static int omap_pm_enter(suspend_state_t suspend_state)
+{
+       int ret = 0;
+
+       if (!omap_pm_suspend)
+               return -ENOENT; /* XXX doublecheck */
+
+       switch (suspend_state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               ret = omap_pm_suspend();
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int omap_pm_begin(suspend_state_t state)
+{
+       disable_hlt();
+       if (cpu_is_omap34xx())
+               omap_prcm_irq_prepare();
+       return 0;
+}
+
+static void omap_pm_end(void)
+{
+       enable_hlt();
+       return;
+}
+
+static void omap_pm_finish(void)
+{
+       if (cpu_is_omap34xx())
+               omap_prcm_irq_complete();
+}
+
+static const struct platform_suspend_ops omap_pm_ops = {
+       .begin          = omap_pm_begin,
+       .end            = omap_pm_end,
+       .enter          = omap_pm_enter,
+       .finish         = omap_pm_finish,
+       .valid          = suspend_valid_only_mem,
+};
+
+#endif /* CONFIG_SUSPEND */
+
 static void __init omap3_init_voltages(void)
 {
        if (!cpu_is_omap34xx())
@@ -230,6 +295,14 @@ postcore_initcall(omap2_common_pm_init);
 
 static int __init omap2_common_pm_late_init(void)
 {
+       /*
+        * In the case of DT, the PMIC and SR initialization will be done using
+        * a completely different mechanism.
+        * Disable this part if a DT blob is available.
+        */
+       if (of_have_populated_dt())
+               return 0;
+
        /* Init the voltage layer */
        omap_pmic_late_init();
        omap_voltage_late_init();
@@ -241,6 +314,10 @@ static int __init omap2_common_pm_late_init(void)
        /* Smartreflex device init */
        omap_devinit_smartreflex();
 
+#ifdef CONFIG_SUSPEND
+       suspend_set_ops(&omap_pm_ops);
+#endif
+
        return 0;
 }
 late_initcall(omap2_common_pm_late_init);
index b737b11..36fa90b 100644 (file)
 extern void *omap3_secure_ram_storage;
 extern void omap3_pm_off_mode_enable(int);
 extern void omap_sram_idle(void);
-extern int omap3_can_sleep(void);
 extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 extern int omap3_idle_init(void);
 extern int omap4_idle_init(void);
+extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused);
+extern int (*omap_pm_suspend)(void);
 
 #if defined(CONFIG_PM_OPP)
 extern int omap3_opp_init(void);
index 730bb00..95442b6 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-#include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/time.h>
 #include <linux/gpio.h>
 #include <asm/mach-types.h>
 #include <asm/system_misc.h>
 
-#include <mach/irqs.h>
 #include <plat/clock.h>
 #include <plat/sram.h>
 #include <plat/dma.h>
 #include <plat/board.h>
 
+#include <mach/irqs.h>
+
 #include "common.h"
 #include "prm2xxx_3xxx.h"
 #include "prm-regbits-24xx.h"
 #include "sdrc.h"
 #include "pm.h"
 #include "control.h"
-
 #include "powerdomain.h"
 #include "clockdomain.h"
 
-#ifdef CONFIG_SUSPEND
-static suspend_state_t suspend_state = PM_SUSPEND_ON;
-static inline bool is_suspending(void)
-{
-       return (suspend_state != PM_SUSPEND_ON);
-}
-#else
-static inline bool is_suspending(void)
-{
-       return false;
-}
-#endif
-
 static void (*omap2_sram_idle)(void);
 static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
                                  void __iomem *sdrc_power);
@@ -86,7 +72,7 @@ static int omap2_fclks_active(void)
        return (f1 | f2) ? 1 : 0;
 }
 
-static void omap2_enter_full_retention(void)
+static int omap2_enter_full_retention(void)
 {
        u32 l;
 
@@ -149,6 +135,8 @@ no_sleep:
 
        /* Mask future PRCM-to-MPU interrupts */
        omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
+
+       return 0;
 }
 
 static int omap2_i2c_active(void)
@@ -227,7 +215,6 @@ static int omap2_can_sleep(void)
 
 static void omap2_pm_idle(void)
 {
-       local_irq_disable();
        local_fiq_disable();
 
        if (!omap2_can_sleep()) {
@@ -244,78 +231,6 @@ static void omap2_pm_idle(void)
 
 out:
        local_fiq_enable();
-       local_irq_enable();
-}
-
-#ifdef CONFIG_SUSPEND
-static int omap2_pm_begin(suspend_state_t state)
-{
-       disable_hlt();
-       suspend_state = state;
-       return 0;
-}
-
-static int omap2_pm_suspend(void)
-{
-       u32 wken_wkup, mir1;
-
-       wken_wkup = omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);
-       wken_wkup &= ~OMAP24XX_EN_GPT1_MASK;
-       omap2_prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
-
-       /* Mask GPT1 */
-       mir1 = omap_readl(0x480fe0a4);
-       omap_writel(1 << 5, 0x480fe0ac);
-
-       omap2_enter_full_retention();
-
-       omap_writel(mir1, 0x480fe0a4);
-       omap2_prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
-
-       return 0;
-}
-
-static int omap2_pm_enter(suspend_state_t state)
-{
-       int ret = 0;
-
-       switch (state) {
-       case PM_SUSPEND_STANDBY:
-       case PM_SUSPEND_MEM:
-               ret = omap2_pm_suspend();
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static void omap2_pm_end(void)
-{
-       suspend_state = PM_SUSPEND_ON;
-       enable_hlt();
-}
-
-static const struct platform_suspend_ops omap_pm_ops = {
-       .begin          = omap2_pm_begin,
-       .enter          = omap2_pm_enter,
-       .end            = omap2_pm_end,
-       .valid          = suspend_valid_only_mem,
-};
-#else
-static const struct platform_suspend_ops __initdata omap_pm_ops;
-#endif /* CONFIG_SUSPEND */
-
-/* XXX This function should be shareable between OMAP2xxx and OMAP3 */
-static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
-{
-       if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
-               clkdm_allow_idle(clkdm);
-       else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
-                atomic_read(&clkdm->usecount) == 0)
-               clkdm_sleep(clkdm);
-       return 0;
 }
 
 static void __init prcm_setup_regs(void)
@@ -359,9 +274,13 @@ static void __init prcm_setup_regs(void)
        clkdm_sleep(gfx_clkdm);
 
        /* Enable hardware-supervised idle for all clkdms */
-       clkdm_for_each(clkdms_setup, NULL);
+       clkdm_for_each(omap_pm_clkdms_setup, NULL);
        clkdm_add_wkdep(mpu_clkdm, wkup_clkdm);
 
+#ifdef CONFIG_SUSPEND
+       omap_pm_suspend = omap2_enter_full_retention;
+#endif
+
        /* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
         * stabilisation */
        omap2_prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
@@ -462,8 +381,7 @@ static int __init omap2_pm_init(void)
                                                    omap24xx_cpu_suspend_sz);
        }
 
-       suspend_set_ops(&omap_pm_ops);
-       pm_idle = omap2_pm_idle;
+       arm_pm_idle = omap2_pm_idle;
 
        return 0;
 }
index 64d95e6..238defc 100644 (file)
 #include "sdrc.h"
 #include "control.h"
 
-#ifdef CONFIG_SUSPEND
-static suspend_state_t suspend_state = PM_SUSPEND_ON;
-#endif
-
 /* pm34xx errata defined in pm.h */
 u16 pm34xx_errata;
 
@@ -76,16 +72,6 @@ static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
 static struct powerdomain *core_pwrdm, *per_pwrdm;
 static struct powerdomain *cam_pwrdm;
 
-static inline void omap3_per_save_context(void)
-{
-       omap_gpio_save_context();
-}
-
-static inline void omap3_per_restore_context(void)
-{
-       omap_gpio_restore_context();
-}
-
 static void omap3_enable_io_chain(void)
 {
        int timeout = 0;
@@ -291,11 +277,6 @@ void omap_sram_idle(void)
        int core_prev_state, per_prev_state;
        u32 sdrc_pwr = 0;
 
-       pwrdm_clear_all_prev_pwrst(mpu_pwrdm);
-       pwrdm_clear_all_prev_pwrst(neon_pwrdm);
-       pwrdm_clear_all_prev_pwrst(core_pwrdm);
-       pwrdm_clear_all_prev_pwrst(per_pwrdm);
-
        mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
        switch (mpu_next_state) {
        case PWRDM_POWER_ON:
@@ -333,8 +314,6 @@ void omap_sram_idle(void)
        if (per_next_state < PWRDM_POWER_ON) {
                per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
                omap2_gpio_prepare_for_idle(per_going_off);
-               if (per_next_state == PWRDM_POWER_OFF)
-                               omap3_per_save_context();
        }
 
        /* CORE */
@@ -400,8 +379,6 @@ void omap_sram_idle(void)
        if (per_next_state < PWRDM_POWER_ON) {
                per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
                omap2_gpio_resume_after_idle();
-               if (per_prev_state == PWRDM_POWER_OFF)
-                       omap3_per_restore_context();
        }
 
        /* Disable IO-PAD and IO-CHAIN wakeup */
@@ -419,10 +396,9 @@ void omap_sram_idle(void)
 
 static void omap3_pm_idle(void)
 {
-       local_irq_disable();
        local_fiq_disable();
 
-       if (omap_irq_pending() || need_resched())
+       if (omap_irq_pending())
                goto out;
 
        trace_power_start(POWER_CSTATE, 1, smp_processor_id());
@@ -435,7 +411,6 @@ static void omap3_pm_idle(void)
 
 out:
        local_fiq_enable();
-       local_irq_enable();
 }
 
 #ifdef CONFIG_SUSPEND
@@ -480,50 +455,6 @@ restore:
        return ret;
 }
 
-static int omap3_pm_enter(suspend_state_t unused)
-{
-       int ret = 0;
-
-       switch (suspend_state) {
-       case PM_SUSPEND_STANDBY:
-       case PM_SUSPEND_MEM:
-               ret = omap3_pm_suspend();
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-/* Hooks to enable / disable UART interrupts during suspend */
-static int omap3_pm_begin(suspend_state_t state)
-{
-       disable_hlt();
-       suspend_state = state;
-       omap_prcm_irq_prepare();
-       return 0;
-}
-
-static void omap3_pm_end(void)
-{
-       suspend_state = PM_SUSPEND_ON;
-       enable_hlt();
-       return;
-}
-
-static void omap3_pm_finish(void)
-{
-       omap_prcm_irq_complete();
-}
-
-static const struct platform_suspend_ops omap_pm_ops = {
-       .begin          = omap3_pm_begin,
-       .end            = omap3_pm_end,
-       .enter          = omap3_pm_enter,
-       .finish         = omap3_pm_finish,
-       .valid          = suspend_valid_only_mem,
-};
 #endif /* CONFIG_SUSPEND */
 
 
@@ -744,21 +675,6 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 }
 
 /*
- * Enable hw supervised mode for all clockdomains if it's
- * supported. Initiate sleep transition for other clockdomains, if
- * they are not used
- */
-static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
-{
-       if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
-               clkdm_allow_idle(clkdm);
-       else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
-                atomic_read(&clkdm->usecount) == 0)
-               clkdm_sleep(clkdm);
-       return 0;
-}
-
-/*
  * Push functions to SRAM
  *
  * The minimum set of functions is pushed to SRAM for execution:
@@ -827,7 +743,7 @@ static int __init omap3_pm_init(void)
                goto err2;
        }
 
-       (void) clkdm_for_each(clkdms_setup, NULL);
+       (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
 
        mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
        if (mpu_pwrdm == NULL) {
@@ -846,10 +762,10 @@ static int __init omap3_pm_init(void)
        core_clkdm = clkdm_lookup("core_clkdm");
 
 #ifdef CONFIG_SUSPEND
-       suspend_set_ops(&omap_pm_ops);
-#endif /* CONFIG_SUSPEND */
+       omap_pm_suspend = omap3_pm_suspend;
+#endif
 
-       pm_idle = omap3_pm_idle;
+       arm_pm_idle = omap3_pm_idle;
        omap3_idle_init();
 
        /*
index a73e325..9ccaadc 100644 (file)
@@ -84,59 +84,8 @@ static int omap4_pm_suspend(void)
 
        return 0;
 }
-
-static int omap4_pm_enter(suspend_state_t suspend_state)
-{
-       int ret = 0;
-
-       switch (suspend_state) {
-       case PM_SUSPEND_STANDBY:
-       case PM_SUSPEND_MEM:
-               ret = omap4_pm_suspend();
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static int omap4_pm_begin(suspend_state_t state)
-{
-       disable_hlt();
-       return 0;
-}
-
-static void omap4_pm_end(void)
-{
-       enable_hlt();
-       return;
-}
-
-static const struct platform_suspend_ops omap_pm_ops = {
-       .begin          = omap4_pm_begin,
-       .end            = omap4_pm_end,
-       .enter          = omap4_pm_enter,
-       .valid          = suspend_valid_only_mem,
-};
 #endif /* CONFIG_SUSPEND */
 
-/*
- * Enable hardware supervised mode for all clockdomains if it's
- * supported. Initiate sleep transition for other clockdomains, if
- * they are not used
- */
-static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
-{
-       if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
-               clkdm_allow_idle(clkdm);
-       else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
-                       atomic_read(&clkdm->usecount) == 0)
-               clkdm_sleep(clkdm);
-       return 0;
-}
-
-
 static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 {
        struct power_state *pwrst;
@@ -174,18 +123,16 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
  * omap_default_idle - OMAP4 default ilde routine.'
  *
  * Implements OMAP4 memory, IO ordering requirements which can't be addressed
- * with default arch_idle() hook. Used by all CPUs with !CONFIG_CPUIDLE and
+ * with default cpu_do_idle() hook. Used by all CPUs with !CONFIG_CPUIDLE and
  * by secondary CPU with CONFIG_CPUIDLE.
  */
 static void omap_default_idle(void)
 {
-       local_irq_disable();
        local_fiq_disable();
 
        omap_do_wfi();
 
        local_fiq_enable();
-       local_irq_enable();
 }
 
 /**
@@ -250,14 +197,14 @@ static int __init omap4_pm_init(void)
                goto err2;
        }
 
-       (void) clkdm_for_each(clkdms_setup, NULL);
+       (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
 
 #ifdef CONFIG_SUSPEND
-       suspend_set_ops(&omap_pm_ops);
-#endif /* CONFIG_SUSPEND */
+       omap_pm_suspend = omap4_pm_suspend;
+#endif
 
-       /* Overwrite the default arch_idle() */
-       pm_idle = omap_default_idle;
+       /* Overwrite the default cpu_do_idle() */
+       arm_pm_idle = omap_default_idle;
 
        omap4_idle_init();
 
index f97afff..c0aeabf 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/bug.h>
 #include "pm.h"
 #include "cm.h"
 #include "cm-regbits-34xx.h"
index 6a17e4c..0f0a9f1 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <linux/bug.h>
 
 #include <plat/prcm.h>
 
index a7880af..601325b 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <linux/bug.h>
 
 #include "powerdomain.h"
 #include <plat/prcm.h>
index 8ef26da..b7ea468 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/bug.h>
 
 #include <plat/cpu.h>
 
index ca669b5..928dbd4 100644 (file)
@@ -15,8 +15,8 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
+#include "iomap.h"
 #include "common.h"
-
 #include "prcm_mpu44xx.h"
 #include "cm-regbits-44xx.h"
 
index a1d6154..eac623c 100644 (file)
 #include <linux/err.h>
 #include <linux/io.h>
 
-#include "common.h"
 #include <plat/cpu.h>
 #include <plat/irqs.h>
 #include <plat/prcm.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "vp.h"
 #include "prm44xx.h"
 #include "prm-regbits-44xx.h"
index 860118a..873b51d 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 
-#include <mach/system.h>
 #include <plat/common.h>
 #include <plat/prcm.h>
 #include <plat/irqs.h>
index f6de5bc..9b3898a 100644 (file)
@@ -16,8 +16,8 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
+#include "iomap.h"
 #include "common.h"
-
 #include "prm44xx.h"
 #include "prminst44xx.h"
 #include "prm-regbits-44xx.h"
index 7479d7e..845c4fd 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/err.h>
 #include <linux/io.h>
 
-#include <plat/io.h>
 #include "common.h"
 #include <plat/clock.h>
 #include <plat/sdrc.h>
index 791a63c..1133bb2 100644 (file)
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include "common.h"
+#include <plat/hardware.h>
 #include <plat/clock.h>
 #include <plat/sram.h>
+#include <plat/sdrc.h>
 
+#include "iomap.h"
+#include "common.h"
 #include "prm2xxx_3xxx.h"
 #include "clock.h"
-#include <plat/sdrc.h>
 #include "sdrc.h"
 
 /* Memory timing, DLL mode flags */
index f590afc..0cdd359 100644 (file)
 
 struct omap_uart_state {
        int num;
-       int can_sleep;
 
        struct list_head node;
        struct omap_hwmod *oh;
-       struct platform_device *pdev;
 };
 
 static LIST_HEAD(uart_list);
@@ -381,8 +379,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
 
        oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt);
 
-       uart->pdev = pdev;
-
        oh->dev_attr = uart;
 
        if (((cpu_is_omap34xx() || cpu_is_omap44xx()) && bdata->pads)
index b5071a4..d4bf904 100644 (file)
@@ -27,7 +27,6 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include <mach/io.h>
 
 #include <plat/omap24xx.h>
 
index f2ea1bd..1f62f23 100644 (file)
  * MA 02111-1307 USA
  */
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
+
+#include <plat/hardware.h>
 #include <plat/sram.h>
-#include <mach/io.h>
 
+#include "iomap.h"
 #include "cm2xxx_3xxx.h"
 #include "prm2xxx_3xxx.h"
 #include "sdrc.h"
index 53d9d0a..955566e 100644 (file)
@@ -29,6 +29,7 @@ static int sr_class3_enable(struct voltagedomain *voltdm)
 
 static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset)
 {
+       sr_disable_errgen(voltdm);
        omap_vp_disable(voltdm);
        sr_disable(voltdm);
        if (is_volt_reset)
index 7e755bb..008fbd7 100644 (file)
 #define SR_DISABLE_TIMEOUT     200
 
 struct omap_sr {
+       struct list_head                node;
+       struct platform_device          *pdev;
+       struct omap_sr_nvalue_table     *nvalue_table;
+       struct voltagedomain            *voltdm;
+       struct dentry                   *dbg_dir;
+       unsigned int                    irq;
        int                             srid;
        int                             ip_type;
        int                             nvalue_count;
@@ -49,13 +55,7 @@ struct omap_sr {
        u32                             senp_avgweight;
        u32                             senp_mod;
        u32                             senn_mod;
-       unsigned int                    irq;
        void __iomem                    *base;
-       struct platform_device          *pdev;
-       struct list_head                node;
-       struct omap_sr_nvalue_table     *nvalue_table;
-       struct voltagedomain            *voltdm;
-       struct dentry                   *dbg_dir;
 };
 
 /* sr_list contains all the instances of smartreflex module */
@@ -74,10 +74,6 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
                                        u32 value)
 {
        u32 reg_val;
-       u32 errconfig_offs = 0, errconfig_mask = 0;
-
-       reg_val = __raw_readl(sr->base + offset);
-       reg_val &= ~mask;
 
        /*
         * Smartreflex error config register is special as it contains
@@ -88,16 +84,15 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
         * if they are currently set, but does allow the caller to write
         * those bits.
         */
-       if (sr->ip_type == SR_TYPE_V1) {
-               errconfig_offs = ERRCONFIG_V1;
-               errconfig_mask = ERRCONFIG_STATUS_V1_MASK;
-       } else if (sr->ip_type == SR_TYPE_V2) {
-               errconfig_offs = ERRCONFIG_V2;
-               errconfig_mask = ERRCONFIG_VPBOUNDINTST_V2;
-       }
+       if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1)
+               mask |= ERRCONFIG_STATUS_V1_MASK;
+       else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2)
+               mask |= ERRCONFIG_VPBOUNDINTST_V2;
+
+       reg_val = __raw_readl(sr->base + offset);
+       reg_val &= ~mask;
 
-       if (offset == errconfig_offs)
-               reg_val &= ~errconfig_mask;
+       value &= mask;
 
        reg_val |= value;
 
@@ -128,21 +123,28 @@ static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm)
 
 static irqreturn_t sr_interrupt(int irq, void *data)
 {
-       struct omap_sr *sr_info = (struct omap_sr *)data;
+       struct omap_sr *sr_info = data;
        u32 status = 0;
 
-       if (sr_info->ip_type == SR_TYPE_V1) {
+       switch (sr_info->ip_type) {
+       case SR_TYPE_V1:
                /* Read the status bits */
                status = sr_read_reg(sr_info, ERRCONFIG_V1);
 
                /* Clear them by writing back */
                sr_write_reg(sr_info, ERRCONFIG_V1, status);
-       } else if (sr_info->ip_type == SR_TYPE_V2) {
+               break;
+       case SR_TYPE_V2:
                /* Read the status bits */
                status = sr_read_reg(sr_info, IRQSTATUS);
 
                /* Clear them by writing back */
                sr_write_reg(sr_info, IRQSTATUS, status);
+               break;
+       default:
+               dev_err(&sr_info->pdev->dev, "UNKNOWN IP type %d\n",
+                       sr_info->ip_type);
+               return IRQ_NONE;
        }
 
        if (sr_class->notify)
@@ -166,6 +168,7 @@ static void sr_set_clk_length(struct omap_sr *sr)
                        __func__);
                return;
        }
+
        sys_clk_speed = clk_get_rate(sys_ck);
        clk_put(sys_ck);
 
@@ -267,7 +270,7 @@ static int sr_late_init(struct omap_sr *sr_info)
                        goto error;
                }
                ret = request_irq(sr_info->irq, sr_interrupt,
-                               0, name, (void *)sr_info);
+                               0, name, sr_info);
                if (ret)
                        goto error;
                disable_irq(sr_info->irq);
@@ -288,12 +291,15 @@ error:
                "not function as desired\n", __func__);
        kfree(name);
        kfree(sr_info);
+
        return ret;
 }
 
 static void sr_v1_disable(struct omap_sr *sr)
 {
        int timeout = 0;
+       int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
+                       ERRCONFIG_MCUBOUNDINTST;
 
        /* Enable MCUDisableAcknowledge interrupt */
        sr_modify_reg(sr, ERRCONFIG_V1,
@@ -302,13 +308,13 @@ static void sr_v1_disable(struct omap_sr *sr)
        /* SRCONFIG - disable SR */
        sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
 
-       /* Disable all other SR interrupts and clear the status */
+       /* Disable all other SR interrupts and clear the status as needed */
+       if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1)
+               errconf_val |= ERRCONFIG_VPBOUNDINTST_V1;
        sr_modify_reg(sr, ERRCONFIG_V1,
                        (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
                        ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1),
-                       (ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
-                       ERRCONFIG_MCUBOUNDINTST |
-                       ERRCONFIG_VPBOUNDINTST_V1));
+                       errconf_val);
 
        /*
         * Wait for SR to be disabled.
@@ -337,9 +343,17 @@ static void sr_v2_disable(struct omap_sr *sr)
        /* SRCONFIG - disable SR */
        sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
 
-       /* Disable all other SR interrupts and clear the status */
-       sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
+       /*
+        * Disable all other SR interrupts and clear the status
+        * write to status register ONLY on need basis - only if status
+        * is set.
+        */
+       if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2)
+               sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
                        ERRCONFIG_VPBOUNDINTST_V2);
+       else
+               sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
+                               0x0);
        sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT |
                        IRQENABLE_MCUVALIDINT |
                        IRQENABLE_MCUBOUNDSINT));
@@ -398,15 +412,16 @@ static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs)
  */
 int sr_configure_errgen(struct voltagedomain *voltdm)
 {
-       u32 sr_config, sr_errconfig, errconfig_offs, vpboundint_en;
-       u32 vpboundint_st, senp_en = 0, senn_en = 0;
+       u32 sr_config, sr_errconfig, errconfig_offs;
+       u32 vpboundint_en, vpboundint_st;
+       u32 senp_en = 0, senn_en = 0;
        u8 senp_shift, senn_shift;
        struct omap_sr *sr = _sr_lookup(voltdm);
 
        if (IS_ERR(sr)) {
                pr_warning("%s: omap_sr struct for sr_%s not found\n",
                        __func__, voltdm->name);
-               return -EINVAL;
+               return PTR_ERR(sr);
        }
 
        if (!sr->clk_length)
@@ -418,20 +433,23 @@ int sr_configure_errgen(struct voltagedomain *voltdm)
        sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
                SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN;
 
-       if (sr->ip_type == SR_TYPE_V1) {
+       switch (sr->ip_type) {
+       case SR_TYPE_V1:
                sr_config |= SRCONFIG_DELAYCTRL;
                senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
                senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
                errconfig_offs = ERRCONFIG_V1;
                vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
                vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
-       } else if (sr->ip_type == SR_TYPE_V2) {
+               break;
+       case SR_TYPE_V2:
                senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
                senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
                errconfig_offs = ERRCONFIG_V2;
                vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
                vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
-       } else {
+               break;
+       default:
                dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
                        "module without specifying the ip\n", __func__);
                return -EINVAL;
@@ -447,8 +465,55 @@ int sr_configure_errgen(struct voltagedomain *voltdm)
                sr_errconfig);
 
        /* Enabling the interrupts if the ERROR module is used */
-       sr_modify_reg(sr, errconfig_offs,
-               vpboundint_en, (vpboundint_en | vpboundint_st));
+       sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st),
+                     vpboundint_en);
+
+       return 0;
+}
+
+/**
+ * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component
+ * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
+ *
+ * This API is to be called from the smartreflex class driver to
+ * disable the error generator module inside the smartreflex module.
+ *
+ * Returns 0 on success and error value in case of failure.
+ */
+int sr_disable_errgen(struct voltagedomain *voltdm)
+{
+       u32 errconfig_offs;
+       u32 vpboundint_en, vpboundint_st;
+       struct omap_sr *sr = _sr_lookup(voltdm);
+
+       if (IS_ERR(sr)) {
+               pr_warning("%s: omap_sr struct for sr_%s not found\n",
+                       __func__, voltdm->name);
+               return PTR_ERR(sr);
+       }
+
+       switch (sr->ip_type) {
+       case SR_TYPE_V1:
+               errconfig_offs = ERRCONFIG_V1;
+               vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
+               vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
+               break;
+       case SR_TYPE_V2:
+               errconfig_offs = ERRCONFIG_V2;
+               vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
+               vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
+               break;
+       default:
+               dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
+                       "module without specifying the ip\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Disable the interrupts of ERROR module */
+       sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0);
+
+       /* Disable the Sensor and errorgen */
+       sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0);
 
        return 0;
 }
@@ -475,7 +540,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm)
        if (IS_ERR(sr)) {
                pr_warning("%s: omap_sr struct for sr_%s not found\n",
                        __func__, voltdm->name);
-               return -EINVAL;
+               return PTR_ERR(sr);
        }
 
        if (!sr->clk_length)
@@ -488,14 +553,17 @@ int sr_configure_minmax(struct voltagedomain *voltdm)
                SRCONFIG_SENENABLE |
                (sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT);
 
-       if (sr->ip_type == SR_TYPE_V1) {
+       switch (sr->ip_type) {
+       case SR_TYPE_V1:
                sr_config |= SRCONFIG_DELAYCTRL;
                senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT;
                senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT;
-       } else if (sr->ip_type == SR_TYPE_V2) {
+               break;
+       case SR_TYPE_V2:
                senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT;
                senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT;
-       } else {
+               break;
+       default:
                dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
                        "module without specifying the ip\n", __func__);
                return -EINVAL;
@@ -511,20 +579,27 @@ int sr_configure_minmax(struct voltagedomain *voltdm)
         * Enabling the interrupts if MINMAXAVG module is used.
         * TODO: check if all the interrupts are mandatory
         */
-       if (sr->ip_type == SR_TYPE_V1) {
+       switch (sr->ip_type) {
+       case SR_TYPE_V1:
                sr_modify_reg(sr, ERRCONFIG_V1,
                        (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
                        ERRCONFIG_MCUBOUNDINTEN),
                        (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST |
                         ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST |
                         ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
-       } else if (sr->ip_type == SR_TYPE_V2) {
+               break;
+       case SR_TYPE_V2:
                sr_write_reg(sr, IRQSTATUS,
                        IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT |
                        IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT);
                sr_write_reg(sr, IRQENABLE_SET,
                        IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT |
                        IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT);
+               break;
+       default:
+               dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
+                       "module without specifying the ip\n", __func__);
+               return -EINVAL;
        }
 
        return 0;
@@ -543,15 +618,15 @@ int sr_configure_minmax(struct voltagedomain *voltdm)
  */
 int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
 {
-       u32 nvalue_reciprocal;
        struct omap_volt_data *volt_data;
        struct omap_sr *sr = _sr_lookup(voltdm);
+       u32 nvalue_reciprocal;
        int ret;
 
        if (IS_ERR(sr)) {
                pr_warning("%s: omap_sr struct for sr_%s not found\n",
                        __func__, voltdm->name);
-               return -EINVAL;
+               return PTR_ERR(sr);
        }
 
        volt_data = omap_voltage_get_voltdata(sr->voltdm, volt);
@@ -559,7 +634,7 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
        if (IS_ERR(volt_data)) {
                dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table"
                        "for nominal voltage %ld\n", __func__, volt);
-               return -ENODATA;
+               return PTR_ERR(volt_data);
        }
 
        nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs);
@@ -617,10 +692,17 @@ void sr_disable(struct voltagedomain *voltdm)
         * disable the clocks.
         */
        if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) {
-               if (sr->ip_type == SR_TYPE_V1)
+               switch (sr->ip_type) {
+               case SR_TYPE_V1:
                        sr_v1_disable(sr);
-               else if (sr->ip_type == SR_TYPE_V2)
+                       break;
+               case SR_TYPE_V2:
                        sr_v2_disable(sr);
+                       break;
+               default:
+                       dev_err(&sr->pdev->dev, "UNKNOWN IP type %d\n",
+                               sr->ip_type);
+               }
        }
 
        pm_runtime_put_sync_suspend(&sr->pdev->dev);
@@ -779,10 +861,10 @@ void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data)
        sr_pmic_data = pmic_data;
 }
 
-/* PM Debug Fs enteries to enable disable smartreflex. */
+/* PM Debug FS entries to enable and disable smartreflex. */
 static int omap_sr_autocomp_show(void *data, u64 *val)
 {
-       struct omap_sr *sr_info = (struct omap_sr *) data;
+       struct omap_sr *sr_info = data;
 
        if (!sr_info) {
                pr_warning("%s: omap_sr struct not found\n", __func__);
@@ -796,7 +878,7 @@ static int omap_sr_autocomp_show(void *data, u64 *val)
 
 static int omap_sr_autocomp_store(void *data, u64 val)
 {
-       struct omap_sr *sr_info = (struct omap_sr *) data;
+       struct omap_sr *sr_info = data;
 
        if (!sr_info) {
                pr_warning("%s: omap_sr struct not found\n", __func__);
@@ -804,7 +886,7 @@ static int omap_sr_autocomp_store(void *data, u64 val)
        }
 
        /* Sanity check */
-       if (val && (val != 1)) {
+       if (val > 1) {
                pr_warning("%s: Invalid argument %lld\n", __func__, val);
                return -EINVAL;
        }
@@ -821,11 +903,11 @@ static int omap_sr_autocomp_store(void *data, u64 val)
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show,
-               omap_sr_autocomp_store, "%llu\n");
+                       omap_sr_autocomp_store, "%llu\n");
 
 static int __init omap_sr_probe(struct platform_device *pdev)
 {
-       struct omap_sr *sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
+       struct omap_sr *sr_info;
        struct omap_sr_data *pdata = pdev->dev.platform_data;
        struct resource *mem, *irq;
        struct dentry *nvalue_dir;
@@ -833,12 +915,15 @@ static int __init omap_sr_probe(struct platform_device *pdev)
        int i, ret = 0;
        char *name;
 
+       sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
        if (!sr_info) {
                dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
                        __func__);
                return -ENOMEM;
        }
 
+       platform_set_drvdata(pdev, sr_info);
+
        if (!pdata) {
                dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
                ret = -EINVAL;
@@ -904,7 +989,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
        dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__);
        if (!sr_dbg_dir) {
                sr_dbg_dir = debugfs_create_dir("smartreflex", NULL);
-               if (!sr_dbg_dir) {
+               if (IS_ERR_OR_NULL(sr_dbg_dir)) {
                        ret = PTR_ERR(sr_dbg_dir);
                        pr_err("%s:sr debugfs dir creation failed(%d)\n",
                                __func__, ret);
@@ -921,7 +1006,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
        }
        sr_info->dbg_dir = debugfs_create_dir(name, sr_dbg_dir);
        kfree(name);
-       if (IS_ERR(sr_info->dbg_dir)) {
+       if (IS_ERR_OR_NULL(sr_info->dbg_dir)) {
                dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
                        __func__);
                ret = PTR_ERR(sr_info->dbg_dir);
@@ -938,7 +1023,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                        &sr_info->err_minlimit);
 
        nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
-       if (IS_ERR(nvalue_dir)) {
+       if (IS_ERR_OR_NULL(nvalue_dir)) {
                dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
                        "for n-values\n", __func__);
                ret = PTR_ERR(nvalue_dir);
@@ -994,7 +1079,7 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)
        if (IS_ERR(sr_info)) {
                dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
                        __func__);
-               return -EINVAL;
+               return PTR_ERR(sr_info);
        }
 
        if (sr_info->autocomp_active)
@@ -1011,8 +1096,32 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)
        return 0;
 }
 
+static void __devexit omap_sr_shutdown(struct platform_device *pdev)
+{
+       struct omap_sr_data *pdata = pdev->dev.platform_data;
+       struct omap_sr *sr_info;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
+               return;
+       }
+
+       sr_info = _sr_lookup(pdata->voltdm);
+       if (IS_ERR(sr_info)) {
+               dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
+                       __func__);
+               return;
+       }
+
+       if (sr_info->autocomp_active)
+               sr_stop_vddautocomp(sr_info);
+
+       return;
+}
+
 static struct platform_driver smartreflex_driver = {
-       .remove         = omap_sr_remove,
+       .remove         = __devexit_p(omap_sr_remove),
+       .shutdown       = __devexit_p(omap_sr_shutdown),
        .driver         = {
                .name   = "smartreflex",
        },
@@ -1042,12 +1151,12 @@ static int __init sr_init(void)
 
        return 0;
 }
+late_initcall(sr_init);
 
 static void __exit sr_exit(void)
 {
        platform_driver_unregister(&smartreflex_driver);
 }
-late_initcall(sr_init);
 module_exit(sr_exit);
 
 MODULE_DESCRIPTION("OMAP Smartreflex Driver");
index 5f35b9e..5809141 100644 (file)
@@ -152,6 +152,15 @@ struct omap_sr_pmic_data {
        void (*sr_pmic_init) (void);
 };
 
+/**
+ * struct omap_smartreflex_dev_attr - Smartreflex Device attribute.
+ *
+ * @sensor_voltdm_name:       Name of voltdomain of SR instance
+ */
+struct omap_smartreflex_dev_attr {
+       const char      *sensor_voltdm_name;
+};
+
 #ifdef CONFIG_OMAP_SMARTREFLEX
 /*
  * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR.
@@ -231,6 +240,7 @@ void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data);
 int sr_enable(struct voltagedomain *voltdm, unsigned long volt);
 void sr_disable(struct voltagedomain *voltdm);
 int sr_configure_errgen(struct voltagedomain *voltdm);
+int sr_disable_errgen(struct voltagedomain *voltdm);
 int sr_configure_minmax(struct voltagedomain *voltdm);
 
 /* API to register the smartreflex class driver with the smartreflex driver */
index 9f43fcc..a503e1e 100644 (file)
@@ -69,11 +69,12 @@ static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
        sr_data->nvalue_count = count;
 }
 
-static int sr_dev_init(struct omap_hwmod *oh, void *user)
+static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
 {
        struct omap_sr_data *sr_data;
        struct platform_device *pdev;
        struct omap_volt_data *volt_data;
+       struct omap_smartreflex_dev_attr *sr_dev_attr;
        char *name = "smartreflex";
        static int i;
 
@@ -84,9 +85,11 @@ static int sr_dev_init(struct omap_hwmod *oh, void *user)
                return -ENOMEM;
        }
 
-       if (!oh->vdd_name) {
+       sr_dev_attr = (struct omap_smartreflex_dev_attr *)oh->dev_attr;
+       if (!sr_dev_attr || !sr_dev_attr->sensor_voltdm_name) {
                pr_err("%s: No voltage domain specified for %s."
-                       "Cannot initialize\n", __func__, oh->name);
+                               "Cannot initialize\n", __func__,
+                                       oh->name);
                goto exit;
        }
 
@@ -94,10 +97,10 @@ static int sr_dev_init(struct omap_hwmod *oh, void *user)
        sr_data->senn_mod = 0x1;
        sr_data->senp_mod = 0x1;
 
-       sr_data->voltdm = voltdm_lookup(oh->vdd_name);
+       sr_data->voltdm = voltdm_lookup(sr_dev_attr->sensor_voltdm_name);
        if (IS_ERR(sr_data->voltdm)) {
                pr_err("%s: Unable to get voltage domain pointer for VDD %s\n",
-                       __func__, oh->vdd_name);
+                       __func__, sr_dev_attr->sensor_voltdm_name);
                goto exit;
        }
 
index ff9b9db..ee0bfcc 100644 (file)
  * These crashes may be intermittent.
  */
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
-#include <mach/io.h>
+
 #include <mach/hardware.h>
 
+#include "iomap.h"
 #include "prm2xxx_3xxx.h"
 #include "cm2xxx_3xxx.h"
 #include "sdrc.h"
index 7673020..d4d39ef 100644 (file)
  * These crashes may be intermittent.
  */
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
-#include <mach/io.h>
+
 #include <mach/hardware.h>
 
+#include "iomap.h"
 #include "prm2xxx_3xxx.h"
 #include "cm2xxx_3xxx.h"
 #include "sdrc.h"
index 6f5849a..df5a213 100644 (file)
  * MA 02111-1307 USA
  */
 #include <linux/linkage.h>
+
 #include <asm/assembler.h>
-#include <mach/hardware.h>
 
-#include <mach/io.h>
+#include <mach/hardware.h>
 
+#include "iomap.h"
 #include "sdrc.h"
 #include "cm2xxx_3xxx.h"
 
diff --git a/arch/arm/mach-omap2/timer-mpu.c b/arch/arm/mach-omap2/timer-mpu.c
deleted file mode 100644 (file)
index 31c0ac4..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * The MPU local timer source file. In OMAP4, both cortex-a9 cores have
- * own timer in it's MPU domain. These timers will be driving the
- * linux kernel SMP tick framework when active. These timers are not
- * part of the wake up domain.
- *
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Author:
- *      Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * This file is based on arm realview smp platform file.
- * Copyright (C) 2002 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-#include <asm/irq.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       /* Local timers are not supprted on OMAP4430 ES1.0 */
-       if (omap_rev() == OMAP4430_REV_ES1_0)
-               return -ENXIO;
-
-       evt->irq = OMAP44XX_IRQ_LOCALTIMER;
-       twd_timer_setup(evt);
-       return 0;
-}
-
index 5c9acea..c512bac 100644 (file)
@@ -39,7 +39,7 @@
 
 #include <asm/mach/time.h>
 #include <plat/dmtimer.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 #include <asm/sched_clock.h>
 #include "common.h"
 #include <plat/omap_hwmod.h>
@@ -324,14 +324,26 @@ OMAP_SYS_TIMER(3_secure)
 #endif
 
 #ifdef CONFIG_ARCH_OMAP4
-static void __init omap4_timer_init(void)
-{
 #ifdef CONFIG_LOCAL_TIMERS
-       twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
-       BUG_ON(!twd_base);
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
+                             OMAP44XX_LOCAL_TWD_BASE,
+                             OMAP44XX_IRQ_LOCALTIMER);
 #endif
+
+static void __init omap4_timer_init(void)
+{
        omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE);
        omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE);
+#ifdef CONFIG_LOCAL_TIMERS
+       /* Local timers are not supprted on OMAP4430 ES1.0 */
+       if (omap_rev() != OMAP4430_REV_ES1_0) {
+               int err;
+
+               err = twd_local_timer_register(&twd_local_timer);
+               if (err)
+                       pr_err("twd_local_timer_register failed %d\n", err);
+       }
+#endif
 }
 OMAP_SYS_TIMER(4)
 #endif
index 175b7d8..84da34f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/bug.h>
 
 #include <plat/cpu.h>
 
index 0df8882..f95c1ba 100644 (file)
@@ -61,8 +61,8 @@ void __init omap_vp_init(struct voltagedomain *voltdm)
        vddmin = voltdm->pmic->vp_vddmin;
        vddmax = voltdm->pmic->vp_vddmax;
 
-       waittime = ((voltdm->pmic->step_size / voltdm->pmic->slew_rate) *
-                   sys_clk_rate) / 1000;
+       waittime = DIV_ROUND_UP(voltdm->pmic->step_size * sys_clk_rate,
+                               1000 * voltdm->pmic->slew_rate);
        vstepmin = voltdm->pmic->vp_vstepmin;
        vstepmax = voltdm->pmic->vp_vstepmax;
 
index d658992..79eb502 100644 (file)
 
 #include <mach/bridge-regs.h>
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =MAIN_IRQ_CAUSE
        .endm
diff --git a/arch/arm/mach-orion5x/include/mach/system.h b/arch/arm/mach-orion5x/include/mach/system.h
deleted file mode 100644 (file)
index 825a265..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-orion5x/include/mach/system.h
- *
- * Tzachi Perelstein <tzachi@marvell.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
index 09a045f..d6a9194 100644 (file)
@@ -171,13 +171,14 @@ static int __init pcie_setup(struct pci_sys_data *sys)
        /*
         * IORESOURCE_IO
         */
+       sys->io_offset = 0;
        res[0].name = "PCIe I/O Space";
        res[0].flags = IORESOURCE_IO;
        res[0].start = ORION5X_PCIE_IO_BUS_BASE;
        res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1;
        if (request_resource(&ioport_resource, &res[0]))
                panic("Request PCIe IO resource failed\n");
-       pci_add_resource(&sys->resources, &res[0]);
+       pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
 
        /*
         * IORESOURCE_MEM
@@ -188,9 +189,7 @@ static int __init pcie_setup(struct pci_sys_data *sys)
        res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1;
        if (request_resource(&iomem_resource, &res[1]))
                panic("Request PCIe Memory resource failed\n");
-       pci_add_resource(&sys->resources, &res[1]);
-
-       sys->io_offset = 0;
+       pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
        return 1;
 }
@@ -499,13 +498,14 @@ static int __init pci_setup(struct pci_sys_data *sys)
        /*
         * IORESOURCE_IO
         */
+       sys->io_offset = 0;
        res[0].name = "PCI I/O Space";
        res[0].flags = IORESOURCE_IO;
        res[0].start = ORION5X_PCI_IO_BUS_BASE;
        res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1;
        if (request_resource(&ioport_resource, &res[0]))
                panic("Request PCI IO resource failed\n");
-       pci_add_resource(&sys->resources, &res[0]);
+       pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
 
        /*
         * IORESOURCE_MEM
@@ -516,9 +516,7 @@ static int __init pci_setup(struct pci_sys_data *sys)
        res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1;
        if (request_resource(&iomem_resource, &res[1]))
                panic("Request PCI Memory resource failed\n");
-       pci_add_resource(&sys->resources, &res[1]);
-
-       sys->io_offset = 0;
+       pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
        return 1;
 }
diff --git a/arch/arm/mach-picoxcell/include/mach/entry-macro.S b/arch/arm/mach-picoxcell/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 9b505ac..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * entry-macro.S
- *
- * Copyright (c) 2011 Picochip Ltd., Jamie Iles
- *
- * Low-level IRQ helper macros for picoXcell platforms
- *
- * 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.
- */
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
diff --git a/arch/arm/mach-picoxcell/include/mach/system.h b/arch/arm/mach-picoxcell/include/mach/system.h
deleted file mode 100644 (file)
index 1a5d8cb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2011 Picochip Ltd., Jamie Iles
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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.
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       /*
-        * This should do all the clock switching and wait for interrupt
-        * tricks.
-        */
-       cpu_do_idle();
-}
-
-#endif /* __ASM_ARCH_SYSTEM_H */
index db7eeeb..77a5558 100644 (file)
 #define SIC1_BASE_INT   32
 #define SIC2_BASE_INT   64
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 /* decode the MIC interrupt numbers */
                ldr     \base, =IO_ADDRESS(PNX4008_INTCTRLMIC_BASE)
diff --git a/arch/arm/mach-pnx4008/include/mach/system.h b/arch/arm/mach-pnx4008/include/mach/system.h
deleted file mode 100644 (file)
index 60cfe71..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * arch/arm/mach-pnx4008/include/mach/system.h
- *
- * Copyright (C) 2003 Philips Semiconductors
- * Copyright (C) 2005 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
index 1c8a50f..86434e7 100644 (file)
        cmp \irqnr, #0x40                       @ the irq num can't be larger than 0x3f
        movges \irqnr, #0
        .endm
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
diff --git a/arch/arm/mach-prima2/include/mach/system.h b/arch/arm/mach-prima2/include/mach/system.h
deleted file mode 100644 (file)
index 2c7d2a9..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-prima2/include/mach/system.h
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-#ifndef __MACH_SYSTEM_H__
-#define __MACH_SYSTEM_H__
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
index 5bc1312..84f2d70 100644 (file)
@@ -406,20 +406,17 @@ static struct resource pxa_rtc_resources[] = {
        [1] = {
                .start  = IRQ_RTC1Hz,
                .end    = IRQ_RTC1Hz,
+               .name   = "rtc 1Hz",
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
                .start  = IRQ_RTCAlrm,
                .end    = IRQ_RTCAlrm,
+               .name   = "rtc alarm",
                .flags  = IORESOURCE_IRQ,
        },
 };
 
-struct platform_device sa1100_device_rtc = {
-       .name           = "sa1100-rtc",
-       .id             = -1,
-};
-
 struct platform_device pxa_device_rtc = {
        .name           = "pxa-rtc",
        .id             = -1,
@@ -427,6 +424,27 @@ struct platform_device pxa_device_rtc = {
        .resource       = pxa_rtc_resources,
 };
 
+static struct resource sa1100_rtc_resources[] = {
+       {
+               .start  = IRQ_RTC1Hz,
+               .end    = IRQ_RTC1Hz,
+               .name   = "rtc 1Hz",
+               .flags  = IORESOURCE_IRQ,
+       }, {
+               .start  = IRQ_RTCAlrm,
+               .end    = IRQ_RTCAlrm,
+               .name   = "rtc alarm",
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device sa1100_device_rtc = {
+       .name           = "sa1100-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(sa1100_rtc_resources),
+       .resource       = sa1100_rtc_resources,
+};
+
 static struct resource pxa_ac97_resources[] = {
        [0] = {
                .start  = 0x40500000,
index 208eef1..3fa929d 100644 (file)
@@ -28,7 +28,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/pda_power.h>
 #include <linux/pwm_backlight.h>
-#include <linux/regulator/bq24022.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/gpio-regulator.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/max1586.h>
 #include <linux/spi/ads7846.h>
@@ -97,9 +98,9 @@ static unsigned long hx4700_pin_config[] __initdata = {
 
        /* BTUART */
        GPIO42_BTUART_RXD,
-       GPIO43_BTUART_TXD,
+       GPIO43_BTUART_TXD_LPM_LOW,
        GPIO44_BTUART_CTS,
-       GPIO45_BTUART_RTS,
+       GPIO45_BTUART_RTS_LPM_LOW,
 
        /* PWM 1 (Backlight) */
        GPIO17_PWM1_OUT,
@@ -245,6 +246,21 @@ static u16 asic3_gpio_config[] = {
        ASIC3_GPIOD15_nPIOW,
 };
 
+static struct asic3_led asic3_leds[ASIC3_NUM_LEDS] = {
+       [0] = {
+               .name = "hx4700:amber",
+               .default_trigger = "ds2760-battery.0-charging-blink-full-solid",
+       },
+       [1] = {
+               .name = "hx4700:green",
+               .default_trigger = "unused",
+       },
+       [2] = {
+               .name = "hx4700:blue",
+               .default_trigger = "hx4700-radio",
+       },
+};
+
 static struct resource asic3_resources[] = {
        /* GPIO part */
        [0] = {
@@ -275,6 +291,7 @@ static struct asic3_platform_data asic3_platform_data = {
        .gpio_config_num = ARRAY_SIZE(asic3_gpio_config),
        .irq_base        = IRQ_BOARD_START,
        .gpio_base       = HX4700_ASIC3_GPIO_BASE,
+       .leds            = asic3_leds,
 };
 
 static struct platform_device asic3 = {
@@ -682,14 +699,34 @@ static struct regulator_init_data bq24022_init_data = {
        .consumer_supplies      = bq24022_consumers,
 };
 
-static struct bq24022_mach_info bq24022_info = {
-       .gpio_nce   = GPIO72_HX4700_BQ24022_nCHARGE_EN,
-       .gpio_iset2 = GPIO96_HX4700_BQ24022_ISET2,
-       .init_data  = &bq24022_init_data,
+static struct gpio bq24022_gpios[] = {
+       { GPIO96_HX4700_BQ24022_ISET2, GPIOF_OUT_INIT_LOW, "bq24022_iset2" },
+};
+
+static struct gpio_regulator_state bq24022_states[] = {
+       { .value = 100000, .gpios = (0 << 0) },
+       { .value = 500000, .gpios = (1 << 0) },
+};
+
+static struct gpio_regulator_config bq24022_info = {
+       .supply_name = "bq24022",
+
+       .enable_gpio = GPIO72_HX4700_BQ24022_nCHARGE_EN,
+       .enable_high = 0,
+       .enabled_at_boot = 0,
+
+       .gpios = bq24022_gpios,
+       .nr_gpios = ARRAY_SIZE(bq24022_gpios),
+
+       .states = bq24022_states,
+       .nr_states = ARRAY_SIZE(bq24022_states),
+
+       .type = REGULATOR_CURRENT,
+       .init_data = &bq24022_init_data,
 };
 
 static struct platform_device bq24022 = {
-       .name = "bq24022",
+       .name = "gpio-regulator",
        .id   = -1,
        .dev  = {
                .platform_data = &bq24022_info,
@@ -705,10 +742,9 @@ static void hx4700_set_vpp(struct platform_device *pdev, int vpp)
        gpio_set_value(GPIO91_HX4700_FLASH_VPEN, vpp);
 }
 
-static struct resource strataflash_resource = {
-       .start = PXA_CS0_PHYS,
-       .end   = PXA_CS0_PHYS + SZ_128M - 1,
-       .flags = IORESOURCE_MEM,
+static struct resource strataflash_resource[] = {
+       [0] = DEFINE_RES_MEM(PXA_CS0_PHYS, SZ_64M),
+       [1] = DEFINE_RES_MEM(PXA_CS0_PHYS + SZ_64M, SZ_64M),
 };
 
 static struct physmap_flash_data strataflash_data = {
@@ -719,8 +755,8 @@ static struct physmap_flash_data strataflash_data = {
 static struct platform_device strataflash = {
        .name          = "physmap-flash",
        .id            = -1,
-       .resource      = &strataflash_resource,
-       .num_resources = 1,
+       .resource      = strataflash_resource,
+       .num_resources = ARRAY_SIZE(strataflash_resource),
        .dev = {
                .platform_data = &strataflash_data,
        },
@@ -788,17 +824,6 @@ static struct platform_device audio = {
 
 
 /*
- * PCMCIA
- */
-
-static struct platform_device pcmcia = {
-       .name = "hx4700-pcmcia",
-       .dev  = {
-               .parent = &asic3.dev,
-       },
-};
-
-/*
  * Platform devices
  */
 
@@ -814,7 +839,6 @@ static struct platform_device *devices[] __initdata = {
        &power_supply,
        &strataflash,
        &audio,
-       &pcmcia,
 };
 
 static struct gpio global_gpios[] = {
@@ -830,7 +854,6 @@ static struct gpio global_gpios[] = {
        { GPIO32_HX4700_RS232_ON,         GPIOF_OUT_INIT_HIGH, "RS232_ON" },
        { GPIO71_HX4700_ASIC3_nRESET,     GPIOF_OUT_INIT_HIGH, "ASIC3_nRESET" },
        { GPIO82_HX4700_EUART_RESET,      GPIOF_OUT_INIT_HIGH, "EUART_RESET" },
-       { GPIO105_HX4700_nIR_ON,          GPIOF_OUT_INIT_HIGH, "nIR_EN" },
 };
 
 static void __init hx4700_init(void)
index f02fa1e..954641e 100644 (file)
@@ -174,7 +174,6 @@ enum balloon3_features {
 
 #define BALLOON3_AUX_NIRQ      PXA_GPIO_TO_IRQ(BALLOON3_GPIO_AUX_NIRQ)
 #define BALLOON3_CODEC_IRQ     PXA_GPIO_TO_IRQ(BALLOON3_GPIO_CODEC_IRQ)
-#define BALLOON3_S0_CD_IRQ     PXA_GPIO_TO_IRQ(BALLOON3_GPIO_S0_CD)
 
 #define BALLOON3_NR_IRQS       (IRQ_BOARD_START + 16)
 
diff --git a/arch/arm/mach-pxa/include/mach/entry-macro.S b/arch/arm/mach-pxa/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 260c0c1..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * arch/arm/mach-pxa/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for PXA-based platforms
- *
- * 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.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index ec0f0b0..a658672 100644 (file)
 #define GPIO44_BTUART_CTS      MFP_CFG_IN(GPIO44, AF1)
 #define GPIO42_BTUART_RXD      MFP_CFG_IN(GPIO42, AF1)
 #define GPIO45_BTUART_RTS      MFP_CFG_OUT(GPIO45, AF2, DRIVE_HIGH)
+#define GPIO45_BTUART_RTS_LPM_LOW      MFP_CFG_OUT(GPIO45, AF2, DRIVE_LOW)
 #define GPIO43_BTUART_TXD      MFP_CFG_OUT(GPIO43, AF2, DRIVE_HIGH)
+#define GPIO43_BTUART_TXD_LPM_LOW      MFP_CFG_OUT(GPIO43, AF2, DRIVE_LOW)
 
 /* STUART */
 #define GPIO46_STUART_RXD      MFP_CFG_IN(GPIO46, AF2)
diff --git a/arch/arm/mach-pxa/include/mach/system.h b/arch/arm/mach-pxa/include/mach/system.h
deleted file mode 100644 (file)
index c5afacd..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * arch/arm/mach-pxa/include/mach/system.h
- *
- * Author:     Nicolas Pitre
- * Created:    Jun 15, 2001
- * Copyright:  MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
index 6ebd276..6bb3f47 100644 (file)
@@ -223,6 +223,7 @@ static struct resource sa1111_resources[] = {
 
 static struct sa1111_platform_data sa1111_info = {
        .irq_base       = LUBBOCK_SA1111_IRQ_BASE,
+       .disable_devs   = SA1111_DEVID_SAC,
 };
 
 static struct platform_device sa1111_device = {
index d4ab515..6f4785b 100644 (file)
@@ -25,7 +25,8 @@
 #include <linux/mtd/physmap.h>
 #include <linux/pda_power.h>
 #include <linux/pwm_backlight.h>
-#include <linux/regulator/bq24022.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/gpio-regulator.h>
 #include <linux/regulator/machine.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/i2c/pxa-i2c.h>
@@ -597,14 +598,34 @@ static struct regulator_init_data bq24022_init_data = {
        .consumer_supplies      = bq24022_consumers,
 };
 
-static struct bq24022_mach_info bq24022_info = {
-       .gpio_nce   = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN,
-       .gpio_iset2 = EGPIO_MAGICIAN_BQ24022_ISET2,
-       .init_data  = &bq24022_init_data,
+static struct gpio bq24022_gpios[] = {
+       { EGPIO_MAGICIAN_BQ24022_ISET2, GPIOF_OUT_INIT_LOW, "bq24022_iset2" },
+};
+
+static struct gpio_regulator_state bq24022_states[] = {
+       { .value = 100000, .gpios = (0 << 0) },
+       { .value = 500000, .gpios = (1 << 0) },
+};
+
+static struct gpio_regulator_config bq24022_info = {
+       .supply_name = "bq24022",
+
+       .enable_gpio = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN,
+       .enable_high = 0,
+       .enabled_at_boot = 0,
+
+       .gpios = bq24022_gpios,
+       .nr_gpios = ARRAY_SIZE(bq24022_gpios),
+
+       .states = bq24022_states,
+       .nr_states = ARRAY_SIZE(bq24022_states),
+
+       .type = REGULATOR_CURRENT,
+       .init_data = &bq24022_init_data,
 };
 
 static struct platform_device bq24022 = {
-       .name = "bq24022",
+       .name = "gpio-regulator",
        .id   = -1,
        .dev  = {
                .platform_data = &bq24022_info,
index 3918a67..1570d45 100644 (file)
@@ -89,6 +89,7 @@ static struct clk_lookup pxa3xx_clkregs[] = {
        INIT_CLKREG(&clk_pxa3xx_mmc2, "pxa2xx-mci.1", NULL),
        INIT_CLKREG(&clk_pxa3xx_smemc, "pxa2xx-pcmcia", NULL),
        INIT_CLKREG(&clk_pxa3xx_gpio, "pxa-gpio", NULL),
+       INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL),
 };
 
 #ifdef CONFIG_PM
index 5ce434b..47601f8 100644 (file)
@@ -231,6 +231,7 @@ static struct clk_lookup pxa95x_clkregs[] = {
        INIT_CLKREG(&clk_pxa95x_pwm0, "pxa27x-pwm.0", NULL),
        INIT_CLKREG(&clk_pxa95x_pwm1, "pxa27x-pwm.1", NULL),
        INIT_CLKREG(&clk_pxa95x_gpio, "pxa-gpio", NULL),
+       INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL),
 };
 
 void __init pxa95x_init_irq(void)
index 735b57a..f8f2c0a 100644 (file)
 #include <asm/setup.h>
 #include <asm/leds.h>
 
-#define AMBA_DEVICE(name,busid,base,plat)                      \
-static struct amba_device name##_device = {                    \
-       .dev            = {                                     \
-               .coherent_dma_mask = ~0,                        \
-               .init_name = busid,                             \
-               .platform_data = plat,                          \
-       },                                                      \
-       .res            = {                                     \
-               .start  = REALVIEW_##base##_BASE,               \
-               .end    = (REALVIEW_##base##_BASE) + SZ_4K - 1, \
-               .flags  = IORESOURCE_MEM,                       \
-       },                                                      \
-       .dma_mask       = ~0,                                   \
-       .irq            = base##_IRQ,                           \
-}
+#define APB_DEVICE(name, busid, base, plat)                    \
+static AMBA_APB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat)
+
+#define AHB_DEVICE(name, busid, base, plat)                    \
+static AMBA_AHB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat)
 
 struct machine_desc;
 
diff --git a/arch/arm/mach-realview/include/mach/entry-macro.S b/arch/arm/mach-realview/include/mach/entry-macro.S
deleted file mode 100644 (file)
index e8a5179..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * arch/arm/mach-realview/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for RealView platforms
- *
- * 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.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
index 204d537..d6b5073 100644 (file)
 #define IRQ_EB11MP_L220_SLAVE  (IRQ_EB_GIC_START + 30)
 #define IRQ_EB11MP_L220_DECODE (IRQ_EB_GIC_START + 31)
 
-#define IRQ_EB11MP_UART2       -1
-#define IRQ_EB11MP_UART3       -1
-#define IRQ_EB11MP_CLCD                -1
-#define IRQ_EB11MP_DMA         -1
-#define IRQ_EB11MP_WDOG                -1
-#define IRQ_EB11MP_GPIO0       -1
-#define IRQ_EB11MP_GPIO1       -1
-#define IRQ_EB11MP_GPIO2       -1
-#define IRQ_EB11MP_SCI         -1
-#define IRQ_EB11MP_SSP         -1
+/*
+ * The 11MPcore tile leaves the following unconnected.
+ */
+#define IRQ_EB11MP_UART2       0
+#define IRQ_EB11MP_UART3       0
+#define IRQ_EB11MP_CLCD                0
+#define IRQ_EB11MP_DMA         0
+#define IRQ_EB11MP_WDOG                0
+#define IRQ_EB11MP_GPIO0       0
+#define IRQ_EB11MP_GPIO1       0
+#define IRQ_EB11MP_GPIO2       0
+#define IRQ_EB11MP_SCI         0
+#define IRQ_EB11MP_SSP         0
 
 #define NR_GIC_EB11MP          2
 
index 5c3c625..708f841 100644 (file)
@@ -40,6 +40,7 @@
 #define IRQ_DC1176_L2CC                (IRQ_DC1176_GIC_START + 13)
 #define IRQ_DC1176_RTC         (IRQ_DC1176_GIC_START + 14)
 #define IRQ_DC1176_CLCD                (IRQ_DC1176_GIC_START + 15)     /* CLCD controller */
+#define IRQ_DC1176_GPIO0       (IRQ_DC1176_GIC_START + 16)
 #define IRQ_DC1176_SSP         (IRQ_DC1176_GIC_START + 17)     /* SSP port */
 #define IRQ_DC1176_UART0       (IRQ_DC1176_GIC_START + 18)     /* UART 0 on development chip */
 #define IRQ_DC1176_UART1       (IRQ_DC1176_GIC_START + 19)     /* UART 1 on development chip */
@@ -73,7 +74,6 @@
 #define IRQ_PB1176_DMAC                (IRQ_PB1176_GIC_START + 24)     /* DMA controller */
 #define IRQ_PB1176_RTC         (IRQ_PB1176_GIC_START + 25)     /* Real Time Clock */
 
-#define IRQ_PB1176_GPIO0       -1
 #define IRQ_PB1176_SCTL                -1
 
 #define NR_GIC_PB1176          2
diff --git a/arch/arm/mach-realview/include/mach/system.h b/arch/arm/mach-realview/include/mach/system.h
deleted file mode 100644 (file)
index 471b671..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-realview/include/mach/system.h
- *
- *  Copyright (C) 2003 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       /*
-        * This should do all the clock switching
-        * and wait for interrupt tricks
-        */
-       cpu_do_idle();
-}
-
-#endif
index 9578145..baf382c 100644 (file)
@@ -36,7 +36,7 @@
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -135,63 +135,63 @@ static struct pl022_ssp_controller ssp0_plat_data = {
 /*
  * These devices are connected via the core APB bridge
  */
-#define GPIO2_IRQ      { IRQ_EB_GPIO2, NO_IRQ }
-#define GPIO3_IRQ      { IRQ_EB_GPIO3, NO_IRQ }
+#define GPIO2_IRQ      { IRQ_EB_GPIO2 }
+#define GPIO3_IRQ      { IRQ_EB_GPIO3 }
 
-#define AACI_IRQ       { IRQ_EB_AACI, NO_IRQ }
+#define AACI_IRQ       { IRQ_EB_AACI }
 #define MMCI0_IRQ      { IRQ_EB_MMCI0A, IRQ_EB_MMCI0B }
-#define KMI0_IRQ       { IRQ_EB_KMI0, NO_IRQ }
-#define KMI1_IRQ       { IRQ_EB_KMI1, NO_IRQ }
+#define KMI0_IRQ       { IRQ_EB_KMI0 }
+#define KMI1_IRQ       { IRQ_EB_KMI1 }
 
 /*
  * These devices are connected directly to the multi-layer AHB switch
  */
-#define EB_SMC_IRQ     { NO_IRQ, NO_IRQ }
-#define MPMC_IRQ       { NO_IRQ, NO_IRQ }
-#define EB_CLCD_IRQ    { IRQ_EB_CLCD, NO_IRQ }
-#define DMAC_IRQ       { IRQ_EB_DMA, NO_IRQ }
+#define EB_SMC_IRQ     { }
+#define MPMC_IRQ       { }
+#define EB_CLCD_IRQ    { IRQ_EB_CLCD }
+#define DMAC_IRQ       { IRQ_EB_DMA }
 
 /*
  * These devices are connected via the core APB bridge
  */
-#define SCTL_IRQ       { NO_IRQ, NO_IRQ }
-#define EB_WATCHDOG_IRQ        { IRQ_EB_WDOG, NO_IRQ }
-#define EB_GPIO0_IRQ   { IRQ_EB_GPIO0, NO_IRQ }
-#define GPIO1_IRQ      { IRQ_EB_GPIO1, NO_IRQ }
-#define EB_RTC_IRQ     { IRQ_EB_RTC, NO_IRQ }
+#define SCTL_IRQ       { }
+#define EB_WATCHDOG_IRQ        { IRQ_EB_WDOG }
+#define EB_GPIO0_IRQ   { IRQ_EB_GPIO0 }
+#define GPIO1_IRQ      { IRQ_EB_GPIO1 }
+#define EB_RTC_IRQ     { IRQ_EB_RTC }
 
 /*
  * These devices are connected via the DMA APB bridge
  */
-#define SCI_IRQ                { IRQ_EB_SCI, NO_IRQ }
-#define EB_UART0_IRQ   { IRQ_EB_UART0, NO_IRQ }
-#define EB_UART1_IRQ   { IRQ_EB_UART1, NO_IRQ }
-#define EB_UART2_IRQ   { IRQ_EB_UART2, NO_IRQ }
-#define EB_UART3_IRQ   { IRQ_EB_UART3, NO_IRQ }
-#define EB_SSP_IRQ     { IRQ_EB_SSP, NO_IRQ }
+#define SCI_IRQ                { IRQ_EB_SCI }
+#define EB_UART0_IRQ   { IRQ_EB_UART0 }
+#define EB_UART1_IRQ   { IRQ_EB_UART1 }
+#define EB_UART2_IRQ   { IRQ_EB_UART2 }
+#define EB_UART3_IRQ   { IRQ_EB_UART3 }
+#define EB_SSP_IRQ     { IRQ_EB_SSP }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,  "fpga:aaci",  AACI,     NULL);
-AMBA_DEVICE(mmc0,  "fpga:mmc0",  MMCI0,    &realview_mmc0_plat_data);
-AMBA_DEVICE(kmi0,  "fpga:kmi0",  KMI0,     NULL);
-AMBA_DEVICE(kmi1,  "fpga:kmi1",  KMI1,     NULL);
-AMBA_DEVICE(uart3, "fpga:uart3", EB_UART3, NULL);
+APB_DEVICE(aaci,  "fpga:aaci",  AACI,     NULL);
+APB_DEVICE(mmc0,  "fpga:mmc0",  MMCI0,    &realview_mmc0_plat_data);
+APB_DEVICE(kmi0,  "fpga:kmi0",  KMI0,     NULL);
+APB_DEVICE(kmi1,  "fpga:kmi1",  KMI1,     NULL);
+APB_DEVICE(uart3, "fpga:uart3", EB_UART3, NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,   "dev:smc",   EB_SMC,   NULL);
-AMBA_DEVICE(clcd,  "dev:clcd",  EB_CLCD,  &clcd_plat_data);
-AMBA_DEVICE(dmac,  "dev:dmac",  DMAC,     NULL);
-AMBA_DEVICE(sctl,  "dev:sctl",  SCTL,     NULL);
-AMBA_DEVICE(wdog,  "dev:wdog",  EB_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:gpio0", EB_GPIO0, &gpio0_plat_data);
-AMBA_DEVICE(gpio1, "dev:gpio1", GPIO1,    &gpio1_plat_data);
-AMBA_DEVICE(gpio2, "dev:gpio2", GPIO2,    &gpio2_plat_data);
-AMBA_DEVICE(rtc,   "dev:rtc",   EB_RTC,   NULL);
-AMBA_DEVICE(sci0,  "dev:sci0",  SCI,      NULL);
-AMBA_DEVICE(uart0, "dev:uart0", EB_UART0, NULL);
-AMBA_DEVICE(uart1, "dev:uart1", EB_UART1, NULL);
-AMBA_DEVICE(uart2, "dev:uart2", EB_UART2, NULL);
-AMBA_DEVICE(ssp0,  "dev:ssp0",  EB_SSP,   &ssp0_plat_data);
+AHB_DEVICE(smc,   "dev:smc",   EB_SMC,   NULL);
+AHB_DEVICE(clcd,  "dev:clcd",  EB_CLCD,  &clcd_plat_data);
+AHB_DEVICE(dmac,  "dev:dmac",  DMAC,     NULL);
+AHB_DEVICE(sctl,  "dev:sctl",  SCTL,     NULL);
+APB_DEVICE(wdog,  "dev:wdog",  EB_WATCHDOG, NULL);
+APB_DEVICE(gpio0, "dev:gpio0", EB_GPIO0, &gpio0_plat_data);
+APB_DEVICE(gpio1, "dev:gpio1", GPIO1,    &gpio1_plat_data);
+APB_DEVICE(gpio2, "dev:gpio2", GPIO2,    &gpio2_plat_data);
+APB_DEVICE(rtc,   "dev:rtc",   EB_RTC,   NULL);
+APB_DEVICE(sci0,  "dev:sci0",  SCI,      NULL);
+APB_DEVICE(uart0, "dev:uart0", EB_UART0, NULL);
+APB_DEVICE(uart1, "dev:uart1", EB_UART1, NULL);
+APB_DEVICE(uart2, "dev:uart2", EB_UART2, NULL);
+APB_DEVICE(ssp0,  "dev:ssp0",  EB_SSP,   &ssp0_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
        &dmac_device,
@@ -383,6 +383,23 @@ static void realview_eb11mp_fixup(void)
        realview_eb_isp1761_resources[1].end    = IRQ_EB11MP_USB;
 }
 
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
+                             REALVIEW_EB11MP_TWD_BASE,
+                             IRQ_LOCALTIMER);
+
+static void __init realview_eb_twd_init(void)
+{
+       if (core_tile_eb11mp() || core_tile_a9mp()) {
+               int err = twd_local_timer_register(&twd_local_timer);
+               if (err)
+                       pr_err("twd_local_timer_register failed %d\n", err);
+       }
+}
+#else
+#define realview_eb_twd_init() do { } while(0)
+#endif
+
 static void __init realview_eb_timer_init(void)
 {
        unsigned int timer_irq;
@@ -392,15 +409,13 @@ static void __init realview_eb_timer_init(void)
        timer2_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE);
        timer3_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE) + 0x20;
 
-       if (core_tile_eb11mp() || core_tile_a9mp()) {
-#ifdef CONFIG_LOCAL_TIMERS
-               twd_base = __io_address(REALVIEW_EB11MP_TWD_BASE);
-#endif
+       if (core_tile_eb11mp() || core_tile_a9mp())
                timer_irq = IRQ_EB11MP_TIMER0_1;
-       } else
+       else
                timer_irq = IRQ_EB_TIMER0_1;
 
        realview_timer_init(timer_irq);
+       realview_eb_twd_init();
 }
 
 static struct sys_timer realview_eb_timer = {
index e4abe94..b1d7caf 100644 (file)
@@ -132,50 +132,50 @@ static struct pl022_ssp_controller ssp0_plat_data = {
 /*
  * RealView PB1176 AMBA devices
  */
-#define GPIO2_IRQ      { IRQ_PB1176_GPIO2, NO_IRQ }
-#define GPIO3_IRQ      { IRQ_PB1176_GPIO3, NO_IRQ }
-#define AACI_IRQ       { IRQ_PB1176_AACI, NO_IRQ }
+#define GPIO2_IRQ      { IRQ_PB1176_GPIO2 }
+#define GPIO3_IRQ      { IRQ_PB1176_GPIO3 }
+#define AACI_IRQ       { IRQ_PB1176_AACI }
 #define MMCI0_IRQ      { IRQ_PB1176_MMCI0A, IRQ_PB1176_MMCI0B }
-#define KMI0_IRQ       { IRQ_PB1176_KMI0, NO_IRQ }
-#define KMI1_IRQ       { IRQ_PB1176_KMI1, NO_IRQ }
-#define PB1176_SMC_IRQ { NO_IRQ, NO_IRQ }
-#define MPMC_IRQ       { NO_IRQ, NO_IRQ }
-#define PB1176_CLCD_IRQ        { IRQ_DC1176_CLCD, NO_IRQ }
-#define SCTL_IRQ       { NO_IRQ, NO_IRQ }
-#define PB1176_WATCHDOG_IRQ    { IRQ_DC1176_WATCHDOG, NO_IRQ }
-#define PB1176_GPIO0_IRQ       { IRQ_PB1176_GPIO0, NO_IRQ }
-#define GPIO1_IRQ      { IRQ_PB1176_GPIO1, NO_IRQ }
-#define PB1176_RTC_IRQ { IRQ_DC1176_RTC, NO_IRQ }
-#define SCI_IRQ                { IRQ_PB1176_SCI, NO_IRQ }
-#define PB1176_UART0_IRQ       { IRQ_DC1176_UART0, NO_IRQ }
-#define PB1176_UART1_IRQ       { IRQ_DC1176_UART1, NO_IRQ }
-#define PB1176_UART2_IRQ       { IRQ_DC1176_UART2, NO_IRQ }
-#define PB1176_UART3_IRQ       { IRQ_DC1176_UART3, NO_IRQ }
-#define PB1176_UART4_IRQ       { IRQ_PB1176_UART4, NO_IRQ }
-#define PB1176_SSP_IRQ         { IRQ_DC1176_SSP, NO_IRQ }
+#define KMI0_IRQ       { IRQ_PB1176_KMI0 }
+#define KMI1_IRQ       { IRQ_PB1176_KMI1 }
+#define PB1176_SMC_IRQ { }
+#define MPMC_IRQ       { }
+#define PB1176_CLCD_IRQ        { IRQ_DC1176_CLCD }
+#define SCTL_IRQ       { }
+#define PB1176_WATCHDOG_IRQ    { IRQ_DC1176_WATCHDOG }
+#define PB1176_GPIO0_IRQ       { IRQ_DC1176_GPIO0 }
+#define GPIO1_IRQ      { IRQ_PB1176_GPIO1 }
+#define PB1176_RTC_IRQ { IRQ_DC1176_RTC }
+#define SCI_IRQ                { IRQ_PB1176_SCI }
+#define PB1176_UART0_IRQ       { IRQ_DC1176_UART0 }
+#define PB1176_UART1_IRQ       { IRQ_DC1176_UART1 }
+#define PB1176_UART2_IRQ       { IRQ_DC1176_UART2 }
+#define PB1176_UART3_IRQ       { IRQ_DC1176_UART3 }
+#define PB1176_UART4_IRQ       { IRQ_PB1176_UART4 }
+#define PB1176_SSP_IRQ         { IRQ_DC1176_SSP }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,      "fpga:aaci",    AACI,           NULL);
-AMBA_DEVICE(mmc0,      "fpga:mmc0",    MMCI0,          &realview_mmc0_plat_data);
-AMBA_DEVICE(kmi0,      "fpga:kmi0",    KMI0,           NULL);
-AMBA_DEVICE(kmi1,      "fpga:kmi1",    KMI1,           NULL);
-AMBA_DEVICE(uart4,     "fpga:uart4",   PB1176_UART4,   NULL);
+APB_DEVICE(aaci,       "fpga:aaci",    AACI,           NULL);
+APB_DEVICE(mmc0,       "fpga:mmc0",    MMCI0,          &realview_mmc0_plat_data);
+APB_DEVICE(kmi0,       "fpga:kmi0",    KMI0,           NULL);
+APB_DEVICE(kmi1,       "fpga:kmi1",    KMI1,           NULL);
+APB_DEVICE(uart4,      "fpga:uart4",   PB1176_UART4,   NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,       "dev:smc",      PB1176_SMC,     NULL);
-AMBA_DEVICE(sctl,      "dev:sctl",     SCTL,           NULL);
-AMBA_DEVICE(wdog,      "dev:wdog",     PB1176_WATCHDOG,        NULL);
-AMBA_DEVICE(gpio0,     "dev:gpio0",    PB1176_GPIO0,   &gpio0_plat_data);
-AMBA_DEVICE(gpio1,     "dev:gpio1",    GPIO1,          &gpio1_plat_data);
-AMBA_DEVICE(gpio2,     "dev:gpio2",    GPIO2,          &gpio2_plat_data);
-AMBA_DEVICE(rtc,       "dev:rtc",      PB1176_RTC,     NULL);
-AMBA_DEVICE(sci0,      "dev:sci0",     SCI,            NULL);
-AMBA_DEVICE(uart0,     "dev:uart0",    PB1176_UART0,   NULL);
-AMBA_DEVICE(uart1,     "dev:uart1",    PB1176_UART1,   NULL);
-AMBA_DEVICE(uart2,     "dev:uart2",    PB1176_UART2,   NULL);
-AMBA_DEVICE(uart3,     "dev:uart3",    PB1176_UART3,   NULL);
-AMBA_DEVICE(ssp0,      "dev:ssp0",     PB1176_SSP,     &ssp0_plat_data);
-AMBA_DEVICE(clcd,      "dev:clcd",     PB1176_CLCD,    &clcd_plat_data);
+AHB_DEVICE(smc,                "dev:smc",      PB1176_SMC,     NULL);
+AHB_DEVICE(sctl,       "dev:sctl",     SCTL,           NULL);
+APB_DEVICE(wdog,       "dev:wdog",     PB1176_WATCHDOG,        NULL);
+APB_DEVICE(gpio0,      "dev:gpio0",    PB1176_GPIO0,   &gpio0_plat_data);
+APB_DEVICE(gpio1,      "dev:gpio1",    GPIO1,          &gpio1_plat_data);
+APB_DEVICE(gpio2,      "dev:gpio2",    GPIO2,          &gpio2_plat_data);
+APB_DEVICE(rtc,                "dev:rtc",      PB1176_RTC,     NULL);
+APB_DEVICE(sci0,       "dev:sci0",     SCI,            NULL);
+APB_DEVICE(uart0,      "dev:uart0",    PB1176_UART0,   NULL);
+APB_DEVICE(uart1,      "dev:uart1",    PB1176_UART1,   NULL);
+APB_DEVICE(uart2,      "dev:uart2",    PB1176_UART2,   NULL);
+APB_DEVICE(uart3,      "dev:uart3",    PB1176_UART3,   NULL);
+APB_DEVICE(ssp0,       "dev:ssp0",     PB1176_SSP,     &ssp0_plat_data);
+AHB_DEVICE(clcd,       "dev:clcd",     PB1176_CLCD,    &clcd_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
        &uart0_device,
index 2147335..a98c536 100644 (file)
@@ -36,7 +36,7 @@
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
@@ -127,52 +127,52 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  * RealView PB11MPCore AMBA devices
  */
 
-#define GPIO2_IRQ              { IRQ_PB11MP_GPIO2, NO_IRQ }
-#define GPIO3_IRQ              { IRQ_PB11MP_GPIO3, NO_IRQ }
-#define AACI_IRQ               { IRQ_TC11MP_AACI, NO_IRQ }
+#define GPIO2_IRQ              { IRQ_PB11MP_GPIO2 }
+#define GPIO3_IRQ              { IRQ_PB11MP_GPIO3 }
+#define AACI_IRQ               { IRQ_TC11MP_AACI }
 #define MMCI0_IRQ              { IRQ_TC11MP_MMCI0A, IRQ_TC11MP_MMCI0B }
-#define KMI0_IRQ               { IRQ_TC11MP_KMI0, NO_IRQ }
-#define KMI1_IRQ               { IRQ_TC11MP_KMI1, NO_IRQ }
-#define PB11MP_SMC_IRQ         { NO_IRQ, NO_IRQ }
-#define MPMC_IRQ               { NO_IRQ, NO_IRQ }
-#define PB11MP_CLCD_IRQ                { IRQ_PB11MP_CLCD, NO_IRQ }
-#define DMAC_IRQ               { IRQ_PB11MP_DMAC, NO_IRQ }
-#define SCTL_IRQ               { NO_IRQ, NO_IRQ }
-#define PB11MP_WATCHDOG_IRQ    { IRQ_PB11MP_WATCHDOG, NO_IRQ }
-#define PB11MP_GPIO0_IRQ       { IRQ_PB11MP_GPIO0, NO_IRQ }
-#define GPIO1_IRQ              { IRQ_PB11MP_GPIO1, NO_IRQ }
-#define PB11MP_RTC_IRQ         { IRQ_TC11MP_RTC, NO_IRQ }
-#define SCI_IRQ                        { IRQ_PB11MP_SCI, NO_IRQ }
-#define PB11MP_UART0_IRQ       { IRQ_TC11MP_UART0, NO_IRQ }
-#define PB11MP_UART1_IRQ       { IRQ_TC11MP_UART1, NO_IRQ }
-#define PB11MP_UART2_IRQ       { IRQ_PB11MP_UART2, NO_IRQ }
-#define PB11MP_UART3_IRQ       { IRQ_PB11MP_UART3, NO_IRQ }
-#define PB11MP_SSP_IRQ         { IRQ_PB11MP_SSP, NO_IRQ }
+#define KMI0_IRQ               { IRQ_TC11MP_KMI0 }
+#define KMI1_IRQ               { IRQ_TC11MP_KMI1 }
+#define PB11MP_SMC_IRQ         { }
+#define MPMC_IRQ               { }
+#define PB11MP_CLCD_IRQ                { IRQ_PB11MP_CLCD }
+#define DMAC_IRQ               { IRQ_PB11MP_DMAC }
+#define SCTL_IRQ               { }
+#define PB11MP_WATCHDOG_IRQ    { IRQ_PB11MP_WATCHDOG }
+#define PB11MP_GPIO0_IRQ       { IRQ_PB11MP_GPIO0 }
+#define GPIO1_IRQ              { IRQ_PB11MP_GPIO1 }
+#define PB11MP_RTC_IRQ         { IRQ_TC11MP_RTC }
+#define SCI_IRQ                        { IRQ_PB11MP_SCI }
+#define PB11MP_UART0_IRQ       { IRQ_TC11MP_UART0 }
+#define PB11MP_UART1_IRQ       { IRQ_TC11MP_UART1 }
+#define PB11MP_UART2_IRQ       { IRQ_PB11MP_UART2 }
+#define PB11MP_UART3_IRQ       { IRQ_PB11MP_UART3 }
+#define PB11MP_SSP_IRQ         { IRQ_PB11MP_SSP }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,      "fpga:aaci",    AACI,           NULL);
-AMBA_DEVICE(mmc0,      "fpga:mmc0",    MMCI0,          &realview_mmc0_plat_data);
-AMBA_DEVICE(kmi0,      "fpga:kmi0",    KMI0,           NULL);
-AMBA_DEVICE(kmi1,      "fpga:kmi1",    KMI1,           NULL);
-AMBA_DEVICE(uart3,     "fpga:uart3",   PB11MP_UART3,   NULL);
+APB_DEVICE(aaci,       "fpga:aaci",    AACI,           NULL);
+APB_DEVICE(mmc0,       "fpga:mmc0",    MMCI0,          &realview_mmc0_plat_data);
+APB_DEVICE(kmi0,       "fpga:kmi0",    KMI0,           NULL);
+APB_DEVICE(kmi1,       "fpga:kmi1",    KMI1,           NULL);
+APB_DEVICE(uart3,      "fpga:uart3",   PB11MP_UART3,   NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,       "dev:smc",      PB11MP_SMC,     NULL);
-AMBA_DEVICE(sctl,      "dev:sctl",     SCTL,           NULL);
-AMBA_DEVICE(wdog,      "dev:wdog",     PB11MP_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0,     "dev:gpio0",    PB11MP_GPIO0,   &gpio0_plat_data);
-AMBA_DEVICE(gpio1,     "dev:gpio1",    GPIO1,          &gpio1_plat_data);
-AMBA_DEVICE(gpio2,     "dev:gpio2",    GPIO2,          &gpio2_plat_data);
-AMBA_DEVICE(rtc,       "dev:rtc",      PB11MP_RTC,     NULL);
-AMBA_DEVICE(sci0,      "dev:sci0",     SCI,            NULL);
-AMBA_DEVICE(uart0,     "dev:uart0",    PB11MP_UART0,   NULL);
-AMBA_DEVICE(uart1,     "dev:uart1",    PB11MP_UART1,   NULL);
-AMBA_DEVICE(uart2,     "dev:uart2",    PB11MP_UART2,   NULL);
-AMBA_DEVICE(ssp0,      "dev:ssp0",     PB11MP_SSP,     &ssp0_plat_data);
+AHB_DEVICE(smc,                "dev:smc",      PB11MP_SMC,     NULL);
+AHB_DEVICE(sctl,       "dev:sctl",     SCTL,           NULL);
+APB_DEVICE(wdog,       "dev:wdog",     PB11MP_WATCHDOG, NULL);
+APB_DEVICE(gpio0,      "dev:gpio0",    PB11MP_GPIO0,   &gpio0_plat_data);
+APB_DEVICE(gpio1,      "dev:gpio1",    GPIO1,          &gpio1_plat_data);
+APB_DEVICE(gpio2,      "dev:gpio2",    GPIO2,          &gpio2_plat_data);
+APB_DEVICE(rtc,                "dev:rtc",      PB11MP_RTC,     NULL);
+APB_DEVICE(sci0,       "dev:sci0",     SCI,            NULL);
+APB_DEVICE(uart0,      "dev:uart0",    PB11MP_UART0,   NULL);
+APB_DEVICE(uart1,      "dev:uart1",    PB11MP_UART1,   NULL);
+APB_DEVICE(uart2,      "dev:uart2",    PB11MP_UART2,   NULL);
+APB_DEVICE(ssp0,       "dev:ssp0",     PB11MP_SSP,     &ssp0_plat_data);
 
 /* Primecells on the NEC ISSP chip */
-AMBA_DEVICE(clcd,      "issp:clcd",    PB11MP_CLCD,    &clcd_plat_data);
-AMBA_DEVICE(dmac,      "issp:dmac",    DMAC,           NULL);
+AHB_DEVICE(clcd,       "issp:clcd",    PB11MP_CLCD,    &clcd_plat_data);
+AHB_DEVICE(dmac,       "issp:dmac",    DMAC,           NULL);
 
 static struct amba_device *amba_devs[] __initdata = {
        &dmac_device,
@@ -290,6 +290,21 @@ static void __init gic_init_irq(void)
        gic_cascade_irq(1, IRQ_TC11MP_PB_IRQ1);
 }
 
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
+                             REALVIEW_TC11MP_TWD_BASE,
+                             IRQ_LOCALTIMER);
+
+static void __init realview_pb11mp_twd_init(void)
+{
+       int err = twd_local_timer_register(&twd_local_timer);
+       if (err)
+               pr_err("twd_local_timer_register failed %d\n", err);
+}
+#else
+#define realview_pb11mp_twd_init()     do {} while(0)
+#endif
+
 static void __init realview_pb11mp_timer_init(void)
 {
        timer0_va_base = __io_address(REALVIEW_PB11MP_TIMER0_1_BASE);
@@ -297,10 +312,8 @@ static void __init realview_pb11mp_timer_init(void)
        timer2_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE);
        timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20;
 
-#ifdef CONFIG_LOCAL_TIMERS
-       twd_base = __io_address(REALVIEW_TC11MP_TWD_BASE);
-#endif
        realview_timer_init(IRQ_TC11MP_TIMER0_1);
+       realview_pb11mp_twd_init();
 }
 
 static struct sys_timer realview_pb11mp_timer = {
index 25b2e59..5965017 100644 (file)
@@ -122,52 +122,52 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  * RealView PBA8Core AMBA devices
  */
 
-#define GPIO2_IRQ              { IRQ_PBA8_GPIO2, NO_IRQ }
-#define GPIO3_IRQ              { IRQ_PBA8_GPIO3, NO_IRQ }
-#define AACI_IRQ               { IRQ_PBA8_AACI, NO_IRQ }
+#define GPIO2_IRQ              { IRQ_PBA8_GPIO2 }
+#define GPIO3_IRQ              { IRQ_PBA8_GPIO3 }
+#define AACI_IRQ               { IRQ_PBA8_AACI }
 #define MMCI0_IRQ              { IRQ_PBA8_MMCI0A, IRQ_PBA8_MMCI0B }
-#define KMI0_IRQ               { IRQ_PBA8_KMI0, NO_IRQ }
-#define KMI1_IRQ               { IRQ_PBA8_KMI1, NO_IRQ }
-#define PBA8_SMC_IRQ           { NO_IRQ, NO_IRQ }
-#define MPMC_IRQ               { NO_IRQ, NO_IRQ }
-#define PBA8_CLCD_IRQ          { IRQ_PBA8_CLCD, NO_IRQ }
-#define DMAC_IRQ               { IRQ_PBA8_DMAC, NO_IRQ }
-#define SCTL_IRQ               { NO_IRQ, NO_IRQ }
-#define PBA8_WATCHDOG_IRQ      { IRQ_PBA8_WATCHDOG, NO_IRQ }
-#define PBA8_GPIO0_IRQ         { IRQ_PBA8_GPIO0, NO_IRQ }
-#define GPIO1_IRQ              { IRQ_PBA8_GPIO1, NO_IRQ }
-#define PBA8_RTC_IRQ           { IRQ_PBA8_RTC, NO_IRQ }
-#define SCI_IRQ                        { IRQ_PBA8_SCI, NO_IRQ }
-#define PBA8_UART0_IRQ         { IRQ_PBA8_UART0, NO_IRQ }
-#define PBA8_UART1_IRQ         { IRQ_PBA8_UART1, NO_IRQ }
-#define PBA8_UART2_IRQ         { IRQ_PBA8_UART2, NO_IRQ }
-#define PBA8_UART3_IRQ         { IRQ_PBA8_UART3, NO_IRQ }
-#define PBA8_SSP_IRQ           { IRQ_PBA8_SSP, NO_IRQ }
+#define KMI0_IRQ               { IRQ_PBA8_KMI0 }
+#define KMI1_IRQ               { IRQ_PBA8_KMI1 }
+#define PBA8_SMC_IRQ           { }
+#define MPMC_IRQ               { }
+#define PBA8_CLCD_IRQ          { IRQ_PBA8_CLCD }
+#define DMAC_IRQ               { IRQ_PBA8_DMAC }
+#define SCTL_IRQ               { }
+#define PBA8_WATCHDOG_IRQ      { IRQ_PBA8_WATCHDOG }
+#define PBA8_GPIO0_IRQ         { IRQ_PBA8_GPIO0 }
+#define GPIO1_IRQ              { IRQ_PBA8_GPIO1 }
+#define PBA8_RTC_IRQ           { IRQ_PBA8_RTC }
+#define SCI_IRQ                        { IRQ_PBA8_SCI }
+#define PBA8_UART0_IRQ         { IRQ_PBA8_UART0 }
+#define PBA8_UART1_IRQ         { IRQ_PBA8_UART1 }
+#define PBA8_UART2_IRQ         { IRQ_PBA8_UART2 }
+#define PBA8_UART3_IRQ         { IRQ_PBA8_UART3 }
+#define PBA8_SSP_IRQ           { IRQ_PBA8_SSP }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,      "fpga:aaci",    AACI,           NULL);
-AMBA_DEVICE(mmc0,      "fpga:mmc0",    MMCI0,          &realview_mmc0_plat_data);
-AMBA_DEVICE(kmi0,      "fpga:kmi0",    KMI0,           NULL);
-AMBA_DEVICE(kmi1,      "fpga:kmi1",    KMI1,           NULL);
-AMBA_DEVICE(uart3,     "fpga:uart3",   PBA8_UART3,     NULL);
+APB_DEVICE(aaci,       "fpga:aaci",    AACI,           NULL);
+APB_DEVICE(mmc0,       "fpga:mmc0",    MMCI0,          &realview_mmc0_plat_data);
+APB_DEVICE(kmi0,       "fpga:kmi0",    KMI0,           NULL);
+APB_DEVICE(kmi1,       "fpga:kmi1",    KMI1,           NULL);
+APB_DEVICE(uart3,      "fpga:uart3",   PBA8_UART3,     NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,       "dev:smc",      PBA8_SMC,       NULL);
-AMBA_DEVICE(sctl,      "dev:sctl",     SCTL,           NULL);
-AMBA_DEVICE(wdog,      "dev:wdog",     PBA8_WATCHDOG, NULL);
-AMBA_DEVICE(gpio0,     "dev:gpio0",    PBA8_GPIO0,     &gpio0_plat_data);
-AMBA_DEVICE(gpio1,     "dev:gpio1",    GPIO1,          &gpio1_plat_data);
-AMBA_DEVICE(gpio2,     "dev:gpio2",    GPIO2,          &gpio2_plat_data);
-AMBA_DEVICE(rtc,       "dev:rtc",      PBA8_RTC,       NULL);
-AMBA_DEVICE(sci0,      "dev:sci0",     SCI,            NULL);
-AMBA_DEVICE(uart0,     "dev:uart0",    PBA8_UART0,     NULL);
-AMBA_DEVICE(uart1,     "dev:uart1",    PBA8_UART1,     NULL);
-AMBA_DEVICE(uart2,     "dev:uart2",    PBA8_UART2,     NULL);
-AMBA_DEVICE(ssp0,      "dev:ssp0",     PBA8_SSP,       &ssp0_plat_data);
+AHB_DEVICE(smc,                "dev:smc",      PBA8_SMC,       NULL);
+AHB_DEVICE(sctl,       "dev:sctl",     SCTL,           NULL);
+APB_DEVICE(wdog,       "dev:wdog",     PBA8_WATCHDOG, NULL);
+APB_DEVICE(gpio0,      "dev:gpio0",    PBA8_GPIO0,     &gpio0_plat_data);
+APB_DEVICE(gpio1,      "dev:gpio1",    GPIO1,          &gpio1_plat_data);
+APB_DEVICE(gpio2,      "dev:gpio2",    GPIO2,          &gpio2_plat_data);
+APB_DEVICE(rtc,                "dev:rtc",      PBA8_RTC,       NULL);
+APB_DEVICE(sci0,       "dev:sci0",     SCI,            NULL);
+APB_DEVICE(uart0,      "dev:uart0",    PBA8_UART0,     NULL);
+APB_DEVICE(uart1,      "dev:uart1",    PBA8_UART1,     NULL);
+APB_DEVICE(uart2,      "dev:uart2",    PBA8_UART2,     NULL);
+APB_DEVICE(ssp0,       "dev:ssp0",     PBA8_SSP,       &ssp0_plat_data);
 
 /* Primecells on the NEC ISSP chip */
-AMBA_DEVICE(clcd,      "issp:clcd",    PBA8_CLCD,      &clcd_plat_data);
-AMBA_DEVICE(dmac,      "issp:dmac",    DMAC,           NULL);
+AHB_DEVICE(clcd,       "issp:clcd",    PBA8_CLCD,      &clcd_plat_data);
+AHB_DEVICE(dmac,       "issp:dmac",    DMAC,           NULL);
 
 static struct amba_device *amba_devs[] __initdata = {
        &dmac_device,
index ac71564..3f2f605 100644 (file)
@@ -144,52 +144,52 @@ static struct pl022_ssp_controller ssp0_plat_data = {
  * RealView PBXCore AMBA devices
  */
 
-#define GPIO2_IRQ              { IRQ_PBX_GPIO2, NO_IRQ }
-#define GPIO3_IRQ              { IRQ_PBX_GPIO3, NO_IRQ }
-#define AACI_IRQ               { IRQ_PBX_AACI, NO_IRQ }
+#define GPIO2_IRQ              { IRQ_PBX_GPIO2 }
+#define GPIO3_IRQ              { IRQ_PBX_GPIO3 }
+#define AACI_IRQ               { IRQ_PBX_AACI }
 #define MMCI0_IRQ              { IRQ_PBX_MMCI0A, IRQ_PBX_MMCI0B }
-#define KMI0_IRQ               { IRQ_PBX_KMI0, NO_IRQ }
-#define KMI1_IRQ               { IRQ_PBX_KMI1, NO_IRQ }
-#define PBX_SMC_IRQ            { NO_IRQ, NO_IRQ }
-#define MPMC_IRQ               { NO_IRQ, NO_IRQ }
-#define PBX_CLCD_IRQ           { IRQ_PBX_CLCD, NO_IRQ }
-#define DMAC_IRQ               { IRQ_PBX_DMAC, NO_IRQ }
-#define SCTL_IRQ               { NO_IRQ, NO_IRQ }
-#define PBX_WATCHDOG_IRQ       { IRQ_PBX_WATCHDOG, NO_IRQ }
-#define PBX_GPIO0_IRQ          { IRQ_PBX_GPIO0, NO_IRQ }
-#define GPIO1_IRQ              { IRQ_PBX_GPIO1, NO_IRQ }
-#define PBX_RTC_IRQ            { IRQ_PBX_RTC, NO_IRQ }
-#define SCI_IRQ                        { IRQ_PBX_SCI, NO_IRQ }
-#define PBX_UART0_IRQ          { IRQ_PBX_UART0, NO_IRQ }
-#define PBX_UART1_IRQ          { IRQ_PBX_UART1, NO_IRQ }
-#define PBX_UART2_IRQ          { IRQ_PBX_UART2, NO_IRQ }
-#define PBX_UART3_IRQ          { IRQ_PBX_UART3, NO_IRQ }
-#define PBX_SSP_IRQ            { IRQ_PBX_SSP, NO_IRQ }
+#define KMI0_IRQ               { IRQ_PBX_KMI0 }
+#define KMI1_IRQ               { IRQ_PBX_KMI1 }
+#define PBX_SMC_IRQ            { }
+#define MPMC_IRQ               { }
+#define PBX_CLCD_IRQ           { IRQ_PBX_CLCD }
+#define DMAC_IRQ               { IRQ_PBX_DMAC }
+#define SCTL_IRQ               { }
+#define PBX_WATCHDOG_IRQ       { IRQ_PBX_WATCHDOG }
+#define PBX_GPIO0_IRQ          { IRQ_PBX_GPIO0 }
+#define GPIO1_IRQ              { IRQ_PBX_GPIO1 }
+#define PBX_RTC_IRQ            { IRQ_PBX_RTC }
+#define SCI_IRQ                        { IRQ_PBX_SCI }
+#define PBX_UART0_IRQ          { IRQ_PBX_UART0 }
+#define PBX_UART1_IRQ          { IRQ_PBX_UART1 }
+#define PBX_UART2_IRQ          { IRQ_PBX_UART2 }
+#define PBX_UART3_IRQ          { IRQ_PBX_UART3 }
+#define PBX_SSP_IRQ            { IRQ_PBX_SSP }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,      "fpga:aaci",    AACI,           NULL);
-AMBA_DEVICE(mmc0,      "fpga:mmc0",    MMCI0,          &realview_mmc0_plat_data);
-AMBA_DEVICE(kmi0,      "fpga:kmi0",    KMI0,           NULL);
-AMBA_DEVICE(kmi1,      "fpga:kmi1",    KMI1,           NULL);
-AMBA_DEVICE(uart3,     "fpga:uart3",   PBX_UART3,      NULL);
+APB_DEVICE(aaci,       "fpga:aaci",    AACI,           NULL);
+APB_DEVICE(mmc0,       "fpga:mmc0",    MMCI0,          &realview_mmc0_plat_data);
+APB_DEVICE(kmi0,       "fpga:kmi0",    KMI0,           NULL);
+APB_DEVICE(kmi1,       "fpga:kmi1",    KMI1,           NULL);
+APB_DEVICE(uart3,      "fpga:uart3",   PBX_UART3,      NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,       "dev:smc",      PBX_SMC,        NULL);
-AMBA_DEVICE(sctl,      "dev:sctl",     SCTL,           NULL);
-AMBA_DEVICE(wdog,      "dev:wdog",     PBX_WATCHDOG,   NULL);
-AMBA_DEVICE(gpio0,     "dev:gpio0",    PBX_GPIO0,      &gpio0_plat_data);
-AMBA_DEVICE(gpio1,     "dev:gpio1",    GPIO1,          &gpio1_plat_data);
-AMBA_DEVICE(gpio2,     "dev:gpio2",    GPIO2,          &gpio2_plat_data);
-AMBA_DEVICE(rtc,       "dev:rtc",      PBX_RTC,        NULL);
-AMBA_DEVICE(sci0,      "dev:sci0",     SCI,            NULL);
-AMBA_DEVICE(uart0,     "dev:uart0",    PBX_UART0,      NULL);
-AMBA_DEVICE(uart1,     "dev:uart1",    PBX_UART1,      NULL);
-AMBA_DEVICE(uart2,     "dev:uart2",    PBX_UART2,      NULL);
-AMBA_DEVICE(ssp0,      "dev:ssp0",     PBX_SSP,        &ssp0_plat_data);
+AHB_DEVICE(smc,        "dev:smc",      PBX_SMC,        NULL);
+AHB_DEVICE(sctl,       "dev:sctl",     SCTL,           NULL);
+APB_DEVICE(wdog,       "dev:wdog",     PBX_WATCHDOG,   NULL);
+APB_DEVICE(gpio0,      "dev:gpio0",    PBX_GPIO0,      &gpio0_plat_data);
+APB_DEVICE(gpio1,      "dev:gpio1",    GPIO1,          &gpio1_plat_data);
+APB_DEVICE(gpio2,      "dev:gpio2",    GPIO2,          &gpio2_plat_data);
+APB_DEVICE(rtc,                "dev:rtc",      PBX_RTC,        NULL);
+APB_DEVICE(sci0,       "dev:sci0",     SCI,            NULL);
+APB_DEVICE(uart0,      "dev:uart0",    PBX_UART0,      NULL);
+APB_DEVICE(uart1,      "dev:uart1",    PBX_UART1,      NULL);
+APB_DEVICE(uart2,      "dev:uart2",    PBX_UART2,      NULL);
+APB_DEVICE(ssp0,       "dev:ssp0",     PBX_SSP,        &ssp0_plat_data);
 
 /* Primecells on the NEC ISSP chip */
-AMBA_DEVICE(clcd,      "issp:clcd",    PBX_CLCD,       &clcd_plat_data);
-AMBA_DEVICE(dmac,      "issp:dmac",    DMAC,           NULL);
+AHB_DEVICE(clcd,       "issp:clcd",    PBX_CLCD,       &clcd_plat_data);
+AHB_DEVICE(dmac,       "issp:dmac",    DMAC,           NULL);
 
 static struct amba_device *amba_devs[] __initdata = {
        &dmac_device,
@@ -298,6 +298,21 @@ static void __init gic_init_irq(void)
        }
 }
 
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
+                             REALVIEW_PBX_TILE_TWD_BASE,
+                             IRQ_LOCALTIMER);
+
+static void __init realview_pbx_twd_init(void)
+{
+       int err = twd_local_timer_register(&twd_local_timer);
+       if (err)
+               pr_err("twd_local_timer_register failed %d\n", err);
+}
+#else
+#define realview_pbx_twd_init()        do { } while(0)
+#endif
+
 static void __init realview_pbx_timer_init(void)
 {
        timer0_va_base = __io_address(REALVIEW_PBX_TIMER0_1_BASE);
@@ -305,11 +320,8 @@ static void __init realview_pbx_timer_init(void)
        timer2_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE);
        timer3_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE) + 0x20;
 
-#ifdef CONFIG_LOCAL_TIMERS
-       if (core_tile_pbx11mp() || core_tile_pbxa9mp())
-               twd_base = __io_address(REALVIEW_PBX_TILE_TWD_BASE);
-#endif
        realview_timer_init(IRQ_PBX_TIMER0_1);
+       realview_pbx_twd_init();
 }
 
 static struct sys_timer realview_pbx_timer = {
index aa77bc9..992e28b 100644 (file)
@@ -4,7 +4,7 @@
 
 # Object file lists.
 
-obj-y                  := dma.o irq.o riscpc.o
+obj-y                  := dma.o ecard.o fiq.o irq.o riscpc.o time.o
 obj-m                  :=
 obj-n                  :=
 obj-                   :=
diff --git a/arch/arm/mach-rpc/ecard.c b/arch/arm/mach-rpc/ecard.c
new file mode 100644 (file)
index 0000000..b91bc87
--- /dev/null
@@ -0,0 +1,1138 @@
+/*
+ *  linux/arch/arm/kernel/ecard.c
+ *
+ *  Copyright 1995-2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Find all installed expansion cards, and handle interrupts from them.
+ *
+ *  Created from information from Acorns RiscOS3 PRMs
+ *
+ *  08-Dec-1996        RMK     Added code for the 9'th expansion card - the ether
+ *                     podule slot.
+ *  06-May-1997        RMK     Added blacklist for cards whose loader doesn't work.
+ *  12-Sep-1997        RMK     Created new handling of interrupt enables/disables
+ *                     - cards can now register their own routine to control
+ *                     interrupts (recommended).
+ *  29-Sep-1997        RMK     Expansion card interrupt hardware not being re-enabled
+ *                     on reset from Linux. (Caused cards not to respond
+ *                     under RiscOS without hard reset).
+ *  15-Feb-1998        RMK     Added DMA support
+ *  12-Sep-1998        RMK     Added EASI support
+ *  10-Jan-1999        RMK     Run loaders in a simulated RISC OS environment.
+ *  17-Apr-1999        RMK     Support for EASI Type C cycles.
+ */
+#define ECARD_C
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/reboot.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mmu_context.h>
+#include <asm/mach/irq.h>
+#include <asm/tlbflush.h>
+
+#include "ecard.h"
+
+struct ecard_request {
+       void            (*fn)(struct ecard_request *);
+       ecard_t         *ec;
+       unsigned int    address;
+       unsigned int    length;
+       unsigned int    use_loader;
+       void            *buffer;
+       struct completion *complete;
+};
+
+struct expcard_blacklist {
+       unsigned short   manufacturer;
+       unsigned short   product;
+       const char      *type;
+};
+
+static ecard_t *cards;
+static ecard_t *slot_to_expcard[MAX_ECARDS];
+static unsigned int ectcr;
+
+/* List of descriptions of cards which don't have an extended
+ * identification, or chunk directories containing a description.
+ */
+static struct expcard_blacklist __initdata blacklist[] = {
+       { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
+};
+
+asmlinkage extern int
+ecard_loader_reset(unsigned long base, loader_t loader);
+asmlinkage extern int
+ecard_loader_read(int off, unsigned long base, loader_t loader);
+
+static inline unsigned short ecard_getu16(unsigned char *v)
+{
+       return v[0] | v[1] << 8;
+}
+
+static inline signed long ecard_gets24(unsigned char *v)
+{
+       return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
+}
+
+static inline ecard_t *slot_to_ecard(unsigned int slot)
+{
+       return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
+}
+
+/* ===================== Expansion card daemon ======================== */
+/*
+ * Since the loader programs on the expansion cards need to be run
+ * in a specific environment, create a separate task with this
+ * environment up, and pass requests to this task as and when we
+ * need to.
+ *
+ * This should allow 99% of loaders to be called from Linux.
+ *
+ * From a security standpoint, we trust the card vendors.  This
+ * may be a misplaced trust.
+ */
+static void ecard_task_reset(struct ecard_request *req)
+{
+       struct expansion_card *ec = req->ec;
+       struct resource *res;
+
+       res = ec->slot_no == 8
+               ? &ec->resource[ECARD_RES_MEMC]
+               : ec->easi
+                 ? &ec->resource[ECARD_RES_EASI]
+                 : &ec->resource[ECARD_RES_IOCSYNC];
+
+       ecard_loader_reset(res->start, ec->loader);
+}
+
+static void ecard_task_readbytes(struct ecard_request *req)
+{
+       struct expansion_card *ec = req->ec;
+       unsigned char *buf = req->buffer;
+       unsigned int len = req->length;
+       unsigned int off = req->address;
+
+       if (ec->slot_no == 8) {
+               void __iomem *base = (void __iomem *)
+                               ec->resource[ECARD_RES_MEMC].start;
+
+               /*
+                * The card maintains an index which increments the address
+                * into a 4096-byte page on each access.  We need to keep
+                * track of the counter.
+                */
+               static unsigned int index;
+               unsigned int page;
+
+               page = (off >> 12) * 4;
+               if (page > 256 * 4)
+                       return;
+
+               off &= 4095;
+
+               /*
+                * If we are reading offset 0, or our current index is
+                * greater than the offset, reset the hardware index counter.
+                */
+               if (off == 0 || index > off) {
+                       writeb(0, base);
+                       index = 0;
+               }
+
+               /*
+                * Increment the hardware index counter until we get to the
+                * required offset.  The read bytes are discarded.
+                */
+               while (index < off) {
+                       readb(base + page);
+                       index += 1;
+               }
+
+               while (len--) {
+                       *buf++ = readb(base + page);
+                       index += 1;
+               }
+       } else {
+               unsigned long base = (ec->easi
+                        ? &ec->resource[ECARD_RES_EASI]
+                        : &ec->resource[ECARD_RES_IOCSYNC])->start;
+               void __iomem *pbase = (void __iomem *)base;
+
+               if (!req->use_loader || !ec->loader) {
+                       off *= 4;
+                       while (len--) {
+                               *buf++ = readb(pbase + off);
+                               off += 4;
+                       }
+               } else {
+                       while(len--) {
+                               /*
+                                * The following is required by some
+                                * expansion card loader programs.
+                                */
+                               *(unsigned long *)0x108 = 0;
+                               *buf++ = ecard_loader_read(off++, base,
+                                                          ec->loader);
+                       }
+               }
+       }
+
+}
+
+static DECLARE_WAIT_QUEUE_HEAD(ecard_wait);
+static struct ecard_request *ecard_req;
+static DEFINE_MUTEX(ecard_mutex);
+
+/*
+ * Set up the expansion card daemon's page tables.
+ */
+static void ecard_init_pgtables(struct mm_struct *mm)
+{
+       struct vm_area_struct vma;
+
+       /* We want to set up the page tables for the following mapping:
+        *  Virtual     Physical
+        *  0x03000000  0x03000000
+        *  0x03010000  unmapped
+        *  0x03210000  0x03210000
+        *  0x03400000  unmapped
+        *  0x08000000  0x08000000
+        *  0x10000000  unmapped
+        *
+        * FIXME: we don't follow this 100% yet.
+        */
+       pgd_t *src_pgd, *dst_pgd;
+
+       src_pgd = pgd_offset(mm, (unsigned long)IO_BASE);
+       dst_pgd = pgd_offset(mm, IO_START);
+
+       memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
+
+       src_pgd = pgd_offset(mm, (unsigned long)EASI_BASE);
+       dst_pgd = pgd_offset(mm, EASI_START);
+
+       memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
+
+       vma.vm_flags = VM_EXEC;
+       vma.vm_mm = mm;
+
+       flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
+       flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE);
+}
+
+static int ecard_init_mm(void)
+{
+       struct mm_struct * mm = mm_alloc();
+       struct mm_struct *active_mm = current->active_mm;
+
+       if (!mm)
+               return -ENOMEM;
+
+       current->mm = mm;
+       current->active_mm = mm;
+       activate_mm(active_mm, mm);
+       mmdrop(active_mm);
+       ecard_init_pgtables(mm);
+       return 0;
+}
+
+static int
+ecard_task(void * unused)
+{
+       /*
+        * Allocate a mm.  We're not a lazy-TLB kernel task since we need
+        * to set page table entries where the user space would be.  Note
+        * that this also creates the page tables.  Failure is not an
+        * option here.
+        */
+       if (ecard_init_mm())
+               panic("kecardd: unable to alloc mm\n");
+
+       while (1) {
+               struct ecard_request *req;
+
+               wait_event_interruptible(ecard_wait, ecard_req != NULL);
+
+               req = xchg(&ecard_req, NULL);
+               if (req != NULL) {
+                       req->fn(req);
+                       complete(req->complete);
+               }
+       }
+}
+
+/*
+ * Wake the expansion card daemon to action our request.
+ *
+ * FIXME: The test here is not sufficient to detect if the
+ * kcardd is running.
+ */
+static void ecard_call(struct ecard_request *req)
+{
+       DECLARE_COMPLETION_ONSTACK(completion);
+
+       req->complete = &completion;
+
+       mutex_lock(&ecard_mutex);
+       ecard_req = req;
+       wake_up(&ecard_wait);
+
+       /*
+        * Now wait for kecardd to run.
+        */
+       wait_for_completion(&completion);
+       mutex_unlock(&ecard_mutex);
+}
+
+/* ======================= Mid-level card control ===================== */
+
+static void
+ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
+{
+       struct ecard_request req;
+
+       req.fn          = ecard_task_readbytes;
+       req.ec          = ec;
+       req.address     = off;
+       req.length      = len;
+       req.use_loader  = useld;
+       req.buffer      = addr;
+
+       ecard_call(&req);
+}
+
+int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
+{
+       struct ex_chunk_dir excd;
+       int index = 16;
+       int useld = 0;
+
+       if (!ec->cid.cd)
+               return 0;
+
+       while(1) {
+               ecard_readbytes(&excd, ec, index, 8, useld);
+               index += 8;
+               if (c_id(&excd) == 0) {
+                       if (!useld && ec->loader) {
+                               useld = 1;
+                               index = 0;
+                               continue;
+                       }
+                       return 0;
+               }
+               if (c_id(&excd) == 0xf0) { /* link */
+                       index = c_start(&excd);
+                       continue;
+               }
+               if (c_id(&excd) == 0x80) { /* loader */
+                       if (!ec->loader) {
+                               ec->loader = kmalloc(c_len(&excd),
+                                                              GFP_KERNEL);
+                               if (ec->loader)
+                                       ecard_readbytes(ec->loader, ec,
+                                                       (int)c_start(&excd),
+                                                       c_len(&excd), useld);
+                               else
+                                       return 0;
+                       }
+                       continue;
+               }
+               if (c_id(&excd) == id && num-- == 0)
+                       break;
+       }
+
+       if (c_id(&excd) & 0x80) {
+               switch (c_id(&excd) & 0x70) {
+               case 0x70:
+                       ecard_readbytes((unsigned char *)excd.d.string, ec,
+                                       (int)c_start(&excd), c_len(&excd),
+                                       useld);
+                       break;
+               case 0x00:
+                       break;
+               }
+       }
+       cd->start_offset = c_start(&excd);
+       memcpy(cd->d.string, excd.d.string, 256);
+       return 1;
+}
+
+/* ======================= Interrupt control ============================ */
+
+static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
+{
+}
+
+static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
+{
+}
+
+static int ecard_def_irq_pending(ecard_t *ec)
+{
+       return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask;
+}
+
+static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
+{
+       panic("ecard_def_fiq_enable called - impossible");
+}
+
+static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
+{
+       panic("ecard_def_fiq_disable called - impossible");
+}
+
+static int ecard_def_fiq_pending(ecard_t *ec)
+{
+       return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask;
+}
+
+static expansioncard_ops_t ecard_default_ops = {
+       ecard_def_irq_enable,
+       ecard_def_irq_disable,
+       ecard_def_irq_pending,
+       ecard_def_fiq_enable,
+       ecard_def_fiq_disable,
+       ecard_def_fiq_pending
+};
+
+/*
+ * Enable and disable interrupts from expansion cards.
+ * (interrupts are disabled for these functions).
+ *
+ * They are not meant to be called directly, but via enable/disable_irq.
+ */
+static void ecard_irq_unmask(struct irq_data *d)
+{
+       ecard_t *ec = irq_data_get_irq_chip_data(d);
+
+       if (ec) {
+               if (!ec->ops)
+                       ec->ops = &ecard_default_ops;
+
+               if (ec->claimed && ec->ops->irqenable)
+                       ec->ops->irqenable(ec, d->irq);
+               else
+                       printk(KERN_ERR "ecard: rejecting request to "
+                               "enable IRQs for %d\n", d->irq);
+       }
+}
+
+static void ecard_irq_mask(struct irq_data *d)
+{
+       ecard_t *ec = irq_data_get_irq_chip_data(d);
+
+       if (ec) {
+               if (!ec->ops)
+                       ec->ops = &ecard_default_ops;
+
+               if (ec->ops && ec->ops->irqdisable)
+                       ec->ops->irqdisable(ec, d->irq);
+       }
+}
+
+static struct irq_chip ecard_chip = {
+       .name           = "ECARD",
+       .irq_ack        = ecard_irq_mask,
+       .irq_mask       = ecard_irq_mask,
+       .irq_unmask     = ecard_irq_unmask,
+};
+
+void ecard_enablefiq(unsigned int fiqnr)
+{
+       ecard_t *ec = slot_to_ecard(fiqnr);
+
+       if (ec) {
+               if (!ec->ops)
+                       ec->ops = &ecard_default_ops;
+
+               if (ec->claimed && ec->ops->fiqenable)
+                       ec->ops->fiqenable(ec, fiqnr);
+               else
+                       printk(KERN_ERR "ecard: rejecting request to "
+                               "enable FIQs for %d\n", fiqnr);
+       }
+}
+
+void ecard_disablefiq(unsigned int fiqnr)
+{
+       ecard_t *ec = slot_to_ecard(fiqnr);
+
+       if (ec) {
+               if (!ec->ops)
+                       ec->ops = &ecard_default_ops;
+
+               if (ec->ops->fiqdisable)
+                       ec->ops->fiqdisable(ec, fiqnr);
+       }
+}
+
+static void ecard_dump_irq_state(void)
+{
+       ecard_t *ec;
+
+       printk("Expansion card IRQ state:\n");
+
+       for (ec = cards; ec; ec = ec->next) {
+               if (ec->slot_no == 8)
+                       continue;
+
+               printk("  %d: %sclaimed, ",
+                      ec->slot_no, ec->claimed ? "" : "not ");
+
+               if (ec->ops && ec->ops->irqpending &&
+                   ec->ops != &ecard_default_ops)
+                       printk("irq %spending\n",
+                              ec->ops->irqpending(ec) ? "" : "not ");
+               else
+                       printk("irqaddr %p, mask = %02X, status = %02X\n",
+                              ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
+       }
+}
+
+static void ecard_check_lockup(struct irq_desc *desc)
+{
+       static unsigned long last;
+       static int lockup;
+
+       /*
+        * If the timer interrupt has not run since the last million
+        * unrecognised expansion card interrupts, then there is
+        * something seriously wrong.  Disable the expansion card
+        * interrupts so at least we can continue.
+        *
+        * Maybe we ought to start a timer to re-enable them some time
+        * later?
+        */
+       if (last == jiffies) {
+               lockup += 1;
+               if (lockup > 1000000) {
+                       printk(KERN_ERR "\nInterrupt lockup detected - "
+                              "disabling all expansion card interrupts\n");
+
+                       desc->irq_data.chip->irq_mask(&desc->irq_data);
+                       ecard_dump_irq_state();
+               }
+       } else
+               lockup = 0;
+
+       /*
+        * If we did not recognise the source of this interrupt,
+        * warn the user, but don't flood the user with these messages.
+        */
+       if (!last || time_after(jiffies, last + 5*HZ)) {
+               last = jiffies;
+               printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
+               ecard_dump_irq_state();
+       }
+}
+
+static void
+ecard_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       ecard_t *ec;
+       int called = 0;
+
+       desc->irq_data.chip->irq_mask(&desc->irq_data);
+       for (ec = cards; ec; ec = ec->next) {
+               int pending;
+
+               if (!ec->claimed || !ec->irq || ec->slot_no == 8)
+                       continue;
+
+               if (ec->ops && ec->ops->irqpending)
+                       pending = ec->ops->irqpending(ec);
+               else
+                       pending = ecard_default_ops.irqpending(ec);
+
+               if (pending) {
+                       generic_handle_irq(ec->irq);
+                       called ++;
+               }
+       }
+       desc->irq_data.chip->irq_unmask(&desc->irq_data);
+
+       if (called == 0)
+               ecard_check_lockup(desc);
+}
+
+static void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
+{
+       void __iomem *address = NULL;
+       int slot = ec->slot_no;
+
+       if (ec->slot_no == 8)
+               return ECARD_MEMC8_BASE;
+
+       ectcr &= ~(1 << slot);
+
+       switch (type) {
+       case ECARD_MEMC:
+               if (slot < 4)
+                       address = ECARD_MEMC_BASE + (slot << 14);
+               break;
+
+       case ECARD_IOC:
+               if (slot < 4)
+                       address = ECARD_IOC_BASE + (slot << 14);
+               else
+                       address = ECARD_IOC4_BASE + ((slot - 4) << 14);
+               if (address)
+                       address += speed << 19;
+               break;
+
+       case ECARD_EASI:
+               address = ECARD_EASI_BASE + (slot << 24);
+               if (speed == ECARD_FAST)
+                       ectcr |= 1 << slot;
+               break;
+
+       default:
+               break;
+       }
+
+#ifdef IOMD_ECTCR
+       iomd_writeb(ectcr, IOMD_ECTCR);
+#endif
+       return address;
+}
+
+static int ecard_prints(struct seq_file *m, ecard_t *ec)
+{
+       seq_printf(m, "  %d: %s ", ec->slot_no, ec->easi ? "EASI" : "    ");
+
+       if (ec->cid.id == 0) {
+               struct in_chunk_dir incd;
+
+               seq_printf(m, "[%04X:%04X] ",
+                       ec->cid.manufacturer, ec->cid.product);
+
+               if (!ec->card_desc && ec->cid.cd &&
+                   ecard_readchunk(&incd, ec, 0xf5, 0)) {
+                       ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL);
+
+                       if (ec->card_desc)
+                               strcpy((char *)ec->card_desc, incd.d.string);
+               }
+
+               seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
+       } else
+               seq_printf(m, "Simple card %d\n", ec->cid.id);
+
+       return 0;
+}
+
+static int ecard_devices_proc_show(struct seq_file *m, void *v)
+{
+       ecard_t *ec = cards;
+
+       while (ec) {
+               ecard_prints(m, ec);
+               ec = ec->next;
+       }
+       return 0;
+}
+
+static int ecard_devices_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ecard_devices_proc_show, NULL);
+}
+
+static const struct file_operations bus_ecard_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ecard_devices_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
+
+static void ecard_proc_init(void)
+{
+       proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL);
+       proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops);
+}
+
+#define ec_set_resource(ec,nr,st,sz)                           \
+       do {                                                    \
+               (ec)->resource[nr].name = dev_name(&ec->dev);   \
+               (ec)->resource[nr].start = st;                  \
+               (ec)->resource[nr].end = (st) + (sz) - 1;       \
+               (ec)->resource[nr].flags = IORESOURCE_MEM;      \
+       } while (0)
+
+static void __init ecard_free_card(struct expansion_card *ec)
+{
+       int i;
+
+       for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+               if (ec->resource[i].flags)
+                       release_resource(&ec->resource[i]);
+
+       kfree(ec);
+}
+
+static struct expansion_card *__init ecard_alloc_card(int type, int slot)
+{
+       struct expansion_card *ec;
+       unsigned long base;
+       int i;
+
+       ec = kzalloc(sizeof(ecard_t), GFP_KERNEL);
+       if (!ec) {
+               ec = ERR_PTR(-ENOMEM);
+               goto nomem;
+       }
+
+       ec->slot_no = slot;
+       ec->easi = type == ECARD_EASI;
+       ec->irq = 0;
+       ec->fiq = 0;
+       ec->dma = NO_DMA;
+       ec->ops = &ecard_default_ops;
+
+       dev_set_name(&ec->dev, "ecard%d", slot);
+       ec->dev.parent = NULL;
+       ec->dev.bus = &ecard_bus_type;
+       ec->dev.dma_mask = &ec->dma_mask;
+       ec->dma_mask = (u64)0xffffffff;
+       ec->dev.coherent_dma_mask = ec->dma_mask;
+
+       if (slot < 4) {
+               ec_set_resource(ec, ECARD_RES_MEMC,
+                               PODSLOT_MEMC_BASE + (slot << 14),
+                               PODSLOT_MEMC_SIZE);
+               base = PODSLOT_IOC0_BASE + (slot << 14);
+       } else
+               base = PODSLOT_IOC4_BASE + ((slot - 4) << 14);
+
+#ifdef CONFIG_ARCH_RPC
+       if (slot < 8) {
+               ec_set_resource(ec, ECARD_RES_EASI,
+                               PODSLOT_EASI_BASE + (slot << 24),
+                               PODSLOT_EASI_SIZE);
+       }
+
+       if (slot == 8) {
+               ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE);
+       } else
+#endif
+
+       for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++)
+               ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
+                               base + (i << 19), PODSLOT_IOC_SIZE);
+
+       for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
+               if (ec->resource[i].flags &&
+                   request_resource(&iomem_resource, &ec->resource[i])) {
+                       dev_err(&ec->dev, "resource(s) not available\n");
+                       ec->resource[i].end -= ec->resource[i].start;
+                       ec->resource[i].start = 0;
+                       ec->resource[i].flags = 0;
+               }
+       }
+
+ nomem:
+       return ec;
+}
+
+static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct expansion_card *ec = ECARD_DEV(dev);
+       return sprintf(buf, "%u\n", ec->irq);
+}
+
+static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct expansion_card *ec = ECARD_DEV(dev);
+       return sprintf(buf, "%u\n", ec->dma);
+}
+
+static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct expansion_card *ec = ECARD_DEV(dev);
+       char *str = buf;
+       int i;
+
+       for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+               str += sprintf(str, "%08x %08x %08lx\n",
+                               ec->resource[i].start,
+                               ec->resource[i].end,
+                               ec->resource[i].flags);
+
+       return str - buf;
+}
+
+static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct expansion_card *ec = ECARD_DEV(dev);
+       return sprintf(buf, "%u\n", ec->cid.manufacturer);
+}
+
+static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct expansion_card *ec = ECARD_DEV(dev);
+       return sprintf(buf, "%u\n", ec->cid.product);
+}
+
+static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct expansion_card *ec = ECARD_DEV(dev);
+       return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
+}
+
+static struct device_attribute ecard_dev_attrs[] = {
+       __ATTR(device,   S_IRUGO, ecard_show_device,    NULL),
+       __ATTR(dma,      S_IRUGO, ecard_show_dma,       NULL),
+       __ATTR(irq,      S_IRUGO, ecard_show_irq,       NULL),
+       __ATTR(resource, S_IRUGO, ecard_show_resources, NULL),
+       __ATTR(type,     S_IRUGO, ecard_show_type,      NULL),
+       __ATTR(vendor,   S_IRUGO, ecard_show_vendor,    NULL),
+       __ATTR_NULL,
+};
+
+
+int ecard_request_resources(struct expansion_card *ec)
+{
+       int i, err = 0;
+
+       for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
+               if (ecard_resource_end(ec, i) &&
+                   !request_mem_region(ecard_resource_start(ec, i),
+                                       ecard_resource_len(ec, i),
+                                       ec->dev.driver->name)) {
+                       err = -EBUSY;
+                       break;
+               }
+       }
+
+       if (err) {
+               while (i--)
+                       if (ecard_resource_end(ec, i))
+                               release_mem_region(ecard_resource_start(ec, i),
+                                                  ecard_resource_len(ec, i));
+       }
+       return err;
+}
+EXPORT_SYMBOL(ecard_request_resources);
+
+void ecard_release_resources(struct expansion_card *ec)
+{
+       int i;
+
+       for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+               if (ecard_resource_end(ec, i))
+                       release_mem_region(ecard_resource_start(ec, i),
+                                          ecard_resource_len(ec, i));
+}
+EXPORT_SYMBOL(ecard_release_resources);
+
+void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data)
+{
+       ec->irq_data = irq_data;
+       barrier();
+       ec->ops = ops;
+}
+EXPORT_SYMBOL(ecard_setirq);
+
+void __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res,
+                          unsigned long offset, unsigned long maxsize)
+{
+       unsigned long start = ecard_resource_start(ec, res);
+       unsigned long end = ecard_resource_end(ec, res);
+
+       if (offset > (end - start))
+               return NULL;
+
+       start += offset;
+       if (maxsize && end - start > maxsize)
+               end = start + maxsize;
+       
+       return devm_ioremap(&ec->dev, start, end - start);
+}
+EXPORT_SYMBOL(ecardm_iomap);
+
+/*
+ * Probe for an expansion card.
+ *
+ * If bit 1 of the first byte of the card is set, then the
+ * card does not exist.
+ */
+static int __init ecard_probe(int slot, unsigned irq, card_type_t type)
+{
+       ecard_t **ecp;
+       ecard_t *ec;
+       struct ex_ecid cid;
+       void __iomem *addr;
+       int i, rc;
+
+       ec = ecard_alloc_card(type, slot);
+       if (IS_ERR(ec)) {
+               rc = PTR_ERR(ec);
+               goto nomem;
+       }
+
+       rc = -ENODEV;
+       if ((addr = __ecard_address(ec, type, ECARD_SYNC)) == NULL)
+               goto nodev;
+
+       cid.r_zero = 1;
+       ecard_readbytes(&cid, ec, 0, 16, 0);
+       if (cid.r_zero)
+               goto nodev;
+
+       ec->cid.id      = cid.r_id;
+       ec->cid.cd      = cid.r_cd;
+       ec->cid.is      = cid.r_is;
+       ec->cid.w       = cid.r_w;
+       ec->cid.manufacturer = ecard_getu16(cid.r_manu);
+       ec->cid.product = ecard_getu16(cid.r_prod);
+       ec->cid.country = cid.r_country;
+       ec->cid.irqmask = cid.r_irqmask;
+       ec->cid.irqoff  = ecard_gets24(cid.r_irqoff);
+       ec->cid.fiqmask = cid.r_fiqmask;
+       ec->cid.fiqoff  = ecard_gets24(cid.r_fiqoff);
+       ec->fiqaddr     =
+       ec->irqaddr     = addr;
+
+       if (ec->cid.is) {
+               ec->irqmask = ec->cid.irqmask;
+               ec->irqaddr += ec->cid.irqoff;
+               ec->fiqmask = ec->cid.fiqmask;
+               ec->fiqaddr += ec->cid.fiqoff;
+       } else {
+               ec->irqmask = 1;
+               ec->fiqmask = 4;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(blacklist); i++)
+               if (blacklist[i].manufacturer == ec->cid.manufacturer &&
+                   blacklist[i].product == ec->cid.product) {
+                       ec->card_desc = blacklist[i].type;
+                       break;
+               }
+
+       ec->irq = irq;
+
+       /*
+        * hook the interrupt handlers
+        */
+       if (slot < 8) {
+               irq_set_chip_and_handler(ec->irq, &ecard_chip,
+                                        handle_level_irq);
+               irq_set_chip_data(ec->irq, ec);
+               set_irq_flags(ec->irq, IRQF_VALID);
+       }
+
+#ifdef CONFIG_ARCH_RPC
+       /* On RiscPC, only first two slots have DMA capability */
+       if (slot < 2)
+               ec->dma = 2 + slot;
+#endif
+
+       for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
+
+       *ecp = ec;
+       slot_to_expcard[slot] = ec;
+
+       device_register(&ec->dev);
+
+       return 0;
+
+ nodev:
+       ecard_free_card(ec);
+ nomem:
+       return rc;
+}
+
+/*
+ * Initialise the expansion card system.
+ * Locate all hardware - interrupt management and
+ * actual cards.
+ */
+static int __init ecard_init(void)
+{
+       struct task_struct *task;
+       int slot, irqbase;
+
+       irqbase = irq_alloc_descs(-1, 0, 8, -1);
+       if (irqbase < 0)
+               return irqbase;
+
+       task = kthread_run(ecard_task, NULL, "kecardd");
+       if (IS_ERR(task)) {
+               printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
+                      PTR_ERR(task));
+               irq_free_descs(irqbase, 8);
+               return PTR_ERR(task);
+       }
+
+       printk("Probing expansion cards\n");
+
+       for (slot = 0; slot < 8; slot ++) {
+               if (ecard_probe(slot, irqbase + slot, ECARD_EASI) == -ENODEV)
+                       ecard_probe(slot, irqbase + slot, ECARD_IOC);
+       }
+
+       ecard_probe(8, 11, ECARD_IOC);
+
+       irq_set_chained_handler(IRQ_EXPANSIONCARD, ecard_irq_handler);
+
+       ecard_proc_init();
+
+       return 0;
+}
+
+subsys_initcall(ecard_init);
+
+/*
+ *     ECARD "bus"
+ */
+static const struct ecard_id *
+ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
+{
+       int i;
+
+       for (i = 0; ids[i].manufacturer != 65535; i++)
+               if (ec->cid.manufacturer == ids[i].manufacturer &&
+                   ec->cid.product == ids[i].product)
+                       return ids + i;
+
+       return NULL;
+}
+
+static int ecard_drv_probe(struct device *dev)
+{
+       struct expansion_card *ec = ECARD_DEV(dev);
+       struct ecard_driver *drv = ECARD_DRV(dev->driver);
+       const struct ecard_id *id;
+       int ret;
+
+       id = ecard_match_device(drv->id_table, ec);
+
+       ec->claimed = 1;
+       ret = drv->probe(ec, id);
+       if (ret)
+               ec->claimed = 0;
+       return ret;
+}
+
+static int ecard_drv_remove(struct device *dev)
+{
+       struct expansion_card *ec = ECARD_DEV(dev);
+       struct ecard_driver *drv = ECARD_DRV(dev->driver);
+
+       drv->remove(ec);
+       ec->claimed = 0;
+
+       /*
+        * Restore the default operations.  We ensure that the
+        * ops are set before we change the data.
+        */
+       ec->ops = &ecard_default_ops;
+       barrier();
+       ec->irq_data = NULL;
+
+       return 0;
+}
+
+/*
+ * Before rebooting, we must make sure that the expansion card is in a
+ * sensible state, so it can be re-detected.  This means that the first
+ * page of the ROM must be visible.  We call the expansion cards reset
+ * handler, if any.
+ */
+static void ecard_drv_shutdown(struct device *dev)
+{
+       struct expansion_card *ec = ECARD_DEV(dev);
+       struct ecard_driver *drv = ECARD_DRV(dev->driver);
+       struct ecard_request req;
+
+       if (dev->driver) {
+               if (drv->shutdown)
+                       drv->shutdown(ec);
+               ec->claimed = 0;
+       }
+
+       /*
+        * If this card has a loader, call the reset handler.
+        */
+       if (ec->loader) {
+               req.fn = ecard_task_reset;
+               req.ec = ec;
+               ecard_call(&req);
+       }
+}
+
+int ecard_register_driver(struct ecard_driver *drv)
+{
+       drv->drv.bus = &ecard_bus_type;
+
+       return driver_register(&drv->drv);
+}
+
+void ecard_remove_driver(struct ecard_driver *drv)
+{
+       driver_unregister(&drv->drv);
+}
+
+static int ecard_match(struct device *_dev, struct device_driver *_drv)
+{
+       struct expansion_card *ec = ECARD_DEV(_dev);
+       struct ecard_driver *drv = ECARD_DRV(_drv);
+       int ret;
+
+       if (drv->id_table) {
+               ret = ecard_match_device(drv->id_table, ec) != NULL;
+       } else {
+               ret = ec->cid.id == drv->id;
+       }
+
+       return ret;
+}
+
+struct bus_type ecard_bus_type = {
+       .name           = "ecard",
+       .dev_attrs      = ecard_dev_attrs,
+       .match          = ecard_match,
+       .probe          = ecard_drv_probe,
+       .remove         = ecard_drv_remove,
+       .shutdown       = ecard_drv_shutdown,
+};
+
+static int ecard_bus_init(void)
+{
+       return bus_register(&ecard_bus_type);
+}
+
+postcore_initcall(ecard_bus_init);
+
+EXPORT_SYMBOL(ecard_readchunk);
+EXPORT_SYMBOL(ecard_register_driver);
+EXPORT_SYMBOL(ecard_remove_driver);
+EXPORT_SYMBOL(ecard_bus_type);
diff --git a/arch/arm/mach-rpc/ecard.h b/arch/arm/mach-rpc/ecard.h
new file mode 100644 (file)
index 0000000..4642d43
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *  ecard.h
+ *
+ *  Copyright 2007 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Definitions internal to ecard.c - for it's use only!!
+ *
+ * External expansion card header as read from the card
+ */
+struct ex_ecid {
+       unsigned char   r_irq:1;
+       unsigned char   r_zero:1;
+       unsigned char   r_fiq:1;
+       unsigned char   r_id:4;
+       unsigned char   r_a:1;
+
+       unsigned char   r_cd:1;
+       unsigned char   r_is:1;
+       unsigned char   r_w:2;
+       unsigned char   r_r1:4;
+
+       unsigned char   r_r2:8;
+
+       unsigned char   r_prod[2];
+
+       unsigned char   r_manu[2];
+
+       unsigned char   r_country;
+
+       unsigned char   r_fiqmask;
+       unsigned char   r_fiqoff[3];
+
+       unsigned char   r_irqmask;
+       unsigned char   r_irqoff[3];
+};
+
+/*
+ * Chunk directory entry as read from the card
+ */
+struct ex_chunk_dir {
+       unsigned char r_id;
+       unsigned char r_len[3];
+       unsigned long r_start;
+       union {
+               char string[256];
+               char data[1];
+       } d;
+#define c_id(x)                ((x)->r_id)
+#define c_len(x)       ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16))
+#define c_start(x)     ((x)->r_start)
+};
+
+typedef enum ecard_type {              /* Cards address space          */
+       ECARD_IOC,
+       ECARD_MEMC,
+       ECARD_EASI
+} card_type_t;
+
+typedef enum {                         /* Speed for ECARD_IOC space    */
+       ECARD_SLOW       = 0,
+       ECARD_MEDIUM     = 1,
+       ECARD_FAST       = 2,
+       ECARD_SYNC       = 3
+} card_speed_t;
diff --git a/arch/arm/mach-rpc/fiq.S b/arch/arm/mach-rpc/fiq.S
new file mode 100644 (file)
index 0000000..48ddd57
--- /dev/null
@@ -0,0 +1,16 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/hardware.h>
+#include <mach/entry-macro.S>
+
+       .text
+
+       .global rpc_default_fiq_end
+ENTRY(rpc_default_fiq_start)
+       mov     r12, #ioc_base_high
+       .if     ioc_base_low
+       orr     r12, r12, #ioc_base_low
+       .endif
+       strb    r12, [r12, #0x38]       @ Disable FIQ register
+       subs    pc, lr, #4
+rpc_default_fiq_end:
index 4e7e541..7178368 100644 (file)
@@ -10,7 +10,3 @@
        orr     \base, \base, #ioc_base_low
        .endif
        .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
index 3d20374..6868e17 100644 (file)
@@ -42,6 +42,4 @@
  */
 #define FIQ_START              64
 
-#define IRQ_TIMER              IRQ_TIMER0
-
 #define NR_IRQS                        128
diff --git a/arch/arm/mach-rpc/include/mach/system.h b/arch/arm/mach-rpc/include/mach/system.h
deleted file mode 100644 (file)
index 359bab9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- *  arch/arm/mach-rpc/include/mach/system.h
- *
- *  Copyright (C) 1996-1999 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
index 2e1b530..cf0e669 100644 (file)
@@ -5,6 +5,7 @@
 #include <asm/mach/irq.h>
 #include <asm/hardware/iomd.h>
 #include <asm/irq.h>
+#include <asm/fiq.h>
 
 static void iomd_ack_irq_a(struct irq_data *d)
 {
@@ -112,6 +113,8 @@ static struct irq_chip iomd_fiq_chip = {
        .irq_unmask     = iomd_unmask_irq_fiq,
 };
 
+extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end;
+
 void __init rpc_init_irq(void)
 {
        unsigned int irq, flags;
@@ -121,6 +124,9 @@ void __init rpc_init_irq(void)
        iomd_writeb(0, IOMD_FIQMASK);
        iomd_writeb(0, IOMD_DMAMASK);
 
+       set_fiq_handler(&rpc_default_fiq_start,
+               &rpc_default_fiq_end - &rpc_default_fiq_start);
+
        for (irq = 0; irq < NR_IRQS; irq++) {
                flags = IRQF_VALID;
 
index e958597..f3fa259 100644 (file)
@@ -99,15 +99,9 @@ static void __init rpc_map_io(void)
 }
 
 static struct resource acornfb_resources[] = {
-       {       /* VIDC */
-               .start          = 0x03400000,
-               .end            = 0x035fffff,
-               .flags          = IORESOURCE_MEM,
-       }, {
-               .start          = IRQ_VSYNCPULSE,
-               .end            = IRQ_VSYNCPULSE,
-               .flags          = IORESOURCE_IRQ,
-       },
+       /* VIDC */
+       DEFINE_RES_MEM(0x03400000, 0x00200000),
+       DEFINE_RES_IRQ(IRQ_VSYNCPULSE),
 };
 
 static struct platform_device acornfb_device = {
@@ -121,11 +115,7 @@ static struct platform_device acornfb_device = {
 };
 
 static struct resource iomd_resources[] = {
-       {
-               .start          = 0x03200000,
-               .end            = 0x0320ffff,
-               .flags          = IORESOURCE_MEM,
-       },
+       DEFINE_RES_MEM(0x03200000, 0x10000),
 };
 
 static struct platform_device iomd_device = {
@@ -135,18 +125,25 @@ static struct platform_device iomd_device = {
        .resource               = iomd_resources,
 };
 
+static struct resource iomd_kart_resources[] = {
+       DEFINE_RES_IRQ(IRQ_KEYBOARDRX),
+       DEFINE_RES_IRQ(IRQ_KEYBOARDTX),
+};
+
 static struct platform_device kbd_device = {
        .name                   = "kart",
        .id                     = -1,
        .dev                    = {
                .parent         = &iomd_device.dev,
        },
+       .num_resources          = ARRAY_SIZE(iomd_kart_resources),
+       .resource               = iomd_kart_resources,
 };
 
 static struct plat_serial8250_port serial_platform_data[] = {
        {
                .mapbase        = 0x03010fe0,
-               .irq            = 10,
+               .irq            = IRQ_SERIALPORT,
                .uartclk        = 1843200,
                .regshift       = 2,
                .iotype         = UPIO_MEM,
@@ -168,21 +165,9 @@ static struct pata_platform_info pata_platform_data = {
 };
 
 static struct resource pata_resources[] = {
-       [0] = {
-               .start          = 0x030107c0,
-               .end            = 0x030107df,
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start          = 0x03010fd8,
-               .end            = 0x03010fdb,
-               .flags          = IORESOURCE_MEM,
-       },
-       [2] = {
-               .start          = IRQ_HARDDISK,
-               .end            = IRQ_HARDDISK,
-               .flags          = IORESOURCE_IRQ,
-       },
+       DEFINE_RES_MEM(0x030107c0, 0x20),
+       DEFINE_RES_MEM(0x03010fd8, 0x04),
+       DEFINE_RES_IRQ(IRQ_HARDDISK),
 };
 
 static struct platform_device pata_device = {
diff --git a/arch/arm/mach-rpc/time.c b/arch/arm/mach-rpc/time.c
new file mode 100644 (file)
index 0000000..581fca9
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *  linux/arch/arm/common/time-acorn.c
+ *
+ *  Copyright (c) 1996-2000 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Changelog:
+ *   24-Sep-1996       RMK     Created
+ *   10-Oct-1996       RMK     Brought up to date with arch-sa110eval
+ *   04-Dec-1997       RMK     Updated for new arch/arm/time.c
+ *   13=Jun-2004       DS      Moved to arch/arm/common b/c shared w/CLPS7500
+ */
+#include <linux/timex.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/ioc.h>
+
+#include <asm/mach/time.h>
+
+unsigned long ioc_timer_gettimeoffset(void)
+{
+       unsigned int count1, count2, status;
+       long offset;
+
+       ioc_writeb (0, IOC_T0LATCH);
+       barrier ();
+       count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
+       barrier ();
+       status = ioc_readb(IOC_IRQREQA);
+       barrier ();
+       ioc_writeb (0, IOC_T0LATCH);
+       barrier ();
+       count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
+
+       offset = count2;
+       if (count2 < count1) {
+               /*
+                * We have not had an interrupt between reading count1
+                * and count2.
+                */
+               if (status & (1 << 5))
+                       offset -= LATCH;
+       } else if (count2 > count1) {
+               /*
+                * We have just had another interrupt between reading
+                * count1 and count2.
+                */
+               offset -= LATCH;
+       }
+
+       offset = (LATCH - offset) * (tick_nsec / 1000);
+       return (offset + LATCH/2) / LATCH;
+}
+
+void __init ioctime_init(void)
+{
+       ioc_writeb(LATCH & 255, IOC_T0LTCHL);
+       ioc_writeb(LATCH >> 8, IOC_T0LTCHH);
+       ioc_writeb(0, IOC_T0GO);
+}
+
+static irqreturn_t
+ioc_timer_interrupt(int irq, void *dev_id)
+{
+       timer_tick();
+       return IRQ_HANDLED;
+}
+
+static struct irqaction ioc_timer_irq = {
+       .name           = "timer",
+       .flags          = IRQF_DISABLED,
+       .handler        = ioc_timer_interrupt
+};
+
+/*
+ * Set up timer interrupt.
+ */
+static void __init ioc_timer_init(void)
+{
+       ioctime_init();
+       setup_irq(IRQ_TIMER0, &ioc_timer_irq);
+}
+
+struct sys_timer ioc_timer = {
+       .init           = ioc_timer_init,
+       .offset         = ioc_timer_gettimeoffset,
+};
+
index 5261a7e..68d89cb 100644 (file)
@@ -2,42 +2,6 @@
 #
 # Licensed under GPLv2
 
-config CPU_S3C2410
-       bool
-       depends on ARCH_S3C2410
-       select CPU_ARM920T
-       select S3C2410_CLOCK
-       select CPU_LLSERIAL_S3C2410
-       select S3C2410_PM if PM
-       select S3C2410_CPUFREQ if CPU_FREQ_S3C24XX
-       help
-         Support for S3C2410 and S3C2410A family from the S3C24XX line
-         of Samsung Mobile CPUs.
-
-config CPU_S3C2410_DMA
-       bool
-       depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
-       default y if CPU_S3C2410 || CPU_S3C2442
-       help
-         DMA device selection for S3C2410 and compatible CPUs
-
-config S3C2410_PM
-       bool
-       help
-         Power Management code common to S3C2410 and better
-
-config SIMTEC_NOR
-       bool
-       help
-         Internal node to specify machine has simtec NOR mapping
-
-config MACH_BAST_IDE
-       bool
-       select HAVE_PATA_PLATFORM
-       help
-         Internal node for machines with an BAST style IDE
-         interface
-
 # cpu frequency scaling support
 
 config S3C2410_CPUFREQ
@@ -54,121 +18,3 @@ config S3C2410_PLLTABLE
        help
          Select the PLL table for the S3C2410
 
-menu "S3C2410 Machines"
-
-config ARCH_SMDK2410
-       bool "SMDK2410/A9M2410"
-       select CPU_S3C2410
-       select MACH_SMDK
-       help
-          Say Y here if you are using the SMDK2410 or the derived module A9M2410
-           <http://www.fsforth.de>
-
-config ARCH_H1940
-       bool "IPAQ H1940"
-       select CPU_S3C2410
-       select PM_H1940 if PM
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       select S3C2410_SETUP_TS
-       help
-         Say Y here if you are using the HP IPAQ H1940
-
-config H1940BT
-        tristate "Control the state of H1940 bluetooth chip"
-        depends on ARCH_H1940
-        select RFKILL
-        help
-          This is a simple driver that is able to control
-          the state of built in bluetooth chip on h1940.
-
-config PM_H1940
-       bool
-       help
-         Internal node for H1940 and related PM
-
-config MACH_N30
-       bool "Acer N30 family"
-       select CPU_S3C2410
-       select MACH_N35
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-         Say Y here if you want suppt for the Acer N30, Acer N35,
-         Navman PiN570, Yakumo AlphaX or Airis NC05 PDAs.
-
-config MACH_N35
-       bool
-       help
-         Internal node in order to enable support for Acer N35 if Acer N30 is
-         selected.
-
-config ARCH_BAST
-       bool "Simtec Electronics BAST (EB2410ITX)"
-       select CPU_S3C2410
-       select S3C2410_IOTIMING if S3C2410_CPUFREQ
-       select PM_SIMTEC if PM
-       select SIMTEC_NOR
-       select MACH_BAST_IDE
-       select S3C24XX_DCLK
-       select ISA
-       select S3C_DEV_HWMON
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-         Say Y here if you are using the Simtec Electronics EB2410ITX
-         development board (also known as BAST)
-
-config MACH_OTOM
-       bool "NexVision OTOM Board"
-       select CPU_S3C2410
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-         Say Y here if you are using the Nex Vision OTOM board
-
-config MACH_AML_M5900
-       bool "AML M5900 Series"
-       select CPU_S3C2410
-       select PM_SIMTEC if PM
-       select S3C_DEV_USB_HOST
-       help
-          Say Y here if you are using the American Microsystems M5900 Series
-           <http://www.amltd.com>
-
-config BAST_PC104_IRQ
-       bool "BAST PC104 IRQ support"
-       depends on ARCH_BAST
-       default y
-       help
-         Say Y here to enable the PC104 IRQ routing on the
-         Simtec BAST (EB2410ITX)
-
-config MACH_TCT_HAMMER
-       bool "TCT Hammer Board"
-       select CPU_S3C2410
-       select S3C_DEV_USB_HOST
-       help
-          Say Y here if you are using the TinCanTools Hammer Board
-           <http://www.tincantools.com>
-
-config MACH_VR1000
-       bool "Thorcom VR1000"
-       select PM_SIMTEC if PM
-       select S3C24XX_DCLK
-       select SIMTEC_NOR
-       select MACH_BAST_IDE
-       select CPU_S3C2410
-       select S3C_DEV_USB_HOST
-       help
-         Say Y here if you are using the Thorcom VR1000 board.
-
-config MACH_QT2410
-       bool "QT2410"
-       select CPU_S3C2410
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-          Say Y here if you are using the Armzone QT2410
-
-endmenu
index 782fd81..6b9a316 100644 (file)
@@ -9,32 +9,6 @@ obj-m                          :=
 obj-n                          :=
 obj-                           :=
 
-obj-$(CONFIG_CPU_S3C2410)      += s3c2410.o
-obj-$(CONFIG_CPU_S3C2410_DMA)  += dma.o
-obj-$(CONFIG_CPU_S3C2410_DMA)  += dma.o
-obj-$(CONFIG_S3C2410_PM)       += pm.o sleep.o
 obj-$(CONFIG_S3C2410_CPUFREQ)  += cpu-freq.o
 obj-$(CONFIG_S3C2410_PLLTABLE) += pll.o
 
-# Machine support
-
-obj-$(CONFIG_ARCH_SMDK2410)    += mach-smdk2410.o
-obj-$(CONFIG_ARCH_H1940)       += mach-h1940.o
-obj-$(CONFIG_H1940BT)          += h1940-bluetooth.o
-obj-$(CONFIG_PM_H1940)         += pm-h1940.o
-obj-$(CONFIG_MACH_N30)         += mach-n30.o
-obj-$(CONFIG_ARCH_BAST)                += mach-bast.o usb-simtec.o
-obj-$(CONFIG_MACH_OTOM)                += mach-otom.o
-obj-$(CONFIG_MACH_AML_M5900)   += mach-amlm5900.o
-obj-$(CONFIG_BAST_PC104_IRQ)   += bast-irq.o
-obj-$(CONFIG_MACH_TCT_HAMMER)  += mach-tct_hammer.o
-obj-$(CONFIG_MACH_VR1000)      += mach-vr1000.o usb-simtec.o
-obj-$(CONFIG_MACH_QT2410)      += mach-qt2410.o
-
-# Common bits of machine support
-
-obj-$(CONFIG_SIMTEC_NOR)       += nor-simtec.o
-
-# machine additions
-
-obj-$(CONFIG_MACH_BAST_IDE)    += bast-ide.o
diff --git a/arch/arm/mach-s3c2410/Makefile.boot b/arch/arm/mach-s3c2410/Makefile.boot
deleted file mode 100644 (file)
index 4457605..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-ifeq ($(CONFIG_PM_H1940),y)
-       zreladdr-y      += 0x30108000
-       params_phys-y   := 0x30100100
-else
-       zreladdr-y      += 0x30008000
-       params_phys-y   := 0x30000100
-endif
diff --git a/arch/arm/mach-s3c2410/bast-ide.c b/arch/arm/mach-s3c2410/bast-ide.c
deleted file mode 100644 (file)
index 298ecec..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/bast-ide.c
- *
- * Copyright 2007 Simtec Electronics
- *     http://www.simtec.co.uk/products/EB2410ITX/
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include <linux/platform_device.h>
-#include <linux/ata_platform.h>
-
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/map.h>
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-
-/* IDE ports */
-
-static struct pata_platform_info bast_ide_platdata = {
-       .ioport_shift   = 5,
-};
-
-#define IDE_CS S3C2410_CS5
-
-static struct resource bast_ide0_resource[] = {
-       [0]     = {
-               .start  = IDE_CS + BAST_PA_IDEPRI,
-               .end    = IDE_CS + BAST_PA_IDEPRI + (8 * 0x20) - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1]     = {
-               .start  = IDE_CS + BAST_PA_IDEPRIAUX + (6 * 0x20) ,
-               .end    = IDE_CS + BAST_PA_IDEPRIAUX + (7 * 0x20) - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [2]     = {
-               .start  = IRQ_IDE0,
-               .end    = IRQ_IDE0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device bast_device_ide0 = {
-       .name           = "pata_platform",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(bast_ide0_resource),
-       .resource       = bast_ide0_resource,
-       .dev            = {
-               .platform_data = &bast_ide_platdata,
-               .coherent_dma_mask = ~0,
-       }
-
-};
-
-static struct resource bast_ide1_resource[] = {
-       [0]     = {
-               .start  = IDE_CS + BAST_PA_IDESEC,
-               .end    = IDE_CS + BAST_PA_IDESEC + (8 * 0x20) - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1]     = {
-               .start  = IDE_CS + BAST_PA_IDESECAUX + (6 * 0x20),
-               .end    = IDE_CS + BAST_PA_IDESECAUX + (7 * 0x20) - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [2]     = {
-               .start  = IRQ_IDE1,
-               .end    = IRQ_IDE1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device bast_device_ide1 = {
-       .name           = "pata_platform",
-       .id             = 1,
-       .num_resources  = ARRAY_SIZE(bast_ide1_resource),
-       .resource       = bast_ide1_resource,
-       .dev            = {
-               .platform_data = &bast_ide_platdata,
-               .coherent_dma_mask = ~0,
-       }
-};
-
-static struct platform_device *bast_ide_devices[] __initdata = {
-       &bast_device_ide0,
-       &bast_device_ide1,
-};
-
-static __init int bast_ide_init(void)
-{
-       if (machine_is_bast() || machine_is_vr1000())
-               return platform_add_devices(bast_ide_devices,
-                                           ARRAY_SIZE(bast_ide_devices));
-
-       return 0;
-}
-
-fs_initcall(bast_ide_init);
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
deleted file mode 100644 (file)
index ac7b2ad..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/bast-irq.c
- *
- * Copyright 2003-2005 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.simtec.co.uk/products/EB2410ITX/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <asm/mach-types.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/regs-irq.h>
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-
-#include <plat/irq.h>
-
-#if 0
-#include <asm/debug-ll.h>
-#endif
-
-#define irqdbf(x...)
-#define irqdbf2(x...)
-
-
-/* handle PC104 ISA interrupts from the system CPLD */
-
-/* table of ISA irq nos to the relevant mask... zero means
- * the irq is not implemented
-*/
-static unsigned char bast_pc104_irqmasks[] = {
-       0,   /* 0 */
-       0,   /* 1 */
-       0,   /* 2 */
-       1,   /* 3 */
-       0,   /* 4 */
-       2,   /* 5 */
-       0,   /* 6 */
-       4,   /* 7 */
-       0,   /* 8 */
-       0,   /* 9 */
-       8,   /* 10 */
-       0,   /* 11 */
-       0,   /* 12 */
-       0,   /* 13 */
-       0,   /* 14 */
-       0,   /* 15 */
-};
-
-static unsigned char bast_pc104_irqs[] = { 3, 5, 7, 10 };
-
-static void
-bast_pc104_mask(struct irq_data *data)
-{
-       unsigned long temp;
-
-       temp = __raw_readb(BAST_VA_PC104_IRQMASK);
-       temp &= ~bast_pc104_irqmasks[data->irq];
-       __raw_writeb(temp, BAST_VA_PC104_IRQMASK);
-}
-
-static void
-bast_pc104_maskack(struct irq_data *data)
-{
-       struct irq_desc *desc = irq_desc + IRQ_ISA;
-
-       bast_pc104_mask(data);
-       desc->irq_data.chip->irq_ack(&desc->irq_data);
-}
-
-static void
-bast_pc104_unmask(struct irq_data *data)
-{
-       unsigned long temp;
-
-       temp = __raw_readb(BAST_VA_PC104_IRQMASK);
-       temp |= bast_pc104_irqmasks[data->irq];
-       __raw_writeb(temp, BAST_VA_PC104_IRQMASK);
-}
-
-static struct irq_chip  bast_pc104_chip = {
-       .irq_mask       = bast_pc104_mask,
-       .irq_unmask     = bast_pc104_unmask,
-       .irq_ack        = bast_pc104_maskack
-};
-
-static void
-bast_irq_pc104_demux(unsigned int irq,
-                    struct irq_desc *desc)
-{
-       unsigned int stat;
-       unsigned int irqno;
-       int i;
-
-       stat = __raw_readb(BAST_VA_PC104_IRQREQ) & 0xf;
-
-       if (unlikely(stat == 0)) {
-               /* ack if we get an irq with nothing (ie, startup) */
-
-               desc = irq_desc + IRQ_ISA;
-               desc->irq_data.chip->irq_ack(&desc->irq_data);
-       } else {
-               /* handle the IRQ */
-
-               for (i = 0; stat != 0; i++, stat >>= 1) {
-                       if (stat & 1) {
-                               irqno = bast_pc104_irqs[i];
-                               generic_handle_irq(irqno);
-                       }
-               }
-       }
-}
-
-static __init int bast_irq_init(void)
-{
-       unsigned int i;
-
-       if (machine_is_bast()) {
-               printk(KERN_INFO "BAST PC104 IRQ routing, Copyright 2005 Simtec Electronics\n");
-
-               /* zap all the IRQs */
-
-               __raw_writeb(0x0, BAST_VA_PC104_IRQMASK);
-
-               irq_set_chained_handler(IRQ_ISA, bast_irq_pc104_demux);
-
-               /* register our IRQs */
-
-               for (i = 0; i < 4; i++) {
-                       unsigned int irqno = bast_pc104_irqs[i];
-
-                       irq_set_chip_and_handler(irqno, &bast_pc104_chip,
-                                                handle_level_irq);
-                       set_irq_flags(irqno, IRQF_VALID);
-               }
-       }
-
-       return 0;
-}
-
-arch_initcall(bast_irq_init);
diff --git a/arch/arm/mach-s3c2410/common.h b/arch/arm/mach-s3c2410/common.h
deleted file mode 100644 (file)
index f65dc80..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Common Header for S3C2410 machines
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ARCH_ARM_MACH_S3C2410_COMMON_H
-#define __ARCH_ARM_MACH_S3C2410_COMMON_H
-
-void s3c2410_restart(char mode, const char *cmd);
-
-#endif /* __ARCH_ARM_MACH_S3C2410_COMMON_H */
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
deleted file mode 100644 (file)
index 4803338..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/dma.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 DMA selection
- *
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-
-#include <plat/cpu.h>
-#include <plat/dma-s3c24xx.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
-#include <plat/regs-dma.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
-#include <plat/regs-spi.h>
-
-static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
-       [DMACH_XD0] = {
-               .name           = "xdreq0",
-               .channels[0]    = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
-       },
-       [DMACH_XD1] = {
-               .name           = "xdreq1",
-               .channels[1]    = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
-       },
-       [DMACH_SDI] = {
-               .name           = "sdi",
-               .channels[0]    = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
-               .channels[2]    = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
-               .channels[3]    = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
-       },
-       [DMACH_SPI0] = {
-               .name           = "spi0",
-               .channels[1]    = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
-       },
-       [DMACH_SPI1] = {
-               .name           = "spi1",
-               .channels[3]    = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
-       },
-       [DMACH_UART0] = {
-               .name           = "uart0",
-               .channels[0]    = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
-       },
-       [DMACH_UART1] = {
-               .name           = "uart1",
-               .channels[1]    = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
-       },
-       [DMACH_UART2] = {
-               .name           = "uart2",
-               .channels[3]    = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
-       },
-       [DMACH_TIMER] = {
-               .name           = "timer",
-               .channels[0]    = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
-               .channels[2]    = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
-               .channels[3]    = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
-       },
-       [DMACH_I2S_IN] = {
-               .name           = "i2s-sdi",
-               .channels[1]    = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
-               .channels[2]    = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
-       },
-       [DMACH_I2S_OUT] = {
-               .name           = "i2s-sdo",
-               .channels[2]    = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
-       },
-       [DMACH_USB_EP1] = {
-               .name           = "usb-ep1",
-               .channels[0]    = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
-       },
-       [DMACH_USB_EP2] = {
-               .name           = "usb-ep2",
-               .channels[1]    = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
-       },
-       [DMACH_USB_EP3] = {
-               .name           = "usb-ep3",
-               .channels[2]    = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
-       },
-       [DMACH_USB_EP4] = {
-               .name           = "usb-ep4",
-               .channels[3]    =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
-       },
-};
-
-static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
-                              struct s3c24xx_dma_map *map)
-{
-       chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
-}
-
-static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
-       .select         = s3c2410_dma_select,
-       .dcon_mask      = 7 << 24,
-       .map            = s3c2410_dma_mappings,
-       .map_size       = ARRAY_SIZE(s3c2410_dma_mappings),
-};
-
-static struct s3c24xx_dma_order __initdata s3c2410_dma_order = {
-       .channels       = {
-               [DMACH_SDI]     = {
-                       .list   = {
-                               [0]     = 3 | DMA_CH_VALID,
-                               [1]     = 2 | DMA_CH_VALID,
-                               [2]     = 0 | DMA_CH_VALID,
-                       },
-               },
-               [DMACH_I2S_IN]  = {
-                       .list   = {
-                               [0]     = 1 | DMA_CH_VALID,
-                               [1]     = 2 | DMA_CH_VALID,
-                       },
-               },
-       },
-};
-
-static int __init s3c2410_dma_add(struct device *dev,
-                                 struct subsys_interface *sif)
-{
-       s3c2410_dma_init();
-       s3c24xx_dma_order_set(&s3c2410_dma_order);
-       return s3c24xx_dma_init_map(&s3c2410_dma_sel);
-}
-
-#if defined(CONFIG_CPU_S3C2410)
-static struct subsys_interface s3c2410_dma_interface = {
-       .name           = "s3c2410_dma",
-       .subsys         = &s3c2410_subsys,
-       .add_dev        = s3c2410_dma_add,
-};
-
-static int __init s3c2410_dma_drvinit(void)
-{
-       return subsys_interface_register(&s3c2410_dma_interface);
-}
-
-arch_initcall(s3c2410_dma_drvinit);
-
-static struct subsys_interface s3c2410a_dma_interface = {
-       .name           = "s3c2410a_dma",
-       .subsys         = &s3c2410a_subsys,
-       .add_dev        = s3c2410_dma_add,
-};
-
-static int __init s3c2410a_dma_drvinit(void)
-{
-       return subsys_interface_register(&s3c2410a_dma_interface);
-}
-
-arch_initcall(s3c2410a_dma_drvinit);
-#endif
-
-#if defined(CONFIG_CPU_S3C2442)
-/* S3C2442 DMA contains the same selection table as the S3C2410 */
-static struct subsys_interface s3c2442_dma_interface = {
-       .name           = "s3c2442_dma",
-       .subsys         = &s3c2442_subsys,
-       .add_dev        = s3c2410_dma_add,
-};
-
-static int __init s3c2442_dma_drvinit(void)
-{
-       return subsys_interface_register(&s3c2442_dma_interface);
-}
-
-arch_initcall(s3c2442_dma_drvinit);
-#endif
-
diff --git a/arch/arm/mach-s3c2410/h1940-bluetooth.c b/arch/arm/mach-s3c2410/h1940-bluetooth.c
deleted file mode 100644 (file)
index a5eeb62..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * arch/arm/mach-s3c2410/h1940-bluetooth.c
- * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
- *
- * 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.
- *
- *         S3C2410 bluetooth "driver"
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/leds.h>
-#include <linux/gpio.h>
-#include <linux/rfkill.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/hardware.h>
-#include <mach/h1940-latch.h>
-#include <mach/h1940.h>
-
-#define DRV_NAME "h1940-bt"
-
-/* Bluetooth control */
-static void h1940bt_enable(int on)
-{
-       if (on) {
-               /* Power on the chip */
-               gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 1);
-               /* Reset the chip */
-               mdelay(10);
-
-               gpio_set_value(S3C2410_GPH(1), 1);
-               mdelay(10);
-               gpio_set_value(S3C2410_GPH(1), 0);
-
-               h1940_led_blink_set(-EINVAL, GPIO_LED_BLINK, NULL, NULL);
-       }
-       else {
-               gpio_set_value(S3C2410_GPH(1), 1);
-               mdelay(10);
-               gpio_set_value(S3C2410_GPH(1), 0);
-               mdelay(10);
-               gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0);
-
-               h1940_led_blink_set(-EINVAL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
-       }
-}
-
-static int h1940bt_set_block(void *data, bool blocked)
-{
-       h1940bt_enable(!blocked);
-       return 0;
-}
-
-static const struct rfkill_ops h1940bt_rfkill_ops = {
-       .set_block = h1940bt_set_block,
-};
-
-static int __devinit h1940bt_probe(struct platform_device *pdev)
-{
-       struct rfkill *rfk;
-       int ret = 0;
-
-       ret = gpio_request(S3C2410_GPH(1), dev_name(&pdev->dev));
-       if (ret) {
-               dev_err(&pdev->dev, "could not get GPH1\n");
-               return ret;
-       }
-
-       ret = gpio_request(H1940_LATCH_BLUETOOTH_POWER, dev_name(&pdev->dev));
-       if (ret) {
-               gpio_free(S3C2410_GPH(1));
-               dev_err(&pdev->dev, "could not get BT_POWER\n");
-               return ret;
-       }
-
-       /* Configures BT serial port GPIOs */
-       s3c_gpio_cfgpin(S3C2410_GPH(0), S3C2410_GPH0_nCTS0);
-       s3c_gpio_setpull(S3C2410_GPH(0), S3C_GPIO_PULL_NONE);
-       s3c_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT);
-       s3c_gpio_setpull(S3C2410_GPH(1), S3C_GPIO_PULL_NONE);
-       s3c_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0);
-       s3c_gpio_setpull(S3C2410_GPH(2), S3C_GPIO_PULL_NONE);
-       s3c_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0);
-       s3c_gpio_setpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE);
-
-       rfk = rfkill_alloc(DRV_NAME, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
-                       &h1940bt_rfkill_ops, NULL);
-       if (!rfk) {
-               ret = -ENOMEM;
-               goto err_rfk_alloc;
-       }
-
-       ret = rfkill_register(rfk);
-       if (ret)
-               goto err_rfkill;
-
-       platform_set_drvdata(pdev, rfk);
-
-       return 0;
-
-err_rfkill:
-       rfkill_destroy(rfk);
-err_rfk_alloc:
-       return ret;
-}
-
-static int h1940bt_remove(struct platform_device *pdev)
-{
-       struct rfkill *rfk = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-       gpio_free(S3C2410_GPH(1));
-
-       if (rfk) {
-               rfkill_unregister(rfk);
-               rfkill_destroy(rfk);
-       }
-       rfk = NULL;
-
-       h1940bt_enable(0);
-
-       return 0;
-}
-
-
-static struct platform_driver h1940bt_driver = {
-       .driver         = {
-               .name   = DRV_NAME,
-       },
-       .probe          = h1940bt_probe,
-       .remove         = h1940bt_remove,
-};
-
-
-static int __init h1940bt_init(void)
-{
-       return platform_driver_register(&h1940bt_driver);
-}
-
-static void __exit h1940bt_exit(void)
-{
-       platform_driver_unregister(&h1940bt_driver);
-}
-
-module_init(h1940bt_init);
-module_exit(h1940bt_exit);
-
-MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
-MODULE_DESCRIPTION("Driver for the iPAQ H1940 bluetooth chip");
-MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-s3c2410/include/mach/anubis-cpld.h b/arch/arm/mach-s3c2410/include/mach/anubis-cpld.h
deleted file mode 100644 (file)
index 1b614d5..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/anubis-cpld.h
- *
- * Copyright (c) 2005 Simtec Electronics
- *     http://www.simtec.co.uk/products/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * ANUBIS - CPLD control constants
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_ANUBISCPLD_H
-#define __ASM_ARCH_ANUBISCPLD_H
-
-/* CTRL2 - NAND WP control, IDE Reset assert/check */
-
-#define ANUBIS_CTRL1_NANDSEL           (0x3)
-
-/* IDREG - revision */
-
-#define ANUBIS_IDREG_REVMASK           (0x7)
-
-#endif /* __ASM_ARCH_ANUBISCPLD_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/anubis-irq.h b/arch/arm/mach-s3c2410/include/mach/anubis-irq.h
deleted file mode 100644 (file)
index a2a3281..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/anubis-irq.h
- *
- * Copyright (c) 2005 Simtec Electronics
- *     http://www.simtec.co.uk/products/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- *  ANUBIS - IRQ Number definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_ANUBISIRQ_H
-#define __ASM_ARCH_ANUBISIRQ_H
-
-#define IRQ_IDE0       IRQ_EINT2
-#define IRQ_IDE1       IRQ_EINT3
-#define IRQ_ASIX       IRQ_EINT1
-
-#endif /* __ASM_ARCH_ANUBISIRQ_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/anubis-map.h b/arch/arm/mach-s3c2410/include/mach/anubis-map.h
deleted file mode 100644 (file)
index c9deb3a..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/anubis-map.h
- *
- * Copyright (c) 2005 Simtec Electronics
- *     http://www.simtec.co.uk/products/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * ANUBIS - Memory map definitions
- *
- * 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.
-*/
-
-/* needs arch/map.h including with this */
-
-#ifndef __ASM_ARCH_ANUBISMAP_H
-#define __ASM_ARCH_ANUBISMAP_H
-
-/* start peripherals off after the S3C2410 */
-
-#define ANUBIS_IOADDR(x)       (S3C2410_ADDR((x) + 0x01800000))
-
-#define ANUBIS_PA_CPLD         (S3C2410_CS1 | (1<<26))
-
-/* we put the CPLD registers next, to get them out of the way */
-
-#define ANUBIS_VA_CTRL1            ANUBIS_IOADDR(0x00000000)    /* 0x01800000 */
-#define ANUBIS_PA_CTRL1            (ANUBIS_PA_CPLD)
-
-#define ANUBIS_VA_IDREG            ANUBIS_IOADDR(0x00300000)    /* 0x01B00000 */
-#define ANUBIS_PA_IDREG            (ANUBIS_PA_CPLD + (3<<23))
-
-#define ANUBIS_IDEPRI      ANUBIS_IOADDR(0x01000000)
-#define ANUBIS_IDEPRIAUX    ANUBIS_IOADDR(0x01100000)
-#define ANUBIS_IDESEC      ANUBIS_IOADDR(0x01200000)
-#define ANUBIS_IDESECAUX    ANUBIS_IOADDR(0x01300000)
-
-#endif /* __ASM_ARCH_ANUBISMAP_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/bast-cpld.h b/arch/arm/mach-s3c2410/include/mach/bast-cpld.h
deleted file mode 100644 (file)
index bee2a7a..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/bast-cpld.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * BAST - CPLD control constants
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_BASTCPLD_H
-#define __ASM_ARCH_BASTCPLD_H
-
-/* CTRL1 - Audio LR routing */
-
-#define BAST_CPLD_CTRL1_LRCOFF     (0x00)
-#define BAST_CPLD_CTRL1_LRCADC     (0x01)
-#define BAST_CPLD_CTRL1_LRCDAC     (0x02)
-#define BAST_CPLD_CTRL1_LRCARM     (0x03)
-#define BAST_CPLD_CTRL1_LRMASK     (0x03)
-
-/* CTRL2 - NAND WP control, IDE Reset assert/check */
-
-#define BAST_CPLD_CTRL2_WNAND       (0x04)
-#define BAST_CPLD_CTLR2_IDERST      (0x08)
-
-/* CTRL3 - rom write control, CPLD identity */
-
-#define BAST_CPLD_CTRL3_IDMASK      (0x0e)
-#define BAST_CPLD_CTRL3_ROMWEN      (0x01)
-
-/* CTRL4 - 8bit LCD interface control/status */
-
-#define BAST_CPLD_CTRL4_LLAT       (0x01)
-#define BAST_CPLD_CTRL4_LCDRW      (0x02)
-#define BAST_CPLD_CTRL4_LCDCMD     (0x04)
-#define BAST_CPLD_CTRL4_LCDE2      (0x01)
-
-/* CTRL5 - DMA routing */
-
-#define BAST_CPLD_DMA0_PRIIDE      (0<<0)
-#define BAST_CPLD_DMA0_SECIDE      (1<<0)
-#define BAST_CPLD_DMA0_ISA15       (2<<0)
-#define BAST_CPLD_DMA0_ISA36       (3<<0)
-
-#define BAST_CPLD_DMA1_PRIIDE      (0<<2)
-#define BAST_CPLD_DMA1_SECIDE      (1<<2)
-#define BAST_CPLD_DMA1_ISA15       (2<<2)
-#define BAST_CPLD_DMA1_ISA36       (3<<2)
-
-#endif /* __ASM_ARCH_BASTCPLD_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/bast-irq.h b/arch/arm/mach-s3c2410/include/mach/bast-irq.h
deleted file mode 100644 (file)
index cac428c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/bast-irq.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Machine BAST - IRQ Number definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_BASTIRQ_H
-#define __ASM_ARCH_BASTIRQ_H
-
-/* irq numbers to onboard peripherals */
-
-#define IRQ_USBOC      IRQ_EINT18
-#define IRQ_IDE0       IRQ_EINT16
-#define IRQ_IDE1       IRQ_EINT17
-#define IRQ_PCSERIAL1  IRQ_EINT15
-#define IRQ_PCSERIAL2  IRQ_EINT14
-#define IRQ_PCPARALLEL IRQ_EINT13
-#define IRQ_ASIX       IRQ_EINT11
-#define IRQ_DM9000     IRQ_EINT10
-#define IRQ_ISA               IRQ_EINT9
-#define IRQ_SMALERT    IRQ_EINT8
-
-#endif /* __ASM_ARCH_BASTIRQ_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/bast-map.h b/arch/arm/mach-s3c2410/include/mach/bast-map.h
deleted file mode 100644 (file)
index 6e7dc9d..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/bast-map.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Machine BAST - Memory map definitions
- *
- * 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.
-*/
-
-/* needs arch/map.h including with this */
-
-/* ok, we've used up to 0x13000000, now we need to find space for the
- * peripherals that live in the nGCS[x] areas, which are quite numerous
- * in their space. We also have the board's CPLD to find register space
- * for.
- */
-
-#ifndef __ASM_ARCH_BASTMAP_H
-#define __ASM_ARCH_BASTMAP_H
-
-#define BAST_IOADDR(x)    (S3C2410_ADDR((x) + 0x01300000))
-
-/* we put the CPLD registers next, to get them out of the way */
-
-#define BAST_VA_CTRL1      BAST_IOADDR(0x00000000)      /* 0x01300000 */
-#define BAST_PA_CTRL1      (S3C2410_CS5 | 0x7800000)
-
-#define BAST_VA_CTRL2      BAST_IOADDR(0x00100000)      /* 0x01400000 */
-#define BAST_PA_CTRL2      (S3C2410_CS1 | 0x6000000)
-
-#define BAST_VA_CTRL3      BAST_IOADDR(0x00200000)      /* 0x01500000 */
-#define BAST_PA_CTRL3      (S3C2410_CS1 | 0x6800000)
-
-#define BAST_VA_CTRL4      BAST_IOADDR(0x00300000)      /* 0x01600000 */
-#define BAST_PA_CTRL4      (S3C2410_CS1 | 0x7000000)
-
-/* next, we have the PC104 ISA interrupt registers */
-
-#define BAST_PA_PC104_IRQREQ  (S3C2410_CS5 | 0x6000000) /* 0x01700000 */
-#define BAST_VA_PC104_IRQREQ  BAST_IOADDR(0x00400000)
-
-#define BAST_PA_PC104_IRQRAW  (S3C2410_CS5 | 0x6800000) /* 0x01800000 */
-#define BAST_VA_PC104_IRQRAW  BAST_IOADDR(0x00500000)
-
-#define BAST_PA_PC104_IRQMASK (S3C2410_CS5 | 0x7000000) /* 0x01900000 */
-#define BAST_VA_PC104_IRQMASK BAST_IOADDR(0x00600000)
-
-#define BAST_PA_LCD_RCMD1     (0x8800000)
-#define BAST_VA_LCD_RCMD1     BAST_IOADDR(0x00700000)
-
-#define BAST_PA_LCD_WCMD1     (0x8000000)
-#define BAST_VA_LCD_WCMD1     BAST_IOADDR(0x00800000)
-
-#define BAST_PA_LCD_RDATA1    (0x9800000)
-#define BAST_VA_LCD_RDATA1    BAST_IOADDR(0x00900000)
-
-#define BAST_PA_LCD_WDATA1    (0x9000000)
-#define BAST_VA_LCD_WDATA1    BAST_IOADDR(0x00A00000)
-
-#define BAST_PA_LCD_RCMD2     (0xA800000)
-#define BAST_VA_LCD_RCMD2     BAST_IOADDR(0x00B00000)
-
-#define BAST_PA_LCD_WCMD2     (0xA000000)
-#define BAST_VA_LCD_WCMD2     BAST_IOADDR(0x00C00000)
-
-#define BAST_PA_LCD_RDATA2    (0xB800000)
-#define BAST_VA_LCD_RDATA2    BAST_IOADDR(0x00D00000)
-
-#define BAST_PA_LCD_WDATA2    (0xB000000)
-#define BAST_VA_LCD_WDATA2    BAST_IOADDR(0x00E00000)
-
-
-/* 0xE0000000 contains the IO space that is split by speed and
- * wether the access is for 8 or 16bit IO... this ensures that
- * the correct access is made
- *
- * 0x10000000 of space, partitioned as so:
- *
- * 0x00000000 to 0x04000000  8bit,  slow
- * 0x04000000 to 0x08000000  16bit, slow
- * 0x08000000 to 0x0C000000  16bit, net
- * 0x0C000000 to 0x10000000  16bit, fast
- *
- * each of these spaces has the following in:
- *
- * 0x00000000 to 0x01000000 16MB ISA IO space
- * 0x01000000 to 0x02000000 16MB ISA memory space
- * 0x02000000 to 0x02100000 1MB  IDE primary channel
- * 0x02100000 to 0x02200000 1MB  IDE primary channel aux
- * 0x02200000 to 0x02400000 1MB  IDE secondary channel
- * 0x02300000 to 0x02400000 1MB  IDE secondary channel aux
- * 0x02400000 to 0x02500000 1MB  ASIX ethernet controller
- * 0x02500000 to 0x02600000 1MB  Davicom DM9000 ethernet controller
- * 0x02600000 to 0x02700000 1MB  PC SuperIO controller
- *
- * the phyiscal layout of the zones are:
- *  nGCS2 - 8bit, slow
- *  nGCS3 - 16bit, slow
- *  nGCS4 - 16bit, net
- *  nGCS5 - 16bit, fast
- */
-
-#define BAST_VA_MULTISPACE (0xE0000000)
-
-#define BAST_VA_ISAIO     (BAST_VA_MULTISPACE + 0x00000000)
-#define BAST_VA_ISAMEM    (BAST_VA_MULTISPACE + 0x01000000)
-#define BAST_VA_IDEPRI    (BAST_VA_MULTISPACE + 0x02000000)
-#define BAST_VA_IDEPRIAUX  (BAST_VA_MULTISPACE + 0x02100000)
-#define BAST_VA_IDESEC    (BAST_VA_MULTISPACE + 0x02200000)
-#define BAST_VA_IDESECAUX  (BAST_VA_MULTISPACE + 0x02300000)
-#define BAST_VA_ASIXNET           (BAST_VA_MULTISPACE + 0x02400000)
-#define BAST_VA_DM9000    (BAST_VA_MULTISPACE + 0x02500000)
-#define BAST_VA_SUPERIO           (BAST_VA_MULTISPACE + 0x02600000)
-
-#define BAST_VA_MULTISPACE (0xE0000000)
-
-#define BAST_VAM_CS2 (0x00000000)
-#define BAST_VAM_CS3 (0x04000000)
-#define BAST_VAM_CS4 (0x08000000)
-#define BAST_VAM_CS5 (0x0C000000)
-
-/* physical offset addresses for the peripherals */
-
-#define BAST_PA_ISAIO    (0x00000000)
-#define BAST_PA_ASIXNET          (0x01000000)
-#define BAST_PA_SUPERIO          (0x01800000)
-#define BAST_PA_IDEPRI   (0x02000000)
-#define BAST_PA_IDEPRIAUX (0x02800000)
-#define BAST_PA_IDESEC   (0x03000000)
-#define BAST_PA_IDESECAUX (0x03800000)
-#define BAST_PA_ISAMEM   (0x04000000)
-#define BAST_PA_DM9000   (0x05000000)
-
-/* some configurations for the peripherals */
-
-#define BAST_PCSIO (BAST_VA_SUPERIO + BAST_VAM_CS2)
-/*  */
-
-#define BAST_ASIXNET_CS  BAST_VAM_CS5
-#define BAST_IDE_CS     BAST_VAM_CS5
-#define BAST_DM9000_CS  BAST_VAM_CS4
-
-#endif /* __ASM_ARCH_BASTMAP_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/bast-pmu.h b/arch/arm/mach-s3c2410/include/mach/bast-pmu.h
deleted file mode 100644 (file)
index 4c38b39..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/bast-pmu.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     Vincent Sanders <vince@simtec.co.uk>
- *
- * Machine BAST - Power Management chip
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_BASTPMU_H
-#define __ASM_ARCH_BASTPMU_H "08_OCT_2004"
-
-#define BASTPMU_REG_IDENT      (0x00)
-#define BASTPMU_REG_VERSION    (0x01)
-#define BASTPMU_REG_DDCCTRL    (0x02)
-#define BASTPMU_REG_POWER      (0x03)
-#define BASTPMU_REG_RESET      (0x04)
-#define BASTPMU_REG_GWO                (0x05)
-#define BASTPMU_REG_WOL                (0x06)
-#define BASTPMU_REG_WOR                (0x07)
-#define BASTPMU_REG_UID                (0x09)
-
-#define BASTPMU_EEPROM         (0xC0)
-
-#define BASTPMU_EEP_UID                (BASTPMU_EEPROM + 0)
-#define BASTPMU_EEP_WOL                (BASTPMU_EEPROM + 8)
-#define BASTPMU_EEP_WOR                (BASTPMU_EEPROM + 9)
-
-#define BASTPMU_IDENT_0                0x53
-#define BASTPMU_IDENT_1                0x42
-#define BASTPMU_IDENT_2                0x50
-#define BASTPMU_IDENT_3                0x4d
-
-#define BASTPMU_RESET_GUARD    (0x55)
-
-#endif /* __ASM_ARCH_BASTPMU_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/debug-macro.S b/arch/arm/mach-s3c2410/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 4135de8..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Copyright (C) 2005 Simtec Electronics
- *
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * 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 <mach/map.h>
-#include <mach/regs-gpio.h>
-#include <plat/regs-serial.h>
-
-#define S3C2410_UART1_OFF (0x4000)
-#define SHIFT_2440TXF (14-9)
-
-       .macro addruart, rp, rv, tmp
-               ldr     \rp, = S3C24XX_PA_UART
-               ldr     \rv, = S3C24XX_VA_UART
-#if CONFIG_DEBUG_S3C_UART != 0
-               add     \rp, \rp, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
-               add     \rv, \rv, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
-#endif
-       .endm
-
-       .macro fifo_full_s3c24xx rd, rx
-               @ check for arm920 vs arm926. currently assume all arm926
-               @ devices have an 64 byte FIFO identical to the s3c2440
-               mrc     p15, 0, \rd, c0, c0
-               and     \rd, \rd, #0xff0
-               teq     \rd, #0x260
-               beq     1004f
-               mrc     p15, 0, \rd, c1, c0
-               tst     \rd, #1
-               addeq   \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
-               addne   \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART)
-               bic     \rd, \rd, #0xff000
-               ldr     \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
-               and     \rd, \rd, #0x00ff0000
-               teq     \rd, #0x00440000                @ is it 2440?
-1004:
-               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
-               moveq   \rd, \rd, lsr #SHIFT_2440TXF
-               tst     \rd, #S3C2410_UFSTAT_TXFULL
-       .endm
-
-       .macro  fifo_full_s3c2410 rd, rx
-               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
-               tst     \rd, #S3C2410_UFSTAT_TXFULL
-       .endm
-
-/* fifo level reading */
-
-       .macro fifo_level_s3c24xx rd, rx
-               @ check for arm920 vs arm926. currently assume all arm926
-               @ devices have an 64 byte FIFO identical to the s3c2440
-               mrc     p15, 0, \rd, c0, c0
-               and     \rd, \rd, #0xff0
-               teq     \rd, #0x260
-               beq     10000f
-               mrc     p15, 0, \rd, c1, c0
-               tst     \rd, #1
-               addeq   \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
-               addne   \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART)
-               bic     \rd, \rd, #0xff000
-               ldr     \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
-               and     \rd, \rd, #0x00ff0000
-               teq     \rd, #0x00440000                @ is it 2440?
-
-10000:
-               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
-               andne   \rd, \rd, #S3C2410_UFSTAT_TXMASK
-               andeq   \rd, \rd, #S3C2440_UFSTAT_TXMASK
-       .endm
-
-       .macro fifo_level_s3c2410 rd, rx
-               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
-               and     \rd, \rd, #S3C2410_UFSTAT_TXMASK
-       .endm
-
-/* Select the correct implementation depending on the configuration. The
- * S3C2440 will get selected by default, as these are the most widely
- * used variants of these
-*/
-
-#if defined(CONFIG_CPU_LLSERIAL_S3C2410_ONLY)
-#define fifo_full  fifo_full_s3c2410
-#define fifo_level fifo_level_s3c2410
-#elif !defined(CONFIG_CPU_LLSERIAL_S3C2440_ONLY)
-#define fifo_full  fifo_full_s3c24xx
-#define fifo_level fifo_level_s3c24xx
-#endif
-
-/* include the reset of the code which will do the work */
-
-#include <plat/debug-macro.S>
diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h
deleted file mode 100644 (file)
index acbdfec..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/dma.h
- *
- * Copyright (C) 2003-2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C24XX DMA support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H __FILE__
-
-#include <linux/device.h>
-
-#define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
-
-/* We use `virtual` dma channels to hide the fact we have only a limited
- * number of DMA channels, and not of all of them (dependent on the device)
- * can be attached to any DMA source. We therefore let the DMA core handle
- * the allocation of hardware channels to clients.
-*/
-
-enum dma_ch {
-       DMACH_XD0,
-       DMACH_XD1,
-       DMACH_SDI,
-       DMACH_SPI0,
-       DMACH_SPI1,
-       DMACH_UART0,
-       DMACH_UART1,
-       DMACH_UART2,
-       DMACH_TIMER,
-       DMACH_I2S_IN,
-       DMACH_I2S_OUT,
-       DMACH_PCM_IN,
-       DMACH_PCM_OUT,
-       DMACH_MIC_IN,
-       DMACH_USB_EP1,
-       DMACH_USB_EP2,
-       DMACH_USB_EP3,
-       DMACH_USB_EP4,
-       DMACH_UART0_SRC2,       /* s3c2412 second uart sources */
-       DMACH_UART1_SRC2,
-       DMACH_UART2_SRC2,
-       DMACH_UART3,            /* s3c2443 has extra uart */
-       DMACH_UART3_SRC2,
-       DMACH_MAX,              /* the end entry */
-};
-
-static inline bool samsung_dma_has_circular(void)
-{
-       return false;
-}
-
-static inline bool samsung_dma_is_dmadev(void)
-{
-       return false;
-}
-
-#include <plat/dma.h>
-
-#define DMACH_LOW_LEVEL        (1<<28) /* use this to specifiy hardware ch no */
-
-/* we have 4 dma channels */
-#if !defined(CONFIG_CPU_S3C2443) && !defined(CONFIG_CPU_S3C2416)
-#define S3C_DMA_CHANNELS               (4)
-#else
-#define S3C_DMA_CHANNELS               (6)
-#endif
-
-/* types */
-
-enum s3c2410_dma_state {
-       S3C2410_DMA_IDLE,
-       S3C2410_DMA_RUNNING,
-       S3C2410_DMA_PAUSED
-};
-
-/* enum s3c2410_dma_loadst
- *
- * This represents the state of the DMA engine, wrt to the loaded / running
- * transfers. Since we don't have any way of knowing exactly the state of
- * the DMA transfers, we need to know the state to make decisions on wether
- * we can
- *
- * S3C2410_DMA_NONE
- *
- * There are no buffers loaded (the channel should be inactive)
- *
- * S3C2410_DMA_1LOADED
- *
- * There is one buffer loaded, however it has not been confirmed to be
- * loaded by the DMA engine. This may be because the channel is not
- * yet running, or the DMA driver decided that it was too costly to
- * sit and wait for it to happen.
- *
- * S3C2410_DMA_1RUNNING
- *
- * The buffer has been confirmed running, and not finisged
- *
- * S3C2410_DMA_1LOADED_1RUNNING
- *
- * There is a buffer waiting to be loaded by the DMA engine, and one
- * currently running.
-*/
-
-enum s3c2410_dma_loadst {
-       S3C2410_DMALOAD_NONE,
-       S3C2410_DMALOAD_1LOADED,
-       S3C2410_DMALOAD_1RUNNING,
-       S3C2410_DMALOAD_1LOADED_1RUNNING,
-};
-
-
-/* flags */
-
-#define S3C2410_DMAF_SLOW         (1<<0)   /* slow, so don't worry about
-                                           * waiting for reloads */
-#define S3C2410_DMAF_AUTOSTART    (1<<1)   /* auto-start if buffer queued */
-
-#define S3C2410_DMAF_CIRCULAR  (1 << 2)        /* no circular dma support */
-
-/* dma buffer */
-
-struct s3c2410_dma_buf;
-
-/* s3c2410_dma_buf
- *
- * internally used buffer structure to describe a queued or running
- * buffer.
-*/
-
-struct s3c2410_dma_buf {
-       struct s3c2410_dma_buf  *next;
-       int                      magic;         /* magic */
-       int                      size;          /* buffer size in bytes */
-       dma_addr_t               data;          /* start of DMA data */
-       dma_addr_t               ptr;           /* where the DMA got to [1] */
-       void                    *id;            /* client's id */
-};
-
-/* [1] is this updated for both recv/send modes? */
-
-struct s3c2410_dma_stats {
-       unsigned long           loads;
-       unsigned long           timeout_longest;
-       unsigned long           timeout_shortest;
-       unsigned long           timeout_avg;
-       unsigned long           timeout_failed;
-};
-
-struct s3c2410_dma_map;
-
-/* struct s3c2410_dma_chan
- *
- * full state information for each DMA channel
-*/
-
-struct s3c2410_dma_chan {
-       /* channel state flags and information */
-       unsigned char            number;      /* number of this dma channel */
-       unsigned char            in_use;      /* channel allocated */
-       unsigned char            irq_claimed; /* irq claimed for channel */
-       unsigned char            irq_enabled; /* irq enabled for channel */
-       unsigned char            xfer_unit;   /* size of an transfer */
-
-       /* channel state */
-
-       enum s3c2410_dma_state   state;
-       enum s3c2410_dma_loadst  load_state;
-       struct s3c2410_dma_client *client;
-
-       /* channel configuration */
-       enum dma_data_direction  source;
-       enum dma_ch              req_ch;
-       unsigned long            dev_addr;
-       unsigned long            load_timeout;
-       unsigned int             flags;         /* channel flags */
-
-       struct s3c24xx_dma_map  *map;           /* channel hw maps */
-
-       /* channel's hardware position and configuration */
-       void __iomem            *regs;          /* channels registers */
-       void __iomem            *addr_reg;      /* data address register */
-       unsigned int             irq;           /* channel irq */
-       unsigned long            dcon;          /* default value of DCON */
-
-       /* driver handles */
-       s3c2410_dma_cbfn_t       callback_fn;   /* buffer done callback */
-       s3c2410_dma_opfn_t       op_fn;         /* channel op callback */
-
-       /* stats gathering */
-       struct s3c2410_dma_stats *stats;
-       struct s3c2410_dma_stats  stats_store;
-
-       /* buffer list and information */
-       struct s3c2410_dma_buf  *curr;          /* current dma buffer */
-       struct s3c2410_dma_buf  *next;          /* next buffer to load */
-       struct s3c2410_dma_buf  *end;           /* end of queue */
-
-       /* system device */
-       struct device   dev;
-};
-
-typedef unsigned long dma_device_t;
-
-#endif /* __ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/entry-macro.S b/arch/arm/mach-s3c2410/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 473b3cd..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * arch/arm/mach-s3c2410/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for S3C2410-based platforms
- *
- * 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.
-*/
-
-/* We have a problem that the INTOFFSET register does not always
- * show one interrupt. Occasionally we get two interrupts through
- * the prioritiser, and this causes the INTOFFSET register to show
- * what looks like the logical-or of the two interrupt numbers.
- *
- * Thanks to Klaus, Shannon, et al for helping to debug this problem
-*/
-
-#define INTPND         (0x10)
-#define INTOFFSET      (0x14)
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-       .macro  get_irqnr_preamble, base, tmp
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
-       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-
-               mov     \base, #S3C24XX_VA_IRQ
-
-               @@ try the interrupt offset register, since it is there
-
-               ldr     \irqstat, [ \base, #INTPND ]
-               teq     \irqstat, #0
-               beq     1002f
-               ldr     \irqnr, [ \base, #INTOFFSET ]
-               mov     \tmp, #1
-               tst     \irqstat, \tmp, lsl \irqnr
-               bne     1001f
-
-               @@ the number specified is not a valid irq, so try
-               @@ and work it out for ourselves
-
-               mov     \irqnr, #0              @@ start here
-
-               @@ work out which irq (if any) we got
-
-               movs    \tmp, \irqstat, lsl#16
-               addeq   \irqnr, \irqnr, #16
-               moveq   \irqstat, \irqstat, lsr#16
-               tst     \irqstat, #0xff
-               addeq   \irqnr, \irqnr, #8
-               moveq   \irqstat, \irqstat, lsr#8
-               tst     \irqstat, #0xf
-               addeq   \irqnr, \irqnr, #4
-               moveq   \irqstat, \irqstat, lsr#4
-               tst     \irqstat, #0x3
-               addeq   \irqnr, \irqnr, #2
-               moveq   \irqstat, \irqstat, lsr#2
-               tst     \irqstat, #0x1
-               addeq   \irqnr, \irqnr, #1
-
-               @@ we have the value
-1001:
-               adds    \irqnr, \irqnr, #IRQ_EINT0
-1002:
-               @@ exit here, Z flag unset if IRQ
-
-       .endm
-
-               /* currently don't need an disable_fiq macro */
-
-               .macro  disable_fiq
-               .endm
diff --git a/arch/arm/mach-s3c2410/include/mach/fb.h b/arch/arm/mach-s3c2410/include/mach/fb.h
deleted file mode 100644 (file)
index a957bc8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <plat/fb-s3c2410.h>
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-fns.h b/arch/arm/mach-s3c2410/include/mach/gpio-fns.h
deleted file mode 100644 (file)
index c53ad34..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <plat/gpio-fns.h>
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-nrs.h b/arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
deleted file mode 100644 (file)
index 019ea86..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
- *
- * Copyright (c) 2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - GPIO bank numbering
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __MACH_GPIONRS_H
-#define __MACH_GPIONRS_H
-
-#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
-
-#define S3C2410_GPIO_BANKG   (32*6)
-#define S3C2410_GPIO_BANKH   (32*7)
-
-/* GPIO sizes for various SoCs:
- *
- *             2442
- *   2410 2412 2440 2443 2416
- *   ---- ---- ---- ---- ----
- * A 23   22   25   16   25
- * B 11   11   11   11   9
- * C 16   15   16   16   16
- * D 16   16   16   16   16
- * E 16   16   16   16   16
- * F 8    8    8    8    8
- * G 16   16   16   16   8
- * H 11   11   9    15   15
- * J --   --   13   16   --
- * K --   --   --   --   16
- * L --   --   --   15   7
- * M --   --   --   2    2
- */
-
-/* GPIO bank sizes */
-#define S3C2410_GPIO_A_NR      (32)
-#define S3C2410_GPIO_B_NR      (32)
-#define S3C2410_GPIO_C_NR      (32)
-#define S3C2410_GPIO_D_NR      (32)
-#define S3C2410_GPIO_E_NR      (32)
-#define S3C2410_GPIO_F_NR      (32)
-#define S3C2410_GPIO_G_NR      (32)
-#define S3C2410_GPIO_H_NR      (32)
-#define S3C2410_GPIO_J_NR      (32)    /* technically 16. */
-#define S3C2410_GPIO_K_NR      (32)    /* technically 16. */
-#define S3C2410_GPIO_L_NR      (32)    /* technically 15. */
-#define S3C2410_GPIO_M_NR      (32)    /* technically 2. */
-
-#if CONFIG_S3C_GPIO_SPACE != 0
-#error CONFIG_S3C_GPIO_SPACE cannot be nonzero at the moment
-#endif
-
-#define S3C2410_GPIO_NEXT(__gpio) \
-       ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)
-
-#ifndef __ASSEMBLY__
-
-enum s3c_gpio_number {
-       S3C2410_GPIO_A_START = 0,
-       S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
-       S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
-       S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
-       S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
-       S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
-       S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
-       S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
-       S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H),
-       S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J),
-       S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K),
-       S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L),
-};
-
-#endif /* __ASSEMBLY__ */
-
-/* S3C2410 GPIO number definitions. */
-
-#define S3C2410_GPA(_nr)       (S3C2410_GPIO_A_START + (_nr))
-#define S3C2410_GPB(_nr)       (S3C2410_GPIO_B_START + (_nr))
-#define S3C2410_GPC(_nr)       (S3C2410_GPIO_C_START + (_nr))
-#define S3C2410_GPD(_nr)       (S3C2410_GPIO_D_START + (_nr))
-#define S3C2410_GPE(_nr)       (S3C2410_GPIO_E_START + (_nr))
-#define S3C2410_GPF(_nr)       (S3C2410_GPIO_F_START + (_nr))
-#define S3C2410_GPG(_nr)       (S3C2410_GPIO_G_START + (_nr))
-#define S3C2410_GPH(_nr)       (S3C2410_GPIO_H_START + (_nr))
-#define S3C2410_GPJ(_nr)       (S3C2410_GPIO_J_START + (_nr))
-#define S3C2410_GPK(_nr)       (S3C2410_GPIO_K_START + (_nr))
-#define S3C2410_GPL(_nr)       (S3C2410_GPIO_L_START + (_nr))
-#define S3C2410_GPM(_nr)       (S3C2410_GPIO_M_START + (_nr))
-
-/* compatibility until drivers can be modified */
-
-#define S3C2410_GPA0   S3C2410_GPA(0)
-#define S3C2410_GPA1   S3C2410_GPA(1)
-#define S3C2410_GPA3   S3C2410_GPA(3)
-#define S3C2410_GPA7   S3C2410_GPA(7)
-
-#define S3C2410_GPE0   S3C2410_GPE(0)
-#define S3C2410_GPE1   S3C2410_GPE(1)
-#define S3C2410_GPE2   S3C2410_GPE(2)
-#define S3C2410_GPE3   S3C2410_GPE(3)
-#define S3C2410_GPE4   S3C2410_GPE(4)
-#define S3C2410_GPE5   S3C2410_GPE(5)
-#define S3C2410_GPE6   S3C2410_GPE(6)
-#define S3C2410_GPE7   S3C2410_GPE(7)
-#define S3C2410_GPE8   S3C2410_GPE(8)
-#define S3C2410_GPE9   S3C2410_GPE(9)
-#define S3C2410_GPE10  S3C2410_GPE(10)
-
-#define S3C2410_GPH10  S3C2410_GPH(10)
-
-#endif /* __MACH_GPIONRS_H */
-
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-track.h b/arch/arm/mach-s3c2410/include/mach/gpio-track.h
deleted file mode 100644 (file)
index c410a07..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* arch/arm/mach-s3c24100/include/mach/gpio-core.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * S3C2410 - GPIO core support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_GPIO_CORE_H
-#define __ASM_ARCH_GPIO_CORE_H __FILE__
-
-#include <mach/regs-gpio.h>
-
-extern struct samsung_gpio_chip s3c24xx_gpios[];
-
-static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int pin)
-{
-       struct samsung_gpio_chip *chip;
-
-       if (pin > S3C_GPIO_END)
-               return NULL;
-
-       chip = &s3c24xx_gpios[pin/32];
-       return ((pin - chip->chip.base) < chip->chip.ngpio) ? chip : NULL;
-}
-
-#endif /* __ASM_ARCH_GPIO_CORE_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio.h b/arch/arm/mach-s3c2410/include/mach/gpio.h
deleted file mode 100644 (file)
index 6fac70f..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/gpio.h
- *
- * Copyright (c) 2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - GPIO lib support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/* some boards require extra gpio capacity to support external
- * devices that need GPIO.
- */
-
-#ifdef CONFIG_CPU_S3C244X
-#define ARCH_NR_GPIOS  (32 * 9 + CONFIG_S3C24XX_GPIO_EXTRA)
-#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
-#define ARCH_NR_GPIOS  (32 * 12 + CONFIG_S3C24XX_GPIO_EXTRA)
-#else
-#define ARCH_NR_GPIOS  (256 + CONFIG_S3C24XX_GPIO_EXTRA)
-#endif
-
-#include <mach/gpio-nrs.h>
-#include <mach/gpio-fns.h>
-
-#ifdef CONFIG_CPU_S3C244X
-#define S3C_GPIO_END   (S3C2410_GPJ(0) + 32)
-#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
-#define S3C_GPIO_END   (S3C2410_GPM(0) + 32)
-#else
-#define S3C_GPIO_END   (S3C2410_GPH(0) + 32)
-#endif
diff --git a/arch/arm/mach-s3c2410/include/mach/h1940-latch.h b/arch/arm/mach-s3c2410/include/mach/h1940-latch.h
deleted file mode 100644 (file)
index fc897d3..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/h1940-latch.h
- *
- * Copyright (c) 2005 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- *  iPAQ H1940 series - latch definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_H1940_LATCH_H
-#define __ASM_ARCH_H1940_LATCH_H
-
-#include <asm/gpio.h>
-
-#define H1940_LATCH_GPIO(x)            (S3C_GPIO_END + (x))
-
-/* SD layer latch */
-
-#define H1940_LATCH_LCD_P0             H1940_LATCH_GPIO(0)
-#define H1940_LATCH_LCD_P1             H1940_LATCH_GPIO(1)
-#define H1940_LATCH_LCD_P2             H1940_LATCH_GPIO(2)
-#define H1940_LATCH_LCD_P3             H1940_LATCH_GPIO(3)
-#define H1940_LATCH_MAX1698_nSHUTDOWN  H1940_LATCH_GPIO(4)
-#define H1940_LATCH_LED_RED            H1940_LATCH_GPIO(5)
-#define H1940_LATCH_SDQ7               H1940_LATCH_GPIO(6)
-#define H1940_LATCH_USB_DP             H1940_LATCH_GPIO(7)
-
-/* CPU layer latch */
-
-#define H1940_LATCH_UDA_POWER          H1940_LATCH_GPIO(8)
-#define H1940_LATCH_AUDIO_POWER                H1940_LATCH_GPIO(9)
-#define H1940_LATCH_SM803_ENABLE       H1940_LATCH_GPIO(10)
-#define H1940_LATCH_LCD_P4             H1940_LATCH_GPIO(11)
-#define H1940_LATCH_SD_POWER           H1940_LATCH_GPIO(12)
-#define H1940_LATCH_BLUETOOTH_POWER    H1940_LATCH_GPIO(13)
-#define H1940_LATCH_LED_GREEN          H1940_LATCH_GPIO(14)
-#define H1940_LATCH_LED_FLASH          H1940_LATCH_GPIO(15)
-
-#endif /* __ASM_ARCH_H1940_LATCH_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/h1940.h b/arch/arm/mach-s3c2410/include/mach/h1940.h
deleted file mode 100644 (file)
index 2aa683c..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/h1940.h
- *
- * Copyright 2006 Ben Dooks <ben-linux@fluff.org>
- *
- * H1940 definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_H1940_H
-#define __ASM_ARCH_H1940_H
-
-#define H1940_SUSPEND_CHECKSUM         (0x30003ff8)
-#define H1940_SUSPEND_RESUMEAT         (0x30081000)
-#define H1940_SUSPEND_CHECK            (0x30080000)
-
-extern void h1940_pm_return(void);
-extern int h1940_led_blink_set(unsigned gpio, int state,
-       unsigned long *delay_on, unsigned long *delay_off);
-
-
-#endif /* __ASM_ARCH_H1940_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/hardware.h b/arch/arm/mach-s3c2410/include/mach/hardware.h
deleted file mode 100644 (file)
index aef5631..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/hardware.h
- *
- * Copyright (c) 2003 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - hardware
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#ifndef __ASSEMBLY__
-
-extern unsigned int s3c2410_modify_misccr(unsigned int clr, unsigned int chg);
-
-#ifdef CONFIG_CPU_S3C2440
-
-extern int s3c2440_set_dsc(unsigned int pin, unsigned int value);
-
-#endif /* CONFIG_CPU_S3C2440 */
-
-#ifdef CONFIG_CPU_S3C2412
-
-extern int s3c2412_gpio_set_sleepcfg(unsigned int pin, unsigned int state);
-
-#endif /* CONFIG_CPU_S3C2412 */
-
-#endif /* __ASSEMBLY__ */
-
-#include <asm/sizes.h>
-#include <mach/map.h>
-
-/* machine specific hardware definitions should go after this */
-
-/* currently here until moved into config (todo) */
-#define CONFIG_NO_MULTIWORD_IO
-
-#endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/idle.h b/arch/arm/mach-s3c2410/include/mach/idle.h
deleted file mode 100644 (file)
index e9ddd70..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/idle.h
- *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
- *             http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2410 CPU Idle controls
-*/
-
-#ifndef __ASM_ARCH_IDLE_H
-#define __ASM_ARCH_IDLE_H __FILE__
-
-/* This allows the over-ride of the default idle code, in case there
- * is any other things to be done over idle (like DVS)
-*/
-
-extern void (*s3c24xx_idle)(void);
-
-extern void s3c24xx_default_idle(void);
-
-#endif /* __ASM_ARCH_IDLE_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/io.h b/arch/arm/mach-s3c2410/include/mach/io.h
deleted file mode 100644 (file)
index 118749f..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * arch/arm/mach-s3c2410/include/mach/io.h
- *  from arch/arm/mach-rpc/include/mach/io.h
- *
- * Copyright (C) 1997 Russell King
- *          (C) 2003 Simtec Electronics
-*/
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#include <mach/hardware.h>
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses.  PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1.  ARM addresses are above A28
- * and are translated to the start of IO.  Note that all addresses are
- * not shifted left!
- */
-
-#define __PORT_PCIO(x) ((x) < (1<<28))
-
-#define PCIO_BASE       (S3C24XX_VA_ISA_WORD)
-#define PCIO_BASE_b     (S3C24XX_VA_ISA_BYTE)
-#define PCIO_BASE_w     (S3C24XX_VA_ISA_WORD)
-#define PCIO_BASE_l     (S3C24XX_VA_ISA_WORD)
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-
-#define DECLARE_DYN_OUT(sz,fnsuffix,instr) \
-static inline void __out##fnsuffix (unsigned int val, unsigned int port) \
-{ \
-       unsigned long temp;                                   \
-       __asm__ __volatile__(                                 \
-       "cmp    %2, #(1<<28)\n\t"                             \
-       "mov    %0, %2\n\t"                                   \
-       "addcc  %0, %0, %3\n\t"                               \
-       "str" instr " %1, [%0, #0 ]     @ out" #fnsuffix      \
-       : "=&r" (temp)                                        \
-       : "r" (val), "r" (port), "Ir" (PCIO_BASE_##fnsuffix)  \
-       : "cc");                                              \
-}
-
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr)                              \
-static inline unsigned sz __in##fnsuffix (unsigned int port)           \
-{                                                                      \
-       unsigned long temp, value;                                      \
-       __asm__ __volatile__(                                           \
-       "cmp    %2, #(1<<28)\n\t"                                       \
-       "mov    %0, %2\n\t"                                             \
-       "addcc  %0, %0, %3\n\t"                                         \
-       "ldr" instr "   %1, [%0, #0 ]   @ in" #fnsuffix         \
-       : "=&r" (temp), "=r" (value)                                    \
-       : "r" (port), "Ir" (PCIO_BASE_##fnsuffix)       \
-       : "cc");                                                        \
-       return (unsigned sz)value;                                      \
-}
-
-static inline void __iomem *__ioaddr (unsigned long port)
-{
-       return __PORT_PCIO(port) ? (PCIO_BASE + port) : (void __iomem *)port;
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr)  \
-       DECLARE_DYN_IN(sz,fnsuffix,instr) \
-       DECLARE_DYN_OUT(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"h")
-DECLARE_IO(int,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port)                                            \
-({                                                                     \
-       if (__PORT_PCIO((port)))                                        \
-               __asm__ __volatile__(                                   \
-               "strb   %0, [%1, %2]    @ outbc"                        \
-               : : "r" (value), "r" (PCIO_BASE), "Jr" ((port)));       \
-       else                                                            \
-               __asm__ __volatile__(                                   \
-               "strb   %0, [%1, #0]    @ outbc"                        \
-               : : "r" (value), "r" ((port)));                         \
-})
-
-#define __inbc(port)                                                   \
-({                                                                     \
-       unsigned char result;                                           \
-       if (__PORT_PCIO((port)))                                        \
-               __asm__ __volatile__(                                   \
-               "ldrb   %0, [%1, %2]    @ inbc"                         \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port)));      \
-       else                                                            \
-               __asm__ __volatile__(                                   \
-               "ldrb   %0, [%1, #0]    @ inbc"                         \
-               : "=r" (result) : "r" ((port)));                        \
-       result;                                                         \
-})
-
-#define __outwc(value,port)                                            \
-({                                                                     \
-       unsigned long v = value;                                        \
-       if (__PORT_PCIO((port))) {                                      \
-               if ((port) < 256 && (port) > -256)                      \
-                       __asm__ __volatile__(                           \
-                       "strh   %0, [%1, %2]    @ outwc"                \
-                       : : "r" (v), "r" (PCIO_BASE), "Jr" ((port)));   \
-               else if ((port) > 0)                                    \
-                       __asm__ __volatile__(                           \
-                       "strh   %0, [%1, %2]    @ outwc"                \
-                       : : "r" (v),                                    \
-                           "r" (PCIO_BASE + ((port) & ~0xff)),         \
-                            "Jr" (((port) & 0xff)));                   \
-               else                                                    \
-                       __asm__ __volatile__(                           \
-                       "strh   %0, [%1, #0]    @ outwc"                \
-                       : : "r" (v),                                    \
-                           "r" (PCIO_BASE + (port)));                  \
-       } else                                                          \
-               __asm__ __volatile__(                                   \
-               "strh   %0, [%1, #0]    @ outwc"                        \
-               : : "r" (v), "r" ((port)));                             \
-})
-
-#define __inwc(port)                                                   \
-({                                                                     \
-       unsigned short result;                                          \
-       if (__PORT_PCIO((port))) {                                      \
-               if ((port) < 256 && (port) > -256 )                     \
-                       __asm__ __volatile__(                           \
-                       "ldrh   %0, [%1, %2]    @ inwc"                 \
-                       : "=r" (result)                                 \
-                       : "r" (PCIO_BASE),                              \
-                         "Jr" ((port)));                               \
-               else if ((port) > 0)                                    \
-                       __asm__ __volatile__(                           \
-                       "ldrh   %0, [%1, %2]    @ inwc"                 \
-                       : "=r" (result)                                 \
-                       : "r" (PCIO_BASE + ((port) & ~0xff)),           \
-                         "Jr" (((port) & 0xff)));                      \
-               else                                                    \
-                       __asm__ __volatile__(                           \
-                       "ldrh   %0, [%1, #0]    @ inwc"                 \
-                       : "=r" (result)                                 \
-                       : "r" (PCIO_BASE + ((port))));                  \
-       } else                                                          \
-               __asm__ __volatile__(                                   \
-               "ldrh   %0, [%1, #0]    @ inwc"                         \
-               : "=r" (result) : "r" ((port)));                        \
-       result;                                                         \
-})
-
-#define __outlc(value,port)                                            \
-({                                                                     \
-       unsigned long v = value;                                        \
-       if (__PORT_PCIO((port)))                                        \
-               __asm__ __volatile__(                                   \
-               "str    %0, [%1, %2]    @ outlc"                        \
-               : : "r" (v), "r" (PCIO_BASE), "Jr" ((port)));   \
-       else                                                            \
-               __asm__ __volatile__(                                   \
-               "str    %0, [%1, #0]    @ outlc"                        \
-               : : "r" (v), "r" ((port)));             \
-})
-
-#define __inlc(port)                                                   \
-({                                                                     \
-       unsigned long result;                                           \
-       if (__PORT_PCIO((port)))                                        \
-               __asm__ __volatile__(                                   \
-               "ldr    %0, [%1, %2]    @ inlc"                         \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port)));      \
-       else                                                            \
-               __asm__ __volatile__(                                   \
-               "ldr    %0, [%1, #0]    @ inlc"                         \
-               : "=r" (result) : "r" ((port)));                \
-       result;                                                         \
-})
-
-#define __ioaddrc(port)        ((__PORT_PCIO(port) ? PCIO_BASE + (port) : (void __iomem *)(port)))
-
-#define inb(p)         (__builtin_constant_p((p)) ? __inbc(p)     : __inb(p))
-#define inw(p)         (__builtin_constant_p((p)) ? __inwc(p)     : __inw(p))
-#define inl(p)         (__builtin_constant_p((p)) ? __inlc(p)     : __inl(p))
-#define outb(v,p)      (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
-#define outw(v,p)      (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
-#define outl(v,p)      (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
-#define __ioaddr(p)    (__builtin_constant_p((p)) ? __ioaddr(p)  : __ioaddrc(p))
-
-#define insb(p,d,l)    __raw_readsb(__ioaddr(p),d,l)
-#define insw(p,d,l)    __raw_readsw(__ioaddr(p),d,l)
-#define insl(p,d,l)    __raw_readsl(__ioaddr(p),d,l)
-
-#define outsb(p,d,l)   __raw_writesb(__ioaddr(p),d,l)
-#define outsw(p,d,l)   __raw_writesw(__ioaddr(p),d,l)
-#define outsl(p,d,l)   __raw_writesl(__ioaddr(p),d,l)
-
-/*
- * 1:1 mapping for ioremapped regions.
- */
-#define __mem_pci(x)   (x)
-
-#endif
diff --git a/arch/arm/mach-s3c2410/include/mach/irqs.h b/arch/arm/mach-s3c2410/include/mach/irqs.h
deleted file mode 100644 (file)
index e53b217..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/irqs.h
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-
-#ifndef __ASM_ARCH_IRQS_H
-#define __ASM_ARCH_IRQS_H __FILE__
-
-/* we keep the first set of CPU IRQs out of the range of
- * the ISA space, so that the PC104 has them to itself
- * and we don't end up having to do horrible things to the
- * standard ISA drivers....
- */
-
-#define S3C2410_CPUIRQ_OFFSET   (16)
-
-#define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET)
-
-/* main cpu interrupts */
-#define IRQ_EINT0      S3C2410_IRQ(0)      /* 16 */
-#define IRQ_EINT1      S3C2410_IRQ(1)
-#define IRQ_EINT2      S3C2410_IRQ(2)
-#define IRQ_EINT3      S3C2410_IRQ(3)
-#define IRQ_EINT4t7    S3C2410_IRQ(4)      /* 20 */
-#define IRQ_EINT8t23   S3C2410_IRQ(5)
-#define IRQ_RESERVED6  S3C2410_IRQ(6)      /* for s3c2410 */
-#define IRQ_CAM        S3C2410_IRQ(6)      /* for s3c2440,s3c2443 */
-#define IRQ_BATT_FLT   S3C2410_IRQ(7)
-#define IRQ_TICK       S3C2410_IRQ(8)      /* 24 */
-#define IRQ_WDT               S3C2410_IRQ(9)       /* WDT/AC97 for s3c2443 */
-#define IRQ_TIMER0     S3C2410_IRQ(10)
-#define IRQ_TIMER1     S3C2410_IRQ(11)
-#define IRQ_TIMER2     S3C2410_IRQ(12)
-#define IRQ_TIMER3     S3C2410_IRQ(13)
-#define IRQ_TIMER4     S3C2410_IRQ(14)
-#define IRQ_UART2      S3C2410_IRQ(15)
-#define IRQ_LCD               S3C2410_IRQ(16)      /* 32 */
-#define IRQ_DMA0       S3C2410_IRQ(17)     /* IRQ_DMA for s3c2443 */
-#define IRQ_DMA1       S3C2410_IRQ(18)
-#define IRQ_DMA2       S3C2410_IRQ(19)
-#define IRQ_DMA3       S3C2410_IRQ(20)
-#define IRQ_SDI               S3C2410_IRQ(21)
-#define IRQ_SPI0       S3C2410_IRQ(22)
-#define IRQ_UART1      S3C2410_IRQ(23)
-#define IRQ_RESERVED24 S3C2410_IRQ(24)     /* 40 */
-#define IRQ_NFCON      S3C2410_IRQ(24)     /* for s3c2440 */
-#define IRQ_USBD       S3C2410_IRQ(25)
-#define IRQ_USBH       S3C2410_IRQ(26)
-#define IRQ_IIC               S3C2410_IRQ(27)
-#define IRQ_UART0      S3C2410_IRQ(28)     /* 44 */
-#define IRQ_SPI1       S3C2410_IRQ(29)
-#define IRQ_RTC               S3C2410_IRQ(30)
-#define IRQ_ADCPARENT  S3C2410_IRQ(31)
-
-/* interrupts generated from the external interrupts sources */
-#define IRQ_EINT4      S3C2410_IRQ(32)    /* 48 */
-#define IRQ_EINT5      S3C2410_IRQ(33)
-#define IRQ_EINT6      S3C2410_IRQ(34)
-#define IRQ_EINT7      S3C2410_IRQ(35)
-#define IRQ_EINT8      S3C2410_IRQ(36)
-#define IRQ_EINT9      S3C2410_IRQ(37)
-#define IRQ_EINT10     S3C2410_IRQ(38)
-#define IRQ_EINT11     S3C2410_IRQ(39)
-#define IRQ_EINT12     S3C2410_IRQ(40)
-#define IRQ_EINT13     S3C2410_IRQ(41)
-#define IRQ_EINT14     S3C2410_IRQ(42)
-#define IRQ_EINT15     S3C2410_IRQ(43)
-#define IRQ_EINT16     S3C2410_IRQ(44)
-#define IRQ_EINT17     S3C2410_IRQ(45)
-#define IRQ_EINT18     S3C2410_IRQ(46)
-#define IRQ_EINT19     S3C2410_IRQ(47)
-#define IRQ_EINT20     S3C2410_IRQ(48)    /* 64 */
-#define IRQ_EINT21     S3C2410_IRQ(49)
-#define IRQ_EINT22     S3C2410_IRQ(50)
-#define IRQ_EINT23     S3C2410_IRQ(51)
-
-#define IRQ_EINT_BIT(x)        ((x) - IRQ_EINT4 + 4)
-#define IRQ_EINT(x)    (((x) >= 4) ? (IRQ_EINT4 + (x) - 4) : (IRQ_EINT0 + (x)))
-
-#define IRQ_LCD_FIFO   S3C2410_IRQ(52)
-#define IRQ_LCD_FRAME  S3C2410_IRQ(53)
-
-/* IRQs for the interal UARTs, and ADC
- * these need to be ordered in number of appearance in the
- * SUBSRC mask register
-*/
-
-#define S3C2410_IRQSUB(x)      S3C2410_IRQ((x)+54)
-
-#define IRQ_S3CUART_RX0                S3C2410_IRQSUB(0)       /* 70 */
-#define IRQ_S3CUART_TX0                S3C2410_IRQSUB(1)
-#define IRQ_S3CUART_ERR0       S3C2410_IRQSUB(2)
-
-#define IRQ_S3CUART_RX1                S3C2410_IRQSUB(3)       /* 73 */
-#define IRQ_S3CUART_TX1                S3C2410_IRQSUB(4)
-#define IRQ_S3CUART_ERR1       S3C2410_IRQSUB(5)
-
-#define IRQ_S3CUART_RX2                S3C2410_IRQSUB(6)       /* 76 */
-#define IRQ_S3CUART_TX2                S3C2410_IRQSUB(7)
-#define IRQ_S3CUART_ERR2       S3C2410_IRQSUB(8)
-
-#define IRQ_TC                 S3C2410_IRQSUB(9)
-#define IRQ_ADC                        S3C2410_IRQSUB(10)
-
-/* extra irqs for s3c2412 */
-
-#define IRQ_S3C2412_CFSDI      S3C2410_IRQ(21)
-
-#define IRQ_S3C2412_SDI                S3C2410_IRQSUB(13)
-#define IRQ_S3C2412_CF         S3C2410_IRQSUB(14)
-
-
-#define IRQ_S3C2416_EINT8t15   S3C2410_IRQ(5)
-#define IRQ_S3C2416_DMA                S3C2410_IRQ(17)
-#define IRQ_S3C2416_UART3      S3C2410_IRQ(18)
-#define IRQ_S3C2416_SDI1       S3C2410_IRQ(20)
-#define IRQ_S3C2416_SDI0       S3C2410_IRQ(21)
-
-#define IRQ_S3C2416_LCD2       S3C2410_IRQSUB(15)
-#define IRQ_S3C2416_LCD3       S3C2410_IRQSUB(16)
-#define IRQ_S3C2416_LCD4       S3C2410_IRQSUB(17)
-#define IRQ_S3C2416_DMA0       S3C2410_IRQSUB(18)
-#define IRQ_S3C2416_DMA1       S3C2410_IRQSUB(19)
-#define IRQ_S3C2416_DMA2       S3C2410_IRQSUB(20)
-#define IRQ_S3C2416_DMA3       S3C2410_IRQSUB(21)
-#define IRQ_S3C2416_DMA4       S3C2410_IRQSUB(22)
-#define IRQ_S3C2416_DMA5       S3C2410_IRQSUB(23)
-#define IRQ_S32416_WDT         S3C2410_IRQSUB(27)
-#define IRQ_S32416_AC97                S3C2410_IRQSUB(28)
-
-
-/* extra irqs for s3c2440 */
-
-#define IRQ_S3C2440_CAM_C      S3C2410_IRQSUB(11)      /* S3C2443 too */
-#define IRQ_S3C2440_CAM_P      S3C2410_IRQSUB(12)      /* S3C2443 too */
-#define IRQ_S3C2440_WDT                S3C2410_IRQSUB(13)
-#define IRQ_S3C2440_AC97       S3C2410_IRQSUB(14)
-
-/* irqs for s3c2443 */
-
-#define IRQ_S3C2443_DMA                S3C2410_IRQ(17)         /* IRQ_DMA1 */
-#define IRQ_S3C2443_UART3      S3C2410_IRQ(18)         /* IRQ_DMA2 */
-#define IRQ_S3C2443_CFCON      S3C2410_IRQ(19)         /* IRQ_DMA3 */
-#define IRQ_S3C2443_HSMMC      S3C2410_IRQ(20)         /* IRQ_SDI */
-#define IRQ_S3C2443_NAND       S3C2410_IRQ(24)         /* reserved */
-
-#define IRQ_S3C2416_HSMMC0     S3C2410_IRQ(21)         /* S3C2416/S3C2450 */
-
-#define IRQ_HSMMC0             IRQ_S3C2416_HSMMC0
-#define IRQ_HSMMC1             IRQ_S3C2443_HSMMC
-
-#define IRQ_S3C2443_LCD1       S3C2410_IRQSUB(14)
-#define IRQ_S3C2443_LCD2       S3C2410_IRQSUB(15)
-#define IRQ_S3C2443_LCD3       S3C2410_IRQSUB(16)
-#define IRQ_S3C2443_LCD4       S3C2410_IRQSUB(17)
-
-#define IRQ_S3C2443_DMA0       S3C2410_IRQSUB(18)
-#define IRQ_S3C2443_DMA1       S3C2410_IRQSUB(19)
-#define IRQ_S3C2443_DMA2       S3C2410_IRQSUB(20)
-#define IRQ_S3C2443_DMA3       S3C2410_IRQSUB(21)
-#define IRQ_S3C2443_DMA4       S3C2410_IRQSUB(22)
-#define IRQ_S3C2443_DMA5       S3C2410_IRQSUB(23)
-
-/* UART3 */
-#define IRQ_S3C2443_RX3                S3C2410_IRQSUB(24)
-#define IRQ_S3C2443_TX3                S3C2410_IRQSUB(25)
-#define IRQ_S3C2443_ERR3       S3C2410_IRQSUB(26)
-
-#define IRQ_S3C2443_WDT                S3C2410_IRQSUB(27)
-#define IRQ_S3C2443_AC97       S3C2410_IRQSUB(28)
-
-#if defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
-#define NR_IRQS (IRQ_S3C2443_AC97+1)
-#else
-#define NR_IRQS (IRQ_S3C2440_AC97+1)
-#endif
-
-/* compatibility define. */
-#define IRQ_UART3              IRQ_S3C2443_UART3
-#define IRQ_S3CUART_RX3                IRQ_S3C2443_RX3
-#define IRQ_S3CUART_TX3                IRQ_S3C2443_TX3
-#define IRQ_S3CUART_ERR3       IRQ_S3C2443_ERR3
-
-#define IRQ_LCD_VSYNC          IRQ_S3C2443_LCD3
-#define IRQ_LCD_SYSTEM         IRQ_S3C2443_LCD2
-
-#ifdef CONFIG_CPU_S3C2440
-#define IRQ_S3C244X_AC97 IRQ_S3C2440_AC97
-#else
-#define IRQ_S3C244X_AC97 IRQ_S3C2443_AC97
-#endif
-
-/* Our FIQs are routable from IRQ_EINT0 to IRQ_ADCPARENT */
-#define FIQ_START              IRQ_EINT0
-
-#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/leds-gpio.h b/arch/arm/mach-s3c2410/include/mach/leds-gpio.h
deleted file mode 100644 (file)
index d8a7672..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/leds-gpio.h
- *
- * Copyright (c) 2006 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C24XX - LEDs GPIO connector
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_LEDSGPIO_H
-#define __ASM_ARCH_LEDSGPIO_H "leds-gpio.h"
-
-#define S3C24XX_LEDF_ACTLOW    (1<<0)          /* LED is on when GPIO low */
-#define S3C24XX_LEDF_TRISTATE  (1<<1)          /* tristate to turn off */
-
-struct s3c24xx_led_platdata {
-       unsigned int             gpio;
-       unsigned int             flags;
-
-       char                    *name;
-       char                    *def_trigger;
-};
-
-#endif /* __ASM_ARCH_LEDSGPIO_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/map.h b/arch/arm/mach-s3c2410/include/mach/map.h
deleted file mode 100644 (file)
index 78ae807..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/map.h
- *
- * Copyright (c) 2003 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - Memory map definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_MAP_H
-#define __ASM_ARCH_MAP_H
-
-#include <plat/map-base.h>
-
-/*
- * S3C2410 UART offset is 0x4000 but the other SoCs are 0x400.
- * So need to define it, and here is to avoid redefinition warning.
- */
-#define S3C_UART_OFFSET                (0x4000)
-
-#include <plat/map-s3c.h>
-
-/*
- * interrupt controller is the first thing we put in, to make
- * the assembly code for the irq detection easier
- */
-#define S3C2410_PA_IRQ         (0x4A000000)
-#define S3C24XX_SZ_IRQ         SZ_1M
-
-/* memory controller registers */
-#define S3C2410_PA_MEMCTRL     (0x48000000)
-#define S3C24XX_SZ_MEMCTRL     SZ_1M
-
-/* UARTs */
-#define S3C_VA_UARTx(uart)     (S3C_VA_UART + ((uart * S3C_UART_OFFSET)))
-
-/* Timers */
-#define S3C2410_PA_TIMER       (0x51000000)
-#define S3C24XX_SZ_TIMER       SZ_1M
-
-/* Clock and Power management */
-#define S3C24XX_SZ_CLKPWR      SZ_1M
-
-/* USB Device port */
-#define S3C2410_PA_USBDEV      (0x52000000)
-#define S3C24XX_SZ_USBDEV      SZ_1M
-
-/* Watchdog */
-#define S3C2410_PA_WATCHDOG    (0x53000000)
-#define S3C24XX_SZ_WATCHDOG    SZ_1M
-
-/* Standard size definitions for peripheral blocks. */
-
-#define S3C24XX_SZ_UART                SZ_1M
-#define S3C24XX_SZ_IIS         SZ_1M
-#define S3C24XX_SZ_ADC         SZ_1M
-#define S3C24XX_SZ_SPI         SZ_1M
-#define S3C24XX_SZ_SDI         SZ_1M
-#define S3C24XX_SZ_NAND                SZ_1M
-#define S3C24XX_SZ_GPIO                SZ_1M
-
-/* USB host controller */
-#define S3C2410_PA_USBHOST (0x49000000)
-
-/* S3C2416/S3C2443/S3C2450 High-Speed USB Gadget */
-#define S3C2416_PA_HSUDC       (0x49800000)
-#define S3C2416_SZ_HSUDC       (SZ_4K)
-
-/* DMA controller */
-#define S3C2410_PA_DMA    (0x4B000000)
-#define S3C24XX_SZ_DMA    SZ_1M
-
-/* Clock and Power management */
-#define S3C2410_PA_CLKPWR  (0x4C000000)
-
-/* LCD controller */
-#define S3C2410_PA_LCD    (0x4D000000)
-#define S3C24XX_SZ_LCD    SZ_1M
-
-/* NAND flash controller */
-#define S3C2410_PA_NAND           (0x4E000000)
-
-/* IIC hardware controller */
-#define S3C2410_PA_IIC    (0x54000000)
-
-/* IIS controller */
-#define S3C2410_PA_IIS    (0x55000000)
-
-/* RTC */
-#define S3C2410_PA_RTC    (0x57000000)
-#define S3C24XX_SZ_RTC    SZ_1M
-
-/* ADC */
-#define S3C2410_PA_ADC    (0x58000000)
-
-/* SPI */
-#define S3C2410_PA_SPI    (0x59000000)
-
-/* SDI */
-#define S3C2410_PA_SDI    (0x5A000000)
-
-/* CAMIF */
-#define S3C2440_PA_CAMIF   (0x4F000000)
-#define S3C2440_SZ_CAMIF   SZ_1M
-
-/* AC97 */
-
-#define S3C2440_PA_AC97           (0x5B000000)
-#define S3C2440_SZ_AC97           SZ_1M
-
-/* S3C2443/S3C2416 High-speed SD/MMC */
-#define S3C2443_PA_HSMMC   (0x4A800000)
-#define S3C2416_PA_HSMMC0  (0x4AC00000)
-
-#define        S3C2443_PA_FB   (0x4C800000)
-
-/* S3C2412 memory and IO controls */
-#define S3C2412_PA_SSMC        (0x4F000000)
-
-#define S3C2412_PA_EBI (0x48800000)
-
-/* physical addresses of all the chip-select areas */
-
-#define S3C2410_CS0 (0x00000000)
-#define S3C2410_CS1 (0x08000000)
-#define S3C2410_CS2 (0x10000000)
-#define S3C2410_CS3 (0x18000000)
-#define S3C2410_CS4 (0x20000000)
-#define S3C2410_CS5 (0x28000000)
-#define S3C2410_CS6 (0x30000000)
-#define S3C2410_CS7 (0x38000000)
-
-#define S3C2410_SDRAM_PA    (S3C2410_CS6)
-
-/* Use a single interface for common resources between S3C24XX cpus */
-
-#define S3C24XX_PA_IRQ      S3C2410_PA_IRQ
-#define S3C24XX_PA_MEMCTRL  S3C2410_PA_MEMCTRL
-#define S3C24XX_PA_DMA      S3C2410_PA_DMA
-#define S3C24XX_PA_CLKPWR   S3C2410_PA_CLKPWR
-#define S3C24XX_PA_LCD      S3C2410_PA_LCD
-#define S3C24XX_PA_TIMER    S3C2410_PA_TIMER
-#define S3C24XX_PA_USBDEV   S3C2410_PA_USBDEV
-#define S3C24XX_PA_WATCHDOG S3C2410_PA_WATCHDOG
-#define S3C24XX_PA_IIS      S3C2410_PA_IIS
-#define S3C24XX_PA_RTC      S3C2410_PA_RTC
-#define S3C24XX_PA_ADC      S3C2410_PA_ADC
-#define S3C24XX_PA_SPI      S3C2410_PA_SPI
-#define S3C24XX_PA_SPI1                (S3C2410_PA_SPI + S3C2410_SPI1)
-#define S3C24XX_PA_SDI      S3C2410_PA_SDI
-#define S3C24XX_PA_NAND            S3C2410_PA_NAND
-
-#define S3C_PA_FB          S3C2443_PA_FB
-#define S3C_PA_IIC          S3C2410_PA_IIC
-#define S3C_PA_UART        S3C24XX_PA_UART
-#define S3C_PA_USBHOST S3C2410_PA_USBHOST
-#define S3C_PA_HSMMC0      S3C2416_PA_HSMMC0
-#define S3C_PA_HSMMC1      S3C2443_PA_HSMMC
-#define S3C_PA_WDT         S3C2410_PA_WATCHDOG
-#define S3C_PA_NAND        S3C24XX_PA_NAND
-
-#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/osiris-cpld.h b/arch/arm/mach-s3c2410/include/mach/osiris-cpld.h
deleted file mode 100644 (file)
index e9e36b0..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/osiris-cpld.h
- *
- * Copyright 2005 Simtec Electronics
- *     http://www.simtec.co.uk/products/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * OSIRIS - CPLD control constants
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_OSIRISCPLD_H
-#define __ASM_ARCH_OSIRISCPLD_H
-
-/* CTRL0 - NAND WP control */
-
-#define OSIRIS_CTRL0_NANDSEL           (0x3)
-#define OSIRIS_CTRL0_BOOT_INT          (1<<3)
-#define OSIRIS_CTRL0_PCMCIA            (1<<4)
-#define OSIRIS_CTRL0_FIX8              (1<<5)
-#define OSIRIS_CTRL0_PCMCIA_nWAIT      (1<<6)
-#define OSIRIS_CTRL0_PCMCIA_nIOIS16    (1<<7)
-
-#define OSIRIS_CTRL1_FIX8              (1<<0)
-
-#define OSIRIS_ID_REVMASK              (0x7)
-
-#endif /* __ASM_ARCH_OSIRISCPLD_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/osiris-map.h b/arch/arm/mach-s3c2410/include/mach/osiris-map.h
deleted file mode 100644 (file)
index 17380f8..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/osiris-map.h
- *
- * Copyright 2005 Simtec Electronics
- *     http://www.simtec.co.uk/products/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * OSIRIS - Memory map definitions
- *
- * 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.
-*/
-
-/* needs arch/map.h including with this */
-
-#ifndef __ASM_ARCH_OSIRISMAP_H
-#define __ASM_ARCH_OSIRISMAP_H
-
-/* start peripherals off after the S3C2410 */
-
-#define OSIRIS_IOADDR(x)       (S3C2410_ADDR((x) + 0x04000000))
-
-#define OSIRIS_PA_CPLD         (S3C2410_CS1 | (1<<26))
-
-/* we put the CPLD registers next, to get them out of the way */
-
-#define OSIRIS_VA_CTRL0                OSIRIS_IOADDR(0x00000000)
-#define OSIRIS_PA_CTRL0                (OSIRIS_PA_CPLD)
-
-#define OSIRIS_VA_CTRL1                OSIRIS_IOADDR(0x00100000)
-#define OSIRIS_PA_CTRL1                (OSIRIS_PA_CPLD + (1<<23))
-
-#define OSIRIS_VA_CTRL2                OSIRIS_IOADDR(0x00200000)
-#define OSIRIS_PA_CTRL2                (OSIRIS_PA_CPLD + (2<<23))
-
-#define OSIRIS_VA_CTRL3                OSIRIS_IOADDR(0x00300000)
-#define OSIRIS_PA_CTRL3                (OSIRIS_PA_CPLD + (2<<23))
-
-#define OSIRIS_VA_IDREG                OSIRIS_IOADDR(0x00700000)
-#define OSIRIS_PA_IDREG                (OSIRIS_PA_CPLD + (7<<23))
-
-#endif /* __ASM_ARCH_OSIRISMAP_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/otom-map.h b/arch/arm/mach-s3c2410/include/mach/otom-map.h
deleted file mode 100644 (file)
index f9277a5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/otom-map.h
- *
- * (c) 2005 Guillaume GOURAT / NexVision
- *          guillaume.gourat@nexvision.fr
- *
- * NexVision OTOM board memory map definitions
- *
- * 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.
-*/
-
-/* needs arch/map.h including with this */
-
-/* ok, we've used up to 0x01300000, now we need to find space for the
- * peripherals that live in the nGCS[x] areas, which are quite numerous
- * in their space.
- */
-
-#ifndef __ASM_ARCH_OTOMMAP_H
-#define __ASM_ARCH_OTOMMAP_H
-
-#define OTOM_PA_CS8900A_BASE       (S3C2410_CS3 + 0x01000000)  /* nGCS3 +0x01000000 */
-#define OTOM_VA_CS8900A_BASE       S3C2410_ADDR(0x04000000)            /* 0xF4000000 */
-
-/* physical offset addresses for the peripherals */
-
-#define OTOM_PA_FLASH0_BASE        (S3C2410_CS0)                               /* Bank 0 */
-
-#endif /* __ASM_ARCH_OTOMMAP_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/pm-core.h b/arch/arm/mach-s3c2410/include/mach/pm-core.h
deleted file mode 100644 (file)
index 2eef7e6..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/include/pm-core.h
- *
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * S3C24xx - PM core support for arch/arm/plat-s3c/pm.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-static inline void s3c_pm_debug_init_uart(void)
-{
-       unsigned long tmp = __raw_readl(S3C2410_CLKCON);
-
-       /* re-start uart clocks */
-       tmp |= S3C2410_CLKCON_UART0;
-       tmp |= S3C2410_CLKCON_UART1;
-       tmp |= S3C2410_CLKCON_UART2;
-
-       __raw_writel(tmp, S3C2410_CLKCON);
-       udelay(10);
-}
-
-static inline void s3c_pm_arch_prepare_irqs(void)
-{
-       __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
-       __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
-
-       /* ack any outstanding external interrupts before we go to sleep */
-
-       __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
-       __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
-       __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
-
-}
-
-static inline void s3c_pm_arch_stop_clocks(void)
-{
-       __raw_writel(0x00, S3C2410_CLKCON);  /* turn off clocks over sleep */
-}
-
-static void s3c_pm_show_resume_irqs(int start, unsigned long which,
-                                   unsigned long mask);
-
-static inline void s3c_pm_arch_show_resume_irqs(void)
-{
-       S3C_PMDBG("post sleep: IRQs 0x%08x, 0x%08x\n",
-                 __raw_readl(S3C2410_SRCPND),
-                 __raw_readl(S3C2410_EINTPEND));
-
-       s3c_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
-                               s3c_irqwake_intmask);
-
-       s3c_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
-                               s3c_irqwake_eintmask);
-}
-
-static inline void s3c_pm_arch_update_uart(void __iomem *regs,
-                                          struct pm_uart_save *save)
-{
-}
-
-static inline void s3c_pm_restored_gpios(void) { }
-static inline void samsung_pm_saved_gpios(void) { }
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-clock.h b/arch/arm/mach-s3c2410/include/mach/regs-clock.h
deleted file mode 100644 (file)
index 3415b60..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-clock.h
- *
- * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * S3C2410 clock register definitions
-*/
-
-#ifndef __ASM_ARM_REGS_CLOCK
-#define __ASM_ARM_REGS_CLOCK
-
-#define S3C2410_CLKREG(x) ((x) + S3C24XX_VA_CLKPWR)
-
-#define S3C2410_PLLVAL(_m,_p,_s) ((_m) << 12 | ((_p) << 4) | ((_s)))
-
-#define S3C2410_LOCKTIME    S3C2410_CLKREG(0x00)
-#define S3C2410_MPLLCON            S3C2410_CLKREG(0x04)
-#define S3C2410_UPLLCON            S3C2410_CLKREG(0x08)
-#define S3C2410_CLKCON     S3C2410_CLKREG(0x0C)
-#define S3C2410_CLKSLOW            S3C2410_CLKREG(0x10)
-#define S3C2410_CLKDIVN            S3C2410_CLKREG(0x14)
-
-#define S3C2410_CLKCON_IDLE         (1<<2)
-#define S3C2410_CLKCON_POWER        (1<<3)
-#define S3C2410_CLKCON_NAND         (1<<4)
-#define S3C2410_CLKCON_LCDC         (1<<5)
-#define S3C2410_CLKCON_USBH         (1<<6)
-#define S3C2410_CLKCON_USBD         (1<<7)
-#define S3C2410_CLKCON_PWMT         (1<<8)
-#define S3C2410_CLKCON_SDI          (1<<9)
-#define S3C2410_CLKCON_UART0        (1<<10)
-#define S3C2410_CLKCON_UART1        (1<<11)
-#define S3C2410_CLKCON_UART2        (1<<12)
-#define S3C2410_CLKCON_GPIO         (1<<13)
-#define S3C2410_CLKCON_RTC          (1<<14)
-#define S3C2410_CLKCON_ADC          (1<<15)
-#define S3C2410_CLKCON_IIC          (1<<16)
-#define S3C2410_CLKCON_IIS          (1<<17)
-#define S3C2410_CLKCON_SPI          (1<<18)
-
-/* DCLKCON register addresses in gpio.h */
-
-#define S3C2410_DCLKCON_DCLK0EN             (1<<0)
-#define S3C2410_DCLKCON_DCLK0_PCLK   (0<<1)
-#define S3C2410_DCLKCON_DCLK0_UCLK   (1<<1)
-#define S3C2410_DCLKCON_DCLK0_DIV(x) (((x) - 1 )<<4)
-#define S3C2410_DCLKCON_DCLK0_CMP(x) (((x) - 1 )<<8)
-#define S3C2410_DCLKCON_DCLK0_DIV_MASK ((0xf)<<4)
-#define S3C2410_DCLKCON_DCLK0_CMP_MASK ((0xf)<<8)
-
-#define S3C2410_DCLKCON_DCLK1EN             (1<<16)
-#define S3C2410_DCLKCON_DCLK1_PCLK   (0<<17)
-#define S3C2410_DCLKCON_DCLK1_UCLK   (1<<17)
-#define S3C2410_DCLKCON_DCLK1_DIV(x) (((x) - 1) <<20)
-#define S3C2410_DCLKCON_DCLK1_CMP(x) (((x) - 1) <<24)
-#define S3C2410_DCLKCON_DCLK1_DIV_MASK ((0xf) <<20)
-#define S3C2410_DCLKCON_DCLK1_CMP_MASK ((0xf) <<24)
-
-#define S3C2410_CLKDIVN_PDIVN       (1<<0)
-#define S3C2410_CLKDIVN_HDIVN       (1<<1)
-
-#define S3C2410_CLKSLOW_UCLK_OFF       (1<<7)
-#define S3C2410_CLKSLOW_MPLL_OFF       (1<<5)
-#define S3C2410_CLKSLOW_SLOW           (1<<4)
-#define S3C2410_CLKSLOW_SLOWVAL(x)     (x)
-#define S3C2410_CLKSLOW_GET_SLOWVAL(x) ((x) & 7)
-
-#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
-
-/* extra registers */
-#define S3C2440_CAMDIVN            S3C2410_CLKREG(0x18)
-
-#define S3C2440_CLKCON_CAMERA        (1<<19)
-#define S3C2440_CLKCON_AC97          (1<<20)
-
-#define S3C2440_CLKDIVN_PDIVN       (1<<0)
-#define S3C2440_CLKDIVN_HDIVN_MASK   (3<<1)
-#define S3C2440_CLKDIVN_HDIVN_1      (0<<1)
-#define S3C2440_CLKDIVN_HDIVN_2      (1<<1)
-#define S3C2440_CLKDIVN_HDIVN_4_8    (2<<1)
-#define S3C2440_CLKDIVN_HDIVN_3_6    (3<<1)
-#define S3C2440_CLKDIVN_UCLK         (1<<3)
-
-#define S3C2440_CAMDIVN_CAMCLK_MASK  (0xf<<0)
-#define S3C2440_CAMDIVN_CAMCLK_SEL   (1<<4)
-#define S3C2440_CAMDIVN_HCLK3_HALF   (1<<8)
-#define S3C2440_CAMDIVN_HCLK4_HALF   (1<<9)
-#define S3C2440_CAMDIVN_DVSEN        (1<<12)
-
-#define S3C2442_CAMDIVN_CAMCLK_DIV3  (1<<5)
-
-#endif /* CONFIG_CPU_S3C2440 or CONFIG_CPU_S3C2442 */
-
-#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
-
-#define S3C2412_OSCSET         S3C2410_CLKREG(0x18)
-#define S3C2412_CLKSRC         S3C2410_CLKREG(0x1C)
-
-#define S3C2412_PLLCON_OFF             (1<<20)
-
-#define S3C2412_CLKDIVN_PDIVN          (1<<2)
-#define S3C2412_CLKDIVN_HDIVN_MASK     (3<<0)
-#define S3C2412_CLKDIVN_ARMDIVN                (1<<3)
-#define S3C2412_CLKDIVN_DVSEN          (1<<4)
-#define S3C2412_CLKDIVN_HALFHCLK       (1<<5)
-#define S3C2412_CLKDIVN_USB48DIV       (1<<6)
-#define S3C2412_CLKDIVN_UARTDIV_MASK   (15<<8)
-#define S3C2412_CLKDIVN_UARTDIV_SHIFT  (8)
-#define S3C2412_CLKDIVN_I2SDIV_MASK    (15<<12)
-#define S3C2412_CLKDIVN_I2SDIV_SHIFT   (12)
-#define S3C2412_CLKDIVN_CAMDIV_MASK    (15<<16)
-#define S3C2412_CLKDIVN_CAMDIV_SHIFT   (16)
-
-#define S3C2412_CLKCON_WDT             (1<<28)
-#define S3C2412_CLKCON_SPI             (1<<27)
-#define S3C2412_CLKCON_IIS             (1<<26)
-#define S3C2412_CLKCON_IIC             (1<<25)
-#define S3C2412_CLKCON_ADC             (1<<24)
-#define S3C2412_CLKCON_RTC             (1<<23)
-#define S3C2412_CLKCON_GPIO            (1<<22)
-#define S3C2412_CLKCON_UART2           (1<<21)
-#define S3C2412_CLKCON_UART1           (1<<20)
-#define S3C2412_CLKCON_UART0           (1<<19)
-#define S3C2412_CLKCON_SDI             (1<<18)
-#define S3C2412_CLKCON_PWMT            (1<<17)
-#define S3C2412_CLKCON_USBD            (1<<16)
-#define S3C2412_CLKCON_CAMCLK          (1<<15)
-#define S3C2412_CLKCON_UARTCLK         (1<<14)
-/* missing 13 */
-#define S3C2412_CLKCON_USB_HOST48      (1<<12)
-#define S3C2412_CLKCON_USB_DEV48       (1<<11)
-#define S3C2412_CLKCON_HCLKdiv2                (1<<10)
-#define S3C2412_CLKCON_HCLKx2          (1<<9)
-#define S3C2412_CLKCON_SDRAM           (1<<8)
-/* missing 7 */
-#define S3C2412_CLKCON_USBH            S3C2410_CLKCON_USBH
-#define S3C2412_CLKCON_LCDC            S3C2410_CLKCON_LCDC
-#define S3C2412_CLKCON_NAND            S3C2410_CLKCON_NAND
-#define S3C2412_CLKCON_DMA3            (1<<3)
-#define S3C2412_CLKCON_DMA2            (1<<2)
-#define S3C2412_CLKCON_DMA1            (1<<1)
-#define S3C2412_CLKCON_DMA0            (1<<0)
-
-/* clock sourec controls */
-
-#define S3C2412_CLKSRC_EXTCLKDIV_MASK          (7 << 0)
-#define S3C2412_CLKSRC_EXTCLKDIV_SHIFT         (0)
-#define S3C2412_CLKSRC_MDIVCLK_EXTCLKDIV       (1<<3)
-#define S3C2412_CLKSRC_MSYSCLK_MPLL            (1<<4)
-#define S3C2412_CLKSRC_USYSCLK_UPLL            (1<<5)
-#define S3C2412_CLKSRC_UARTCLK_MPLL            (1<<8)
-#define S3C2412_CLKSRC_I2SCLK_MPLL             (1<<9)
-#define S3C2412_CLKSRC_USBCLK_HCLK             (1<<10)
-#define S3C2412_CLKSRC_CAMCLK_HCLK             (1<<11)
-#define S3C2412_CLKSRC_UREFCLK_EXTCLK  (1<<12)
-#define S3C2412_CLKSRC_EREFCLK_EXTCLK  (1<<14)
-
-#endif /* CONFIG_CPU_S3C2412 | CONFIG_CPU_S3C2413 */
-
-#define S3C2416_CLKDIV2                S3C2410_CLKREG(0x28)
-
-#endif /* __ASM_ARM_REGS_CLOCK */
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-dsc.h b/arch/arm/mach-s3c2410/include/mach/regs-dsc.h
deleted file mode 100644 (file)
index 98fd4a0..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-dsc.h
- *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
- *                   http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2440/S3C2412 Signal Drive Strength Control
-*/
-
-
-#ifndef __ASM_ARCH_REGS_DSC_H
-#define __ASM_ARCH_REGS_DSC_H "2440-dsc"
-
-#if defined(CONFIG_CPU_S3C2412)
-#define S3C2412_DSC0      S3C2410_GPIOREG(0xdc)
-#define S3C2412_DSC1      S3C2410_GPIOREG(0xe0)
-#endif
-
-#if defined(CONFIG_CPU_S3C2416)
-#define S3C2416_DSC0      S3C2410_GPIOREG(0xc0)
-#define S3C2416_DSC1      S3C2410_GPIOREG(0xc4)
-#define S3C2416_DSC2      S3C2410_GPIOREG(0xc8)
-#define S3C2416_DSC3      S3C2410_GPIOREG(0x110)
-
-#define S3C2416_SELECT_DSC0    (0 << 30)
-#define S3C2416_SELECT_DSC1    (1 << 30)
-#define S3C2416_SELECT_DSC2    (2 << 30)
-#define S3C2416_SELECT_DSC3    (3 << 30)
-
-#define S3C2416_DSC_GETSHIFT(x)        (x & 30)
-
-#define S3C2416_DSC0_CF                (S3C2416_SELECT_DSC0 | 28)
-#define        S3C2416_DSC0_CF_5mA     (0 << 28)
-#define        S3C2416_DSC0_CF_10mA    (1 << 28)
-#define        S3C2416_DSC0_CF_15mA    (2 << 28)
-#define        S3C2416_DSC0_CF_21mA    (3 << 28)
-#define        S3C2416_DSC0_CF_MASK    (3 << 28)
-
-#define S3C2416_DSC0_nRBE      (S3C2416_SELECT_DSC0 | 26)
-#define        S3C2416_DSC0_nRBE_5mA   (0 << 26)
-#define        S3C2416_DSC0_nRBE_10mA  (1 << 26)
-#define        S3C2416_DSC0_nRBE_15mA  (2 << 26)
-#define        S3C2416_DSC0_nRBE_21mA  (3 << 26)
-#define        S3C2416_DSC0_nRBE_MASK  (3 << 26)
-
-#define S3C2416_DSC0_nROE      (S3C2416_SELECT_DSC0 | 24)
-#define        S3C2416_DSC0_nROE_5mA   (0 << 24)
-#define        S3C2416_DSC0_nROE_10mA  (1 << 24)
-#define        S3C2416_DSC0_nROE_15mA  (2 << 24)
-#define        S3C2416_DSC0_nROE_21mA  (3 << 24)
-#define        S3C2416_DSC0_nROE_MASK  (3 << 24)
-
-#endif
-
-#if defined(CONFIG_CPU_S3C244X)
-
-#define S3C2440_DSC0      S3C2410_GPIOREG(0xc4)
-#define S3C2440_DSC1      S3C2410_GPIOREG(0xc8)
-
-#define S3C2440_SELECT_DSC0 (0)
-#define S3C2440_SELECT_DSC1 (1<<31)
-
-#define S3C2440_DSC_GETSHIFT(x) ((x) & 31)
-
-#define S3C2440_DSC0_DISABLE   (1<<31)
-
-#define S3C2440_DSC0_ADDR       (S3C2440_SELECT_DSC0 | 8)
-#define S3C2440_DSC0_ADDR_12mA  (0<<8)
-#define S3C2440_DSC0_ADDR_10mA  (1<<8)
-#define S3C2440_DSC0_ADDR_8mA   (2<<8)
-#define S3C2440_DSC0_ADDR_6mA   (3<<8)
-#define S3C2440_DSC0_ADDR_MASK  (3<<8)
-
-/* D24..D31 */
-#define S3C2440_DSC0_DATA3      (S3C2440_SELECT_DSC0 | 6)
-#define S3C2440_DSC0_DATA3_12mA (0<<6)
-#define S3C2440_DSC0_DATA3_10mA (1<<6)
-#define S3C2440_DSC0_DATA3_8mA  (2<<6)
-#define S3C2440_DSC0_DATA3_6mA  (3<<6)
-#define S3C2440_DSC0_DATA3_MASK (3<<6)
-
-/* D16..D23 */
-#define S3C2440_DSC0_DATA2      (S3C2440_SELECT_DSC0 | 4)
-#define S3C2440_DSC0_DATA2_12mA (0<<4)
-#define S3C2440_DSC0_DATA2_10mA (1<<4)
-#define S3C2440_DSC0_DATA2_8mA  (2<<4)
-#define S3C2440_DSC0_DATA2_6mA  (3<<4)
-#define S3C2440_DSC0_DATA2_MASK (3<<4)
-
-/* D8..D15 */
-#define S3C2440_DSC0_DATA1      (S3C2440_SELECT_DSC0 | 2)
-#define S3C2440_DSC0_DATA1_12mA (0<<2)
-#define S3C2440_DSC0_DATA1_10mA (1<<2)
-#define S3C2440_DSC0_DATA1_8mA  (2<<2)
-#define S3C2440_DSC0_DATA1_6mA  (3<<2)
-#define S3C2440_DSC0_DATA1_MASK (3<<2)
-
-/* D0..D7 */
-#define S3C2440_DSC0_DATA0      (S3C2440_SELECT_DSC0 | 0)
-#define S3C2440_DSC0_DATA0_12mA (0<<0)
-#define S3C2440_DSC0_DATA0_10mA (1<<0)
-#define S3C2440_DSC0_DATA0_8mA  (2<<0)
-#define S3C2440_DSC0_DATA0_6mA  (3<<0)
-#define S3C2440_DSC0_DATA0_MASK (3<<0)
-
-#define S3C2440_DSC1_SCK1       (S3C2440_SELECT_DSC1 | 28)
-#define S3C2440_DSC1_SCK1_12mA  (0<<28)
-#define S3C2440_DSC1_SCK1_10mA  (1<<28)
-#define S3C2440_DSC1_SCK1_8mA   (2<<28)
-#define S3C2440_DSC1_SCK1_6mA   (3<<28)
-#define S3C2440_DSC1_SCK1_MASK  (3<<28)
-
-#define S3C2440_DSC1_SCK0       (S3C2440_SELECT_DSC1 | 26)
-#define S3C2440_DSC1_SCK0_12mA  (0<<26)
-#define S3C2440_DSC1_SCK0_10mA  (1<<26)
-#define S3C2440_DSC1_SCK0_8mA   (2<<26)
-#define S3C2440_DSC1_SCK0_6mA   (3<<26)
-#define S3C2440_DSC1_SCK0_MASK  (3<<26)
-
-#define S3C2440_DSC1_SCKE       (S3C2440_SELECT_DSC1 | 24)
-#define S3C2440_DSC1_SCKE_10mA  (0<<24)
-#define S3C2440_DSC1_SCKE_8mA   (1<<24)
-#define S3C2440_DSC1_SCKE_6mA   (2<<24)
-#define S3C2440_DSC1_SCKE_4mA   (3<<24)
-#define S3C2440_DSC1_SCKE_MASK  (3<<24)
-
-/* SDRAM nRAS/nCAS */
-#define S3C2440_DSC1_SDR        (S3C2440_SELECT_DSC1 | 22)
-#define S3C2440_DSC1_SDR_10mA   (0<<22)
-#define S3C2440_DSC1_SDR_8mA    (1<<22)
-#define S3C2440_DSC1_SDR_6mA    (2<<22)
-#define S3C2440_DSC1_SDR_4mA    (3<<22)
-#define S3C2440_DSC1_SDR_MASK   (3<<22)
-
-/* NAND Flash Controller */
-#define S3C2440_DSC1_NFC        (S3C2440_SELECT_DSC1 | 20)
-#define S3C2440_DSC1_NFC_10mA   (0<<20)
-#define S3C2440_DSC1_NFC_8mA    (1<<20)
-#define S3C2440_DSC1_NFC_6mA    (2<<20)
-#define S3C2440_DSC1_NFC_4mA    (3<<20)
-#define S3C2440_DSC1_NFC_MASK   (3<<20)
-
-/* nBE[0..3] */
-#define S3C2440_DSC1_nBE        (S3C2440_SELECT_DSC1 | 18)
-#define S3C2440_DSC1_nBE_10mA   (0<<18)
-#define S3C2440_DSC1_nBE_8mA    (1<<18)
-#define S3C2440_DSC1_nBE_6mA    (2<<18)
-#define S3C2440_DSC1_nBE_4mA    (3<<18)
-#define S3C2440_DSC1_nBE_MASK   (3<<18)
-
-#define S3C2440_DSC1_WOE        (S3C2440_SELECT_DSC1 | 16)
-#define S3C2440_DSC1_WOE_10mA   (0<<16)
-#define S3C2440_DSC1_WOE_8mA    (1<<16)
-#define S3C2440_DSC1_WOE_6mA    (2<<16)
-#define S3C2440_DSC1_WOE_4mA    (3<<16)
-#define S3C2440_DSC1_WOE_MASK   (3<<16)
-
-#define S3C2440_DSC1_CS7        (S3C2440_SELECT_DSC1 | 14)
-#define S3C2440_DSC1_CS7_10mA   (0<<14)
-#define S3C2440_DSC1_CS7_8mA    (1<<14)
-#define S3C2440_DSC1_CS7_6mA    (2<<14)
-#define S3C2440_DSC1_CS7_4mA    (3<<14)
-#define S3C2440_DSC1_CS7_MASK   (3<<14)
-
-#define S3C2440_DSC1_CS6        (S3C2440_SELECT_DSC1 | 12)
-#define S3C2440_DSC1_CS6_10mA   (0<<12)
-#define S3C2440_DSC1_CS6_8mA    (1<<12)
-#define S3C2440_DSC1_CS6_6mA    (2<<12)
-#define S3C2440_DSC1_CS6_4mA    (3<<12)
-#define S3C2440_DSC1_CS6_MASK   (3<<12)
-
-#define S3C2440_DSC1_CS5        (S3C2440_SELECT_DSC1 | 10)
-#define S3C2440_DSC1_CS5_10mA   (0<<10)
-#define S3C2440_DSC1_CS5_8mA    (1<<10)
-#define S3C2440_DSC1_CS5_6mA    (2<<10)
-#define S3C2440_DSC1_CS5_4mA    (3<<10)
-#define S3C2440_DSC1_CS5_MASK   (3<<10)
-
-#define S3C2440_DSC1_CS4        (S3C2440_SELECT_DSC1 | 8)
-#define S3C2440_DSC1_CS4_10mA   (0<<8)
-#define S3C2440_DSC1_CS4_8mA    (1<<8)
-#define S3C2440_DSC1_CS4_6mA    (2<<8)
-#define S3C2440_DSC1_CS4_4mA    (3<<8)
-#define S3C2440_DSC1_CS4_MASK   (3<<8)
-
-#define S3C2440_DSC1_CS3        (S3C2440_SELECT_DSC1 | 6)
-#define S3C2440_DSC1_CS3_10mA   (0<<6)
-#define S3C2440_DSC1_CS3_8mA    (1<<6)
-#define S3C2440_DSC1_CS3_6mA    (2<<6)
-#define S3C2440_DSC1_CS3_4mA    (3<<6)
-#define S3C2440_DSC1_CS3_MASK   (3<<6)
-
-#define S3C2440_DSC1_CS2        (S3C2440_SELECT_DSC1 | 4)
-#define S3C2440_DSC1_CS2_10mA   (0<<4)
-#define S3C2440_DSC1_CS2_8mA    (1<<4)
-#define S3C2440_DSC1_CS2_6mA    (2<<4)
-#define S3C2440_DSC1_CS2_4mA    (3<<4)
-#define S3C2440_DSC1_CS2_MASK   (3<<4)
-
-#define S3C2440_DSC1_CS1        (S3C2440_SELECT_DSC1 | 2)
-#define S3C2440_DSC1_CS1_10mA   (0<<2)
-#define S3C2440_DSC1_CS1_8mA    (1<<2)
-#define S3C2440_DSC1_CS1_6mA    (2<<2)
-#define S3C2440_DSC1_CS1_4mA    (3<<2)
-#define S3C2440_DSC1_CS1_MASK   (3<<2)
-
-#define S3C2440_DSC1_CS0        (S3C2440_SELECT_DSC1 | 0)
-#define S3C2440_DSC1_CS0_10mA   (0<<0)
-#define S3C2440_DSC1_CS0_8mA    (1<<0)
-#define S3C2440_DSC1_CS0_6mA    (2<<0)
-#define S3C2440_DSC1_CS0_4mA    (3<<0)
-#define S3C2440_DSC1_CS0_MASK   (3<<0)
-
-#endif /* CONFIG_CPU_S3C2440 */
-
-#endif /* __ASM_ARCH_REGS_DSC_H */
-
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-gpio.h b/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
deleted file mode 100644 (file)
index cac1ad6..0000000
+++ /dev/null
@@ -1,602 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-gpio.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics <linux@simtec.co.uk>
- *     http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2410 GPIO register definitions
-*/
-
-
-#ifndef __ASM_ARCH_REGS_GPIO_H
-#define __ASM_ARCH_REGS_GPIO_H
-
-#include <mach/gpio-nrs.h>
-
-#define S3C24XX_MISCCR         S3C24XX_GPIOREG2(0x80)
-
-/* general configuration options */
-
-#define S3C2410_GPIO_LEAVE   (0xFFFFFFFF)
-#define S3C2410_GPIO_INPUT   (0xFFFFFFF0)      /* not available on A */
-#define S3C2410_GPIO_OUTPUT  (0xFFFFFFF1)
-#define S3C2410_GPIO_IRQ     (0xFFFFFFF2)      /* not available for all */
-#define S3C2410_GPIO_SFN2    (0xFFFFFFF2)      /* bank A => addr/cs/nand */
-#define S3C2410_GPIO_SFN3    (0xFFFFFFF3)      /* not available on A */
-
-/* register address for the GPIO registers.
- * S3C24XX_GPIOREG2 is for the second set of registers in the
- * GPIO which move between s3c2410 and s3c2412 type systems */
-
-#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)
-#define S3C24XX_GPIOREG2(x) ((x) + S3C24XX_VA_GPIO2)
-
-
-/* configure GPIO ports A..G */
-
-/* port A - S3C2410: 22bits, zero in bit X makes pin X output
- * 1 makes port special function, this is default
-*/
-#define S3C2410_GPACON    S3C2410_GPIOREG(0x00)
-#define S3C2410_GPADAT    S3C2410_GPIOREG(0x04)
-
-#define S3C2410_GPA0_ADDR0   (1<<0)
-#define S3C2410_GPA1_ADDR16  (1<<1)
-#define S3C2410_GPA2_ADDR17  (1<<2)
-#define S3C2410_GPA3_ADDR18  (1<<3)
-#define S3C2410_GPA4_ADDR19  (1<<4)
-#define S3C2410_GPA5_ADDR20  (1<<5)
-#define S3C2410_GPA6_ADDR21  (1<<6)
-#define S3C2410_GPA7_ADDR22  (1<<7)
-#define S3C2410_GPA8_ADDR23  (1<<8)
-#define S3C2410_GPA9_ADDR24  (1<<9)
-#define S3C2410_GPA10_ADDR25 (1<<10)
-#define S3C2410_GPA11_ADDR26 (1<<11)
-#define S3C2410_GPA12_nGCS1  (1<<12)
-#define S3C2410_GPA13_nGCS2  (1<<13)
-#define S3C2410_GPA14_nGCS3  (1<<14)
-#define S3C2410_GPA15_nGCS4  (1<<15)
-#define S3C2410_GPA16_nGCS5  (1<<16)
-#define S3C2410_GPA17_CLE    (1<<17)
-#define S3C2410_GPA18_ALE    (1<<18)
-#define S3C2410_GPA19_nFWE   (1<<19)
-#define S3C2410_GPA20_nFRE   (1<<20)
-#define S3C2410_GPA21_nRSTOUT (1<<21)
-#define S3C2410_GPA22_nFCE   (1<<22)
-
-/* 0x08 and 0x0c are reserved on S3C2410 */
-
-/* S3C2410:
- * GPB is 10 IO pins, each configured by 2 bits each in GPBCON.
- *   00 = input, 01 = output, 10=special function, 11=reserved
-
- * bit 0,1 = pin 0, 2,3= pin 1...
- *
- * CPBUP = pull up resistor control, 1=disabled, 0=enabled
-*/
-
-#define S3C2410_GPBCON    S3C2410_GPIOREG(0x10)
-#define S3C2410_GPBDAT    S3C2410_GPIOREG(0x14)
-#define S3C2410_GPBUP     S3C2410_GPIOREG(0x18)
-
-/* no i/o pin in port b can have value 3 (unless it is a s3c2443) ! */
-
-#define S3C2410_GPB0_TOUT0   (0x02 << 0)
-
-#define S3C2410_GPB1_TOUT1   (0x02 << 2)
-
-#define S3C2410_GPB2_TOUT2   (0x02 << 4)
-
-#define S3C2410_GPB3_TOUT3   (0x02 << 6)
-
-#define S3C2410_GPB4_TCLK0   (0x02 << 8)
-#define S3C2410_GPB4_MASK    (0x03 << 8)
-
-#define S3C2410_GPB5_nXBACK  (0x02 << 10)
-#define S3C2443_GPB5_XBACK   (0x03 << 10)
-
-#define S3C2410_GPB6_nXBREQ  (0x02 << 12)
-#define S3C2443_GPB6_XBREQ   (0x03 << 12)
-
-#define S3C2410_GPB7_nXDACK1 (0x02 << 14)
-#define S3C2443_GPB7_XDACK1  (0x03 << 14)
-
-#define S3C2410_GPB8_nXDREQ1 (0x02 << 16)
-
-#define S3C2410_GPB9_nXDACK0 (0x02 << 18)
-#define S3C2443_GPB9_XDACK0  (0x03 << 18)
-
-#define S3C2410_GPB10_nXDRE0 (0x02 << 20)
-#define S3C2443_GPB10_XDREQ0 (0x03 << 20)
-
-#define S3C2410_GPB_PUPDIS(x)  (1<<(x))
-
-/* Port C consits of 16 GPIO/Special function
- *
- * almost identical setup to port b, but the special functions are mostly
- * to do with the video system's sync/etc.
-*/
-
-#define S3C2410_GPCCON    S3C2410_GPIOREG(0x20)
-#define S3C2410_GPCDAT    S3C2410_GPIOREG(0x24)
-#define S3C2410_GPCUP     S3C2410_GPIOREG(0x28)
-#define S3C2410_GPC0_LEND      (0x02 << 0)
-#define S3C2410_GPC1_VCLK      (0x02 << 2)
-#define S3C2410_GPC2_VLINE     (0x02 << 4)
-#define S3C2410_GPC3_VFRAME    (0x02 << 6)
-#define S3C2410_GPC4_VM                (0x02 << 8)
-#define S3C2410_GPC5_LCDVF0    (0x02 << 10)
-#define S3C2410_GPC6_LCDVF1    (0x02 << 12)
-#define S3C2410_GPC7_LCDVF2    (0x02 << 14)
-#define S3C2410_GPC8_VD0       (0x02 << 16)
-#define S3C2410_GPC9_VD1       (0x02 << 18)
-#define S3C2410_GPC10_VD2      (0x02 << 20)
-#define S3C2410_GPC11_VD3      (0x02 << 22)
-#define S3C2410_GPC12_VD4      (0x02 << 24)
-#define S3C2410_GPC13_VD5      (0x02 << 26)
-#define S3C2410_GPC14_VD6      (0x02 << 28)
-#define S3C2410_GPC15_VD7      (0x02 << 30)
-#define S3C2410_GPC_PUPDIS(x)  (1<<(x))
-
-/*
- * S3C2410: Port D consists of 16 GPIO/Special function
- *
- * almost identical setup to port b, but the special functions are mostly
- * to do with the video system's data.
- *
- * almost identical setup to port c
-*/
-
-#define S3C2410_GPDCON    S3C2410_GPIOREG(0x30)
-#define S3C2410_GPDDAT    S3C2410_GPIOREG(0x34)
-#define S3C2410_GPDUP     S3C2410_GPIOREG(0x38)
-
-#define S3C2410_GPD0_VD8       (0x02 << 0)
-#define S3C2442_GPD0_nSPICS1   (0x03 << 0)
-
-#define S3C2410_GPD1_VD9       (0x02 << 2)
-#define S3C2442_GPD1_SPICLK1   (0x03 << 2)
-
-#define S3C2410_GPD2_VD10      (0x02 << 4)
-
-#define S3C2410_GPD3_VD11      (0x02 << 6)
-
-#define S3C2410_GPD4_VD12      (0x02 << 8)
-
-#define S3C2410_GPD5_VD13      (0x02 << 10)
-
-#define S3C2410_GPD6_VD14      (0x02 << 12)
-
-#define S3C2410_GPD7_VD15      (0x02 << 14)
-
-#define S3C2410_GPD8_VD16      (0x02 << 16)
-#define S3C2440_GPD8_SPIMISO1  (0x03 << 16)
-
-#define S3C2410_GPD9_VD17      (0x02 << 18)
-#define S3C2440_GPD9_SPIMOSI1  (0x03 << 18)
-
-#define S3C2410_GPD10_VD18     (0x02 << 20)
-#define S3C2440_GPD10_SPICLK1  (0x03 << 20)
-
-#define S3C2410_GPD11_VD19     (0x02 << 22)
-
-#define S3C2410_GPD12_VD20     (0x02 << 24)
-
-#define S3C2410_GPD13_VD21     (0x02 << 26)
-
-#define S3C2410_GPD14_VD22     (0x02 << 28)
-#define S3C2410_GPD14_nSS1     (0x03 << 28)
-
-#define S3C2410_GPD15_VD23     (0x02 << 30)
-#define S3C2410_GPD15_nSS0     (0x03 << 30)
-
-#define S3C2410_GPD_PUPDIS(x)  (1<<(x))
-
-/* S3C2410:
- * Port E consists of 16 GPIO/Special function
- *
- * again, the same as port B, but dealing with I2S, SDI, and
- * more miscellaneous functions
- *
- * GPIO / interrupt inputs
-*/
-
-#define S3C2410_GPECON    S3C2410_GPIOREG(0x40)
-#define S3C2410_GPEDAT    S3C2410_GPIOREG(0x44)
-#define S3C2410_GPEUP     S3C2410_GPIOREG(0x48)
-
-#define S3C2410_GPE0_I2SLRCK   (0x02 << 0)
-#define S3C2443_GPE0_AC_nRESET (0x03 << 0)
-#define S3C2410_GPE0_MASK      (0x03 << 0)
-
-#define S3C2410_GPE1_I2SSCLK   (0x02 << 2)
-#define S3C2443_GPE1_AC_SYNC   (0x03 << 2)
-#define S3C2410_GPE1_MASK      (0x03 << 2)
-
-#define S3C2410_GPE2_CDCLK     (0x02 << 4)
-#define S3C2443_GPE2_AC_BITCLK (0x03 << 4)
-
-#define S3C2410_GPE3_I2SSDI    (0x02 << 6)
-#define S3C2443_GPE3_AC_SDI    (0x03 << 6)
-#define S3C2410_GPE3_nSS0      (0x03 << 6)
-#define S3C2410_GPE3_MASK      (0x03 << 6)
-
-#define S3C2410_GPE4_I2SSDO    (0x02 << 8)
-#define S3C2443_GPE4_AC_SDO    (0x03 << 8)
-#define S3C2410_GPE4_I2SSDI    (0x03 << 8)
-#define S3C2410_GPE4_MASK      (0x03 << 8)
-
-#define S3C2410_GPE5_SDCLK     (0x02 << 10)
-#define S3C2443_GPE5_SD1_CLK   (0x02 << 10)
-#define S3C2443_GPE5_AC_BITCLK (0x03 << 10)
-
-#define S3C2410_GPE6_SDCMD     (0x02 << 12)
-#define S3C2443_GPE6_SD1_CMD   (0x02 << 12)
-#define S3C2443_GPE6_AC_SDI    (0x03 << 12)
-
-#define S3C2410_GPE7_SDDAT0    (0x02 << 14)
-#define S3C2443_GPE5_SD1_DAT0  (0x02 << 14)
-#define S3C2443_GPE7_AC_SDO    (0x03 << 14)
-
-#define S3C2410_GPE8_SDDAT1    (0x02 << 16)
-#define S3C2443_GPE8_SD1_DAT1  (0x02 << 16)
-#define S3C2443_GPE8_AC_SYNC   (0x03 << 16)
-
-#define S3C2410_GPE9_SDDAT2    (0x02 << 18)
-#define S3C2443_GPE9_SD1_DAT2  (0x02 << 18)
-#define S3C2443_GPE9_AC_nRESET (0x03 << 18)
-
-#define S3C2410_GPE10_SDDAT3   (0x02 << 20)
-#define S3C2443_GPE10_SD1_DAT3 (0x02 << 20)
-
-#define S3C2410_GPE11_SPIMISO0 (0x02 << 22)
-
-#define S3C2410_GPE12_SPIMOSI0 (0x02 << 24)
-
-#define S3C2410_GPE13_SPICLK0  (0x02 << 26)
-
-#define S3C2410_GPE14_IICSCL   (0x02 << 28)
-#define S3C2410_GPE14_MASK     (0x03 << 28)
-
-#define S3C2410_GPE15_IICSDA   (0x02 << 30)
-#define S3C2410_GPE15_MASK     (0x03 << 30)
-
-#define S3C2440_GPE0_ACSYNC    (0x03 << 0)
-#define S3C2440_GPE1_ACBITCLK  (0x03 << 2)
-#define S3C2440_GPE2_ACRESET   (0x03 << 4)
-#define S3C2440_GPE3_ACIN      (0x03 << 6)
-#define S3C2440_GPE4_ACOUT     (0x03 << 8)
-
-#define S3C2410_GPE_PUPDIS(x)  (1<<(x))
-
-/* S3C2410:
- * Port F consists of 8 GPIO/Special function
- *
- * GPIO / interrupt inputs
- *
- * GPFCON has 2 bits for each of the input pins on port F
- *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 undefined
- *
- * pull up works like all other ports.
- *
- * GPIO/serial/misc pins
-*/
-
-#define S3C2410_GPFCON    S3C2410_GPIOREG(0x50)
-#define S3C2410_GPFDAT    S3C2410_GPIOREG(0x54)
-#define S3C2410_GPFUP     S3C2410_GPIOREG(0x58)
-
-#define S3C2410_GPF0_EINT0  (0x02 << 0)
-#define S3C2410_GPF1_EINT1  (0x02 << 2)
-#define S3C2410_GPF2_EINT2  (0x02 << 4)
-#define S3C2410_GPF3_EINT3  (0x02 << 6)
-#define S3C2410_GPF4_EINT4  (0x02 << 8)
-#define S3C2410_GPF5_EINT5  (0x02 << 10)
-#define S3C2410_GPF6_EINT6  (0x02 << 12)
-#define S3C2410_GPF7_EINT7  (0x02 << 14)
-#define S3C2410_GPF_PUPDIS(x)  (1<<(x))
-
-/* S3C2410:
- * Port G consists of 8 GPIO/IRQ/Special function
- *
- * GPGCON has 2 bits for each of the input pins on port F
- *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func
- *
- * pull up works like all other ports.
-*/
-
-#define S3C2410_GPGCON    S3C2410_GPIOREG(0x60)
-#define S3C2410_GPGDAT    S3C2410_GPIOREG(0x64)
-#define S3C2410_GPGUP     S3C2410_GPIOREG(0x68)
-
-#define S3C2410_GPG0_EINT8    (0x02 << 0)
-
-#define S3C2410_GPG1_EINT9    (0x02 << 2)
-
-#define S3C2410_GPG2_EINT10   (0x02 << 4)
-#define S3C2410_GPG2_nSS0     (0x03 << 4)
-
-#define S3C2410_GPG3_EINT11   (0x02 << 6)
-#define S3C2410_GPG3_nSS1     (0x03 << 6)
-
-#define S3C2410_GPG4_EINT12   (0x02 << 8)
-#define S3C2410_GPG4_LCDPWREN (0x03 << 8)
-#define S3C2443_GPG4_LCDPWRDN (0x03 << 8)
-
-#define S3C2410_GPG5_EINT13   (0x02 << 10)
-#define S3C2410_GPG5_SPIMISO1 (0x03 << 10)     /* not s3c2443 */
-
-#define S3C2410_GPG6_EINT14   (0x02 << 12)
-#define S3C2410_GPG6_SPIMOSI1 (0x03 << 12)
-
-#define S3C2410_GPG7_EINT15   (0x02 << 14)
-#define S3C2410_GPG7_SPICLK1  (0x03 << 14)
-
-#define S3C2410_GPG8_EINT16   (0x02 << 16)
-
-#define S3C2410_GPG9_EINT17   (0x02 << 18)
-
-#define S3C2410_GPG10_EINT18  (0x02 << 20)
-
-#define S3C2410_GPG11_EINT19  (0x02 << 22)
-#define S3C2410_GPG11_TCLK1   (0x03 << 22)
-#define S3C2443_GPG11_CF_nIREQ (0x03 << 22)
-
-#define S3C2410_GPG12_EINT20  (0x02 << 24)
-#define S3C2410_GPG12_XMON    (0x03 << 24)
-#define S3C2442_GPG12_nSPICS0 (0x03 << 24)
-#define S3C2443_GPG12_nINPACK (0x03 << 24)
-
-#define S3C2410_GPG13_EINT21  (0x02 << 26)
-#define S3C2410_GPG13_nXPON   (0x03 << 26)
-#define S3C2443_GPG13_CF_nREG (0x03 << 26)
-
-#define S3C2410_GPG14_EINT22  (0x02 << 28)
-#define S3C2410_GPG14_YMON    (0x03 << 28)
-#define S3C2443_GPG14_CF_RESET (0x03 << 28)
-
-#define S3C2410_GPG15_EINT23  (0x02 << 30)
-#define S3C2410_GPG15_nYPON   (0x03 << 30)
-#define S3C2443_GPG15_CF_PWR  (0x03 << 30)
-
-#define S3C2410_GPG_PUPDIS(x)  (1<<(x))
-
-/* Port H consists of11 GPIO/serial/Misc pins
- *
- * GPGCON has 2 bits for each of the input pins on port F
- *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func
- *
- * pull up works like all other ports.
-*/
-
-#define S3C2410_GPHCON    S3C2410_GPIOREG(0x70)
-#define S3C2410_GPHDAT    S3C2410_GPIOREG(0x74)
-#define S3C2410_GPHUP     S3C2410_GPIOREG(0x78)
-
-#define S3C2410_GPH0_nCTS0  (0x02 << 0)
-#define S3C2416_GPH0_TXD0  (0x02 << 0)
-
-#define S3C2410_GPH1_nRTS0  (0x02 << 2)
-#define S3C2416_GPH1_RXD0  (0x02 << 2)
-
-#define S3C2410_GPH2_TXD0   (0x02 << 4)
-#define S3C2416_GPH2_TXD1   (0x02 << 4)
-
-#define S3C2410_GPH3_RXD0   (0x02 << 6)
-#define S3C2416_GPH3_RXD1   (0x02 << 6)
-
-#define S3C2410_GPH4_TXD1   (0x02 << 8)
-#define S3C2416_GPH4_TXD2   (0x02 << 8)
-
-#define S3C2410_GPH5_RXD1   (0x02 << 10)
-#define S3C2416_GPH5_RXD2   (0x02 << 10)
-
-#define S3C2410_GPH6_TXD2   (0x02 << 12)
-#define S3C2416_GPH6_TXD3   (0x02 << 12)
-#define S3C2410_GPH6_nRTS1  (0x03 << 12)
-#define S3C2416_GPH6_nRTS2  (0x03 << 12)
-
-#define S3C2410_GPH7_RXD2   (0x02 << 14)
-#define S3C2416_GPH7_RXD3   (0x02 << 14)
-#define S3C2410_GPH7_nCTS1  (0x03 << 14)
-#define S3C2416_GPH7_nCTS2  (0x03 << 14)
-
-#define S3C2410_GPH8_UCLK   (0x02 << 16)
-#define S3C2416_GPH8_nCTS0  (0x02 << 16)
-
-#define S3C2410_GPH9_CLKOUT0  (0x02 << 18)
-#define S3C2442_GPH9_nSPICS0  (0x03 << 18)
-#define S3C2416_GPH9_nRTS0    (0x02 << 18)
-
-#define S3C2410_GPH10_CLKOUT1 (0x02 << 20)
-#define S3C2416_GPH10_nCTS1   (0x02 << 20)
-
-#define S3C2416_GPH11_nRTS1   (0x02 << 22)
-
-#define S3C2416_GPH12_EXTUARTCLK (0x02 << 24)
-
-#define S3C2416_GPH13_CLKOUT0 (0x02 << 26)
-
-#define S3C2416_GPH14_CLKOUT1 (0x02 << 28)
-
-/* The S3C2412 and S3C2413 move the GPJ register set to after
- * GPH, which means all registers after 0x80 are now offset by 0x10
- * for the 2412/2413 from the 2410/2440/2442
-*/
-
-/* S3C2443 and above */
-#define S3C2440_GPJCON    S3C2410_GPIOREG(0xD0)
-#define S3C2440_GPJDAT    S3C2410_GPIOREG(0xD4)
-#define S3C2440_GPJUP     S3C2410_GPIOREG(0xD8)
-
-#define S3C2443_GPKCON    S3C2410_GPIOREG(0xE0)
-#define S3C2443_GPKDAT    S3C2410_GPIOREG(0xE4)
-#define S3C2443_GPKUP     S3C2410_GPIOREG(0xE8)
-
-#define S3C2443_GPLCON    S3C2410_GPIOREG(0xF0)
-#define S3C2443_GPLDAT    S3C2410_GPIOREG(0xF4)
-#define S3C2443_GPLUP     S3C2410_GPIOREG(0xF8)
-
-#define S3C2443_GPMCON    S3C2410_GPIOREG(0x100)
-#define S3C2443_GPMDAT    S3C2410_GPIOREG(0x104)
-#define S3C2443_GPMUP     S3C2410_GPIOREG(0x108)
-
-/* miscellaneous control */
-#define S3C2410_MISCCR    S3C2410_GPIOREG(0x80)
-#define S3C2410_DCLKCON           S3C2410_GPIOREG(0x84)
-
-#define S3C24XX_DCLKCON           S3C24XX_GPIOREG2(0x84)
-
-/* see clock.h for dclk definitions */
-
-/* pullup control on databus */
-#define S3C2410_MISCCR_SPUCR_HEN    (0<<0)
-#define S3C2410_MISCCR_SPUCR_HDIS   (1<<0)
-#define S3C2410_MISCCR_SPUCR_LEN    (0<<1)
-#define S3C2410_MISCCR_SPUCR_LDIS   (1<<1)
-
-#define S3C2410_MISCCR_USBDEV      (0<<3)
-#define S3C2410_MISCCR_USBHOST     (1<<3)
-
-#define S3C2410_MISCCR_CLK0_MPLL    (0<<4)
-#define S3C2410_MISCCR_CLK0_UPLL    (1<<4)
-#define S3C2410_MISCCR_CLK0_FCLK    (2<<4)
-#define S3C2410_MISCCR_CLK0_HCLK    (3<<4)
-#define S3C2410_MISCCR_CLK0_PCLK    (4<<4)
-#define S3C2410_MISCCR_CLK0_DCLK0   (5<<4)
-#define S3C2410_MISCCR_CLK0_MASK    (7<<4)
-
-#define S3C2412_MISCCR_CLK0_RTC            (2<<4)
-
-#define S3C2410_MISCCR_CLK1_MPLL    (0<<8)
-#define S3C2410_MISCCR_CLK1_UPLL    (1<<8)
-#define S3C2410_MISCCR_CLK1_FCLK    (2<<8)
-#define S3C2410_MISCCR_CLK1_HCLK    (3<<8)
-#define S3C2410_MISCCR_CLK1_PCLK    (4<<8)
-#define S3C2410_MISCCR_CLK1_DCLK1   (5<<8)
-#define S3C2410_MISCCR_CLK1_MASK    (7<<8)
-
-#define S3C2412_MISCCR_CLK1_CLKsrc  (0<<8)
-
-#define S3C2410_MISCCR_USBSUSPND0   (1<<12)
-#define S3C2416_MISCCR_SEL_SUSPND   (1<<12)
-#define S3C2410_MISCCR_USBSUSPND1   (1<<13)
-
-#define S3C2410_MISCCR_nRSTCON     (1<<16)
-
-#define S3C2410_MISCCR_nEN_SCLK0    (1<<17)
-#define S3C2410_MISCCR_nEN_SCLK1    (1<<18)
-#define S3C2410_MISCCR_nEN_SCLKE    (1<<19)    /* not 2412 */
-#define S3C2410_MISCCR_SDSLEEP     (7<<17)
-
-#define S3C2416_MISCCR_FLT_I2C      (1<<24)
-#define S3C2416_MISCCR_HSSPI_EN2    (1<<31)
-
-/* external interrupt control... */
-/* S3C2410_EXTINT0 -> irq sense control for EINT0..EINT7
- * S3C2410_EXTINT1 -> irq sense control for EINT8..EINT15
- * S3C2410_EXTINT2 -> irq sense control for EINT16..EINT23
- *
- * note S3C2410_EXTINT2 has filtering options for EINT16..EINT23
- *
- * Samsung datasheet p9-25
-*/
-#define S3C2410_EXTINT0           S3C2410_GPIOREG(0x88)
-#define S3C2410_EXTINT1           S3C2410_GPIOREG(0x8C)
-#define S3C2410_EXTINT2           S3C2410_GPIOREG(0x90)
-
-#define S3C24XX_EXTINT0           S3C24XX_GPIOREG2(0x88)
-#define S3C24XX_EXTINT1           S3C24XX_GPIOREG2(0x8C)
-#define S3C24XX_EXTINT2           S3C24XX_GPIOREG2(0x90)
-
-/* interrupt filtering conrrol for EINT16..EINT23 */
-#define S3C2410_EINFLT0           S3C2410_GPIOREG(0x94)
-#define S3C2410_EINFLT1           S3C2410_GPIOREG(0x98)
-#define S3C2410_EINFLT2           S3C2410_GPIOREG(0x9C)
-#define S3C2410_EINFLT3           S3C2410_GPIOREG(0xA0)
-
-#define S3C24XX_EINFLT0           S3C24XX_GPIOREG2(0x94)
-#define S3C24XX_EINFLT1           S3C24XX_GPIOREG2(0x98)
-#define S3C24XX_EINFLT2           S3C24XX_GPIOREG2(0x9C)
-#define S3C24XX_EINFLT3           S3C24XX_GPIOREG2(0xA0)
-
-/* values for interrupt filtering */
-#define S3C2410_EINTFLT_PCLK           (0x00)
-#define S3C2410_EINTFLT_EXTCLK         (1<<7)
-#define S3C2410_EINTFLT_WIDTHMSK(x)    ((x) & 0x3f)
-
-/* removed EINTxxxx defs from here, not meant for this */
-
-/* GSTATUS have miscellaneous information in them
- *
- * These move between s3c2410 and s3c2412 style systems.
- */
-
-#define S3C2410_GSTATUS0   S3C2410_GPIOREG(0x0AC)
-#define S3C2410_GSTATUS1   S3C2410_GPIOREG(0x0B0)
-#define S3C2410_GSTATUS2   S3C2410_GPIOREG(0x0B4)
-#define S3C2410_GSTATUS3   S3C2410_GPIOREG(0x0B8)
-#define S3C2410_GSTATUS4   S3C2410_GPIOREG(0x0BC)
-
-#define S3C2412_GSTATUS0   S3C2410_GPIOREG(0x0BC)
-#define S3C2412_GSTATUS1   S3C2410_GPIOREG(0x0C0)
-#define S3C2412_GSTATUS2   S3C2410_GPIOREG(0x0C4)
-#define S3C2412_GSTATUS3   S3C2410_GPIOREG(0x0C8)
-#define S3C2412_GSTATUS4   S3C2410_GPIOREG(0x0CC)
-
-#define S3C24XX_GSTATUS0   S3C24XX_GPIOREG2(0x0AC)
-#define S3C24XX_GSTATUS1   S3C24XX_GPIOREG2(0x0B0)
-#define S3C24XX_GSTATUS2   S3C24XX_GPIOREG2(0x0B4)
-#define S3C24XX_GSTATUS3   S3C24XX_GPIOREG2(0x0B8)
-#define S3C24XX_GSTATUS4   S3C24XX_GPIOREG2(0x0BC)
-
-#define S3C2410_GSTATUS0_nWAIT    (1<<3)
-#define S3C2410_GSTATUS0_NCON     (1<<2)
-#define S3C2410_GSTATUS0_RnB      (1<<1)
-#define S3C2410_GSTATUS0_nBATTFLT  (1<<0)
-
-#define S3C2410_GSTATUS1_IDMASK           (0xffff0000)
-#define S3C2410_GSTATUS1_2410     (0x32410000)
-#define S3C2410_GSTATUS1_2412     (0x32412001)
-#define S3C2410_GSTATUS1_2416     (0x32416003)
-#define S3C2410_GSTATUS1_2440     (0x32440000)
-#define S3C2410_GSTATUS1_2442     (0x32440aaa)
-/* some 2416 CPUs report this value also */
-#define S3C2410_GSTATUS1_2450     (0x32450003)
-
-#define S3C2410_GSTATUS2_WTRESET   (1<<2)
-#define S3C2410_GSTATUS2_OFFRESET  (1<<1)
-#define S3C2410_GSTATUS2_PONRESET  (1<<0)
-
-/* 2412/2413 sleep configuration registers */
-
-#define S3C2412_GPBSLPCON      S3C2410_GPIOREG(0x1C)
-#define S3C2412_GPCSLPCON      S3C2410_GPIOREG(0x2C)
-#define S3C2412_GPDSLPCON      S3C2410_GPIOREG(0x3C)
-#define S3C2412_GPFSLPCON      S3C2410_GPIOREG(0x5C)
-#define S3C2412_GPGSLPCON      S3C2410_GPIOREG(0x6C)
-#define S3C2412_GPHSLPCON      S3C2410_GPIOREG(0x7C)
-
-/* definitions for each pin bit */
-#define S3C2412_GPIO_SLPCON_LOW         ( 0x00 )
-#define S3C2412_GPIO_SLPCON_HIGH ( 0x01 )
-#define S3C2412_GPIO_SLPCON_IN   ( 0x02 )
-#define S3C2412_GPIO_SLPCON_PULL ( 0x03 )
-
-#define S3C2412_SLPCON_LOW(x)  ( 0x00 << ((x) * 2))
-#define S3C2412_SLPCON_HIGH(x) ( 0x01 << ((x) * 2))
-#define S3C2412_SLPCON_IN(x)   ( 0x02 << ((x) * 2))
-#define S3C2412_SLPCON_PULL(x) ( 0x03 << ((x) * 2))
-#define S3C2412_SLPCON_EINT(x) ( 0x02 << ((x) * 2))  /* only IRQ pins */
-#define S3C2412_SLPCON_MASK(x) ( 0x03 << ((x) * 2))
-
-#define S3C2412_SLPCON_ALL_LOW (0x0)
-#define S3C2412_SLPCON_ALL_HIGH        (0x11111111 | 0x44444444)
-#define S3C2412_SLPCON_ALL_IN          (0x22222222 | 0x88888888)
-#define S3C2412_SLPCON_ALL_PULL        (0x33333333)
-
-#endif /* __ASM_ARCH_REGS_GPIO_H */
-
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-gpioj.h b/arch/arm/mach-s3c2410/include/mach/regs-gpioj.h
deleted file mode 100644 (file)
index 19575e0..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-gpioj.h
- *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
- *                   http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2440 GPIO J register definitions
-*/
-
-
-#ifndef __ASM_ARCH_REGS_GPIOJ_H
-#define __ASM_ARCH_REGS_GPIOJ_H "gpioj"
-
-/* Port J consists of 13 GPIO/Camera pins
- *
- * GPJCON has 2 bits for each of the input pins on port F
- *   00 = 0 input, 1 output, 2 Camera
- *
- * pull up works like all other ports.
-*/
-
-#define S3C2413_GPJCON         S3C2410_GPIOREG(0x80)
-#define S3C2413_GPJDAT         S3C2410_GPIOREG(0x84)
-#define S3C2413_GPJUP          S3C2410_GPIOREG(0x88)
-#define S3C2413_GPJSLPCON      S3C2410_GPIOREG(0x8C)
-
-#define S3C2440_GPJ0_OUTP       (0x01 << 0)
-#define S3C2440_GPJ0_CAMDATA0   (0x02 << 0)
-
-#define S3C2440_GPJ1_OUTP       (0x01 << 2)
-#define S3C2440_GPJ1_CAMDATA1   (0x02 << 2)
-
-#define S3C2440_GPJ2_OUTP       (0x01 << 4)
-#define S3C2440_GPJ2_CAMDATA2   (0x02 << 4)
-
-#define S3C2440_GPJ3_OUTP       (0x01 << 6)
-#define S3C2440_GPJ3_CAMDATA3   (0x02 << 6)
-
-#define S3C2440_GPJ4_OUTP       (0x01 << 8)
-#define S3C2440_GPJ4_CAMDATA4   (0x02 << 8)
-
-#define S3C2440_GPJ5_OUTP       (0x01 << 10)
-#define S3C2440_GPJ5_CAMDATA5   (0x02 << 10)
-
-#define S3C2440_GPJ6_OUTP       (0x01 << 12)
-#define S3C2440_GPJ6_CAMDATA6   (0x02 << 12)
-
-#define S3C2440_GPJ7_OUTP       (0x01 << 14)
-#define S3C2440_GPJ7_CAMDATA7   (0x02 << 14)
-
-#define S3C2440_GPJ8_OUTP       (0x01 << 16)
-#define S3C2440_GPJ8_CAMPCLK    (0x02 << 16)
-
-#define S3C2440_GPJ9_OUTP       (0x01 << 18)
-#define S3C2440_GPJ9_CAMVSYNC   (0x02 << 18)
-
-#define S3C2440_GPJ10_OUTP      (0x01 << 20)
-#define S3C2440_GPJ10_CAMHREF   (0x02 << 20)
-
-#define S3C2440_GPJ11_OUTP      (0x01 << 22)
-#define S3C2440_GPJ11_CAMCLKOUT (0x02 << 22)
-
-#define S3C2440_GPJ12_OUTP      (0x01 << 24)
-#define S3C2440_GPJ12_CAMRESET  (0x02 << 24)
-
-#endif /* __ASM_ARCH_REGS_GPIOJ_H */
-
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-irq.h b/arch/arm/mach-s3c2410/include/mach/regs-irq.h
deleted file mode 100644 (file)
index 0f07ba3..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-irq.h
- *
- * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
- *                   http://www.simtec.co.uk/products/SWLINUX/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-
-#ifndef ___ASM_ARCH_REGS_IRQ_H
-#define ___ASM_ARCH_REGS_IRQ_H
-
-/* interrupt controller */
-
-#define S3C2410_IRQREG(x)   ((x) + S3C24XX_VA_IRQ)
-#define S3C2410_EINTREG(x)  ((x) + S3C24XX_VA_GPIO)
-#define S3C24XX_EINTREG(x)  ((x) + S3C24XX_VA_GPIO2)
-
-#define S3C2410_SRCPND        S3C2410_IRQREG(0x000)
-#define S3C2410_INTMOD        S3C2410_IRQREG(0x004)
-#define S3C2410_INTMSK        S3C2410_IRQREG(0x008)
-#define S3C2410_PRIORITY       S3C2410_IRQREG(0x00C)
-#define S3C2410_INTPND        S3C2410_IRQREG(0x010)
-#define S3C2410_INTOFFSET      S3C2410_IRQREG(0x014)
-#define S3C2410_SUBSRCPND      S3C2410_IRQREG(0x018)
-#define S3C2410_INTSUBMSK      S3C2410_IRQREG(0x01C)
-
-#define S3C2416_PRIORITY_MODE1         S3C2410_IRQREG(0x030)
-#define S3C2416_PRIORITY_UPDATE1       S3C2410_IRQREG(0x034)
-#define S3C2416_SRCPND2                        S3C2410_IRQREG(0x040)
-#define S3C2416_INTMOD2                        S3C2410_IRQREG(0x044)
-#define S3C2416_INTMSK2                        S3C2410_IRQREG(0x048)
-#define S3C2416_INTPND2                        S3C2410_IRQREG(0x050)
-#define S3C2416_INTOFFSET2             S3C2410_IRQREG(0x054)
-#define S3C2416_PRIORITY_MODE2         S3C2410_IRQREG(0x070)
-#define S3C2416_PRIORITY_UPDATE2       S3C2410_IRQREG(0x074)
-
-/* mask: 0=enable, 1=disable
- * 1 bit EINT, 4=EINT4, 23=EINT23
- * EINT0,1,2,3 are not handled here.
-*/
-
-#define S3C2410_EINTMASK       S3C2410_EINTREG(0x0A4)
-#define S3C2410_EINTPEND       S3C2410_EINTREG(0X0A8)
-#define S3C2412_EINTMASK       S3C2410_EINTREG(0x0B4)
-#define S3C2412_EINTPEND       S3C2410_EINTREG(0X0B8)
-
-#define S3C24XX_EINTMASK       S3C24XX_EINTREG(0x0A4)
-#define S3C24XX_EINTPEND       S3C24XX_EINTREG(0X0A8)
-
-#endif /* ___ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-lcd.h b/arch/arm/mach-s3c2410/include/mach/regs-lcd.h
deleted file mode 100644 (file)
index ee8f040..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-lcd.h
- *
- * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
- *                   http://www.simtec.co.uk/products/SWLINUX/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-
-#ifndef ___ASM_ARCH_REGS_LCD_H
-#define ___ASM_ARCH_REGS_LCD_H
-
-#define S3C2410_LCDREG(x)      (x)
-
-/* LCD control registers */
-#define S3C2410_LCDCON1            S3C2410_LCDREG(0x00)
-#define S3C2410_LCDCON2            S3C2410_LCDREG(0x04)
-#define S3C2410_LCDCON3            S3C2410_LCDREG(0x08)
-#define S3C2410_LCDCON4            S3C2410_LCDREG(0x0C)
-#define S3C2410_LCDCON5            S3C2410_LCDREG(0x10)
-
-#define S3C2410_LCDCON1_CLKVAL(x)  ((x) << 8)
-#define S3C2410_LCDCON1_MMODE     (1<<7)
-#define S3C2410_LCDCON1_DSCAN4    (0<<5)
-#define S3C2410_LCDCON1_STN4      (1<<5)
-#define S3C2410_LCDCON1_STN8      (2<<5)
-#define S3C2410_LCDCON1_TFT       (3<<5)
-
-#define S3C2410_LCDCON1_STN1BPP           (0<<1)
-#define S3C2410_LCDCON1_STN2GREY   (1<<1)
-#define S3C2410_LCDCON1_STN4GREY   (2<<1)
-#define S3C2410_LCDCON1_STN8BPP           (3<<1)
-#define S3C2410_LCDCON1_STN12BPP   (4<<1)
-
-#define S3C2410_LCDCON1_TFT1BPP           (8<<1)
-#define S3C2410_LCDCON1_TFT2BPP           (9<<1)
-#define S3C2410_LCDCON1_TFT4BPP           (10<<1)
-#define S3C2410_LCDCON1_TFT8BPP           (11<<1)
-#define S3C2410_LCDCON1_TFT16BPP   (12<<1)
-#define S3C2410_LCDCON1_TFT24BPP   (13<<1)
-
-#define S3C2410_LCDCON1_ENVID     (1)
-
-#define S3C2410_LCDCON1_MODEMASK    0x1E
-
-#define S3C2410_LCDCON2_VBPD(x)            ((x) << 24)
-#define S3C2410_LCDCON2_LINEVAL(x)  ((x) << 14)
-#define S3C2410_LCDCON2_VFPD(x)            ((x) << 6)
-#define S3C2410_LCDCON2_VSPW(x)            ((x) << 0)
-
-#define S3C2410_LCDCON2_GET_VBPD(x) ( ((x) >> 24) & 0xFF)
-#define S3C2410_LCDCON2_GET_VFPD(x) ( ((x) >>  6) & 0xFF)
-#define S3C2410_LCDCON2_GET_VSPW(x) ( ((x) >>  0) & 0x3F)
-
-#define S3C2410_LCDCON3_HBPD(x)            ((x) << 19)
-#define S3C2410_LCDCON3_WDLY(x)            ((x) << 19)
-#define S3C2410_LCDCON3_HOZVAL(x)   ((x) << 8)
-#define S3C2410_LCDCON3_HFPD(x)            ((x) << 0)
-#define S3C2410_LCDCON3_LINEBLANK(x)((x) << 0)
-
-#define S3C2410_LCDCON3_GET_HBPD(x) ( ((x) >> 19) & 0x7F)
-#define S3C2410_LCDCON3_GET_HFPD(x) ( ((x) >>  0) & 0xFF)
-
-/* LDCCON4 changes for STN mode on the S3C2412 */
-
-#define S3C2410_LCDCON4_MVAL(x)            ((x) << 8)
-#define S3C2410_LCDCON4_HSPW(x)            ((x) << 0)
-#define S3C2410_LCDCON4_WLH(x)     ((x) << 0)
-
-#define S3C2410_LCDCON4_GET_HSPW(x) ( ((x) >>  0) & 0xFF)
-
-#define S3C2410_LCDCON5_BPP24BL            (1<<12)
-#define S3C2410_LCDCON5_FRM565     (1<<11)
-#define S3C2410_LCDCON5_INVVCLK            (1<<10)
-#define S3C2410_LCDCON5_INVVLINE    (1<<9)
-#define S3C2410_LCDCON5_INVVFRAME   (1<<8)
-#define S3C2410_LCDCON5_INVVD      (1<<7)
-#define S3C2410_LCDCON5_INVVDEN            (1<<6)
-#define S3C2410_LCDCON5_INVPWREN    (1<<5)
-#define S3C2410_LCDCON5_INVLEND            (1<<4)
-#define S3C2410_LCDCON5_PWREN      (1<<3)
-#define S3C2410_LCDCON5_ENLEND     (1<<2)
-#define S3C2410_LCDCON5_BSWP       (1<<1)
-#define S3C2410_LCDCON5_HWSWP      (1<<0)
-
-/* framebuffer start addressed */
-#define S3C2410_LCDSADDR1   S3C2410_LCDREG(0x14)
-#define S3C2410_LCDSADDR2   S3C2410_LCDREG(0x18)
-#define S3C2410_LCDSADDR3   S3C2410_LCDREG(0x1C)
-
-#define S3C2410_LCDBANK(x)     ((x) << 21)
-#define S3C2410_LCDBASEU(x)    (x)
-
-#define S3C2410_OFFSIZE(x)     ((x) << 11)
-#define S3C2410_PAGEWIDTH(x)   (x)
-
-/* colour lookup and miscellaneous controls */
-
-#define S3C2410_REDLUT    S3C2410_LCDREG(0x20)
-#define S3C2410_GREENLUT   S3C2410_LCDREG(0x24)
-#define S3C2410_BLUELUT           S3C2410_LCDREG(0x28)
-
-#define S3C2410_DITHMODE   S3C2410_LCDREG(0x4C)
-#define S3C2410_TPAL      S3C2410_LCDREG(0x50)
-
-#define S3C2410_TPAL_EN                (1<<24)
-
-/* interrupt info */
-#define S3C2410_LCDINTPND  S3C2410_LCDREG(0x54)
-#define S3C2410_LCDSRCPND  S3C2410_LCDREG(0x58)
-#define S3C2410_LCDINTMSK  S3C2410_LCDREG(0x5C)
-#define S3C2410_LCDINT_FIWSEL  (1<<2)
-#define        S3C2410_LCDINT_FRSYNC   (1<<1)
-#define S3C2410_LCDINT_FICNT   (1<<0)
-
-/* s3c2442 extra stn registers */
-
-#define S3C2442_REDLUT         S3C2410_LCDREG(0x20)
-#define S3C2442_GREENLUT       S3C2410_LCDREG(0x24)
-#define S3C2442_BLUELUT                S3C2410_LCDREG(0x28)
-#define S3C2442_DITHMODE       S3C2410_LCDREG(0x20)
-
-#define S3C2410_LPCSEL    S3C2410_LCDREG(0x60)
-
-#define S3C2410_TFTPAL(x)  S3C2410_LCDREG((0x400 + (x)*4))
-
-/* S3C2412 registers */
-
-#define S3C2412_TPAL           S3C2410_LCDREG(0x20)
-
-#define S3C2412_LCDINTPND      S3C2410_LCDREG(0x24)
-#define S3C2412_LCDSRCPND      S3C2410_LCDREG(0x28)
-#define S3C2412_LCDINTMSK      S3C2410_LCDREG(0x2C)
-
-#define S3C2412_TCONSEL                S3C2410_LCDREG(0x30)
-
-#define S3C2412_LCDCON6                S3C2410_LCDREG(0x34)
-#define S3C2412_LCDCON7                S3C2410_LCDREG(0x38)
-#define S3C2412_LCDCON8                S3C2410_LCDREG(0x3C)
-#define S3C2412_LCDCON9                S3C2410_LCDREG(0x40)
-
-#define S3C2412_REDLUT(x)      S3C2410_LCDREG(0x44 + ((x)*4))
-#define S3C2412_GREENLUT(x)    S3C2410_LCDREG(0x60 + ((x)*4))
-#define S3C2412_BLUELUT(x)     S3C2410_LCDREG(0x98 + ((x)*4))
-
-#define S3C2412_FRCPAT(x)      S3C2410_LCDREG(0xB4 + ((x)*4))
-
-/* general registers */
-
-/* base of the LCD registers, where INTPND, INTSRC and then INTMSK
- * are available. */
-
-#define S3C2410_LCDINTBASE     S3C2410_LCDREG(0x54)
-#define S3C2412_LCDINTBASE     S3C2410_LCDREG(0x24)
-
-#define S3C24XX_LCDINTPND      (0x00)
-#define S3C24XX_LCDSRCPND      (0x04)
-#define S3C24XX_LCDINTMSK      (0x08)
-
-#endif /* ___ASM_ARCH_REGS_LCD_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-mem.h b/arch/arm/mach-s3c2410/include/mach/regs-mem.h
deleted file mode 100644 (file)
index e0c67b0..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-mem.h
- *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
- *             http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2410 Memory Control register definitions
-*/
-
-#ifndef __ASM_ARM_MEMREGS_H
-#define __ASM_ARM_MEMREGS_H
-
-#ifndef S3C2410_MEMREG
-#define S3C2410_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
-#endif
-
-/* bus width, and wait state control */
-#define S3C2410_BWSCON                 S3C2410_MEMREG(0x0000)
-
-/* bank zero config - note, pinstrapped from OM pins! */
-#define S3C2410_BWSCON_DW0_16          (1<<1)
-#define S3C2410_BWSCON_DW0_32          (2<<1)
-
-/* bank one configs */
-#define S3C2410_BWSCON_DW1_8           (0<<4)
-#define S3C2410_BWSCON_DW1_16          (1<<4)
-#define S3C2410_BWSCON_DW1_32          (2<<4)
-#define S3C2410_BWSCON_WS1             (1<<6)
-#define S3C2410_BWSCON_ST1             (1<<7)
-
-/* bank 2 configurations */
-#define S3C2410_BWSCON_DW2_8           (0<<8)
-#define S3C2410_BWSCON_DW2_16          (1<<8)
-#define S3C2410_BWSCON_DW2_32          (2<<8)
-#define S3C2410_BWSCON_WS2             (1<<10)
-#define S3C2410_BWSCON_ST2             (1<<11)
-
-/* bank 3 configurations */
-#define S3C2410_BWSCON_DW3_8           (0<<12)
-#define S3C2410_BWSCON_DW3_16          (1<<12)
-#define S3C2410_BWSCON_DW3_32          (2<<12)
-#define S3C2410_BWSCON_WS3             (1<<14)
-#define S3C2410_BWSCON_ST3             (1<<15)
-
-/* bank 4 configurations */
-#define S3C2410_BWSCON_DW4_8           (0<<16)
-#define S3C2410_BWSCON_DW4_16          (1<<16)
-#define S3C2410_BWSCON_DW4_32          (2<<16)
-#define S3C2410_BWSCON_WS4             (1<<18)
-#define S3C2410_BWSCON_ST4             (1<<19)
-
-/* bank 5 configurations */
-#define S3C2410_BWSCON_DW5_8           (0<<20)
-#define S3C2410_BWSCON_DW5_16          (1<<20)
-#define S3C2410_BWSCON_DW5_32          (2<<20)
-#define S3C2410_BWSCON_WS5             (1<<22)
-#define S3C2410_BWSCON_ST5             (1<<23)
-
-/* bank 6 configurations */
-#define S3C2410_BWSCON_DW6_8           (0<<24)
-#define S3C2410_BWSCON_DW6_16          (1<<24)
-#define S3C2410_BWSCON_DW6_32          (2<<24)
-#define S3C2410_BWSCON_WS6             (1<<26)
-#define S3C2410_BWSCON_ST6             (1<<27)
-
-/* bank 7 configurations */
-#define S3C2410_BWSCON_DW7_8           (0<<28)
-#define S3C2410_BWSCON_DW7_16          (1<<28)
-#define S3C2410_BWSCON_DW7_32          (2<<28)
-#define S3C2410_BWSCON_WS7             (1<<30)
-#define S3C2410_BWSCON_ST7             (1<<31)
-
-/* accesor functions for getting BANK(n) configuration. (n != 0) */
-
-#define S3C2410_BWSCON_GET(_bwscon, _bank) (((_bwscon) >> ((_bank) * 4)) & 0xf)
-
-#define S3C2410_BWSCON_DW8             (0)
-#define S3C2410_BWSCON_DW16            (1)
-#define S3C2410_BWSCON_DW32            (2)
-#define S3C2410_BWSCON_WS              (1 << 2)
-#define S3C2410_BWSCON_ST              (1 << 3)
-
-/* memory set (rom, ram) */
-#define S3C2410_BANKCON0               S3C2410_MEMREG(0x0004)
-#define S3C2410_BANKCON1               S3C2410_MEMREG(0x0008)
-#define S3C2410_BANKCON2               S3C2410_MEMREG(0x000C)
-#define S3C2410_BANKCON3               S3C2410_MEMREG(0x0010)
-#define S3C2410_BANKCON4               S3C2410_MEMREG(0x0014)
-#define S3C2410_BANKCON5               S3C2410_MEMREG(0x0018)
-#define S3C2410_BANKCON6               S3C2410_MEMREG(0x001C)
-#define S3C2410_BANKCON7               S3C2410_MEMREG(0x0020)
-
-/* bank configuration registers */
-
-#define S3C2410_BANKCON_PMCnorm                (0x00)
-#define S3C2410_BANKCON_PMC4           (0x01)
-#define S3C2410_BANKCON_PMC8           (0x02)
-#define S3C2410_BANKCON_PMC16          (0x03)
-
-/* bank configurations for banks 0..7, note banks
- * 6 and 7 have different configurations depending on
- * the memory type bits */
-
-#define S3C2410_BANKCON_Tacp2          (0x0 << 2)
-#define S3C2410_BANKCON_Tacp3          (0x1 << 2)
-#define S3C2410_BANKCON_Tacp4          (0x2 << 2)
-#define S3C2410_BANKCON_Tacp6          (0x3 << 2)
-#define S3C2410_BANKCON_Tacp_SHIFT     (2)
-
-#define S3C2410_BANKCON_Tcah0          (0x0 << 4)
-#define S3C2410_BANKCON_Tcah1          (0x1 << 4)
-#define S3C2410_BANKCON_Tcah2          (0x2 << 4)
-#define S3C2410_BANKCON_Tcah4          (0x3 << 4)
-#define S3C2410_BANKCON_Tcah_SHIFT     (4)
-
-#define S3C2410_BANKCON_Tcoh0          (0x0 << 6)
-#define S3C2410_BANKCON_Tcoh1          (0x1 << 6)
-#define S3C2410_BANKCON_Tcoh2          (0x2 << 6)
-#define S3C2410_BANKCON_Tcoh4          (0x3 << 6)
-#define S3C2410_BANKCON_Tcoh_SHIFT     (6)
-
-#define S3C2410_BANKCON_Tacc1          (0x0 << 8)
-#define S3C2410_BANKCON_Tacc2          (0x1 << 8)
-#define S3C2410_BANKCON_Tacc3          (0x2 << 8)
-#define S3C2410_BANKCON_Tacc4          (0x3 << 8)
-#define S3C2410_BANKCON_Tacc6          (0x4 << 8)
-#define S3C2410_BANKCON_Tacc8          (0x5 << 8)
-#define S3C2410_BANKCON_Tacc10         (0x6 << 8)
-#define S3C2410_BANKCON_Tacc14         (0x7 << 8)
-#define S3C2410_BANKCON_Tacc_SHIFT     (8)
-
-#define S3C2410_BANKCON_Tcos0          (0x0 << 11)
-#define S3C2410_BANKCON_Tcos1          (0x1 << 11)
-#define S3C2410_BANKCON_Tcos2          (0x2 << 11)
-#define S3C2410_BANKCON_Tcos4          (0x3 << 11)
-#define S3C2410_BANKCON_Tcos_SHIFT     (11)
-
-#define S3C2410_BANKCON_Tacs0          (0x0 << 13)
-#define S3C2410_BANKCON_Tacs1          (0x1 << 13)
-#define S3C2410_BANKCON_Tacs2          (0x2 << 13)
-#define S3C2410_BANKCON_Tacs4          (0x3 << 13)
-#define S3C2410_BANKCON_Tacs_SHIFT     (13)
-
-#define S3C2410_BANKCON_SRAM           (0x0 << 15)
-#define S3C2410_BANKCON_SDRAM          (0x3 << 15)
-
-/* next bits only for SDRAM in 6,7 */
-#define S3C2410_BANKCON_Trcd2          (0x00 << 2)
-#define S3C2410_BANKCON_Trcd3          (0x01 << 2)
-#define S3C2410_BANKCON_Trcd4          (0x02 << 2)
-
-/* control column address select */
-#define S3C2410_BANKCON_SCANb8         (0x00 << 0)
-#define S3C2410_BANKCON_SCANb9         (0x01 << 0)
-#define S3C2410_BANKCON_SCANb10                (0x02 << 0)
-
-#define S3C2410_REFRESH                        S3C2410_MEMREG(0x0024)
-#define S3C2410_BANKSIZE               S3C2410_MEMREG(0x0028)
-#define S3C2410_MRSRB6                 S3C2410_MEMREG(0x002C)
-#define S3C2410_MRSRB7                 S3C2410_MEMREG(0x0030)
-
-/* refresh control */
-
-#define S3C2410_REFRESH_REFEN          (1<<23)
-#define S3C2410_REFRESH_SELF           (1<<22)
-#define S3C2410_REFRESH_REFCOUNTER     ((1<<11)-1)
-
-#define S3C2410_REFRESH_TRP_MASK       (3<<20)
-#define S3C2410_REFRESH_TRP_2clk       (0<<20)
-#define S3C2410_REFRESH_TRP_3clk       (1<<20)
-#define S3C2410_REFRESH_TRP_4clk       (2<<20)
-
-#define S3C2410_REFRESH_TSRC_MASK      (3<<18)
-#define S3C2410_REFRESH_TSRC_4clk      (0<<18)
-#define S3C2410_REFRESH_TSRC_5clk      (1<<18)
-#define S3C2410_REFRESH_TSRC_6clk      (2<<18)
-#define S3C2410_REFRESH_TSRC_7clk      (3<<18)
-
-
-/* mode select register(s) */
-
-#define  S3C2410_MRSRB_CL1             (0x00 << 4)
-#define  S3C2410_MRSRB_CL2             (0x02 << 4)
-#define  S3C2410_MRSRB_CL3             (0x03 << 4)
-
-/* bank size register */
-#define S3C2410_BANKSIZE_128M          (0x2 << 0)
-#define S3C2410_BANKSIZE_64M           (0x1 << 0)
-#define S3C2410_BANKSIZE_32M           (0x0 << 0)
-#define S3C2410_BANKSIZE_16M           (0x7 << 0)
-#define S3C2410_BANKSIZE_8M            (0x6 << 0)
-#define S3C2410_BANKSIZE_4M            (0x5 << 0)
-#define S3C2410_BANKSIZE_2M            (0x4 << 0)
-#define S3C2410_BANKSIZE_MASK          (0x7 << 0)
-#define S3C2410_BANKSIZE_SCLK_EN       (1<<4)
-#define S3C2410_BANKSIZE_SCKE_EN       (1<<5)
-#define S3C2410_BANKSIZE_BURST         (1<<7)
-
-#endif /* __ASM_ARM_MEMREGS_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-power.h b/arch/arm/mach-s3c2410/include/mach/regs-power.h
deleted file mode 100644 (file)
index 4932b87..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-power.h
- *
- * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * S3C24XX power control register definitions
-*/
-
-#ifndef __ASM_ARM_REGS_PWR
-#define __ASM_ARM_REGS_PWR __FILE__
-
-#define S3C24XX_PWRREG(x) ((x) + S3C24XX_VA_CLKPWR)
-
-#define S3C2412_PWRMODECON     S3C24XX_PWRREG(0x20)
-#define S3C2412_PWRCFG         S3C24XX_PWRREG(0x24)
-
-#define S3C2412_INFORM0                S3C24XX_PWRREG(0x70)
-#define S3C2412_INFORM1                S3C24XX_PWRREG(0x74)
-#define S3C2412_INFORM2                S3C24XX_PWRREG(0x78)
-#define S3C2412_INFORM3                S3C24XX_PWRREG(0x7C)
-
-#define S3C2412_PWRCFG_BATF_IRQ                        (1<<0)
-#define S3C2412_PWRCFG_BATF_IGNORE             (2<<0)
-#define S3C2412_PWRCFG_BATF_SLEEP              (3<<0)
-#define S3C2412_PWRCFG_BATF_MASK               (3<<0)
-
-#define S3C2412_PWRCFG_STANDBYWFI_IGNORE       (0<<6)
-#define S3C2412_PWRCFG_STANDBYWFI_IDLE         (1<<6)
-#define S3C2412_PWRCFG_STANDBYWFI_STOP         (2<<6)
-#define S3C2412_PWRCFG_STANDBYWFI_SLEEP                (3<<6)
-#define S3C2412_PWRCFG_STANDBYWFI_MASK         (3<<6)
-
-#define S3C2412_PWRCFG_RTC_MASKIRQ             (1<<8)
-#define S3C2412_PWRCFG_NAND_NORST              (1<<9)
-
-#endif /* __ASM_ARM_REGS_PWR */
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2412-mem.h b/arch/arm/mach-s3c2410/include/mach/regs-s3c2412-mem.h
deleted file mode 100644 (file)
index fb63525..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-s3c2412-mem.h
- *
- * Copyright (c) 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * S3C2412 memory register definitions
-*/
-
-#ifndef __ASM_ARM_REGS_S3C2412_MEM
-#define __ASM_ARM_REGS_S3C2412_MEM
-
-#define S3C2412_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
-#define S3C2412_EBIREG(x) (S3C2412_VA_EBI + (x))
-
-#define S3C2412_SSMCREG(x) (S3C2412_VA_SSMC + (x))
-#define S3C2412_SSMC(x, o) (S3C2412_SSMCREG((x * 0x20) + (o)))
-
-#define S3C2412_BANKCFG                        S3C2412_MEMREG(0x00)
-#define S3C2412_BANKCON1               S3C2412_MEMREG(0x04)
-#define S3C2412_BANKCON2               S3C2412_MEMREG(0x08)
-#define S3C2412_BANKCON3               S3C2412_MEMREG(0x0C)
-
-#define S3C2412_REFRESH                        S3C2412_MEMREG(0x10)
-#define S3C2412_TIMEOUT                        S3C2412_MEMREG(0x14)
-
-/* EBI control registers */
-
-#define S3C2412_EBI_PR                 S3C2412_EBIREG(0x00)
-#define S3C2412_EBI_BANKCFG            S3C2412_EBIREG(0x04)
-
-/* SSMC control registers */
-
-#define S3C2412_SSMC_BANK(x)           S3C2412_SSMC(x, 0x00)
-#define S3C2412_SMIDCYR(x)             S3C2412_SSMC(x, 0x00)
-#define S3C2412_SMBWSTRD(x)            S3C2412_SSMC(x, 0x04)
-#define S3C2412_SMBWSTWRR(x)           S3C2412_SSMC(x, 0x08)
-#define S3C2412_SMBWSTOENR(x)          S3C2412_SSMC(x, 0x0C)
-#define S3C2412_SMBWSTWENR(x)          S3C2412_SSMC(x, 0x10)
-#define S3C2412_SMBCR(x)               S3C2412_SSMC(x, 0x14)
-#define S3C2412_SMBSR(x)               S3C2412_SSMC(x, 0x18)
-#define S3C2412_SMBWSTBRDR(x)          S3C2412_SSMC(x, 0x1C)
-
-#endif /*  __ASM_ARM_REGS_S3C2412_MEM */
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2412.h b/arch/arm/mach-s3c2410/include/mach/regs-s3c2412.h
deleted file mode 100644 (file)
index aa69dc7..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-s3c2412.h
- *
- * Copyright 2007 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * S3C2412 specific register definitions
-*/
-
-#ifndef __ASM_ARCH_REGS_S3C2412_H
-#define __ASM_ARCH_REGS_S3C2412_H "s3c2412"
-
-#define S3C2412_SWRST          (S3C24XX_VA_CLKPWR + 0x30)
-#define S3C2412_SWRST_RESET    (0x533C2412)
-
-/* see regs-power.h for the other registers in the power block. */
-
-#endif /* __ASM_ARCH_REGS_S3C2412_H */
-
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2416-mem.h b/arch/arm/mach-s3c2410/include/mach/regs-s3c2416-mem.h
deleted file mode 100644 (file)
index 2f31b74..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-s3c2416-mem.h
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- *     as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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.
- *
- * S3C2416 memory register definitions
-*/
-
-#ifndef __ASM_ARM_REGS_S3C2416_MEM
-#define __ASM_ARM_REGS_S3C2416_MEM
-
-#ifndef S3C2416_MEMREG
-#define S3C2416_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
-#endif
-
-#define S3C2416_BANKCFG                        S3C2416_MEMREG(0x00)
-#define S3C2416_BANKCON1               S3C2416_MEMREG(0x04)
-#define S3C2416_BANKCON2               S3C2416_MEMREG(0x08)
-#define S3C2416_BANKCON3               S3C2416_MEMREG(0x0C)
-
-#define S3C2416_REFRESH                        S3C2416_MEMREG(0x10)
-#define S3C2416_TIMEOUT                        S3C2416_MEMREG(0x14)
-
-#endif /*  __ASM_ARM_REGS_S3C2416_MEM */
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2416.h b/arch/arm/mach-s3c2410/include/mach/regs-s3c2416.h
deleted file mode 100644 (file)
index e443167..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-s3c2416.h
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- *     as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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.
- *
- * S3C2416 specific register definitions
-*/
-
-#ifndef __ASM_ARCH_REGS_S3C2416_H
-#define __ASM_ARCH_REGS_S3C2416_H "s3c2416"
-
-#define S3C2416_SWRST          (S3C24XX_VA_CLKPWR + 0x44)
-#define S3C2416_SWRST_RESET    (0x533C2416)
-
-/* see regs-power.h for the other registers in the power block. */
-
-#endif /* __ASM_ARCH_REGS_S3C2416_H */
-
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
deleted file mode 100644 (file)
index c3feff3..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
- *
- * Copyright (c) 2007 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * S3C2443 clock register definitions
-*/
-
-#ifndef __ASM_ARM_REGS_S3C2443_CLOCK
-#define __ASM_ARM_REGS_S3C2443_CLOCK
-
-#define S3C2443_CLKREG(x)              ((x) + S3C24XX_VA_CLKPWR)
-
-#define S3C2443_PLLCON_MDIVSHIFT       16
-#define S3C2443_PLLCON_PDIVSHIFT       8
-#define S3C2443_PLLCON_SDIVSHIFT       0
-#define S3C2443_PLLCON_MDIVMASK                ((1<<(1+(23-16)))-1)
-#define S3C2443_PLLCON_PDIVMASK                ((1<<(1+(9-8)))-1)
-#define S3C2443_PLLCON_SDIVMASK                (3)
-
-#define S3C2443_MPLLCON                        S3C2443_CLKREG(0x10)
-#define S3C2443_EPLLCON                        S3C2443_CLKREG(0x18)
-#define S3C2443_CLKSRC                 S3C2443_CLKREG(0x20)
-#define S3C2443_CLKDIV0                        S3C2443_CLKREG(0x24)
-#define S3C2443_CLKDIV1                        S3C2443_CLKREG(0x28)
-#define S3C2443_HCLKCON                        S3C2443_CLKREG(0x30)
-#define S3C2443_PCLKCON                        S3C2443_CLKREG(0x34)
-#define S3C2443_SCLKCON                        S3C2443_CLKREG(0x38)
-#define S3C2443_PWRMODE                        S3C2443_CLKREG(0x40)
-#define S3C2443_SWRST                  S3C2443_CLKREG(0x44)
-#define S3C2443_BUSPRI0                        S3C2443_CLKREG(0x50)
-#define S3C2443_SYSID                  S3C2443_CLKREG(0x5C)
-#define S3C2443_PWRCFG                 S3C2443_CLKREG(0x60)
-#define S3C2443_RSTCON                 S3C2443_CLKREG(0x64)
-#define S3C2443_PHYCTRL                        S3C2443_CLKREG(0x80)
-#define S3C2443_PHYPWR                 S3C2443_CLKREG(0x84)
-#define S3C2443_URSTCON                        S3C2443_CLKREG(0x88)
-#define S3C2443_UCLKCON                        S3C2443_CLKREG(0x8C)
-
-#define S3C2443_SWRST_RESET            (0x533c2443)
-
-#define S3C2443_PLLCON_OFF             (1<<24)
-
-#define S3C2443_CLKSRC_EPLLREF_XTAL    (2<<7)
-#define S3C2443_CLKSRC_EPLLREF_EXTCLK  (3<<7)
-#define S3C2443_CLKSRC_EPLLREF_MPLLREF (0<<7)
-#define S3C2443_CLKSRC_EPLLREF_MPLLREF2        (1<<7)
-#define S3C2443_CLKSRC_EPLLREF_MASK    (3<<7)
-
-#define S3C2443_CLKSRC_EXTCLK_DIV      (1<<3)
-
-#define S3C2443_CLKDIV0_HALF_HCLK      (1<<3)
-#define S3C2443_CLKDIV0_HALF_PCLK      (1<<2)
-
-#define S3C2443_CLKDIV0_HCLKDIV_MASK   (3<<0)
-
-#define S3C2443_CLKDIV0_EXTDIV_MASK    (3<<6)
-#define S3C2443_CLKDIV0_EXTDIV_SHIFT   (6)
-
-#define S3C2443_CLKDIV0_PREDIV_MASK    (3<<4)
-#define S3C2443_CLKDIV0_PREDIV_SHIFT   (4)
-
-#define S3C2416_CLKDIV0_ARMDIV_MASK    (7 << 9)
-#define S3C2443_CLKDIV0_ARMDIV_MASK    (15<<9)
-#define S3C2443_CLKDIV0_ARMDIV_SHIFT   (9)
-#define S3C2443_CLKDIV0_ARMDIV_1       (0<<9)
-#define S3C2443_CLKDIV0_ARMDIV_2       (8<<9)
-#define S3C2443_CLKDIV0_ARMDIV_3       (2<<9)
-#define S3C2443_CLKDIV0_ARMDIV_4       (9<<9)
-#define S3C2443_CLKDIV0_ARMDIV_6       (10<<9)
-#define S3C2443_CLKDIV0_ARMDIV_8       (11<<9)
-#define S3C2443_CLKDIV0_ARMDIV_12      (13<<9)
-#define S3C2443_CLKDIV0_ARMDIV_16      (15<<9)
-
-/* S3C2443_CLKDIV1 removed, only used in clock.c code */
-
-#define S3C2443_CLKCON_NAND
-
-#define S3C2443_HCLKCON_DMA0           (1<<0)
-#define S3C2443_HCLKCON_DMA1           (1<<1)
-#define S3C2443_HCLKCON_DMA2           (1<<2)
-#define S3C2443_HCLKCON_DMA3           (1<<3)
-#define S3C2443_HCLKCON_DMA4           (1<<4)
-#define S3C2443_HCLKCON_DMA5           (1<<5)
-#define S3C2443_HCLKCON_CAMIF          (1<<8)
-#define S3C2443_HCLKCON_LCDC           (1<<9)
-#define S3C2443_HCLKCON_USBH           (1<<11)
-#define S3C2443_HCLKCON_USBD           (1<<12)
-#define S3C2416_HCLKCON_HSMMC0         (1<<15)
-#define S3C2443_HCLKCON_HSMMC          (1<<16)
-#define S3C2443_HCLKCON_CFC            (1<<17)
-#define S3C2443_HCLKCON_SSMC           (1<<18)
-#define S3C2443_HCLKCON_DRAMC          (1<<19)
-
-#define S3C2443_PCLKCON_UART0          (1<<0)
-#define S3C2443_PCLKCON_UART1          (1<<1)
-#define S3C2443_PCLKCON_UART2          (1<<2)
-#define S3C2443_PCLKCON_UART3          (1<<3)
-#define S3C2443_PCLKCON_IIC            (1<<4)
-#define S3C2443_PCLKCON_SDI            (1<<5)
-#define S3C2443_PCLKCON_HSSPI          (1<<6)
-#define S3C2443_PCLKCON_ADC            (1<<7)
-#define S3C2443_PCLKCON_AC97           (1<<8)
-#define S3C2443_PCLKCON_IIS            (1<<9)
-#define S3C2443_PCLKCON_PWMT           (1<<10)
-#define S3C2443_PCLKCON_WDT            (1<<11)
-#define S3C2443_PCLKCON_RTC            (1<<12)
-#define S3C2443_PCLKCON_GPIO           (1<<13)
-#define S3C2443_PCLKCON_SPI0           (1<<14)
-#define S3C2443_PCLKCON_SPI1           (1<<15)
-
-#define S3C2443_SCLKCON_DDRCLK         (1<<16)
-#define S3C2443_SCLKCON_SSMCCLK                (1<<15)
-#define S3C2443_SCLKCON_HSSPICLK       (1<<14)
-#define S3C2443_SCLKCON_HSMMCCLK_EXT   (1<<13)
-#define S3C2443_SCLKCON_HSMMCCLK_EPLL  (1<<12)
-#define S3C2443_SCLKCON_CAMCLK         (1<<11)
-#define S3C2443_SCLKCON_DISPCLK                (1<<10)
-#define S3C2443_SCLKCON_I2SCLK         (1<<9)
-#define S3C2443_SCLKCON_UARTCLK                (1<<8)
-#define S3C2443_SCLKCON_USBHOST                (1<<1)
-
-#define S3C2443_PWRCFG_SLEEP           (1<<15)
-
-#define S3C2443_PWRCFG_USBPHY          (1 << 4)
-
-#define S3C2443_URSTCON_FUNCRST                (1 << 2)
-#define S3C2443_URSTCON_PHYRST         (1 << 0)
-
-#define S3C2443_PHYCTRL_CLKSEL         (1 << 3)
-#define S3C2443_PHYCTRL_EXTCLK         (1 << 2)
-#define S3C2443_PHYCTRL_PLLSEL         (1 << 1)
-#define S3C2443_PHYCTRL_DSPORT         (1 << 0)
-
-#define S3C2443_PHYPWR_COMMON_ON       (1 << 31)
-#define S3C2443_PHYPWR_ANALOG_PD       (1 << 4)
-#define S3C2443_PHYPWR_PLL_REFCLK      (1 << 3)
-#define S3C2443_PHYPWR_XO_ON           (1 << 2)
-#define S3C2443_PHYPWR_PLL_PWRDN       (1 << 1)
-#define S3C2443_PHYPWR_FSUSPEND                (1 << 0)
-
-#define S3C2443_UCLKCON_DETECT_VBUS    (1 << 31)
-#define S3C2443_UCLKCON_FUNC_CLKEN     (1 << 2)
-#define S3C2443_UCLKCON_TCLKEN         (1 << 0)
-
-#include <asm/div64.h>
-
-static inline unsigned int
-s3c2443_get_mpll(unsigned int pllval, unsigned int baseclk)
-{
-       unsigned int mdiv, pdiv, sdiv;
-       uint64_t fvco;
-
-       mdiv = pllval >> S3C2443_PLLCON_MDIVSHIFT;
-       pdiv = pllval >> S3C2443_PLLCON_PDIVSHIFT;
-       sdiv = pllval >> S3C2443_PLLCON_SDIVSHIFT;
-
-       mdiv &= S3C2443_PLLCON_MDIVMASK;
-       pdiv &= S3C2443_PLLCON_PDIVMASK;
-       sdiv &= S3C2443_PLLCON_SDIVMASK;
-
-       fvco = (uint64_t)baseclk * (2 * (mdiv + 8));
-       do_div(fvco, pdiv << sdiv);
-
-       return (unsigned int)fvco;
-}
-
-static inline unsigned int
-s3c2443_get_epll(unsigned int pllval, unsigned int baseclk)
-{
-       unsigned int mdiv, pdiv, sdiv;
-       uint64_t fvco;
-
-       mdiv = pllval >> S3C2443_PLLCON_MDIVSHIFT;
-       pdiv = pllval >> S3C2443_PLLCON_PDIVSHIFT;
-       sdiv = pllval >> S3C2443_PLLCON_SDIVSHIFT;
-
-       mdiv &= S3C2443_PLLCON_MDIVMASK;
-       pdiv &= S3C2443_PLLCON_PDIVMASK;
-       sdiv &= S3C2443_PLLCON_SDIVMASK;
-
-       fvco = (uint64_t)baseclk * (mdiv + 8);
-       do_div(fvco, (pdiv + 2) << sdiv);
-
-       return (unsigned int)fvco;
-}
-
-#endif /*  __ASM_ARM_REGS_S3C2443_CLOCK */
-
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-sdi.h b/arch/arm/mach-s3c2410/include/mach/regs-sdi.h
deleted file mode 100644 (file)
index cbf2d88..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-sdi.h
- *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
- *                   http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2410 MMC/SDIO register definitions
-*/
-
-#ifndef __ASM_ARM_REGS_SDI
-#define __ASM_ARM_REGS_SDI "regs-sdi.h"
-
-#define S3C2410_SDICON                (0x00)
-#define S3C2410_SDIPRE                (0x04)
-#define S3C2410_SDICMDARG             (0x08)
-#define S3C2410_SDICMDCON             (0x0C)
-#define S3C2410_SDICMDSTAT            (0x10)
-#define S3C2410_SDIRSP0               (0x14)
-#define S3C2410_SDIRSP1               (0x18)
-#define S3C2410_SDIRSP2               (0x1C)
-#define S3C2410_SDIRSP3               (0x20)
-#define S3C2410_SDITIMER              (0x24)
-#define S3C2410_SDIBSIZE              (0x28)
-#define S3C2410_SDIDCON               (0x2C)
-#define S3C2410_SDIDCNT               (0x30)
-#define S3C2410_SDIDSTA               (0x34)
-#define S3C2410_SDIFSTA               (0x38)
-
-#define S3C2410_SDIDATA               (0x3C)
-#define S3C2410_SDIIMSK               (0x40)
-
-#define S3C2440_SDIDATA               (0x40)
-#define S3C2440_SDIIMSK               (0x3C)
-
-#define S3C2440_SDICON_SDRESET        (1<<8)
-#define S3C2440_SDICON_MMCCLOCK       (1<<5)
-#define S3C2410_SDICON_BYTEORDER      (1<<4)
-#define S3C2410_SDICON_SDIOIRQ        (1<<3)
-#define S3C2410_SDICON_RWAITEN        (1<<2)
-#define S3C2410_SDICON_FIFORESET      (1<<1)
-#define S3C2410_SDICON_CLOCKTYPE      (1<<0)
-
-#define S3C2410_SDICMDCON_ABORT       (1<<12)
-#define S3C2410_SDICMDCON_WITHDATA    (1<<11)
-#define S3C2410_SDICMDCON_LONGRSP     (1<<10)
-#define S3C2410_SDICMDCON_WAITRSP     (1<<9)
-#define S3C2410_SDICMDCON_CMDSTART    (1<<8)
-#define S3C2410_SDICMDCON_SENDERHOST  (1<<6)
-#define S3C2410_SDICMDCON_INDEX       (0x3f)
-
-#define S3C2410_SDICMDSTAT_CRCFAIL    (1<<12)
-#define S3C2410_SDICMDSTAT_CMDSENT    (1<<11)
-#define S3C2410_SDICMDSTAT_CMDTIMEOUT (1<<10)
-#define S3C2410_SDICMDSTAT_RSPFIN     (1<<9)
-#define S3C2410_SDICMDSTAT_XFERING    (1<<8)
-#define S3C2410_SDICMDSTAT_INDEX      (0xff)
-
-#define S3C2440_SDIDCON_DS_BYTE       (0<<22)
-#define S3C2440_SDIDCON_DS_HALFWORD   (1<<22)
-#define S3C2440_SDIDCON_DS_WORD       (2<<22)
-#define S3C2410_SDIDCON_IRQPERIOD     (1<<21)
-#define S3C2410_SDIDCON_TXAFTERRESP   (1<<20)
-#define S3C2410_SDIDCON_RXAFTERCMD    (1<<19)
-#define S3C2410_SDIDCON_BUSYAFTERCMD  (1<<18)
-#define S3C2410_SDIDCON_BLOCKMODE     (1<<17)
-#define S3C2410_SDIDCON_WIDEBUS       (1<<16)
-#define S3C2410_SDIDCON_DMAEN         (1<<15)
-#define S3C2410_SDIDCON_STOP          (1<<14)
-#define S3C2440_SDIDCON_DATSTART      (1<<14)
-#define S3C2410_SDIDCON_DATMODE              (3<<12)
-#define S3C2410_SDIDCON_BLKNUM        (0x7ff)
-
-/* constants for S3C2410_SDIDCON_DATMODE */
-#define S3C2410_SDIDCON_XFER_READY    (0<<12)
-#define S3C2410_SDIDCON_XFER_CHKSTART (1<<12)
-#define S3C2410_SDIDCON_XFER_RXSTART  (2<<12)
-#define S3C2410_SDIDCON_XFER_TXSTART  (3<<12)
-
-#define S3C2410_SDIDCON_BLKNUM_MASK   (0xFFF)
-#define S3C2410_SDIDCNT_BLKNUM_SHIFT  (12)
-
-#define S3C2410_SDIDSTA_RDYWAITREQ    (1<<10)
-#define S3C2410_SDIDSTA_SDIOIRQDETECT (1<<9)
-#define S3C2410_SDIDSTA_FIFOFAIL      (1<<8)   /* reserved on 2440 */
-#define S3C2410_SDIDSTA_CRCFAIL       (1<<7)
-#define S3C2410_SDIDSTA_RXCRCFAIL     (1<<6)
-#define S3C2410_SDIDSTA_DATATIMEOUT   (1<<5)
-#define S3C2410_SDIDSTA_XFERFINISH    (1<<4)
-#define S3C2410_SDIDSTA_BUSYFINISH    (1<<3)
-#define S3C2410_SDIDSTA_SBITERR       (1<<2)   /* reserved on 2410a/2440 */
-#define S3C2410_SDIDSTA_TXDATAON      (1<<1)
-#define S3C2410_SDIDSTA_RXDATAON      (1<<0)
-
-#define S3C2440_SDIFSTA_FIFORESET      (1<<16)
-#define S3C2440_SDIFSTA_FIFOFAIL       (3<<14)  /* 3 is correct (2 bits) */
-#define S3C2410_SDIFSTA_TFDET          (1<<13)
-#define S3C2410_SDIFSTA_RFDET          (1<<12)
-#define S3C2410_SDIFSTA_TFHALF         (1<<11)
-#define S3C2410_SDIFSTA_TFEMPTY        (1<<10)
-#define S3C2410_SDIFSTA_RFLAST         (1<<9)
-#define S3C2410_SDIFSTA_RFFULL         (1<<8)
-#define S3C2410_SDIFSTA_RFHALF         (1<<7)
-#define S3C2410_SDIFSTA_COUNTMASK      (0x7f)
-
-#define S3C2410_SDIIMSK_RESPONSECRC    (1<<17)
-#define S3C2410_SDIIMSK_CMDSENT        (1<<16)
-#define S3C2410_SDIIMSK_CMDTIMEOUT     (1<<15)
-#define S3C2410_SDIIMSK_RESPONSEND     (1<<14)
-#define S3C2410_SDIIMSK_READWAIT       (1<<13)
-#define S3C2410_SDIIMSK_SDIOIRQ        (1<<12)
-#define S3C2410_SDIIMSK_FIFOFAIL       (1<<11)
-#define S3C2410_SDIIMSK_CRCSTATUS      (1<<10)
-#define S3C2410_SDIIMSK_DATACRC        (1<<9)
-#define S3C2410_SDIIMSK_DATATIMEOUT    (1<<8)
-#define S3C2410_SDIIMSK_DATAFINISH     (1<<7)
-#define S3C2410_SDIIMSK_BUSYFINISH     (1<<6)
-#define S3C2410_SDIIMSK_SBITERR        (1<<5)  /* reserved 2440/2410a */
-#define S3C2410_SDIIMSK_TXFIFOHALF     (1<<4)
-#define S3C2410_SDIIMSK_TXFIFOEMPTY    (1<<3)
-#define S3C2410_SDIIMSK_RXFIFOLAST     (1<<2)
-#define S3C2410_SDIIMSK_RXFIFOFULL     (1<<1)
-#define S3C2410_SDIIMSK_RXFIFOHALF     (1<<0)
-
-#endif /* __ASM_ARM_REGS_SDI */
diff --git a/arch/arm/mach-s3c2410/include/mach/spi.h b/arch/arm/mach-s3c2410/include/mach/spi.h
deleted file mode 100644 (file)
index 4d95883..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/spi.h
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - SPI Controller platform_device info
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SPI_H
-#define __ASM_ARCH_SPI_H __FILE__
-
-struct s3c2410_spi_info {
-       int                      pin_cs;        /* simple gpio cs */
-       unsigned int             num_cs;        /* total chipselects */
-       int                      bus_num;       /* bus number to use. */
-
-       unsigned int             use_fiq:1;     /* use fiq */
-
-       void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);
-       void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
-};
-
-/* Standard setup / suspend routines for SPI GPIO pins. */
-
-extern void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
-                                                int enable);
-
-extern void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
-                                             int enable);
-
-extern void s3c24xx_spi_gpiocfg_bus1_gpd8_9_10(struct s3c2410_spi_info *spi,
-                                              int enable);
-
-#endif /* __ASM_ARCH_SPI_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/system.h b/arch/arm/mach-s3c2410/include/mach/system.h
deleted file mode 100644 (file)
index 5e215c1..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/system.h
- *
- * Copyright (c) 2003 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - System function defines and includes
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/io.h>
-#include <mach/hardware.h>
-
-#include <mach/map.h>
-#include <mach/idle.h>
-
-#include <mach/regs-clock.h>
-
-void (*s3c24xx_idle)(void);
-
-void s3c24xx_default_idle(void)
-{
-       unsigned long tmp;
-       int i;
-
-       /* idle the system by using the idle mode which will wait for an
-        * interrupt to happen before restarting the system.
-        */
-
-       /* Warning: going into idle state upsets jtag scanning */
-
-       __raw_writel(__raw_readl(S3C2410_CLKCON) | S3C2410_CLKCON_IDLE,
-                    S3C2410_CLKCON);
-
-       /* the samsung port seems to do a loop and then unset idle.. */
-       for (i = 0; i < 50; i++) {
-               tmp += __raw_readl(S3C2410_CLKCON); /* ensure loop not optimised out */
-       }
-
-       /* this bit is not cleared on re-start... */
-
-       __raw_writel(__raw_readl(S3C2410_CLKCON) & ~S3C2410_CLKCON_IDLE,
-                    S3C2410_CLKCON);
-}
-
-static void arch_idle(void)
-{
-       if (s3c24xx_idle != NULL)
-               (s3c24xx_idle)();
-       else
-               s3c24xx_default_idle();
-}
diff --git a/arch/arm/mach-s3c2410/include/mach/tick.h b/arch/arm/mach-s3c2410/include/mach/tick.h
deleted file mode 100644 (file)
index 544da41..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/include/mach/tick.h
- *
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * S3C2410 - timer tick support
- */
-
-#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0))
-
-static inline int s3c24xx_ostimer_pending(void)
-{
-       return __raw_readl(S3C2410_SRCPND) & SRCPND_TIMER4;
-}
diff --git a/arch/arm/mach-s3c2410/include/mach/timex.h b/arch/arm/mach-s3c2410/include/mach/timex.h
deleted file mode 100644 (file)
index fe9ca1f..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/timex.h
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - time parameters
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_TIMEX_H
-#define __ASM_ARCH_TIMEX_H
-
-/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it
- * a variable is useless. It seems as long as we make our timers an
- * exact multiple of HZ, any value that makes a 1->1 correspondence
- * for the time conversion functions to/from jiffies is acceptable.
-*/
-
-#define CLOCK_TICK_RATE 12000000
-
-#endif /* __ASM_ARCH_TIMEX_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/uncompress.h b/arch/arm/mach-s3c2410/include/mach/uncompress.h
deleted file mode 100644 (file)
index 8b283f8..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/uncompress.h
- *
- * Copyright (c) 2003-2007 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - uncompress code
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_UNCOMPRESS_H
-#define __ASM_ARCH_UNCOMPRESS_H
-
-#include <mach/regs-gpio.h>
-#include <mach/map.h>
-
-/* working in physical space... */
-#undef S3C2410_GPIOREG
-#define S3C2410_GPIOREG(x) ((S3C24XX_PA_GPIO + (x)))
-
-#include <plat/uncompress.h>
-
-static inline int is_arm926(void)
-{
-       unsigned int cpuid;
-
-       asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (cpuid));
-
-       return ((cpuid & 0xff0) == 0x260);
-}
-
-static void arch_detect_cpu(void)
-{
-       unsigned int cpuid;
-
-       cpuid = *((volatile unsigned int *)S3C2410_GSTATUS1);
-       cpuid &= S3C2410_GSTATUS1_IDMASK;
-
-       if (is_arm926() || cpuid == S3C2410_GSTATUS1_2440 ||
-           cpuid == S3C2410_GSTATUS1_2442 ||
-           cpuid == S3C2410_GSTATUS1_2416 ||
-           cpuid == S3C2410_GSTATUS1_2450) {
-               fifo_mask = S3C2440_UFSTAT_TXMASK;
-               fifo_max = 63 << S3C2440_UFSTAT_TXSHIFT;
-       } else {
-               fifo_mask = S3C2410_UFSTAT_TXMASK;
-               fifo_max = 15 << S3C2410_UFSTAT_TXSHIFT;
-       }
-}
-
-#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/vr1000-cpld.h b/arch/arm/mach-s3c2410/include/mach/vr1000-cpld.h
deleted file mode 100644 (file)
index e411991..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/vr1000-cpld.h
- *
- * Copyright (c) 2003 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * VR1000 - CPLD control constants
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_VR1000CPLD_H
-#define __ASM_ARCH_VR1000CPLD_H
-
-#define VR1000_CPLD_CTRL2_RAMWEN     (0x04)   /* SRAM Write Enable */
-
-#endif /* __ASM_ARCH_VR1000CPLD_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/vr1000-irq.h b/arch/arm/mach-s3c2410/include/mach/vr1000-irq.h
deleted file mode 100644 (file)
index 47add13..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/vr1000-irq.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Machine VR1000 - IRQ Number definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_VR1000IRQ_H
-#define __ASM_ARCH_VR1000IRQ_H
-
-/* irq numbers to onboard peripherals */
-
-#define IRQ_USBOC           IRQ_EINT19
-#define IRQ_IDE0            IRQ_EINT16
-#define IRQ_IDE1            IRQ_EINT17
-#define IRQ_VR1000_SERIAL    IRQ_EINT12
-#define IRQ_VR1000_DM9000A   IRQ_EINT10
-#define IRQ_VR1000_DM9000N   IRQ_EINT9
-#define IRQ_SMALERT         IRQ_EINT8
-
-#endif /* __ASM_ARCH_VR1000IRQ_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/vr1000-map.h b/arch/arm/mach-s3c2410/include/mach/vr1000-map.h
deleted file mode 100644 (file)
index 99612fc..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/vr1000-map.h
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Machine VR1000 - Memory map definitions
- *
- * 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.
-*/
-
-/* needs arch/map.h including with this */
-
-/* ok, we've used up to 0x13000000, now we need to find space for the
- * peripherals that live in the nGCS[x] areas, which are quite numerous
- * in their space. We also have the board's CPLD to find register space
- * for.
- */
-
-#ifndef __ASM_ARCH_VR1000MAP_H
-#define __ASM_ARCH_VR1000MAP_H
-
-#include <mach/bast-map.h>
-
-#define VR1000_IOADDR(x) BAST_IOADDR(x)
-
-/* we put the CPLD registers next, to get them out of the way */
-
-#define VR1000_VA_CTRL1            VR1000_IOADDR(0x00000000)    /* 0x01300000 */
-#define VR1000_PA_CTRL1            (S3C2410_CS5 | 0x7800000)
-
-#define VR1000_VA_CTRL2            VR1000_IOADDR(0x00100000)    /* 0x01400000 */
-#define VR1000_PA_CTRL2            (S3C2410_CS1 | 0x6000000)
-
-#define VR1000_VA_CTRL3            VR1000_IOADDR(0x00200000)    /* 0x01500000 */
-#define VR1000_PA_CTRL3            (S3C2410_CS1 | 0x6800000)
-
-#define VR1000_VA_CTRL4            VR1000_IOADDR(0x00300000)    /* 0x01600000 */
-#define VR1000_PA_CTRL4            (S3C2410_CS1 | 0x7000000)
-
-/* next, we have the PC104 ISA interrupt registers */
-
-#define VR1000_PA_PC104_IRQREQ  (S3C2410_CS5 | 0x6000000) /* 0x01700000 */
-#define VR1000_VA_PC104_IRQREQ  VR1000_IOADDR(0x00400000)
-
-#define VR1000_PA_PC104_IRQRAW  (S3C2410_CS5 | 0x6800000) /* 0x01800000 */
-#define VR1000_VA_PC104_IRQRAW  VR1000_IOADDR(0x00500000)
-
-#define VR1000_PA_PC104_IRQMASK (S3C2410_CS5 | 0x7000000) /* 0x01900000 */
-#define VR1000_VA_PC104_IRQMASK VR1000_IOADDR(0x00600000)
-
-/* 0xE0000000 contains the IO space that is split by speed and
- * wether the access is for 8 or 16bit IO... this ensures that
- * the correct access is made
- *
- * 0x10000000 of space, partitioned as so:
- *
- * 0x00000000 to 0x04000000  8bit,  slow
- * 0x04000000 to 0x08000000  16bit, slow
- * 0x08000000 to 0x0C000000  16bit, net
- * 0x0C000000 to 0x10000000  16bit, fast
- *
- * each of these spaces has the following in:
- *
- * 0x02000000 to 0x02100000 1MB  IDE primary channel
- * 0x02100000 to 0x02200000 1MB  IDE primary channel aux
- * 0x02200000 to 0x02400000 1MB  IDE secondary channel
- * 0x02300000 to 0x02400000 1MB  IDE secondary channel aux
- * 0x02500000 to 0x02600000 1MB  Davicom DM9000 ethernet controllers
- * 0x02600000 to 0x02700000 1MB
- *
- * the phyiscal layout of the zones are:
- *  nGCS2 - 8bit, slow
- *  nGCS3 - 16bit, slow
- *  nGCS4 - 16bit, net
- *  nGCS5 - 16bit, fast
- */
-
-#define VR1000_VA_MULTISPACE (0xE0000000)
-
-#define VR1000_VA_ISAIO                   (VR1000_VA_MULTISPACE + 0x00000000)
-#define VR1000_VA_ISAMEM          (VR1000_VA_MULTISPACE + 0x01000000)
-#define VR1000_VA_IDEPRI          (VR1000_VA_MULTISPACE + 0x02000000)
-#define VR1000_VA_IDEPRIAUX       (VR1000_VA_MULTISPACE + 0x02100000)
-#define VR1000_VA_IDESEC          (VR1000_VA_MULTISPACE + 0x02200000)
-#define VR1000_VA_IDESECAUX       (VR1000_VA_MULTISPACE + 0x02300000)
-#define VR1000_VA_ASIXNET         (VR1000_VA_MULTISPACE + 0x02400000)
-#define VR1000_VA_DM9000          (VR1000_VA_MULTISPACE + 0x02500000)
-#define VR1000_VA_SUPERIO         (VR1000_VA_MULTISPACE + 0x02600000)
-
-/* physical offset addresses for the peripherals */
-
-#define VR1000_PA_IDEPRI          (0x02000000)
-#define VR1000_PA_IDEPRIAUX       (0x02800000)
-#define VR1000_PA_IDESEC          (0x03000000)
-#define VR1000_PA_IDESECAUX       (0x03800000)
-#define VR1000_PA_DM9000          (0x05000000)
-
-#define VR1000_PA_SERIAL          (0x11800000)
-#define VR1000_VA_SERIAL          (VR1000_IOADDR(0x00700000))
-
-/* VR1000 ram is in CS1, with A26..A24 = 2_101 */
-#define VR1000_PA_SRAM            (S3C2410_CS1 | 0x05000000)
-
-/* some configurations for the peripherals */
-
-#define VR1000_DM9000_CS        VR1000_VAM_CS4
-
-#endif /* __ASM_ARCH_VR1000MAP_H */
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c
deleted file mode 100644 (file)
index 4220cc6..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-amlm5900.c
- *
- * linux/arch/arm/mach-s3c2410/mach-amlm5900.c
- *
- * Copyright (c) 2006 American Microsystems Limited
- *     David Anders <danders@amltd.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
- *
- * @History:
- * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
- * Ben Dooks <ben@simtec.co.uk>
- *
- ***********************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/proc_fs.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/flash.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <mach/fb.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/iic.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/gpio-cfg.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/physmap.h>
-
-#include "common.h"
-
-static struct resource amlm5900_nor_resource = {
-               .start = 0x00000000,
-               .end   = 0x01000000 - 1,
-               .flags = IORESOURCE_MEM,
-};
-
-
-
-static struct mtd_partition amlm5900_mtd_partitions[] = {
-       {
-               .name           = "System",
-               .size           = 0x240000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "Kernel",
-               .size           = 0x100000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .name           = "Ramdisk",
-               .size           = 0x300000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .name           = "JFFS2",
-               .size           = 0x9A0000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .name           = "Settings",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-
-static struct physmap_flash_data amlm5900_flash_data = {
-       .width          = 2,
-       .parts          = amlm5900_mtd_partitions,
-       .nr_parts       = ARRAY_SIZE(amlm5900_mtd_partitions),
-};
-
-static struct platform_device amlm5900_device_nor = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev = {
-                       .platform_data = &amlm5900_flash_data,
-               },
-       .num_resources  = 1,
-       .resource       = &amlm5900_nor_resource,
-};
-
-static struct map_desc amlm5900_iodesc[] __initdata = {
-};
-
-#define UCON S3C2410_UCON_DEFAULT
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg amlm5900_uartcfgs[] = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       }
-};
-
-
-static struct platform_device *amlm5900_devices[] __initdata = {
-#ifdef CONFIG_FB_S3C2410
-       &s3c_device_lcd,
-#endif
-       &s3c_device_adc,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_ohci,
-       &s3c_device_rtc,
-       &s3c_device_usbgadget,
-        &s3c_device_sdi,
-       &amlm5900_device_nor,
-};
-
-static void __init amlm5900_map_io(void)
-{
-       s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc));
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(amlm5900_uartcfgs, ARRAY_SIZE(amlm5900_uartcfgs));
-}
-
-#ifdef CONFIG_FB_S3C2410
-static struct s3c2410fb_display __initdata amlm5900_lcd_info = {
-       .width          = 160,
-       .height         = 160,
-
-       .type           = S3C2410_LCDCON1_STN4,
-
-       .pixclock       = 680000, /* HCLK = 100MHz */
-       .xres           = 160,
-       .yres           = 160,
-       .bpp            = 4,
-       .left_margin    = 1 << (4 + 3),
-       .right_margin   = 8 << 3,
-       .hsync_len      = 48,
-       .upper_margin   = 0,
-       .lower_margin   = 0,
-
-       .lcdcon5        = 0x00000001,
-};
-
-static struct s3c2410fb_mach_info __initdata amlm5900_fb_info = {
-
-       .displays = &amlm5900_lcd_info,
-       .num_displays = 1,
-       .default_display = 0,
-
-       .gpccon =       0xaaaaaaaa,
-       .gpccon_mask =  0xffffffff,
-       .gpcup =        0x0000ffff,
-       .gpcup_mask =   0xffffffff,
-
-       .gpdcon =       0xaaaaaaaa,
-       .gpdcon_mask =  0xffffffff,
-       .gpdup =        0x0000ffff,
-       .gpdup_mask =   0xffffffff,
-};
-#endif
-
-static irqreturn_t
-amlm5900_wake_interrupt(int irq, void *ignored)
-{
-       return IRQ_HANDLED;
-}
-
-static void amlm5900_init_pm(void)
-{
-       int ret = 0;
-
-       ret = request_irq(IRQ_EINT9, &amlm5900_wake_interrupt,
-                               IRQF_TRIGGER_RISING | IRQF_SHARED,
-                               "amlm5900_wakeup", &amlm5900_wake_interrupt);
-       if (ret != 0) {
-               printk(KERN_ERR "AML-M5900: no wakeup irq, %d?\n", ret);
-       } else {
-               enable_irq_wake(IRQ_EINT9);
-               /* configure the suspend/resume status pin */
-               s3c_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT);
-               s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_UP);
-       }
-}
-static void __init amlm5900_init(void)
-{
-       amlm5900_init_pm();
-#ifdef CONFIG_FB_S3C2410
-       s3c24xx_fb_set_platdata(&amlm5900_fb_info);
-#endif
-       s3c_i2c0_set_platdata(NULL);
-       platform_add_devices(amlm5900_devices, ARRAY_SIZE(amlm5900_devices));
-}
-
-MACHINE_START(AML_M5900, "AML_M5900")
-       .atag_offset    = 0x100,
-       .map_io         = amlm5900_map_io,
-       .init_irq       = s3c24xx_init_irq,
-       .init_machine   = amlm5900_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
deleted file mode 100644 (file)
index feeaf73..0000000
+++ /dev/null
@@ -1,645 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-bast.c
- *
- * Copyright 2003-2008 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.simtec.co.uk/products/EB2410ITX/
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/syscore_ops.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/dm9000.h>
-#include <linux/ata_platform.h>
-#include <linux/i2c.h>
-#include <linux/io.h>
-
-#include <net/ax88796.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-#include <mach/bast-cpld.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-//#include <asm/debug-ll.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-
-#include <plat/hwmon.h>
-#include <plat/nand.h>
-#include <plat/iic.h>
-#include <mach/fb.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <linux/serial_8250.h>
-
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/cpu-freq.h>
-#include <plat/gpio-cfg.h>
-#include <plat/audio-simtec.h>
-
-#include "usb-simtec.h"
-#include "nor-simtec.h"
-#include "common.h"
-
-#define COPYRIGHT ", Copyright 2004-2008 Simtec Electronics"
-
-/* macros for virtual address mods for the io space entries */
-#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
-#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
-#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
-#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
-
-/* macros to modify the physical addresses for io space */
-
-#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
-#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
-#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
-#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
-
-static struct map_desc bast_iodesc[] __initdata = {
-  /* ISA IO areas */
-  {
-         .virtual      = (u32)S3C24XX_VA_ISA_BYTE,
-         .pfn          = PA_CS2(BAST_PA_ISAIO),
-         .length       = SZ_16M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)S3C24XX_VA_ISA_WORD,
-         .pfn          = PA_CS3(BAST_PA_ISAIO),
-         .length       = SZ_16M,
-         .type         = MT_DEVICE,
-  },
-  /* bast CPLD control registers, and external interrupt controls */
-  {
-         .virtual      = (u32)BAST_VA_CTRL1,
-         .pfn          = __phys_to_pfn(BAST_PA_CTRL1),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)BAST_VA_CTRL2,
-         .pfn          = __phys_to_pfn(BAST_PA_CTRL2),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)BAST_VA_CTRL3,
-         .pfn          = __phys_to_pfn(BAST_PA_CTRL3),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)BAST_VA_CTRL4,
-         .pfn          = __phys_to_pfn(BAST_PA_CTRL4),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  },
-  /* PC104 IRQ mux */
-  {
-         .virtual      = (u32)BAST_VA_PC104_IRQREQ,
-         .pfn          = __phys_to_pfn(BAST_PA_PC104_IRQREQ),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)BAST_VA_PC104_IRQRAW,
-         .pfn          = __phys_to_pfn(BAST_PA_PC104_IRQRAW),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)BAST_VA_PC104_IRQMASK,
-         .pfn          = __phys_to_pfn(BAST_PA_PC104_IRQMASK),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  },
-
-  /* peripheral space... one for each of fast/slow/byte/16bit */
-  /* note, ide is only decoded in word space, even though some registers
-   * are only 8bit */
-
-  /* slow, byte */
-  { VA_C2(BAST_VA_ISAIO),   PA_CS2(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
-  { VA_C2(BAST_VA_ISAMEM),  PA_CS2(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C2(BAST_VA_SUPERIO), PA_CS2(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
-
-  /* slow, word */
-  { VA_C3(BAST_VA_ISAIO),   PA_CS3(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
-  { VA_C3(BAST_VA_ISAMEM),  PA_CS3(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C3(BAST_VA_SUPERIO), PA_CS3(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
-
-  /* fast, byte */
-  { VA_C4(BAST_VA_ISAIO),   PA_CS4(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
-  { VA_C4(BAST_VA_ISAMEM),  PA_CS4(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C4(BAST_VA_SUPERIO), PA_CS4(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
-
-  /* fast, word */
-  { VA_C5(BAST_VA_ISAIO),   PA_CS5(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
-  { VA_C5(BAST_VA_ISAMEM),  PA_CS5(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C5(BAST_VA_SUPERIO), PA_CS5(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       /* port 2 is not actually used */
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       }
-};
-
-/* NAND Flash on BAST board */
-
-#ifdef CONFIG_PM
-static int bast_pm_suspend(void)
-{
-       /* ensure that an nRESET is not generated on resume. */
-       gpio_direction_output(S3C2410_GPA(21), 1);
-       return 0;
-}
-
-static void bast_pm_resume(void)
-{
-       s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
-}
-
-#else
-#define bast_pm_suspend NULL
-#define bast_pm_resume NULL
-#endif
-
-static struct syscore_ops bast_pm_syscore_ops = {
-       .suspend        = bast_pm_suspend,
-       .resume         = bast_pm_resume,
-};
-
-static int smartmedia_map[] = { 0 };
-static int chip0_map[] = { 1 };
-static int chip1_map[] = { 2 };
-static int chip2_map[] = { 3 };
-
-static struct mtd_partition __initdata bast_default_nand_part[] = {
-       [0] = {
-               .name   = "Boot Agent",
-               .size   = SZ_16K,
-               .offset = 0,
-       },
-       [1] = {
-               .name   = "/boot",
-               .size   = SZ_4M - SZ_16K,
-               .offset = SZ_16K,
-       },
-       [2] = {
-               .name   = "user",
-               .offset = SZ_4M,
-               .size   = MTDPART_SIZ_FULL,
-       }
-};
-
-/* the bast has 4 selectable slots for nand-flash, the three
- * on-board chip areas, as well as the external SmartMedia
- * slot.
- *
- * Note, there is no current hot-plug support for the SmartMedia
- * socket.
-*/
-
-static struct s3c2410_nand_set __initdata bast_nand_sets[] = {
-       [0] = {
-               .name           = "SmartMedia",
-               .nr_chips       = 1,
-               .nr_map         = smartmedia_map,
-               .options        = NAND_SCAN_SILENT_NODEV,
-               .nr_partitions  = ARRAY_SIZE(bast_default_nand_part),
-               .partitions     = bast_default_nand_part,
-       },
-       [1] = {
-               .name           = "chip0",
-               .nr_chips       = 1,
-               .nr_map         = chip0_map,
-               .nr_partitions  = ARRAY_SIZE(bast_default_nand_part),
-               .partitions     = bast_default_nand_part,
-       },
-       [2] = {
-               .name           = "chip1",
-               .nr_chips       = 1,
-               .nr_map         = chip1_map,
-               .options        = NAND_SCAN_SILENT_NODEV,
-               .nr_partitions  = ARRAY_SIZE(bast_default_nand_part),
-               .partitions     = bast_default_nand_part,
-       },
-       [3] = {
-               .name           = "chip2",
-               .nr_chips       = 1,
-               .nr_map         = chip2_map,
-               .options        = NAND_SCAN_SILENT_NODEV,
-               .nr_partitions  = ARRAY_SIZE(bast_default_nand_part),
-               .partitions     = bast_default_nand_part,
-       }
-};
-
-static void bast_nand_select(struct s3c2410_nand_set *set, int slot)
-{
-       unsigned int tmp;
-
-       slot = set->nr_map[slot] & 3;
-
-       pr_debug("bast_nand: selecting slot %d (set %p,%p)\n",
-                slot, set, set->nr_map);
-
-       tmp = __raw_readb(BAST_VA_CTRL2);
-       tmp &= BAST_CPLD_CTLR2_IDERST;
-       tmp |= slot;
-       tmp |= BAST_CPLD_CTRL2_WNAND;
-
-       pr_debug("bast_nand: ctrl2 now %02x\n", tmp);
-
-       __raw_writeb(tmp, BAST_VA_CTRL2);
-}
-
-static struct s3c2410_platform_nand __initdata bast_nand_info = {
-       .tacls          = 30,
-       .twrph0         = 60,
-       .twrph1         = 60,
-       .nr_sets        = ARRAY_SIZE(bast_nand_sets),
-       .sets           = bast_nand_sets,
-       .select_chip    = bast_nand_select,
-};
-
-/* DM9000 */
-
-static struct resource bast_dm9k_resource[] = {
-       [0] = {
-               .start = S3C2410_CS5 + BAST_PA_DM9000,
-               .end   = S3C2410_CS5 + BAST_PA_DM9000 + 3,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = S3C2410_CS5 + BAST_PA_DM9000 + 0x40,
-               .end   = S3C2410_CS5 + BAST_PA_DM9000 + 0x40 + 0x3f,
-               .flags = IORESOURCE_MEM,
-       },
-       [2] = {
-               .start = IRQ_DM9000,
-               .end   = IRQ_DM9000,
-               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-       }
-
-};
-
-/* for the moment we limit ourselves to 16bit IO until some
- * better IO routines can be written and tested
-*/
-
-static struct dm9000_plat_data bast_dm9k_platdata = {
-       .flags          = DM9000_PLATF_16BITONLY,
-};
-
-static struct platform_device bast_device_dm9k = {
-       .name           = "dm9000",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(bast_dm9k_resource),
-       .resource       = bast_dm9k_resource,
-       .dev            = {
-               .platform_data = &bast_dm9k_platdata,
-       }
-};
-
-/* serial devices */
-
-#define SERIAL_BASE  (S3C2410_CS2 + BAST_PA_SUPERIO)
-#define SERIAL_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SHARE_IRQ)
-#define SERIAL_CLK   (1843200)
-
-static struct plat_serial8250_port bast_sio_data[] = {
-       [0] = {
-               .mapbase        = SERIAL_BASE + 0x2f8,
-               .irq            = IRQ_PCSERIAL1,
-               .flags          = SERIAL_FLAGS,
-               .iotype         = UPIO_MEM,
-               .regshift       = 0,
-               .uartclk        = SERIAL_CLK,
-       },
-       [1] = {
-               .mapbase        = SERIAL_BASE + 0x3f8,
-               .irq            = IRQ_PCSERIAL2,
-               .flags          = SERIAL_FLAGS,
-               .iotype         = UPIO_MEM,
-               .regshift       = 0,
-               .uartclk        = SERIAL_CLK,
-       },
-       { }
-};
-
-static struct platform_device bast_sio = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_PLATFORM,
-       .dev                    = {
-               .platform_data  = &bast_sio_data,
-       },
-};
-
-/* we have devices on the bus which cannot work much over the
- * standard 100KHz i2c bus frequency
-*/
-
-static struct s3c2410_platform_i2c __initdata bast_i2c_info = {
-       .flags          = 0,
-       .slave_addr     = 0x10,
-       .frequency      = 100*1000,
-};
-
-/* Asix AX88796 10/100 ethernet controller */
-
-static struct ax_plat_data bast_asix_platdata = {
-       .flags          = AXFLG_MAC_FROMDEV,
-       .wordlength     = 2,
-       .dcr_val        = 0x48,
-       .rcr_val        = 0x40,
-};
-
-static struct resource bast_asix_resource[] = {
-       [0] = {
-               .start = S3C2410_CS5 + BAST_PA_ASIXNET,
-               .end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20) - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
-               .end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
-               .flags = IORESOURCE_MEM,
-       },
-       [2] = {
-               .start = IRQ_ASIX,
-               .end   = IRQ_ASIX,
-               .flags = IORESOURCE_IRQ
-       }
-};
-
-static struct platform_device bast_device_asix = {
-       .name           = "ax88796",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(bast_asix_resource),
-       .resource       = bast_asix_resource,
-       .dev            = {
-               .platform_data = &bast_asix_platdata
-       }
-};
-
-/* Asix AX88796 10/100 ethernet controller parallel port */
-
-static struct resource bast_asixpp_resource[] = {
-       [0] = {
-               .start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20),
-               .end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1b * 0x20) - 1,
-               .flags = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device bast_device_axpp = {
-       .name           = "ax88796-pp",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(bast_asixpp_resource),
-       .resource       = bast_asixpp_resource,
-};
-
-/* LCD/VGA controller */
-
-static struct s3c2410fb_display __initdata bast_lcd_info[] = {
-       {
-               .type           = S3C2410_LCDCON1_TFT,
-               .width          = 640,
-               .height         = 480,
-
-               .pixclock       = 33333,
-               .xres           = 640,
-               .yres           = 480,
-               .bpp            = 4,
-               .left_margin    = 40,
-               .right_margin   = 20,
-               .hsync_len      = 88,
-               .upper_margin   = 30,
-               .lower_margin   = 32,
-               .vsync_len      = 3,
-
-               .lcdcon5        = 0x00014b02,
-       },
-       {
-               .type           = S3C2410_LCDCON1_TFT,
-               .width          = 640,
-               .height         = 480,
-
-               .pixclock       = 33333,
-               .xres           = 640,
-               .yres           = 480,
-               .bpp            = 8,
-               .left_margin    = 40,
-               .right_margin   = 20,
-               .hsync_len      = 88,
-               .upper_margin   = 30,
-               .lower_margin   = 32,
-               .vsync_len      = 3,
-
-               .lcdcon5        = 0x00014b02,
-       },
-       {
-               .type           = S3C2410_LCDCON1_TFT,
-               .width          = 640,
-               .height         = 480,
-
-               .pixclock       = 33333,
-               .xres           = 640,
-               .yres           = 480,
-               .bpp            = 16,
-               .left_margin    = 40,
-               .right_margin   = 20,
-               .hsync_len      = 88,
-               .upper_margin   = 30,
-               .lower_margin   = 32,
-               .vsync_len      = 3,
-
-               .lcdcon5        = 0x00014b02,
-       },
-};
-
-/* LCD/VGA controller */
-
-static struct s3c2410fb_mach_info __initdata bast_fb_info = {
-
-       .displays = bast_lcd_info,
-       .num_displays = ARRAY_SIZE(bast_lcd_info),
-       .default_display = 1,
-};
-
-/* I2C devices fitted. */
-
-static struct i2c_board_info bast_i2c_devs[] __initdata = {
-       {
-               I2C_BOARD_INFO("tlv320aic23", 0x1a),
-       }, {
-               I2C_BOARD_INFO("simtec-pmu", 0x6b),
-       }, {
-               I2C_BOARD_INFO("ch7013", 0x75),
-       },
-};
-
-static struct s3c_hwmon_pdata bast_hwmon_info = {
-       /* LCD contrast (0-6.6V) */
-       .in[0] = &(struct s3c_hwmon_chcfg) {
-               .name           = "lcd-contrast",
-               .mult           = 3300,
-               .div            = 512,
-       },
-       /* LED current feedback */
-       .in[1] = &(struct s3c_hwmon_chcfg) {
-               .name           = "led-feedback",
-               .mult           = 3300,
-               .div            = 1024,
-       },
-       /* LCD feedback (0-6.6V) */
-       .in[2] = &(struct s3c_hwmon_chcfg) {
-               .name           = "lcd-feedback",
-               .mult           = 3300,
-               .div            = 512,
-       },
-       /* Vcore (1.8-2.0V), Vref 3.3V  */
-       .in[3] = &(struct s3c_hwmon_chcfg) {
-               .name           = "vcore",
-               .mult           = 3300,
-               .div            = 1024,
-       },
-};
-
-/* Standard BAST devices */
-// cat /sys/devices/platform/s3c24xx-adc/s3c-hwmon/in_0
-
-static struct platform_device *bast_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_rtc,
-       &s3c_device_nand,
-       &s3c_device_adc,
-       &s3c_device_hwmon,
-       &bast_device_dm9k,
-       &bast_device_asix,
-       &bast_device_axpp,
-       &bast_sio,
-};
-
-static struct clk *bast_clocks[] __initdata = {
-       &s3c24xx_dclk0,
-       &s3c24xx_dclk1,
-       &s3c24xx_clkout0,
-       &s3c24xx_clkout1,
-       &s3c24xx_uclk,
-};
-
-static struct s3c_cpufreq_board __initdata bast_cpufreq = {
-       .refresh        = 7800, /* 7.8usec */
-       .auto_io        = 1,
-       .need_io        = 1,
-};
-
-static struct s3c24xx_audio_simtec_pdata __initdata bast_audio = {
-       .have_mic       = 1,
-       .have_lout      = 1,
-};
-
-static void __init bast_map_io(void)
-{
-       /* initialise the clocks */
-
-       s3c24xx_dclk0.parent = &clk_upll;
-       s3c24xx_dclk0.rate   = 12*1000*1000;
-
-       s3c24xx_dclk1.parent = &clk_upll;
-       s3c24xx_dclk1.rate   = 24*1000*1000;
-
-       s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
-       s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
-
-       s3c24xx_uclk.parent  = &s3c24xx_clkout1;
-
-       s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks));
-
-       s3c_hwmon_set_platdata(&bast_hwmon_info);
-
-       s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs));
-}
-
-static void __init bast_init(void)
-{
-       register_syscore_ops(&bast_pm_syscore_ops);
-
-       s3c_i2c0_set_platdata(&bast_i2c_info);
-       s3c_nand_set_platdata(&bast_nand_info);
-       s3c24xx_fb_set_platdata(&bast_fb_info);
-       platform_add_devices(bast_devices, ARRAY_SIZE(bast_devices));
-
-       i2c_register_board_info(0, bast_i2c_devs,
-                               ARRAY_SIZE(bast_i2c_devs));
-
-       usb_simtec_init();
-       nor_simtec_init();
-       simtec_audio_add(NULL, true, &bast_audio);
-
-       WARN_ON(gpio_request(S3C2410_GPA(21), "bast nreset"));
-       
-       s3c_cpufreq_setboard(&bast_cpufreq);
-}
-
-MACHINE_START(BAST, "Simtec-BAST")
-       /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .atag_offset    = 0x100,
-       .map_io         = bast_map_io,
-       .init_irq       = s3c24xx_init_irq,
-       .init_machine   = bast_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
deleted file mode 100644 (file)
index 41245a6..0000000
+++ /dev/null
@@ -1,757 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-h1940.c
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.handhelds.org/projects/h1940.html
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/memblock.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
-#include <linux/pwm_backlight.h>
-#include <linux/i2c.h>
-#include <linux/leds.h>
-#include <linux/pda_power.h>
-#include <linux/s3c_adc_battery.h>
-#include <linux/delay.h>
-
-#include <video/platform_lcd.h>
-
-#include <linux/mmc/host.h>
-#include <linux/export.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-clock.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/gpio-fns.h>
-#include <mach/gpio-nrs.h>
-
-#include <mach/h1940.h>
-#include <mach/h1940-latch.h>
-#include <mach/fb.h>
-#include <plat/udc.h>
-#include <plat/iic.h>
-
-#include <plat/gpio-cfg.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pll.h>
-#include <plat/pm.h>
-#include <plat/mci.h>
-#include <plat/ts.h>
-
-#include <sound/uda1380.h>
-
-#include "common.h"
-
-#define H1940_LATCH            ((void __force __iomem *)0xF8000000)
-
-#define H1940_PA_LATCH         S3C2410_CS2
-
-#define H1940_LATCH_BIT(x)     (1 << ((x) + 16 - S3C_GPIO_END))
-
-static struct map_desc h1940_iodesc[] __initdata = {
-       [0] = {
-               .virtual        = (unsigned long)H1940_LATCH,
-               .pfn            = __phys_to_pfn(H1940_PA_LATCH),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE
-       },
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg h1940_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = 0x245,
-               .ulcon       = 0x03,
-               .ufcon       = 0x00,
-       },
-       /* IR port */
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .uart_flags  = UPF_CONS_FLOW,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x43,
-               .ufcon       = 0x51,
-       }
-};
-
-/* Board control latch control */
-
-static unsigned int latch_state;
-
-static void h1940_latch_control(unsigned int clear, unsigned int set)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       latch_state &= ~clear;
-       latch_state |= set;
-
-       __raw_writel(latch_state, H1940_LATCH);
-
-       local_irq_restore(flags);
-}
-
-static inline int h1940_gpiolib_to_latch(int offset)
-{
-       return 1 << (offset + 16);
-}
-
-static void h1940_gpiolib_latch_set(struct gpio_chip *chip,
-                                       unsigned offset, int value)
-{
-       int latch_bit = h1940_gpiolib_to_latch(offset);
-
-       h1940_latch_control(value ? 0 : latch_bit,
-               value ? latch_bit : 0);
-}
-
-static int h1940_gpiolib_latch_output(struct gpio_chip *chip,
-                                       unsigned offset, int value)
-{
-       h1940_gpiolib_latch_set(chip, offset, value);
-       return 0;
-}
-
-static int h1940_gpiolib_latch_get(struct gpio_chip *chip,
-                                       unsigned offset)
-{
-       return (latch_state >> (offset + 16)) & 1;
-}
-
-struct gpio_chip h1940_latch_gpiochip = {
-       .base                   = H1940_LATCH_GPIO(0),
-       .owner                  = THIS_MODULE,
-       .label                  = "H1940_LATCH",
-       .ngpio                  = 16,
-       .direction_output       = h1940_gpiolib_latch_output,
-       .set                    = h1940_gpiolib_latch_set,
-       .get                    = h1940_gpiolib_latch_get,
-};
-
-static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
-       .vbus_pin               = S3C2410_GPG(5),
-       .vbus_pin_inverted      = 1,
-       .pullup_pin             = H1940_LATCH_USB_DP,
-};
-
-static struct s3c2410_ts_mach_info h1940_ts_cfg __initdata = {
-               .delay = 10000,
-               .presc = 49,
-               .oversampling_shift = 2,
-               .cfg_gpio = s3c24xx_ts_cfg_gpio,
-};
-
-/**
- * Set lcd on or off
- **/
-static struct s3c2410fb_display h1940_lcd __initdata = {
-       .lcdcon5=       S3C2410_LCDCON5_FRM565 | \
-                       S3C2410_LCDCON5_INVVLINE | \
-                       S3C2410_LCDCON5_HWSWP,
-
-       .type =         S3C2410_LCDCON1_TFT,
-       .width =        240,
-       .height =       320,
-       .pixclock =     260000,
-       .xres =         240,
-       .yres =         320,
-       .bpp =          16,
-       .left_margin =  8,
-       .right_margin = 20,
-       .hsync_len =    4,
-       .upper_margin = 8,
-       .lower_margin = 7,
-       .vsync_len =    1,
-};
-
-static struct s3c2410fb_mach_info h1940_fb_info __initdata = {
-       .displays = &h1940_lcd,
-       .num_displays = 1,
-       .default_display = 0,
-
-       .lpcsel =       0x02,
-       .gpccon =       0xaa940659,
-       .gpccon_mask =  0xffffc0f0,
-       .gpcup =        0x0000ffff,
-       .gpcup_mask =   0xffffffff,
-       .gpdcon =       0xaa84aaa0,
-       .gpdcon_mask =  0xffffffff,
-       .gpdup =        0x0000faff,
-       .gpdup_mask =   0xffffffff,
-};
-
-static int power_supply_init(struct device *dev)
-{
-       return gpio_request(S3C2410_GPF(2), "cable plugged");
-}
-
-static int h1940_is_ac_online(void)
-{
-       return !gpio_get_value(S3C2410_GPF(2));
-}
-
-static void power_supply_exit(struct device *dev)
-{
-       gpio_free(S3C2410_GPF(2));
-}
-
-static char *h1940_supplicants[] = {
-       "main-battery",
-       "backup-battery",
-};
-
-static struct pda_power_pdata power_supply_info = {
-       .init                   = power_supply_init,
-       .is_ac_online           = h1940_is_ac_online,
-       .exit                   = power_supply_exit,
-       .supplied_to            = h1940_supplicants,
-       .num_supplicants        = ARRAY_SIZE(h1940_supplicants),
-};
-
-static struct resource power_supply_resources[] = {
-       [0] = {
-                       .name   = "ac",
-                       .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
-                                         IORESOURCE_IRQ_HIGHEDGE,
-                       .start  = IRQ_EINT2,
-                       .end    = IRQ_EINT2,
-       },
-};
-
-static struct platform_device power_supply = {
-       .name           = "pda-power",
-       .id             = -1,
-       .dev            = {
-                               .platform_data =
-                                       &power_supply_info,
-       },
-       .resource       = power_supply_resources,
-       .num_resources  = ARRAY_SIZE(power_supply_resources),
-};
-
-static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
-       { .volt = 4070, .cur = 162, .level = 100},
-       { .volt = 4040, .cur = 165, .level = 95},
-       { .volt = 4016, .cur = 164, .level = 90},
-       { .volt = 3996, .cur = 166, .level = 85},
-       { .volt = 3971, .cur = 168, .level = 80},
-       { .volt = 3951, .cur = 168, .level = 75},
-       { .volt = 3931, .cur = 170, .level = 70},
-       { .volt = 3903, .cur = 172, .level = 65},
-       { .volt = 3886, .cur = 172, .level = 60},
-       { .volt = 3858, .cur = 176, .level = 55},
-       { .volt = 3842, .cur = 176, .level = 50},
-       { .volt = 3818, .cur = 176, .level = 45},
-       { .volt = 3789, .cur = 180, .level = 40},
-       { .volt = 3769, .cur = 180, .level = 35},
-       { .volt = 3749, .cur = 184, .level = 30},
-       { .volt = 3732, .cur = 184, .level = 25},
-       { .volt = 3716, .cur = 184, .level = 20},
-       { .volt = 3708, .cur = 184, .level = 15},
-       { .volt = 3716, .cur = 96, .level = 10},
-       { .volt = 3700, .cur = 96, .level = 5},
-       { .volt = 3684, .cur = 96, .level = 0},
-};
-
-static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
-       { .volt = 4130, .cur = 0, .level = 100},
-       { .volt = 3982, .cur = 0, .level = 50},
-       { .volt = 3854, .cur = 0, .level = 10},
-       { .volt = 3841, .cur = 0, .level = 0},
-};
-
-int h1940_bat_init(void)
-{
-       int ret;
-
-       ret = gpio_request(H1940_LATCH_SM803_ENABLE, "h1940-charger-enable");
-       if (ret)
-               return ret;
-       gpio_direction_output(H1940_LATCH_SM803_ENABLE, 0);
-
-       return 0;
-
-}
-
-void h1940_bat_exit(void)
-{
-       gpio_free(H1940_LATCH_SM803_ENABLE);
-}
-
-void h1940_enable_charger(void)
-{
-       gpio_set_value(H1940_LATCH_SM803_ENABLE, 1);
-}
-
-void h1940_disable_charger(void)
-{
-       gpio_set_value(H1940_LATCH_SM803_ENABLE, 0);
-}
-
-static struct s3c_adc_bat_pdata h1940_bat_cfg = {
-       .init = h1940_bat_init,
-       .exit = h1940_bat_exit,
-       .enable_charger = h1940_enable_charger,
-       .disable_charger = h1940_disable_charger,
-       .gpio_charge_finished = S3C2410_GPF(3),
-       .gpio_inverted = 1,
-       .lut_noac = bat_lut_noac,
-       .lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
-       .lut_acin = bat_lut_acin,
-       .lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
-       .volt_channel = 0,
-       .current_channel = 1,
-       .volt_mult = 4056,
-       .current_mult = 1893,
-       .internal_impedance = 200,
-       .backup_volt_channel = 3,
-       /* TODO Check backup volt multiplier */
-       .backup_volt_mult = 4056,
-       .backup_volt_min = 0,
-       .backup_volt_max = 4149288
-};
-
-static struct platform_device h1940_battery = {
-       .name             = "s3c-adc-battery",
-       .id               = -1,
-       .dev = {
-               .parent = &s3c_device_adc.dev,
-               .platform_data = &h1940_bat_cfg,
-       },
-};
-
-DEFINE_SPINLOCK(h1940_blink_spin);
-
-int h1940_led_blink_set(unsigned gpio, int state,
-       unsigned long *delay_on, unsigned long *delay_off)
-{
-       int blink_gpio, check_gpio1, check_gpio2;
-
-       switch (gpio) {
-       case H1940_LATCH_LED_GREEN:
-               blink_gpio = S3C2410_GPA(7);
-               check_gpio1 = S3C2410_GPA(1);
-               check_gpio2 = S3C2410_GPA(3);
-               break;
-       case H1940_LATCH_LED_RED:
-               blink_gpio = S3C2410_GPA(1);
-               check_gpio1 = S3C2410_GPA(7);
-               check_gpio2 = S3C2410_GPA(3);
-               break;
-       default:
-               blink_gpio = S3C2410_GPA(3);
-               check_gpio1 = S3C2410_GPA(1);
-               check_gpio1 = S3C2410_GPA(7);
-               break;
-       }
-
-       if (delay_on && delay_off && !*delay_on && !*delay_off)
-               *delay_on = *delay_off = 500;
-
-       spin_lock(&h1940_blink_spin);
-
-       switch (state) {
-       case GPIO_LED_NO_BLINK_LOW:
-       case GPIO_LED_NO_BLINK_HIGH:
-               if (!gpio_get_value(check_gpio1) &&
-                   !gpio_get_value(check_gpio2))
-                       gpio_set_value(H1940_LATCH_LED_FLASH, 0);
-               gpio_set_value(blink_gpio, 0);
-               if (gpio_is_valid(gpio))
-                       gpio_set_value(gpio, state);
-               break;
-       case GPIO_LED_BLINK:
-               if (gpio_is_valid(gpio))
-                       gpio_set_value(gpio, 0);
-               gpio_set_value(H1940_LATCH_LED_FLASH, 1);
-               gpio_set_value(blink_gpio, 1);
-               break;
-       }
-
-       spin_unlock(&h1940_blink_spin);
-
-       return 0;
-}
-EXPORT_SYMBOL(h1940_led_blink_set);
-
-static struct gpio_led h1940_leds_desc[] = {
-       {
-               .name                   = "Green",
-               .default_trigger        = "main-battery-full",
-               .gpio                   = H1940_LATCH_LED_GREEN,
-               .retain_state_suspended = 1,
-       },
-       {
-               .name                   = "Red",
-               .default_trigger
-                       = "main-battery-charging-blink-full-solid",
-               .gpio                   = H1940_LATCH_LED_RED,
-               .retain_state_suspended = 1,
-       },
-};
-
-static struct gpio_led_platform_data h1940_leds_pdata = {
-       .num_leds       = ARRAY_SIZE(h1940_leds_desc),
-       .leds           = h1940_leds_desc,
-       .gpio_blink_set = h1940_led_blink_set,
-};
-
-static struct platform_device h1940_device_leds = {
-       .name   = "leds-gpio",
-       .id     = -1,
-       .dev    = {
-                       .platform_data = &h1940_leds_pdata,
-       },
-};
-
-static struct platform_device h1940_device_bluetooth = {
-       .name             = "h1940-bt",
-       .id               = -1,
-};
-
-static void h1940_set_mmc_power(unsigned char power_mode, unsigned short vdd)
-{
-       switch (power_mode) {
-       case MMC_POWER_OFF:
-               gpio_set_value(H1940_LATCH_SD_POWER, 0);
-               break;
-       case MMC_POWER_UP:
-       case MMC_POWER_ON:
-               gpio_set_value(H1940_LATCH_SD_POWER, 1);
-               break;
-       default:
-               break;
-       };
-}
-
-static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = {
-       .gpio_detect   = S3C2410_GPF(5),
-       .gpio_wprotect = S3C2410_GPH(8),
-       .set_power     = h1940_set_mmc_power,
-       .ocr_avail     = MMC_VDD_32_33,
-};
-
-static int h1940_backlight_init(struct device *dev)
-{
-       gpio_request(S3C2410_GPB(0), "Backlight");
-
-       gpio_direction_output(S3C2410_GPB(0), 0);
-       s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE);
-       s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
-       gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1);
-
-       return 0;
-}
-
-static int h1940_backlight_notify(struct device *dev, int brightness)
-{
-       if (!brightness) {
-               gpio_direction_output(S3C2410_GPB(0), 1);
-               gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
-       } else {
-               gpio_direction_output(S3C2410_GPB(0), 0);
-               s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE);
-               s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
-               gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1);
-       }
-       return brightness;
-}
-
-static void h1940_backlight_exit(struct device *dev)
-{
-       gpio_direction_output(S3C2410_GPB(0), 1);
-       gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
-}
-
-
-static struct platform_pwm_backlight_data backlight_data = {
-       .pwm_id         = 0,
-       .max_brightness = 100,
-       .dft_brightness = 50,
-       /* tcnt = 0x31 */
-       .pwm_period_ns  = 36296,
-       .init           = h1940_backlight_init,
-       .notify         = h1940_backlight_notify,
-       .exit           = h1940_backlight_exit,
-};
-
-static struct platform_device h1940_backlight = {
-       .name = "pwm-backlight",
-       .dev  = {
-               .parent = &s3c_device_timer[0].dev,
-               .platform_data = &backlight_data,
-       },
-       .id   = -1,
-};
-
-static void h1940_lcd_power_set(struct plat_lcd_data *pd,
-                                       unsigned int power)
-{
-       int value, retries = 100;
-
-       if (!power) {
-               gpio_set_value(S3C2410_GPC(0), 0);
-               /* wait for 3ac */
-               do {
-                       value = gpio_get_value(S3C2410_GPC(6));
-               } while (value && retries--);
-
-               gpio_set_value(H1940_LATCH_LCD_P2, 0);
-               gpio_set_value(H1940_LATCH_LCD_P3, 0);
-               gpio_set_value(H1940_LATCH_LCD_P4, 0);
-
-               gpio_direction_output(S3C2410_GPC(1), 0);
-               gpio_direction_output(S3C2410_GPC(4), 0);
-
-               gpio_set_value(H1940_LATCH_LCD_P1, 0);
-               gpio_set_value(H1940_LATCH_LCD_P0, 0);
-
-               gpio_set_value(S3C2410_GPC(5), 0);
-
-       } else {
-               gpio_set_value(H1940_LATCH_LCD_P0, 1);
-               gpio_set_value(H1940_LATCH_LCD_P1, 1);
-
-               gpio_direction_input(S3C2410_GPC(1));
-               gpio_direction_input(S3C2410_GPC(4));
-               mdelay(10);
-               s3c_gpio_cfgpin(S3C2410_GPC(1), S3C_GPIO_SFN(2));
-               s3c_gpio_cfgpin(S3C2410_GPC(4), S3C_GPIO_SFN(2));
-
-               gpio_set_value(S3C2410_GPC(5), 1);
-               gpio_set_value(S3C2410_GPC(0), 1);
-
-               gpio_set_value(H1940_LATCH_LCD_P3, 1);
-               gpio_set_value(H1940_LATCH_LCD_P2, 1);
-               gpio_set_value(H1940_LATCH_LCD_P4, 1);
-       }
-}
-
-static struct plat_lcd_data h1940_lcd_power_data = {
-       .set_power      = h1940_lcd_power_set,
-};
-
-static struct platform_device h1940_lcd_powerdev = {
-       .name                   = "platform-lcd",
-       .dev.parent             = &s3c_device_lcd.dev,
-       .dev.platform_data      = &h1940_lcd_power_data,
-};
-
-static struct uda1380_platform_data uda1380_info = {
-       .gpio_power     = H1940_LATCH_UDA_POWER,
-       .gpio_reset     = S3C2410_GPA(12),
-       .dac_clk        = UDA1380_DAC_CLK_SYSCLK,
-};
-
-static struct i2c_board_info h1940_i2c_devices[] = {
-       {
-               I2C_BOARD_INFO("uda1380", 0x1a),
-               .platform_data = &uda1380_info,
-       },
-};
-
-#define DECLARE_BUTTON(p, k, n, w)     \
-       {                               \
-               .gpio           = p,    \
-               .code           = k,    \
-               .desc           = n,    \
-               .wakeup         = w,    \
-               .active_low     = 1,    \
-       }
-
-static struct gpio_keys_button h1940_buttons[] = {
-       DECLARE_BUTTON(S3C2410_GPF(0),       KEY_POWER,          "Power", 1),
-       DECLARE_BUTTON(S3C2410_GPF(6),       KEY_ENTER,         "Select", 1),
-       DECLARE_BUTTON(S3C2410_GPF(7),      KEY_RECORD,         "Record", 0),
-       DECLARE_BUTTON(S3C2410_GPG(0),         KEY_F11,       "Calendar", 0),
-       DECLARE_BUTTON(S3C2410_GPG(2),         KEY_F12,       "Contacts", 0),
-       DECLARE_BUTTON(S3C2410_GPG(3),        KEY_MAIL,           "Mail", 0),
-       DECLARE_BUTTON(S3C2410_GPG(6),        KEY_LEFT,     "Left_arrow", 0),
-       DECLARE_BUTTON(S3C2410_GPG(7),    KEY_HOMEPAGE,           "Home", 0),
-       DECLARE_BUTTON(S3C2410_GPG(8),       KEY_RIGHT,    "Right_arrow", 0),
-       DECLARE_BUTTON(S3C2410_GPG(9),          KEY_UP,       "Up_arrow", 0),
-       DECLARE_BUTTON(S3C2410_GPG(10),       KEY_DOWN,     "Down_arrow", 0),
-};
-
-static struct gpio_keys_platform_data h1940_buttons_data = {
-       .buttons        = h1940_buttons,
-       .nbuttons       = ARRAY_SIZE(h1940_buttons),
-};
-
-static struct platform_device h1940_dev_buttons = {
-       .name           = "gpio-keys",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &h1940_buttons_data,
-       }
-};
-
-static struct platform_device *h1940_devices[] __initdata = {
-       &h1940_dev_buttons,
-       &s3c_device_ohci,
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-       &samsung_asoc_dma,
-       &s3c_device_usbgadget,
-       &h1940_device_leds,
-       &h1940_device_bluetooth,
-       &s3c_device_sdi,
-       &s3c_device_rtc,
-       &s3c_device_timer[0],
-       &h1940_backlight,
-       &h1940_lcd_powerdev,
-       &s3c_device_adc,
-       &s3c_device_ts,
-       &power_supply,
-       &h1940_battery,
-};
-
-static void __init h1940_map_io(void)
-{
-       s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc));
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs));
-
-       /* setup PM */
-
-#ifdef CONFIG_PM_H1940
-       memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 1024);
-#endif
-       s3c_pm_init();
-
-       /* Add latch gpio chip, set latch initial value */
-       h1940_latch_control(0, 0);
-       WARN_ON(gpiochip_add(&h1940_latch_gpiochip));
-}
-
-/* H1940 and RX3715 need to reserve this for suspend */
-static void __init h1940_reserve(void)
-{
-       memblock_reserve(0x30003000, 0x1000);
-       memblock_reserve(0x30081000, 0x1000);
-}
-
-static void __init h1940_init_irq(void)
-{
-       s3c24xx_init_irq();
-}
-
-static void __init h1940_init(void)
-{
-       u32 tmp;
-
-       s3c24xx_fb_set_platdata(&h1940_fb_info);
-       s3c24xx_mci_set_platdata(&h1940_mmc_cfg);
-       s3c24xx_udc_set_platdata(&h1940_udc_cfg);
-       s3c24xx_ts_set_platdata(&h1940_ts_cfg);
-       s3c_i2c0_set_platdata(NULL);
-
-       /* Turn off suspend on both USB ports, and switch the
-        * selectable USB port to USB device mode. */
-
-       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
-                             S3C2410_MISCCR_USBSUSPND0 |
-                             S3C2410_MISCCR_USBSUSPND1, 0x0);
-
-       tmp =   (0x78 << S3C24XX_PLL_MDIV_SHIFT)
-             | (0x02 << S3C24XX_PLL_PDIV_SHIFT)
-             | (0x03 << S3C24XX_PLL_SDIV_SHIFT);
-       writel(tmp, S3C2410_UPLLCON);
-
-       gpio_request(S3C2410_GPC(0), "LCD power");
-       gpio_request(S3C2410_GPC(1), "LCD power");
-       gpio_request(S3C2410_GPC(4), "LCD power");
-       gpio_request(S3C2410_GPC(5), "LCD power");
-       gpio_request(S3C2410_GPC(6), "LCD power");
-       gpio_request(H1940_LATCH_LCD_P0, "LCD power");
-       gpio_request(H1940_LATCH_LCD_P1, "LCD power");
-       gpio_request(H1940_LATCH_LCD_P2, "LCD power");
-       gpio_request(H1940_LATCH_LCD_P3, "LCD power");
-       gpio_request(H1940_LATCH_LCD_P4, "LCD power");
-       gpio_request(H1940_LATCH_MAX1698_nSHUTDOWN, "LCD power");
-       gpio_direction_output(S3C2410_GPC(0), 0);
-       gpio_direction_output(S3C2410_GPC(1), 0);
-       gpio_direction_output(S3C2410_GPC(4), 0);
-       gpio_direction_output(S3C2410_GPC(5), 0);
-       gpio_direction_input(S3C2410_GPC(6));
-       gpio_direction_output(H1940_LATCH_LCD_P0, 0);
-       gpio_direction_output(H1940_LATCH_LCD_P1, 0);
-       gpio_direction_output(H1940_LATCH_LCD_P2, 0);
-       gpio_direction_output(H1940_LATCH_LCD_P3, 0);
-       gpio_direction_output(H1940_LATCH_LCD_P4, 0);
-       gpio_direction_output(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
-
-       gpio_request(H1940_LATCH_SD_POWER, "SD power");
-       gpio_direction_output(H1940_LATCH_SD_POWER, 0);
-
-       platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
-
-       gpio_request(S3C2410_GPA(1), "Red LED blink");
-       gpio_request(S3C2410_GPA(3), "Blue LED blink");
-       gpio_request(S3C2410_GPA(7), "Green LED blink");
-       gpio_request(H1940_LATCH_LED_FLASH, "LED blink");
-       gpio_direction_output(S3C2410_GPA(1), 0);
-       gpio_direction_output(S3C2410_GPA(3), 0);
-       gpio_direction_output(S3C2410_GPA(7), 0);
-       gpio_direction_output(H1940_LATCH_LED_FLASH, 0);
-
-       i2c_register_board_info(0, h1940_i2c_devices,
-               ARRAY_SIZE(h1940_i2c_devices));
-}
-
-MACHINE_START(H1940, "IPAQ-H1940")
-       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .atag_offset    = 0x100,
-       .map_io         = h1940_map_io,
-       .reserve        = h1940_reserve,
-       .init_irq       = h1940_init_irq,
-       .init_machine   = h1940_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
deleted file mode 100644 (file)
index 383d00c..0000000
+++ /dev/null
@@ -1,608 +0,0 @@
-/* Machine specific code for the Acer n30, Acer N35, Navman PiN 570,
- * Yakumo AlphaX and Airis NC05 PDAs.
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Copyright (c) 2005-2008 Christer Weinigel <christer@weinigel.se>
- *
- * There is a wiki with more information about the n30 port at
- * http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
- *
- * 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/types.h>
-
-#include <linux/gpio_keys.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/timer.h>
-#include <linux/io.h>
-#include <linux/mmc/host.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <mach/fb.h>
-#include <mach/leds-gpio.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-lcd.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/map.h>
-
-#include <plat/iic.h>
-#include <plat/regs-serial.h>
-
-#include <plat/clock.h>
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/mci.h>
-#include <plat/s3c2410.h>
-#include <plat/udc.h>
-
-#include "common.h"
-
-static struct map_desc n30_iodesc[] __initdata = {
-       /* nothing here yet */
-};
-
-static struct s3c2410_uartcfg n30_uartcfgs[] = {
-       /* Normal serial port */
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = 0x2c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-       /* IR port */
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .uart_flags  = UPF_CONS_FLOW,
-               .ucon        = 0x2c5,
-               .ulcon       = 0x43,
-               .ufcon       = 0x51,
-       },
-       /* On the N30 the bluetooth controller is connected here.
-        * On the N35 and variants the GPS receiver is connected here. */
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = 0x2c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-};
-
-static struct s3c2410_udc_mach_info n30_udc_cfg __initdata = {
-       .vbus_pin               = S3C2410_GPG(1),
-       .vbus_pin_inverted      = 0,
-       .pullup_pin             = S3C2410_GPB(3),
-};
-
-static struct gpio_keys_button n30_buttons[] = {
-       {
-               .gpio           = S3C2410_GPF(0),
-               .code           = KEY_POWER,
-               .desc           = "Power",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPG(9),
-               .code           = KEY_UP,
-               .desc           = "Thumbwheel Up",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPG(8),
-               .code           = KEY_DOWN,
-               .desc           = "Thumbwheel Down",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPG(7),
-               .code           = KEY_ENTER,
-               .desc           = "Thumbwheel Press",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPF(7),
-               .code           = KEY_HOMEPAGE,
-               .desc           = "Home",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPF(6),
-               .code           = KEY_CALENDAR,
-               .desc           = "Calendar",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPF(5),
-               .code           = KEY_ADDRESSBOOK,
-               .desc           = "Contacts",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPF(4),
-               .code           = KEY_MAIL,
-               .desc           = "Mail",
-               .active_low     = 0,
-       },
-};
-
-static struct gpio_keys_platform_data n30_button_data = {
-       .buttons        = n30_buttons,
-       .nbuttons       = ARRAY_SIZE(n30_buttons),
-};
-
-static struct platform_device n30_button_device = {
-       .name           = "gpio-keys",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &n30_button_data,
-       }
-};
-
-static struct gpio_keys_button n35_buttons[] = {
-       {
-               .gpio           = S3C2410_GPF(0),
-               .code           = KEY_POWER,
-               .type           = EV_PWR,
-               .desc           = "Power",
-               .active_low     = 0,
-               .wakeup         = 1,
-       },
-       {
-               .gpio           = S3C2410_GPG(9),
-               .code           = KEY_UP,
-               .desc           = "Joystick Up",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPG(8),
-               .code           = KEY_DOWN,
-               .desc           = "Joystick Down",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPG(6),
-               .code           = KEY_DOWN,
-               .desc           = "Joystick Left",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPG(5),
-               .code           = KEY_DOWN,
-               .desc           = "Joystick Right",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPG(7),
-               .code           = KEY_ENTER,
-               .desc           = "Joystick Press",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPF(7),
-               .code           = KEY_HOMEPAGE,
-               .desc           = "Home",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPF(6),
-               .code           = KEY_CALENDAR,
-               .desc           = "Calendar",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPF(5),
-               .code           = KEY_ADDRESSBOOK,
-               .desc           = "Contacts",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPF(4),
-               .code           = KEY_MAIL,
-               .desc           = "Mail",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPF(3),
-               .code           = SW_RADIO,
-               .desc           = "GPS Antenna",
-               .active_low     = 0,
-       },
-       {
-               .gpio           = S3C2410_GPG(2),
-               .code           = SW_HEADPHONE_INSERT,
-               .desc           = "Headphone",
-               .active_low     = 0,
-       },
-};
-
-static struct gpio_keys_platform_data n35_button_data = {
-       .buttons        = n35_buttons,
-       .nbuttons       = ARRAY_SIZE(n35_buttons),
-};
-
-static struct platform_device n35_button_device = {
-       .name           = "gpio-keys",
-       .id             = -1,
-       .num_resources  = 0,
-       .dev            = {
-               .platform_data  = &n35_button_data,
-       }
-};
-
-/* This is the bluetooth LED on the device. */
-static struct s3c24xx_led_platdata n30_blue_led_pdata = {
-       .name           = "blue_led",
-       .gpio           = S3C2410_GPG(6),
-       .def_trigger    = "",
-};
-
-/* This is the blue LED on the device. Originally used to indicate GPS activity
- * by flashing. */
-static struct s3c24xx_led_platdata n35_blue_led_pdata = {
-       .name           = "blue_led",
-       .gpio           = S3C2410_GPD(8),
-       .def_trigger    = "",
-};
-
-/* This LED is driven by the battery microcontroller, and is blinking
- * red, blinking green or solid green when the battery is low,
- * charging or full respectively.  By driving GPD9 low, it's possible
- * to force the LED to blink red, so call that warning LED.  */
-static struct s3c24xx_led_platdata n30_warning_led_pdata = {
-       .name           = "warning_led",
-       .flags          = S3C24XX_LEDF_ACTLOW,
-       .gpio           = S3C2410_GPD(9),
-       .def_trigger    = "",
-};
-
-static struct s3c24xx_led_platdata n35_warning_led_pdata = {
-       .name           = "warning_led",
-       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
-       .gpio           = S3C2410_GPD(9),
-       .def_trigger    = "",
-};
-
-static struct platform_device n30_blue_led = {
-       .name           = "s3c24xx_led",
-       .id             = 1,
-       .dev            = {
-               .platform_data  = &n30_blue_led_pdata,
-       },
-};
-
-static struct platform_device n35_blue_led = {
-       .name           = "s3c24xx_led",
-       .id             = 1,
-       .dev            = {
-               .platform_data  = &n35_blue_led_pdata,
-       },
-};
-
-static struct platform_device n30_warning_led = {
-       .name           = "s3c24xx_led",
-       .id             = 2,
-       .dev            = {
-               .platform_data  = &n30_warning_led_pdata,
-       },
-};
-
-static struct platform_device n35_warning_led = {
-       .name           = "s3c24xx_led",
-       .id             = 2,
-       .dev            = {
-               .platform_data  = &n35_warning_led_pdata,
-       },
-};
-
-static struct s3c2410fb_display n30_display __initdata = {
-       .type           = S3C2410_LCDCON1_TFT,
-       .width          = 240,
-       .height         = 320,
-       .pixclock       = 170000,
-
-       .xres           = 240,
-       .yres           = 320,
-       .bpp            = 16,
-       .left_margin    = 3,
-       .right_margin   = 40,
-       .hsync_len      = 40,
-       .upper_margin   = 2,
-       .lower_margin   = 3,
-       .vsync_len      = 2,
-
-       .lcdcon5 = S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME,
-};
-
-static struct s3c2410fb_mach_info n30_fb_info __initdata = {
-       .displays       = &n30_display,
-       .num_displays   = 1,
-       .default_display = 0,
-       .lpcsel         = 0x06,
-};
-
-static void n30_sdi_set_power(unsigned char power_mode, unsigned short vdd)
-{
-       switch (power_mode) {
-       case MMC_POWER_ON:
-       case MMC_POWER_UP:
-               gpio_set_value(S3C2410_GPG(4), 1);
-               break;
-       case MMC_POWER_OFF:
-       default:
-               gpio_set_value(S3C2410_GPG(4), 0);
-               break;
-       }
-}
-
-static struct s3c24xx_mci_pdata n30_mci_cfg __initdata = {
-       .gpio_detect    = S3C2410_GPF(1),
-       .gpio_wprotect  = S3C2410_GPG(10),
-       .ocr_avail      = MMC_VDD_32_33,
-       .set_power      = n30_sdi_set_power,
-};
-
-static struct platform_device *n30_devices[] __initdata = {
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-       &s3c_device_ohci,
-       &s3c_device_rtc,
-       &s3c_device_usbgadget,
-       &s3c_device_sdi,
-       &n30_button_device,
-       &n30_blue_led,
-       &n30_warning_led,
-};
-
-static struct platform_device *n35_devices[] __initdata = {
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-       &s3c_device_rtc,
-       &s3c_device_usbgadget,
-       &s3c_device_sdi,
-       &n35_button_device,
-       &n35_blue_led,
-       &n35_warning_led,
-};
-
-static struct s3c2410_platform_i2c __initdata n30_i2ccfg = {
-       .flags          = 0,
-       .slave_addr     = 0x10,
-       .frequency      = 10*1000,
-};
-
-/* Lots of hardcoded stuff, but it sets up the hardware in a useful
- * state so that we can boot Linux directly from flash. */
-static void __init n30_hwinit(void)
-{
-       /* GPA0-11 special functions -- unknown what they do
-        * GPA12 N30 special function -- unknown what it does
-        *       N35/PiN output -- unknown what it does
-        *
-        * A12 is nGCS1 on the N30 and an output on the N35/PiN.  I
-        * don't think it does anything useful on the N30, so I ought
-        * to make it an output there too since it always driven to 0
-        * as far as I can tell. */
-       if (machine_is_n30())
-               __raw_writel(0x007fffff, S3C2410_GPACON);
-       if (machine_is_n35())
-               __raw_writel(0x007fefff, S3C2410_GPACON);
-       __raw_writel(0x00000000, S3C2410_GPADAT);
-
-       /* GPB0 TOUT0 backlight level
-        * GPB1 output 1=backlight on
-        * GPB2 output IrDA enable 0=transceiver enabled, 1=disabled
-        * GPB3 output USB D+ pull up 0=disabled, 1=enabled
-        * GPB4 N30 output -- unknown function
-        *      N30/PiN GPS control 0=GPS enabled, 1=GPS disabled
-        * GPB5 output -- unknown function
-        * GPB6 input -- unknown function
-        * GPB7 output -- unknown function
-        * GPB8 output -- probably LCD driver enable
-        * GPB9 output -- probably LCD VSYNC driver enable
-        * GPB10 output -- probably LCD HSYNC driver enable
-        */
-       __raw_writel(0x00154556, S3C2410_GPBCON);
-       __raw_writel(0x00000750, S3C2410_GPBDAT);
-       __raw_writel(0x00000073, S3C2410_GPBUP);
-
-       /* GPC0 input RS232 DCD/DSR/RI
-        * GPC1 LCD
-        * GPC2 output RS232 DTR?
-        * GPC3 input RS232 DCD/DSR/RI
-        * GPC4 LCD
-        * GPC5 output 0=NAND write enabled, 1=NAND write protect
-        * GPC6 input -- unknown function
-        * GPC7 input charger status 0=charger connected
-        *      this input can be triggered by power on the USB device
-        *      port too, but will go back to disconnected soon after.
-        * GPC8 N30/N35 output -- unknown function, always driven to 1
-        *      PiN input -- unknown function, always read as 1
-        *      Make it an input with a pull up for all models.
-        * GPC9-15 LCD
-        */
-       __raw_writel(0xaaa80618, S3C2410_GPCCON);
-       __raw_writel(0x0000014c, S3C2410_GPCDAT);
-       __raw_writel(0x0000fef2, S3C2410_GPCUP);
-
-       /* GPD0 input -- unknown function
-        * GPD1-D7 LCD
-        * GPD8 N30 output -- unknown function
-        *      N35/PiN output 1=GPS LED on
-        * GPD9 output 0=power led blinks red, 1=normal power led function
-        * GPD10 output -- unknown function
-        * GPD11-15 LCD drivers
-        */
-       __raw_writel(0xaa95aaa4, S3C2410_GPDCON);
-       __raw_writel(0x00000601, S3C2410_GPDDAT);
-       __raw_writel(0x0000fbfe, S3C2410_GPDUP);
-
-       /* GPE0-4 I2S audio bus
-        * GPE5-10 SD/MMC bus
-        * E11-13 outputs -- unknown function, probably power management
-        * E14-15 I2C bus connected to the battery controller
-        */
-       __raw_writel(0xa56aaaaa, S3C2410_GPECON);
-       __raw_writel(0x0000efc5, S3C2410_GPEDAT);
-       __raw_writel(0x0000f81f, S3C2410_GPEUP);
-
-       /* GPF0  input 0=power button pressed
-        * GPF1  input SD/MMC switch 0=card present
-        * GPF2  N30 1=reset button pressed (inverted compared to the rest)
-        *       N35/PiN 0=reset button pressed
-        * GPF3  N30/PiN input -- unknown function
-        *       N35 input GPS antenna position, 0=antenna closed, 1=open
-        * GPF4  input 0=button 4 pressed
-        * GPF5  input 0=button 3 pressed
-        * GPF6  input 0=button 2 pressed
-        * GPF7  input 0=button 1 pressed
-        */
-       __raw_writel(0x0000aaaa, S3C2410_GPFCON);
-       __raw_writel(0x00000000, S3C2410_GPFDAT);
-       __raw_writel(0x000000ff, S3C2410_GPFUP);
-
-       /* GPG0  input RS232 DCD/DSR/RI
-        * GPG1  input 1=USB gadget port has power from a host
-        * GPG2  N30 input -- unknown function
-        *       N35/PiN input 0=headphones plugged in, 1=not plugged in
-        * GPG3  N30 output -- unknown function
-        *       N35/PiN input with unknown function
-        * GPG4  N30 output 0=MMC enabled, 1=MMC disabled
-        * GPG5  N30 output 0=BlueTooth chip disabled, 1=enabled
-        *       N35/PiN input joystick right
-        * GPG6  N30 output 0=blue led on, 1=off
-        *       N35/PiN input joystick left
-        * GPG7  input 0=thumbwheel pressed
-        * GPG8  input 0=thumbwheel down
-        * GPG9  input 0=thumbwheel up
-        * GPG10 input SD/MMC write protect switch
-        * GPG11 N30 input -- unknown function
-        *       N35 output 0=GPS antenna powered, 1=not powered
-        *       PiN output -- unknown function
-        * GPG12-15 touch screen functions
-        *
-        * The pullups differ between the models, so enable all
-        * pullups that are enabled on any of the models.
-        */
-       if (machine_is_n30())
-               __raw_writel(0xff0a956a, S3C2410_GPGCON);
-       if (machine_is_n35())
-               __raw_writel(0xff4aa92a, S3C2410_GPGCON);
-       __raw_writel(0x0000e800, S3C2410_GPGDAT);
-       __raw_writel(0x0000f86f, S3C2410_GPGUP);
-
-       /* GPH0/1/2/3 RS232 serial port
-        * GPH4/5 IrDA serial port
-        * GPH6/7  N30 BlueTooth serial port
-        *         N35/PiN GPS receiver
-        * GPH8 input -- unknown function
-        * GPH9 CLKOUT0 HCLK -- unknown use
-        * GPH10 CLKOUT1 FCLK -- unknown use
-        *
-        * The pull ups for H6/H7 are enabled on N30 but not on the
-        * N35/PiN.  I suppose is useful for a budget model of the N30
-        * with no bluetooh.  It doesn't hurt to have the pull ups
-        * enabled on the N35, so leave them enabled for all models.
-        */
-       __raw_writel(0x0028aaaa, S3C2410_GPHCON);
-       __raw_writel(0x000005ef, S3C2410_GPHDAT);
-       __raw_writel(0x0000063f, S3C2410_GPHUP);
-}
-
-static void __init n30_map_io(void)
-{
-       s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
-       n30_hwinit();
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
-}
-
-/* GPB3 is the line that controls the pull-up for the USB D+ line */
-
-static void __init n30_init(void)
-{
-       WARN_ON(gpio_request(S3C2410_GPG(4), "mmc power"));
-
-       s3c24xx_fb_set_platdata(&n30_fb_info);
-       s3c24xx_udc_set_platdata(&n30_udc_cfg);
-       s3c24xx_mci_set_platdata(&n30_mci_cfg);
-       s3c_i2c0_set_platdata(&n30_i2ccfg);
-
-       /* Turn off suspend on both USB ports, and switch the
-        * selectable USB port to USB device mode. */
-
-       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
-                             S3C2410_MISCCR_USBSUSPND0 |
-                             S3C2410_MISCCR_USBSUSPND1, 0x0);
-
-       if (machine_is_n30()) {
-               /* Turn off suspend on both USB ports, and switch the
-                * selectable USB port to USB device mode. */
-               s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
-                                     S3C2410_MISCCR_USBSUSPND0 |
-                                     S3C2410_MISCCR_USBSUSPND1, 0x0);
-
-               platform_add_devices(n30_devices, ARRAY_SIZE(n30_devices));
-       }
-
-       if (machine_is_n35()) {
-               /* Turn off suspend and switch the selectable USB port
-                * to USB device mode.  Turn on suspend for the host
-                * port since it is not connected on the N35.
-                *
-                * Actually, the host port is available at some pads
-                * on the back of the device, so it would actually be
-                * possible to add a USB device inside the N35 if you
-                * are willing to do some hardware modifications. */
-               s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
-                                     S3C2410_MISCCR_USBSUSPND0 |
-                                     S3C2410_MISCCR_USBSUSPND1,
-                                     S3C2410_MISCCR_USBSUSPND0);
-
-               platform_add_devices(n35_devices, ARRAY_SIZE(n35_devices));
-       }
-}
-
-MACHINE_START(N30, "Acer-N30")
-       /* Maintainer: Christer Weinigel <christer@weinigel.se>,
-                               Ben Dooks <ben-linux@fluff.org>
-       */
-       .atag_offset    = 0x100,
-       .timer          = &s3c24xx_timer,
-       .init_machine   = n30_init,
-       .init_irq       = s3c24xx_init_irq,
-       .map_io         = n30_map_io,
-       .restart        = s3c2410_restart,
-MACHINE_END
-
-MACHINE_START(N35, "Acer-N35")
-       /* Maintainer: Christer Weinigel <christer@weinigel.se>
-       */
-       .atag_offset    = 0x100,
-       .timer          = &s3c24xx_timer,
-       .init_machine   = n30_init,
-       .init_irq       = s3c24xx_init_irq,
-       .map_io         = n30_map_io,
-       .restart        = s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
deleted file mode 100644 (file)
index 5f1e0ee..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-otom.c
- *
- * Copyright (c) 2004 Nex Vision
- *   Guillaume GOURAT <guillaume.gourat@nexvision.fr>
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/otom-map.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/s3c2410.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/iic.h>
-#include <plat/cpu.h>
-
-#include "common.h"
-
-static struct map_desc otom11_iodesc[] __initdata = {
-  /* Device area */
-       { (u32)OTOM_VA_CS8900A_BASE, OTOM_PA_CS8900A_BASE, SZ_16M, MT_DEVICE },
-};
-
-#define UCON S3C2410_UCON_DEFAULT
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG12 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg otom11_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       /* port 2 is not actually used */
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       }
-};
-
-/* NOR Flash on NexVision OTOM board */
-
-static struct resource otom_nor_resource[] = {
-       [0] = {
-               .start = S3C2410_CS0,
-               .end   = S3C2410_CS0 + (4*1024*1024) - 1,
-               .flags = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device otom_device_nor = {
-       .name           = "mtd-flash",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(otom_nor_resource),
-       .resource       = otom_nor_resource,
-};
-
-/* Standard OTOM devices */
-
-static struct platform_device *otom11_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-       &s3c_device_rtc,
-       &otom_device_nor,
-};
-
-static void __init otom11_map_io(void)
-{
-       s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc));
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(otom11_uartcfgs, ARRAY_SIZE(otom11_uartcfgs));
-}
-
-static void __init otom11_init(void)
-{
-       s3c_i2c0_set_platdata(NULL);
-       platform_add_devices(otom11_devices, ARRAY_SIZE(otom11_devices));
-}
-
-MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
-       /* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
-       .atag_offset    = 0x100,
-       .map_io         = otom11_map_io,
-       .init_machine   = otom11_init,
-       .init_irq       = s3c24xx_init_irq,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c2410/mach-qt2410.c
deleted file mode 100644 (file)
index 91c16d9..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-qt2410.c
- *
- * Copyright (C) 2006 by OpenMoko, Inc.
- * Author: Harald Welte <laforge@openmoko.org>
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_gpio.h>
-#include <linux/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/leds-gpio.h>
-#include <mach/regs-lcd.h>
-#include <plat/regs-serial.h>
-#include <mach/fb.h>
-#include <plat/nand.h>
-#include <plat/udc.h>
-#include <plat/iic.h>
-
-#include <plat/common-smdk.h>
-#include <plat/gpio-cfg.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pm.h>
-
-#include "common.h"
-
-static struct map_desc qt2410_iodesc[] __initdata = {
-       { 0xe0000000, __phys_to_pfn(S3C2410_CS3+0x01000000), SZ_1M, MT_DEVICE }
-};
-
-#define UCON S3C2410_UCON_DEFAULT
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg smdk2410_uartcfgs[] = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       }
-};
-
-/* LCD driver info */
-
-static struct s3c2410fb_display qt2410_lcd_cfg[] __initdata = {
-       {
-               /* Configuration for 640x480 SHARP LQ080V3DG01 */
-               .lcdcon5 = S3C2410_LCDCON5_FRM565 |
-                          S3C2410_LCDCON5_INVVLINE |
-                          S3C2410_LCDCON5_INVVFRAME |
-                          S3C2410_LCDCON5_PWREN |
-                          S3C2410_LCDCON5_HWSWP,
-
-               .type           = S3C2410_LCDCON1_TFT,
-               .width          = 640,
-               .height         = 480,
-
-               .pixclock       = 40000, /* HCLK/4 */
-               .xres           = 640,
-               .yres           = 480,
-               .bpp            = 16,
-               .left_margin    = 44,
-               .right_margin   = 116,
-               .hsync_len      = 96,
-               .upper_margin   = 19,
-               .lower_margin   = 11,
-               .vsync_len      = 15,
-       },
-       {
-               /* Configuration for 480x640 toppoly TD028TTEC1 */
-               .lcdcon5 = S3C2410_LCDCON5_FRM565 |
-                          S3C2410_LCDCON5_INVVLINE |
-                          S3C2410_LCDCON5_INVVFRAME |
-                          S3C2410_LCDCON5_PWREN |
-                          S3C2410_LCDCON5_HWSWP,
-
-               .type           = S3C2410_LCDCON1_TFT,
-               .width          = 480,
-               .height         = 640,
-               .pixclock       = 40000, /* HCLK/4 */
-               .xres           = 480,
-               .yres           = 640,
-               .bpp            = 16,
-               .left_margin    = 8,
-               .right_margin   = 24,
-               .hsync_len      = 8,
-               .upper_margin   = 2,
-               .lower_margin   = 4,
-               .vsync_len      = 2,
-       },
-       {
-               /* Config for 240x320 LCD */
-               .lcdcon5 = S3C2410_LCDCON5_FRM565 |
-                          S3C2410_LCDCON5_INVVLINE |
-                          S3C2410_LCDCON5_INVVFRAME |
-                          S3C2410_LCDCON5_PWREN |
-                          S3C2410_LCDCON5_HWSWP,
-
-               .type           = S3C2410_LCDCON1_TFT,
-               .width          = 240,
-               .height         = 320,
-               .pixclock       = 100000, /* HCLK/10 */
-               .xres           = 240,
-               .yres           = 320,
-               .bpp            = 16,
-               .left_margin    = 13,
-               .right_margin   = 8,
-               .hsync_len      = 4,
-               .upper_margin   = 2,
-               .lower_margin   = 7,
-               .vsync_len      = 4,
-       },
-};
-
-
-static struct s3c2410fb_mach_info qt2410_fb_info __initdata = {
-       .displays       = qt2410_lcd_cfg,
-       .num_displays   = ARRAY_SIZE(qt2410_lcd_cfg),
-       .default_display = 0,
-
-       .lpcsel         = ((0xCE6) & ~7) | 1<<4,
-};
-
-/* CS8900 */
-
-static struct resource qt2410_cs89x0_resources[] = {
-       [0] = {
-               .start  = 0x19000000,
-               .end    = 0x19000000 + 16,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_EINT9,
-               .end    = IRQ_EINT9,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device qt2410_cs89x0 = {
-       .name           = "cirrus-cs89x0",
-       .num_resources  = ARRAY_SIZE(qt2410_cs89x0_resources),
-       .resource       = qt2410_cs89x0_resources,
-};
-
-/* LED */
-
-static struct s3c24xx_led_platdata qt2410_pdata_led = {
-       .gpio           = S3C2410_GPB(0),
-       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
-       .name           = "led",
-       .def_trigger    = "timer",
-};
-
-static struct platform_device qt2410_led = {
-       .name           = "s3c24xx_led",
-       .id             = 0,
-       .dev            = {
-               .platform_data = &qt2410_pdata_led,
-       },
-};
-
-/* SPI */
-
-static struct spi_gpio_platform_data spi_gpio_cfg = {
-       .sck            = S3C2410_GPG(7),
-       .mosi           = S3C2410_GPG(6),
-       .miso           = S3C2410_GPG(5),
-};
-
-static struct platform_device qt2410_spi = {
-       .name           = "spi-gpio",
-       .id             = 1,
-       .dev.platform_data = &spi_gpio_cfg,
-};
-
-/* Board devices */
-
-static struct platform_device *qt2410_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-       &s3c_device_sdi,
-       &s3c_device_usbgadget,
-       &qt2410_spi,
-       &qt2410_cs89x0,
-       &qt2410_led,
-};
-
-static struct mtd_partition __initdata qt2410_nand_part[] = {
-       [0] = {
-               .name   = "U-Boot",
-               .size   = 0x30000,
-               .offset = 0,
-       },
-       [1] = {
-               .name   = "U-Boot environment",
-               .offset = 0x30000,
-               .size   = 0x4000,
-       },
-       [2] = {
-               .name   = "kernel",
-               .offset = 0x34000,
-               .size   = SZ_2M,
-       },
-       [3] = {
-               .name   = "initrd",
-               .offset = 0x234000,
-               .size   = SZ_4M,
-       },
-       [4] = {
-               .name   = "jffs2",
-               .offset = 0x634000,
-               .size   = 0x39cc000,
-       },
-};
-
-static struct s3c2410_nand_set __initdata qt2410_nand_sets[] = {
-       [0] = {
-               .name           = "NAND",
-               .nr_chips       = 1,
-               .nr_partitions  = ARRAY_SIZE(qt2410_nand_part),
-               .partitions     = qt2410_nand_part,
-       },
-};
-
-/* choose a set of timings which should suit most 512Mbit
- * chips and beyond.
- */
-
-static struct s3c2410_platform_nand __initdata qt2410_nand_info = {
-       .tacls          = 20,
-       .twrph0         = 60,
-       .twrph1         = 20,
-       .nr_sets        = ARRAY_SIZE(qt2410_nand_sets),
-       .sets           = qt2410_nand_sets,
-};
-
-/* UDC */
-
-static struct s3c2410_udc_mach_info qt2410_udc_cfg = {
-};
-
-static char tft_type = 's';
-
-static int __init qt2410_tft_setup(char *str)
-{
-       tft_type = str[0];
-       return 1;
-}
-
-__setup("tft=", qt2410_tft_setup);
-
-static void __init qt2410_map_io(void)
-{
-       s3c24xx_init_io(qt2410_iodesc, ARRAY_SIZE(qt2410_iodesc));
-       s3c24xx_init_clocks(12*1000*1000);
-       s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
-}
-
-static void __init qt2410_machine_init(void)
-{
-       s3c_nand_set_platdata(&qt2410_nand_info);
-
-       switch (tft_type) {
-       case 'p': /* production */
-               qt2410_fb_info.default_display = 1;
-               break;
-       case 'b': /* big */
-               qt2410_fb_info.default_display = 0;
-               break;
-       case 's': /* small */
-       default:
-               qt2410_fb_info.default_display = 2;
-               break;
-       }
-       s3c24xx_fb_set_platdata(&qt2410_fb_info);
-
-       s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);
-       s3c2410_gpio_setpin(S3C2410_GPB(0), 1);
-
-       s3c24xx_udc_set_platdata(&qt2410_udc_cfg);
-       s3c_i2c0_set_platdata(NULL);
-
-       WARN_ON(gpio_request(S3C2410_GPB(5), "spi cs"));
-       gpio_direction_output(S3C2410_GPB(5), 1);
-
-       platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices));
-       s3c_pm_init();
-}
-
-MACHINE_START(QT2410, "QT2410")
-       .atag_offset    = 0x100,
-       .map_io         = qt2410_map_io,
-       .init_irq       = s3c24xx_init_irq,
-       .init_machine   = qt2410_machine_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
deleted file mode 100644 (file)
index bdc27e7..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-smdk2410.c
- *
- * linux/arch/arm/mach-s3c2410/mach-smdk2410.c
- *
- * Copyright (C) 2004 by FS Forth-Systeme GmbH
- * All rights reserved.
- *
- * @Author: Jonas Dietsche
- *
- * 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
- *
- * @History:
- * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
- * Ben Dooks <ben@simtec.co.uk>
- *
- ***********************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <plat/iic.h>
-
-#include <plat/devs.h>
-#include <plat/cpu.h>
-
-#include <plat/common-smdk.h>
-
-#include "common.h"
-
-static struct map_desc smdk2410_iodesc[] __initdata = {
-  /* nothing here yet */
-};
-
-#define UCON S3C2410_UCON_DEFAULT
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg smdk2410_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       }
-};
-
-static struct platform_device *smdk2410_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-};
-
-static void __init smdk2410_map_io(void)
-{
-       s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
-}
-
-static void __init smdk2410_init(void)
-{
-       s3c_i2c0_set_platdata(NULL);
-       platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
-       smdk_machine_init();
-}
-
-MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
-                                   * to SMDK2410 */
-       /* Maintainer: Jonas Dietsche */
-       .atag_offset    = 0x100,
-       .map_io         = smdk2410_map_io,
-       .init_irq       = s3c24xx_init_irq,
-       .init_machine   = smdk2410_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-tct_hammer.c b/arch/arm/mach-s3c2410/mach-tct_hammer.c
deleted file mode 100644 (file)
index 1114666..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-tct_hammer.c
- *
- * Copyright (c) 2007 TinCanTools
- *     David Anders <danders@amltd.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
- *
- * @History:
- * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
- * Ben Dooks <ben@simtec.co.uk>
- *
- ***********************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/flash.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <plat/iic.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/physmap.h>
-
-#include "common.h"
-
-static struct resource tct_hammer_nor_resource = {
-               .start = 0x00000000,
-               .end   = 0x01000000 - 1,
-               .flags = IORESOURCE_MEM,
-};
-
-static struct mtd_partition tct_hammer_mtd_partitions[] = {
-       {
-               .name           = "System",
-               .size           = 0x240000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "JFFS2",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-
-static struct physmap_flash_data tct_hammer_flash_data = {
-       .width          = 2,
-       .parts          = tct_hammer_mtd_partitions,
-       .nr_parts       = ARRAY_SIZE(tct_hammer_mtd_partitions),
-};
-
-static struct platform_device tct_hammer_device_nor = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev = {
-                       .platform_data = &tct_hammer_flash_data,
-               },
-       .num_resources  = 1,
-       .resource       = &tct_hammer_nor_resource,
-};
-
-static struct map_desc tct_hammer_iodesc[] __initdata = {
-};
-
-#define UCON S3C2410_UCON_DEFAULT
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg tct_hammer_uartcfgs[] = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       }
-};
-
-
-static struct platform_device *tct_hammer_devices[] __initdata = {
-       &s3c_device_adc,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_ohci,
-       &s3c_device_rtc,
-       &s3c_device_usbgadget,
-       &s3c_device_sdi,
-       &tct_hammer_device_nor,
-};
-
-static void __init tct_hammer_map_io(void)
-{
-       s3c24xx_init_io(tct_hammer_iodesc, ARRAY_SIZE(tct_hammer_iodesc));
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(tct_hammer_uartcfgs, ARRAY_SIZE(tct_hammer_uartcfgs));
-}
-
-static void __init tct_hammer_init(void)
-{
-       s3c_i2c0_set_platdata(NULL);
-       platform_add_devices(tct_hammer_devices, ARRAY_SIZE(tct_hammer_devices));
-}
-
-MACHINE_START(TCT_HAMMER, "TCT_HAMMER")
-       .atag_offset    = 0x100,
-       .map_io         = tct_hammer_map_io,
-       .init_irq       = s3c24xx_init_irq,
-       .init_machine   = tct_hammer_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
deleted file mode 100644 (file)
index dbe668a..0000000
+++ /dev/null
@@ -1,386 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-vr1000.c
- *
- * Copyright (c) 2003-2008 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * Machine support for Thorcom VR1000 board. Designed for Thorcom by
- * Simtec Electronics, http://www.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/dm9000.h>
-#include <linux/i2c.h>
-
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/bast-map.h>
-#include <mach/vr1000-map.h>
-#include <mach/vr1000-irq.h>
-#include <mach/vr1000-cpld.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/leds-gpio.h>
-
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/iic.h>
-#include <plat/audio-simtec.h>
-
-#include "usb-simtec.h"
-#include "nor-simtec.h"
-#include "common.h"
-
-/* macros for virtual address mods for the io space entries */
-#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
-#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
-#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
-#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
-
-/* macros to modify the physical addresses for io space */
-
-#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
-#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
-#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
-#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
-
-static struct map_desc vr1000_iodesc[] __initdata = {
-  /* ISA IO areas */
-  {
-         .virtual      = (u32)S3C24XX_VA_ISA_BYTE,
-         .pfn          = PA_CS2(BAST_PA_ISAIO),
-         .length       = SZ_16M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)S3C24XX_VA_ISA_WORD,
-         .pfn          = PA_CS3(BAST_PA_ISAIO),
-         .length       = SZ_16M,
-         .type         = MT_DEVICE,
-  },
-
-  /*  CPLD control registers, and external interrupt controls */
-  {
-         .virtual      = (u32)VR1000_VA_CTRL1,
-         .pfn          = __phys_to_pfn(VR1000_PA_CTRL1),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)VR1000_VA_CTRL2,
-         .pfn          = __phys_to_pfn(VR1000_PA_CTRL2),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)VR1000_VA_CTRL3,
-         .pfn          = __phys_to_pfn(VR1000_PA_CTRL3),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)VR1000_VA_CTRL4,
-         .pfn          = __phys_to_pfn(VR1000_PA_CTRL4),
-         .length       = SZ_1M,
-         .type         = MT_DEVICE,
-  },
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg vr1000_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       /* port 2 is not actually used */
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       }
-};
-
-/* definitions for the vr1000 extra 16550 serial ports */
-
-#define VR1000_BAUDBASE (3692307)
-
-#define VR1000_SERIAL_MAPBASE(x) (VR1000_PA_SERIAL + 0x80 + ((x) << 5))
-
-static struct plat_serial8250_port serial_platform_data[] = {
-       [0] = {
-               .mapbase        = VR1000_SERIAL_MAPBASE(0),
-               .irq            = IRQ_VR1000_SERIAL + 0,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 0,
-               .uartclk        = VR1000_BAUDBASE,
-       },
-       [1] = {
-               .mapbase        = VR1000_SERIAL_MAPBASE(1),
-               .irq            = IRQ_VR1000_SERIAL + 1,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 0,
-               .uartclk        = VR1000_BAUDBASE,
-       },
-       [2] = {
-               .mapbase        = VR1000_SERIAL_MAPBASE(2),
-               .irq            = IRQ_VR1000_SERIAL + 2,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 0,
-               .uartclk        = VR1000_BAUDBASE,
-       },
-       [3] = {
-               .mapbase        = VR1000_SERIAL_MAPBASE(3),
-               .irq            = IRQ_VR1000_SERIAL + 3,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 0,
-               .uartclk        = VR1000_BAUDBASE,
-       },
-       { },
-};
-
-static struct platform_device serial_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_PLATFORM,
-       .dev                    = {
-               .platform_data  = serial_platform_data,
-       },
-};
-
-/* DM9000 ethernet devices */
-
-static struct resource vr1000_dm9k0_resource[] = {
-       [0] = {
-               .start = S3C2410_CS5 + VR1000_PA_DM9000,
-               .end   = S3C2410_CS5 + VR1000_PA_DM9000 + 3,
-               .flags = IORESOURCE_MEM
-       },
-       [1] = {
-               .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x40,
-               .end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0x7f,
-               .flags = IORESOURCE_MEM
-       },
-       [2] = {
-               .start = IRQ_VR1000_DM9000A,
-               .end   = IRQ_VR1000_DM9000A,
-               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-       }
-
-};
-
-static struct resource vr1000_dm9k1_resource[] = {
-       [0] = {
-               .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x80,
-               .end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0x83,
-               .flags = IORESOURCE_MEM
-       },
-       [1] = {
-               .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0,
-               .end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0xFF,
-               .flags = IORESOURCE_MEM
-       },
-       [2] = {
-               .start = IRQ_VR1000_DM9000N,
-               .end   = IRQ_VR1000_DM9000N,
-               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
-       }
-};
-
-/* for the moment we limit ourselves to 16bit IO until some
- * better IO routines can be written and tested
-*/
-
-static struct dm9000_plat_data vr1000_dm9k_platdata = {
-       .flags          = DM9000_PLATF_16BITONLY,
-};
-
-static struct platform_device vr1000_dm9k0 = {
-       .name           = "dm9000",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(vr1000_dm9k0_resource),
-       .resource       = vr1000_dm9k0_resource,
-       .dev            = {
-               .platform_data = &vr1000_dm9k_platdata,
-       }
-};
-
-static struct platform_device vr1000_dm9k1 = {
-       .name           = "dm9000",
-       .id             = 1,
-       .num_resources  = ARRAY_SIZE(vr1000_dm9k1_resource),
-       .resource       = vr1000_dm9k1_resource,
-       .dev            = {
-               .platform_data = &vr1000_dm9k_platdata,
-       }
-};
-
-/* LEDS */
-
-static struct s3c24xx_led_platdata vr1000_led1_pdata = {
-       .name           = "led1",
-       .gpio           = S3C2410_GPB(0),
-       .def_trigger    = "",
-};
-
-static struct s3c24xx_led_platdata vr1000_led2_pdata = {
-       .name           = "led2",
-       .gpio           = S3C2410_GPB(1),
-       .def_trigger    = "",
-};
-
-static struct s3c24xx_led_platdata vr1000_led3_pdata = {
-       .name           = "led3",
-       .gpio           = S3C2410_GPB(2),
-       .def_trigger    = "",
-};
-
-static struct platform_device vr1000_led1 = {
-       .name           = "s3c24xx_led",
-       .id             = 1,
-       .dev            = {
-               .platform_data  = &vr1000_led1_pdata,
-       },
-};
-
-static struct platform_device vr1000_led2 = {
-       .name           = "s3c24xx_led",
-       .id             = 2,
-       .dev            = {
-               .platform_data  = &vr1000_led2_pdata,
-       },
-};
-
-static struct platform_device vr1000_led3 = {
-       .name           = "s3c24xx_led",
-       .id             = 3,
-       .dev            = {
-               .platform_data  = &vr1000_led3_pdata,
-       },
-};
-
-/* I2C devices. */
-
-static struct i2c_board_info vr1000_i2c_devs[] __initdata = {
-       {
-               I2C_BOARD_INFO("tlv320aic23", 0x1a),
-       }, {
-               I2C_BOARD_INFO("tmp101", 0x48),
-       }, {
-               I2C_BOARD_INFO("m41st87", 0x68),
-       },
-};
-
-/* devices for this board */
-
-static struct platform_device *vr1000_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_adc,
-       &serial_device,
-       &vr1000_dm9k0,
-       &vr1000_dm9k1,
-       &vr1000_led1,
-       &vr1000_led2,
-       &vr1000_led3,
-};
-
-static struct clk *vr1000_clocks[] __initdata = {
-       &s3c24xx_dclk0,
-       &s3c24xx_dclk1,
-       &s3c24xx_clkout0,
-       &s3c24xx_clkout1,
-       &s3c24xx_uclk,
-};
-
-static void vr1000_power_off(void)
-{
-       gpio_direction_output(S3C2410_GPB(9), 1);
-}
-
-static void __init vr1000_map_io(void)
-{
-       /* initialise clock sources */
-
-       s3c24xx_dclk0.parent = &clk_upll;
-       s3c24xx_dclk0.rate   = 12*1000*1000;
-
-       s3c24xx_dclk1.parent = NULL;
-       s3c24xx_dclk1.rate   = 3692307;
-
-       s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
-       s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
-
-       s3c24xx_uclk.parent  = &s3c24xx_clkout1;
-
-       s3c24xx_register_clocks(vr1000_clocks, ARRAY_SIZE(vr1000_clocks));
-
-       pm_power_off = vr1000_power_off;
-
-       s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc));
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs));
-}
-
-static void __init vr1000_init(void)
-{
-       s3c_i2c0_set_platdata(NULL);
-       platform_add_devices(vr1000_devices, ARRAY_SIZE(vr1000_devices));
-
-       i2c_register_board_info(0, vr1000_i2c_devs,
-                               ARRAY_SIZE(vr1000_i2c_devs));
-
-       nor_simtec_init();
-       simtec_audio_add(NULL, true, NULL);
-
-       WARN_ON(gpio_request(S3C2410_GPB(9), "power off"));
-}
-
-MACHINE_START(VR1000, "Thorcom-VR1000")
-       /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .atag_offset    = 0x100,
-       .map_io         = vr1000_map_io,
-       .init_machine   = vr1000_init,
-       .init_irq       = s3c24xx_init_irq,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2410_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2410/nor-simtec.c b/arch/arm/mach-s3c2410/nor-simtec.c
deleted file mode 100644 (file)
index ad9f750..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/nor-simtec.c
- *
- * Copyright (c) 2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Simtec NOR mapping
- *
- * 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/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/map.h>
-#include <mach/bast-map.h>
-#include <mach/bast-cpld.h>
-
-#include "nor-simtec.h"
-
-static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
-{
-       unsigned int val;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       val = __raw_readb(BAST_VA_CTRL3);
-
-       printk(KERN_DEBUG "%s(%d)\n", __func__, vpp);
-
-       if (vpp)
-               val |= BAST_CPLD_CTRL3_ROMWEN;
-       else
-               val &= ~BAST_CPLD_CTRL3_ROMWEN;
-
-       __raw_writeb(val, BAST_VA_CTRL3);
-       local_irq_restore(flags);
-}
-
-static struct physmap_flash_data simtec_nor_pdata = {
-       .width          = 2,
-       .set_vpp        = simtec_nor_vpp,
-       .nr_parts       = 0,
-};
-
-static struct resource simtec_nor_resource[] = {
-       [0] = {
-               .start = S3C2410_CS1 + 0x4000000,
-               .end   = S3C2410_CS1 + 0x4000000 + SZ_8M - 1,
-               .flags = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device simtec_device_nor = {
-       .name           = "physmap-flash",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(simtec_nor_resource),
-       .resource       = simtec_nor_resource,
-       .dev            = {
-               .platform_data = &simtec_nor_pdata,
-       },
-};
-
-void __init nor_simtec_init(void)
-{
-       int ret;
-
-       ret = platform_device_register(&simtec_device_nor);
-       if (ret < 0)
-               printk(KERN_ERR "failed to register physmap-flash device\n");
-       else
-               simtec_nor_vpp(NULL, 1);
-}
diff --git a/arch/arm/mach-s3c2410/nor-simtec.h b/arch/arm/mach-s3c2410/nor-simtec.h
deleted file mode 100644 (file)
index f619c1e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/nor-simtec.h
- *
- * Copyright (c) 2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Simtec NOR mapping
- *
- * 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.
-*/
-
-extern void nor_simtec_init(void);
diff --git a/arch/arm/mach-s3c2410/pm-h1940.S b/arch/arm/mach-s3c2410/pm-h1940.S
deleted file mode 100644 (file)
index c93bf2d..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/pm-h1940.S
- *
- * Copyright (c) 2006 Ben Dooks <ben-linux@fluff.org>
- *
- * H1940 Suspend to RAM
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <mach/regs-gpio.h>
-
-       .text
-       .global h1940_pm_return
-
-h1940_pm_return:
-       mov     r0, #S3C2410_PA_GPIO
-       ldr     pc, [ r0, #S3C2410_GSTATUS3 - S3C24XX_VA_GPIO ]
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
deleted file mode 100644 (file)
index 03f706d..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/pm.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/init.h>
-#include <linux/suspend.h>
-#include <linux/errno.h>
-#include <linux/time.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-
-#include <asm/mach-types.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/h1940.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-
-static void s3c2410_pm_prepare(void)
-{
-       /* ensure at least GSTATUS3 has the resume address */
-
-       __raw_writel(virt_to_phys(s3c_cpu_resume), S3C2410_GSTATUS3);
-
-       S3C_PMDBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
-       S3C_PMDBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
-
-       if (machine_is_h1940()) {
-               void *base = phys_to_virt(H1940_SUSPEND_CHECK);
-               unsigned long ptr;
-               unsigned long calc = 0;
-
-               /* generate check for the bootloader to check on resume */
-
-               for (ptr = 0; ptr < 0x40000; ptr += 0x400)
-                       calc += __raw_readl(base+ptr);
-
-               __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
-       }
-
-       /* RX3715 and RX1950 use similar to H1940 code and the
-        * same offsets for resume and checksum pointers */
-
-       if (machine_is_rx3715() || machine_is_rx1950()) {
-               void *base = phys_to_virt(H1940_SUSPEND_CHECK);
-               unsigned long ptr;
-               unsigned long calc = 0;
-
-               /* generate check for the bootloader to check on resume */
-
-               for (ptr = 0; ptr < 0x40000; ptr += 0x4)
-                       calc += __raw_readl(base+ptr);
-
-               __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
-       }
-
-       if ( machine_is_aml_m5900() )
-               s3c2410_gpio_setpin(S3C2410_GPF(2), 1);
-
-       if (machine_is_rx1950()) {
-               /* According to S3C2442 user's manual, page 7-17,
-                * when the system is operating in NAND boot mode,
-                * the hardware pin configuration - EINT[23:21] â€“
-                * must be set as input for starting up after
-                * wakeup from sleep mode
-                */
-               s3c_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPIO_INPUT);
-               s3c_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPIO_INPUT);
-               s3c_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPIO_INPUT);
-       }
-}
-
-static void s3c2410_pm_resume(void)
-{
-       unsigned long tmp;
-
-       /* unset the return-from-sleep flag, to ensure reset */
-
-       tmp = __raw_readl(S3C2410_GSTATUS2);
-       tmp &= S3C2410_GSTATUS2_OFFRESET;
-       __raw_writel(tmp, S3C2410_GSTATUS2);
-
-       if ( machine_is_aml_m5900() )
-               s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
-}
-
-struct syscore_ops s3c2410_pm_syscore_ops = {
-       .resume         = s3c2410_pm_resume,
-};
-
-static int s3c2410_pm_add(struct device *dev, struct subsys_interface *sif)
-{
-       pm_cpu_prep = s3c2410_pm_prepare;
-       pm_cpu_sleep = s3c2410_cpu_suspend;
-
-       return 0;
-}
-
-#if defined(CONFIG_CPU_S3C2410)
-static struct subsys_interface s3c2410_pm_interface = {
-       .name           = "s3c2410_pm",
-       .subsys         = &s3c2410_subsys,
-       .add_dev        = s3c2410_pm_add,
-};
-
-/* register ourselves */
-
-static int __init s3c2410_pm_drvinit(void)
-{
-       return subsys_interface_register(&s3c2410_pm_interface);
-}
-
-arch_initcall(s3c2410_pm_drvinit);
-
-static struct subsys_interface s3c2410a_pm_interface = {
-       .name           = "s3c2410a_pm",
-       .subsys         = &s3c2410a_subsys,
-       .add_dev        = s3c2410_pm_add,
-};
-
-static int __init s3c2410a_pm_drvinit(void)
-{
-       return subsys_interface_register(&s3c2410a_pm_interface);
-}
-
-arch_initcall(s3c2410a_pm_drvinit);
-#endif
-
-#if defined(CONFIG_CPU_S3C2440)
-static struct subsys_interface s3c2440_pm_interface = {
-       .name           = "s3c2440_pm",
-       .subsys         = &s3c2440_subsys,
-       .add_dev        = s3c2410_pm_add,
-};
-
-static int __init s3c2440_pm_drvinit(void)
-{
-       return subsys_interface_register(&s3c2440_pm_interface);
-}
-
-arch_initcall(s3c2440_pm_drvinit);
-#endif
-
-#if defined(CONFIG_CPU_S3C2442)
-static struct subsys_interface s3c2442_pm_interface = {
-       .name           = "s3c2442_pm",
-       .subsys         = &s3c2442_subsys,
-       .add_dev        = s3c2410_pm_add,
-};
-
-static int __init s3c2442_pm_drvinit(void)
-{
-       return subsys_interface_register(&s3c2442_pm_interface);
-}
-
-arch_initcall(s3c2442_pm_drvinit);
-#endif
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
deleted file mode 100644 (file)
index a3c5cb0..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410.c
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.simtec.co.uk/products/EB2410ITX/
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/system_misc.h>
-
-#include <plat/cpu-freq.h>
-
-#include <mach/regs-clock.h>
-#include <plat/regs-serial.h>
-
-#include <plat/s3c2410.h>
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/clock.h>
-#include <plat/pll.h>
-#include <plat/pm.h>
-#include <plat/watchdog-reset.h>
-
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-
-/* Initial IO mappings */
-
-static struct map_desc s3c2410_iodesc[] __initdata = {
-       IODESC_ENT(CLKPWR),
-       IODESC_ENT(TIMER),
-       IODESC_ENT(WATCHDOG),
-};
-
-/* our uart devices */
-
-/* uart registration process */
-
-void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-       s3c24xx_init_uartdevs("s3c2410-uart", s3c2410_uart_resources, cfg, no);
-}
-
-/* s3c2410_map_io
- *
- * register the standard cpu IO areas, and any passed in from the
- * machine specific initialisation.
-*/
-
-void __init s3c2410_map_io(void)
-{
-       s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up;
-       s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up;
-
-       iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
-}
-
-void __init_or_cpufreq s3c2410_setup_clocks(void)
-{
-       struct clk *xtal_clk;
-       unsigned long tmp;
-       unsigned long xtal;
-       unsigned long fclk;
-       unsigned long hclk;
-       unsigned long pclk;
-
-       xtal_clk = clk_get(NULL, "xtal");
-       xtal = clk_get_rate(xtal_clk);
-       clk_put(xtal_clk);
-
-       /* now we've got our machine bits initialised, work out what
-        * clocks we've got */
-
-       fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
-
-       tmp = __raw_readl(S3C2410_CLKDIVN);
-
-       /* work out clock scalings */
-
-       hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);
-       pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);
-
-       /* print brieft summary of clocks, etc */
-
-       printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
-              print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
-
-       /* initialise the clocks here, to allow other things like the
-        * console to use them
-        */
-
-       s3c24xx_setup_clocks(fclk, hclk, pclk);
-}
-
-/* fake ARMCLK for use with cpufreq, etc. */
-
-static struct clk s3c2410_armclk = {
-       .name   = "armclk",
-       .parent = &clk_f,
-       .id     = -1,
-};
-
-static struct clk_lookup s3c2410_clk_lookup[] = {
-       CLKDEV_INIT(NULL, "clk_uart_baud0", &clk_p),
-       CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
-};
-
-void __init s3c2410_init_clocks(int xtal)
-{
-       s3c24xx_register_baseclocks(xtal);
-       s3c2410_setup_clocks();
-       s3c2410_baseclk_add();
-       s3c24xx_register_clock(&s3c2410_armclk);
-       clkdev_add_table(s3c2410_clk_lookup, ARRAY_SIZE(s3c2410_clk_lookup));
-}
-
-struct bus_type s3c2410_subsys = {
-       .name = "s3c2410-core",
-       .dev_name = "s3c2410-core",
-};
-
-/* Note, we would have liked to name this s3c2410-core, but we cannot
- * register two subsystems with the same name.
- */
-struct bus_type s3c2410a_subsys = {
-       .name = "s3c2410a-core",
-       .dev_name = "s3c2410a-core",
-};
-
-static struct device s3c2410_dev = {
-       .bus            = &s3c2410_subsys,
-};
-
-/* need to register the subsystem before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2410 based system)
- * as a driver which may support both 2410 and 2440 may try and use it.
-*/
-
-static int __init s3c2410_core_init(void)
-{
-       return subsys_system_register(&s3c2410_subsys, NULL);
-}
-
-core_initcall(s3c2410_core_init);
-
-static int __init s3c2410a_core_init(void)
-{
-       return subsys_system_register(&s3c2410a_subsys, NULL);
-}
-
-core_initcall(s3c2410a_core_init);
-
-int __init s3c2410_init(void)
-{
-       printk("S3C2410: Initialising architecture\n");
-
-#ifdef CONFIG_PM
-       register_syscore_ops(&s3c2410_pm_syscore_ops);
-#endif
-       register_syscore_ops(&s3c24xx_irq_syscore_ops);
-
-       return device_register(&s3c2410_dev);
-}
-
-int __init s3c2410a_init(void)
-{
-       s3c2410_dev.bus = &s3c2410a_subsys;
-       return s3c2410_init();
-}
-
-void s3c2410_restart(char mode, const char *cmd)
-{
-       if (mode == 's') {
-               soft_restart(0);
-       }
-
-       arch_wdt_reset();
-
-       /* we'll take a jump through zero as a poor second */
-       soft_restart(0);
-}
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
deleted file mode 100644 (file)
index dd5b638..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/sleep.S
- *
- * Copyright (c) 2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 Power Manager (Suspend-To-RAM) support
- *
- * Based on PXA/SA1100 sleep code by:
- *     Nicolas Pitre, (c) 2002 Monta Vista Software Inc
- *     Cliff Brake, (c) 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/regs-clock.h>
-#include <mach/regs-mem.h>
-#include <plat/regs-serial.h>
-
-       /* s3c2410_cpu_suspend
-        *
-        * put the cpu into sleep mode
-       */
-
-ENTRY(s3c2410_cpu_suspend)
-       @@ prepare cpu to sleep
-
-       ldr     r4, =S3C2410_REFRESH
-       ldr     r5, =S3C24XX_MISCCR
-       ldr     r6, =S3C2410_CLKCON
-       ldr     r7, [ r4 ]              @ get REFRESH (and ensure in TLB)
-       ldr     r8, [ r5 ]              @ get MISCCR (and ensure in TLB)
-       ldr     r9, [ r6 ]              @ get CLKCON (and ensure in TLB)
-
-       orr     r7, r7, #S3C2410_REFRESH_SELF   @ SDRAM sleep command
-       orr     r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
-       orr     r9, r9, #S3C2410_CLKCON_POWER   @ power down command
-
-       teq     pc, #0                  @ first as a trial-run to load cache
-       bl      s3c2410_do_sleep
-       teq     r0, r0                  @ now do it for real
-       b       s3c2410_do_sleep        @
-
-       @@ align next bit of code to cache line
-       .align  5
-s3c2410_do_sleep:
-       streq   r7, [ r4 ]                      @ SDRAM sleep command
-       streq   r8, [ r5 ]                      @ SDRAM power-down config
-       streq   r9, [ r6 ]                      @ CPU sleep
-1:     beq     1b
-       mov     pc, r14
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
deleted file mode 100644 (file)
index 29bd3d9..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/usb-simtec.c
- *
- * Copyright 2004-2005 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.simtec.co.uk/products/EB2410ITX/
- *
- * Simtec BAST and Thorcom VR1000 USB port support functions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#define DEBUG
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/gpio.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <plat/usb-control.h>
-#include <plat/devs.h>
-
-#include "usb-simtec.h"
-
-/* control power and monitor over-current events on various Simtec
- * designed boards.
-*/
-
-static unsigned int power_state[2];
-
-static void
-usb_simtec_powercontrol(int port, int to)
-{
-       pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
-
-       power_state[port] = to;
-
-       if (power_state[0] && power_state[1])
-               gpio_set_value(S3C2410_GPB(4), 0);
-       else
-               gpio_set_value(S3C2410_GPB(4), 1);
-}
-
-static irqreturn_t
-usb_simtec_ocirq(int irq, void *pw)
-{
-       struct s3c2410_hcd_info *info = pw;
-
-       if (gpio_get_value(S3C2410_GPG(10)) == 0) {
-               pr_debug("usb_simtec: over-current irq (oc detected)\n");
-               s3c2410_usb_report_oc(info, 3);
-       } else {
-               pr_debug("usb_simtec: over-current irq (oc cleared)\n");
-               s3c2410_usb_report_oc(info, 0);
-       }
-
-       return IRQ_HANDLED;
-}
-
-static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
-{
-       int ret;
-
-       if (on) {
-               ret = request_irq(IRQ_USBOC, usb_simtec_ocirq,
-                                 IRQF_DISABLED | IRQF_TRIGGER_RISING |
-                                  IRQF_TRIGGER_FALLING,
-                                 "USB Over-current", info);
-               if (ret != 0) {
-                       printk(KERN_ERR "failed to request usb oc irq\n");
-               }
-       } else {
-               free_irq(IRQ_USBOC, info);
-       }
-}
-
-static struct s3c2410_hcd_info usb_simtec_info __initdata = {
-       .port[0]        = {
-               .flags  = S3C_HCDFLG_USED
-       },
-       .port[1]        = {
-               .flags  = S3C_HCDFLG_USED
-       },
-
-       .power_control  = usb_simtec_powercontrol,
-       .enable_oc      = usb_simtec_enableoc,
-};
-
-
-int usb_simtec_init(void)
-{
-       int ret;
-
-       printk("USB Power Control, Copyright 2004 Simtec Electronics\n");
-
-       ret = gpio_request(S3C2410_GPB(4), "USB power control");
-       if (ret < 0) {
-               pr_err("%s: failed to get GPB4\n", __func__);
-               return ret;
-       }
-
-       ret = gpio_request(S3C2410_GPG(10), "USB overcurrent");
-       if (ret < 0) {
-               pr_err("%s: failed to get GPG10\n", __func__);
-               gpio_free(S3C2410_GPB(4));
-               return ret;
-       }
-
-       /* turn power on */
-       gpio_direction_output(S3C2410_GPB(4), 1);
-       gpio_direction_input(S3C2410_GPG(10));
-
-       s3c_ohci_set_platdata(&usb_simtec_info);
-       return 0;
-}
diff --git a/arch/arm/mach-s3c2410/usb-simtec.h b/arch/arm/mach-s3c2410/usb-simtec.h
deleted file mode 100644 (file)
index 03842ed..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/usb-simtec.h
- *
- * Copyright (c) 2004 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.simtec.co.uk/products/EB2410ITX/
- *
- * Simtec BAST and Thorcom VR1000 USB port support functions
- *
- * 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.
-*/
-
-extern int usb_simtec_init(void);
-
index b8b9029..c5256f4 100644 (file)
@@ -2,41 +2,6 @@
 #
 # Licensed under GPLv2
 
-config CPU_S3C2412
-       bool
-       depends on ARCH_S3C2410
-       select CPU_ARM926T
-       select CPU_LLSERIAL_S3C2440
-       select S3C2412_PM if PM
-       select S3C2412_DMA if S3C2410_DMA
-       help
-         Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
-
-config CPU_S3C2412_ONLY
-       bool
-       depends on ARCH_S3C2410 && !CPU_S3C2410 && \
-                  !CPU_S3C2416 && !CPU_S3C2440 && !CPU_S3C2442 && \
-                  !CPU_S3C2443 && CPU_S3C2412
-       default y if CPU_S3C2412
-
-config S3C2412_DMA
-       bool
-       depends on CPU_S3C2412
-       help
-         Internal config node for S3C2412 DMA support
-
-config S3C2412_PM
-       bool
-       select S3C2412_PM_SLEEP
-       help
-         Internal config node to apply S3C2412 power management
-
-config S3C2412_PM_SLEEP
-       bool
-       help
-         Internal config node to apply sleep for S3C2412 power management.
-         Can be selected by another SoCs with similar sleep procedure.
-
 # Note, the S3C2412 IOtiming support is in plat-s3c24xx
 
 config S3C2412_CPUFREQ
@@ -46,53 +11,3 @@ config S3C2412_CPUFREQ
        default y
        help
          CPU Frequency scaling support for S3C2412 and S3C2413 SoC CPUs.
-
-menu "S3C2412 Machines"
-
-config MACH_JIVE
-       bool "Logitech Jive"
-       select CPU_S3C2412
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-         Say Y here if you are using the Logitech Jive.
-
-config MACH_JIVE_SHOW_BOOTLOADER
-       bool "Allow access to bootloader partitions in MTD (EXPERIMENTAL)"
-       depends on MACH_JIVE && EXPERIMENTAL
-
-config MACH_SMDK2413
-       bool "SMDK2413"
-       select CPU_S3C2412
-       select MACH_S3C2413
-       select MACH_SMDK
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-         Say Y here if you are using an SMDK2413
-
-config MACH_S3C2413
-       bool
-       help
-         Internal node for S3C2413 version of SMDK2413, so that
-         machine_is_s3c2413() will work when MACH_SMDK2413 is
-         selected
-
-config MACH_SMDK2412
-       bool "SMDK2412"
-       select MACH_SMDK2413
-       help
-         Say Y here if you are using an SMDK2412
-
-         Note, this shares support with SMDK2413, so will automatically
-         select MACH_SMDK2413.
-
-config MACH_VSTMS
-       bool "VMSTMS"
-       select CPU_S3C2412
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-         Say Y here if you are using an VSTMS board
-
-endmenu
index 7e4d95f..41a6c27 100644 (file)
@@ -9,16 +9,4 @@ obj-m                          :=
 obj-n                          :=
 obj-                           :=
 
-obj-$(CONFIG_CPU_S3C2412)      += s3c2412.o
-obj-$(CONFIG_CPU_S3C2412)      += irq.o
-obj-$(CONFIG_CPU_S3C2412)      += clock.o
-obj-$(CONFIG_S3C2412_DMA)      += dma.o
-obj-$(CONFIG_S3C2412_PM)       += pm.o
-obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep.o
 obj-$(CONFIG_S3C2412_CPUFREQ)  += cpu-freq.o
-
-# Machine support
-
-obj-$(CONFIG_MACH_JIVE)                += mach-jive.o
-obj-$(CONFIG_MACH_SMDK2413)    += mach-smdk2413.o
-obj-$(CONFIG_MACH_VSTMS)       += mach-vstms.o
diff --git a/arch/arm/mach-s3c2412/clock.c b/arch/arm/mach-s3c2412/clock.c
deleted file mode 100644 (file)
index d10b695..0000000
+++ /dev/null
@@ -1,763 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/clock.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2412,S3C2413 Clock control support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-clock.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/s3c2412.h>
-#include <plat/clock.h>
-#include <plat/cpu.h>
-
-/* We currently have to assume that the system is running
- * from the XTPll input, and that all ***REFCLKs are being
- * fed from it, as we cannot read the state of OM[4] from
- * software.
- *
- * It would be possible for each board initialisation to
- * set the correct muxing at initialisation
-*/
-
-static int s3c2412_clkcon_enable(struct clk *clk, int enable)
-{
-       unsigned int clocks = clk->ctrlbit;
-       unsigned long clkcon;
-
-       clkcon = __raw_readl(S3C2410_CLKCON);
-
-       if (enable)
-               clkcon |= clocks;
-       else
-               clkcon &= ~clocks;
-
-       __raw_writel(clkcon, S3C2410_CLKCON);
-
-       return 0;
-}
-
-static int s3c2412_upll_enable(struct clk *clk, int enable)
-{
-       unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
-       unsigned long orig = upllcon;
-
-       if (!enable)
-               upllcon |= S3C2412_PLLCON_OFF;
-       else
-               upllcon &= ~S3C2412_PLLCON_OFF;
-
-       __raw_writel(upllcon, S3C2410_UPLLCON);
-
-       /* allow ~150uS for the PLL to settle and lock */
-
-       if (enable && (orig & S3C2412_PLLCON_OFF))
-               udelay(150);
-
-       return 0;
-}
-
-/* clock selections */
-
-static struct clk clk_erefclk = {
-       .name           = "erefclk",
-};
-
-static struct clk clk_urefclk = {
-       .name           = "urefclk",
-};
-
-static int s3c2412_setparent_usysclk(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_urefclk)
-               clksrc &= ~S3C2412_CLKSRC_USYSCLK_UPLL;
-       else if (parent == &clk_upll)
-               clksrc |= S3C2412_CLKSRC_USYSCLK_UPLL;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-
-static struct clk clk_usysclk = {
-       .name           = "usysclk",
-       .parent         = &clk_xtal,
-       .ops            = &(struct clk_ops) {
-               .set_parent     = s3c2412_setparent_usysclk,
-       },
-};
-
-static struct clk clk_mrefclk = {
-       .name           = "mrefclk",
-       .parent         = &clk_xtal,
-};
-
-static struct clk clk_mdivclk = {
-       .name           = "mdivclk",
-       .parent         = &clk_xtal,
-};
-
-static int s3c2412_setparent_usbsrc(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_usysclk)
-               clksrc &= ~S3C2412_CLKSRC_USBCLK_HCLK;
-       else if (parent == &clk_h)
-               clksrc |= S3C2412_CLKSRC_USBCLK_HCLK;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-
-static unsigned long s3c2412_roundrate_usbsrc(struct clk *clk,
-                                             unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       int div;
-
-       if (rate > parent_rate)
-               return parent_rate;
-
-       div = parent_rate / rate;
-       if (div > 2)
-               div = 2;
-
-       return parent_rate / div;
-}
-
-static unsigned long s3c2412_getrate_usbsrc(struct clk *clk)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
-
-       return parent_rate / ((div & S3C2412_CLKDIVN_USB48DIV) ? 2 : 1);
-}
-
-static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
-
-       rate = s3c2412_roundrate_usbsrc(clk, rate);
-
-       if ((parent_rate / rate) == 2)
-               clkdivn |= S3C2412_CLKDIVN_USB48DIV;
-       else
-               clkdivn &= ~S3C2412_CLKDIVN_USB48DIV;
-
-       __raw_writel(clkdivn, S3C2410_CLKDIVN);
-       return 0;
-}
-
-static struct clk clk_usbsrc = {
-       .name           = "usbsrc",
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2412_getrate_usbsrc,
-               .set_rate       = s3c2412_setrate_usbsrc,
-               .round_rate     = s3c2412_roundrate_usbsrc,
-               .set_parent     = s3c2412_setparent_usbsrc,
-       },
-};
-
-static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_mdivclk)
-               clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL;
-       else if (parent == &clk_mpll)
-               clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-
-static struct clk clk_msysclk = {
-       .name           = "msysclk",
-       .ops            = &(struct clk_ops) {
-               .set_parent     = s3c2412_setparent_msysclk,
-       },
-};
-
-static int s3c2412_setparent_armclk(struct clk *clk, struct clk *parent)
-{
-       unsigned long flags;
-       unsigned long clkdiv;
-       unsigned long dvs;
-
-       /* Note, we current equate fclk andf msysclk for S3C2412 */
-
-       if (parent == &clk_msysclk || parent == &clk_f)
-               dvs = 0;
-       else if (parent == &clk_h)
-               dvs = S3C2412_CLKDIVN_DVSEN;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       /* update this under irq lockdown, clkdivn is not protected
-        * by the clock system. */
-
-       local_irq_save(flags);
-
-       clkdiv  = __raw_readl(S3C2410_CLKDIVN);
-       clkdiv &= ~S3C2412_CLKDIVN_DVSEN;
-       clkdiv |= dvs;
-       __raw_writel(clkdiv, S3C2410_CLKDIVN);
-
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-static struct clk clk_armclk = {
-       .name           = "armclk",
-       .parent         = &clk_msysclk,
-       .ops            = &(struct clk_ops) {
-               .set_parent     = s3c2412_setparent_armclk,
-       },
-};
-
-/* these next clocks have an divider immediately after them,
- * so we can register them with their divider and leave out the
- * intermediate clock stage
-*/
-static unsigned long s3c2412_roundrate_clksrc(struct clk *clk,
-                                             unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       int div;
-
-       if (rate > parent_rate)
-               return parent_rate;
-
-       /* note, we remove the +/- 1 calculations as they cancel out */
-
-       div = (rate / parent_rate);
-
-       if (div < 1)
-               div = 1;
-       else if (div > 16)
-               div = 16;
-
-       return parent_rate / div;
-}
-
-static int s3c2412_setparent_uart(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_erefclk)
-               clksrc &= ~S3C2412_CLKSRC_UARTCLK_MPLL;
-       else if (parent == &clk_mpll)
-               clksrc |= S3C2412_CLKSRC_UARTCLK_MPLL;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-
-static unsigned long s3c2412_getrate_uart(struct clk *clk)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
-
-       div &= S3C2412_CLKDIVN_UARTDIV_MASK;
-       div >>= S3C2412_CLKDIVN_UARTDIV_SHIFT;
-
-       return parent_rate / (div + 1);
-}
-
-static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
-
-       rate = s3c2412_roundrate_clksrc(clk, rate);
-
-       clkdivn &= ~S3C2412_CLKDIVN_UARTDIV_MASK;
-       clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_UARTDIV_SHIFT;
-
-       __raw_writel(clkdivn, S3C2410_CLKDIVN);
-       return 0;
-}
-
-static struct clk clk_uart = {
-       .name           = "uartclk",
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2412_getrate_uart,
-               .set_rate       = s3c2412_setrate_uart,
-               .set_parent     = s3c2412_setparent_uart,
-               .round_rate     = s3c2412_roundrate_clksrc,
-       },
-};
-
-static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_erefclk)
-               clksrc &= ~S3C2412_CLKSRC_I2SCLK_MPLL;
-       else if (parent == &clk_mpll)
-               clksrc |= S3C2412_CLKSRC_I2SCLK_MPLL;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-
-static unsigned long s3c2412_getrate_i2s(struct clk *clk)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
-
-       div &= S3C2412_CLKDIVN_I2SDIV_MASK;
-       div >>= S3C2412_CLKDIVN_I2SDIV_SHIFT;
-
-       return parent_rate / (div + 1);
-}
-
-static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
-
-       rate = s3c2412_roundrate_clksrc(clk, rate);
-
-       clkdivn &= ~S3C2412_CLKDIVN_I2SDIV_MASK;
-       clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_I2SDIV_SHIFT;
-
-       __raw_writel(clkdivn, S3C2410_CLKDIVN);
-       return 0;
-}
-
-static struct clk clk_i2s = {
-       .name           = "i2sclk",
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2412_getrate_i2s,
-               .set_rate       = s3c2412_setrate_i2s,
-               .set_parent     = s3c2412_setparent_i2s,
-               .round_rate     = s3c2412_roundrate_clksrc,
-       },
-};
-
-static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-
-       if (parent == &clk_usysclk)
-               clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK;
-       else if (parent == &clk_h)
-               clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       __raw_writel(clksrc, S3C2412_CLKSRC);
-       return 0;
-}
-static unsigned long s3c2412_getrate_cam(struct clk *clk)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
-
-       div &= S3C2412_CLKDIVN_CAMDIV_MASK;
-       div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT;
-
-       return parent_rate / (div + 1);
-}
-
-static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
-
-       rate = s3c2412_roundrate_clksrc(clk, rate);
-
-       clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK;
-       clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT;
-
-       __raw_writel(clkdivn, S3C2410_CLKDIVN);
-       return 0;
-}
-
-static struct clk clk_cam = {
-       .name           = "camif-upll", /* same as 2440 name */
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2412_getrate_cam,
-               .set_rate       = s3c2412_setrate_cam,
-               .set_parent     = s3c2412_setparent_cam,
-               .round_rate     = s3c2412_roundrate_clksrc,
-       },
-};
-
-/* standard clock definitions */
-
-static struct clk init_clocks_disable[] = {
-       {
-               .name           = "nand",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_NAND,
-       }, {
-               .name           = "sdi",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_SDI,
-       }, {
-               .name           = "adc",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_ADC,
-       }, {
-               .name           = "i2c",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_IIC,
-       }, {
-               .name           = "iis",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_IIS,
-       }, {
-               .name           = "spi",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_SPI,
-       }
-};
-
-static struct clk init_clocks[] = {
-       {
-               .name           = "dma",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_DMA0,
-       }, {
-               .name           = "dma",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_DMA1,
-       }, {
-               .name           = "dma",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_DMA2,
-       }, {
-               .name           = "dma",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_DMA3,
-       }, {
-               .name           = "lcd",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_LCDC,
-       }, {
-               .name           = "gpio",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_GPIO,
-       }, {
-               .name           = "usb-host",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_USBH,
-       }, {
-               .name           = "usb-device",
-               .parent         = &clk_h,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_USBD,
-       }, {
-               .name           = "timers",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_PWMT,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2412-uart.0",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_UART0,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2412-uart.1",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_UART1,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2412-uart.2",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_UART2,
-       }, {
-               .name           = "rtc",
-               .parent         = &clk_p,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_RTC,
-       }, {
-               .name           = "watchdog",
-               .parent         = &clk_p,
-               .ctrlbit        = 0,
-       }, {
-               .name           = "usb-bus-gadget",
-               .parent         = &clk_usb_bus,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_USB_DEV48,
-       }, {
-               .name           = "usb-bus-host",
-               .parent         = &clk_usb_bus,
-               .enable         = s3c2412_clkcon_enable,
-               .ctrlbit        = S3C2412_CLKCON_USB_HOST48,
-       }
-};
-
-/* clocks to add where we need to check their parentage */
-
-struct clk_init {
-       struct clk      *clk;
-       unsigned int     bit;
-       struct clk      *src_0;
-       struct clk      *src_1;
-};
-
-static struct clk_init clks_src[] __initdata = {
-       {
-               .clk    = &clk_usysclk,
-               .bit    = S3C2412_CLKSRC_USBCLK_HCLK,
-               .src_0  = &clk_urefclk,
-               .src_1  = &clk_upll,
-       }, {
-               .clk    = &clk_i2s,
-               .bit    = S3C2412_CLKSRC_I2SCLK_MPLL,
-               .src_0  = &clk_erefclk,
-               .src_1  = &clk_mpll,
-       }, {
-               .clk    = &clk_cam,
-               .bit    = S3C2412_CLKSRC_CAMCLK_HCLK,
-               .src_0  = &clk_usysclk,
-               .src_1  = &clk_h,
-       }, {
-               .clk    = &clk_msysclk,
-               .bit    = S3C2412_CLKSRC_MSYSCLK_MPLL,
-               .src_0  = &clk_mdivclk,
-               .src_1  = &clk_mpll,
-       }, {
-               .clk    = &clk_uart,
-               .bit    = S3C2412_CLKSRC_UARTCLK_MPLL,
-               .src_0  = &clk_erefclk,
-               .src_1  = &clk_mpll,
-       }, {
-               .clk    = &clk_usbsrc,
-               .bit    = S3C2412_CLKSRC_USBCLK_HCLK,
-               .src_0  = &clk_usysclk,
-               .src_1  = &clk_h,
-       /* here we assume  OM[4] select xtal */
-       }, {
-               .clk    = &clk_erefclk,
-               .bit    = S3C2412_CLKSRC_EREFCLK_EXTCLK,
-               .src_0  = &clk_xtal,
-               .src_1  = &clk_ext,
-       }, {
-               .clk    = &clk_urefclk,
-               .bit    = S3C2412_CLKSRC_UREFCLK_EXTCLK,
-               .src_0  = &clk_xtal,
-               .src_1  = &clk_ext,
-       },
-};
-
-/* s3c2412_clk_initparents
- *
- * Initialise the parents for the clocks that we get at start-time
-*/
-
-static void __init s3c2412_clk_initparents(void)
-{
-       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
-       struct clk_init *cip = clks_src;
-       struct clk *src;
-       int ptr;
-       int ret;
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) {
-               ret = s3c24xx_register_clock(cip->clk);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              cip->clk->name, ret);
-               }
-
-               src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0;
-
-               printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name);
-               clk_set_parent(cip->clk, src);
-       }
-}
-
-/* clocks to add straight away */
-
-static struct clk *clks[] __initdata = {
-       &clk_ext,
-       &clk_usb_bus,
-       &clk_mrefclk,
-       &clk_armclk,
-};
-
-static struct clk_lookup s3c2412_clk_lookup[] = {
-       CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
-       CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
-       CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_usysclk),
-};
-
-int __init s3c2412_baseclk_add(void)
-{
-       unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
-       unsigned int dvs;
-       struct clk *clkp;
-       int ret;
-       int ptr;
-
-       clk_upll.enable = s3c2412_upll_enable;
-       clk_usb_bus.parent = &clk_usbsrc;
-       clk_usb_bus.rate = 0x0;
-
-       clk_f.parent = &clk_msysclk;
-
-       s3c2412_clk_initparents();
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
-               clkp = clks[ptr];
-
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-       }
-
-       /* set the dvs state according to what we got at boot time */
-
-       dvs = __raw_readl(S3C2410_CLKDIVN) & S3C2412_CLKDIVN_DVSEN;
-
-       if (dvs)
-               clk_armclk.parent = &clk_h;
-
-       printk(KERN_INFO "S3C2412: DVS is %s\n", dvs ? "on" : "off");
-
-       /* ensure usb bus clock is within correct rate of 48MHz */
-
-       if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) {
-               printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n");
-
-               /* for the moment, let's use the UPLL, and see if we can
-                * get 48MHz */
-
-               clk_set_parent(&clk_usysclk, &clk_upll);
-               clk_set_parent(&clk_usbsrc, &clk_usysclk);
-               clk_set_rate(&clk_usbsrc, 48*1000*1000);
-       }
-
-       printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
-              (__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on",
-              print_mhz(clk_get_rate(&clk_upll)),
-              print_mhz(clk_get_rate(&clk_usb_bus)));
-
-       /* register clocks from clock array */
-
-       clkp = init_clocks;
-       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
-               /* ensure that we note the clock state */
-
-               clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
-
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-       }
-
-       /* We must be careful disabling the clocks we are not intending to
-        * be using at boot time, as subsystems such as the LCD which do
-        * their own DMA requests to the bus can cause the system to lockup
-        * if they where in the middle of requesting bus access.
-        *
-        * Disabling the LCD clock if the LCD is active is very dangerous,
-        * and therefore the bootloader should be careful to not enable
-        * the LCD clock if it is not needed.
-       */
-
-       /* install (and disable) the clocks we do not need immediately */
-
-       clkp = init_clocks_disable;
-       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
-
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-
-               s3c2412_clkcon_enable(clkp, 0);
-       }
-
-       clkdev_add_table(s3c2412_clk_lookup, ARRAY_SIZE(s3c2412_clk_lookup));
-       s3c_pwmclk_init();
-       return 0;
-}
diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c2412/dma.c
deleted file mode 100644 (file)
index 38472ac..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/dma.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2412 DMA selection
- *
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#include <mach/dma.h>
-
-#include <plat/dma-s3c24xx.h>
-#include <plat/cpu.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
-#include <plat/regs-dma.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
-#include <plat/regs-spi.h>
-
-#define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
-
-static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
-       [DMACH_XD0] = {
-               .name           = "xdreq0",
-               .channels       = MAP(S3C2412_DMAREQSEL_XDREQ0),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_XDREQ0),
-       },
-       [DMACH_XD1] = {
-               .name           = "xdreq1",
-               .channels       = MAP(S3C2412_DMAREQSEL_XDREQ1),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_XDREQ1),
-       },
-       [DMACH_SDI] = {
-               .name           = "sdi",
-               .channels       = MAP(S3C2412_DMAREQSEL_SDI),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_SDI),
-       },
-       [DMACH_SPI0] = {
-               .name           = "spi0",
-               .channels       = MAP(S3C2412_DMAREQSEL_SPI0TX),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_SPI0RX),
-       },
-       [DMACH_SPI1] = {
-               .name           = "spi1",
-               .channels       = MAP(S3C2412_DMAREQSEL_SPI1TX),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_SPI1RX),
-       },
-       [DMACH_UART0] = {
-               .name           = "uart0",
-               .channels       = MAP(S3C2412_DMAREQSEL_UART0_0),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART0_0),
-       },
-       [DMACH_UART1] = {
-               .name           = "uart1",
-               .channels       = MAP(S3C2412_DMAREQSEL_UART1_0),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART1_0),
-       },
-       [DMACH_UART2] = {
-               .name           = "uart2",
-               .channels       = MAP(S3C2412_DMAREQSEL_UART2_0),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART2_0),
-       },
-       [DMACH_UART0_SRC2] = {
-               .name           = "uart0",
-               .channels       = MAP(S3C2412_DMAREQSEL_UART0_1),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART0_1),
-       },
-       [DMACH_UART1_SRC2] = {
-               .name           = "uart1",
-               .channels       = MAP(S3C2412_DMAREQSEL_UART1_1),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART1_1),
-       },
-       [DMACH_UART2_SRC2] = {
-               .name           = "uart2",
-               .channels       = MAP(S3C2412_DMAREQSEL_UART2_1),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART2_1),
-       },
-       [DMACH_TIMER] = {
-               .name           = "timer",
-               .channels       = MAP(S3C2412_DMAREQSEL_TIMER),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_TIMER),
-       },
-       [DMACH_I2S_IN] = {
-               .name           = "i2s-sdi",
-               .channels       = MAP(S3C2412_DMAREQSEL_I2SRX),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_I2SRX),
-       },
-       [DMACH_I2S_OUT] = {
-               .name           = "i2s-sdo",
-               .channels       = MAP(S3C2412_DMAREQSEL_I2STX),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_I2STX),
-       },
-       [DMACH_USB_EP1] = {
-               .name           = "usb-ep1",
-               .channels       = MAP(S3C2412_DMAREQSEL_USBEP1),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_USBEP1),
-       },
-       [DMACH_USB_EP2] = {
-               .name           = "usb-ep2",
-               .channels       = MAP(S3C2412_DMAREQSEL_USBEP2),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_USBEP2),
-       },
-       [DMACH_USB_EP3] = {
-               .name           = "usb-ep3",
-               .channels       = MAP(S3C2412_DMAREQSEL_USBEP3),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_USBEP3),
-       },
-       [DMACH_USB_EP4] = {
-               .name           = "usb-ep4",
-               .channels       = MAP(S3C2412_DMAREQSEL_USBEP4),
-               .channels_rx    = MAP(S3C2412_DMAREQSEL_USBEP4),
-       },
-};
-
-static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan,
-                                 struct s3c24xx_dma_map *map,
-                                 enum dma_data_direction dir)
-{
-       unsigned long chsel;
-
-       if (dir == DMA_FROM_DEVICE)
-               chsel = map->channels_rx[0];
-       else
-               chsel = map->channels[0];
-
-       chsel &= ~DMA_CH_VALID;
-       chsel |= S3C2412_DMAREQSEL_HW;
-
-       writel(chsel, chan->regs + S3C2412_DMA_DMAREQSEL);
-}
-
-static void s3c2412_dma_select(struct s3c2410_dma_chan *chan,
-                              struct s3c24xx_dma_map *map)
-{
-       s3c2412_dma_direction(chan, map, chan->source);
-}
-
-static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = {
-       .select         = s3c2412_dma_select,
-       .direction      = s3c2412_dma_direction,
-       .dcon_mask      = 0,
-       .map            = s3c2412_dma_mappings,
-       .map_size       = ARRAY_SIZE(s3c2412_dma_mappings),
-};
-
-static int __init s3c2412_dma_add(struct device *dev,
-                                 struct subsys_interface *sif)
-{
-       s3c2410_dma_init();
-       return s3c24xx_dma_init_map(&s3c2412_dma_sel);
-}
-
-static struct subsys_interface s3c2412_dma_interface = {
-       .name           = "s3c2412_dma",
-       .subsys         = &s3c2412_subsys,
-       .add_dev        = s3c2412_dma_add,
-};
-
-static int __init s3c2412_dma_init(void)
-{
-       return subsys_interface_register(&s3c2412_dma_interface);
-}
-
-arch_initcall(s3c2412_dma_init);
diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c
deleted file mode 100644 (file)
index e65619d..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/irq.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-power.h>
-
-#include <plat/cpu.h>
-#include <plat/irq.h>
-#include <plat/pm.h>
-
-#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
-#define INTMSK_SUB(start, end) (INTMSK(start, end) << ((start - S3C2410_IRQSUB(0))))
-
-/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by
- * having them turn up in both the INT* and the EINT* registers. Whilst
- * both show the status, they both now need to be acked when the IRQs
- * go off.
-*/
-
-static void
-s3c2412_irq_mask(struct irq_data *data)
-{
-       unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
-       unsigned long mask;
-
-       mask = __raw_readl(S3C2410_INTMSK);
-       __raw_writel(mask | bitval, S3C2410_INTMSK);
-
-       mask = __raw_readl(S3C2412_EINTMASK);
-       __raw_writel(mask | bitval, S3C2412_EINTMASK);
-}
-
-static inline void
-s3c2412_irq_ack(struct irq_data *data)
-{
-       unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
-
-       __raw_writel(bitval, S3C2412_EINTPEND);
-       __raw_writel(bitval, S3C2410_SRCPND);
-       __raw_writel(bitval, S3C2410_INTPND);
-}
-
-static inline void
-s3c2412_irq_maskack(struct irq_data *data)
-{
-       unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
-       unsigned long mask;
-
-       mask = __raw_readl(S3C2410_INTMSK);
-       __raw_writel(mask|bitval, S3C2410_INTMSK);
-
-       mask = __raw_readl(S3C2412_EINTMASK);
-       __raw_writel(mask | bitval, S3C2412_EINTMASK);
-
-       __raw_writel(bitval, S3C2412_EINTPEND);
-       __raw_writel(bitval, S3C2410_SRCPND);
-       __raw_writel(bitval, S3C2410_INTPND);
-}
-
-static void
-s3c2412_irq_unmask(struct irq_data *data)
-{
-       unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
-       unsigned long mask;
-
-       mask = __raw_readl(S3C2412_EINTMASK);
-       __raw_writel(mask & ~bitval, S3C2412_EINTMASK);
-
-       mask = __raw_readl(S3C2410_INTMSK);
-       __raw_writel(mask & ~bitval, S3C2410_INTMSK);
-}
-
-static struct irq_chip s3c2412_irq_eint0t4 = {
-       .irq_ack        = s3c2412_irq_ack,
-       .irq_mask       = s3c2412_irq_mask,
-       .irq_unmask     = s3c2412_irq_unmask,
-       .irq_set_wake   = s3c_irq_wake,
-       .irq_set_type   = s3c_irqext_type,
-};
-
-#define INTBIT(x)      (1 << ((x) - S3C2410_IRQSUB(0)))
-
-/* CF and SDI sub interrupts */
-
-static void s3c2412_irq_demux_cfsdi(unsigned int irq, struct irq_desc *desc)
-{
-       unsigned int subsrc, submsk;
-
-       subsrc = __raw_readl(S3C2410_SUBSRCPND);
-       submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-       subsrc  &= ~submsk;
-
-       if (subsrc & INTBIT(IRQ_S3C2412_SDI))
-               generic_handle_irq(IRQ_S3C2412_SDI);
-
-       if (subsrc & INTBIT(IRQ_S3C2412_CF))
-               generic_handle_irq(IRQ_S3C2412_CF);
-}
-
-#define INTMSK_CFSDI   (1UL << (IRQ_S3C2412_CFSDI - IRQ_EINT0))
-#define SUBMSK_CFSDI   INTMSK_SUB(IRQ_S3C2412_SDI, IRQ_S3C2412_CF)
-
-static void s3c2412_irq_cfsdi_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI);
-}
-
-static void s3c2412_irq_cfsdi_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_CFSDI);
-}
-
-static void s3c2412_irq_cfsdi_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI);
-}
-
-static struct irq_chip s3c2412_irq_cfsdi = {
-       .name           = "s3c2412-cfsdi",
-       .irq_ack        = s3c2412_irq_cfsdi_ack,
-       .irq_mask       = s3c2412_irq_cfsdi_mask,
-       .irq_unmask     = s3c2412_irq_cfsdi_unmask,
-};
-
-static int s3c2412_irq_rtc_wake(struct irq_data *data, unsigned int state)
-{
-       unsigned long pwrcfg;
-
-       pwrcfg = __raw_readl(S3C2412_PWRCFG);
-       if (state)
-               pwrcfg &= ~S3C2412_PWRCFG_RTC_MASKIRQ;
-       else
-               pwrcfg |= S3C2412_PWRCFG_RTC_MASKIRQ;
-       __raw_writel(pwrcfg, S3C2412_PWRCFG);
-
-       return s3c_irq_chip.irq_set_wake(data, state);
-}
-
-static struct irq_chip s3c2412_irq_rtc_chip;
-
-static int s3c2412_irq_add(struct device *dev, struct subsys_interface *sif)
-{
-       unsigned int irqno;
-
-       for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
-               irq_set_chip_and_handler(irqno, &s3c2412_irq_eint0t4,
-                                        handle_edge_irq);
-               set_irq_flags(irqno, IRQF_VALID);
-       }
-
-       /* add demux support for CF/SDI */
-
-       irq_set_chained_handler(IRQ_S3C2412_CFSDI, s3c2412_irq_demux_cfsdi);
-
-       for (irqno = IRQ_S3C2412_SDI; irqno <= IRQ_S3C2412_CF; irqno++) {
-               irq_set_chip_and_handler(irqno, &s3c2412_irq_cfsdi,
-                                        handle_level_irq);
-               set_irq_flags(irqno, IRQF_VALID);
-       }
-
-       /* change RTC IRQ's set wake method */
-
-       s3c2412_irq_rtc_chip = s3c_irq_chip;
-       s3c2412_irq_rtc_chip.irq_set_wake = s3c2412_irq_rtc_wake;
-
-       irq_set_chip(IRQ_RTC, &s3c2412_irq_rtc_chip);
-
-       return 0;
-}
-
-static struct subsys_interface s3c2412_irq_interface = {
-       .name           = "s3c2412_irq",
-       .subsys         = &s3c2412_subsys,
-       .add_dev        = s3c2412_irq_add,
-};
-
-static int s3c2412_irq_init(void)
-{
-       return subsys_interface_register(&s3c2412_irq_interface);
-}
-
-arch_initcall(s3c2412_irq_init);
diff --git a/arch/arm/mach-s3c2412/mach-jive.c b/arch/arm/mach-s3c2412/mach-jive.c
deleted file mode 100644 (file)
index ae73ba3..0000000
+++ /dev/null
@@ -1,666 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/mach-jive.c
- *
- * Copyright 2007 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/syscore_ops.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-
-#include <video/ili9320.h>
-
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_gpio.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <plat/regs-serial.h>
-#include <plat/nand.h>
-#include <plat/iic.h>
-
-#include <mach/regs-power.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <mach/fb.h>
-
-#include <asm/mach-types.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <plat/s3c2412.h>
-#include <plat/gpio-cfg.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/udc.h>
-
-static struct map_desc jive_iodesc[] __initdata = {
-};
-
-#define UCON S3C2410_UCON_DEFAULT
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg jive_uartcfgs[] = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       }
-};
-
-/* Jive flash assignment
- *
- * 0x00000000-0x00028000 : uboot
- * 0x00028000-0x0002c000 : uboot env
- * 0x0002c000-0x00030000 : spare
- * 0x00030000-0x00200000 : zimage A
- * 0x00200000-0x01600000 : cramfs A
- * 0x01600000-0x017d0000 : zimage B
- * 0x017d0000-0x02bd0000 : cramfs B
- * 0x02bd0000-0x03fd0000 : yaffs
- */
-static struct mtd_partition __initdata jive_imageA_nand_part[] = {
-
-#ifdef CONFIG_MACH_JIVE_SHOW_BOOTLOADER
-       /* Don't allow access to the bootloader from linux */
-       {
-               .name           = "uboot",
-               .offset         = 0,
-               .size           = (160 * SZ_1K),
-               .mask_flags     = MTD_WRITEABLE, /* force read-only */
-       },
-
-       /* spare */
-        {
-                .name           = "spare",
-                .offset         = (176 * SZ_1K),
-                .size           = (16 * SZ_1K),
-        },
-#endif
-
-       /* booted images */
-        {
-               .name           = "kernel (ro)",
-               .offset         = (192 * SZ_1K),
-               .size           = (SZ_2M) - (192 * SZ_1K),
-               .mask_flags     = MTD_WRITEABLE, /* force read-only */
-        }, {
-                .name           = "root (ro)",
-                .offset         = (SZ_2M),
-                .size           = (20 * SZ_1M),
-               .mask_flags     = MTD_WRITEABLE, /* force read-only */
-        },
-
-       /* yaffs */
-       {
-               .name           = "yaffs",
-               .offset         = (44 * SZ_1M),
-               .size           = (20 * SZ_1M),
-       },
-
-       /* bootloader environment */
-       {
-                .name          = "env",
-               .offset         = (160 * SZ_1K),
-               .size           = (16 * SZ_1K),
-       },
-
-       /* upgrade images */
-        {
-               .name           = "zimage",
-               .offset         = (22 * SZ_1M),
-               .size           = (2 * SZ_1M) - (192 * SZ_1K),
-        }, {
-               .name           = "cramfs",
-               .offset         = (24 * SZ_1M) - (192*SZ_1K),
-               .size           = (20 * SZ_1M),
-        },
-};
-
-static struct mtd_partition __initdata jive_imageB_nand_part[] = {
-
-#ifdef CONFIG_MACH_JIVE_SHOW_BOOTLOADER
-       /* Don't allow access to the bootloader from linux */
-       {
-               .name           = "uboot",
-               .offset         = 0,
-               .size           = (160 * SZ_1K),
-               .mask_flags     = MTD_WRITEABLE, /* force read-only */
-       },
-
-       /* spare */
-        {
-                .name           = "spare",
-                .offset         = (176 * SZ_1K),
-                .size           = (16 * SZ_1K),
-        },
-#endif
-
-       /* booted images */
-        {
-               .name           = "kernel (ro)",
-               .offset         = (22 * SZ_1M),
-               .size           = (2 * SZ_1M) - (192 * SZ_1K),
-               .mask_flags     = MTD_WRITEABLE, /* force read-only */
-        },
-       {
-               .name           = "root (ro)",
-               .offset         = (24 * SZ_1M) - (192 * SZ_1K),
-                .size          = (20 * SZ_1M),
-               .mask_flags     = MTD_WRITEABLE, /* force read-only */
-       },
-
-       /* yaffs */
-       {
-               .name           = "yaffs",
-               .offset         = (44 * SZ_1M),
-               .size           = (20 * SZ_1M),
-        },
-
-       /* bootloader environment */
-       {
-               .name           = "env",
-               .offset         = (160 * SZ_1K),
-               .size           = (16 * SZ_1K),
-       },
-
-       /* upgrade images */
-       {
-               .name           = "zimage",
-               .offset         = (192 * SZ_1K),
-               .size           = (2 * SZ_1M) - (192 * SZ_1K),
-        }, {
-               .name           = "cramfs",
-               .offset         = (2 * SZ_1M),
-               .size           = (20 * SZ_1M),
-        },
-};
-
-static struct s3c2410_nand_set __initdata jive_nand_sets[] = {
-       [0] = {
-               .name           = "flash",
-               .nr_chips       = 1,
-               .nr_partitions  = ARRAY_SIZE(jive_imageA_nand_part),
-               .partitions     = jive_imageA_nand_part,
-       },
-};
-
-static struct s3c2410_platform_nand __initdata jive_nand_info = {
-       /* set taken from osiris nand timings, possibly still conservative */
-       .tacls          = 30,
-       .twrph0         = 55,
-       .twrph1         = 40,
-       .sets           = jive_nand_sets,
-       .nr_sets        = ARRAY_SIZE(jive_nand_sets),
-};
-
-static int __init jive_mtdset(char *options)
-{
-       struct s3c2410_nand_set *nand = &jive_nand_sets[0];
-       unsigned long set;
-
-       if (options == NULL || options[0] == '\0')
-               return 0;
-
-       if (strict_strtoul(options, 10, &set)) {
-               printk(KERN_ERR "failed to parse mtdset=%s\n", options);
-               return 0;
-       }
-
-       switch (set) {
-       case 1:
-               nand->nr_partitions = ARRAY_SIZE(jive_imageB_nand_part);
-               nand->partitions = jive_imageB_nand_part;
-       case 0:
-               /* this is already setup in the nand info */
-               break;
-       default:
-               printk(KERN_ERR "Unknown mtd set %ld specified,"
-                      "using default.", set);
-       }
-
-       return 0;
-}
-
-/* parse the mtdset= option given to the kernel command line */
-__setup("mtdset=", jive_mtdset);
-
-/* LCD timing and setup */
-
-#define LCD_XRES        (240)
-#define LCD_YRES        (320)
-#define LCD_LEFT_MARGIN  (12)
-#define LCD_RIGHT_MARGIN (12)
-#define LCD_LOWER_MARGIN (12)
-#define LCD_UPPER_MARGIN (12)
-#define LCD_VSYNC       (2)
-#define LCD_HSYNC       (2)
-
-#define LCD_REFRESH     (60)
-
-#define LCD_HTOT (LCD_HSYNC + LCD_LEFT_MARGIN + LCD_XRES + LCD_RIGHT_MARGIN)
-#define LCD_VTOT (LCD_VSYNC + LCD_LOWER_MARGIN + LCD_YRES + LCD_UPPER_MARGIN)
-
-static struct s3c2410fb_display jive_vgg2432a4_display[] = {
-       [0] = {
-               .width          = LCD_XRES,
-               .height         = LCD_YRES,
-               .xres           = LCD_XRES,
-               .yres           = LCD_YRES,
-               .left_margin    = LCD_LEFT_MARGIN,
-               .right_margin   = LCD_RIGHT_MARGIN,
-               .upper_margin   = LCD_UPPER_MARGIN,
-               .lower_margin   = LCD_LOWER_MARGIN,
-               .hsync_len      = LCD_HSYNC,
-               .vsync_len      = LCD_VSYNC,
-
-               .pixclock       = (1000000000000LL /
-                                  (LCD_REFRESH * LCD_HTOT * LCD_VTOT)),
-
-               .bpp            = 16,
-               .type           = (S3C2410_LCDCON1_TFT16BPP |
-                                  S3C2410_LCDCON1_TFT),
-
-               .lcdcon5        = (S3C2410_LCDCON5_FRM565 |
-                                  S3C2410_LCDCON5_INVVLINE |
-                                  S3C2410_LCDCON5_INVVFRAME |
-                                  S3C2410_LCDCON5_INVVDEN |
-                                  S3C2410_LCDCON5_PWREN),
-       },
-};
-
-/* todo - put into gpio header */
-
-#define S3C2410_GPCCON_MASK(x) (3 << ((x) * 2))
-#define S3C2410_GPDCON_MASK(x) (3 << ((x) * 2))
-
-static struct s3c2410fb_mach_info jive_lcd_config = {
-       .displays        = jive_vgg2432a4_display,
-       .num_displays    = ARRAY_SIZE(jive_vgg2432a4_display),
-       .default_display = 0,
-
-       /* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN
-        * and disable the pull down resistors on pins we are using for LCD
-        * data. */
-
-       .gpcup          = (0xf << 1) | (0x3f << 10),
-
-       .gpccon         = (S3C2410_GPC1_VCLK   | S3C2410_GPC2_VLINE |
-                          S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM |
-                          S3C2410_GPC10_VD2   | S3C2410_GPC11_VD3 |
-                          S3C2410_GPC12_VD4   | S3C2410_GPC13_VD5 |
-                          S3C2410_GPC14_VD6   | S3C2410_GPC15_VD7),
-
-       .gpccon_mask    = (S3C2410_GPCCON_MASK(1)  | S3C2410_GPCCON_MASK(2)  |
-                          S3C2410_GPCCON_MASK(3)  | S3C2410_GPCCON_MASK(4)  |
-                          S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) |
-                          S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) |
-                          S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)),
-
-       .gpdup          = (0x3f << 2) | (0x3f << 10),
-
-       .gpdcon         = (S3C2410_GPD2_VD10  | S3C2410_GPD3_VD11 |
-                          S3C2410_GPD4_VD12  | S3C2410_GPD5_VD13 |
-                          S3C2410_GPD6_VD14  | S3C2410_GPD7_VD15 |
-                          S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 |
-                          S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 |
-                          S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23),
-
-       .gpdcon_mask    = (S3C2410_GPDCON_MASK(2)  | S3C2410_GPDCON_MASK(3) |
-                          S3C2410_GPDCON_MASK(4)  | S3C2410_GPDCON_MASK(5) |
-                          S3C2410_GPDCON_MASK(6)  | S3C2410_GPDCON_MASK(7) |
-                          S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)|
-                          S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)|
-                          S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)),
-};
-
-/* ILI9320 support. */
-
-static void jive_lcm_reset(unsigned int set)
-{
-       printk(KERN_DEBUG "%s(%d)\n", __func__, set);
-
-       gpio_set_value(S3C2410_GPG(13), set);
-}
-
-#undef LCD_UPPER_MARGIN
-#define LCD_UPPER_MARGIN 2
-
-static struct ili9320_platdata jive_lcm_config = {
-       .hsize          = LCD_XRES,
-       .vsize          = LCD_YRES,
-
-       .reset          = jive_lcm_reset,
-       .suspend        = ILI9320_SUSPEND_DEEP,
-
-       .entry_mode     = ILI9320_ENTRYMODE_ID(3) | ILI9320_ENTRYMODE_BGR,
-       .display2       = (ILI9320_DISPLAY2_FP(LCD_UPPER_MARGIN) |
-                          ILI9320_DISPLAY2_BP(LCD_LOWER_MARGIN)),
-       .display3       = 0x0,
-       .display4       = 0x0,
-       .rgb_if1        = (ILI9320_RGBIF1_RIM_RGB18 |
-                          ILI9320_RGBIF1_RM | ILI9320_RGBIF1_CLK_RGBIF),
-       .rgb_if2        = ILI9320_RGBIF2_DPL,
-       .interface2     = 0x0,
-       .interface3     = 0x3,
-       .interface4     = (ILI9320_INTERFACE4_RTNE(16) |
-                          ILI9320_INTERFACE4_DIVE(1)),
-       .interface5     = 0x0,
-       .interface6     = 0x0,
-};
-
-/* LCD SPI support */
-
-static struct spi_gpio_platform_data jive_lcd_spi = {
-       .sck            = S3C2410_GPG(8),
-       .mosi           = S3C2410_GPB(8),
-       .miso           = SPI_GPIO_NO_MISO,
-};
-
-static struct platform_device jive_device_lcdspi = {
-       .name           = "spi-gpio",
-       .id             = 1,
-       .dev.platform_data = &jive_lcd_spi,
-};
-
-
-/* WM8750 audio code SPI definition */
-
-static struct spi_gpio_platform_data jive_wm8750_spi = {
-       .sck            = S3C2410_GPB(4),
-       .mosi           = S3C2410_GPB(9),
-       .miso           = SPI_GPIO_NO_MISO,
-};
-
-static struct platform_device jive_device_wm8750 = {
-       .name           = "spi-gpio",
-       .id             = 2,
-       .dev.platform_data = &jive_wm8750_spi,
-};
-
-/* JIVE SPI devices. */
-
-static struct spi_board_info __initdata jive_spi_devs[] = {
-       [0] = {
-               .modalias       = "VGG2432A4",
-               .bus_num        = 1,
-               .chip_select    = 0,
-               .mode           = SPI_MODE_3,   /* CPOL=1, CPHA=1 */
-               .max_speed_hz   = 100000,
-               .platform_data  = &jive_lcm_config,
-               .controller_data = (void *)S3C2410_GPB(7),
-       }, {
-               .modalias       = "WM8750",
-               .bus_num        = 2,
-               .chip_select    = 0,
-               .mode           = SPI_MODE_0,   /* CPOL=0, CPHA=0 */
-               .max_speed_hz   = 100000,
-               .controller_data = (void *)S3C2410_GPH(10),
-       },
-};
-
-/* I2C bus and device configuration. */
-
-static struct s3c2410_platform_i2c jive_i2c_cfg __initdata = {
-       .frequency      = 80 * 1000,
-       .flags          = S3C_IICFLG_FILTER,
-       .sda_delay      = 2,
-};
-
-static struct i2c_board_info jive_i2c_devs[] __initdata = {
-       [0] = {
-               I2C_BOARD_INFO("lis302dl", 0x1c),
-               .irq    = IRQ_EINT14,
-       },
-};
-
-/* The platform devices being used. */
-
-static struct platform_device *jive_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_rtc,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_lcd,
-       &jive_device_lcdspi,
-       &jive_device_wm8750,
-       &s3c_device_nand,
-       &s3c_device_usbgadget,
-};
-
-static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = {
-       .vbus_pin       = S3C2410_GPG(1),               /* detect is on GPG1 */
-};
-
-/* Jive power management device */
-
-#ifdef CONFIG_PM
-static int jive_pm_suspend(void)
-{
-       /* Write the magic value u-boot uses to check for resume into
-        * the INFORM0 register, and ensure INFORM1 is set to the
-        * correct address to resume from. */
-
-       __raw_writel(0x2BED, S3C2412_INFORM0);
-       __raw_writel(virt_to_phys(s3c_cpu_resume), S3C2412_INFORM1);
-
-       return 0;
-}
-
-static void jive_pm_resume(void)
-{
-       __raw_writel(0x0, S3C2412_INFORM0);
-}
-
-#else
-#define jive_pm_suspend NULL
-#define jive_pm_resume NULL
-#endif
-
-static struct syscore_ops jive_pm_syscore_ops = {
-       .suspend        = jive_pm_suspend,
-       .resume         = jive_pm_resume,
-};
-
-static void __init jive_map_io(void)
-{
-       s3c24xx_init_io(jive_iodesc, ARRAY_SIZE(jive_iodesc));
-       s3c24xx_init_clocks(12000000);
-       s3c24xx_init_uarts(jive_uartcfgs, ARRAY_SIZE(jive_uartcfgs));
-}
-
-static void jive_power_off(void)
-{
-       printk(KERN_INFO "powering system down...\n");
-
-       s3c2410_gpio_setpin(S3C2410_GPC(5), 1);
-       s3c_gpio_cfgpin(S3C2410_GPC(5), S3C2410_GPIO_OUTPUT);
-}
-
-static void __init jive_machine_init(void)
-{
-       /* register system core operations for managing low level suspend */
-
-       register_syscore_ops(&jive_pm_syscore_ops);
-
-       /* write our sleep configurations for the IO. Pull down all unused
-        * IO, ensure that we have turned off all peripherals we do not
-        * need, and configure the ones we do need. */
-
-       /* Port B sleep */
-
-       __raw_writel(S3C2412_SLPCON_IN(0)   |
-                    S3C2412_SLPCON_PULL(1) |
-                    S3C2412_SLPCON_HIGH(2) |
-                    S3C2412_SLPCON_PULL(3) |
-                    S3C2412_SLPCON_PULL(4) |
-                    S3C2412_SLPCON_PULL(5) |
-                    S3C2412_SLPCON_PULL(6) |
-                    S3C2412_SLPCON_HIGH(7) |
-                    S3C2412_SLPCON_PULL(8) |
-                    S3C2412_SLPCON_PULL(9) |
-                    S3C2412_SLPCON_PULL(10), S3C2412_GPBSLPCON);
-
-       /* Port C sleep */
-
-       __raw_writel(S3C2412_SLPCON_PULL(0) |
-                    S3C2412_SLPCON_PULL(1) |
-                    S3C2412_SLPCON_PULL(2) |
-                    S3C2412_SLPCON_PULL(3) |
-                    S3C2412_SLPCON_PULL(4) |
-                    S3C2412_SLPCON_PULL(5) |
-                    S3C2412_SLPCON_LOW(6)  |
-                    S3C2412_SLPCON_PULL(6) |
-                    S3C2412_SLPCON_PULL(7) |
-                    S3C2412_SLPCON_PULL(8) |
-                    S3C2412_SLPCON_PULL(9) |
-                    S3C2412_SLPCON_PULL(10) |
-                    S3C2412_SLPCON_PULL(11) |
-                    S3C2412_SLPCON_PULL(12) |
-                    S3C2412_SLPCON_PULL(13) |
-                    S3C2412_SLPCON_PULL(14) |
-                    S3C2412_SLPCON_PULL(15), S3C2412_GPCSLPCON);
-
-       /* Port D sleep */
-
-       __raw_writel(S3C2412_SLPCON_ALL_PULL, S3C2412_GPDSLPCON);
-
-       /* Port F sleep */
-
-       __raw_writel(S3C2412_SLPCON_LOW(0)  |
-                    S3C2412_SLPCON_LOW(1)  |
-                    S3C2412_SLPCON_LOW(2)  |
-                    S3C2412_SLPCON_EINT(3) |
-                    S3C2412_SLPCON_EINT(4) |
-                    S3C2412_SLPCON_EINT(5) |
-                    S3C2412_SLPCON_EINT(6) |
-                    S3C2412_SLPCON_EINT(7), S3C2412_GPFSLPCON);
-
-       /* Port G sleep */
-
-       __raw_writel(S3C2412_SLPCON_IN(0)    |
-                    S3C2412_SLPCON_IN(1)    |
-                    S3C2412_SLPCON_IN(2)    |
-                    S3C2412_SLPCON_IN(3)    |
-                    S3C2412_SLPCON_IN(4)    |
-                    S3C2412_SLPCON_IN(5)    |
-                    S3C2412_SLPCON_IN(6)    |
-                    S3C2412_SLPCON_IN(7)    |
-                    S3C2412_SLPCON_PULL(8)  |
-                    S3C2412_SLPCON_PULL(9)  |
-                    S3C2412_SLPCON_IN(10)   |
-                    S3C2412_SLPCON_PULL(11) |
-                    S3C2412_SLPCON_PULL(12) |
-                    S3C2412_SLPCON_PULL(13) |
-                    S3C2412_SLPCON_IN(14)   |
-                    S3C2412_SLPCON_PULL(15), S3C2412_GPGSLPCON);
-
-       /* Port H sleep */
-
-       __raw_writel(S3C2412_SLPCON_PULL(0) |
-                    S3C2412_SLPCON_PULL(1) |
-                    S3C2412_SLPCON_PULL(2) |
-                    S3C2412_SLPCON_PULL(3) |
-                    S3C2412_SLPCON_PULL(4) |
-                    S3C2412_SLPCON_PULL(5) |
-                    S3C2412_SLPCON_PULL(6) |
-                    S3C2412_SLPCON_IN(7)   |
-                    S3C2412_SLPCON_IN(8)   |
-                    S3C2412_SLPCON_PULL(9) |
-                    S3C2412_SLPCON_IN(10), S3C2412_GPHSLPCON);
-
-       /* initialise the power management now we've setup everything. */
-
-       s3c_pm_init();
-
-       /** TODO - check that this is after the cmdline option! */
-       s3c_nand_set_platdata(&jive_nand_info);
-
-       /* initialise the spi */
-
-       gpio_request(S3C2410_GPG(13), "lcm reset");
-       gpio_direction_output(S3C2410_GPG(13), 0);
-
-       gpio_request(S3C2410_GPB(7), "jive spi");
-       gpio_direction_output(S3C2410_GPB(7), 1);
-
-       s3c2410_gpio_setpin(S3C2410_GPB(6), 0);
-       s3c_gpio_cfgpin(S3C2410_GPB(6), S3C2410_GPIO_OUTPUT);
-
-       s3c2410_gpio_setpin(S3C2410_GPG(8), 1);
-       s3c_gpio_cfgpin(S3C2410_GPG(8), S3C2410_GPIO_OUTPUT);
-
-       /* initialise the WM8750 spi */
-
-       gpio_request(S3C2410_GPH(10), "jive wm8750 spi");
-       gpio_direction_output(S3C2410_GPH(10), 1);
-
-       /* Turn off suspend on both USB ports, and switch the
-        * selectable USB port to USB device mode. */
-
-       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
-                             S3C2410_MISCCR_USBSUSPND0 |
-                             S3C2410_MISCCR_USBSUSPND1, 0x0);
-
-       s3c24xx_udc_set_platdata(&jive_udc_cfg);
-       s3c24xx_fb_set_platdata(&jive_lcd_config);
-
-       spi_register_board_info(jive_spi_devs, ARRAY_SIZE(jive_spi_devs));
-
-       s3c_i2c0_set_platdata(&jive_i2c_cfg);
-       i2c_register_board_info(0, jive_i2c_devs, ARRAY_SIZE(jive_i2c_devs));
-
-       pm_power_off = jive_power_off;
-
-       platform_add_devices(jive_devices, ARRAY_SIZE(jive_devices));
-}
-
-MACHINE_START(JIVE, "JIVE")
-       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .atag_offset    = 0x100,
-
-       .init_irq       = s3c24xx_init_irq,
-       .map_io         = jive_map_io,
-       .init_machine   = jive_machine_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2412_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2412/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c
deleted file mode 100644 (file)
index b11451b..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/mach-smdk2413.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Thanks to Dimity Andric (TomTom) and Steven Ryu (Samsung) for the
- * loans of SMDK2413 to work with.
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/hardware/iomd.h>
-#include <asm/setup.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-//#include <asm/debug-ll.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-lcd.h>
-
-#include <mach/idle.h>
-#include <plat/udc.h>
-#include <plat/iic.h>
-#include <mach/fb.h>
-
-#include <plat/s3c2410.h>
-#include <plat/s3c2412.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-
-#include <plat/common-smdk.h>
-
-static struct map_desc smdk2413_iodesc[] __initdata = {
-};
-
-static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-       /* IR port */
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x43,
-               .ufcon       = 0x51,
-       }
-};
-
-
-static struct s3c2410_udc_mach_info smdk2413_udc_cfg __initdata = {
-       .pullup_pin = S3C2410_GPF(2),
-};
-
-
-static struct platform_device *smdk2413_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-       &s3c_device_usbgadget,
-};
-
-static void __init smdk2413_fixup(struct tag *tags, char **cmdline,
-                                 struct meminfo *mi)
-{
-       if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
-               mi->nr_banks=1;
-               mi->bank[0].start = 0x30000000;
-               mi->bank[0].size = SZ_64M;
-       }
-}
-
-static void __init smdk2413_map_io(void)
-{
-       s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc));
-       s3c24xx_init_clocks(12000000);
-       s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs));
-}
-
-static void __init smdk2413_machine_init(void)
-{      /* Turn off suspend on both USB ports, and switch the
-        * selectable USB port to USB device mode. */
-
-       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
-                             S3C2410_MISCCR_USBSUSPND0 |
-                             S3C2410_MISCCR_USBSUSPND1, 0x0);
-
-
-       s3c24xx_udc_set_platdata(&smdk2413_udc_cfg);
-       s3c_i2c0_set_platdata(NULL);
-
-       platform_add_devices(smdk2413_devices, ARRAY_SIZE(smdk2413_devices));
-       smdk_machine_init();
-}
-
-MACHINE_START(S3C2413, "S3C2413")
-       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .atag_offset    = 0x100,
-
-       .fixup          = smdk2413_fixup,
-       .init_irq       = s3c24xx_init_irq,
-       .map_io         = smdk2413_map_io,
-       .init_machine   = smdk2413_machine_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2412_restart,
-MACHINE_END
-
-MACHINE_START(SMDK2412, "SMDK2412")
-       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .atag_offset    = 0x100,
-
-       .fixup          = smdk2413_fixup,
-       .init_irq       = s3c24xx_init_irq,
-       .map_io         = smdk2413_map_io,
-       .init_machine   = smdk2413_machine_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2412_restart,
-MACHINE_END
-
-MACHINE_START(SMDK2413, "SMDK2413")
-       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .atag_offset    = 0x100,
-
-       .fixup          = smdk2413_fixup,
-       .init_irq       = s3c24xx_init_irq,
-       .map_io         = smdk2413_map_io,
-       .init_machine   = smdk2413_machine_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2412_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2412/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c
deleted file mode 100644 (file)
index 94bfaa1..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/mach-vstms.c
- *
- * (C) 2006 Thomas Gleixner <tglx@linutronix.de>
- *
- * Derived from mach-smdk2413.c - (C) 2006 Simtec Electronics
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-lcd.h>
-
-#include <mach/idle.h>
-#include <mach/fb.h>
-
-#include <plat/iic.h>
-#include <plat/nand.h>
-
-#include <plat/s3c2410.h>
-#include <plat/s3c2412.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-
-
-static struct map_desc vstms_iodesc[] __initdata = {
-};
-
-static struct s3c2410_uartcfg vstms_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       }
-};
-
-static struct mtd_partition __initdata vstms_nand_part[] = {
-       [0] = {
-               .name   = "Boot Agent",
-               .size   = 0x7C000,
-               .offset = 0,
-       },
-       [1] = {
-               .name   = "UBoot Config",
-               .offset = 0x7C000,
-               .size   = 0x4000,
-       },
-       [2] = {
-               .name   = "Kernel",
-               .offset = 0x80000,
-               .size   = 0x200000,
-       },
-       [3] = {
-               .name   = "RFS",
-               .offset = 0x280000,
-               .size   = 0x3d80000,
-       },
-};
-
-static struct s3c2410_nand_set __initdata vstms_nand_sets[] = {
-       [0] = {
-               .name           = "NAND",
-               .nr_chips       = 1,
-               .nr_partitions  = ARRAY_SIZE(vstms_nand_part),
-               .partitions     = vstms_nand_part,
-       },
-};
-
-/* choose a set of timings which should suit most 512Mbit
- * chips and beyond.
-*/
-
-static struct s3c2410_platform_nand __initdata vstms_nand_info = {
-       .tacls          = 20,
-       .twrph0         = 60,
-       .twrph1         = 20,
-       .nr_sets        = ARRAY_SIZE(vstms_nand_sets),
-       .sets           = vstms_nand_sets,
-};
-
-static struct platform_device *vstms_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-       &s3c_device_rtc,
-       &s3c_device_nand,
-};
-
-static void __init vstms_fixup(struct tag *tags, char **cmdline,
-                              struct meminfo *mi)
-{
-       if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
-               mi->nr_banks=1;
-               mi->bank[0].start = 0x30000000;
-               mi->bank[0].size = SZ_64M;
-       }
-}
-
-static void __init vstms_map_io(void)
-{
-       s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc));
-       s3c24xx_init_clocks(12000000);
-       s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs));
-}
-
-static void __init vstms_init(void)
-{
-       s3c_i2c0_set_platdata(NULL);
-       s3c_nand_set_platdata(&vstms_nand_info);
-
-       platform_add_devices(vstms_devices, ARRAY_SIZE(vstms_devices));
-}
-
-MACHINE_START(VSTMS, "VSTMS")
-       .atag_offset    = 0x100,
-
-       .fixup          = vstms_fixup,
-       .init_irq       = s3c24xx_init_irq,
-       .init_machine   = vstms_init,
-       .map_io         = vstms_map_io,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2412_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c2412/pm.c
deleted file mode 100644 (file)
index d045885..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/pm.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * http://armlinux.simtec.co.uk/.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/cacheflush.h>
-#include <asm/irq.h>
-
-#include <mach/regs-power.h>
-#include <mach/regs-gpioj.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-dsc.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-
-#include <plat/s3c2412.h>
-
-extern void s3c2412_sleep_enter(void);
-
-static int s3c2412_cpu_suspend(unsigned long arg)
-{
-       unsigned long tmp;
-
-       /* set our standby method to sleep */
-
-       tmp = __raw_readl(S3C2412_PWRCFG);
-       tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP;
-       __raw_writel(tmp, S3C2412_PWRCFG);
-
-       s3c2412_sleep_enter();
-
-       panic("sleep resumed to originator?");
-}
-
-static void s3c2412_pm_prepare(void)
-{
-}
-
-static int s3c2412_pm_add(struct device *dev, struct subsys_interface *sif)
-{
-       pm_cpu_prep = s3c2412_pm_prepare;
-       pm_cpu_sleep = s3c2412_cpu_suspend;
-
-       return 0;
-}
-
-static struct sleep_save s3c2412_sleep[] = {
-       SAVE_ITEM(S3C2412_DSC0),
-       SAVE_ITEM(S3C2412_DSC1),
-       SAVE_ITEM(S3C2413_GPJDAT),
-       SAVE_ITEM(S3C2413_GPJCON),
-       SAVE_ITEM(S3C2413_GPJUP),
-
-       /* save the PWRCFG to get back to original sleep method */
-
-       SAVE_ITEM(S3C2412_PWRCFG),
-
-       /* save the sleep configuration anyway, just in case these
-        * get damaged during wakeup */
-
-       SAVE_ITEM(S3C2412_GPBSLPCON),
-       SAVE_ITEM(S3C2412_GPCSLPCON),
-       SAVE_ITEM(S3C2412_GPDSLPCON),
-       SAVE_ITEM(S3C2412_GPFSLPCON),
-       SAVE_ITEM(S3C2412_GPGSLPCON),
-       SAVE_ITEM(S3C2412_GPHSLPCON),
-       SAVE_ITEM(S3C2413_GPJSLPCON),
-};
-
-static struct subsys_interface s3c2412_pm_interface = {
-       .name           = "s3c2412_pm",
-       .subsys         = &s3c2412_subsys,
-       .add_dev        = s3c2412_pm_add,
-};
-
-static __init int s3c2412_pm_init(void)
-{
-       return subsys_interface_register(&s3c2412_pm_interface);
-}
-
-arch_initcall(s3c2412_pm_init);
-
-static int s3c2412_pm_suspend(void)
-{
-       s3c_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
-       return 0;
-}
-
-static void s3c2412_pm_resume(void)
-{
-       unsigned long tmp;
-
-       tmp = __raw_readl(S3C2412_PWRCFG);
-       tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK;
-       tmp |=  S3C2412_PWRCFG_STANDBYWFI_IDLE;
-       __raw_writel(tmp, S3C2412_PWRCFG);
-
-       s3c_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
-}
-
-struct syscore_ops s3c2412_pm_syscore_ops = {
-       .suspend        = s3c2412_pm_suspend,
-       .resume         = s3c2412_pm_resume,
-};
diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
deleted file mode 100644 (file)
index 100ef1c..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/s3c2412.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * http://armlinux.simtec.co.uk/.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/proc-fns.h>
-#include <asm/irq.h>
-#include <asm/system_misc.h>
-
-#include <mach/idle.h>
-
-#include <plat/cpu-freq.h>
-
-#include <mach/regs-clock.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-power.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
-#include <mach/regs-dsc.h>
-#include <plat/regs-spi.h>
-#include <mach/regs-s3c2412.h>
-
-#include <plat/s3c2412.h>
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/clock.h>
-#include <plat/pm.h>
-#include <plat/pll.h>
-#include <plat/nand-core.h>
-
-#ifndef CONFIG_CPU_S3C2412_ONLY
-void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
-
-static inline void s3c2412_init_gpio2(void)
-{
-       s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
-}
-#else
-#define s3c2412_init_gpio2() do { } while(0)
-#endif
-
-/* Initial IO mappings */
-
-static struct map_desc s3c2412_iodesc[] __initdata = {
-       IODESC_ENT(CLKPWR),
-       IODESC_ENT(TIMER),
-       IODESC_ENT(WATCHDOG),
-       {
-               .virtual = (unsigned long)S3C2412_VA_SSMC,
-               .pfn     = __phys_to_pfn(S3C2412_PA_SSMC),
-               .length  = SZ_1M,
-               .type    = MT_DEVICE,
-       },
-       {
-               .virtual = (unsigned long)S3C2412_VA_EBI,
-               .pfn     = __phys_to_pfn(S3C2412_PA_EBI),
-               .length  = SZ_1M,
-               .type    = MT_DEVICE,
-       },
-};
-
-/* uart registration process */
-
-void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-       s3c24xx_init_uartdevs("s3c2412-uart", s3c2410_uart_resources, cfg, no);
-
-       /* rename devices that are s3c2412/s3c2413 specific */
-       s3c_device_sdi.name  = "s3c2412-sdi";
-       s3c_device_lcd.name  = "s3c2412-lcd";
-       s3c_nand_setname("s3c2412-nand");
-
-       /* alter IRQ of SDI controller */
-
-       s3c_device_sdi.resource[1].start = IRQ_S3C2412_SDI;
-       s3c_device_sdi.resource[1].end   = IRQ_S3C2412_SDI;
-
-       /* spi channel related changes, s3c2412/13 specific */
-       s3c_device_spi0.name = "s3c2412-spi";
-       s3c_device_spi0.resource[0].end = S3C24XX_PA_SPI + 0x24;
-       s3c_device_spi1.name = "s3c2412-spi";
-       s3c_device_spi1.resource[0].start = S3C24XX_PA_SPI + S3C2412_SPI1;
-       s3c_device_spi1.resource[0].end = S3C24XX_PA_SPI + S3C2412_SPI1 + 0x24;
-
-}
-
-/* s3c2412_idle
- *
- * use the standard idle call by ensuring the idle mode
- * in power config, then issuing the idle co-processor
- * instruction
-*/
-
-static void s3c2412_idle(void)
-{
-       unsigned long tmp;
-
-       /* ensure our idle mode is to go to idle */
-
-       tmp = __raw_readl(S3C2412_PWRCFG);
-       tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK;
-       tmp |= S3C2412_PWRCFG_STANDBYWFI_IDLE;
-       __raw_writel(tmp, S3C2412_PWRCFG);
-
-       cpu_do_idle();
-}
-
-void s3c2412_restart(char mode, const char *cmd)
-{
-       if (mode == 's')
-               soft_restart(0);
-
-       /* errata "Watch-dog/Software Reset Problem" specifies that
-        * this reset must be done with the SYSCLK sourced from
-        * EXTCLK instead of FOUT to avoid a glitch in the reset
-        * mechanism.
-        *
-        * See the watchdog section of the S3C2412 manual for more
-        * information on this fix.
-        */
-
-       __raw_writel(0x00, S3C2412_CLKSRC);
-       __raw_writel(S3C2412_SWRST_RESET, S3C2412_SWRST);
-
-       mdelay(1);
-}
-
-/* s3c2412_map_io
- *
- * register the standard cpu IO areas, and any passed in from the
- * machine specific initialisation.
-*/
-
-void __init s3c2412_map_io(void)
-{
-       /* move base of IO */
-
-       s3c2412_init_gpio2();
-
-       /* set our idle function */
-
-       s3c24xx_idle = s3c2412_idle;
-
-       /* register our io-tables */
-
-       iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
-}
-
-void __init_or_cpufreq s3c2412_setup_clocks(void)
-{
-       struct clk *xtal_clk;
-       unsigned long tmp;
-       unsigned long xtal;
-       unsigned long fclk;
-       unsigned long hclk;
-       unsigned long pclk;
-
-       xtal_clk = clk_get(NULL, "xtal");
-       xtal = clk_get_rate(xtal_clk);
-       clk_put(xtal_clk);
-
-       /* now we've got our machine bits initialised, work out what
-        * clocks we've got */
-
-       fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal * 2);
-
-       clk_mpll.rate = fclk;
-
-       tmp = __raw_readl(S3C2410_CLKDIVN);
-
-       /* work out clock scalings */
-
-       hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1);
-       hclk /= ((tmp & S3C2412_CLKDIVN_ARMDIVN) ? 2 : 1);
-       pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1);
-
-       /* print brieft summary of clocks, etc */
-
-       printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
-              print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
-
-       s3c24xx_setup_clocks(fclk, hclk, pclk);
-}
-
-void __init s3c2412_init_clocks(int xtal)
-{
-       /* initialise the clocks here, to allow other things like the
-        * console to use them
-        */
-
-       s3c24xx_register_baseclocks(xtal);
-       s3c2412_setup_clocks();
-       s3c2412_baseclk_add();
-}
-
-/* need to register the subsystem before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2412 based system)
- * as a driver which may support both 2410 and 2440 may try and use it.
-*/
-
-struct bus_type s3c2412_subsys = {
-       .name = "s3c2412-core",
-       .dev_name = "s3c2412-core",
-};
-
-static int __init s3c2412_core_init(void)
-{
-       return subsys_system_register(&s3c2412_subsys, NULL);
-}
-
-core_initcall(s3c2412_core_init);
-
-static struct device s3c2412_dev = {
-       .bus            = &s3c2412_subsys,
-};
-
-int __init s3c2412_init(void)
-{
-       printk("S3C2412: Initialising architecture\n");
-
-#ifdef CONFIG_PM
-       register_syscore_ops(&s3c2412_pm_syscore_ops);
-#endif
-       register_syscore_ops(&s3c24xx_irq_syscore_ops);
-
-       return device_register(&s3c2412_dev);
-}
diff --git a/arch/arm/mach-s3c2412/sleep.S b/arch/arm/mach-s3c2412/sleep.S
deleted file mode 100644 (file)
index c82418e..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* linux/arch/arm/mach-s3c2412/sleep.S
- *
- * Copyright (c) 2007 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2412 Power Manager low-level sleep support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <mach/regs-irq.h>
-
-       .text
-
-       .global s3c2412_sleep_enter
-
-s3c2412_sleep_enter:
-       mov     r0, #0                  /* argument for coprocessors */
-       ldr     r1, =S3C2410_INTPND
-       ldr     r2, =S3C2410_SRCPND
-       ldr     r3, =S3C2410_EINTPEND
-
-       teq     r0, r0
-       bl      s3c2412_sleep_enter1
-       teq     pc, r0
-       bl      s3c2412_sleep_enter1
-
-       .align  5
-
-       /* this is called twice, first with the Z flag to ensure that the
-        * instructions have been loaded into the cache, and the second
-        * time to try and suspend the system.
-       */
-s3c2412_sleep_enter1:
-       mcr     p15, 0, r0, c7, c10, 4
-       mcrne   p15, 0, r0, c7, c0, 4
-
-       /* if we return from here, it is because an interrupt was
-        * active when we tried to shutdown. Try and ack the IRQ and
-        * retry, as simply returning causes the system to lock.
-       */
-
-       ldrne   r9, [ r1 ]
-       strne   r9, [ r1 ]
-       ldrne   r9, [ r2 ]
-       strne   r9, [ r2 ]
-       ldrne   r9, [ r3 ]
-       strne   r9, [ r3 ]
-       bne     s3c2412_sleep_enter1
-
-       mov     pc, r14
diff --git a/arch/arm/mach-s3c2416/Kconfig b/arch/arm/mach-s3c2416/Kconfig
deleted file mode 100644 (file)
index 84c7b03..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-# arch/arm/mach-s3c2416/Kconfig
-#
-# Copyright 2009 Yauhen Kharuzhy <jekhor@gmail.com>
-#
-# Licensed under GPLv2
-
-# note, this also supports the S3C2450 which is so similar it has the same
-# ID code as the S3C2416.
-
-config CPU_S3C2416
-       bool
-       depends on ARCH_S3C2410
-       select CPU_ARM926T
-       select S3C2416_DMA if S3C2410_DMA
-       select CPU_LLSERIAL_S3C2440
-       select SAMSUNG_CLKSRC
-       select S3C2443_CLOCK
-       help
-         Support for the S3C2416 SoC from the S3C24XX line
-
-config S3C2416_DMA
-       bool
-       depends on CPU_S3C2416
-       help
-         Internal config node for S3C2416 DMA support
-
-config S3C2416_PM
-       bool
-       select S3C2412_PM_SLEEP
-       help
-         Internal config node to apply S3C2416 power management
-
-config S3C2416_SETUP_SDHCI
-       bool
-       select S3C2416_SETUP_SDHCI_GPIO
-       help
-         Internal helper functions for S3C2416 based SDHCI systems
-
-config S3C2416_SETUP_SDHCI_GPIO
-       bool
-       help
-         Common setup code for SDHCI gpio.
-
-menu "S3C2416 Machines"
-
-config MACH_SMDK2416
-       bool "SMDK2416"
-       select CPU_S3C2416
-       select MACH_SMDK
-       select S3C_DEV_FB
-       select S3C_DEV_HSMMC
-       select S3C_DEV_HSMMC1
-       select S3C_DEV_NAND
-       select S3C_DEV_USB_HOST
-       select S3C2416_SETUP_SDHCI
-       select S3C2416_PM if PM
-       help
-         Say Y here if you are using an SMDK2416
-
-endmenu
diff --git a/arch/arm/mach-s3c2416/Makefile b/arch/arm/mach-s3c2416/Makefile
deleted file mode 100644 (file)
index ca0cd22..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# arch/arm/mach-s3c2416/Makefile
-#
-# Copyright 2009 Yauhen Kharuzhy <jekhor@gmail.com>
-#
-# Licensed under GPLv2
-
-obj-y                          :=
-obj-m                          :=
-obj-n                          :=
-obj-                           :=
-
-obj-$(CONFIG_CPU_S3C2416)      += s3c2416.o clock.o
-obj-$(CONFIG_CPU_S3C2416)      += irq.o
-obj-$(CONFIG_S3C2416_PM)       += pm.o
-#obj-$(CONFIG_S3C2416_DMA)     += dma.o
-
-# Device setup
-obj-$(CONFIG_S3C2416_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
-
-# Machine support
-
-obj-$(CONFIG_MACH_SMDK2416)    += mach-smdk2416.o
diff --git a/arch/arm/mach-s3c2416/clock.c b/arch/arm/mach-s3c2416/clock.c
deleted file mode 100644 (file)
index 59f54d1..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/clock.c
- *
- * Copyright (c) 2010 Simtec Electronics
- * Copyright (c) 2010 Ben Dooks <ben-linux@fluff.org>
- *
- * S3C2416 Clock control support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/clk.h>
-
-#include <plat/s3c2416.h>
-#include <plat/s3c2443.h>
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-
-#include <plat/cpu-freq.h>
-#include <plat/pll.h>
-
-#include <asm/mach/map.h>
-
-#include <mach/regs-clock.h>
-#include <mach/regs-s3c2443-clock.h>
-
-/* armdiv
- *
- * this clock is sourced from msysclk and can have a number of
- * divider values applied to it to then be fed into armclk.
- * The real clock definition is done in s3c2443-clock.c,
- * only the armdiv divisor table must be defined here.
-*/
-
-static unsigned int armdiv[8] = {
-       [0] = 1,
-       [1] = 2,
-       [2] = 3,
-       [3] = 4,
-       [5] = 6,
-       [7] = 8,
-};
-
-static struct clksrc_clk hsspi_eplldiv = {
-       .clk = {
-               .name   = "hsspi-eplldiv",
-               .parent = &clk_esysclk.clk,
-               .ctrlbit = (1 << 14),
-               .enable = s3c2443_clkcon_enable_s,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 24 },
-};
-
-static struct clk *hsspi_sources[] = {
-       [0] = &hsspi_eplldiv.clk,
-       [1] = NULL, /* to fix */
-};
-
-static struct clksrc_clk hsspi_mux = {
-       .clk    = {
-               .name   = "hsspi-if",
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = hsspi_sources,
-               .nr_sources = ARRAY_SIZE(hsspi_sources),
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 18 },
-};
-
-static struct clksrc_clk hsmmc_div[] = {
-       [0] = {
-               .clk = {
-                       .name   = "hsmmc-div",
-                       .devname        = "s3c-sdhci.0",
-                       .parent = &clk_esysclk.clk,
-               },
-               .reg_div = { .reg = S3C2416_CLKDIV2, .size = 2, .shift = 6 },
-       },
-       [1] = {
-               .clk = {
-                       .name   = "hsmmc-div",
-                       .devname        = "s3c-sdhci.1",
-                       .parent = &clk_esysclk.clk,
-               },
-               .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
-       },
-};
-
-static struct clksrc_clk hsmmc_mux0 = {
-       .clk    = {
-               .name           = "hsmmc-if",
-               .devname        = "s3c-sdhci.0",
-               .ctrlbit        = (1 << 6),
-               .enable         = s3c2443_clkcon_enable_s,
-       },
-       .sources        = &(struct clksrc_sources) {
-               .nr_sources     = 2,
-               .sources        = (struct clk * []) {
-                       [0]     = &hsmmc_div[0].clk,
-                       [1]     = NULL, /* to fix */
-               },
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 16 },
-};
-
-static struct clksrc_clk hsmmc_mux1 = {
-       .clk    = {
-               .name           = "hsmmc-if",
-               .devname        = "s3c-sdhci.1",
-               .ctrlbit        = (1 << 12),
-               .enable         = s3c2443_clkcon_enable_s,
-       },
-       .sources        = &(struct clksrc_sources) {
-               .nr_sources     = 2,
-               .sources        = (struct clk * []) {
-                       [0]     = &hsmmc_div[1].clk,
-                       [1]     = NULL, /* to fix */
-               },
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 17 },
-};
-
-static struct clk hsmmc0_clk = {
-       .name           = "hsmmc",
-       .devname        = "s3c-sdhci.0",
-       .parent         = &clk_h,
-       .enable         = s3c2443_clkcon_enable_h,
-       .ctrlbit        = S3C2416_HCLKCON_HSMMC0,
-};
-
-void __init_or_cpufreq s3c2416_setup_clocks(void)
-{
-       s3c2443_common_setup_clocks(s3c2416_get_pll);
-}
-
-
-static struct clksrc_clk *clksrcs[] __initdata = {
-       &hsspi_eplldiv,
-       &hsspi_mux,
-       &hsmmc_div[0],
-       &hsmmc_div[1],
-       &hsmmc_mux0,
-       &hsmmc_mux1,
-};
-
-static struct clk_lookup s3c2416_clk_lookup[] = {
-       CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk),
-       CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk),
-       CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk),
-};
-
-void __init s3c2416_init_clocks(int xtal)
-{
-       u32 epllcon = __raw_readl(S3C2443_EPLLCON);
-       u32 epllcon1 = __raw_readl(S3C2443_EPLLCON+4);
-       int ptr;
-
-       /* s3c2416 EPLL compatible with s3c64xx */
-       clk_epll.rate = s3c_get_pll6553x(xtal, epllcon, epllcon1);
-
-       clk_epll.parent = &clk_epllref.clk;
-
-       s3c2443_common_init_clocks(xtal, s3c2416_get_pll,
-                                  armdiv, ARRAY_SIZE(armdiv),
-                                  S3C2416_CLKDIV0_ARMDIV_MASK);
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-               s3c_register_clksrc(clksrcs[ptr], 1);
-
-       s3c24xx_register_clock(&hsmmc0_clk);
-       clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup));
-
-       s3c_pwmclk_init();
-
-}
diff --git a/arch/arm/mach-s3c2416/irq.c b/arch/arm/mach-s3c2416/irq.c
deleted file mode 100644 (file)
index fd49f35..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/irq.c
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- *     as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-
-#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
-
-static inline void s3c2416_irq_demux(unsigned int irq, unsigned int len)
-{
-       unsigned int subsrc, submsk;
-       unsigned int end;
-
-       /* read the current pending interrupts, and the mask
-        * for what it is available */
-
-       subsrc = __raw_readl(S3C2410_SUBSRCPND);
-       submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-       subsrc  &= ~submsk;
-       subsrc >>= (irq - S3C2410_IRQSUB(0));
-       subsrc  &= (1 << len)-1;
-
-       end = len + irq;
-
-       for (; irq < end && subsrc; irq++) {
-               if (subsrc & 1)
-                       generic_handle_irq(irq);
-
-               subsrc >>= 1;
-       }
-}
-
-/* WDT/AC97 sub interrupts */
-
-static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
-{
-       s3c2416_irq_demux(IRQ_S3C2443_WDT, 4);
-}
-
-#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
-#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
-
-static void s3c2416_irq_wdtac97_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static void s3c2416_irq_wdtac97_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
-}
-
-static void s3c2416_irq_wdtac97_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static struct irq_chip s3c2416_irq_wdtac97 = {
-       .irq_mask       = s3c2416_irq_wdtac97_mask,
-       .irq_unmask     = s3c2416_irq_wdtac97_unmask,
-       .irq_ack        = s3c2416_irq_wdtac97_ack,
-};
-
-/* LCD sub interrupts */
-
-static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
-{
-       s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4);
-}
-
-#define INTMSK_LCD     (1UL << (IRQ_LCD - IRQ_EINT0))
-#define SUBMSK_LCD     INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
-
-static void s3c2416_irq_lcd_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static void s3c2416_irq_lcd_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_LCD);
-}
-
-static void s3c2416_irq_lcd_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static struct irq_chip s3c2416_irq_lcd = {
-       .irq_mask       = s3c2416_irq_lcd_mask,
-       .irq_unmask     = s3c2416_irq_lcd_unmask,
-       .irq_ack        = s3c2416_irq_lcd_ack,
-};
-
-/* DMA sub interrupts */
-
-static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
-{
-       s3c2416_irq_demux(IRQ_S3C2443_DMA0, 6);
-}
-
-#define INTMSK_DMA     (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
-#define SUBMSK_DMA     INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
-
-
-static void s3c2416_irq_dma_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static void s3c2416_irq_dma_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_DMA);
-}
-
-static void s3c2416_irq_dma_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static struct irq_chip s3c2416_irq_dma = {
-       .irq_mask       = s3c2416_irq_dma_mask,
-       .irq_unmask     = s3c2416_irq_dma_unmask,
-       .irq_ack        = s3c2416_irq_dma_ack,
-};
-
-/* UART3 sub interrupts */
-
-static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
-{
-       s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
-}
-
-#define INTMSK_UART3   (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3   (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
-static void s3c2416_irq_uart3_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static void s3c2416_irq_uart3_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_UART3);
-}
-
-static void s3c2416_irq_uart3_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static struct irq_chip s3c2416_irq_uart3 = {
-       .irq_mask       = s3c2416_irq_uart3_mask,
-       .irq_unmask     = s3c2416_irq_uart3_unmask,
-       .irq_ack        = s3c2416_irq_uart3_ack,
-};
-
-/* IRQ initialisation code */
-
-static int __init s3c2416_add_sub(unsigned int base,
-                                  void (*demux)(unsigned int,
-                                                struct irq_desc *),
-                                  struct irq_chip *chip,
-                                  unsigned int start, unsigned int end)
-{
-       unsigned int irqno;
-
-       irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
-       irq_set_chained_handler(base, demux);
-
-       for (irqno = start; irqno <= end; irqno++) {
-               irq_set_chip_and_handler(irqno, chip, handle_level_irq);
-               set_irq_flags(irqno, IRQF_VALID);
-       }
-
-       return 0;
-}
-
-static int __init s3c2416_irq_add(struct device *dev,
-                                 struct subsys_interface *sif)
-{
-       printk(KERN_INFO "S3C2416: IRQ Support\n");
-
-       s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd,
-                       IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4);
-
-       s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma,
-                       &s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
-
-       s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3,
-                       &s3c2416_irq_uart3,
-                       IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
-
-       s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97,
-                       &s3c2416_irq_wdtac97,
-                       IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
-
-       return 0;
-}
-
-static struct subsys_interface s3c2416_irq_interface = {
-       .name           = "s3c2416_irq",
-       .subsys         = &s3c2416_subsys,
-       .add_dev        = s3c2416_irq_add,
-};
-
-static int __init s3c2416_irq_init(void)
-{
-       return subsys_interface_register(&s3c2416_irq_interface);
-}
-
-arch_initcall(s3c2416_irq_init);
-
diff --git a/arch/arm/mach-s3c2416/mach-smdk2416.c b/arch/arm/mach-s3c2416/mach-smdk2416.c
deleted file mode 100644 (file)
index eebe1e7..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/mach-hanlin_v3c.c
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- *     as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/mtd/partitions.h>
-#include <linux/gpio.h>
-#include <linux/fb.h>
-#include <linux/delay.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-s3c2443-clock.h>
-
-#include <mach/idle.h>
-#include <mach/leds-gpio.h>
-#include <plat/iic.h>
-
-#include <plat/s3c2416.h>
-#include <plat/gpio-cfg.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/nand.h>
-#include <plat/sdhci.h>
-#include <plat/udc.h>
-#include <linux/platform_data/s3c-hsudc.h>
-
-#include <plat/regs-fb-v4.h>
-#include <plat/fb.h>
-
-#include <plat/common-smdk.h>
-
-static struct map_desc smdk2416_iodesc[] __initdata = {
-       /* ISA IO Space map (memory space selected by A24) */
-
-       {
-               .virtual        = (u32)S3C24XX_VA_ISA_WORD,
-               .pfn            = __phys_to_pfn(S3C2410_CS2),
-               .length         = 0x10000,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (u32)S3C24XX_VA_ISA_WORD + 0x10000,
-               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
-               .length         = SZ_4M,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (u32)S3C24XX_VA_ISA_BYTE,
-               .pfn            = __phys_to_pfn(S3C2410_CS2),
-               .length         = 0x10000,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
-               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
-               .length         = SZ_4M,
-               .type           = MT_DEVICE,
-       }
-};
-
-#define UCON (S3C2410_UCON_DEFAULT     | \
-               S3C2440_UCON_PCLK       | \
-               S3C2443_UCON_RXERR_IRQEN)
-
-#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE)
-
-#define UFCON (S3C2410_UFCON_RXTRIG8   | \
-               S3C2410_UFCON_FIFOMODE  | \
-               S3C2440_UFCON_TXTRIG16)
-
-static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       /* IR port */
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON | 0x50,
-               .ufcon       = UFCON,
-       },
-       [3] = {
-               .hwport      = 3,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       }
-};
-
-void smdk2416_hsudc_gpio_init(void)
-{
-       s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_UP);
-       s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_NONE);
-       s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(1));
-       s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 0);
-}
-
-void smdk2416_hsudc_gpio_uninit(void)
-{
-       s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 1);
-       s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_NONE);
-       s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(0));
-}
-
-struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
-       .epnum = 9,
-       .gpio_init = smdk2416_hsudc_gpio_init,
-       .gpio_uninit = smdk2416_hsudc_gpio_uninit,
-};
-
-struct s3c_fb_pd_win smdk2416_fb_win[] = {
-       [0] = {
-               /* think this is the same as the smdk6410 */
-               .win_mode       = {
-                       .pixclock       = 41094,
-                       .left_margin    = 8,
-                       .right_margin   = 13,
-                       .upper_margin   = 7,
-                       .lower_margin   = 5,
-                       .hsync_len      = 3,
-                       .vsync_len      = 1,
-                       .xres           = 800,
-                       .yres           = 480,
-               },
-               .default_bpp    = 16,
-               .max_bpp        = 32,
-       },
-};
-
-static void s3c2416_fb_gpio_setup_24bpp(void)
-{
-       unsigned int gpio;
-
-       for (gpio = S3C2410_GPC(1); gpio <= S3C2410_GPC(4); gpio++) {
-               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-       }
-
-       for (gpio = S3C2410_GPC(8); gpio <= S3C2410_GPC(15); gpio++) {
-               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-       }
-
-       for (gpio = S3C2410_GPD(0); gpio <= S3C2410_GPD(15); gpio++) {
-               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-       }
-}
-
-static struct s3c_fb_platdata smdk2416_fb_platdata = {
-       .win[0]         = &smdk2416_fb_win[0],
-       .setup_gpio     = s3c2416_fb_gpio_setup_24bpp,
-       .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
-       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
-};
-
-static struct s3c_sdhci_platdata smdk2416_hsmmc0_pdata __initdata = {
-       .max_width              = 4,
-       .cd_type                = S3C_SDHCI_CD_GPIO,
-       .ext_cd_gpio            = S3C2410_GPF(1),
-       .ext_cd_gpio_invert     = 1,
-};
-
-static struct s3c_sdhci_platdata smdk2416_hsmmc1_pdata __initdata = {
-       .max_width              = 4,
-       .cd_type                = S3C_SDHCI_CD_NONE,
-};
-
-static struct platform_device *smdk2416_devices[] __initdata = {
-       &s3c_device_fb,
-       &s3c_device_wdt,
-       &s3c_device_ohci,
-       &s3c_device_i2c0,
-       &s3c_device_hsmmc0,
-       &s3c_device_hsmmc1,
-       &s3c_device_usb_hsudc,
-};
-
-static void __init smdk2416_map_io(void)
-{
-       s3c24xx_init_io(smdk2416_iodesc, ARRAY_SIZE(smdk2416_iodesc));
-       s3c24xx_init_clocks(12000000);
-       s3c24xx_init_uarts(smdk2416_uartcfgs, ARRAY_SIZE(smdk2416_uartcfgs));
-}
-
-static void __init smdk2416_machine_init(void)
-{
-       s3c_i2c0_set_platdata(NULL);
-       s3c_fb_set_platdata(&smdk2416_fb_platdata);
-
-       s3c_sdhci0_set_platdata(&smdk2416_hsmmc0_pdata);
-       s3c_sdhci1_set_platdata(&smdk2416_hsmmc1_pdata);
-
-       s3c24xx_hsudc_set_platdata(&smdk2416_hsudc_platdata);
-
-       gpio_request(S3C2410_GPB(4), "USBHost Power");
-       gpio_direction_output(S3C2410_GPB(4), 1);
-
-       gpio_request(S3C2410_GPB(3), "Display Power");
-       gpio_direction_output(S3C2410_GPB(3), 1);
-
-       gpio_request(S3C2410_GPB(1), "Display Reset");
-       gpio_direction_output(S3C2410_GPB(1), 1);
-
-       platform_add_devices(smdk2416_devices, ARRAY_SIZE(smdk2416_devices));
-       smdk_machine_init();
-}
-
-MACHINE_START(SMDK2416, "SMDK2416")
-       /* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */
-       .atag_offset    = 0x100,
-
-       .init_irq       = s3c24xx_init_irq,
-       .map_io         = smdk2416_map_io,
-       .init_machine   = smdk2416_machine_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2416_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2416/pm.c b/arch/arm/mach-s3c2416/pm.c
deleted file mode 100644 (file)
index 1bd4817..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/pm.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * S3C2416 - PM support (Based on Ben Dooks' S3C2412 PM support)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/io.h>
-
-#include <asm/cacheflush.h>
-
-#include <mach/regs-power.h>
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-
-extern void s3c2412_sleep_enter(void);
-
-static int s3c2416_cpu_suspend(unsigned long arg)
-{
-       /* enable wakeup sources regardless of battery state */
-       __raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG);
-
-       /* set the mode as sleep, 2BED represents "Go to BED" */
-       __raw_writel(0x2BED, S3C2443_PWRMODE);
-
-       s3c2412_sleep_enter();
-
-       panic("sleep resumed to originator?");
-}
-
-static void s3c2416_pm_prepare(void)
-{
-       /*
-        * write the magic value u-boot uses to check for resume into
-        * the INFORM0 register, and ensure INFORM1 is set to the
-        * correct address to resume from.
-        */
-       __raw_writel(0x2BED, S3C2412_INFORM0);
-       __raw_writel(virt_to_phys(s3c_cpu_resume), S3C2412_INFORM1);
-}
-
-static int s3c2416_pm_add(struct device *dev, struct subsys_interface *sif)
-{
-       pm_cpu_prep = s3c2416_pm_prepare;
-       pm_cpu_sleep = s3c2416_cpu_suspend;
-
-       return 0;
-}
-
-static struct subsys_interface s3c2416_pm_interface = {
-       .name           = "s3c2416_pm",
-       .subsys         = &s3c2416_subsys,
-       .add_dev        = s3c2416_pm_add,
-};
-
-static __init int s3c2416_pm_init(void)
-{
-       return subsys_interface_register(&s3c2416_pm_interface);
-}
-
-arch_initcall(s3c2416_pm_init);
-
-
-static void s3c2416_pm_resume(void)
-{
-       /* unset the return-from-sleep amd inform flags */
-       __raw_writel(0x0, S3C2443_PWRMODE);
-       __raw_writel(0x0, S3C2412_INFORM0);
-       __raw_writel(0x0, S3C2412_INFORM1);
-}
-
-struct syscore_ops s3c2416_pm_syscore_ops = {
-       .resume         = s3c2416_pm_resume,
-};
diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c
deleted file mode 100644 (file)
index ed67ec9..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/* linux/arch/arm/mach-s3c2416/s3c2416.c
- *
- * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
- *     as part of OpenInkpot project
- * Copyright (c) 2009 Promwad Innovation Company
- *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
- *
- * Samsung S3C2416 Mobile CPU support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/proc-fns.h>
-#include <asm/irq.h>
-#include <asm/system_misc.h>
-
-#include <mach/idle.h>
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-#include <plat/s3c2416.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/sdhci.h>
-#include <plat/pm.h>
-
-#include <plat/iic-core.h>
-#include <plat/fb-core.h>
-#include <plat/nand-core.h>
-#include <plat/adc-core.h>
-
-static struct map_desc s3c2416_iodesc[] __initdata = {
-       IODESC_ENT(WATCHDOG),
-       IODESC_ENT(CLKPWR),
-       IODESC_ENT(TIMER),
-};
-
-struct bus_type s3c2416_subsys = {
-       .name = "s3c2416-core",
-       .dev_name = "s3c2416-core",
-};
-
-static struct device s3c2416_dev = {
-       .bus            = &s3c2416_subsys,
-};
-
-void s3c2416_restart(char mode, const char *cmd)
-{
-       if (mode == 's')
-               soft_restart(0);
-
-       __raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
-}
-
-int __init s3c2416_init(void)
-{
-       printk(KERN_INFO "S3C2416: Initializing architecture\n");
-
-       /* s3c24xx_idle = s3c2416_idle; */
-
-       /* change WDT IRQ number */
-       s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT;
-       s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT;
-
-       /* the i2c devices are directly compatible with s3c2440 */
-       s3c_i2c0_setname("s3c2440-i2c");
-       s3c_i2c1_setname("s3c2440-i2c");
-
-       s3c_fb_setname("s3c2443-fb");
-
-       s3c_adc_setname("s3c2416-adc");
-
-#ifdef CONFIG_PM
-       register_syscore_ops(&s3c2416_pm_syscore_ops);
-#endif
-       register_syscore_ops(&s3c24xx_irq_syscore_ops);
-
-       return device_register(&s3c2416_dev);
-}
-
-void __init s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-       s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
-
-       s3c_nand_setname("s3c2412-nand");
-}
-
-/* s3c2416_map_io
- *
- * register the standard cpu IO areas, and any passed in from the
- * machine specific initialisation.
- */
-
-void __init s3c2416_map_io(void)
-{
-       s3c24xx_gpiocfg_default.set_pull = samsung_gpio_setpull_updown;
-       s3c24xx_gpiocfg_default.get_pull = samsung_gpio_getpull_updown;
-
-       /* initialize device information early */
-       s3c2416_default_sdhci0();
-       s3c2416_default_sdhci1();
-
-       iotable_init(s3c2416_iodesc, ARRAY_SIZE(s3c2416_iodesc));
-}
-
-/* need to register the subsystem before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2416 based system)
- * as a driver which may support both 2443 and 2440 may try and use it.
-*/
-
-static int __init s3c2416_core_init(void)
-{
-       return subsys_system_register(&s3c2416_subsys, NULL);
-}
-
-core_initcall(s3c2416_core_init);
diff --git a/arch/arm/mach-s3c2416/setup-sdhci-gpio.c b/arch/arm/mach-s3c2416/setup-sdhci-gpio.c
deleted file mode 100644 (file)
index f65cb3e..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* linux/arch/arm/plat-s3c2416/setup-sdhci-gpio.c
- *
- * Copyright 2010 Promwad Innovation Company
- *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
- *
- * S3C2416 - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
- *
- * Based on mach-s3c64xx/setup-sdhci-gpio.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-
-#include <mach/regs-gpio.h>
-#include <plat/gpio-cfg.h>
-
-void s3c2416_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
-{
-       s3c_gpio_cfgrange_nopull(S3C2410_GPE(5), 2 + width, S3C_GPIO_SFN(2));
-}
-
-void s3c2416_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
-{
-       s3c_gpio_cfgrange_nopull(S3C2410_GPL(0), width, S3C_GPIO_SFN(2));
-       s3c_gpio_cfgrange_nopull(S3C2410_GPL(8), 2, S3C_GPIO_SFN(2));
-}
index 914e620..ece7a10 100644 (file)
@@ -2,35 +2,6 @@
 #
 # Licensed under GPLv2
 
-config CPU_S3C2440
-       bool
-       select CPU_ARM920T
-       select S3C2410_CLOCK
-       select S3C2410_PM if PM
-       select S3C2440_DMA if S3C2410_DMA
-       select CPU_S3C244X
-       select CPU_LLSERIAL_S3C2440
-       help
-         Support for S3C2440 Samsung Mobile CPU based systems.
-
-config CPU_S3C2442
-       bool
-       select CPU_ARM920T
-       select S3C2410_CLOCK
-       select S3C2410_PM if PM
-       select CPU_S3C244X
-       select CPU_LLSERIAL_S3C2440
-       help
-         Support for S3C2442 Samsung Mobile CPU based systems.
-
-config CPU_S3C244X
-       bool
-       depends on CPU_S3C2440 || CPU_S3C2442
-       help
-         Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
-
-
-
 config S3C2440_CPUFREQ
        bool "S3C2440/S3C2442 CPU Frequency scaling support"
        depends on CPU_FREQ_S3C24XX && (CPU_S3C2440 || CPU_S3C2442)
@@ -64,139 +35,3 @@ config S3C2440_PLL_16934400
        default y if CPU_FREQ_S3C24XX_PLL
        help
          PLL tables for S3C2440 or S3C2442 CPUs with 16.934MHz crystals.
-
-config S3C2440_DMA
-       bool
-       depends on CPU_S3C2440
-       help
-         Support for S3C2440 specific DMA code5A
-
-menu "S3C2440 and S3C2442 Machines"
-
-config MACH_ANUBIS
-       bool "Simtec Electronics ANUBIS"
-       select CPU_S3C2440
-       select S3C24XX_DCLK
-       select PM_SIMTEC if PM
-       select HAVE_PATA_PLATFORM
-       select S3C24XX_GPIO_EXTRA64
-       select S3C2440_XTAL_12000000
-       select S3C_DEV_USB_HOST
-       help
-         Say Y here if you are using the Simtec Electronics ANUBIS
-         development system
-
-config MACH_NEO1973_GTA02
-       bool "Openmoko GTA02 / Freerunner phone"
-       select CPU_S3C2442
-       select MFD_PCF50633
-       select PCF50633_GPIO
-       select I2C
-       select POWER_SUPPLY
-       select MACH_NEO1973
-       select S3C2410_PWM
-       select S3C_DEV_USB_HOST
-       help
-          Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
-
-config MACH_OSIRIS
-       bool "Simtec IM2440D20 (OSIRIS) module"
-       select CPU_S3C2440
-       select S3C24XX_DCLK
-       select PM_SIMTEC if PM
-       select S3C24XX_GPIO_EXTRA128
-       select S3C2440_XTAL_12000000
-       select S3C2410_IOTIMING if S3C2440_CPUFREQ
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-         Say Y here if you are using the Simtec IM2440D20 module, also
-         known as the Osiris.
-
-config MACH_OSIRIS_DVS
-       tristate "Simtec IM2440D20 (OSIRIS) Dynamic Voltage Scaling driver"
-       depends on MACH_OSIRIS
-       select TPS65010
-       help
-         Say Y/M here if you want to have dynamic voltage scaling support
-         on the Simtec IM2440D20 (OSIRIS) module via the TPS65011.
-
-         The DVS driver alters the voltage supplied to the ARM core
-         depending on the frequency it is running at. The driver itself
-         does not do any of the frequency alteration, which is left up
-         to the cpufreq driver.
-
-config MACH_RX3715
-       bool "HP iPAQ rx3715"
-       select CPU_S3C2440
-       select S3C2440_XTAL_16934400
-       select PM_H1940 if PM
-       select S3C_DEV_NAND
-       help
-         Say Y here if you are using the HP iPAQ rx3715.
-
-config ARCH_S3C2440
-       bool "SMDK2440"
-       select CPU_S3C2440
-       select S3C2440_XTAL_16934400
-       select MACH_SMDK
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-         Say Y here if you are using the SMDK2440.
-
-config MACH_NEXCODER_2440
-       bool "NexVision NEXCODER 2440 Light Board"
-       select CPU_S3C2440
-       select S3C2440_XTAL_12000000
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-         Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
-
-config SMDK2440_CPU2440
-       bool "SMDK2440 with S3C2440 CPU module"
-       default y if ARCH_S3C2440
-       select S3C2440_XTAL_16934400
-       select CPU_S3C2440
-
-config SMDK2440_CPU2442
-       bool "SMDM2440 with S3C2442 CPU module"
-       select CPU_S3C2442
-
-config MACH_AT2440EVB
-       bool "Avantech AT2440EVB development board"
-       select CPU_S3C2440
-       select S3C_DEV_USB_HOST
-       select S3C_DEV_NAND
-       help
-         Say Y here if you are using the AT2440EVB development board
-
-config MACH_MINI2440
-       bool "MINI2440 development board"
-       select CPU_S3C2440
-       select EEPROM_AT24
-       select NEW_LEDS
-       select LEDS_CLASS
-       select LEDS_TRIGGER
-       select LEDS_TRIGGER_BACKLIGHT
-       select S3C_DEV_NAND
-       select S3C_DEV_USB_HOST
-       help
-         Say Y here to select support for the MINI2440. Is a 10cm x 10cm board
-         available via various sources. It can come with a 3.5" or 7" touch LCD.
-
-config MACH_RX1950
-       bool "HP iPAQ rx1950"
-       select CPU_S3C2442
-       select S3C24XX_DCLK
-       select PM_H1940 if PM
-       select I2C
-       select S3C2410_PWM
-       select S3C_DEV_NAND
-       select S3C2410_IOTIMING if S3C2440_CPUFREQ
-       select S3C2440_XTAL_16934400
-       help
-          Say Y here if you're using HP iPAQ rx1950
-
-endmenu
index d5440fa..c460924 100644 (file)
@@ -9,33 +9,9 @@ obj-m                          :=
 obj-n                          :=
 obj-                           :=
 
-obj-$(CONFIG_CPU_S3C2440)      += s3c2440.o dsc.o
-obj-$(CONFIG_CPU_S3C2442)      += s3c2442.o
+obj-$(CONFIG_CPU_S3C2440)      += dsc.o
 
-obj-$(CONFIG_CPU_S3C2440)      += irq.o
-obj-$(CONFIG_CPU_S3C2440)      += clock.o
-obj-$(CONFIG_S3C2440_DMA)      += dma.o
-
-obj-$(CONFIG_CPU_S3C244X)      += s3c244x.o
-obj-$(CONFIG_CPU_S3C244X)      += s3c244x-irq.o
-obj-$(CONFIG_CPU_S3C244X)      += s3c244x-clock.o
 obj-$(CONFIG_S3C2440_CPUFREQ)  += s3c2440-cpufreq.o
 
 obj-$(CONFIG_S3C2440_PLL_12000000) += s3c2440-pll-12000000.o
 obj-$(CONFIG_S3C2440_PLL_16934400) += s3c2440-pll-16934400.o
-
-# Machine support
-
-obj-$(CONFIG_MACH_ANUBIS)      += mach-anubis.o
-obj-$(CONFIG_MACH_OSIRIS)      += mach-osiris.o
-obj-$(CONFIG_MACH_RX3715)      += mach-rx3715.o
-obj-$(CONFIG_ARCH_S3C2440)     += mach-smdk2440.o
-obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
-obj-$(CONFIG_MACH_AT2440EVB) += mach-at2440evb.o
-obj-$(CONFIG_MACH_MINI2440) += mach-mini2440.o
-obj-$(CONFIG_MACH_NEO1973_GTA02) += mach-gta02.o
-obj-$(CONFIG_MACH_RX1950) += mach-rx1950.o
-
-# extra machine support
-
-obj-$(CONFIG_MACH_OSIRIS_DVS)  += mach-osiris-dvs.o
diff --git a/arch/arm/mach-s3c2440/clock.c b/arch/arm/mach-s3c2440/clock.c
deleted file mode 100644 (file)
index 414364e..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/clock.c
- *
- * Copyright (c) 2004-2005 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2440 Clock support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mutex.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/serial_core.h>
-
-#include <mach/hardware.h>
-#include <linux/atomic.h>
-#include <asm/irq.h>
-
-#include <mach/regs-clock.h>
-
-#include <plat/clock.h>
-#include <plat/cpu.h>
-#include <plat/regs-serial.h>
-
-/* S3C2440 extended clock support */
-
-static unsigned long s3c2440_camif_upll_round(struct clk *clk,
-                                             unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       int div;
-
-       if (rate > parent_rate)
-               return parent_rate;
-
-       /* note, we remove the +/- 1 calculations for the divisor */
-
-       div = (parent_rate / rate) / 2;
-
-       if (div < 1)
-               div = 1;
-       else if (div > 16)
-               div = 16;
-
-       return parent_rate / (div * 2);
-}
-
-static int s3c2440_camif_upll_setrate(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long camdivn =  __raw_readl(S3C2440_CAMDIVN);
-
-       rate = s3c2440_camif_upll_round(clk, rate);
-
-       camdivn &= ~(S3C2440_CAMDIVN_CAMCLK_SEL | S3C2440_CAMDIVN_CAMCLK_MASK);
-
-       if (rate != parent_rate) {
-               camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
-               camdivn |= (((parent_rate / rate) / 2) - 1);
-       }
-
-       __raw_writel(camdivn, S3C2440_CAMDIVN);
-
-       return 0;
-}
-
-/* Extra S3C2440 clocks */
-
-static struct clk s3c2440_clk_cam = {
-       .name           = "camif",
-       .enable         = s3c2410_clkcon_enable,
-       .ctrlbit        = S3C2440_CLKCON_CAMERA,
-};
-
-static struct clk s3c2440_clk_cam_upll = {
-       .name           = "camif-upll",
-       .ops            = &(struct clk_ops) {
-               .set_rate       = s3c2440_camif_upll_setrate,
-               .round_rate     = s3c2440_camif_upll_round,
-       },
-};
-
-static struct clk s3c2440_clk_ac97 = {
-       .name           = "ac97",
-       .enable         = s3c2410_clkcon_enable,
-       .ctrlbit        = S3C2440_CLKCON_CAMERA,
-};
-
-static unsigned long  s3c2440_fclk_n_getrate(struct clk *clk)
-{
-       unsigned long ucon0, ucon1, ucon2, divisor;
-
-       /* the fun of calculating the uart divisors on the s3c2440 */
-       ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
-       ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
-       ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
-
-       ucon0 &= S3C2440_UCON0_DIVMASK;
-       ucon1 &= S3C2440_UCON1_DIVMASK;
-       ucon2 &= S3C2440_UCON2_DIVMASK;
-
-       if (ucon0 != 0)
-               divisor = (ucon0 >> S3C2440_UCON_DIVSHIFT) + 6;
-       else if (ucon1 != 0)
-               divisor = (ucon1 >> S3C2440_UCON_DIVSHIFT) + 21;
-       else if (ucon2 != 0)
-               divisor = (ucon2 >> S3C2440_UCON_DIVSHIFT) + 36;
-       else
-               /* manual calims 44, seems to be 9 */
-               divisor = 9;
-
-       return clk_get_rate(clk->parent) / divisor;
-}
-
-static struct clk s3c2440_clk_fclk_n = {
-       .name           = "fclk_n",
-       .parent         = &clk_f,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2440_fclk_n_getrate,
-       },
-};
-
-static struct clk_lookup s3c2440_clk_lookup[] = {
-       CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
-       CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
-       CLKDEV_INIT(NULL, "clk_uart_baud3", &s3c2440_clk_fclk_n),
-};
-
-static int s3c2440_clk_add(struct device *dev, struct subsys_interface *sif)
-{
-       struct clk *clock_upll;
-       struct clk *clock_h;
-       struct clk *clock_p;
-
-       clock_p = clk_get(NULL, "pclk");
-       clock_h = clk_get(NULL, "hclk");
-       clock_upll = clk_get(NULL, "upll");
-
-       if (IS_ERR(clock_p) || IS_ERR(clock_h) || IS_ERR(clock_upll)) {
-               printk(KERN_ERR "S3C2440: Failed to get parent clocks\n");
-               return -EINVAL;
-       }
-
-       s3c2440_clk_cam.parent = clock_h;
-       s3c2440_clk_ac97.parent = clock_p;
-       s3c2440_clk_cam_upll.parent = clock_upll;
-       s3c24xx_register_clock(&s3c2440_clk_fclk_n);
-
-       s3c24xx_register_clock(&s3c2440_clk_ac97);
-       s3c24xx_register_clock(&s3c2440_clk_cam);
-       s3c24xx_register_clock(&s3c2440_clk_cam_upll);
-       clkdev_add_table(s3c2440_clk_lookup, ARRAY_SIZE(s3c2440_clk_lookup));
-
-       clk_disable(&s3c2440_clk_ac97);
-       clk_disable(&s3c2440_clk_cam);
-
-       return 0;
-}
-
-static struct subsys_interface s3c2440_clk_interface = {
-       .name           = "s3c2440_clk",
-       .subsys         = &s3c2440_subsys,
-       .add_dev        = s3c2440_clk_add,
-};
-
-static __init int s3c24xx_clk_init(void)
-{
-       return subsys_interface_register(&s3c2440_clk_interface);
-}
-
-arch_initcall(s3c24xx_clk_init);
diff --git a/arch/arm/mach-s3c2440/common.h b/arch/arm/mach-s3c2440/common.h
deleted file mode 100644 (file)
index 0c1eb1d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Common Header for S3C2440 machines
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ARCH_ARM_MACH_S3C2440_COMMON_H
-#define __ARCH_ARM_MACH_S3C2440_COMMON_H
-
-void s3c244x_restart(char mode, const char *cmd);
-
-#endif /* __ARCH_ARM_MACH_S3C2440_COMMON_H */
diff --git a/arch/arm/mach-s3c2440/dma.c b/arch/arm/mach-s3c2440/dma.c
deleted file mode 100644 (file)
index 5f0a0c8..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/dma.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2440 DMA selection
- *
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-
-#include <plat/dma-s3c24xx.h>
-#include <plat/cpu.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
-#include <plat/regs-dma.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
-#include <plat/regs-spi.h>
-
-static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
-       [DMACH_XD0] = {
-               .name           = "xdreq0",
-               .channels[0]    = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
-       },
-       [DMACH_XD1] = {
-               .name           = "xdreq1",
-               .channels[1]    = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
-       },
-       [DMACH_SDI] = {
-               .name           = "sdi",
-               .channels[0]    = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
-               .channels[1]    = S3C2440_DCON_CH1_SDI | DMA_CH_VALID,
-               .channels[2]    = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
-               .channels[3]    = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
-       },
-       [DMACH_SPI0] = {
-               .name           = "spi0",
-               .channels[1]    = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
-       },
-       [DMACH_SPI1] = {
-               .name           = "spi1",
-               .channels[3]    = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
-       },
-       [DMACH_UART0] = {
-               .name           = "uart0",
-               .channels[0]    = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
-       },
-       [DMACH_UART1] = {
-               .name           = "uart1",
-               .channels[1]    = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
-       },
-       [DMACH_UART2] = {
-               .name           = "uart2",
-               .channels[3]    = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
-       },
-       [DMACH_TIMER] = {
-               .name           = "timer",
-               .channels[0]    = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
-               .channels[2]    = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
-               .channels[3]    = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
-       },
-       [DMACH_I2S_IN] = {
-               .name           = "i2s-sdi",
-               .channels[1]    = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
-               .channels[2]    = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
-       },
-       [DMACH_I2S_OUT] = {
-               .name           = "i2s-sdo",
-               .channels[0]    = S3C2440_DCON_CH0_I2SSDO | DMA_CH_VALID,
-               .channels[2]    = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
-       },
-       [DMACH_PCM_IN] = {
-               .name           = "pcm-in",
-               .channels[0]    = S3C2440_DCON_CH0_PCMIN | DMA_CH_VALID,
-               .channels[2]    = S3C2440_DCON_CH2_PCMIN | DMA_CH_VALID,
-       },
-       [DMACH_PCM_OUT] = {
-               .name           = "pcm-out",
-               .channels[1]    = S3C2440_DCON_CH1_PCMOUT | DMA_CH_VALID,
-               .channels[3]    = S3C2440_DCON_CH3_PCMOUT | DMA_CH_VALID,
-       },
-       [DMACH_MIC_IN] = {
-               .name           = "mic-in",
-               .channels[2]    = S3C2440_DCON_CH2_MICIN | DMA_CH_VALID,
-               .channels[3]    = S3C2440_DCON_CH3_MICIN | DMA_CH_VALID,
-       },
-       [DMACH_USB_EP1] = {
-               .name           = "usb-ep1",
-               .channels[0]    = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
-       },
-       [DMACH_USB_EP2] = {
-               .name           = "usb-ep2",
-               .channels[1]    = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
-       },
-       [DMACH_USB_EP3] = {
-               .name           = "usb-ep3",
-               .channels[2]    = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
-       },
-       [DMACH_USB_EP4] = {
-               .name           = "usb-ep4",
-               .channels[3]    = S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
-       },
-};
-
-static void s3c2440_dma_select(struct s3c2410_dma_chan *chan,
-                              struct s3c24xx_dma_map *map)
-{
-       chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
-}
-
-static struct s3c24xx_dma_selection __initdata s3c2440_dma_sel = {
-       .select         = s3c2440_dma_select,
-       .dcon_mask      = 7 << 24,
-       .map            = s3c2440_dma_mappings,
-       .map_size       = ARRAY_SIZE(s3c2440_dma_mappings),
-};
-
-static struct s3c24xx_dma_order __initdata s3c2440_dma_order = {
-       .channels       = {
-               [DMACH_SDI]     = {
-                       .list   = {
-                               [0]     = 3 | DMA_CH_VALID,
-                               [1]     = 2 | DMA_CH_VALID,
-                               [2]     = 1 | DMA_CH_VALID,
-                               [3]     = 0 | DMA_CH_VALID,
-                       },
-               },
-               [DMACH_I2S_IN]  = {
-                       .list   = {
-                               [0]     = 1 | DMA_CH_VALID,
-                               [1]     = 2 | DMA_CH_VALID,
-                       },
-               },
-               [DMACH_I2S_OUT] = {
-                       .list   = {
-                               [0]     = 2 | DMA_CH_VALID,
-                               [1]     = 1 | DMA_CH_VALID,
-                       },
-               },
-               [DMACH_PCM_IN] = {
-                       .list   = {
-                               [0]     = 2 | DMA_CH_VALID,
-                               [1]     = 1 | DMA_CH_VALID,
-                       },
-               },
-               [DMACH_PCM_OUT] = {
-                       .list   = {
-                               [0]     = 1 | DMA_CH_VALID,
-                               [1]     = 3 | DMA_CH_VALID,
-                       },
-               },
-               [DMACH_MIC_IN] = {
-                       .list   = {
-                               [0]     = 3 | DMA_CH_VALID,
-                               [1]     = 2 | DMA_CH_VALID,
-                       },
-               },
-       },
-};
-
-static int __init s3c2440_dma_add(struct device *dev,
-                                 struct subsys_interface *sif)
-{
-       s3c2410_dma_init();
-       s3c24xx_dma_order_set(&s3c2440_dma_order);
-       return s3c24xx_dma_init_map(&s3c2440_dma_sel);
-}
-
-static struct subsys_interface s3c2440_dma_interface = {
-       .name           = "s3c2440_dma",
-       .subsys         = &s3c2440_subsys,
-       .add_dev        = s3c2440_dma_add,
-};
-
-static int __init s3c2440_dma_init(void)
-{
-       return subsys_interface_register(&s3c2440_dma_interface);
-}
-
-arch_initcall(s3c2440_dma_init);
-
diff --git a/arch/arm/mach-s3c2440/include/mach/gta02.h b/arch/arm/mach-s3c2440/include/mach/gta02.h
deleted file mode 100644 (file)
index 3a56a22..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef _GTA02_H
-#define _GTA02_H
-
-#include <mach/regs-gpio.h>
-
-/* Different hardware revisions, passed in ATAG_REVISION by u-boot */
-#define GTA02v1_SYSTEM_REV     0x00000310
-#define GTA02v2_SYSTEM_REV     0x00000320
-#define GTA02v3_SYSTEM_REV     0x00000330
-#define GTA02v4_SYSTEM_REV     0x00000340
-#define GTA02v5_SYSTEM_REV     0x00000350
-/* since A7 is basically same as A6, we use A6 PCB ID */
-#define GTA02v6_SYSTEM_REV     0x00000360
-
-#define GTA02_GPIO_n3DL_GSM    S3C2410_GPA(13) /* v1 + v2 + v3 only */
-
-#define GTA02_GPIO_PWR_LED1    S3C2410_GPB(0)
-#define GTA02_GPIO_PWR_LED2    S3C2410_GPB(1)
-#define GTA02_GPIO_AUX_LED     S3C2410_GPB(2)
-#define GTA02_GPIO_VIBRATOR_ON S3C2410_GPB(3)
-#define GTA02_GPIO_MODEM_RST   S3C2410_GPB(5)
-#define GTA02_GPIO_BT_EN       S3C2410_GPB(6)
-#define GTA02_GPIO_MODEM_ON    S3C2410_GPB(7)
-#define GTA02_GPIO_EXTINT8     S3C2410_GPB(8)
-#define GTA02_GPIO_USB_PULLUP  S3C2410_GPB(9)
-
-#define GTA02_GPIO_PIO5                S3C2410_GPC(5)  /* v3 + v4 only */
-
-#define GTA02v3_GPIO_nG1_CS    S3C2410_GPD(12) /* v3 + v4 only */
-#define GTA02v3_GPIO_nG2_CS    S3C2410_GPD(13) /* v3 + v4 only */
-#define GTA02v5_GPIO_HDQ       S3C2410_GPD(14)   /* v5 + */
-
-#define GTA02_GPIO_nG1_INT     S3C2410_GPF(0)
-#define GTA02_GPIO_IO1         S3C2410_GPF(1)
-#define GTA02_GPIO_PIO_2       S3C2410_GPF(2)  /* v2 + v3 + v4 only */
-#define GTA02_GPIO_JACK_INSERT S3C2410_GPF(4)
-#define GTA02_GPIO_WLAN_GPIO1  S3C2410_GPF(5)  /* v2 + v3 + v4 only */
-#define GTA02_GPIO_AUX_KEY     S3C2410_GPF(6)
-#define GTA02_GPIO_HOLD_KEY    S3C2410_GPF(7)
-
-#define GTA02_GPIO_3D_IRQ      S3C2410_GPG(4)
-#define GTA02v2_GPIO_nG2_INT   S3C2410_GPG(8)  /* v2 + v3 + v4 only */
-#define GTA02v3_GPIO_nUSB_OC   S3C2410_GPG(9)  /* v3 + v4 only */
-#define GTA02v3_GPIO_nUSB_FLT  S3C2410_GPG(10) /* v3 + v4 only */
-#define GTA02v3_GPIO_nGSM_OC   S3C2410_GPG(11) /* v3 + v4 only */
-
-#define GTA02_GPIO_AMP_SHUT    S3C2410_GPJ(1)  /* v2 + v3 + v4 only */
-#define GTA02v1_GPIO_WLAN_GPIO10       S3C2410_GPJ(2)
-#define GTA02_GPIO_HP_IN       S3C2410_GPJ(2)  /* v2 + v3 + v4 only */
-#define GTA02_GPIO_INT0                S3C2410_GPJ(3)  /* v2 + v3 + v4 only */
-#define GTA02_GPIO_nGSM_EN     S3C2410_GPJ(4)
-#define GTA02_GPIO_3D_RESET    S3C2410_GPJ(5)
-#define GTA02_GPIO_nDL_GSM     S3C2410_GPJ(6)  /* v4 + v5 only */
-#define GTA02_GPIO_WLAN_GPIO0  S3C2410_GPJ(7)
-#define GTA02v1_GPIO_BAT_ID    S3C2410_GPJ(8)
-#define GTA02_GPIO_KEEPACT     S3C2410_GPJ(8)
-#define GTA02v1_GPIO_HP_IN     S3C2410_GPJ(10)
-#define GTA02_CHIP_PWD         S3C2410_GPJ(11) /* v2 + v3 + v4 only */
-#define GTA02_GPIO_nWLAN_RESET S3C2410_GPJ(12) /* v2 + v3 + v4 only */
-
-#define GTA02_IRQ_GSENSOR_1    IRQ_EINT0
-#define GTA02_IRQ_MODEM                IRQ_EINT1
-#define GTA02_IRQ_PIO_2                IRQ_EINT2       /* v2 + v3 + v4 only */
-#define GTA02_IRQ_nJACK_INSERT IRQ_EINT4
-#define GTA02_IRQ_WLAN_GPIO1   IRQ_EINT5
-#define GTA02_IRQ_AUX          IRQ_EINT6
-#define GTA02_IRQ_nHOLD                IRQ_EINT7
-#define GTA02_IRQ_PCF50633     IRQ_EINT9
-#define GTA02_IRQ_3D           IRQ_EINT12
-#define GTA02_IRQ_GSENSOR_2    IRQ_EINT16      /* v2 + v3 + v4 only */
-#define GTA02v3_IRQ_nUSB_OC    IRQ_EINT17      /* v3 + v4 only */
-#define GTA02v3_IRQ_nUSB_FLT   IRQ_EINT18      /* v3 + v4 only */
-#define GTA02v3_IRQ_nGSM_OC    IRQ_EINT19      /* v3 + v4 only */
-
-/* returns 00 000 on GTA02 A5 and earlier, A6 returns 01 001 */
-#define GTA02_PCB_ID1_0                S3C2410_GPC(13)
-#define GTA02_PCB_ID1_1                S3C2410_GPC(15)
-#define GTA02_PCB_ID1_2                S3C2410_GPD(0)
-#define GTA02_PCB_ID2_0                S3C2410_GPD(3)
-#define GTA02_PCB_ID2_1                S3C2410_GPD(4)
-
-int gta02_get_pcb_revision(void);
-
-#endif /* _GTA02_H */
diff --git a/arch/arm/mach-s3c2440/irq.c b/arch/arm/mach-s3c2440/irq.c
deleted file mode 100644 (file)
index 4a18cde..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/irq.c
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-
-/* WDT/AC97 */
-
-static void s3c_irq_demux_wdtac97(unsigned int irq,
-                                 struct irq_desc *desc)
-{
-       unsigned int subsrc, submsk;
-
-       /* read the current pending interrupts, and the mask
-        * for what it is available */
-
-       subsrc = __raw_readl(S3C2410_SUBSRCPND);
-       submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-       subsrc &= ~submsk;
-       subsrc >>= 13;
-       subsrc &= 3;
-
-       if (subsrc != 0) {
-               if (subsrc & 1) {
-                       generic_handle_irq(IRQ_S3C2440_WDT);
-               }
-               if (subsrc & 2) {
-                       generic_handle_irq(IRQ_S3C2440_AC97);
-               }
-       }
-}
-
-
-#define INTMSK_WDT      (1UL << (IRQ_WDT - IRQ_EINT0))
-
-static void
-s3c_irq_wdtac97_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_WDT, 3 << 13);
-}
-
-static void
-s3c_irq_wdtac97_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_WDT);
-}
-
-static void
-s3c_irq_wdtac97_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_WDT, 3 << 13);
-}
-
-static struct irq_chip s3c_irq_wdtac97 = {
-       .irq_mask       = s3c_irq_wdtac97_mask,
-       .irq_unmask     = s3c_irq_wdtac97_unmask,
-       .irq_ack        = s3c_irq_wdtac97_ack,
-};
-
-static int s3c2440_irq_add(struct device *dev, struct subsys_interface *sif)
-{
-       unsigned int irqno;
-
-       printk("S3C2440: IRQ Support\n");
-
-       /* add new chained handler for wdt, ac7 */
-
-       irq_set_chip_and_handler(IRQ_WDT, &s3c_irq_level_chip,
-                                handle_level_irq);
-       irq_set_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97);
-
-       for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) {
-               irq_set_chip_and_handler(irqno, &s3c_irq_wdtac97,
-                                        handle_level_irq);
-               set_irq_flags(irqno, IRQF_VALID);
-       }
-
-       return 0;
-}
-
-static struct subsys_interface s3c2440_irq_interface = {
-       .name           = "s3c2440_irq",
-       .subsys         = &s3c2440_subsys,
-       .add_dev        = s3c2440_irq_add,
-};
-
-static int s3c2440_irq_init(void)
-{
-       return subsys_interface_register(&s3c2440_irq_interface);
-}
-
-arch_initcall(s3c2440_irq_init);
-
diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
deleted file mode 100644 (file)
index 19b577b..0000000
+++ /dev/null
@@ -1,491 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-anubis.c
- *
- * Copyright 2003-2009 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/ata_platform.h>
-#include <linux/i2c.h>
-#include <linux/io.h>
-#include <linux/sm501.h>
-#include <linux/sm501-regs.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/anubis-map.h>
-#include <mach/anubis-irq.h>
-#include <mach/anubis-cpld.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <plat/nand.h>
-#include <plat/iic.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <net/ax88796.h>
-
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/audio-simtec.h>
-
-#include "common.h"
-
-#define COPYRIGHT ", Copyright 2005-2009 Simtec Electronics"
-
-static struct map_desc anubis_iodesc[] __initdata = {
-  /* ISA IO areas */
-
-  {
-       .virtual        = (u32)S3C24XX_VA_ISA_BYTE,
-       .pfn            = __phys_to_pfn(0x0),
-       .length         = SZ_4M,
-       .type           = MT_DEVICE,
-  }, {
-       .virtual        = (u32)S3C24XX_VA_ISA_WORD,
-       .pfn            = __phys_to_pfn(0x0),
-       .length         = SZ_4M,
-       .type           = MT_DEVICE,
-  },
-
-  /* we could possibly compress the next set down into a set of smaller tables
-   * pagetables, but that would mean using an L2 section, and it still means
-   * we cannot actually feed the same register to an LDR due to 16K spacing
-   */
-
-  /* CPLD control registers */
-
-  {
-       .virtual        = (u32)ANUBIS_VA_CTRL1,
-       .pfn            = __phys_to_pfn(ANUBIS_PA_CTRL1),
-       .length         = SZ_4K,
-       .type           = MT_DEVICE,
-  }, {
-       .virtual        = (u32)ANUBIS_VA_IDREG,
-       .pfn            = __phys_to_pfn(ANUBIS_PA_IDREG),
-       .length         = SZ_4K,
-       .type           = MT_DEVICE,
-  },
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg anubis_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
-       },
-       [1] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
-       },
-};
-
-/* NAND Flash on Anubis board */
-
-static int external_map[]   = { 2 };
-static int chip0_map[]      = { 0 };
-static int chip1_map[]      = { 1 };
-
-static struct mtd_partition __initdata anubis_default_nand_part[] = {
-       [0] = {
-               .name   = "Boot Agent",
-               .size   = SZ_16K,
-               .offset = 0,
-       },
-       [1] = {
-               .name   = "/boot",
-               .size   = SZ_4M - SZ_16K,
-               .offset = SZ_16K,
-       },
-       [2] = {
-               .name   = "user1",
-               .offset = SZ_4M,
-               .size   = SZ_32M - SZ_4M,
-       },
-       [3] = {
-               .name   = "user2",
-               .offset = SZ_32M,
-               .size   = MTDPART_SIZ_FULL,
-       }
-};
-
-static struct mtd_partition __initdata anubis_default_nand_part_large[] = {
-       [0] = {
-               .name   = "Boot Agent",
-               .size   = SZ_128K,
-               .offset = 0,
-       },
-       [1] = {
-               .name   = "/boot",
-               .size   = SZ_4M - SZ_128K,
-               .offset = SZ_128K,
-       },
-       [2] = {
-               .name   = "user1",
-               .offset = SZ_4M,
-               .size   = SZ_32M - SZ_4M,
-       },
-       [3] = {
-               .name   = "user2",
-               .offset = SZ_32M,
-               .size   = MTDPART_SIZ_FULL,
-       }
-};
-
-/* the Anubis has 3 selectable slots for nand-flash, the two
- * on-board chip areas, as well as the external slot.
- *
- * Note, there is no current hot-plug support for the External
- * socket.
-*/
-
-static struct s3c2410_nand_set __initdata anubis_nand_sets[] = {
-       [1] = {
-               .name           = "External",
-               .nr_chips       = 1,
-               .nr_map         = external_map,
-               .nr_partitions  = ARRAY_SIZE(anubis_default_nand_part),
-               .partitions     = anubis_default_nand_part,
-       },
-       [0] = {
-               .name           = "chip0",
-               .nr_chips       = 1,
-               .nr_map         = chip0_map,
-               .nr_partitions  = ARRAY_SIZE(anubis_default_nand_part),
-               .partitions     = anubis_default_nand_part,
-       },
-       [2] = {
-               .name           = "chip1",
-               .nr_chips       = 1,
-               .nr_map         = chip1_map,
-               .nr_partitions  = ARRAY_SIZE(anubis_default_nand_part),
-               .partitions     = anubis_default_nand_part,
-       },
-};
-
-static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
-{
-       unsigned int tmp;
-
-       slot = set->nr_map[slot] & 3;
-
-       pr_debug("anubis_nand: selecting slot %d (set %p,%p)\n",
-                slot, set, set->nr_map);
-
-       tmp = __raw_readb(ANUBIS_VA_CTRL1);
-       tmp &= ~ANUBIS_CTRL1_NANDSEL;
-       tmp |= slot;
-
-       pr_debug("anubis_nand: ctrl1 now %02x\n", tmp);
-
-       __raw_writeb(tmp, ANUBIS_VA_CTRL1);
-}
-
-static struct s3c2410_platform_nand __initdata anubis_nand_info = {
-       .tacls          = 25,
-       .twrph0         = 55,
-       .twrph1         = 40,
-       .nr_sets        = ARRAY_SIZE(anubis_nand_sets),
-       .sets           = anubis_nand_sets,
-       .select_chip    = anubis_nand_select,
-};
-
-/* IDE channels */
-
-static struct pata_platform_info anubis_ide_platdata = {
-       .ioport_shift   = 5,
-};
-
-static struct resource anubis_ide0_resource[] = {
-       {
-               .start  = S3C2410_CS3,
-               .end    = S3C2410_CS3 + (8*32) - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = S3C2410_CS3 + (1<<26) + (6*32),
-               .end    = S3C2410_CS3 + (1<<26) + (7*32) - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = IRQ_IDE0,
-               .end    = IRQ_IDE0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device anubis_device_ide0 = {
-       .name           = "pata_platform",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(anubis_ide0_resource),
-       .resource       = anubis_ide0_resource,
-       .dev    = {
-               .platform_data = &anubis_ide_platdata,
-               .coherent_dma_mask = ~0,
-       },
-};
-
-static struct resource anubis_ide1_resource[] = {
-       {
-               .start  = S3C2410_CS4,
-               .end    = S3C2410_CS4 + (8*32) - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = S3C2410_CS4 + (1<<26) + (6*32),
-               .end    = S3C2410_CS4 + (1<<26) + (7*32) - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = IRQ_IDE0,
-               .end    = IRQ_IDE0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device anubis_device_ide1 = {
-       .name           = "pata_platform",
-       .id             = 1,
-       .num_resources  = ARRAY_SIZE(anubis_ide1_resource),
-       .resource       = anubis_ide1_resource,
-       .dev    = {
-               .platform_data = &anubis_ide_platdata,
-               .coherent_dma_mask = ~0,
-       },
-};
-
-/* Asix AX88796 10/100 ethernet controller */
-
-static struct ax_plat_data anubis_asix_platdata = {
-       .flags          = AXFLG_MAC_FROMDEV,
-       .wordlength     = 2,
-       .dcr_val        = 0x48,
-       .rcr_val        = 0x40,
-};
-
-static struct resource anubis_asix_resource[] = {
-       [0] = {
-               .start = S3C2410_CS5,
-               .end   = S3C2410_CS5 + (0x20 * 0x20) -1,
-               .flags = IORESOURCE_MEM
-       },
-       [1] = {
-               .start = IRQ_ASIX,
-               .end   = IRQ_ASIX,
-               .flags = IORESOURCE_IRQ
-       }
-};
-
-static struct platform_device anubis_device_asix = {
-       .name           = "ax88796",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(anubis_asix_resource),
-       .resource       = anubis_asix_resource,
-       .dev            = {
-               .platform_data = &anubis_asix_platdata,
-       }
-};
-
-/* SM501 */
-
-static struct resource anubis_sm501_resource[] = {
-       [0] = {
-               .start  = S3C2410_CS2,
-               .end    = S3C2410_CS2 + SZ_8M,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = S3C2410_CS2 + SZ_64M - SZ_2M,
-               .end    = S3C2410_CS2 + SZ_64M - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [2] = {
-               .start  = IRQ_EINT0,
-               .end    = IRQ_EINT0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct sm501_initdata anubis_sm501_initdata = {
-       .gpio_high      = {
-               .set    = 0x3F000000,           /* 24bit panel */
-               .mask   = 0x0,
-       },
-       .misc_timing    = {
-               .set    = 0x010100,             /* SDRAM timing */
-               .mask   = 0x1F1F00,
-       },
-       .misc_control   = {
-               .set    = SM501_MISC_PNL_24BIT,
-               .mask   = 0,
-       },
-
-       .devices        = SM501_USE_GPIO,
-
-       /* set the SDRAM and bus clocks */
-       .mclk           = 72 * MHZ,
-       .m1xclk         = 144 * MHZ,
-};
-
-static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = {
-       [0] = {
-               .bus_num        = 1,
-               .pin_scl        = 44,
-               .pin_sda        = 45,
-       },
-       [1] = {
-               .bus_num        = 2,
-               .pin_scl        = 40,
-               .pin_sda        = 41,
-       },
-};
-
-static struct sm501_platdata anubis_sm501_platdata = {
-       .init           = &anubis_sm501_initdata,
-       .gpio_base      = -1,
-       .gpio_i2c       = anubis_sm501_gpio_i2c,
-       .gpio_i2c_nr    = ARRAY_SIZE(anubis_sm501_gpio_i2c),
-};
-
-static struct platform_device anubis_device_sm501 = {
-       .name           = "sm501",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(anubis_sm501_resource),
-       .resource       = anubis_sm501_resource,
-       .dev            = {
-               .platform_data = &anubis_sm501_platdata,
-       },
-};
-
-/* Standard Anubis devices */
-
-static struct platform_device *anubis_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_wdt,
-       &s3c_device_adc,
-       &s3c_device_i2c0,
-       &s3c_device_rtc,
-       &s3c_device_nand,
-       &anubis_device_ide0,
-       &anubis_device_ide1,
-       &anubis_device_asix,
-       &anubis_device_sm501,
-};
-
-static struct clk *anubis_clocks[] __initdata = {
-       &s3c24xx_dclk0,
-       &s3c24xx_dclk1,
-       &s3c24xx_clkout0,
-       &s3c24xx_clkout1,
-       &s3c24xx_uclk,
-};
-
-/* I2C devices. */
-
-static struct i2c_board_info anubis_i2c_devs[] __initdata = {
-       {
-               I2C_BOARD_INFO("tps65011", 0x48),
-               .irq    = IRQ_EINT20,
-       }
-};
-
-/* Audio setup */
-static struct s3c24xx_audio_simtec_pdata __initdata anubis_audio = {
-       .have_mic       = 1,
-       .have_lout      = 1,
-       .output_cdclk   = 1,
-       .use_mpllin     = 1,
-       .amp_gpio       = S3C2410_GPB(2),
-       .amp_gain[0]    = S3C2410_GPD(10),
-       .amp_gain[1]    = S3C2410_GPD(11),
-};
-
-static void __init anubis_map_io(void)
-{
-       /* initialise the clocks */
-
-       s3c24xx_dclk0.parent = &clk_upll;
-       s3c24xx_dclk0.rate   = 12*1000*1000;
-
-       s3c24xx_dclk1.parent = &clk_upll;
-       s3c24xx_dclk1.rate   = 24*1000*1000;
-
-       s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
-       s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
-
-       s3c24xx_uclk.parent  = &s3c24xx_clkout1;
-
-       s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks));
-
-       s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc));
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
-
-       /* check for the newer revision boards with large page nand */
-
-       if ((__raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK) >= 4) {
-               printk(KERN_INFO "ANUBIS-B detected (revision %d)\n",
-                      __raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK);
-               anubis_nand_sets[0].partitions = anubis_default_nand_part_large;
-               anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large);
-       } else {
-               /* ensure that the GPIO is setup */
-               s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
-       }
-}
-
-static void __init anubis_init(void)
-{
-       s3c_i2c0_set_platdata(NULL);
-       s3c_nand_set_platdata(&anubis_nand_info);
-       simtec_audio_add(NULL, false, &anubis_audio);
-
-       platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices));
-
-       i2c_register_board_info(0, anubis_i2c_devs,
-                               ARRAY_SIZE(anubis_i2c_devs));
-}
-
-
-MACHINE_START(ANUBIS, "Simtec-Anubis")
-       /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .atag_offset    = 0x100,
-       .map_io         = anubis_map_io,
-       .init_machine   = anubis_init,
-       .init_irq       = s3c24xx_init_irq,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-at2440evb.c b/arch/arm/mach-s3c2440/mach-at2440evb.c
deleted file mode 100644 (file)
index d7ae49c..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-at2440evb.c
- *
- * Copyright (c) 2008 Ramax Lo <ramaxlo@gmail.com>
- *      Based on mach-anubis.c by Ben Dooks <ben@simtec.co.uk>
- *      and modifications by SBZ <sbz@spgui.org> and
- *      Weibing <http://weibing.blogbus.com>
- *
- * For product information, visit http://www.arm.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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/serial_core.h>
-#include <linux/dm9000.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/fb.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <plat/nand.h>
-#include <plat/iic.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/mci.h>
-
-#include "common.h"
-
-static struct map_desc at2440evb_iodesc[] __initdata = {
-       /* Nothing here */
-};
-
-#define UCON S3C2410_UCON_DEFAULT
-#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE)
-#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
-
-static struct s3c2410_uartcfg at2440evb_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
-       },
-};
-
-/* NAND Flash on AT2440EVB board */
-
-static struct mtd_partition __initdata at2440evb_default_nand_part[] = {
-       [0] = {
-               .name   = "Boot Agent",
-               .size   = SZ_256K,
-               .offset = 0,
-       },
-       [1] = {
-               .name   = "Kernel",
-               .size   = SZ_2M,
-               .offset = SZ_256K,
-       },
-       [2] = {
-               .name   = "Root",
-               .offset = SZ_256K + SZ_2M,
-               .size   = MTDPART_SIZ_FULL,
-       },
-};
-
-static struct s3c2410_nand_set __initdata at2440evb_nand_sets[] = {
-       [0] = {
-               .name           = "nand",
-               .nr_chips       = 1,
-               .nr_partitions  = ARRAY_SIZE(at2440evb_default_nand_part),
-               .partitions     = at2440evb_default_nand_part,
-       },
-};
-
-static struct s3c2410_platform_nand __initdata at2440evb_nand_info = {
-       .tacls          = 25,
-       .twrph0         = 55,
-       .twrph1         = 40,
-       .nr_sets        = ARRAY_SIZE(at2440evb_nand_sets),
-       .sets           = at2440evb_nand_sets,
-};
-
-/* DM9000AEP 10/100 ethernet controller */
-
-static struct resource at2440evb_dm9k_resource[] = {
-       [0] = {
-               .start = S3C2410_CS3,
-               .end   = S3C2410_CS3 + 3,
-               .flags = IORESOURCE_MEM
-       },
-       [1] = {
-               .start = S3C2410_CS3 + 4,
-               .end   = S3C2410_CS3 + 7,
-               .flags = IORESOURCE_MEM
-       },
-       [2] = {
-               .start = IRQ_EINT7,
-               .end   = IRQ_EINT7,
-               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
-       }
-};
-
-static struct dm9000_plat_data at2440evb_dm9k_pdata = {
-       .flags          = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
-};
-
-static struct platform_device at2440evb_device_eth = {
-       .name           = "dm9000",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(at2440evb_dm9k_resource),
-       .resource       = at2440evb_dm9k_resource,
-       .dev            = {
-               .platform_data  = &at2440evb_dm9k_pdata,
-       },
-};
-
-static struct s3c24xx_mci_pdata at2440evb_mci_pdata __initdata = {
-       .gpio_detect    = S3C2410_GPG(10),
-};
-
-/* 7" LCD panel */
-
-static struct s3c2410fb_display at2440evb_lcd_cfg __initdata = {
-
-       .lcdcon5        = S3C2410_LCDCON5_FRM565 |
-                         S3C2410_LCDCON5_INVVLINE |
-                         S3C2410_LCDCON5_INVVFRAME |
-                         S3C2410_LCDCON5_PWREN |
-                         S3C2410_LCDCON5_HWSWP,
-
-       .type           = S3C2410_LCDCON1_TFT,
-
-       .width          = 800,
-       .height         = 480,
-
-       .pixclock       = 33333, /* HCLK 60 MHz, divisor 2 */
-       .xres           = 800,
-       .yres           = 480,
-       .bpp            = 16,
-       .left_margin    = 88,
-       .right_margin   = 40,
-       .hsync_len      = 128,
-       .upper_margin   = 32,
-       .lower_margin   = 11,
-       .vsync_len      = 2,
-};
-
-static struct s3c2410fb_mach_info at2440evb_fb_info __initdata = {
-       .displays       = &at2440evb_lcd_cfg,
-       .num_displays   = 1,
-       .default_display = 0,
-};
-
-static struct platform_device *at2440evb_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_wdt,
-       &s3c_device_adc,
-       &s3c_device_i2c0,
-       &s3c_device_rtc,
-       &s3c_device_nand,
-       &s3c_device_sdi,
-       &s3c_device_lcd,
-       &at2440evb_device_eth,
-};
-
-static void __init at2440evb_map_io(void)
-{
-       s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc));
-       s3c24xx_init_clocks(16934400);
-       s3c24xx_init_uarts(at2440evb_uartcfgs, ARRAY_SIZE(at2440evb_uartcfgs));
-}
-
-static void __init at2440evb_init(void)
-{
-       s3c24xx_fb_set_platdata(&at2440evb_fb_info);
-       s3c24xx_mci_set_platdata(&at2440evb_mci_pdata);
-       s3c_nand_set_platdata(&at2440evb_nand_info);
-       s3c_i2c0_set_platdata(NULL);
-
-       platform_add_devices(at2440evb_devices, ARRAY_SIZE(at2440evb_devices));
-}
-
-
-MACHINE_START(AT2440EVB, "AT2440EVB")
-       .atag_offset    = 0x100,
-       .map_io         = at2440evb_map_io,
-       .init_machine   = at2440evb_init,
-       .init_irq       = s3c24xx_init_irq,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
deleted file mode 100644 (file)
index 9a4a5bc..0000000
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * linux/arch/arm/mach-s3c2442/mach-gta02.c
- *
- * S3C2442 Machine Support for Openmoko GTA02 / FreeRunner.
- *
- * Copyright (C) 2006-2009 by Openmoko, Inc.
- * Authors: Harald Welte <laforge@openmoko.org>
- *          Andy Green <andy@openmoko.org>
- *          Werner Almesberger <werner@openmoko.org>
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/spi/spi.h>
-
-#include <linux/mmc/host.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <linux/io.h>
-
-#include <linux/i2c.h>
-#include <linux/regulator/machine.h>
-
-#include <linux/mfd/pcf50633/core.h>
-#include <linux/mfd/pcf50633/mbc.h>
-#include <linux/mfd/pcf50633/adc.h>
-#include <linux/mfd/pcf50633/gpio.h>
-#include <linux/mfd/pcf50633/pmic.h>
-#include <linux/mfd/pcf50633/backlight.h>
-
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
-#include <mach/fb.h>
-
-#include <mach/spi.h>
-#include <plat/usb-control.h>
-#include <mach/regs-mem.h>
-#include <mach/hardware.h>
-
-#include <mach/gta02.h>
-
-#include <plat/regs-serial.h>
-#include <plat/nand.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/udc.h>
-#include <plat/gpio-cfg.h>
-#include <plat/iic.h>
-#include <plat/ts.h>
-
-#include "common.h"
-
-static struct pcf50633 *gta02_pcf;
-
-/*
- * This gets called frequently when we paniced.
- */
-
-static long gta02_panic_blink(int state)
-{
-       long delay = 0;
-       char led;
-
-       led = (state) ? 1 : 0;
-       gpio_direction_output(GTA02_GPIO_AUX_LED, led);
-
-       return delay;
-}
-
-
-static struct map_desc gta02_iodesc[] __initdata = {
-       {
-               .virtual        = 0xe0000000,
-               .pfn            = __phys_to_pfn(S3C2410_CS3 + 0x01000000),
-               .length         = SZ_1M,
-               .type           = MT_DEVICE
-       },
-};
-
-#define UCON (S3C2410_UCON_DEFAULT | S3C2443_UCON_RXERR_IRQEN)
-#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
-#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
-
-static struct s3c2410_uartcfg gta02_uartcfgs[] = {
-       [0] = {
-               .hwport         = 0,
-               .flags          = 0,
-               .ucon           = UCON,
-               .ulcon          = ULCON,
-               .ufcon          = UFCON,
-       },
-       [1] = {
-               .hwport         = 1,
-               .flags          = 0,
-               .ucon           = UCON,
-               .ulcon          = ULCON,
-               .ufcon          = UFCON,
-       },
-       [2] = {
-               .hwport         = 2,
-               .flags          = 0,
-               .ucon           = UCON,
-               .ulcon          = ULCON,
-               .ufcon          = UFCON,
-       },
-};
-
-#ifdef CONFIG_CHARGER_PCF50633
-/*
- * On GTA02 the 1A charger features a 48K resistor to 0V on the ID pin.
- * We use this to recognize that we can pull 1A from the USB socket.
- *
- * These constants are the measured pcf50633 ADC levels with the 1A
- * charger / 48K resistor, and with no pulldown resistor.
- */
-
-#define ADC_NOM_CHG_DETECT_1A 6
-#define ADC_NOM_CHG_DETECT_USB 43
-
-static void
-gta02_configure_pmu_for_charger(struct pcf50633 *pcf, void *unused, int res)
-{
-       int  ma;
-
-       /* Interpret charger type */
-       if (res < ((ADC_NOM_CHG_DETECT_USB + ADC_NOM_CHG_DETECT_1A) / 2)) {
-
-               /*
-                * Sanity - stop GPO driving out now that we have a 1A charger
-                * GPO controls USB Host power generation on GTA02
-                */
-               pcf50633_gpio_set(pcf, PCF50633_GPO, 0);
-
-               ma = 1000;
-       } else
-               ma = 100;
-
-       pcf50633_mbc_usb_curlim_set(pcf, ma);
-}
-
-static struct delayed_work gta02_charger_work;
-static int gta02_usb_vbus_draw;
-
-static void gta02_charger_worker(struct work_struct *work)
-{
-       if (gta02_usb_vbus_draw) {
-               pcf50633_mbc_usb_curlim_set(gta02_pcf, gta02_usb_vbus_draw);
-               return;
-       }
-
-#ifdef CONFIG_PCF50633_ADC
-       pcf50633_adc_async_read(gta02_pcf,
-                               PCF50633_ADCC1_MUX_ADCIN1,
-                               PCF50633_ADCC1_AVERAGE_16,
-                               gta02_configure_pmu_for_charger,
-                               NULL);
-#else
-       /*
-        * If the PCF50633 ADC is disabled we fallback to a
-        * 100mA limit for safety.
-        */
-       pcf50633_mbc_usb_curlim_set(pcf, 100);
-#endif
-}
-
-#define GTA02_CHARGER_CONFIGURE_TIMEOUT ((3000 * HZ) / 1000)
-
-static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq)
-{
-       if (irq == PCF50633_IRQ_USBINS) {
-               schedule_delayed_work(&gta02_charger_work,
-                                     GTA02_CHARGER_CONFIGURE_TIMEOUT);
-
-               return;
-       }
-
-       if (irq == PCF50633_IRQ_USBREM) {
-               cancel_delayed_work_sync(&gta02_charger_work);
-               gta02_usb_vbus_draw = 0;
-       }
-}
-
-static void gta02_udc_vbus_draw(unsigned int ma)
-{
-       if (!gta02_pcf)
-               return;
-
-       gta02_usb_vbus_draw = ma;
-
-       schedule_delayed_work(&gta02_charger_work,
-                             GTA02_CHARGER_CONFIGURE_TIMEOUT);
-}
-#else /* !CONFIG_CHARGER_PCF50633 */
-#define gta02_pmu_event_callback       NULL
-#define gta02_udc_vbus_draw            NULL
-#endif
-
-/*
- * This is called when pc50633 is probed, unfortunately quite late in the
- * day since it is an I2C bus device. Here we can belatedly define some
- * platform devices with the advantage that we can mark the pcf50633 as the
- * parent. This makes them get suspended and resumed with their parent
- * the pcf50633 still around.
- */
-
-static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf);
-
-
-static char *gta02_batteries[] = {
-       "battery",
-};
-
-static struct pcf50633_bl_platform_data gta02_backlight_data = {
-       .default_brightness = 0x3f,
-       .default_brightness_limit = 0,
-       .ramp_time = 5,
-};
-
-struct pcf50633_platform_data gta02_pcf_pdata = {
-       .resumers = {
-               [0] =   PCF50633_INT1_USBINS |
-                       PCF50633_INT1_USBREM |
-                       PCF50633_INT1_ALARM,
-               [1] =   PCF50633_INT2_ONKEYF,
-               [2] =   PCF50633_INT3_ONKEY1S,
-               [3] =   PCF50633_INT4_LOWSYS |
-                       PCF50633_INT4_LOWBAT |
-                       PCF50633_INT4_HIGHTMP,
-       },
-
-       .batteries = gta02_batteries,
-       .num_batteries = ARRAY_SIZE(gta02_batteries),
-
-       .charger_reference_current_ma = 1000,
-
-       .backlight_data = &gta02_backlight_data,
-
-       .reg_init_data = {
-               [PCF50633_REGULATOR_AUTO] = {
-                       .constraints = {
-                               .min_uV = 3300000,
-                               .max_uV = 3300000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                               .always_on = 1,
-                               .apply_uV = 1,
-                       },
-               },
-               [PCF50633_REGULATOR_DOWN1] = {
-                       .constraints = {
-                               .min_uV = 1300000,
-                               .max_uV = 1600000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                               .always_on = 1,
-                               .apply_uV = 1,
-                       },
-               },
-               [PCF50633_REGULATOR_DOWN2] = {
-                       .constraints = {
-                               .min_uV = 1800000,
-                               .max_uV = 1800000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                               .apply_uV = 1,
-                               .always_on = 1,
-                       },
-               },
-               [PCF50633_REGULATOR_HCLDO] = {
-                       .constraints = {
-                               .min_uV = 2000000,
-                               .max_uV = 3300000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
-                                               REGULATOR_CHANGE_STATUS,
-                       },
-               },
-               [PCF50633_REGULATOR_LDO1] = {
-                       .constraints = {
-                               .min_uV = 3300000,
-                               .max_uV = 3300000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
-                               .apply_uV = 1,
-                       },
-               },
-               [PCF50633_REGULATOR_LDO2] = {
-                       .constraints = {
-                               .min_uV = 3300000,
-                               .max_uV = 3300000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                               .apply_uV = 1,
-                       },
-               },
-               [PCF50633_REGULATOR_LDO3] = {
-                       .constraints = {
-                               .min_uV = 3000000,
-                               .max_uV = 3000000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                               .apply_uV = 1,
-                       },
-               },
-               [PCF50633_REGULATOR_LDO4] = {
-                       .constraints = {
-                               .min_uV = 3200000,
-                               .max_uV = 3200000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
-                               .apply_uV = 1,
-                       },
-               },
-               [PCF50633_REGULATOR_LDO5] = {
-                       .constraints = {
-                               .min_uV = 3000000,
-                               .max_uV = 3000000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
-                               .apply_uV = 1,
-                       },
-               },
-               [PCF50633_REGULATOR_LDO6] = {
-                       .constraints = {
-                               .min_uV = 3000000,
-                               .max_uV = 3000000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                       },
-               },
-               [PCF50633_REGULATOR_MEMLDO] = {
-                       .constraints = {
-                               .min_uV = 1800000,
-                               .max_uV = 1800000,
-                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
-                       },
-               },
-
-       },
-       .probe_done = gta02_pmu_attach_child_devices,
-       .mbc_event_callback = gta02_pmu_event_callback,
-};
-
-
-/* NOR Flash. */
-
-#define GTA02_FLASH_BASE       0x18000000 /* GCS3 */
-#define GTA02_FLASH_SIZE       0x200000 /* 2MBytes */
-
-static struct physmap_flash_data gta02_nor_flash_data = {
-       .width          = 2,
-};
-
-static struct resource gta02_nor_flash_resource = {
-       .start          = GTA02_FLASH_BASE,
-       .end            = GTA02_FLASH_BASE + GTA02_FLASH_SIZE - 1,
-       .flags          = IORESOURCE_MEM,
-};
-
-static struct platform_device gta02_nor_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &gta02_nor_flash_data,
-       },
-       .resource       = &gta02_nor_flash_resource,
-       .num_resources  = 1,
-};
-
-
-struct platform_device s3c24xx_pwm_device = {
-       .name           = "s3c24xx_pwm",
-       .num_resources  = 0,
-};
-
-static struct platform_device gta02_dfbmcs320_device = {
-       .name = "dfbmcs320",
-};
-
-static struct i2c_board_info gta02_i2c_devs[] __initdata = {
-       {
-               I2C_BOARD_INFO("pcf50633", 0x73),
-               .irq = GTA02_IRQ_PCF50633,
-               .platform_data = &gta02_pcf_pdata,
-       },
-       {
-               I2C_BOARD_INFO("wm8753", 0x1a),
-       },
-};
-
-static struct s3c2410_nand_set __initdata gta02_nand_sets[] = {
-       [0] = {
-               /*
-                * This name is also hard-coded in the boot loaders, so
-                * changing it would would require all users to upgrade
-                * their boot loaders, some of which are stored in a NOR
-                * that is considered to be immutable.
-                */
-               .name           = "neo1973-nand",
-               .nr_chips       = 1,
-               .flash_bbt      = 1,
-       },
-};
-
-/*
- * Choose a set of timings derived from S3C@2442B MCP54
- * data sheet (K5D2G13ACM-D075 MCP Memory).
- */
-
-static struct s3c2410_platform_nand __initdata gta02_nand_info = {
-       .tacls          = 0,
-       .twrph0         = 25,
-       .twrph1         = 15,
-       .nr_sets        = ARRAY_SIZE(gta02_nand_sets),
-       .sets           = gta02_nand_sets,
-};
-
-
-/* Get PMU to set USB current limit accordingly. */
-static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = {
-       .vbus_draw      = gta02_udc_vbus_draw,
-       .pullup_pin = GTA02_GPIO_USB_PULLUP,
-};
-
-/* USB */
-static struct s3c2410_hcd_info gta02_usb_info __initdata = {
-       .port[0]        = {
-               .flags  = S3C_HCDFLG_USED,
-       },
-       .port[1]        = {
-               .flags  = 0,
-       },
-};
-
-/* Touchscreen */
-static struct s3c2410_ts_mach_info gta02_ts_info = {
-       .delay                  = 10000,
-       .presc                  = 0xff, /* slow as we can go */
-       .oversampling_shift     = 2,
-};
-
-/* Buttons */
-static struct gpio_keys_button gta02_buttons[] = {
-       {
-               .gpio = GTA02_GPIO_AUX_KEY,
-               .code = KEY_PHONE,
-               .desc = "Aux",
-               .type = EV_KEY,
-               .debounce_interval = 100,
-       },
-       {
-               .gpio = GTA02_GPIO_HOLD_KEY,
-               .code = KEY_PAUSE,
-               .desc = "Hold",
-               .type = EV_KEY,
-               .debounce_interval = 100,
-       },
-};
-
-static struct gpio_keys_platform_data gta02_buttons_pdata = {
-       .buttons = gta02_buttons,
-       .nbuttons = ARRAY_SIZE(gta02_buttons),
-};
-
-static struct platform_device gta02_buttons_device = {
-       .name = "gpio-keys",
-       .id = -1,
-       .dev = {
-               .platform_data = &gta02_buttons_pdata,
-       },
-};
-
-static void __init gta02_map_io(void)
-{
-       s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc));
-       s3c24xx_init_clocks(12000000);
-       s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs));
-}
-
-
-/* These are the guys that don't need to be children of PMU. */
-
-static struct platform_device *gta02_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_wdt,
-       &s3c_device_sdi,
-       &s3c_device_usbgadget,
-       &s3c_device_nand,
-       &gta02_nor_flash,
-       &s3c24xx_pwm_device,
-       &s3c_device_iis,
-       &samsung_asoc_dma,
-       &s3c_device_i2c0,
-       &gta02_dfbmcs320_device,
-       &gta02_buttons_device,
-       &s3c_device_adc,
-       &s3c_device_ts,
-};
-
-/* These guys DO need to be children of PMU. */
-
-static struct platform_device *gta02_devices_pmu_children[] = {
-};
-
-
-/*
- * This is called when pc50633 is probed, quite late in the day since it is an
- * I2C bus device.  Here we can define platform devices with the advantage that
- * we can mark the pcf50633 as the parent.  This makes them get suspended and
- * resumed with their parent the pcf50633 still around.  All devices whose
- * operation depends on something from pcf50633 must have this relationship
- * made explicit like this, or suspend and resume will become an unreliable
- * hellworld.
- */
-
-static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf)
-{
-       int n;
-
-       /* Grab a copy of the now probed PMU pointer. */
-       gta02_pcf = pcf;
-
-       for (n = 0; n < ARRAY_SIZE(gta02_devices_pmu_children); n++)
-               gta02_devices_pmu_children[n]->dev.parent = pcf->dev;
-
-       platform_add_devices(gta02_devices_pmu_children,
-                            ARRAY_SIZE(gta02_devices_pmu_children));
-}
-
-static void gta02_poweroff(void)
-{
-       pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN, 1, 1);
-}
-
-static void __init gta02_machine_init(void)
-{
-       /* Set the panic callback to turn AUX LED on or off. */
-       panic_blink = gta02_panic_blink;
-
-       s3c_pm_init();
-
-#ifdef CONFIG_CHARGER_PCF50633
-       INIT_DELAYED_WORK(&gta02_charger_work, gta02_charger_worker);
-#endif
-
-       s3c24xx_udc_set_platdata(&gta02_udc_cfg);
-       s3c24xx_ts_set_platdata(&gta02_ts_info);
-       s3c_ohci_set_platdata(&gta02_usb_info);
-       s3c_nand_set_platdata(&gta02_nand_info);
-       s3c_i2c0_set_platdata(NULL);
-
-       i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs));
-
-       platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices));
-       pm_power_off = gta02_poweroff;
-
-       regulator_has_full_constraints();
-}
-
-
-MACHINE_START(NEO1973_GTA02, "GTA02")
-       /* Maintainer: Nelson Castillo <arhuaco@freaks-unidos.net> */
-       .atag_offset    = 0x100,
-       .map_io         = gta02_map_io,
-       .init_irq       = s3c24xx_init_irq,
-       .init_machine   = gta02_machine_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-mini2440.c b/arch/arm/mach-s3c2440/mach-mini2440.c
deleted file mode 100644 (file)
index 5d66fb2..0000000
+++ /dev/null
@@ -1,705 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-mini2440.c
- *
- * Copyright (c) 2008 Ramax Lo <ramaxlo@gmail.com>
- *      Based on mach-anubis.c by Ben Dooks <ben@simtec.co.uk>
- *      and modifications by SBZ <sbz@spgui.org> and
- *      Weibing <http://weibing.blogbus.com> and
- *      Michel Pollet <buserror@gmail.com>
- *
- * For product information, visit http://code.google.com/p/mini2440/
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/input.h>
-#include <linux/io.h>
-#include <linux/serial_core.h>
-#include <linux/dm9000.h>
-#include <linux/i2c/at24.h>
-#include <linux/platform_device.h>
-#include <linux/gpio_keys.h>
-#include <linux/i2c.h>
-#include <linux/mmc/host.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
-#include <mach/fb.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/leds-gpio.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <mach/irqs.h>
-#include <plat/nand.h>
-#include <plat/iic.h>
-#include <plat/mci.h>
-#include <plat/udc.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <plat/gpio-cfg.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-
-#include <sound/s3c24xx_uda134x.h>
-
-#include "common.h"
-
-#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300)
-
-static struct map_desc mini2440_iodesc[] __initdata = {
-       /* nothing to declare, move along */
-};
-
-#define UCON S3C2410_UCON_DEFAULT
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-
-static struct s3c2410_uartcfg mini2440_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-};
-
-/* USB device UDC support */
-
-static struct s3c2410_udc_mach_info mini2440_udc_cfg __initdata = {
-       .pullup_pin = S3C2410_GPC(5),
-};
-
-
-/* LCD timing and setup */
-
-/*
- * This macro simplifies the table bellow
- */
-#define _LCD_DECLARE(_clock,_xres,margin_left,margin_right,hsync, \
-                       _yres,margin_top,margin_bottom,vsync, refresh) \
-       .width = _xres, \
-       .xres = _xres, \
-       .height = _yres, \
-       .yres = _yres, \
-       .left_margin    = margin_left,  \
-       .right_margin   = margin_right, \
-       .upper_margin   = margin_top,   \
-       .lower_margin   = margin_bottom,        \
-       .hsync_len      = hsync,        \
-       .vsync_len      = vsync,        \
-       .pixclock       = ((_clock*100000000000LL) /    \
-                          ((refresh) * \
-                          (hsync + margin_left + _xres + margin_right) * \
-                          (vsync + margin_top + _yres + margin_bottom))), \
-       .bpp            = 16,\
-       .type           = (S3C2410_LCDCON1_TFT16BPP |\
-                          S3C2410_LCDCON1_TFT)
-
-static struct s3c2410fb_display mini2440_lcd_cfg[] __initdata = {
-       [0] = { /* mini2440 + 3.5" TFT + touchscreen */
-               _LCD_DECLARE(
-                       7,                      /* The 3.5 is quite fast */
-                       240, 21, 38, 6,         /* x timing */
-                       320, 4, 4, 2,           /* y timing */
-                       60),                    /* refresh rate */
-               .lcdcon5        = (S3C2410_LCDCON5_FRM565 |
-                                  S3C2410_LCDCON5_INVVLINE |
-                                  S3C2410_LCDCON5_INVVFRAME |
-                                  S3C2410_LCDCON5_INVVDEN |
-                                  S3C2410_LCDCON5_PWREN),
-       },
-       [1] = { /* mini2440 + 7" TFT + touchscreen */
-               _LCD_DECLARE(
-                       10,                     /* the 7" runs slower */
-                       800, 40, 40, 48,        /* x timing */
-                       480, 29, 3, 3,          /* y timing */
-                       50),                    /* refresh rate */
-               .lcdcon5        = (S3C2410_LCDCON5_FRM565 |
-                                  S3C2410_LCDCON5_INVVLINE |
-                                  S3C2410_LCDCON5_INVVFRAME |
-                                  S3C2410_LCDCON5_PWREN),
-       },
-       /* The VGA shield can outout at several resolutions. All share 
-        * the same timings, however, anything smaller than 1024x768
-        * will only be displayed in the top left corner of a 1024x768
-        * XGA output unless you add optional dip switches to the shield.
-        * Therefore timings for other resolutions have been omitted here.
-        */
-       [2] = {
-               _LCD_DECLARE(
-                       10,
-                       1024, 1, 2, 2,          /* y timing */
-                       768, 200, 16, 16,       /* x timing */
-                       24),    /* refresh rate, maximum stable,
-                                tested with the FPGA shield */
-               .lcdcon5        = (S3C2410_LCDCON5_FRM565 |
-                                  S3C2410_LCDCON5_HWSWP),
-       },
-       /* mini2440 + 3.5" TFT (LCD-W35i, LQ035Q1DG06 type) + touchscreen*/
-       [3] = {
-               _LCD_DECLARE(
-                       /* clock */
-                       7,
-                       /* xres, margin_right, margin_left, hsync */
-                       320, 68, 66, 4,
-                       /* yres, margin_top, margin_bottom, vsync */
-                       240, 4, 4, 9,
-                       /* refresh rate */
-                       60),
-               .lcdcon5        = (S3C2410_LCDCON5_FRM565 |
-                                  S3C2410_LCDCON5_INVVDEN |
-                                  S3C2410_LCDCON5_INVVFRAME |
-                                  S3C2410_LCDCON5_INVVLINE |
-                                  S3C2410_LCDCON5_INVVCLK |
-                                  S3C2410_LCDCON5_HWSWP),
-       },
-};
-
-/* todo - put into gpio header */
-
-#define S3C2410_GPCCON_MASK(x) (3 << ((x) * 2))
-#define S3C2410_GPDCON_MASK(x) (3 << ((x) * 2))
-
-static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
-       .displays        = &mini2440_lcd_cfg[0], /* not constant! see init */
-       .num_displays    = 1,
-       .default_display = 0,
-
-       /* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN
-        * and disable the pull down resistors on pins we are using for LCD
-        * data. */
-
-       .gpcup          = (0xf << 1) | (0x3f << 10),
-
-       .gpccon         = (S3C2410_GPC1_VCLK   | S3C2410_GPC2_VLINE |
-                          S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM |
-                          S3C2410_GPC10_VD2   | S3C2410_GPC11_VD3 |
-                          S3C2410_GPC12_VD4   | S3C2410_GPC13_VD5 |
-                          S3C2410_GPC14_VD6   | S3C2410_GPC15_VD7),
-
-       .gpccon_mask    = (S3C2410_GPCCON_MASK(1)  | S3C2410_GPCCON_MASK(2)  |
-                          S3C2410_GPCCON_MASK(3)  | S3C2410_GPCCON_MASK(4)  |
-                          S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) |
-                          S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) |
-                          S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)),
-
-       .gpdup          = (0x3f << 2) | (0x3f << 10),
-
-       .gpdcon         = (S3C2410_GPD2_VD10  | S3C2410_GPD3_VD11 |
-                          S3C2410_GPD4_VD12  | S3C2410_GPD5_VD13 |
-                          S3C2410_GPD6_VD14  | S3C2410_GPD7_VD15 |
-                          S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 |
-                          S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 |
-                          S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23),
-
-       .gpdcon_mask    = (S3C2410_GPDCON_MASK(2)  | S3C2410_GPDCON_MASK(3) |
-                          S3C2410_GPDCON_MASK(4)  | S3C2410_GPDCON_MASK(5) |
-                          S3C2410_GPDCON_MASK(6)  | S3C2410_GPDCON_MASK(7) |
-                          S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)|
-                          S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)|
-                          S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)),
-};
-
-/* MMC/SD  */
-
-static struct s3c24xx_mci_pdata mini2440_mmc_cfg __initdata = {
-   .gpio_detect   = S3C2410_GPG(8),
-   .gpio_wprotect = S3C2410_GPH(8),
-   .set_power     = NULL,
-   .ocr_avail     = MMC_VDD_32_33|MMC_VDD_33_34,
-};
-
-/* NAND Flash on MINI2440 board */
-
-static struct mtd_partition mini2440_default_nand_part[] __initdata = {
-       [0] = {
-               .name   = "u-boot",
-               .size   = SZ_256K,
-               .offset = 0,
-       },
-       [1] = {
-               .name   = "u-boot-env",
-               .size   = SZ_128K,
-               .offset = SZ_256K,
-       },
-       [2] = {
-               .name   = "kernel",
-               /* 5 megabytes, for a kernel with no modules
-                * or a uImage with a ramdisk attached */
-               .size   = 0x00500000,
-               .offset = SZ_256K + SZ_128K,
-       },
-       [3] = {
-               .name   = "root",
-               .offset = SZ_256K + SZ_128K + 0x00500000,
-               .size   = MTDPART_SIZ_FULL,
-       },
-};
-
-static struct s3c2410_nand_set mini2440_nand_sets[] __initdata = {
-       [0] = {
-               .name           = "nand",
-               .nr_chips       = 1,
-               .nr_partitions  = ARRAY_SIZE(mini2440_default_nand_part),
-               .partitions     = mini2440_default_nand_part,
-               .flash_bbt      = 1, /* we use u-boot to create a BBT */
-       },
-};
-
-static struct s3c2410_platform_nand mini2440_nand_info __initdata = {
-       .tacls          = 0,
-       .twrph0         = 25,
-       .twrph1         = 15,
-       .nr_sets        = ARRAY_SIZE(mini2440_nand_sets),
-       .sets           = mini2440_nand_sets,
-       .ignore_unset_ecc = 1,
-};
-
-/* DM9000AEP 10/100 ethernet controller */
-
-static struct resource mini2440_dm9k_resource[] = {
-       [0] = {
-               .start = MACH_MINI2440_DM9K_BASE,
-               .end   = MACH_MINI2440_DM9K_BASE + 3,
-               .flags = IORESOURCE_MEM
-       },
-       [1] = {
-               .start = MACH_MINI2440_DM9K_BASE + 4,
-               .end   = MACH_MINI2440_DM9K_BASE + 7,
-               .flags = IORESOURCE_MEM
-       },
-       [2] = {
-               .start = IRQ_EINT7,
-               .end   = IRQ_EINT7,
-               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
-       }
-};
-
-/*
- * The DM9000 has no eeprom, and it's MAC address is set by
- * the bootloader before starting the kernel.
- */
-static struct dm9000_plat_data mini2440_dm9k_pdata = {
-       .flags          = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
-};
-
-static struct platform_device mini2440_device_eth = {
-       .name           = "dm9000",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(mini2440_dm9k_resource),
-       .resource       = mini2440_dm9k_resource,
-       .dev            = {
-               .platform_data  = &mini2440_dm9k_pdata,
-       },
-};
-
-/*  CON5
- *     +--+     /-----\
- *     |  |    |       |
- *     |  |    |  BAT  |
- *     |  |     \_____/
- *     |  |
- *     |  |  +----+  +----+
- *     |  |  | K5 |  | K1 |
- *     |  |  +----+  +----+
- *     |  |  +----+  +----+
- *     |  |  | K4 |  | K2 |
- *     |  |  +----+  +----+
- *     |  |  +----+  +----+
- *     |  |  | K6 |  | K3 |
- *     |  |  +----+  +----+
- *       .....
- */
-static struct gpio_keys_button mini2440_buttons[] = {
-       {
-               .gpio           = S3C2410_GPG(0),               /* K1 */
-               .code           = KEY_F1,
-               .desc           = "Button 1",
-               .active_low     = 1,
-       },
-       {
-               .gpio           = S3C2410_GPG(3),               /* K2 */
-               .code           = KEY_F2,
-               .desc           = "Button 2",
-               .active_low     = 1,
-       },
-       {
-               .gpio           = S3C2410_GPG(5),               /* K3 */
-               .code           = KEY_F3,
-               .desc           = "Button 3",
-               .active_low     = 1,
-       },
-       {
-               .gpio           = S3C2410_GPG(6),               /* K4 */
-               .code           = KEY_POWER,
-               .desc           = "Power",
-               .active_low     = 1,
-       },
-       {
-               .gpio           = S3C2410_GPG(7),               /* K5 */
-               .code           = KEY_F5,
-               .desc           = "Button 5",
-               .active_low     = 1,
-       },
-#if 0
-       /* this pin is also known as TCLK1 and seems to already
-        * marked as "in use" somehow in the kernel -- possibly wrongly */
-       {
-               .gpio           = S3C2410_GPG(11),      /* K6 */
-               .code           = KEY_F6,
-               .desc           = "Button 6",
-               .active_low     = 1,
-       },
-#endif
-};
-
-static struct gpio_keys_platform_data mini2440_button_data = {
-       .buttons        = mini2440_buttons,
-       .nbuttons       = ARRAY_SIZE(mini2440_buttons),
-};
-
-static struct platform_device mini2440_button_device = {
-       .name           = "gpio-keys",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &mini2440_button_data,
-       }
-};
-
-/* LEDS */
-
-static struct s3c24xx_led_platdata mini2440_led1_pdata = {
-       .name           = "led1",
-       .gpio           = S3C2410_GPB(5),
-       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
-       .def_trigger    = "heartbeat",
-};
-
-static struct s3c24xx_led_platdata mini2440_led2_pdata = {
-       .name           = "led2",
-       .gpio           = S3C2410_GPB(6),
-       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
-       .def_trigger    = "nand-disk",
-};
-
-static struct s3c24xx_led_platdata mini2440_led3_pdata = {
-       .name           = "led3",
-       .gpio           = S3C2410_GPB(7),
-       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
-       .def_trigger    = "mmc0",
-};
-
-static struct s3c24xx_led_platdata mini2440_led4_pdata = {
-       .name           = "led4",
-       .gpio           = S3C2410_GPB(8),
-       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
-       .def_trigger    = "",
-};
-
-static struct s3c24xx_led_platdata mini2440_led_backlight_pdata = {
-       .name           = "backlight",
-       .gpio           = S3C2410_GPG(4),
-       .def_trigger    = "backlight",
-};
-
-static struct platform_device mini2440_led1 = {
-       .name           = "s3c24xx_led",
-       .id             = 1,
-       .dev            = {
-               .platform_data  = &mini2440_led1_pdata,
-       },
-};
-
-static struct platform_device mini2440_led2 = {
-       .name           = "s3c24xx_led",
-       .id             = 2,
-       .dev            = {
-               .platform_data  = &mini2440_led2_pdata,
-       },
-};
-
-static struct platform_device mini2440_led3 = {
-       .name           = "s3c24xx_led",
-       .id             = 3,
-       .dev            = {
-               .platform_data  = &mini2440_led3_pdata,
-       },
-};
-
-static struct platform_device mini2440_led4 = {
-       .name           = "s3c24xx_led",
-       .id             = 4,
-       .dev            = {
-               .platform_data  = &mini2440_led4_pdata,
-       },
-};
-
-static struct platform_device mini2440_led_backlight = {
-       .name           = "s3c24xx_led",
-       .id             = 5,
-       .dev            = {
-               .platform_data  = &mini2440_led_backlight_pdata,
-       },
-};
-
-/* AUDIO */
-
-static struct s3c24xx_uda134x_platform_data mini2440_audio_pins = {
-       .l3_clk = S3C2410_GPB(4),
-       .l3_mode = S3C2410_GPB(2),
-       .l3_data = S3C2410_GPB(3),
-       .model = UDA134X_UDA1341
-};
-
-static struct platform_device mini2440_audio = {
-       .name           = "s3c24xx_uda134x",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &mini2440_audio_pins,
-       },
-};
-
-/*
- * I2C devices
- */
-static struct at24_platform_data at24c08 = {
-       .byte_len       = SZ_8K / 8,
-       .page_size      = 16,
-};
-
-static struct i2c_board_info mini2440_i2c_devs[] __initdata = {
-       {
-               I2C_BOARD_INFO("24c08", 0x50),
-               .platform_data = &at24c08,
-       },
-};
-
-static struct platform_device uda1340_codec = {
-               .name = "uda134x-codec",
-               .id = -1,
-};
-
-static struct platform_device *mini2440_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_rtc,
-       &s3c_device_usbgadget,
-       &mini2440_device_eth,
-       &mini2440_led1,
-       &mini2440_led2,
-       &mini2440_led3,
-       &mini2440_led4,
-       &mini2440_button_device,
-       &s3c_device_nand,
-       &s3c_device_sdi,
-       &s3c_device_iis,
-       &uda1340_codec,
-       &mini2440_audio,
-       &samsung_asoc_dma,
-};
-
-static void __init mini2440_map_io(void)
-{
-       s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc));
-       s3c24xx_init_clocks(12000000);
-       s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs));
-}
-
-/*
- * mini2440_features string
- *
- * t = Touchscreen present
- * b = backlight control
- * c = camera [TODO]
- * 0-9 LCD configuration
- *
- */
-static char mini2440_features_str[12] __initdata = "0tb";
-
-static int __init mini2440_features_setup(char *str)
-{
-       if (str)
-               strlcpy(mini2440_features_str, str, sizeof(mini2440_features_str));
-       return 1;
-}
-
-__setup("mini2440=", mini2440_features_setup);
-
-#define FEATURE_SCREEN (1 << 0)
-#define FEATURE_BACKLIGHT (1 << 1)
-#define FEATURE_TOUCH (1 << 2)
-#define FEATURE_CAMERA (1 << 3)
-
-struct mini2440_features_t {
-       int count;
-       int done;
-       int lcd_index;
-       struct platform_device *optional[8];
-};
-
-static void __init mini2440_parse_features(
-               struct mini2440_features_t * features,
-               const char * features_str )
-{
-       const char * fp = features_str;
-
-       features->count = 0;
-       features->done = 0;
-       features->lcd_index = -1;
-
-       while (*fp) {
-               char f = *fp++;
-
-               switch (f) {
-               case '0'...'9': /* tft screen */
-                       if (features->done & FEATURE_SCREEN) {
-                               printk(KERN_INFO "MINI2440: '%c' ignored, "
-                                       "screen type already set\n", f);
-                       } else {
-                               int li = f - '0';
-                               if (li >= ARRAY_SIZE(mini2440_lcd_cfg))
-                                       printk(KERN_INFO "MINI2440: "
-                                               "'%c' out of range LCD mode\n", f);
-                               else {
-                                       features->optional[features->count++] =
-                                                       &s3c_device_lcd;
-                                       features->lcd_index = li;
-                               }
-                       }
-                       features->done |= FEATURE_SCREEN;
-                       break;
-               case 'b':
-                       if (features->done & FEATURE_BACKLIGHT)
-                               printk(KERN_INFO "MINI2440: '%c' ignored, "
-                                       "backlight already set\n", f);
-                       else {
-                               features->optional[features->count++] =
-                                               &mini2440_led_backlight;
-                       }
-                       features->done |= FEATURE_BACKLIGHT;
-                       break;
-               case 't':
-                       printk(KERN_INFO "MINI2440: '%c' ignored, "
-                               "touchscreen not compiled in\n", f);
-                       break;
-               case 'c':
-                       if (features->done & FEATURE_CAMERA)
-                               printk(KERN_INFO "MINI2440: '%c' ignored, "
-                                       "camera already registered\n", f);
-                       else
-                               features->optional[features->count++] =
-                                       &s3c_device_camif;
-                       features->done |= FEATURE_CAMERA;
-                       break;
-               }
-       }
-}
-
-static void __init mini2440_init(void)
-{
-       struct mini2440_features_t features = { 0 };
-       int i;
-
-       printk(KERN_INFO "MINI2440: Option string mini2440=%s\n",
-                       mini2440_features_str);
-
-       /* Parse the feature string */
-       mini2440_parse_features(&features, mini2440_features_str);
-
-       /* turn LCD on */
-       s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);
-
-       /* Turn the backlight early on */
-       WARN_ON(gpio_request(S3C2410_GPG(4), "backlight"));
-       gpio_direction_output(S3C2410_GPG(4), 1);
-
-       /* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */
-       s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);
-       s3c2410_gpio_setpin(S3C2410_GPB(1), 0);
-       s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPIO_INPUT);
-
-       /* mark the key as input, without pullups (there is one on the board) */
-       for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {
-               s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP);
-               s3c_gpio_cfgpin(mini2440_buttons[i].gpio, S3C2410_GPIO_INPUT);
-       }
-       if (features.lcd_index != -1) {
-               int li;
-
-               mini2440_fb_info.displays =
-                       &mini2440_lcd_cfg[features.lcd_index];
-
-               printk(KERN_INFO "MINI2440: LCD");
-               for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++)
-                       if (li == features.lcd_index)
-                               printk(" [%d:%dx%d]", li,
-                                       mini2440_lcd_cfg[li].width,
-                                       mini2440_lcd_cfg[li].height);
-                       else
-                               printk(" %d:%dx%d", li,
-                                       mini2440_lcd_cfg[li].width,
-                                       mini2440_lcd_cfg[li].height);
-               printk("\n");
-               s3c24xx_fb_set_platdata(&mini2440_fb_info);
-       }
-
-       s3c24xx_udc_set_platdata(&mini2440_udc_cfg);
-       s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);
-       s3c_nand_set_platdata(&mini2440_nand_info);
-       s3c_i2c0_set_platdata(NULL);
-
-       i2c_register_board_info(0, mini2440_i2c_devs,
-                               ARRAY_SIZE(mini2440_i2c_devs));
-
-       platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
-
-       if (features.count)     /* the optional features */
-               platform_add_devices(features.optional, features.count);
-
-}
-
-
-MACHINE_START(MINI2440, "MINI2440")
-       /* Maintainer: Michel Pollet <buserror@gmail.com> */
-       .atag_offset    = 0x100,
-       .map_io         = mini2440_map_io,
-       .init_machine   = mini2440_init,
-       .init_irq       = s3c24xx_init_irq,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c
deleted file mode 100644 (file)
index 5198e3e..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-nexcoder.c
- *
- * Copyright (c) 2004 Nex Vision
- *   Guillaume GOURAT <guillaume.gourat@nexvision.tv>
- *
- * 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.
- *
- * Modifications:
- *     15-10-2004 GG  Created initial version
- *     12-03-2005 BJD Updated for release
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/string.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <linux/mtd/map.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <asm/setup.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-//#include <asm/debug-ll.h>
-#include <mach/regs-gpio.h>
-#include <plat/regs-serial.h>
-#include <plat/iic.h>
-
-#include <plat/gpio-cfg.h>
-#include <plat/s3c2410.h>
-#include <plat/s3c244x.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-
-#include "common.h"
-
-static struct map_desc nexcoder_iodesc[] __initdata = {
-       /* nothing here yet */
-};
-
-#define UCON S3C2410_UCON_DEFAULT
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG12 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg nexcoder_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       },
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-       }
-};
-
-/* NOR Flash on NexVision NexCoder 2440 board */
-
-static struct resource nexcoder_nor_resource[] = {
-       [0] = {
-               .start = S3C2410_CS0,
-               .end   = S3C2410_CS0 + (8*1024*1024) - 1,
-               .flags = IORESOURCE_MEM,
-       }
-};
-
-static struct map_info nexcoder_nor_map = {
-       .bankwidth = 2,
-};
-
-static struct platform_device nexcoder_device_nor = {
-       .name           = "mtd-flash",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(nexcoder_nor_resource),
-       .resource       = nexcoder_nor_resource,
-       .dev =
-       {
-               .platform_data = &nexcoder_nor_map,
-       }
-};
-
-/* Standard Nexcoder devices */
-
-static struct platform_device *nexcoder_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-       &s3c_device_rtc,
-       &s3c_device_camif,
-       &s3c_device_spi0,
-       &s3c_device_spi1,
-       &nexcoder_device_nor,
-};
-
-static void __init nexcoder_sensorboard_init(void)
-{
-       // Initialize SCCB bus
-       s3c2410_gpio_setpin(S3C2410_GPE(14), 1); // IICSCL
-       s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPIO_OUTPUT);
-       s3c2410_gpio_setpin(S3C2410_GPE(15), 1); // IICSDA
-       s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPIO_OUTPUT);
-
-       // Power up the sensor board
-       s3c2410_gpio_setpin(S3C2410_GPF(1), 1);
-       s3c_gpio_cfgpin(S3C2410_GPF(1), S3C2410_GPIO_OUTPUT); // CAM_GPIO7 => nLDO_PWRDN
-       s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
-       s3c_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT); // CAM_GPIO6 => CAM_PWRDN
-}
-
-static void __init nexcoder_map_io(void)
-{
-       s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc));
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(nexcoder_uartcfgs, ARRAY_SIZE(nexcoder_uartcfgs));
-
-       nexcoder_sensorboard_init();
-}
-
-static void __init nexcoder_init(void)
-{
-       s3c_i2c0_set_platdata(NULL);
-       platform_add_devices(nexcoder_devices, ARRAY_SIZE(nexcoder_devices));
-};
-
-MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
-       /* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
-       .atag_offset    = 0x100,
-       .map_io         = nexcoder_map_io,
-       .init_machine   = nexcoder_init,
-       .init_irq       = s3c24xx_init_irq,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-osiris-dvs.c b/arch/arm/mach-s3c2440/mach-osiris-dvs.c
deleted file mode 100644 (file)
index ad2792d..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-osiris-dvs.c
- *
- * Copyright (c) 2009 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Simtec Osiris Dynamic Voltage Scaling support.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/cpufreq.h>
-#include <linux/gpio.h>
-
-#include <linux/i2c/tps65010.h>
-
-#include <plat/cpu-freq.h>
-
-#define OSIRIS_GPIO_DVS        S3C2410_GPB(5)
-
-static bool dvs_en;
-
-static void osiris_dvs_tps_setdvs(bool on)
-{
-       unsigned vregs1 = 0, vdcdc2 = 0;
-
-       if (!on) {
-               vdcdc2 = TPS_VCORE_DISCH | TPS_LP_COREOFF;
-               vregs1 = TPS_LDO1_OFF;  /* turn off in low-power mode */
-       }
-
-       dvs_en = on;
-       vdcdc2 |= TPS_VCORE_1_3V | TPS_VCORE_LP_1_0V;
-       vregs1 |= TPS_LDO2_ENABLE | TPS_LDO1_ENABLE;
-
-       tps65010_config_vregs1(vregs1);
-       tps65010_config_vdcdc2(vdcdc2);
-}
-
-static bool is_dvs(struct s3c_freq *f)
-{
-       /* at the moment, we assume ARMCLK = HCLK => DVS */
-       return f->armclk == f->hclk;
-}
-
-/* keep track of current state */
-static bool cur_dvs = false;
-
-static int osiris_dvs_notify(struct notifier_block *nb,
-                             unsigned long val, void *data)
-{
-       struct cpufreq_freqs *cf = data;
-       struct s3c_cpufreq_freqs *freqs = to_s3c_cpufreq(cf);
-       bool old_dvs = is_dvs(&freqs->old);
-       bool new_dvs = is_dvs(&freqs->new);
-       int ret = 0;
-
-       if (!dvs_en)
-               return 0;
-
-       printk(KERN_DEBUG "%s: old %ld,%ld new %ld,%ld\n", __func__,
-              freqs->old.armclk, freqs->old.hclk,
-              freqs->new.armclk, freqs->new.hclk);
-
-       switch (val) {
-       case CPUFREQ_PRECHANGE:
-               if (old_dvs & !new_dvs ||
-                   cur_dvs & !new_dvs) {
-                       pr_debug("%s: exiting dvs\n", __func__);
-                       cur_dvs = false;
-                       gpio_set_value(OSIRIS_GPIO_DVS, 1);
-               }
-               break;
-       case CPUFREQ_POSTCHANGE:
-               if (!old_dvs & new_dvs ||
-                   !cur_dvs & new_dvs) {
-                       pr_debug("entering dvs\n");
-                       cur_dvs = true;
-                       gpio_set_value(OSIRIS_GPIO_DVS, 0);
-               }
-               break;
-       }
-
-       return ret;
-}
-
-static struct notifier_block osiris_dvs_nb = {
-       .notifier_call  = osiris_dvs_notify,
-};
-
-static int __devinit osiris_dvs_probe(struct platform_device *pdev)
-{
-       int ret;
-
-       dev_info(&pdev->dev, "initialising\n");
-
-       ret = gpio_request(OSIRIS_GPIO_DVS, "osiris-dvs");
-       if (ret) {
-               dev_err(&pdev->dev, "cannot claim gpio\n");
-               goto err_nogpio;
-       }
-
-       /* start with dvs disabled */
-       gpio_direction_output(OSIRIS_GPIO_DVS, 1);
-
-       ret = cpufreq_register_notifier(&osiris_dvs_nb,
-                                       CPUFREQ_TRANSITION_NOTIFIER);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to register with cpufreq\n");
-               goto err_nofreq;
-       }
-
-       osiris_dvs_tps_setdvs(true);
-
-       return 0;
-
-err_nofreq:
-       gpio_free(OSIRIS_GPIO_DVS);
-
-err_nogpio:
-       return ret;
-}
-
-static int __devexit osiris_dvs_remove(struct platform_device *pdev)
-{
-       dev_info(&pdev->dev, "exiting\n");
-
-       /* disable any current dvs */
-       gpio_set_value(OSIRIS_GPIO_DVS, 1);
-       osiris_dvs_tps_setdvs(false);
-
-       cpufreq_unregister_notifier(&osiris_dvs_nb,
-                                   CPUFREQ_TRANSITION_NOTIFIER);
-
-       gpio_free(OSIRIS_GPIO_DVS);
-
-       return 0;
-}
-
-/* the CONFIG_PM block is so small, it isn't worth actaully compiling it
- * out if the configuration isn't set. */
-
-static int osiris_dvs_suspend(struct device *dev)
-{
-       gpio_set_value(OSIRIS_GPIO_DVS, 1);
-       osiris_dvs_tps_setdvs(false);
-       cur_dvs = false;
-
-       return 0;
-}
-
-static int osiris_dvs_resume(struct device *dev)
-{
-       osiris_dvs_tps_setdvs(true);
-       return 0;
-}
-
-static const struct dev_pm_ops osiris_dvs_pm = {
-       .suspend        = osiris_dvs_suspend,
-       .resume         = osiris_dvs_resume,
-};
-
-static struct platform_driver osiris_dvs_driver = {
-       .probe          = osiris_dvs_probe,
-       .remove         = __devexit_p(osiris_dvs_remove),
-       .driver         = {
-               .name   = "osiris-dvs",
-               .owner  = THIS_MODULE,
-               .pm     = &osiris_dvs_pm,
-       },
-};
-
-static int __init osiris_dvs_init(void)
-{
-       return platform_driver_register(&osiris_dvs_driver);
-}
-
-static void __exit osiris_dvs_exit(void)
-{
-       platform_driver_unregister(&osiris_dvs_driver);
-}
-
-module_init(osiris_dvs_init);
-module_exit(osiris_dvs_exit);
-
-MODULE_DESCRIPTION("Simtec OSIRIS DVS support");
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:osiris-dvs");
diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
deleted file mode 100644 (file)
index c5daeb6..0000000
+++ /dev/null
@@ -1,440 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-osiris.c
- *
- * Copyright (c) 2005-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/serial_core.h>
-#include <linux/clk.h>
-#include <linux/i2c.h>
-#include <linux/io.h>
-
-#include <linux/i2c/tps65010.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/osiris-map.h>
-#include <mach/osiris-cpld.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/cpu-freq.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <plat/nand.h>
-#include <plat/iic.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <plat/gpio-cfg.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-
-#include "common.h"
-
-/* onboard perihperal map */
-
-static struct map_desc osiris_iodesc[] __initdata = {
-  /* ISA IO areas (may be over-written later) */
-
-  {
-         .virtual      = (u32)S3C24XX_VA_ISA_BYTE,
-         .pfn          = __phys_to_pfn(S3C2410_CS5),
-         .length       = SZ_16M,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)S3C24XX_VA_ISA_WORD,
-         .pfn          = __phys_to_pfn(S3C2410_CS5),
-         .length       = SZ_16M,
-         .type         = MT_DEVICE,
-  },
-
-  /* CPLD control registers */
-
-  {
-         .virtual      = (u32)OSIRIS_VA_CTRL0,
-         .pfn          = __phys_to_pfn(OSIRIS_PA_CTRL0),
-         .length       = SZ_16K,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)OSIRIS_VA_CTRL1,
-         .pfn          = __phys_to_pfn(OSIRIS_PA_CTRL1),
-         .length       = SZ_16K,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)OSIRIS_VA_CTRL2,
-         .pfn          = __phys_to_pfn(OSIRIS_PA_CTRL2),
-         .length       = SZ_16K,
-         .type         = MT_DEVICE,
-  }, {
-         .virtual      = (u32)OSIRIS_VA_IDREG,
-         .pfn          = __phys_to_pfn(OSIRIS_PA_IDREG),
-         .length       = SZ_16K,
-         .type         = MT_DEVICE,
-  },
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg osiris_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
-       },
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = UCON,
-               .ulcon       = ULCON,
-               .ufcon       = UFCON,
-               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
-       }
-};
-
-/* NAND Flash on Osiris board */
-
-static int external_map[]   = { 2 };
-static int chip0_map[]      = { 0 };
-static int chip1_map[]      = { 1 };
-
-static struct mtd_partition __initdata osiris_default_nand_part[] = {
-       [0] = {
-               .name   = "Boot Agent",
-               .size   = SZ_16K,
-               .offset = 0,
-       },
-       [1] = {
-               .name   = "/boot",
-               .size   = SZ_4M - SZ_16K,
-               .offset = SZ_16K,
-       },
-       [2] = {
-               .name   = "user1",
-               .offset = SZ_4M,
-               .size   = SZ_32M - SZ_4M,
-       },
-       [3] = {
-               .name   = "user2",
-               .offset = SZ_32M,
-               .size   = MTDPART_SIZ_FULL,
-       }
-};
-
-static struct mtd_partition __initdata osiris_default_nand_part_large[] = {
-       [0] = {
-               .name   = "Boot Agent",
-               .size   = SZ_128K,
-               .offset = 0,
-       },
-       [1] = {
-               .name   = "/boot",
-               .size   = SZ_4M - SZ_128K,
-               .offset = SZ_128K,
-       },
-       [2] = {
-               .name   = "user1",
-               .offset = SZ_4M,
-               .size   = SZ_32M - SZ_4M,
-       },
-       [3] = {
-               .name   = "user2",
-               .offset = SZ_32M,
-               .size   = MTDPART_SIZ_FULL,
-       }
-};
-
-/* the Osiris has 3 selectable slots for nand-flash, the two
- * on-board chip areas, as well as the external slot.
- *
- * Note, there is no current hot-plug support for the External
- * socket.
-*/
-
-static struct s3c2410_nand_set __initdata osiris_nand_sets[] = {
-       [1] = {
-               .name           = "External",
-               .nr_chips       = 1,
-               .nr_map         = external_map,
-               .options        = NAND_SCAN_SILENT_NODEV,
-               .nr_partitions  = ARRAY_SIZE(osiris_default_nand_part),
-               .partitions     = osiris_default_nand_part,
-       },
-       [0] = {
-               .name           = "chip0",
-               .nr_chips       = 1,
-               .nr_map         = chip0_map,
-               .nr_partitions  = ARRAY_SIZE(osiris_default_nand_part),
-               .partitions     = osiris_default_nand_part,
-       },
-       [2] = {
-               .name           = "chip1",
-               .nr_chips       = 1,
-               .nr_map         = chip1_map,
-               .options        = NAND_SCAN_SILENT_NODEV,
-               .nr_partitions  = ARRAY_SIZE(osiris_default_nand_part),
-               .partitions     = osiris_default_nand_part,
-       },
-};
-
-static void osiris_nand_select(struct s3c2410_nand_set *set, int slot)
-{
-       unsigned int tmp;
-
-       slot = set->nr_map[slot] & 3;
-
-       pr_debug("osiris_nand: selecting slot %d (set %p,%p)\n",
-                slot, set, set->nr_map);
-
-       tmp = __raw_readb(OSIRIS_VA_CTRL0);
-       tmp &= ~OSIRIS_CTRL0_NANDSEL;
-       tmp |= slot;
-
-       pr_debug("osiris_nand: ctrl0 now %02x\n", tmp);
-
-       __raw_writeb(tmp, OSIRIS_VA_CTRL0);
-}
-
-static struct s3c2410_platform_nand __initdata osiris_nand_info = {
-       .tacls          = 25,
-       .twrph0         = 60,
-       .twrph1         = 60,
-       .nr_sets        = ARRAY_SIZE(osiris_nand_sets),
-       .sets           = osiris_nand_sets,
-       .select_chip    = osiris_nand_select,
-};
-
-/* PCMCIA control and configuration */
-
-static struct resource osiris_pcmcia_resource[] = {
-       [0] = {
-               .start  = 0x0f000000,
-               .end    = 0x0f100000,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = 0x0c000000,
-               .end    = 0x0c100000,
-               .flags  = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device osiris_pcmcia = {
-       .name           = "osiris-pcmcia",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(osiris_pcmcia_resource),
-       .resource       = osiris_pcmcia_resource,
-};
-
-/* Osiris power management device */
-
-#ifdef CONFIG_PM
-static unsigned char pm_osiris_ctrl0;
-
-static int osiris_pm_suspend(void)
-{
-       unsigned int tmp;
-
-       pm_osiris_ctrl0 = __raw_readb(OSIRIS_VA_CTRL0);
-       tmp = pm_osiris_ctrl0 & ~OSIRIS_CTRL0_NANDSEL;
-
-       /* ensure correct NAND slot is selected on resume */
-       if ((pm_osiris_ctrl0 & OSIRIS_CTRL0_BOOT_INT) == 0)
-               tmp |= 2;
-
-       __raw_writeb(tmp, OSIRIS_VA_CTRL0);
-
-       /* ensure that an nRESET is not generated on resume. */
-       s3c2410_gpio_setpin(S3C2410_GPA(21), 1);
-       s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPIO_OUTPUT);
-
-       return 0;
-}
-
-static void osiris_pm_resume(void)
-{
-       if (pm_osiris_ctrl0 & OSIRIS_CTRL0_FIX8)
-               __raw_writeb(OSIRIS_CTRL1_FIX8, OSIRIS_VA_CTRL1);
-
-       __raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0);
-
-       s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
-}
-
-#else
-#define osiris_pm_suspend NULL
-#define osiris_pm_resume NULL
-#endif
-
-static struct syscore_ops osiris_pm_syscore_ops = {
-       .suspend        = osiris_pm_suspend,
-       .resume         = osiris_pm_resume,
-};
-
-/* Link for DVS driver to TPS65011 */
-
-static void osiris_tps_release(struct device *dev)
-{
-       /* static device, do not need to release anything */
-}
-
-static struct platform_device osiris_tps_device = {
-       .name   = "osiris-dvs",
-       .id     = -1,
-       .dev.release = osiris_tps_release,
-};
-
-static int osiris_tps_setup(struct i2c_client *client, void *context)
-{
-       osiris_tps_device.dev.parent = &client->dev;
-       return platform_device_register(&osiris_tps_device);
-}
-
-static int osiris_tps_remove(struct i2c_client *client, void *context)
-{
-       platform_device_unregister(&osiris_tps_device);
-       return 0;
-}
-
-static struct tps65010_board osiris_tps_board = {
-       .base           = -1,   /* GPIO can go anywhere at the moment */
-       .setup          = osiris_tps_setup,
-       .teardown       = osiris_tps_remove,
-};
-
-/* I2C devices fitted. */
-
-static struct i2c_board_info osiris_i2c_devs[] __initdata = {
-       {
-               I2C_BOARD_INFO("tps65011", 0x48),
-               .irq    = IRQ_EINT20,
-               .platform_data = &osiris_tps_board,
-       },
-};
-
-/* Standard Osiris devices */
-
-static struct platform_device *osiris_devices[] __initdata = {
-       &s3c_device_i2c0,
-       &s3c_device_wdt,
-       &s3c_device_nand,
-       &osiris_pcmcia,
-};
-
-static struct clk *osiris_clocks[] __initdata = {
-       &s3c24xx_dclk0,
-       &s3c24xx_dclk1,
-       &s3c24xx_clkout0,
-       &s3c24xx_clkout1,
-       &s3c24xx_uclk,
-};
-
-static struct s3c_cpufreq_board __initdata osiris_cpufreq = {
-       .refresh        = 7800, /* refresh period is 7.8usec */
-       .auto_io        = 1,
-       .need_io        = 1,
-};
-
-static void __init osiris_map_io(void)
-{
-       unsigned long flags;
-
-       /* initialise the clocks */
-
-       s3c24xx_dclk0.parent = &clk_upll;
-       s3c24xx_dclk0.rate   = 12*1000*1000;
-
-       s3c24xx_dclk1.parent = &clk_upll;
-       s3c24xx_dclk1.rate   = 24*1000*1000;
-
-       s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
-       s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
-
-       s3c24xx_uclk.parent  = &s3c24xx_clkout1;
-
-       s3c24xx_register_clocks(osiris_clocks, ARRAY_SIZE(osiris_clocks));
-
-       s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc));
-       s3c24xx_init_clocks(0);
-       s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs));
-
-       /* check for the newer revision boards with large page nand */
-
-       if ((__raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK) >= 4) {
-               printk(KERN_INFO "OSIRIS-B detected (revision %d)\n",
-                      __raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK);
-               osiris_nand_sets[0].partitions = osiris_default_nand_part_large;
-               osiris_nand_sets[0].nr_partitions = ARRAY_SIZE(osiris_default_nand_part_large);
-       } else {
-               /* write-protect line to the NAND */
-               s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
-       }
-
-       /* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */
-
-       local_irq_save(flags);
-       __raw_writel(__raw_readl(S3C2410_BWSCON) | S3C2410_BWSCON_ST1 | S3C2410_BWSCON_ST2 | S3C2410_BWSCON_ST3 | S3C2410_BWSCON_ST4 | S3C2410_BWSCON_ST5, S3C2410_BWSCON);
-       local_irq_restore(flags);
-}
-
-static void __init osiris_init(void)
-{
-       register_syscore_ops(&osiris_pm_syscore_ops);
-
-       s3c_i2c0_set_platdata(NULL);
-       s3c_nand_set_platdata(&osiris_nand_info);
-
-       s3c_cpufreq_setboard(&osiris_cpufreq);
-
-       i2c_register_board_info(0, osiris_i2c_devs,
-                               ARRAY_SIZE(osiris_i2c_devs));
-
-       platform_add_devices(osiris_devices, ARRAY_SIZE(osiris_devices));
-};
-
-MACHINE_START(OSIRIS, "Simtec-OSIRIS")
-       /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .atag_offset    = 0x100,
-       .map_io         = osiris_map_io,
-       .init_irq       = s3c24xx_init_irq,
-       .init_machine   = osiris_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-rx1950.c b/arch/arm/mach-s3c2440/mach-rx1950.c
deleted file mode 100644 (file)
index 6f68abf..0000000
+++ /dev/null
@@ -1,826 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-rx1950.c
- *
- * Copyright (c) 2006-2009 Victor Chukhantsev, Denis Grigoriev,
- * Copyright (c) 2007-2010 Vasily Khoruzhick
- *
- * based on smdk2440 written by Ben Dooks
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/memblock.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
-#include <linux/device.h>
-#include <linux/pda_power.h>
-#include <linux/pwm_backlight.h>
-#include <linux/pwm.h>
-#include <linux/s3c_adc_battery.h>
-#include <linux/leds.h>
-#include <linux/i2c.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-
-#include <linux/mmc/host.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach-types.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
-#include <mach/regs-lcd.h>
-#include <mach/h1940.h>
-#include <mach/fb.h>
-
-#include <plat/clock.h>
-#include <plat/regs-serial.h>
-#include <plat/regs-iic.h>
-#include <plat/mci.h>
-#include <plat/udc.h>
-#include <plat/nand.h>
-#include <plat/iic.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-#include <plat/ts.h>
-
-#include <sound/uda1380.h>
-
-#include "common.h"
-
-#define LCD_PWM_PERIOD 192960
-#define LCD_PWM_DUTY 127353
-
-static struct map_desc rx1950_iodesc[] __initdata = {
-};
-
-static struct s3c2410_uartcfg rx1950_uartcfgs[] __initdata = {
-       [0] = {
-              .hwport = 0,
-              .flags = 0,
-              .ucon = 0x3c5,
-              .ulcon = 0x03,
-              .ufcon = 0x51,
-               .clk_sel = S3C2410_UCON_CLKSEL3,
-       },
-       [1] = {
-              .hwport = 1,
-              .flags = 0,
-              .ucon = 0x3c5,
-              .ulcon = 0x03,
-              .ufcon = 0x51,
-               .clk_sel = S3C2410_UCON_CLKSEL3,
-       },
-       /* IR port */
-       [2] = {
-              .hwport = 2,
-              .flags = 0,
-              .ucon = 0x3c5,
-              .ulcon = 0x43,
-              .ufcon = 0xf1,
-               .clk_sel = S3C2410_UCON_CLKSEL3,
-       },
-};
-
-static struct s3c2410fb_display rx1950_display = {
-       .type = S3C2410_LCDCON1_TFT,
-       .width = 240,
-       .height = 320,
-       .xres = 240,
-       .yres = 320,
-       .bpp = 16,
-
-       .pixclock = 260000,
-       .left_margin = 10,
-       .right_margin = 20,
-       .hsync_len = 10,
-       .upper_margin = 2,
-       .lower_margin = 2,
-       .vsync_len = 2,
-
-       .lcdcon5 = S3C2410_LCDCON5_FRM565 |
-                          S3C2410_LCDCON5_INVVCLK |
-                          S3C2410_LCDCON5_INVVLINE |
-                          S3C2410_LCDCON5_INVVFRAME |
-                          S3C2410_LCDCON5_HWSWP |
-                          (0x02 << 13) |
-                          (0x02 << 15),
-
-};
-
-static int power_supply_init(struct device *dev)
-{
-       return gpio_request(S3C2410_GPF(2), "cable plugged");
-}
-
-static int rx1950_is_ac_online(void)
-{
-       return !gpio_get_value(S3C2410_GPF(2));
-}
-
-static void power_supply_exit(struct device *dev)
-{
-       gpio_free(S3C2410_GPF(2));
-}
-
-static char *rx1950_supplicants[] = {
-       "main-battery"
-};
-
-static struct pda_power_pdata power_supply_info = {
-       .init                   = power_supply_init,
-       .is_ac_online           = rx1950_is_ac_online,
-       .exit                   = power_supply_exit,
-       .supplied_to            = rx1950_supplicants,
-       .num_supplicants        = ARRAY_SIZE(rx1950_supplicants),
-};
-
-static struct resource power_supply_resources[] = {
-       [0] = {
-                       .name   = "ac",
-                       .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
-                                         IORESOURCE_IRQ_HIGHEDGE,
-                       .start  = IRQ_EINT2,
-                       .end    = IRQ_EINT2,
-       },
-};
-
-static struct platform_device power_supply = {
-       .name                   = "pda-power",
-       .id                     = -1,
-       .dev                    = {
-                                       .platform_data =
-                                               &power_supply_info,
-       },
-       .resource               = power_supply_resources,
-       .num_resources          = ARRAY_SIZE(power_supply_resources),
-};
-
-static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
-       { .volt = 4100, .cur = 156, .level = 100},
-       { .volt = 4050, .cur = 156, .level = 95},
-       { .volt = 4025, .cur = 141, .level = 90},
-       { .volt = 3995, .cur = 144, .level = 85},
-       { .volt = 3957, .cur = 162, .level = 80},
-       { .volt = 3931, .cur = 147, .level = 75},
-       { .volt = 3902, .cur = 147, .level = 70},
-       { .volt = 3863, .cur = 153, .level = 65},
-       { .volt = 3838, .cur = 150, .level = 60},
-       { .volt = 3800, .cur = 153, .level = 55},
-       { .volt = 3765, .cur = 153, .level = 50},
-       { .volt = 3748, .cur = 172, .level = 45},
-       { .volt = 3740, .cur = 153, .level = 40},
-       { .volt = 3714, .cur = 175, .level = 35},
-       { .volt = 3710, .cur = 156, .level = 30},
-       { .volt = 3963, .cur = 156, .level = 25},
-       { .volt = 3672, .cur = 178, .level = 20},
-       { .volt = 3651, .cur = 178, .level = 15},
-       { .volt = 3629, .cur = 178, .level = 10},
-       { .volt = 3612, .cur = 162, .level = 5},
-       { .volt = 3605, .cur = 162, .level = 0},
-};
-
-static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
-       { .volt = 4200, .cur = 0, .level = 100},
-       { .volt = 4190, .cur = 0, .level = 99},
-       { .volt = 4178, .cur = 0, .level = 95},
-       { .volt = 4110, .cur = 0, .level = 70},
-       { .volt = 4076, .cur = 0, .level = 65},
-       { .volt = 4046, .cur = 0, .level = 60},
-       { .volt = 4021, .cur = 0, .level = 55},
-       { .volt = 3999, .cur = 0, .level = 50},
-       { .volt = 3982, .cur = 0, .level = 45},
-       { .volt = 3965, .cur = 0, .level = 40},
-       { .volt = 3957, .cur = 0, .level = 35},
-       { .volt = 3948, .cur = 0, .level = 30},
-       { .volt = 3936, .cur = 0, .level = 25},
-       { .volt = 3927, .cur = 0, .level = 20},
-       { .volt = 3906, .cur = 0, .level = 15},
-       { .volt = 3880, .cur = 0, .level = 10},
-       { .volt = 3829, .cur = 0, .level = 5},
-       { .volt = 3820, .cur = 0, .level = 0},
-};
-
-int rx1950_bat_init(void)
-{
-       int ret;
-
-       ret = gpio_request(S3C2410_GPJ(2), "rx1950-charger-enable-1");
-       if (ret)
-               goto err_gpio1;
-       ret = gpio_request(S3C2410_GPJ(3), "rx1950-charger-enable-2");
-       if (ret)
-               goto err_gpio2;
-
-       return 0;
-
-err_gpio2:
-       gpio_free(S3C2410_GPJ(2));
-err_gpio1:
-       return ret;
-}
-
-void rx1950_bat_exit(void)
-{
-       gpio_free(S3C2410_GPJ(2));
-       gpio_free(S3C2410_GPJ(3));
-}
-
-void rx1950_enable_charger(void)
-{
-       gpio_direction_output(S3C2410_GPJ(2), 1);
-       gpio_direction_output(S3C2410_GPJ(3), 1);
-}
-
-void rx1950_disable_charger(void)
-{
-       gpio_direction_output(S3C2410_GPJ(2), 0);
-       gpio_direction_output(S3C2410_GPJ(3), 0);
-}
-
-DEFINE_SPINLOCK(rx1950_blink_spin);
-
-static int rx1950_led_blink_set(unsigned gpio, int state,
-       unsigned long *delay_on, unsigned long *delay_off)
-{
-       int blink_gpio, check_gpio;
-
-       switch (gpio) {
-       case S3C2410_GPA(6):
-               blink_gpio = S3C2410_GPA(4);
-               check_gpio = S3C2410_GPA(3);
-               break;
-       case S3C2410_GPA(7):
-               blink_gpio = S3C2410_GPA(3);
-               check_gpio = S3C2410_GPA(4);
-               break;
-       default:
-               return -EINVAL;
-               break;
-       }
-
-       if (delay_on && delay_off && !*delay_on && !*delay_off)
-               *delay_on = *delay_off = 500;
-
-       spin_lock(&rx1950_blink_spin);
-
-       switch (state) {
-       case GPIO_LED_NO_BLINK_LOW:
-       case GPIO_LED_NO_BLINK_HIGH:
-               if (!gpio_get_value(check_gpio))
-                       gpio_set_value(S3C2410_GPJ(6), 0);
-               gpio_set_value(blink_gpio, 0);
-               gpio_set_value(gpio, state);
-               break;
-       case GPIO_LED_BLINK:
-               gpio_set_value(gpio, 0);
-               gpio_set_value(S3C2410_GPJ(6), 1);
-               gpio_set_value(blink_gpio, 1);
-               break;
-       }
-
-       spin_unlock(&rx1950_blink_spin);
-
-       return 0;
-}
-
-static struct gpio_led rx1950_leds_desc[] = {
-       {
-               .name                   = "Green",
-               .default_trigger        = "main-battery-full",
-               .gpio                   = S3C2410_GPA(6),
-               .retain_state_suspended = 1,
-       },
-       {
-               .name                   = "Red",
-               .default_trigger
-                       = "main-battery-charging-blink-full-solid",
-               .gpio                   = S3C2410_GPA(7),
-               .retain_state_suspended = 1,
-       },
-       {
-               .name                   = "Blue",
-               .default_trigger        = "rx1950-acx-mem",
-               .gpio                   = S3C2410_GPA(11),
-               .retain_state_suspended = 1,
-       },
-};
-
-static struct gpio_led_platform_data rx1950_leds_pdata = {
-       .num_leds       = ARRAY_SIZE(rx1950_leds_desc),
-       .leds           = rx1950_leds_desc,
-       .gpio_blink_set = rx1950_led_blink_set,
-};
-
-static struct platform_device rx1950_leds = {
-       .name   = "leds-gpio",
-       .id             = -1,
-       .dev    = {
-                               .platform_data = &rx1950_leds_pdata,
-       },
-};
-
-static struct s3c_adc_bat_pdata rx1950_bat_cfg = {
-       .init = rx1950_bat_init,
-       .exit = rx1950_bat_exit,
-       .enable_charger = rx1950_enable_charger,
-       .disable_charger = rx1950_disable_charger,
-       .gpio_charge_finished = S3C2410_GPF(3),
-       .lut_noac = bat_lut_noac,
-       .lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
-       .lut_acin = bat_lut_acin,
-       .lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
-       .volt_channel = 0,
-       .current_channel = 1,
-       .volt_mult = 4235,
-       .current_mult = 2900,
-       .internal_impedance = 200,
-};
-
-static struct platform_device rx1950_battery = {
-       .name             = "s3c-adc-battery",
-       .id               = -1,
-       .dev = {
-               .parent = &s3c_device_adc.dev,
-               .platform_data = &rx1950_bat_cfg,
-       },
-};
-
-static struct s3c2410fb_mach_info rx1950_lcd_cfg = {
-       .displays = &rx1950_display,
-       .num_displays = 1,
-       .default_display = 0,
-
-       .lpcsel = 0x02,
-       .gpccon = 0xaa9556a9,
-       .gpccon_mask = 0xffc003fc,
-       .gpcup = 0x0000ffff,
-       .gpcup_mask = 0xffffffff,
-
-       .gpdcon = 0xaa90aaa1,
-       .gpdcon_mask = 0xffc0fff0,
-       .gpdup = 0x0000fcfd,
-       .gpdup_mask = 0xffffffff,
-
-};
-
-static struct pwm_device *lcd_pwm;
-
-void rx1950_lcd_power(int enable)
-{
-       int i;
-       static int enabled;
-       if (enabled == enable)
-               return;
-       if (!enable) {
-
-               /* GPC11-GPC15->OUTPUT */
-               for (i = 11; i < 16; i++)
-                       gpio_direction_output(S3C2410_GPC(i), 1);
-
-               /* Wait a bit here... */
-               mdelay(100);
-
-               /* GPD2-GPD7->OUTPUT */
-               /* GPD11-GPD15->OUTPUT */
-               /* GPD2-GPD7->1, GPD11-GPD15->1 */
-               for (i = 2; i < 8; i++)
-                       gpio_direction_output(S3C2410_GPD(i), 1);
-               for (i = 11; i < 16; i++)
-                       gpio_direction_output(S3C2410_GPD(i), 1);
-
-               /* Wait a bit here...*/
-               mdelay(100);
-
-               /* GPB0->OUTPUT, GPB0->0 */
-               gpio_direction_output(S3C2410_GPB(0), 0);
-
-               /* GPC1-GPC4->OUTPUT, GPC1-4->0 */
-               for (i = 1; i < 5; i++)
-                       gpio_direction_output(S3C2410_GPC(i), 0);
-
-               /* GPC15-GPC11->0 */
-               for (i = 11; i < 16; i++)
-                       gpio_direction_output(S3C2410_GPC(i), 0);
-
-               /* GPD15-GPD11->0, GPD2->GPD7->0 */
-               for (i = 11; i < 16; i++)
-                       gpio_direction_output(S3C2410_GPD(i), 0);
-
-               for (i = 2; i < 8; i++)
-                       gpio_direction_output(S3C2410_GPD(i), 0);
-
-               /* GPC6->0, GPC7->0, GPC5->0 */
-               gpio_direction_output(S3C2410_GPC(6), 0);
-               gpio_direction_output(S3C2410_GPC(7), 0);
-               gpio_direction_output(S3C2410_GPC(5), 0);
-
-               /* GPB1->OUTPUT, GPB1->0 */
-               gpio_direction_output(S3C2410_GPB(1), 0);
-               pwm_config(lcd_pwm, 0, LCD_PWM_PERIOD);
-               pwm_disable(lcd_pwm);
-
-               /* GPC0->0, GPC10->0 */
-               gpio_direction_output(S3C2410_GPC(0), 0);
-               gpio_direction_output(S3C2410_GPC(10), 0);
-       } else {
-               pwm_config(lcd_pwm, LCD_PWM_DUTY, LCD_PWM_PERIOD);
-               pwm_enable(lcd_pwm);
-
-               gpio_direction_output(S3C2410_GPC(0), 1);
-               gpio_direction_output(S3C2410_GPC(5), 1);
-
-               s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPB1_TOUT1);
-               gpio_direction_output(S3C2410_GPC(7), 1);
-
-               for (i = 1; i < 5; i++)
-                       s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2));
-
-               for (i = 11; i < 16; i++)
-                       s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2));
-
-               for (i = 2; i < 8; i++)
-                       s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2));
-
-               for (i = 11; i < 16; i++)
-                       s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2));
-
-               gpio_direction_output(S3C2410_GPC(10), 1);
-               gpio_direction_output(S3C2410_GPC(6), 1);
-       }
-       enabled = enable;
-}
-
-static void rx1950_bl_power(int enable)
-{
-       static int enabled;
-       if (enabled == enable)
-               return;
-       if (!enable) {
-                       gpio_direction_output(S3C2410_GPB(0), 0);
-       } else {
-                       /* LED driver need a "push" to power on */
-                       gpio_direction_output(S3C2410_GPB(0), 1);
-                       /* Warm up backlight for one period of PWM.
-                        * Without this trick its almost impossible to
-                        * enable backlight with low brightness value
-                        */
-                       ndelay(48000);
-                       s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
-       }
-       enabled = enable;
-}
-
-static int rx1950_backlight_init(struct device *dev)
-{
-       WARN_ON(gpio_request(S3C2410_GPB(0), "Backlight"));
-       lcd_pwm = pwm_request(1, "RX1950 LCD");
-       if (IS_ERR(lcd_pwm)) {
-               dev_err(dev, "Unable to request PWM for LCD power!\n");
-               return PTR_ERR(lcd_pwm);
-       }
-
-       rx1950_lcd_power(1);
-       rx1950_bl_power(1);
-
-       return 0;
-}
-
-static void rx1950_backlight_exit(struct device *dev)
-{
-       rx1950_bl_power(0);
-       rx1950_lcd_power(0);
-
-       pwm_free(lcd_pwm);
-       gpio_free(S3C2410_GPB(0));
-}
-
-
-static int rx1950_backlight_notify(struct device *dev, int brightness)
-{
-       if (!brightness) {
-               rx1950_bl_power(0);
-               rx1950_lcd_power(0);
-       } else {
-               rx1950_lcd_power(1);
-               rx1950_bl_power(1);
-       }
-       return brightness;
-}
-
-static struct platform_pwm_backlight_data rx1950_backlight_data = {
-       .pwm_id = 0,
-       .max_brightness = 24,
-       .dft_brightness = 4,
-       .pwm_period_ns = 48000,
-       .init = rx1950_backlight_init,
-       .notify = rx1950_backlight_notify,
-       .exit = rx1950_backlight_exit,
-};
-
-static struct platform_device rx1950_backlight = {
-       .name = "pwm-backlight",
-       .dev = {
-               .parent = &s3c_device_timer[0].dev,
-               .platform_data = &rx1950_backlight_data,
-       },
-};
-
-static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
-{
-       switch (power_mode) {
-       case MMC_POWER_OFF:
-               gpio_direction_output(S3C2410_GPJ(1), 0);
-               break;
-       case MMC_POWER_UP:
-       case MMC_POWER_ON:
-               gpio_direction_output(S3C2410_GPJ(1), 1);
-               break;
-       default:
-               break;
-       }
-}
-
-static struct s3c24xx_mci_pdata rx1950_mmc_cfg __initdata = {
-       .gpio_detect = S3C2410_GPF(5),
-       .gpio_wprotect = S3C2410_GPH(8),
-       .set_power = rx1950_set_mmc_power,
-       .ocr_avail = MMC_VDD_32_33,
-};
-
-static struct mtd_partition rx1950_nand_part[] = {
-       [0] = {
-                       .name = "Boot0",
-                       .offset = 0,
-                       .size = 0x4000,
-                       .mask_flags = MTD_WRITEABLE,
-       },
-       [1] = {
-                       .name = "Boot1",
-                       .offset = MTDPART_OFS_APPEND,
-                       .size = 0x40000,
-                       .mask_flags = MTD_WRITEABLE,
-       },
-       [2] = {
-                       .name = "Kernel",
-                       .offset = MTDPART_OFS_APPEND,
-                       .size = 0x300000,
-                       .mask_flags = 0,
-       },
-       [3] = {
-                       .name = "Filesystem",
-                       .offset = MTDPART_OFS_APPEND,
-                       .size = MTDPART_SIZ_FULL,
-                       .mask_flags = 0,
-       },
-};
-
-static struct s3c2410_nand_set rx1950_nand_sets[] = {
-       [0] = {
-                       .name = "Internal",
-                       .nr_chips = 1,
-                       .nr_partitions = ARRAY_SIZE(rx1950_nand_part),
-                       .partitions = rx1950_nand_part,
-       },
-};
-
-static struct s3c2410_platform_nand rx1950_nand_info = {
-       .tacls = 25,
-       .twrph0 = 50,
-       .twrph1 = 15,
-       .nr_sets = ARRAY_SIZE(rx1950_nand_sets),
-       .sets = rx1950_nand_sets,
-};
-
-static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
-       .vbus_pin = S3C2410_GPG(5),
-       .vbus_pin_inverted = 1,
-       .pullup_pin = S3C2410_GPJ(5),
-};
-
-static struct s3c2410_ts_mach_info rx1950_ts_cfg __initdata = {
-       .delay = 10000,
-       .presc = 49,
-       .oversampling_shift = 3,
-};
-
-static struct gpio_keys_button rx1950_gpio_keys_table[] = {
-       {
-               .code           = KEY_POWER,
-               .gpio           = S3C2410_GPF(0),
-               .active_low     = 1,
-               .desc           = "Power button",
-               .wakeup         = 1,
-       },
-       {
-               .code           = KEY_F5,
-               .gpio           = S3C2410_GPF(7),
-               .active_low     = 1,
-               .desc           = "Record button",
-       },
-       {
-               .code           = KEY_F1,
-               .gpio           = S3C2410_GPG(0),
-               .active_low     = 1,
-               .desc           = "Calendar button",
-       },
-       {
-               .code           = KEY_F2,
-               .gpio           = S3C2410_GPG(2),
-               .active_low     = 1,
-               .desc           = "Contacts button",
-       },
-       {
-               .code           = KEY_F3,
-               .gpio           = S3C2410_GPG(3),
-               .active_low     = 1,
-               .desc           = "Mail button",
-       },
-       {
-               .code           = KEY_F4,
-               .gpio           = S3C2410_GPG(7),
-               .active_low     = 1,
-               .desc           = "WLAN button",
-       },
-       {
-               .code           = KEY_LEFT,
-               .gpio           = S3C2410_GPG(10),
-               .active_low     = 1,
-               .desc           = "Left button",
-       },
-       {
-               .code           = KEY_RIGHT,
-               .gpio           = S3C2410_GPG(11),
-               .active_low     = 1,
-               .desc           = "Right button",
-       },
-       {
-               .code           = KEY_UP,
-               .gpio           = S3C2410_GPG(4),
-               .active_low     = 1,
-               .desc           = "Up button",
-       },
-       {
-               .code           = KEY_DOWN,
-               .gpio           = S3C2410_GPG(6),
-               .active_low     = 1,
-               .desc           = "Down button",
-       },
-       {
-               .code           = KEY_ENTER,
-               .gpio           = S3C2410_GPG(9),
-               .active_low     = 1,
-               .desc           = "Ok button"
-       },
-};
-
-static struct gpio_keys_platform_data rx1950_gpio_keys_data = {
-       .buttons = rx1950_gpio_keys_table,
-       .nbuttons = ARRAY_SIZE(rx1950_gpio_keys_table),
-};
-
-static struct platform_device rx1950_device_gpiokeys = {
-       .name = "gpio-keys",
-       .dev.platform_data = &rx1950_gpio_keys_data,
-};
-
-static struct uda1380_platform_data uda1380_info = {
-       .gpio_power     = S3C2410_GPJ(0),
-       .gpio_reset     = S3C2410_GPD(0),
-       .dac_clk        = UDA1380_DAC_CLK_SYSCLK,
-};
-
-static struct i2c_board_info rx1950_i2c_devices[] = {
-       {
-               I2C_BOARD_INFO("uda1380", 0x1a),
-               .platform_data = &uda1380_info,
-       },
-};
-
-static struct platform_device *rx1950_devices[] __initdata = {
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-       &samsung_asoc_dma,
-       &s3c_device_usbgadget,
-       &s3c_device_rtc,
-       &s3c_device_nand,
-       &s3c_device_sdi,
-       &s3c_device_adc,
-       &s3c_device_ts,
-       &s3c_device_timer[0],
-       &s3c_device_timer[1],
-       &rx1950_backlight,
-       &rx1950_device_gpiokeys,
-       &power_supply,
-       &rx1950_battery,
-       &rx1950_leds,
-};
-
-static struct clk *rx1950_clocks[] __initdata = {
-       &s3c24xx_clkout0,
-       &s3c24xx_clkout1,
-};
-
-static void __init rx1950_map_io(void)
-{
-       s3c24xx_clkout0.parent  = &clk_h;
-       s3c24xx_clkout1.parent  = &clk_f;
-
-       s3c24xx_register_clocks(rx1950_clocks, ARRAY_SIZE(rx1950_clocks));
-
-       s3c24xx_init_io(rx1950_iodesc, ARRAY_SIZE(rx1950_iodesc));
-       s3c24xx_init_clocks(16934000);
-       s3c24xx_init_uarts(rx1950_uartcfgs, ARRAY_SIZE(rx1950_uartcfgs));
-
-       /* setup PM */
-
-#ifdef CONFIG_PM_H1940
-       memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 8);
-#endif
-
-       s3c_pm_init();
-}
-
-static void __init rx1950_init_machine(void)
-{
-       int i;
-
-       s3c24xx_fb_set_platdata(&rx1950_lcd_cfg);
-       s3c24xx_udc_set_platdata(&rx1950_udc_cfg);
-       s3c24xx_ts_set_platdata(&rx1950_ts_cfg);
-       s3c24xx_mci_set_platdata(&rx1950_mmc_cfg);
-       s3c_i2c0_set_platdata(NULL);
-       s3c_nand_set_platdata(&rx1950_nand_info);
-
-       /* Turn off suspend on both USB ports, and switch the
-        * selectable USB port to USB device mode. */
-       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
-                                               S3C2410_MISCCR_USBSUSPND0 |
-                                               S3C2410_MISCCR_USBSUSPND1, 0x0);
-
-       /* mmc power is disabled by default */
-       WARN_ON(gpio_request(S3C2410_GPJ(1), "MMC power"));
-       gpio_direction_output(S3C2410_GPJ(1), 0);
-
-       for (i = 0; i < 8; i++)
-               WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power"));
-
-       for (i = 10; i < 16; i++)
-               WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power"));
-
-       for (i = 2; i < 8; i++)
-               WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power"));
-
-       for (i = 11; i < 16; i++)
-               WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power"));
-
-       WARN_ON(gpio_request(S3C2410_GPB(1), "LCD power"));
-
-       WARN_ON(gpio_request(S3C2410_GPA(3), "Red blink"));
-       WARN_ON(gpio_request(S3C2410_GPA(4), "Green blink"));
-       WARN_ON(gpio_request(S3C2410_GPJ(6), "LED blink"));
-       gpio_direction_output(S3C2410_GPA(3), 0);
-       gpio_direction_output(S3C2410_GPA(4), 0);
-       gpio_direction_output(S3C2410_GPJ(6), 0);
-
-       platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices));
-
-       i2c_register_board_info(0, rx1950_i2c_devices,
-               ARRAY_SIZE(rx1950_i2c_devices));
-}
-
-/* H1940 and RX3715 need to reserve this for suspend */
-static void __init rx1950_reserve(void)
-{
-       memblock_reserve(0x30003000, 0x1000);
-       memblock_reserve(0x30081000, 0x1000);
-}
-
-MACHINE_START(RX1950, "HP iPAQ RX1950")
-    /* Maintainers: Vasily Khoruzhick */
-       .atag_offset = 0x100,
-       .map_io = rx1950_map_io,
-       .reserve        = rx1950_reserve,
-       .init_irq = s3c24xx_init_irq,
-       .init_machine = rx1950_init_machine,
-       .timer = &s3c24xx_timer,
-       .restart        = s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c
deleted file mode 100644 (file)
index 56af354..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-rx3715.c
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.handhelds.org/projects/rx3715.html
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/memblock.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-lcd.h>
-
-#include <mach/h1940.h>
-#include <plat/nand.h>
-#include <mach/fb.h>
-
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pm.h>
-
-#include "common.h"
-
-static struct map_desc rx3715_iodesc[] __initdata = {
-       /* dump ISA space somewhere unused */
-
-       {
-               .virtual        = (u32)S3C24XX_VA_ISA_WORD,
-               .pfn            = __phys_to_pfn(S3C2410_CS3),
-               .length         = SZ_1M,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (u32)S3C24XX_VA_ISA_BYTE,
-               .pfn            = __phys_to_pfn(S3C2410_CS3),
-               .length         = SZ_1M,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct s3c2410_uartcfg rx3715_uartcfgs[] = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-               .clk_sel        = S3C2410_UCON_CLKSEL3,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x00,
-               .clk_sel        = S3C2410_UCON_CLKSEL3,
-       },
-       /* IR port */
-       [2] = {
-               .hwport      = 2,
-               .uart_flags  = UPF_CONS_FLOW,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x43,
-               .ufcon       = 0x51,
-               .clk_sel        = S3C2410_UCON_CLKSEL3,
-       }
-};
-
-/* framebuffer lcd controller information */
-
-static struct s3c2410fb_display rx3715_lcdcfg __initdata = {
-       .lcdcon5 =      S3C2410_LCDCON5_INVVLINE |
-                       S3C2410_LCDCON5_FRM565 |
-                       S3C2410_LCDCON5_HWSWP,
-
-       .type           = S3C2410_LCDCON1_TFT,
-       .width          = 240,
-       .height         = 320,
-
-       .pixclock       = 260000,
-       .xres           = 240,
-       .yres           = 320,
-       .bpp            = 16,
-       .left_margin    = 36,
-       .right_margin   = 36,
-       .hsync_len      = 8,
-       .upper_margin   = 6,
-       .lower_margin   = 7,
-       .vsync_len      = 3,
-};
-
-static struct s3c2410fb_mach_info rx3715_fb_info __initdata = {
-
-       .displays =     &rx3715_lcdcfg,
-       .num_displays = 1,
-       .default_display = 0,
-
-       .lpcsel =       0xf82,
-
-       .gpccon =       0xaa955699,
-       .gpccon_mask =  0xffc003cc,
-       .gpcup =        0x0000ffff,
-       .gpcup_mask =   0xffffffff,
-
-       .gpdcon =       0xaa95aaa1,
-       .gpdcon_mask =  0xffc0fff0,
-       .gpdup =        0x0000faff,
-       .gpdup_mask =   0xffffffff,
-};
-
-static struct mtd_partition __initdata rx3715_nand_part[] = {
-       [0] = {
-               .name           = "Whole Flash",
-               .offset         = 0,
-               .size           = MTDPART_SIZ_FULL,
-               .mask_flags     = MTD_WRITEABLE,
-       }
-};
-
-static struct s3c2410_nand_set __initdata rx3715_nand_sets[] = {
-       [0] = {
-               .name           = "Internal",
-               .nr_chips       = 1,
-               .nr_partitions  = ARRAY_SIZE(rx3715_nand_part),
-               .partitions     = rx3715_nand_part,
-       },
-};
-
-static struct s3c2410_platform_nand __initdata rx3715_nand_info = {
-       .tacls          = 25,
-       .twrph0         = 50,
-       .twrph1         = 15,
-       .nr_sets        = ARRAY_SIZE(rx3715_nand_sets),
-       .sets           = rx3715_nand_sets,
-};
-
-static struct platform_device *rx3715_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-       &s3c_device_nand,
-};
-
-static void __init rx3715_map_io(void)
-{
-       s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc));
-       s3c24xx_init_clocks(16934000);
-       s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs));
-}
-
-/* H1940 and RX3715 need to reserve this for suspend */
-static void __init rx3715_reserve(void)
-{
-       memblock_reserve(0x30003000, 0x1000);
-       memblock_reserve(0x30081000, 0x1000);
-}
-
-static void __init rx3715_init_irq(void)
-{
-       s3c24xx_init_irq();
-}
-
-static void __init rx3715_init_machine(void)
-{
-#ifdef CONFIG_PM_H1940
-       memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 1024);
-#endif
-       s3c_pm_init();
-
-       s3c_nand_set_platdata(&rx3715_nand_info);
-       s3c24xx_fb_set_platdata(&rx3715_fb_info);
-       platform_add_devices(rx3715_devices, ARRAY_SIZE(rx3715_devices));
-}
-
-MACHINE_START(RX3715, "IPAQ-RX3715")
-       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .atag_offset    = 0x100,
-       .map_io         = rx3715_map_io,
-       .reserve        = rx3715_reserve,
-       .init_irq       = rx3715_init_irq,
-       .init_machine   = rx3715_init_machine,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c
deleted file mode 100644 (file)
index 83a1036..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/mach-smdk2440.c
- *
- * Copyright (c) 2004-2005 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.fluff.org/ben/smdk2440/
- *
- * Thanks to Dimity Andric and TomTom for the loan of an SMDK2440.
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-lcd.h>
-
-#include <mach/idle.h>
-#include <mach/fb.h>
-#include <plat/iic.h>
-
-#include <plat/s3c2410.h>
-#include <plat/s3c244x.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-
-#include <plat/common-smdk.h>
-
-#include "common.h"
-
-static struct map_desc smdk2440_iodesc[] __initdata = {
-       /* ISA IO Space map (memory space selected by A24) */
-
-       {
-               .virtual        = (u32)S3C24XX_VA_ISA_WORD,
-               .pfn            = __phys_to_pfn(S3C2410_CS2),
-               .length         = 0x10000,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (u32)S3C24XX_VA_ISA_WORD + 0x10000,
-               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
-               .length         = SZ_4M,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (u32)S3C24XX_VA_ISA_BYTE,
-               .pfn            = __phys_to_pfn(S3C2410_CS2),
-               .length         = 0x10000,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
-               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
-               .length         = SZ_4M,
-               .type           = MT_DEVICE,
-       }
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg smdk2440_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-       /* IR port */
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x43,
-               .ufcon       = 0x51,
-       }
-};
-
-/* LCD driver info */
-
-static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {
-
-       .lcdcon5        = S3C2410_LCDCON5_FRM565 |
-                         S3C2410_LCDCON5_INVVLINE |
-                         S3C2410_LCDCON5_INVVFRAME |
-                         S3C2410_LCDCON5_PWREN |
-                         S3C2410_LCDCON5_HWSWP,
-
-       .type           = S3C2410_LCDCON1_TFT,
-
-       .width          = 240,
-       .height         = 320,
-
-       .pixclock       = 166667, /* HCLK 60 MHz, divisor 10 */
-       .xres           = 240,
-       .yres           = 320,
-       .bpp            = 16,
-       .left_margin    = 20,
-       .right_margin   = 8,
-       .hsync_len      = 4,
-       .upper_margin   = 8,
-       .lower_margin   = 7,
-       .vsync_len      = 4,
-};
-
-static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
-       .displays       = &smdk2440_lcd_cfg,
-       .num_displays   = 1,
-       .default_display = 0,
-
-#if 0
-       /* currently setup by downloader */
-       .gpccon         = 0xaa940659,
-       .gpccon_mask    = 0xffffffff,
-       .gpcup          = 0x0000ffff,
-       .gpcup_mask     = 0xffffffff,
-       .gpdcon         = 0xaa84aaa0,
-       .gpdcon_mask    = 0xffffffff,
-       .gpdup          = 0x0000faff,
-       .gpdup_mask     = 0xffffffff,
-#endif
-
-       .lpcsel         = ((0xCE6) & ~7) | 1<<4,
-};
-
-static struct platform_device *smdk2440_devices[] __initdata = {
-       &s3c_device_ohci,
-       &s3c_device_lcd,
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_iis,
-};
-
-static void __init smdk2440_map_io(void)
-{
-       s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
-       s3c24xx_init_clocks(16934400);
-       s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
-}
-
-static void __init smdk2440_machine_init(void)
-{
-       s3c24xx_fb_set_platdata(&smdk2440_fb_info);
-       s3c_i2c0_set_platdata(NULL);
-
-       platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
-       smdk_machine_init();
-}
-
-MACHINE_START(S3C2440, "SMDK2440")
-       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .atag_offset    = 0x100,
-
-       .init_irq       = s3c24xx_init_irq,
-       .map_io         = smdk2440_map_io,
-       .init_machine   = smdk2440_machine_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c244x_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
deleted file mode 100644 (file)
index 2b3dddb..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* linux/arch/arm/mach-s3c2440/s3c2440.c
- *
- * Copyright (c) 2004-2006 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C2440 Mobile CPU support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/s3c244x.h>
-#include <plat/pm.h>
-
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-
-static struct device s3c2440_dev = {
-       .bus            = &s3c2440_subsys,
-};
-
-int __init s3c2440_init(void)
-{
-       printk("S3C2440: Initialising architecture\n");
-
-       /* change irq for watchdog */
-
-       s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
-       s3c_device_wdt.resource[1].end   = IRQ_S3C2440_WDT;
-
-       /* register suspend/resume handlers */
-
-#ifdef CONFIG_PM
-       register_syscore_ops(&s3c2410_pm_syscore_ops);
-#endif
-       register_syscore_ops(&s3c244x_pm_syscore_ops);
-       register_syscore_ops(&s3c24xx_irq_syscore_ops);
-
-       /* register our system device for everything else */
-
-       return device_register(&s3c2440_dev);
-}
-
-void __init s3c2440_map_io(void)
-{
-       s3c244x_map_io();
-
-       s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up;
-       s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up;
-}
diff --git a/arch/arm/mach-s3c2440/s3c2442.c b/arch/arm/mach-s3c2440/s3c2442.c
deleted file mode 100644 (file)
index 22cb7c9..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/* linux/arch/arm/mach-s3c2442/s3c2442.c
- *
- * Copyright (c) 2004-2005 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2442 core and lock support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mutex.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <linux/atomic.h>
-#include <asm/irq.h>
-
-#include <mach/regs-clock.h>
-
-#include <plat/clock.h>
-#include <plat/cpu.h>
-#include <plat/s3c244x.h>
-#include <plat/pm.h>
-
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-
-/* S3C2442 extended clock support */
-
-static unsigned long s3c2442_camif_upll_round(struct clk *clk,
-                                             unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       int div;
-
-       if (rate > parent_rate)
-               return parent_rate;
-
-       div = parent_rate / rate;
-
-       if (div == 3)
-               return parent_rate / 3;
-
-       /* note, we remove the +/- 1 calculations for the divisor */
-
-       div /= 2;
-
-       if (div < 1)
-               div = 1;
-       else if (div > 16)
-               div = 16;
-
-       return parent_rate / (div * 2);
-}
-
-static int s3c2442_camif_upll_setrate(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long camdivn =  __raw_readl(S3C2440_CAMDIVN);
-
-       rate = s3c2442_camif_upll_round(clk, rate);
-
-       camdivn &= ~S3C2442_CAMDIVN_CAMCLK_DIV3;
-
-       if (rate == parent_rate) {
-               camdivn &= ~S3C2440_CAMDIVN_CAMCLK_SEL;
-       } else if ((parent_rate / rate) == 3) {
-               camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
-               camdivn |= S3C2442_CAMDIVN_CAMCLK_DIV3;
-       } else {
-               camdivn &= ~S3C2440_CAMDIVN_CAMCLK_MASK;
-               camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
-               camdivn |= (((parent_rate / rate) / 2) - 1);
-       }
-
-       __raw_writel(camdivn, S3C2440_CAMDIVN);
-
-       return 0;
-}
-
-/* Extra S3C2442 clocks */
-
-static struct clk s3c2442_clk_cam = {
-       .name           = "camif",
-       .id             = -1,
-       .enable         = s3c2410_clkcon_enable,
-       .ctrlbit        = S3C2440_CLKCON_CAMERA,
-};
-
-static struct clk s3c2442_clk_cam_upll = {
-       .name           = "camif-upll",
-       .id             = -1,
-       .ops            = &(struct clk_ops) {
-               .set_rate       = s3c2442_camif_upll_setrate,
-               .round_rate     = s3c2442_camif_upll_round,
-       },
-};
-
-static int s3c2442_clk_add(struct device *dev, struct subsys_interface *sif)
-{
-       struct clk *clock_upll;
-       struct clk *clock_h;
-       struct clk *clock_p;
-
-       clock_p = clk_get(NULL, "pclk");
-       clock_h = clk_get(NULL, "hclk");
-       clock_upll = clk_get(NULL, "upll");
-
-       if (IS_ERR(clock_p) || IS_ERR(clock_h) || IS_ERR(clock_upll)) {
-               printk(KERN_ERR "S3C2442: Failed to get parent clocks\n");
-               return -EINVAL;
-       }
-
-       s3c2442_clk_cam.parent = clock_h;
-       s3c2442_clk_cam_upll.parent = clock_upll;
-
-       s3c24xx_register_clock(&s3c2442_clk_cam);
-       s3c24xx_register_clock(&s3c2442_clk_cam_upll);
-
-       clk_disable(&s3c2442_clk_cam);
-
-       return 0;
-}
-
-static struct subsys_interface s3c2442_clk_interface = {
-       .name           = "s3c2442_clk",
-       .subsys         = &s3c2442_subsys,
-       .add_dev        = s3c2442_clk_add,
-};
-
-static __init int s3c2442_clk_init(void)
-{
-       return subsys_interface_register(&s3c2442_clk_interface);
-}
-
-arch_initcall(s3c2442_clk_init);
-
-
-static struct device s3c2442_dev = {
-       .bus            = &s3c2442_subsys,
-};
-
-int __init s3c2442_init(void)
-{
-       printk("S3C2442: Initialising architecture\n");
-
-#ifdef CONFIG_PM
-       register_syscore_ops(&s3c2410_pm_syscore_ops);
-#endif
-       register_syscore_ops(&s3c244x_pm_syscore_ops);
-       register_syscore_ops(&s3c24xx_irq_syscore_ops);
-
-       return device_register(&s3c2442_dev);
-}
-
-void __init s3c2442_map_io(void)
-{
-       s3c244x_map_io();
-
-       s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1down;
-       s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1down;
-}
diff --git a/arch/arm/mach-s3c2440/s3c244x-clock.c b/arch/arm/mach-s3c2440/s3c244x-clock.c
deleted file mode 100644 (file)
index 6d9b688..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/s3c24xx-clock.c
- *
- * Copyright (c) 2004-2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2440/S3C2442 Common clock support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <linux/atomic.h>
-#include <asm/irq.h>
-
-#include <mach/regs-clock.h>
-
-#include <plat/clock.h>
-#include <plat/cpu.h>
-
-static int s3c2440_setparent_armclk(struct clk *clk, struct clk *parent)
-{
-       unsigned long camdivn;
-       unsigned long dvs;
-
-       if (parent == &clk_f)
-               dvs = 0;
-       else if (parent == &clk_h)
-               dvs = S3C2440_CAMDIVN_DVSEN;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       camdivn  = __raw_readl(S3C2440_CAMDIVN);
-       camdivn &= ~S3C2440_CAMDIVN_DVSEN;
-       camdivn |= dvs;
-       __raw_writel(camdivn, S3C2440_CAMDIVN);
-
-       return 0;
-}
-
-static struct clk clk_arm = {
-       .name           = "armclk",
-       .id             = -1,
-       .ops            = &(struct clk_ops) {
-               .set_parent     = s3c2440_setparent_armclk,
-       },
-};
-
-static int s3c244x_clk_add(struct device *dev, struct subsys_interface *sif)
-{
-       unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
-       unsigned long clkdivn;
-       struct clk *clock_upll;
-       int ret;
-
-       printk("S3C244X: Clock Support, DVS %s\n",
-              (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
-
-       clk_arm.parent = (camdivn & S3C2440_CAMDIVN_DVSEN) ? &clk_h : &clk_f;
-
-       ret = s3c24xx_register_clock(&clk_arm);
-       if (ret < 0) {
-               printk(KERN_ERR "S3C24XX: Failed to add armclk (%d)\n", ret);
-               return ret;
-       }
-
-       clock_upll = clk_get(NULL, "upll");
-       if (IS_ERR(clock_upll)) {
-               printk(KERN_ERR "S3C244X: Failed to get upll clock\n");
-               return -ENOENT;
-       }
-
-       /* check rate of UPLL, and if it is near 96MHz, then change
-        * to using half the UPLL rate for the system */
-
-       if (clk_get_rate(clock_upll) > (94 * MHZ)) {
-               clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
-
-               spin_lock(&clocks_lock);
-
-               clkdivn = __raw_readl(S3C2410_CLKDIVN);
-               clkdivn |= S3C2440_CLKDIVN_UCLK;
-               __raw_writel(clkdivn, S3C2410_CLKDIVN);
-
-               spin_unlock(&clocks_lock);
-       }
-
-       return 0;
-}
-
-static struct subsys_interface s3c2440_clk_interface = {
-       .name           = "s3c2440_clk",
-       .subsys         = &s3c2440_subsys,
-       .add_dev        = s3c244x_clk_add,
-};
-
-static int s3c2440_clk_init(void)
-{
-       return subsys_interface_register(&s3c2440_clk_interface);
-}
-
-arch_initcall(s3c2440_clk_init);
-
-static struct subsys_interface s3c2442_clk_interface = {
-       .name           = "s3c2442_clk",
-       .subsys         = &s3c2442_subsys,
-       .add_dev        = s3c244x_clk_add,
-};
-
-static int s3c2442_clk_init(void)
-{
-       return subsys_interface_register(&s3c2442_clk_interface);
-}
-
-arch_initcall(s3c2442_clk_init);
diff --git a/arch/arm/mach-s3c2440/s3c244x-irq.c b/arch/arm/mach-s3c2440/s3c244x-irq.c
deleted file mode 100644 (file)
index 5fe8e58..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/s3c244x-irq.c
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-
-/* camera irq */
-
-static void s3c_irq_demux_cam(unsigned int irq,
-                             struct irq_desc *desc)
-{
-       unsigned int subsrc, submsk;
-
-       /* read the current pending interrupts, and the mask
-        * for what it is available */
-
-       subsrc = __raw_readl(S3C2410_SUBSRCPND);
-       submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-       subsrc &= ~submsk;
-       subsrc >>= 11;
-       subsrc &= 3;
-
-       if (subsrc != 0) {
-               if (subsrc & 1) {
-                       generic_handle_irq(IRQ_S3C2440_CAM_C);
-               }
-               if (subsrc & 2) {
-                       generic_handle_irq(IRQ_S3C2440_CAM_P);
-               }
-       }
-}
-
-#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
-
-static void
-s3c_irq_cam_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_CAM, 3 << 11);
-}
-
-static void
-s3c_irq_cam_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_CAM);
-}
-
-static void
-s3c_irq_cam_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_CAM, 3 << 11);
-}
-
-static struct irq_chip s3c_irq_cam = {
-       .irq_mask       = s3c_irq_cam_mask,
-       .irq_unmask     = s3c_irq_cam_unmask,
-       .irq_ack        = s3c_irq_cam_ack,
-};
-
-static int s3c244x_irq_add(struct device *dev, struct subsys_interface *sif)
-{
-       unsigned int irqno;
-
-       irq_set_chip_and_handler(IRQ_NFCON, &s3c_irq_level_chip,
-                                handle_level_irq);
-       set_irq_flags(IRQ_NFCON, IRQF_VALID);
-
-       /* add chained handler for camera */
-
-       irq_set_chip_and_handler(IRQ_CAM, &s3c_irq_level_chip,
-                                handle_level_irq);
-       irq_set_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
-
-       for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
-               irq_set_chip_and_handler(irqno, &s3c_irq_cam,
-                                        handle_level_irq);
-               set_irq_flags(irqno, IRQF_VALID);
-       }
-
-       return 0;
-}
-
-static struct subsys_interface s3c2440_irq_interface = {
-       .name           = "s3c2440_irq",
-       .subsys         = &s3c2440_subsys,
-       .add_dev        = s3c244x_irq_add,
-};
-
-static int s3c2440_irq_init(void)
-{
-       return subsys_interface_register(&s3c2440_irq_interface);
-}
-
-arch_initcall(s3c2440_irq_init);
-
-static struct subsys_interface s3c2442_irq_interface = {
-       .name           = "s3c2442_irq",
-       .subsys         = &s3c2442_subsys,
-       .add_dev        = s3c244x_irq_add,
-};
-
-
-static int s3c2442_irq_init(void)
-{
-       return subsys_interface_register(&s3c2442_irq_interface);
-}
-
-arch_initcall(s3c2442_irq_init);
diff --git a/arch/arm/mach-s3c2440/s3c244x.c b/arch/arm/mach-s3c2440/s3c244x.c
deleted file mode 100644 (file)
index 6f74118..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/s3c244x.c
- *
- * Copyright (c) 2004-2006 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C2440 and S3C2442 Mobile CPU support (not S3C2443)
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/system_misc.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <plat/cpu-freq.h>
-
-#include <mach/regs-clock.h>
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
-#include <mach/regs-dsc.h>
-
-#include <plat/s3c2410.h>
-#include <plat/s3c244x.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/pll.h>
-#include <plat/nand-core.h>
-#include <plat/watchdog-reset.h>
-
-static struct map_desc s3c244x_iodesc[] __initdata = {
-       IODESC_ENT(CLKPWR),
-       IODESC_ENT(TIMER),
-       IODESC_ENT(WATCHDOG),
-};
-
-/* uart initialisation */
-
-void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-       s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
-}
-
-void __init s3c244x_map_io(void)
-{
-       /* register our io-tables */
-
-       iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
-
-       /* rename any peripherals used differing from the s3c2410 */
-
-       s3c_device_sdi.name  = "s3c2440-sdi";
-       s3c_device_i2c0.name  = "s3c2440-i2c";
-       s3c_nand_setname("s3c2440-nand");
-       s3c_device_ts.name = "s3c2440-ts";
-       s3c_device_usbgadget.name = "s3c2440-usbgadget";
-}
-
-void __init_or_cpufreq s3c244x_setup_clocks(void)
-{
-       struct clk *xtal_clk;
-       unsigned long clkdiv;
-       unsigned long camdiv;
-       unsigned long xtal;
-       unsigned long hclk, fclk, pclk;
-       int hdiv = 1;
-
-       xtal_clk = clk_get(NULL, "xtal");
-       xtal = clk_get_rate(xtal_clk);
-       clk_put(xtal_clk);
-
-       fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
-
-       clkdiv = __raw_readl(S3C2410_CLKDIVN);
-       camdiv = __raw_readl(S3C2440_CAMDIVN);
-
-       /* work out clock scalings */
-
-       switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
-       case S3C2440_CLKDIVN_HDIVN_1:
-               hdiv = 1;
-               break;
-
-       case S3C2440_CLKDIVN_HDIVN_2:
-               hdiv = 2;
-               break;
-
-       case S3C2440_CLKDIVN_HDIVN_4_8:
-               hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
-               break;
-
-       case S3C2440_CLKDIVN_HDIVN_3_6:
-               hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
-               break;
-       }
-
-       hclk = fclk / hdiv;
-       pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
-
-       /* print brief summary of clocks, etc */
-
-       printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
-              print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
-
-       s3c24xx_setup_clocks(fclk, hclk, pclk);
-}
-
-void __init s3c244x_init_clocks(int xtal)
-{
-       /* initialise the clocks here, to allow other things like the
-        * console to use them, and to add new ones after the initialisation
-        */
-
-       s3c24xx_register_baseclocks(xtal);
-       s3c244x_setup_clocks();
-       s3c2410_baseclk_add();
-}
-
-/* Since the S3C2442 and S3C2440 share items, put both subsystems here */
-
-struct bus_type s3c2440_subsys = {
-       .name           = "s3c2440-core",
-       .dev_name       = "s3c2440-core",
-};
-
-struct bus_type s3c2442_subsys = {
-       .name           = "s3c2442-core",
-       .dev_name       = "s3c2442-core",
-};
-
-/* need to register the subsystem before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2440 based system)
- * as a driver which may support both 2410 and 2440 may try and use it.
-*/
-
-static int __init s3c2440_core_init(void)
-{
-       return subsys_system_register(&s3c2440_subsys, NULL);
-}
-
-core_initcall(s3c2440_core_init);
-
-static int __init s3c2442_core_init(void)
-{
-       return subsys_system_register(&s3c2442_subsys, NULL);
-}
-
-core_initcall(s3c2442_core_init);
-
-
-#ifdef CONFIG_PM
-static struct sleep_save s3c244x_sleep[] = {
-       SAVE_ITEM(S3C2440_DSC0),
-       SAVE_ITEM(S3C2440_DSC1),
-       SAVE_ITEM(S3C2440_GPJDAT),
-       SAVE_ITEM(S3C2440_GPJCON),
-       SAVE_ITEM(S3C2440_GPJUP)
-};
-
-static int s3c244x_suspend(void)
-{
-       s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
-       return 0;
-}
-
-static void s3c244x_resume(void)
-{
-       s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
-}
-#else
-#define s3c244x_suspend NULL
-#define s3c244x_resume  NULL
-#endif
-
-struct syscore_ops s3c244x_pm_syscore_ops = {
-       .suspend        = s3c244x_suspend,
-       .resume         = s3c244x_resume,
-};
-
-void s3c244x_restart(char mode, const char *cmd)
-{
-       if (mode == 's')
-               soft_restart(0);
-
-       arch_wdt_reset();
-
-       /* we'll take a jump through zero as a poor second */
-       soft_restart(0);
-}
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig
deleted file mode 100644 (file)
index 8814031..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-config CPU_S3C2443
-       bool
-       depends on ARCH_S3C2410
-       select CPU_ARM920T
-       select S3C2443_DMA if S3C2410_DMA
-       select CPU_LLSERIAL_S3C2440
-       select SAMSUNG_CLKSRC
-       select S3C2443_CLOCK
-       help
-         Support for the S3C2443 SoC from the S3C24XX line
-
-config S3C2443_DMA
-       bool
-       depends on CPU_S3C2443
-       help
-         Internal config node for S3C2443 DMA support
-
-menu "S3C2443 Machines"
-
-config MACH_SMDK2443
-       bool "SMDK2443"
-       select CPU_S3C2443
-       select MACH_SMDK
-       select S3C_DEV_HSMMC1
-       help
-         Say Y here if you are using an SMDK2443
-
-endmenu
diff --git a/arch/arm/mach-s3c2443/Makefile b/arch/arm/mach-s3c2443/Makefile
deleted file mode 100644 (file)
index d1843c9..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# arch/arm/mach-s3c2443/Makefile
-#
-# Copyright 2007 Simtec Electronics
-#
-# Licensed under GPLv2
-
-obj-y                          :=
-obj-m                          :=
-obj-n                          :=
-obj-                           :=
-
-obj-$(CONFIG_CPU_S3C2443)      += s3c2443.o
-obj-$(CONFIG_CPU_S3C2443)      += irq.o
-obj-$(CONFIG_CPU_S3C2443)      += clock.o
-
-obj-$(CONFIG_S3C2443_DMA)      += dma.o
-
-# Machine support
-
-obj-$(CONFIG_MACH_SMDK2443)    += mach-smdk2443.o
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
deleted file mode 100644 (file)
index 6dde269..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/clock.c
- *
- * Copyright (c) 2007, 2010 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2443 Clock control support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/init.h>
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
-
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/cpu-freq.h>
-
-#include <plat/s3c2443.h>
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-
-/* We currently have to assume that the system is running
- * from the XTPll input, and that all ***REFCLKs are being
- * fed from it, as we cannot read the state of OM[4] from
- * software.
- *
- * It would be possible for each board initialisation to
- * set the correct muxing at initialisation
-*/
-
-/* clock selections */
-
-/* armdiv
- *
- * this clock is sourced from msysclk and can have a number of
- * divider values applied to it to then be fed into armclk.
- * The real clock definition is done in s3c2443-clock.c,
- * only the armdiv divisor table must be defined here.
-*/
-
-static unsigned int armdiv[16] = {
-       [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 1,
-       [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 2,
-       [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 3,
-       [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 4,
-       [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 6,
-       [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 8,
-       [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 12,
-       [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 16,
-};
-
-/* hsspi
- *
- * high-speed spi clock, sourced from esysclk
-*/
-
-static struct clksrc_clk clk_hsspi = {
-       .clk    = {
-               .name           = "hsspi-if",
-               .parent         = &clk_esysclk.clk,
-               .ctrlbit        = S3C2443_SCLKCON_HSSPICLK,
-               .enable         = s3c2443_clkcon_enable_s,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
-};
-
-
-/* clk_hsmcc_div
- *
- * this clock is sourced from epll, and is fed through a divider,
- * to a mux controlled by sclkcon where either it or a extclk can
- * be fed to the hsmmc block
-*/
-
-static struct clksrc_clk clk_hsmmc_div = {
-       .clk    = {
-               .name           = "hsmmc-div",
-               .devname        = "s3c-sdhci.1",
-               .parent         = &clk_esysclk.clk,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
-};
-
-static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
-{
-       unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
-
-       clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
-                   S3C2443_SCLKCON_HSMMCCLK_EPLL);
-
-       if (parent == &clk_epll)
-               clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
-       else if (parent == &clk_ext)
-               clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
-       else
-               return -EINVAL;
-
-       if (clk->usage > 0) {
-               __raw_writel(clksrc, S3C2443_SCLKCON);
-       }
-
-       clk->parent = parent;
-       return 0;
-}
-
-static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
-{
-       return s3c2443_setparent_hsmmc(clk, clk->parent);
-}
-
-static struct clk clk_hsmmc = {
-       .name           = "hsmmc-if",
-       .devname        = "s3c-sdhci.1",
-       .parent         = &clk_hsmmc_div.clk,
-       .enable         = s3c2443_enable_hsmmc,
-       .ops            = &(struct clk_ops) {
-               .set_parent     = s3c2443_setparent_hsmmc,
-       },
-};
-
-/* standard clock definitions */
-
-static struct clk init_clocks_off[] = {
-       {
-               .name           = "sdi",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_SDI,
-       }, {
-               .name           = "spi",
-               .devname        = "s3c2410-spi.0",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_SPI0,
-       }, {
-               .name           = "spi",
-               .devname        = "s3c2410-spi.1",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_SPI1,
-       }
-};
-
-/* clocks to add straight away */
-
-static struct clksrc_clk *clksrcs[] __initdata = {
-       &clk_hsspi,
-       &clk_hsmmc_div,
-};
-
-static struct clk *clks[] __initdata = {
-       &clk_hsmmc,
-};
-
-void __init_or_cpufreq s3c2443_setup_clocks(void)
-{
-       s3c2443_common_setup_clocks(s3c2443_get_mpll);
-}
-
-void __init s3c2443_init_clocks(int xtal)
-{
-       unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
-       int ptr;
-
-       clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
-       clk_epll.parent = &clk_epllref.clk;
-
-       s3c2443_common_init_clocks(xtal, s3c2443_get_mpll,
-                                  armdiv, ARRAY_SIZE(armdiv),
-                                  S3C2443_CLKDIV0_ARMDIV_MASK);
-
-       s3c2443_setup_clocks();
-
-       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-               s3c_register_clksrc(clksrcs[ptr], 1);
-
-       /* We must be careful disabling the clocks we are not intending to
-        * be using at boot time, as subsystems such as the LCD which do
-        * their own DMA requests to the bus can cause the system to lockup
-        * if they where in the middle of requesting bus access.
-        *
-        * Disabling the LCD clock if the LCD is active is very dangerous,
-        * and therefore the bootloader should be careful to not enable
-        * the LCD clock if it is not needed.
-       */
-
-       /* install (and disable) the clocks we do not need immediately */
-
-       s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-       s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-
-       s3c_pwmclk_init();
-}
diff --git a/arch/arm/mach-s3c2443/dma.c b/arch/arm/mach-s3c2443/dma.c
deleted file mode 100644 (file)
index 1422451..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/dma.c
- *
- * Copyright (c) 2007 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2443 DMA selection
- *
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#include <mach/dma.h>
-
-#include <plat/dma-s3c24xx.h>
-#include <plat/cpu.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
-#include <plat/regs-dma.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-lcd.h>
-#include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
-#include <plat/regs-spi.h>
-
-#define MAP(x) { \
-               [0]     = (x) | DMA_CH_VALID,   \
-               [1]     = (x) | DMA_CH_VALID,   \
-               [2]     = (x) | DMA_CH_VALID,   \
-               [3]     = (x) | DMA_CH_VALID,   \
-               [4]     = (x) | DMA_CH_VALID,   \
-               [5]     = (x) | DMA_CH_VALID,   \
-       }
-
-static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = {
-       [DMACH_XD0] = {
-               .name           = "xdreq0",
-               .channels       = MAP(S3C2443_DMAREQSEL_XDREQ0),
-       },
-       [DMACH_XD1] = {
-               .name           = "xdreq1",
-               .channels       = MAP(S3C2443_DMAREQSEL_XDREQ1),
-       },
-       [DMACH_SDI] = {
-               .name           = "sdi",
-               .channels       = MAP(S3C2443_DMAREQSEL_SDI),
-       },
-       [DMACH_SPI0] = {
-               .name           = "spi0",
-               .channels       = MAP(S3C2443_DMAREQSEL_SPI0TX),
-       },
-       [DMACH_SPI1] = {
-               .name           = "spi1",
-               .channels       = MAP(S3C2443_DMAREQSEL_SPI1TX),
-       },
-       [DMACH_UART0] = {
-               .name           = "uart0",
-               .channels       = MAP(S3C2443_DMAREQSEL_UART0_0),
-       },
-       [DMACH_UART1] = {
-               .name           = "uart1",
-               .channels       = MAP(S3C2443_DMAREQSEL_UART1_0),
-       },
-       [DMACH_UART2] = {
-               .name           = "uart2",
-               .channels       = MAP(S3C2443_DMAREQSEL_UART2_0),
-       },
-       [DMACH_UART3] = {
-               .name           = "uart3",
-               .channels       = MAP(S3C2443_DMAREQSEL_UART3_0),
-       },
-       [DMACH_UART0_SRC2] = {
-               .name           = "uart0",
-               .channels       = MAP(S3C2443_DMAREQSEL_UART0_1),
-       },
-       [DMACH_UART1_SRC2] = {
-               .name           = "uart1",
-               .channels       = MAP(S3C2443_DMAREQSEL_UART1_1),
-       },
-       [DMACH_UART2_SRC2] = {
-               .name           = "uart2",
-               .channels       = MAP(S3C2443_DMAREQSEL_UART2_1),
-       },
-       [DMACH_UART3_SRC2] = {
-               .name           = "uart3",
-               .channels       = MAP(S3C2443_DMAREQSEL_UART3_1),
-       },
-       [DMACH_TIMER] = {
-               .name           = "timer",
-               .channels       = MAP(S3C2443_DMAREQSEL_TIMER),
-       },
-       [DMACH_I2S_IN] = {
-               .name           = "i2s-sdi",
-               .channels       = MAP(S3C2443_DMAREQSEL_I2SRX),
-       },
-       [DMACH_I2S_OUT] = {
-               .name           = "i2s-sdo",
-               .channels       = MAP(S3C2443_DMAREQSEL_I2STX),
-       },
-       [DMACH_PCM_IN] = {
-               .name           = "pcm-in",
-               .channels       = MAP(S3C2443_DMAREQSEL_PCMIN),
-       },
-       [DMACH_PCM_OUT] = {
-               .name           = "pcm-out",
-               .channels       = MAP(S3C2443_DMAREQSEL_PCMOUT),
-       },
-       [DMACH_MIC_IN] = {
-               .name           = "mic-in",
-               .channels       = MAP(S3C2443_DMAREQSEL_MICIN),
-       },
-};
-
-static void s3c2443_dma_select(struct s3c2410_dma_chan *chan,
-                              struct s3c24xx_dma_map *map)
-{
-       writel(map->channels[0] | S3C2443_DMAREQSEL_HW,
-              chan->regs + S3C2443_DMA_DMAREQSEL);
-}
-
-static struct s3c24xx_dma_selection __initdata s3c2443_dma_sel = {
-       .select         = s3c2443_dma_select,
-       .dcon_mask      = 0,
-       .map            = s3c2443_dma_mappings,
-       .map_size       = ARRAY_SIZE(s3c2443_dma_mappings),
-};
-
-static int __init s3c2443_dma_add(struct device *dev,
-                                 struct subsys_interface *sif)
-{
-       s3c24xx_dma_init(6, IRQ_S3C2443_DMA0, 0x100);
-       return s3c24xx_dma_init_map(&s3c2443_dma_sel);
-}
-
-static struct subsys_interface s3c2443_dma_interface = {
-       .name           = "s3c2443_dma",
-       .subsys         = &s3c2443_subsys,
-       .add_dev        = s3c2443_dma_add,
-};
-
-static int __init s3c2443_dma_init(void)
-{
-       return subsys_interface_register(&s3c2443_dma_interface);
-}
-
-arch_initcall(s3c2443_dma_init);
diff --git a/arch/arm/mach-s3c2443/irq.c b/arch/arm/mach-s3c2443/irq.c
deleted file mode 100644 (file)
index ac2829f..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/irq.c
- *
- * Copyright (c) 2007 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/regs-irq.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/cpu.h>
-#include <plat/pm.h>
-#include <plat/irq.h>
-
-#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
-
-static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len)
-{
-       unsigned int subsrc, submsk;
-       unsigned int end;
-
-       /* read the current pending interrupts, and the mask
-        * for what it is available */
-
-       subsrc = __raw_readl(S3C2410_SUBSRCPND);
-       submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-       subsrc  &= ~submsk;
-       subsrc >>= (irq - S3C2410_IRQSUB(0));
-       subsrc  &= (1 << len)-1;
-
-       end = len + irq;
-
-       for (; irq < end && subsrc; irq++) {
-               if (subsrc & 1)
-                       generic_handle_irq(irq);
-
-               subsrc >>= 1;
-       }
-}
-
-/* WDT/AC97 sub interrupts */
-
-static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
-{
-       s3c2443_irq_demux(IRQ_S3C2443_WDT, 4);
-}
-
-#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
-#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
-
-static void s3c2443_irq_wdtac97_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static void s3c2443_irq_wdtac97_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
-}
-
-static void s3c2443_irq_wdtac97_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
-}
-
-static struct irq_chip s3c2443_irq_wdtac97 = {
-       .irq_mask       = s3c2443_irq_wdtac97_mask,
-       .irq_unmask     = s3c2443_irq_wdtac97_unmask,
-       .irq_ack        = s3c2443_irq_wdtac97_ack,
-};
-
-/* LCD sub interrupts */
-
-static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
-{
-       s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4);
-}
-
-#define INTMSK_LCD     (1UL << (IRQ_LCD - IRQ_EINT0))
-#define SUBMSK_LCD     INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
-
-static void s3c2443_irq_lcd_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static void s3c2443_irq_lcd_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_LCD);
-}
-
-static void s3c2443_irq_lcd_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
-}
-
-static struct irq_chip s3c2443_irq_lcd = {
-       .irq_mask       = s3c2443_irq_lcd_mask,
-       .irq_unmask     = s3c2443_irq_lcd_unmask,
-       .irq_ack        = s3c2443_irq_lcd_ack,
-};
-
-/* DMA sub interrupts */
-
-static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
-{
-       s3c2443_irq_demux(IRQ_S3C2443_DMA0, 6);
-}
-
-#define INTMSK_DMA     (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
-#define SUBMSK_DMA     INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
-
-static void s3c2443_irq_dma_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static void s3c2443_irq_dma_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_DMA);
-}
-
-static void s3c2443_irq_dma_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
-}
-
-static struct irq_chip s3c2443_irq_dma = {
-       .irq_mask       = s3c2443_irq_dma_mask,
-       .irq_unmask     = s3c2443_irq_dma_unmask,
-       .irq_ack        = s3c2443_irq_dma_ack,
-};
-
-/* UART3 sub interrupts */
-
-static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
-{
-       s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
-}
-
-#define INTMSK_UART3   (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3   (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
-static void s3c2443_irq_uart3_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static void s3c2443_irq_uart3_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_UART3);
-}
-
-static void s3c2443_irq_uart3_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
-}
-
-static struct irq_chip s3c2443_irq_uart3 = {
-       .irq_mask       = s3c2443_irq_uart3_mask,
-       .irq_unmask     = s3c2443_irq_uart3_unmask,
-       .irq_ack        = s3c2443_irq_uart3_ack,
-};
-
-/* CAM sub interrupts */
-
-static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc)
-{
-       s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4);
-}
-
-#define INTMSK_CAM     (1UL << (IRQ_CAM - IRQ_EINT0))
-#define SUBMSK_CAM     INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P)
-
-static void s3c2443_irq_cam_mask(struct irq_data *data)
-{
-       s3c_irqsub_mask(data->irq, INTMSK_CAM, SUBMSK_CAM);
-}
-
-static void s3c2443_irq_cam_unmask(struct irq_data *data)
-{
-       s3c_irqsub_unmask(data->irq, INTMSK_CAM);
-}
-
-static void s3c2443_irq_cam_ack(struct irq_data *data)
-{
-       s3c_irqsub_maskack(data->irq, INTMSK_CAM, SUBMSK_CAM);
-}
-
-static struct irq_chip s3c2443_irq_cam = {
-       .irq_mask       = s3c2443_irq_cam_mask,
-       .irq_unmask     = s3c2443_irq_cam_unmask,
-       .irq_ack        = s3c2443_irq_cam_ack,
-};
-
-/* IRQ initialisation code */
-
-static int __init s3c2443_add_sub(unsigned int base,
-                                  void (*demux)(unsigned int,
-                                                struct irq_desc *),
-                                  struct irq_chip *chip,
-                                  unsigned int start, unsigned int end)
-{
-       unsigned int irqno;
-
-       irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
-       irq_set_chained_handler(base, demux);
-
-       for (irqno = start; irqno <= end; irqno++) {
-               irq_set_chip_and_handler(irqno, chip, handle_level_irq);
-               set_irq_flags(irqno, IRQF_VALID);
-       }
-
-       return 0;
-}
-
-static int __init s3c2443_irq_add(struct device *dev,
-                                 struct subsys_interface *sif)
-{
-       printk("S3C2443: IRQ Support\n");
-
-       s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam,
-                       IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P);
-
-       s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd,
-                       IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4);
-
-       s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma,
-                       &s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
-
-       s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3,
-                       &s3c2443_irq_uart3,
-                       IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
-
-       s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97,
-                       &s3c2443_irq_wdtac97,
-                       IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
-
-       return 0;
-}
-
-static struct subsys_interface s3c2443_irq_interface = {
-       .name           = "s3c2443_irq",
-       .subsys         = &s3c2443_subsys,
-       .add_dev        = s3c2443_irq_add,
-};
-
-static int __init s3c2443_irq_init(void)
-{
-       return subsys_interface_register(&s3c2443_irq_interface);
-}
-
-arch_initcall(s3c2443_irq_init);
-
diff --git a/arch/arm/mach-s3c2443/mach-smdk2443.c b/arch/arm/mach-s3c2443/mach-smdk2443.c
deleted file mode 100644 (file)
index 2092369..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/mach-smdk2443.c
- *
- * Copyright (c) 2007 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * http://www.fluff.org/ben/smdk2443/
- *
- * Thanks to Samsung for the loan of an SMDK2443
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-lcd.h>
-
-#include <mach/idle.h>
-#include <mach/fb.h>
-#include <plat/iic.h>
-
-#include <plat/s3c2410.h>
-#include <plat/s3c2443.h>
-#include <plat/clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-
-#include <plat/common-smdk.h>
-
-static struct map_desc smdk2443_iodesc[] __initdata = {
-       /* ISA IO Space map (memory space selected by A24) */
-
-       {
-               .virtual        = (u32)S3C24XX_VA_ISA_WORD,
-               .pfn            = __phys_to_pfn(S3C2410_CS2),
-               .length         = 0x10000,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (u32)S3C24XX_VA_ISA_WORD + 0x10000,
-               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
-               .length         = SZ_4M,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (u32)S3C24XX_VA_ISA_BYTE,
-               .pfn            = __phys_to_pfn(S3C2410_CS2),
-               .length         = 0x10000,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
-               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
-               .length         = SZ_4M,
-               .type           = MT_DEVICE,
-       }
-};
-
-#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
-#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
-#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
-
-static struct s3c2410_uartcfg smdk2443_uartcfgs[] __initdata = {
-       [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-       [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       },
-       /* IR port */
-       [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x43,
-               .ufcon       = 0x51,
-       },
-       [3] = {
-               .hwport      = 3,
-               .flags       = 0,
-               .ucon        = 0x3c5,
-               .ulcon       = 0x03,
-               .ufcon       = 0x51,
-       }
-};
-
-static struct platform_device *smdk2443_devices[] __initdata = {
-       &s3c_device_wdt,
-       &s3c_device_i2c0,
-       &s3c_device_hsmmc1,
-#ifdef CONFIG_SND_SOC_SMDK2443_WM9710
-       &s3c_device_ac97,
-#endif
-};
-
-static void __init smdk2443_map_io(void)
-{
-       s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc));
-       s3c24xx_init_clocks(12000000);
-       s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs));
-}
-
-static void __init smdk2443_machine_init(void)
-{
-       s3c_i2c0_set_platdata(NULL);
-
-#ifdef CONFIG_SND_SOC_SMDK2443_WM9710
-       s3c24xx_ac97_setup_gpio(S3C24XX_AC97_GPE0);
-#endif
-
-       platform_add_devices(smdk2443_devices, ARRAY_SIZE(smdk2443_devices));
-       smdk_machine_init();
-}
-
-MACHINE_START(SMDK2443, "SMDK2443")
-       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .atag_offset    = 0x100,
-
-       .init_irq       = s3c24xx_init_irq,
-       .map_io         = smdk2443_map_io,
-       .init_machine   = smdk2443_machine_init,
-       .timer          = &s3c24xx_timer,
-       .restart        = s3c2443_restart,
-MACHINE_END
diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c
deleted file mode 100644 (file)
index 9318847..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/* linux/arch/arm/mach-s3c2443/s3c2443.c
- *
- * Copyright (c) 2007 Simtec Electronics
- *   Ben Dooks <ben@simtec.co.uk>
- *
- * Samsung S3C2443 Mobile CPU support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/system_misc.h>
-
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-#include <plat/s3c2443.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/fb-core.h>
-#include <plat/nand-core.h>
-#include <plat/adc-core.h>
-
-static struct map_desc s3c2443_iodesc[] __initdata = {
-       IODESC_ENT(WATCHDOG),
-       IODESC_ENT(CLKPWR),
-       IODESC_ENT(TIMER),
-};
-
-struct bus_type s3c2443_subsys = {
-       .name = "s3c2443-core",
-       .dev_name = "s3c2443-core",
-};
-
-static struct device s3c2443_dev = {
-       .bus            = &s3c2443_subsys,
-};
-
-void s3c2443_restart(char mode, const char *cmd)
-{
-       if (mode == 's')
-               soft_restart(0);
-
-       __raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
-}
-
-int __init s3c2443_init(void)
-{
-       printk("S3C2443: Initialising architecture\n");
-
-       s3c_nand_setname("s3c2412-nand");
-       s3c_fb_setname("s3c2443-fb");
-
-       s3c_adc_setname("s3c2443-adc");
-
-       /* change WDT IRQ number */
-       s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT;
-       s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT;
-
-       return device_register(&s3c2443_dev);
-}
-
-void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-       s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
-}
-
-/* s3c2443_map_io
- *
- * register the standard cpu IO areas, and any passed in from the
- * machine specific initialisation.
- */
-
-void __init s3c2443_map_io(void)
-{
-       s3c24xx_gpiocfg_default.set_pull = s3c2443_gpio_setpull;
-       s3c24xx_gpiocfg_default.get_pull = s3c2443_gpio_getpull;
-
-       iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
-}
-
-/* need to register the subsystem before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2443 based system)
- * as a driver which may support both 2443 and 2440 may try and use it.
-*/
-
-static int __init s3c2443_core_init(void)
-{
-       return subsys_system_register(&s3c2443_subsys, NULL);
-}
-
-core_initcall(s3c2443_core_init);
diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig
new file mode 100644 (file)
index 0000000..0f3a327
--- /dev/null
@@ -0,0 +1,538 @@
+# arch/arm/mach-s3c24xx/Kconfig
+#
+# Copyright (c) 2012 Samsung Electronics Co., Ltd.
+#              http://www.samsung.com/
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+if ARCH_S3C24XX
+
+menu "SAMSUNG S3C24XX SoCs Support"
+
+comment "S3C24XX SoCs"
+
+config CPU_S3C2410
+       bool "SAMSUNG S3C2410"
+       default y
+       select CPU_ARM920T
+       select S3C2410_CLOCK
+       select CPU_LLSERIAL_S3C2410
+       select S3C2410_PM if PM
+       select S3C2410_CPUFREQ if CPU_FREQ_S3C24XX
+       help
+         Support for S3C2410 and S3C2410A family from the S3C24XX line
+         of Samsung Mobile CPUs.
+
+config CPU_S3C2412
+       bool "SAMSUNG S3C2412"
+       depends on ARCH_S3C24XX
+       select CPU_ARM926T
+       select CPU_LLSERIAL_S3C2440
+       select S3C2412_PM if PM
+       select S3C2412_DMA if S3C24XX_DMA
+       help
+         Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
+
+config CPU_S3C2416
+       bool "SAMSUNG S3C2416/S3C2450"
+       depends on ARCH_S3C24XX
+       select CPU_ARM926T
+       select CPU_LLSERIAL_S3C2440
+       select SAMSUNG_CLKSRC
+       select S3C2443_COMMON
+       select S3C2443_DMA if S3C24XX_DMA
+       select S3C2416_PM if PM
+       help
+         Support for the S3C2416 SoC from the S3C24XX line
+
+config CPU_S3C2440
+       bool "SAMSUNG S3C2440"
+       select CPU_ARM920T
+       select CPU_LLSERIAL_S3C2440
+       select S3C2410_CLOCK
+       select S3C2410_PM if PM
+       select S3C2440_DMA if S3C24XX_DMA
+       help
+         Support for S3C2440 Samsung Mobile CPU based systems.
+
+config CPU_S3C2442
+       bool "SAMSUNG S3C2442"
+       select CPU_ARM920T
+       select CPU_LLSERIAL_S3C2440
+       select S3C2410_CLOCK
+       select S3C2410_PM if PM
+       help
+         Support for S3C2442 Samsung Mobile CPU based systems.
+
+config CPU_S3C244X
+       def_bool y
+       depends on CPU_S3C2440 || CPU_S3C2442
+
+config CPU_S3C2443
+       bool "SAMSUNG S3C2443"
+       depends on ARCH_S3C24XX
+       select CPU_ARM920T
+       select CPU_LLSERIAL_S3C2440
+       select SAMSUNG_CLKSRC
+       select S3C2443_COMMON
+       select S3C2443_DMA if S3C24XX_DMA
+       help
+         Support for the S3C2443 SoC from the S3C24XX line
+
+# common code
+
+config S3C24XX_SMDK
+       bool
+       help
+         Common machine code for SMDK2410 and SMDK2440
+
+config S3C24XX_SIMTEC_AUDIO
+       bool
+       depends on (ARCH_BAST || MACH_VR1000 || MACH_OSIRIS || MACH_ANUBIS)
+       default y
+       help
+         Add audio devices for common Simtec S3C24XX boards
+
+config S3C24XX_SIMTEC_PM
+       bool
+       help
+         Common power management code for systems that are
+         compatible with the Simtec style of power management
+
+config S3C24XX_SIMTEC_USB
+       bool
+       help
+         USB management code for common Simtec S3C24XX boards
+
+config S3C24XX_SETUP_TS
+       bool
+       help
+         Compile in platform device definition for Samsung TouchScreen.
+
+# cpu-specific sections
+
+if CPU_S3C2410
+
+config S3C2410_DMA
+       bool
+       depends on S3C24XX_DMA && (CPU_S3C2410 || CPU_S3C2442)
+       default y if CPU_S3C2410 || CPU_S3C2442
+       help
+         DMA device selection for S3C2410 and compatible CPUs
+
+config S3C2410_PM
+       bool
+       help
+         Power Management code common to S3C2410 and better
+
+config S3C24XX_SIMTEC_NOR
+       bool
+       help
+         Internal node to specify machine has simtec NOR mapping
+
+config MACH_BAST_IDE
+       bool
+       select HAVE_PATA_PLATFORM
+       help
+         Internal node for machines with an BAST style IDE
+         interface
+
+comment "S3C2410 Boards"
+
+#
+# The "S3C2410 Boards" list is ordered alphabetically by option text.
+# (without ARCH_ or MACH_)
+#
+
+config MACH_AML_M5900
+       bool "AML M5900 Series"
+       select S3C24XX_SIMTEC_PM if PM
+       select S3C_DEV_USB_HOST
+       help
+         Say Y here if you are using the American Microsystems M5900 Series
+         <http://www.amltd.com>
+
+config ARCH_BAST
+       bool "Simtec Electronics BAST (EB2410ITX)"
+       select S3C2410_IOTIMING if S3C2410_CPUFREQ
+       select S3C24XX_SIMTEC_PM if PM
+       select S3C24XX_SIMTEC_NOR
+       select S3C24XX_SIMTEC_USB
+       select MACH_BAST_IDE
+       select S3C24XX_DCLK
+       select ISA
+       select S3C_DEV_HWMON
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using the Simtec Electronics EB2410ITX
+         development board (also known as BAST)
+
+config BAST_PC104_IRQ
+       bool "BAST PC104 IRQ support"
+       depends on ARCH_BAST
+       default y
+       help
+         Say Y here to enable the PC104 IRQ routing on the
+         Simtec BAST (EB2410ITX)
+
+config ARCH_H1940
+       bool "IPAQ H1940"
+       select PM_H1940 if PM
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       select S3C24XX_SETUP_TS
+       help
+         Say Y here if you are using the HP IPAQ H1940
+
+config H1940BT
+       tristate "Control the state of H1940 bluetooth chip"
+       depends on ARCH_H1940
+       select RFKILL
+       help
+         This is a simple driver that is able to control
+         the state of built in bluetooth chip on h1940.
+
+config PM_H1940
+       bool
+       help
+         Internal node for H1940 and related PM
+
+config MACH_N30
+       bool "Acer N30 family"
+       select MACH_N35
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you want suppt for the Acer N30, Acer N35,
+         Navman PiN570, Yakumo AlphaX or Airis NC05 PDAs.
+
+config MACH_OTOM
+       bool "NexVision OTOM Board"
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using the Nex Vision OTOM board
+
+config MACH_QT2410
+       bool "QT2410"
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using the Armzone QT2410
+
+config ARCH_SMDK2410
+       bool "SMDK2410/A9M2410"
+       select S3C24XX_SMDK
+       help
+         Say Y here if you are using the SMDK2410 or the derived module A9M2410
+         <http://www.fsforth.de>
+
+config MACH_TCT_HAMMER
+       bool "TCT Hammer Board"
+       select S3C_DEV_USB_HOST
+       help
+         Say Y here if you are using the TinCanTools Hammer Board
+         <http://www.tincantools.com>
+
+config MACH_VR1000
+       bool "Thorcom VR1000"
+       select S3C24XX_SIMTEC_PM if PM
+       select S3C24XX_DCLK
+       select S3C24XX_SIMTEC_NOR
+       select MACH_BAST_IDE
+       select S3C_DEV_USB_HOST
+       select S3C24XX_SIMTEC_USB
+       help
+         Say Y here if you are using the Thorcom VR1000 board.
+
+endif  # CPU_S3C2410
+
+config S3C2412_PM_SLEEP
+       bool
+       help
+         Internal config node to apply sleep for S3C2412 power management.
+         Can be selected by another SoCs such as S3C2416 with similar
+         sleep procedure.
+
+if CPU_S3C2412
+
+config CPU_S3C2412_ONLY
+       bool
+       depends on ARCH_S3C24XX && !CPU_S3C2410 && \
+                  !CPU_S3C2416 && !CPU_S3C2440 && !CPU_S3C2442 && \
+                  !CPU_S3C2443 && CPU_S3C2412
+       default y
+
+config S3C2412_DMA
+       bool
+       help
+         Internal config node for S3C2412 DMA support
+
+config S3C2412_PM
+       bool
+       help
+         Internal config node to apply S3C2412 power management
+
+comment "S3C2412 Boards"
+
+#
+# The "S3C2412 Boards" list is ordered alphabetically by option text.
+# (without ARCH_ or MACH_)
+#
+
+config MACH_JIVE
+       bool "Logitech Jive"
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using the Logitech Jive.
+
+config MACH_JIVE_SHOW_BOOTLOADER
+       bool "Allow access to bootloader partitions in MTD (EXPERIMENTAL)"
+       depends on MACH_JIVE && EXPERIMENTAL
+
+config MACH_S3C2413
+       bool
+       help
+         Internal node for S3C2413 version of SMDK2413, so that
+         machine_is_s3c2413() will work when MACH_SMDK2413 is
+         selected
+
+config MACH_SMDK2412
+       bool "SMDK2412"
+       select MACH_SMDK2413
+       help
+         Say Y here if you are using an SMDK2412
+
+         Note, this shares support with SMDK2413, so will automatically
+         select MACH_SMDK2413.
+
+config MACH_SMDK2413
+       bool "SMDK2413"
+       select MACH_S3C2413
+       select S3C24XX_SMDK
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using an SMDK2413
+
+config MACH_VSTMS
+       bool "VMSTMS"
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using an VSTMS board
+
+endif  # CPU_S3C2412
+
+if CPU_S3C2416
+
+config S3C2416_PM
+       bool
+       select S3C2412_PM_SLEEP
+       help
+         Internal config node to apply S3C2416 power management
+
+config S3C2416_SETUP_SDHCI
+       bool
+       select S3C2416_SETUP_SDHCI_GPIO
+       help
+         Internal helper functions for S3C2416 based SDHCI systems
+
+config S3C2416_SETUP_SDHCI_GPIO
+       bool
+       help
+         Common setup code for SDHCI gpio.
+
+comment "S3C2416 Boards"
+
+config MACH_SMDK2416
+       bool "SMDK2416"
+       select S3C24XX_SMDK
+       select S3C_DEV_FB
+       select S3C_DEV_HSMMC
+       select S3C_DEV_HSMMC1
+       select S3C_DEV_NAND
+       select S3C_DEV_USB_HOST
+       select S3C2416_SETUP_SDHCI
+       help
+         Say Y here if you are using an SMDK2416
+
+endif  # CPU_S3C2416
+
+if CPU_S3C2440
+
+config S3C2440_DMA
+       bool
+       help
+         Support for S3C2440 specific DMA code5A
+
+comment "S3C2440 Boards"
+
+#
+# The "S3C2440 Boards" list is ordered alphabetically by option text.
+# (without ARCH_ or MACH_)
+#
+
+config MACH_ANUBIS
+       bool "Simtec Electronics ANUBIS"
+       select S3C24XX_DCLK
+       select S3C24XX_SIMTEC_PM if PM
+       select HAVE_PATA_PLATFORM
+       select S3C24XX_GPIO_EXTRA64
+       select S3C2440_XTAL_12000000
+       select S3C_DEV_USB_HOST
+       help
+         Say Y here if you are using the Simtec Electronics ANUBIS
+         development system
+
+config MACH_AT2440EVB
+       bool "Avantech AT2440EVB development board"
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using the AT2440EVB development board
+
+config MACH_MINI2440
+       bool "MINI2440 development board"
+       select EEPROM_AT24
+       select NEW_LEDS
+       select LEDS_CLASS
+       select LEDS_TRIGGER
+       select LEDS_TRIGGER_BACKLIGHT
+       select S3C_DEV_NAND
+       select S3C_DEV_USB_HOST
+       help
+         Say Y here to select support for the MINI2440. Is a 10cm x 10cm board
+         available via various sources. It can come with a 3.5" or 7" touch LCD.
+
+config MACH_NEXCODER_2440
+       bool "NexVision NEXCODER 2440 Light Board"
+       select S3C2440_XTAL_12000000
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
+
+config MACH_OSIRIS
+       bool "Simtec IM2440D20 (OSIRIS) module"
+       select S3C24XX_DCLK
+       select S3C24XX_SIMTEC_PM if PM
+       select S3C24XX_GPIO_EXTRA128
+       select S3C2440_XTAL_12000000
+       select S3C2410_IOTIMING if S3C2440_CPUFREQ
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using the Simtec IM2440D20 module, also
+         known as the Osiris.
+
+config MACH_OSIRIS_DVS
+       tristate "Simtec IM2440D20 (OSIRIS) Dynamic Voltage Scaling driver"
+       depends on MACH_OSIRIS
+       select TPS65010
+       help
+         Say Y/M here if you want to have dynamic voltage scaling support
+         on the Simtec IM2440D20 (OSIRIS) module via the TPS65011.
+
+         The DVS driver alters the voltage supplied to the ARM core
+         depending on the frequency it is running at. The driver itself
+         does not do any of the frequency alteration, which is left up
+         to the cpufreq driver.
+
+config MACH_RX3715
+       bool "HP iPAQ rx3715"
+       select S3C2440_XTAL_16934400
+       select PM_H1940 if PM
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using the HP iPAQ rx3715.
+
+config ARCH_S3C2440
+       bool "SMDK2440"
+       select S3C2440_XTAL_16934400
+       select S3C24XX_SMDK
+       select S3C_DEV_USB_HOST
+       select S3C_DEV_NAND
+       help
+         Say Y here if you are using the SMDK2440.
+
+config SMDK2440_CPU2440
+       bool "SMDK2440 with S3C2440 CPU module"
+       default y if ARCH_S3C2440
+       select S3C2440_XTAL_16934400
+
+endif  # CPU_S3C2440
+
+if CPU_S3C2442
+
+comment "S3C2442 Boards"
+
+#
+# The "S3C2442 Boards" list is ordered alphabetically by option text.
+# (without ARCH_ or MACH_)
+#
+
+config MACH_NEO1973_GTA02
+       bool "Openmoko GTA02 / Freerunner phone"
+       select MFD_PCF50633
+       select PCF50633_GPIO
+       select I2C
+       select POWER_SUPPLY
+       select MACH_NEO1973
+       select S3C2410_PWM
+       select S3C_DEV_USB_HOST
+       help
+          Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
+
+config MACH_RX1950
+       bool "HP iPAQ rx1950"
+       select S3C24XX_DCLK
+       select PM_H1940 if PM
+       select I2C
+       select S3C2410_PWM
+       select S3C_DEV_NAND
+       select S3C2410_IOTIMING if S3C2440_CPUFREQ
+       select S3C2440_XTAL_16934400
+       help
+          Say Y here if you're using HP iPAQ rx1950
+
+config SMDK2440_CPU2442
+       bool "SMDM2440 with S3C2442 CPU module"
+
+endif  # CPU_S3C2440
+
+if CPU_S3C2443 || CPU_S3C2416
+
+config S3C2443_COMMON
+       bool
+       help
+         Common code for the S3C2443 and similar processors, which includes
+         the S3C2416 and S3C2450.
+
+config S3C2443_DMA
+       bool
+       help
+         Internal config node for S3C2443 DMA support
+
+endif  # CPU_S3C2443 || CPU_S3C2416
+
+if CPU_S3C2443
+
+comment "S3C2443 Boards"
+
+config MACH_SMDK2443
+       bool "SMDK2443"
+       select S3C24XX_SMDK
+       select S3C_DEV_HSMMC1
+       help
+         Say Y here if you are using an SMDK2443
+
+endif  # CPU_S3C2443
+
+endmenu        # SAMSUNG S3C24XX SoCs Support
+
+endif  # ARCH_S3C24XX
diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile
new file mode 100644 (file)
index 0000000..3518fe8
--- /dev/null
@@ -0,0 +1,95 @@
+# arch/arm/mach-s3c24xx/Makefile
+#
+# Copyright (c) 2012 Samsung Electronics Co., Ltd.
+#              http://www.samsung.com/
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y                          :=
+obj-m                          :=
+obj-n                          :=
+obj-                           :=
+
+# core
+
+obj-$(CONFIG_CPU_S3C2410)      += s3c2410.o
+obj-$(CONFIG_S3C2410_DMA)      += dma-s3c2410.o
+obj-$(CONFIG_S3C2410_PM)       += pm-s3c2410.o sleep-s3c2410.o
+
+obj-$(CONFIG_CPU_S3C2412)      += s3c2412.o irq-s3c2412.o clock-s3c2412.o
+obj-$(CONFIG_S3C2412_DMA)      += dma-s3c2412.o
+obj-$(CONFIG_S3C2412_PM)       += pm-s3c2412.o
+obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep-s3c2412.o
+
+obj-$(CONFIG_CPU_S3C2416)      += s3c2416.o irq-s3c2416.o clock-s3c2416.o
+obj-$(CONFIG_S3C2416_PM)       += pm-s3c2416.o
+
+obj-$(CONFIG_CPU_S3C2440)      += s3c2440.o irq-s3c2440.o clock-s3c2440.o
+obj-$(CONFIG_CPU_S3C2442)      += s3c2442.o
+obj-$(CONFIG_CPU_S3C244X)      += s3c244x.o irq-s3c244x.o clock-s3c244x.o
+obj-$(CONFIG_S3C2440_DMA)      += dma-s3c2440.o
+
+obj-$(CONFIG_CPU_S3C2443)      += s3c2443.o irq-s3c2443.o clock-s3c2443.o
+
+# common code
+
+obj-$(CONFIG_S3C2443_COMMON)   += common-s3c2443.o
+obj-$(CONFIG_S3C2443_DMA)      += dma-s3c2443.o
+
+#
+# machine support
+# following is ordered alphabetically by option text.
+#
+
+obj-$(CONFIG_MACH_AML_M5900)           += mach-amlm5900.o
+obj-$(CONFIG_ARCH_BAST)                        += mach-bast.o
+obj-$(CONFIG_BAST_PC104_IRQ)           += bast-irq.o
+obj-$(CONFIG_ARCH_H1940)               += mach-h1940.o
+obj-$(CONFIG_H1940BT)                  += h1940-bluetooth.o
+obj-$(CONFIG_PM_H1940)                 += pm-h1940.o
+obj-$(CONFIG_MACH_N30)                 += mach-n30.o
+obj-$(CONFIG_MACH_OTOM)                        += mach-otom.o
+obj-$(CONFIG_MACH_QT2410)              += mach-qt2410.o
+obj-$(CONFIG_ARCH_SMDK2410)            += mach-smdk2410.o
+obj-$(CONFIG_MACH_TCT_HAMMER)          += mach-tct_hammer.o
+obj-$(CONFIG_MACH_VR1000)              += mach-vr1000.o
+
+obj-$(CONFIG_MACH_JIVE)                        += mach-jive.o
+obj-$(CONFIG_MACH_SMDK2413)            += mach-smdk2413.o
+obj-$(CONFIG_MACH_VSTMS)               += mach-vstms.o
+
+obj-$(CONFIG_MACH_SMDK2416)            += mach-smdk2416.o
+
+obj-$(CONFIG_MACH_ANUBIS)              += mach-anubis.o
+obj-$(CONFIG_MACH_AT2440EVB)           += mach-at2440evb.o
+obj-$(CONFIG_MACH_MINI2440)            += mach-mini2440.o
+obj-$(CONFIG_MACH_NEXCODER_2440)       += mach-nexcoder.o
+obj-$(CONFIG_MACH_OSIRIS)              += mach-osiris.o
+obj-$(CONFIG_MACH_RX3715)              += mach-rx3715.o
+obj-$(CONFIG_ARCH_S3C2440)             += mach-smdk2440.o
+
+obj-$(CONFIG_MACH_NEO1973_GTA02)       += mach-gta02.o
+obj-$(CONFIG_MACH_RX1950)              += mach-rx1950.o
+
+obj-$(CONFIG_MACH_SMDK2443)            += mach-smdk2443.o
+
+# common bits of machine support
+
+obj-$(CONFIG_S3C24XX_SMDK)             += common-smdk.o
+obj-$(CONFIG_S3C24XX_SIMTEC_AUDIO)     += simtec-audio.o
+obj-$(CONFIG_S3C24XX_SIMTEC_NOR)       += simtec-nor.o
+obj-$(CONFIG_S3C24XX_SIMTEC_PM)                += simtec-pm.o
+obj-$(CONFIG_S3C24XX_SIMTEC_USB)       += simtec-usb.o
+
+# machine additions
+
+obj-$(CONFIG_MACH_BAST_IDE)            += bast-ide.o
+obj-$(CONFIG_MACH_OSIRIS_DVS)          += mach-osiris-dvs.o
+
+# device setup
+
+obj-$(CONFIG_S3C2416_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
+obj-$(CONFIG_ARCH_S3C24XX)             += setup-i2c.o
+obj-$(CONFIG_S3C24XX_SETUP_TS)         += setup-ts.o
diff --git a/arch/arm/mach-s3c24xx/Makefile.boot b/arch/arm/mach-s3c24xx/Makefile.boot
new file mode 100644 (file)
index 0000000..4457605
--- /dev/null
@@ -0,0 +1,7 @@
+ifeq ($(CONFIG_PM_H1940),y)
+       zreladdr-y      += 0x30108000
+       params_phys-y   := 0x30100100
+else
+       zreladdr-y      += 0x30008000
+       params_phys-y   := 0x30000100
+endif
diff --git a/arch/arm/mach-s3c24xx/bast-ide.c b/arch/arm/mach-s3c24xx/bast-ide.c
new file mode 100644 (file)
index 0000000..298ecec
--- /dev/null
@@ -0,0 +1,112 @@
+/* linux/arch/arm/mach-s3c2410/bast-ide.c
+ *
+ * Copyright 2007 Simtec Electronics
+ *     http://www.simtec.co.uk/products/EB2410ITX/
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/map.h>
+#include <mach/bast-map.h>
+#include <mach/bast-irq.h>
+
+/* IDE ports */
+
+static struct pata_platform_info bast_ide_platdata = {
+       .ioport_shift   = 5,
+};
+
+#define IDE_CS S3C2410_CS5
+
+static struct resource bast_ide0_resource[] = {
+       [0]     = {
+               .start  = IDE_CS + BAST_PA_IDEPRI,
+               .end    = IDE_CS + BAST_PA_IDEPRI + (8 * 0x20) - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1]     = {
+               .start  = IDE_CS + BAST_PA_IDEPRIAUX + (6 * 0x20) ,
+               .end    = IDE_CS + BAST_PA_IDEPRIAUX + (7 * 0x20) - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2]     = {
+               .start  = IRQ_IDE0,
+               .end    = IRQ_IDE0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bast_device_ide0 = {
+       .name           = "pata_platform",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(bast_ide0_resource),
+       .resource       = bast_ide0_resource,
+       .dev            = {
+               .platform_data = &bast_ide_platdata,
+               .coherent_dma_mask = ~0,
+       }
+
+};
+
+static struct resource bast_ide1_resource[] = {
+       [0]     = {
+               .start  = IDE_CS + BAST_PA_IDESEC,
+               .end    = IDE_CS + BAST_PA_IDESEC + (8 * 0x20) - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1]     = {
+               .start  = IDE_CS + BAST_PA_IDESECAUX + (6 * 0x20),
+               .end    = IDE_CS + BAST_PA_IDESECAUX + (7 * 0x20) - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2]     = {
+               .start  = IRQ_IDE1,
+               .end    = IRQ_IDE1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bast_device_ide1 = {
+       .name           = "pata_platform",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(bast_ide1_resource),
+       .resource       = bast_ide1_resource,
+       .dev            = {
+               .platform_data = &bast_ide_platdata,
+               .coherent_dma_mask = ~0,
+       }
+};
+
+static struct platform_device *bast_ide_devices[] __initdata = {
+       &bast_device_ide0,
+       &bast_device_ide1,
+};
+
+static __init int bast_ide_init(void)
+{
+       if (machine_is_bast() || machine_is_vr1000())
+               return platform_add_devices(bast_ide_devices,
+                                           ARRAY_SIZE(bast_ide_devices));
+
+       return 0;
+}
+
+fs_initcall(bast_ide_init);
diff --git a/arch/arm/mach-s3c24xx/bast-irq.c b/arch/arm/mach-s3c24xx/bast-irq.c
new file mode 100644 (file)
index 0000000..ac7b2ad
--- /dev/null
@@ -0,0 +1,166 @@
+/* linux/arch/arm/mach-s3c2410/bast-irq.c
+ *
+ * Copyright 2003-2005 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.simtec.co.uk/products/EB2410ITX/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/regs-irq.h>
+#include <mach/bast-map.h>
+#include <mach/bast-irq.h>
+
+#include <plat/irq.h>
+
+#if 0
+#include <asm/debug-ll.h>
+#endif
+
+#define irqdbf(x...)
+#define irqdbf2(x...)
+
+
+/* handle PC104 ISA interrupts from the system CPLD */
+
+/* table of ISA irq nos to the relevant mask... zero means
+ * the irq is not implemented
+*/
+static unsigned char bast_pc104_irqmasks[] = {
+       0,   /* 0 */
+       0,   /* 1 */
+       0,   /* 2 */
+       1,   /* 3 */
+       0,   /* 4 */
+       2,   /* 5 */
+       0,   /* 6 */
+       4,   /* 7 */
+       0,   /* 8 */
+       0,   /* 9 */
+       8,   /* 10 */
+       0,   /* 11 */
+       0,   /* 12 */
+       0,   /* 13 */
+       0,   /* 14 */
+       0,   /* 15 */
+};
+
+static unsigned char bast_pc104_irqs[] = { 3, 5, 7, 10 };
+
+static void
+bast_pc104_mask(struct irq_data *data)
+{
+       unsigned long temp;
+
+       temp = __raw_readb(BAST_VA_PC104_IRQMASK);
+       temp &= ~bast_pc104_irqmasks[data->irq];
+       __raw_writeb(temp, BAST_VA_PC104_IRQMASK);
+}
+
+static void
+bast_pc104_maskack(struct irq_data *data)
+{
+       struct irq_desc *desc = irq_desc + IRQ_ISA;
+
+       bast_pc104_mask(data);
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
+}
+
+static void
+bast_pc104_unmask(struct irq_data *data)
+{
+       unsigned long temp;
+
+       temp = __raw_readb(BAST_VA_PC104_IRQMASK);
+       temp |= bast_pc104_irqmasks[data->irq];
+       __raw_writeb(temp, BAST_VA_PC104_IRQMASK);
+}
+
+static struct irq_chip  bast_pc104_chip = {
+       .irq_mask       = bast_pc104_mask,
+       .irq_unmask     = bast_pc104_unmask,
+       .irq_ack        = bast_pc104_maskack
+};
+
+static void
+bast_irq_pc104_demux(unsigned int irq,
+                    struct irq_desc *desc)
+{
+       unsigned int stat;
+       unsigned int irqno;
+       int i;
+
+       stat = __raw_readb(BAST_VA_PC104_IRQREQ) & 0xf;
+
+       if (unlikely(stat == 0)) {
+               /* ack if we get an irq with nothing (ie, startup) */
+
+               desc = irq_desc + IRQ_ISA;
+               desc->irq_data.chip->irq_ack(&desc->irq_data);
+       } else {
+               /* handle the IRQ */
+
+               for (i = 0; stat != 0; i++, stat >>= 1) {
+                       if (stat & 1) {
+                               irqno = bast_pc104_irqs[i];
+                               generic_handle_irq(irqno);
+                       }
+               }
+       }
+}
+
+static __init int bast_irq_init(void)
+{
+       unsigned int i;
+
+       if (machine_is_bast()) {
+               printk(KERN_INFO "BAST PC104 IRQ routing, Copyright 2005 Simtec Electronics\n");
+
+               /* zap all the IRQs */
+
+               __raw_writeb(0x0, BAST_VA_PC104_IRQMASK);
+
+               irq_set_chained_handler(IRQ_ISA, bast_irq_pc104_demux);
+
+               /* register our IRQs */
+
+               for (i = 0; i < 4; i++) {
+                       unsigned int irqno = bast_pc104_irqs[i];
+
+                       irq_set_chip_and_handler(irqno, &bast_pc104_chip,
+                                                handle_level_irq);
+                       set_irq_flags(irqno, IRQF_VALID);
+               }
+       }
+
+       return 0;
+}
+
+arch_initcall(bast_irq_init);
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2412.c b/arch/arm/mach-s3c24xx/clock-s3c2412.c
new file mode 100644 (file)
index 0000000..d10b695
--- /dev/null
@@ -0,0 +1,763 @@
+/* linux/arch/arm/mach-s3c2412/clock.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2412,S3C2413 Clock control support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/s3c2412.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+/* We currently have to assume that the system is running
+ * from the XTPll input, and that all ***REFCLKs are being
+ * fed from it, as we cannot read the state of OM[4] from
+ * software.
+ *
+ * It would be possible for each board initialisation to
+ * set the correct muxing at initialisation
+*/
+
+static int s3c2412_clkcon_enable(struct clk *clk, int enable)
+{
+       unsigned int clocks = clk->ctrlbit;
+       unsigned long clkcon;
+
+       clkcon = __raw_readl(S3C2410_CLKCON);
+
+       if (enable)
+               clkcon |= clocks;
+       else
+               clkcon &= ~clocks;
+
+       __raw_writel(clkcon, S3C2410_CLKCON);
+
+       return 0;
+}
+
+static int s3c2412_upll_enable(struct clk *clk, int enable)
+{
+       unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
+       unsigned long orig = upllcon;
+
+       if (!enable)
+               upllcon |= S3C2412_PLLCON_OFF;
+       else
+               upllcon &= ~S3C2412_PLLCON_OFF;
+
+       __raw_writel(upllcon, S3C2410_UPLLCON);
+
+       /* allow ~150uS for the PLL to settle and lock */
+
+       if (enable && (orig & S3C2412_PLLCON_OFF))
+               udelay(150);
+
+       return 0;
+}
+
+/* clock selections */
+
+static struct clk clk_erefclk = {
+       .name           = "erefclk",
+};
+
+static struct clk clk_urefclk = {
+       .name           = "urefclk",
+};
+
+static int s3c2412_setparent_usysclk(struct clk *clk, struct clk *parent)
+{
+       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+       if (parent == &clk_urefclk)
+               clksrc &= ~S3C2412_CLKSRC_USYSCLK_UPLL;
+       else if (parent == &clk_upll)
+               clksrc |= S3C2412_CLKSRC_USYSCLK_UPLL;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       __raw_writel(clksrc, S3C2412_CLKSRC);
+       return 0;
+}
+
+static struct clk clk_usysclk = {
+       .name           = "usysclk",
+       .parent         = &clk_xtal,
+       .ops            = &(struct clk_ops) {
+               .set_parent     = s3c2412_setparent_usysclk,
+       },
+};
+
+static struct clk clk_mrefclk = {
+       .name           = "mrefclk",
+       .parent         = &clk_xtal,
+};
+
+static struct clk clk_mdivclk = {
+       .name           = "mdivclk",
+       .parent         = &clk_xtal,
+};
+
+static int s3c2412_setparent_usbsrc(struct clk *clk, struct clk *parent)
+{
+       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+       if (parent == &clk_usysclk)
+               clksrc &= ~S3C2412_CLKSRC_USBCLK_HCLK;
+       else if (parent == &clk_h)
+               clksrc |= S3C2412_CLKSRC_USBCLK_HCLK;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       __raw_writel(clksrc, S3C2412_CLKSRC);
+       return 0;
+}
+
+static unsigned long s3c2412_roundrate_usbsrc(struct clk *clk,
+                                             unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       int div;
+
+       if (rate > parent_rate)
+               return parent_rate;
+
+       div = parent_rate / rate;
+       if (div > 2)
+               div = 2;
+
+       return parent_rate / div;
+}
+
+static unsigned long s3c2412_getrate_usbsrc(struct clk *clk)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
+
+       return parent_rate / ((div & S3C2412_CLKDIVN_USB48DIV) ? 2 : 1);
+}
+
+static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
+
+       rate = s3c2412_roundrate_usbsrc(clk, rate);
+
+       if ((parent_rate / rate) == 2)
+               clkdivn |= S3C2412_CLKDIVN_USB48DIV;
+       else
+               clkdivn &= ~S3C2412_CLKDIVN_USB48DIV;
+
+       __raw_writel(clkdivn, S3C2410_CLKDIVN);
+       return 0;
+}
+
+static struct clk clk_usbsrc = {
+       .name           = "usbsrc",
+       .ops            = &(struct clk_ops) {
+               .get_rate       = s3c2412_getrate_usbsrc,
+               .set_rate       = s3c2412_setrate_usbsrc,
+               .round_rate     = s3c2412_roundrate_usbsrc,
+               .set_parent     = s3c2412_setparent_usbsrc,
+       },
+};
+
+static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
+{
+       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+       if (parent == &clk_mdivclk)
+               clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL;
+       else if (parent == &clk_mpll)
+               clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       __raw_writel(clksrc, S3C2412_CLKSRC);
+       return 0;
+}
+
+static struct clk clk_msysclk = {
+       .name           = "msysclk",
+       .ops            = &(struct clk_ops) {
+               .set_parent     = s3c2412_setparent_msysclk,
+       },
+};
+
+static int s3c2412_setparent_armclk(struct clk *clk, struct clk *parent)
+{
+       unsigned long flags;
+       unsigned long clkdiv;
+       unsigned long dvs;
+
+       /* Note, we current equate fclk andf msysclk for S3C2412 */
+
+       if (parent == &clk_msysclk || parent == &clk_f)
+               dvs = 0;
+       else if (parent == &clk_h)
+               dvs = S3C2412_CLKDIVN_DVSEN;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       /* update this under irq lockdown, clkdivn is not protected
+        * by the clock system. */
+
+       local_irq_save(flags);
+
+       clkdiv  = __raw_readl(S3C2410_CLKDIVN);
+       clkdiv &= ~S3C2412_CLKDIVN_DVSEN;
+       clkdiv |= dvs;
+       __raw_writel(clkdiv, S3C2410_CLKDIVN);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static struct clk clk_armclk = {
+       .name           = "armclk",
+       .parent         = &clk_msysclk,
+       .ops            = &(struct clk_ops) {
+               .set_parent     = s3c2412_setparent_armclk,
+       },
+};
+
+/* these next clocks have an divider immediately after them,
+ * so we can register them with their divider and leave out the
+ * intermediate clock stage
+*/
+static unsigned long s3c2412_roundrate_clksrc(struct clk *clk,
+                                             unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       int div;
+
+       if (rate > parent_rate)
+               return parent_rate;
+
+       /* note, we remove the +/- 1 calculations as they cancel out */
+
+       div = (rate / parent_rate);
+
+       if (div < 1)
+               div = 1;
+       else if (div > 16)
+               div = 16;
+
+       return parent_rate / div;
+}
+
+static int s3c2412_setparent_uart(struct clk *clk, struct clk *parent)
+{
+       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+       if (parent == &clk_erefclk)
+               clksrc &= ~S3C2412_CLKSRC_UARTCLK_MPLL;
+       else if (parent == &clk_mpll)
+               clksrc |= S3C2412_CLKSRC_UARTCLK_MPLL;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       __raw_writel(clksrc, S3C2412_CLKSRC);
+       return 0;
+}
+
+static unsigned long s3c2412_getrate_uart(struct clk *clk)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
+
+       div &= S3C2412_CLKDIVN_UARTDIV_MASK;
+       div >>= S3C2412_CLKDIVN_UARTDIV_SHIFT;
+
+       return parent_rate / (div + 1);
+}
+
+static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
+
+       rate = s3c2412_roundrate_clksrc(clk, rate);
+
+       clkdivn &= ~S3C2412_CLKDIVN_UARTDIV_MASK;
+       clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_UARTDIV_SHIFT;
+
+       __raw_writel(clkdivn, S3C2410_CLKDIVN);
+       return 0;
+}
+
+static struct clk clk_uart = {
+       .name           = "uartclk",
+       .ops            = &(struct clk_ops) {
+               .get_rate       = s3c2412_getrate_uart,
+               .set_rate       = s3c2412_setrate_uart,
+               .set_parent     = s3c2412_setparent_uart,
+               .round_rate     = s3c2412_roundrate_clksrc,
+       },
+};
+
+static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent)
+{
+       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+       if (parent == &clk_erefclk)
+               clksrc &= ~S3C2412_CLKSRC_I2SCLK_MPLL;
+       else if (parent == &clk_mpll)
+               clksrc |= S3C2412_CLKSRC_I2SCLK_MPLL;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       __raw_writel(clksrc, S3C2412_CLKSRC);
+       return 0;
+}
+
+static unsigned long s3c2412_getrate_i2s(struct clk *clk)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
+
+       div &= S3C2412_CLKDIVN_I2SDIV_MASK;
+       div >>= S3C2412_CLKDIVN_I2SDIV_SHIFT;
+
+       return parent_rate / (div + 1);
+}
+
+static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
+
+       rate = s3c2412_roundrate_clksrc(clk, rate);
+
+       clkdivn &= ~S3C2412_CLKDIVN_I2SDIV_MASK;
+       clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_I2SDIV_SHIFT;
+
+       __raw_writel(clkdivn, S3C2410_CLKDIVN);
+       return 0;
+}
+
+static struct clk clk_i2s = {
+       .name           = "i2sclk",
+       .ops            = &(struct clk_ops) {
+               .get_rate       = s3c2412_getrate_i2s,
+               .set_rate       = s3c2412_setrate_i2s,
+               .set_parent     = s3c2412_setparent_i2s,
+               .round_rate     = s3c2412_roundrate_clksrc,
+       },
+};
+
+static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent)
+{
+       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+
+       if (parent == &clk_usysclk)
+               clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK;
+       else if (parent == &clk_h)
+               clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       __raw_writel(clksrc, S3C2412_CLKSRC);
+       return 0;
+}
+static unsigned long s3c2412_getrate_cam(struct clk *clk)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long div = __raw_readl(S3C2410_CLKDIVN);
+
+       div &= S3C2412_CLKDIVN_CAMDIV_MASK;
+       div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT;
+
+       return parent_rate / (div + 1);
+}
+
+static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
+
+       rate = s3c2412_roundrate_clksrc(clk, rate);
+
+       clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK;
+       clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT;
+
+       __raw_writel(clkdivn, S3C2410_CLKDIVN);
+       return 0;
+}
+
+static struct clk clk_cam = {
+       .name           = "camif-upll", /* same as 2440 name */
+       .ops            = &(struct clk_ops) {
+               .get_rate       = s3c2412_getrate_cam,
+               .set_rate       = s3c2412_setrate_cam,
+               .set_parent     = s3c2412_setparent_cam,
+               .round_rate     = s3c2412_roundrate_clksrc,
+       },
+};
+
+/* standard clock definitions */
+
+static struct clk init_clocks_disable[] = {
+       {
+               .name           = "nand",
+               .parent         = &clk_h,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_NAND,
+       }, {
+               .name           = "sdi",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_SDI,
+       }, {
+               .name           = "adc",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_ADC,
+       }, {
+               .name           = "i2c",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_IIC,
+       }, {
+               .name           = "iis",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_IIS,
+       }, {
+               .name           = "spi",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_SPI,
+       }
+};
+
+static struct clk init_clocks[] = {
+       {
+               .name           = "dma",
+               .parent         = &clk_h,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_DMA0,
+       }, {
+               .name           = "dma",
+               .parent         = &clk_h,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_DMA1,
+       }, {
+               .name           = "dma",
+               .parent         = &clk_h,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_DMA2,
+       }, {
+               .name           = "dma",
+               .parent         = &clk_h,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_DMA3,
+       }, {
+               .name           = "lcd",
+               .parent         = &clk_h,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_LCDC,
+       }, {
+               .name           = "gpio",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_GPIO,
+       }, {
+               .name           = "usb-host",
+               .parent         = &clk_h,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_USBH,
+       }, {
+               .name           = "usb-device",
+               .parent         = &clk_h,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_USBD,
+       }, {
+               .name           = "timers",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_PWMT,
+       }, {
+               .name           = "uart",
+               .devname        = "s3c2412-uart.0",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_UART0,
+       }, {
+               .name           = "uart",
+               .devname        = "s3c2412-uart.1",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_UART1,
+       }, {
+               .name           = "uart",
+               .devname        = "s3c2412-uart.2",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_UART2,
+       }, {
+               .name           = "rtc",
+               .parent         = &clk_p,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_RTC,
+       }, {
+               .name           = "watchdog",
+               .parent         = &clk_p,
+               .ctrlbit        = 0,
+       }, {
+               .name           = "usb-bus-gadget",
+               .parent         = &clk_usb_bus,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_USB_DEV48,
+       }, {
+               .name           = "usb-bus-host",
+               .parent         = &clk_usb_bus,
+               .enable         = s3c2412_clkcon_enable,
+               .ctrlbit        = S3C2412_CLKCON_USB_HOST48,
+       }
+};
+
+/* clocks to add where we need to check their parentage */
+
+struct clk_init {
+       struct clk      *clk;
+       unsigned int     bit;
+       struct clk      *src_0;
+       struct clk      *src_1;
+};
+
+static struct clk_init clks_src[] __initdata = {
+       {
+               .clk    = &clk_usysclk,
+               .bit    = S3C2412_CLKSRC_USBCLK_HCLK,
+               .src_0  = &clk_urefclk,
+               .src_1  = &clk_upll,
+       }, {
+               .clk    = &clk_i2s,
+               .bit    = S3C2412_CLKSRC_I2SCLK_MPLL,
+               .src_0  = &clk_erefclk,
+               .src_1  = &clk_mpll,
+       }, {
+               .clk    = &clk_cam,
+               .bit    = S3C2412_CLKSRC_CAMCLK_HCLK,
+               .src_0  = &clk_usysclk,
+               .src_1  = &clk_h,
+       }, {
+               .clk    = &clk_msysclk,
+               .bit    = S3C2412_CLKSRC_MSYSCLK_MPLL,
+               .src_0  = &clk_mdivclk,
+               .src_1  = &clk_mpll,
+       }, {
+               .clk    = &clk_uart,
+               .bit    = S3C2412_CLKSRC_UARTCLK_MPLL,
+               .src_0  = &clk_erefclk,
+               .src_1  = &clk_mpll,
+       }, {
+               .clk    = &clk_usbsrc,
+               .bit    = S3C2412_CLKSRC_USBCLK_HCLK,
+               .src_0  = &clk_usysclk,
+               .src_1  = &clk_h,
+       /* here we assume  OM[4] select xtal */
+       }, {
+               .clk    = &clk_erefclk,
+               .bit    = S3C2412_CLKSRC_EREFCLK_EXTCLK,
+               .src_0  = &clk_xtal,
+               .src_1  = &clk_ext,
+       }, {
+               .clk    = &clk_urefclk,
+               .bit    = S3C2412_CLKSRC_UREFCLK_EXTCLK,
+               .src_0  = &clk_xtal,
+               .src_1  = &clk_ext,
+       },
+};
+
+/* s3c2412_clk_initparents
+ *
+ * Initialise the parents for the clocks that we get at start-time
+*/
+
+static void __init s3c2412_clk_initparents(void)
+{
+       unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
+       struct clk_init *cip = clks_src;
+       struct clk *src;
+       int ptr;
+       int ret;
+
+       for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) {
+               ret = s3c24xx_register_clock(cip->clk);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              cip->clk->name, ret);
+               }
+
+               src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0;
+
+               printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name);
+               clk_set_parent(cip->clk, src);
+       }
+}
+
+/* clocks to add straight away */
+
+static struct clk *clks[] __initdata = {
+       &clk_ext,
+       &clk_usb_bus,
+       &clk_mrefclk,
+       &clk_armclk,
+};
+
+static struct clk_lookup s3c2412_clk_lookup[] = {
+       CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
+       CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
+       CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_usysclk),
+};
+
+int __init s3c2412_baseclk_add(void)
+{
+       unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
+       unsigned int dvs;
+       struct clk *clkp;
+       int ret;
+       int ptr;
+
+       clk_upll.enable = s3c2412_upll_enable;
+       clk_usb_bus.parent = &clk_usbsrc;
+       clk_usb_bus.rate = 0x0;
+
+       clk_f.parent = &clk_msysclk;
+
+       s3c2412_clk_initparents();
+
+       for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
+               clkp = clks[ptr];
+
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+       }
+
+       /* set the dvs state according to what we got at boot time */
+
+       dvs = __raw_readl(S3C2410_CLKDIVN) & S3C2412_CLKDIVN_DVSEN;
+
+       if (dvs)
+               clk_armclk.parent = &clk_h;
+
+       printk(KERN_INFO "S3C2412: DVS is %s\n", dvs ? "on" : "off");
+
+       /* ensure usb bus clock is within correct rate of 48MHz */
+
+       if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) {
+               printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n");
+
+               /* for the moment, let's use the UPLL, and see if we can
+                * get 48MHz */
+
+               clk_set_parent(&clk_usysclk, &clk_upll);
+               clk_set_parent(&clk_usbsrc, &clk_usysclk);
+               clk_set_rate(&clk_usbsrc, 48*1000*1000);
+       }
+
+       printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
+              (__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on",
+              print_mhz(clk_get_rate(&clk_upll)),
+              print_mhz(clk_get_rate(&clk_usb_bus)));
+
+       /* register clocks from clock array */
+
+       clkp = init_clocks;
+       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
+               /* ensure that we note the clock state */
+
+               clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
+
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+       }
+
+       /* We must be careful disabling the clocks we are not intending to
+        * be using at boot time, as subsystems such as the LCD which do
+        * their own DMA requests to the bus can cause the system to lockup
+        * if they where in the middle of requesting bus access.
+        *
+        * Disabling the LCD clock if the LCD is active is very dangerous,
+        * and therefore the bootloader should be careful to not enable
+        * the LCD clock if it is not needed.
+       */
+
+       /* install (and disable) the clocks we do not need immediately */
+
+       clkp = init_clocks_disable;
+       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+
+               s3c2412_clkcon_enable(clkp, 0);
+       }
+
+       clkdev_add_table(s3c2412_clk_lookup, ARRAY_SIZE(s3c2412_clk_lookup));
+       s3c_pwmclk_init();
+       return 0;
+}
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2416.c b/arch/arm/mach-s3c24xx/clock-s3c2416.c
new file mode 100644 (file)
index 0000000..dbc9ab4
--- /dev/null
@@ -0,0 +1,172 @@
+/* linux/arch/arm/mach-s3c2416/clock.c
+ *
+ * Copyright (c) 2010 Simtec Electronics
+ * Copyright (c) 2010 Ben Dooks <ben-linux@fluff.org>
+ *
+ * S3C2416 Clock control support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/clk.h>
+
+#include <plat/s3c2416.h>
+#include <plat/clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/cpu.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/pll.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/regs-clock.h>
+#include <mach/regs-s3c2443-clock.h>
+
+/* armdiv
+ *
+ * this clock is sourced from msysclk and can have a number of
+ * divider values applied to it to then be fed into armclk.
+ * The real clock definition is done in s3c2443-clock.c,
+ * only the armdiv divisor table must be defined here.
+*/
+
+static unsigned int armdiv[8] = {
+       [0] = 1,
+       [1] = 2,
+       [2] = 3,
+       [3] = 4,
+       [5] = 6,
+       [7] = 8,
+};
+
+static struct clksrc_clk hsspi_eplldiv = {
+       .clk = {
+               .name   = "hsspi-eplldiv",
+               .parent = &clk_esysclk.clk,
+               .ctrlbit = (1 << 14),
+               .enable = s3c2443_clkcon_enable_s,
+       },
+       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 24 },
+};
+
+static struct clk *hsspi_sources[] = {
+       [0] = &hsspi_eplldiv.clk,
+       [1] = NULL, /* to fix */
+};
+
+static struct clksrc_clk hsspi_mux = {
+       .clk    = {
+               .name   = "hsspi-if",
+       },
+       .sources = &(struct clksrc_sources) {
+               .sources = hsspi_sources,
+               .nr_sources = ARRAY_SIZE(hsspi_sources),
+       },
+       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 18 },
+};
+
+static struct clksrc_clk hsmmc_div[] = {
+       [0] = {
+               .clk = {
+                       .name   = "hsmmc-div",
+                       .devname        = "s3c-sdhci.0",
+                       .parent = &clk_esysclk.clk,
+               },
+               .reg_div = { .reg = S3C2416_CLKDIV2, .size = 2, .shift = 6 },
+       },
+       [1] = {
+               .clk = {
+                       .name   = "hsmmc-div",
+                       .devname        = "s3c-sdhci.1",
+                       .parent = &clk_esysclk.clk,
+               },
+               .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
+       },
+};
+
+static struct clksrc_clk hsmmc_mux0 = {
+       .clk    = {
+               .name           = "hsmmc-if",
+               .devname        = "s3c-sdhci.0",
+               .ctrlbit        = (1 << 6),
+               .enable         = s3c2443_clkcon_enable_s,
+       },
+       .sources        = &(struct clksrc_sources) {
+               .nr_sources     = 2,
+               .sources        = (struct clk * []) {
+                       [0]     = &hsmmc_div[0].clk,
+                       [1]     = NULL, /* to fix */
+               },
+       },
+       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 16 },
+};
+
+static struct clksrc_clk hsmmc_mux1 = {
+       .clk    = {
+               .name           = "hsmmc-if",
+               .devname        = "s3c-sdhci.1",
+               .ctrlbit        = (1 << 12),
+               .enable         = s3c2443_clkcon_enable_s,
+       },
+       .sources        = &(struct clksrc_sources) {
+               .nr_sources     = 2,
+               .sources        = (struct clk * []) {
+                       [0]     = &hsmmc_div[1].clk,
+                       [1]     = NULL, /* to fix */
+               },
+       },
+       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 17 },
+};
+
+static struct clk hsmmc0_clk = {
+       .name           = "hsmmc",
+       .devname        = "s3c-sdhci.0",
+       .parent         = &clk_h,
+       .enable         = s3c2443_clkcon_enable_h,
+       .ctrlbit        = S3C2416_HCLKCON_HSMMC0,
+};
+
+static struct clksrc_clk *clksrcs[] __initdata = {
+       &hsspi_eplldiv,
+       &hsspi_mux,
+       &hsmmc_div[0],
+       &hsmmc_div[1],
+       &hsmmc_mux0,
+       &hsmmc_mux1,
+};
+
+static struct clk_lookup s3c2416_clk_lookup[] = {
+       CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk),
+       CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk),
+       CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk),
+};
+
+void __init s3c2416_init_clocks(int xtal)
+{
+       u32 epllcon = __raw_readl(S3C2443_EPLLCON);
+       u32 epllcon1 = __raw_readl(S3C2443_EPLLCON+4);
+       int ptr;
+
+       /* s3c2416 EPLL compatible with s3c64xx */
+       clk_epll.rate = s3c_get_pll6553x(xtal, epllcon, epllcon1);
+
+       clk_epll.parent = &clk_epllref.clk;
+
+       s3c2443_common_init_clocks(xtal, s3c2416_get_pll,
+                                  armdiv, ARRAY_SIZE(armdiv),
+                                  S3C2416_CLKDIV0_ARMDIV_MASK);
+
+       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+               s3c_register_clksrc(clksrcs[ptr], 1);
+
+       s3c24xx_register_clock(&hsmmc0_clk);
+       clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup));
+
+       s3c_pwmclk_init();
+
+}
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2440.c b/arch/arm/mach-s3c24xx/clock-s3c2440.c
new file mode 100644 (file)
index 0000000..414364e
--- /dev/null
@@ -0,0 +1,194 @@
+/* linux/arch/arm/mach-s3c2440/clock.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2440 Clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/serial_core.h>
+
+#include <mach/hardware.h>
+#include <linux/atomic.h>
+#include <asm/irq.h>
+
+#include <mach/regs-clock.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/regs-serial.h>
+
+/* S3C2440 extended clock support */
+
+static unsigned long s3c2440_camif_upll_round(struct clk *clk,
+                                             unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       int div;
+
+       if (rate > parent_rate)
+               return parent_rate;
+
+       /* note, we remove the +/- 1 calculations for the divisor */
+
+       div = (parent_rate / rate) / 2;
+
+       if (div < 1)
+               div = 1;
+       else if (div > 16)
+               div = 16;
+
+       return parent_rate / (div * 2);
+}
+
+static int s3c2440_camif_upll_setrate(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long camdivn =  __raw_readl(S3C2440_CAMDIVN);
+
+       rate = s3c2440_camif_upll_round(clk, rate);
+
+       camdivn &= ~(S3C2440_CAMDIVN_CAMCLK_SEL | S3C2440_CAMDIVN_CAMCLK_MASK);
+
+       if (rate != parent_rate) {
+               camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
+               camdivn |= (((parent_rate / rate) / 2) - 1);
+       }
+
+       __raw_writel(camdivn, S3C2440_CAMDIVN);
+
+       return 0;
+}
+
+/* Extra S3C2440 clocks */
+
+static struct clk s3c2440_clk_cam = {
+       .name           = "camif",
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2440_CLKCON_CAMERA,
+};
+
+static struct clk s3c2440_clk_cam_upll = {
+       .name           = "camif-upll",
+       .ops            = &(struct clk_ops) {
+               .set_rate       = s3c2440_camif_upll_setrate,
+               .round_rate     = s3c2440_camif_upll_round,
+       },
+};
+
+static struct clk s3c2440_clk_ac97 = {
+       .name           = "ac97",
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2440_CLKCON_CAMERA,
+};
+
+static unsigned long  s3c2440_fclk_n_getrate(struct clk *clk)
+{
+       unsigned long ucon0, ucon1, ucon2, divisor;
+
+       /* the fun of calculating the uart divisors on the s3c2440 */
+       ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
+       ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
+       ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
+
+       ucon0 &= S3C2440_UCON0_DIVMASK;
+       ucon1 &= S3C2440_UCON1_DIVMASK;
+       ucon2 &= S3C2440_UCON2_DIVMASK;
+
+       if (ucon0 != 0)
+               divisor = (ucon0 >> S3C2440_UCON_DIVSHIFT) + 6;
+       else if (ucon1 != 0)
+               divisor = (ucon1 >> S3C2440_UCON_DIVSHIFT) + 21;
+       else if (ucon2 != 0)
+               divisor = (ucon2 >> S3C2440_UCON_DIVSHIFT) + 36;
+       else
+               /* manual calims 44, seems to be 9 */
+               divisor = 9;
+
+       return clk_get_rate(clk->parent) / divisor;
+}
+
+static struct clk s3c2440_clk_fclk_n = {
+       .name           = "fclk_n",
+       .parent         = &clk_f,
+       .ops            = &(struct clk_ops) {
+               .get_rate       = s3c2440_fclk_n_getrate,
+       },
+};
+
+static struct clk_lookup s3c2440_clk_lookup[] = {
+       CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
+       CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
+       CLKDEV_INIT(NULL, "clk_uart_baud3", &s3c2440_clk_fclk_n),
+};
+
+static int s3c2440_clk_add(struct device *dev, struct subsys_interface *sif)
+{
+       struct clk *clock_upll;
+       struct clk *clock_h;
+       struct clk *clock_p;
+
+       clock_p = clk_get(NULL, "pclk");
+       clock_h = clk_get(NULL, "hclk");
+       clock_upll = clk_get(NULL, "upll");
+
+       if (IS_ERR(clock_p) || IS_ERR(clock_h) || IS_ERR(clock_upll)) {
+               printk(KERN_ERR "S3C2440: Failed to get parent clocks\n");
+               return -EINVAL;
+       }
+
+       s3c2440_clk_cam.parent = clock_h;
+       s3c2440_clk_ac97.parent = clock_p;
+       s3c2440_clk_cam_upll.parent = clock_upll;
+       s3c24xx_register_clock(&s3c2440_clk_fclk_n);
+
+       s3c24xx_register_clock(&s3c2440_clk_ac97);
+       s3c24xx_register_clock(&s3c2440_clk_cam);
+       s3c24xx_register_clock(&s3c2440_clk_cam_upll);
+       clkdev_add_table(s3c2440_clk_lookup, ARRAY_SIZE(s3c2440_clk_lookup));
+
+       clk_disable(&s3c2440_clk_ac97);
+       clk_disable(&s3c2440_clk_cam);
+
+       return 0;
+}
+
+static struct subsys_interface s3c2440_clk_interface = {
+       .name           = "s3c2440_clk",
+       .subsys         = &s3c2440_subsys,
+       .add_dev        = s3c2440_clk_add,
+};
+
+static __init int s3c24xx_clk_init(void)
+{
+       return subsys_interface_register(&s3c2440_clk_interface);
+}
+
+arch_initcall(s3c24xx_clk_init);
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2443.c b/arch/arm/mach-s3c24xx/clock-s3c2443.c
new file mode 100644 (file)
index 0000000..efb3ac3
--- /dev/null
@@ -0,0 +1,215 @@
+/* linux/arch/arm/mach-s3c2443/clock.c
+ *
+ * Copyright (c) 2007, 2010 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2443 Clock control support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/init.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+
+#include <mach/regs-s3c2443-clock.h>
+
+#include <plat/cpu-freq.h>
+
+#include <plat/s3c2443.h>
+#include <plat/clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/cpu.h>
+
+/* We currently have to assume that the system is running
+ * from the XTPll input, and that all ***REFCLKs are being
+ * fed from it, as we cannot read the state of OM[4] from
+ * software.
+ *
+ * It would be possible for each board initialisation to
+ * set the correct muxing at initialisation
+*/
+
+/* clock selections */
+
+/* armdiv
+ *
+ * this clock is sourced from msysclk and can have a number of
+ * divider values applied to it to then be fed into armclk.
+ * The real clock definition is done in s3c2443-clock.c,
+ * only the armdiv divisor table must be defined here.
+*/
+
+static unsigned int armdiv[16] = {
+       [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 1,
+       [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 2,
+       [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 3,
+       [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 4,
+       [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 6,
+       [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 8,
+       [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 12,
+       [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 16,
+};
+
+/* hsspi
+ *
+ * high-speed spi clock, sourced from esysclk
+*/
+
+static struct clksrc_clk clk_hsspi = {
+       .clk    = {
+               .name           = "hsspi-if",
+               .parent         = &clk_esysclk.clk,
+               .ctrlbit        = S3C2443_SCLKCON_HSSPICLK,
+               .enable         = s3c2443_clkcon_enable_s,
+       },
+       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
+};
+
+
+/* clk_hsmcc_div
+ *
+ * this clock is sourced from epll, and is fed through a divider,
+ * to a mux controlled by sclkcon where either it or a extclk can
+ * be fed to the hsmmc block
+*/
+
+static struct clksrc_clk clk_hsmmc_div = {
+       .clk    = {
+               .name           = "hsmmc-div",
+               .devname        = "s3c-sdhci.1",
+               .parent         = &clk_esysclk.clk,
+       },
+       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
+};
+
+static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
+{
+       unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
+
+       clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
+                   S3C2443_SCLKCON_HSMMCCLK_EPLL);
+
+       if (parent == &clk_epll)
+               clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
+       else if (parent == &clk_ext)
+               clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
+       else
+               return -EINVAL;
+
+       if (clk->usage > 0) {
+               __raw_writel(clksrc, S3C2443_SCLKCON);
+       }
+
+       clk->parent = parent;
+       return 0;
+}
+
+static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
+{
+       return s3c2443_setparent_hsmmc(clk, clk->parent);
+}
+
+static struct clk clk_hsmmc = {
+       .name           = "hsmmc-if",
+       .devname        = "s3c-sdhci.1",
+       .parent         = &clk_hsmmc_div.clk,
+       .enable         = s3c2443_enable_hsmmc,
+       .ops            = &(struct clk_ops) {
+               .set_parent     = s3c2443_setparent_hsmmc,
+       },
+};
+
+/* standard clock definitions */
+
+static struct clk init_clocks_off[] = {
+       {
+               .name           = "sdi",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_SDI,
+       }, {
+               .name           = "spi",
+               .devname        = "s3c2410-spi.0",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_SPI0,
+       }, {
+               .name           = "spi",
+               .devname        = "s3c2410-spi.1",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_SPI1,
+       }
+};
+
+/* clocks to add straight away */
+
+static struct clksrc_clk *clksrcs[] __initdata = {
+       &clk_hsspi,
+       &clk_hsmmc_div,
+};
+
+static struct clk *clks[] __initdata = {
+       &clk_hsmmc,
+};
+
+void __init s3c2443_init_clocks(int xtal)
+{
+       unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
+       int ptr;
+
+       clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
+       clk_epll.parent = &clk_epllref.clk;
+
+       s3c2443_common_init_clocks(xtal, s3c2443_get_mpll,
+                                  armdiv, ARRAY_SIZE(armdiv),
+                                  S3C2443_CLKDIV0_ARMDIV_MASK);
+
+       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
+
+       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+               s3c_register_clksrc(clksrcs[ptr], 1);
+
+       /* We must be careful disabling the clocks we are not intending to
+        * be using at boot time, as subsystems such as the LCD which do
+        * their own DMA requests to the bus can cause the system to lockup
+        * if they where in the middle of requesting bus access.
+        *
+        * Disabling the LCD clock if the LCD is active is very dangerous,
+        * and therefore the bootloader should be careful to not enable
+        * the LCD clock if it is not needed.
+       */
+
+       /* install (and disable) the clocks we do not need immediately */
+
+       s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+       s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+
+       s3c_pwmclk_init();
+}
diff --git a/arch/arm/mach-s3c24xx/clock-s3c244x.c b/arch/arm/mach-s3c24xx/clock-s3c244x.c
new file mode 100644 (file)
index 0000000..6d9b688
--- /dev/null
@@ -0,0 +1,141 @@
+/* linux/arch/arm/plat-s3c24xx/s3c24xx-clock.c
+ *
+ * Copyright (c) 2004-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2440/S3C2442 Common clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <linux/atomic.h>
+#include <asm/irq.h>
+
+#include <mach/regs-clock.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+static int s3c2440_setparent_armclk(struct clk *clk, struct clk *parent)
+{
+       unsigned long camdivn;
+       unsigned long dvs;
+
+       if (parent == &clk_f)
+               dvs = 0;
+       else if (parent == &clk_h)
+               dvs = S3C2440_CAMDIVN_DVSEN;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       camdivn  = __raw_readl(S3C2440_CAMDIVN);
+       camdivn &= ~S3C2440_CAMDIVN_DVSEN;
+       camdivn |= dvs;
+       __raw_writel(camdivn, S3C2440_CAMDIVN);
+
+       return 0;
+}
+
+static struct clk clk_arm = {
+       .name           = "armclk",
+       .id             = -1,
+       .ops            = &(struct clk_ops) {
+               .set_parent     = s3c2440_setparent_armclk,
+       },
+};
+
+static int s3c244x_clk_add(struct device *dev, struct subsys_interface *sif)
+{
+       unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
+       unsigned long clkdivn;
+       struct clk *clock_upll;
+       int ret;
+
+       printk("S3C244X: Clock Support, DVS %s\n",
+              (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
+
+       clk_arm.parent = (camdivn & S3C2440_CAMDIVN_DVSEN) ? &clk_h : &clk_f;
+
+       ret = s3c24xx_register_clock(&clk_arm);
+       if (ret < 0) {
+               printk(KERN_ERR "S3C24XX: Failed to add armclk (%d)\n", ret);
+               return ret;
+       }
+
+       clock_upll = clk_get(NULL, "upll");
+       if (IS_ERR(clock_upll)) {
+               printk(KERN_ERR "S3C244X: Failed to get upll clock\n");
+               return -ENOENT;
+       }
+
+       /* check rate of UPLL, and if it is near 96MHz, then change
+        * to using half the UPLL rate for the system */
+
+       if (clk_get_rate(clock_upll) > (94 * MHZ)) {
+               clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
+
+               spin_lock(&clocks_lock);
+
+               clkdivn = __raw_readl(S3C2410_CLKDIVN);
+               clkdivn |= S3C2440_CLKDIVN_UCLK;
+               __raw_writel(clkdivn, S3C2410_CLKDIVN);
+
+               spin_unlock(&clocks_lock);
+       }
+
+       return 0;
+}
+
+static struct subsys_interface s3c2440_clk_interface = {
+       .name           = "s3c2440_clk",
+       .subsys         = &s3c2440_subsys,
+       .add_dev        = s3c244x_clk_add,
+};
+
+static int s3c2440_clk_init(void)
+{
+       return subsys_interface_register(&s3c2440_clk_interface);
+}
+
+arch_initcall(s3c2440_clk_init);
+
+static struct subsys_interface s3c2442_clk_interface = {
+       .name           = "s3c2442_clk",
+       .subsys         = &s3c2442_subsys,
+       .add_dev        = s3c244x_clk_add,
+};
+
+static int s3c2442_clk_init(void)
+{
+       return subsys_interface_register(&s3c2442_clk_interface);
+}
+
+arch_initcall(s3c2442_clk_init);
diff --git a/arch/arm/mach-s3c24xx/common-s3c2443.c b/arch/arm/mach-s3c24xx/common-s3c2443.c
new file mode 100644 (file)
index 0000000..4604315
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * Common code for SoCs starting with the S3C2443
+ *
+ * Copyright (c) 2007, 2010 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/regs-s3c2443-clock.h>
+
+#include <plat/clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/cpu.h>
+
+#include <plat/cpu-freq.h>
+
+
+static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
+{
+       u32 ctrlbit = clk->ctrlbit;
+       u32 con = __raw_readl(reg);
+
+       if (enable)
+               con |= ctrlbit;
+       else
+               con &= ~ctrlbit;
+
+       __raw_writel(con, reg);
+       return 0;
+}
+
+int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
+{
+       return s3c2443_gate(S3C2443_HCLKCON, clk, enable);
+}
+
+int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
+{
+       return s3c2443_gate(S3C2443_PCLKCON, clk, enable);
+}
+
+int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
+{
+       return s3c2443_gate(S3C2443_SCLKCON, clk, enable);
+}
+
+/* mpllref is a direct descendant of clk_xtal by default, but it is not
+ * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as
+ * such directly equating the two source clocks is impossible.
+ */
+static struct clk clk_mpllref = {
+       .name           = "mpllref",
+       .parent         = &clk_xtal,
+};
+
+static struct clk *clk_epllref_sources[] = {
+       [0] = &clk_mpllref,
+       [1] = &clk_mpllref,
+       [2] = &clk_xtal,
+       [3] = &clk_ext,
+};
+
+struct clksrc_clk clk_epllref = {
+       .clk    = {
+               .name           = "epllref",
+       },
+       .sources = &(struct clksrc_sources) {
+               .sources = clk_epllref_sources,
+               .nr_sources = ARRAY_SIZE(clk_epllref_sources),
+       },
+       .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
+};
+
+/* esysclk
+ *
+ * this is sourced from either the EPLL or the EPLLref clock
+*/
+
+static struct clk *clk_sysclk_sources[] = {
+       [0] = &clk_epllref.clk,
+       [1] = &clk_epll,
+};
+
+struct clksrc_clk clk_esysclk = {
+       .clk    = {
+               .name           = "esysclk",
+               .parent         = &clk_epll,
+       },
+       .sources = &(struct clksrc_sources) {
+               .sources = clk_sysclk_sources,
+               .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
+       },
+       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
+};
+
+static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long div = __raw_readl(S3C2443_CLKDIV0);
+
+       div  &= S3C2443_CLKDIV0_EXTDIV_MASK;
+       div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1);       /* x2 */
+
+       return parent_rate / (div + 1);
+}
+
+static struct clk clk_mdivclk = {
+       .name           = "mdivclk",
+       .parent         = &clk_mpllref,
+       .ops            = &(struct clk_ops) {
+               .get_rate       = s3c2443_getrate_mdivclk,
+       },
+};
+
+static struct clk *clk_msysclk_sources[] = {
+       [0] = &clk_mpllref,
+       [1] = &clk_mpll,
+       [2] = &clk_mdivclk,
+       [3] = &clk_mpllref,
+};
+
+struct clksrc_clk clk_msysclk = {
+       .clk    = {
+               .name           = "msysclk",
+               .parent         = &clk_xtal,
+       },
+       .sources = &(struct clksrc_sources) {
+               .sources = clk_msysclk_sources,
+               .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
+       },
+       .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
+};
+
+/* prediv
+ *
+ * this divides the msysclk down to pass to h/p/etc.
+ */
+
+static unsigned long s3c2443_prediv_getrate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+
+       clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
+       clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
+
+       return rate / (clkdiv0 + 1);
+}
+
+static struct clk clk_prediv = {
+       .name           = "prediv",
+       .parent         = &clk_msysclk.clk,
+       .ops            = &(struct clk_ops) {
+               .get_rate       = s3c2443_prediv_getrate,
+       },
+};
+
+/* hclk divider
+ *
+ * divides the prediv and provides the hclk.
+ */
+
+static unsigned long s3c2443_hclkdiv_getrate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+
+       clkdiv0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
+
+       return rate / (clkdiv0 + 1);
+}
+
+static struct clk_ops clk_h_ops = {
+       .get_rate       = s3c2443_hclkdiv_getrate,
+};
+
+/* pclk divider
+ *
+ * divides the hclk and provides the pclk.
+ */
+
+static unsigned long s3c2443_pclkdiv_getrate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+
+       clkdiv0 = ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 1 : 0);
+
+       return rate / (clkdiv0 + 1);
+}
+
+static struct clk_ops clk_p_ops = {
+       .get_rate       = s3c2443_pclkdiv_getrate,
+};
+
+/* armdiv
+ *
+ * this clock is sourced from msysclk and can have a number of
+ * divider values applied to it to then be fed into armclk.
+*/
+
+static unsigned int *armdiv;
+static int nr_armdiv;
+static int armdivmask;
+
+static unsigned long s3c2443_armclk_roundrate(struct clk *clk,
+                                             unsigned long rate)
+{
+       unsigned long parent = clk_get_rate(clk->parent);
+       unsigned long calc;
+       unsigned best = 256; /* bigger than any value */
+       unsigned div;
+       int ptr;
+
+       if (!nr_armdiv)
+               return -EINVAL;
+
+       for (ptr = 0; ptr < nr_armdiv; ptr++) {
+               div = armdiv[ptr];
+               if (div) {
+                       /* cpufreq provides 266mhz as 266666000 not 266666666 */
+                       calc = (parent / div / 1000) * 1000;
+                       if (calc <= rate && div < best)
+                               best = div;
+               }
+       }
+
+       return parent / best;
+}
+
+static unsigned long s3c2443_armclk_getrate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+       unsigned long clkcon0;
+       int val;
+
+       if (!nr_armdiv || !armdivmask)
+               return -EINVAL;
+
+       clkcon0 = __raw_readl(S3C2443_CLKDIV0);
+       clkcon0 &= armdivmask;
+       val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT;
+
+       return rate / armdiv[val];
+}
+
+static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent = clk_get_rate(clk->parent);
+       unsigned long calc;
+       unsigned div;
+       unsigned best = 256; /* bigger than any value */
+       int ptr;
+       int val = -1;
+
+       if (!nr_armdiv || !armdivmask)
+               return -EINVAL;
+
+       for (ptr = 0; ptr < nr_armdiv; ptr++) {
+               div = armdiv[ptr];
+               if (div) {
+                       /* cpufreq provides 266mhz as 266666000 not 266666666 */
+                       calc = (parent / div / 1000) * 1000;
+                       if (calc <= rate && div < best) {
+                               best = div;
+                               val = ptr;
+                       }
+               }
+       }
+
+       if (val >= 0) {
+               unsigned long clkcon0;
+
+               clkcon0 = __raw_readl(S3C2443_CLKDIV0);
+               clkcon0 &= ~armdivmask;
+               clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
+               __raw_writel(clkcon0, S3C2443_CLKDIV0);
+       }
+
+       return (val == -1) ? -EINVAL : 0;
+}
+
+static struct clk clk_armdiv = {
+       .name           = "armdiv",
+       .parent         = &clk_msysclk.clk,
+       .ops            = &(struct clk_ops) {
+               .round_rate = s3c2443_armclk_roundrate,
+               .get_rate = s3c2443_armclk_getrate,
+               .set_rate = s3c2443_armclk_setrate,
+       },
+};
+
+/* armclk
+ *
+ * this is the clock fed into the ARM core itself, from armdiv or from hclk.
+ */
+
+static struct clk *clk_arm_sources[] = {
+       [0] = &clk_armdiv,
+       [1] = &clk_h,
+};
+
+static struct clksrc_clk clk_arm = {
+       .clk    = {
+               .name           = "armclk",
+       },
+       .sources = &(struct clksrc_sources) {
+               .sources = clk_arm_sources,
+               .nr_sources = ARRAY_SIZE(clk_arm_sources),
+       },
+       .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
+};
+
+/* usbhost
+ *
+ * usb host bus-clock, usually 48MHz to provide USB bus clock timing
+*/
+
+static struct clksrc_clk clk_usb_bus_host = {
+       .clk    = {
+               .name           = "usb-bus-host-parent",
+               .parent         = &clk_esysclk.clk,
+               .ctrlbit        = S3C2443_SCLKCON_USBHOST,
+               .enable         = s3c2443_clkcon_enable_s,
+       },
+       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
+};
+
+/* common clksrc clocks */
+
+static struct clksrc_clk clksrc_clks[] = {
+       {
+               /* camera interface bus-clock, divided down from esysclk */
+               .clk    = {
+                       .name           = "camif-upll", /* same as 2440 name */
+                       .parent         = &clk_esysclk.clk,
+                       .ctrlbit        = S3C2443_SCLKCON_CAMCLK,
+                       .enable         = s3c2443_clkcon_enable_s,
+               },
+               .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
+       }, {
+               .clk    = {
+                       .name           = "display-if",
+                       .parent         = &clk_esysclk.clk,
+                       .ctrlbit        = S3C2443_SCLKCON_DISPCLK,
+                       .enable         = s3c2443_clkcon_enable_s,
+               },
+               .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
+       },
+};
+
+static struct clksrc_clk clk_esys_uart = {
+       /* ART baud-rate clock sourced from esysclk via a divisor */
+       .clk    = {
+               .name           = "uartclk",
+               .parent         = &clk_esysclk.clk,
+       },
+       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
+};
+
+static struct clk clk_i2s_ext = {
+       .name           = "i2s-ext",
+};
+
+/* i2s_eplldiv
+ *
+ * This clock is the output from the I2S divisor of ESYSCLK, and is separate
+ * from the mux that comes after it (cannot merge into one single clock)
+*/
+
+static struct clksrc_clk clk_i2s_eplldiv = {
+       .clk    = {
+               .name           = "i2s-eplldiv",
+               .parent         = &clk_esysclk.clk,
+       },
+       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
+};
+
+/* i2s-ref
+ *
+ * i2s bus reference clock, selectable from external, esysclk or epllref
+ *
+ * Note, this used to be two clocks, but was compressed into one.
+*/
+
+static struct clk *clk_i2s_srclist[] = {
+       [0] = &clk_i2s_eplldiv.clk,
+       [1] = &clk_i2s_ext,
+       [2] = &clk_epllref.clk,
+       [3] = &clk_epllref.clk,
+};
+
+static struct clksrc_clk clk_i2s = {
+       .clk    = {
+               .name           = "i2s-if",
+               .ctrlbit        = S3C2443_SCLKCON_I2SCLK,
+               .enable         = s3c2443_clkcon_enable_s,
+
+       },
+       .sources = &(struct clksrc_sources) {
+               .sources = clk_i2s_srclist,
+               .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
+       },
+       .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
+};
+
+static struct clk init_clocks_off[] = {
+       {
+               .name           = "iis",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_IIS,
+       }, {
+               .name           = "hsspi",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_HSSPI,
+       }, {
+               .name           = "adc",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_ADC,
+       }, {
+               .name           = "i2c",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_IIC,
+       }
+};
+
+static struct clk init_clocks[] = {
+       {
+               .name           = "dma",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_DMA0,
+       }, {
+               .name           = "dma",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_DMA1,
+       }, {
+               .name           = "dma",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_DMA2,
+       }, {
+               .name           = "dma",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_DMA3,
+       }, {
+               .name           = "dma",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_DMA4,
+       }, {
+               .name           = "dma",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_DMA5,
+       }, {
+               .name           = "gpio",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_GPIO,
+       }, {
+               .name           = "usb-host",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_USBH,
+       }, {
+               .name           = "usb-device",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_USBD,
+       }, {
+               .name           = "lcd",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_LCDC,
+
+       }, {
+               .name           = "timers",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_PWMT,
+       }, {
+               .name           = "cfc",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_CFC,
+       }, {
+               .name           = "ssmc",
+               .parent         = &clk_h,
+               .enable         = s3c2443_clkcon_enable_h,
+               .ctrlbit        = S3C2443_HCLKCON_SSMC,
+       }, {
+               .name           = "uart",
+               .devname        = "s3c2440-uart.0",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_UART0,
+       }, {
+               .name           = "uart",
+               .devname        = "s3c2440-uart.1",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_UART1,
+       }, {
+               .name           = "uart",
+               .devname        = "s3c2440-uart.2",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_UART2,
+       }, {
+               .name           = "uart",
+               .devname        = "s3c2440-uart.3",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_UART3,
+       }, {
+               .name           = "rtc",
+               .parent         = &clk_p,
+               .enable         = s3c2443_clkcon_enable_p,
+               .ctrlbit        = S3C2443_PCLKCON_RTC,
+       }, {
+               .name           = "watchdog",
+               .parent         = &clk_p,
+               .ctrlbit        = S3C2443_PCLKCON_WDT,
+       }, {
+               .name           = "ac97",
+               .parent         = &clk_p,
+               .ctrlbit        = S3C2443_PCLKCON_AC97,
+       }, {
+               .name           = "nand",
+               .parent         = &clk_h,
+       }, {
+               .name           = "usb-bus-host",
+               .parent         = &clk_usb_bus_host.clk,
+       }
+};
+
+static struct clk hsmmc1_clk = {
+       .name           = "hsmmc",
+       .devname        = "s3c-sdhci.1",
+       .parent         = &clk_h,
+       .enable         = s3c2443_clkcon_enable_h,
+       .ctrlbit        = S3C2443_HCLKCON_HSMMC,
+};
+
+/* EPLLCON compatible enough to get on/off information */
+
+void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll)
+{
+       unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
+       unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
+       struct clk *xtal_clk;
+       unsigned long xtal;
+       unsigned long pll;
+       int ptr;
+
+       xtal_clk = clk_get(NULL, "xtal");
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
+
+       pll = get_mpll(mpllcon, xtal);
+       clk_msysclk.clk.rate = pll;
+       clk_mpll.rate = pll;
+
+       printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
+              (mpllcon & S3C2443_PLLCON_OFF) ? "off" : "on",
+              print_mhz(pll), print_mhz(clk_get_rate(&clk_armdiv)),
+              print_mhz(clk_get_rate(&clk_h)),
+              print_mhz(clk_get_rate(&clk_p)));
+
+       for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++)
+               s3c_set_clksrc(&clksrc_clks[ptr], true);
+
+       /* ensure usb bus clock is within correct rate of 48MHz */
+
+       if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
+               printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
+               clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
+       }
+
+       printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
+              (epllcon & S3C2443_PLLCON_OFF) ? "off" : "on",
+              print_mhz(clk_get_rate(&clk_epll)),
+              print_mhz(clk_get_rate(&clk_usb_bus)));
+}
+
+static struct clk *clks[] __initdata = {
+       &clk_prediv,
+       &clk_mpllref,
+       &clk_mdivclk,
+       &clk_ext,
+       &clk_epll,
+       &clk_usb_bus,
+       &clk_armdiv,
+       &hsmmc1_clk,
+};
+
+static struct clksrc_clk *clksrcs[] __initdata = {
+       &clk_i2s_eplldiv,
+       &clk_i2s,
+       &clk_usb_bus_host,
+       &clk_epllref,
+       &clk_esysclk,
+       &clk_msysclk,
+       &clk_arm,
+};
+
+static struct clk_lookup s3c2443_clk_lookup[] = {
+       CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
+       CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
+       CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk),
+       CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk),
+};
+
+void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
+                                      unsigned int *divs, int nr_divs,
+                                      int divmask)
+{
+       int ptr;
+
+       armdiv = divs;
+       nr_armdiv = nr_divs;
+       armdivmask = divmask;
+
+       /* s3c2443 parents h clock from prediv */
+       clk_h.parent = &clk_prediv;
+       clk_h.ops = &clk_h_ops;
+
+       /* and p clock from h clock */
+       clk_p.parent = &clk_h;
+       clk_p.ops = &clk_p_ops;
+
+       clk_usb_bus.parent = &clk_usb_bus_host.clk;
+       clk_epll.parent = &clk_epllref.clk;
+
+       s3c24xx_register_baseclocks(xtal);
+       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
+
+       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+               s3c_register_clksrc(clksrcs[ptr], 1);
+
+       s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks));
+       s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
+
+       /* See s3c2443/etc notes on disabling clocks at init time */
+       s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+       s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+       clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup));
+
+       s3c2443_common_setup_clocks(get_mpll);
+}
diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c
new file mode 100644 (file)
index 0000000..084604b
--- /dev/null
@@ -0,0 +1,207 @@
+/* linux/arch/arm/plat-s3c24xx/common-smdk.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Common code for SMDK2410 and SMDK2440 boards
+ *
+ * http://www.fluff.org/ben/smdk2440/
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/leds-gpio.h>
+
+#include <plat/nand.h>
+
+#include <plat/common-smdk.h>
+#include <plat/gpio-cfg.h>
+#include <plat/devs.h>
+#include <plat/pm.h>
+
+/* LED devices */
+
+static struct s3c24xx_led_platdata smdk_pdata_led4 = {
+       .gpio           = S3C2410_GPF(4),
+       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+       .name           = "led4",
+       .def_trigger    = "timer",
+};
+
+static struct s3c24xx_led_platdata smdk_pdata_led5 = {
+       .gpio           = S3C2410_GPF(5),
+       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+       .name           = "led5",
+       .def_trigger    = "nand-disk",
+};
+
+static struct s3c24xx_led_platdata smdk_pdata_led6 = {
+       .gpio           = S3C2410_GPF(6),
+       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+       .name           = "led6",
+};
+
+static struct s3c24xx_led_platdata smdk_pdata_led7 = {
+       .gpio           = S3C2410_GPF(7),
+       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+       .name           = "led7",
+};
+
+static struct platform_device smdk_led4 = {
+       .name           = "s3c24xx_led",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &smdk_pdata_led4,
+       },
+};
+
+static struct platform_device smdk_led5 = {
+       .name           = "s3c24xx_led",
+       .id             = 1,
+       .dev            = {
+               .platform_data = &smdk_pdata_led5,
+       },
+};
+
+static struct platform_device smdk_led6 = {
+       .name           = "s3c24xx_led",
+       .id             = 2,
+       .dev            = {
+               .platform_data = &smdk_pdata_led6,
+       },
+};
+
+static struct platform_device smdk_led7 = {
+       .name           = "s3c24xx_led",
+       .id             = 3,
+       .dev            = {
+               .platform_data = &smdk_pdata_led7,
+       },
+};
+
+/* NAND parititon from 2.4.18-swl5 */
+
+static struct mtd_partition smdk_default_nand_part[] = {
+       [0] = {
+               .name   = "Boot Agent",
+               .size   = SZ_16K,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "S3C2410 flash partition 1",
+               .offset = 0,
+               .size   = SZ_2M,
+       },
+       [2] = {
+               .name   = "S3C2410 flash partition 2",
+               .offset = SZ_4M,
+               .size   = SZ_4M,
+       },
+       [3] = {
+               .name   = "S3C2410 flash partition 3",
+               .offset = SZ_8M,
+               .size   = SZ_2M,
+       },
+       [4] = {
+               .name   = "S3C2410 flash partition 4",
+               .offset = SZ_1M * 10,
+               .size   = SZ_4M,
+       },
+       [5] = {
+               .name   = "S3C2410 flash partition 5",
+               .offset = SZ_1M * 14,
+               .size   = SZ_1M * 10,
+       },
+       [6] = {
+               .name   = "S3C2410 flash partition 6",
+               .offset = SZ_1M * 24,
+               .size   = SZ_1M * 24,
+       },
+       [7] = {
+               .name   = "S3C2410 flash partition 7",
+               .offset = SZ_1M * 48,
+               .size   = MTDPART_SIZ_FULL,
+       }
+};
+
+static struct s3c2410_nand_set smdk_nand_sets[] = {
+       [0] = {
+               .name           = "NAND",
+               .nr_chips       = 1,
+               .nr_partitions  = ARRAY_SIZE(smdk_default_nand_part),
+               .partitions     = smdk_default_nand_part,
+       },
+};
+
+/* choose a set of timings which should suit most 512Mbit
+ * chips and beyond.
+*/
+
+static struct s3c2410_platform_nand smdk_nand_info = {
+       .tacls          = 20,
+       .twrph0         = 60,
+       .twrph1         = 20,
+       .nr_sets        = ARRAY_SIZE(smdk_nand_sets),
+       .sets           = smdk_nand_sets,
+};
+
+/* devices we initialise */
+
+static struct platform_device __initdata *smdk_devs[] = {
+       &s3c_device_nand,
+       &smdk_led4,
+       &smdk_led5,
+       &smdk_led6,
+       &smdk_led7,
+};
+
+void __init smdk_machine_init(void)
+{
+       /* Configure the LEDs (even if we have no LED support)*/
+
+       s3c_gpio_cfgpin(S3C2410_GPF(4), S3C2410_GPIO_OUTPUT);
+       s3c_gpio_cfgpin(S3C2410_GPF(5), S3C2410_GPIO_OUTPUT);
+       s3c_gpio_cfgpin(S3C2410_GPF(6), S3C2410_GPIO_OUTPUT);
+       s3c_gpio_cfgpin(S3C2410_GPF(7), S3C2410_GPIO_OUTPUT);
+
+       s3c2410_gpio_setpin(S3C2410_GPF(4), 1);
+       s3c2410_gpio_setpin(S3C2410_GPF(5), 1);
+       s3c2410_gpio_setpin(S3C2410_GPF(6), 1);
+       s3c2410_gpio_setpin(S3C2410_GPF(7), 1);
+
+       if (machine_is_smdk2443())
+               smdk_nand_info.twrph0 = 50;
+
+       s3c_nand_set_platdata(&smdk_nand_info);
+
+       platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));
+
+       s3c_pm_init();
+}
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2410.c b/arch/arm/mach-s3c24xx/dma-s3c2410.c
new file mode 100644 (file)
index 0000000..4803338
--- /dev/null
@@ -0,0 +1,186 @@
+/* linux/arch/arm/mach-s3c2410/dma.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+
+#include <mach/map.h>
+#include <mach/dma.h>
+
+#include <plat/cpu.h>
+#include <plat/dma-s3c24xx.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <plat/regs-ac97.h>
+#include <plat/regs-dma.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-sdi.h>
+#include <plat/regs-iis.h>
+#include <plat/regs-spi.h>
+
+static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
+       [DMACH_XD0] = {
+               .name           = "xdreq0",
+               .channels[0]    = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
+       },
+       [DMACH_XD1] = {
+               .name           = "xdreq1",
+               .channels[1]    = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
+       },
+       [DMACH_SDI] = {
+               .name           = "sdi",
+               .channels[0]    = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
+               .channels[2]    = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
+               .channels[3]    = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
+       },
+       [DMACH_SPI0] = {
+               .name           = "spi0",
+               .channels[1]    = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
+       },
+       [DMACH_SPI1] = {
+               .name           = "spi1",
+               .channels[3]    = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
+       },
+       [DMACH_UART0] = {
+               .name           = "uart0",
+               .channels[0]    = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
+       },
+       [DMACH_UART1] = {
+               .name           = "uart1",
+               .channels[1]    = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
+       },
+       [DMACH_UART2] = {
+               .name           = "uart2",
+               .channels[3]    = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
+       },
+       [DMACH_TIMER] = {
+               .name           = "timer",
+               .channels[0]    = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
+               .channels[2]    = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
+               .channels[3]    = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
+       },
+       [DMACH_I2S_IN] = {
+               .name           = "i2s-sdi",
+               .channels[1]    = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
+               .channels[2]    = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
+       },
+       [DMACH_I2S_OUT] = {
+               .name           = "i2s-sdo",
+               .channels[2]    = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
+       },
+       [DMACH_USB_EP1] = {
+               .name           = "usb-ep1",
+               .channels[0]    = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
+       },
+       [DMACH_USB_EP2] = {
+               .name           = "usb-ep2",
+               .channels[1]    = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
+       },
+       [DMACH_USB_EP3] = {
+               .name           = "usb-ep3",
+               .channels[2]    = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
+       },
+       [DMACH_USB_EP4] = {
+               .name           = "usb-ep4",
+               .channels[3]    =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
+       },
+};
+
+static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
+                              struct s3c24xx_dma_map *map)
+{
+       chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
+       .select         = s3c2410_dma_select,
+       .dcon_mask      = 7 << 24,
+       .map            = s3c2410_dma_mappings,
+       .map_size       = ARRAY_SIZE(s3c2410_dma_mappings),
+};
+
+static struct s3c24xx_dma_order __initdata s3c2410_dma_order = {
+       .channels       = {
+               [DMACH_SDI]     = {
+                       .list   = {
+                               [0]     = 3 | DMA_CH_VALID,
+                               [1]     = 2 | DMA_CH_VALID,
+                               [2]     = 0 | DMA_CH_VALID,
+                       },
+               },
+               [DMACH_I2S_IN]  = {
+                       .list   = {
+                               [0]     = 1 | DMA_CH_VALID,
+                               [1]     = 2 | DMA_CH_VALID,
+                       },
+               },
+       },
+};
+
+static int __init s3c2410_dma_add(struct device *dev,
+                                 struct subsys_interface *sif)
+{
+       s3c2410_dma_init();
+       s3c24xx_dma_order_set(&s3c2410_dma_order);
+       return s3c24xx_dma_init_map(&s3c2410_dma_sel);
+}
+
+#if defined(CONFIG_CPU_S3C2410)
+static struct subsys_interface s3c2410_dma_interface = {
+       .name           = "s3c2410_dma",
+       .subsys         = &s3c2410_subsys,
+       .add_dev        = s3c2410_dma_add,
+};
+
+static int __init s3c2410_dma_drvinit(void)
+{
+       return subsys_interface_register(&s3c2410_dma_interface);
+}
+
+arch_initcall(s3c2410_dma_drvinit);
+
+static struct subsys_interface s3c2410a_dma_interface = {
+       .name           = "s3c2410a_dma",
+       .subsys         = &s3c2410a_subsys,
+       .add_dev        = s3c2410_dma_add,
+};
+
+static int __init s3c2410a_dma_drvinit(void)
+{
+       return subsys_interface_register(&s3c2410a_dma_interface);
+}
+
+arch_initcall(s3c2410a_dma_drvinit);
+#endif
+
+#if defined(CONFIG_CPU_S3C2442)
+/* S3C2442 DMA contains the same selection table as the S3C2410 */
+static struct subsys_interface s3c2442_dma_interface = {
+       .name           = "s3c2442_dma",
+       .subsys         = &s3c2442_subsys,
+       .add_dev        = s3c2410_dma_add,
+};
+
+static int __init s3c2442_dma_drvinit(void)
+{
+       return subsys_interface_register(&s3c2442_dma_interface);
+}
+
+arch_initcall(s3c2442_dma_drvinit);
+#endif
+
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2412.c b/arch/arm/mach-s3c24xx/dma-s3c2412.c
new file mode 100644 (file)
index 0000000..38472ac
--- /dev/null
@@ -0,0 +1,180 @@
+/* linux/arch/arm/mach-s3c2412/dma.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2412 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <mach/dma.h>
+
+#include <plat/dma-s3c24xx.h>
+#include <plat/cpu.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <plat/regs-ac97.h>
+#include <plat/regs-dma.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-sdi.h>
+#include <plat/regs-iis.h>
+#include <plat/regs-spi.h>
+
+#define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
+
+static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
+       [DMACH_XD0] = {
+               .name           = "xdreq0",
+               .channels       = MAP(S3C2412_DMAREQSEL_XDREQ0),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_XDREQ0),
+       },
+       [DMACH_XD1] = {
+               .name           = "xdreq1",
+               .channels       = MAP(S3C2412_DMAREQSEL_XDREQ1),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_XDREQ1),
+       },
+       [DMACH_SDI] = {
+               .name           = "sdi",
+               .channels       = MAP(S3C2412_DMAREQSEL_SDI),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_SDI),
+       },
+       [DMACH_SPI0] = {
+               .name           = "spi0",
+               .channels       = MAP(S3C2412_DMAREQSEL_SPI0TX),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_SPI0RX),
+       },
+       [DMACH_SPI1] = {
+               .name           = "spi1",
+               .channels       = MAP(S3C2412_DMAREQSEL_SPI1TX),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_SPI1RX),
+       },
+       [DMACH_UART0] = {
+               .name           = "uart0",
+               .channels       = MAP(S3C2412_DMAREQSEL_UART0_0),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART0_0),
+       },
+       [DMACH_UART1] = {
+               .name           = "uart1",
+               .channels       = MAP(S3C2412_DMAREQSEL_UART1_0),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART1_0),
+       },
+       [DMACH_UART2] = {
+               .name           = "uart2",
+               .channels       = MAP(S3C2412_DMAREQSEL_UART2_0),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART2_0),
+       },
+       [DMACH_UART0_SRC2] = {
+               .name           = "uart0",
+               .channels       = MAP(S3C2412_DMAREQSEL_UART0_1),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART0_1),
+       },
+       [DMACH_UART1_SRC2] = {
+               .name           = "uart1",
+               .channels       = MAP(S3C2412_DMAREQSEL_UART1_1),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART1_1),
+       },
+       [DMACH_UART2_SRC2] = {
+               .name           = "uart2",
+               .channels       = MAP(S3C2412_DMAREQSEL_UART2_1),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_UART2_1),
+       },
+       [DMACH_TIMER] = {
+               .name           = "timer",
+               .channels       = MAP(S3C2412_DMAREQSEL_TIMER),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_TIMER),
+       },
+       [DMACH_I2S_IN] = {
+               .name           = "i2s-sdi",
+               .channels       = MAP(S3C2412_DMAREQSEL_I2SRX),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_I2SRX),
+       },
+       [DMACH_I2S_OUT] = {
+               .name           = "i2s-sdo",
+               .channels       = MAP(S3C2412_DMAREQSEL_I2STX),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_I2STX),
+       },
+       [DMACH_USB_EP1] = {
+               .name           = "usb-ep1",
+               .channels       = MAP(S3C2412_DMAREQSEL_USBEP1),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_USBEP1),
+       },
+       [DMACH_USB_EP2] = {
+               .name           = "usb-ep2",
+               .channels       = MAP(S3C2412_DMAREQSEL_USBEP2),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_USBEP2),
+       },
+       [DMACH_USB_EP3] = {
+               .name           = "usb-ep3",
+               .channels       = MAP(S3C2412_DMAREQSEL_USBEP3),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_USBEP3),
+       },
+       [DMACH_USB_EP4] = {
+               .name           = "usb-ep4",
+               .channels       = MAP(S3C2412_DMAREQSEL_USBEP4),
+               .channels_rx    = MAP(S3C2412_DMAREQSEL_USBEP4),
+       },
+};
+
+static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan,
+                                 struct s3c24xx_dma_map *map,
+                                 enum dma_data_direction dir)
+{
+       unsigned long chsel;
+
+       if (dir == DMA_FROM_DEVICE)
+               chsel = map->channels_rx[0];
+       else
+               chsel = map->channels[0];
+
+       chsel &= ~DMA_CH_VALID;
+       chsel |= S3C2412_DMAREQSEL_HW;
+
+       writel(chsel, chan->regs + S3C2412_DMA_DMAREQSEL);
+}
+
+static void s3c2412_dma_select(struct s3c2410_dma_chan *chan,
+                              struct s3c24xx_dma_map *map)
+{
+       s3c2412_dma_direction(chan, map, chan->source);
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = {
+       .select         = s3c2412_dma_select,
+       .direction      = s3c2412_dma_direction,
+       .dcon_mask      = 0,
+       .map            = s3c2412_dma_mappings,
+       .map_size       = ARRAY_SIZE(s3c2412_dma_mappings),
+};
+
+static int __init s3c2412_dma_add(struct device *dev,
+                                 struct subsys_interface *sif)
+{
+       s3c2410_dma_init();
+       return s3c24xx_dma_init_map(&s3c2412_dma_sel);
+}
+
+static struct subsys_interface s3c2412_dma_interface = {
+       .name           = "s3c2412_dma",
+       .subsys         = &s3c2412_subsys,
+       .add_dev        = s3c2412_dma_add,
+};
+
+static int __init s3c2412_dma_init(void)
+{
+       return subsys_interface_register(&s3c2412_dma_interface);
+}
+
+arch_initcall(s3c2412_dma_init);
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2440.c b/arch/arm/mach-s3c24xx/dma-s3c2440.c
new file mode 100644 (file)
index 0000000..5f0a0c8
--- /dev/null
@@ -0,0 +1,197 @@
+/* linux/arch/arm/mach-s3c2440/dma.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2440 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+
+#include <mach/map.h>
+#include <mach/dma.h>
+
+#include <plat/dma-s3c24xx.h>
+#include <plat/cpu.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <plat/regs-ac97.h>
+#include <plat/regs-dma.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-sdi.h>
+#include <plat/regs-iis.h>
+#include <plat/regs-spi.h>
+
+static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
+       [DMACH_XD0] = {
+               .name           = "xdreq0",
+               .channels[0]    = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
+       },
+       [DMACH_XD1] = {
+               .name           = "xdreq1",
+               .channels[1]    = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
+       },
+       [DMACH_SDI] = {
+               .name           = "sdi",
+               .channels[0]    = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
+               .channels[1]    = S3C2440_DCON_CH1_SDI | DMA_CH_VALID,
+               .channels[2]    = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
+               .channels[3]    = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
+       },
+       [DMACH_SPI0] = {
+               .name           = "spi0",
+               .channels[1]    = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
+       },
+       [DMACH_SPI1] = {
+               .name           = "spi1",
+               .channels[3]    = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
+       },
+       [DMACH_UART0] = {
+               .name           = "uart0",
+               .channels[0]    = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
+       },
+       [DMACH_UART1] = {
+               .name           = "uart1",
+               .channels[1]    = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
+       },
+       [DMACH_UART2] = {
+               .name           = "uart2",
+               .channels[3]    = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
+       },
+       [DMACH_TIMER] = {
+               .name           = "timer",
+               .channels[0]    = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
+               .channels[2]    = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
+               .channels[3]    = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
+       },
+       [DMACH_I2S_IN] = {
+               .name           = "i2s-sdi",
+               .channels[1]    = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
+               .channels[2]    = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
+       },
+       [DMACH_I2S_OUT] = {
+               .name           = "i2s-sdo",
+               .channels[0]    = S3C2440_DCON_CH0_I2SSDO | DMA_CH_VALID,
+               .channels[2]    = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
+       },
+       [DMACH_PCM_IN] = {
+               .name           = "pcm-in",
+               .channels[0]    = S3C2440_DCON_CH0_PCMIN | DMA_CH_VALID,
+               .channels[2]    = S3C2440_DCON_CH2_PCMIN | DMA_CH_VALID,
+       },
+       [DMACH_PCM_OUT] = {
+               .name           = "pcm-out",
+               .channels[1]    = S3C2440_DCON_CH1_PCMOUT | DMA_CH_VALID,
+               .channels[3]    = S3C2440_DCON_CH3_PCMOUT | DMA_CH_VALID,
+       },
+       [DMACH_MIC_IN] = {
+               .name           = "mic-in",
+               .channels[2]    = S3C2440_DCON_CH2_MICIN | DMA_CH_VALID,
+               .channels[3]    = S3C2440_DCON_CH3_MICIN | DMA_CH_VALID,
+       },
+       [DMACH_USB_EP1] = {
+               .name           = "usb-ep1",
+               .channels[0]    = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
+       },
+       [DMACH_USB_EP2] = {
+               .name           = "usb-ep2",
+               .channels[1]    = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
+       },
+       [DMACH_USB_EP3] = {
+               .name           = "usb-ep3",
+               .channels[2]    = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
+       },
+       [DMACH_USB_EP4] = {
+               .name           = "usb-ep4",
+               .channels[3]    = S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
+       },
+};
+
+static void s3c2440_dma_select(struct s3c2410_dma_chan *chan,
+                              struct s3c24xx_dma_map *map)
+{
+       chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2440_dma_sel = {
+       .select         = s3c2440_dma_select,
+       .dcon_mask      = 7 << 24,
+       .map            = s3c2440_dma_mappings,
+       .map_size       = ARRAY_SIZE(s3c2440_dma_mappings),
+};
+
+static struct s3c24xx_dma_order __initdata s3c2440_dma_order = {
+       .channels       = {
+               [DMACH_SDI]     = {
+                       .list   = {
+                               [0]     = 3 | DMA_CH_VALID,
+                               [1]     = 2 | DMA_CH_VALID,
+                               [2]     = 1 | DMA_CH_VALID,
+                               [3]     = 0 | DMA_CH_VALID,
+                       },
+               },
+               [DMACH_I2S_IN]  = {
+                       .list   = {
+                               [0]     = 1 | DMA_CH_VALID,
+                               [1]     = 2 | DMA_CH_VALID,
+                       },
+               },
+               [DMACH_I2S_OUT] = {
+                       .list   = {
+                               [0]     = 2 | DMA_CH_VALID,
+                               [1]     = 1 | DMA_CH_VALID,
+                       },
+               },
+               [DMACH_PCM_IN] = {
+                       .list   = {
+                               [0]     = 2 | DMA_CH_VALID,
+                               [1]     = 1 | DMA_CH_VALID,
+                       },
+               },
+               [DMACH_PCM_OUT] = {
+                       .list   = {
+                               [0]     = 1 | DMA_CH_VALID,
+                               [1]     = 3 | DMA_CH_VALID,
+                       },
+               },
+               [DMACH_MIC_IN] = {
+                       .list   = {
+                               [0]     = 3 | DMA_CH_VALID,
+                               [1]     = 2 | DMA_CH_VALID,
+                       },
+               },
+       },
+};
+
+static int __init s3c2440_dma_add(struct device *dev,
+                                 struct subsys_interface *sif)
+{
+       s3c2410_dma_init();
+       s3c24xx_dma_order_set(&s3c2440_dma_order);
+       return s3c24xx_dma_init_map(&s3c2440_dma_sel);
+}
+
+static struct subsys_interface s3c2440_dma_interface = {
+       .name           = "s3c2440_dma",
+       .subsys         = &s3c2440_subsys,
+       .add_dev        = s3c2440_dma_add,
+};
+
+static int __init s3c2440_dma_init(void)
+{
+       return subsys_interface_register(&s3c2440_dma_interface);
+}
+
+arch_initcall(s3c2440_dma_init);
+
diff --git a/arch/arm/mach-s3c24xx/dma-s3c2443.c b/arch/arm/mach-s3c24xx/dma-s3c2443.c
new file mode 100644 (file)
index 0000000..e227c47
--- /dev/null
@@ -0,0 +1,174 @@
+/* linux/arch/arm/mach-s3c2443/dma.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2443 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <mach/dma.h>
+
+#include <plat/dma-s3c24xx.h>
+#include <plat/cpu.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <plat/regs-ac97.h>
+#include <plat/regs-dma.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-sdi.h>
+#include <plat/regs-iis.h>
+#include <plat/regs-spi.h>
+
+#define MAP(x) { \
+               [0]     = (x) | DMA_CH_VALID,   \
+               [1]     = (x) | DMA_CH_VALID,   \
+               [2]     = (x) | DMA_CH_VALID,   \
+               [3]     = (x) | DMA_CH_VALID,   \
+               [4]     = (x) | DMA_CH_VALID,   \
+               [5]     = (x) | DMA_CH_VALID,   \
+       }
+
+static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = {
+       [DMACH_XD0] = {
+               .name           = "xdreq0",
+               .channels       = MAP(S3C2443_DMAREQSEL_XDREQ0),
+       },
+       [DMACH_XD1] = {
+               .name           = "xdreq1",
+               .channels       = MAP(S3C2443_DMAREQSEL_XDREQ1),
+       },
+       [DMACH_SDI] = { /* only on S3C2443 */
+               .name           = "sdi",
+               .channels       = MAP(S3C2443_DMAREQSEL_SDI),
+       },
+       [DMACH_SPI0] = {
+               .name           = "spi0",
+               .channels       = MAP(S3C2443_DMAREQSEL_SPI0TX),
+       },
+       [DMACH_SPI1] = { /* only on S3C2443/S3C2450 */
+               .name           = "spi1",
+               .channels       = MAP(S3C2443_DMAREQSEL_SPI1TX),
+       },
+       [DMACH_UART0] = {
+               .name           = "uart0",
+               .channels       = MAP(S3C2443_DMAREQSEL_UART0_0),
+       },
+       [DMACH_UART1] = {
+               .name           = "uart1",
+               .channels       = MAP(S3C2443_DMAREQSEL_UART1_0),
+       },
+       [DMACH_UART2] = {
+               .name           = "uart2",
+               .channels       = MAP(S3C2443_DMAREQSEL_UART2_0),
+       },
+       [DMACH_UART3] = {
+               .name           = "uart3",
+               .channels       = MAP(S3C2443_DMAREQSEL_UART3_0),
+       },
+       [DMACH_UART0_SRC2] = {
+               .name           = "uart0",
+               .channels       = MAP(S3C2443_DMAREQSEL_UART0_1),
+       },
+       [DMACH_UART1_SRC2] = {
+               .name           = "uart1",
+               .channels       = MAP(S3C2443_DMAREQSEL_UART1_1),
+       },
+       [DMACH_UART2_SRC2] = {
+               .name           = "uart2",
+               .channels       = MAP(S3C2443_DMAREQSEL_UART2_1),
+       },
+       [DMACH_UART3_SRC2] = {
+               .name           = "uart3",
+               .channels       = MAP(S3C2443_DMAREQSEL_UART3_1),
+       },
+       [DMACH_TIMER] = {
+               .name           = "timer",
+               .channels       = MAP(S3C2443_DMAREQSEL_TIMER),
+       },
+       [DMACH_I2S_IN] = {
+               .name           = "i2s-sdi",
+               .channels       = MAP(S3C2443_DMAREQSEL_I2SRX),
+       },
+       [DMACH_I2S_OUT] = {
+               .name           = "i2s-sdo",
+               .channels       = MAP(S3C2443_DMAREQSEL_I2STX),
+       },
+       [DMACH_PCM_IN] = {
+               .name           = "pcm-in",
+               .channels       = MAP(S3C2443_DMAREQSEL_PCMIN),
+       },
+       [DMACH_PCM_OUT] = {
+               .name           = "pcm-out",
+               .channels       = MAP(S3C2443_DMAREQSEL_PCMOUT),
+       },
+       [DMACH_MIC_IN] = {
+               .name           = "mic-in",
+               .channels       = MAP(S3C2443_DMAREQSEL_MICIN),
+       },
+};
+
+static void s3c2443_dma_select(struct s3c2410_dma_chan *chan,
+                              struct s3c24xx_dma_map *map)
+{
+       writel(map->channels[0] | S3C2443_DMAREQSEL_HW,
+              chan->regs + S3C2443_DMA_DMAREQSEL);
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2443_dma_sel = {
+       .select         = s3c2443_dma_select,
+       .dcon_mask      = 0,
+       .map            = s3c2443_dma_mappings,
+       .map_size       = ARRAY_SIZE(s3c2443_dma_mappings),
+};
+
+static int __init s3c2443_dma_add(struct device *dev,
+                                 struct subsys_interface *sif)
+{
+       s3c24xx_dma_init(6, IRQ_S3C2443_DMA0, 0x100);
+       return s3c24xx_dma_init_map(&s3c2443_dma_sel);
+}
+
+#ifdef CONFIG_CPU_S3C2416
+/* S3C2416 DMA contains the same selection table as the S3C2443 */
+static struct subsys_interface s3c2416_dma_interface = {
+       .name           = "s3c2416_dma",
+       .subsys         = &s3c2416_subsys,
+       .add_dev        = s3c2443_dma_add,
+};
+
+static int __init s3c2416_dma_init(void)
+{
+       return subsys_interface_register(&s3c2416_dma_interface);
+}
+
+arch_initcall(s3c2416_dma_init);
+#endif
+
+#ifdef CONFIG_CPU_S3C2443
+static struct subsys_interface s3c2443_dma_interface = {
+       .name           = "s3c2443_dma",
+       .subsys         = &s3c2443_subsys,
+       .add_dev        = s3c2443_dma_add,
+};
+
+static int __init s3c2443_dma_init(void)
+{
+       return subsys_interface_register(&s3c2443_dma_interface);
+}
+
+arch_initcall(s3c2443_dma_init);
+#endif
diff --git a/arch/arm/mach-s3c24xx/h1940-bluetooth.c b/arch/arm/mach-s3c24xx/h1940-bluetooth.c
new file mode 100644 (file)
index 0000000..a5eeb62
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * arch/arm/mach-s3c2410/h1940-bluetooth.c
+ * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * 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.
+ *
+ *         S3C2410 bluetooth "driver"
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/rfkill.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/hardware.h>
+#include <mach/h1940-latch.h>
+#include <mach/h1940.h>
+
+#define DRV_NAME "h1940-bt"
+
+/* Bluetooth control */
+static void h1940bt_enable(int on)
+{
+       if (on) {
+               /* Power on the chip */
+               gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 1);
+               /* Reset the chip */
+               mdelay(10);
+
+               gpio_set_value(S3C2410_GPH(1), 1);
+               mdelay(10);
+               gpio_set_value(S3C2410_GPH(1), 0);
+
+               h1940_led_blink_set(-EINVAL, GPIO_LED_BLINK, NULL, NULL);
+       }
+       else {
+               gpio_set_value(S3C2410_GPH(1), 1);
+               mdelay(10);
+               gpio_set_value(S3C2410_GPH(1), 0);
+               mdelay(10);
+               gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0);
+
+               h1940_led_blink_set(-EINVAL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
+       }
+}
+
+static int h1940bt_set_block(void *data, bool blocked)
+{
+       h1940bt_enable(!blocked);
+       return 0;
+}
+
+static const struct rfkill_ops h1940bt_rfkill_ops = {
+       .set_block = h1940bt_set_block,
+};
+
+static int __devinit h1940bt_probe(struct platform_device *pdev)
+{
+       struct rfkill *rfk;
+       int ret = 0;
+
+       ret = gpio_request(S3C2410_GPH(1), dev_name(&pdev->dev));
+       if (ret) {
+               dev_err(&pdev->dev, "could not get GPH1\n");
+               return ret;
+       }
+
+       ret = gpio_request(H1940_LATCH_BLUETOOTH_POWER, dev_name(&pdev->dev));
+       if (ret) {
+               gpio_free(S3C2410_GPH(1));
+               dev_err(&pdev->dev, "could not get BT_POWER\n");
+               return ret;
+       }
+
+       /* Configures BT serial port GPIOs */
+       s3c_gpio_cfgpin(S3C2410_GPH(0), S3C2410_GPH0_nCTS0);
+       s3c_gpio_setpull(S3C2410_GPH(0), S3C_GPIO_PULL_NONE);
+       s3c_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT);
+       s3c_gpio_setpull(S3C2410_GPH(1), S3C_GPIO_PULL_NONE);
+       s3c_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0);
+       s3c_gpio_setpull(S3C2410_GPH(2), S3C_GPIO_PULL_NONE);
+       s3c_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0);
+       s3c_gpio_setpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE);
+
+       rfk = rfkill_alloc(DRV_NAME, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
+                       &h1940bt_rfkill_ops, NULL);
+       if (!rfk) {
+               ret = -ENOMEM;
+               goto err_rfk_alloc;
+       }
+
+       ret = rfkill_register(rfk);
+       if (ret)
+               goto err_rfkill;
+
+       platform_set_drvdata(pdev, rfk);
+
+       return 0;
+
+err_rfkill:
+       rfkill_destroy(rfk);
+err_rfk_alloc:
+       return ret;
+}
+
+static int h1940bt_remove(struct platform_device *pdev)
+{
+       struct rfkill *rfk = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       gpio_free(S3C2410_GPH(1));
+
+       if (rfk) {
+               rfkill_unregister(rfk);
+               rfkill_destroy(rfk);
+       }
+       rfk = NULL;
+
+       h1940bt_enable(0);
+
+       return 0;
+}
+
+
+static struct platform_driver h1940bt_driver = {
+       .driver         = {
+               .name   = DRV_NAME,
+       },
+       .probe          = h1940bt_probe,
+       .remove         = h1940bt_remove,
+};
+
+
+static int __init h1940bt_init(void)
+{
+       return platform_driver_register(&h1940bt_driver);
+}
+
+static void __exit h1940bt_exit(void)
+{
+       platform_driver_unregister(&h1940bt_driver);
+}
+
+module_init(h1940bt_init);
+module_exit(h1940bt_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_DESCRIPTION("Driver for the iPAQ H1940 bluetooth chip");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-s3c24xx/include/mach/anubis-cpld.h b/arch/arm/mach-s3c24xx/include/mach/anubis-cpld.h
new file mode 100644 (file)
index 0000000..1b614d5
--- /dev/null
@@ -0,0 +1,25 @@
+/* arch/arm/mach-s3c2410/include/mach/anubis-cpld.h
+ *
+ * Copyright (c) 2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * ANUBIS - CPLD control constants
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_ANUBISCPLD_H
+#define __ASM_ARCH_ANUBISCPLD_H
+
+/* CTRL2 - NAND WP control, IDE Reset assert/check */
+
+#define ANUBIS_CTRL1_NANDSEL           (0x3)
+
+/* IDREG - revision */
+
+#define ANUBIS_IDREG_REVMASK           (0x7)
+
+#endif /* __ASM_ARCH_ANUBISCPLD_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/anubis-irq.h b/arch/arm/mach-s3c24xx/include/mach/anubis-irq.h
new file mode 100644 (file)
index 0000000..a2a3281
--- /dev/null
@@ -0,0 +1,21 @@
+/* arch/arm/mach-s3c2410/include/mach/anubis-irq.h
+ *
+ * Copyright (c) 2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *  ANUBIS - IRQ Number definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_ANUBISIRQ_H
+#define __ASM_ARCH_ANUBISIRQ_H
+
+#define IRQ_IDE0       IRQ_EINT2
+#define IRQ_IDE1       IRQ_EINT3
+#define IRQ_ASIX       IRQ_EINT1
+
+#endif /* __ASM_ARCH_ANUBISIRQ_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/anubis-map.h b/arch/arm/mach-s3c24xx/include/mach/anubis-map.h
new file mode 100644 (file)
index 0000000..c9deb3a
--- /dev/null
@@ -0,0 +1,38 @@
+/* arch/arm/mach-s3c2410/include/mach/anubis-map.h
+ *
+ * Copyright (c) 2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * ANUBIS - Memory map definitions
+ *
+ * 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.
+*/
+
+/* needs arch/map.h including with this */
+
+#ifndef __ASM_ARCH_ANUBISMAP_H
+#define __ASM_ARCH_ANUBISMAP_H
+
+/* start peripherals off after the S3C2410 */
+
+#define ANUBIS_IOADDR(x)       (S3C2410_ADDR((x) + 0x01800000))
+
+#define ANUBIS_PA_CPLD         (S3C2410_CS1 | (1<<26))
+
+/* we put the CPLD registers next, to get them out of the way */
+
+#define ANUBIS_VA_CTRL1            ANUBIS_IOADDR(0x00000000)    /* 0x01800000 */
+#define ANUBIS_PA_CTRL1            (ANUBIS_PA_CPLD)
+
+#define ANUBIS_VA_IDREG            ANUBIS_IOADDR(0x00300000)    /* 0x01B00000 */
+#define ANUBIS_PA_IDREG            (ANUBIS_PA_CPLD + (3<<23))
+
+#define ANUBIS_IDEPRI      ANUBIS_IOADDR(0x01000000)
+#define ANUBIS_IDEPRIAUX    ANUBIS_IOADDR(0x01100000)
+#define ANUBIS_IDESEC      ANUBIS_IOADDR(0x01200000)
+#define ANUBIS_IDESECAUX    ANUBIS_IOADDR(0x01300000)
+
+#endif /* __ASM_ARCH_ANUBISMAP_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/bast-cpld.h b/arch/arm/mach-s3c24xx/include/mach/bast-cpld.h
new file mode 100644 (file)
index 0000000..bee2a7a
--- /dev/null
@@ -0,0 +1,53 @@
+/* arch/arm/mach-s3c2410/include/mach/bast-cpld.h
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * BAST - CPLD control constants
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_BASTCPLD_H
+#define __ASM_ARCH_BASTCPLD_H
+
+/* CTRL1 - Audio LR routing */
+
+#define BAST_CPLD_CTRL1_LRCOFF     (0x00)
+#define BAST_CPLD_CTRL1_LRCADC     (0x01)
+#define BAST_CPLD_CTRL1_LRCDAC     (0x02)
+#define BAST_CPLD_CTRL1_LRCARM     (0x03)
+#define BAST_CPLD_CTRL1_LRMASK     (0x03)
+
+/* CTRL2 - NAND WP control, IDE Reset assert/check */
+
+#define BAST_CPLD_CTRL2_WNAND       (0x04)
+#define BAST_CPLD_CTLR2_IDERST      (0x08)
+
+/* CTRL3 - rom write control, CPLD identity */
+
+#define BAST_CPLD_CTRL3_IDMASK      (0x0e)
+#define BAST_CPLD_CTRL3_ROMWEN      (0x01)
+
+/* CTRL4 - 8bit LCD interface control/status */
+
+#define BAST_CPLD_CTRL4_LLAT       (0x01)
+#define BAST_CPLD_CTRL4_LCDRW      (0x02)
+#define BAST_CPLD_CTRL4_LCDCMD     (0x04)
+#define BAST_CPLD_CTRL4_LCDE2      (0x01)
+
+/* CTRL5 - DMA routing */
+
+#define BAST_CPLD_DMA0_PRIIDE      (0<<0)
+#define BAST_CPLD_DMA0_SECIDE      (1<<0)
+#define BAST_CPLD_DMA0_ISA15       (2<<0)
+#define BAST_CPLD_DMA0_ISA36       (3<<0)
+
+#define BAST_CPLD_DMA1_PRIIDE      (0<<2)
+#define BAST_CPLD_DMA1_SECIDE      (1<<2)
+#define BAST_CPLD_DMA1_ISA15       (2<<2)
+#define BAST_CPLD_DMA1_ISA36       (3<<2)
+
+#endif /* __ASM_ARCH_BASTCPLD_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/bast-irq.h b/arch/arm/mach-s3c24xx/include/mach/bast-irq.h
new file mode 100644 (file)
index 0000000..cac428c
--- /dev/null
@@ -0,0 +1,29 @@
+/* arch/arm/mach-s3c2410/include/mach/bast-irq.h
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Machine BAST - IRQ Number definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_BASTIRQ_H
+#define __ASM_ARCH_BASTIRQ_H
+
+/* irq numbers to onboard peripherals */
+
+#define IRQ_USBOC      IRQ_EINT18
+#define IRQ_IDE0       IRQ_EINT16
+#define IRQ_IDE1       IRQ_EINT17
+#define IRQ_PCSERIAL1  IRQ_EINT15
+#define IRQ_PCSERIAL2  IRQ_EINT14
+#define IRQ_PCPARALLEL IRQ_EINT13
+#define IRQ_ASIX       IRQ_EINT11
+#define IRQ_DM9000     IRQ_EINT10
+#define IRQ_ISA               IRQ_EINT9
+#define IRQ_SMALERT    IRQ_EINT8
+
+#endif /* __ASM_ARCH_BASTIRQ_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/bast-map.h b/arch/arm/mach-s3c24xx/include/mach/bast-map.h
new file mode 100644 (file)
index 0000000..6e7dc9d
--- /dev/null
@@ -0,0 +1,146 @@
+/* arch/arm/mach-s3c2410/include/mach/bast-map.h
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Machine BAST - Memory map definitions
+ *
+ * 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.
+*/
+
+/* needs arch/map.h including with this */
+
+/* ok, we've used up to 0x13000000, now we need to find space for the
+ * peripherals that live in the nGCS[x] areas, which are quite numerous
+ * in their space. We also have the board's CPLD to find register space
+ * for.
+ */
+
+#ifndef __ASM_ARCH_BASTMAP_H
+#define __ASM_ARCH_BASTMAP_H
+
+#define BAST_IOADDR(x)    (S3C2410_ADDR((x) + 0x01300000))
+
+/* we put the CPLD registers next, to get them out of the way */
+
+#define BAST_VA_CTRL1      BAST_IOADDR(0x00000000)      /* 0x01300000 */
+#define BAST_PA_CTRL1      (S3C2410_CS5 | 0x7800000)
+
+#define BAST_VA_CTRL2      BAST_IOADDR(0x00100000)      /* 0x01400000 */
+#define BAST_PA_CTRL2      (S3C2410_CS1 | 0x6000000)
+
+#define BAST_VA_CTRL3      BAST_IOADDR(0x00200000)      /* 0x01500000 */
+#define BAST_PA_CTRL3      (S3C2410_CS1 | 0x6800000)
+
+#define BAST_VA_CTRL4      BAST_IOADDR(0x00300000)      /* 0x01600000 */
+#define BAST_PA_CTRL4      (S3C2410_CS1 | 0x7000000)
+
+/* next, we have the PC104 ISA interrupt registers */
+
+#define BAST_PA_PC104_IRQREQ  (S3C2410_CS5 | 0x6000000) /* 0x01700000 */
+#define BAST_VA_PC104_IRQREQ  BAST_IOADDR(0x00400000)
+
+#define BAST_PA_PC104_IRQRAW  (S3C2410_CS5 | 0x6800000) /* 0x01800000 */
+#define BAST_VA_PC104_IRQRAW  BAST_IOADDR(0x00500000)
+
+#define BAST_PA_PC104_IRQMASK (S3C2410_CS5 | 0x7000000) /* 0x01900000 */
+#define BAST_VA_PC104_IRQMASK BAST_IOADDR(0x00600000)
+
+#define BAST_PA_LCD_RCMD1     (0x8800000)
+#define BAST_VA_LCD_RCMD1     BAST_IOADDR(0x00700000)
+
+#define BAST_PA_LCD_WCMD1     (0x8000000)
+#define BAST_VA_LCD_WCMD1     BAST_IOADDR(0x00800000)
+
+#define BAST_PA_LCD_RDATA1    (0x9800000)
+#define BAST_VA_LCD_RDATA1    BAST_IOADDR(0x00900000)
+
+#define BAST_PA_LCD_WDATA1    (0x9000000)
+#define BAST_VA_LCD_WDATA1    BAST_IOADDR(0x00A00000)
+
+#define BAST_PA_LCD_RCMD2     (0xA800000)
+#define BAST_VA_LCD_RCMD2     BAST_IOADDR(0x00B00000)
+
+#define BAST_PA_LCD_WCMD2     (0xA000000)
+#define BAST_VA_LCD_WCMD2     BAST_IOADDR(0x00C00000)
+
+#define BAST_PA_LCD_RDATA2    (0xB800000)
+#define BAST_VA_LCD_RDATA2    BAST_IOADDR(0x00D00000)
+
+#define BAST_PA_LCD_WDATA2    (0xB000000)
+#define BAST_VA_LCD_WDATA2    BAST_IOADDR(0x00E00000)
+
+
+/* 0xE0000000 contains the IO space that is split by speed and
+ * wether the access is for 8 or 16bit IO... this ensures that
+ * the correct access is made
+ *
+ * 0x10000000 of space, partitioned as so:
+ *
+ * 0x00000000 to 0x04000000  8bit,  slow
+ * 0x04000000 to 0x08000000  16bit, slow
+ * 0x08000000 to 0x0C000000  16bit, net
+ * 0x0C000000 to 0x10000000  16bit, fast
+ *
+ * each of these spaces has the following in:
+ *
+ * 0x00000000 to 0x01000000 16MB ISA IO space
+ * 0x01000000 to 0x02000000 16MB ISA memory space
+ * 0x02000000 to 0x02100000 1MB  IDE primary channel
+ * 0x02100000 to 0x02200000 1MB  IDE primary channel aux
+ * 0x02200000 to 0x02400000 1MB  IDE secondary channel
+ * 0x02300000 to 0x02400000 1MB  IDE secondary channel aux
+ * 0x02400000 to 0x02500000 1MB  ASIX ethernet controller
+ * 0x02500000 to 0x02600000 1MB  Davicom DM9000 ethernet controller
+ * 0x02600000 to 0x02700000 1MB  PC SuperIO controller
+ *
+ * the phyiscal layout of the zones are:
+ *  nGCS2 - 8bit, slow
+ *  nGCS3 - 16bit, slow
+ *  nGCS4 - 16bit, net
+ *  nGCS5 - 16bit, fast
+ */
+
+#define BAST_VA_MULTISPACE (0xE0000000)
+
+#define BAST_VA_ISAIO     (BAST_VA_MULTISPACE + 0x00000000)
+#define BAST_VA_ISAMEM    (BAST_VA_MULTISPACE + 0x01000000)
+#define BAST_VA_IDEPRI    (BAST_VA_MULTISPACE + 0x02000000)
+#define BAST_VA_IDEPRIAUX  (BAST_VA_MULTISPACE + 0x02100000)
+#define BAST_VA_IDESEC    (BAST_VA_MULTISPACE + 0x02200000)
+#define BAST_VA_IDESECAUX  (BAST_VA_MULTISPACE + 0x02300000)
+#define BAST_VA_ASIXNET           (BAST_VA_MULTISPACE + 0x02400000)
+#define BAST_VA_DM9000    (BAST_VA_MULTISPACE + 0x02500000)
+#define BAST_VA_SUPERIO           (BAST_VA_MULTISPACE + 0x02600000)
+
+#define BAST_VA_MULTISPACE (0xE0000000)
+
+#define BAST_VAM_CS2 (0x00000000)
+#define BAST_VAM_CS3 (0x04000000)
+#define BAST_VAM_CS4 (0x08000000)
+#define BAST_VAM_CS5 (0x0C000000)
+
+/* physical offset addresses for the peripherals */
+
+#define BAST_PA_ISAIO    (0x00000000)
+#define BAST_PA_ASIXNET          (0x01000000)
+#define BAST_PA_SUPERIO          (0x01800000)
+#define BAST_PA_IDEPRI   (0x02000000)
+#define BAST_PA_IDEPRIAUX (0x02800000)
+#define BAST_PA_IDESEC   (0x03000000)
+#define BAST_PA_IDESECAUX (0x03800000)
+#define BAST_PA_ISAMEM   (0x04000000)
+#define BAST_PA_DM9000   (0x05000000)
+
+/* some configurations for the peripherals */
+
+#define BAST_PCSIO (BAST_VA_SUPERIO + BAST_VAM_CS2)
+/*  */
+
+#define BAST_ASIXNET_CS  BAST_VAM_CS5
+#define BAST_IDE_CS     BAST_VAM_CS5
+#define BAST_DM9000_CS  BAST_VAM_CS4
+
+#endif /* __ASM_ARCH_BASTMAP_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/bast-pmu.h b/arch/arm/mach-s3c24xx/include/mach/bast-pmu.h
new file mode 100644 (file)
index 0000000..4c38b39
--- /dev/null
@@ -0,0 +1,40 @@
+/* arch/arm/mach-s3c2410/include/mach/bast-pmu.h
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Machine BAST - Power Management chip
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_BASTPMU_H
+#define __ASM_ARCH_BASTPMU_H "08_OCT_2004"
+
+#define BASTPMU_REG_IDENT      (0x00)
+#define BASTPMU_REG_VERSION    (0x01)
+#define BASTPMU_REG_DDCCTRL    (0x02)
+#define BASTPMU_REG_POWER      (0x03)
+#define BASTPMU_REG_RESET      (0x04)
+#define BASTPMU_REG_GWO                (0x05)
+#define BASTPMU_REG_WOL                (0x06)
+#define BASTPMU_REG_WOR                (0x07)
+#define BASTPMU_REG_UID                (0x09)
+
+#define BASTPMU_EEPROM         (0xC0)
+
+#define BASTPMU_EEP_UID                (BASTPMU_EEPROM + 0)
+#define BASTPMU_EEP_WOL                (BASTPMU_EEPROM + 8)
+#define BASTPMU_EEP_WOR                (BASTPMU_EEPROM + 9)
+
+#define BASTPMU_IDENT_0                0x53
+#define BASTPMU_IDENT_1                0x42
+#define BASTPMU_IDENT_2                0x50
+#define BASTPMU_IDENT_3                0x4d
+
+#define BASTPMU_RESET_GUARD    (0x55)
+
+#endif /* __ASM_ARCH_BASTPMU_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/debug-macro.S b/arch/arm/mach-s3c24xx/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..4135de8
--- /dev/null
@@ -0,0 +1,101 @@
+/* arch/arm/mach-s3c2410/include/mach/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ *  Copyright (C) 1994-1999 Russell King
+ *  Copyright (C) 2005 Simtec Electronics
+ *
+ *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ *
+ * 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 <mach/map.h>
+#include <mach/regs-gpio.h>
+#include <plat/regs-serial.h>
+
+#define S3C2410_UART1_OFF (0x4000)
+#define SHIFT_2440TXF (14-9)
+
+       .macro addruart, rp, rv, tmp
+               ldr     \rp, = S3C24XX_PA_UART
+               ldr     \rv, = S3C24XX_VA_UART
+#if CONFIG_DEBUG_S3C_UART != 0
+               add     \rp, \rp, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+               add     \rv, \rv, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+#endif
+       .endm
+
+       .macro fifo_full_s3c24xx rd, rx
+               @ check for arm920 vs arm926. currently assume all arm926
+               @ devices have an 64 byte FIFO identical to the s3c2440
+               mrc     p15, 0, \rd, c0, c0
+               and     \rd, \rd, #0xff0
+               teq     \rd, #0x260
+               beq     1004f
+               mrc     p15, 0, \rd, c1, c0
+               tst     \rd, #1
+               addeq   \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
+               addne   \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART)
+               bic     \rd, \rd, #0xff000
+               ldr     \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
+               and     \rd, \rd, #0x00ff0000
+               teq     \rd, #0x00440000                @ is it 2440?
+1004:
+               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
+               moveq   \rd, \rd, lsr #SHIFT_2440TXF
+               tst     \rd, #S3C2410_UFSTAT_TXFULL
+       .endm
+
+       .macro  fifo_full_s3c2410 rd, rx
+               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
+               tst     \rd, #S3C2410_UFSTAT_TXFULL
+       .endm
+
+/* fifo level reading */
+
+       .macro fifo_level_s3c24xx rd, rx
+               @ check for arm920 vs arm926. currently assume all arm926
+               @ devices have an 64 byte FIFO identical to the s3c2440
+               mrc     p15, 0, \rd, c0, c0
+               and     \rd, \rd, #0xff0
+               teq     \rd, #0x260
+               beq     10000f
+               mrc     p15, 0, \rd, c1, c0
+               tst     \rd, #1
+               addeq   \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
+               addne   \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART)
+               bic     \rd, \rd, #0xff000
+               ldr     \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
+               and     \rd, \rd, #0x00ff0000
+               teq     \rd, #0x00440000                @ is it 2440?
+
+10000:
+               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
+               andne   \rd, \rd, #S3C2410_UFSTAT_TXMASK
+               andeq   \rd, \rd, #S3C2440_UFSTAT_TXMASK
+       .endm
+
+       .macro fifo_level_s3c2410 rd, rx
+               ldr     \rd, [ \rx, # S3C2410_UFSTAT ]
+               and     \rd, \rd, #S3C2410_UFSTAT_TXMASK
+       .endm
+
+/* Select the correct implementation depending on the configuration. The
+ * S3C2440 will get selected by default, as these are the most widely
+ * used variants of these
+*/
+
+#if defined(CONFIG_CPU_LLSERIAL_S3C2410_ONLY)
+#define fifo_full  fifo_full_s3c2410
+#define fifo_level fifo_level_s3c2410
+#elif !defined(CONFIG_CPU_LLSERIAL_S3C2440_ONLY)
+#define fifo_full  fifo_full_s3c24xx
+#define fifo_level fifo_level_s3c24xx
+#endif
+
+/* include the reset of the code which will do the work */
+
+#include <plat/debug-macro.S>
diff --git a/arch/arm/mach-s3c24xx/include/mach/dma.h b/arch/arm/mach-s3c24xx/include/mach/dma.h
new file mode 100644 (file)
index 0000000..acbdfec
--- /dev/null
@@ -0,0 +1,210 @@
+/* arch/arm/mach-s3c2410/include/mach/dma.h
+ *
+ * Copyright (C) 2003-2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C24XX DMA support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H __FILE__
+
+#include <linux/device.h>
+
+#define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
+
+/* We use `virtual` dma channels to hide the fact we have only a limited
+ * number of DMA channels, and not of all of them (dependent on the device)
+ * can be attached to any DMA source. We therefore let the DMA core handle
+ * the allocation of hardware channels to clients.
+*/
+
+enum dma_ch {
+       DMACH_XD0,
+       DMACH_XD1,
+       DMACH_SDI,
+       DMACH_SPI0,
+       DMACH_SPI1,
+       DMACH_UART0,
+       DMACH_UART1,
+       DMACH_UART2,
+       DMACH_TIMER,
+       DMACH_I2S_IN,
+       DMACH_I2S_OUT,
+       DMACH_PCM_IN,
+       DMACH_PCM_OUT,
+       DMACH_MIC_IN,
+       DMACH_USB_EP1,
+       DMACH_USB_EP2,
+       DMACH_USB_EP3,
+       DMACH_USB_EP4,
+       DMACH_UART0_SRC2,       /* s3c2412 second uart sources */
+       DMACH_UART1_SRC2,
+       DMACH_UART2_SRC2,
+       DMACH_UART3,            /* s3c2443 has extra uart */
+       DMACH_UART3_SRC2,
+       DMACH_MAX,              /* the end entry */
+};
+
+static inline bool samsung_dma_has_circular(void)
+{
+       return false;
+}
+
+static inline bool samsung_dma_is_dmadev(void)
+{
+       return false;
+}
+
+#include <plat/dma.h>
+
+#define DMACH_LOW_LEVEL        (1<<28) /* use this to specifiy hardware ch no */
+
+/* we have 4 dma channels */
+#if !defined(CONFIG_CPU_S3C2443) && !defined(CONFIG_CPU_S3C2416)
+#define S3C_DMA_CHANNELS               (4)
+#else
+#define S3C_DMA_CHANNELS               (6)
+#endif
+
+/* types */
+
+enum s3c2410_dma_state {
+       S3C2410_DMA_IDLE,
+       S3C2410_DMA_RUNNING,
+       S3C2410_DMA_PAUSED
+};
+
+/* enum s3c2410_dma_loadst
+ *
+ * This represents the state of the DMA engine, wrt to the loaded / running
+ * transfers. Since we don't have any way of knowing exactly the state of
+ * the DMA transfers, we need to know the state to make decisions on wether
+ * we can
+ *
+ * S3C2410_DMA_NONE
+ *
+ * There are no buffers loaded (the channel should be inactive)
+ *
+ * S3C2410_DMA_1LOADED
+ *
+ * There is one buffer loaded, however it has not been confirmed to be
+ * loaded by the DMA engine. This may be because the channel is not
+ * yet running, or the DMA driver decided that it was too costly to
+ * sit and wait for it to happen.
+ *
+ * S3C2410_DMA_1RUNNING
+ *
+ * The buffer has been confirmed running, and not finisged
+ *
+ * S3C2410_DMA_1LOADED_1RUNNING
+ *
+ * There is a buffer waiting to be loaded by the DMA engine, and one
+ * currently running.
+*/
+
+enum s3c2410_dma_loadst {
+       S3C2410_DMALOAD_NONE,
+       S3C2410_DMALOAD_1LOADED,
+       S3C2410_DMALOAD_1RUNNING,
+       S3C2410_DMALOAD_1LOADED_1RUNNING,
+};
+
+
+/* flags */
+
+#define S3C2410_DMAF_SLOW         (1<<0)   /* slow, so don't worry about
+                                           * waiting for reloads */
+#define S3C2410_DMAF_AUTOSTART    (1<<1)   /* auto-start if buffer queued */
+
+#define S3C2410_DMAF_CIRCULAR  (1 << 2)        /* no circular dma support */
+
+/* dma buffer */
+
+struct s3c2410_dma_buf;
+
+/* s3c2410_dma_buf
+ *
+ * internally used buffer structure to describe a queued or running
+ * buffer.
+*/
+
+struct s3c2410_dma_buf {
+       struct s3c2410_dma_buf  *next;
+       int                      magic;         /* magic */
+       int                      size;          /* buffer size in bytes */
+       dma_addr_t               data;          /* start of DMA data */
+       dma_addr_t               ptr;           /* where the DMA got to [1] */
+       void                    *id;            /* client's id */
+};
+
+/* [1] is this updated for both recv/send modes? */
+
+struct s3c2410_dma_stats {
+       unsigned long           loads;
+       unsigned long           timeout_longest;
+       unsigned long           timeout_shortest;
+       unsigned long           timeout_avg;
+       unsigned long           timeout_failed;
+};
+
+struct s3c2410_dma_map;
+
+/* struct s3c2410_dma_chan
+ *
+ * full state information for each DMA channel
+*/
+
+struct s3c2410_dma_chan {
+       /* channel state flags and information */
+       unsigned char            number;      /* number of this dma channel */
+       unsigned char            in_use;      /* channel allocated */
+       unsigned char            irq_claimed; /* irq claimed for channel */
+       unsigned char            irq_enabled; /* irq enabled for channel */
+       unsigned char            xfer_unit;   /* size of an transfer */
+
+       /* channel state */
+
+       enum s3c2410_dma_state   state;
+       enum s3c2410_dma_loadst  load_state;
+       struct s3c2410_dma_client *client;
+
+       /* channel configuration */
+       enum dma_data_direction  source;
+       enum dma_ch              req_ch;
+       unsigned long            dev_addr;
+       unsigned long            load_timeout;
+       unsigned int             flags;         /* channel flags */
+
+       struct s3c24xx_dma_map  *map;           /* channel hw maps */
+
+       /* channel's hardware position and configuration */
+       void __iomem            *regs;          /* channels registers */
+       void __iomem            *addr_reg;      /* data address register */
+       unsigned int             irq;           /* channel irq */
+       unsigned long            dcon;          /* default value of DCON */
+
+       /* driver handles */
+       s3c2410_dma_cbfn_t       callback_fn;   /* buffer done callback */
+       s3c2410_dma_opfn_t       op_fn;         /* channel op callback */
+
+       /* stats gathering */
+       struct s3c2410_dma_stats *stats;
+       struct s3c2410_dma_stats  stats_store;
+
+       /* buffer list and information */
+       struct s3c2410_dma_buf  *curr;          /* current dma buffer */
+       struct s3c2410_dma_buf  *next;          /* next buffer to load */
+       struct s3c2410_dma_buf  *end;           /* end of queue */
+
+       /* system device */
+       struct device   dev;
+};
+
+typedef unsigned long dma_device_t;
+
+#endif /* __ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..7615a14
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/mach-s3c2410/include/mach/entry-macro.S
+ *
+ * Low-level IRQ helper macros for S3C2410-based platforms
+ *
+ * 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.
+*/
+
+/* We have a problem that the INTOFFSET register does not always
+ * show one interrupt. Occasionally we get two interrupts through
+ * the prioritiser, and this causes the INTOFFSET register to show
+ * what looks like the logical-or of the two interrupt numbers.
+ *
+ * Thanks to Klaus, Shannon, et al for helping to debug this problem
+*/
+
+#define INTPND         (0x10)
+#define INTOFFSET      (0x14)
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+       .macro  get_irqnr_preamble, base, tmp
+       .endm
+
+       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+               mov     \base, #S3C24XX_VA_IRQ
+
+               @@ try the interrupt offset register, since it is there
+
+               ldr     \irqstat, [ \base, #INTPND ]
+               teq     \irqstat, #0
+               beq     1002f
+               ldr     \irqnr, [ \base, #INTOFFSET ]
+               mov     \tmp, #1
+               tst     \irqstat, \tmp, lsl \irqnr
+               bne     1001f
+
+               @@ the number specified is not a valid irq, so try
+               @@ and work it out for ourselves
+
+               mov     \irqnr, #0              @@ start here
+
+               @@ work out which irq (if any) we got
+
+               movs    \tmp, \irqstat, lsl#16
+               addeq   \irqnr, \irqnr, #16
+               moveq   \irqstat, \irqstat, lsr#16
+               tst     \irqstat, #0xff
+               addeq   \irqnr, \irqnr, #8
+               moveq   \irqstat, \irqstat, lsr#8
+               tst     \irqstat, #0xf
+               addeq   \irqnr, \irqnr, #4
+               moveq   \irqstat, \irqstat, lsr#4
+               tst     \irqstat, #0x3
+               addeq   \irqnr, \irqnr, #2
+               moveq   \irqstat, \irqstat, lsr#2
+               tst     \irqstat, #0x1
+               addeq   \irqnr, \irqnr, #1
+
+               @@ we have the value
+1001:
+               adds    \irqnr, \irqnr, #IRQ_EINT0
+1002:
+               @@ exit here, Z flag unset if IRQ
+
+       .endm
diff --git a/arch/arm/mach-s3c24xx/include/mach/fb.h b/arch/arm/mach-s3c24xx/include/mach/fb.h
new file mode 100644 (file)
index 0000000..a957bc8
--- /dev/null
@@ -0,0 +1 @@
+#include <plat/fb-s3c2410.h>
diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio-fns.h b/arch/arm/mach-s3c24xx/include/mach/gpio-fns.h
new file mode 100644 (file)
index 0000000..c53ad34
--- /dev/null
@@ -0,0 +1 @@
+#include <plat/gpio-fns.h>
diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio-nrs.h b/arch/arm/mach-s3c24xx/include/mach/gpio-nrs.h
new file mode 100644 (file)
index 0000000..019ea86
--- /dev/null
@@ -0,0 +1,118 @@
+/* arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - GPIO bank numbering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __MACH_GPIONRS_H
+#define __MACH_GPIONRS_H
+
+#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))
+
+#define S3C2410_GPIO_BANKG   (32*6)
+#define S3C2410_GPIO_BANKH   (32*7)
+
+/* GPIO sizes for various SoCs:
+ *
+ *             2442
+ *   2410 2412 2440 2443 2416
+ *   ---- ---- ---- ---- ----
+ * A 23   22   25   16   25
+ * B 11   11   11   11   9
+ * C 16   15   16   16   16
+ * D 16   16   16   16   16
+ * E 16   16   16   16   16
+ * F 8    8    8    8    8
+ * G 16   16   16   16   8
+ * H 11   11   9    15   15
+ * J --   --   13   16   --
+ * K --   --   --   --   16
+ * L --   --   --   15   7
+ * M --   --   --   2    2
+ */
+
+/* GPIO bank sizes */
+#define S3C2410_GPIO_A_NR      (32)
+#define S3C2410_GPIO_B_NR      (32)
+#define S3C2410_GPIO_C_NR      (32)
+#define S3C2410_GPIO_D_NR      (32)
+#define S3C2410_GPIO_E_NR      (32)
+#define S3C2410_GPIO_F_NR      (32)
+#define S3C2410_GPIO_G_NR      (32)
+#define S3C2410_GPIO_H_NR      (32)
+#define S3C2410_GPIO_J_NR      (32)    /* technically 16. */
+#define S3C2410_GPIO_K_NR      (32)    /* technically 16. */
+#define S3C2410_GPIO_L_NR      (32)    /* technically 15. */
+#define S3C2410_GPIO_M_NR      (32)    /* technically 2. */
+
+#if CONFIG_S3C_GPIO_SPACE != 0
+#error CONFIG_S3C_GPIO_SPACE cannot be nonzero at the moment
+#endif
+
+#define S3C2410_GPIO_NEXT(__gpio) \
+       ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)
+
+#ifndef __ASSEMBLY__
+
+enum s3c_gpio_number {
+       S3C2410_GPIO_A_START = 0,
+       S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
+       S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
+       S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
+       S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
+       S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
+       S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
+       S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
+       S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H),
+       S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J),
+       S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K),
+       S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L),
+};
+
+#endif /* __ASSEMBLY__ */
+
+/* S3C2410 GPIO number definitions. */
+
+#define S3C2410_GPA(_nr)       (S3C2410_GPIO_A_START + (_nr))
+#define S3C2410_GPB(_nr)       (S3C2410_GPIO_B_START + (_nr))
+#define S3C2410_GPC(_nr)       (S3C2410_GPIO_C_START + (_nr))
+#define S3C2410_GPD(_nr)       (S3C2410_GPIO_D_START + (_nr))
+#define S3C2410_GPE(_nr)       (S3C2410_GPIO_E_START + (_nr))
+#define S3C2410_GPF(_nr)       (S3C2410_GPIO_F_START + (_nr))
+#define S3C2410_GPG(_nr)       (S3C2410_GPIO_G_START + (_nr))
+#define S3C2410_GPH(_nr)       (S3C2410_GPIO_H_START + (_nr))
+#define S3C2410_GPJ(_nr)       (S3C2410_GPIO_J_START + (_nr))
+#define S3C2410_GPK(_nr)       (S3C2410_GPIO_K_START + (_nr))
+#define S3C2410_GPL(_nr)       (S3C2410_GPIO_L_START + (_nr))
+#define S3C2410_GPM(_nr)       (S3C2410_GPIO_M_START + (_nr))
+
+/* compatibility until drivers can be modified */
+
+#define S3C2410_GPA0   S3C2410_GPA(0)
+#define S3C2410_GPA1   S3C2410_GPA(1)
+#define S3C2410_GPA3   S3C2410_GPA(3)
+#define S3C2410_GPA7   S3C2410_GPA(7)
+
+#define S3C2410_GPE0   S3C2410_GPE(0)
+#define S3C2410_GPE1   S3C2410_GPE(1)
+#define S3C2410_GPE2   S3C2410_GPE(2)
+#define S3C2410_GPE3   S3C2410_GPE(3)
+#define S3C2410_GPE4   S3C2410_GPE(4)
+#define S3C2410_GPE5   S3C2410_GPE(5)
+#define S3C2410_GPE6   S3C2410_GPE(6)
+#define S3C2410_GPE7   S3C2410_GPE(7)
+#define S3C2410_GPE8   S3C2410_GPE(8)
+#define S3C2410_GPE9   S3C2410_GPE(9)
+#define S3C2410_GPE10  S3C2410_GPE(10)
+
+#define S3C2410_GPH10  S3C2410_GPH(10)
+
+#endif /* __MACH_GPIONRS_H */
+
diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio-track.h b/arch/arm/mach-s3c24xx/include/mach/gpio-track.h
new file mode 100644 (file)
index 0000000..c410a07
--- /dev/null
@@ -0,0 +1,33 @@
+/* arch/arm/mach-s3c24100/include/mach/gpio-core.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C2410 - GPIO core support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_GPIO_CORE_H
+#define __ASM_ARCH_GPIO_CORE_H __FILE__
+
+#include <mach/regs-gpio.h>
+
+extern struct samsung_gpio_chip s3c24xx_gpios[];
+
+static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int pin)
+{
+       struct samsung_gpio_chip *chip;
+
+       if (pin > S3C_GPIO_END)
+               return NULL;
+
+       chip = &s3c24xx_gpios[pin/32];
+       return ((pin - chip->chip.base) < chip->chip.ngpio) ? chip : NULL;
+}
+
+#endif /* __ASM_ARCH_GPIO_CORE_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio.h b/arch/arm/mach-s3c24xx/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..6fac70f
--- /dev/null
@@ -0,0 +1,35 @@
+/* arch/arm/mach-s3c2410/include/mach/gpio.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - GPIO lib support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* some boards require extra gpio capacity to support external
+ * devices that need GPIO.
+ */
+
+#ifdef CONFIG_CPU_S3C244X
+#define ARCH_NR_GPIOS  (32 * 9 + CONFIG_S3C24XX_GPIO_EXTRA)
+#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
+#define ARCH_NR_GPIOS  (32 * 12 + CONFIG_S3C24XX_GPIO_EXTRA)
+#else
+#define ARCH_NR_GPIOS  (256 + CONFIG_S3C24XX_GPIO_EXTRA)
+#endif
+
+#include <mach/gpio-nrs.h>
+#include <mach/gpio-fns.h>
+
+#ifdef CONFIG_CPU_S3C244X
+#define S3C_GPIO_END   (S3C2410_GPJ(0) + 32)
+#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
+#define S3C_GPIO_END   (S3C2410_GPM(0) + 32)
+#else
+#define S3C_GPIO_END   (S3C2410_GPH(0) + 32)
+#endif
diff --git a/arch/arm/mach-s3c24xx/include/mach/gta02.h b/arch/arm/mach-s3c24xx/include/mach/gta02.h
new file mode 100644 (file)
index 0000000..3a56a22
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef _GTA02_H
+#define _GTA02_H
+
+#include <mach/regs-gpio.h>
+
+/* Different hardware revisions, passed in ATAG_REVISION by u-boot */
+#define GTA02v1_SYSTEM_REV     0x00000310
+#define GTA02v2_SYSTEM_REV     0x00000320
+#define GTA02v3_SYSTEM_REV     0x00000330
+#define GTA02v4_SYSTEM_REV     0x00000340
+#define GTA02v5_SYSTEM_REV     0x00000350
+/* since A7 is basically same as A6, we use A6 PCB ID */
+#define GTA02v6_SYSTEM_REV     0x00000360
+
+#define GTA02_GPIO_n3DL_GSM    S3C2410_GPA(13) /* v1 + v2 + v3 only */
+
+#define GTA02_GPIO_PWR_LED1    S3C2410_GPB(0)
+#define GTA02_GPIO_PWR_LED2    S3C2410_GPB(1)
+#define GTA02_GPIO_AUX_LED     S3C2410_GPB(2)
+#define GTA02_GPIO_VIBRATOR_ON S3C2410_GPB(3)
+#define GTA02_GPIO_MODEM_RST   S3C2410_GPB(5)
+#define GTA02_GPIO_BT_EN       S3C2410_GPB(6)
+#define GTA02_GPIO_MODEM_ON    S3C2410_GPB(7)
+#define GTA02_GPIO_EXTINT8     S3C2410_GPB(8)
+#define GTA02_GPIO_USB_PULLUP  S3C2410_GPB(9)
+
+#define GTA02_GPIO_PIO5                S3C2410_GPC(5)  /* v3 + v4 only */
+
+#define GTA02v3_GPIO_nG1_CS    S3C2410_GPD(12) /* v3 + v4 only */
+#define GTA02v3_GPIO_nG2_CS    S3C2410_GPD(13) /* v3 + v4 only */
+#define GTA02v5_GPIO_HDQ       S3C2410_GPD(14)   /* v5 + */
+
+#define GTA02_GPIO_nG1_INT     S3C2410_GPF(0)
+#define GTA02_GPIO_IO1         S3C2410_GPF(1)
+#define GTA02_GPIO_PIO_2       S3C2410_GPF(2)  /* v2 + v3 + v4 only */
+#define GTA02_GPIO_JACK_INSERT S3C2410_GPF(4)
+#define GTA02_GPIO_WLAN_GPIO1  S3C2410_GPF(5)  /* v2 + v3 + v4 only */
+#define GTA02_GPIO_AUX_KEY     S3C2410_GPF(6)
+#define GTA02_GPIO_HOLD_KEY    S3C2410_GPF(7)
+
+#define GTA02_GPIO_3D_IRQ      S3C2410_GPG(4)
+#define GTA02v2_GPIO_nG2_INT   S3C2410_GPG(8)  /* v2 + v3 + v4 only */
+#define GTA02v3_GPIO_nUSB_OC   S3C2410_GPG(9)  /* v3 + v4 only */
+#define GTA02v3_GPIO_nUSB_FLT  S3C2410_GPG(10) /* v3 + v4 only */
+#define GTA02v3_GPIO_nGSM_OC   S3C2410_GPG(11) /* v3 + v4 only */
+
+#define GTA02_GPIO_AMP_SHUT    S3C2410_GPJ(1)  /* v2 + v3 + v4 only */
+#define GTA02v1_GPIO_WLAN_GPIO10       S3C2410_GPJ(2)
+#define GTA02_GPIO_HP_IN       S3C2410_GPJ(2)  /* v2 + v3 + v4 only */
+#define GTA02_GPIO_INT0                S3C2410_GPJ(3)  /* v2 + v3 + v4 only */
+#define GTA02_GPIO_nGSM_EN     S3C2410_GPJ(4)
+#define GTA02_GPIO_3D_RESET    S3C2410_GPJ(5)
+#define GTA02_GPIO_nDL_GSM     S3C2410_GPJ(6)  /* v4 + v5 only */
+#define GTA02_GPIO_WLAN_GPIO0  S3C2410_GPJ(7)
+#define GTA02v1_GPIO_BAT_ID    S3C2410_GPJ(8)
+#define GTA02_GPIO_KEEPACT     S3C2410_GPJ(8)
+#define GTA02v1_GPIO_HP_IN     S3C2410_GPJ(10)
+#define GTA02_CHIP_PWD         S3C2410_GPJ(11) /* v2 + v3 + v4 only */
+#define GTA02_GPIO_nWLAN_RESET S3C2410_GPJ(12) /* v2 + v3 + v4 only */
+
+#define GTA02_IRQ_GSENSOR_1    IRQ_EINT0
+#define GTA02_IRQ_MODEM                IRQ_EINT1
+#define GTA02_IRQ_PIO_2                IRQ_EINT2       /* v2 + v3 + v4 only */
+#define GTA02_IRQ_nJACK_INSERT IRQ_EINT4
+#define GTA02_IRQ_WLAN_GPIO1   IRQ_EINT5
+#define GTA02_IRQ_AUX          IRQ_EINT6
+#define GTA02_IRQ_nHOLD                IRQ_EINT7
+#define GTA02_IRQ_PCF50633     IRQ_EINT9
+#define GTA02_IRQ_3D           IRQ_EINT12
+#define GTA02_IRQ_GSENSOR_2    IRQ_EINT16      /* v2 + v3 + v4 only */
+#define GTA02v3_IRQ_nUSB_OC    IRQ_EINT17      /* v3 + v4 only */
+#define GTA02v3_IRQ_nUSB_FLT   IRQ_EINT18      /* v3 + v4 only */
+#define GTA02v3_IRQ_nGSM_OC    IRQ_EINT19      /* v3 + v4 only */
+
+/* returns 00 000 on GTA02 A5 and earlier, A6 returns 01 001 */
+#define GTA02_PCB_ID1_0                S3C2410_GPC(13)
+#define GTA02_PCB_ID1_1                S3C2410_GPC(15)
+#define GTA02_PCB_ID1_2                S3C2410_GPD(0)
+#define GTA02_PCB_ID2_0                S3C2410_GPD(3)
+#define GTA02_PCB_ID2_1                S3C2410_GPD(4)
+
+int gta02_get_pcb_revision(void);
+
+#endif /* _GTA02_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/h1940-latch.h b/arch/arm/mach-s3c24xx/include/mach/h1940-latch.h
new file mode 100644 (file)
index 0000000..fc897d3
--- /dev/null
@@ -0,0 +1,43 @@
+/* arch/arm/mach-s3c2410/include/mach/h1940-latch.h
+ *
+ * Copyright (c) 2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *  iPAQ H1940 series - latch definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_H1940_LATCH_H
+#define __ASM_ARCH_H1940_LATCH_H
+
+#include <asm/gpio.h>
+
+#define H1940_LATCH_GPIO(x)            (S3C_GPIO_END + (x))
+
+/* SD layer latch */
+
+#define H1940_LATCH_LCD_P0             H1940_LATCH_GPIO(0)
+#define H1940_LATCH_LCD_P1             H1940_LATCH_GPIO(1)
+#define H1940_LATCH_LCD_P2             H1940_LATCH_GPIO(2)
+#define H1940_LATCH_LCD_P3             H1940_LATCH_GPIO(3)
+#define H1940_LATCH_MAX1698_nSHUTDOWN  H1940_LATCH_GPIO(4)
+#define H1940_LATCH_LED_RED            H1940_LATCH_GPIO(5)
+#define H1940_LATCH_SDQ7               H1940_LATCH_GPIO(6)
+#define H1940_LATCH_USB_DP             H1940_LATCH_GPIO(7)
+
+/* CPU layer latch */
+
+#define H1940_LATCH_UDA_POWER          H1940_LATCH_GPIO(8)
+#define H1940_LATCH_AUDIO_POWER                H1940_LATCH_GPIO(9)
+#define H1940_LATCH_SM803_ENABLE       H1940_LATCH_GPIO(10)
+#define H1940_LATCH_LCD_P4             H1940_LATCH_GPIO(11)
+#define H1940_LATCH_SD_POWER           H1940_LATCH_GPIO(12)
+#define H1940_LATCH_BLUETOOTH_POWER    H1940_LATCH_GPIO(13)
+#define H1940_LATCH_LED_GREEN          H1940_LATCH_GPIO(14)
+#define H1940_LATCH_LED_FLASH          H1940_LATCH_GPIO(15)
+
+#endif /* __ASM_ARCH_H1940_LATCH_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/h1940.h b/arch/arm/mach-s3c24xx/include/mach/h1940.h
new file mode 100644 (file)
index 0000000..2aa683c
--- /dev/null
@@ -0,0 +1,24 @@
+/* arch/arm/mach-s3c2410/include/mach/h1940.h
+ *
+ * Copyright 2006 Ben Dooks <ben-linux@fluff.org>
+ *
+ * H1940 definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_H1940_H
+#define __ASM_ARCH_H1940_H
+
+#define H1940_SUSPEND_CHECKSUM         (0x30003ff8)
+#define H1940_SUSPEND_RESUMEAT         (0x30081000)
+#define H1940_SUSPEND_CHECK            (0x30080000)
+
+extern void h1940_pm_return(void);
+extern int h1940_led_blink_set(unsigned gpio, int state,
+       unsigned long *delay_on, unsigned long *delay_off);
+
+
+#endif /* __ASM_ARCH_H1940_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/hardware.h b/arch/arm/mach-s3c24xx/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..aef5631
--- /dev/null
@@ -0,0 +1,42 @@
+/* arch/arm/mach-s3c2410/include/mach/hardware.h
+ *
+ * Copyright (c) 2003 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - hardware
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#ifndef __ASSEMBLY__
+
+extern unsigned int s3c2410_modify_misccr(unsigned int clr, unsigned int chg);
+
+#ifdef CONFIG_CPU_S3C2440
+
+extern int s3c2440_set_dsc(unsigned int pin, unsigned int value);
+
+#endif /* CONFIG_CPU_S3C2440 */
+
+#ifdef CONFIG_CPU_S3C2412
+
+extern int s3c2412_gpio_set_sleepcfg(unsigned int pin, unsigned int state);
+
+#endif /* CONFIG_CPU_S3C2412 */
+
+#endif /* __ASSEMBLY__ */
+
+#include <asm/sizes.h>
+#include <mach/map.h>
+
+/* machine specific hardware definitions should go after this */
+
+/* currently here until moved into config (todo) */
+#define CONFIG_NO_MULTIWORD_IO
+
+#endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/idle.h b/arch/arm/mach-s3c24xx/include/mach/idle.h
new file mode 100644 (file)
index 0000000..e9ddd70
--- /dev/null
@@ -0,0 +1,24 @@
+/* arch/arm/mach-s3c2410/include/mach/idle.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *             http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 CPU Idle controls
+*/
+
+#ifndef __ASM_ARCH_IDLE_H
+#define __ASM_ARCH_IDLE_H __FILE__
+
+/* This allows the over-ride of the default idle code, in case there
+ * is any other things to be done over idle (like DVS)
+*/
+
+extern void (*s3c24xx_idle)(void);
+
+extern void s3c24xx_default_idle(void);
+
+#endif /* __ASM_ARCH_IDLE_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/io.h b/arch/arm/mach-s3c24xx/include/mach/io.h
new file mode 100644 (file)
index 0000000..118749f
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * arch/arm/mach-s3c2410/include/mach/io.h
+ *  from arch/arm/mach-rpc/include/mach/io.h
+ *
+ * Copyright (C) 1997 Russell King
+ *          (C) 2003 Simtec Electronics
+*/
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#include <mach/hardware.h>
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We use two different types of addressing - PC style addresses, and ARM
+ * addresses.  PC style accesses the PC hardware with the normal PC IO
+ * addresses, eg 0x3f8 for serial#1.  ARM addresses are above A28
+ * and are translated to the start of IO.  Note that all addresses are
+ * not shifted left!
+ */
+
+#define __PORT_PCIO(x) ((x) < (1<<28))
+
+#define PCIO_BASE       (S3C24XX_VA_ISA_WORD)
+#define PCIO_BASE_b     (S3C24XX_VA_ISA_BYTE)
+#define PCIO_BASE_w     (S3C24XX_VA_ISA_WORD)
+#define PCIO_BASE_l     (S3C24XX_VA_ISA_WORD)
+/*
+ * Dynamic IO functions - let the compiler
+ * optimize the expressions
+ */
+
+#define DECLARE_DYN_OUT(sz,fnsuffix,instr) \
+static inline void __out##fnsuffix (unsigned int val, unsigned int port) \
+{ \
+       unsigned long temp;                                   \
+       __asm__ __volatile__(                                 \
+       "cmp    %2, #(1<<28)\n\t"                             \
+       "mov    %0, %2\n\t"                                   \
+       "addcc  %0, %0, %3\n\t"                               \
+       "str" instr " %1, [%0, #0 ]     @ out" #fnsuffix      \
+       : "=&r" (temp)                                        \
+       : "r" (val), "r" (port), "Ir" (PCIO_BASE_##fnsuffix)  \
+       : "cc");                                              \
+}
+
+
+#define DECLARE_DYN_IN(sz,fnsuffix,instr)                              \
+static inline unsigned sz __in##fnsuffix (unsigned int port)           \
+{                                                                      \
+       unsigned long temp, value;                                      \
+       __asm__ __volatile__(                                           \
+       "cmp    %2, #(1<<28)\n\t"                                       \
+       "mov    %0, %2\n\t"                                             \
+       "addcc  %0, %0, %3\n\t"                                         \
+       "ldr" instr "   %1, [%0, #0 ]   @ in" #fnsuffix         \
+       : "=&r" (temp), "=r" (value)                                    \
+       : "r" (port), "Ir" (PCIO_BASE_##fnsuffix)       \
+       : "cc");                                                        \
+       return (unsigned sz)value;                                      \
+}
+
+static inline void __iomem *__ioaddr (unsigned long port)
+{
+       return __PORT_PCIO(port) ? (PCIO_BASE + port) : (void __iomem *)port;
+}
+
+#define DECLARE_IO(sz,fnsuffix,instr)  \
+       DECLARE_DYN_IN(sz,fnsuffix,instr) \
+       DECLARE_DYN_OUT(sz,fnsuffix,instr)
+
+DECLARE_IO(char,b,"b")
+DECLARE_IO(short,w,"h")
+DECLARE_IO(int,l,"")
+
+#undef DECLARE_IO
+#undef DECLARE_DYN_IN
+
+/*
+ * Constant address IO functions
+ *
+ * These have to be macros for the 'J' constraint to work -
+ * +/-4096 immediate operand.
+ */
+#define __outbc(value,port)                                            \
+({                                                                     \
+       if (__PORT_PCIO((port)))                                        \
+               __asm__ __volatile__(                                   \
+               "strb   %0, [%1, %2]    @ outbc"                        \
+               : : "r" (value), "r" (PCIO_BASE), "Jr" ((port)));       \
+       else                                                            \
+               __asm__ __volatile__(                                   \
+               "strb   %0, [%1, #0]    @ outbc"                        \
+               : : "r" (value), "r" ((port)));                         \
+})
+
+#define __inbc(port)                                                   \
+({                                                                     \
+       unsigned char result;                                           \
+       if (__PORT_PCIO((port)))                                        \
+               __asm__ __volatile__(                                   \
+               "ldrb   %0, [%1, %2]    @ inbc"                         \
+               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port)));      \
+       else                                                            \
+               __asm__ __volatile__(                                   \
+               "ldrb   %0, [%1, #0]    @ inbc"                         \
+               : "=r" (result) : "r" ((port)));                        \
+       result;                                                         \
+})
+
+#define __outwc(value,port)                                            \
+({                                                                     \
+       unsigned long v = value;                                        \
+       if (__PORT_PCIO((port))) {                                      \
+               if ((port) < 256 && (port) > -256)                      \
+                       __asm__ __volatile__(                           \
+                       "strh   %0, [%1, %2]    @ outwc"                \
+                       : : "r" (v), "r" (PCIO_BASE), "Jr" ((port)));   \
+               else if ((port) > 0)                                    \
+                       __asm__ __volatile__(                           \
+                       "strh   %0, [%1, %2]    @ outwc"                \
+                       : : "r" (v),                                    \
+                           "r" (PCIO_BASE + ((port) & ~0xff)),         \
+                            "Jr" (((port) & 0xff)));                   \
+               else                                                    \
+                       __asm__ __volatile__(                           \
+                       "strh   %0, [%1, #0]    @ outwc"                \
+                       : : "r" (v),                                    \
+                           "r" (PCIO_BASE + (port)));                  \
+       } else                                                          \
+               __asm__ __volatile__(                                   \
+               "strh   %0, [%1, #0]    @ outwc"                        \
+               : : "r" (v), "r" ((port)));                             \
+})
+
+#define __inwc(port)                                                   \
+({                                                                     \
+       unsigned short result;                                          \
+       if (__PORT_PCIO((port))) {                                      \
+               if ((port) < 256 && (port) > -256 )                     \
+                       __asm__ __volatile__(                           \
+                       "ldrh   %0, [%1, %2]    @ inwc"                 \
+                       : "=r" (result)                                 \
+                       : "r" (PCIO_BASE),                              \
+                         "Jr" ((port)));                               \
+               else if ((port) > 0)                                    \
+                       __asm__ __volatile__(                           \
+                       "ldrh   %0, [%1, %2]    @ inwc"                 \
+                       : "=r" (result)                                 \
+                       : "r" (PCIO_BASE + ((port) & ~0xff)),           \
+                         "Jr" (((port) & 0xff)));                      \
+               else                                                    \
+                       __asm__ __volatile__(                           \
+                       "ldrh   %0, [%1, #0]    @ inwc"                 \
+                       : "=r" (result)                                 \
+                       : "r" (PCIO_BASE + ((port))));                  \
+       } else                                                          \
+               __asm__ __volatile__(                                   \
+               "ldrh   %0, [%1, #0]    @ inwc"                         \
+               : "=r" (result) : "r" ((port)));                        \
+       result;                                                         \
+})
+
+#define __outlc(value,port)                                            \
+({                                                                     \
+       unsigned long v = value;                                        \
+       if (__PORT_PCIO((port)))                                        \
+               __asm__ __volatile__(                                   \
+               "str    %0, [%1, %2]    @ outlc"                        \
+               : : "r" (v), "r" (PCIO_BASE), "Jr" ((port)));   \
+       else                                                            \
+               __asm__ __volatile__(                                   \
+               "str    %0, [%1, #0]    @ outlc"                        \
+               : : "r" (v), "r" ((port)));             \
+})
+
+#define __inlc(port)                                                   \
+({                                                                     \
+       unsigned long result;                                           \
+       if (__PORT_PCIO((port)))                                        \
+               __asm__ __volatile__(                                   \
+               "ldr    %0, [%1, %2]    @ inlc"                         \
+               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port)));      \
+       else                                                            \
+               __asm__ __volatile__(                                   \
+               "ldr    %0, [%1, #0]    @ inlc"                         \
+               : "=r" (result) : "r" ((port)));                \
+       result;                                                         \
+})
+
+#define __ioaddrc(port)        ((__PORT_PCIO(port) ? PCIO_BASE + (port) : (void __iomem *)(port)))
+
+#define inb(p)         (__builtin_constant_p((p)) ? __inbc(p)     : __inb(p))
+#define inw(p)         (__builtin_constant_p((p)) ? __inwc(p)     : __inw(p))
+#define inl(p)         (__builtin_constant_p((p)) ? __inlc(p)     : __inl(p))
+#define outb(v,p)      (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
+#define outw(v,p)      (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
+#define outl(v,p)      (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
+#define __ioaddr(p)    (__builtin_constant_p((p)) ? __ioaddr(p)  : __ioaddrc(p))
+
+#define insb(p,d,l)    __raw_readsb(__ioaddr(p),d,l)
+#define insw(p,d,l)    __raw_readsw(__ioaddr(p),d,l)
+#define insl(p,d,l)    __raw_readsl(__ioaddr(p),d,l)
+
+#define outsb(p,d,l)   __raw_writesb(__ioaddr(p),d,l)
+#define outsw(p,d,l)   __raw_writesw(__ioaddr(p),d,l)
+#define outsl(p,d,l)   __raw_writesl(__ioaddr(p),d,l)
+
+/*
+ * 1:1 mapping for ioremapped regions.
+ */
+#define __mem_pci(x)   (x)
+
+#endif
diff --git a/arch/arm/mach-s3c24xx/include/mach/irqs.h b/arch/arm/mach-s3c24xx/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..e53b217
--- /dev/null
@@ -0,0 +1,202 @@
+/* arch/arm/mach-s3c2410/include/mach/irqs.h
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H __FILE__
+
+/* we keep the first set of CPU IRQs out of the range of
+ * the ISA space, so that the PC104 has them to itself
+ * and we don't end up having to do horrible things to the
+ * standard ISA drivers....
+ */
+
+#define S3C2410_CPUIRQ_OFFSET   (16)
+
+#define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET)
+
+/* main cpu interrupts */
+#define IRQ_EINT0      S3C2410_IRQ(0)      /* 16 */
+#define IRQ_EINT1      S3C2410_IRQ(1)
+#define IRQ_EINT2      S3C2410_IRQ(2)
+#define IRQ_EINT3      S3C2410_IRQ(3)
+#define IRQ_EINT4t7    S3C2410_IRQ(4)      /* 20 */
+#define IRQ_EINT8t23   S3C2410_IRQ(5)
+#define IRQ_RESERVED6  S3C2410_IRQ(6)      /* for s3c2410 */
+#define IRQ_CAM        S3C2410_IRQ(6)      /* for s3c2440,s3c2443 */
+#define IRQ_BATT_FLT   S3C2410_IRQ(7)
+#define IRQ_TICK       S3C2410_IRQ(8)      /* 24 */
+#define IRQ_WDT               S3C2410_IRQ(9)       /* WDT/AC97 for s3c2443 */
+#define IRQ_TIMER0     S3C2410_IRQ(10)
+#define IRQ_TIMER1     S3C2410_IRQ(11)
+#define IRQ_TIMER2     S3C2410_IRQ(12)
+#define IRQ_TIMER3     S3C2410_IRQ(13)
+#define IRQ_TIMER4     S3C2410_IRQ(14)
+#define IRQ_UART2      S3C2410_IRQ(15)
+#define IRQ_LCD               S3C2410_IRQ(16)      /* 32 */
+#define IRQ_DMA0       S3C2410_IRQ(17)     /* IRQ_DMA for s3c2443 */
+#define IRQ_DMA1       S3C2410_IRQ(18)
+#define IRQ_DMA2       S3C2410_IRQ(19)
+#define IRQ_DMA3       S3C2410_IRQ(20)
+#define IRQ_SDI               S3C2410_IRQ(21)
+#define IRQ_SPI0       S3C2410_IRQ(22)
+#define IRQ_UART1      S3C2410_IRQ(23)
+#define IRQ_RESERVED24 S3C2410_IRQ(24)     /* 40 */
+#define IRQ_NFCON      S3C2410_IRQ(24)     /* for s3c2440 */
+#define IRQ_USBD       S3C2410_IRQ(25)
+#define IRQ_USBH       S3C2410_IRQ(26)
+#define IRQ_IIC               S3C2410_IRQ(27)
+#define IRQ_UART0      S3C2410_IRQ(28)     /* 44 */
+#define IRQ_SPI1       S3C2410_IRQ(29)
+#define IRQ_RTC               S3C2410_IRQ(30)
+#define IRQ_ADCPARENT  S3C2410_IRQ(31)
+
+/* interrupts generated from the external interrupts sources */
+#define IRQ_EINT4      S3C2410_IRQ(32)    /* 48 */
+#define IRQ_EINT5      S3C2410_IRQ(33)
+#define IRQ_EINT6      S3C2410_IRQ(34)
+#define IRQ_EINT7      S3C2410_IRQ(35)
+#define IRQ_EINT8      S3C2410_IRQ(36)
+#define IRQ_EINT9      S3C2410_IRQ(37)
+#define IRQ_EINT10     S3C2410_IRQ(38)
+#define IRQ_EINT11     S3C2410_IRQ(39)
+#define IRQ_EINT12     S3C2410_IRQ(40)
+#define IRQ_EINT13     S3C2410_IRQ(41)
+#define IRQ_EINT14     S3C2410_IRQ(42)
+#define IRQ_EINT15     S3C2410_IRQ(43)
+#define IRQ_EINT16     S3C2410_IRQ(44)
+#define IRQ_EINT17     S3C2410_IRQ(45)
+#define IRQ_EINT18     S3C2410_IRQ(46)
+#define IRQ_EINT19     S3C2410_IRQ(47)
+#define IRQ_EINT20     S3C2410_IRQ(48)    /* 64 */
+#define IRQ_EINT21     S3C2410_IRQ(49)
+#define IRQ_EINT22     S3C2410_IRQ(50)
+#define IRQ_EINT23     S3C2410_IRQ(51)
+
+#define IRQ_EINT_BIT(x)        ((x) - IRQ_EINT4 + 4)
+#define IRQ_EINT(x)    (((x) >= 4) ? (IRQ_EINT4 + (x) - 4) : (IRQ_EINT0 + (x)))
+
+#define IRQ_LCD_FIFO   S3C2410_IRQ(52)
+#define IRQ_LCD_FRAME  S3C2410_IRQ(53)
+
+/* IRQs for the interal UARTs, and ADC
+ * these need to be ordered in number of appearance in the
+ * SUBSRC mask register
+*/
+
+#define S3C2410_IRQSUB(x)      S3C2410_IRQ((x)+54)
+
+#define IRQ_S3CUART_RX0                S3C2410_IRQSUB(0)       /* 70 */
+#define IRQ_S3CUART_TX0                S3C2410_IRQSUB(1)
+#define IRQ_S3CUART_ERR0       S3C2410_IRQSUB(2)
+
+#define IRQ_S3CUART_RX1                S3C2410_IRQSUB(3)       /* 73 */
+#define IRQ_S3CUART_TX1                S3C2410_IRQSUB(4)
+#define IRQ_S3CUART_ERR1       S3C2410_IRQSUB(5)
+
+#define IRQ_S3CUART_RX2                S3C2410_IRQSUB(6)       /* 76 */
+#define IRQ_S3CUART_TX2                S3C2410_IRQSUB(7)
+#define IRQ_S3CUART_ERR2       S3C2410_IRQSUB(8)
+
+#define IRQ_TC                 S3C2410_IRQSUB(9)
+#define IRQ_ADC                        S3C2410_IRQSUB(10)
+
+/* extra irqs for s3c2412 */
+
+#define IRQ_S3C2412_CFSDI      S3C2410_IRQ(21)
+
+#define IRQ_S3C2412_SDI                S3C2410_IRQSUB(13)
+#define IRQ_S3C2412_CF         S3C2410_IRQSUB(14)
+
+
+#define IRQ_S3C2416_EINT8t15   S3C2410_IRQ(5)
+#define IRQ_S3C2416_DMA                S3C2410_IRQ(17)
+#define IRQ_S3C2416_UART3      S3C2410_IRQ(18)
+#define IRQ_S3C2416_SDI1       S3C2410_IRQ(20)
+#define IRQ_S3C2416_SDI0       S3C2410_IRQ(21)
+
+#define IRQ_S3C2416_LCD2       S3C2410_IRQSUB(15)
+#define IRQ_S3C2416_LCD3       S3C2410_IRQSUB(16)
+#define IRQ_S3C2416_LCD4       S3C2410_IRQSUB(17)
+#define IRQ_S3C2416_DMA0       S3C2410_IRQSUB(18)
+#define IRQ_S3C2416_DMA1       S3C2410_IRQSUB(19)
+#define IRQ_S3C2416_DMA2       S3C2410_IRQSUB(20)
+#define IRQ_S3C2416_DMA3       S3C2410_IRQSUB(21)
+#define IRQ_S3C2416_DMA4       S3C2410_IRQSUB(22)
+#define IRQ_S3C2416_DMA5       S3C2410_IRQSUB(23)
+#define IRQ_S32416_WDT         S3C2410_IRQSUB(27)
+#define IRQ_S32416_AC97                S3C2410_IRQSUB(28)
+
+
+/* extra irqs for s3c2440 */
+
+#define IRQ_S3C2440_CAM_C      S3C2410_IRQSUB(11)      /* S3C2443 too */
+#define IRQ_S3C2440_CAM_P      S3C2410_IRQSUB(12)      /* S3C2443 too */
+#define IRQ_S3C2440_WDT                S3C2410_IRQSUB(13)
+#define IRQ_S3C2440_AC97       S3C2410_IRQSUB(14)
+
+/* irqs for s3c2443 */
+
+#define IRQ_S3C2443_DMA                S3C2410_IRQ(17)         /* IRQ_DMA1 */
+#define IRQ_S3C2443_UART3      S3C2410_IRQ(18)         /* IRQ_DMA2 */
+#define IRQ_S3C2443_CFCON      S3C2410_IRQ(19)         /* IRQ_DMA3 */
+#define IRQ_S3C2443_HSMMC      S3C2410_IRQ(20)         /* IRQ_SDI */
+#define IRQ_S3C2443_NAND       S3C2410_IRQ(24)         /* reserved */
+
+#define IRQ_S3C2416_HSMMC0     S3C2410_IRQ(21)         /* S3C2416/S3C2450 */
+
+#define IRQ_HSMMC0             IRQ_S3C2416_HSMMC0
+#define IRQ_HSMMC1             IRQ_S3C2443_HSMMC
+
+#define IRQ_S3C2443_LCD1       S3C2410_IRQSUB(14)
+#define IRQ_S3C2443_LCD2       S3C2410_IRQSUB(15)
+#define IRQ_S3C2443_LCD3       S3C2410_IRQSUB(16)
+#define IRQ_S3C2443_LCD4       S3C2410_IRQSUB(17)
+
+#define IRQ_S3C2443_DMA0       S3C2410_IRQSUB(18)
+#define IRQ_S3C2443_DMA1       S3C2410_IRQSUB(19)
+#define IRQ_S3C2443_DMA2       S3C2410_IRQSUB(20)
+#define IRQ_S3C2443_DMA3       S3C2410_IRQSUB(21)
+#define IRQ_S3C2443_DMA4       S3C2410_IRQSUB(22)
+#define IRQ_S3C2443_DMA5       S3C2410_IRQSUB(23)
+
+/* UART3 */
+#define IRQ_S3C2443_RX3                S3C2410_IRQSUB(24)
+#define IRQ_S3C2443_TX3                S3C2410_IRQSUB(25)
+#define IRQ_S3C2443_ERR3       S3C2410_IRQSUB(26)
+
+#define IRQ_S3C2443_WDT                S3C2410_IRQSUB(27)
+#define IRQ_S3C2443_AC97       S3C2410_IRQSUB(28)
+
+#if defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
+#define NR_IRQS (IRQ_S3C2443_AC97+1)
+#else
+#define NR_IRQS (IRQ_S3C2440_AC97+1)
+#endif
+
+/* compatibility define. */
+#define IRQ_UART3              IRQ_S3C2443_UART3
+#define IRQ_S3CUART_RX3                IRQ_S3C2443_RX3
+#define IRQ_S3CUART_TX3                IRQ_S3C2443_TX3
+#define IRQ_S3CUART_ERR3       IRQ_S3C2443_ERR3
+
+#define IRQ_LCD_VSYNC          IRQ_S3C2443_LCD3
+#define IRQ_LCD_SYSTEM         IRQ_S3C2443_LCD2
+
+#ifdef CONFIG_CPU_S3C2440
+#define IRQ_S3C244X_AC97 IRQ_S3C2440_AC97
+#else
+#define IRQ_S3C244X_AC97 IRQ_S3C2443_AC97
+#endif
+
+/* Our FIQs are routable from IRQ_EINT0 to IRQ_ADCPARENT */
+#define FIQ_START              IRQ_EINT0
+
+#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/leds-gpio.h b/arch/arm/mach-s3c24xx/include/mach/leds-gpio.h
new file mode 100644 (file)
index 0000000..d8a7672
--- /dev/null
@@ -0,0 +1,28 @@
+/* arch/arm/mach-s3c2410/include/mach/leds-gpio.h
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX - LEDs GPIO connector
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_LEDSGPIO_H
+#define __ASM_ARCH_LEDSGPIO_H "leds-gpio.h"
+
+#define S3C24XX_LEDF_ACTLOW    (1<<0)          /* LED is on when GPIO low */
+#define S3C24XX_LEDF_TRISTATE  (1<<1)          /* tristate to turn off */
+
+struct s3c24xx_led_platdata {
+       unsigned int             gpio;
+       unsigned int             flags;
+
+       char                    *name;
+       char                    *def_trigger;
+};
+
+#endif /* __ASM_ARCH_LEDSGPIO_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/map.h b/arch/arm/mach-s3c24xx/include/mach/map.h
new file mode 100644 (file)
index 0000000..78ae807
--- /dev/null
@@ -0,0 +1,165 @@
+/* arch/arm/mach-s3c2410/include/mach/map.h
+ *
+ * Copyright (c) 2003 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - Memory map definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_MAP_H
+#define __ASM_ARCH_MAP_H
+
+#include <plat/map-base.h>
+
+/*
+ * S3C2410 UART offset is 0x4000 but the other SoCs are 0x400.
+ * So need to define it, and here is to avoid redefinition warning.
+ */
+#define S3C_UART_OFFSET                (0x4000)
+
+#include <plat/map-s3c.h>
+
+/*
+ * interrupt controller is the first thing we put in, to make
+ * the assembly code for the irq detection easier
+ */
+#define S3C2410_PA_IRQ         (0x4A000000)
+#define S3C24XX_SZ_IRQ         SZ_1M
+
+/* memory controller registers */
+#define S3C2410_PA_MEMCTRL     (0x48000000)
+#define S3C24XX_SZ_MEMCTRL     SZ_1M
+
+/* UARTs */
+#define S3C_VA_UARTx(uart)     (S3C_VA_UART + ((uart * S3C_UART_OFFSET)))
+
+/* Timers */
+#define S3C2410_PA_TIMER       (0x51000000)
+#define S3C24XX_SZ_TIMER       SZ_1M
+
+/* Clock and Power management */
+#define S3C24XX_SZ_CLKPWR      SZ_1M
+
+/* USB Device port */
+#define S3C2410_PA_USBDEV      (0x52000000)
+#define S3C24XX_SZ_USBDEV      SZ_1M
+
+/* Watchdog */
+#define S3C2410_PA_WATCHDOG    (0x53000000)
+#define S3C24XX_SZ_WATCHDOG    SZ_1M
+
+/* Standard size definitions for peripheral blocks. */
+
+#define S3C24XX_SZ_UART                SZ_1M
+#define S3C24XX_SZ_IIS         SZ_1M
+#define S3C24XX_SZ_ADC         SZ_1M
+#define S3C24XX_SZ_SPI         SZ_1M
+#define S3C24XX_SZ_SDI         SZ_1M
+#define S3C24XX_SZ_NAND                SZ_1M
+#define S3C24XX_SZ_GPIO                SZ_1M
+
+/* USB host controller */
+#define S3C2410_PA_USBHOST (0x49000000)
+
+/* S3C2416/S3C2443/S3C2450 High-Speed USB Gadget */
+#define S3C2416_PA_HSUDC       (0x49800000)
+#define S3C2416_SZ_HSUDC       (SZ_4K)
+
+/* DMA controller */
+#define S3C2410_PA_DMA    (0x4B000000)
+#define S3C24XX_SZ_DMA    SZ_1M
+
+/* Clock and Power management */
+#define S3C2410_PA_CLKPWR  (0x4C000000)
+
+/* LCD controller */
+#define S3C2410_PA_LCD    (0x4D000000)
+#define S3C24XX_SZ_LCD    SZ_1M
+
+/* NAND flash controller */
+#define S3C2410_PA_NAND           (0x4E000000)
+
+/* IIC hardware controller */
+#define S3C2410_PA_IIC    (0x54000000)
+
+/* IIS controller */
+#define S3C2410_PA_IIS    (0x55000000)
+
+/* RTC */
+#define S3C2410_PA_RTC    (0x57000000)
+#define S3C24XX_SZ_RTC    SZ_1M
+
+/* ADC */
+#define S3C2410_PA_ADC    (0x58000000)
+
+/* SPI */
+#define S3C2410_PA_SPI    (0x59000000)
+
+/* SDI */
+#define S3C2410_PA_SDI    (0x5A000000)
+
+/* CAMIF */
+#define S3C2440_PA_CAMIF   (0x4F000000)
+#define S3C2440_SZ_CAMIF   SZ_1M
+
+/* AC97 */
+
+#define S3C2440_PA_AC97           (0x5B000000)
+#define S3C2440_SZ_AC97           SZ_1M
+
+/* S3C2443/S3C2416 High-speed SD/MMC */
+#define S3C2443_PA_HSMMC   (0x4A800000)
+#define S3C2416_PA_HSMMC0  (0x4AC00000)
+
+#define        S3C2443_PA_FB   (0x4C800000)
+
+/* S3C2412 memory and IO controls */
+#define S3C2412_PA_SSMC        (0x4F000000)
+
+#define S3C2412_PA_EBI (0x48800000)
+
+/* physical addresses of all the chip-select areas */
+
+#define S3C2410_CS0 (0x00000000)
+#define S3C2410_CS1 (0x08000000)
+#define S3C2410_CS2 (0x10000000)
+#define S3C2410_CS3 (0x18000000)
+#define S3C2410_CS4 (0x20000000)
+#define S3C2410_CS5 (0x28000000)
+#define S3C2410_CS6 (0x30000000)
+#define S3C2410_CS7 (0x38000000)
+
+#define S3C2410_SDRAM_PA    (S3C2410_CS6)
+
+/* Use a single interface for common resources between S3C24XX cpus */
+
+#define S3C24XX_PA_IRQ      S3C2410_PA_IRQ
+#define S3C24XX_PA_MEMCTRL  S3C2410_PA_MEMCTRL
+#define S3C24XX_PA_DMA      S3C2410_PA_DMA
+#define S3C24XX_PA_CLKPWR   S3C2410_PA_CLKPWR
+#define S3C24XX_PA_LCD      S3C2410_PA_LCD
+#define S3C24XX_PA_TIMER    S3C2410_PA_TIMER
+#define S3C24XX_PA_USBDEV   S3C2410_PA_USBDEV
+#define S3C24XX_PA_WATCHDOG S3C2410_PA_WATCHDOG
+#define S3C24XX_PA_IIS      S3C2410_PA_IIS
+#define S3C24XX_PA_RTC      S3C2410_PA_RTC
+#define S3C24XX_PA_ADC      S3C2410_PA_ADC
+#define S3C24XX_PA_SPI      S3C2410_PA_SPI
+#define S3C24XX_PA_SPI1                (S3C2410_PA_SPI + S3C2410_SPI1)
+#define S3C24XX_PA_SDI      S3C2410_PA_SDI
+#define S3C24XX_PA_NAND            S3C2410_PA_NAND
+
+#define S3C_PA_FB          S3C2443_PA_FB
+#define S3C_PA_IIC          S3C2410_PA_IIC
+#define S3C_PA_UART        S3C24XX_PA_UART
+#define S3C_PA_USBHOST S3C2410_PA_USBHOST
+#define S3C_PA_HSMMC0      S3C2416_PA_HSMMC0
+#define S3C_PA_HSMMC1      S3C2443_PA_HSMMC
+#define S3C_PA_WDT         S3C2410_PA_WATCHDOG
+#define S3C_PA_NAND        S3C24XX_PA_NAND
+
+#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/osiris-cpld.h b/arch/arm/mach-s3c24xx/include/mach/osiris-cpld.h
new file mode 100644 (file)
index 0000000..e9e36b0
--- /dev/null
@@ -0,0 +1,30 @@
+/* arch/arm/mach-s3c2410/include/mach/osiris-cpld.h
+ *
+ * Copyright 2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * OSIRIS - CPLD control constants
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_OSIRISCPLD_H
+#define __ASM_ARCH_OSIRISCPLD_H
+
+/* CTRL0 - NAND WP control */
+
+#define OSIRIS_CTRL0_NANDSEL           (0x3)
+#define OSIRIS_CTRL0_BOOT_INT          (1<<3)
+#define OSIRIS_CTRL0_PCMCIA            (1<<4)
+#define OSIRIS_CTRL0_FIX8              (1<<5)
+#define OSIRIS_CTRL0_PCMCIA_nWAIT      (1<<6)
+#define OSIRIS_CTRL0_PCMCIA_nIOIS16    (1<<7)
+
+#define OSIRIS_CTRL1_FIX8              (1<<0)
+
+#define OSIRIS_ID_REVMASK              (0x7)
+
+#endif /* __ASM_ARCH_OSIRISCPLD_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/osiris-map.h b/arch/arm/mach-s3c24xx/include/mach/osiris-map.h
new file mode 100644 (file)
index 0000000..17380f8
--- /dev/null
@@ -0,0 +1,42 @@
+/* arch/arm/mach-s3c2410/include/mach/osiris-map.h
+ *
+ * Copyright 2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * OSIRIS - Memory map definitions
+ *
+ * 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.
+*/
+
+/* needs arch/map.h including with this */
+
+#ifndef __ASM_ARCH_OSIRISMAP_H
+#define __ASM_ARCH_OSIRISMAP_H
+
+/* start peripherals off after the S3C2410 */
+
+#define OSIRIS_IOADDR(x)       (S3C2410_ADDR((x) + 0x04000000))
+
+#define OSIRIS_PA_CPLD         (S3C2410_CS1 | (1<<26))
+
+/* we put the CPLD registers next, to get them out of the way */
+
+#define OSIRIS_VA_CTRL0                OSIRIS_IOADDR(0x00000000)
+#define OSIRIS_PA_CTRL0                (OSIRIS_PA_CPLD)
+
+#define OSIRIS_VA_CTRL1                OSIRIS_IOADDR(0x00100000)
+#define OSIRIS_PA_CTRL1                (OSIRIS_PA_CPLD + (1<<23))
+
+#define OSIRIS_VA_CTRL2                OSIRIS_IOADDR(0x00200000)
+#define OSIRIS_PA_CTRL2                (OSIRIS_PA_CPLD + (2<<23))
+
+#define OSIRIS_VA_CTRL3                OSIRIS_IOADDR(0x00300000)
+#define OSIRIS_PA_CTRL3                (OSIRIS_PA_CPLD + (2<<23))
+
+#define OSIRIS_VA_IDREG                OSIRIS_IOADDR(0x00700000)
+#define OSIRIS_PA_IDREG                (OSIRIS_PA_CPLD + (7<<23))
+
+#endif /* __ASM_ARCH_OSIRISMAP_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/otom-map.h b/arch/arm/mach-s3c24xx/include/mach/otom-map.h
new file mode 100644 (file)
index 0000000..f9277a5
--- /dev/null
@@ -0,0 +1,30 @@
+/* arch/arm/mach-s3c2410/include/mach/otom-map.h
+ *
+ * (c) 2005 Guillaume GOURAT / NexVision
+ *          guillaume.gourat@nexvision.fr
+ *
+ * NexVision OTOM board memory map definitions
+ *
+ * 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.
+*/
+
+/* needs arch/map.h including with this */
+
+/* ok, we've used up to 0x01300000, now we need to find space for the
+ * peripherals that live in the nGCS[x] areas, which are quite numerous
+ * in their space.
+ */
+
+#ifndef __ASM_ARCH_OTOMMAP_H
+#define __ASM_ARCH_OTOMMAP_H
+
+#define OTOM_PA_CS8900A_BASE       (S3C2410_CS3 + 0x01000000)  /* nGCS3 +0x01000000 */
+#define OTOM_VA_CS8900A_BASE       S3C2410_ADDR(0x04000000)            /* 0xF4000000 */
+
+/* physical offset addresses for the peripherals */
+
+#define OTOM_PA_FLASH0_BASE        (S3C2410_CS0)                               /* Bank 0 */
+
+#endif /* __ASM_ARCH_OTOMMAP_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/pm-core.h b/arch/arm/mach-s3c24xx/include/mach/pm-core.h
new file mode 100644 (file)
index 0000000..2eef7e6
--- /dev/null
@@ -0,0 +1,67 @@
+/* linux/arch/arm/mach-s3c2410/include/pm-core.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C24xx - PM core support for arch/arm/plat-s3c/pm.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+static inline void s3c_pm_debug_init_uart(void)
+{
+       unsigned long tmp = __raw_readl(S3C2410_CLKCON);
+
+       /* re-start uart clocks */
+       tmp |= S3C2410_CLKCON_UART0;
+       tmp |= S3C2410_CLKCON_UART1;
+       tmp |= S3C2410_CLKCON_UART2;
+
+       __raw_writel(tmp, S3C2410_CLKCON);
+       udelay(10);
+}
+
+static inline void s3c_pm_arch_prepare_irqs(void)
+{
+       __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
+       __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
+
+       /* ack any outstanding external interrupts before we go to sleep */
+
+       __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
+       __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
+       __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
+
+}
+
+static inline void s3c_pm_arch_stop_clocks(void)
+{
+       __raw_writel(0x00, S3C2410_CLKCON);  /* turn off clocks over sleep */
+}
+
+static void s3c_pm_show_resume_irqs(int start, unsigned long which,
+                                   unsigned long mask);
+
+static inline void s3c_pm_arch_show_resume_irqs(void)
+{
+       S3C_PMDBG("post sleep: IRQs 0x%08x, 0x%08x\n",
+                 __raw_readl(S3C2410_SRCPND),
+                 __raw_readl(S3C2410_EINTPEND));
+
+       s3c_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
+                               s3c_irqwake_intmask);
+
+       s3c_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
+                               s3c_irqwake_eintmask);
+}
+
+static inline void s3c_pm_arch_update_uart(void __iomem *regs,
+                                          struct pm_uart_save *save)
+{
+}
+
+static inline void s3c_pm_restored_gpios(void) { }
+static inline void samsung_pm_saved_gpios(void) { }
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-clock.h b/arch/arm/mach-s3c24xx/include/mach/regs-clock.h
new file mode 100644 (file)
index 0000000..3415b60
--- /dev/null
@@ -0,0 +1,166 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-clock.h
+ *
+ * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C2410 clock register definitions
+*/
+
+#ifndef __ASM_ARM_REGS_CLOCK
+#define __ASM_ARM_REGS_CLOCK
+
+#define S3C2410_CLKREG(x) ((x) + S3C24XX_VA_CLKPWR)
+
+#define S3C2410_PLLVAL(_m,_p,_s) ((_m) << 12 | ((_p) << 4) | ((_s)))
+
+#define S3C2410_LOCKTIME    S3C2410_CLKREG(0x00)
+#define S3C2410_MPLLCON            S3C2410_CLKREG(0x04)
+#define S3C2410_UPLLCON            S3C2410_CLKREG(0x08)
+#define S3C2410_CLKCON     S3C2410_CLKREG(0x0C)
+#define S3C2410_CLKSLOW            S3C2410_CLKREG(0x10)
+#define S3C2410_CLKDIVN            S3C2410_CLKREG(0x14)
+
+#define S3C2410_CLKCON_IDLE         (1<<2)
+#define S3C2410_CLKCON_POWER        (1<<3)
+#define S3C2410_CLKCON_NAND         (1<<4)
+#define S3C2410_CLKCON_LCDC         (1<<5)
+#define S3C2410_CLKCON_USBH         (1<<6)
+#define S3C2410_CLKCON_USBD         (1<<7)
+#define S3C2410_CLKCON_PWMT         (1<<8)
+#define S3C2410_CLKCON_SDI          (1<<9)
+#define S3C2410_CLKCON_UART0        (1<<10)
+#define S3C2410_CLKCON_UART1        (1<<11)
+#define S3C2410_CLKCON_UART2        (1<<12)
+#define S3C2410_CLKCON_GPIO         (1<<13)
+#define S3C2410_CLKCON_RTC          (1<<14)
+#define S3C2410_CLKCON_ADC          (1<<15)
+#define S3C2410_CLKCON_IIC          (1<<16)
+#define S3C2410_CLKCON_IIS          (1<<17)
+#define S3C2410_CLKCON_SPI          (1<<18)
+
+/* DCLKCON register addresses in gpio.h */
+
+#define S3C2410_DCLKCON_DCLK0EN             (1<<0)
+#define S3C2410_DCLKCON_DCLK0_PCLK   (0<<1)
+#define S3C2410_DCLKCON_DCLK0_UCLK   (1<<1)
+#define S3C2410_DCLKCON_DCLK0_DIV(x) (((x) - 1 )<<4)
+#define S3C2410_DCLKCON_DCLK0_CMP(x) (((x) - 1 )<<8)
+#define S3C2410_DCLKCON_DCLK0_DIV_MASK ((0xf)<<4)
+#define S3C2410_DCLKCON_DCLK0_CMP_MASK ((0xf)<<8)
+
+#define S3C2410_DCLKCON_DCLK1EN             (1<<16)
+#define S3C2410_DCLKCON_DCLK1_PCLK   (0<<17)
+#define S3C2410_DCLKCON_DCLK1_UCLK   (1<<17)
+#define S3C2410_DCLKCON_DCLK1_DIV(x) (((x) - 1) <<20)
+#define S3C2410_DCLKCON_DCLK1_CMP(x) (((x) - 1) <<24)
+#define S3C2410_DCLKCON_DCLK1_DIV_MASK ((0xf) <<20)
+#define S3C2410_DCLKCON_DCLK1_CMP_MASK ((0xf) <<24)
+
+#define S3C2410_CLKDIVN_PDIVN       (1<<0)
+#define S3C2410_CLKDIVN_HDIVN       (1<<1)
+
+#define S3C2410_CLKSLOW_UCLK_OFF       (1<<7)
+#define S3C2410_CLKSLOW_MPLL_OFF       (1<<5)
+#define S3C2410_CLKSLOW_SLOW           (1<<4)
+#define S3C2410_CLKSLOW_SLOWVAL(x)     (x)
+#define S3C2410_CLKSLOW_GET_SLOWVAL(x) ((x) & 7)
+
+#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
+
+/* extra registers */
+#define S3C2440_CAMDIVN            S3C2410_CLKREG(0x18)
+
+#define S3C2440_CLKCON_CAMERA        (1<<19)
+#define S3C2440_CLKCON_AC97          (1<<20)
+
+#define S3C2440_CLKDIVN_PDIVN       (1<<0)
+#define S3C2440_CLKDIVN_HDIVN_MASK   (3<<1)
+#define S3C2440_CLKDIVN_HDIVN_1      (0<<1)
+#define S3C2440_CLKDIVN_HDIVN_2      (1<<1)
+#define S3C2440_CLKDIVN_HDIVN_4_8    (2<<1)
+#define S3C2440_CLKDIVN_HDIVN_3_6    (3<<1)
+#define S3C2440_CLKDIVN_UCLK         (1<<3)
+
+#define S3C2440_CAMDIVN_CAMCLK_MASK  (0xf<<0)
+#define S3C2440_CAMDIVN_CAMCLK_SEL   (1<<4)
+#define S3C2440_CAMDIVN_HCLK3_HALF   (1<<8)
+#define S3C2440_CAMDIVN_HCLK4_HALF   (1<<9)
+#define S3C2440_CAMDIVN_DVSEN        (1<<12)
+
+#define S3C2442_CAMDIVN_CAMCLK_DIV3  (1<<5)
+
+#endif /* CONFIG_CPU_S3C2440 or CONFIG_CPU_S3C2442 */
+
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+
+#define S3C2412_OSCSET         S3C2410_CLKREG(0x18)
+#define S3C2412_CLKSRC         S3C2410_CLKREG(0x1C)
+
+#define S3C2412_PLLCON_OFF             (1<<20)
+
+#define S3C2412_CLKDIVN_PDIVN          (1<<2)
+#define S3C2412_CLKDIVN_HDIVN_MASK     (3<<0)
+#define S3C2412_CLKDIVN_ARMDIVN                (1<<3)
+#define S3C2412_CLKDIVN_DVSEN          (1<<4)
+#define S3C2412_CLKDIVN_HALFHCLK       (1<<5)
+#define S3C2412_CLKDIVN_USB48DIV       (1<<6)
+#define S3C2412_CLKDIVN_UARTDIV_MASK   (15<<8)
+#define S3C2412_CLKDIVN_UARTDIV_SHIFT  (8)
+#define S3C2412_CLKDIVN_I2SDIV_MASK    (15<<12)
+#define S3C2412_CLKDIVN_I2SDIV_SHIFT   (12)
+#define S3C2412_CLKDIVN_CAMDIV_MASK    (15<<16)
+#define S3C2412_CLKDIVN_CAMDIV_SHIFT   (16)
+
+#define S3C2412_CLKCON_WDT             (1<<28)
+#define S3C2412_CLKCON_SPI             (1<<27)
+#define S3C2412_CLKCON_IIS             (1<<26)
+#define S3C2412_CLKCON_IIC             (1<<25)
+#define S3C2412_CLKCON_ADC             (1<<24)
+#define S3C2412_CLKCON_RTC             (1<<23)
+#define S3C2412_CLKCON_GPIO            (1<<22)
+#define S3C2412_CLKCON_UART2           (1<<21)
+#define S3C2412_CLKCON_UART1           (1<<20)
+#define S3C2412_CLKCON_UART0           (1<<19)
+#define S3C2412_CLKCON_SDI             (1<<18)
+#define S3C2412_CLKCON_PWMT            (1<<17)
+#define S3C2412_CLKCON_USBD            (1<<16)
+#define S3C2412_CLKCON_CAMCLK          (1<<15)
+#define S3C2412_CLKCON_UARTCLK         (1<<14)
+/* missing 13 */
+#define S3C2412_CLKCON_USB_HOST48      (1<<12)
+#define S3C2412_CLKCON_USB_DEV48       (1<<11)
+#define S3C2412_CLKCON_HCLKdiv2                (1<<10)
+#define S3C2412_CLKCON_HCLKx2          (1<<9)
+#define S3C2412_CLKCON_SDRAM           (1<<8)
+/* missing 7 */
+#define S3C2412_CLKCON_USBH            S3C2410_CLKCON_USBH
+#define S3C2412_CLKCON_LCDC            S3C2410_CLKCON_LCDC
+#define S3C2412_CLKCON_NAND            S3C2410_CLKCON_NAND
+#define S3C2412_CLKCON_DMA3            (1<<3)
+#define S3C2412_CLKCON_DMA2            (1<<2)
+#define S3C2412_CLKCON_DMA1            (1<<1)
+#define S3C2412_CLKCON_DMA0            (1<<0)
+
+/* clock sourec controls */
+
+#define S3C2412_CLKSRC_EXTCLKDIV_MASK          (7 << 0)
+#define S3C2412_CLKSRC_EXTCLKDIV_SHIFT         (0)
+#define S3C2412_CLKSRC_MDIVCLK_EXTCLKDIV       (1<<3)
+#define S3C2412_CLKSRC_MSYSCLK_MPLL            (1<<4)
+#define S3C2412_CLKSRC_USYSCLK_UPLL            (1<<5)
+#define S3C2412_CLKSRC_UARTCLK_MPLL            (1<<8)
+#define S3C2412_CLKSRC_I2SCLK_MPLL             (1<<9)
+#define S3C2412_CLKSRC_USBCLK_HCLK             (1<<10)
+#define S3C2412_CLKSRC_CAMCLK_HCLK             (1<<11)
+#define S3C2412_CLKSRC_UREFCLK_EXTCLK  (1<<12)
+#define S3C2412_CLKSRC_EREFCLK_EXTCLK  (1<<14)
+
+#endif /* CONFIG_CPU_S3C2412 | CONFIG_CPU_S3C2413 */
+
+#define S3C2416_CLKDIV2                S3C2410_CLKREG(0x28)
+
+#endif /* __ASM_ARM_REGS_CLOCK */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-dsc.h b/arch/arm/mach-s3c24xx/include/mach/regs-dsc.h
new file mode 100644 (file)
index 0000000..98fd4a0
--- /dev/null
@@ -0,0 +1,220 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-dsc.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2440/S3C2412 Signal Drive Strength Control
+*/
+
+
+#ifndef __ASM_ARCH_REGS_DSC_H
+#define __ASM_ARCH_REGS_DSC_H "2440-dsc"
+
+#if defined(CONFIG_CPU_S3C2412)
+#define S3C2412_DSC0      S3C2410_GPIOREG(0xdc)
+#define S3C2412_DSC1      S3C2410_GPIOREG(0xe0)
+#endif
+
+#if defined(CONFIG_CPU_S3C2416)
+#define S3C2416_DSC0      S3C2410_GPIOREG(0xc0)
+#define S3C2416_DSC1      S3C2410_GPIOREG(0xc4)
+#define S3C2416_DSC2      S3C2410_GPIOREG(0xc8)
+#define S3C2416_DSC3      S3C2410_GPIOREG(0x110)
+
+#define S3C2416_SELECT_DSC0    (0 << 30)
+#define S3C2416_SELECT_DSC1    (1 << 30)
+#define S3C2416_SELECT_DSC2    (2 << 30)
+#define S3C2416_SELECT_DSC3    (3 << 30)
+
+#define S3C2416_DSC_GETSHIFT(x)        (x & 30)
+
+#define S3C2416_DSC0_CF                (S3C2416_SELECT_DSC0 | 28)
+#define        S3C2416_DSC0_CF_5mA     (0 << 28)
+#define        S3C2416_DSC0_CF_10mA    (1 << 28)
+#define        S3C2416_DSC0_CF_15mA    (2 << 28)
+#define        S3C2416_DSC0_CF_21mA    (3 << 28)
+#define        S3C2416_DSC0_CF_MASK    (3 << 28)
+
+#define S3C2416_DSC0_nRBE      (S3C2416_SELECT_DSC0 | 26)
+#define        S3C2416_DSC0_nRBE_5mA   (0 << 26)
+#define        S3C2416_DSC0_nRBE_10mA  (1 << 26)
+#define        S3C2416_DSC0_nRBE_15mA  (2 << 26)
+#define        S3C2416_DSC0_nRBE_21mA  (3 << 26)
+#define        S3C2416_DSC0_nRBE_MASK  (3 << 26)
+
+#define S3C2416_DSC0_nROE      (S3C2416_SELECT_DSC0 | 24)
+#define        S3C2416_DSC0_nROE_5mA   (0 << 24)
+#define        S3C2416_DSC0_nROE_10mA  (1 << 24)
+#define        S3C2416_DSC0_nROE_15mA  (2 << 24)
+#define        S3C2416_DSC0_nROE_21mA  (3 << 24)
+#define        S3C2416_DSC0_nROE_MASK  (3 << 24)
+
+#endif
+
+#if defined(CONFIG_CPU_S3C244X)
+
+#define S3C2440_DSC0      S3C2410_GPIOREG(0xc4)
+#define S3C2440_DSC1      S3C2410_GPIOREG(0xc8)
+
+#define S3C2440_SELECT_DSC0 (0)
+#define S3C2440_SELECT_DSC1 (1<<31)
+
+#define S3C2440_DSC_GETSHIFT(x) ((x) & 31)
+
+#define S3C2440_DSC0_DISABLE   (1<<31)
+
+#define S3C2440_DSC0_ADDR       (S3C2440_SELECT_DSC0 | 8)
+#define S3C2440_DSC0_ADDR_12mA  (0<<8)
+#define S3C2440_DSC0_ADDR_10mA  (1<<8)
+#define S3C2440_DSC0_ADDR_8mA   (2<<8)
+#define S3C2440_DSC0_ADDR_6mA   (3<<8)
+#define S3C2440_DSC0_ADDR_MASK  (3<<8)
+
+/* D24..D31 */
+#define S3C2440_DSC0_DATA3      (S3C2440_SELECT_DSC0 | 6)
+#define S3C2440_DSC0_DATA3_12mA (0<<6)
+#define S3C2440_DSC0_DATA3_10mA (1<<6)
+#define S3C2440_DSC0_DATA3_8mA  (2<<6)
+#define S3C2440_DSC0_DATA3_6mA  (3<<6)
+#define S3C2440_DSC0_DATA3_MASK (3<<6)
+
+/* D16..D23 */
+#define S3C2440_DSC0_DATA2      (S3C2440_SELECT_DSC0 | 4)
+#define S3C2440_DSC0_DATA2_12mA (0<<4)
+#define S3C2440_DSC0_DATA2_10mA (1<<4)
+#define S3C2440_DSC0_DATA2_8mA  (2<<4)
+#define S3C2440_DSC0_DATA2_6mA  (3<<4)
+#define S3C2440_DSC0_DATA2_MASK (3<<4)
+
+/* D8..D15 */
+#define S3C2440_DSC0_DATA1      (S3C2440_SELECT_DSC0 | 2)
+#define S3C2440_DSC0_DATA1_12mA (0<<2)
+#define S3C2440_DSC0_DATA1_10mA (1<<2)
+#define S3C2440_DSC0_DATA1_8mA  (2<<2)
+#define S3C2440_DSC0_DATA1_6mA  (3<<2)
+#define S3C2440_DSC0_DATA1_MASK (3<<2)
+
+/* D0..D7 */
+#define S3C2440_DSC0_DATA0      (S3C2440_SELECT_DSC0 | 0)
+#define S3C2440_DSC0_DATA0_12mA (0<<0)
+#define S3C2440_DSC0_DATA0_10mA (1<<0)
+#define S3C2440_DSC0_DATA0_8mA  (2<<0)
+#define S3C2440_DSC0_DATA0_6mA  (3<<0)
+#define S3C2440_DSC0_DATA0_MASK (3<<0)
+
+#define S3C2440_DSC1_SCK1       (S3C2440_SELECT_DSC1 | 28)
+#define S3C2440_DSC1_SCK1_12mA  (0<<28)
+#define S3C2440_DSC1_SCK1_10mA  (1<<28)
+#define S3C2440_DSC1_SCK1_8mA   (2<<28)
+#define S3C2440_DSC1_SCK1_6mA   (3<<28)
+#define S3C2440_DSC1_SCK1_MASK  (3<<28)
+
+#define S3C2440_DSC1_SCK0       (S3C2440_SELECT_DSC1 | 26)
+#define S3C2440_DSC1_SCK0_12mA  (0<<26)
+#define S3C2440_DSC1_SCK0_10mA  (1<<26)
+#define S3C2440_DSC1_SCK0_8mA   (2<<26)
+#define S3C2440_DSC1_SCK0_6mA   (3<<26)
+#define S3C2440_DSC1_SCK0_MASK  (3<<26)
+
+#define S3C2440_DSC1_SCKE       (S3C2440_SELECT_DSC1 | 24)
+#define S3C2440_DSC1_SCKE_10mA  (0<<24)
+#define S3C2440_DSC1_SCKE_8mA   (1<<24)
+#define S3C2440_DSC1_SCKE_6mA   (2<<24)
+#define S3C2440_DSC1_SCKE_4mA   (3<<24)
+#define S3C2440_DSC1_SCKE_MASK  (3<<24)
+
+/* SDRAM nRAS/nCAS */
+#define S3C2440_DSC1_SDR        (S3C2440_SELECT_DSC1 | 22)
+#define S3C2440_DSC1_SDR_10mA   (0<<22)
+#define S3C2440_DSC1_SDR_8mA    (1<<22)
+#define S3C2440_DSC1_SDR_6mA    (2<<22)
+#define S3C2440_DSC1_SDR_4mA    (3<<22)
+#define S3C2440_DSC1_SDR_MASK   (3<<22)
+
+/* NAND Flash Controller */
+#define S3C2440_DSC1_NFC        (S3C2440_SELECT_DSC1 | 20)
+#define S3C2440_DSC1_NFC_10mA   (0<<20)
+#define S3C2440_DSC1_NFC_8mA    (1<<20)
+#define S3C2440_DSC1_NFC_6mA    (2<<20)
+#define S3C2440_DSC1_NFC_4mA    (3<<20)
+#define S3C2440_DSC1_NFC_MASK   (3<<20)
+
+/* nBE[0..3] */
+#define S3C2440_DSC1_nBE        (S3C2440_SELECT_DSC1 | 18)
+#define S3C2440_DSC1_nBE_10mA   (0<<18)
+#define S3C2440_DSC1_nBE_8mA    (1<<18)
+#define S3C2440_DSC1_nBE_6mA    (2<<18)
+#define S3C2440_DSC1_nBE_4mA    (3<<18)
+#define S3C2440_DSC1_nBE_MASK   (3<<18)
+
+#define S3C2440_DSC1_WOE        (S3C2440_SELECT_DSC1 | 16)
+#define S3C2440_DSC1_WOE_10mA   (0<<16)
+#define S3C2440_DSC1_WOE_8mA    (1<<16)
+#define S3C2440_DSC1_WOE_6mA    (2<<16)
+#define S3C2440_DSC1_WOE_4mA    (3<<16)
+#define S3C2440_DSC1_WOE_MASK   (3<<16)
+
+#define S3C2440_DSC1_CS7        (S3C2440_SELECT_DSC1 | 14)
+#define S3C2440_DSC1_CS7_10mA   (0<<14)
+#define S3C2440_DSC1_CS7_8mA    (1<<14)
+#define S3C2440_DSC1_CS7_6mA    (2<<14)
+#define S3C2440_DSC1_CS7_4mA    (3<<14)
+#define S3C2440_DSC1_CS7_MASK   (3<<14)
+
+#define S3C2440_DSC1_CS6        (S3C2440_SELECT_DSC1 | 12)
+#define S3C2440_DSC1_CS6_10mA   (0<<12)
+#define S3C2440_DSC1_CS6_8mA    (1<<12)
+#define S3C2440_DSC1_CS6_6mA    (2<<12)
+#define S3C2440_DSC1_CS6_4mA    (3<<12)
+#define S3C2440_DSC1_CS6_MASK   (3<<12)
+
+#define S3C2440_DSC1_CS5        (S3C2440_SELECT_DSC1 | 10)
+#define S3C2440_DSC1_CS5_10mA   (0<<10)
+#define S3C2440_DSC1_CS5_8mA    (1<<10)
+#define S3C2440_DSC1_CS5_6mA    (2<<10)
+#define S3C2440_DSC1_CS5_4mA    (3<<10)
+#define S3C2440_DSC1_CS5_MASK   (3<<10)
+
+#define S3C2440_DSC1_CS4        (S3C2440_SELECT_DSC1 | 8)
+#define S3C2440_DSC1_CS4_10mA   (0<<8)
+#define S3C2440_DSC1_CS4_8mA    (1<<8)
+#define S3C2440_DSC1_CS4_6mA    (2<<8)
+#define S3C2440_DSC1_CS4_4mA    (3<<8)
+#define S3C2440_DSC1_CS4_MASK   (3<<8)
+
+#define S3C2440_DSC1_CS3        (S3C2440_SELECT_DSC1 | 6)
+#define S3C2440_DSC1_CS3_10mA   (0<<6)
+#define S3C2440_DSC1_CS3_8mA    (1<<6)
+#define S3C2440_DSC1_CS3_6mA    (2<<6)
+#define S3C2440_DSC1_CS3_4mA    (3<<6)
+#define S3C2440_DSC1_CS3_MASK   (3<<6)
+
+#define S3C2440_DSC1_CS2        (S3C2440_SELECT_DSC1 | 4)
+#define S3C2440_DSC1_CS2_10mA   (0<<4)
+#define S3C2440_DSC1_CS2_8mA    (1<<4)
+#define S3C2440_DSC1_CS2_6mA    (2<<4)
+#define S3C2440_DSC1_CS2_4mA    (3<<4)
+#define S3C2440_DSC1_CS2_MASK   (3<<4)
+
+#define S3C2440_DSC1_CS1        (S3C2440_SELECT_DSC1 | 2)
+#define S3C2440_DSC1_CS1_10mA   (0<<2)
+#define S3C2440_DSC1_CS1_8mA    (1<<2)
+#define S3C2440_DSC1_CS1_6mA    (2<<2)
+#define S3C2440_DSC1_CS1_4mA    (3<<2)
+#define S3C2440_DSC1_CS1_MASK   (3<<2)
+
+#define S3C2440_DSC1_CS0        (S3C2440_SELECT_DSC1 | 0)
+#define S3C2440_DSC1_CS0_10mA   (0<<0)
+#define S3C2440_DSC1_CS0_8mA    (1<<0)
+#define S3C2440_DSC1_CS0_6mA    (2<<0)
+#define S3C2440_DSC1_CS0_4mA    (3<<0)
+#define S3C2440_DSC1_CS0_MASK   (3<<0)
+
+#endif /* CONFIG_CPU_S3C2440 */
+
+#endif /* __ASM_ARCH_REGS_DSC_H */
+
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h b/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h
new file mode 100644 (file)
index 0000000..cac1ad6
--- /dev/null
@@ -0,0 +1,602 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-gpio.h
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics <linux@simtec.co.uk>
+ *     http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 GPIO register definitions
+*/
+
+
+#ifndef __ASM_ARCH_REGS_GPIO_H
+#define __ASM_ARCH_REGS_GPIO_H
+
+#include <mach/gpio-nrs.h>
+
+#define S3C24XX_MISCCR         S3C24XX_GPIOREG2(0x80)
+
+/* general configuration options */
+
+#define S3C2410_GPIO_LEAVE   (0xFFFFFFFF)
+#define S3C2410_GPIO_INPUT   (0xFFFFFFF0)      /* not available on A */
+#define S3C2410_GPIO_OUTPUT  (0xFFFFFFF1)
+#define S3C2410_GPIO_IRQ     (0xFFFFFFF2)      /* not available for all */
+#define S3C2410_GPIO_SFN2    (0xFFFFFFF2)      /* bank A => addr/cs/nand */
+#define S3C2410_GPIO_SFN3    (0xFFFFFFF3)      /* not available on A */
+
+/* register address for the GPIO registers.
+ * S3C24XX_GPIOREG2 is for the second set of registers in the
+ * GPIO which move between s3c2410 and s3c2412 type systems */
+
+#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)
+#define S3C24XX_GPIOREG2(x) ((x) + S3C24XX_VA_GPIO2)
+
+
+/* configure GPIO ports A..G */
+
+/* port A - S3C2410: 22bits, zero in bit X makes pin X output
+ * 1 makes port special function, this is default
+*/
+#define S3C2410_GPACON    S3C2410_GPIOREG(0x00)
+#define S3C2410_GPADAT    S3C2410_GPIOREG(0x04)
+
+#define S3C2410_GPA0_ADDR0   (1<<0)
+#define S3C2410_GPA1_ADDR16  (1<<1)
+#define S3C2410_GPA2_ADDR17  (1<<2)
+#define S3C2410_GPA3_ADDR18  (1<<3)
+#define S3C2410_GPA4_ADDR19  (1<<4)
+#define S3C2410_GPA5_ADDR20  (1<<5)
+#define S3C2410_GPA6_ADDR21  (1<<6)
+#define S3C2410_GPA7_ADDR22  (1<<7)
+#define S3C2410_GPA8_ADDR23  (1<<8)
+#define S3C2410_GPA9_ADDR24  (1<<9)
+#define S3C2410_GPA10_ADDR25 (1<<10)
+#define S3C2410_GPA11_ADDR26 (1<<11)
+#define S3C2410_GPA12_nGCS1  (1<<12)
+#define S3C2410_GPA13_nGCS2  (1<<13)
+#define S3C2410_GPA14_nGCS3  (1<<14)
+#define S3C2410_GPA15_nGCS4  (1<<15)
+#define S3C2410_GPA16_nGCS5  (1<<16)
+#define S3C2410_GPA17_CLE    (1<<17)
+#define S3C2410_GPA18_ALE    (1<<18)
+#define S3C2410_GPA19_nFWE   (1<<19)
+#define S3C2410_GPA20_nFRE   (1<<20)
+#define S3C2410_GPA21_nRSTOUT (1<<21)
+#define S3C2410_GPA22_nFCE   (1<<22)
+
+/* 0x08 and 0x0c are reserved on S3C2410 */
+
+/* S3C2410:
+ * GPB is 10 IO pins, each configured by 2 bits each in GPBCON.
+ *   00 = input, 01 = output, 10=special function, 11=reserved
+
+ * bit 0,1 = pin 0, 2,3= pin 1...
+ *
+ * CPBUP = pull up resistor control, 1=disabled, 0=enabled
+*/
+
+#define S3C2410_GPBCON    S3C2410_GPIOREG(0x10)
+#define S3C2410_GPBDAT    S3C2410_GPIOREG(0x14)
+#define S3C2410_GPBUP     S3C2410_GPIOREG(0x18)
+
+/* no i/o pin in port b can have value 3 (unless it is a s3c2443) ! */
+
+#define S3C2410_GPB0_TOUT0   (0x02 << 0)
+
+#define S3C2410_GPB1_TOUT1   (0x02 << 2)
+
+#define S3C2410_GPB2_TOUT2   (0x02 << 4)
+
+#define S3C2410_GPB3_TOUT3   (0x02 << 6)
+
+#define S3C2410_GPB4_TCLK0   (0x02 << 8)
+#define S3C2410_GPB4_MASK    (0x03 << 8)
+
+#define S3C2410_GPB5_nXBACK  (0x02 << 10)
+#define S3C2443_GPB5_XBACK   (0x03 << 10)
+
+#define S3C2410_GPB6_nXBREQ  (0x02 << 12)
+#define S3C2443_GPB6_XBREQ   (0x03 << 12)
+
+#define S3C2410_GPB7_nXDACK1 (0x02 << 14)
+#define S3C2443_GPB7_XDACK1  (0x03 << 14)
+
+#define S3C2410_GPB8_nXDREQ1 (0x02 << 16)
+
+#define S3C2410_GPB9_nXDACK0 (0x02 << 18)
+#define S3C2443_GPB9_XDACK0  (0x03 << 18)
+
+#define S3C2410_GPB10_nXDRE0 (0x02 << 20)
+#define S3C2443_GPB10_XDREQ0 (0x03 << 20)
+
+#define S3C2410_GPB_PUPDIS(x)  (1<<(x))
+
+/* Port C consits of 16 GPIO/Special function
+ *
+ * almost identical setup to port b, but the special functions are mostly
+ * to do with the video system's sync/etc.
+*/
+
+#define S3C2410_GPCCON    S3C2410_GPIOREG(0x20)
+#define S3C2410_GPCDAT    S3C2410_GPIOREG(0x24)
+#define S3C2410_GPCUP     S3C2410_GPIOREG(0x28)
+#define S3C2410_GPC0_LEND      (0x02 << 0)
+#define S3C2410_GPC1_VCLK      (0x02 << 2)
+#define S3C2410_GPC2_VLINE     (0x02 << 4)
+#define S3C2410_GPC3_VFRAME    (0x02 << 6)
+#define S3C2410_GPC4_VM                (0x02 << 8)
+#define S3C2410_GPC5_LCDVF0    (0x02 << 10)
+#define S3C2410_GPC6_LCDVF1    (0x02 << 12)
+#define S3C2410_GPC7_LCDVF2    (0x02 << 14)
+#define S3C2410_GPC8_VD0       (0x02 << 16)
+#define S3C2410_GPC9_VD1       (0x02 << 18)
+#define S3C2410_GPC10_VD2      (0x02 << 20)
+#define S3C2410_GPC11_VD3      (0x02 << 22)
+#define S3C2410_GPC12_VD4      (0x02 << 24)
+#define S3C2410_GPC13_VD5      (0x02 << 26)
+#define S3C2410_GPC14_VD6      (0x02 << 28)
+#define S3C2410_GPC15_VD7      (0x02 << 30)
+#define S3C2410_GPC_PUPDIS(x)  (1<<(x))
+
+/*
+ * S3C2410: Port D consists of 16 GPIO/Special function
+ *
+ * almost identical setup to port b, but the special functions are mostly
+ * to do with the video system's data.
+ *
+ * almost identical setup to port c
+*/
+
+#define S3C2410_GPDCON    S3C2410_GPIOREG(0x30)
+#define S3C2410_GPDDAT    S3C2410_GPIOREG(0x34)
+#define S3C2410_GPDUP     S3C2410_GPIOREG(0x38)
+
+#define S3C2410_GPD0_VD8       (0x02 << 0)
+#define S3C2442_GPD0_nSPICS1   (0x03 << 0)
+
+#define S3C2410_GPD1_VD9       (0x02 << 2)
+#define S3C2442_GPD1_SPICLK1   (0x03 << 2)
+
+#define S3C2410_GPD2_VD10      (0x02 << 4)
+
+#define S3C2410_GPD3_VD11      (0x02 << 6)
+
+#define S3C2410_GPD4_VD12      (0x02 << 8)
+
+#define S3C2410_GPD5_VD13      (0x02 << 10)
+
+#define S3C2410_GPD6_VD14      (0x02 << 12)
+
+#define S3C2410_GPD7_VD15      (0x02 << 14)
+
+#define S3C2410_GPD8_VD16      (0x02 << 16)
+#define S3C2440_GPD8_SPIMISO1  (0x03 << 16)
+
+#define S3C2410_GPD9_VD17      (0x02 << 18)
+#define S3C2440_GPD9_SPIMOSI1  (0x03 << 18)
+
+#define S3C2410_GPD10_VD18     (0x02 << 20)
+#define S3C2440_GPD10_SPICLK1  (0x03 << 20)
+
+#define S3C2410_GPD11_VD19     (0x02 << 22)
+
+#define S3C2410_GPD12_VD20     (0x02 << 24)
+
+#define S3C2410_GPD13_VD21     (0x02 << 26)
+
+#define S3C2410_GPD14_VD22     (0x02 << 28)
+#define S3C2410_GPD14_nSS1     (0x03 << 28)
+
+#define S3C2410_GPD15_VD23     (0x02 << 30)
+#define S3C2410_GPD15_nSS0     (0x03 << 30)
+
+#define S3C2410_GPD_PUPDIS(x)  (1<<(x))
+
+/* S3C2410:
+ * Port E consists of 16 GPIO/Special function
+ *
+ * again, the same as port B, but dealing with I2S, SDI, and
+ * more miscellaneous functions
+ *
+ * GPIO / interrupt inputs
+*/
+
+#define S3C2410_GPECON    S3C2410_GPIOREG(0x40)
+#define S3C2410_GPEDAT    S3C2410_GPIOREG(0x44)
+#define S3C2410_GPEUP     S3C2410_GPIOREG(0x48)
+
+#define S3C2410_GPE0_I2SLRCK   (0x02 << 0)
+#define S3C2443_GPE0_AC_nRESET (0x03 << 0)
+#define S3C2410_GPE0_MASK      (0x03 << 0)
+
+#define S3C2410_GPE1_I2SSCLK   (0x02 << 2)
+#define S3C2443_GPE1_AC_SYNC   (0x03 << 2)
+#define S3C2410_GPE1_MASK      (0x03 << 2)
+
+#define S3C2410_GPE2_CDCLK     (0x02 << 4)
+#define S3C2443_GPE2_AC_BITCLK (0x03 << 4)
+
+#define S3C2410_GPE3_I2SSDI    (0x02 << 6)
+#define S3C2443_GPE3_AC_SDI    (0x03 << 6)
+#define S3C2410_GPE3_nSS0      (0x03 << 6)
+#define S3C2410_GPE3_MASK      (0x03 << 6)
+
+#define S3C2410_GPE4_I2SSDO    (0x02 << 8)
+#define S3C2443_GPE4_AC_SDO    (0x03 << 8)
+#define S3C2410_GPE4_I2SSDI    (0x03 << 8)
+#define S3C2410_GPE4_MASK      (0x03 << 8)
+
+#define S3C2410_GPE5_SDCLK     (0x02 << 10)
+#define S3C2443_GPE5_SD1_CLK   (0x02 << 10)
+#define S3C2443_GPE5_AC_BITCLK (0x03 << 10)
+
+#define S3C2410_GPE6_SDCMD     (0x02 << 12)
+#define S3C2443_GPE6_SD1_CMD   (0x02 << 12)
+#define S3C2443_GPE6_AC_SDI    (0x03 << 12)
+
+#define S3C2410_GPE7_SDDAT0    (0x02 << 14)
+#define S3C2443_GPE5_SD1_DAT0  (0x02 << 14)
+#define S3C2443_GPE7_AC_SDO    (0x03 << 14)
+
+#define S3C2410_GPE8_SDDAT1    (0x02 << 16)
+#define S3C2443_GPE8_SD1_DAT1  (0x02 << 16)
+#define S3C2443_GPE8_AC_SYNC   (0x03 << 16)
+
+#define S3C2410_GPE9_SDDAT2    (0x02 << 18)
+#define S3C2443_GPE9_SD1_DAT2  (0x02 << 18)
+#define S3C2443_GPE9_AC_nRESET (0x03 << 18)
+
+#define S3C2410_GPE10_SDDAT3   (0x02 << 20)
+#define S3C2443_GPE10_SD1_DAT3 (0x02 << 20)
+
+#define S3C2410_GPE11_SPIMISO0 (0x02 << 22)
+
+#define S3C2410_GPE12_SPIMOSI0 (0x02 << 24)
+
+#define S3C2410_GPE13_SPICLK0  (0x02 << 26)
+
+#define S3C2410_GPE14_IICSCL   (0x02 << 28)
+#define S3C2410_GPE14_MASK     (0x03 << 28)
+
+#define S3C2410_GPE15_IICSDA   (0x02 << 30)
+#define S3C2410_GPE15_MASK     (0x03 << 30)
+
+#define S3C2440_GPE0_ACSYNC    (0x03 << 0)
+#define S3C2440_GPE1_ACBITCLK  (0x03 << 2)
+#define S3C2440_GPE2_ACRESET   (0x03 << 4)
+#define S3C2440_GPE3_ACIN      (0x03 << 6)
+#define S3C2440_GPE4_ACOUT     (0x03 << 8)
+
+#define S3C2410_GPE_PUPDIS(x)  (1<<(x))
+
+/* S3C2410:
+ * Port F consists of 8 GPIO/Special function
+ *
+ * GPIO / interrupt inputs
+ *
+ * GPFCON has 2 bits for each of the input pins on port F
+ *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 undefined
+ *
+ * pull up works like all other ports.
+ *
+ * GPIO/serial/misc pins
+*/
+
+#define S3C2410_GPFCON    S3C2410_GPIOREG(0x50)
+#define S3C2410_GPFDAT    S3C2410_GPIOREG(0x54)
+#define S3C2410_GPFUP     S3C2410_GPIOREG(0x58)
+
+#define S3C2410_GPF0_EINT0  (0x02 << 0)
+#define S3C2410_GPF1_EINT1  (0x02 << 2)
+#define S3C2410_GPF2_EINT2  (0x02 << 4)
+#define S3C2410_GPF3_EINT3  (0x02 << 6)
+#define S3C2410_GPF4_EINT4  (0x02 << 8)
+#define S3C2410_GPF5_EINT5  (0x02 << 10)
+#define S3C2410_GPF6_EINT6  (0x02 << 12)
+#define S3C2410_GPF7_EINT7  (0x02 << 14)
+#define S3C2410_GPF_PUPDIS(x)  (1<<(x))
+
+/* S3C2410:
+ * Port G consists of 8 GPIO/IRQ/Special function
+ *
+ * GPGCON has 2 bits for each of the input pins on port F
+ *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func
+ *
+ * pull up works like all other ports.
+*/
+
+#define S3C2410_GPGCON    S3C2410_GPIOREG(0x60)
+#define S3C2410_GPGDAT    S3C2410_GPIOREG(0x64)
+#define S3C2410_GPGUP     S3C2410_GPIOREG(0x68)
+
+#define S3C2410_GPG0_EINT8    (0x02 << 0)
+
+#define S3C2410_GPG1_EINT9    (0x02 << 2)
+
+#define S3C2410_GPG2_EINT10   (0x02 << 4)
+#define S3C2410_GPG2_nSS0     (0x03 << 4)
+
+#define S3C2410_GPG3_EINT11   (0x02 << 6)
+#define S3C2410_GPG3_nSS1     (0x03 << 6)
+
+#define S3C2410_GPG4_EINT12   (0x02 << 8)
+#define S3C2410_GPG4_LCDPWREN (0x03 << 8)
+#define S3C2443_GPG4_LCDPWRDN (0x03 << 8)
+
+#define S3C2410_GPG5_EINT13   (0x02 << 10)
+#define S3C2410_GPG5_SPIMISO1 (0x03 << 10)     /* not s3c2443 */
+
+#define S3C2410_GPG6_EINT14   (0x02 << 12)
+#define S3C2410_GPG6_SPIMOSI1 (0x03 << 12)
+
+#define S3C2410_GPG7_EINT15   (0x02 << 14)
+#define S3C2410_GPG7_SPICLK1  (0x03 << 14)
+
+#define S3C2410_GPG8_EINT16   (0x02 << 16)
+
+#define S3C2410_GPG9_EINT17   (0x02 << 18)
+
+#define S3C2410_GPG10_EINT18  (0x02 << 20)
+
+#define S3C2410_GPG11_EINT19  (0x02 << 22)
+#define S3C2410_GPG11_TCLK1   (0x03 << 22)
+#define S3C2443_GPG11_CF_nIREQ (0x03 << 22)
+
+#define S3C2410_GPG12_EINT20  (0x02 << 24)
+#define S3C2410_GPG12_XMON    (0x03 << 24)
+#define S3C2442_GPG12_nSPICS0 (0x03 << 24)
+#define S3C2443_GPG12_nINPACK (0x03 << 24)
+
+#define S3C2410_GPG13_EINT21  (0x02 << 26)
+#define S3C2410_GPG13_nXPON   (0x03 << 26)
+#define S3C2443_GPG13_CF_nREG (0x03 << 26)
+
+#define S3C2410_GPG14_EINT22  (0x02 << 28)
+#define S3C2410_GPG14_YMON    (0x03 << 28)
+#define S3C2443_GPG14_CF_RESET (0x03 << 28)
+
+#define S3C2410_GPG15_EINT23  (0x02 << 30)
+#define S3C2410_GPG15_nYPON   (0x03 << 30)
+#define S3C2443_GPG15_CF_PWR  (0x03 << 30)
+
+#define S3C2410_GPG_PUPDIS(x)  (1<<(x))
+
+/* Port H consists of11 GPIO/serial/Misc pins
+ *
+ * GPGCON has 2 bits for each of the input pins on port F
+ *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func
+ *
+ * pull up works like all other ports.
+*/
+
+#define S3C2410_GPHCON    S3C2410_GPIOREG(0x70)
+#define S3C2410_GPHDAT    S3C2410_GPIOREG(0x74)
+#define S3C2410_GPHUP     S3C2410_GPIOREG(0x78)
+
+#define S3C2410_GPH0_nCTS0  (0x02 << 0)
+#define S3C2416_GPH0_TXD0  (0x02 << 0)
+
+#define S3C2410_GPH1_nRTS0  (0x02 << 2)
+#define S3C2416_GPH1_RXD0  (0x02 << 2)
+
+#define S3C2410_GPH2_TXD0   (0x02 << 4)
+#define S3C2416_GPH2_TXD1   (0x02 << 4)
+
+#define S3C2410_GPH3_RXD0   (0x02 << 6)
+#define S3C2416_GPH3_RXD1   (0x02 << 6)
+
+#define S3C2410_GPH4_TXD1   (0x02 << 8)
+#define S3C2416_GPH4_TXD2   (0x02 << 8)
+
+#define S3C2410_GPH5_RXD1   (0x02 << 10)
+#define S3C2416_GPH5_RXD2   (0x02 << 10)
+
+#define S3C2410_GPH6_TXD2   (0x02 << 12)
+#define S3C2416_GPH6_TXD3   (0x02 << 12)
+#define S3C2410_GPH6_nRTS1  (0x03 << 12)
+#define S3C2416_GPH6_nRTS2  (0x03 << 12)
+
+#define S3C2410_GPH7_RXD2   (0x02 << 14)
+#define S3C2416_GPH7_RXD3   (0x02 << 14)
+#define S3C2410_GPH7_nCTS1  (0x03 << 14)
+#define S3C2416_GPH7_nCTS2  (0x03 << 14)
+
+#define S3C2410_GPH8_UCLK   (0x02 << 16)
+#define S3C2416_GPH8_nCTS0  (0x02 << 16)
+
+#define S3C2410_GPH9_CLKOUT0  (0x02 << 18)
+#define S3C2442_GPH9_nSPICS0  (0x03 << 18)
+#define S3C2416_GPH9_nRTS0    (0x02 << 18)
+
+#define S3C2410_GPH10_CLKOUT1 (0x02 << 20)
+#define S3C2416_GPH10_nCTS1   (0x02 << 20)
+
+#define S3C2416_GPH11_nRTS1   (0x02 << 22)
+
+#define S3C2416_GPH12_EXTUARTCLK (0x02 << 24)
+
+#define S3C2416_GPH13_CLKOUT0 (0x02 << 26)
+
+#define S3C2416_GPH14_CLKOUT1 (0x02 << 28)
+
+/* The S3C2412 and S3C2413 move the GPJ register set to after
+ * GPH, which means all registers after 0x80 are now offset by 0x10
+ * for the 2412/2413 from the 2410/2440/2442
+*/
+
+/* S3C2443 and above */
+#define S3C2440_GPJCON    S3C2410_GPIOREG(0xD0)
+#define S3C2440_GPJDAT    S3C2410_GPIOREG(0xD4)
+#define S3C2440_GPJUP     S3C2410_GPIOREG(0xD8)
+
+#define S3C2443_GPKCON    S3C2410_GPIOREG(0xE0)
+#define S3C2443_GPKDAT    S3C2410_GPIOREG(0xE4)
+#define S3C2443_GPKUP     S3C2410_GPIOREG(0xE8)
+
+#define S3C2443_GPLCON    S3C2410_GPIOREG(0xF0)
+#define S3C2443_GPLDAT    S3C2410_GPIOREG(0xF4)
+#define S3C2443_GPLUP     S3C2410_GPIOREG(0xF8)
+
+#define S3C2443_GPMCON    S3C2410_GPIOREG(0x100)
+#define S3C2443_GPMDAT    S3C2410_GPIOREG(0x104)
+#define S3C2443_GPMUP     S3C2410_GPIOREG(0x108)
+
+/* miscellaneous control */
+#define S3C2410_MISCCR    S3C2410_GPIOREG(0x80)
+#define S3C2410_DCLKCON           S3C2410_GPIOREG(0x84)
+
+#define S3C24XX_DCLKCON           S3C24XX_GPIOREG2(0x84)
+
+/* see clock.h for dclk definitions */
+
+/* pullup control on databus */
+#define S3C2410_MISCCR_SPUCR_HEN    (0<<0)
+#define S3C2410_MISCCR_SPUCR_HDIS   (1<<0)
+#define S3C2410_MISCCR_SPUCR_LEN    (0<<1)
+#define S3C2410_MISCCR_SPUCR_LDIS   (1<<1)
+
+#define S3C2410_MISCCR_USBDEV      (0<<3)
+#define S3C2410_MISCCR_USBHOST     (1<<3)
+
+#define S3C2410_MISCCR_CLK0_MPLL    (0<<4)
+#define S3C2410_MISCCR_CLK0_UPLL    (1<<4)
+#define S3C2410_MISCCR_CLK0_FCLK    (2<<4)
+#define S3C2410_MISCCR_CLK0_HCLK    (3<<4)
+#define S3C2410_MISCCR_CLK0_PCLK    (4<<4)
+#define S3C2410_MISCCR_CLK0_DCLK0   (5<<4)
+#define S3C2410_MISCCR_CLK0_MASK    (7<<4)
+
+#define S3C2412_MISCCR_CLK0_RTC            (2<<4)
+
+#define S3C2410_MISCCR_CLK1_MPLL    (0<<8)
+#define S3C2410_MISCCR_CLK1_UPLL    (1<<8)
+#define S3C2410_MISCCR_CLK1_FCLK    (2<<8)
+#define S3C2410_MISCCR_CLK1_HCLK    (3<<8)
+#define S3C2410_MISCCR_CLK1_PCLK    (4<<8)
+#define S3C2410_MISCCR_CLK1_DCLK1   (5<<8)
+#define S3C2410_MISCCR_CLK1_MASK    (7<<8)
+
+#define S3C2412_MISCCR_CLK1_CLKsrc  (0<<8)
+
+#define S3C2410_MISCCR_USBSUSPND0   (1<<12)
+#define S3C2416_MISCCR_SEL_SUSPND   (1<<12)
+#define S3C2410_MISCCR_USBSUSPND1   (1<<13)
+
+#define S3C2410_MISCCR_nRSTCON     (1<<16)
+
+#define S3C2410_MISCCR_nEN_SCLK0    (1<<17)
+#define S3C2410_MISCCR_nEN_SCLK1    (1<<18)
+#define S3C2410_MISCCR_nEN_SCLKE    (1<<19)    /* not 2412 */
+#define S3C2410_MISCCR_SDSLEEP     (7<<17)
+
+#define S3C2416_MISCCR_FLT_I2C      (1<<24)
+#define S3C2416_MISCCR_HSSPI_EN2    (1<<31)
+
+/* external interrupt control... */
+/* S3C2410_EXTINT0 -> irq sense control for EINT0..EINT7
+ * S3C2410_EXTINT1 -> irq sense control for EINT8..EINT15
+ * S3C2410_EXTINT2 -> irq sense control for EINT16..EINT23
+ *
+ * note S3C2410_EXTINT2 has filtering options for EINT16..EINT23
+ *
+ * Samsung datasheet p9-25
+*/
+#define S3C2410_EXTINT0           S3C2410_GPIOREG(0x88)
+#define S3C2410_EXTINT1           S3C2410_GPIOREG(0x8C)
+#define S3C2410_EXTINT2           S3C2410_GPIOREG(0x90)
+
+#define S3C24XX_EXTINT0           S3C24XX_GPIOREG2(0x88)
+#define S3C24XX_EXTINT1           S3C24XX_GPIOREG2(0x8C)
+#define S3C24XX_EXTINT2           S3C24XX_GPIOREG2(0x90)
+
+/* interrupt filtering conrrol for EINT16..EINT23 */
+#define S3C2410_EINFLT0           S3C2410_GPIOREG(0x94)
+#define S3C2410_EINFLT1           S3C2410_GPIOREG(0x98)
+#define S3C2410_EINFLT2           S3C2410_GPIOREG(0x9C)
+#define S3C2410_EINFLT3           S3C2410_GPIOREG(0xA0)
+
+#define S3C24XX_EINFLT0           S3C24XX_GPIOREG2(0x94)
+#define S3C24XX_EINFLT1           S3C24XX_GPIOREG2(0x98)
+#define S3C24XX_EINFLT2           S3C24XX_GPIOREG2(0x9C)
+#define S3C24XX_EINFLT3           S3C24XX_GPIOREG2(0xA0)
+
+/* values for interrupt filtering */
+#define S3C2410_EINTFLT_PCLK           (0x00)
+#define S3C2410_EINTFLT_EXTCLK         (1<<7)
+#define S3C2410_EINTFLT_WIDTHMSK(x)    ((x) & 0x3f)
+
+/* removed EINTxxxx defs from here, not meant for this */
+
+/* GSTATUS have miscellaneous information in them
+ *
+ * These move between s3c2410 and s3c2412 style systems.
+ */
+
+#define S3C2410_GSTATUS0   S3C2410_GPIOREG(0x0AC)
+#define S3C2410_GSTATUS1   S3C2410_GPIOREG(0x0B0)
+#define S3C2410_GSTATUS2   S3C2410_GPIOREG(0x0B4)
+#define S3C2410_GSTATUS3   S3C2410_GPIOREG(0x0B8)
+#define S3C2410_GSTATUS4   S3C2410_GPIOREG(0x0BC)
+
+#define S3C2412_GSTATUS0   S3C2410_GPIOREG(0x0BC)
+#define S3C2412_GSTATUS1   S3C2410_GPIOREG(0x0C0)
+#define S3C2412_GSTATUS2   S3C2410_GPIOREG(0x0C4)
+#define S3C2412_GSTATUS3   S3C2410_GPIOREG(0x0C8)
+#define S3C2412_GSTATUS4   S3C2410_GPIOREG(0x0CC)
+
+#define S3C24XX_GSTATUS0   S3C24XX_GPIOREG2(0x0AC)
+#define S3C24XX_GSTATUS1   S3C24XX_GPIOREG2(0x0B0)
+#define S3C24XX_GSTATUS2   S3C24XX_GPIOREG2(0x0B4)
+#define S3C24XX_GSTATUS3   S3C24XX_GPIOREG2(0x0B8)
+#define S3C24XX_GSTATUS4   S3C24XX_GPIOREG2(0x0BC)
+
+#define S3C2410_GSTATUS0_nWAIT    (1<<3)
+#define S3C2410_GSTATUS0_NCON     (1<<2)
+#define S3C2410_GSTATUS0_RnB      (1<<1)
+#define S3C2410_GSTATUS0_nBATTFLT  (1<<0)
+
+#define S3C2410_GSTATUS1_IDMASK           (0xffff0000)
+#define S3C2410_GSTATUS1_2410     (0x32410000)
+#define S3C2410_GSTATUS1_2412     (0x32412001)
+#define S3C2410_GSTATUS1_2416     (0x32416003)
+#define S3C2410_GSTATUS1_2440     (0x32440000)
+#define S3C2410_GSTATUS1_2442     (0x32440aaa)
+/* some 2416 CPUs report this value also */
+#define S3C2410_GSTATUS1_2450     (0x32450003)
+
+#define S3C2410_GSTATUS2_WTRESET   (1<<2)
+#define S3C2410_GSTATUS2_OFFRESET  (1<<1)
+#define S3C2410_GSTATUS2_PONRESET  (1<<0)
+
+/* 2412/2413 sleep configuration registers */
+
+#define S3C2412_GPBSLPCON      S3C2410_GPIOREG(0x1C)
+#define S3C2412_GPCSLPCON      S3C2410_GPIOREG(0x2C)
+#define S3C2412_GPDSLPCON      S3C2410_GPIOREG(0x3C)
+#define S3C2412_GPFSLPCON      S3C2410_GPIOREG(0x5C)
+#define S3C2412_GPGSLPCON      S3C2410_GPIOREG(0x6C)
+#define S3C2412_GPHSLPCON      S3C2410_GPIOREG(0x7C)
+
+/* definitions for each pin bit */
+#define S3C2412_GPIO_SLPCON_LOW         ( 0x00 )
+#define S3C2412_GPIO_SLPCON_HIGH ( 0x01 )
+#define S3C2412_GPIO_SLPCON_IN   ( 0x02 )
+#define S3C2412_GPIO_SLPCON_PULL ( 0x03 )
+
+#define S3C2412_SLPCON_LOW(x)  ( 0x00 << ((x) * 2))
+#define S3C2412_SLPCON_HIGH(x) ( 0x01 << ((x) * 2))
+#define S3C2412_SLPCON_IN(x)   ( 0x02 << ((x) * 2))
+#define S3C2412_SLPCON_PULL(x) ( 0x03 << ((x) * 2))
+#define S3C2412_SLPCON_EINT(x) ( 0x02 << ((x) * 2))  /* only IRQ pins */
+#define S3C2412_SLPCON_MASK(x) ( 0x03 << ((x) * 2))
+
+#define S3C2412_SLPCON_ALL_LOW (0x0)
+#define S3C2412_SLPCON_ALL_HIGH        (0x11111111 | 0x44444444)
+#define S3C2412_SLPCON_ALL_IN          (0x22222222 | 0x88888888)
+#define S3C2412_SLPCON_ALL_PULL        (0x33333333)
+
+#endif /* __ASM_ARCH_REGS_GPIO_H */
+
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-gpioj.h b/arch/arm/mach-s3c24xx/include/mach/regs-gpioj.h
new file mode 100644 (file)
index 0000000..19575e0
--- /dev/null
@@ -0,0 +1,70 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-gpioj.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2440 GPIO J register definitions
+*/
+
+
+#ifndef __ASM_ARCH_REGS_GPIOJ_H
+#define __ASM_ARCH_REGS_GPIOJ_H "gpioj"
+
+/* Port J consists of 13 GPIO/Camera pins
+ *
+ * GPJCON has 2 bits for each of the input pins on port F
+ *   00 = 0 input, 1 output, 2 Camera
+ *
+ * pull up works like all other ports.
+*/
+
+#define S3C2413_GPJCON         S3C2410_GPIOREG(0x80)
+#define S3C2413_GPJDAT         S3C2410_GPIOREG(0x84)
+#define S3C2413_GPJUP          S3C2410_GPIOREG(0x88)
+#define S3C2413_GPJSLPCON      S3C2410_GPIOREG(0x8C)
+
+#define S3C2440_GPJ0_OUTP       (0x01 << 0)
+#define S3C2440_GPJ0_CAMDATA0   (0x02 << 0)
+
+#define S3C2440_GPJ1_OUTP       (0x01 << 2)
+#define S3C2440_GPJ1_CAMDATA1   (0x02 << 2)
+
+#define S3C2440_GPJ2_OUTP       (0x01 << 4)
+#define S3C2440_GPJ2_CAMDATA2   (0x02 << 4)
+
+#define S3C2440_GPJ3_OUTP       (0x01 << 6)
+#define S3C2440_GPJ3_CAMDATA3   (0x02 << 6)
+
+#define S3C2440_GPJ4_OUTP       (0x01 << 8)
+#define S3C2440_GPJ4_CAMDATA4   (0x02 << 8)
+
+#define S3C2440_GPJ5_OUTP       (0x01 << 10)
+#define S3C2440_GPJ5_CAMDATA5   (0x02 << 10)
+
+#define S3C2440_GPJ6_OUTP       (0x01 << 12)
+#define S3C2440_GPJ6_CAMDATA6   (0x02 << 12)
+
+#define S3C2440_GPJ7_OUTP       (0x01 << 14)
+#define S3C2440_GPJ7_CAMDATA7   (0x02 << 14)
+
+#define S3C2440_GPJ8_OUTP       (0x01 << 16)
+#define S3C2440_GPJ8_CAMPCLK    (0x02 << 16)
+
+#define S3C2440_GPJ9_OUTP       (0x01 << 18)
+#define S3C2440_GPJ9_CAMVSYNC   (0x02 << 18)
+
+#define S3C2440_GPJ10_OUTP      (0x01 << 20)
+#define S3C2440_GPJ10_CAMHREF   (0x02 << 20)
+
+#define S3C2440_GPJ11_OUTP      (0x01 << 22)
+#define S3C2440_GPJ11_CAMCLKOUT (0x02 << 22)
+
+#define S3C2440_GPJ12_OUTP      (0x01 << 24)
+#define S3C2440_GPJ12_CAMRESET  (0x02 << 24)
+
+#endif /* __ASM_ARCH_REGS_GPIOJ_H */
+
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-irq.h b/arch/arm/mach-s3c24xx/include/mach/regs-irq.h
new file mode 100644 (file)
index 0000000..0f07ba3
--- /dev/null
@@ -0,0 +1,53 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-irq.h
+ *
+ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+
+#ifndef ___ASM_ARCH_REGS_IRQ_H
+#define ___ASM_ARCH_REGS_IRQ_H
+
+/* interrupt controller */
+
+#define S3C2410_IRQREG(x)   ((x) + S3C24XX_VA_IRQ)
+#define S3C2410_EINTREG(x)  ((x) + S3C24XX_VA_GPIO)
+#define S3C24XX_EINTREG(x)  ((x) + S3C24XX_VA_GPIO2)
+
+#define S3C2410_SRCPND        S3C2410_IRQREG(0x000)
+#define S3C2410_INTMOD        S3C2410_IRQREG(0x004)
+#define S3C2410_INTMSK        S3C2410_IRQREG(0x008)
+#define S3C2410_PRIORITY       S3C2410_IRQREG(0x00C)
+#define S3C2410_INTPND        S3C2410_IRQREG(0x010)
+#define S3C2410_INTOFFSET      S3C2410_IRQREG(0x014)
+#define S3C2410_SUBSRCPND      S3C2410_IRQREG(0x018)
+#define S3C2410_INTSUBMSK      S3C2410_IRQREG(0x01C)
+
+#define S3C2416_PRIORITY_MODE1         S3C2410_IRQREG(0x030)
+#define S3C2416_PRIORITY_UPDATE1       S3C2410_IRQREG(0x034)
+#define S3C2416_SRCPND2                        S3C2410_IRQREG(0x040)
+#define S3C2416_INTMOD2                        S3C2410_IRQREG(0x044)
+#define S3C2416_INTMSK2                        S3C2410_IRQREG(0x048)
+#define S3C2416_INTPND2                        S3C2410_IRQREG(0x050)
+#define S3C2416_INTOFFSET2             S3C2410_IRQREG(0x054)
+#define S3C2416_PRIORITY_MODE2         S3C2410_IRQREG(0x070)
+#define S3C2416_PRIORITY_UPDATE2       S3C2410_IRQREG(0x074)
+
+/* mask: 0=enable, 1=disable
+ * 1 bit EINT, 4=EINT4, 23=EINT23
+ * EINT0,1,2,3 are not handled here.
+*/
+
+#define S3C2410_EINTMASK       S3C2410_EINTREG(0x0A4)
+#define S3C2410_EINTPEND       S3C2410_EINTREG(0X0A8)
+#define S3C2412_EINTMASK       S3C2410_EINTREG(0x0B4)
+#define S3C2412_EINTPEND       S3C2410_EINTREG(0X0B8)
+
+#define S3C24XX_EINTMASK       S3C24XX_EINTREG(0x0A4)
+#define S3C24XX_EINTPEND       S3C24XX_EINTREG(0X0A8)
+
+#endif /* ___ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-lcd.h b/arch/arm/mach-s3c24xx/include/mach/regs-lcd.h
new file mode 100644 (file)
index 0000000..ee8f040
--- /dev/null
@@ -0,0 +1,162 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-lcd.h
+ *
+ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+
+#ifndef ___ASM_ARCH_REGS_LCD_H
+#define ___ASM_ARCH_REGS_LCD_H
+
+#define S3C2410_LCDREG(x)      (x)
+
+/* LCD control registers */
+#define S3C2410_LCDCON1            S3C2410_LCDREG(0x00)
+#define S3C2410_LCDCON2            S3C2410_LCDREG(0x04)
+#define S3C2410_LCDCON3            S3C2410_LCDREG(0x08)
+#define S3C2410_LCDCON4            S3C2410_LCDREG(0x0C)
+#define S3C2410_LCDCON5            S3C2410_LCDREG(0x10)
+
+#define S3C2410_LCDCON1_CLKVAL(x)  ((x) << 8)
+#define S3C2410_LCDCON1_MMODE     (1<<7)
+#define S3C2410_LCDCON1_DSCAN4    (0<<5)
+#define S3C2410_LCDCON1_STN4      (1<<5)
+#define S3C2410_LCDCON1_STN8      (2<<5)
+#define S3C2410_LCDCON1_TFT       (3<<5)
+
+#define S3C2410_LCDCON1_STN1BPP           (0<<1)
+#define S3C2410_LCDCON1_STN2GREY   (1<<1)
+#define S3C2410_LCDCON1_STN4GREY   (2<<1)
+#define S3C2410_LCDCON1_STN8BPP           (3<<1)
+#define S3C2410_LCDCON1_STN12BPP   (4<<1)
+
+#define S3C2410_LCDCON1_TFT1BPP           (8<<1)
+#define S3C2410_LCDCON1_TFT2BPP           (9<<1)
+#define S3C2410_LCDCON1_TFT4BPP           (10<<1)
+#define S3C2410_LCDCON1_TFT8BPP           (11<<1)
+#define S3C2410_LCDCON1_TFT16BPP   (12<<1)
+#define S3C2410_LCDCON1_TFT24BPP   (13<<1)
+
+#define S3C2410_LCDCON1_ENVID     (1)
+
+#define S3C2410_LCDCON1_MODEMASK    0x1E
+
+#define S3C2410_LCDCON2_VBPD(x)            ((x) << 24)
+#define S3C2410_LCDCON2_LINEVAL(x)  ((x) << 14)
+#define S3C2410_LCDCON2_VFPD(x)            ((x) << 6)
+#define S3C2410_LCDCON2_VSPW(x)            ((x) << 0)
+
+#define S3C2410_LCDCON2_GET_VBPD(x) ( ((x) >> 24) & 0xFF)
+#define S3C2410_LCDCON2_GET_VFPD(x) ( ((x) >>  6) & 0xFF)
+#define S3C2410_LCDCON2_GET_VSPW(x) ( ((x) >>  0) & 0x3F)
+
+#define S3C2410_LCDCON3_HBPD(x)            ((x) << 19)
+#define S3C2410_LCDCON3_WDLY(x)            ((x) << 19)
+#define S3C2410_LCDCON3_HOZVAL(x)   ((x) << 8)
+#define S3C2410_LCDCON3_HFPD(x)            ((x) << 0)
+#define S3C2410_LCDCON3_LINEBLANK(x)((x) << 0)
+
+#define S3C2410_LCDCON3_GET_HBPD(x) ( ((x) >> 19) & 0x7F)
+#define S3C2410_LCDCON3_GET_HFPD(x) ( ((x) >>  0) & 0xFF)
+
+/* LDCCON4 changes for STN mode on the S3C2412 */
+
+#define S3C2410_LCDCON4_MVAL(x)            ((x) << 8)
+#define S3C2410_LCDCON4_HSPW(x)            ((x) << 0)
+#define S3C2410_LCDCON4_WLH(x)     ((x) << 0)
+
+#define S3C2410_LCDCON4_GET_HSPW(x) ( ((x) >>  0) & 0xFF)
+
+#define S3C2410_LCDCON5_BPP24BL            (1<<12)
+#define S3C2410_LCDCON5_FRM565     (1<<11)
+#define S3C2410_LCDCON5_INVVCLK            (1<<10)
+#define S3C2410_LCDCON5_INVVLINE    (1<<9)
+#define S3C2410_LCDCON5_INVVFRAME   (1<<8)
+#define S3C2410_LCDCON5_INVVD      (1<<7)
+#define S3C2410_LCDCON5_INVVDEN            (1<<6)
+#define S3C2410_LCDCON5_INVPWREN    (1<<5)
+#define S3C2410_LCDCON5_INVLEND            (1<<4)
+#define S3C2410_LCDCON5_PWREN      (1<<3)
+#define S3C2410_LCDCON5_ENLEND     (1<<2)
+#define S3C2410_LCDCON5_BSWP       (1<<1)
+#define S3C2410_LCDCON5_HWSWP      (1<<0)
+
+/* framebuffer start addressed */
+#define S3C2410_LCDSADDR1   S3C2410_LCDREG(0x14)
+#define S3C2410_LCDSADDR2   S3C2410_LCDREG(0x18)
+#define S3C2410_LCDSADDR3   S3C2410_LCDREG(0x1C)
+
+#define S3C2410_LCDBANK(x)     ((x) << 21)
+#define S3C2410_LCDBASEU(x)    (x)
+
+#define S3C2410_OFFSIZE(x)     ((x) << 11)
+#define S3C2410_PAGEWIDTH(x)   (x)
+
+/* colour lookup and miscellaneous controls */
+
+#define S3C2410_REDLUT    S3C2410_LCDREG(0x20)
+#define S3C2410_GREENLUT   S3C2410_LCDREG(0x24)
+#define S3C2410_BLUELUT           S3C2410_LCDREG(0x28)
+
+#define S3C2410_DITHMODE   S3C2410_LCDREG(0x4C)
+#define S3C2410_TPAL      S3C2410_LCDREG(0x50)
+
+#define S3C2410_TPAL_EN                (1<<24)
+
+/* interrupt info */
+#define S3C2410_LCDINTPND  S3C2410_LCDREG(0x54)
+#define S3C2410_LCDSRCPND  S3C2410_LCDREG(0x58)
+#define S3C2410_LCDINTMSK  S3C2410_LCDREG(0x5C)
+#define S3C2410_LCDINT_FIWSEL  (1<<2)
+#define        S3C2410_LCDINT_FRSYNC   (1<<1)
+#define S3C2410_LCDINT_FICNT   (1<<0)
+
+/* s3c2442 extra stn registers */
+
+#define S3C2442_REDLUT         S3C2410_LCDREG(0x20)
+#define S3C2442_GREENLUT       S3C2410_LCDREG(0x24)
+#define S3C2442_BLUELUT                S3C2410_LCDREG(0x28)
+#define S3C2442_DITHMODE       S3C2410_LCDREG(0x20)
+
+#define S3C2410_LPCSEL    S3C2410_LCDREG(0x60)
+
+#define S3C2410_TFTPAL(x)  S3C2410_LCDREG((0x400 + (x)*4))
+
+/* S3C2412 registers */
+
+#define S3C2412_TPAL           S3C2410_LCDREG(0x20)
+
+#define S3C2412_LCDINTPND      S3C2410_LCDREG(0x24)
+#define S3C2412_LCDSRCPND      S3C2410_LCDREG(0x28)
+#define S3C2412_LCDINTMSK      S3C2410_LCDREG(0x2C)
+
+#define S3C2412_TCONSEL                S3C2410_LCDREG(0x30)
+
+#define S3C2412_LCDCON6                S3C2410_LCDREG(0x34)
+#define S3C2412_LCDCON7                S3C2410_LCDREG(0x38)
+#define S3C2412_LCDCON8                S3C2410_LCDREG(0x3C)
+#define S3C2412_LCDCON9                S3C2410_LCDREG(0x40)
+
+#define S3C2412_REDLUT(x)      S3C2410_LCDREG(0x44 + ((x)*4))
+#define S3C2412_GREENLUT(x)    S3C2410_LCDREG(0x60 + ((x)*4))
+#define S3C2412_BLUELUT(x)     S3C2410_LCDREG(0x98 + ((x)*4))
+
+#define S3C2412_FRCPAT(x)      S3C2410_LCDREG(0xB4 + ((x)*4))
+
+/* general registers */
+
+/* base of the LCD registers, where INTPND, INTSRC and then INTMSK
+ * are available. */
+
+#define S3C2410_LCDINTBASE     S3C2410_LCDREG(0x54)
+#define S3C2412_LCDINTBASE     S3C2410_LCDREG(0x24)
+
+#define S3C24XX_LCDINTPND      (0x00)
+#define S3C24XX_LCDSRCPND      (0x04)
+#define S3C24XX_LCDINTMSK      (0x08)
+
+#endif /* ___ASM_ARCH_REGS_LCD_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-mem.h b/arch/arm/mach-s3c24xx/include/mach/regs-mem.h
new file mode 100644 (file)
index 0000000..e0c67b0
--- /dev/null
@@ -0,0 +1,202 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-mem.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *             http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 Memory Control register definitions
+*/
+
+#ifndef __ASM_ARM_MEMREGS_H
+#define __ASM_ARM_MEMREGS_H
+
+#ifndef S3C2410_MEMREG
+#define S3C2410_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
+#endif
+
+/* bus width, and wait state control */
+#define S3C2410_BWSCON                 S3C2410_MEMREG(0x0000)
+
+/* bank zero config - note, pinstrapped from OM pins! */
+#define S3C2410_BWSCON_DW0_16          (1<<1)
+#define S3C2410_BWSCON_DW0_32          (2<<1)
+
+/* bank one configs */
+#define S3C2410_BWSCON_DW1_8           (0<<4)
+#define S3C2410_BWSCON_DW1_16          (1<<4)
+#define S3C2410_BWSCON_DW1_32          (2<<4)
+#define S3C2410_BWSCON_WS1             (1<<6)
+#define S3C2410_BWSCON_ST1             (1<<7)
+
+/* bank 2 configurations */
+#define S3C2410_BWSCON_DW2_8           (0<<8)
+#define S3C2410_BWSCON_DW2_16          (1<<8)
+#define S3C2410_BWSCON_DW2_32          (2<<8)
+#define S3C2410_BWSCON_WS2             (1<<10)
+#define S3C2410_BWSCON_ST2             (1<<11)
+
+/* bank 3 configurations */
+#define S3C2410_BWSCON_DW3_8           (0<<12)
+#define S3C2410_BWSCON_DW3_16          (1<<12)
+#define S3C2410_BWSCON_DW3_32          (2<<12)
+#define S3C2410_BWSCON_WS3             (1<<14)
+#define S3C2410_BWSCON_ST3             (1<<15)
+
+/* bank 4 configurations */
+#define S3C2410_BWSCON_DW4_8           (0<<16)
+#define S3C2410_BWSCON_DW4_16          (1<<16)
+#define S3C2410_BWSCON_DW4_32          (2<<16)
+#define S3C2410_BWSCON_WS4             (1<<18)
+#define S3C2410_BWSCON_ST4             (1<<19)
+
+/* bank 5 configurations */
+#define S3C2410_BWSCON_DW5_8           (0<<20)
+#define S3C2410_BWSCON_DW5_16          (1<<20)
+#define S3C2410_BWSCON_DW5_32          (2<<20)
+#define S3C2410_BWSCON_WS5             (1<<22)
+#define S3C2410_BWSCON_ST5             (1<<23)
+
+/* bank 6 configurations */
+#define S3C2410_BWSCON_DW6_8           (0<<24)
+#define S3C2410_BWSCON_DW6_16          (1<<24)
+#define S3C2410_BWSCON_DW6_32          (2<<24)
+#define S3C2410_BWSCON_WS6             (1<<26)
+#define S3C2410_BWSCON_ST6             (1<<27)
+
+/* bank 7 configurations */
+#define S3C2410_BWSCON_DW7_8           (0<<28)
+#define S3C2410_BWSCON_DW7_16          (1<<28)
+#define S3C2410_BWSCON_DW7_32          (2<<28)
+#define S3C2410_BWSCON_WS7             (1<<30)
+#define S3C2410_BWSCON_ST7             (1<<31)
+
+/* accesor functions for getting BANK(n) configuration. (n != 0) */
+
+#define S3C2410_BWSCON_GET(_bwscon, _bank) (((_bwscon) >> ((_bank) * 4)) & 0xf)
+
+#define S3C2410_BWSCON_DW8             (0)
+#define S3C2410_BWSCON_DW16            (1)
+#define S3C2410_BWSCON_DW32            (2)
+#define S3C2410_BWSCON_WS              (1 << 2)
+#define S3C2410_BWSCON_ST              (1 << 3)
+
+/* memory set (rom, ram) */
+#define S3C2410_BANKCON0               S3C2410_MEMREG(0x0004)
+#define S3C2410_BANKCON1               S3C2410_MEMREG(0x0008)
+#define S3C2410_BANKCON2               S3C2410_MEMREG(0x000C)
+#define S3C2410_BANKCON3               S3C2410_MEMREG(0x0010)
+#define S3C2410_BANKCON4               S3C2410_MEMREG(0x0014)
+#define S3C2410_BANKCON5               S3C2410_MEMREG(0x0018)
+#define S3C2410_BANKCON6               S3C2410_MEMREG(0x001C)
+#define S3C2410_BANKCON7               S3C2410_MEMREG(0x0020)
+
+/* bank configuration registers */
+
+#define S3C2410_BANKCON_PMCnorm                (0x00)
+#define S3C2410_BANKCON_PMC4           (0x01)
+#define S3C2410_BANKCON_PMC8           (0x02)
+#define S3C2410_BANKCON_PMC16          (0x03)
+
+/* bank configurations for banks 0..7, note banks
+ * 6 and 7 have different configurations depending on
+ * the memory type bits */
+
+#define S3C2410_BANKCON_Tacp2          (0x0 << 2)
+#define S3C2410_BANKCON_Tacp3          (0x1 << 2)
+#define S3C2410_BANKCON_Tacp4          (0x2 << 2)
+#define S3C2410_BANKCON_Tacp6          (0x3 << 2)
+#define S3C2410_BANKCON_Tacp_SHIFT     (2)
+
+#define S3C2410_BANKCON_Tcah0          (0x0 << 4)
+#define S3C2410_BANKCON_Tcah1          (0x1 << 4)
+#define S3C2410_BANKCON_Tcah2          (0x2 << 4)
+#define S3C2410_BANKCON_Tcah4          (0x3 << 4)
+#define S3C2410_BANKCON_Tcah_SHIFT     (4)
+
+#define S3C2410_BANKCON_Tcoh0          (0x0 << 6)
+#define S3C2410_BANKCON_Tcoh1          (0x1 << 6)
+#define S3C2410_BANKCON_Tcoh2          (0x2 << 6)
+#define S3C2410_BANKCON_Tcoh4          (0x3 << 6)
+#define S3C2410_BANKCON_Tcoh_SHIFT     (6)
+
+#define S3C2410_BANKCON_Tacc1          (0x0 << 8)
+#define S3C2410_BANKCON_Tacc2          (0x1 << 8)
+#define S3C2410_BANKCON_Tacc3          (0x2 << 8)
+#define S3C2410_BANKCON_Tacc4          (0x3 << 8)
+#define S3C2410_BANKCON_Tacc6          (0x4 << 8)
+#define S3C2410_BANKCON_Tacc8          (0x5 << 8)
+#define S3C2410_BANKCON_Tacc10         (0x6 << 8)
+#define S3C2410_BANKCON_Tacc14         (0x7 << 8)
+#define S3C2410_BANKCON_Tacc_SHIFT     (8)
+
+#define S3C2410_BANKCON_Tcos0          (0x0 << 11)
+#define S3C2410_BANKCON_Tcos1          (0x1 << 11)
+#define S3C2410_BANKCON_Tcos2          (0x2 << 11)
+#define S3C2410_BANKCON_Tcos4          (0x3 << 11)
+#define S3C2410_BANKCON_Tcos_SHIFT     (11)
+
+#define S3C2410_BANKCON_Tacs0          (0x0 << 13)
+#define S3C2410_BANKCON_Tacs1          (0x1 << 13)
+#define S3C2410_BANKCON_Tacs2          (0x2 << 13)
+#define S3C2410_BANKCON_Tacs4          (0x3 << 13)
+#define S3C2410_BANKCON_Tacs_SHIFT     (13)
+
+#define S3C2410_BANKCON_SRAM           (0x0 << 15)
+#define S3C2410_BANKCON_SDRAM          (0x3 << 15)
+
+/* next bits only for SDRAM in 6,7 */
+#define S3C2410_BANKCON_Trcd2          (0x00 << 2)
+#define S3C2410_BANKCON_Trcd3          (0x01 << 2)
+#define S3C2410_BANKCON_Trcd4          (0x02 << 2)
+
+/* control column address select */
+#define S3C2410_BANKCON_SCANb8         (0x00 << 0)
+#define S3C2410_BANKCON_SCANb9         (0x01 << 0)
+#define S3C2410_BANKCON_SCANb10                (0x02 << 0)
+
+#define S3C2410_REFRESH                        S3C2410_MEMREG(0x0024)
+#define S3C2410_BANKSIZE               S3C2410_MEMREG(0x0028)
+#define S3C2410_MRSRB6                 S3C2410_MEMREG(0x002C)
+#define S3C2410_MRSRB7                 S3C2410_MEMREG(0x0030)
+
+/* refresh control */
+
+#define S3C2410_REFRESH_REFEN          (1<<23)
+#define S3C2410_REFRESH_SELF           (1<<22)
+#define S3C2410_REFRESH_REFCOUNTER     ((1<<11)-1)
+
+#define S3C2410_REFRESH_TRP_MASK       (3<<20)
+#define S3C2410_REFRESH_TRP_2clk       (0<<20)
+#define S3C2410_REFRESH_TRP_3clk       (1<<20)
+#define S3C2410_REFRESH_TRP_4clk       (2<<20)
+
+#define S3C2410_REFRESH_TSRC_MASK      (3<<18)
+#define S3C2410_REFRESH_TSRC_4clk      (0<<18)
+#define S3C2410_REFRESH_TSRC_5clk      (1<<18)
+#define S3C2410_REFRESH_TSRC_6clk      (2<<18)
+#define S3C2410_REFRESH_TSRC_7clk      (3<<18)
+
+
+/* mode select register(s) */
+
+#define  S3C2410_MRSRB_CL1             (0x00 << 4)
+#define  S3C2410_MRSRB_CL2             (0x02 << 4)
+#define  S3C2410_MRSRB_CL3             (0x03 << 4)
+
+/* bank size register */
+#define S3C2410_BANKSIZE_128M          (0x2 << 0)
+#define S3C2410_BANKSIZE_64M           (0x1 << 0)
+#define S3C2410_BANKSIZE_32M           (0x0 << 0)
+#define S3C2410_BANKSIZE_16M           (0x7 << 0)
+#define S3C2410_BANKSIZE_8M            (0x6 << 0)
+#define S3C2410_BANKSIZE_4M            (0x5 << 0)
+#define S3C2410_BANKSIZE_2M            (0x4 << 0)
+#define S3C2410_BANKSIZE_MASK          (0x7 << 0)
+#define S3C2410_BANKSIZE_SCLK_EN       (1<<4)
+#define S3C2410_BANKSIZE_SCKE_EN       (1<<5)
+#define S3C2410_BANKSIZE_BURST         (1<<7)
+
+#endif /* __ASM_ARM_MEMREGS_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-power.h b/arch/arm/mach-s3c24xx/include/mach/regs-power.h
new file mode 100644 (file)
index 0000000..4932b87
--- /dev/null
@@ -0,0 +1,40 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-power.h
+ *
+ * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C24XX power control register definitions
+*/
+
+#ifndef __ASM_ARM_REGS_PWR
+#define __ASM_ARM_REGS_PWR __FILE__
+
+#define S3C24XX_PWRREG(x) ((x) + S3C24XX_VA_CLKPWR)
+
+#define S3C2412_PWRMODECON     S3C24XX_PWRREG(0x20)
+#define S3C2412_PWRCFG         S3C24XX_PWRREG(0x24)
+
+#define S3C2412_INFORM0                S3C24XX_PWRREG(0x70)
+#define S3C2412_INFORM1                S3C24XX_PWRREG(0x74)
+#define S3C2412_INFORM2                S3C24XX_PWRREG(0x78)
+#define S3C2412_INFORM3                S3C24XX_PWRREG(0x7C)
+
+#define S3C2412_PWRCFG_BATF_IRQ                        (1<<0)
+#define S3C2412_PWRCFG_BATF_IGNORE             (2<<0)
+#define S3C2412_PWRCFG_BATF_SLEEP              (3<<0)
+#define S3C2412_PWRCFG_BATF_MASK               (3<<0)
+
+#define S3C2412_PWRCFG_STANDBYWFI_IGNORE       (0<<6)
+#define S3C2412_PWRCFG_STANDBYWFI_IDLE         (1<<6)
+#define S3C2412_PWRCFG_STANDBYWFI_STOP         (2<<6)
+#define S3C2412_PWRCFG_STANDBYWFI_SLEEP                (3<<6)
+#define S3C2412_PWRCFG_STANDBYWFI_MASK         (3<<6)
+
+#define S3C2412_PWRCFG_RTC_MASKIRQ             (1<<8)
+#define S3C2412_PWRCFG_NAND_NORST              (1<<9)
+
+#endif /* __ASM_ARM_REGS_PWR */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412-mem.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412-mem.h
new file mode 100644 (file)
index 0000000..fb63525
--- /dev/null
@@ -0,0 +1,48 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-s3c2412-mem.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C2412 memory register definitions
+*/
+
+#ifndef __ASM_ARM_REGS_S3C2412_MEM
+#define __ASM_ARM_REGS_S3C2412_MEM
+
+#define S3C2412_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
+#define S3C2412_EBIREG(x) (S3C2412_VA_EBI + (x))
+
+#define S3C2412_SSMCREG(x) (S3C2412_VA_SSMC + (x))
+#define S3C2412_SSMC(x, o) (S3C2412_SSMCREG((x * 0x20) + (o)))
+
+#define S3C2412_BANKCFG                        S3C2412_MEMREG(0x00)
+#define S3C2412_BANKCON1               S3C2412_MEMREG(0x04)
+#define S3C2412_BANKCON2               S3C2412_MEMREG(0x08)
+#define S3C2412_BANKCON3               S3C2412_MEMREG(0x0C)
+
+#define S3C2412_REFRESH                        S3C2412_MEMREG(0x10)
+#define S3C2412_TIMEOUT                        S3C2412_MEMREG(0x14)
+
+/* EBI control registers */
+
+#define S3C2412_EBI_PR                 S3C2412_EBIREG(0x00)
+#define S3C2412_EBI_BANKCFG            S3C2412_EBIREG(0x04)
+
+/* SSMC control registers */
+
+#define S3C2412_SSMC_BANK(x)           S3C2412_SSMC(x, 0x00)
+#define S3C2412_SMIDCYR(x)             S3C2412_SSMC(x, 0x00)
+#define S3C2412_SMBWSTRD(x)            S3C2412_SSMC(x, 0x04)
+#define S3C2412_SMBWSTWRR(x)           S3C2412_SSMC(x, 0x08)
+#define S3C2412_SMBWSTOENR(x)          S3C2412_SSMC(x, 0x0C)
+#define S3C2412_SMBWSTWENR(x)          S3C2412_SSMC(x, 0x10)
+#define S3C2412_SMBCR(x)               S3C2412_SSMC(x, 0x14)
+#define S3C2412_SMBSR(x)               S3C2412_SSMC(x, 0x18)
+#define S3C2412_SMBWSTBRDR(x)          S3C2412_SSMC(x, 0x1C)
+
+#endif /*  __ASM_ARM_REGS_S3C2412_MEM */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2412.h
new file mode 100644 (file)
index 0000000..aa69dc7
--- /dev/null
@@ -0,0 +1,23 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-s3c2412.h
+ *
+ * Copyright 2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C2412 specific register definitions
+*/
+
+#ifndef __ASM_ARCH_REGS_S3C2412_H
+#define __ASM_ARCH_REGS_S3C2412_H "s3c2412"
+
+#define S3C2412_SWRST          (S3C24XX_VA_CLKPWR + 0x30)
+#define S3C2412_SWRST_RESET    (0x533C2412)
+
+/* see regs-power.h for the other registers in the power block. */
+
+#endif /* __ASM_ARCH_REGS_S3C2412_H */
+
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416-mem.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416-mem.h
new file mode 100644 (file)
index 0000000..2f31b74
--- /dev/null
@@ -0,0 +1,30 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-s3c2416-mem.h
+ *
+ * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
+ *     as part of OpenInkpot project
+ * Copyright (c) 2009 Promwad Innovation Company
+ *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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.
+ *
+ * S3C2416 memory register definitions
+*/
+
+#ifndef __ASM_ARM_REGS_S3C2416_MEM
+#define __ASM_ARM_REGS_S3C2416_MEM
+
+#ifndef S3C2416_MEMREG
+#define S3C2416_MEMREG(x) (S3C24XX_VA_MEMCTRL + (x))
+#endif
+
+#define S3C2416_BANKCFG                        S3C2416_MEMREG(0x00)
+#define S3C2416_BANKCON1               S3C2416_MEMREG(0x04)
+#define S3C2416_BANKCON2               S3C2416_MEMREG(0x08)
+#define S3C2416_BANKCON3               S3C2416_MEMREG(0x0C)
+
+#define S3C2416_REFRESH                        S3C2416_MEMREG(0x10)
+#define S3C2416_TIMEOUT                        S3C2416_MEMREG(0x14)
+
+#endif /*  __ASM_ARM_REGS_S3C2416_MEM */
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2416.h
new file mode 100644 (file)
index 0000000..e443167
--- /dev/null
@@ -0,0 +1,24 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-s3c2416.h
+ *
+ * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
+ *     as part of OpenInkpot project
+ * Copyright (c) 2009 Promwad Innovation Company
+ *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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.
+ *
+ * S3C2416 specific register definitions
+*/
+
+#ifndef __ASM_ARCH_REGS_S3C2416_H
+#define __ASM_ARCH_REGS_S3C2416_H "s3c2416"
+
+#define S3C2416_SWRST          (S3C24XX_VA_CLKPWR + 0x44)
+#define S3C2416_SWRST_RESET    (0x533C2416)
+
+/* see regs-power.h for the other registers in the power block. */
+
+#endif /* __ASM_ARCH_REGS_S3C2416_H */
+
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2443-clock.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2443-clock.h
new file mode 100644 (file)
index 0000000..c3feff3
--- /dev/null
@@ -0,0 +1,194 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C2443 clock register definitions
+*/
+
+#ifndef __ASM_ARM_REGS_S3C2443_CLOCK
+#define __ASM_ARM_REGS_S3C2443_CLOCK
+
+#define S3C2443_CLKREG(x)              ((x) + S3C24XX_VA_CLKPWR)
+
+#define S3C2443_PLLCON_MDIVSHIFT       16
+#define S3C2443_PLLCON_PDIVSHIFT       8
+#define S3C2443_PLLCON_SDIVSHIFT       0
+#define S3C2443_PLLCON_MDIVMASK                ((1<<(1+(23-16)))-1)
+#define S3C2443_PLLCON_PDIVMASK                ((1<<(1+(9-8)))-1)
+#define S3C2443_PLLCON_SDIVMASK                (3)
+
+#define S3C2443_MPLLCON                        S3C2443_CLKREG(0x10)
+#define S3C2443_EPLLCON                        S3C2443_CLKREG(0x18)
+#define S3C2443_CLKSRC                 S3C2443_CLKREG(0x20)
+#define S3C2443_CLKDIV0                        S3C2443_CLKREG(0x24)
+#define S3C2443_CLKDIV1                        S3C2443_CLKREG(0x28)
+#define S3C2443_HCLKCON                        S3C2443_CLKREG(0x30)
+#define S3C2443_PCLKCON                        S3C2443_CLKREG(0x34)
+#define S3C2443_SCLKCON                        S3C2443_CLKREG(0x38)
+#define S3C2443_PWRMODE                        S3C2443_CLKREG(0x40)
+#define S3C2443_SWRST                  S3C2443_CLKREG(0x44)
+#define S3C2443_BUSPRI0                        S3C2443_CLKREG(0x50)
+#define S3C2443_SYSID                  S3C2443_CLKREG(0x5C)
+#define S3C2443_PWRCFG                 S3C2443_CLKREG(0x60)
+#define S3C2443_RSTCON                 S3C2443_CLKREG(0x64)
+#define S3C2443_PHYCTRL                        S3C2443_CLKREG(0x80)
+#define S3C2443_PHYPWR                 S3C2443_CLKREG(0x84)
+#define S3C2443_URSTCON                        S3C2443_CLKREG(0x88)
+#define S3C2443_UCLKCON                        S3C2443_CLKREG(0x8C)
+
+#define S3C2443_SWRST_RESET            (0x533c2443)
+
+#define S3C2443_PLLCON_OFF             (1<<24)
+
+#define S3C2443_CLKSRC_EPLLREF_XTAL    (2<<7)
+#define S3C2443_CLKSRC_EPLLREF_EXTCLK  (3<<7)
+#define S3C2443_CLKSRC_EPLLREF_MPLLREF (0<<7)
+#define S3C2443_CLKSRC_EPLLREF_MPLLREF2        (1<<7)
+#define S3C2443_CLKSRC_EPLLREF_MASK    (3<<7)
+
+#define S3C2443_CLKSRC_EXTCLK_DIV      (1<<3)
+
+#define S3C2443_CLKDIV0_HALF_HCLK      (1<<3)
+#define S3C2443_CLKDIV0_HALF_PCLK      (1<<2)
+
+#define S3C2443_CLKDIV0_HCLKDIV_MASK   (3<<0)
+
+#define S3C2443_CLKDIV0_EXTDIV_MASK    (3<<6)
+#define S3C2443_CLKDIV0_EXTDIV_SHIFT   (6)
+
+#define S3C2443_CLKDIV0_PREDIV_MASK    (3<<4)
+#define S3C2443_CLKDIV0_PREDIV_SHIFT   (4)
+
+#define S3C2416_CLKDIV0_ARMDIV_MASK    (7 << 9)
+#define S3C2443_CLKDIV0_ARMDIV_MASK    (15<<9)
+#define S3C2443_CLKDIV0_ARMDIV_SHIFT   (9)
+#define S3C2443_CLKDIV0_ARMDIV_1       (0<<9)
+#define S3C2443_CLKDIV0_ARMDIV_2       (8<<9)
+#define S3C2443_CLKDIV0_ARMDIV_3       (2<<9)
+#define S3C2443_CLKDIV0_ARMDIV_4       (9<<9)
+#define S3C2443_CLKDIV0_ARMDIV_6       (10<<9)
+#define S3C2443_CLKDIV0_ARMDIV_8       (11<<9)
+#define S3C2443_CLKDIV0_ARMDIV_12      (13<<9)
+#define S3C2443_CLKDIV0_ARMDIV_16      (15<<9)
+
+/* S3C2443_CLKDIV1 removed, only used in clock.c code */
+
+#define S3C2443_CLKCON_NAND
+
+#define S3C2443_HCLKCON_DMA0           (1<<0)
+#define S3C2443_HCLKCON_DMA1           (1<<1)
+#define S3C2443_HCLKCON_DMA2           (1<<2)
+#define S3C2443_HCLKCON_DMA3           (1<<3)
+#define S3C2443_HCLKCON_DMA4           (1<<4)
+#define S3C2443_HCLKCON_DMA5           (1<<5)
+#define S3C2443_HCLKCON_CAMIF          (1<<8)
+#define S3C2443_HCLKCON_LCDC           (1<<9)
+#define S3C2443_HCLKCON_USBH           (1<<11)
+#define S3C2443_HCLKCON_USBD           (1<<12)
+#define S3C2416_HCLKCON_HSMMC0         (1<<15)
+#define S3C2443_HCLKCON_HSMMC          (1<<16)
+#define S3C2443_HCLKCON_CFC            (1<<17)
+#define S3C2443_HCLKCON_SSMC           (1<<18)
+#define S3C2443_HCLKCON_DRAMC          (1<<19)
+
+#define S3C2443_PCLKCON_UART0          (1<<0)
+#define S3C2443_PCLKCON_UART1          (1<<1)
+#define S3C2443_PCLKCON_UART2          (1<<2)
+#define S3C2443_PCLKCON_UART3          (1<<3)
+#define S3C2443_PCLKCON_IIC            (1<<4)
+#define S3C2443_PCLKCON_SDI            (1<<5)
+#define S3C2443_PCLKCON_HSSPI          (1<<6)
+#define S3C2443_PCLKCON_ADC            (1<<7)
+#define S3C2443_PCLKCON_AC97           (1<<8)
+#define S3C2443_PCLKCON_IIS            (1<<9)
+#define S3C2443_PCLKCON_PWMT           (1<<10)
+#define S3C2443_PCLKCON_WDT            (1<<11)
+#define S3C2443_PCLKCON_RTC            (1<<12)
+#define S3C2443_PCLKCON_GPIO           (1<<13)
+#define S3C2443_PCLKCON_SPI0           (1<<14)
+#define S3C2443_PCLKCON_SPI1           (1<<15)
+
+#define S3C2443_SCLKCON_DDRCLK         (1<<16)
+#define S3C2443_SCLKCON_SSMCCLK                (1<<15)
+#define S3C2443_SCLKCON_HSSPICLK       (1<<14)
+#define S3C2443_SCLKCON_HSMMCCLK_EXT   (1<<13)
+#define S3C2443_SCLKCON_HSMMCCLK_EPLL  (1<<12)
+#define S3C2443_SCLKCON_CAMCLK         (1<<11)
+#define S3C2443_SCLKCON_DISPCLK                (1<<10)
+#define S3C2443_SCLKCON_I2SCLK         (1<<9)
+#define S3C2443_SCLKCON_UARTCLK                (1<<8)
+#define S3C2443_SCLKCON_USBHOST                (1<<1)
+
+#define S3C2443_PWRCFG_SLEEP           (1<<15)
+
+#define S3C2443_PWRCFG_USBPHY          (1 << 4)
+
+#define S3C2443_URSTCON_FUNCRST                (1 << 2)
+#define S3C2443_URSTCON_PHYRST         (1 << 0)
+
+#define S3C2443_PHYCTRL_CLKSEL         (1 << 3)
+#define S3C2443_PHYCTRL_EXTCLK         (1 << 2)
+#define S3C2443_PHYCTRL_PLLSEL         (1 << 1)
+#define S3C2443_PHYCTRL_DSPORT         (1 << 0)
+
+#define S3C2443_PHYPWR_COMMON_ON       (1 << 31)
+#define S3C2443_PHYPWR_ANALOG_PD       (1 << 4)
+#define S3C2443_PHYPWR_PLL_REFCLK      (1 << 3)
+#define S3C2443_PHYPWR_XO_ON           (1 << 2)
+#define S3C2443_PHYPWR_PLL_PWRDN       (1 << 1)
+#define S3C2443_PHYPWR_FSUSPEND                (1 << 0)
+
+#define S3C2443_UCLKCON_DETECT_VBUS    (1 << 31)
+#define S3C2443_UCLKCON_FUNC_CLKEN     (1 << 2)
+#define S3C2443_UCLKCON_TCLKEN         (1 << 0)
+
+#include <asm/div64.h>
+
+static inline unsigned int
+s3c2443_get_mpll(unsigned int pllval, unsigned int baseclk)
+{
+       unsigned int mdiv, pdiv, sdiv;
+       uint64_t fvco;
+
+       mdiv = pllval >> S3C2443_PLLCON_MDIVSHIFT;
+       pdiv = pllval >> S3C2443_PLLCON_PDIVSHIFT;
+       sdiv = pllval >> S3C2443_PLLCON_SDIVSHIFT;
+
+       mdiv &= S3C2443_PLLCON_MDIVMASK;
+       pdiv &= S3C2443_PLLCON_PDIVMASK;
+       sdiv &= S3C2443_PLLCON_SDIVMASK;
+
+       fvco = (uint64_t)baseclk * (2 * (mdiv + 8));
+       do_div(fvco, pdiv << sdiv);
+
+       return (unsigned int)fvco;
+}
+
+static inline unsigned int
+s3c2443_get_epll(unsigned int pllval, unsigned int baseclk)
+{
+       unsigned int mdiv, pdiv, sdiv;
+       uint64_t fvco;
+
+       mdiv = pllval >> S3C2443_PLLCON_MDIVSHIFT;
+       pdiv = pllval >> S3C2443_PLLCON_PDIVSHIFT;
+       sdiv = pllval >> S3C2443_PLLCON_SDIVSHIFT;
+
+       mdiv &= S3C2443_PLLCON_MDIVMASK;
+       pdiv &= S3C2443_PLLCON_PDIVMASK;
+       sdiv &= S3C2443_PLLCON_SDIVMASK;
+
+       fvco = (uint64_t)baseclk * (mdiv + 8);
+       do_div(fvco, (pdiv + 2) << sdiv);
+
+       return (unsigned int)fvco;
+}
+
+#endif /*  __ASM_ARM_REGS_S3C2443_CLOCK */
+
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-sdi.h b/arch/arm/mach-s3c24xx/include/mach/regs-sdi.h
new file mode 100644 (file)
index 0000000..cbf2d88
--- /dev/null
@@ -0,0 +1,127 @@
+/* arch/arm/mach-s3c2410/include/mach/regs-sdi.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 MMC/SDIO register definitions
+*/
+
+#ifndef __ASM_ARM_REGS_SDI
+#define __ASM_ARM_REGS_SDI "regs-sdi.h"
+
+#define S3C2410_SDICON                (0x00)
+#define S3C2410_SDIPRE                (0x04)
+#define S3C2410_SDICMDARG             (0x08)
+#define S3C2410_SDICMDCON             (0x0C)
+#define S3C2410_SDICMDSTAT            (0x10)
+#define S3C2410_SDIRSP0               (0x14)
+#define S3C2410_SDIRSP1               (0x18)
+#define S3C2410_SDIRSP2               (0x1C)
+#define S3C2410_SDIRSP3               (0x20)
+#define S3C2410_SDITIMER              (0x24)
+#define S3C2410_SDIBSIZE              (0x28)
+#define S3C2410_SDIDCON               (0x2C)
+#define S3C2410_SDIDCNT               (0x30)
+#define S3C2410_SDIDSTA               (0x34)
+#define S3C2410_SDIFSTA               (0x38)
+
+#define S3C2410_SDIDATA               (0x3C)
+#define S3C2410_SDIIMSK               (0x40)
+
+#define S3C2440_SDIDATA               (0x40)
+#define S3C2440_SDIIMSK               (0x3C)
+
+#define S3C2440_SDICON_SDRESET        (1<<8)
+#define S3C2440_SDICON_MMCCLOCK       (1<<5)
+#define S3C2410_SDICON_BYTEORDER      (1<<4)
+#define S3C2410_SDICON_SDIOIRQ        (1<<3)
+#define S3C2410_SDICON_RWAITEN        (1<<2)
+#define S3C2410_SDICON_FIFORESET      (1<<1)
+#define S3C2410_SDICON_CLOCKTYPE      (1<<0)
+
+#define S3C2410_SDICMDCON_ABORT       (1<<12)
+#define S3C2410_SDICMDCON_WITHDATA    (1<<11)
+#define S3C2410_SDICMDCON_LONGRSP     (1<<10)
+#define S3C2410_SDICMDCON_WAITRSP     (1<<9)
+#define S3C2410_SDICMDCON_CMDSTART    (1<<8)
+#define S3C2410_SDICMDCON_SENDERHOST  (1<<6)
+#define S3C2410_SDICMDCON_INDEX       (0x3f)
+
+#define S3C2410_SDICMDSTAT_CRCFAIL    (1<<12)
+#define S3C2410_SDICMDSTAT_CMDSENT    (1<<11)
+#define S3C2410_SDICMDSTAT_CMDTIMEOUT (1<<10)
+#define S3C2410_SDICMDSTAT_RSPFIN     (1<<9)
+#define S3C2410_SDICMDSTAT_XFERING    (1<<8)
+#define S3C2410_SDICMDSTAT_INDEX      (0xff)
+
+#define S3C2440_SDIDCON_DS_BYTE       (0<<22)
+#define S3C2440_SDIDCON_DS_HALFWORD   (1<<22)
+#define S3C2440_SDIDCON_DS_WORD       (2<<22)
+#define S3C2410_SDIDCON_IRQPERIOD     (1<<21)
+#define S3C2410_SDIDCON_TXAFTERRESP   (1<<20)
+#define S3C2410_SDIDCON_RXAFTERCMD    (1<<19)
+#define S3C2410_SDIDCON_BUSYAFTERCMD  (1<<18)
+#define S3C2410_SDIDCON_BLOCKMODE     (1<<17)
+#define S3C2410_SDIDCON_WIDEBUS       (1<<16)
+#define S3C2410_SDIDCON_DMAEN         (1<<15)
+#define S3C2410_SDIDCON_STOP          (1<<14)
+#define S3C2440_SDIDCON_DATSTART      (1<<14)
+#define S3C2410_SDIDCON_DATMODE              (3<<12)
+#define S3C2410_SDIDCON_BLKNUM        (0x7ff)
+
+/* constants for S3C2410_SDIDCON_DATMODE */
+#define S3C2410_SDIDCON_XFER_READY    (0<<12)
+#define S3C2410_SDIDCON_XFER_CHKSTART (1<<12)
+#define S3C2410_SDIDCON_XFER_RXSTART  (2<<12)
+#define S3C2410_SDIDCON_XFER_TXSTART  (3<<12)
+
+#define S3C2410_SDIDCON_BLKNUM_MASK   (0xFFF)
+#define S3C2410_SDIDCNT_BLKNUM_SHIFT  (12)
+
+#define S3C2410_SDIDSTA_RDYWAITREQ    (1<<10)
+#define S3C2410_SDIDSTA_SDIOIRQDETECT (1<<9)
+#define S3C2410_SDIDSTA_FIFOFAIL      (1<<8)   /* reserved on 2440 */
+#define S3C2410_SDIDSTA_CRCFAIL       (1<<7)
+#define S3C2410_SDIDSTA_RXCRCFAIL     (1<<6)
+#define S3C2410_SDIDSTA_DATATIMEOUT   (1<<5)
+#define S3C2410_SDIDSTA_XFERFINISH    (1<<4)
+#define S3C2410_SDIDSTA_BUSYFINISH    (1<<3)
+#define S3C2410_SDIDSTA_SBITERR       (1<<2)   /* reserved on 2410a/2440 */
+#define S3C2410_SDIDSTA_TXDATAON      (1<<1)
+#define S3C2410_SDIDSTA_RXDATAON      (1<<0)
+
+#define S3C2440_SDIFSTA_FIFORESET      (1<<16)
+#define S3C2440_SDIFSTA_FIFOFAIL       (3<<14)  /* 3 is correct (2 bits) */
+#define S3C2410_SDIFSTA_TFDET          (1<<13)
+#define S3C2410_SDIFSTA_RFDET          (1<<12)
+#define S3C2410_SDIFSTA_TFHALF         (1<<11)
+#define S3C2410_SDIFSTA_TFEMPTY        (1<<10)
+#define S3C2410_SDIFSTA_RFLAST         (1<<9)
+#define S3C2410_SDIFSTA_RFFULL         (1<<8)
+#define S3C2410_SDIFSTA_RFHALF         (1<<7)
+#define S3C2410_SDIFSTA_COUNTMASK      (0x7f)
+
+#define S3C2410_SDIIMSK_RESPONSECRC    (1<<17)
+#define S3C2410_SDIIMSK_CMDSENT        (1<<16)
+#define S3C2410_SDIIMSK_CMDTIMEOUT     (1<<15)
+#define S3C2410_SDIIMSK_RESPONSEND     (1<<14)
+#define S3C2410_SDIIMSK_READWAIT       (1<<13)
+#define S3C2410_SDIIMSK_SDIOIRQ        (1<<12)
+#define S3C2410_SDIIMSK_FIFOFAIL       (1<<11)
+#define S3C2410_SDIIMSK_CRCSTATUS      (1<<10)
+#define S3C2410_SDIIMSK_DATACRC        (1<<9)
+#define S3C2410_SDIIMSK_DATATIMEOUT    (1<<8)
+#define S3C2410_SDIIMSK_DATAFINISH     (1<<7)
+#define S3C2410_SDIIMSK_BUSYFINISH     (1<<6)
+#define S3C2410_SDIIMSK_SBITERR        (1<<5)  /* reserved 2440/2410a */
+#define S3C2410_SDIIMSK_TXFIFOHALF     (1<<4)
+#define S3C2410_SDIIMSK_TXFIFOEMPTY    (1<<3)
+#define S3C2410_SDIIMSK_RXFIFOLAST     (1<<2)
+#define S3C2410_SDIIMSK_RXFIFOFULL     (1<<1)
+#define S3C2410_SDIIMSK_RXFIFOHALF     (1<<0)
+
+#endif /* __ASM_ARM_REGS_SDI */
diff --git a/arch/arm/mach-s3c24xx/include/mach/tick.h b/arch/arm/mach-s3c24xx/include/mach/tick.h
new file mode 100644 (file)
index 0000000..544da41
--- /dev/null
@@ -0,0 +1,15 @@
+/* linux/arch/arm/mach-s3c2410/include/mach/tick.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C2410 - timer tick support
+ */
+
+#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0))
+
+static inline int s3c24xx_ostimer_pending(void)
+{
+       return __raw_readl(S3C2410_SRCPND) & SRCPND_TIMER4;
+}
diff --git a/arch/arm/mach-s3c24xx/include/mach/timex.h b/arch/arm/mach-s3c24xx/include/mach/timex.h
new file mode 100644 (file)
index 0000000..fe9ca1f
--- /dev/null
@@ -0,0 +1,24 @@
+/* arch/arm/mach-s3c2410/include/mach/timex.h
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - time parameters
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it
+ * a variable is useless. It seems as long as we make our timers an
+ * exact multiple of HZ, any value that makes a 1->1 correspondence
+ * for the time conversion functions to/from jiffies is acceptable.
+*/
+
+#define CLOCK_TICK_RATE 12000000
+
+#endif /* __ASM_ARCH_TIMEX_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/uncompress.h b/arch/arm/mach-s3c24xx/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..8b283f8
--- /dev/null
@@ -0,0 +1,54 @@
+/* arch/arm/mach-s3c2410/include/mach/uncompress.h
+ *
+ * Copyright (c) 2003-2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - uncompress code
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+
+#include <mach/regs-gpio.h>
+#include <mach/map.h>
+
+/* working in physical space... */
+#undef S3C2410_GPIOREG
+#define S3C2410_GPIOREG(x) ((S3C24XX_PA_GPIO + (x)))
+
+#include <plat/uncompress.h>
+
+static inline int is_arm926(void)
+{
+       unsigned int cpuid;
+
+       asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (cpuid));
+
+       return ((cpuid & 0xff0) == 0x260);
+}
+
+static void arch_detect_cpu(void)
+{
+       unsigned int cpuid;
+
+       cpuid = *((volatile unsigned int *)S3C2410_GSTATUS1);
+       cpuid &= S3C2410_GSTATUS1_IDMASK;
+
+       if (is_arm926() || cpuid == S3C2410_GSTATUS1_2440 ||
+           cpuid == S3C2410_GSTATUS1_2442 ||
+           cpuid == S3C2410_GSTATUS1_2416 ||
+           cpuid == S3C2410_GSTATUS1_2450) {
+               fifo_mask = S3C2440_UFSTAT_TXMASK;
+               fifo_max = 63 << S3C2440_UFSTAT_TXSHIFT;
+       } else {
+               fifo_mask = S3C2410_UFSTAT_TXMASK;
+               fifo_max = 15 << S3C2410_UFSTAT_TXSHIFT;
+       }
+}
+
+#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/vr1000-cpld.h b/arch/arm/mach-s3c24xx/include/mach/vr1000-cpld.h
new file mode 100644 (file)
index 0000000..e411991
--- /dev/null
@@ -0,0 +1,18 @@
+/* arch/arm/mach-s3c2410/include/mach/vr1000-cpld.h
+ *
+ * Copyright (c) 2003 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * VR1000 - CPLD control constants
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_VR1000CPLD_H
+#define __ASM_ARCH_VR1000CPLD_H
+
+#define VR1000_CPLD_CTRL2_RAMWEN     (0x04)   /* SRAM Write Enable */
+
+#endif /* __ASM_ARCH_VR1000CPLD_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/vr1000-irq.h b/arch/arm/mach-s3c24xx/include/mach/vr1000-irq.h
new file mode 100644 (file)
index 0000000..47add13
--- /dev/null
@@ -0,0 +1,26 @@
+/* arch/arm/mach-s3c2410/include/mach/vr1000-irq.h
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Machine VR1000 - IRQ Number definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_VR1000IRQ_H
+#define __ASM_ARCH_VR1000IRQ_H
+
+/* irq numbers to onboard peripherals */
+
+#define IRQ_USBOC           IRQ_EINT19
+#define IRQ_IDE0            IRQ_EINT16
+#define IRQ_IDE1            IRQ_EINT17
+#define IRQ_VR1000_SERIAL    IRQ_EINT12
+#define IRQ_VR1000_DM9000A   IRQ_EINT10
+#define IRQ_VR1000_DM9000N   IRQ_EINT9
+#define IRQ_SMALERT         IRQ_EINT8
+
+#endif /* __ASM_ARCH_VR1000IRQ_H */
diff --git a/arch/arm/mach-s3c24xx/include/mach/vr1000-map.h b/arch/arm/mach-s3c24xx/include/mach/vr1000-map.h
new file mode 100644 (file)
index 0000000..99612fc
--- /dev/null
@@ -0,0 +1,110 @@
+/* arch/arm/mach-s3c2410/include/mach/vr1000-map.h
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Machine VR1000 - Memory map definitions
+ *
+ * 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.
+*/
+
+/* needs arch/map.h including with this */
+
+/* ok, we've used up to 0x13000000, now we need to find space for the
+ * peripherals that live in the nGCS[x] areas, which are quite numerous
+ * in their space. We also have the board's CPLD to find register space
+ * for.
+ */
+
+#ifndef __ASM_ARCH_VR1000MAP_H
+#define __ASM_ARCH_VR1000MAP_H
+
+#include <mach/bast-map.h>
+
+#define VR1000_IOADDR(x) BAST_IOADDR(x)
+
+/* we put the CPLD registers next, to get them out of the way */
+
+#define VR1000_VA_CTRL1            VR1000_IOADDR(0x00000000)    /* 0x01300000 */
+#define VR1000_PA_CTRL1            (S3C2410_CS5 | 0x7800000)
+
+#define VR1000_VA_CTRL2            VR1000_IOADDR(0x00100000)    /* 0x01400000 */
+#define VR1000_PA_CTRL2            (S3C2410_CS1 | 0x6000000)
+
+#define VR1000_VA_CTRL3            VR1000_IOADDR(0x00200000)    /* 0x01500000 */
+#define VR1000_PA_CTRL3            (S3C2410_CS1 | 0x6800000)
+
+#define VR1000_VA_CTRL4            VR1000_IOADDR(0x00300000)    /* 0x01600000 */
+#define VR1000_PA_CTRL4            (S3C2410_CS1 | 0x7000000)
+
+/* next, we have the PC104 ISA interrupt registers */
+
+#define VR1000_PA_PC104_IRQREQ  (S3C2410_CS5 | 0x6000000) /* 0x01700000 */
+#define VR1000_VA_PC104_IRQREQ  VR1000_IOADDR(0x00400000)
+
+#define VR1000_PA_PC104_IRQRAW  (S3C2410_CS5 | 0x6800000) /* 0x01800000 */
+#define VR1000_VA_PC104_IRQRAW  VR1000_IOADDR(0x00500000)
+
+#define VR1000_PA_PC104_IRQMASK (S3C2410_CS5 | 0x7000000) /* 0x01900000 */
+#define VR1000_VA_PC104_IRQMASK VR1000_IOADDR(0x00600000)
+
+/* 0xE0000000 contains the IO space that is split by speed and
+ * wether the access is for 8 or 16bit IO... this ensures that
+ * the correct access is made
+ *
+ * 0x10000000 of space, partitioned as so:
+ *
+ * 0x00000000 to 0x04000000  8bit,  slow
+ * 0x04000000 to 0x08000000  16bit, slow
+ * 0x08000000 to 0x0C000000  16bit, net
+ * 0x0C000000 to 0x10000000  16bit, fast
+ *
+ * each of these spaces has the following in:
+ *
+ * 0x02000000 to 0x02100000 1MB  IDE primary channel
+ * 0x02100000 to 0x02200000 1MB  IDE primary channel aux
+ * 0x02200000 to 0x02400000 1MB  IDE secondary channel
+ * 0x02300000 to 0x02400000 1MB  IDE secondary channel aux
+ * 0x02500000 to 0x02600000 1MB  Davicom DM9000 ethernet controllers
+ * 0x02600000 to 0x02700000 1MB
+ *
+ * the phyiscal layout of the zones are:
+ *  nGCS2 - 8bit, slow
+ *  nGCS3 - 16bit, slow
+ *  nGCS4 - 16bit, net
+ *  nGCS5 - 16bit, fast
+ */
+
+#define VR1000_VA_MULTISPACE (0xE0000000)
+
+#define VR1000_VA_ISAIO                   (VR1000_VA_MULTISPACE + 0x00000000)
+#define VR1000_VA_ISAMEM          (VR1000_VA_MULTISPACE + 0x01000000)
+#define VR1000_VA_IDEPRI          (VR1000_VA_MULTISPACE + 0x02000000)
+#define VR1000_VA_IDEPRIAUX       (VR1000_VA_MULTISPACE + 0x02100000)
+#define VR1000_VA_IDESEC          (VR1000_VA_MULTISPACE + 0x02200000)
+#define VR1000_VA_IDESECAUX       (VR1000_VA_MULTISPACE + 0x02300000)
+#define VR1000_VA_ASIXNET         (VR1000_VA_MULTISPACE + 0x02400000)
+#define VR1000_VA_DM9000          (VR1000_VA_MULTISPACE + 0x02500000)
+#define VR1000_VA_SUPERIO         (VR1000_VA_MULTISPACE + 0x02600000)
+
+/* physical offset addresses for the peripherals */
+
+#define VR1000_PA_IDEPRI          (0x02000000)
+#define VR1000_PA_IDEPRIAUX       (0x02800000)
+#define VR1000_PA_IDESEC          (0x03000000)
+#define VR1000_PA_IDESECAUX       (0x03800000)
+#define VR1000_PA_DM9000          (0x05000000)
+
+#define VR1000_PA_SERIAL          (0x11800000)
+#define VR1000_VA_SERIAL          (VR1000_IOADDR(0x00700000))
+
+/* VR1000 ram is in CS1, with A26..A24 = 2_101 */
+#define VR1000_PA_SRAM            (S3C2410_CS1 | 0x05000000)
+
+/* some configurations for the peripherals */
+
+#define VR1000_DM9000_CS        VR1000_VAM_CS4
+
+#endif /* __ASM_ARCH_VR1000MAP_H */
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2412.c b/arch/arm/mach-s3c24xx/irq-s3c2412.c
new file mode 100644 (file)
index 0000000..e65619d
--- /dev/null
@@ -0,0 +1,214 @@
+/* linux/arch/arm/mach-s3c2412/irq.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-power.h>
+
+#include <plat/cpu.h>
+#include <plat/irq.h>
+#include <plat/pm.h>
+
+#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
+#define INTMSK_SUB(start, end) (INTMSK(start, end) << ((start - S3C2410_IRQSUB(0))))
+
+/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by
+ * having them turn up in both the INT* and the EINT* registers. Whilst
+ * both show the status, they both now need to be acked when the IRQs
+ * go off.
+*/
+
+static void
+s3c2412_irq_mask(struct irq_data *data)
+{
+       unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
+       unsigned long mask;
+
+       mask = __raw_readl(S3C2410_INTMSK);
+       __raw_writel(mask | bitval, S3C2410_INTMSK);
+
+       mask = __raw_readl(S3C2412_EINTMASK);
+       __raw_writel(mask | bitval, S3C2412_EINTMASK);
+}
+
+static inline void
+s3c2412_irq_ack(struct irq_data *data)
+{
+       unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
+
+       __raw_writel(bitval, S3C2412_EINTPEND);
+       __raw_writel(bitval, S3C2410_SRCPND);
+       __raw_writel(bitval, S3C2410_INTPND);
+}
+
+static inline void
+s3c2412_irq_maskack(struct irq_data *data)
+{
+       unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
+       unsigned long mask;
+
+       mask = __raw_readl(S3C2410_INTMSK);
+       __raw_writel(mask|bitval, S3C2410_INTMSK);
+
+       mask = __raw_readl(S3C2412_EINTMASK);
+       __raw_writel(mask | bitval, S3C2412_EINTMASK);
+
+       __raw_writel(bitval, S3C2412_EINTPEND);
+       __raw_writel(bitval, S3C2410_SRCPND);
+       __raw_writel(bitval, S3C2410_INTPND);
+}
+
+static void
+s3c2412_irq_unmask(struct irq_data *data)
+{
+       unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
+       unsigned long mask;
+
+       mask = __raw_readl(S3C2412_EINTMASK);
+       __raw_writel(mask & ~bitval, S3C2412_EINTMASK);
+
+       mask = __raw_readl(S3C2410_INTMSK);
+       __raw_writel(mask & ~bitval, S3C2410_INTMSK);
+}
+
+static struct irq_chip s3c2412_irq_eint0t4 = {
+       .irq_ack        = s3c2412_irq_ack,
+       .irq_mask       = s3c2412_irq_mask,
+       .irq_unmask     = s3c2412_irq_unmask,
+       .irq_set_wake   = s3c_irq_wake,
+       .irq_set_type   = s3c_irqext_type,
+};
+
+#define INTBIT(x)      (1 << ((x) - S3C2410_IRQSUB(0)))
+
+/* CF and SDI sub interrupts */
+
+static void s3c2412_irq_demux_cfsdi(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned int subsrc, submsk;
+
+       subsrc = __raw_readl(S3C2410_SUBSRCPND);
+       submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+       subsrc  &= ~submsk;
+
+       if (subsrc & INTBIT(IRQ_S3C2412_SDI))
+               generic_handle_irq(IRQ_S3C2412_SDI);
+
+       if (subsrc & INTBIT(IRQ_S3C2412_CF))
+               generic_handle_irq(IRQ_S3C2412_CF);
+}
+
+#define INTMSK_CFSDI   (1UL << (IRQ_S3C2412_CFSDI - IRQ_EINT0))
+#define SUBMSK_CFSDI   INTMSK_SUB(IRQ_S3C2412_SDI, IRQ_S3C2412_CF)
+
+static void s3c2412_irq_cfsdi_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI);
+}
+
+static void s3c2412_irq_cfsdi_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_CFSDI);
+}
+
+static void s3c2412_irq_cfsdi_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI);
+}
+
+static struct irq_chip s3c2412_irq_cfsdi = {
+       .name           = "s3c2412-cfsdi",
+       .irq_ack        = s3c2412_irq_cfsdi_ack,
+       .irq_mask       = s3c2412_irq_cfsdi_mask,
+       .irq_unmask     = s3c2412_irq_cfsdi_unmask,
+};
+
+static int s3c2412_irq_rtc_wake(struct irq_data *data, unsigned int state)
+{
+       unsigned long pwrcfg;
+
+       pwrcfg = __raw_readl(S3C2412_PWRCFG);
+       if (state)
+               pwrcfg &= ~S3C2412_PWRCFG_RTC_MASKIRQ;
+       else
+               pwrcfg |= S3C2412_PWRCFG_RTC_MASKIRQ;
+       __raw_writel(pwrcfg, S3C2412_PWRCFG);
+
+       return s3c_irq_chip.irq_set_wake(data, state);
+}
+
+static struct irq_chip s3c2412_irq_rtc_chip;
+
+static int s3c2412_irq_add(struct device *dev, struct subsys_interface *sif)
+{
+       unsigned int irqno;
+
+       for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
+               irq_set_chip_and_handler(irqno, &s3c2412_irq_eint0t4,
+                                        handle_edge_irq);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+
+       /* add demux support for CF/SDI */
+
+       irq_set_chained_handler(IRQ_S3C2412_CFSDI, s3c2412_irq_demux_cfsdi);
+
+       for (irqno = IRQ_S3C2412_SDI; irqno <= IRQ_S3C2412_CF; irqno++) {
+               irq_set_chip_and_handler(irqno, &s3c2412_irq_cfsdi,
+                                        handle_level_irq);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+
+       /* change RTC IRQ's set wake method */
+
+       s3c2412_irq_rtc_chip = s3c_irq_chip;
+       s3c2412_irq_rtc_chip.irq_set_wake = s3c2412_irq_rtc_wake;
+
+       irq_set_chip(IRQ_RTC, &s3c2412_irq_rtc_chip);
+
+       return 0;
+}
+
+static struct subsys_interface s3c2412_irq_interface = {
+       .name           = "s3c2412_irq",
+       .subsys         = &s3c2412_subsys,
+       .add_dev        = s3c2412_irq_add,
+};
+
+static int s3c2412_irq_init(void)
+{
+       return subsys_interface_register(&s3c2412_irq_interface);
+}
+
+arch_initcall(s3c2412_irq_init);
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2416.c b/arch/arm/mach-s3c24xx/irq-s3c2416.c
new file mode 100644 (file)
index 0000000..fd49f35
--- /dev/null
@@ -0,0 +1,250 @@
+/* linux/arch/arm/mach-s3c2416/irq.c
+ *
+ * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
+ *     as part of OpenInkpot project
+ * Copyright (c) 2009 Promwad Innovation Company
+ *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
+
+#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
+
+static inline void s3c2416_irq_demux(unsigned int irq, unsigned int len)
+{
+       unsigned int subsrc, submsk;
+       unsigned int end;
+
+       /* read the current pending interrupts, and the mask
+        * for what it is available */
+
+       subsrc = __raw_readl(S3C2410_SUBSRCPND);
+       submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+       subsrc  &= ~submsk;
+       subsrc >>= (irq - S3C2410_IRQSUB(0));
+       subsrc  &= (1 << len)-1;
+
+       end = len + irq;
+
+       for (; irq < end && subsrc; irq++) {
+               if (subsrc & 1)
+                       generic_handle_irq(irq);
+
+               subsrc >>= 1;
+       }
+}
+
+/* WDT/AC97 sub interrupts */
+
+static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
+{
+       s3c2416_irq_demux(IRQ_S3C2443_WDT, 4);
+}
+
+#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
+#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
+
+static void s3c2416_irq_wdtac97_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+}
+
+static void s3c2416_irq_wdtac97_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
+}
+
+static void s3c2416_irq_wdtac97_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+}
+
+static struct irq_chip s3c2416_irq_wdtac97 = {
+       .irq_mask       = s3c2416_irq_wdtac97_mask,
+       .irq_unmask     = s3c2416_irq_wdtac97_unmask,
+       .irq_ack        = s3c2416_irq_wdtac97_ack,
+};
+
+/* LCD sub interrupts */
+
+static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
+{
+       s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4);
+}
+
+#define INTMSK_LCD     (1UL << (IRQ_LCD - IRQ_EINT0))
+#define SUBMSK_LCD     INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
+
+static void s3c2416_irq_lcd_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
+}
+
+static void s3c2416_irq_lcd_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_LCD);
+}
+
+static void s3c2416_irq_lcd_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
+}
+
+static struct irq_chip s3c2416_irq_lcd = {
+       .irq_mask       = s3c2416_irq_lcd_mask,
+       .irq_unmask     = s3c2416_irq_lcd_unmask,
+       .irq_ack        = s3c2416_irq_lcd_ack,
+};
+
+/* DMA sub interrupts */
+
+static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
+{
+       s3c2416_irq_demux(IRQ_S3C2443_DMA0, 6);
+}
+
+#define INTMSK_DMA     (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
+#define SUBMSK_DMA     INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
+
+
+static void s3c2416_irq_dma_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
+}
+
+static void s3c2416_irq_dma_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_DMA);
+}
+
+static void s3c2416_irq_dma_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
+}
+
+static struct irq_chip s3c2416_irq_dma = {
+       .irq_mask       = s3c2416_irq_dma_mask,
+       .irq_unmask     = s3c2416_irq_dma_unmask,
+       .irq_ack        = s3c2416_irq_dma_ack,
+};
+
+/* UART3 sub interrupts */
+
+static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
+{
+       s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
+}
+
+#define INTMSK_UART3   (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
+#define SUBMSK_UART3   (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
+
+static void s3c2416_irq_uart3_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
+}
+
+static void s3c2416_irq_uart3_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_UART3);
+}
+
+static void s3c2416_irq_uart3_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
+}
+
+static struct irq_chip s3c2416_irq_uart3 = {
+       .irq_mask       = s3c2416_irq_uart3_mask,
+       .irq_unmask     = s3c2416_irq_uart3_unmask,
+       .irq_ack        = s3c2416_irq_uart3_ack,
+};
+
+/* IRQ initialisation code */
+
+static int __init s3c2416_add_sub(unsigned int base,
+                                  void (*demux)(unsigned int,
+                                                struct irq_desc *),
+                                  struct irq_chip *chip,
+                                  unsigned int start, unsigned int end)
+{
+       unsigned int irqno;
+
+       irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
+       irq_set_chained_handler(base, demux);
+
+       for (irqno = start; irqno <= end; irqno++) {
+               irq_set_chip_and_handler(irqno, chip, handle_level_irq);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+
+       return 0;
+}
+
+static int __init s3c2416_irq_add(struct device *dev,
+                                 struct subsys_interface *sif)
+{
+       printk(KERN_INFO "S3C2416: IRQ Support\n");
+
+       s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd,
+                       IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4);
+
+       s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma,
+                       &s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
+
+       s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3,
+                       &s3c2416_irq_uart3,
+                       IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
+
+       s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97,
+                       &s3c2416_irq_wdtac97,
+                       IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
+
+       return 0;
+}
+
+static struct subsys_interface s3c2416_irq_interface = {
+       .name           = "s3c2416_irq",
+       .subsys         = &s3c2416_subsys,
+       .add_dev        = s3c2416_irq_add,
+};
+
+static int __init s3c2416_irq_init(void)
+{
+       return subsys_interface_register(&s3c2416_irq_interface);
+}
+
+arch_initcall(s3c2416_irq_init);
+
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2440.c b/arch/arm/mach-s3c24xx/irq-s3c2440.c
new file mode 100644 (file)
index 0000000..4a18cde
--- /dev/null
@@ -0,0 +1,128 @@
+/* linux/arch/arm/mach-s3c2440/irq.c
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
+
+/* WDT/AC97 */
+
+static void s3c_irq_demux_wdtac97(unsigned int irq,
+                                 struct irq_desc *desc)
+{
+       unsigned int subsrc, submsk;
+
+       /* read the current pending interrupts, and the mask
+        * for what it is available */
+
+       subsrc = __raw_readl(S3C2410_SUBSRCPND);
+       submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+       subsrc &= ~submsk;
+       subsrc >>= 13;
+       subsrc &= 3;
+
+       if (subsrc != 0) {
+               if (subsrc & 1) {
+                       generic_handle_irq(IRQ_S3C2440_WDT);
+               }
+               if (subsrc & 2) {
+                       generic_handle_irq(IRQ_S3C2440_AC97);
+               }
+       }
+}
+
+
+#define INTMSK_WDT      (1UL << (IRQ_WDT - IRQ_EINT0))
+
+static void
+s3c_irq_wdtac97_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_WDT, 3 << 13);
+}
+
+static void
+s3c_irq_wdtac97_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_WDT);
+}
+
+static void
+s3c_irq_wdtac97_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_WDT, 3 << 13);
+}
+
+static struct irq_chip s3c_irq_wdtac97 = {
+       .irq_mask       = s3c_irq_wdtac97_mask,
+       .irq_unmask     = s3c_irq_wdtac97_unmask,
+       .irq_ack        = s3c_irq_wdtac97_ack,
+};
+
+static int s3c2440_irq_add(struct device *dev, struct subsys_interface *sif)
+{
+       unsigned int irqno;
+
+       printk("S3C2440: IRQ Support\n");
+
+       /* add new chained handler for wdt, ac7 */
+
+       irq_set_chip_and_handler(IRQ_WDT, &s3c_irq_level_chip,
+                                handle_level_irq);
+       irq_set_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97);
+
+       for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) {
+               irq_set_chip_and_handler(irqno, &s3c_irq_wdtac97,
+                                        handle_level_irq);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+
+       return 0;
+}
+
+static struct subsys_interface s3c2440_irq_interface = {
+       .name           = "s3c2440_irq",
+       .subsys         = &s3c2440_subsys,
+       .add_dev        = s3c2440_irq_add,
+};
+
+static int s3c2440_irq_init(void)
+{
+       return subsys_interface_register(&s3c2440_irq_interface);
+}
+
+arch_initcall(s3c2440_irq_init);
+
diff --git a/arch/arm/mach-s3c24xx/irq-s3c2443.c b/arch/arm/mach-s3c24xx/irq-s3c2443.c
new file mode 100644 (file)
index 0000000..ac2829f
--- /dev/null
@@ -0,0 +1,281 @@
+/* linux/arch/arm/mach-s3c2443/irq.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
+
+#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
+
+static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len)
+{
+       unsigned int subsrc, submsk;
+       unsigned int end;
+
+       /* read the current pending interrupts, and the mask
+        * for what it is available */
+
+       subsrc = __raw_readl(S3C2410_SUBSRCPND);
+       submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+       subsrc  &= ~submsk;
+       subsrc >>= (irq - S3C2410_IRQSUB(0));
+       subsrc  &= (1 << len)-1;
+
+       end = len + irq;
+
+       for (; irq < end && subsrc; irq++) {
+               if (subsrc & 1)
+                       generic_handle_irq(irq);
+
+               subsrc >>= 1;
+       }
+}
+
+/* WDT/AC97 sub interrupts */
+
+static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
+{
+       s3c2443_irq_demux(IRQ_S3C2443_WDT, 4);
+}
+
+#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
+#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
+
+static void s3c2443_irq_wdtac97_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+}
+
+static void s3c2443_irq_wdtac97_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
+}
+
+static void s3c2443_irq_wdtac97_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+}
+
+static struct irq_chip s3c2443_irq_wdtac97 = {
+       .irq_mask       = s3c2443_irq_wdtac97_mask,
+       .irq_unmask     = s3c2443_irq_wdtac97_unmask,
+       .irq_ack        = s3c2443_irq_wdtac97_ack,
+};
+
+/* LCD sub interrupts */
+
+static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
+{
+       s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4);
+}
+
+#define INTMSK_LCD     (1UL << (IRQ_LCD - IRQ_EINT0))
+#define SUBMSK_LCD     INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
+
+static void s3c2443_irq_lcd_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
+}
+
+static void s3c2443_irq_lcd_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_LCD);
+}
+
+static void s3c2443_irq_lcd_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
+}
+
+static struct irq_chip s3c2443_irq_lcd = {
+       .irq_mask       = s3c2443_irq_lcd_mask,
+       .irq_unmask     = s3c2443_irq_lcd_unmask,
+       .irq_ack        = s3c2443_irq_lcd_ack,
+};
+
+/* DMA sub interrupts */
+
+static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
+{
+       s3c2443_irq_demux(IRQ_S3C2443_DMA0, 6);
+}
+
+#define INTMSK_DMA     (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
+#define SUBMSK_DMA     INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
+
+static void s3c2443_irq_dma_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
+}
+
+static void s3c2443_irq_dma_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_DMA);
+}
+
+static void s3c2443_irq_dma_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
+}
+
+static struct irq_chip s3c2443_irq_dma = {
+       .irq_mask       = s3c2443_irq_dma_mask,
+       .irq_unmask     = s3c2443_irq_dma_unmask,
+       .irq_ack        = s3c2443_irq_dma_ack,
+};
+
+/* UART3 sub interrupts */
+
+static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
+{
+       s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
+}
+
+#define INTMSK_UART3   (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
+#define SUBMSK_UART3   (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
+
+static void s3c2443_irq_uart3_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
+}
+
+static void s3c2443_irq_uart3_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_UART3);
+}
+
+static void s3c2443_irq_uart3_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
+}
+
+static struct irq_chip s3c2443_irq_uart3 = {
+       .irq_mask       = s3c2443_irq_uart3_mask,
+       .irq_unmask     = s3c2443_irq_uart3_unmask,
+       .irq_ack        = s3c2443_irq_uart3_ack,
+};
+
+/* CAM sub interrupts */
+
+static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc)
+{
+       s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4);
+}
+
+#define INTMSK_CAM     (1UL << (IRQ_CAM - IRQ_EINT0))
+#define SUBMSK_CAM     INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P)
+
+static void s3c2443_irq_cam_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_CAM, SUBMSK_CAM);
+}
+
+static void s3c2443_irq_cam_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_CAM);
+}
+
+static void s3c2443_irq_cam_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_CAM, SUBMSK_CAM);
+}
+
+static struct irq_chip s3c2443_irq_cam = {
+       .irq_mask       = s3c2443_irq_cam_mask,
+       .irq_unmask     = s3c2443_irq_cam_unmask,
+       .irq_ack        = s3c2443_irq_cam_ack,
+};
+
+/* IRQ initialisation code */
+
+static int __init s3c2443_add_sub(unsigned int base,
+                                  void (*demux)(unsigned int,
+                                                struct irq_desc *),
+                                  struct irq_chip *chip,
+                                  unsigned int start, unsigned int end)
+{
+       unsigned int irqno;
+
+       irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq);
+       irq_set_chained_handler(base, demux);
+
+       for (irqno = start; irqno <= end; irqno++) {
+               irq_set_chip_and_handler(irqno, chip, handle_level_irq);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+
+       return 0;
+}
+
+static int __init s3c2443_irq_add(struct device *dev,
+                                 struct subsys_interface *sif)
+{
+       printk("S3C2443: IRQ Support\n");
+
+       s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam,
+                       IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P);
+
+       s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd,
+                       IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4);
+
+       s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma,
+                       &s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
+
+       s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3,
+                       &s3c2443_irq_uart3,
+                       IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
+
+       s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97,
+                       &s3c2443_irq_wdtac97,
+                       IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
+
+       return 0;
+}
+
+static struct subsys_interface s3c2443_irq_interface = {
+       .name           = "s3c2443_irq",
+       .subsys         = &s3c2443_subsys,
+       .add_dev        = s3c2443_irq_add,
+};
+
+static int __init s3c2443_irq_init(void)
+{
+       return subsys_interface_register(&s3c2443_irq_interface);
+}
+
+arch_initcall(s3c2443_irq_init);
+
diff --git a/arch/arm/mach-s3c24xx/irq-s3c244x.c b/arch/arm/mach-s3c24xx/irq-s3c244x.c
new file mode 100644 (file)
index 0000000..5fe8e58
--- /dev/null
@@ -0,0 +1,142 @@
+/* linux/arch/arm/plat-s3c24xx/s3c244x-irq.c
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
+
+/* camera irq */
+
+static void s3c_irq_demux_cam(unsigned int irq,
+                             struct irq_desc *desc)
+{
+       unsigned int subsrc, submsk;
+
+       /* read the current pending interrupts, and the mask
+        * for what it is available */
+
+       subsrc = __raw_readl(S3C2410_SUBSRCPND);
+       submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+       subsrc &= ~submsk;
+       subsrc >>= 11;
+       subsrc &= 3;
+
+       if (subsrc != 0) {
+               if (subsrc & 1) {
+                       generic_handle_irq(IRQ_S3C2440_CAM_C);
+               }
+               if (subsrc & 2) {
+                       generic_handle_irq(IRQ_S3C2440_CAM_P);
+               }
+       }
+}
+
+#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
+
+static void
+s3c_irq_cam_mask(struct irq_data *data)
+{
+       s3c_irqsub_mask(data->irq, INTMSK_CAM, 3 << 11);
+}
+
+static void
+s3c_irq_cam_unmask(struct irq_data *data)
+{
+       s3c_irqsub_unmask(data->irq, INTMSK_CAM);
+}
+
+static void
+s3c_irq_cam_ack(struct irq_data *data)
+{
+       s3c_irqsub_maskack(data->irq, INTMSK_CAM, 3 << 11);
+}
+
+static struct irq_chip s3c_irq_cam = {
+       .irq_mask       = s3c_irq_cam_mask,
+       .irq_unmask     = s3c_irq_cam_unmask,
+       .irq_ack        = s3c_irq_cam_ack,
+};
+
+static int s3c244x_irq_add(struct device *dev, struct subsys_interface *sif)
+{
+       unsigned int irqno;
+
+       irq_set_chip_and_handler(IRQ_NFCON, &s3c_irq_level_chip,
+                                handle_level_irq);
+       set_irq_flags(IRQ_NFCON, IRQF_VALID);
+
+       /* add chained handler for camera */
+
+       irq_set_chip_and_handler(IRQ_CAM, &s3c_irq_level_chip,
+                                handle_level_irq);
+       irq_set_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
+
+       for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
+               irq_set_chip_and_handler(irqno, &s3c_irq_cam,
+                                        handle_level_irq);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+
+       return 0;
+}
+
+static struct subsys_interface s3c2440_irq_interface = {
+       .name           = "s3c2440_irq",
+       .subsys         = &s3c2440_subsys,
+       .add_dev        = s3c244x_irq_add,
+};
+
+static int s3c2440_irq_init(void)
+{
+       return subsys_interface_register(&s3c2440_irq_interface);
+}
+
+arch_initcall(s3c2440_irq_init);
+
+static struct subsys_interface s3c2442_irq_interface = {
+       .name           = "s3c2442_irq",
+       .subsys         = &s3c2442_subsys,
+       .add_dev        = s3c244x_irq_add,
+};
+
+
+static int s3c2442_irq_init(void)
+{
+       return subsys_interface_register(&s3c2442_irq_interface);
+}
+
+arch_initcall(s3c2442_irq_init);
diff --git a/arch/arm/mach-s3c24xx/mach-amlm5900.c b/arch/arm/mach-s3c24xx/mach-amlm5900.c
new file mode 100644 (file)
index 0000000..4220cc6
--- /dev/null
@@ -0,0 +1,247 @@
+/* linux/arch/arm/mach-s3c2410/mach-amlm5900.c
+ *
+ * linux/arch/arm/mach-s3c2410/mach-amlm5900.c
+ *
+ * Copyright (c) 2006 American Microsystems Limited
+ *     David Anders <danders@amltd.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
+ *
+ * @History:
+ * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ ***********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/flash.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <mach/fb.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/gpio-cfg.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/physmap.h>
+
+#include "common.h"
+
+static struct resource amlm5900_nor_resource = {
+               .start = 0x00000000,
+               .end   = 0x01000000 - 1,
+               .flags = IORESOURCE_MEM,
+};
+
+
+
+static struct mtd_partition amlm5900_mtd_partitions[] = {
+       {
+               .name           = "System",
+               .size           = 0x240000,
+               .offset         = 0,
+               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
+       }, {
+               .name           = "Kernel",
+               .size           = 0x100000,
+               .offset         = MTDPART_OFS_APPEND,
+       }, {
+               .name           = "Ramdisk",
+               .size           = 0x300000,
+               .offset         = MTDPART_OFS_APPEND,
+       }, {
+               .name           = "JFFS2",
+               .size           = 0x9A0000,
+               .offset         = MTDPART_OFS_APPEND,
+       }, {
+               .name           = "Settings",
+               .size           = MTDPART_SIZ_FULL,
+               .offset         = MTDPART_OFS_APPEND,
+       }
+};
+
+static struct physmap_flash_data amlm5900_flash_data = {
+       .width          = 2,
+       .parts          = amlm5900_mtd_partitions,
+       .nr_parts       = ARRAY_SIZE(amlm5900_mtd_partitions),
+};
+
+static struct platform_device amlm5900_device_nor = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev = {
+                       .platform_data = &amlm5900_flash_data,
+               },
+       .num_resources  = 1,
+       .resource       = &amlm5900_nor_resource,
+};
+
+static struct map_desc amlm5900_iodesc[] __initdata = {
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg amlm5900_uartcfgs[] = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+
+static struct platform_device *amlm5900_devices[] __initdata = {
+#ifdef CONFIG_FB_S3C2410
+       &s3c_device_lcd,
+#endif
+       &s3c_device_adc,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_ohci,
+       &s3c_device_rtc,
+       &s3c_device_usbgadget,
+        &s3c_device_sdi,
+       &amlm5900_device_nor,
+};
+
+static void __init amlm5900_map_io(void)
+{
+       s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(amlm5900_uartcfgs, ARRAY_SIZE(amlm5900_uartcfgs));
+}
+
+#ifdef CONFIG_FB_S3C2410
+static struct s3c2410fb_display __initdata amlm5900_lcd_info = {
+       .width          = 160,
+       .height         = 160,
+
+       .type           = S3C2410_LCDCON1_STN4,
+
+       .pixclock       = 680000, /* HCLK = 100MHz */
+       .xres           = 160,
+       .yres           = 160,
+       .bpp            = 4,
+       .left_margin    = 1 << (4 + 3),
+       .right_margin   = 8 << 3,
+       .hsync_len      = 48,
+       .upper_margin   = 0,
+       .lower_margin   = 0,
+
+       .lcdcon5        = 0x00000001,
+};
+
+static struct s3c2410fb_mach_info __initdata amlm5900_fb_info = {
+
+       .displays = &amlm5900_lcd_info,
+       .num_displays = 1,
+       .default_display = 0,
+
+       .gpccon =       0xaaaaaaaa,
+       .gpccon_mask =  0xffffffff,
+       .gpcup =        0x0000ffff,
+       .gpcup_mask =   0xffffffff,
+
+       .gpdcon =       0xaaaaaaaa,
+       .gpdcon_mask =  0xffffffff,
+       .gpdup =        0x0000ffff,
+       .gpdup_mask =   0xffffffff,
+};
+#endif
+
+static irqreturn_t
+amlm5900_wake_interrupt(int irq, void *ignored)
+{
+       return IRQ_HANDLED;
+}
+
+static void amlm5900_init_pm(void)
+{
+       int ret = 0;
+
+       ret = request_irq(IRQ_EINT9, &amlm5900_wake_interrupt,
+                               IRQF_TRIGGER_RISING | IRQF_SHARED,
+                               "amlm5900_wakeup", &amlm5900_wake_interrupt);
+       if (ret != 0) {
+               printk(KERN_ERR "AML-M5900: no wakeup irq, %d?\n", ret);
+       } else {
+               enable_irq_wake(IRQ_EINT9);
+               /* configure the suspend/resume status pin */
+               s3c_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT);
+               s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_UP);
+       }
+}
+static void __init amlm5900_init(void)
+{
+       amlm5900_init_pm();
+#ifdef CONFIG_FB_S3C2410
+       s3c24xx_fb_set_platdata(&amlm5900_fb_info);
+#endif
+       s3c_i2c0_set_platdata(NULL);
+       platform_add_devices(amlm5900_devices, ARRAY_SIZE(amlm5900_devices));
+}
+
+MACHINE_START(AML_M5900, "AML_M5900")
+       .atag_offset    = 0x100,
+       .map_io         = amlm5900_map_io,
+       .init_irq       = s3c24xx_init_irq,
+       .init_machine   = amlm5900_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
new file mode 100644 (file)
index 0000000..60c72c5
--- /dev/null
@@ -0,0 +1,492 @@
+/* linux/arch/arm/mach-s3c2440/mach-anubis.c
+ *
+ * Copyright 2003-2009 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/anubis-map.h>
+#include <mach/anubis-irq.h>
+#include <mach/anubis-cpld.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <net/ax88796.h>
+
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/audio-simtec.h>
+
+#include "simtec.h"
+#include "common.h"
+
+#define COPYRIGHT ", Copyright 2005-2009 Simtec Electronics"
+
+static struct map_desc anubis_iodesc[] __initdata = {
+  /* ISA IO areas */
+
+  {
+       .virtual        = (u32)S3C24XX_VA_ISA_BYTE,
+       .pfn            = __phys_to_pfn(0x0),
+       .length         = SZ_4M,
+       .type           = MT_DEVICE,
+  }, {
+       .virtual        = (u32)S3C24XX_VA_ISA_WORD,
+       .pfn            = __phys_to_pfn(0x0),
+       .length         = SZ_4M,
+       .type           = MT_DEVICE,
+  },
+
+  /* we could possibly compress the next set down into a set of smaller tables
+   * pagetables, but that would mean using an L2 section, and it still means
+   * we cannot actually feed the same register to an LDR due to 16K spacing
+   */
+
+  /* CPLD control registers */
+
+  {
+       .virtual        = (u32)ANUBIS_VA_CTRL1,
+       .pfn            = __phys_to_pfn(ANUBIS_PA_CTRL1),
+       .length         = SZ_4K,
+       .type           = MT_DEVICE,
+  }, {
+       .virtual        = (u32)ANUBIS_VA_IDREG,
+       .pfn            = __phys_to_pfn(ANUBIS_PA_IDREG),
+       .length         = SZ_4K,
+       .type           = MT_DEVICE,
+  },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg anubis_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
+       },
+       [1] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
+       },
+};
+
+/* NAND Flash on Anubis board */
+
+static int external_map[]   = { 2 };
+static int chip0_map[]      = { 0 };
+static int chip1_map[]      = { 1 };
+
+static struct mtd_partition __initdata anubis_default_nand_part[] = {
+       [0] = {
+               .name   = "Boot Agent",
+               .size   = SZ_16K,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "/boot",
+               .size   = SZ_4M - SZ_16K,
+               .offset = SZ_16K,
+       },
+       [2] = {
+               .name   = "user1",
+               .offset = SZ_4M,
+               .size   = SZ_32M - SZ_4M,
+       },
+       [3] = {
+               .name   = "user2",
+               .offset = SZ_32M,
+               .size   = MTDPART_SIZ_FULL,
+       }
+};
+
+static struct mtd_partition __initdata anubis_default_nand_part_large[] = {
+       [0] = {
+               .name   = "Boot Agent",
+               .size   = SZ_128K,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "/boot",
+               .size   = SZ_4M - SZ_128K,
+               .offset = SZ_128K,
+       },
+       [2] = {
+               .name   = "user1",
+               .offset = SZ_4M,
+               .size   = SZ_32M - SZ_4M,
+       },
+       [3] = {
+               .name   = "user2",
+               .offset = SZ_32M,
+               .size   = MTDPART_SIZ_FULL,
+       }
+};
+
+/* the Anubis has 3 selectable slots for nand-flash, the two
+ * on-board chip areas, as well as the external slot.
+ *
+ * Note, there is no current hot-plug support for the External
+ * socket.
+*/
+
+static struct s3c2410_nand_set __initdata anubis_nand_sets[] = {
+       [1] = {
+               .name           = "External",
+               .nr_chips       = 1,
+               .nr_map         = external_map,
+               .nr_partitions  = ARRAY_SIZE(anubis_default_nand_part),
+               .partitions     = anubis_default_nand_part,
+       },
+       [0] = {
+               .name           = "chip0",
+               .nr_chips       = 1,
+               .nr_map         = chip0_map,
+               .nr_partitions  = ARRAY_SIZE(anubis_default_nand_part),
+               .partitions     = anubis_default_nand_part,
+       },
+       [2] = {
+               .name           = "chip1",
+               .nr_chips       = 1,
+               .nr_map         = chip1_map,
+               .nr_partitions  = ARRAY_SIZE(anubis_default_nand_part),
+               .partitions     = anubis_default_nand_part,
+       },
+};
+
+static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
+{
+       unsigned int tmp;
+
+       slot = set->nr_map[slot] & 3;
+
+       pr_debug("anubis_nand: selecting slot %d (set %p,%p)\n",
+                slot, set, set->nr_map);
+
+       tmp = __raw_readb(ANUBIS_VA_CTRL1);
+       tmp &= ~ANUBIS_CTRL1_NANDSEL;
+       tmp |= slot;
+
+       pr_debug("anubis_nand: ctrl1 now %02x\n", tmp);
+
+       __raw_writeb(tmp, ANUBIS_VA_CTRL1);
+}
+
+static struct s3c2410_platform_nand __initdata anubis_nand_info = {
+       .tacls          = 25,
+       .twrph0         = 55,
+       .twrph1         = 40,
+       .nr_sets        = ARRAY_SIZE(anubis_nand_sets),
+       .sets           = anubis_nand_sets,
+       .select_chip    = anubis_nand_select,
+};
+
+/* IDE channels */
+
+static struct pata_platform_info anubis_ide_platdata = {
+       .ioport_shift   = 5,
+};
+
+static struct resource anubis_ide0_resource[] = {
+       {
+               .start  = S3C2410_CS3,
+               .end    = S3C2410_CS3 + (8*32) - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = S3C2410_CS3 + (1<<26) + (6*32),
+               .end    = S3C2410_CS3 + (1<<26) + (7*32) - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_IDE0,
+               .end    = IRQ_IDE0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device anubis_device_ide0 = {
+       .name           = "pata_platform",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(anubis_ide0_resource),
+       .resource       = anubis_ide0_resource,
+       .dev    = {
+               .platform_data = &anubis_ide_platdata,
+               .coherent_dma_mask = ~0,
+       },
+};
+
+static struct resource anubis_ide1_resource[] = {
+       {
+               .start  = S3C2410_CS4,
+               .end    = S3C2410_CS4 + (8*32) - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = S3C2410_CS4 + (1<<26) + (6*32),
+               .end    = S3C2410_CS4 + (1<<26) + (7*32) - 1,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_IDE0,
+               .end    = IRQ_IDE0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device anubis_device_ide1 = {
+       .name           = "pata_platform",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(anubis_ide1_resource),
+       .resource       = anubis_ide1_resource,
+       .dev    = {
+               .platform_data = &anubis_ide_platdata,
+               .coherent_dma_mask = ~0,
+       },
+};
+
+/* Asix AX88796 10/100 ethernet controller */
+
+static struct ax_plat_data anubis_asix_platdata = {
+       .flags          = AXFLG_MAC_FROMDEV,
+       .wordlength     = 2,
+       .dcr_val        = 0x48,
+       .rcr_val        = 0x40,
+};
+
+static struct resource anubis_asix_resource[] = {
+       [0] = {
+               .start = S3C2410_CS5,
+               .end   = S3C2410_CS5 + (0x20 * 0x20) -1,
+               .flags = IORESOURCE_MEM
+       },
+       [1] = {
+               .start = IRQ_ASIX,
+               .end   = IRQ_ASIX,
+               .flags = IORESOURCE_IRQ
+       }
+};
+
+static struct platform_device anubis_device_asix = {
+       .name           = "ax88796",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(anubis_asix_resource),
+       .resource       = anubis_asix_resource,
+       .dev            = {
+               .platform_data = &anubis_asix_platdata,
+       }
+};
+
+/* SM501 */
+
+static struct resource anubis_sm501_resource[] = {
+       [0] = {
+               .start  = S3C2410_CS2,
+               .end    = S3C2410_CS2 + SZ_8M,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = S3C2410_CS2 + SZ_64M - SZ_2M,
+               .end    = S3C2410_CS2 + SZ_64M - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start  = IRQ_EINT0,
+               .end    = IRQ_EINT0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct sm501_initdata anubis_sm501_initdata = {
+       .gpio_high      = {
+               .set    = 0x3F000000,           /* 24bit panel */
+               .mask   = 0x0,
+       },
+       .misc_timing    = {
+               .set    = 0x010100,             /* SDRAM timing */
+               .mask   = 0x1F1F00,
+       },
+       .misc_control   = {
+               .set    = SM501_MISC_PNL_24BIT,
+               .mask   = 0,
+       },
+
+       .devices        = SM501_USE_GPIO,
+
+       /* set the SDRAM and bus clocks */
+       .mclk           = 72 * MHZ,
+       .m1xclk         = 144 * MHZ,
+};
+
+static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = {
+       [0] = {
+               .bus_num        = 1,
+               .pin_scl        = 44,
+               .pin_sda        = 45,
+       },
+       [1] = {
+               .bus_num        = 2,
+               .pin_scl        = 40,
+               .pin_sda        = 41,
+       },
+};
+
+static struct sm501_platdata anubis_sm501_platdata = {
+       .init           = &anubis_sm501_initdata,
+       .gpio_base      = -1,
+       .gpio_i2c       = anubis_sm501_gpio_i2c,
+       .gpio_i2c_nr    = ARRAY_SIZE(anubis_sm501_gpio_i2c),
+};
+
+static struct platform_device anubis_device_sm501 = {
+       .name           = "sm501",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(anubis_sm501_resource),
+       .resource       = anubis_sm501_resource,
+       .dev            = {
+               .platform_data = &anubis_sm501_platdata,
+       },
+};
+
+/* Standard Anubis devices */
+
+static struct platform_device *anubis_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_wdt,
+       &s3c_device_adc,
+       &s3c_device_i2c0,
+       &s3c_device_rtc,
+       &s3c_device_nand,
+       &anubis_device_ide0,
+       &anubis_device_ide1,
+       &anubis_device_asix,
+       &anubis_device_sm501,
+};
+
+static struct clk *anubis_clocks[] __initdata = {
+       &s3c24xx_dclk0,
+       &s3c24xx_dclk1,
+       &s3c24xx_clkout0,
+       &s3c24xx_clkout1,
+       &s3c24xx_uclk,
+};
+
+/* I2C devices. */
+
+static struct i2c_board_info anubis_i2c_devs[] __initdata = {
+       {
+               I2C_BOARD_INFO("tps65011", 0x48),
+               .irq    = IRQ_EINT20,
+       }
+};
+
+/* Audio setup */
+static struct s3c24xx_audio_simtec_pdata __initdata anubis_audio = {
+       .have_mic       = 1,
+       .have_lout      = 1,
+       .output_cdclk   = 1,
+       .use_mpllin     = 1,
+       .amp_gpio       = S3C2410_GPB(2),
+       .amp_gain[0]    = S3C2410_GPD(10),
+       .amp_gain[1]    = S3C2410_GPD(11),
+};
+
+static void __init anubis_map_io(void)
+{
+       /* initialise the clocks */
+
+       s3c24xx_dclk0.parent = &clk_upll;
+       s3c24xx_dclk0.rate   = 12*1000*1000;
+
+       s3c24xx_dclk1.parent = &clk_upll;
+       s3c24xx_dclk1.rate   = 24*1000*1000;
+
+       s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
+       s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
+
+       s3c24xx_uclk.parent  = &s3c24xx_clkout1;
+
+       s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks));
+
+       s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
+
+       /* check for the newer revision boards with large page nand */
+
+       if ((__raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK) >= 4) {
+               printk(KERN_INFO "ANUBIS-B detected (revision %d)\n",
+                      __raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK);
+               anubis_nand_sets[0].partitions = anubis_default_nand_part_large;
+               anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large);
+       } else {
+               /* ensure that the GPIO is setup */
+               s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
+       }
+}
+
+static void __init anubis_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+       s3c_nand_set_platdata(&anubis_nand_info);
+       simtec_audio_add(NULL, false, &anubis_audio);
+
+       platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices));
+
+       i2c_register_board_info(0, anubis_i2c_devs,
+                               ARRAY_SIZE(anubis_i2c_devs));
+}
+
+
+MACHINE_START(ANUBIS, "Simtec-Anubis")
+       /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+       .atag_offset    = 0x100,
+       .map_io         = anubis_map_io,
+       .init_machine   = anubis_init,
+       .init_irq       = s3c24xx_init_irq,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
new file mode 100644 (file)
index 0000000..d7ae49c
--- /dev/null
@@ -0,0 +1,226 @@
+/* linux/arch/arm/mach-s3c2440/mach-at2440evb.c
+ *
+ * Copyright (c) 2008 Ramax Lo <ramaxlo@gmail.com>
+ *      Based on mach-anubis.c by Ben Dooks <ben@simtec.co.uk>
+ *      and modifications by SBZ <sbz@spgui.org> and
+ *      Weibing <http://weibing.blogbus.com>
+ *
+ * For product information, visit http://www.arm.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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/serial_core.h>
+#include <linux/dm9000.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/fb.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/mci.h>
+
+#include "common.h"
+
+static struct map_desc at2440evb_iodesc[] __initdata = {
+       /* Nothing here */
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE)
+#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
+
+static struct s3c2410_uartcfg at2440evb_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
+       },
+};
+
+/* NAND Flash on AT2440EVB board */
+
+static struct mtd_partition __initdata at2440evb_default_nand_part[] = {
+       [0] = {
+               .name   = "Boot Agent",
+               .size   = SZ_256K,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "Kernel",
+               .size   = SZ_2M,
+               .offset = SZ_256K,
+       },
+       [2] = {
+               .name   = "Root",
+               .offset = SZ_256K + SZ_2M,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct s3c2410_nand_set __initdata at2440evb_nand_sets[] = {
+       [0] = {
+               .name           = "nand",
+               .nr_chips       = 1,
+               .nr_partitions  = ARRAY_SIZE(at2440evb_default_nand_part),
+               .partitions     = at2440evb_default_nand_part,
+       },
+};
+
+static struct s3c2410_platform_nand __initdata at2440evb_nand_info = {
+       .tacls          = 25,
+       .twrph0         = 55,
+       .twrph1         = 40,
+       .nr_sets        = ARRAY_SIZE(at2440evb_nand_sets),
+       .sets           = at2440evb_nand_sets,
+};
+
+/* DM9000AEP 10/100 ethernet controller */
+
+static struct resource at2440evb_dm9k_resource[] = {
+       [0] = {
+               .start = S3C2410_CS3,
+               .end   = S3C2410_CS3 + 3,
+               .flags = IORESOURCE_MEM
+       },
+       [1] = {
+               .start = S3C2410_CS3 + 4,
+               .end   = S3C2410_CS3 + 7,
+               .flags = IORESOURCE_MEM
+       },
+       [2] = {
+               .start = IRQ_EINT7,
+               .end   = IRQ_EINT7,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+       }
+};
+
+static struct dm9000_plat_data at2440evb_dm9k_pdata = {
+       .flags          = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
+};
+
+static struct platform_device at2440evb_device_eth = {
+       .name           = "dm9000",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(at2440evb_dm9k_resource),
+       .resource       = at2440evb_dm9k_resource,
+       .dev            = {
+               .platform_data  = &at2440evb_dm9k_pdata,
+       },
+};
+
+static struct s3c24xx_mci_pdata at2440evb_mci_pdata __initdata = {
+       .gpio_detect    = S3C2410_GPG(10),
+};
+
+/* 7" LCD panel */
+
+static struct s3c2410fb_display at2440evb_lcd_cfg __initdata = {
+
+       .lcdcon5        = S3C2410_LCDCON5_FRM565 |
+                         S3C2410_LCDCON5_INVVLINE |
+                         S3C2410_LCDCON5_INVVFRAME |
+                         S3C2410_LCDCON5_PWREN |
+                         S3C2410_LCDCON5_HWSWP,
+
+       .type           = S3C2410_LCDCON1_TFT,
+
+       .width          = 800,
+       .height         = 480,
+
+       .pixclock       = 33333, /* HCLK 60 MHz, divisor 2 */
+       .xres           = 800,
+       .yres           = 480,
+       .bpp            = 16,
+       .left_margin    = 88,
+       .right_margin   = 40,
+       .hsync_len      = 128,
+       .upper_margin   = 32,
+       .lower_margin   = 11,
+       .vsync_len      = 2,
+};
+
+static struct s3c2410fb_mach_info at2440evb_fb_info __initdata = {
+       .displays       = &at2440evb_lcd_cfg,
+       .num_displays   = 1,
+       .default_display = 0,
+};
+
+static struct platform_device *at2440evb_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_wdt,
+       &s3c_device_adc,
+       &s3c_device_i2c0,
+       &s3c_device_rtc,
+       &s3c_device_nand,
+       &s3c_device_sdi,
+       &s3c_device_lcd,
+       &at2440evb_device_eth,
+};
+
+static void __init at2440evb_map_io(void)
+{
+       s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc));
+       s3c24xx_init_clocks(16934400);
+       s3c24xx_init_uarts(at2440evb_uartcfgs, ARRAY_SIZE(at2440evb_uartcfgs));
+}
+
+static void __init at2440evb_init(void)
+{
+       s3c24xx_fb_set_platdata(&at2440evb_fb_info);
+       s3c24xx_mci_set_platdata(&at2440evb_mci_pdata);
+       s3c_nand_set_platdata(&at2440evb_nand_info);
+       s3c_i2c0_set_platdata(NULL);
+
+       platform_add_devices(at2440evb_devices, ARRAY_SIZE(at2440evb_devices));
+}
+
+
+MACHINE_START(AT2440EVB, "AT2440EVB")
+       .atag_offset    = 0x100,
+       .map_io         = at2440evb_map_io,
+       .init_machine   = at2440evb_init,
+       .init_irq       = s3c24xx_init_irq,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
new file mode 100644 (file)
index 0000000..53219c0
--- /dev/null
@@ -0,0 +1,644 @@
+/* linux/arch/arm/mach-s3c2410/mach-bast.c
+ *
+ * Copyright 2003-2008 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.simtec.co.uk/products/EB2410ITX/
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/syscore_ops.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/dm9000.h>
+#include <linux/ata_platform.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+
+#include <net/ax88796.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/bast-map.h>
+#include <mach/bast-irq.h>
+#include <mach/bast-cpld.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+//#include <asm/debug-ll.h>
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+
+#include <plat/hwmon.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
+#include <mach/fb.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/serial_8250.h>
+
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/cpu-freq.h>
+#include <plat/gpio-cfg.h>
+#include <plat/audio-simtec.h>
+
+#include "simtec.h"
+#include "common.h"
+
+#define COPYRIGHT ", Copyright 2004-2008 Simtec Electronics"
+
+/* macros for virtual address mods for the io space entries */
+#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
+#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
+#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
+#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
+
+/* macros to modify the physical addresses for io space */
+
+#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
+#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
+#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
+#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
+
+static struct map_desc bast_iodesc[] __initdata = {
+  /* ISA IO areas */
+  {
+         .virtual      = (u32)S3C24XX_VA_ISA_BYTE,
+         .pfn          = PA_CS2(BAST_PA_ISAIO),
+         .length       = SZ_16M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)S3C24XX_VA_ISA_WORD,
+         .pfn          = PA_CS3(BAST_PA_ISAIO),
+         .length       = SZ_16M,
+         .type         = MT_DEVICE,
+  },
+  /* bast CPLD control registers, and external interrupt controls */
+  {
+         .virtual      = (u32)BAST_VA_CTRL1,
+         .pfn          = __phys_to_pfn(BAST_PA_CTRL1),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)BAST_VA_CTRL2,
+         .pfn          = __phys_to_pfn(BAST_PA_CTRL2),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)BAST_VA_CTRL3,
+         .pfn          = __phys_to_pfn(BAST_PA_CTRL3),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)BAST_VA_CTRL4,
+         .pfn          = __phys_to_pfn(BAST_PA_CTRL4),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  },
+  /* PC104 IRQ mux */
+  {
+         .virtual      = (u32)BAST_VA_PC104_IRQREQ,
+         .pfn          = __phys_to_pfn(BAST_PA_PC104_IRQREQ),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)BAST_VA_PC104_IRQRAW,
+         .pfn          = __phys_to_pfn(BAST_PA_PC104_IRQRAW),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)BAST_VA_PC104_IRQMASK,
+         .pfn          = __phys_to_pfn(BAST_PA_PC104_IRQMASK),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  },
+
+  /* peripheral space... one for each of fast/slow/byte/16bit */
+  /* note, ide is only decoded in word space, even though some registers
+   * are only 8bit */
+
+  /* slow, byte */
+  { VA_C2(BAST_VA_ISAIO),   PA_CS2(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
+  { VA_C2(BAST_VA_ISAMEM),  PA_CS2(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
+  { VA_C2(BAST_VA_SUPERIO), PA_CS2(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
+
+  /* slow, word */
+  { VA_C3(BAST_VA_ISAIO),   PA_CS3(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
+  { VA_C3(BAST_VA_ISAMEM),  PA_CS3(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
+  { VA_C3(BAST_VA_SUPERIO), PA_CS3(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
+
+  /* fast, byte */
+  { VA_C4(BAST_VA_ISAIO),   PA_CS4(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
+  { VA_C4(BAST_VA_ISAMEM),  PA_CS4(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
+  { VA_C4(BAST_VA_SUPERIO), PA_CS4(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
+
+  /* fast, word */
+  { VA_C5(BAST_VA_ISAIO),   PA_CS5(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
+  { VA_C5(BAST_VA_ISAMEM),  PA_CS5(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
+  { VA_C5(BAST_VA_SUPERIO), PA_CS5(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       /* port 2 is not actually used */
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+/* NAND Flash on BAST board */
+
+#ifdef CONFIG_PM
+static int bast_pm_suspend(void)
+{
+       /* ensure that an nRESET is not generated on resume. */
+       gpio_direction_output(S3C2410_GPA(21), 1);
+       return 0;
+}
+
+static void bast_pm_resume(void)
+{
+       s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
+}
+
+#else
+#define bast_pm_suspend NULL
+#define bast_pm_resume NULL
+#endif
+
+static struct syscore_ops bast_pm_syscore_ops = {
+       .suspend        = bast_pm_suspend,
+       .resume         = bast_pm_resume,
+};
+
+static int smartmedia_map[] = { 0 };
+static int chip0_map[] = { 1 };
+static int chip1_map[] = { 2 };
+static int chip2_map[] = { 3 };
+
+static struct mtd_partition __initdata bast_default_nand_part[] = {
+       [0] = {
+               .name   = "Boot Agent",
+               .size   = SZ_16K,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "/boot",
+               .size   = SZ_4M - SZ_16K,
+               .offset = SZ_16K,
+       },
+       [2] = {
+               .name   = "user",
+               .offset = SZ_4M,
+               .size   = MTDPART_SIZ_FULL,
+       }
+};
+
+/* the bast has 4 selectable slots for nand-flash, the three
+ * on-board chip areas, as well as the external SmartMedia
+ * slot.
+ *
+ * Note, there is no current hot-plug support for the SmartMedia
+ * socket.
+*/
+
+static struct s3c2410_nand_set __initdata bast_nand_sets[] = {
+       [0] = {
+               .name           = "SmartMedia",
+               .nr_chips       = 1,
+               .nr_map         = smartmedia_map,
+               .options        = NAND_SCAN_SILENT_NODEV,
+               .nr_partitions  = ARRAY_SIZE(bast_default_nand_part),
+               .partitions     = bast_default_nand_part,
+       },
+       [1] = {
+               .name           = "chip0",
+               .nr_chips       = 1,
+               .nr_map         = chip0_map,
+               .nr_partitions  = ARRAY_SIZE(bast_default_nand_part),
+               .partitions     = bast_default_nand_part,
+       },
+       [2] = {
+               .name           = "chip1",
+               .nr_chips       = 1,
+               .nr_map         = chip1_map,
+               .options        = NAND_SCAN_SILENT_NODEV,
+               .nr_partitions  = ARRAY_SIZE(bast_default_nand_part),
+               .partitions     = bast_default_nand_part,
+       },
+       [3] = {
+               .name           = "chip2",
+               .nr_chips       = 1,
+               .nr_map         = chip2_map,
+               .options        = NAND_SCAN_SILENT_NODEV,
+               .nr_partitions  = ARRAY_SIZE(bast_default_nand_part),
+               .partitions     = bast_default_nand_part,
+       }
+};
+
+static void bast_nand_select(struct s3c2410_nand_set *set, int slot)
+{
+       unsigned int tmp;
+
+       slot = set->nr_map[slot] & 3;
+
+       pr_debug("bast_nand: selecting slot %d (set %p,%p)\n",
+                slot, set, set->nr_map);
+
+       tmp = __raw_readb(BAST_VA_CTRL2);
+       tmp &= BAST_CPLD_CTLR2_IDERST;
+       tmp |= slot;
+       tmp |= BAST_CPLD_CTRL2_WNAND;
+
+       pr_debug("bast_nand: ctrl2 now %02x\n", tmp);
+
+       __raw_writeb(tmp, BAST_VA_CTRL2);
+}
+
+static struct s3c2410_platform_nand __initdata bast_nand_info = {
+       .tacls          = 30,
+       .twrph0         = 60,
+       .twrph1         = 60,
+       .nr_sets        = ARRAY_SIZE(bast_nand_sets),
+       .sets           = bast_nand_sets,
+       .select_chip    = bast_nand_select,
+};
+
+/* DM9000 */
+
+static struct resource bast_dm9k_resource[] = {
+       [0] = {
+               .start = S3C2410_CS5 + BAST_PA_DM9000,
+               .end   = S3C2410_CS5 + BAST_PA_DM9000 + 3,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = S3C2410_CS5 + BAST_PA_DM9000 + 0x40,
+               .end   = S3C2410_CS5 + BAST_PA_DM9000 + 0x40 + 0x3f,
+               .flags = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start = IRQ_DM9000,
+               .end   = IRQ_DM9000,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       }
+
+};
+
+/* for the moment we limit ourselves to 16bit IO until some
+ * better IO routines can be written and tested
+*/
+
+static struct dm9000_plat_data bast_dm9k_platdata = {
+       .flags          = DM9000_PLATF_16BITONLY,
+};
+
+static struct platform_device bast_device_dm9k = {
+       .name           = "dm9000",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(bast_dm9k_resource),
+       .resource       = bast_dm9k_resource,
+       .dev            = {
+               .platform_data = &bast_dm9k_platdata,
+       }
+};
+
+/* serial devices */
+
+#define SERIAL_BASE  (S3C2410_CS2 + BAST_PA_SUPERIO)
+#define SERIAL_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SHARE_IRQ)
+#define SERIAL_CLK   (1843200)
+
+static struct plat_serial8250_port bast_sio_data[] = {
+       [0] = {
+               .mapbase        = SERIAL_BASE + 0x2f8,
+               .irq            = IRQ_PCSERIAL1,
+               .flags          = SERIAL_FLAGS,
+               .iotype         = UPIO_MEM,
+               .regshift       = 0,
+               .uartclk        = SERIAL_CLK,
+       },
+       [1] = {
+               .mapbase        = SERIAL_BASE + 0x3f8,
+               .irq            = IRQ_PCSERIAL2,
+               .flags          = SERIAL_FLAGS,
+               .iotype         = UPIO_MEM,
+               .regshift       = 0,
+               .uartclk        = SERIAL_CLK,
+       },
+       { }
+};
+
+static struct platform_device bast_sio = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = &bast_sio_data,
+       },
+};
+
+/* we have devices on the bus which cannot work much over the
+ * standard 100KHz i2c bus frequency
+*/
+
+static struct s3c2410_platform_i2c __initdata bast_i2c_info = {
+       .flags          = 0,
+       .slave_addr     = 0x10,
+       .frequency      = 100*1000,
+};
+
+/* Asix AX88796 10/100 ethernet controller */
+
+static struct ax_plat_data bast_asix_platdata = {
+       .flags          = AXFLG_MAC_FROMDEV,
+       .wordlength     = 2,
+       .dcr_val        = 0x48,
+       .rcr_val        = 0x40,
+};
+
+static struct resource bast_asix_resource[] = {
+       [0] = {
+               .start = S3C2410_CS5 + BAST_PA_ASIXNET,
+               .end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20) - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
+               .end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
+               .flags = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start = IRQ_ASIX,
+               .end   = IRQ_ASIX,
+               .flags = IORESOURCE_IRQ
+       }
+};
+
+static struct platform_device bast_device_asix = {
+       .name           = "ax88796",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(bast_asix_resource),
+       .resource       = bast_asix_resource,
+       .dev            = {
+               .platform_data = &bast_asix_platdata
+       }
+};
+
+/* Asix AX88796 10/100 ethernet controller parallel port */
+
+static struct resource bast_asixpp_resource[] = {
+       [0] = {
+               .start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20),
+               .end   = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1b * 0x20) - 1,
+               .flags = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device bast_device_axpp = {
+       .name           = "ax88796-pp",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(bast_asixpp_resource),
+       .resource       = bast_asixpp_resource,
+};
+
+/* LCD/VGA controller */
+
+static struct s3c2410fb_display __initdata bast_lcd_info[] = {
+       {
+               .type           = S3C2410_LCDCON1_TFT,
+               .width          = 640,
+               .height         = 480,
+
+               .pixclock       = 33333,
+               .xres           = 640,
+               .yres           = 480,
+               .bpp            = 4,
+               .left_margin    = 40,
+               .right_margin   = 20,
+               .hsync_len      = 88,
+               .upper_margin   = 30,
+               .lower_margin   = 32,
+               .vsync_len      = 3,
+
+               .lcdcon5        = 0x00014b02,
+       },
+       {
+               .type           = S3C2410_LCDCON1_TFT,
+               .width          = 640,
+               .height         = 480,
+
+               .pixclock       = 33333,
+               .xres           = 640,
+               .yres           = 480,
+               .bpp            = 8,
+               .left_margin    = 40,
+               .right_margin   = 20,
+               .hsync_len      = 88,
+               .upper_margin   = 30,
+               .lower_margin   = 32,
+               .vsync_len      = 3,
+
+               .lcdcon5        = 0x00014b02,
+       },
+       {
+               .type           = S3C2410_LCDCON1_TFT,
+               .width          = 640,
+               .height         = 480,
+
+               .pixclock       = 33333,
+               .xres           = 640,
+               .yres           = 480,
+               .bpp            = 16,
+               .left_margin    = 40,
+               .right_margin   = 20,
+               .hsync_len      = 88,
+               .upper_margin   = 30,
+               .lower_margin   = 32,
+               .vsync_len      = 3,
+
+               .lcdcon5        = 0x00014b02,
+       },
+};
+
+/* LCD/VGA controller */
+
+static struct s3c2410fb_mach_info __initdata bast_fb_info = {
+
+       .displays = bast_lcd_info,
+       .num_displays = ARRAY_SIZE(bast_lcd_info),
+       .default_display = 1,
+};
+
+/* I2C devices fitted. */
+
+static struct i2c_board_info bast_i2c_devs[] __initdata = {
+       {
+               I2C_BOARD_INFO("tlv320aic23", 0x1a),
+       }, {
+               I2C_BOARD_INFO("simtec-pmu", 0x6b),
+       }, {
+               I2C_BOARD_INFO("ch7013", 0x75),
+       },
+};
+
+static struct s3c_hwmon_pdata bast_hwmon_info = {
+       /* LCD contrast (0-6.6V) */
+       .in[0] = &(struct s3c_hwmon_chcfg) {
+               .name           = "lcd-contrast",
+               .mult           = 3300,
+               .div            = 512,
+       },
+       /* LED current feedback */
+       .in[1] = &(struct s3c_hwmon_chcfg) {
+               .name           = "led-feedback",
+               .mult           = 3300,
+               .div            = 1024,
+       },
+       /* LCD feedback (0-6.6V) */
+       .in[2] = &(struct s3c_hwmon_chcfg) {
+               .name           = "lcd-feedback",
+               .mult           = 3300,
+               .div            = 512,
+       },
+       /* Vcore (1.8-2.0V), Vref 3.3V  */
+       .in[3] = &(struct s3c_hwmon_chcfg) {
+               .name           = "vcore",
+               .mult           = 3300,
+               .div            = 1024,
+       },
+};
+
+/* Standard BAST devices */
+// cat /sys/devices/platform/s3c24xx-adc/s3c-hwmon/in_0
+
+static struct platform_device *bast_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_rtc,
+       &s3c_device_nand,
+       &s3c_device_adc,
+       &s3c_device_hwmon,
+       &bast_device_dm9k,
+       &bast_device_asix,
+       &bast_device_axpp,
+       &bast_sio,
+};
+
+static struct clk *bast_clocks[] __initdata = {
+       &s3c24xx_dclk0,
+       &s3c24xx_dclk1,
+       &s3c24xx_clkout0,
+       &s3c24xx_clkout1,
+       &s3c24xx_uclk,
+};
+
+static struct s3c_cpufreq_board __initdata bast_cpufreq = {
+       .refresh        = 7800, /* 7.8usec */
+       .auto_io        = 1,
+       .need_io        = 1,
+};
+
+static struct s3c24xx_audio_simtec_pdata __initdata bast_audio = {
+       .have_mic       = 1,
+       .have_lout      = 1,
+};
+
+static void __init bast_map_io(void)
+{
+       /* initialise the clocks */
+
+       s3c24xx_dclk0.parent = &clk_upll;
+       s3c24xx_dclk0.rate   = 12*1000*1000;
+
+       s3c24xx_dclk1.parent = &clk_upll;
+       s3c24xx_dclk1.rate   = 24*1000*1000;
+
+       s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
+       s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
+
+       s3c24xx_uclk.parent  = &s3c24xx_clkout1;
+
+       s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks));
+
+       s3c_hwmon_set_platdata(&bast_hwmon_info);
+
+       s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs));
+}
+
+static void __init bast_init(void)
+{
+       register_syscore_ops(&bast_pm_syscore_ops);
+
+       s3c_i2c0_set_platdata(&bast_i2c_info);
+       s3c_nand_set_platdata(&bast_nand_info);
+       s3c24xx_fb_set_platdata(&bast_fb_info);
+       platform_add_devices(bast_devices, ARRAY_SIZE(bast_devices));
+
+       i2c_register_board_info(0, bast_i2c_devs,
+                               ARRAY_SIZE(bast_i2c_devs));
+
+       usb_simtec_init();
+       nor_simtec_init();
+       simtec_audio_add(NULL, true, &bast_audio);
+
+       WARN_ON(gpio_request(S3C2410_GPA(21), "bast nreset"));
+       
+       s3c_cpufreq_setboard(&bast_cpufreq);
+}
+
+MACHINE_START(BAST, "Simtec-BAST")
+       /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+       .atag_offset    = 0x100,
+       .map_io         = bast_map_io,
+       .init_irq       = s3c24xx_init_irq,
+       .init_machine   = bast_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
new file mode 100644 (file)
index 0000000..ba5d853
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * linux/arch/arm/mach-s3c2442/mach-gta02.c
+ *
+ * S3C2442 Machine Support for Openmoko GTA02 / FreeRunner.
+ *
+ * Copyright (C) 2006-2009 by Openmoko, Inc.
+ * Authors: Harald Welte <laforge@openmoko.org>
+ *          Andy Green <andy@openmoko.org>
+ *          Werner Almesberger <werner@openmoko.org>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/s3c24xx.h>
+
+#include <linux/mmc/host.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/io.h>
+
+#include <linux/i2c.h>
+#include <linux/regulator/machine.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/mbc.h>
+#include <linux/mfd/pcf50633/adc.h>
+#include <linux/mfd/pcf50633/gpio.h>
+#include <linux/mfd/pcf50633/pmic.h>
+#include <linux/mfd/pcf50633/backlight.h>
+
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
+#include <mach/fb.h>
+
+#include <plat/usb-control.h>
+#include <mach/regs-mem.h>
+#include <mach/hardware.h>
+
+#include <mach/gta02.h>
+
+#include <plat/regs-serial.h>
+#include <plat/nand.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/udc.h>
+#include <plat/gpio-cfg.h>
+#include <plat/iic.h>
+#include <plat/ts.h>
+
+#include "common.h"
+
+static struct pcf50633 *gta02_pcf;
+
+/*
+ * This gets called frequently when we paniced.
+ */
+
+static long gta02_panic_blink(int state)
+{
+       long delay = 0;
+       char led;
+
+       led = (state) ? 1 : 0;
+       gpio_direction_output(GTA02_GPIO_AUX_LED, led);
+
+       return delay;
+}
+
+
+static struct map_desc gta02_iodesc[] __initdata = {
+       {
+               .virtual        = 0xe0000000,
+               .pfn            = __phys_to_pfn(S3C2410_CS3 + 0x01000000),
+               .length         = SZ_1M,
+               .type           = MT_DEVICE
+       },
+};
+
+#define UCON (S3C2410_UCON_DEFAULT | S3C2443_UCON_RXERR_IRQEN)
+#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
+#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
+
+static struct s3c2410_uartcfg gta02_uartcfgs[] = {
+       [0] = {
+               .hwport         = 0,
+               .flags          = 0,
+               .ucon           = UCON,
+               .ulcon          = ULCON,
+               .ufcon          = UFCON,
+       },
+       [1] = {
+               .hwport         = 1,
+               .flags          = 0,
+               .ucon           = UCON,
+               .ulcon          = ULCON,
+               .ufcon          = UFCON,
+       },
+       [2] = {
+               .hwport         = 2,
+               .flags          = 0,
+               .ucon           = UCON,
+               .ulcon          = ULCON,
+               .ufcon          = UFCON,
+       },
+};
+
+#ifdef CONFIG_CHARGER_PCF50633
+/*
+ * On GTA02 the 1A charger features a 48K resistor to 0V on the ID pin.
+ * We use this to recognize that we can pull 1A from the USB socket.
+ *
+ * These constants are the measured pcf50633 ADC levels with the 1A
+ * charger / 48K resistor, and with no pulldown resistor.
+ */
+
+#define ADC_NOM_CHG_DETECT_1A 6
+#define ADC_NOM_CHG_DETECT_USB 43
+
+static void
+gta02_configure_pmu_for_charger(struct pcf50633 *pcf, void *unused, int res)
+{
+       int  ma;
+
+       /* Interpret charger type */
+       if (res < ((ADC_NOM_CHG_DETECT_USB + ADC_NOM_CHG_DETECT_1A) / 2)) {
+
+               /*
+                * Sanity - stop GPO driving out now that we have a 1A charger
+                * GPO controls USB Host power generation on GTA02
+                */
+               pcf50633_gpio_set(pcf, PCF50633_GPO, 0);
+
+               ma = 1000;
+       } else
+               ma = 100;
+
+       pcf50633_mbc_usb_curlim_set(pcf, ma);
+}
+
+static struct delayed_work gta02_charger_work;
+static int gta02_usb_vbus_draw;
+
+static void gta02_charger_worker(struct work_struct *work)
+{
+       if (gta02_usb_vbus_draw) {
+               pcf50633_mbc_usb_curlim_set(gta02_pcf, gta02_usb_vbus_draw);
+               return;
+       }
+
+#ifdef CONFIG_PCF50633_ADC
+       pcf50633_adc_async_read(gta02_pcf,
+                               PCF50633_ADCC1_MUX_ADCIN1,
+                               PCF50633_ADCC1_AVERAGE_16,
+                               gta02_configure_pmu_for_charger,
+                               NULL);
+#else
+       /*
+        * If the PCF50633 ADC is disabled we fallback to a
+        * 100mA limit for safety.
+        */
+       pcf50633_mbc_usb_curlim_set(pcf, 100);
+#endif
+}
+
+#define GTA02_CHARGER_CONFIGURE_TIMEOUT ((3000 * HZ) / 1000)
+
+static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq)
+{
+       if (irq == PCF50633_IRQ_USBINS) {
+               schedule_delayed_work(&gta02_charger_work,
+                                     GTA02_CHARGER_CONFIGURE_TIMEOUT);
+
+               return;
+       }
+
+       if (irq == PCF50633_IRQ_USBREM) {
+               cancel_delayed_work_sync(&gta02_charger_work);
+               gta02_usb_vbus_draw = 0;
+       }
+}
+
+static void gta02_udc_vbus_draw(unsigned int ma)
+{
+       if (!gta02_pcf)
+               return;
+
+       gta02_usb_vbus_draw = ma;
+
+       schedule_delayed_work(&gta02_charger_work,
+                             GTA02_CHARGER_CONFIGURE_TIMEOUT);
+}
+#else /* !CONFIG_CHARGER_PCF50633 */
+#define gta02_pmu_event_callback       NULL
+#define gta02_udc_vbus_draw            NULL
+#endif
+
+/*
+ * This is called when pc50633 is probed, unfortunately quite late in the
+ * day since it is an I2C bus device. Here we can belatedly define some
+ * platform devices with the advantage that we can mark the pcf50633 as the
+ * parent. This makes them get suspended and resumed with their parent
+ * the pcf50633 still around.
+ */
+
+static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf);
+
+
+static char *gta02_batteries[] = {
+       "battery",
+};
+
+static struct pcf50633_bl_platform_data gta02_backlight_data = {
+       .default_brightness = 0x3f,
+       .default_brightness_limit = 0,
+       .ramp_time = 5,
+};
+
+static struct pcf50633_platform_data gta02_pcf_pdata = {
+       .resumers = {
+               [0] =   PCF50633_INT1_USBINS |
+                       PCF50633_INT1_USBREM |
+                       PCF50633_INT1_ALARM,
+               [1] =   PCF50633_INT2_ONKEYF,
+               [2] =   PCF50633_INT3_ONKEY1S,
+               [3] =   PCF50633_INT4_LOWSYS |
+                       PCF50633_INT4_LOWBAT |
+                       PCF50633_INT4_HIGHTMP,
+       },
+
+       .batteries = gta02_batteries,
+       .num_batteries = ARRAY_SIZE(gta02_batteries),
+
+       .charger_reference_current_ma = 1000,
+
+       .backlight_data = &gta02_backlight_data,
+
+       .reg_init_data = {
+               [PCF50633_REGULATOR_AUTO] = {
+                       .constraints = {
+                               .min_uV = 3300000,
+                               .max_uV = 3300000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .always_on = 1,
+                               .apply_uV = 1,
+                       },
+               },
+               [PCF50633_REGULATOR_DOWN1] = {
+                       .constraints = {
+                               .min_uV = 1300000,
+                               .max_uV = 1600000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .always_on = 1,
+                               .apply_uV = 1,
+                       },
+               },
+               [PCF50633_REGULATOR_DOWN2] = {
+                       .constraints = {
+                               .min_uV = 1800000,
+                               .max_uV = 1800000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .apply_uV = 1,
+                               .always_on = 1,
+                       },
+               },
+               [PCF50633_REGULATOR_HCLDO] = {
+                       .constraints = {
+                               .min_uV = 2000000,
+                               .max_uV = 3300000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+                                               REGULATOR_CHANGE_STATUS,
+                       },
+               },
+               [PCF50633_REGULATOR_LDO1] = {
+                       .constraints = {
+                               .min_uV = 3300000,
+                               .max_uV = 3300000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+                               .apply_uV = 1,
+                       },
+               },
+               [PCF50633_REGULATOR_LDO2] = {
+                       .constraints = {
+                               .min_uV = 3300000,
+                               .max_uV = 3300000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .apply_uV = 1,
+                       },
+               },
+               [PCF50633_REGULATOR_LDO3] = {
+                       .constraints = {
+                               .min_uV = 3000000,
+                               .max_uV = 3000000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .apply_uV = 1,
+                       },
+               },
+               [PCF50633_REGULATOR_LDO4] = {
+                       .constraints = {
+                               .min_uV = 3200000,
+                               .max_uV = 3200000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+                               .apply_uV = 1,
+                       },
+               },
+               [PCF50633_REGULATOR_LDO5] = {
+                       .constraints = {
+                               .min_uV = 3000000,
+                               .max_uV = 3000000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+                               .apply_uV = 1,
+                       },
+               },
+               [PCF50633_REGULATOR_LDO6] = {
+                       .constraints = {
+                               .min_uV = 3000000,
+                               .max_uV = 3000000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                       },
+               },
+               [PCF50633_REGULATOR_MEMLDO] = {
+                       .constraints = {
+                               .min_uV = 1800000,
+                               .max_uV = 1800000,
+                               .valid_modes_mask = REGULATOR_MODE_NORMAL,
+                       },
+               },
+
+       },
+       .probe_done = gta02_pmu_attach_child_devices,
+       .mbc_event_callback = gta02_pmu_event_callback,
+};
+
+
+/* NOR Flash. */
+
+#define GTA02_FLASH_BASE       0x18000000 /* GCS3 */
+#define GTA02_FLASH_SIZE       0x200000 /* 2MBytes */
+
+static struct physmap_flash_data gta02_nor_flash_data = {
+       .width          = 2,
+};
+
+static struct resource gta02_nor_flash_resource = {
+       .start          = GTA02_FLASH_BASE,
+       .end            = GTA02_FLASH_BASE + GTA02_FLASH_SIZE - 1,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device gta02_nor_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &gta02_nor_flash_data,
+       },
+       .resource       = &gta02_nor_flash_resource,
+       .num_resources  = 1,
+};
+
+
+static struct platform_device s3c24xx_pwm_device = {
+       .name           = "s3c24xx_pwm",
+       .num_resources  = 0,
+};
+
+static struct platform_device gta02_dfbmcs320_device = {
+       .name = "dfbmcs320",
+};
+
+static struct i2c_board_info gta02_i2c_devs[] __initdata = {
+       {
+               I2C_BOARD_INFO("pcf50633", 0x73),
+               .irq = GTA02_IRQ_PCF50633,
+               .platform_data = &gta02_pcf_pdata,
+       },
+       {
+               I2C_BOARD_INFO("wm8753", 0x1a),
+       },
+};
+
+static struct s3c2410_nand_set __initdata gta02_nand_sets[] = {
+       [0] = {
+               /*
+                * This name is also hard-coded in the boot loaders, so
+                * changing it would would require all users to upgrade
+                * their boot loaders, some of which are stored in a NOR
+                * that is considered to be immutable.
+                */
+               .name           = "neo1973-nand",
+               .nr_chips       = 1,
+               .flash_bbt      = 1,
+       },
+};
+
+/*
+ * Choose a set of timings derived from S3C@2442B MCP54
+ * data sheet (K5D2G13ACM-D075 MCP Memory).
+ */
+
+static struct s3c2410_platform_nand __initdata gta02_nand_info = {
+       .tacls          = 0,
+       .twrph0         = 25,
+       .twrph1         = 15,
+       .nr_sets        = ARRAY_SIZE(gta02_nand_sets),
+       .sets           = gta02_nand_sets,
+};
+
+
+/* Get PMU to set USB current limit accordingly. */
+static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = {
+       .vbus_draw      = gta02_udc_vbus_draw,
+       .pullup_pin = GTA02_GPIO_USB_PULLUP,
+};
+
+/* USB */
+static struct s3c2410_hcd_info gta02_usb_info __initdata = {
+       .port[0]        = {
+               .flags  = S3C_HCDFLG_USED,
+       },
+       .port[1]        = {
+               .flags  = 0,
+       },
+};
+
+/* Touchscreen */
+static struct s3c2410_ts_mach_info gta02_ts_info = {
+       .delay                  = 10000,
+       .presc                  = 0xff, /* slow as we can go */
+       .oversampling_shift     = 2,
+};
+
+/* Buttons */
+static struct gpio_keys_button gta02_buttons[] = {
+       {
+               .gpio = GTA02_GPIO_AUX_KEY,
+               .code = KEY_PHONE,
+               .desc = "Aux",
+               .type = EV_KEY,
+               .debounce_interval = 100,
+       },
+       {
+               .gpio = GTA02_GPIO_HOLD_KEY,
+               .code = KEY_PAUSE,
+               .desc = "Hold",
+               .type = EV_KEY,
+               .debounce_interval = 100,
+       },
+};
+
+static struct gpio_keys_platform_data gta02_buttons_pdata = {
+       .buttons = gta02_buttons,
+       .nbuttons = ARRAY_SIZE(gta02_buttons),
+};
+
+static struct platform_device gta02_buttons_device = {
+       .name = "gpio-keys",
+       .id = -1,
+       .dev = {
+               .platform_data = &gta02_buttons_pdata,
+       },
+};
+
+static void __init gta02_map_io(void)
+{
+       s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs));
+}
+
+
+/* These are the guys that don't need to be children of PMU. */
+
+static struct platform_device *gta02_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_wdt,
+       &s3c_device_sdi,
+       &s3c_device_usbgadget,
+       &s3c_device_nand,
+       &gta02_nor_flash,
+       &s3c24xx_pwm_device,
+       &s3c_device_iis,
+       &samsung_asoc_dma,
+       &s3c_device_i2c0,
+       &gta02_dfbmcs320_device,
+       &gta02_buttons_device,
+       &s3c_device_adc,
+       &s3c_device_ts,
+};
+
+/* These guys DO need to be children of PMU. */
+
+static struct platform_device *gta02_devices_pmu_children[] = {
+};
+
+
+/*
+ * This is called when pc50633 is probed, quite late in the day since it is an
+ * I2C bus device.  Here we can define platform devices with the advantage that
+ * we can mark the pcf50633 as the parent.  This makes them get suspended and
+ * resumed with their parent the pcf50633 still around.  All devices whose
+ * operation depends on something from pcf50633 must have this relationship
+ * made explicit like this, or suspend and resume will become an unreliable
+ * hellworld.
+ */
+
+static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf)
+{
+       int n;
+
+       /* Grab a copy of the now probed PMU pointer. */
+       gta02_pcf = pcf;
+
+       for (n = 0; n < ARRAY_SIZE(gta02_devices_pmu_children); n++)
+               gta02_devices_pmu_children[n]->dev.parent = pcf->dev;
+
+       platform_add_devices(gta02_devices_pmu_children,
+                            ARRAY_SIZE(gta02_devices_pmu_children));
+}
+
+static void gta02_poweroff(void)
+{
+       pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN, 1, 1);
+}
+
+static void __init gta02_machine_init(void)
+{
+       /* Set the panic callback to turn AUX LED on or off. */
+       panic_blink = gta02_panic_blink;
+
+       s3c_pm_init();
+
+#ifdef CONFIG_CHARGER_PCF50633
+       INIT_DELAYED_WORK(&gta02_charger_work, gta02_charger_worker);
+#endif
+
+       s3c24xx_udc_set_platdata(&gta02_udc_cfg);
+       s3c24xx_ts_set_platdata(&gta02_ts_info);
+       s3c_ohci_set_platdata(&gta02_usb_info);
+       s3c_nand_set_platdata(&gta02_nand_info);
+       s3c_i2c0_set_platdata(NULL);
+
+       i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs));
+
+       platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices));
+       pm_power_off = gta02_poweroff;
+
+       regulator_has_full_constraints();
+}
+
+
+MACHINE_START(NEO1973_GTA02, "GTA02")
+       /* Maintainer: Nelson Castillo <arhuaco@freaks-unidos.net> */
+       .atag_offset    = 0x100,
+       .map_io         = gta02_map_io,
+       .init_irq       = s3c24xx_init_irq,
+       .init_machine   = gta02_machine_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
new file mode 100644 (file)
index 0000000..6b21ba1
--- /dev/null
@@ -0,0 +1,757 @@
+/* linux/arch/arm/mach-s3c2410/mach-h1940.c
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.handhelds.org/projects/h1940.html
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/pwm_backlight.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/pda_power.h>
+#include <linux/s3c_adc_battery.h>
+#include <linux/delay.h>
+
+#include <video/platform_lcd.h>
+
+#include <linux/mmc/host.h>
+#include <linux/export.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-clock.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/gpio-fns.h>
+#include <mach/gpio-nrs.h>
+
+#include <mach/h1940.h>
+#include <mach/h1940-latch.h>
+#include <mach/fb.h>
+#include <plat/udc.h>
+#include <plat/iic.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/pm.h>
+#include <plat/mci.h>
+#include <plat/ts.h>
+
+#include <sound/uda1380.h>
+
+#include "common.h"
+
+#define H1940_LATCH            ((void __force __iomem *)0xF8000000)
+
+#define H1940_PA_LATCH         S3C2410_CS2
+
+#define H1940_LATCH_BIT(x)     (1 << ((x) + 16 - S3C_GPIO_END))
+
+static struct map_desc h1940_iodesc[] __initdata = {
+       [0] = {
+               .virtual        = (unsigned long)H1940_LATCH,
+               .pfn            = __phys_to_pfn(H1940_PA_LATCH),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE
+       },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg h1940_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = 0x245,
+               .ulcon       = 0x03,
+               .ufcon       = 0x00,
+       },
+       /* IR port */
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .uart_flags  = UPF_CONS_FLOW,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x43,
+               .ufcon       = 0x51,
+       }
+};
+
+/* Board control latch control */
+
+static unsigned int latch_state;
+
+static void h1940_latch_control(unsigned int clear, unsigned int set)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       latch_state &= ~clear;
+       latch_state |= set;
+
+       __raw_writel(latch_state, H1940_LATCH);
+
+       local_irq_restore(flags);
+}
+
+static inline int h1940_gpiolib_to_latch(int offset)
+{
+       return 1 << (offset + 16);
+}
+
+static void h1940_gpiolib_latch_set(struct gpio_chip *chip,
+                                       unsigned offset, int value)
+{
+       int latch_bit = h1940_gpiolib_to_latch(offset);
+
+       h1940_latch_control(value ? 0 : latch_bit,
+               value ? latch_bit : 0);
+}
+
+static int h1940_gpiolib_latch_output(struct gpio_chip *chip,
+                                       unsigned offset, int value)
+{
+       h1940_gpiolib_latch_set(chip, offset, value);
+       return 0;
+}
+
+static int h1940_gpiolib_latch_get(struct gpio_chip *chip,
+                                       unsigned offset)
+{
+       return (latch_state >> (offset + 16)) & 1;
+}
+
+static struct gpio_chip h1940_latch_gpiochip = {
+       .base                   = H1940_LATCH_GPIO(0),
+       .owner                  = THIS_MODULE,
+       .label                  = "H1940_LATCH",
+       .ngpio                  = 16,
+       .direction_output       = h1940_gpiolib_latch_output,
+       .set                    = h1940_gpiolib_latch_set,
+       .get                    = h1940_gpiolib_latch_get,
+};
+
+static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
+       .vbus_pin               = S3C2410_GPG(5),
+       .vbus_pin_inverted      = 1,
+       .pullup_pin             = H1940_LATCH_USB_DP,
+};
+
+static struct s3c2410_ts_mach_info h1940_ts_cfg __initdata = {
+               .delay = 10000,
+               .presc = 49,
+               .oversampling_shift = 2,
+               .cfg_gpio = s3c24xx_ts_cfg_gpio,
+};
+
+/**
+ * Set lcd on or off
+ **/
+static struct s3c2410fb_display h1940_lcd __initdata = {
+       .lcdcon5=       S3C2410_LCDCON5_FRM565 | \
+                       S3C2410_LCDCON5_INVVLINE | \
+                       S3C2410_LCDCON5_HWSWP,
+
+       .type =         S3C2410_LCDCON1_TFT,
+       .width =        240,
+       .height =       320,
+       .pixclock =     260000,
+       .xres =         240,
+       .yres =         320,
+       .bpp =          16,
+       .left_margin =  8,
+       .right_margin = 20,
+       .hsync_len =    4,
+       .upper_margin = 8,
+       .lower_margin = 7,
+       .vsync_len =    1,
+};
+
+static struct s3c2410fb_mach_info h1940_fb_info __initdata = {
+       .displays = &h1940_lcd,
+       .num_displays = 1,
+       .default_display = 0,
+
+       .lpcsel =       0x02,
+       .gpccon =       0xaa940659,
+       .gpccon_mask =  0xffffc0f0,
+       .gpcup =        0x0000ffff,
+       .gpcup_mask =   0xffffffff,
+       .gpdcon =       0xaa84aaa0,
+       .gpdcon_mask =  0xffffffff,
+       .gpdup =        0x0000faff,
+       .gpdup_mask =   0xffffffff,
+};
+
+static int power_supply_init(struct device *dev)
+{
+       return gpio_request(S3C2410_GPF(2), "cable plugged");
+}
+
+static int h1940_is_ac_online(void)
+{
+       return !gpio_get_value(S3C2410_GPF(2));
+}
+
+static void power_supply_exit(struct device *dev)
+{
+       gpio_free(S3C2410_GPF(2));
+}
+
+static char *h1940_supplicants[] = {
+       "main-battery",
+       "backup-battery",
+};
+
+static struct pda_power_pdata power_supply_info = {
+       .init                   = power_supply_init,
+       .is_ac_online           = h1940_is_ac_online,
+       .exit                   = power_supply_exit,
+       .supplied_to            = h1940_supplicants,
+       .num_supplicants        = ARRAY_SIZE(h1940_supplicants),
+};
+
+static struct resource power_supply_resources[] = {
+       [0] = {
+                       .name   = "ac",
+                       .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
+                                         IORESOURCE_IRQ_HIGHEDGE,
+                       .start  = IRQ_EINT2,
+                       .end    = IRQ_EINT2,
+       },
+};
+
+static struct platform_device power_supply = {
+       .name           = "pda-power",
+       .id             = -1,
+       .dev            = {
+                               .platform_data =
+                                       &power_supply_info,
+       },
+       .resource       = power_supply_resources,
+       .num_resources  = ARRAY_SIZE(power_supply_resources),
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
+       { .volt = 4070, .cur = 162, .level = 100},
+       { .volt = 4040, .cur = 165, .level = 95},
+       { .volt = 4016, .cur = 164, .level = 90},
+       { .volt = 3996, .cur = 166, .level = 85},
+       { .volt = 3971, .cur = 168, .level = 80},
+       { .volt = 3951, .cur = 168, .level = 75},
+       { .volt = 3931, .cur = 170, .level = 70},
+       { .volt = 3903, .cur = 172, .level = 65},
+       { .volt = 3886, .cur = 172, .level = 60},
+       { .volt = 3858, .cur = 176, .level = 55},
+       { .volt = 3842, .cur = 176, .level = 50},
+       { .volt = 3818, .cur = 176, .level = 45},
+       { .volt = 3789, .cur = 180, .level = 40},
+       { .volt = 3769, .cur = 180, .level = 35},
+       { .volt = 3749, .cur = 184, .level = 30},
+       { .volt = 3732, .cur = 184, .level = 25},
+       { .volt = 3716, .cur = 184, .level = 20},
+       { .volt = 3708, .cur = 184, .level = 15},
+       { .volt = 3716, .cur = 96, .level = 10},
+       { .volt = 3700, .cur = 96, .level = 5},
+       { .volt = 3684, .cur = 96, .level = 0},
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
+       { .volt = 4130, .cur = 0, .level = 100},
+       { .volt = 3982, .cur = 0, .level = 50},
+       { .volt = 3854, .cur = 0, .level = 10},
+       { .volt = 3841, .cur = 0, .level = 0},
+};
+
+static int h1940_bat_init(void)
+{
+       int ret;
+
+       ret = gpio_request(H1940_LATCH_SM803_ENABLE, "h1940-charger-enable");
+       if (ret)
+               return ret;
+       gpio_direction_output(H1940_LATCH_SM803_ENABLE, 0);
+
+       return 0;
+
+}
+
+static void h1940_bat_exit(void)
+{
+       gpio_free(H1940_LATCH_SM803_ENABLE);
+}
+
+static void h1940_enable_charger(void)
+{
+       gpio_set_value(H1940_LATCH_SM803_ENABLE, 1);
+}
+
+static void h1940_disable_charger(void)
+{
+       gpio_set_value(H1940_LATCH_SM803_ENABLE, 0);
+}
+
+static struct s3c_adc_bat_pdata h1940_bat_cfg = {
+       .init = h1940_bat_init,
+       .exit = h1940_bat_exit,
+       .enable_charger = h1940_enable_charger,
+       .disable_charger = h1940_disable_charger,
+       .gpio_charge_finished = S3C2410_GPF(3),
+       .gpio_inverted = 1,
+       .lut_noac = bat_lut_noac,
+       .lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
+       .lut_acin = bat_lut_acin,
+       .lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
+       .volt_channel = 0,
+       .current_channel = 1,
+       .volt_mult = 4056,
+       .current_mult = 1893,
+       .internal_impedance = 200,
+       .backup_volt_channel = 3,
+       /* TODO Check backup volt multiplier */
+       .backup_volt_mult = 4056,
+       .backup_volt_min = 0,
+       .backup_volt_max = 4149288
+};
+
+static struct platform_device h1940_battery = {
+       .name             = "s3c-adc-battery",
+       .id               = -1,
+       .dev = {
+               .parent = &s3c_device_adc.dev,
+               .platform_data = &h1940_bat_cfg,
+       },
+};
+
+static DEFINE_SPINLOCK(h1940_blink_spin);
+
+int h1940_led_blink_set(unsigned gpio, int state,
+       unsigned long *delay_on, unsigned long *delay_off)
+{
+       int blink_gpio, check_gpio1, check_gpio2;
+
+       switch (gpio) {
+       case H1940_LATCH_LED_GREEN:
+               blink_gpio = S3C2410_GPA(7);
+               check_gpio1 = S3C2410_GPA(1);
+               check_gpio2 = S3C2410_GPA(3);
+               break;
+       case H1940_LATCH_LED_RED:
+               blink_gpio = S3C2410_GPA(1);
+               check_gpio1 = S3C2410_GPA(7);
+               check_gpio2 = S3C2410_GPA(3);
+               break;
+       default:
+               blink_gpio = S3C2410_GPA(3);
+               check_gpio1 = S3C2410_GPA(1);
+               check_gpio1 = S3C2410_GPA(7);
+               break;
+       }
+
+       if (delay_on && delay_off && !*delay_on && !*delay_off)
+               *delay_on = *delay_off = 500;
+
+       spin_lock(&h1940_blink_spin);
+
+       switch (state) {
+       case GPIO_LED_NO_BLINK_LOW:
+       case GPIO_LED_NO_BLINK_HIGH:
+               if (!gpio_get_value(check_gpio1) &&
+                   !gpio_get_value(check_gpio2))
+                       gpio_set_value(H1940_LATCH_LED_FLASH, 0);
+               gpio_set_value(blink_gpio, 0);
+               if (gpio_is_valid(gpio))
+                       gpio_set_value(gpio, state);
+               break;
+       case GPIO_LED_BLINK:
+               if (gpio_is_valid(gpio))
+                       gpio_set_value(gpio, 0);
+               gpio_set_value(H1940_LATCH_LED_FLASH, 1);
+               gpio_set_value(blink_gpio, 1);
+               break;
+       }
+
+       spin_unlock(&h1940_blink_spin);
+
+       return 0;
+}
+EXPORT_SYMBOL(h1940_led_blink_set);
+
+static struct gpio_led h1940_leds_desc[] = {
+       {
+               .name                   = "Green",
+               .default_trigger        = "main-battery-full",
+               .gpio                   = H1940_LATCH_LED_GREEN,
+               .retain_state_suspended = 1,
+       },
+       {
+               .name                   = "Red",
+               .default_trigger
+                       = "main-battery-charging-blink-full-solid",
+               .gpio                   = H1940_LATCH_LED_RED,
+               .retain_state_suspended = 1,
+       },
+};
+
+static struct gpio_led_platform_data h1940_leds_pdata = {
+       .num_leds       = ARRAY_SIZE(h1940_leds_desc),
+       .leds           = h1940_leds_desc,
+       .gpio_blink_set = h1940_led_blink_set,
+};
+
+static struct platform_device h1940_device_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+                       .platform_data = &h1940_leds_pdata,
+       },
+};
+
+static struct platform_device h1940_device_bluetooth = {
+       .name             = "h1940-bt",
+       .id               = -1,
+};
+
+static void h1940_set_mmc_power(unsigned char power_mode, unsigned short vdd)
+{
+       switch (power_mode) {
+       case MMC_POWER_OFF:
+               gpio_set_value(H1940_LATCH_SD_POWER, 0);
+               break;
+       case MMC_POWER_UP:
+       case MMC_POWER_ON:
+               gpio_set_value(H1940_LATCH_SD_POWER, 1);
+               break;
+       default:
+               break;
+       };
+}
+
+static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = {
+       .gpio_detect   = S3C2410_GPF(5),
+       .gpio_wprotect = S3C2410_GPH(8),
+       .set_power     = h1940_set_mmc_power,
+       .ocr_avail     = MMC_VDD_32_33,
+};
+
+static int h1940_backlight_init(struct device *dev)
+{
+       gpio_request(S3C2410_GPB(0), "Backlight");
+
+       gpio_direction_output(S3C2410_GPB(0), 0);
+       s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE);
+       s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
+       gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1);
+
+       return 0;
+}
+
+static int h1940_backlight_notify(struct device *dev, int brightness)
+{
+       if (!brightness) {
+               gpio_direction_output(S3C2410_GPB(0), 1);
+               gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
+       } else {
+               gpio_direction_output(S3C2410_GPB(0), 0);
+               s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE);
+               s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
+               gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1);
+       }
+       return brightness;
+}
+
+static void h1940_backlight_exit(struct device *dev)
+{
+       gpio_direction_output(S3C2410_GPB(0), 1);
+       gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
+}
+
+
+static struct platform_pwm_backlight_data backlight_data = {
+       .pwm_id         = 0,
+       .max_brightness = 100,
+       .dft_brightness = 50,
+       /* tcnt = 0x31 */
+       .pwm_period_ns  = 36296,
+       .init           = h1940_backlight_init,
+       .notify         = h1940_backlight_notify,
+       .exit           = h1940_backlight_exit,
+};
+
+static struct platform_device h1940_backlight = {
+       .name = "pwm-backlight",
+       .dev  = {
+               .parent = &s3c_device_timer[0].dev,
+               .platform_data = &backlight_data,
+       },
+       .id   = -1,
+};
+
+static void h1940_lcd_power_set(struct plat_lcd_data *pd,
+                                       unsigned int power)
+{
+       int value, retries = 100;
+
+       if (!power) {
+               gpio_set_value(S3C2410_GPC(0), 0);
+               /* wait for 3ac */
+               do {
+                       value = gpio_get_value(S3C2410_GPC(6));
+               } while (value && retries--);
+
+               gpio_set_value(H1940_LATCH_LCD_P2, 0);
+               gpio_set_value(H1940_LATCH_LCD_P3, 0);
+               gpio_set_value(H1940_LATCH_LCD_P4, 0);
+
+               gpio_direction_output(S3C2410_GPC(1), 0);
+               gpio_direction_output(S3C2410_GPC(4), 0);
+
+               gpio_set_value(H1940_LATCH_LCD_P1, 0);
+               gpio_set_value(H1940_LATCH_LCD_P0, 0);
+
+               gpio_set_value(S3C2410_GPC(5), 0);
+
+       } else {
+               gpio_set_value(H1940_LATCH_LCD_P0, 1);
+               gpio_set_value(H1940_LATCH_LCD_P1, 1);
+
+               gpio_direction_input(S3C2410_GPC(1));
+               gpio_direction_input(S3C2410_GPC(4));
+               mdelay(10);
+               s3c_gpio_cfgpin(S3C2410_GPC(1), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S3C2410_GPC(4), S3C_GPIO_SFN(2));
+
+               gpio_set_value(S3C2410_GPC(5), 1);
+               gpio_set_value(S3C2410_GPC(0), 1);
+
+               gpio_set_value(H1940_LATCH_LCD_P3, 1);
+               gpio_set_value(H1940_LATCH_LCD_P2, 1);
+               gpio_set_value(H1940_LATCH_LCD_P4, 1);
+       }
+}
+
+static struct plat_lcd_data h1940_lcd_power_data = {
+       .set_power      = h1940_lcd_power_set,
+};
+
+static struct platform_device h1940_lcd_powerdev = {
+       .name                   = "platform-lcd",
+       .dev.parent             = &s3c_device_lcd.dev,
+       .dev.platform_data      = &h1940_lcd_power_data,
+};
+
+static struct uda1380_platform_data uda1380_info = {
+       .gpio_power     = H1940_LATCH_UDA_POWER,
+       .gpio_reset     = S3C2410_GPA(12),
+       .dac_clk        = UDA1380_DAC_CLK_SYSCLK,
+};
+
+static struct i2c_board_info h1940_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("uda1380", 0x1a),
+               .platform_data = &uda1380_info,
+       },
+};
+
+#define DECLARE_BUTTON(p, k, n, w)     \
+       {                               \
+               .gpio           = p,    \
+               .code           = k,    \
+               .desc           = n,    \
+               .wakeup         = w,    \
+               .active_low     = 1,    \
+       }
+
+static struct gpio_keys_button h1940_buttons[] = {
+       DECLARE_BUTTON(S3C2410_GPF(0),       KEY_POWER,          "Power", 1),
+       DECLARE_BUTTON(S3C2410_GPF(6),       KEY_ENTER,         "Select", 1),
+       DECLARE_BUTTON(S3C2410_GPF(7),      KEY_RECORD,         "Record", 0),
+       DECLARE_BUTTON(S3C2410_GPG(0),         KEY_F11,       "Calendar", 0),
+       DECLARE_BUTTON(S3C2410_GPG(2),         KEY_F12,       "Contacts", 0),
+       DECLARE_BUTTON(S3C2410_GPG(3),        KEY_MAIL,           "Mail", 0),
+       DECLARE_BUTTON(S3C2410_GPG(6),        KEY_LEFT,     "Left_arrow", 0),
+       DECLARE_BUTTON(S3C2410_GPG(7),    KEY_HOMEPAGE,           "Home", 0),
+       DECLARE_BUTTON(S3C2410_GPG(8),       KEY_RIGHT,    "Right_arrow", 0),
+       DECLARE_BUTTON(S3C2410_GPG(9),          KEY_UP,       "Up_arrow", 0),
+       DECLARE_BUTTON(S3C2410_GPG(10),       KEY_DOWN,     "Down_arrow", 0),
+};
+
+static struct gpio_keys_platform_data h1940_buttons_data = {
+       .buttons        = h1940_buttons,
+       .nbuttons       = ARRAY_SIZE(h1940_buttons),
+};
+
+static struct platform_device h1940_dev_buttons = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &h1940_buttons_data,
+       }
+};
+
+static struct platform_device *h1940_devices[] __initdata = {
+       &h1940_dev_buttons,
+       &s3c_device_ohci,
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+       &samsung_asoc_dma,
+       &s3c_device_usbgadget,
+       &h1940_device_leds,
+       &h1940_device_bluetooth,
+       &s3c_device_sdi,
+       &s3c_device_rtc,
+       &s3c_device_timer[0],
+       &h1940_backlight,
+       &h1940_lcd_powerdev,
+       &s3c_device_adc,
+       &s3c_device_ts,
+       &power_supply,
+       &h1940_battery,
+};
+
+static void __init h1940_map_io(void)
+{
+       s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs));
+
+       /* setup PM */
+
+#ifdef CONFIG_PM_H1940
+       memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 1024);
+#endif
+       s3c_pm_init();
+
+       /* Add latch gpio chip, set latch initial value */
+       h1940_latch_control(0, 0);
+       WARN_ON(gpiochip_add(&h1940_latch_gpiochip));
+}
+
+/* H1940 and RX3715 need to reserve this for suspend */
+static void __init h1940_reserve(void)
+{
+       memblock_reserve(0x30003000, 0x1000);
+       memblock_reserve(0x30081000, 0x1000);
+}
+
+static void __init h1940_init_irq(void)
+{
+       s3c24xx_init_irq();
+}
+
+static void __init h1940_init(void)
+{
+       u32 tmp;
+
+       s3c24xx_fb_set_platdata(&h1940_fb_info);
+       s3c24xx_mci_set_platdata(&h1940_mmc_cfg);
+       s3c24xx_udc_set_platdata(&h1940_udc_cfg);
+       s3c24xx_ts_set_platdata(&h1940_ts_cfg);
+       s3c_i2c0_set_platdata(NULL);
+
+       /* Turn off suspend on both USB ports, and switch the
+        * selectable USB port to USB device mode. */
+
+       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+                             S3C2410_MISCCR_USBSUSPND0 |
+                             S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+       tmp =   (0x78 << S3C24XX_PLL_MDIV_SHIFT)
+             | (0x02 << S3C24XX_PLL_PDIV_SHIFT)
+             | (0x03 << S3C24XX_PLL_SDIV_SHIFT);
+       writel(tmp, S3C2410_UPLLCON);
+
+       gpio_request(S3C2410_GPC(0), "LCD power");
+       gpio_request(S3C2410_GPC(1), "LCD power");
+       gpio_request(S3C2410_GPC(4), "LCD power");
+       gpio_request(S3C2410_GPC(5), "LCD power");
+       gpio_request(S3C2410_GPC(6), "LCD power");
+       gpio_request(H1940_LATCH_LCD_P0, "LCD power");
+       gpio_request(H1940_LATCH_LCD_P1, "LCD power");
+       gpio_request(H1940_LATCH_LCD_P2, "LCD power");
+       gpio_request(H1940_LATCH_LCD_P3, "LCD power");
+       gpio_request(H1940_LATCH_LCD_P4, "LCD power");
+       gpio_request(H1940_LATCH_MAX1698_nSHUTDOWN, "LCD power");
+       gpio_direction_output(S3C2410_GPC(0), 0);
+       gpio_direction_output(S3C2410_GPC(1), 0);
+       gpio_direction_output(S3C2410_GPC(4), 0);
+       gpio_direction_output(S3C2410_GPC(5), 0);
+       gpio_direction_input(S3C2410_GPC(6));
+       gpio_direction_output(H1940_LATCH_LCD_P0, 0);
+       gpio_direction_output(H1940_LATCH_LCD_P1, 0);
+       gpio_direction_output(H1940_LATCH_LCD_P2, 0);
+       gpio_direction_output(H1940_LATCH_LCD_P3, 0);
+       gpio_direction_output(H1940_LATCH_LCD_P4, 0);
+       gpio_direction_output(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
+
+       gpio_request(H1940_LATCH_SD_POWER, "SD power");
+       gpio_direction_output(H1940_LATCH_SD_POWER, 0);
+
+       platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
+
+       gpio_request(S3C2410_GPA(1), "Red LED blink");
+       gpio_request(S3C2410_GPA(3), "Blue LED blink");
+       gpio_request(S3C2410_GPA(7), "Green LED blink");
+       gpio_request(H1940_LATCH_LED_FLASH, "LED blink");
+       gpio_direction_output(S3C2410_GPA(1), 0);
+       gpio_direction_output(S3C2410_GPA(3), 0);
+       gpio_direction_output(S3C2410_GPA(7), 0);
+       gpio_direction_output(H1940_LATCH_LED_FLASH, 0);
+
+       i2c_register_board_info(0, h1940_i2c_devices,
+               ARRAY_SIZE(h1940_i2c_devices));
+}
+
+MACHINE_START(H1940, "IPAQ-H1940")
+       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
+       .atag_offset    = 0x100,
+       .map_io         = h1940_map_io,
+       .reserve        = h1940_reserve,
+       .init_irq       = h1940_init_irq,
+       .init_machine   = h1940_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
new file mode 100644 (file)
index 0000000..ae73ba3
--- /dev/null
@@ -0,0 +1,666 @@
+/* linux/arch/arm/mach-s3c2410/mach-jive.c
+ *
+ * Copyright 2007 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/syscore_ops.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+#include <video/ili9320.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <plat/regs-serial.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
+
+#include <mach/regs-power.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <mach/fb.h>
+
+#include <asm/mach-types.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <plat/s3c2412.h>
+#include <plat/gpio-cfg.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/udc.h>
+
+static struct map_desc jive_iodesc[] __initdata = {
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg jive_uartcfgs[] = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+/* Jive flash assignment
+ *
+ * 0x00000000-0x00028000 : uboot
+ * 0x00028000-0x0002c000 : uboot env
+ * 0x0002c000-0x00030000 : spare
+ * 0x00030000-0x00200000 : zimage A
+ * 0x00200000-0x01600000 : cramfs A
+ * 0x01600000-0x017d0000 : zimage B
+ * 0x017d0000-0x02bd0000 : cramfs B
+ * 0x02bd0000-0x03fd0000 : yaffs
+ */
+static struct mtd_partition __initdata jive_imageA_nand_part[] = {
+
+#ifdef CONFIG_MACH_JIVE_SHOW_BOOTLOADER
+       /* Don't allow access to the bootloader from linux */
+       {
+               .name           = "uboot",
+               .offset         = 0,
+               .size           = (160 * SZ_1K),
+               .mask_flags     = MTD_WRITEABLE, /* force read-only */
+       },
+
+       /* spare */
+        {
+                .name           = "spare",
+                .offset         = (176 * SZ_1K),
+                .size           = (16 * SZ_1K),
+        },
+#endif
+
+       /* booted images */
+        {
+               .name           = "kernel (ro)",
+               .offset         = (192 * SZ_1K),
+               .size           = (SZ_2M) - (192 * SZ_1K),
+               .mask_flags     = MTD_WRITEABLE, /* force read-only */
+        }, {
+                .name           = "root (ro)",
+                .offset         = (SZ_2M),
+                .size           = (20 * SZ_1M),
+               .mask_flags     = MTD_WRITEABLE, /* force read-only */
+        },
+
+       /* yaffs */
+       {
+               .name           = "yaffs",
+               .offset         = (44 * SZ_1M),
+               .size           = (20 * SZ_1M),
+       },
+
+       /* bootloader environment */
+       {
+                .name          = "env",
+               .offset         = (160 * SZ_1K),
+               .size           = (16 * SZ_1K),
+       },
+
+       /* upgrade images */
+        {
+               .name           = "zimage",
+               .offset         = (22 * SZ_1M),
+               .size           = (2 * SZ_1M) - (192 * SZ_1K),
+        }, {
+               .name           = "cramfs",
+               .offset         = (24 * SZ_1M) - (192*SZ_1K),
+               .size           = (20 * SZ_1M),
+        },
+};
+
+static struct mtd_partition __initdata jive_imageB_nand_part[] = {
+
+#ifdef CONFIG_MACH_JIVE_SHOW_BOOTLOADER
+       /* Don't allow access to the bootloader from linux */
+       {
+               .name           = "uboot",
+               .offset         = 0,
+               .size           = (160 * SZ_1K),
+               .mask_flags     = MTD_WRITEABLE, /* force read-only */
+       },
+
+       /* spare */
+        {
+                .name           = "spare",
+                .offset         = (176 * SZ_1K),
+                .size           = (16 * SZ_1K),
+        },
+#endif
+
+       /* booted images */
+        {
+               .name           = "kernel (ro)",
+               .offset         = (22 * SZ_1M),
+               .size           = (2 * SZ_1M) - (192 * SZ_1K),
+               .mask_flags     = MTD_WRITEABLE, /* force read-only */
+        },
+       {
+               .name           = "root (ro)",
+               .offset         = (24 * SZ_1M) - (192 * SZ_1K),
+                .size          = (20 * SZ_1M),
+               .mask_flags     = MTD_WRITEABLE, /* force read-only */
+       },
+
+       /* yaffs */
+       {
+               .name           = "yaffs",
+               .offset         = (44 * SZ_1M),
+               .size           = (20 * SZ_1M),
+        },
+
+       /* bootloader environment */
+       {
+               .name           = "env",
+               .offset         = (160 * SZ_1K),
+               .size           = (16 * SZ_1K),
+       },
+
+       /* upgrade images */
+       {
+               .name           = "zimage",
+               .offset         = (192 * SZ_1K),
+               .size           = (2 * SZ_1M) - (192 * SZ_1K),
+        }, {
+               .name           = "cramfs",
+               .offset         = (2 * SZ_1M),
+               .size           = (20 * SZ_1M),
+        },
+};
+
+static struct s3c2410_nand_set __initdata jive_nand_sets[] = {
+       [0] = {
+               .name           = "flash",
+               .nr_chips       = 1,
+               .nr_partitions  = ARRAY_SIZE(jive_imageA_nand_part),
+               .partitions     = jive_imageA_nand_part,
+       },
+};
+
+static struct s3c2410_platform_nand __initdata jive_nand_info = {
+       /* set taken from osiris nand timings, possibly still conservative */
+       .tacls          = 30,
+       .twrph0         = 55,
+       .twrph1         = 40,
+       .sets           = jive_nand_sets,
+       .nr_sets        = ARRAY_SIZE(jive_nand_sets),
+};
+
+static int __init jive_mtdset(char *options)
+{
+       struct s3c2410_nand_set *nand = &jive_nand_sets[0];
+       unsigned long set;
+
+       if (options == NULL || options[0] == '\0')
+               return 0;
+
+       if (strict_strtoul(options, 10, &set)) {
+               printk(KERN_ERR "failed to parse mtdset=%s\n", options);
+               return 0;
+       }
+
+       switch (set) {
+       case 1:
+               nand->nr_partitions = ARRAY_SIZE(jive_imageB_nand_part);
+               nand->partitions = jive_imageB_nand_part;
+       case 0:
+               /* this is already setup in the nand info */
+               break;
+       default:
+               printk(KERN_ERR "Unknown mtd set %ld specified,"
+                      "using default.", set);
+       }
+
+       return 0;
+}
+
+/* parse the mtdset= option given to the kernel command line */
+__setup("mtdset=", jive_mtdset);
+
+/* LCD timing and setup */
+
+#define LCD_XRES        (240)
+#define LCD_YRES        (320)
+#define LCD_LEFT_MARGIN  (12)
+#define LCD_RIGHT_MARGIN (12)
+#define LCD_LOWER_MARGIN (12)
+#define LCD_UPPER_MARGIN (12)
+#define LCD_VSYNC       (2)
+#define LCD_HSYNC       (2)
+
+#define LCD_REFRESH     (60)
+
+#define LCD_HTOT (LCD_HSYNC + LCD_LEFT_MARGIN + LCD_XRES + LCD_RIGHT_MARGIN)
+#define LCD_VTOT (LCD_VSYNC + LCD_LOWER_MARGIN + LCD_YRES + LCD_UPPER_MARGIN)
+
+static struct s3c2410fb_display jive_vgg2432a4_display[] = {
+       [0] = {
+               .width          = LCD_XRES,
+               .height         = LCD_YRES,
+               .xres           = LCD_XRES,
+               .yres           = LCD_YRES,
+               .left_margin    = LCD_LEFT_MARGIN,
+               .right_margin   = LCD_RIGHT_MARGIN,
+               .upper_margin   = LCD_UPPER_MARGIN,
+               .lower_margin   = LCD_LOWER_MARGIN,
+               .hsync_len      = LCD_HSYNC,
+               .vsync_len      = LCD_VSYNC,
+
+               .pixclock       = (1000000000000LL /
+                                  (LCD_REFRESH * LCD_HTOT * LCD_VTOT)),
+
+               .bpp            = 16,
+               .type           = (S3C2410_LCDCON1_TFT16BPP |
+                                  S3C2410_LCDCON1_TFT),
+
+               .lcdcon5        = (S3C2410_LCDCON5_FRM565 |
+                                  S3C2410_LCDCON5_INVVLINE |
+                                  S3C2410_LCDCON5_INVVFRAME |
+                                  S3C2410_LCDCON5_INVVDEN |
+                                  S3C2410_LCDCON5_PWREN),
+       },
+};
+
+/* todo - put into gpio header */
+
+#define S3C2410_GPCCON_MASK(x) (3 << ((x) * 2))
+#define S3C2410_GPDCON_MASK(x) (3 << ((x) * 2))
+
+static struct s3c2410fb_mach_info jive_lcd_config = {
+       .displays        = jive_vgg2432a4_display,
+       .num_displays    = ARRAY_SIZE(jive_vgg2432a4_display),
+       .default_display = 0,
+
+       /* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN
+        * and disable the pull down resistors on pins we are using for LCD
+        * data. */
+
+       .gpcup          = (0xf << 1) | (0x3f << 10),
+
+       .gpccon         = (S3C2410_GPC1_VCLK   | S3C2410_GPC2_VLINE |
+                          S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM |
+                          S3C2410_GPC10_VD2   | S3C2410_GPC11_VD3 |
+                          S3C2410_GPC12_VD4   | S3C2410_GPC13_VD5 |
+                          S3C2410_GPC14_VD6   | S3C2410_GPC15_VD7),
+
+       .gpccon_mask    = (S3C2410_GPCCON_MASK(1)  | S3C2410_GPCCON_MASK(2)  |
+                          S3C2410_GPCCON_MASK(3)  | S3C2410_GPCCON_MASK(4)  |
+                          S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) |
+                          S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) |
+                          S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)),
+
+       .gpdup          = (0x3f << 2) | (0x3f << 10),
+
+       .gpdcon         = (S3C2410_GPD2_VD10  | S3C2410_GPD3_VD11 |
+                          S3C2410_GPD4_VD12  | S3C2410_GPD5_VD13 |
+                          S3C2410_GPD6_VD14  | S3C2410_GPD7_VD15 |
+                          S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 |
+                          S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 |
+                          S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23),
+
+       .gpdcon_mask    = (S3C2410_GPDCON_MASK(2)  | S3C2410_GPDCON_MASK(3) |
+                          S3C2410_GPDCON_MASK(4)  | S3C2410_GPDCON_MASK(5) |
+                          S3C2410_GPDCON_MASK(6)  | S3C2410_GPDCON_MASK(7) |
+                          S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)|
+                          S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)|
+                          S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)),
+};
+
+/* ILI9320 support. */
+
+static void jive_lcm_reset(unsigned int set)
+{
+       printk(KERN_DEBUG "%s(%d)\n", __func__, set);
+
+       gpio_set_value(S3C2410_GPG(13), set);
+}
+
+#undef LCD_UPPER_MARGIN
+#define LCD_UPPER_MARGIN 2
+
+static struct ili9320_platdata jive_lcm_config = {
+       .hsize          = LCD_XRES,
+       .vsize          = LCD_YRES,
+
+       .reset          = jive_lcm_reset,
+       .suspend        = ILI9320_SUSPEND_DEEP,
+
+       .entry_mode     = ILI9320_ENTRYMODE_ID(3) | ILI9320_ENTRYMODE_BGR,
+       .display2       = (ILI9320_DISPLAY2_FP(LCD_UPPER_MARGIN) |
+                          ILI9320_DISPLAY2_BP(LCD_LOWER_MARGIN)),
+       .display3       = 0x0,
+       .display4       = 0x0,
+       .rgb_if1        = (ILI9320_RGBIF1_RIM_RGB18 |
+                          ILI9320_RGBIF1_RM | ILI9320_RGBIF1_CLK_RGBIF),
+       .rgb_if2        = ILI9320_RGBIF2_DPL,
+       .interface2     = 0x0,
+       .interface3     = 0x3,
+       .interface4     = (ILI9320_INTERFACE4_RTNE(16) |
+                          ILI9320_INTERFACE4_DIVE(1)),
+       .interface5     = 0x0,
+       .interface6     = 0x0,
+};
+
+/* LCD SPI support */
+
+static struct spi_gpio_platform_data jive_lcd_spi = {
+       .sck            = S3C2410_GPG(8),
+       .mosi           = S3C2410_GPB(8),
+       .miso           = SPI_GPIO_NO_MISO,
+};
+
+static struct platform_device jive_device_lcdspi = {
+       .name           = "spi-gpio",
+       .id             = 1,
+       .dev.platform_data = &jive_lcd_spi,
+};
+
+
+/* WM8750 audio code SPI definition */
+
+static struct spi_gpio_platform_data jive_wm8750_spi = {
+       .sck            = S3C2410_GPB(4),
+       .mosi           = S3C2410_GPB(9),
+       .miso           = SPI_GPIO_NO_MISO,
+};
+
+static struct platform_device jive_device_wm8750 = {
+       .name           = "spi-gpio",
+       .id             = 2,
+       .dev.platform_data = &jive_wm8750_spi,
+};
+
+/* JIVE SPI devices. */
+
+static struct spi_board_info __initdata jive_spi_devs[] = {
+       [0] = {
+               .modalias       = "VGG2432A4",
+               .bus_num        = 1,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_3,   /* CPOL=1, CPHA=1 */
+               .max_speed_hz   = 100000,
+               .platform_data  = &jive_lcm_config,
+               .controller_data = (void *)S3C2410_GPB(7),
+       }, {
+               .modalias       = "WM8750",
+               .bus_num        = 2,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_0,   /* CPOL=0, CPHA=0 */
+               .max_speed_hz   = 100000,
+               .controller_data = (void *)S3C2410_GPH(10),
+       },
+};
+
+/* I2C bus and device configuration. */
+
+static struct s3c2410_platform_i2c jive_i2c_cfg __initdata = {
+       .frequency      = 80 * 1000,
+       .flags          = S3C_IICFLG_FILTER,
+       .sda_delay      = 2,
+};
+
+static struct i2c_board_info jive_i2c_devs[] __initdata = {
+       [0] = {
+               I2C_BOARD_INFO("lis302dl", 0x1c),
+               .irq    = IRQ_EINT14,
+       },
+};
+
+/* The platform devices being used. */
+
+static struct platform_device *jive_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_rtc,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_lcd,
+       &jive_device_lcdspi,
+       &jive_device_wm8750,
+       &s3c_device_nand,
+       &s3c_device_usbgadget,
+};
+
+static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = {
+       .vbus_pin       = S3C2410_GPG(1),               /* detect is on GPG1 */
+};
+
+/* Jive power management device */
+
+#ifdef CONFIG_PM
+static int jive_pm_suspend(void)
+{
+       /* Write the magic value u-boot uses to check for resume into
+        * the INFORM0 register, and ensure INFORM1 is set to the
+        * correct address to resume from. */
+
+       __raw_writel(0x2BED, S3C2412_INFORM0);
+       __raw_writel(virt_to_phys(s3c_cpu_resume), S3C2412_INFORM1);
+
+       return 0;
+}
+
+static void jive_pm_resume(void)
+{
+       __raw_writel(0x0, S3C2412_INFORM0);
+}
+
+#else
+#define jive_pm_suspend NULL
+#define jive_pm_resume NULL
+#endif
+
+static struct syscore_ops jive_pm_syscore_ops = {
+       .suspend        = jive_pm_suspend,
+       .resume         = jive_pm_resume,
+};
+
+static void __init jive_map_io(void)
+{
+       s3c24xx_init_io(jive_iodesc, ARRAY_SIZE(jive_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(jive_uartcfgs, ARRAY_SIZE(jive_uartcfgs));
+}
+
+static void jive_power_off(void)
+{
+       printk(KERN_INFO "powering system down...\n");
+
+       s3c2410_gpio_setpin(S3C2410_GPC(5), 1);
+       s3c_gpio_cfgpin(S3C2410_GPC(5), S3C2410_GPIO_OUTPUT);
+}
+
+static void __init jive_machine_init(void)
+{
+       /* register system core operations for managing low level suspend */
+
+       register_syscore_ops(&jive_pm_syscore_ops);
+
+       /* write our sleep configurations for the IO. Pull down all unused
+        * IO, ensure that we have turned off all peripherals we do not
+        * need, and configure the ones we do need. */
+
+       /* Port B sleep */
+
+       __raw_writel(S3C2412_SLPCON_IN(0)   |
+                    S3C2412_SLPCON_PULL(1) |
+                    S3C2412_SLPCON_HIGH(2) |
+                    S3C2412_SLPCON_PULL(3) |
+                    S3C2412_SLPCON_PULL(4) |
+                    S3C2412_SLPCON_PULL(5) |
+                    S3C2412_SLPCON_PULL(6) |
+                    S3C2412_SLPCON_HIGH(7) |
+                    S3C2412_SLPCON_PULL(8) |
+                    S3C2412_SLPCON_PULL(9) |
+                    S3C2412_SLPCON_PULL(10), S3C2412_GPBSLPCON);
+
+       /* Port C sleep */
+
+       __raw_writel(S3C2412_SLPCON_PULL(0) |
+                    S3C2412_SLPCON_PULL(1) |
+                    S3C2412_SLPCON_PULL(2) |
+                    S3C2412_SLPCON_PULL(3) |
+                    S3C2412_SLPCON_PULL(4) |
+                    S3C2412_SLPCON_PULL(5) |
+                    S3C2412_SLPCON_LOW(6)  |
+                    S3C2412_SLPCON_PULL(6) |
+                    S3C2412_SLPCON_PULL(7) |
+                    S3C2412_SLPCON_PULL(8) |
+                    S3C2412_SLPCON_PULL(9) |
+                    S3C2412_SLPCON_PULL(10) |
+                    S3C2412_SLPCON_PULL(11) |
+                    S3C2412_SLPCON_PULL(12) |
+                    S3C2412_SLPCON_PULL(13) |
+                    S3C2412_SLPCON_PULL(14) |
+                    S3C2412_SLPCON_PULL(15), S3C2412_GPCSLPCON);
+
+       /* Port D sleep */
+
+       __raw_writel(S3C2412_SLPCON_ALL_PULL, S3C2412_GPDSLPCON);
+
+       /* Port F sleep */
+
+       __raw_writel(S3C2412_SLPCON_LOW(0)  |
+                    S3C2412_SLPCON_LOW(1)  |
+                    S3C2412_SLPCON_LOW(2)  |
+                    S3C2412_SLPCON_EINT(3) |
+                    S3C2412_SLPCON_EINT(4) |
+                    S3C2412_SLPCON_EINT(5) |
+                    S3C2412_SLPCON_EINT(6) |
+                    S3C2412_SLPCON_EINT(7), S3C2412_GPFSLPCON);
+
+       /* Port G sleep */
+
+       __raw_writel(S3C2412_SLPCON_IN(0)    |
+                    S3C2412_SLPCON_IN(1)    |
+                    S3C2412_SLPCON_IN(2)    |
+                    S3C2412_SLPCON_IN(3)    |
+                    S3C2412_SLPCON_IN(4)    |
+                    S3C2412_SLPCON_IN(5)    |
+                    S3C2412_SLPCON_IN(6)    |
+                    S3C2412_SLPCON_IN(7)    |
+                    S3C2412_SLPCON_PULL(8)  |
+                    S3C2412_SLPCON_PULL(9)  |
+                    S3C2412_SLPCON_IN(10)   |
+                    S3C2412_SLPCON_PULL(11) |
+                    S3C2412_SLPCON_PULL(12) |
+                    S3C2412_SLPCON_PULL(13) |
+                    S3C2412_SLPCON_IN(14)   |
+                    S3C2412_SLPCON_PULL(15), S3C2412_GPGSLPCON);
+
+       /* Port H sleep */
+
+       __raw_writel(S3C2412_SLPCON_PULL(0) |
+                    S3C2412_SLPCON_PULL(1) |
+                    S3C2412_SLPCON_PULL(2) |
+                    S3C2412_SLPCON_PULL(3) |
+                    S3C2412_SLPCON_PULL(4) |
+                    S3C2412_SLPCON_PULL(5) |
+                    S3C2412_SLPCON_PULL(6) |
+                    S3C2412_SLPCON_IN(7)   |
+                    S3C2412_SLPCON_IN(8)   |
+                    S3C2412_SLPCON_PULL(9) |
+                    S3C2412_SLPCON_IN(10), S3C2412_GPHSLPCON);
+
+       /* initialise the power management now we've setup everything. */
+
+       s3c_pm_init();
+
+       /** TODO - check that this is after the cmdline option! */
+       s3c_nand_set_platdata(&jive_nand_info);
+
+       /* initialise the spi */
+
+       gpio_request(S3C2410_GPG(13), "lcm reset");
+       gpio_direction_output(S3C2410_GPG(13), 0);
+
+       gpio_request(S3C2410_GPB(7), "jive spi");
+       gpio_direction_output(S3C2410_GPB(7), 1);
+
+       s3c2410_gpio_setpin(S3C2410_GPB(6), 0);
+       s3c_gpio_cfgpin(S3C2410_GPB(6), S3C2410_GPIO_OUTPUT);
+
+       s3c2410_gpio_setpin(S3C2410_GPG(8), 1);
+       s3c_gpio_cfgpin(S3C2410_GPG(8), S3C2410_GPIO_OUTPUT);
+
+       /* initialise the WM8750 spi */
+
+       gpio_request(S3C2410_GPH(10), "jive wm8750 spi");
+       gpio_direction_output(S3C2410_GPH(10), 1);
+
+       /* Turn off suspend on both USB ports, and switch the
+        * selectable USB port to USB device mode. */
+
+       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+                             S3C2410_MISCCR_USBSUSPND0 |
+                             S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+       s3c24xx_udc_set_platdata(&jive_udc_cfg);
+       s3c24xx_fb_set_platdata(&jive_lcd_config);
+
+       spi_register_board_info(jive_spi_devs, ARRAY_SIZE(jive_spi_devs));
+
+       s3c_i2c0_set_platdata(&jive_i2c_cfg);
+       i2c_register_board_info(0, jive_i2c_devs, ARRAY_SIZE(jive_i2c_devs));
+
+       pm_power_off = jive_power_off;
+
+       platform_add_devices(jive_devices, ARRAY_SIZE(jive_devices));
+}
+
+MACHINE_START(JIVE, "JIVE")
+       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
+       .atag_offset    = 0x100,
+
+       .init_irq       = s3c24xx_init_irq,
+       .map_io         = jive_map_io,
+       .init_machine   = jive_machine_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2412_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
new file mode 100644 (file)
index 0000000..5d66fb2
--- /dev/null
@@ -0,0 +1,705 @@
+/* linux/arch/arm/mach-s3c2440/mach-mini2440.c
+ *
+ * Copyright (c) 2008 Ramax Lo <ramaxlo@gmail.com>
+ *      Based on mach-anubis.c by Ben Dooks <ben@simtec.co.uk>
+ *      and modifications by SBZ <sbz@spgui.org> and
+ *      Weibing <http://weibing.blogbus.com> and
+ *      Michel Pollet <buserror@gmail.com>
+ *
+ * For product information, visit http://code.google.com/p/mini2440/
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/serial_core.h>
+#include <linux/dm9000.h>
+#include <linux/i2c/at24.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_keys.h>
+#include <linux/i2c.h>
+#include <linux/mmc/host.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/fb.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/leds-gpio.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <mach/irqs.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
+#include <plat/mci.h>
+#include <plat/udc.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#include <sound/s3c24xx_uda134x.h>
+
+#include "common.h"
+
+#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300)
+
+static struct map_desc mini2440_iodesc[] __initdata = {
+       /* nothing to declare, move along */
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+
+static struct s3c2410_uartcfg mini2440_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+};
+
+/* USB device UDC support */
+
+static struct s3c2410_udc_mach_info mini2440_udc_cfg __initdata = {
+       .pullup_pin = S3C2410_GPC(5),
+};
+
+
+/* LCD timing and setup */
+
+/*
+ * This macro simplifies the table bellow
+ */
+#define _LCD_DECLARE(_clock,_xres,margin_left,margin_right,hsync, \
+                       _yres,margin_top,margin_bottom,vsync, refresh) \
+       .width = _xres, \
+       .xres = _xres, \
+       .height = _yres, \
+       .yres = _yres, \
+       .left_margin    = margin_left,  \
+       .right_margin   = margin_right, \
+       .upper_margin   = margin_top,   \
+       .lower_margin   = margin_bottom,        \
+       .hsync_len      = hsync,        \
+       .vsync_len      = vsync,        \
+       .pixclock       = ((_clock*100000000000LL) /    \
+                          ((refresh) * \
+                          (hsync + margin_left + _xres + margin_right) * \
+                          (vsync + margin_top + _yres + margin_bottom))), \
+       .bpp            = 16,\
+       .type           = (S3C2410_LCDCON1_TFT16BPP |\
+                          S3C2410_LCDCON1_TFT)
+
+static struct s3c2410fb_display mini2440_lcd_cfg[] __initdata = {
+       [0] = { /* mini2440 + 3.5" TFT + touchscreen */
+               _LCD_DECLARE(
+                       7,                      /* The 3.5 is quite fast */
+                       240, 21, 38, 6,         /* x timing */
+                       320, 4, 4, 2,           /* y timing */
+                       60),                    /* refresh rate */
+               .lcdcon5        = (S3C2410_LCDCON5_FRM565 |
+                                  S3C2410_LCDCON5_INVVLINE |
+                                  S3C2410_LCDCON5_INVVFRAME |
+                                  S3C2410_LCDCON5_INVVDEN |
+                                  S3C2410_LCDCON5_PWREN),
+       },
+       [1] = { /* mini2440 + 7" TFT + touchscreen */
+               _LCD_DECLARE(
+                       10,                     /* the 7" runs slower */
+                       800, 40, 40, 48,        /* x timing */
+                       480, 29, 3, 3,          /* y timing */
+                       50),                    /* refresh rate */
+               .lcdcon5        = (S3C2410_LCDCON5_FRM565 |
+                                  S3C2410_LCDCON5_INVVLINE |
+                                  S3C2410_LCDCON5_INVVFRAME |
+                                  S3C2410_LCDCON5_PWREN),
+       },
+       /* The VGA shield can outout at several resolutions. All share 
+        * the same timings, however, anything smaller than 1024x768
+        * will only be displayed in the top left corner of a 1024x768
+        * XGA output unless you add optional dip switches to the shield.
+        * Therefore timings for other resolutions have been omitted here.
+        */
+       [2] = {
+               _LCD_DECLARE(
+                       10,
+                       1024, 1, 2, 2,          /* y timing */
+                       768, 200, 16, 16,       /* x timing */
+                       24),    /* refresh rate, maximum stable,
+                                tested with the FPGA shield */
+               .lcdcon5        = (S3C2410_LCDCON5_FRM565 |
+                                  S3C2410_LCDCON5_HWSWP),
+       },
+       /* mini2440 + 3.5" TFT (LCD-W35i, LQ035Q1DG06 type) + touchscreen*/
+       [3] = {
+               _LCD_DECLARE(
+                       /* clock */
+                       7,
+                       /* xres, margin_right, margin_left, hsync */
+                       320, 68, 66, 4,
+                       /* yres, margin_top, margin_bottom, vsync */
+                       240, 4, 4, 9,
+                       /* refresh rate */
+                       60),
+               .lcdcon5        = (S3C2410_LCDCON5_FRM565 |
+                                  S3C2410_LCDCON5_INVVDEN |
+                                  S3C2410_LCDCON5_INVVFRAME |
+                                  S3C2410_LCDCON5_INVVLINE |
+                                  S3C2410_LCDCON5_INVVCLK |
+                                  S3C2410_LCDCON5_HWSWP),
+       },
+};
+
+/* todo - put into gpio header */
+
+#define S3C2410_GPCCON_MASK(x) (3 << ((x) * 2))
+#define S3C2410_GPDCON_MASK(x) (3 << ((x) * 2))
+
+static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
+       .displays        = &mini2440_lcd_cfg[0], /* not constant! see init */
+       .num_displays    = 1,
+       .default_display = 0,
+
+       /* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN
+        * and disable the pull down resistors on pins we are using for LCD
+        * data. */
+
+       .gpcup          = (0xf << 1) | (0x3f << 10),
+
+       .gpccon         = (S3C2410_GPC1_VCLK   | S3C2410_GPC2_VLINE |
+                          S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM |
+                          S3C2410_GPC10_VD2   | S3C2410_GPC11_VD3 |
+                          S3C2410_GPC12_VD4   | S3C2410_GPC13_VD5 |
+                          S3C2410_GPC14_VD6   | S3C2410_GPC15_VD7),
+
+       .gpccon_mask    = (S3C2410_GPCCON_MASK(1)  | S3C2410_GPCCON_MASK(2)  |
+                          S3C2410_GPCCON_MASK(3)  | S3C2410_GPCCON_MASK(4)  |
+                          S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) |
+                          S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) |
+                          S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)),
+
+       .gpdup          = (0x3f << 2) | (0x3f << 10),
+
+       .gpdcon         = (S3C2410_GPD2_VD10  | S3C2410_GPD3_VD11 |
+                          S3C2410_GPD4_VD12  | S3C2410_GPD5_VD13 |
+                          S3C2410_GPD6_VD14  | S3C2410_GPD7_VD15 |
+                          S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 |
+                          S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 |
+                          S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23),
+
+       .gpdcon_mask    = (S3C2410_GPDCON_MASK(2)  | S3C2410_GPDCON_MASK(3) |
+                          S3C2410_GPDCON_MASK(4)  | S3C2410_GPDCON_MASK(5) |
+                          S3C2410_GPDCON_MASK(6)  | S3C2410_GPDCON_MASK(7) |
+                          S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)|
+                          S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)|
+                          S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)),
+};
+
+/* MMC/SD  */
+
+static struct s3c24xx_mci_pdata mini2440_mmc_cfg __initdata = {
+   .gpio_detect   = S3C2410_GPG(8),
+   .gpio_wprotect = S3C2410_GPH(8),
+   .set_power     = NULL,
+   .ocr_avail     = MMC_VDD_32_33|MMC_VDD_33_34,
+};
+
+/* NAND Flash on MINI2440 board */
+
+static struct mtd_partition mini2440_default_nand_part[] __initdata = {
+       [0] = {
+               .name   = "u-boot",
+               .size   = SZ_256K,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "u-boot-env",
+               .size   = SZ_128K,
+               .offset = SZ_256K,
+       },
+       [2] = {
+               .name   = "kernel",
+               /* 5 megabytes, for a kernel with no modules
+                * or a uImage with a ramdisk attached */
+               .size   = 0x00500000,
+               .offset = SZ_256K + SZ_128K,
+       },
+       [3] = {
+               .name   = "root",
+               .offset = SZ_256K + SZ_128K + 0x00500000,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct s3c2410_nand_set mini2440_nand_sets[] __initdata = {
+       [0] = {
+               .name           = "nand",
+               .nr_chips       = 1,
+               .nr_partitions  = ARRAY_SIZE(mini2440_default_nand_part),
+               .partitions     = mini2440_default_nand_part,
+               .flash_bbt      = 1, /* we use u-boot to create a BBT */
+       },
+};
+
+static struct s3c2410_platform_nand mini2440_nand_info __initdata = {
+       .tacls          = 0,
+       .twrph0         = 25,
+       .twrph1         = 15,
+       .nr_sets        = ARRAY_SIZE(mini2440_nand_sets),
+       .sets           = mini2440_nand_sets,
+       .ignore_unset_ecc = 1,
+};
+
+/* DM9000AEP 10/100 ethernet controller */
+
+static struct resource mini2440_dm9k_resource[] = {
+       [0] = {
+               .start = MACH_MINI2440_DM9K_BASE,
+               .end   = MACH_MINI2440_DM9K_BASE + 3,
+               .flags = IORESOURCE_MEM
+       },
+       [1] = {
+               .start = MACH_MINI2440_DM9K_BASE + 4,
+               .end   = MACH_MINI2440_DM9K_BASE + 7,
+               .flags = IORESOURCE_MEM
+       },
+       [2] = {
+               .start = IRQ_EINT7,
+               .end   = IRQ_EINT7,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+       }
+};
+
+/*
+ * The DM9000 has no eeprom, and it's MAC address is set by
+ * the bootloader before starting the kernel.
+ */
+static struct dm9000_plat_data mini2440_dm9k_pdata = {
+       .flags          = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
+};
+
+static struct platform_device mini2440_device_eth = {
+       .name           = "dm9000",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(mini2440_dm9k_resource),
+       .resource       = mini2440_dm9k_resource,
+       .dev            = {
+               .platform_data  = &mini2440_dm9k_pdata,
+       },
+};
+
+/*  CON5
+ *     +--+     /-----\
+ *     |  |    |       |
+ *     |  |    |  BAT  |
+ *     |  |     \_____/
+ *     |  |
+ *     |  |  +----+  +----+
+ *     |  |  | K5 |  | K1 |
+ *     |  |  +----+  +----+
+ *     |  |  +----+  +----+
+ *     |  |  | K4 |  | K2 |
+ *     |  |  +----+  +----+
+ *     |  |  +----+  +----+
+ *     |  |  | K6 |  | K3 |
+ *     |  |  +----+  +----+
+ *       .....
+ */
+static struct gpio_keys_button mini2440_buttons[] = {
+       {
+               .gpio           = S3C2410_GPG(0),               /* K1 */
+               .code           = KEY_F1,
+               .desc           = "Button 1",
+               .active_low     = 1,
+       },
+       {
+               .gpio           = S3C2410_GPG(3),               /* K2 */
+               .code           = KEY_F2,
+               .desc           = "Button 2",
+               .active_low     = 1,
+       },
+       {
+               .gpio           = S3C2410_GPG(5),               /* K3 */
+               .code           = KEY_F3,
+               .desc           = "Button 3",
+               .active_low     = 1,
+       },
+       {
+               .gpio           = S3C2410_GPG(6),               /* K4 */
+               .code           = KEY_POWER,
+               .desc           = "Power",
+               .active_low     = 1,
+       },
+       {
+               .gpio           = S3C2410_GPG(7),               /* K5 */
+               .code           = KEY_F5,
+               .desc           = "Button 5",
+               .active_low     = 1,
+       },
+#if 0
+       /* this pin is also known as TCLK1 and seems to already
+        * marked as "in use" somehow in the kernel -- possibly wrongly */
+       {
+               .gpio           = S3C2410_GPG(11),      /* K6 */
+               .code           = KEY_F6,
+               .desc           = "Button 6",
+               .active_low     = 1,
+       },
+#endif
+};
+
+static struct gpio_keys_platform_data mini2440_button_data = {
+       .buttons        = mini2440_buttons,
+       .nbuttons       = ARRAY_SIZE(mini2440_buttons),
+};
+
+static struct platform_device mini2440_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &mini2440_button_data,
+       }
+};
+
+/* LEDS */
+
+static struct s3c24xx_led_platdata mini2440_led1_pdata = {
+       .name           = "led1",
+       .gpio           = S3C2410_GPB(5),
+       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+       .def_trigger    = "heartbeat",
+};
+
+static struct s3c24xx_led_platdata mini2440_led2_pdata = {
+       .name           = "led2",
+       .gpio           = S3C2410_GPB(6),
+       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+       .def_trigger    = "nand-disk",
+};
+
+static struct s3c24xx_led_platdata mini2440_led3_pdata = {
+       .name           = "led3",
+       .gpio           = S3C2410_GPB(7),
+       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+       .def_trigger    = "mmc0",
+};
+
+static struct s3c24xx_led_platdata mini2440_led4_pdata = {
+       .name           = "led4",
+       .gpio           = S3C2410_GPB(8),
+       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+       .def_trigger    = "",
+};
+
+static struct s3c24xx_led_platdata mini2440_led_backlight_pdata = {
+       .name           = "backlight",
+       .gpio           = S3C2410_GPG(4),
+       .def_trigger    = "backlight",
+};
+
+static struct platform_device mini2440_led1 = {
+       .name           = "s3c24xx_led",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &mini2440_led1_pdata,
+       },
+};
+
+static struct platform_device mini2440_led2 = {
+       .name           = "s3c24xx_led",
+       .id             = 2,
+       .dev            = {
+               .platform_data  = &mini2440_led2_pdata,
+       },
+};
+
+static struct platform_device mini2440_led3 = {
+       .name           = "s3c24xx_led",
+       .id             = 3,
+       .dev            = {
+               .platform_data  = &mini2440_led3_pdata,
+       },
+};
+
+static struct platform_device mini2440_led4 = {
+       .name           = "s3c24xx_led",
+       .id             = 4,
+       .dev            = {
+               .platform_data  = &mini2440_led4_pdata,
+       },
+};
+
+static struct platform_device mini2440_led_backlight = {
+       .name           = "s3c24xx_led",
+       .id             = 5,
+       .dev            = {
+               .platform_data  = &mini2440_led_backlight_pdata,
+       },
+};
+
+/* AUDIO */
+
+static struct s3c24xx_uda134x_platform_data mini2440_audio_pins = {
+       .l3_clk = S3C2410_GPB(4),
+       .l3_mode = S3C2410_GPB(2),
+       .l3_data = S3C2410_GPB(3),
+       .model = UDA134X_UDA1341
+};
+
+static struct platform_device mini2440_audio = {
+       .name           = "s3c24xx_uda134x",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &mini2440_audio_pins,
+       },
+};
+
+/*
+ * I2C devices
+ */
+static struct at24_platform_data at24c08 = {
+       .byte_len       = SZ_8K / 8,
+       .page_size      = 16,
+};
+
+static struct i2c_board_info mini2440_i2c_devs[] __initdata = {
+       {
+               I2C_BOARD_INFO("24c08", 0x50),
+               .platform_data = &at24c08,
+       },
+};
+
+static struct platform_device uda1340_codec = {
+               .name = "uda134x-codec",
+               .id = -1,
+};
+
+static struct platform_device *mini2440_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_rtc,
+       &s3c_device_usbgadget,
+       &mini2440_device_eth,
+       &mini2440_led1,
+       &mini2440_led2,
+       &mini2440_led3,
+       &mini2440_led4,
+       &mini2440_button_device,
+       &s3c_device_nand,
+       &s3c_device_sdi,
+       &s3c_device_iis,
+       &uda1340_codec,
+       &mini2440_audio,
+       &samsung_asoc_dma,
+};
+
+static void __init mini2440_map_io(void)
+{
+       s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs));
+}
+
+/*
+ * mini2440_features string
+ *
+ * t = Touchscreen present
+ * b = backlight control
+ * c = camera [TODO]
+ * 0-9 LCD configuration
+ *
+ */
+static char mini2440_features_str[12] __initdata = "0tb";
+
+static int __init mini2440_features_setup(char *str)
+{
+       if (str)
+               strlcpy(mini2440_features_str, str, sizeof(mini2440_features_str));
+       return 1;
+}
+
+__setup("mini2440=", mini2440_features_setup);
+
+#define FEATURE_SCREEN (1 << 0)
+#define FEATURE_BACKLIGHT (1 << 1)
+#define FEATURE_TOUCH (1 << 2)
+#define FEATURE_CAMERA (1 << 3)
+
+struct mini2440_features_t {
+       int count;
+       int done;
+       int lcd_index;
+       struct platform_device *optional[8];
+};
+
+static void __init mini2440_parse_features(
+               struct mini2440_features_t * features,
+               const char * features_str )
+{
+       const char * fp = features_str;
+
+       features->count = 0;
+       features->done = 0;
+       features->lcd_index = -1;
+
+       while (*fp) {
+               char f = *fp++;
+
+               switch (f) {
+               case '0'...'9': /* tft screen */
+                       if (features->done & FEATURE_SCREEN) {
+                               printk(KERN_INFO "MINI2440: '%c' ignored, "
+                                       "screen type already set\n", f);
+                       } else {
+                               int li = f - '0';
+                               if (li >= ARRAY_SIZE(mini2440_lcd_cfg))
+                                       printk(KERN_INFO "MINI2440: "
+                                               "'%c' out of range LCD mode\n", f);
+                               else {
+                                       features->optional[features->count++] =
+                                                       &s3c_device_lcd;
+                                       features->lcd_index = li;
+                               }
+                       }
+                       features->done |= FEATURE_SCREEN;
+                       break;
+               case 'b':
+                       if (features->done & FEATURE_BACKLIGHT)
+                               printk(KERN_INFO "MINI2440: '%c' ignored, "
+                                       "backlight already set\n", f);
+                       else {
+                               features->optional[features->count++] =
+                                               &mini2440_led_backlight;
+                       }
+                       features->done |= FEATURE_BACKLIGHT;
+                       break;
+               case 't':
+                       printk(KERN_INFO "MINI2440: '%c' ignored, "
+                               "touchscreen not compiled in\n", f);
+                       break;
+               case 'c':
+                       if (features->done & FEATURE_CAMERA)
+                               printk(KERN_INFO "MINI2440: '%c' ignored, "
+                                       "camera already registered\n", f);
+                       else
+                               features->optional[features->count++] =
+                                       &s3c_device_camif;
+                       features->done |= FEATURE_CAMERA;
+                       break;
+               }
+       }
+}
+
+static void __init mini2440_init(void)
+{
+       struct mini2440_features_t features = { 0 };
+       int i;
+
+       printk(KERN_INFO "MINI2440: Option string mini2440=%s\n",
+                       mini2440_features_str);
+
+       /* Parse the feature string */
+       mini2440_parse_features(&features, mini2440_features_str);
+
+       /* turn LCD on */
+       s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);
+
+       /* Turn the backlight early on */
+       WARN_ON(gpio_request(S3C2410_GPG(4), "backlight"));
+       gpio_direction_output(S3C2410_GPG(4), 1);
+
+       /* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */
+       s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);
+       s3c2410_gpio_setpin(S3C2410_GPB(1), 0);
+       s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPIO_INPUT);
+
+       /* mark the key as input, without pullups (there is one on the board) */
+       for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {
+               s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP);
+               s3c_gpio_cfgpin(mini2440_buttons[i].gpio, S3C2410_GPIO_INPUT);
+       }
+       if (features.lcd_index != -1) {
+               int li;
+
+               mini2440_fb_info.displays =
+                       &mini2440_lcd_cfg[features.lcd_index];
+
+               printk(KERN_INFO "MINI2440: LCD");
+               for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++)
+                       if (li == features.lcd_index)
+                               printk(" [%d:%dx%d]", li,
+                                       mini2440_lcd_cfg[li].width,
+                                       mini2440_lcd_cfg[li].height);
+                       else
+                               printk(" %d:%dx%d", li,
+                                       mini2440_lcd_cfg[li].width,
+                                       mini2440_lcd_cfg[li].height);
+               printk("\n");
+               s3c24xx_fb_set_platdata(&mini2440_fb_info);
+       }
+
+       s3c24xx_udc_set_platdata(&mini2440_udc_cfg);
+       s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);
+       s3c_nand_set_platdata(&mini2440_nand_info);
+       s3c_i2c0_set_platdata(NULL);
+
+       i2c_register_board_info(0, mini2440_i2c_devs,
+                               ARRAY_SIZE(mini2440_i2c_devs));
+
+       platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
+
+       if (features.count)     /* the optional features */
+               platform_add_devices(features.optional, features.count);
+
+}
+
+
+MACHINE_START(MINI2440, "MINI2440")
+       /* Maintainer: Michel Pollet <buserror@gmail.com> */
+       .atag_offset    = 0x100,
+       .map_io         = mini2440_map_io,
+       .init_machine   = mini2440_init,
+       .init_irq       = s3c24xx_init_irq,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-n30.c b/arch/arm/mach-s3c24xx/mach-n30.c
new file mode 100644 (file)
index 0000000..383d00c
--- /dev/null
@@ -0,0 +1,608 @@
+/* Machine specific code for the Acer n30, Acer N35, Navman PiN 570,
+ * Yakumo AlphaX and Airis NC05 PDAs.
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Copyright (c) 2005-2008 Christer Weinigel <christer@weinigel.se>
+ *
+ * There is a wiki with more information about the n30 port at
+ * http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
+ *
+ * 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/types.h>
+
+#include <linux/gpio_keys.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/fb.h>
+#include <mach/leds-gpio.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-lcd.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+
+#include <plat/iic.h>
+#include <plat/regs-serial.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/mci.h>
+#include <plat/s3c2410.h>
+#include <plat/udc.h>
+
+#include "common.h"
+
+static struct map_desc n30_iodesc[] __initdata = {
+       /* nothing here yet */
+};
+
+static struct s3c2410_uartcfg n30_uartcfgs[] = {
+       /* Normal serial port */
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x2c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       /* IR port */
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .uart_flags  = UPF_CONS_FLOW,
+               .ucon        = 0x2c5,
+               .ulcon       = 0x43,
+               .ufcon       = 0x51,
+       },
+       /* On the N30 the bluetooth controller is connected here.
+        * On the N35 and variants the GPS receiver is connected here. */
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = 0x2c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+};
+
+static struct s3c2410_udc_mach_info n30_udc_cfg __initdata = {
+       .vbus_pin               = S3C2410_GPG(1),
+       .vbus_pin_inverted      = 0,
+       .pullup_pin             = S3C2410_GPB(3),
+};
+
+static struct gpio_keys_button n30_buttons[] = {
+       {
+               .gpio           = S3C2410_GPF(0),
+               .code           = KEY_POWER,
+               .desc           = "Power",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPG(9),
+               .code           = KEY_UP,
+               .desc           = "Thumbwheel Up",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPG(8),
+               .code           = KEY_DOWN,
+               .desc           = "Thumbwheel Down",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPG(7),
+               .code           = KEY_ENTER,
+               .desc           = "Thumbwheel Press",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPF(7),
+               .code           = KEY_HOMEPAGE,
+               .desc           = "Home",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPF(6),
+               .code           = KEY_CALENDAR,
+               .desc           = "Calendar",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPF(5),
+               .code           = KEY_ADDRESSBOOK,
+               .desc           = "Contacts",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPF(4),
+               .code           = KEY_MAIL,
+               .desc           = "Mail",
+               .active_low     = 0,
+       },
+};
+
+static struct gpio_keys_platform_data n30_button_data = {
+       .buttons        = n30_buttons,
+       .nbuttons       = ARRAY_SIZE(n30_buttons),
+};
+
+static struct platform_device n30_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &n30_button_data,
+       }
+};
+
+static struct gpio_keys_button n35_buttons[] = {
+       {
+               .gpio           = S3C2410_GPF(0),
+               .code           = KEY_POWER,
+               .type           = EV_PWR,
+               .desc           = "Power",
+               .active_low     = 0,
+               .wakeup         = 1,
+       },
+       {
+               .gpio           = S3C2410_GPG(9),
+               .code           = KEY_UP,
+               .desc           = "Joystick Up",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPG(8),
+               .code           = KEY_DOWN,
+               .desc           = "Joystick Down",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPG(6),
+               .code           = KEY_DOWN,
+               .desc           = "Joystick Left",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPG(5),
+               .code           = KEY_DOWN,
+               .desc           = "Joystick Right",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPG(7),
+               .code           = KEY_ENTER,
+               .desc           = "Joystick Press",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPF(7),
+               .code           = KEY_HOMEPAGE,
+               .desc           = "Home",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPF(6),
+               .code           = KEY_CALENDAR,
+               .desc           = "Calendar",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPF(5),
+               .code           = KEY_ADDRESSBOOK,
+               .desc           = "Contacts",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPF(4),
+               .code           = KEY_MAIL,
+               .desc           = "Mail",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPF(3),
+               .code           = SW_RADIO,
+               .desc           = "GPS Antenna",
+               .active_low     = 0,
+       },
+       {
+               .gpio           = S3C2410_GPG(2),
+               .code           = SW_HEADPHONE_INSERT,
+               .desc           = "Headphone",
+               .active_low     = 0,
+       },
+};
+
+static struct gpio_keys_platform_data n35_button_data = {
+       .buttons        = n35_buttons,
+       .nbuttons       = ARRAY_SIZE(n35_buttons),
+};
+
+static struct platform_device n35_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &n35_button_data,
+       }
+};
+
+/* This is the bluetooth LED on the device. */
+static struct s3c24xx_led_platdata n30_blue_led_pdata = {
+       .name           = "blue_led",
+       .gpio           = S3C2410_GPG(6),
+       .def_trigger    = "",
+};
+
+/* This is the blue LED on the device. Originally used to indicate GPS activity
+ * by flashing. */
+static struct s3c24xx_led_platdata n35_blue_led_pdata = {
+       .name           = "blue_led",
+       .gpio           = S3C2410_GPD(8),
+       .def_trigger    = "",
+};
+
+/* This LED is driven by the battery microcontroller, and is blinking
+ * red, blinking green or solid green when the battery is low,
+ * charging or full respectively.  By driving GPD9 low, it's possible
+ * to force the LED to blink red, so call that warning LED.  */
+static struct s3c24xx_led_platdata n30_warning_led_pdata = {
+       .name           = "warning_led",
+       .flags          = S3C24XX_LEDF_ACTLOW,
+       .gpio           = S3C2410_GPD(9),
+       .def_trigger    = "",
+};
+
+static struct s3c24xx_led_platdata n35_warning_led_pdata = {
+       .name           = "warning_led",
+       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+       .gpio           = S3C2410_GPD(9),
+       .def_trigger    = "",
+};
+
+static struct platform_device n30_blue_led = {
+       .name           = "s3c24xx_led",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &n30_blue_led_pdata,
+       },
+};
+
+static struct platform_device n35_blue_led = {
+       .name           = "s3c24xx_led",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &n35_blue_led_pdata,
+       },
+};
+
+static struct platform_device n30_warning_led = {
+       .name           = "s3c24xx_led",
+       .id             = 2,
+       .dev            = {
+               .platform_data  = &n30_warning_led_pdata,
+       },
+};
+
+static struct platform_device n35_warning_led = {
+       .name           = "s3c24xx_led",
+       .id             = 2,
+       .dev            = {
+               .platform_data  = &n35_warning_led_pdata,
+       },
+};
+
+static struct s3c2410fb_display n30_display __initdata = {
+       .type           = S3C2410_LCDCON1_TFT,
+       .width          = 240,
+       .height         = 320,
+       .pixclock       = 170000,
+
+       .xres           = 240,
+       .yres           = 320,
+       .bpp            = 16,
+       .left_margin    = 3,
+       .right_margin   = 40,
+       .hsync_len      = 40,
+       .upper_margin   = 2,
+       .lower_margin   = 3,
+       .vsync_len      = 2,
+
+       .lcdcon5 = S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME,
+};
+
+static struct s3c2410fb_mach_info n30_fb_info __initdata = {
+       .displays       = &n30_display,
+       .num_displays   = 1,
+       .default_display = 0,
+       .lpcsel         = 0x06,
+};
+
+static void n30_sdi_set_power(unsigned char power_mode, unsigned short vdd)
+{
+       switch (power_mode) {
+       case MMC_POWER_ON:
+       case MMC_POWER_UP:
+               gpio_set_value(S3C2410_GPG(4), 1);
+               break;
+       case MMC_POWER_OFF:
+       default:
+               gpio_set_value(S3C2410_GPG(4), 0);
+               break;
+       }
+}
+
+static struct s3c24xx_mci_pdata n30_mci_cfg __initdata = {
+       .gpio_detect    = S3C2410_GPF(1),
+       .gpio_wprotect  = S3C2410_GPG(10),
+       .ocr_avail      = MMC_VDD_32_33,
+       .set_power      = n30_sdi_set_power,
+};
+
+static struct platform_device *n30_devices[] __initdata = {
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+       &s3c_device_ohci,
+       &s3c_device_rtc,
+       &s3c_device_usbgadget,
+       &s3c_device_sdi,
+       &n30_button_device,
+       &n30_blue_led,
+       &n30_warning_led,
+};
+
+static struct platform_device *n35_devices[] __initdata = {
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+       &s3c_device_rtc,
+       &s3c_device_usbgadget,
+       &s3c_device_sdi,
+       &n35_button_device,
+       &n35_blue_led,
+       &n35_warning_led,
+};
+
+static struct s3c2410_platform_i2c __initdata n30_i2ccfg = {
+       .flags          = 0,
+       .slave_addr     = 0x10,
+       .frequency      = 10*1000,
+};
+
+/* Lots of hardcoded stuff, but it sets up the hardware in a useful
+ * state so that we can boot Linux directly from flash. */
+static void __init n30_hwinit(void)
+{
+       /* GPA0-11 special functions -- unknown what they do
+        * GPA12 N30 special function -- unknown what it does
+        *       N35/PiN output -- unknown what it does
+        *
+        * A12 is nGCS1 on the N30 and an output on the N35/PiN.  I
+        * don't think it does anything useful on the N30, so I ought
+        * to make it an output there too since it always driven to 0
+        * as far as I can tell. */
+       if (machine_is_n30())
+               __raw_writel(0x007fffff, S3C2410_GPACON);
+       if (machine_is_n35())
+               __raw_writel(0x007fefff, S3C2410_GPACON);
+       __raw_writel(0x00000000, S3C2410_GPADAT);
+
+       /* GPB0 TOUT0 backlight level
+        * GPB1 output 1=backlight on
+        * GPB2 output IrDA enable 0=transceiver enabled, 1=disabled
+        * GPB3 output USB D+ pull up 0=disabled, 1=enabled
+        * GPB4 N30 output -- unknown function
+        *      N30/PiN GPS control 0=GPS enabled, 1=GPS disabled
+        * GPB5 output -- unknown function
+        * GPB6 input -- unknown function
+        * GPB7 output -- unknown function
+        * GPB8 output -- probably LCD driver enable
+        * GPB9 output -- probably LCD VSYNC driver enable
+        * GPB10 output -- probably LCD HSYNC driver enable
+        */
+       __raw_writel(0x00154556, S3C2410_GPBCON);
+       __raw_writel(0x00000750, S3C2410_GPBDAT);
+       __raw_writel(0x00000073, S3C2410_GPBUP);
+
+       /* GPC0 input RS232 DCD/DSR/RI
+        * GPC1 LCD
+        * GPC2 output RS232 DTR?
+        * GPC3 input RS232 DCD/DSR/RI
+        * GPC4 LCD
+        * GPC5 output 0=NAND write enabled, 1=NAND write protect
+        * GPC6 input -- unknown function
+        * GPC7 input charger status 0=charger connected
+        *      this input can be triggered by power on the USB device
+        *      port too, but will go back to disconnected soon after.
+        * GPC8 N30/N35 output -- unknown function, always driven to 1
+        *      PiN input -- unknown function, always read as 1
+        *      Make it an input with a pull up for all models.
+        * GPC9-15 LCD
+        */
+       __raw_writel(0xaaa80618, S3C2410_GPCCON);
+       __raw_writel(0x0000014c, S3C2410_GPCDAT);
+       __raw_writel(0x0000fef2, S3C2410_GPCUP);
+
+       /* GPD0 input -- unknown function
+        * GPD1-D7 LCD
+        * GPD8 N30 output -- unknown function
+        *      N35/PiN output 1=GPS LED on
+        * GPD9 output 0=power led blinks red, 1=normal power led function
+        * GPD10 output -- unknown function
+        * GPD11-15 LCD drivers
+        */
+       __raw_writel(0xaa95aaa4, S3C2410_GPDCON);
+       __raw_writel(0x00000601, S3C2410_GPDDAT);
+       __raw_writel(0x0000fbfe, S3C2410_GPDUP);
+
+       /* GPE0-4 I2S audio bus
+        * GPE5-10 SD/MMC bus
+        * E11-13 outputs -- unknown function, probably power management
+        * E14-15 I2C bus connected to the battery controller
+        */
+       __raw_writel(0xa56aaaaa, S3C2410_GPECON);
+       __raw_writel(0x0000efc5, S3C2410_GPEDAT);
+       __raw_writel(0x0000f81f, S3C2410_GPEUP);
+
+       /* GPF0  input 0=power button pressed
+        * GPF1  input SD/MMC switch 0=card present
+        * GPF2  N30 1=reset button pressed (inverted compared to the rest)
+        *       N35/PiN 0=reset button pressed
+        * GPF3  N30/PiN input -- unknown function
+        *       N35 input GPS antenna position, 0=antenna closed, 1=open
+        * GPF4  input 0=button 4 pressed
+        * GPF5  input 0=button 3 pressed
+        * GPF6  input 0=button 2 pressed
+        * GPF7  input 0=button 1 pressed
+        */
+       __raw_writel(0x0000aaaa, S3C2410_GPFCON);
+       __raw_writel(0x00000000, S3C2410_GPFDAT);
+       __raw_writel(0x000000ff, S3C2410_GPFUP);
+
+       /* GPG0  input RS232 DCD/DSR/RI
+        * GPG1  input 1=USB gadget port has power from a host
+        * GPG2  N30 input -- unknown function
+        *       N35/PiN input 0=headphones plugged in, 1=not plugged in
+        * GPG3  N30 output -- unknown function
+        *       N35/PiN input with unknown function
+        * GPG4  N30 output 0=MMC enabled, 1=MMC disabled
+        * GPG5  N30 output 0=BlueTooth chip disabled, 1=enabled
+        *       N35/PiN input joystick right
+        * GPG6  N30 output 0=blue led on, 1=off
+        *       N35/PiN input joystick left
+        * GPG7  input 0=thumbwheel pressed
+        * GPG8  input 0=thumbwheel down
+        * GPG9  input 0=thumbwheel up
+        * GPG10 input SD/MMC write protect switch
+        * GPG11 N30 input -- unknown function
+        *       N35 output 0=GPS antenna powered, 1=not powered
+        *       PiN output -- unknown function
+        * GPG12-15 touch screen functions
+        *
+        * The pullups differ between the models, so enable all
+        * pullups that are enabled on any of the models.
+        */
+       if (machine_is_n30())
+               __raw_writel(0xff0a956a, S3C2410_GPGCON);
+       if (machine_is_n35())
+               __raw_writel(0xff4aa92a, S3C2410_GPGCON);
+       __raw_writel(0x0000e800, S3C2410_GPGDAT);
+       __raw_writel(0x0000f86f, S3C2410_GPGUP);
+
+       /* GPH0/1/2/3 RS232 serial port
+        * GPH4/5 IrDA serial port
+        * GPH6/7  N30 BlueTooth serial port
+        *         N35/PiN GPS receiver
+        * GPH8 input -- unknown function
+        * GPH9 CLKOUT0 HCLK -- unknown use
+        * GPH10 CLKOUT1 FCLK -- unknown use
+        *
+        * The pull ups for H6/H7 are enabled on N30 but not on the
+        * N35/PiN.  I suppose is useful for a budget model of the N30
+        * with no bluetooh.  It doesn't hurt to have the pull ups
+        * enabled on the N35, so leave them enabled for all models.
+        */
+       __raw_writel(0x0028aaaa, S3C2410_GPHCON);
+       __raw_writel(0x000005ef, S3C2410_GPHDAT);
+       __raw_writel(0x0000063f, S3C2410_GPHUP);
+}
+
+static void __init n30_map_io(void)
+{
+       s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
+       n30_hwinit();
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
+}
+
+/* GPB3 is the line that controls the pull-up for the USB D+ line */
+
+static void __init n30_init(void)
+{
+       WARN_ON(gpio_request(S3C2410_GPG(4), "mmc power"));
+
+       s3c24xx_fb_set_platdata(&n30_fb_info);
+       s3c24xx_udc_set_platdata(&n30_udc_cfg);
+       s3c24xx_mci_set_platdata(&n30_mci_cfg);
+       s3c_i2c0_set_platdata(&n30_i2ccfg);
+
+       /* Turn off suspend on both USB ports, and switch the
+        * selectable USB port to USB device mode. */
+
+       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+                             S3C2410_MISCCR_USBSUSPND0 |
+                             S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+       if (machine_is_n30()) {
+               /* Turn off suspend on both USB ports, and switch the
+                * selectable USB port to USB device mode. */
+               s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+                                     S3C2410_MISCCR_USBSUSPND0 |
+                                     S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+               platform_add_devices(n30_devices, ARRAY_SIZE(n30_devices));
+       }
+
+       if (machine_is_n35()) {
+               /* Turn off suspend and switch the selectable USB port
+                * to USB device mode.  Turn on suspend for the host
+                * port since it is not connected on the N35.
+                *
+                * Actually, the host port is available at some pads
+                * on the back of the device, so it would actually be
+                * possible to add a USB device inside the N35 if you
+                * are willing to do some hardware modifications. */
+               s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+                                     S3C2410_MISCCR_USBSUSPND0 |
+                                     S3C2410_MISCCR_USBSUSPND1,
+                                     S3C2410_MISCCR_USBSUSPND0);
+
+               platform_add_devices(n35_devices, ARRAY_SIZE(n35_devices));
+       }
+}
+
+MACHINE_START(N30, "Acer-N30")
+       /* Maintainer: Christer Weinigel <christer@weinigel.se>,
+                               Ben Dooks <ben-linux@fluff.org>
+       */
+       .atag_offset    = 0x100,
+       .timer          = &s3c24xx_timer,
+       .init_machine   = n30_init,
+       .init_irq       = s3c24xx_init_irq,
+       .map_io         = n30_map_io,
+       .restart        = s3c2410_restart,
+MACHINE_END
+
+MACHINE_START(N35, "Acer-N35")
+       /* Maintainer: Christer Weinigel <christer@weinigel.se>
+       */
+       .atag_offset    = 0x100,
+       .timer          = &s3c24xx_timer,
+       .init_machine   = n30_init,
+       .init_irq       = s3c24xx_init_irq,
+       .map_io         = n30_map_io,
+       .restart        = s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-nexcoder.c b/arch/arm/mach-s3c24xx/mach-nexcoder.c
new file mode 100644 (file)
index 0000000..5198e3e
--- /dev/null
@@ -0,0 +1,162 @@
+/* linux/arch/arm/mach-s3c2440/mach-nexcoder.c
+ *
+ * Copyright (c) 2004 Nex Vision
+ *   Guillaume GOURAT <guillaume.gourat@nexvision.tv>
+ *
+ * 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.
+ *
+ * Modifications:
+ *     15-10-2004 GG  Created initial version
+ *     12-03-2005 BJD Updated for release
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/string.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <linux/mtd/map.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/setup.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+//#include <asm/debug-ll.h>
+#include <mach/regs-gpio.h>
+#include <plat/regs-serial.h>
+#include <plat/iic.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/s3c2410.h>
+#include <plat/s3c244x.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#include "common.h"
+
+static struct map_desc nexcoder_iodesc[] __initdata = {
+       /* nothing here yet */
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG12 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg nexcoder_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+/* NOR Flash on NexVision NexCoder 2440 board */
+
+static struct resource nexcoder_nor_resource[] = {
+       [0] = {
+               .start = S3C2410_CS0,
+               .end   = S3C2410_CS0 + (8*1024*1024) - 1,
+               .flags = IORESOURCE_MEM,
+       }
+};
+
+static struct map_info nexcoder_nor_map = {
+       .bankwidth = 2,
+};
+
+static struct platform_device nexcoder_device_nor = {
+       .name           = "mtd-flash",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(nexcoder_nor_resource),
+       .resource       = nexcoder_nor_resource,
+       .dev =
+       {
+               .platform_data = &nexcoder_nor_map,
+       }
+};
+
+/* Standard Nexcoder devices */
+
+static struct platform_device *nexcoder_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+       &s3c_device_rtc,
+       &s3c_device_camif,
+       &s3c_device_spi0,
+       &s3c_device_spi1,
+       &nexcoder_device_nor,
+};
+
+static void __init nexcoder_sensorboard_init(void)
+{
+       // Initialize SCCB bus
+       s3c2410_gpio_setpin(S3C2410_GPE(14), 1); // IICSCL
+       s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPE(15), 1); // IICSDA
+       s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPIO_OUTPUT);
+
+       // Power up the sensor board
+       s3c2410_gpio_setpin(S3C2410_GPF(1), 1);
+       s3c_gpio_cfgpin(S3C2410_GPF(1), S3C2410_GPIO_OUTPUT); // CAM_GPIO7 => nLDO_PWRDN
+       s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
+       s3c_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT); // CAM_GPIO6 => CAM_PWRDN
+}
+
+static void __init nexcoder_map_io(void)
+{
+       s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(nexcoder_uartcfgs, ARRAY_SIZE(nexcoder_uartcfgs));
+
+       nexcoder_sensorboard_init();
+}
+
+static void __init nexcoder_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+       platform_add_devices(nexcoder_devices, ARRAY_SIZE(nexcoder_devices));
+};
+
+MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
+       /* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
+       .atag_offset    = 0x100,
+       .map_io         = nexcoder_map_io,
+       .init_machine   = nexcoder_init,
+       .init_irq       = s3c24xx_init_irq,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-osiris-dvs.c b/arch/arm/mach-s3c24xx/mach-osiris-dvs.c
new file mode 100644 (file)
index 0000000..ad2792d
--- /dev/null
@@ -0,0 +1,194 @@
+/* linux/arch/arm/mach-s3c2440/mach-osiris-dvs.c
+ *
+ * Copyright (c) 2009 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec Osiris Dynamic Voltage Scaling support.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/gpio.h>
+
+#include <linux/i2c/tps65010.h>
+
+#include <plat/cpu-freq.h>
+
+#define OSIRIS_GPIO_DVS        S3C2410_GPB(5)
+
+static bool dvs_en;
+
+static void osiris_dvs_tps_setdvs(bool on)
+{
+       unsigned vregs1 = 0, vdcdc2 = 0;
+
+       if (!on) {
+               vdcdc2 = TPS_VCORE_DISCH | TPS_LP_COREOFF;
+               vregs1 = TPS_LDO1_OFF;  /* turn off in low-power mode */
+       }
+
+       dvs_en = on;
+       vdcdc2 |= TPS_VCORE_1_3V | TPS_VCORE_LP_1_0V;
+       vregs1 |= TPS_LDO2_ENABLE | TPS_LDO1_ENABLE;
+
+       tps65010_config_vregs1(vregs1);
+       tps65010_config_vdcdc2(vdcdc2);
+}
+
+static bool is_dvs(struct s3c_freq *f)
+{
+       /* at the moment, we assume ARMCLK = HCLK => DVS */
+       return f->armclk == f->hclk;
+}
+
+/* keep track of current state */
+static bool cur_dvs = false;
+
+static int osiris_dvs_notify(struct notifier_block *nb,
+                             unsigned long val, void *data)
+{
+       struct cpufreq_freqs *cf = data;
+       struct s3c_cpufreq_freqs *freqs = to_s3c_cpufreq(cf);
+       bool old_dvs = is_dvs(&freqs->old);
+       bool new_dvs = is_dvs(&freqs->new);
+       int ret = 0;
+
+       if (!dvs_en)
+               return 0;
+
+       printk(KERN_DEBUG "%s: old %ld,%ld new %ld,%ld\n", __func__,
+              freqs->old.armclk, freqs->old.hclk,
+              freqs->new.armclk, freqs->new.hclk);
+
+       switch (val) {
+       case CPUFREQ_PRECHANGE:
+               if (old_dvs & !new_dvs ||
+                   cur_dvs & !new_dvs) {
+                       pr_debug("%s: exiting dvs\n", __func__);
+                       cur_dvs = false;
+                       gpio_set_value(OSIRIS_GPIO_DVS, 1);
+               }
+               break;
+       case CPUFREQ_POSTCHANGE:
+               if (!old_dvs & new_dvs ||
+                   !cur_dvs & new_dvs) {
+                       pr_debug("entering dvs\n");
+                       cur_dvs = true;
+                       gpio_set_value(OSIRIS_GPIO_DVS, 0);
+               }
+               break;
+       }
+
+       return ret;
+}
+
+static struct notifier_block osiris_dvs_nb = {
+       .notifier_call  = osiris_dvs_notify,
+};
+
+static int __devinit osiris_dvs_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       dev_info(&pdev->dev, "initialising\n");
+
+       ret = gpio_request(OSIRIS_GPIO_DVS, "osiris-dvs");
+       if (ret) {
+               dev_err(&pdev->dev, "cannot claim gpio\n");
+               goto err_nogpio;
+       }
+
+       /* start with dvs disabled */
+       gpio_direction_output(OSIRIS_GPIO_DVS, 1);
+
+       ret = cpufreq_register_notifier(&osiris_dvs_nb,
+                                       CPUFREQ_TRANSITION_NOTIFIER);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register with cpufreq\n");
+               goto err_nofreq;
+       }
+
+       osiris_dvs_tps_setdvs(true);
+
+       return 0;
+
+err_nofreq:
+       gpio_free(OSIRIS_GPIO_DVS);
+
+err_nogpio:
+       return ret;
+}
+
+static int __devexit osiris_dvs_remove(struct platform_device *pdev)
+{
+       dev_info(&pdev->dev, "exiting\n");
+
+       /* disable any current dvs */
+       gpio_set_value(OSIRIS_GPIO_DVS, 1);
+       osiris_dvs_tps_setdvs(false);
+
+       cpufreq_unregister_notifier(&osiris_dvs_nb,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+
+       gpio_free(OSIRIS_GPIO_DVS);
+
+       return 0;
+}
+
+/* the CONFIG_PM block is so small, it isn't worth actaully compiling it
+ * out if the configuration isn't set. */
+
+static int osiris_dvs_suspend(struct device *dev)
+{
+       gpio_set_value(OSIRIS_GPIO_DVS, 1);
+       osiris_dvs_tps_setdvs(false);
+       cur_dvs = false;
+
+       return 0;
+}
+
+static int osiris_dvs_resume(struct device *dev)
+{
+       osiris_dvs_tps_setdvs(true);
+       return 0;
+}
+
+static const struct dev_pm_ops osiris_dvs_pm = {
+       .suspend        = osiris_dvs_suspend,
+       .resume         = osiris_dvs_resume,
+};
+
+static struct platform_driver osiris_dvs_driver = {
+       .probe          = osiris_dvs_probe,
+       .remove         = __devexit_p(osiris_dvs_remove),
+       .driver         = {
+               .name   = "osiris-dvs",
+               .owner  = THIS_MODULE,
+               .pm     = &osiris_dvs_pm,
+       },
+};
+
+static int __init osiris_dvs_init(void)
+{
+       return platform_driver_register(&osiris_dvs_driver);
+}
+
+static void __exit osiris_dvs_exit(void)
+{
+       platform_driver_unregister(&osiris_dvs_driver);
+}
+
+module_init(osiris_dvs_init);
+module_exit(osiris_dvs_exit);
+
+MODULE_DESCRIPTION("Simtec OSIRIS DVS support");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:osiris-dvs");
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
new file mode 100644 (file)
index 0000000..c5daeb6
--- /dev/null
@@ -0,0 +1,440 @@
+/* linux/arch/arm/mach-s3c2440/mach-osiris.c
+ *
+ * Copyright (c) 2005-2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+
+#include <linux/i2c/tps65010.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/osiris-map.h>
+#include <mach/osiris-cpld.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-mem.h>
+#include <mach/regs-lcd.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#include "common.h"
+
+/* onboard perihperal map */
+
+static struct map_desc osiris_iodesc[] __initdata = {
+  /* ISA IO areas (may be over-written later) */
+
+  {
+         .virtual      = (u32)S3C24XX_VA_ISA_BYTE,
+         .pfn          = __phys_to_pfn(S3C2410_CS5),
+         .length       = SZ_16M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)S3C24XX_VA_ISA_WORD,
+         .pfn          = __phys_to_pfn(S3C2410_CS5),
+         .length       = SZ_16M,
+         .type         = MT_DEVICE,
+  },
+
+  /* CPLD control registers */
+
+  {
+         .virtual      = (u32)OSIRIS_VA_CTRL0,
+         .pfn          = __phys_to_pfn(OSIRIS_PA_CTRL0),
+         .length       = SZ_16K,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)OSIRIS_VA_CTRL1,
+         .pfn          = __phys_to_pfn(OSIRIS_PA_CTRL1),
+         .length       = SZ_16K,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)OSIRIS_VA_CTRL2,
+         .pfn          = __phys_to_pfn(OSIRIS_PA_CTRL2),
+         .length       = SZ_16K,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)OSIRIS_VA_IDREG,
+         .pfn          = __phys_to_pfn(OSIRIS_PA_IDREG),
+         .length       = SZ_16K,
+         .type         = MT_DEVICE,
+  },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg osiris_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+               .clk_sel        = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2,
+       }
+};
+
+/* NAND Flash on Osiris board */
+
+static int external_map[]   = { 2 };
+static int chip0_map[]      = { 0 };
+static int chip1_map[]      = { 1 };
+
+static struct mtd_partition __initdata osiris_default_nand_part[] = {
+       [0] = {
+               .name   = "Boot Agent",
+               .size   = SZ_16K,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "/boot",
+               .size   = SZ_4M - SZ_16K,
+               .offset = SZ_16K,
+       },
+       [2] = {
+               .name   = "user1",
+               .offset = SZ_4M,
+               .size   = SZ_32M - SZ_4M,
+       },
+       [3] = {
+               .name   = "user2",
+               .offset = SZ_32M,
+               .size   = MTDPART_SIZ_FULL,
+       }
+};
+
+static struct mtd_partition __initdata osiris_default_nand_part_large[] = {
+       [0] = {
+               .name   = "Boot Agent",
+               .size   = SZ_128K,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "/boot",
+               .size   = SZ_4M - SZ_128K,
+               .offset = SZ_128K,
+       },
+       [2] = {
+               .name   = "user1",
+               .offset = SZ_4M,
+               .size   = SZ_32M - SZ_4M,
+       },
+       [3] = {
+               .name   = "user2",
+               .offset = SZ_32M,
+               .size   = MTDPART_SIZ_FULL,
+       }
+};
+
+/* the Osiris has 3 selectable slots for nand-flash, the two
+ * on-board chip areas, as well as the external slot.
+ *
+ * Note, there is no current hot-plug support for the External
+ * socket.
+*/
+
+static struct s3c2410_nand_set __initdata osiris_nand_sets[] = {
+       [1] = {
+               .name           = "External",
+               .nr_chips       = 1,
+               .nr_map         = external_map,
+               .options        = NAND_SCAN_SILENT_NODEV,
+               .nr_partitions  = ARRAY_SIZE(osiris_default_nand_part),
+               .partitions     = osiris_default_nand_part,
+       },
+       [0] = {
+               .name           = "chip0",
+               .nr_chips       = 1,
+               .nr_map         = chip0_map,
+               .nr_partitions  = ARRAY_SIZE(osiris_default_nand_part),
+               .partitions     = osiris_default_nand_part,
+       },
+       [2] = {
+               .name           = "chip1",
+               .nr_chips       = 1,
+               .nr_map         = chip1_map,
+               .options        = NAND_SCAN_SILENT_NODEV,
+               .nr_partitions  = ARRAY_SIZE(osiris_default_nand_part),
+               .partitions     = osiris_default_nand_part,
+       },
+};
+
+static void osiris_nand_select(struct s3c2410_nand_set *set, int slot)
+{
+       unsigned int tmp;
+
+       slot = set->nr_map[slot] & 3;
+
+       pr_debug("osiris_nand: selecting slot %d (set %p,%p)\n",
+                slot, set, set->nr_map);
+
+       tmp = __raw_readb(OSIRIS_VA_CTRL0);
+       tmp &= ~OSIRIS_CTRL0_NANDSEL;
+       tmp |= slot;
+
+       pr_debug("osiris_nand: ctrl0 now %02x\n", tmp);
+
+       __raw_writeb(tmp, OSIRIS_VA_CTRL0);
+}
+
+static struct s3c2410_platform_nand __initdata osiris_nand_info = {
+       .tacls          = 25,
+       .twrph0         = 60,
+       .twrph1         = 60,
+       .nr_sets        = ARRAY_SIZE(osiris_nand_sets),
+       .sets           = osiris_nand_sets,
+       .select_chip    = osiris_nand_select,
+};
+
+/* PCMCIA control and configuration */
+
+static struct resource osiris_pcmcia_resource[] = {
+       [0] = {
+               .start  = 0x0f000000,
+               .end    = 0x0f100000,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 0x0c000000,
+               .end    = 0x0c100000,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device osiris_pcmcia = {
+       .name           = "osiris-pcmcia",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(osiris_pcmcia_resource),
+       .resource       = osiris_pcmcia_resource,
+};
+
+/* Osiris power management device */
+
+#ifdef CONFIG_PM
+static unsigned char pm_osiris_ctrl0;
+
+static int osiris_pm_suspend(void)
+{
+       unsigned int tmp;
+
+       pm_osiris_ctrl0 = __raw_readb(OSIRIS_VA_CTRL0);
+       tmp = pm_osiris_ctrl0 & ~OSIRIS_CTRL0_NANDSEL;
+
+       /* ensure correct NAND slot is selected on resume */
+       if ((pm_osiris_ctrl0 & OSIRIS_CTRL0_BOOT_INT) == 0)
+               tmp |= 2;
+
+       __raw_writeb(tmp, OSIRIS_VA_CTRL0);
+
+       /* ensure that an nRESET is not generated on resume. */
+       s3c2410_gpio_setpin(S3C2410_GPA(21), 1);
+       s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPIO_OUTPUT);
+
+       return 0;
+}
+
+static void osiris_pm_resume(void)
+{
+       if (pm_osiris_ctrl0 & OSIRIS_CTRL0_FIX8)
+               __raw_writeb(OSIRIS_CTRL1_FIX8, OSIRIS_VA_CTRL1);
+
+       __raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0);
+
+       s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
+}
+
+#else
+#define osiris_pm_suspend NULL
+#define osiris_pm_resume NULL
+#endif
+
+static struct syscore_ops osiris_pm_syscore_ops = {
+       .suspend        = osiris_pm_suspend,
+       .resume         = osiris_pm_resume,
+};
+
+/* Link for DVS driver to TPS65011 */
+
+static void osiris_tps_release(struct device *dev)
+{
+       /* static device, do not need to release anything */
+}
+
+static struct platform_device osiris_tps_device = {
+       .name   = "osiris-dvs",
+       .id     = -1,
+       .dev.release = osiris_tps_release,
+};
+
+static int osiris_tps_setup(struct i2c_client *client, void *context)
+{
+       osiris_tps_device.dev.parent = &client->dev;
+       return platform_device_register(&osiris_tps_device);
+}
+
+static int osiris_tps_remove(struct i2c_client *client, void *context)
+{
+       platform_device_unregister(&osiris_tps_device);
+       return 0;
+}
+
+static struct tps65010_board osiris_tps_board = {
+       .base           = -1,   /* GPIO can go anywhere at the moment */
+       .setup          = osiris_tps_setup,
+       .teardown       = osiris_tps_remove,
+};
+
+/* I2C devices fitted. */
+
+static struct i2c_board_info osiris_i2c_devs[] __initdata = {
+       {
+               I2C_BOARD_INFO("tps65011", 0x48),
+               .irq    = IRQ_EINT20,
+               .platform_data = &osiris_tps_board,
+       },
+};
+
+/* Standard Osiris devices */
+
+static struct platform_device *osiris_devices[] __initdata = {
+       &s3c_device_i2c0,
+       &s3c_device_wdt,
+       &s3c_device_nand,
+       &osiris_pcmcia,
+};
+
+static struct clk *osiris_clocks[] __initdata = {
+       &s3c24xx_dclk0,
+       &s3c24xx_dclk1,
+       &s3c24xx_clkout0,
+       &s3c24xx_clkout1,
+       &s3c24xx_uclk,
+};
+
+static struct s3c_cpufreq_board __initdata osiris_cpufreq = {
+       .refresh        = 7800, /* refresh period is 7.8usec */
+       .auto_io        = 1,
+       .need_io        = 1,
+};
+
+static void __init osiris_map_io(void)
+{
+       unsigned long flags;
+
+       /* initialise the clocks */
+
+       s3c24xx_dclk0.parent = &clk_upll;
+       s3c24xx_dclk0.rate   = 12*1000*1000;
+
+       s3c24xx_dclk1.parent = &clk_upll;
+       s3c24xx_dclk1.rate   = 24*1000*1000;
+
+       s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
+       s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
+
+       s3c24xx_uclk.parent  = &s3c24xx_clkout1;
+
+       s3c24xx_register_clocks(osiris_clocks, ARRAY_SIZE(osiris_clocks));
+
+       s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs));
+
+       /* check for the newer revision boards with large page nand */
+
+       if ((__raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK) >= 4) {
+               printk(KERN_INFO "OSIRIS-B detected (revision %d)\n",
+                      __raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK);
+               osiris_nand_sets[0].partitions = osiris_default_nand_part_large;
+               osiris_nand_sets[0].nr_partitions = ARRAY_SIZE(osiris_default_nand_part_large);
+       } else {
+               /* write-protect line to the NAND */
+               s3c2410_gpio_setpin(S3C2410_GPA(0), 1);
+       }
+
+       /* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */
+
+       local_irq_save(flags);
+       __raw_writel(__raw_readl(S3C2410_BWSCON) | S3C2410_BWSCON_ST1 | S3C2410_BWSCON_ST2 | S3C2410_BWSCON_ST3 | S3C2410_BWSCON_ST4 | S3C2410_BWSCON_ST5, S3C2410_BWSCON);
+       local_irq_restore(flags);
+}
+
+static void __init osiris_init(void)
+{
+       register_syscore_ops(&osiris_pm_syscore_ops);
+
+       s3c_i2c0_set_platdata(NULL);
+       s3c_nand_set_platdata(&osiris_nand_info);
+
+       s3c_cpufreq_setboard(&osiris_cpufreq);
+
+       i2c_register_board_info(0, osiris_i2c_devs,
+                               ARRAY_SIZE(osiris_i2c_devs));
+
+       platform_add_devices(osiris_devices, ARRAY_SIZE(osiris_devices));
+};
+
+MACHINE_START(OSIRIS, "Simtec-OSIRIS")
+       /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+       .atag_offset    = 0x100,
+       .map_io         = osiris_map_io,
+       .init_irq       = s3c24xx_init_irq,
+       .init_machine   = osiris_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-otom.c b/arch/arm/mach-s3c24xx/mach-otom.c
new file mode 100644 (file)
index 0000000..5f1e0ee
--- /dev/null
@@ -0,0 +1,127 @@
+/* linux/arch/arm/mach-s3c2410/mach-otom.c
+ *
+ * Copyright (c) 2004 Nex Vision
+ *   Guillaume GOURAT <guillaume.gourat@nexvision.fr>
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/otom-map.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/s3c2410.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/iic.h>
+#include <plat/cpu.h>
+
+#include "common.h"
+
+static struct map_desc otom11_iodesc[] __initdata = {
+  /* Device area */
+       { (u32)OTOM_VA_CS8900A_BASE, OTOM_PA_CS8900A_BASE, SZ_16M, MT_DEVICE },
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG12 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg otom11_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       /* port 2 is not actually used */
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+/* NOR Flash on NexVision OTOM board */
+
+static struct resource otom_nor_resource[] = {
+       [0] = {
+               .start = S3C2410_CS0,
+               .end   = S3C2410_CS0 + (4*1024*1024) - 1,
+               .flags = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device otom_device_nor = {
+       .name           = "mtd-flash",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(otom_nor_resource),
+       .resource       = otom_nor_resource,
+};
+
+/* Standard OTOM devices */
+
+static struct platform_device *otom11_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+       &s3c_device_rtc,
+       &otom_device_nor,
+};
+
+static void __init otom11_map_io(void)
+{
+       s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(otom11_uartcfgs, ARRAY_SIZE(otom11_uartcfgs));
+}
+
+static void __init otom11_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+       platform_add_devices(otom11_devices, ARRAY_SIZE(otom11_devices));
+}
+
+MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
+       /* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
+       .atag_offset    = 0x100,
+       .map_io         = otom11_map_io,
+       .init_machine   = otom11_init,
+       .init_irq       = s3c24xx_init_irq,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
new file mode 100644 (file)
index 0000000..91c16d9
--- /dev/null
@@ -0,0 +1,356 @@
+/* linux/arch/arm/mach-s3c2410/mach-qt2410.c
+ *
+ * Copyright (C) 2006 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/leds-gpio.h>
+#include <mach/regs-lcd.h>
+#include <plat/regs-serial.h>
+#include <mach/fb.h>
+#include <plat/nand.h>
+#include <plat/udc.h>
+#include <plat/iic.h>
+
+#include <plat/common-smdk.h>
+#include <plat/gpio-cfg.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+#include "common.h"
+
+static struct map_desc qt2410_iodesc[] __initdata = {
+       { 0xe0000000, __phys_to_pfn(S3C2410_CS3+0x01000000), SZ_1M, MT_DEVICE }
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg smdk2410_uartcfgs[] = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+/* LCD driver info */
+
+static struct s3c2410fb_display qt2410_lcd_cfg[] __initdata = {
+       {
+               /* Configuration for 640x480 SHARP LQ080V3DG01 */
+               .lcdcon5 = S3C2410_LCDCON5_FRM565 |
+                          S3C2410_LCDCON5_INVVLINE |
+                          S3C2410_LCDCON5_INVVFRAME |
+                          S3C2410_LCDCON5_PWREN |
+                          S3C2410_LCDCON5_HWSWP,
+
+               .type           = S3C2410_LCDCON1_TFT,
+               .width          = 640,
+               .height         = 480,
+
+               .pixclock       = 40000, /* HCLK/4 */
+               .xres           = 640,
+               .yres           = 480,
+               .bpp            = 16,
+               .left_margin    = 44,
+               .right_margin   = 116,
+               .hsync_len      = 96,
+               .upper_margin   = 19,
+               .lower_margin   = 11,
+               .vsync_len      = 15,
+       },
+       {
+               /* Configuration for 480x640 toppoly TD028TTEC1 */
+               .lcdcon5 = S3C2410_LCDCON5_FRM565 |
+                          S3C2410_LCDCON5_INVVLINE |
+                          S3C2410_LCDCON5_INVVFRAME |
+                          S3C2410_LCDCON5_PWREN |
+                          S3C2410_LCDCON5_HWSWP,
+
+               .type           = S3C2410_LCDCON1_TFT,
+               .width          = 480,
+               .height         = 640,
+               .pixclock       = 40000, /* HCLK/4 */
+               .xres           = 480,
+               .yres           = 640,
+               .bpp            = 16,
+               .left_margin    = 8,
+               .right_margin   = 24,
+               .hsync_len      = 8,
+               .upper_margin   = 2,
+               .lower_margin   = 4,
+               .vsync_len      = 2,
+       },
+       {
+               /* Config for 240x320 LCD */
+               .lcdcon5 = S3C2410_LCDCON5_FRM565 |
+                          S3C2410_LCDCON5_INVVLINE |
+                          S3C2410_LCDCON5_INVVFRAME |
+                          S3C2410_LCDCON5_PWREN |
+                          S3C2410_LCDCON5_HWSWP,
+
+               .type           = S3C2410_LCDCON1_TFT,
+               .width          = 240,
+               .height         = 320,
+               .pixclock       = 100000, /* HCLK/10 */
+               .xres           = 240,
+               .yres           = 320,
+               .bpp            = 16,
+               .left_margin    = 13,
+               .right_margin   = 8,
+               .hsync_len      = 4,
+               .upper_margin   = 2,
+               .lower_margin   = 7,
+               .vsync_len      = 4,
+       },
+};
+
+
+static struct s3c2410fb_mach_info qt2410_fb_info __initdata = {
+       .displays       = qt2410_lcd_cfg,
+       .num_displays   = ARRAY_SIZE(qt2410_lcd_cfg),
+       .default_display = 0,
+
+       .lpcsel         = ((0xCE6) & ~7) | 1<<4,
+};
+
+/* CS8900 */
+
+static struct resource qt2410_cs89x0_resources[] = {
+       [0] = {
+               .start  = 0x19000000,
+               .end    = 0x19000000 + 16,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_EINT9,
+               .end    = IRQ_EINT9,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device qt2410_cs89x0 = {
+       .name           = "cirrus-cs89x0",
+       .num_resources  = ARRAY_SIZE(qt2410_cs89x0_resources),
+       .resource       = qt2410_cs89x0_resources,
+};
+
+/* LED */
+
+static struct s3c24xx_led_platdata qt2410_pdata_led = {
+       .gpio           = S3C2410_GPB(0),
+       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+       .name           = "led",
+       .def_trigger    = "timer",
+};
+
+static struct platform_device qt2410_led = {
+       .name           = "s3c24xx_led",
+       .id             = 0,
+       .dev            = {
+               .platform_data = &qt2410_pdata_led,
+       },
+};
+
+/* SPI */
+
+static struct spi_gpio_platform_data spi_gpio_cfg = {
+       .sck            = S3C2410_GPG(7),
+       .mosi           = S3C2410_GPG(6),
+       .miso           = S3C2410_GPG(5),
+};
+
+static struct platform_device qt2410_spi = {
+       .name           = "spi-gpio",
+       .id             = 1,
+       .dev.platform_data = &spi_gpio_cfg,
+};
+
+/* Board devices */
+
+static struct platform_device *qt2410_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+       &s3c_device_sdi,
+       &s3c_device_usbgadget,
+       &qt2410_spi,
+       &qt2410_cs89x0,
+       &qt2410_led,
+};
+
+static struct mtd_partition __initdata qt2410_nand_part[] = {
+       [0] = {
+               .name   = "U-Boot",
+               .size   = 0x30000,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "U-Boot environment",
+               .offset = 0x30000,
+               .size   = 0x4000,
+       },
+       [2] = {
+               .name   = "kernel",
+               .offset = 0x34000,
+               .size   = SZ_2M,
+       },
+       [3] = {
+               .name   = "initrd",
+               .offset = 0x234000,
+               .size   = SZ_4M,
+       },
+       [4] = {
+               .name   = "jffs2",
+               .offset = 0x634000,
+               .size   = 0x39cc000,
+       },
+};
+
+static struct s3c2410_nand_set __initdata qt2410_nand_sets[] = {
+       [0] = {
+               .name           = "NAND",
+               .nr_chips       = 1,
+               .nr_partitions  = ARRAY_SIZE(qt2410_nand_part),
+               .partitions     = qt2410_nand_part,
+       },
+};
+
+/* choose a set of timings which should suit most 512Mbit
+ * chips and beyond.
+ */
+
+static struct s3c2410_platform_nand __initdata qt2410_nand_info = {
+       .tacls          = 20,
+       .twrph0         = 60,
+       .twrph1         = 20,
+       .nr_sets        = ARRAY_SIZE(qt2410_nand_sets),
+       .sets           = qt2410_nand_sets,
+};
+
+/* UDC */
+
+static struct s3c2410_udc_mach_info qt2410_udc_cfg = {
+};
+
+static char tft_type = 's';
+
+static int __init qt2410_tft_setup(char *str)
+{
+       tft_type = str[0];
+       return 1;
+}
+
+__setup("tft=", qt2410_tft_setup);
+
+static void __init qt2410_map_io(void)
+{
+       s3c24xx_init_io(qt2410_iodesc, ARRAY_SIZE(qt2410_iodesc));
+       s3c24xx_init_clocks(12*1000*1000);
+       s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
+}
+
+static void __init qt2410_machine_init(void)
+{
+       s3c_nand_set_platdata(&qt2410_nand_info);
+
+       switch (tft_type) {
+       case 'p': /* production */
+               qt2410_fb_info.default_display = 1;
+               break;
+       case 'b': /* big */
+               qt2410_fb_info.default_display = 0;
+               break;
+       case 's': /* small */
+       default:
+               qt2410_fb_info.default_display = 2;
+               break;
+       }
+       s3c24xx_fb_set_platdata(&qt2410_fb_info);
+
+       s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);
+       s3c2410_gpio_setpin(S3C2410_GPB(0), 1);
+
+       s3c24xx_udc_set_platdata(&qt2410_udc_cfg);
+       s3c_i2c0_set_platdata(NULL);
+
+       WARN_ON(gpio_request(S3C2410_GPB(5), "spi cs"));
+       gpio_direction_output(S3C2410_GPB(5), 1);
+
+       platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices));
+       s3c_pm_init();
+}
+
+MACHINE_START(QT2410, "QT2410")
+       .atag_offset    = 0x100,
+       .map_io         = qt2410_map_io,
+       .init_irq       = s3c24xx_init_irq,
+       .init_machine   = qt2410_machine_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
new file mode 100644 (file)
index 0000000..200debb
--- /dev/null
@@ -0,0 +1,826 @@
+/* linux/arch/arm/mach-s3c2440/mach-rx1950.c
+ *
+ * Copyright (c) 2006-2009 Victor Chukhantsev, Denis Grigoriev,
+ * Copyright (c) 2007-2010 Vasily Khoruzhick
+ *
+ * based on smdk2440 written by Ben Dooks
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/device.h>
+#include <linux/pda_power.h>
+#include <linux/pwm_backlight.h>
+#include <linux/pwm.h>
+#include <linux/s3c_adc_battery.h>
+#include <linux/leds.h>
+#include <linux/i2c.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/mmc/host.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
+#include <mach/regs-lcd.h>
+#include <mach/h1940.h>
+#include <mach/fb.h>
+
+#include <plat/clock.h>
+#include <plat/regs-serial.h>
+#include <plat/regs-iic.h>
+#include <plat/mci.h>
+#include <plat/udc.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/irq.h>
+#include <plat/ts.h>
+
+#include <sound/uda1380.h>
+
+#include "common.h"
+
+#define LCD_PWM_PERIOD 192960
+#define LCD_PWM_DUTY 127353
+
+static struct map_desc rx1950_iodesc[] __initdata = {
+};
+
+static struct s3c2410_uartcfg rx1950_uartcfgs[] __initdata = {
+       [0] = {
+              .hwport = 0,
+              .flags = 0,
+              .ucon = 0x3c5,
+              .ulcon = 0x03,
+              .ufcon = 0x51,
+               .clk_sel = S3C2410_UCON_CLKSEL3,
+       },
+       [1] = {
+              .hwport = 1,
+              .flags = 0,
+              .ucon = 0x3c5,
+              .ulcon = 0x03,
+              .ufcon = 0x51,
+               .clk_sel = S3C2410_UCON_CLKSEL3,
+       },
+       /* IR port */
+       [2] = {
+              .hwport = 2,
+              .flags = 0,
+              .ucon = 0x3c5,
+              .ulcon = 0x43,
+              .ufcon = 0xf1,
+               .clk_sel = S3C2410_UCON_CLKSEL3,
+       },
+};
+
+static struct s3c2410fb_display rx1950_display = {
+       .type = S3C2410_LCDCON1_TFT,
+       .width = 240,
+       .height = 320,
+       .xres = 240,
+       .yres = 320,
+       .bpp = 16,
+
+       .pixclock = 260000,
+       .left_margin = 10,
+       .right_margin = 20,
+       .hsync_len = 10,
+       .upper_margin = 2,
+       .lower_margin = 2,
+       .vsync_len = 2,
+
+       .lcdcon5 = S3C2410_LCDCON5_FRM565 |
+                          S3C2410_LCDCON5_INVVCLK |
+                          S3C2410_LCDCON5_INVVLINE |
+                          S3C2410_LCDCON5_INVVFRAME |
+                          S3C2410_LCDCON5_HWSWP |
+                          (0x02 << 13) |
+                          (0x02 << 15),
+
+};
+
+static int power_supply_init(struct device *dev)
+{
+       return gpio_request(S3C2410_GPF(2), "cable plugged");
+}
+
+static int rx1950_is_ac_online(void)
+{
+       return !gpio_get_value(S3C2410_GPF(2));
+}
+
+static void power_supply_exit(struct device *dev)
+{
+       gpio_free(S3C2410_GPF(2));
+}
+
+static char *rx1950_supplicants[] = {
+       "main-battery"
+};
+
+static struct pda_power_pdata power_supply_info = {
+       .init                   = power_supply_init,
+       .is_ac_online           = rx1950_is_ac_online,
+       .exit                   = power_supply_exit,
+       .supplied_to            = rx1950_supplicants,
+       .num_supplicants        = ARRAY_SIZE(rx1950_supplicants),
+};
+
+static struct resource power_supply_resources[] = {
+       [0] = {
+                       .name   = "ac",
+                       .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
+                                         IORESOURCE_IRQ_HIGHEDGE,
+                       .start  = IRQ_EINT2,
+                       .end    = IRQ_EINT2,
+       },
+};
+
+static struct platform_device power_supply = {
+       .name                   = "pda-power",
+       .id                     = -1,
+       .dev                    = {
+                                       .platform_data =
+                                               &power_supply_info,
+       },
+       .resource               = power_supply_resources,
+       .num_resources          = ARRAY_SIZE(power_supply_resources),
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
+       { .volt = 4100, .cur = 156, .level = 100},
+       { .volt = 4050, .cur = 156, .level = 95},
+       { .volt = 4025, .cur = 141, .level = 90},
+       { .volt = 3995, .cur = 144, .level = 85},
+       { .volt = 3957, .cur = 162, .level = 80},
+       { .volt = 3931, .cur = 147, .level = 75},
+       { .volt = 3902, .cur = 147, .level = 70},
+       { .volt = 3863, .cur = 153, .level = 65},
+       { .volt = 3838, .cur = 150, .level = 60},
+       { .volt = 3800, .cur = 153, .level = 55},
+       { .volt = 3765, .cur = 153, .level = 50},
+       { .volt = 3748, .cur = 172, .level = 45},
+       { .volt = 3740, .cur = 153, .level = 40},
+       { .volt = 3714, .cur = 175, .level = 35},
+       { .volt = 3710, .cur = 156, .level = 30},
+       { .volt = 3963, .cur = 156, .level = 25},
+       { .volt = 3672, .cur = 178, .level = 20},
+       { .volt = 3651, .cur = 178, .level = 15},
+       { .volt = 3629, .cur = 178, .level = 10},
+       { .volt = 3612, .cur = 162, .level = 5},
+       { .volt = 3605, .cur = 162, .level = 0},
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
+       { .volt = 4200, .cur = 0, .level = 100},
+       { .volt = 4190, .cur = 0, .level = 99},
+       { .volt = 4178, .cur = 0, .level = 95},
+       { .volt = 4110, .cur = 0, .level = 70},
+       { .volt = 4076, .cur = 0, .level = 65},
+       { .volt = 4046, .cur = 0, .level = 60},
+       { .volt = 4021, .cur = 0, .level = 55},
+       { .volt = 3999, .cur = 0, .level = 50},
+       { .volt = 3982, .cur = 0, .level = 45},
+       { .volt = 3965, .cur = 0, .level = 40},
+       { .volt = 3957, .cur = 0, .level = 35},
+       { .volt = 3948, .cur = 0, .level = 30},
+       { .volt = 3936, .cur = 0, .level = 25},
+       { .volt = 3927, .cur = 0, .level = 20},
+       { .volt = 3906, .cur = 0, .level = 15},
+       { .volt = 3880, .cur = 0, .level = 10},
+       { .volt = 3829, .cur = 0, .level = 5},
+       { .volt = 3820, .cur = 0, .level = 0},
+};
+
+static int rx1950_bat_init(void)
+{
+       int ret;
+
+       ret = gpio_request(S3C2410_GPJ(2), "rx1950-charger-enable-1");
+       if (ret)
+               goto err_gpio1;
+       ret = gpio_request(S3C2410_GPJ(3), "rx1950-charger-enable-2");
+       if (ret)
+               goto err_gpio2;
+
+       return 0;
+
+err_gpio2:
+       gpio_free(S3C2410_GPJ(2));
+err_gpio1:
+       return ret;
+}
+
+static void rx1950_bat_exit(void)
+{
+       gpio_free(S3C2410_GPJ(2));
+       gpio_free(S3C2410_GPJ(3));
+}
+
+static void rx1950_enable_charger(void)
+{
+       gpio_direction_output(S3C2410_GPJ(2), 1);
+       gpio_direction_output(S3C2410_GPJ(3), 1);
+}
+
+static void rx1950_disable_charger(void)
+{
+       gpio_direction_output(S3C2410_GPJ(2), 0);
+       gpio_direction_output(S3C2410_GPJ(3), 0);
+}
+
+static DEFINE_SPINLOCK(rx1950_blink_spin);
+
+static int rx1950_led_blink_set(unsigned gpio, int state,
+       unsigned long *delay_on, unsigned long *delay_off)
+{
+       int blink_gpio, check_gpio;
+
+       switch (gpio) {
+       case S3C2410_GPA(6):
+               blink_gpio = S3C2410_GPA(4);
+               check_gpio = S3C2410_GPA(3);
+               break;
+       case S3C2410_GPA(7):
+               blink_gpio = S3C2410_GPA(3);
+               check_gpio = S3C2410_GPA(4);
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+
+       if (delay_on && delay_off && !*delay_on && !*delay_off)
+               *delay_on = *delay_off = 500;
+
+       spin_lock(&rx1950_blink_spin);
+
+       switch (state) {
+       case GPIO_LED_NO_BLINK_LOW:
+       case GPIO_LED_NO_BLINK_HIGH:
+               if (!gpio_get_value(check_gpio))
+                       gpio_set_value(S3C2410_GPJ(6), 0);
+               gpio_set_value(blink_gpio, 0);
+               gpio_set_value(gpio, state);
+               break;
+       case GPIO_LED_BLINK:
+               gpio_set_value(gpio, 0);
+               gpio_set_value(S3C2410_GPJ(6), 1);
+               gpio_set_value(blink_gpio, 1);
+               break;
+       }
+
+       spin_unlock(&rx1950_blink_spin);
+
+       return 0;
+}
+
+static struct gpio_led rx1950_leds_desc[] = {
+       {
+               .name                   = "Green",
+               .default_trigger        = "main-battery-full",
+               .gpio                   = S3C2410_GPA(6),
+               .retain_state_suspended = 1,
+       },
+       {
+               .name                   = "Red",
+               .default_trigger
+                       = "main-battery-charging-blink-full-solid",
+               .gpio                   = S3C2410_GPA(7),
+               .retain_state_suspended = 1,
+       },
+       {
+               .name                   = "Blue",
+               .default_trigger        = "rx1950-acx-mem",
+               .gpio                   = S3C2410_GPA(11),
+               .retain_state_suspended = 1,
+       },
+};
+
+static struct gpio_led_platform_data rx1950_leds_pdata = {
+       .num_leds       = ARRAY_SIZE(rx1950_leds_desc),
+       .leds           = rx1950_leds_desc,
+       .gpio_blink_set = rx1950_led_blink_set,
+};
+
+static struct platform_device rx1950_leds = {
+       .name   = "leds-gpio",
+       .id             = -1,
+       .dev    = {
+                               .platform_data = &rx1950_leds_pdata,
+       },
+};
+
+static struct s3c_adc_bat_pdata rx1950_bat_cfg = {
+       .init = rx1950_bat_init,
+       .exit = rx1950_bat_exit,
+       .enable_charger = rx1950_enable_charger,
+       .disable_charger = rx1950_disable_charger,
+       .gpio_charge_finished = S3C2410_GPF(3),
+       .lut_noac = bat_lut_noac,
+       .lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
+       .lut_acin = bat_lut_acin,
+       .lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
+       .volt_channel = 0,
+       .current_channel = 1,
+       .volt_mult = 4235,
+       .current_mult = 2900,
+       .internal_impedance = 200,
+};
+
+static struct platform_device rx1950_battery = {
+       .name             = "s3c-adc-battery",
+       .id               = -1,
+       .dev = {
+               .parent = &s3c_device_adc.dev,
+               .platform_data = &rx1950_bat_cfg,
+       },
+};
+
+static struct s3c2410fb_mach_info rx1950_lcd_cfg = {
+       .displays = &rx1950_display,
+       .num_displays = 1,
+       .default_display = 0,
+
+       .lpcsel = 0x02,
+       .gpccon = 0xaa9556a9,
+       .gpccon_mask = 0xffc003fc,
+       .gpcup = 0x0000ffff,
+       .gpcup_mask = 0xffffffff,
+
+       .gpdcon = 0xaa90aaa1,
+       .gpdcon_mask = 0xffc0fff0,
+       .gpdup = 0x0000fcfd,
+       .gpdup_mask = 0xffffffff,
+
+};
+
+static struct pwm_device *lcd_pwm;
+
+static void rx1950_lcd_power(int enable)
+{
+       int i;
+       static int enabled;
+       if (enabled == enable)
+               return;
+       if (!enable) {
+
+               /* GPC11-GPC15->OUTPUT */
+               for (i = 11; i < 16; i++)
+                       gpio_direction_output(S3C2410_GPC(i), 1);
+
+               /* Wait a bit here... */
+               mdelay(100);
+
+               /* GPD2-GPD7->OUTPUT */
+               /* GPD11-GPD15->OUTPUT */
+               /* GPD2-GPD7->1, GPD11-GPD15->1 */
+               for (i = 2; i < 8; i++)
+                       gpio_direction_output(S3C2410_GPD(i), 1);
+               for (i = 11; i < 16; i++)
+                       gpio_direction_output(S3C2410_GPD(i), 1);
+
+               /* Wait a bit here...*/
+               mdelay(100);
+
+               /* GPB0->OUTPUT, GPB0->0 */
+               gpio_direction_output(S3C2410_GPB(0), 0);
+
+               /* GPC1-GPC4->OUTPUT, GPC1-4->0 */
+               for (i = 1; i < 5; i++)
+                       gpio_direction_output(S3C2410_GPC(i), 0);
+
+               /* GPC15-GPC11->0 */
+               for (i = 11; i < 16; i++)
+                       gpio_direction_output(S3C2410_GPC(i), 0);
+
+               /* GPD15-GPD11->0, GPD2->GPD7->0 */
+               for (i = 11; i < 16; i++)
+                       gpio_direction_output(S3C2410_GPD(i), 0);
+
+               for (i = 2; i < 8; i++)
+                       gpio_direction_output(S3C2410_GPD(i), 0);
+
+               /* GPC6->0, GPC7->0, GPC5->0 */
+               gpio_direction_output(S3C2410_GPC(6), 0);
+               gpio_direction_output(S3C2410_GPC(7), 0);
+               gpio_direction_output(S3C2410_GPC(5), 0);
+
+               /* GPB1->OUTPUT, GPB1->0 */
+               gpio_direction_output(S3C2410_GPB(1), 0);
+               pwm_config(lcd_pwm, 0, LCD_PWM_PERIOD);
+               pwm_disable(lcd_pwm);
+
+               /* GPC0->0, GPC10->0 */
+               gpio_direction_output(S3C2410_GPC(0), 0);
+               gpio_direction_output(S3C2410_GPC(10), 0);
+       } else {
+               pwm_config(lcd_pwm, LCD_PWM_DUTY, LCD_PWM_PERIOD);
+               pwm_enable(lcd_pwm);
+
+               gpio_direction_output(S3C2410_GPC(0), 1);
+               gpio_direction_output(S3C2410_GPC(5), 1);
+
+               s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPB1_TOUT1);
+               gpio_direction_output(S3C2410_GPC(7), 1);
+
+               for (i = 1; i < 5; i++)
+                       s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2));
+
+               for (i = 11; i < 16; i++)
+                       s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2));
+
+               for (i = 2; i < 8; i++)
+                       s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2));
+
+               for (i = 11; i < 16; i++)
+                       s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2));
+
+               gpio_direction_output(S3C2410_GPC(10), 1);
+               gpio_direction_output(S3C2410_GPC(6), 1);
+       }
+       enabled = enable;
+}
+
+static void rx1950_bl_power(int enable)
+{
+       static int enabled;
+       if (enabled == enable)
+               return;
+       if (!enable) {
+                       gpio_direction_output(S3C2410_GPB(0), 0);
+       } else {
+                       /* LED driver need a "push" to power on */
+                       gpio_direction_output(S3C2410_GPB(0), 1);
+                       /* Warm up backlight for one period of PWM.
+                        * Without this trick its almost impossible to
+                        * enable backlight with low brightness value
+                        */
+                       ndelay(48000);
+                       s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
+       }
+       enabled = enable;
+}
+
+static int rx1950_backlight_init(struct device *dev)
+{
+       WARN_ON(gpio_request(S3C2410_GPB(0), "Backlight"));
+       lcd_pwm = pwm_request(1, "RX1950 LCD");
+       if (IS_ERR(lcd_pwm)) {
+               dev_err(dev, "Unable to request PWM for LCD power!\n");
+               return PTR_ERR(lcd_pwm);
+       }
+
+       rx1950_lcd_power(1);
+       rx1950_bl_power(1);
+
+       return 0;
+}
+
+static void rx1950_backlight_exit(struct device *dev)
+{
+       rx1950_bl_power(0);
+       rx1950_lcd_power(0);
+
+       pwm_free(lcd_pwm);
+       gpio_free(S3C2410_GPB(0));
+}
+
+
+static int rx1950_backlight_notify(struct device *dev, int brightness)
+{
+       if (!brightness) {
+               rx1950_bl_power(0);
+               rx1950_lcd_power(0);
+       } else {
+               rx1950_lcd_power(1);
+               rx1950_bl_power(1);
+       }
+       return brightness;
+}
+
+static struct platform_pwm_backlight_data rx1950_backlight_data = {
+       .pwm_id = 0,
+       .max_brightness = 24,
+       .dft_brightness = 4,
+       .pwm_period_ns = 48000,
+       .init = rx1950_backlight_init,
+       .notify = rx1950_backlight_notify,
+       .exit = rx1950_backlight_exit,
+};
+
+static struct platform_device rx1950_backlight = {
+       .name = "pwm-backlight",
+       .dev = {
+               .parent = &s3c_device_timer[0].dev,
+               .platform_data = &rx1950_backlight_data,
+       },
+};
+
+static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
+{
+       switch (power_mode) {
+       case MMC_POWER_OFF:
+               gpio_direction_output(S3C2410_GPJ(1), 0);
+               break;
+       case MMC_POWER_UP:
+       case MMC_POWER_ON:
+               gpio_direction_output(S3C2410_GPJ(1), 1);
+               break;
+       default:
+               break;
+       }
+}
+
+static struct s3c24xx_mci_pdata rx1950_mmc_cfg __initdata = {
+       .gpio_detect = S3C2410_GPF(5),
+       .gpio_wprotect = S3C2410_GPH(8),
+       .set_power = rx1950_set_mmc_power,
+       .ocr_avail = MMC_VDD_32_33,
+};
+
+static struct mtd_partition rx1950_nand_part[] = {
+       [0] = {
+                       .name = "Boot0",
+                       .offset = 0,
+                       .size = 0x4000,
+                       .mask_flags = MTD_WRITEABLE,
+       },
+       [1] = {
+                       .name = "Boot1",
+                       .offset = MTDPART_OFS_APPEND,
+                       .size = 0x40000,
+                       .mask_flags = MTD_WRITEABLE,
+       },
+       [2] = {
+                       .name = "Kernel",
+                       .offset = MTDPART_OFS_APPEND,
+                       .size = 0x300000,
+                       .mask_flags = 0,
+       },
+       [3] = {
+                       .name = "Filesystem",
+                       .offset = MTDPART_OFS_APPEND,
+                       .size = MTDPART_SIZ_FULL,
+                       .mask_flags = 0,
+       },
+};
+
+static struct s3c2410_nand_set rx1950_nand_sets[] = {
+       [0] = {
+                       .name = "Internal",
+                       .nr_chips = 1,
+                       .nr_partitions = ARRAY_SIZE(rx1950_nand_part),
+                       .partitions = rx1950_nand_part,
+       },
+};
+
+static struct s3c2410_platform_nand rx1950_nand_info = {
+       .tacls = 25,
+       .twrph0 = 50,
+       .twrph1 = 15,
+       .nr_sets = ARRAY_SIZE(rx1950_nand_sets),
+       .sets = rx1950_nand_sets,
+};
+
+static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
+       .vbus_pin = S3C2410_GPG(5),
+       .vbus_pin_inverted = 1,
+       .pullup_pin = S3C2410_GPJ(5),
+};
+
+static struct s3c2410_ts_mach_info rx1950_ts_cfg __initdata = {
+       .delay = 10000,
+       .presc = 49,
+       .oversampling_shift = 3,
+};
+
+static struct gpio_keys_button rx1950_gpio_keys_table[] = {
+       {
+               .code           = KEY_POWER,
+               .gpio           = S3C2410_GPF(0),
+               .active_low     = 1,
+               .desc           = "Power button",
+               .wakeup         = 1,
+       },
+       {
+               .code           = KEY_F5,
+               .gpio           = S3C2410_GPF(7),
+               .active_low     = 1,
+               .desc           = "Record button",
+       },
+       {
+               .code           = KEY_F1,
+               .gpio           = S3C2410_GPG(0),
+               .active_low     = 1,
+               .desc           = "Calendar button",
+       },
+       {
+               .code           = KEY_F2,
+               .gpio           = S3C2410_GPG(2),
+               .active_low     = 1,
+               .desc           = "Contacts button",
+       },
+       {
+               .code           = KEY_F3,
+               .gpio           = S3C2410_GPG(3),
+               .active_low     = 1,
+               .desc           = "Mail button",
+       },
+       {
+               .code           = KEY_F4,
+               .gpio           = S3C2410_GPG(7),
+               .active_low     = 1,
+               .desc           = "WLAN button",
+       },
+       {
+               .code           = KEY_LEFT,
+               .gpio           = S3C2410_GPG(10),
+               .active_low     = 1,
+               .desc           = "Left button",
+       },
+       {
+               .code           = KEY_RIGHT,
+               .gpio           = S3C2410_GPG(11),
+               .active_low     = 1,
+               .desc           = "Right button",
+       },
+       {
+               .code           = KEY_UP,
+               .gpio           = S3C2410_GPG(4),
+               .active_low     = 1,
+               .desc           = "Up button",
+       },
+       {
+               .code           = KEY_DOWN,
+               .gpio           = S3C2410_GPG(6),
+               .active_low     = 1,
+               .desc           = "Down button",
+       },
+       {
+               .code           = KEY_ENTER,
+               .gpio           = S3C2410_GPG(9),
+               .active_low     = 1,
+               .desc           = "Ok button"
+       },
+};
+
+static struct gpio_keys_platform_data rx1950_gpio_keys_data = {
+       .buttons = rx1950_gpio_keys_table,
+       .nbuttons = ARRAY_SIZE(rx1950_gpio_keys_table),
+};
+
+static struct platform_device rx1950_device_gpiokeys = {
+       .name = "gpio-keys",
+       .dev.platform_data = &rx1950_gpio_keys_data,
+};
+
+static struct uda1380_platform_data uda1380_info = {
+       .gpio_power     = S3C2410_GPJ(0),
+       .gpio_reset     = S3C2410_GPD(0),
+       .dac_clk        = UDA1380_DAC_CLK_SYSCLK,
+};
+
+static struct i2c_board_info rx1950_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("uda1380", 0x1a),
+               .platform_data = &uda1380_info,
+       },
+};
+
+static struct platform_device *rx1950_devices[] __initdata = {
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+       &samsung_asoc_dma,
+       &s3c_device_usbgadget,
+       &s3c_device_rtc,
+       &s3c_device_nand,
+       &s3c_device_sdi,
+       &s3c_device_adc,
+       &s3c_device_ts,
+       &s3c_device_timer[0],
+       &s3c_device_timer[1],
+       &rx1950_backlight,
+       &rx1950_device_gpiokeys,
+       &power_supply,
+       &rx1950_battery,
+       &rx1950_leds,
+};
+
+static struct clk *rx1950_clocks[] __initdata = {
+       &s3c24xx_clkout0,
+       &s3c24xx_clkout1,
+};
+
+static void __init rx1950_map_io(void)
+{
+       s3c24xx_clkout0.parent  = &clk_h;
+       s3c24xx_clkout1.parent  = &clk_f;
+
+       s3c24xx_register_clocks(rx1950_clocks, ARRAY_SIZE(rx1950_clocks));
+
+       s3c24xx_init_io(rx1950_iodesc, ARRAY_SIZE(rx1950_iodesc));
+       s3c24xx_init_clocks(16934000);
+       s3c24xx_init_uarts(rx1950_uartcfgs, ARRAY_SIZE(rx1950_uartcfgs));
+
+       /* setup PM */
+
+#ifdef CONFIG_PM_H1940
+       memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 8);
+#endif
+
+       s3c_pm_init();
+}
+
+static void __init rx1950_init_machine(void)
+{
+       int i;
+
+       s3c24xx_fb_set_platdata(&rx1950_lcd_cfg);
+       s3c24xx_udc_set_platdata(&rx1950_udc_cfg);
+       s3c24xx_ts_set_platdata(&rx1950_ts_cfg);
+       s3c24xx_mci_set_platdata(&rx1950_mmc_cfg);
+       s3c_i2c0_set_platdata(NULL);
+       s3c_nand_set_platdata(&rx1950_nand_info);
+
+       /* Turn off suspend on both USB ports, and switch the
+        * selectable USB port to USB device mode. */
+       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+                                               S3C2410_MISCCR_USBSUSPND0 |
+                                               S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+       /* mmc power is disabled by default */
+       WARN_ON(gpio_request(S3C2410_GPJ(1), "MMC power"));
+       gpio_direction_output(S3C2410_GPJ(1), 0);
+
+       for (i = 0; i < 8; i++)
+               WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power"));
+
+       for (i = 10; i < 16; i++)
+               WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power"));
+
+       for (i = 2; i < 8; i++)
+               WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power"));
+
+       for (i = 11; i < 16; i++)
+               WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power"));
+
+       WARN_ON(gpio_request(S3C2410_GPB(1), "LCD power"));
+
+       WARN_ON(gpio_request(S3C2410_GPA(3), "Red blink"));
+       WARN_ON(gpio_request(S3C2410_GPA(4), "Green blink"));
+       WARN_ON(gpio_request(S3C2410_GPJ(6), "LED blink"));
+       gpio_direction_output(S3C2410_GPA(3), 0);
+       gpio_direction_output(S3C2410_GPA(4), 0);
+       gpio_direction_output(S3C2410_GPJ(6), 0);
+
+       platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices));
+
+       i2c_register_board_info(0, rx1950_i2c_devices,
+               ARRAY_SIZE(rx1950_i2c_devices));
+}
+
+/* H1940 and RX3715 need to reserve this for suspend */
+static void __init rx1950_reserve(void)
+{
+       memblock_reserve(0x30003000, 0x1000);
+       memblock_reserve(0x30081000, 0x1000);
+}
+
+MACHINE_START(RX1950, "HP iPAQ RX1950")
+    /* Maintainers: Vasily Khoruzhick */
+       .atag_offset = 0x100,
+       .map_io = rx1950_map_io,
+       .reserve        = rx1950_reserve,
+       .init_irq = s3c24xx_init_irq,
+       .init_machine = rx1950_init_machine,
+       .timer = &s3c24xx_timer,
+       .restart        = s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c
new file mode 100644 (file)
index 0000000..56af354
--- /dev/null
@@ -0,0 +1,217 @@
+/* linux/arch/arm/mach-s3c2440/mach-rx3715.c
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.handhelds.org/projects/rx3715.html
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-lcd.h>
+
+#include <mach/h1940.h>
+#include <plat/nand.h>
+#include <mach/fb.h>
+
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+#include "common.h"
+
+static struct map_desc rx3715_iodesc[] __initdata = {
+       /* dump ISA space somewhere unused */
+
+       {
+               .virtual        = (u32)S3C24XX_VA_ISA_WORD,
+               .pfn            = __phys_to_pfn(S3C2410_CS3),
+               .length         = SZ_1M,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (u32)S3C24XX_VA_ISA_BYTE,
+               .pfn            = __phys_to_pfn(S3C2410_CS3),
+               .length         = SZ_1M,
+               .type           = MT_DEVICE,
+       },
+};
+
+static struct s3c2410_uartcfg rx3715_uartcfgs[] = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+               .clk_sel        = S3C2410_UCON_CLKSEL3,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x00,
+               .clk_sel        = S3C2410_UCON_CLKSEL3,
+       },
+       /* IR port */
+       [2] = {
+               .hwport      = 2,
+               .uart_flags  = UPF_CONS_FLOW,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x43,
+               .ufcon       = 0x51,
+               .clk_sel        = S3C2410_UCON_CLKSEL3,
+       }
+};
+
+/* framebuffer lcd controller information */
+
+static struct s3c2410fb_display rx3715_lcdcfg __initdata = {
+       .lcdcon5 =      S3C2410_LCDCON5_INVVLINE |
+                       S3C2410_LCDCON5_FRM565 |
+                       S3C2410_LCDCON5_HWSWP,
+
+       .type           = S3C2410_LCDCON1_TFT,
+       .width          = 240,
+       .height         = 320,
+
+       .pixclock       = 260000,
+       .xres           = 240,
+       .yres           = 320,
+       .bpp            = 16,
+       .left_margin    = 36,
+       .right_margin   = 36,
+       .hsync_len      = 8,
+       .upper_margin   = 6,
+       .lower_margin   = 7,
+       .vsync_len      = 3,
+};
+
+static struct s3c2410fb_mach_info rx3715_fb_info __initdata = {
+
+       .displays =     &rx3715_lcdcfg,
+       .num_displays = 1,
+       .default_display = 0,
+
+       .lpcsel =       0xf82,
+
+       .gpccon =       0xaa955699,
+       .gpccon_mask =  0xffc003cc,
+       .gpcup =        0x0000ffff,
+       .gpcup_mask =   0xffffffff,
+
+       .gpdcon =       0xaa95aaa1,
+       .gpdcon_mask =  0xffc0fff0,
+       .gpdup =        0x0000faff,
+       .gpdup_mask =   0xffffffff,
+};
+
+static struct mtd_partition __initdata rx3715_nand_part[] = {
+       [0] = {
+               .name           = "Whole Flash",
+               .offset         = 0,
+               .size           = MTDPART_SIZ_FULL,
+               .mask_flags     = MTD_WRITEABLE,
+       }
+};
+
+static struct s3c2410_nand_set __initdata rx3715_nand_sets[] = {
+       [0] = {
+               .name           = "Internal",
+               .nr_chips       = 1,
+               .nr_partitions  = ARRAY_SIZE(rx3715_nand_part),
+               .partitions     = rx3715_nand_part,
+       },
+};
+
+static struct s3c2410_platform_nand __initdata rx3715_nand_info = {
+       .tacls          = 25,
+       .twrph0         = 50,
+       .twrph1         = 15,
+       .nr_sets        = ARRAY_SIZE(rx3715_nand_sets),
+       .sets           = rx3715_nand_sets,
+};
+
+static struct platform_device *rx3715_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+       &s3c_device_nand,
+};
+
+static void __init rx3715_map_io(void)
+{
+       s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc));
+       s3c24xx_init_clocks(16934000);
+       s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs));
+}
+
+/* H1940 and RX3715 need to reserve this for suspend */
+static void __init rx3715_reserve(void)
+{
+       memblock_reserve(0x30003000, 0x1000);
+       memblock_reserve(0x30081000, 0x1000);
+}
+
+static void __init rx3715_init_irq(void)
+{
+       s3c24xx_init_irq();
+}
+
+static void __init rx3715_init_machine(void)
+{
+#ifdef CONFIG_PM_H1940
+       memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 1024);
+#endif
+       s3c_pm_init();
+
+       s3c_nand_set_platdata(&rx3715_nand_info);
+       s3c24xx_fb_set_platdata(&rx3715_fb_info);
+       platform_add_devices(rx3715_devices, ARRAY_SIZE(rx3715_devices));
+}
+
+MACHINE_START(RX3715, "IPAQ-RX3715")
+       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
+       .atag_offset    = 0x100,
+       .map_io         = rx3715_map_io,
+       .reserve        = rx3715_reserve,
+       .init_irq       = rx3715_init_irq,
+       .init_machine   = rx3715_init_machine,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2410.c b/arch/arm/mach-s3c24xx/mach-smdk2410.c
new file mode 100644 (file)
index 0000000..bdc27e7
--- /dev/null
@@ -0,0 +1,122 @@
+/* linux/arch/arm/mach-s3c2410/mach-smdk2410.c
+ *
+ * linux/arch/arm/mach-s3c2410/mach-smdk2410.c
+ *
+ * Copyright (C) 2004 by FS Forth-Systeme GmbH
+ * All rights reserved.
+ *
+ * @Author: Jonas Dietsche
+ *
+ * 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
+ *
+ * @History:
+ * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ ***********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/iic.h>
+
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#include <plat/common-smdk.h>
+
+#include "common.h"
+
+static struct map_desc smdk2410_iodesc[] __initdata = {
+  /* nothing here yet */
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg smdk2410_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+static struct platform_device *smdk2410_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+};
+
+static void __init smdk2410_map_io(void)
+{
+       s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
+}
+
+static void __init smdk2410_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+       platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
+       smdk_machine_init();
+}
+
+MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
+                                   * to SMDK2410 */
+       /* Maintainer: Jonas Dietsche */
+       .atag_offset    = 0x100,
+       .map_io         = smdk2410_map_io,
+       .init_irq       = s3c24xx_init_irq,
+       .init_machine   = smdk2410_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2413.c b/arch/arm/mach-s3c24xx/mach-smdk2413.c
new file mode 100644 (file)
index 0000000..b11451b
--- /dev/null
@@ -0,0 +1,162 @@
+/* linux/arch/arm/mach-s3c2412/mach-smdk2413.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Thanks to Dimity Andric (TomTom) and Steven Ryu (Samsung) for the
+ * loans of SMDK2413 to work with.
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/iomd.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+//#include <asm/debug-ll.h>
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-lcd.h>
+
+#include <mach/idle.h>
+#include <plat/udc.h>
+#include <plat/iic.h>
+#include <mach/fb.h>
+
+#include <plat/s3c2410.h>
+#include <plat/s3c2412.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#include <plat/common-smdk.h>
+
+static struct map_desc smdk2413_iodesc[] __initdata = {
+};
+
+static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       /* IR port */
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x43,
+               .ufcon       = 0x51,
+       }
+};
+
+
+static struct s3c2410_udc_mach_info smdk2413_udc_cfg __initdata = {
+       .pullup_pin = S3C2410_GPF(2),
+};
+
+
+static struct platform_device *smdk2413_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+       &s3c_device_usbgadget,
+};
+
+static void __init smdk2413_fixup(struct tag *tags, char **cmdline,
+                                 struct meminfo *mi)
+{
+       if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
+               mi->nr_banks=1;
+               mi->bank[0].start = 0x30000000;
+               mi->bank[0].size = SZ_64M;
+       }
+}
+
+static void __init smdk2413_map_io(void)
+{
+       s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs));
+}
+
+static void __init smdk2413_machine_init(void)
+{      /* Turn off suspend on both USB ports, and switch the
+        * selectable USB port to USB device mode. */
+
+       s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+                             S3C2410_MISCCR_USBSUSPND0 |
+                             S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+
+       s3c24xx_udc_set_platdata(&smdk2413_udc_cfg);
+       s3c_i2c0_set_platdata(NULL);
+
+       platform_add_devices(smdk2413_devices, ARRAY_SIZE(smdk2413_devices));
+       smdk_machine_init();
+}
+
+MACHINE_START(S3C2413, "S3C2413")
+       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
+       .atag_offset    = 0x100,
+
+       .fixup          = smdk2413_fixup,
+       .init_irq       = s3c24xx_init_irq,
+       .map_io         = smdk2413_map_io,
+       .init_machine   = smdk2413_machine_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2412_restart,
+MACHINE_END
+
+MACHINE_START(SMDK2412, "SMDK2412")
+       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
+       .atag_offset    = 0x100,
+
+       .fixup          = smdk2413_fixup,
+       .init_irq       = s3c24xx_init_irq,
+       .map_io         = smdk2413_map_io,
+       .init_machine   = smdk2413_machine_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2412_restart,
+MACHINE_END
+
+MACHINE_START(SMDK2413, "SMDK2413")
+       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
+       .atag_offset    = 0x100,
+
+       .fixup          = smdk2413_fixup,
+       .init_irq       = s3c24xx_init_irq,
+       .map_io         = smdk2413_map_io,
+       .init_machine   = smdk2413_machine_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2412_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c
new file mode 100644 (file)
index 0000000..30a44f8
--- /dev/null
@@ -0,0 +1,256 @@
+/* linux/arch/arm/mach-s3c2416/mach-hanlin_v3c.c
+ *
+ * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
+ *     as part of OpenInkpot project
+ * Copyright (c) 2009 Promwad Innovation Company
+ *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/mtd/partitions.h>
+#include <linux/gpio.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-lcd.h>
+#include <mach/regs-s3c2443-clock.h>
+
+#include <mach/idle.h>
+#include <mach/leds-gpio.h>
+#include <plat/iic.h>
+
+#include <plat/s3c2416.h>
+#include <plat/gpio-cfg.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/nand.h>
+#include <plat/sdhci.h>
+#include <plat/udc.h>
+#include <linux/platform_data/s3c-hsudc.h>
+
+#include <plat/regs-fb-v4.h>
+#include <plat/fb.h>
+
+#include <plat/common-smdk.h>
+
+static struct map_desc smdk2416_iodesc[] __initdata = {
+       /* ISA IO Space map (memory space selected by A24) */
+
+       {
+               .virtual        = (u32)S3C24XX_VA_ISA_WORD,
+               .pfn            = __phys_to_pfn(S3C2410_CS2),
+               .length         = 0x10000,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (u32)S3C24XX_VA_ISA_WORD + 0x10000,
+               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+               .length         = SZ_4M,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (u32)S3C24XX_VA_ISA_BYTE,
+               .pfn            = __phys_to_pfn(S3C2410_CS2),
+               .length         = 0x10000,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
+               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+               .length         = SZ_4M,
+               .type           = MT_DEVICE,
+       }
+};
+
+#define UCON (S3C2410_UCON_DEFAULT     | \
+               S3C2440_UCON_PCLK       | \
+               S3C2443_UCON_RXERR_IRQEN)
+
+#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE)
+
+#define UFCON (S3C2410_UFCON_RXTRIG8   | \
+               S3C2410_UFCON_FIFOMODE  | \
+               S3C2440_UFCON_TXTRIG16)
+
+static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       /* IR port */
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON | 0x50,
+               .ufcon       = UFCON,
+       },
+       [3] = {
+               .hwport      = 3,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+static void smdk2416_hsudc_gpio_init(void)
+{
+       s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_UP);
+       s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_NONE);
+       s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(1));
+       s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 0);
+}
+
+static void smdk2416_hsudc_gpio_uninit(void)
+{
+       s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 1);
+       s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_NONE);
+       s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(0));
+}
+
+static struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
+       .epnum = 9,
+       .gpio_init = smdk2416_hsudc_gpio_init,
+       .gpio_uninit = smdk2416_hsudc_gpio_uninit,
+};
+
+static struct s3c_fb_pd_win smdk2416_fb_win[] = {
+       [0] = {
+               /* think this is the same as the smdk6410 */
+               .win_mode       = {
+                       .pixclock       = 41094,
+                       .left_margin    = 8,
+                       .right_margin   = 13,
+                       .upper_margin   = 7,
+                       .lower_margin   = 5,
+                       .hsync_len      = 3,
+                       .vsync_len      = 1,
+                       .xres           = 800,
+                       .yres           = 480,
+               },
+               .default_bpp    = 16,
+               .max_bpp        = 32,
+       },
+};
+
+static void s3c2416_fb_gpio_setup_24bpp(void)
+{
+       unsigned int gpio;
+
+       for (gpio = S3C2410_GPC(1); gpio <= S3C2410_GPC(4); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       for (gpio = S3C2410_GPC(8); gpio <= S3C2410_GPC(15); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       for (gpio = S3C2410_GPD(0); gpio <= S3C2410_GPD(15); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+}
+
+static struct s3c_fb_platdata smdk2416_fb_platdata = {
+       .win[0]         = &smdk2416_fb_win[0],
+       .setup_gpio     = s3c2416_fb_gpio_setup_24bpp,
+       .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+};
+
+static struct s3c_sdhci_platdata smdk2416_hsmmc0_pdata __initdata = {
+       .max_width              = 4,
+       .cd_type                = S3C_SDHCI_CD_GPIO,
+       .ext_cd_gpio            = S3C2410_GPF(1),
+       .ext_cd_gpio_invert     = 1,
+};
+
+static struct s3c_sdhci_platdata smdk2416_hsmmc1_pdata __initdata = {
+       .max_width              = 4,
+       .cd_type                = S3C_SDHCI_CD_NONE,
+};
+
+static struct platform_device *smdk2416_devices[] __initdata = {
+       &s3c_device_fb,
+       &s3c_device_wdt,
+       &s3c_device_ohci,
+       &s3c_device_i2c0,
+       &s3c_device_hsmmc0,
+       &s3c_device_hsmmc1,
+       &s3c_device_usb_hsudc,
+};
+
+static void __init smdk2416_map_io(void)
+{
+       s3c24xx_init_io(smdk2416_iodesc, ARRAY_SIZE(smdk2416_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(smdk2416_uartcfgs, ARRAY_SIZE(smdk2416_uartcfgs));
+}
+
+static void __init smdk2416_machine_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+       s3c_fb_set_platdata(&smdk2416_fb_platdata);
+
+       s3c_sdhci0_set_platdata(&smdk2416_hsmmc0_pdata);
+       s3c_sdhci1_set_platdata(&smdk2416_hsmmc1_pdata);
+
+       s3c24xx_hsudc_set_platdata(&smdk2416_hsudc_platdata);
+
+       gpio_request(S3C2410_GPB(4), "USBHost Power");
+       gpio_direction_output(S3C2410_GPB(4), 1);
+
+       gpio_request(S3C2410_GPB(3), "Display Power");
+       gpio_direction_output(S3C2410_GPB(3), 1);
+
+       gpio_request(S3C2410_GPB(1), "Display Reset");
+       gpio_direction_output(S3C2410_GPB(1), 1);
+
+       platform_add_devices(smdk2416_devices, ARRAY_SIZE(smdk2416_devices));
+       smdk_machine_init();
+}
+
+MACHINE_START(SMDK2416, "SMDK2416")
+       /* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */
+       .atag_offset    = 0x100,
+
+       .init_irq       = s3c24xx_init_irq,
+       .map_io         = smdk2416_map_io,
+       .init_machine   = smdk2416_machine_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2416_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2440.c b/arch/arm/mach-s3c24xx/mach-smdk2440.c
new file mode 100644 (file)
index 0000000..83a1036
--- /dev/null
@@ -0,0 +1,187 @@
+/* linux/arch/arm/mach-s3c2440/mach-smdk2440.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.fluff.org/ben/smdk2440/
+ *
+ * Thanks to Dimity Andric and TomTom for the loan of an SMDK2440.
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-lcd.h>
+
+#include <mach/idle.h>
+#include <mach/fb.h>
+#include <plat/iic.h>
+
+#include <plat/s3c2410.h>
+#include <plat/s3c244x.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#include <plat/common-smdk.h>
+
+#include "common.h"
+
+static struct map_desc smdk2440_iodesc[] __initdata = {
+       /* ISA IO Space map (memory space selected by A24) */
+
+       {
+               .virtual        = (u32)S3C24XX_VA_ISA_WORD,
+               .pfn            = __phys_to_pfn(S3C2410_CS2),
+               .length         = 0x10000,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (u32)S3C24XX_VA_ISA_WORD + 0x10000,
+               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+               .length         = SZ_4M,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (u32)S3C24XX_VA_ISA_BYTE,
+               .pfn            = __phys_to_pfn(S3C2410_CS2),
+               .length         = 0x10000,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
+               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+               .length         = SZ_4M,
+               .type           = MT_DEVICE,
+       }
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg smdk2440_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       /* IR port */
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x43,
+               .ufcon       = 0x51,
+       }
+};
+
+/* LCD driver info */
+
+static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {
+
+       .lcdcon5        = S3C2410_LCDCON5_FRM565 |
+                         S3C2410_LCDCON5_INVVLINE |
+                         S3C2410_LCDCON5_INVVFRAME |
+                         S3C2410_LCDCON5_PWREN |
+                         S3C2410_LCDCON5_HWSWP,
+
+       .type           = S3C2410_LCDCON1_TFT,
+
+       .width          = 240,
+       .height         = 320,
+
+       .pixclock       = 166667, /* HCLK 60 MHz, divisor 10 */
+       .xres           = 240,
+       .yres           = 320,
+       .bpp            = 16,
+       .left_margin    = 20,
+       .right_margin   = 8,
+       .hsync_len      = 4,
+       .upper_margin   = 8,
+       .lower_margin   = 7,
+       .vsync_len      = 4,
+};
+
+static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
+       .displays       = &smdk2440_lcd_cfg,
+       .num_displays   = 1,
+       .default_display = 0,
+
+#if 0
+       /* currently setup by downloader */
+       .gpccon         = 0xaa940659,
+       .gpccon_mask    = 0xffffffff,
+       .gpcup          = 0x0000ffff,
+       .gpcup_mask     = 0xffffffff,
+       .gpdcon         = 0xaa84aaa0,
+       .gpdcon_mask    = 0xffffffff,
+       .gpdup          = 0x0000faff,
+       .gpdup_mask     = 0xffffffff,
+#endif
+
+       .lpcsel         = ((0xCE6) & ~7) | 1<<4,
+};
+
+static struct platform_device *smdk2440_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+};
+
+static void __init smdk2440_map_io(void)
+{
+       s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
+       s3c24xx_init_clocks(16934400);
+       s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
+}
+
+static void __init smdk2440_machine_init(void)
+{
+       s3c24xx_fb_set_platdata(&smdk2440_fb_info);
+       s3c_i2c0_set_platdata(NULL);
+
+       platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
+       smdk_machine_init();
+}
+
+MACHINE_START(S3C2440, "SMDK2440")
+       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
+       .atag_offset    = 0x100,
+
+       .init_irq       = s3c24xx_init_irq,
+       .map_io         = smdk2440_map_io,
+       .init_machine   = smdk2440_machine_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c244x_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2443.c b/arch/arm/mach-s3c24xx/mach-smdk2443.c
new file mode 100644 (file)
index 0000000..2092369
--- /dev/null
@@ -0,0 +1,149 @@
+/* linux/arch/arm/mach-s3c2443/mach-smdk2443.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.fluff.org/ben/smdk2443/
+ *
+ * Thanks to Samsung for the loan of an SMDK2443
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-lcd.h>
+
+#include <mach/idle.h>
+#include <mach/fb.h>
+#include <plat/iic.h>
+
+#include <plat/s3c2410.h>
+#include <plat/s3c2443.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#include <plat/common-smdk.h>
+
+static struct map_desc smdk2443_iodesc[] __initdata = {
+       /* ISA IO Space map (memory space selected by A24) */
+
+       {
+               .virtual        = (u32)S3C24XX_VA_ISA_WORD,
+               .pfn            = __phys_to_pfn(S3C2410_CS2),
+               .length         = 0x10000,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (u32)S3C24XX_VA_ISA_WORD + 0x10000,
+               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+               .length         = SZ_4M,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (u32)S3C24XX_VA_ISA_BYTE,
+               .pfn            = __phys_to_pfn(S3C2410_CS2),
+               .length         = 0x10000,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
+               .pfn            = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+               .length         = SZ_4M,
+               .type           = MT_DEVICE,
+       }
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg smdk2443_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       /* IR port */
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x43,
+               .ufcon       = 0x51,
+       },
+       [3] = {
+               .hwport      = 3,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       }
+};
+
+static struct platform_device *smdk2443_devices[] __initdata = {
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_hsmmc1,
+#ifdef CONFIG_SND_SOC_SMDK2443_WM9710
+       &s3c_device_ac97,
+#endif
+};
+
+static void __init smdk2443_map_io(void)
+{
+       s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs));
+}
+
+static void __init smdk2443_machine_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+
+#ifdef CONFIG_SND_SOC_SMDK2443_WM9710
+       s3c24xx_ac97_setup_gpio(S3C24XX_AC97_GPE0);
+#endif
+
+       platform_add_devices(smdk2443_devices, ARRAY_SIZE(smdk2443_devices));
+       smdk_machine_init();
+}
+
+MACHINE_START(SMDK2443, "SMDK2443")
+       /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
+       .atag_offset    = 0x100,
+
+       .init_irq       = s3c24xx_init_irq,
+       .map_io         = smdk2443_map_io,
+       .init_machine   = smdk2443_machine_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2443_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-tct_hammer.c b/arch/arm/mach-s3c24xx/mach-tct_hammer.c
new file mode 100644 (file)
index 0000000..1114666
--- /dev/null
@@ -0,0 +1,157 @@
+/* linux/arch/arm/mach-s3c2410/mach-tct_hammer.c
+ *
+ * Copyright (c) 2007 TinCanTools
+ *     David Anders <danders@amltd.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
+ *
+ * @History:
+ * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ ***********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/flash.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/physmap.h>
+
+#include "common.h"
+
+static struct resource tct_hammer_nor_resource = {
+               .start = 0x00000000,
+               .end   = 0x01000000 - 1,
+               .flags = IORESOURCE_MEM,
+};
+
+static struct mtd_partition tct_hammer_mtd_partitions[] = {
+       {
+               .name           = "System",
+               .size           = 0x240000,
+               .offset         = 0,
+               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
+       }, {
+               .name           = "JFFS2",
+               .size           = MTDPART_SIZ_FULL,
+               .offset         = MTDPART_OFS_APPEND,
+       }
+};
+
+static struct physmap_flash_data tct_hammer_flash_data = {
+       .width          = 2,
+       .parts          = tct_hammer_mtd_partitions,
+       .nr_parts       = ARRAY_SIZE(tct_hammer_mtd_partitions),
+};
+
+static struct platform_device tct_hammer_device_nor = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev = {
+                       .platform_data = &tct_hammer_flash_data,
+               },
+       .num_resources  = 1,
+       .resource       = &tct_hammer_nor_resource,
+};
+
+static struct map_desc tct_hammer_iodesc[] __initdata = {
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg tct_hammer_uartcfgs[] = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+
+static struct platform_device *tct_hammer_devices[] __initdata = {
+       &s3c_device_adc,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_ohci,
+       &s3c_device_rtc,
+       &s3c_device_usbgadget,
+       &s3c_device_sdi,
+       &tct_hammer_device_nor,
+};
+
+static void __init tct_hammer_map_io(void)
+{
+       s3c24xx_init_io(tct_hammer_iodesc, ARRAY_SIZE(tct_hammer_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(tct_hammer_uartcfgs, ARRAY_SIZE(tct_hammer_uartcfgs));
+}
+
+static void __init tct_hammer_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+       platform_add_devices(tct_hammer_devices, ARRAY_SIZE(tct_hammer_devices));
+}
+
+MACHINE_START(TCT_HAMMER, "TCT_HAMMER")
+       .atag_offset    = 0x100,
+       .map_io         = tct_hammer_map_io,
+       .init_irq       = s3c24xx_init_irq,
+       .init_machine   = tct_hammer_init,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-vr1000.c b/arch/arm/mach-s3c24xx/mach-vr1000.c
new file mode 100644 (file)
index 0000000..87608d4
--- /dev/null
@@ -0,0 +1,385 @@
+/* linux/arch/arm/mach-s3c2410/mach-vr1000.c
+ *
+ * Copyright (c) 2003-2008 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Machine support for Thorcom VR1000 board. Designed for Thorcom by
+ * Simtec Electronics, http://www.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/dm9000.h>
+#include <linux/i2c.h>
+
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/bast-map.h>
+#include <mach/vr1000-map.h>
+#include <mach/vr1000-irq.h>
+#include <mach/vr1000-cpld.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/leds-gpio.h>
+
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/iic.h>
+#include <plat/audio-simtec.h>
+
+#include "simtec.h"
+#include "common.h"
+
+/* macros for virtual address mods for the io space entries */
+#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
+#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
+#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
+#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
+
+/* macros to modify the physical addresses for io space */
+
+#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
+#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
+#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
+#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
+
+static struct map_desc vr1000_iodesc[] __initdata = {
+  /* ISA IO areas */
+  {
+         .virtual      = (u32)S3C24XX_VA_ISA_BYTE,
+         .pfn          = PA_CS2(BAST_PA_ISAIO),
+         .length       = SZ_16M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)S3C24XX_VA_ISA_WORD,
+         .pfn          = PA_CS3(BAST_PA_ISAIO),
+         .length       = SZ_16M,
+         .type         = MT_DEVICE,
+  },
+
+  /*  CPLD control registers, and external interrupt controls */
+  {
+         .virtual      = (u32)VR1000_VA_CTRL1,
+         .pfn          = __phys_to_pfn(VR1000_PA_CTRL1),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)VR1000_VA_CTRL2,
+         .pfn          = __phys_to_pfn(VR1000_PA_CTRL2),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)VR1000_VA_CTRL3,
+         .pfn          = __phys_to_pfn(VR1000_PA_CTRL3),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)VR1000_VA_CTRL4,
+         .pfn          = __phys_to_pfn(VR1000_PA_CTRL4),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  },
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg vr1000_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       },
+       /* port 2 is not actually used */
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = UCON,
+               .ulcon       = ULCON,
+               .ufcon       = UFCON,
+       }
+};
+
+/* definitions for the vr1000 extra 16550 serial ports */
+
+#define VR1000_BAUDBASE (3692307)
+
+#define VR1000_SERIAL_MAPBASE(x) (VR1000_PA_SERIAL + 0x80 + ((x) << 5))
+
+static struct plat_serial8250_port serial_platform_data[] = {
+       [0] = {
+               .mapbase        = VR1000_SERIAL_MAPBASE(0),
+               .irq            = IRQ_VR1000_SERIAL + 0,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+               .iotype         = UPIO_MEM,
+               .regshift       = 0,
+               .uartclk        = VR1000_BAUDBASE,
+       },
+       [1] = {
+               .mapbase        = VR1000_SERIAL_MAPBASE(1),
+               .irq            = IRQ_VR1000_SERIAL + 1,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+               .iotype         = UPIO_MEM,
+               .regshift       = 0,
+               .uartclk        = VR1000_BAUDBASE,
+       },
+       [2] = {
+               .mapbase        = VR1000_SERIAL_MAPBASE(2),
+               .irq            = IRQ_VR1000_SERIAL + 2,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+               .iotype         = UPIO_MEM,
+               .regshift       = 0,
+               .uartclk        = VR1000_BAUDBASE,
+       },
+       [3] = {
+               .mapbase        = VR1000_SERIAL_MAPBASE(3),
+               .irq            = IRQ_VR1000_SERIAL + 3,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+               .iotype         = UPIO_MEM,
+               .regshift       = 0,
+               .uartclk        = VR1000_BAUDBASE,
+       },
+       { },
+};
+
+static struct platform_device serial_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = serial_platform_data,
+       },
+};
+
+/* DM9000 ethernet devices */
+
+static struct resource vr1000_dm9k0_resource[] = {
+       [0] = {
+               .start = S3C2410_CS5 + VR1000_PA_DM9000,
+               .end   = S3C2410_CS5 + VR1000_PA_DM9000 + 3,
+               .flags = IORESOURCE_MEM
+       },
+       [1] = {
+               .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x40,
+               .end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0x7f,
+               .flags = IORESOURCE_MEM
+       },
+       [2] = {
+               .start = IRQ_VR1000_DM9000A,
+               .end   = IRQ_VR1000_DM9000A,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       }
+
+};
+
+static struct resource vr1000_dm9k1_resource[] = {
+       [0] = {
+               .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x80,
+               .end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0x83,
+               .flags = IORESOURCE_MEM
+       },
+       [1] = {
+               .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0,
+               .end   = S3C2410_CS5 + VR1000_PA_DM9000 + 0xFF,
+               .flags = IORESOURCE_MEM
+       },
+       [2] = {
+               .start = IRQ_VR1000_DM9000N,
+               .end   = IRQ_VR1000_DM9000N,
+               .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+       }
+};
+
+/* for the moment we limit ourselves to 16bit IO until some
+ * better IO routines can be written and tested
+*/
+
+static struct dm9000_plat_data vr1000_dm9k_platdata = {
+       .flags          = DM9000_PLATF_16BITONLY,
+};
+
+static struct platform_device vr1000_dm9k0 = {
+       .name           = "dm9000",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(vr1000_dm9k0_resource),
+       .resource       = vr1000_dm9k0_resource,
+       .dev            = {
+               .platform_data = &vr1000_dm9k_platdata,
+       }
+};
+
+static struct platform_device vr1000_dm9k1 = {
+       .name           = "dm9000",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(vr1000_dm9k1_resource),
+       .resource       = vr1000_dm9k1_resource,
+       .dev            = {
+               .platform_data = &vr1000_dm9k_platdata,
+       }
+};
+
+/* LEDS */
+
+static struct s3c24xx_led_platdata vr1000_led1_pdata = {
+       .name           = "led1",
+       .gpio           = S3C2410_GPB(0),
+       .def_trigger    = "",
+};
+
+static struct s3c24xx_led_platdata vr1000_led2_pdata = {
+       .name           = "led2",
+       .gpio           = S3C2410_GPB(1),
+       .def_trigger    = "",
+};
+
+static struct s3c24xx_led_platdata vr1000_led3_pdata = {
+       .name           = "led3",
+       .gpio           = S3C2410_GPB(2),
+       .def_trigger    = "",
+};
+
+static struct platform_device vr1000_led1 = {
+       .name           = "s3c24xx_led",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &vr1000_led1_pdata,
+       },
+};
+
+static struct platform_device vr1000_led2 = {
+       .name           = "s3c24xx_led",
+       .id             = 2,
+       .dev            = {
+               .platform_data  = &vr1000_led2_pdata,
+       },
+};
+
+static struct platform_device vr1000_led3 = {
+       .name           = "s3c24xx_led",
+       .id             = 3,
+       .dev            = {
+               .platform_data  = &vr1000_led3_pdata,
+       },
+};
+
+/* I2C devices. */
+
+static struct i2c_board_info vr1000_i2c_devs[] __initdata = {
+       {
+               I2C_BOARD_INFO("tlv320aic23", 0x1a),
+       }, {
+               I2C_BOARD_INFO("tmp101", 0x48),
+       }, {
+               I2C_BOARD_INFO("m41st87", 0x68),
+       },
+};
+
+/* devices for this board */
+
+static struct platform_device *vr1000_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_lcd,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_adc,
+       &serial_device,
+       &vr1000_dm9k0,
+       &vr1000_dm9k1,
+       &vr1000_led1,
+       &vr1000_led2,
+       &vr1000_led3,
+};
+
+static struct clk *vr1000_clocks[] __initdata = {
+       &s3c24xx_dclk0,
+       &s3c24xx_dclk1,
+       &s3c24xx_clkout0,
+       &s3c24xx_clkout1,
+       &s3c24xx_uclk,
+};
+
+static void vr1000_power_off(void)
+{
+       gpio_direction_output(S3C2410_GPB(9), 1);
+}
+
+static void __init vr1000_map_io(void)
+{
+       /* initialise clock sources */
+
+       s3c24xx_dclk0.parent = &clk_upll;
+       s3c24xx_dclk0.rate   = 12*1000*1000;
+
+       s3c24xx_dclk1.parent = NULL;
+       s3c24xx_dclk1.rate   = 3692307;
+
+       s3c24xx_clkout0.parent  = &s3c24xx_dclk0;
+       s3c24xx_clkout1.parent  = &s3c24xx_dclk1;
+
+       s3c24xx_uclk.parent  = &s3c24xx_clkout1;
+
+       s3c24xx_register_clocks(vr1000_clocks, ARRAY_SIZE(vr1000_clocks));
+
+       pm_power_off = vr1000_power_off;
+
+       s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc));
+       s3c24xx_init_clocks(0);
+       s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs));
+}
+
+static void __init vr1000_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+       platform_add_devices(vr1000_devices, ARRAY_SIZE(vr1000_devices));
+
+       i2c_register_board_info(0, vr1000_i2c_devs,
+                               ARRAY_SIZE(vr1000_i2c_devs));
+
+       nor_simtec_init();
+       simtec_audio_add(NULL, true, NULL);
+
+       WARN_ON(gpio_request(S3C2410_GPB(9), "power off"));
+}
+
+MACHINE_START(VR1000, "Thorcom-VR1000")
+       /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+       .atag_offset    = 0x100,
+       .map_io         = vr1000_map_io,
+       .init_machine   = vr1000_init,
+       .init_irq       = s3c24xx_init_irq,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2410_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c
new file mode 100644 (file)
index 0000000..94bfaa1
--- /dev/null
@@ -0,0 +1,166 @@
+/* linux/arch/arm/mach-s3c2412/mach-vstms.c
+ *
+ * (C) 2006 Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Derived from mach-smdk2413.c - (C) 2006 Simtec Electronics
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-lcd.h>
+
+#include <mach/idle.h>
+#include <mach/fb.h>
+
+#include <plat/iic.h>
+#include <plat/nand.h>
+
+#include <plat/s3c2410.h>
+#include <plat/s3c2412.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+
+static struct map_desc vstms_iodesc[] __initdata = {
+};
+
+static struct s3c2410_uartcfg vstms_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       [2] = {
+               .hwport      = 2,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       }
+};
+
+static struct mtd_partition __initdata vstms_nand_part[] = {
+       [0] = {
+               .name   = "Boot Agent",
+               .size   = 0x7C000,
+               .offset = 0,
+       },
+       [1] = {
+               .name   = "UBoot Config",
+               .offset = 0x7C000,
+               .size   = 0x4000,
+       },
+       [2] = {
+               .name   = "Kernel",
+               .offset = 0x80000,
+               .size   = 0x200000,
+       },
+       [3] = {
+               .name   = "RFS",
+               .offset = 0x280000,
+               .size   = 0x3d80000,
+       },
+};
+
+static struct s3c2410_nand_set __initdata vstms_nand_sets[] = {
+       [0] = {
+               .name           = "NAND",
+               .nr_chips       = 1,
+               .nr_partitions  = ARRAY_SIZE(vstms_nand_part),
+               .partitions     = vstms_nand_part,
+       },
+};
+
+/* choose a set of timings which should suit most 512Mbit
+ * chips and beyond.
+*/
+
+static struct s3c2410_platform_nand __initdata vstms_nand_info = {
+       .tacls          = 20,
+       .twrph0         = 60,
+       .twrph1         = 20,
+       .nr_sets        = ARRAY_SIZE(vstms_nand_sets),
+       .sets           = vstms_nand_sets,
+};
+
+static struct platform_device *vstms_devices[] __initdata = {
+       &s3c_device_ohci,
+       &s3c_device_wdt,
+       &s3c_device_i2c0,
+       &s3c_device_iis,
+       &s3c_device_rtc,
+       &s3c_device_nand,
+};
+
+static void __init vstms_fixup(struct tag *tags, char **cmdline,
+                              struct meminfo *mi)
+{
+       if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
+               mi->nr_banks=1;
+               mi->bank[0].start = 0x30000000;
+               mi->bank[0].size = SZ_64M;
+       }
+}
+
+static void __init vstms_map_io(void)
+{
+       s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs));
+}
+
+static void __init vstms_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+       s3c_nand_set_platdata(&vstms_nand_info);
+
+       platform_add_devices(vstms_devices, ARRAY_SIZE(vstms_devices));
+}
+
+MACHINE_START(VSTMS, "VSTMS")
+       .atag_offset    = 0x100,
+
+       .fixup          = vstms_fixup,
+       .init_irq       = s3c24xx_init_irq,
+       .init_machine   = vstms_init,
+       .map_io         = vstms_map_io,
+       .timer          = &s3c24xx_timer,
+       .restart        = s3c2412_restart,
+MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/pm-h1940.S b/arch/arm/mach-s3c24xx/pm-h1940.S
new file mode 100644 (file)
index 0000000..c93bf2d
--- /dev/null
@@ -0,0 +1,33 @@
+/* linux/arch/arm/mach-s3c2410/pm-h1940.S
+ *
+ * Copyright (c) 2006 Ben Dooks <ben-linux@fluff.org>
+ *
+ * H1940 Suspend to RAM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <mach/regs-gpio.h>
+
+       .text
+       .global h1940_pm_return
+
+h1940_pm_return:
+       mov     r0, #S3C2410_PA_GPIO
+       ldr     pc, [ r0, #S3C2410_GSTATUS3 - S3C24XX_VA_GPIO ]
diff --git a/arch/arm/mach-s3c24xx/pm-s3c2410.c b/arch/arm/mach-s3c24xx/pm-s3c2410.c
new file mode 100644 (file)
index 0000000..03f706d
--- /dev/null
@@ -0,0 +1,180 @@
+/* linux/arch/arm/mach-s3c2410/pm.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/h1940.h>
+
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+static void s3c2410_pm_prepare(void)
+{
+       /* ensure at least GSTATUS3 has the resume address */
+
+       __raw_writel(virt_to_phys(s3c_cpu_resume), S3C2410_GSTATUS3);
+
+       S3C_PMDBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
+       S3C_PMDBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
+
+       if (machine_is_h1940()) {
+               void *base = phys_to_virt(H1940_SUSPEND_CHECK);
+               unsigned long ptr;
+               unsigned long calc = 0;
+
+               /* generate check for the bootloader to check on resume */
+
+               for (ptr = 0; ptr < 0x40000; ptr += 0x400)
+                       calc += __raw_readl(base+ptr);
+
+               __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
+       }
+
+       /* RX3715 and RX1950 use similar to H1940 code and the
+        * same offsets for resume and checksum pointers */
+
+       if (machine_is_rx3715() || machine_is_rx1950()) {
+               void *base = phys_to_virt(H1940_SUSPEND_CHECK);
+               unsigned long ptr;
+               unsigned long calc = 0;
+
+               /* generate check for the bootloader to check on resume */
+
+               for (ptr = 0; ptr < 0x40000; ptr += 0x4)
+                       calc += __raw_readl(base+ptr);
+
+               __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
+       }
+
+       if ( machine_is_aml_m5900() )
+               s3c2410_gpio_setpin(S3C2410_GPF(2), 1);
+
+       if (machine_is_rx1950()) {
+               /* According to S3C2442 user's manual, page 7-17,
+                * when the system is operating in NAND boot mode,
+                * the hardware pin configuration - EINT[23:21] â€“
+                * must be set as input for starting up after
+                * wakeup from sleep mode
+                */
+               s3c_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPIO_INPUT);
+               s3c_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPIO_INPUT);
+               s3c_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPIO_INPUT);
+       }
+}
+
+static void s3c2410_pm_resume(void)
+{
+       unsigned long tmp;
+
+       /* unset the return-from-sleep flag, to ensure reset */
+
+       tmp = __raw_readl(S3C2410_GSTATUS2);
+       tmp &= S3C2410_GSTATUS2_OFFRESET;
+       __raw_writel(tmp, S3C2410_GSTATUS2);
+
+       if ( machine_is_aml_m5900() )
+               s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
+}
+
+struct syscore_ops s3c2410_pm_syscore_ops = {
+       .resume         = s3c2410_pm_resume,
+};
+
+static int s3c2410_pm_add(struct device *dev, struct subsys_interface *sif)
+{
+       pm_cpu_prep = s3c2410_pm_prepare;
+       pm_cpu_sleep = s3c2410_cpu_suspend;
+
+       return 0;
+}
+
+#if defined(CONFIG_CPU_S3C2410)
+static struct subsys_interface s3c2410_pm_interface = {
+       .name           = "s3c2410_pm",
+       .subsys         = &s3c2410_subsys,
+       .add_dev        = s3c2410_pm_add,
+};
+
+/* register ourselves */
+
+static int __init s3c2410_pm_drvinit(void)
+{
+       return subsys_interface_register(&s3c2410_pm_interface);
+}
+
+arch_initcall(s3c2410_pm_drvinit);
+
+static struct subsys_interface s3c2410a_pm_interface = {
+       .name           = "s3c2410a_pm",
+       .subsys         = &s3c2410a_subsys,
+       .add_dev        = s3c2410_pm_add,
+};
+
+static int __init s3c2410a_pm_drvinit(void)
+{
+       return subsys_interface_register(&s3c2410a_pm_interface);
+}
+
+arch_initcall(s3c2410a_pm_drvinit);
+#endif
+
+#if defined(CONFIG_CPU_S3C2440)
+static struct subsys_interface s3c2440_pm_interface = {
+       .name           = "s3c2440_pm",
+       .subsys         = &s3c2440_subsys,
+       .add_dev        = s3c2410_pm_add,
+};
+
+static int __init s3c2440_pm_drvinit(void)
+{
+       return subsys_interface_register(&s3c2440_pm_interface);
+}
+
+arch_initcall(s3c2440_pm_drvinit);
+#endif
+
+#if defined(CONFIG_CPU_S3C2442)
+static struct subsys_interface s3c2442_pm_interface = {
+       .name           = "s3c2442_pm",
+       .subsys         = &s3c2442_subsys,
+       .add_dev        = s3c2410_pm_add,
+};
+
+static int __init s3c2442_pm_drvinit(void)
+{
+       return subsys_interface_register(&s3c2442_pm_interface);
+}
+
+arch_initcall(s3c2442_pm_drvinit);
+#endif
diff --git a/arch/arm/mach-s3c24xx/pm-s3c2412.c b/arch/arm/mach-s3c24xx/pm-s3c2412.c
new file mode 100644 (file)
index 0000000..d045885
--- /dev/null
@@ -0,0 +1,124 @@
+/* linux/arch/arm/mach-s3c2412/pm.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://armlinux.simtec.co.uk/.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/cacheflush.h>
+#include <asm/irq.h>
+
+#include <mach/regs-power.h>
+#include <mach/regs-gpioj.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-dsc.h>
+
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+#include <plat/s3c2412.h>
+
+extern void s3c2412_sleep_enter(void);
+
+static int s3c2412_cpu_suspend(unsigned long arg)
+{
+       unsigned long tmp;
+
+       /* set our standby method to sleep */
+
+       tmp = __raw_readl(S3C2412_PWRCFG);
+       tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP;
+       __raw_writel(tmp, S3C2412_PWRCFG);
+
+       s3c2412_sleep_enter();
+
+       panic("sleep resumed to originator?");
+}
+
+static void s3c2412_pm_prepare(void)
+{
+}
+
+static int s3c2412_pm_add(struct device *dev, struct subsys_interface *sif)
+{
+       pm_cpu_prep = s3c2412_pm_prepare;
+       pm_cpu_sleep = s3c2412_cpu_suspend;
+
+       return 0;
+}
+
+static struct sleep_save s3c2412_sleep[] = {
+       SAVE_ITEM(S3C2412_DSC0),
+       SAVE_ITEM(S3C2412_DSC1),
+       SAVE_ITEM(S3C2413_GPJDAT),
+       SAVE_ITEM(S3C2413_GPJCON),
+       SAVE_ITEM(S3C2413_GPJUP),
+
+       /* save the PWRCFG to get back to original sleep method */
+
+       SAVE_ITEM(S3C2412_PWRCFG),
+
+       /* save the sleep configuration anyway, just in case these
+        * get damaged during wakeup */
+
+       SAVE_ITEM(S3C2412_GPBSLPCON),
+       SAVE_ITEM(S3C2412_GPCSLPCON),
+       SAVE_ITEM(S3C2412_GPDSLPCON),
+       SAVE_ITEM(S3C2412_GPFSLPCON),
+       SAVE_ITEM(S3C2412_GPGSLPCON),
+       SAVE_ITEM(S3C2412_GPHSLPCON),
+       SAVE_ITEM(S3C2413_GPJSLPCON),
+};
+
+static struct subsys_interface s3c2412_pm_interface = {
+       .name           = "s3c2412_pm",
+       .subsys         = &s3c2412_subsys,
+       .add_dev        = s3c2412_pm_add,
+};
+
+static __init int s3c2412_pm_init(void)
+{
+       return subsys_interface_register(&s3c2412_pm_interface);
+}
+
+arch_initcall(s3c2412_pm_init);
+
+static int s3c2412_pm_suspend(void)
+{
+       s3c_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
+       return 0;
+}
+
+static void s3c2412_pm_resume(void)
+{
+       unsigned long tmp;
+
+       tmp = __raw_readl(S3C2412_PWRCFG);
+       tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK;
+       tmp |=  S3C2412_PWRCFG_STANDBYWFI_IDLE;
+       __raw_writel(tmp, S3C2412_PWRCFG);
+
+       s3c_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
+}
+
+struct syscore_ops s3c2412_pm_syscore_ops = {
+       .suspend        = s3c2412_pm_suspend,
+       .resume         = s3c2412_pm_resume,
+};
diff --git a/arch/arm/mach-s3c24xx/pm-s3c2416.c b/arch/arm/mach-s3c24xx/pm-s3c2416.c
new file mode 100644 (file)
index 0000000..1bd4817
--- /dev/null
@@ -0,0 +1,83 @@
+/* linux/arch/arm/mach-s3c2416/pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S3C2416 - PM support (Based on Ben Dooks' S3C2412 PM support)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/io.h>
+
+#include <asm/cacheflush.h>
+
+#include <mach/regs-power.h>
+#include <mach/regs-s3c2443-clock.h>
+
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+extern void s3c2412_sleep_enter(void);
+
+static int s3c2416_cpu_suspend(unsigned long arg)
+{
+       /* enable wakeup sources regardless of battery state */
+       __raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG);
+
+       /* set the mode as sleep, 2BED represents "Go to BED" */
+       __raw_writel(0x2BED, S3C2443_PWRMODE);
+
+       s3c2412_sleep_enter();
+
+       panic("sleep resumed to originator?");
+}
+
+static void s3c2416_pm_prepare(void)
+{
+       /*
+        * write the magic value u-boot uses to check for resume into
+        * the INFORM0 register, and ensure INFORM1 is set to the
+        * correct address to resume from.
+        */
+       __raw_writel(0x2BED, S3C2412_INFORM0);
+       __raw_writel(virt_to_phys(s3c_cpu_resume), S3C2412_INFORM1);
+}
+
+static int s3c2416_pm_add(struct device *dev, struct subsys_interface *sif)
+{
+       pm_cpu_prep = s3c2416_pm_prepare;
+       pm_cpu_sleep = s3c2416_cpu_suspend;
+
+       return 0;
+}
+
+static struct subsys_interface s3c2416_pm_interface = {
+       .name           = "s3c2416_pm",
+       .subsys         = &s3c2416_subsys,
+       .add_dev        = s3c2416_pm_add,
+};
+
+static __init int s3c2416_pm_init(void)
+{
+       return subsys_interface_register(&s3c2416_pm_interface);
+}
+
+arch_initcall(s3c2416_pm_init);
+
+
+static void s3c2416_pm_resume(void)
+{
+       /* unset the return-from-sleep amd inform flags */
+       __raw_writel(0x0, S3C2443_PWRMODE);
+       __raw_writel(0x0, S3C2412_INFORM0);
+       __raw_writel(0x0, S3C2412_INFORM1);
+}
+
+struct syscore_ops s3c2416_pm_syscore_ops = {
+       .resume         = s3c2416_pm_resume,
+};
diff --git a/arch/arm/mach-s3c24xx/s3c2410.c b/arch/arm/mach-s3c24xx/s3c2410.c
new file mode 100644 (file)
index 0000000..a3c5cb0
--- /dev/null
@@ -0,0 +1,207 @@
+/* linux/arch/arm/mach-s3c2410/s3c2410.c
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.simtec.co.uk/products/EB2410ITX/
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/system_misc.h>
+
+#include <plat/cpu-freq.h>
+
+#include <mach/regs-clock.h>
+#include <plat/regs-serial.h>
+
+#include <plat/s3c2410.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/pll.h>
+#include <plat/pm.h>
+#include <plat/watchdog-reset.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+
+/* Initial IO mappings */
+
+static struct map_desc s3c2410_iodesc[] __initdata = {
+       IODESC_ENT(CLKPWR),
+       IODESC_ENT(TIMER),
+       IODESC_ENT(WATCHDOG),
+};
+
+/* our uart devices */
+
+/* uart registration process */
+
+void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       s3c24xx_init_uartdevs("s3c2410-uart", s3c2410_uart_resources, cfg, no);
+}
+
+/* s3c2410_map_io
+ *
+ * register the standard cpu IO areas, and any passed in from the
+ * machine specific initialisation.
+*/
+
+void __init s3c2410_map_io(void)
+{
+       s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up;
+       s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up;
+
+       iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
+}
+
+void __init_or_cpufreq s3c2410_setup_clocks(void)
+{
+       struct clk *xtal_clk;
+       unsigned long tmp;
+       unsigned long xtal;
+       unsigned long fclk;
+       unsigned long hclk;
+       unsigned long pclk;
+
+       xtal_clk = clk_get(NULL, "xtal");
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
+
+       /* now we've got our machine bits initialised, work out what
+        * clocks we've got */
+
+       fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
+
+       tmp = __raw_readl(S3C2410_CLKDIVN);
+
+       /* work out clock scalings */
+
+       hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);
+       pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);
+
+       /* print brieft summary of clocks, etc */
+
+       printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
+              print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
+
+       /* initialise the clocks here, to allow other things like the
+        * console to use them
+        */
+
+       s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+/* fake ARMCLK for use with cpufreq, etc. */
+
+static struct clk s3c2410_armclk = {
+       .name   = "armclk",
+       .parent = &clk_f,
+       .id     = -1,
+};
+
+static struct clk_lookup s3c2410_clk_lookup[] = {
+       CLKDEV_INIT(NULL, "clk_uart_baud0", &clk_p),
+       CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
+};
+
+void __init s3c2410_init_clocks(int xtal)
+{
+       s3c24xx_register_baseclocks(xtal);
+       s3c2410_setup_clocks();
+       s3c2410_baseclk_add();
+       s3c24xx_register_clock(&s3c2410_armclk);
+       clkdev_add_table(s3c2410_clk_lookup, ARRAY_SIZE(s3c2410_clk_lookup));
+}
+
+struct bus_type s3c2410_subsys = {
+       .name = "s3c2410-core",
+       .dev_name = "s3c2410-core",
+};
+
+/* Note, we would have liked to name this s3c2410-core, but we cannot
+ * register two subsystems with the same name.
+ */
+struct bus_type s3c2410a_subsys = {
+       .name = "s3c2410a-core",
+       .dev_name = "s3c2410a-core",
+};
+
+static struct device s3c2410_dev = {
+       .bus            = &s3c2410_subsys,
+};
+
+/* need to register the subsystem before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2410 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
+
+static int __init s3c2410_core_init(void)
+{
+       return subsys_system_register(&s3c2410_subsys, NULL);
+}
+
+core_initcall(s3c2410_core_init);
+
+static int __init s3c2410a_core_init(void)
+{
+       return subsys_system_register(&s3c2410a_subsys, NULL);
+}
+
+core_initcall(s3c2410a_core_init);
+
+int __init s3c2410_init(void)
+{
+       printk("S3C2410: Initialising architecture\n");
+
+#ifdef CONFIG_PM
+       register_syscore_ops(&s3c2410_pm_syscore_ops);
+#endif
+       register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
+       return device_register(&s3c2410_dev);
+}
+
+int __init s3c2410a_init(void)
+{
+       s3c2410_dev.bus = &s3c2410a_subsys;
+       return s3c2410_init();
+}
+
+void s3c2410_restart(char mode, const char *cmd)
+{
+       if (mode == 's') {
+               soft_restart(0);
+       }
+
+       arch_wdt_reset();
+
+       /* we'll take a jump through zero as a poor second */
+       soft_restart(0);
+}
diff --git a/arch/arm/mach-s3c24xx/s3c2412.c b/arch/arm/mach-s3c24xx/s3c2412.c
new file mode 100644 (file)
index 0000000..d4bc7f9
--- /dev/null
@@ -0,0 +1,252 @@
+/* linux/arch/arm/mach-s3c2412/s3c2412.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://armlinux.simtec.co.uk/.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/proc-fns.h>
+#include <asm/irq.h>
+#include <asm/system_misc.h>
+
+#include <plat/cpu-freq.h>
+
+#include <mach/regs-clock.h>
+#include <plat/regs-serial.h>
+#include <mach/regs-power.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
+#include <mach/regs-dsc.h>
+#include <plat/regs-spi.h>
+#include <mach/regs-s3c2412.h>
+
+#include <plat/s3c2412.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/pm.h>
+#include <plat/pll.h>
+#include <plat/nand-core.h>
+
+#ifndef CONFIG_CPU_S3C2412_ONLY
+void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
+
+static inline void s3c2412_init_gpio2(void)
+{
+       s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
+}
+#else
+#define s3c2412_init_gpio2() do { } while(0)
+#endif
+
+/* Initial IO mappings */
+
+static struct map_desc s3c2412_iodesc[] __initdata = {
+       IODESC_ENT(CLKPWR),
+       IODESC_ENT(TIMER),
+       IODESC_ENT(WATCHDOG),
+       {
+               .virtual = (unsigned long)S3C2412_VA_SSMC,
+               .pfn     = __phys_to_pfn(S3C2412_PA_SSMC),
+               .length  = SZ_1M,
+               .type    = MT_DEVICE,
+       },
+       {
+               .virtual = (unsigned long)S3C2412_VA_EBI,
+               .pfn     = __phys_to_pfn(S3C2412_PA_EBI),
+               .length  = SZ_1M,
+               .type    = MT_DEVICE,
+       },
+};
+
+/* uart registration process */
+
+void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       s3c24xx_init_uartdevs("s3c2412-uart", s3c2410_uart_resources, cfg, no);
+
+       /* rename devices that are s3c2412/s3c2413 specific */
+       s3c_device_sdi.name  = "s3c2412-sdi";
+       s3c_device_lcd.name  = "s3c2412-lcd";
+       s3c_nand_setname("s3c2412-nand");
+
+       /* alter IRQ of SDI controller */
+
+       s3c_device_sdi.resource[1].start = IRQ_S3C2412_SDI;
+       s3c_device_sdi.resource[1].end   = IRQ_S3C2412_SDI;
+
+       /* spi channel related changes, s3c2412/13 specific */
+       s3c_device_spi0.name = "s3c2412-spi";
+       s3c_device_spi0.resource[0].end = S3C24XX_PA_SPI + 0x24;
+       s3c_device_spi1.name = "s3c2412-spi";
+       s3c_device_spi1.resource[0].start = S3C24XX_PA_SPI + S3C2412_SPI1;
+       s3c_device_spi1.resource[0].end = S3C24XX_PA_SPI + S3C2412_SPI1 + 0x24;
+
+}
+
+/* s3c2412_idle
+ *
+ * use the standard idle call by ensuring the idle mode
+ * in power config, then issuing the idle co-processor
+ * instruction
+*/
+
+static void s3c2412_idle(void)
+{
+       unsigned long tmp;
+
+       /* ensure our idle mode is to go to idle */
+
+       tmp = __raw_readl(S3C2412_PWRCFG);
+       tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK;
+       tmp |= S3C2412_PWRCFG_STANDBYWFI_IDLE;
+       __raw_writel(tmp, S3C2412_PWRCFG);
+
+       cpu_do_idle();
+}
+
+void s3c2412_restart(char mode, const char *cmd)
+{
+       if (mode == 's')
+               soft_restart(0);
+
+       /* errata "Watch-dog/Software Reset Problem" specifies that
+        * this reset must be done with the SYSCLK sourced from
+        * EXTCLK instead of FOUT to avoid a glitch in the reset
+        * mechanism.
+        *
+        * See the watchdog section of the S3C2412 manual for more
+        * information on this fix.
+        */
+
+       __raw_writel(0x00, S3C2412_CLKSRC);
+       __raw_writel(S3C2412_SWRST_RESET, S3C2412_SWRST);
+
+       mdelay(1);
+}
+
+/* s3c2412_map_io
+ *
+ * register the standard cpu IO areas, and any passed in from the
+ * machine specific initialisation.
+*/
+
+void __init s3c2412_map_io(void)
+{
+       /* move base of IO */
+
+       s3c2412_init_gpio2();
+
+       /* set our idle function */
+
+       arm_pm_idle = s3c2412_idle;
+
+       /* register our io-tables */
+
+       iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
+}
+
+void __init_or_cpufreq s3c2412_setup_clocks(void)
+{
+       struct clk *xtal_clk;
+       unsigned long tmp;
+       unsigned long xtal;
+       unsigned long fclk;
+       unsigned long hclk;
+       unsigned long pclk;
+
+       xtal_clk = clk_get(NULL, "xtal");
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
+
+       /* now we've got our machine bits initialised, work out what
+        * clocks we've got */
+
+       fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal * 2);
+
+       clk_mpll.rate = fclk;
+
+       tmp = __raw_readl(S3C2410_CLKDIVN);
+
+       /* work out clock scalings */
+
+       hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1);
+       hclk /= ((tmp & S3C2412_CLKDIVN_ARMDIVN) ? 2 : 1);
+       pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1);
+
+       /* print brieft summary of clocks, etc */
+
+       printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
+              print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
+
+       s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c2412_init_clocks(int xtal)
+{
+       /* initialise the clocks here, to allow other things like the
+        * console to use them
+        */
+
+       s3c24xx_register_baseclocks(xtal);
+       s3c2412_setup_clocks();
+       s3c2412_baseclk_add();
+}
+
+/* need to register the subsystem before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2412 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
+
+struct bus_type s3c2412_subsys = {
+       .name = "s3c2412-core",
+       .dev_name = "s3c2412-core",
+};
+
+static int __init s3c2412_core_init(void)
+{
+       return subsys_system_register(&s3c2412_subsys, NULL);
+}
+
+core_initcall(s3c2412_core_init);
+
+static struct device s3c2412_dev = {
+       .bus            = &s3c2412_subsys,
+};
+
+int __init s3c2412_init(void)
+{
+       printk("S3C2412: Initialising architecture\n");
+
+#ifdef CONFIG_PM
+       register_syscore_ops(&s3c2412_pm_syscore_ops);
+#endif
+       register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
+       return device_register(&s3c2412_dev);
+}
diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c
new file mode 100644 (file)
index 0000000..7743fad
--- /dev/null
@@ -0,0 +1,149 @@
+/* linux/arch/arm/mach-s3c2416/s3c2416.c
+ *
+ * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>,
+ *     as part of OpenInkpot project
+ * Copyright (c) 2009 Promwad Innovation Company
+ *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
+ *
+ * Samsung S3C2416 Mobile CPU support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/proc-fns.h>
+#include <asm/irq.h>
+#include <asm/system_misc.h>
+
+#include <mach/regs-s3c2443-clock.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+#include <plat/s3c2416.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/sdhci.h>
+#include <plat/pm.h>
+
+#include <plat/iic-core.h>
+#include <plat/fb-core.h>
+#include <plat/nand-core.h>
+#include <plat/adc-core.h>
+#include <plat/rtc-core.h>
+
+static struct map_desc s3c2416_iodesc[] __initdata = {
+       IODESC_ENT(WATCHDOG),
+       IODESC_ENT(CLKPWR),
+       IODESC_ENT(TIMER),
+};
+
+struct bus_type s3c2416_subsys = {
+       .name = "s3c2416-core",
+       .dev_name = "s3c2416-core",
+};
+
+static struct device s3c2416_dev = {
+       .bus            = &s3c2416_subsys,
+};
+
+void s3c2416_restart(char mode, const char *cmd)
+{
+       if (mode == 's')
+               soft_restart(0);
+
+       __raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
+}
+
+int __init s3c2416_init(void)
+{
+       printk(KERN_INFO "S3C2416: Initializing architecture\n");
+
+       /* change WDT IRQ number */
+       s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT;
+       s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT;
+
+       /* the i2c devices are directly compatible with s3c2440 */
+       s3c_i2c0_setname("s3c2440-i2c");
+       s3c_i2c1_setname("s3c2440-i2c");
+
+       s3c_fb_setname("s3c2443-fb");
+
+       s3c_adc_setname("s3c2416-adc");
+       s3c_rtc_setname("s3c2416-rtc");
+
+#ifdef CONFIG_PM
+       register_syscore_ops(&s3c2416_pm_syscore_ops);
+#endif
+       register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
+       return device_register(&s3c2416_dev);
+}
+
+void __init s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
+
+       s3c_nand_setname("s3c2412-nand");
+}
+
+/* s3c2416_map_io
+ *
+ * register the standard cpu IO areas, and any passed in from the
+ * machine specific initialisation.
+ */
+
+void __init s3c2416_map_io(void)
+{
+       s3c24xx_gpiocfg_default.set_pull = samsung_gpio_setpull_updown;
+       s3c24xx_gpiocfg_default.get_pull = samsung_gpio_getpull_updown;
+
+       /* initialize device information early */
+       s3c2416_default_sdhci0();
+       s3c2416_default_sdhci1();
+
+       iotable_init(s3c2416_iodesc, ARRAY_SIZE(s3c2416_iodesc));
+}
+
+/* need to register the subsystem before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2416 based system)
+ * as a driver which may support both 2443 and 2440 may try and use it.
+*/
+
+static int __init s3c2416_core_init(void)
+{
+       return subsys_system_register(&s3c2416_subsys, NULL);
+}
+
+core_initcall(s3c2416_core_init);
diff --git a/arch/arm/mach-s3c24xx/s3c2440.c b/arch/arm/mach-s3c24xx/s3c2440.c
new file mode 100644 (file)
index 0000000..2b3dddb
--- /dev/null
@@ -0,0 +1,75 @@
+/* linux/arch/arm/mach-s3c2440/s3c2440.c
+ *
+ * Copyright (c) 2004-2006 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2440 Mobile CPU support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/s3c244x.h>
+#include <plat/pm.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+
+static struct device s3c2440_dev = {
+       .bus            = &s3c2440_subsys,
+};
+
+int __init s3c2440_init(void)
+{
+       printk("S3C2440: Initialising architecture\n");
+
+       /* change irq for watchdog */
+
+       s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
+       s3c_device_wdt.resource[1].end   = IRQ_S3C2440_WDT;
+
+       /* register suspend/resume handlers */
+
+#ifdef CONFIG_PM
+       register_syscore_ops(&s3c2410_pm_syscore_ops);
+#endif
+       register_syscore_ops(&s3c244x_pm_syscore_ops);
+       register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
+       /* register our system device for everything else */
+
+       return device_register(&s3c2440_dev);
+}
+
+void __init s3c2440_map_io(void)
+{
+       s3c244x_map_io();
+
+       s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up;
+       s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up;
+}
diff --git a/arch/arm/mach-s3c24xx/s3c2442.c b/arch/arm/mach-s3c24xx/s3c2442.c
new file mode 100644 (file)
index 0000000..22cb7c9
--- /dev/null
@@ -0,0 +1,188 @@
+/* linux/arch/arm/mach-s3c2442/s3c2442.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2442 core and lock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <linux/atomic.h>
+#include <asm/irq.h>
+
+#include <mach/regs-clock.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/s3c244x.h>
+#include <plat/pm.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+
+/* S3C2442 extended clock support */
+
+static unsigned long s3c2442_camif_upll_round(struct clk *clk,
+                                             unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       int div;
+
+       if (rate > parent_rate)
+               return parent_rate;
+
+       div = parent_rate / rate;
+
+       if (div == 3)
+               return parent_rate / 3;
+
+       /* note, we remove the +/- 1 calculations for the divisor */
+
+       div /= 2;
+
+       if (div < 1)
+               div = 1;
+       else if (div > 16)
+               div = 16;
+
+       return parent_rate / (div * 2);
+}
+
+static int s3c2442_camif_upll_setrate(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long camdivn =  __raw_readl(S3C2440_CAMDIVN);
+
+       rate = s3c2442_camif_upll_round(clk, rate);
+
+       camdivn &= ~S3C2442_CAMDIVN_CAMCLK_DIV3;
+
+       if (rate == parent_rate) {
+               camdivn &= ~S3C2440_CAMDIVN_CAMCLK_SEL;
+       } else if ((parent_rate / rate) == 3) {
+               camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
+               camdivn |= S3C2442_CAMDIVN_CAMCLK_DIV3;
+       } else {
+               camdivn &= ~S3C2440_CAMDIVN_CAMCLK_MASK;
+               camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
+               camdivn |= (((parent_rate / rate) / 2) - 1);
+       }
+
+       __raw_writel(camdivn, S3C2440_CAMDIVN);
+
+       return 0;
+}
+
+/* Extra S3C2442 clocks */
+
+static struct clk s3c2442_clk_cam = {
+       .name           = "camif",
+       .id             = -1,
+       .enable         = s3c2410_clkcon_enable,
+       .ctrlbit        = S3C2440_CLKCON_CAMERA,
+};
+
+static struct clk s3c2442_clk_cam_upll = {
+       .name           = "camif-upll",
+       .id             = -1,
+       .ops            = &(struct clk_ops) {
+               .set_rate       = s3c2442_camif_upll_setrate,
+               .round_rate     = s3c2442_camif_upll_round,
+       },
+};
+
+static int s3c2442_clk_add(struct device *dev, struct subsys_interface *sif)
+{
+       struct clk *clock_upll;
+       struct clk *clock_h;
+       struct clk *clock_p;
+
+       clock_p = clk_get(NULL, "pclk");
+       clock_h = clk_get(NULL, "hclk");
+       clock_upll = clk_get(NULL, "upll");
+
+       if (IS_ERR(clock_p) || IS_ERR(clock_h) || IS_ERR(clock_upll)) {
+               printk(KERN_ERR "S3C2442: Failed to get parent clocks\n");
+               return -EINVAL;
+       }
+
+       s3c2442_clk_cam.parent = clock_h;
+       s3c2442_clk_cam_upll.parent = clock_upll;
+
+       s3c24xx_register_clock(&s3c2442_clk_cam);
+       s3c24xx_register_clock(&s3c2442_clk_cam_upll);
+
+       clk_disable(&s3c2442_clk_cam);
+
+       return 0;
+}
+
+static struct subsys_interface s3c2442_clk_interface = {
+       .name           = "s3c2442_clk",
+       .subsys         = &s3c2442_subsys,
+       .add_dev        = s3c2442_clk_add,
+};
+
+static __init int s3c2442_clk_init(void)
+{
+       return subsys_interface_register(&s3c2442_clk_interface);
+}
+
+arch_initcall(s3c2442_clk_init);
+
+
+static struct device s3c2442_dev = {
+       .bus            = &s3c2442_subsys,
+};
+
+int __init s3c2442_init(void)
+{
+       printk("S3C2442: Initialising architecture\n");
+
+#ifdef CONFIG_PM
+       register_syscore_ops(&s3c2410_pm_syscore_ops);
+#endif
+       register_syscore_ops(&s3c244x_pm_syscore_ops);
+       register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
+       return device_register(&s3c2442_dev);
+}
+
+void __init s3c2442_map_io(void)
+{
+       s3c244x_map_io();
+
+       s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1down;
+       s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1down;
+}
diff --git a/arch/arm/mach-s3c24xx/s3c2443.c b/arch/arm/mach-s3c24xx/s3c2443.c
new file mode 100644 (file)
index 0000000..ab648ad
--- /dev/null
@@ -0,0 +1,117 @@
+/* linux/arch/arm/mach-s3c2443/s3c2443.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2443 Mobile CPU support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/system_misc.h>
+
+#include <mach/regs-s3c2443-clock.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+#include <plat/s3c2443.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/fb-core.h>
+#include <plat/nand-core.h>
+#include <plat/adc-core.h>
+#include <plat/rtc-core.h>
+
+static struct map_desc s3c2443_iodesc[] __initdata = {
+       IODESC_ENT(WATCHDOG),
+       IODESC_ENT(CLKPWR),
+       IODESC_ENT(TIMER),
+};
+
+struct bus_type s3c2443_subsys = {
+       .name = "s3c2443-core",
+       .dev_name = "s3c2443-core",
+};
+
+static struct device s3c2443_dev = {
+       .bus            = &s3c2443_subsys,
+};
+
+void s3c2443_restart(char mode, const char *cmd)
+{
+       if (mode == 's')
+               soft_restart(0);
+
+       __raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
+}
+
+int __init s3c2443_init(void)
+{
+       printk("S3C2443: Initialising architecture\n");
+
+       s3c_nand_setname("s3c2412-nand");
+       s3c_fb_setname("s3c2443-fb");
+
+       s3c_adc_setname("s3c2443-adc");
+       s3c_rtc_setname("s3c2443-rtc");
+
+       /* change WDT IRQ number */
+       s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT;
+       s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT;
+
+       return device_register(&s3c2443_dev);
+}
+
+void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
+}
+
+/* s3c2443_map_io
+ *
+ * register the standard cpu IO areas, and any passed in from the
+ * machine specific initialisation.
+ */
+
+void __init s3c2443_map_io(void)
+{
+       s3c24xx_gpiocfg_default.set_pull = s3c2443_gpio_setpull;
+       s3c24xx_gpiocfg_default.get_pull = s3c2443_gpio_getpull;
+
+       iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
+}
+
+/* need to register the subsystem before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2443 based system)
+ * as a driver which may support both 2443 and 2440 may try and use it.
+*/
+
+static int __init s3c2443_core_init(void)
+{
+       return subsys_system_register(&s3c2443_subsys, NULL);
+}
+
+core_initcall(s3c2443_core_init);
diff --git a/arch/arm/mach-s3c24xx/s3c244x.c b/arch/arm/mach-s3c24xx/s3c244x.c
new file mode 100644 (file)
index 0000000..6f74118
--- /dev/null
@@ -0,0 +1,211 @@
+/* linux/arch/arm/plat-s3c24xx/s3c244x.c
+ *
+ * Copyright (c) 2004-2006 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2440 and S3C2442 Mobile CPU support (not S3C2443)
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/syscore_ops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/system_misc.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <plat/cpu-freq.h>
+
+#include <mach/regs-clock.h>
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-gpioj.h>
+#include <mach/regs-dsc.h>
+
+#include <plat/s3c2410.h>
+#include <plat/s3c244x.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/pll.h>
+#include <plat/nand-core.h>
+#include <plat/watchdog-reset.h>
+
+static struct map_desc s3c244x_iodesc[] __initdata = {
+       IODESC_ENT(CLKPWR),
+       IODESC_ENT(TIMER),
+       IODESC_ENT(WATCHDOG),
+};
+
+/* uart initialisation */
+
+void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
+}
+
+void __init s3c244x_map_io(void)
+{
+       /* register our io-tables */
+
+       iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
+
+       /* rename any peripherals used differing from the s3c2410 */
+
+       s3c_device_sdi.name  = "s3c2440-sdi";
+       s3c_device_i2c0.name  = "s3c2440-i2c";
+       s3c_nand_setname("s3c2440-nand");
+       s3c_device_ts.name = "s3c2440-ts";
+       s3c_device_usbgadget.name = "s3c2440-usbgadget";
+}
+
+void __init_or_cpufreq s3c244x_setup_clocks(void)
+{
+       struct clk *xtal_clk;
+       unsigned long clkdiv;
+       unsigned long camdiv;
+       unsigned long xtal;
+       unsigned long hclk, fclk, pclk;
+       int hdiv = 1;
+
+       xtal_clk = clk_get(NULL, "xtal");
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
+
+       fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
+
+       clkdiv = __raw_readl(S3C2410_CLKDIVN);
+       camdiv = __raw_readl(S3C2440_CAMDIVN);
+
+       /* work out clock scalings */
+
+       switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
+       case S3C2440_CLKDIVN_HDIVN_1:
+               hdiv = 1;
+               break;
+
+       case S3C2440_CLKDIVN_HDIVN_2:
+               hdiv = 2;
+               break;
+
+       case S3C2440_CLKDIVN_HDIVN_4_8:
+               hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
+               break;
+
+       case S3C2440_CLKDIVN_HDIVN_3_6:
+               hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
+               break;
+       }
+
+       hclk = fclk / hdiv;
+       pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
+
+       /* print brief summary of clocks, etc */
+
+       printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
+              print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
+
+       s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c244x_init_clocks(int xtal)
+{
+       /* initialise the clocks here, to allow other things like the
+        * console to use them, and to add new ones after the initialisation
+        */
+
+       s3c24xx_register_baseclocks(xtal);
+       s3c244x_setup_clocks();
+       s3c2410_baseclk_add();
+}
+
+/* Since the S3C2442 and S3C2440 share items, put both subsystems here */
+
+struct bus_type s3c2440_subsys = {
+       .name           = "s3c2440-core",
+       .dev_name       = "s3c2440-core",
+};
+
+struct bus_type s3c2442_subsys = {
+       .name           = "s3c2442-core",
+       .dev_name       = "s3c2442-core",
+};
+
+/* need to register the subsystem before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2440 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
+
+static int __init s3c2440_core_init(void)
+{
+       return subsys_system_register(&s3c2440_subsys, NULL);
+}
+
+core_initcall(s3c2440_core_init);
+
+static int __init s3c2442_core_init(void)
+{
+       return subsys_system_register(&s3c2442_subsys, NULL);
+}
+
+core_initcall(s3c2442_core_init);
+
+
+#ifdef CONFIG_PM
+static struct sleep_save s3c244x_sleep[] = {
+       SAVE_ITEM(S3C2440_DSC0),
+       SAVE_ITEM(S3C2440_DSC1),
+       SAVE_ITEM(S3C2440_GPJDAT),
+       SAVE_ITEM(S3C2440_GPJCON),
+       SAVE_ITEM(S3C2440_GPJUP)
+};
+
+static int s3c244x_suspend(void)
+{
+       s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+       return 0;
+}
+
+static void s3c244x_resume(void)
+{
+       s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+}
+#else
+#define s3c244x_suspend NULL
+#define s3c244x_resume  NULL
+#endif
+
+struct syscore_ops s3c244x_pm_syscore_ops = {
+       .suspend        = s3c244x_suspend,
+       .resume         = s3c244x_resume,
+};
+
+void s3c244x_restart(char mode, const char *cmd)
+{
+       if (mode == 's')
+               soft_restart(0);
+
+       arch_wdt_reset();
+
+       /* we'll take a jump through zero as a poor second */
+       soft_restart(0);
+}
diff --git a/arch/arm/mach-s3c24xx/setup-i2c.c b/arch/arm/mach-s3c24xx/setup-i2c.c
new file mode 100644 (file)
index 0000000..9e90a7c
--- /dev/null
@@ -0,0 +1,27 @@
+/* linux/arch/arm/plat-s3c24xx/setup-i2c.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX Base setup for i2c device
+ *
+ * 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/gpio.h>
+
+struct platform_device;
+
+#include <plat/gpio-cfg.h>
+#include <plat/iic.h>
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+
+void s3c_i2c0_cfg_gpio(struct platform_device *dev)
+{
+       s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
+       s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
+}
diff --git a/arch/arm/mach-s3c24xx/setup-sdhci-gpio.c b/arch/arm/mach-s3c24xx/setup-sdhci-gpio.c
new file mode 100644 (file)
index 0000000..f65cb3e
--- /dev/null
@@ -0,0 +1,34 @@
+/* linux/arch/arm/plat-s3c2416/setup-sdhci-gpio.c
+ *
+ * Copyright 2010 Promwad Innovation Company
+ *     Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
+ *
+ * S3C2416 - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
+ *
+ * Based on mach-s3c64xx/setup-sdhci-gpio.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/regs-gpio.h>
+#include <plat/gpio-cfg.h>
+
+void s3c2416_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
+{
+       s3c_gpio_cfgrange_nopull(S3C2410_GPE(5), 2 + width, S3C_GPIO_SFN(2));
+}
+
+void s3c2416_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
+{
+       s3c_gpio_cfgrange_nopull(S3C2410_GPL(0), width, S3C_GPIO_SFN(2));
+       s3c_gpio_cfgrange_nopull(S3C2410_GPL(8), 2, S3C_GPIO_SFN(2));
+}
diff --git a/arch/arm/mach-s3c24xx/setup-ts.c b/arch/arm/mach-s3c24xx/setup-ts.c
new file mode 100644 (file)
index 0000000..ed26386
--- /dev/null
@@ -0,0 +1,34 @@
+/* linux/arch/arm/plat-s3c24xx/setup-ts.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *                     http://www.samsung.com/
+ *
+ * Based on S3C24XX setup for i2c device
+ *
+ * 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/gpio.h>
+
+struct platform_device; /* don't need the contents */
+
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+
+/**
+ * s3c24xx_ts_cfg_gpio - configure gpio for s3c2410 systems
+ *
+ * Configure the GPIO for the S3C2410 system, where we have external FETs
+ * connected to the device (later systems such as the S3C2440 integrate
+ * these into the device).
+ */
+void s3c24xx_ts_cfg_gpio(struct platform_device *dev)
+{
+       s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON);
+       s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON);
+       s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON);
+       s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON);
+}
diff --git a/arch/arm/mach-s3c24xx/simtec-audio.c b/arch/arm/mach-s3c24xx/simtec-audio.c
new file mode 100644 (file)
index 0000000..11881c9
--- /dev/null
@@ -0,0 +1,79 @@
+/* linux/arch/arm/plat-s3c24xx/simtec-audio.c
+ *
+ * Copyright (c) 2009 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Audio setup for various Simtec S3C24XX implementations
+ *
+ * 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/interrupt.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <mach/bast-map.h>
+#include <mach/bast-irq.h>
+#include <mach/bast-cpld.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/audio-simtec.h>
+#include <plat/devs.h>
+
+#include "simtec.h"
+
+/* platform ops for audio */
+
+static void simtec_audio_startup_lrroute(void)
+{
+       unsigned int tmp;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       tmp = __raw_readb(BAST_VA_CTRL1);
+       tmp &= ~BAST_CPLD_CTRL1_LRMASK;
+       tmp |= BAST_CPLD_CTRL1_LRCDAC;
+       __raw_writeb(tmp, BAST_VA_CTRL1);
+
+       local_irq_restore(flags);
+}
+
+static struct s3c24xx_audio_simtec_pdata simtec_audio_platdata;
+static char our_name[32];
+
+static struct platform_device simtec_audio_dev = {
+       .name   = our_name,
+       .id     = -1,
+       .dev    = {
+               .parent         = &s3c_device_iis.dev,
+               .platform_data  = &simtec_audio_platdata,
+       },
+};
+
+int __init simtec_audio_add(const char *name, bool has_lr_routing,
+                           struct s3c24xx_audio_simtec_pdata *spd)
+{
+       if (!name)
+               name = "tlv320aic23";
+
+       snprintf(our_name, sizeof(our_name)-1, "s3c24xx-simtec-%s", name);
+
+       /* copy platform data so the source can be __initdata */
+       if (spd)
+               simtec_audio_platdata = *spd;
+
+       if (has_lr_routing)
+               simtec_audio_platdata.startup = simtec_audio_startup_lrroute;
+
+       platform_device_register(&s3c_device_iis);
+       platform_device_register(&simtec_audio_dev);
+       return 0;
+}
diff --git a/arch/arm/mach-s3c24xx/simtec-nor.c b/arch/arm/mach-s3c24xx/simtec-nor.c
new file mode 100644 (file)
index 0000000..2119ca6
--- /dev/null
@@ -0,0 +1,87 @@
+/* linux/arch/arm/mach-s3c2410/nor-simtec.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec NOR mapping
+ *
+ * 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/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/map.h>
+#include <mach/bast-map.h>
+#include <mach/bast-cpld.h>
+
+#include "simtec.h"
+
+static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       val = __raw_readb(BAST_VA_CTRL3);
+
+       printk(KERN_DEBUG "%s(%d)\n", __func__, vpp);
+
+       if (vpp)
+               val |= BAST_CPLD_CTRL3_ROMWEN;
+       else
+               val &= ~BAST_CPLD_CTRL3_ROMWEN;
+
+       __raw_writeb(val, BAST_VA_CTRL3);
+       local_irq_restore(flags);
+}
+
+static struct physmap_flash_data simtec_nor_pdata = {
+       .width          = 2,
+       .set_vpp        = simtec_nor_vpp,
+       .nr_parts       = 0,
+};
+
+static struct resource simtec_nor_resource[] = {
+       [0] = {
+               .start = S3C2410_CS1 + 0x4000000,
+               .end   = S3C2410_CS1 + 0x4000000 + SZ_8M - 1,
+               .flags = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device simtec_device_nor = {
+       .name           = "physmap-flash",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(simtec_nor_resource),
+       .resource       = simtec_nor_resource,
+       .dev            = {
+               .platform_data = &simtec_nor_pdata,
+       },
+};
+
+void __init nor_simtec_init(void)
+{
+       int ret;
+
+       ret = platform_device_register(&simtec_device_nor);
+       if (ret < 0)
+               printk(KERN_ERR "failed to register physmap-flash device\n");
+       else
+               simtec_nor_vpp(NULL, 1);
+}
diff --git a/arch/arm/mach-s3c24xx/simtec-pm.c b/arch/arm/mach-s3c24xx/simtec-pm.c
new file mode 100644 (file)
index 0000000..699f931
--- /dev/null
@@ -0,0 +1,66 @@
+/* linux/arch/arm/plat-s3c24xx/pm-simtec.c
+ *
+ * Copyright 2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * Power Management helpers for Simtec S3C24XX implementations
+ *
+ * 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+
+#include <mach/map.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-mem.h>
+
+#include <asm/mach-types.h>
+
+#include <plat/pm.h>
+
+#define COPYRIGHT ", Copyright 2005 Simtec Electronics"
+
+/* pm_simtec_init
+ *
+ * enable the power management functions
+*/
+
+static __init int pm_simtec_init(void)
+{
+       unsigned long gstatus4;
+
+       /* check which machine we are running on */
+
+       if (!machine_is_bast() && !machine_is_vr1000() &&
+           !machine_is_anubis() && !machine_is_osiris() &&
+           !machine_is_aml_m5900())
+               return 0;
+
+       printk(KERN_INFO "Simtec Board Power Management" COPYRIGHT "\n");
+
+       gstatus4  = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30;
+       gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28;
+       gstatus4 |= (__raw_readl(S3C2410_BANKSIZE) & S3C2410_BANKSIZE_MASK);
+
+       __raw_writel(gstatus4, S3C2410_GSTATUS4);
+
+       return s3c_pm_init();
+}
+
+arch_initcall(pm_simtec_init);
diff --git a/arch/arm/mach-s3c24xx/simtec-usb.c b/arch/arm/mach-s3c24xx/simtec-usb.c
new file mode 100644 (file)
index 0000000..d91c1a7
--- /dev/null
@@ -0,0 +1,132 @@
+/* linux/arch/arm/mach-s3c2410/usb-simtec.c
+ *
+ * Copyright 2004-2005 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.simtec.co.uk/products/EB2410ITX/
+ *
+ * Simtec BAST and Thorcom VR1000 USB port support functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/gpio.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/bast-map.h>
+#include <mach/bast-irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <plat/usb-control.h>
+#include <plat/devs.h>
+
+#include "simtec.h"
+
+/* control power and monitor over-current events on various Simtec
+ * designed boards.
+*/
+
+static unsigned int power_state[2];
+
+static void
+usb_simtec_powercontrol(int port, int to)
+{
+       pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
+
+       power_state[port] = to;
+
+       if (power_state[0] && power_state[1])
+               gpio_set_value(S3C2410_GPB(4), 0);
+       else
+               gpio_set_value(S3C2410_GPB(4), 1);
+}
+
+static irqreturn_t
+usb_simtec_ocirq(int irq, void *pw)
+{
+       struct s3c2410_hcd_info *info = pw;
+
+       if (gpio_get_value(S3C2410_GPG(10)) == 0) {
+               pr_debug("usb_simtec: over-current irq (oc detected)\n");
+               s3c2410_usb_report_oc(info, 3);
+       } else {
+               pr_debug("usb_simtec: over-current irq (oc cleared)\n");
+               s3c2410_usb_report_oc(info, 0);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
+{
+       int ret;
+
+       if (on) {
+               ret = request_irq(IRQ_USBOC, usb_simtec_ocirq,
+                                 IRQF_DISABLED | IRQF_TRIGGER_RISING |
+                                  IRQF_TRIGGER_FALLING,
+                                 "USB Over-current", info);
+               if (ret != 0) {
+                       printk(KERN_ERR "failed to request usb oc irq\n");
+               }
+       } else {
+               free_irq(IRQ_USBOC, info);
+       }
+}
+
+static struct s3c2410_hcd_info usb_simtec_info __initdata = {
+       .port[0]        = {
+               .flags  = S3C_HCDFLG_USED
+       },
+       .port[1]        = {
+               .flags  = S3C_HCDFLG_USED
+       },
+
+       .power_control  = usb_simtec_powercontrol,
+       .enable_oc      = usb_simtec_enableoc,
+};
+
+
+int usb_simtec_init(void)
+{
+       int ret;
+
+       printk("USB Power Control, Copyright 2004 Simtec Electronics\n");
+
+       ret = gpio_request(S3C2410_GPB(4), "USB power control");
+       if (ret < 0) {
+               pr_err("%s: failed to get GPB4\n", __func__);
+               return ret;
+       }
+
+       ret = gpio_request(S3C2410_GPG(10), "USB overcurrent");
+       if (ret < 0) {
+               pr_err("%s: failed to get GPG10\n", __func__);
+               gpio_free(S3C2410_GPB(4));
+               return ret;
+       }
+
+       /* turn power on */
+       gpio_direction_output(S3C2410_GPB(4), 1);
+       gpio_direction_input(S3C2410_GPG(10));
+
+       s3c_ohci_set_platdata(&usb_simtec_info);
+       return 0;
+}
diff --git a/arch/arm/mach-s3c24xx/simtec.h b/arch/arm/mach-s3c24xx/simtec.h
new file mode 100644 (file)
index 0000000..ae8f4f9
--- /dev/null
@@ -0,0 +1,21 @@
+/* linux/arch/arm/mach-s3c2410/nor-simtec.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec common functions
+ *
+ * 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 s3c24xx_audio_simtec_pdata;
+
+extern void nor_simtec_init(void);
+
+extern int usb_simtec_init(void);
+
+extern int simtec_audio_add(const char *codec_name, bool has_lr_routing,
+                           struct s3c24xx_audio_simtec_pdata *pdata);
diff --git a/arch/arm/mach-s3c24xx/sleep-s3c2410.S b/arch/arm/mach-s3c24xx/sleep-s3c2410.S
new file mode 100644 (file)
index 0000000..dd5b638
--- /dev/null
@@ -0,0 +1,68 @@
+/* linux/arch/arm/mach-s3c2410/sleep.S
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 Power Manager (Suspend-To-RAM) support
+ *
+ * Based on PXA/SA1100 sleep code by:
+ *     Nicolas Pitre, (c) 2002 Monta Vista Software Inc
+ *     Cliff Brake, (c) 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-mem.h>
+#include <plat/regs-serial.h>
+
+       /* s3c2410_cpu_suspend
+        *
+        * put the cpu into sleep mode
+       */
+
+ENTRY(s3c2410_cpu_suspend)
+       @@ prepare cpu to sleep
+
+       ldr     r4, =S3C2410_REFRESH
+       ldr     r5, =S3C24XX_MISCCR
+       ldr     r6, =S3C2410_CLKCON
+       ldr     r7, [ r4 ]              @ get REFRESH (and ensure in TLB)
+       ldr     r8, [ r5 ]              @ get MISCCR (and ensure in TLB)
+       ldr     r9, [ r6 ]              @ get CLKCON (and ensure in TLB)
+
+       orr     r7, r7, #S3C2410_REFRESH_SELF   @ SDRAM sleep command
+       orr     r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
+       orr     r9, r9, #S3C2410_CLKCON_POWER   @ power down command
+
+       teq     pc, #0                  @ first as a trial-run to load cache
+       bl      s3c2410_do_sleep
+       teq     r0, r0                  @ now do it for real
+       b       s3c2410_do_sleep        @
+
+       @@ align next bit of code to cache line
+       .align  5
+s3c2410_do_sleep:
+       streq   r7, [ r4 ]                      @ SDRAM sleep command
+       streq   r8, [ r5 ]                      @ SDRAM power-down config
+       streq   r9, [ r6 ]                      @ CPU sleep
+1:     beq     1b
+       mov     pc, r14
diff --git a/arch/arm/mach-s3c24xx/sleep-s3c2412.S b/arch/arm/mach-s3c24xx/sleep-s3c2412.S
new file mode 100644 (file)
index 0000000..c82418e
--- /dev/null
@@ -0,0 +1,68 @@
+/* linux/arch/arm/mach-s3c2412/sleep.S
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2412 Power Manager low-level sleep support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <mach/regs-irq.h>
+
+       .text
+
+       .global s3c2412_sleep_enter
+
+s3c2412_sleep_enter:
+       mov     r0, #0                  /* argument for coprocessors */
+       ldr     r1, =S3C2410_INTPND
+       ldr     r2, =S3C2410_SRCPND
+       ldr     r3, =S3C2410_EINTPEND
+
+       teq     r0, r0
+       bl      s3c2412_sleep_enter1
+       teq     pc, r0
+       bl      s3c2412_sleep_enter1
+
+       .align  5
+
+       /* this is called twice, first with the Z flag to ensure that the
+        * instructions have been loaded into the cache, and the second
+        * time to try and suspend the system.
+       */
+s3c2412_sleep_enter1:
+       mcr     p15, 0, r0, c7, c10, 4
+       mcrne   p15, 0, r0, c7, c0, 4
+
+       /* if we return from here, it is because an interrupt was
+        * active when we tried to shutdown. Try and ack the IRQ and
+        * retry, as simply returning causes the system to lock.
+       */
+
+       ldrne   r9, [ r1 ]
+       strne   r9, [ r1 ]
+       ldrne   r9, [ r2 ]
+       strne   r9, [ r2 ]
+       ldrne   r9, [ r3 ]
+       strne   r9, [ r3 ]
+       bne     s3c2412_sleep_enter1
+
+       mov     pc, r14
index dd20c66..82c0915 100644 (file)
@@ -83,6 +83,11 @@ config S3C64XX_SETUP_SPI
        help
         Common setup code for SPI GPIO configurations
 
+config S3C64XX_SETUP_USB_PHY
+       bool
+       help
+         Common setup code for USB PHY controller
+
 # S36400 Macchine support
 
 config MACH_SMDK6400
@@ -157,6 +162,7 @@ config MACH_SMDK6410
        select S3C64XX_SETUP_IDE
        select S3C64XX_SETUP_FB_24BPP
        select S3C64XX_SETUP_KEYPAD
+       select S3C64XX_SETUP_USB_PHY
        help
          Machine support for the Samsung SMDK6410
 
@@ -256,6 +262,7 @@ config MACH_SMARTQ
        select S3C_DEV_USB_HOST
        select S3C64XX_SETUP_SDHCI
        select S3C64XX_SETUP_FB_24BPP
+       select S3C64XX_SETUP_USB_PHY
        select SAMSUNG_DEV_ADC
        select SAMSUNG_DEV_PWM
        select SAMSUNG_DEV_TS
@@ -283,6 +290,7 @@ config MACH_WLF_CRAGG_6410
        select S3C64XX_SETUP_FB_24BPP
        select S3C64XX_SETUP_KEYPAD
        select S3C64XX_SETUP_SPI
+       select S3C64XX_SETUP_USB_PHY
        select SAMSUNG_DEV_ADC
        select SAMSUNG_DEV_KEYPAD
        select S3C_DEV_USB_HOST
@@ -296,5 +304,6 @@ config MACH_WLF_CRAGG_6410
        select S3C64XX_DEV_SPI0
        select SAMSUNG_GPIO_EXTRA128
        select I2C
+       select LEDS_GPIO_REGISTER
        help
          Machine support for the Wolfson Cragganmore S3C6410 variant.
index 1822ac2..f9ce1dc 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_CPU_S3C6410)     += s3c6410.o
 # PM
 
 obj-$(CONFIG_PM)               += pm.o irq-pm.o sleep.o
+obj-$(CONFIG_CPU_IDLE)         += cpuidle.o
 
 # DMA support
 
@@ -42,6 +43,7 @@ obj-$(CONFIG_S3C64XX_SETUP_IDE)               += setup-ide.o
 obj-$(CONFIG_S3C64XX_SETUP_KEYPAD)     += setup-keypad.o
 obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
 obj-$(CONFIG_S3C64XX_SETUP_SPI)                += setup-spi.o
+obj-$(CONFIG_S3C64XX_SETUP_USB_PHY) += setup-usb-phy.o
 
 # Machine support
 
index aebbcc2..52f079a 100644 (file)
@@ -207,6 +207,15 @@ static struct clk init_clocks_off[] = {
                .enable         = s3c64xx_sclk_ctrl,
                .ctrlbit        = S3C_CLKCON_SCLK_MMC2_48,
        }, {
+               .name           = "ac97",
+               .parent         = &clk_p,
+               .ctrlbit        = S3C_CLKCON_PCLK_AC97,
+       }, {
+               .name           = "cfcon",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_IHOST,
+       }, {
                .name           = "dma0",
                .parent         = &clk_h,
                .enable         = s3c64xx_hclk_ctrl,
@@ -216,6 +225,107 @@ static struct clk init_clocks_off[] = {
                .parent         = &clk_h,
                .enable         = s3c64xx_hclk_ctrl,
                .ctrlbit        = S3C_CLKCON_HCLK_DMA1,
+       }, {
+               .name           = "3dse",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_3DSE,
+       }, {
+               .name           = "hclk_secur",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_SECUR,
+       }, {
+               .name           = "sdma1",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_SDMA1,
+       }, {
+               .name           = "sdma0",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_SDMA0,
+       }, {
+               .name           = "hclk_jpeg",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_JPEG,
+       }, {
+               .name           = "camif",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_CAMIF,
+       }, {
+               .name           = "hclk_scaler",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_SCALER,
+       }, {
+               .name           = "2d",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_2D,
+       }, {
+               .name           = "tv",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_TV,
+       }, {
+               .name           = "post0",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_POST0,
+       }, {
+               .name           = "rot",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_ROT,
+       }, {
+               .name           = "hclk_mfc",
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_MFC,
+       }, {
+               .name           = "pclk_mfc",
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_MFC,
+       }, {
+               .name           = "dac27",
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_DAC27,
+       }, {
+               .name           = "tv27",
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_TV27,
+       }, {
+               .name           = "scaler27",
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_SCALER27,
+       }, {
+               .name           = "sclk_scaler",
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_SCALER,
+       }, {
+               .name           = "post0_27",
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_POST0_27,
+       }, {
+               .name           = "secur",
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_SECUR,
+       }, {
+               .name           = "sclk_mfc",
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_MFC,
+       }, {
+               .name           = "cam",
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_CAM,
+       }, {
+               .name           = "sclk_jpeg",
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_JPEG,
        },
 };
 
@@ -289,16 +399,7 @@ static struct clk init_clocks[] = {
                .name           = "watchdog",
                .parent         = &clk_p,
                .ctrlbit        = S3C_CLKCON_PCLK_WDT,
-       }, {
-               .name           = "ac97",
-               .parent         = &clk_p,
-               .ctrlbit        = S3C_CLKCON_PCLK_AC97,
-       }, {
-               .name           = "cfcon",
-               .parent         = &clk_h,
-               .enable         = s3c64xx_hclk_ctrl,
-               .ctrlbit        = S3C_CLKCON_HCLK_IHOST,
-       }
+       },
 };
 
 static struct clk clk_hsmmc0 = {
index 5eb9c9a..7a10be6 100644 (file)
@@ -25,8 +25,6 @@ void s3c64xx_setup_clocks(void);
 
 void s3c64xx_restart(char mode, const char *cmd);
 
-extern struct syscore_ops s3c64xx_irq_syscore_ops;
-
 #ifdef CONFIG_CPU_S3C6400
 
 extern  int s3c6400_init(void);
diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c
new file mode 100644 (file)
index 0000000..179460f
--- /dev/null
@@ -0,0 +1,91 @@
+/* linux/arch/arm/mach-s3c64xx/cpuidle.c
+ *
+ * Copyright (c) 2011 Wolfson Microelectronics, plc
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cpuidle.h>
+#include <linux/io.h>
+#include <linux/export.h>
+#include <linux/time.h>
+
+#include <asm/proc-fns.h>
+
+#include <mach/map.h>
+
+#include <mach/regs-sys.h>
+#include <mach/regs-syscon-power.h>
+
+static int s3c64xx_enter_idle(struct cpuidle_device *dev,
+                             struct cpuidle_driver *drv,
+                             int index)
+{
+       struct timeval before, after;
+       unsigned long tmp;
+       int idle_time;
+
+       local_irq_disable();
+       do_gettimeofday(&before);
+
+       /* Setup PWRCFG to enter idle mode */
+       tmp = __raw_readl(S3C64XX_PWR_CFG);
+       tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK;
+       tmp |= S3C64XX_PWRCFG_CFG_WFI_IDLE;
+       __raw_writel(tmp, S3C64XX_PWR_CFG);
+
+       cpu_do_idle();
+
+       do_gettimeofday(&after);
+       local_irq_enable();
+       idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+                   (after.tv_usec - before.tv_usec);
+
+       dev->last_residency = idle_time;
+       return index;
+}
+
+static struct cpuidle_state s3c64xx_cpuidle_set[] = {
+       [0] = {
+               .enter                  = s3c64xx_enter_idle,
+               .exit_latency           = 1,
+               .target_residency       = 1,
+               .flags                  = CPUIDLE_FLAG_TIME_VALID,
+               .name                   = "IDLE",
+               .desc                   = "System active, ARM gated",
+       },
+};
+
+static struct cpuidle_driver s3c64xx_cpuidle_driver = {
+       .name           = "s3c64xx_cpuidle",
+       .owner          = THIS_MODULE,
+       .state_count    = ARRAY_SIZE(s3c64xx_cpuidle_set),
+};
+
+static struct cpuidle_device s3c64xx_cpuidle_device = {
+       .state_count    = ARRAY_SIZE(s3c64xx_cpuidle_set),
+};
+
+static int __init s3c64xx_init_cpuidle(void)
+{
+       int ret;
+
+       memcpy(s3c64xx_cpuidle_driver.states, s3c64xx_cpuidle_set,
+              sizeof(s3c64xx_cpuidle_set));
+       cpuidle_register_driver(&s3c64xx_cpuidle_driver);
+
+       ret = cpuidle_register_device(&s3c64xx_cpuidle_device);
+       if (ret) {
+               pr_err("Failed to register cpuidle device: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+device_initcall(s3c64xx_init_cpuidle);
diff --git a/arch/arm/mach-s3c64xx/include/mach/entry-macro.S b/arch/arm/mach-s3c64xx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index dc2bc15..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* arch/arm/mach-s3c6400/include/mach/entry-macro.S
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Low-level IRQ helper macros for the Samsung S3C64XX series
- *
- * 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.
-*/
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-s3c64xx/include/mach/system.h b/arch/arm/mach-s3c64xx/include/mach/system.h
deleted file mode 100644 (file)
index 353ed43..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* linux/arch/arm/mach-s3c6400/include/mach/system.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * S3C6400 - system implementation
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-static void arch_idle(void)
-{
-       /* nothing here yet */
-}
-
-#endif /* __ASM_ARCH_IRQ_H */
index 8bec61e..0c7e1d9 100644 (file)
@@ -96,7 +96,7 @@ static void s3c64xx_irq_pm_resume(void)
        S3C_PMDBG("%s: IRQ configuration restored\n", __func__);
 }
 
-struct syscore_ops s3c64xx_irq_syscore_ops = {
+static struct syscore_ops s3c64xx_irq_syscore_ops = {
        .suspend = s3c64xx_irq_pm_suspend,
        .resume  = s3c64xx_irq_pm_resume,
 };
index 32a30f3..0ace108 100644 (file)
 #include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 
 #include <linux/mfd/wm831x/irq.h>
 #include <linux/mfd/wm831x/gpio.h>
 #include <linux/mfd/wm8994/pdata.h>
 
+#include <linux/regulator/machine.h>
+
 #include <sound/wm5100.h>
 #include <sound/wm8996.h>
 #include <sound/wm8962.h>
 #include <sound/wm9081.h>
 
+#include <plat/s3c64xx-spi.h>
+
 #include <mach/crag6410.h>
 
+static struct s3c64xx_spi_csinfo wm0010_spi_csinfo = {
+       .set_level = gpio_set_value,
+       .line = S3C64XX_GPC(3),
+};
+
+static struct spi_board_info wm1253_devs[] = {
+       [0] = {
+               .modalias       = "wm0010",
+               .bus_num        = 0,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_0,
+               .controller_data = &wm0010_spi_csinfo,
+       },
+};
+
 static struct wm5100_pdata wm5100_pdata = {
        .ldo_ena = S3C64XX_GPN(7),
        .irq_flags = IRQF_TRIGGER_HIGH,
@@ -135,6 +155,14 @@ static const struct i2c_board_info wm1259_devs[] = {
        },
 };
 
+static struct regulator_init_data wm8994_ldo1 = {
+       .supply_regulator = "WALLVDD",
+};
+
+static struct regulator_init_data wm8994_ldo2 = {
+       .supply_regulator = "WALLVDD",
+};
+
 static struct wm8994_pdata wm8994_pdata = {
        .gpio_base = CODEC_GPIO_BASE,
        .gpio_defaults = {
@@ -142,8 +170,8 @@ static struct wm8994_pdata wm8994_pdata = {
        },
        .irq_base = CODEC_IRQ_BASE,
        .ldo = {
-               { .supply = "WALLVDD" },
-               { .supply = "WALLVDD" },
+                { .init_data = &wm8994_ldo1, },
+                { .init_data = &wm8994_ldo2, },
        },
 };
 
@@ -159,14 +187,21 @@ static __devinitdata const struct {
        const char *name;
        const struct i2c_board_info *i2c_devs;
        int num_i2c_devs;
+       const struct spi_board_info *spi_devs;
+       int num_spi_devs;
 } gf_mods[] = {
        { .id = 0x01, .name = "1250-EV1 Springbank" },
        { .id = 0x02, .name = "1251-EV1 Jura" },
        { .id = 0x03, .name = "1252-EV1 Glenlivet" },
        { .id = 0x11, .name = "6249-EV2 Glenfarclas", },
+       { .id = 0x14, .name = "6271-EV1 Lochnagar" },
+       { .id = 0x15, .name = "XXXX-EV1 Bells" },
        { .id = 0x21, .name = "1275-EV1 Mortlach" },
        { .id = 0x25, .name = "1274-EV1 Glencadam" },
-       { .id = 0x31, .name = "1253-EV1 Tomatin", },
+       { .id = 0x31, .name = "1253-EV1 Tomatin",
+         .spi_devs = wm1253_devs, .num_spi_devs = ARRAY_SIZE(wm1253_devs) },
+       { .id = 0x32, .name = "XXXX-EV1 Caol Illa" },
+       { .id = 0x33, .name = "XXXX-EV1 Oban" },
        { .id = 0x39, .name = "1254-EV1 Dallas Dhu",
          .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs) },
        { .id = 0x3a, .name = "1259-EV1 Tobermory",
@@ -198,12 +233,16 @@ static __devinit int wlf_gf_module_probe(struct i2c_client *i2c,
        if (i < ARRAY_SIZE(gf_mods)) {
                dev_info(&i2c->dev, "%s revision %d\n",
                         gf_mods[i].name, rev + 1);
+
                for (j = 0; j < gf_mods[i].num_i2c_devs; j++) {
                        if (!i2c_new_device(i2c->adapter,
                                            &(gf_mods[i].i2c_devs[j])))
                                dev_err(&i2c->dev,
                                        "Failed to register dev: %d\n", ret);
                }
+
+               spi_register_board_info(gf_mods[i].spi_devs,
+                                       gf_mods[i].num_spi_devs);
        } else {
                dev_warn(&i2c->dev, "Unknown module ID 0x%x revision %d\n",
                         id, rev + 1);
index 8077f65..e20bf58 100644 (file)
@@ -19,7 +19,9 @@
 #include <linux/io.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/leds.h>
 #include <linux/delay.h>
+#include <linux/mmc/host.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
 #include <linux/pwm_backlight.h>
@@ -59,6 +61,7 @@
 #include <plat/sdhci.h>
 #include <plat/gpio-cfg.h>
 #include <plat/s3c64xx-spi.h>
+#include <plat/udc-hs.h>
 
 #include <plat/keypad.h>
 #include <plat/clock.h>
@@ -298,6 +301,7 @@ static struct platform_device littlemill_device = {
 };
 
 static struct regulator_consumer_supply wallvdd_consumers[] = {
+       REGULATOR_SUPPLY("SPKVDD", "1-001a"),
        REGULATOR_SUPPLY("SPKVDD1", "1-001a"),
        REGULATOR_SUPPLY("SPKVDD2", "1-001a"),
        REGULATOR_SUPPLY("SPKVDDL", "1-001a"),
@@ -574,11 +578,19 @@ static struct s3c2410_platform_i2c i2c0_pdata = {
        .frequency = 400000,
 };
 
+static struct regulator_consumer_supply pvdd_1v2_consumers[] __initdata = {
+       REGULATOR_SUPPLY("DCVDD", "spi0.0"),
+       REGULATOR_SUPPLY("AVDD", "spi0.0"),
+};
+
 static struct regulator_init_data pvdd_1v2 __initdata = {
        .constraints = {
                .name = "PVDD_1V2",
-               .always_on = 1,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
        },
+
+       .consumer_supplies = pvdd_1v2_consumers,
+       .num_consumer_supplies = ARRAY_SIZE(pvdd_1v2_consumers),
 };
 
 static struct regulator_consumer_supply pvdd_1v8_consumers[] __initdata = {
@@ -592,6 +604,7 @@ static struct regulator_consumer_supply pvdd_1v8_consumers[] __initdata = {
        REGULATOR_SUPPLY("AVDD2", "1-001a"),
        REGULATOR_SUPPLY("DCVDD", "1-001a"),
        REGULATOR_SUPPLY("AVDD", "1-001a"),
+       REGULATOR_SUPPLY("DBVDD", "spi0.0"),
 };
 
 static struct regulator_init_data pvdd_1v8 __initdata = {
@@ -681,6 +694,7 @@ static void __init crag6410_map_io(void)
 static struct s3c_sdhci_platdata crag6410_hsmmc2_pdata = {
        .max_width              = 4,
        .cd_type                = S3C_SDHCI_CD_PERMANENT,
+       .host_caps              = MMC_CAP_POWER_OFF_CARD,
 };
 
 static void crag6410_cfg_sdhci0(struct platform_device *dev, int width)
@@ -696,8 +710,59 @@ static struct s3c_sdhci_platdata crag6410_hsmmc0_pdata = {
        .max_width              = 4,
        .cd_type                = S3C_SDHCI_CD_INTERNAL,
        .cfg_gpio               = crag6410_cfg_sdhci0,
+       .host_caps              = MMC_CAP_POWER_OFF_CARD,
+};
+
+static const struct gpio_led gpio_leds[] = {
+       {
+               .name = "d13:green:",
+               .gpio = MMGPIO_GPIO_BASE + 0,
+               .default_state = LEDS_GPIO_DEFSTATE_ON,
+       },
+       {
+               .name = "d14:green:",
+               .gpio = MMGPIO_GPIO_BASE + 1,
+               .default_state = LEDS_GPIO_DEFSTATE_ON,
+       },
+       {
+               .name = "d15:green:",
+               .gpio = MMGPIO_GPIO_BASE + 2,
+               .default_state = LEDS_GPIO_DEFSTATE_ON,
+       },
+       {
+               .name = "d16:green:",
+               .gpio = MMGPIO_GPIO_BASE + 3,
+               .default_state = LEDS_GPIO_DEFSTATE_ON,
+       },
+       {
+               .name = "d17:green:",
+               .gpio = MMGPIO_GPIO_BASE + 4,
+               .default_state = LEDS_GPIO_DEFSTATE_ON,
+       },
+       {
+               .name = "d18:green:",
+               .gpio = MMGPIO_GPIO_BASE + 5,
+               .default_state = LEDS_GPIO_DEFSTATE_ON,
+       },
+       {
+               .name = "d19:green:",
+               .gpio = MMGPIO_GPIO_BASE + 6,
+               .default_state = LEDS_GPIO_DEFSTATE_ON,
+       },
+       {
+               .name = "d20:green:",
+               .gpio = MMGPIO_GPIO_BASE + 7,
+               .default_state = LEDS_GPIO_DEFSTATE_ON,
+       },
 };
 
+static const struct gpio_led_platform_data gpio_leds_pdata = {
+       .leds = gpio_leds,
+       .num_leds = ARRAY_SIZE(gpio_leds),
+};
+
+static struct s3c_hsotg_plat crag6410_hsotg_pdata;
+
 static void __init crag6410_machine_init(void)
 {
        /* Open drain IRQs need pullups */
@@ -722,14 +787,18 @@ static void __init crag6410_machine_init(void)
        s3c_i2c0_set_platdata(&i2c0_pdata);
        s3c_i2c1_set_platdata(&i2c1_pdata);
        s3c_fb_set_platdata(&crag6410_lcd_pdata);
+       s3c_hsotg_set_platdata(&crag6410_hsotg_pdata);
 
        i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
        i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
 
        samsung_keypad_set_platdata(&crag6410_keypad_data);
+       s3c64xx_spi0_set_platdata(&s3c64xx_spi0_pdata, 0, 1);
 
        platform_add_devices(crag6410_devices, ARRAY_SIZE(crag6410_devices));
 
+       gpio_led_register_device(-1, &gpio_leds_pdata);
+
        regulator_has_full_constraints();
 
        s3c64xx_pm_init();
index ce31db1..ce745e1 100644 (file)
@@ -187,6 +187,8 @@ static struct s3c_hwmon_pdata smartq_hwmon_pdata __initdata = {
        },
 };
 
+static struct s3c_hsotg_plat smartq_hsotg_pdata;
+
 static int __init smartq_lcd_setup_gpio(void)
 {
        int ret;
@@ -383,6 +385,7 @@ void __init smartq_map_io(void)
 void __init smartq_machine_init(void)
 {
        s3c_i2c0_set_platdata(NULL);
+       s3c_hsotg_set_platdata(&smartq_hsotg_pdata);
        s3c_hwmon_set_platdata(&smartq_hwmon_pdata);
        s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata);
        s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata);
index ca6fc20..d55bc96 100644 (file)
@@ -72,6 +72,7 @@
 #include <plat/keypad.h>
 #include <plat/backlight.h>
 #include <plat/regs-fb-v4.h>
+#include <plat/udc-hs.h>
 
 #include "common.h"
 
@@ -631,6 +632,8 @@ static struct platform_pwm_backlight_data smdk6410_bl_data = {
        .pwm_id = 1,
 };
 
+static struct s3c_hsotg_plat smdk6410_hsotg_pdata;
+
 static void __init smdk6410_map_io(void)
 {
        u32 tmp;
@@ -659,6 +662,7 @@ static void __init smdk6410_machine_init(void)
        s3c_i2c0_set_platdata(NULL);
        s3c_i2c1_set_platdata(NULL);
        s3c_fb_set_platdata(&smdk6410_lcd_pdata);
+       s3c_hsotg_set_platdata(&smdk6410_hsotg_pdata);
 
        samsung_keypad_set_platdata(&smdk6410_keypad_data);
 
diff --git a/arch/arm/mach-s3c64xx/setup-usb-phy.c b/arch/arm/mach-s3c64xx/setup-usb-phy.c
new file mode 100644 (file)
index 0000000..f6757e0
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+#include <mach/regs-sys.h>
+#include <plat/cpu.h>
+#include <plat/regs-usb-hsotg-phy.h>
+#include <plat/usb-phy.h>
+
+static int s3c_usb_otgphy_init(struct platform_device *pdev)
+{
+       struct clk *xusbxti;
+       u32 phyclk;
+
+       writel(readl(S3C64XX_OTHERS) | S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
+
+       /* set clock frequency for PLL */
+       phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK;
+
+       xusbxti = clk_get(&pdev->dev, "xusbxti");
+       if (xusbxti && !IS_ERR(xusbxti)) {
+               switch (clk_get_rate(xusbxti)) {
+               case 12 * MHZ:
+                       phyclk |= S3C_PHYCLK_CLKSEL_12M;
+                       break;
+               case 24 * MHZ:
+                       phyclk |= S3C_PHYCLK_CLKSEL_24M;
+                       break;
+               default:
+               case 48 * MHZ:
+                       /* default reference clock */
+                       break;
+               }
+               clk_put(xusbxti);
+       }
+
+       /* TODO: select external clock/oscillator */
+       writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK);
+
+       /* set to normal OTG PHY */
+       writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR);
+       mdelay(1);
+
+       /* reset OTG PHY and Link */
+       writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK,
+                       S3C_RSTCON);
+       udelay(20);     /* at-least 10uS */
+       writel(0, S3C_RSTCON);
+
+       return 0;
+}
+
+static int s3c_usb_otgphy_exit(struct platform_device *pdev)
+{
+       writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN |
+                               S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR);
+
+       writel(readl(S3C64XX_OTHERS) & ~S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
+
+       return 0;
+}
+
+int s5p_usb_phy_init(struct platform_device *pdev, int type)
+{
+       if (type == S5P_USB_PHY_DEVICE)
+               return s3c_usb_otgphy_init(pdev);
+
+       return -EINVAL;
+}
+
+int s5p_usb_phy_exit(struct platform_device *pdev, int type)
+{
+       if (type == S5P_USB_PHY_DEVICE)
+               return s3c_usb_otgphy_exit(pdev);
+
+       return -EINVAL;
+}
index 241d0e6..57e7189 100644 (file)
@@ -73,7 +73,7 @@ static const u32 clock_table[][3] = {
        {L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
 };
 
-unsigned long s5p64x0_armclk_get_rate(struct clk *clk)
+static unsigned long s5p64x0_armclk_get_rate(struct clk *clk)
 {
        unsigned long rate = clk_get_rate(clk->parent);
        u32 clkdiv;
@@ -84,7 +84,8 @@ unsigned long s5p64x0_armclk_get_rate(struct clk *clk)
        return rate / (clkdiv + 1);
 }
 
-unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate)
+static unsigned long s5p64x0_armclk_round_rate(struct clk *clk,
+                                              unsigned long rate)
 {
        u32 iter;
 
@@ -96,7 +97,7 @@ unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate)
        return clock_table[ARRAY_SIZE(clock_table) - 1][0];
 }
 
-int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate)
+static int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate)
 {
        u32 round_tmp;
        u32 iter;
@@ -148,7 +149,7 @@ int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate)
        return 0;
 }
 
-struct clk_ops s5p64x0_clkarm_ops = {
+static struct clk_ops s5p64x0_clkarm_ops = {
        .get_rate       = s5p64x0_armclk_get_rate,
        .set_rate       = s5p64x0_armclk_set_rate,
        .round_rate     = s5p64x0_armclk_round_rate,
@@ -173,7 +174,7 @@ struct clksrc_clk clk_dout_mpll = {
        .reg_div        = { .reg = S5P64X0_CLK_DIV0, .shift = 4, .size = 1 },
 };
 
-struct clk *clkset_hclk_low_list[] = {
+static struct clk *clkset_hclk_low_list[] = {
        &clk_mout_apll.clk,
        &clk_mout_mpll.clk,
 };
index 4325b93..6e6a0a9 100644 (file)
@@ -147,15 +147,12 @@ static void s5p64x0_idle(void)
 {
        unsigned long val;
 
-       if (!need_resched()) {
-               val = __raw_readl(S5P64X0_PWR_CFG);
-               val &= ~(0x3 << 5);
-               val |= (0x1 << 5);
-               __raw_writel(val, S5P64X0_PWR_CFG);
+       val = __raw_readl(S5P64X0_PWR_CFG);
+       val &= ~(0x3 << 5);
+       val |= (0x1 << 5);
+       __raw_writel(val, S5P64X0_PWR_CFG);
 
-               cpu_do_idle();
-       }
-       local_irq_enable();
+       cpu_do_idle();
 }
 
 /*
@@ -287,7 +284,7 @@ int __init s5p64x0_init(void)
        printk(KERN_INFO "S5P64X0(S5P6440/S5P6450): Initializing architecture\n");
 
        /* set idle function */
-       pm_idle = s5p64x0_idle;
+       arm_pm_idle = s5p64x0_idle;
 
        return device_register(&s5p64x0_dev);
 }
index f820c07..2ee5dc0 100644 (file)
@@ -38,7 +38,7 @@
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-u8 s5p6440_pdma_peri[] = {
+static u8 s5p6440_pdma_peri[] = {
        DMACH_UART0_RX,
        DMACH_UART0_TX,
        DMACH_UART1_RX,
@@ -63,12 +63,12 @@ u8 s5p6440_pdma_peri[] = {
        DMACH_SPI1_RX,
 };
 
-struct dma_pl330_platdata s5p6440_pdma_pdata = {
+static struct dma_pl330_platdata s5p6440_pdma_pdata = {
        .nr_valid_peri = ARRAY_SIZE(s5p6440_pdma_peri),
        .peri_id = s5p6440_pdma_peri,
 };
 
-u8 s5p6450_pdma_peri[] = {
+static u8 s5p6450_pdma_peri[] = {
        DMACH_UART0_RX,
        DMACH_UART0_TX,
        DMACH_UART1_RX,
@@ -103,39 +103,27 @@ u8 s5p6450_pdma_peri[] = {
        DMACH_UART5_TX,
 };
 
-struct dma_pl330_platdata s5p6450_pdma_pdata = {
+static struct dma_pl330_platdata s5p6450_pdma_pdata = {
        .nr_valid_peri = ARRAY_SIZE(s5p6450_pdma_peri),
        .peri_id = s5p6450_pdma_peri,
 };
 
-struct amba_device s5p64x0_device_pdma = {
-       .dev = {
-               .init_name = "dma-pl330",
-               .dma_mask = &dma_dmamask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
-       },
-       .res = {
-               .start = S5P64X0_PA_PDMA,
-               .end = S5P64X0_PA_PDMA + SZ_4K,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {IRQ_DMA0, NO_IRQ},
-       .periphid = 0x00041330,
-};
+static AMBA_AHB_DEVICE(s5p64x0_pdma, "dma-pl330", 0x00041330,
+       S5P64X0_PA_PDMA, {IRQ_DMA0}, NULL);
 
 static int __init s5p64x0_dma_init(void)
 {
        if (soc_is_s5p6450()) {
                dma_cap_set(DMA_SLAVE, s5p6450_pdma_pdata.cap_mask);
                dma_cap_set(DMA_CYCLIC, s5p6450_pdma_pdata.cap_mask);
-               s5p64x0_device_pdma.dev.platform_data = &s5p6450_pdma_pdata;
+               s5p64x0_pdma_device.dev.platform_data = &s5p6450_pdma_pdata;
        } else {
                dma_cap_set(DMA_SLAVE, s5p6440_pdma_pdata.cap_mask);
                dma_cap_set(DMA_CYCLIC, s5p6440_pdma_pdata.cap_mask);
-               s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata;
+               s5p64x0_pdma_device.dev.platform_data = &s5p6440_pdma_pdata;
        }
 
-       amba_device_register(&s5p64x0_device_pdma, &iomem_resource);
+       amba_device_register(&s5p64x0_pdma_device, &iomem_resource);
 
        return 0;
 }
diff --git a/arch/arm/mach-s5p64x0/include/mach/entry-macro.S b/arch/arm/mach-s5p64x0/include/mach/entry-macro.S
deleted file mode 100644 (file)
index fbb246d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/entry-macro.S
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Low-level IRQ helper macros for the Samsung S5P64X0
- *
- * 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.
-*/
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index ff85b4b..0ef47d1 100644 (file)
@@ -22,16 +22,9 @@ extern struct clksrc_clk clk_mout_epll;
 extern int s5p64x0_epll_enable(struct clk *clk, int enable);
 extern unsigned long s5p64x0_epll_get_rate(struct clk *clk);
 
-extern unsigned long s5p64x0_armclk_get_rate(struct clk *clk);
-extern unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate);
-extern int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate);
-
-extern struct clk_ops s5p64x0_clkarm_ops;
-
 extern struct clksrc_clk clk_armclk;
 extern struct clksrc_clk clk_dout_mpll;
 
-extern struct clk *clkset_hclk_low_list[];
 extern struct clksrc_sources clkset_hclk_low;
 
 extern int s5p64x0_pclk_ctrl(struct clk *clk, int enable);
diff --git a/arch/arm/mach-s5p64x0/include/mach/system.h b/arch/arm/mach-s5p64x0/include/mach/system.h
deleted file mode 100644 (file)
index cf26e09..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/system.h
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * S5P64X0 - system support header
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-static void arch_idle(void)
-{
-       /* nothing here yet */
-}
-
-#endif /* __ASM_ARCH_SYSTEM_H */
index 247194d..16eca4e 100644 (file)
@@ -170,7 +170,7 @@ static struct clk *clk_src_mout_am_list[] = {
        [1] = &clk_div_apll2.clk,
 };
 
-struct clksrc_sources clk_src_mout_am = {
+static struct clksrc_sources clk_src_mout_am = {
        .sources        = clk_src_mout_am_list,
        .nr_sources     = ARRAY_SIZE(clk_src_mout_am_list),
 };
@@ -212,7 +212,7 @@ static struct clk *clk_src_mout_onenand_list[] = {
        [1] = &clk_div_d1_bus.clk,
 };
 
-struct clksrc_sources clk_src_mout_onenand = {
+static struct clksrc_sources clk_src_mout_onenand = {
        .sources        = clk_src_mout_onenand_list,
        .nr_sources     = ARRAY_SIZE(clk_src_mout_onenand_list),
 };
@@ -756,7 +756,7 @@ static struct clk *clk_src_group1_list[] = {
        [3] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_group1 = {
+static struct clksrc_sources clk_src_group1 = {
        .sources        = clk_src_group1_list,
        .nr_sources     = ARRAY_SIZE(clk_src_group1_list),
 };
@@ -766,7 +766,7 @@ static struct clk *clk_src_group2_list[] = {
        [1] = &clk_div_mpll.clk,
 };
 
-struct clksrc_sources clk_src_group2 = {
+static struct clksrc_sources clk_src_group2 = {
        .sources        = clk_src_group2_list,
        .nr_sources     = ARRAY_SIZE(clk_src_group2_list),
 };
@@ -780,7 +780,7 @@ static struct clk *clk_src_group3_list[] = {
        [5] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_group3 = {
+static struct clksrc_sources clk_src_group3 = {
        .sources        = clk_src_group3_list,
        .nr_sources     = ARRAY_SIZE(clk_src_group3_list),
 };
@@ -806,7 +806,7 @@ static struct clk *clk_src_group4_list[] = {
        [5] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_group4 = {
+static struct clksrc_sources clk_src_group4 = {
        .sources        = clk_src_group4_list,
        .nr_sources     = ARRAY_SIZE(clk_src_group4_list),
 };
@@ -831,7 +831,7 @@ static struct clk *clk_src_group5_list[] = {
        [4] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_group5 = {
+static struct clksrc_sources clk_src_group5 = {
        .sources        = clk_src_group5_list,
        .nr_sources     = ARRAY_SIZE(clk_src_group5_list),
 };
@@ -854,7 +854,7 @@ static struct clk *clk_src_group6_list[] = {
        [2] = &clk_div_hdmi.clk,
 };
 
-struct clksrc_sources clk_src_group6 = {
+static struct clksrc_sources clk_src_group6 = {
        .sources        = clk_src_group6_list,
        .nr_sources     = ARRAY_SIZE(clk_src_group6_list),
 };
@@ -866,7 +866,7 @@ static struct clk *clk_src_group7_list[] = {
        [3] = &clk_vclk54m,
 };
 
-struct clksrc_sources clk_src_group7 = {
+static struct clksrc_sources clk_src_group7 = {
        .sources        = clk_src_group7_list,
        .nr_sources     = ARRAY_SIZE(clk_src_group7_list),
 };
@@ -877,7 +877,7 @@ static struct clk *clk_src_mmc0_list[] = {
        [2] = &clk_fin_epll,
 };
 
-struct clksrc_sources clk_src_mmc0 = {
+static struct clksrc_sources clk_src_mmc0 = {
        .sources        = clk_src_mmc0_list,
        .nr_sources     = ARRAY_SIZE(clk_src_mmc0_list),
 };
@@ -889,7 +889,7 @@ static struct clk *clk_src_mmc12_list[] = {
        [3] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_mmc12 = {
+static struct clksrc_sources clk_src_mmc12 = {
        .sources        = clk_src_mmc12_list,
        .nr_sources     = ARRAY_SIZE(clk_src_mmc12_list),
 };
@@ -901,7 +901,7 @@ static struct clk *clk_src_irda_usb_list[] = {
        [3] = &clk_mout_hpll.clk,
 };
 
-struct clksrc_sources clk_src_irda_usb = {
+static struct clksrc_sources clk_src_irda_usb = {
        .sources        = clk_src_irda_usb_list,
        .nr_sources     = ARRAY_SIZE(clk_src_irda_usb_list),
 };
@@ -912,7 +912,7 @@ static struct clk *clk_src_pwi_list[] = {
        [2] = &clk_div_mpll.clk,
 };
 
-struct clksrc_sources clk_src_pwi = {
+static struct clksrc_sources clk_src_pwi = {
        .sources        = clk_src_pwi_list,
        .nr_sources     = ARRAY_SIZE(clk_src_pwi_list),
 };
@@ -923,7 +923,7 @@ static struct clk *clk_sclk_spdif_list[] = {
        [2] = &clk_sclk_audio2.clk,
 };
 
-struct clksrc_sources clk_src_sclk_spdif = {
+static struct clksrc_sources clk_src_sclk_spdif = {
        .sources        = clk_sclk_spdif_list,
        .nr_sources     = ARRAY_SIZE(clk_sclk_spdif_list),
 };
index df3a41e..6219086 100644 (file)
@@ -130,14 +130,6 @@ static struct map_desc s5pc100_iodesc[] __initdata = {
        }
 };
 
-static void s5pc100_idle(void)
-{
-       if (!need_resched())
-               cpu_do_idle();
-
-       local_irq_enable();
-}
-
 /*
  * s5pc100_map_io
  *
@@ -211,10 +203,6 @@ core_initcall(s5pc100_core_init);
 int __init s5pc100_init(void)
 {
        printk(KERN_INFO "S5PC100: Initializing architecture\n");
-
-       /* set idle function */
-       pm_idle = s5pc100_idle;
-
        return device_register(&s5pc100_dev);
 }
 
index c841f4d..afd8db2 100644 (file)
@@ -35,7 +35,7 @@
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-u8 pdma0_peri[] = {
+static u8 pdma0_peri[] = {
        DMACH_UART0_RX,
        DMACH_UART0_TX,
        DMACH_UART1_RX,
@@ -68,28 +68,15 @@ u8 pdma0_peri[] = {
        DMACH_HSI_TX,
 };
 
-struct dma_pl330_platdata s5pc100_pdma0_pdata = {
+static struct dma_pl330_platdata s5pc100_pdma0_pdata = {
        .nr_valid_peri = ARRAY_SIZE(pdma0_peri),
        .peri_id = pdma0_peri,
 };
 
-struct amba_device s5pc100_device_pdma0 = {
-       .dev = {
-               .init_name = "dma-pl330.0",
-               .dma_mask = &dma_dmamask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
-               .platform_data = &s5pc100_pdma0_pdata,
-       },
-       .res = {
-               .start = S5PC100_PA_PDMA0,
-               .end = S5PC100_PA_PDMA0 + SZ_4K,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {IRQ_PDMA0, NO_IRQ},
-       .periphid = 0x00041330,
-};
+static AMBA_AHB_DEVICE(s5pc100_pdma0,  "dma-pl330.0", 0x00041330,
+       S5PC100_PA_PDMA0, {IRQ_PDMA0}, &s5pc100_pdma0_pdata);
 
-u8 pdma1_peri[] = {
+static u8 pdma1_peri[] = {
        DMACH_UART0_RX,
        DMACH_UART0_TX,
        DMACH_UART1_RX,
@@ -122,36 +109,23 @@ u8 pdma1_peri[] = {
        DMACH_MSM_REQ3,
 };
 
-struct dma_pl330_platdata s5pc100_pdma1_pdata = {
+static struct dma_pl330_platdata s5pc100_pdma1_pdata = {
        .nr_valid_peri = ARRAY_SIZE(pdma1_peri),
        .peri_id = pdma1_peri,
 };
 
-struct amba_device s5pc100_device_pdma1 = {
-       .dev = {
-               .init_name = "dma-pl330.1",
-               .dma_mask = &dma_dmamask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
-               .platform_data = &s5pc100_pdma1_pdata,
-       },
-       .res = {
-               .start = S5PC100_PA_PDMA1,
-               .end = S5PC100_PA_PDMA1 + SZ_4K,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {IRQ_PDMA1, NO_IRQ},
-       .periphid = 0x00041330,
-};
+static AMBA_AHB_DEVICE(s5pc100_pdma1, "dma-pl330.1", 0x00041330,
+       S5PC100_PA_PDMA1, {IRQ_PDMA1}, &s5pc100_pdma1_pdata);
 
 static int __init s5pc100_dma_init(void)
 {
        dma_cap_set(DMA_SLAVE, s5pc100_pdma0_pdata.cap_mask);
        dma_cap_set(DMA_CYCLIC, s5pc100_pdma0_pdata.cap_mask);
-       amba_device_register(&s5pc100_device_pdma0, &iomem_resource);
+       amba_device_register(&s5pc100_pdma0_device, &iomem_resource);
 
        dma_cap_set(DMA_SLAVE, s5pc100_pdma1_pdata.cap_mask);
        dma_cap_set(DMA_CYCLIC, s5pc100_pdma1_pdata.cap_mask);
-       amba_device_register(&s5pc100_device_pdma1, &iomem_resource);
+       amba_device_register(&s5pc100_pdma1_device, &iomem_resource);
 
        return 0;
 }
index b8c242e..bad0700 100644 (file)
  * warranty of any kind, whether express or implied.
 */
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
        .endm
diff --git a/arch/arm/mach-s5pc100/include/mach/system.h b/arch/arm/mach-s5pc100/include/mach/system.h
deleted file mode 100644 (file)
index afc96c2..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* linux/arch/arm/mach-s5pc100/include/mach/system.h
- *
- * Copyright 2009 Samsung Electronics Co.
- *      Byungho Min <bhmin@samsung.com>
- *
- * S5PC100 - system implementation
- *
- * Based on mach-s3c6400/include/mach/system.h
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-static void arch_idle(void)
-{
-       /* nothing here yet */
-}
-
-#endif /* __ASM_ARCH_IRQ_H */
index 2cdc42e..29594fc 100644 (file)
@@ -65,6 +65,11 @@ config S5PV210_SETUP_SPI
        help
          Common setup code for SPI GPIO configurations.
 
+config S5PV210_SETUP_USB_PHY
+       bool
+       help
+         Common setup code for USB PHY controller
+
 menu "S5PC110 Machines"
 
 config MACH_AQUILA
@@ -107,6 +112,7 @@ config MACH_GONI
        select S5PV210_SETUP_KEYPAD
        select S5PV210_SETUP_SDHCI
        select S5PV210_SETUP_FIMC
+       select S5PV210_SETUP_USB_PHY
        help
          Machine support for Samsung GONI board
          S5PC110(MCP) is one of package option of S5PV210
@@ -118,6 +124,10 @@ config MACH_SMDKC110
        select S3C_DEV_I2C2
        select S3C_DEV_RTC
        select S3C_DEV_WDT
+       select S5P_DEV_FIMC0
+       select S5P_DEV_FIMC1
+       select S5P_DEV_FIMC2
+       select S5P_DEV_MFC
        select SAMSUNG_DEV_IDE
        select S5PV210_SETUP_I2C1
        select S5PV210_SETUP_I2C2
@@ -142,6 +152,11 @@ config MACH_SMDKV210
        select S3C_DEV_I2C2
        select S3C_DEV_RTC
        select S3C_DEV_WDT
+       select S5P_DEV_FIMC0
+       select S5P_DEV_FIMC1
+       select S5P_DEV_FIMC2
+       select S5P_DEV_JPEG
+       select S5P_DEV_MFC
        select SAMSUNG_DEV_ADC
        select SAMSUNG_DEV_BACKLIGHT
        select SAMSUNG_DEV_IDE
index 76a121d..1c4e419 100644 (file)
@@ -39,3 +39,4 @@ obj-$(CONFIG_S5PV210_SETUP_IDE)               += setup-ide.o
 obj-$(CONFIG_S5PV210_SETUP_KEYPAD)     += setup-keypad.o
 obj-$(CONFIG_S5PV210_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
 obj-$(CONFIG_S5PV210_SETUP_SPI)                += setup-spi.o
+obj-$(CONFIG_S5PV210_SETUP_USB_PHY) += setup-usb-phy.o
index b9ec0c3..09609d5 100644 (file)
@@ -340,6 +340,11 @@ static struct clk init_clocks_off[] = {
                .enable         = s5pv210_clk_ip0_ctrl,
                .ctrlbit        = (1 << 26),
        }, {
+               .name           = "jpeg",
+               .parent         = &clk_hclk_dsys.clk,
+               .enable         = s5pv210_clk_ip0_ctrl,
+               .ctrlbit        = (1 << 28),
+       }, {
                .name           = "mfc",
                .devname        = "s5p-mfc",
                .parent         = &clk_pclk_psys.clk,
index 9c1bcdc..4c9e902 100644 (file)
@@ -142,14 +142,6 @@ static struct map_desc s5pv210_iodesc[] __initdata = {
        }
 };
 
-static void s5pv210_idle(void)
-{
-       if (!need_resched())
-               cpu_do_idle();
-
-       local_irq_enable();
-}
-
 void s5pv210_restart(char mode, const char *cmd)
 {
        __raw_writel(0x1, S5P_SWRESET);
@@ -247,10 +239,6 @@ core_initcall(s5pv210_core_init);
 int __init s5pv210_init(void)
 {
        printk(KERN_INFO "S5PV210: Initializing architecture\n");
-
-       /* set idle function */
-       pm_idle = s5pv210_idle;
-
        return device_register(&s5pv210_dev);
 }
 
index a6113e0..86ce62f 100644 (file)
@@ -35,7 +35,7 @@
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-u8 pdma0_peri[] = {
+static u8 pdma0_peri[] = {
        DMACH_UART0_RX,
        DMACH_UART0_TX,
        DMACH_UART1_RX,
@@ -66,28 +66,15 @@ u8 pdma0_peri[] = {
        DMACH_SPDIF,
 };
 
-struct dma_pl330_platdata s5pv210_pdma0_pdata = {
+static struct dma_pl330_platdata s5pv210_pdma0_pdata = {
        .nr_valid_peri = ARRAY_SIZE(pdma0_peri),
        .peri_id = pdma0_peri,
 };
 
-struct amba_device s5pv210_device_pdma0 = {
-       .dev = {
-               .init_name = "dma-pl330.0",
-               .dma_mask = &dma_dmamask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
-               .platform_data = &s5pv210_pdma0_pdata,
-       },
-       .res = {
-               .start = S5PV210_PA_PDMA0,
-               .end = S5PV210_PA_PDMA0 + SZ_4K,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {IRQ_PDMA0, NO_IRQ},
-       .periphid = 0x00041330,
-};
+static AMBA_AHB_DEVICE(s5pv210_pdma0, "dma-pl330.0", 0x00041330,
+       S5PV210_PA_PDMA0, {IRQ_PDMA0}, &s5pv210_pdma0_pdata);
 
-u8 pdma1_peri[] = {
+static u8 pdma1_peri[] = {
        DMACH_UART0_RX,
        DMACH_UART0_TX,
        DMACH_UART1_RX,
@@ -122,36 +109,23 @@ u8 pdma1_peri[] = {
        DMACH_PCM2_TX,
 };
 
-struct dma_pl330_platdata s5pv210_pdma1_pdata = {
+static struct dma_pl330_platdata s5pv210_pdma1_pdata = {
        .nr_valid_peri = ARRAY_SIZE(pdma1_peri),
        .peri_id = pdma1_peri,
 };
 
-struct amba_device s5pv210_device_pdma1 = {
-       .dev = {
-               .init_name = "dma-pl330.1",
-               .dma_mask = &dma_dmamask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
-               .platform_data = &s5pv210_pdma1_pdata,
-       },
-       .res = {
-               .start = S5PV210_PA_PDMA1,
-               .end = S5PV210_PA_PDMA1 + SZ_4K,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {IRQ_PDMA1, NO_IRQ},
-       .periphid = 0x00041330,
-};
+static AMBA_AHB_DEVICE(s5pv210_pdma1, "dma-pl330.1", 0x00041330,
+       S5PV210_PA_PDMA1, {IRQ_PDMA1}, &s5pv210_pdma1_pdata);
 
 static int __init s5pv210_dma_init(void)
 {
        dma_cap_set(DMA_SLAVE, s5pv210_pdma0_pdata.cap_mask);
        dma_cap_set(DMA_CYCLIC, s5pv210_pdma0_pdata.cap_mask);
-       amba_device_register(&s5pv210_device_pdma0, &iomem_resource);
+       amba_device_register(&s5pv210_pdma0_device, &iomem_resource);
 
        dma_cap_set(DMA_SLAVE, s5pv210_pdma1_pdata.cap_mask);
        dma_cap_set(DMA_CYCLIC, s5pv210_pdma1_pdata.cap_mask);
-       amba_device_register(&s5pv210_device_pdma1, &iomem_resource);
+       amba_device_register(&s5pv210_pdma1_device, &iomem_resource);
 
        return 0;
 }
diff --git a/arch/arm/mach-s5pv210/include/mach/entry-macro.S b/arch/arm/mach-s5pv210/include/mach/entry-macro.S
deleted file mode 100644 (file)
index bebca1b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5pv210/include/mach/entry-macro.S
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Low-level IRQ helper macros for the Samsung S5PV210
- *
- * 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.
-*/
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
index 89c34b8..b7c8a19 100644 (file)
@@ -90,6 +90,8 @@
 #define S5PV210_PA_FIMC1               0xFB300000
 #define S5PV210_PA_FIMC2               0xFB400000
 
+#define S5PV210_PA_JPEG                        0xFB600000
+
 #define S5PV210_PA_SDO                 0xF9000000
 #define S5PV210_PA_VP                  0xF9100000
 #define S5PV210_PA_MIXER               0xF9200000
 #define S5P_PA_SYSCON                  S5PV210_PA_SYSCON
 #define S5P_PA_TIMER                   S5PV210_PA_TIMER
 
+#define S5P_PA_JPEG                    S5PV210_PA_JPEG
+
 #define SAMSUNG_PA_ADC                 S5PV210_PA_ADC
 #define SAMSUNG_PA_CFCON               S5PV210_PA_CFCON
 #define SAMSUNG_PA_KEYPAD              S5PV210_PA_KEYPAD
index 26691d3..cccb1ed 100644 (file)
@@ -13,7 +13,3 @@
 #define S5PV210_USB_PHY_CON    (S3C_VA_SYS + 0xE80C)
 #define S5PV210_USB_PHY0_EN    (1 << 0)
 #define S5PV210_USB_PHY1_EN    (1 << 1)
-
-/* compatibility defines for s3c-hsotg driver */
-#define S3C64XX_OTHERS         S5PV210_USB_PHY_CON
-#define S3C64XX_OTHERS_USBMASK S5PV210_USB_PHY0_EN
diff --git a/arch/arm/mach-s5pv210/include/mach/system.h b/arch/arm/mach-s5pv210/include/mach/system.h
deleted file mode 100644 (file)
index bf288ce..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* linux/arch/arm/mach-s5pv210/include/mach/system.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5PV210 - system support header
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-static void arch_idle(void)
-{
-       /* nothing here yet */
-}
-
-#endif /* __ASM_ARCH_SYSTEM_H */
index 5e734d0..a9ea64e 100644 (file)
@@ -616,6 +616,7 @@ static struct platform_device *aquila_devices[] __initdata = {
        &s5p_device_fimc0,
        &s5p_device_fimc1,
        &s5p_device_fimc2,
+       &s5p_device_fimc_md,
        &s5pv210_device_iis0,
        &wm8994_fixed_voltage0,
        &wm8994_fixed_voltage1,
index ff91526..2cf5ed7 100644 (file)
@@ -844,7 +844,7 @@ static struct s5p_fimc_isp_info goni_camera_sensors[] = {
        },
 };
 
-struct s5p_platform_fimc goni_fimc_md_platdata __initdata = {
+static struct s5p_platform_fimc goni_fimc_md_platdata __initdata = {
        .isp_info       = goni_camera_sensors,
        .num_clients    = ARRAY_SIZE(goni_camera_sensors),
 };
index b323983..dfc2923 100644 (file)
@@ -31,6 +31,7 @@
 #include <plat/iic.h>
 #include <plat/pm.h>
 #include <plat/s5p-time.h>
+#include <plat/mfc.h>
 
 #include "common.h"
 
@@ -94,6 +95,13 @@ static struct platform_device *smdkc110_devices[] __initdata = {
        &s3c_device_i2c2,
        &s3c_device_rtc,
        &s3c_device_wdt,
+       &s5p_device_fimc0,
+       &s5p_device_fimc1,
+       &s5p_device_fimc2,
+       &s5p_device_fimc_md,
+       &s5p_device_mfc,
+       &s5p_device_mfc_l,
+       &s5p_device_mfc_r,
 };
 
 static struct i2c_board_info smdkc110_i2c_devs0[] __initdata = {
@@ -117,6 +125,11 @@ static void __init smdkc110_map_io(void)
        s5p_set_timer_source(S5P_PWM3, S5P_PWM4);
 }
 
+static void __init smdkc110_reserve(void)
+{
+       s5p_mfc_reserve_mem(0x43000000, 8 << 20, 0x51000000, 8 << 20);
+}
+
 static void __init smdkc110_machine_init(void)
 {
        s3c_pm_init();
@@ -145,4 +158,5 @@ MACHINE_START(SMDKC110, "SMDKC110")
        .init_machine   = smdkc110_machine_init,
        .timer          = &s5p_timer,
        .restart        = s5pv210_restart,
+       .reserve        = &smdkc110_reserve,
 MACHINE_END
index dff9ea7..91d4ad8 100644 (file)
@@ -46,6 +46,7 @@
 #include <plat/s5p-time.h>
 #include <plat/backlight.h>
 #include <plat/regs-fb-v4.h>
+#include <plat/mfc.h>
 
 #include "common.h"
 
@@ -140,7 +141,7 @@ static struct dm9000_plat_data smdkv210_dm9000_platdata = {
        .dev_addr       = { 0x00, 0x09, 0xc0, 0xff, 0xec, 0x48 },
 };
 
-struct platform_device smdkv210_dm9000 = {
+static struct platform_device smdkv210_dm9000 = {
        .name           = "dm9000",
        .id             = -1,
        .num_resources  = ARRAY_SIZE(smdkv210_dm9000_resources),
@@ -223,6 +224,14 @@ static struct platform_device *smdkv210_devices[] __initdata = {
        &s3c_device_rtc,
        &s3c_device_ts,
        &s3c_device_wdt,
+       &s5p_device_fimc0,
+       &s5p_device_fimc1,
+       &s5p_device_fimc2,
+       &s5p_device_fimc_md,
+       &s5p_device_jpeg,
+       &s5p_device_mfc,
+       &s5p_device_mfc_l,
+       &s5p_device_mfc_r,
        &s5pv210_device_ac97,
        &s5pv210_device_iis0,
        &s5pv210_device_spdif,
@@ -282,6 +291,11 @@ static void __init smdkv210_map_io(void)
        s5p_set_timer_source(S5P_PWM2, S5P_PWM4);
 }
 
+static void __init smdkv210_reserve(void)
+{
+       s5p_mfc_reserve_mem(0x43000000, 8 << 20, 0x51000000, 8 << 20);
+}
+
 static void __init smdkv210_machine_init(void)
 {
        s3c_pm_init();
@@ -319,4 +333,5 @@ MACHINE_START(SMDKV210, "SMDKV210")
        .init_machine   = smdkv210_machine_init,
        .timer          = &s5p_timer,
        .restart        = s5pv210_restart,
+       .reserve        = &smdkv210_reserve,
 MACHINE_END
diff --git a/arch/arm/mach-s5pv210/setup-usb-phy.c b/arch/arm/mach-s5pv210/setup-usb-phy.c
new file mode 100644 (file)
index 0000000..be39cf4
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@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 Foundationr
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+#include <mach/regs-sys.h>
+#include <plat/cpu.h>
+#include <plat/regs-usb-hsotg-phy.h>
+#include <plat/usb-phy.h>
+
+static int s5pv210_usb_otgphy_init(struct platform_device *pdev)
+{
+       struct clk *xusbxti;
+       u32 phyclk;
+
+       writel(readl(S5PV210_USB_PHY_CON) | S5PV210_USB_PHY0_EN,
+                       S5PV210_USB_PHY_CON);
+
+       /* set clock frequency for PLL */
+       phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK;
+
+       xusbxti = clk_get(&pdev->dev, "xusbxti");
+       if (xusbxti && !IS_ERR(xusbxti)) {
+               switch (clk_get_rate(xusbxti)) {
+               case 12 * MHZ:
+                       phyclk |= S3C_PHYCLK_CLKSEL_12M;
+                       break;
+               case 24 * MHZ:
+                       phyclk |= S3C_PHYCLK_CLKSEL_24M;
+                       break;
+               default:
+               case 48 * MHZ:
+                       /* default reference clock */
+                       break;
+               }
+               clk_put(xusbxti);
+       }
+
+       /* TODO: select external clock/oscillator */
+       writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK);
+
+       /* set to normal OTG PHY */
+       writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR);
+       mdelay(1);
+
+       /* reset OTG PHY and Link */
+       writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK,
+                       S3C_RSTCON);
+       udelay(20);     /* at-least 10uS */
+       writel(0, S3C_RSTCON);
+
+       return 0;
+}
+
+static int s5pv210_usb_otgphy_exit(struct platform_device *pdev)
+{
+       writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN |
+                               S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR);
+
+       writel(readl(S5PV210_USB_PHY_CON) & ~S5PV210_USB_PHY0_EN,
+                       S5PV210_USB_PHY_CON);
+
+       return 0;
+}
+
+int s5p_usb_phy_init(struct platform_device *pdev, int type)
+{
+       if (type == S5P_USB_PHY_DEVICE)
+               return s5pv210_usb_otgphy_init(pdev);
+
+       return -EINVAL;
+}
+
+int s5p_usb_phy_exit(struct platform_device *pdev, int type)
+{
+       if (type == S5P_USB_PHY_DEVICE)
+               return s5pv210_usb_otgphy_exit(pdev);
+
+       return -EINVAL;
+}
index ed7408d..60b97ec 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := clock.o generic.o irq.o dma.o time.o #nmi-oopser.o
+obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o
 obj-m :=
 obj-n :=
 obj-  :=
index 0c4b76a..375d3f7 100644 (file)
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/serial_core.h>
+#include <linux/mfd/ucb1x00.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/mach/serial_sa1100.h>
 #include <mach/assabet.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
 #define ASSABET_BCR_DB1110 \
-       (ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
+       (ASSABET_BCR_SPK_OFF    | \
         ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
         ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
         ASSABET_BCR_IRDA_MD0)
 
 #define ASSABET_BCR_DB1111 \
-       (ASSABET_BCR_SPK_OFF    | ASSABET_BCR_QMUTE     | \
+       (ASSABET_BCR_SPK_OFF    | \
         ASSABET_BCR_LED_GREEN  | ASSABET_BCR_LED_RED   | \
         ASSABET_BCR_RS232EN    | ASSABET_BCR_LCD_12RGB | \
         ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \
@@ -69,31 +72,10 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
 
 EXPORT_SYMBOL(ASSABET_BCR_frob);
 
-static void assabet_backlight_power(int on)
-{
-#ifndef ASSABET_PAL_VIDEO
-       if (on)
-               ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
-       else
-#endif
-               ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
-}
-
-/*
- * Turn on/off the backlight.  When turning the backlight on,
- * we wait 500us after turning it on so we don't cause the
- * supplies to droop when we enable the LCD controller (and
- * cause a hard reset.)
- */
-static void assabet_lcd_power(int on)
+static void assabet_ucb1x00_reset(enum ucb1x00_reset state)
 {
-#ifndef ASSABET_PAL_VIDEO
-       if (on) {
-               ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
-               udelay(500);
-       } else
-#endif
-               ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
+       if (state == UCB_RST_PROBE)
+               ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
 }
 
 
@@ -152,15 +134,8 @@ static struct flash_platform_data assabet_flash_data = {
 };
 
 static struct resource assabet_flash_resources[] = {
-       {
-               .start  = SA1100_CS0_PHYS,
-               .end    = SA1100_CS0_PHYS + SZ_32M - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = SA1100_CS1_PHYS,
-               .end    = SA1100_CS1_PHYS + SZ_32M - 1,
-               .flags  = IORESOURCE_MEM,
-       }
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
+       DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M),
 };
 
 
@@ -199,18 +174,126 @@ static struct irda_platform_data assabet_irda_data = {
        .set_speed      = assabet_irda_set_speed,
 };
 
+static struct ucb1x00_plat_data assabet_ucb1x00_data = {
+       .reset          = assabet_ucb1x00_reset,
+       .gpio_base      = -1,
+};
+
 static struct mcp_plat_data assabet_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
+       .codec_pdata    = &assabet_ucb1x00_data,
+};
+
+static void assabet_lcd_set_visual(u32 visual)
+{
+       u_int is_true_color = visual == FB_VISUAL_TRUECOLOR;
+
+       if (machine_is_assabet()) {
+#if 1          // phase 4 or newer Assabet's
+               if (is_true_color)
+                       ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
+               else
+                       ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
+#else
+               // older Assabet's
+               if (is_true_color)
+                       ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
+               else
+                       ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
+#endif
+       }
+}
+
+#ifndef ASSABET_PAL_VIDEO
+static void assabet_lcd_backlight_power(int on)
+{
+       if (on)
+               ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
+       else
+               ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
+}
+
+/*
+ * Turn on/off the backlight.  When turning the backlight on, we wait
+ * 500us after turning it on so we don't cause the supplies to droop
+ * when we enable the LCD controller (and cause a hard reset.)
+ */
+static void assabet_lcd_power(int on)
+{
+       if (on) {
+               ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
+               udelay(500);
+       } else
+               ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
+}
+
+/*
+ * The assabet uses a sharp LQ039Q2DS54 LCD module.  It is actually
+ * takes an RGB666 signal, but we provide it with an RGB565 signal
+ * instead (def_rgb_16).
+ */
+static struct sa1100fb_mach_info lq039q2ds54_info = {
+       .pixclock       = 171521,       .bpp            = 16,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 5,            .vsync_len      = 1,
+       .left_margin    = 61,           .upper_margin   = 3,
+       .right_margin   = 9,            .lower_margin   = 0,
+
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+
+       .backlight_power = assabet_lcd_backlight_power,
+       .lcd_power = assabet_lcd_power,
+       .set_visual = assabet_lcd_set_visual,
+};
+#else
+static void assabet_pal_backlight_power(int on)
+{
+       ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
+}
+
+static void assabet_pal_power(int on)
+{
+       ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
+}
+
+static struct sa1100fb_mach_info pal_info = {
+       .pixclock       = 67797,        .bpp            = 16,
+       .xres           = 640,          .yres           = 512,
+
+       .hsync_len      = 64,           .vsync_len      = 6,
+       .left_margin    = 125,          .upper_margin   = 70,
+       .right_margin   = 115,          .lower_margin   = 36,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+
+       .backlight_power = assabet_pal_backlight_power,
+       .lcd_power = assabet_pal_power,
+       .set_visual = assabet_lcd_set_visual,
 };
+#endif
+
+#ifdef CONFIG_ASSABET_NEPONSET
+static struct resource neponset_resources[] = {
+       DEFINE_RES_MEM(0x10000000, 0x08000000),
+       DEFINE_RES_MEM(0x18000000, 0x04000000),
+       DEFINE_RES_MEM(0x40000000, SZ_8K),
+       DEFINE_RES_IRQ(IRQ_GPIO25),
+};
+#endif
 
 static void __init assabet_init(void)
 {
        /*
         * Ensure that the power supply is in "high power" mode.
         */
-       GPDR |= GPIO_GPIO16;
        GPSR = GPIO_GPIO16;
+       GPDR |= GPIO_GPIO16;
 
        /*
         * Ensure that these pins are set as outputs and are driving
@@ -218,8 +301,16 @@ static void __init assabet_init(void)
         * the WS latch in the CPLD, and we don't float causing
         * excessive power drain.  --rmk
         */
-       GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
        GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
+       GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
+
+       /*
+        * Also set GPIO27 as an output; this is used to clock UART3
+        * via the FPGA and as otherwise has no pullups or pulldowns,
+        * so stop it floating.
+        */
+       GPCR = GPIO_GPIO27;
+       GPDR |= GPIO_GPIO27;
 
        /*
         * Set up registers for sleep mode.
@@ -231,8 +322,7 @@ static void __init assabet_init(void)
        PPDR |= PPC_TXD3 | PPC_TXD1;
        PPSR |= PPC_TXD3 | PPC_TXD1;
 
-       sa1100fb_lcd_power = assabet_lcd_power;
-       sa1100fb_backlight_power = assabet_backlight_power;
+       sa11x0_ppc_configure_mcp();
 
        if (machine_has_neponset()) {
                /*
@@ -246,9 +336,17 @@ static void __init assabet_init(void)
 #ifndef CONFIG_ASSABET_NEPONSET
                printk( "Warning: Neponset detected but full support "
                        "hasn't been configured in the kernel\n" );
+#else
+               platform_device_register_simple("neponset", 0,
+                       neponset_resources, ARRAY_SIZE(neponset_resources));
 #endif
        }
 
+#ifndef ASSABET_PAL_VIDEO
+       sa11x0_register_lcd(&lq039q2ds54_info);
+#else
+       sa11x0_register_lcd(&pal_video);
+#endif
        sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources,
                            ARRAY_SIZE(assabet_flash_resources));
        sa11x0_register_irda(&assabet_irda_data);
@@ -412,21 +510,8 @@ static void __init assabet_map_io(void)
         */
        Ser1SDCR0 |= SDCR0_SUS;
 
-       if (machine_has_neponset()) {
-#ifdef CONFIG_ASSABET_NEPONSET
-               extern void neponset_map_io(void);
-
-               /*
-                * We map Neponset registers even if it isn't present since
-                * many drivers will try to probe their stuff (and fail).
-                * This is still more friendly than a kernel paging request
-                * crash.
-                */
-               neponset_map_io();
-#endif
-       } else {
+       if (!machine_has_neponset())
                sa1100_register_uart_fns(&assabet_port_fns);
-       }
 
        /*
         * When Neponset is attached, the first UART should be
@@ -449,6 +534,7 @@ MACHINE_START(ASSABET, "Intel-Assabet")
        .atag_offset    = 0x100,
        .fixup          = fixup_assabet,
        .map_io         = assabet_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = assabet_init,
index b07a2c0..e0f0c03 100644 (file)
 #include "generic.h"
 
 static struct resource sa1111_resources[] = {
-       [0] = {
-               .start          = BADGE4_SA1111_BASE,
-               .end            = BADGE4_SA1111_BASE + 0x00001fff,
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start          = BADGE4_IRQ_GPIO_SA1111,
-               .end            = BADGE4_IRQ_GPIO_SA1111,
-               .flags          = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(BADGE4_SA1111_BASE, 0x2000),
+       [1] = DEFINE_RES_IRQ(BADGE4_IRQ_GPIO_SA1111),
 };
 
+static int badge4_sa1111_enable(void *data, unsigned devid)
+{
+       if (devid == SA1111_DEVID_USB)
+               badge4_set_5V(BADGE4_5V_USB, 1);
+       return 0;
+}
+
+static void badge4_sa1111_disable(void *data, unsigned devid)
+{
+       if (devid == SA1111_DEVID_USB)
+               badge4_set_5V(BADGE4_5V_USB, 0);
+}
+
 static struct sa1111_platform_data sa1111_info = {
-       .irq_base       = IRQ_BOARD_END,
+       .disable_devs   = SA1111_DEVID_PS2_MSE,
+       .enable         = badge4_sa1111_enable,
+       .disable        = badge4_sa1111_disable,
 };
 
 static u64 sa1111_dmamask = 0xffffffffUL;
@@ -121,11 +128,8 @@ static struct flash_platform_data badge4_flash_data = {
        .nr_parts       = ARRAY_SIZE(badge4_partitions),
 };
 
-static struct resource badge4_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_64M - 1,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource badge4_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_64M);
 
 static int five_v_on __initdata = 0;
 
@@ -269,11 +273,6 @@ static struct map_desc badge4_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(0x10000000),
                .length         = 0x00100000,
                .type           = MT_DEVICE
-       }, {    /* SA-1111      */
-               .virtual        = 0xf4000000,
-               .pfn            = __phys_to_pfn(0x48000000),
-               .length         = 0x00100000,
-               .type           = MT_DEVICE
        }
 };
 
@@ -304,6 +303,7 @@ static void __init badge4_map_io(void)
 MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
        .atag_offset    = 0x100,
        .map_io         = badge4_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
 #ifdef CONFIG_SA1111
index 11bb6d0..4a61f60 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/setup.h>
 
 
 #include <mach/cerf.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 #include "generic.h"
 
 static struct resource cerfuart2_resources[] = {
-       [0] = {
-               .start  = 0x80030000,
-               .end    = 0x8003ffff,
-               .flags  = IORESOURCE_MEM,
-       },
+       [0] = DEFINE_RES_MEM(0x80030000, SZ_64K),
 };
 
 static struct platform_device cerfuart2_device = {
@@ -87,11 +83,8 @@ static struct flash_platform_data cerf_flash_data = {
        .nr_parts       = ARRAY_SIZE(cerf_partitions),
 };
 
-static struct resource cerf_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource cerf_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 static void __init cerf_init_irq(void)
 {
@@ -128,6 +121,7 @@ static struct mcp_plat_data cerf_mcp_data = {
 
 static void __init cerf_init(void)
 {
+       sa11x0_ppc_configure_mcp();
        platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
        sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
        sa11x0_register_mcp(&cerf_mcp_data);
@@ -136,6 +130,7 @@ static void __init cerf_init(void)
 MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
        /* Maintainer: support@intrinsyc.com */
        .map_io         = cerf_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = cerf_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = cerf_init,
index dab3c63..172ebd0 100644 (file)
 #include <linux/clk.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
 
 #include <mach/hardware.h>
 
-/*
- * Very simple clock implementation - we only have one clock to deal with.
- */
+struct clkops {
+       void                    (*enable)(struct clk *);
+       void                    (*disable)(struct clk *);
+};
+
 struct clk {
+       const struct clkops     *ops;
        unsigned int            enabled;
 };
 
-static void clk_gpio27_enable(void)
+#define DEFINE_CLK(_name, _ops)                                \
+struct clk clk_##_name = {                             \
+               .ops    = _ops,                         \
+       }
+
+static DEFINE_SPINLOCK(clocks_lock);
+
+static void clk_gpio27_enable(struct clk *clk)
 {
        /*
         * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
@@ -32,38 +44,24 @@ static void clk_gpio27_enable(void)
        TUCR = TUCR_3_6864MHz;
 }
 
-static void clk_gpio27_disable(void)
+static void clk_gpio27_disable(struct clk *clk)
 {
        TUCR = 0;
        GPDR &= ~GPIO_32_768kHz;
        GAFR &= ~GPIO_32_768kHz;
 }
 
-static struct clk clk_gpio27;
-
-static DEFINE_SPINLOCK(clocks_lock);
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       const char *devname = dev_name(dev);
-
-       return strcmp(devname, "sa1111.0") ? ERR_PTR(-ENOENT) : &clk_gpio27;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
 int clk_enable(struct clk *clk)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&clocks_lock, flags);
-       if (clk->enabled++ == 0)
-               clk_gpio27_enable();
-       spin_unlock_irqrestore(&clocks_lock, flags);
+       if (clk) {
+               spin_lock_irqsave(&clocks_lock, flags);
+               if (clk->enabled++ == 0)
+                       clk->ops->enable(clk);
+               spin_unlock_irqrestore(&clocks_lock, flags);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(clk_enable);
@@ -72,17 +70,31 @@ void clk_disable(struct clk *clk)
 {
        unsigned long flags;
 
-       WARN_ON(clk->enabled == 0);
-
-       spin_lock_irqsave(&clocks_lock, flags);
-       if (--clk->enabled == 0)
-               clk_gpio27_disable();
-       spin_unlock_irqrestore(&clocks_lock, flags);
+       if (clk) {
+               WARN_ON(clk->enabled == 0);
+               spin_lock_irqsave(&clocks_lock, flags);
+               if (--clk->enabled == 0)
+                       clk->ops->disable(clk);
+               spin_unlock_irqrestore(&clocks_lock, flags);
+       }
 }
 EXPORT_SYMBOL(clk_disable);
 
-unsigned long clk_get_rate(struct clk *clk)
+const struct clkops clk_gpio27_ops = {
+       .enable         = clk_gpio27_enable,
+       .disable        = clk_gpio27_disable,
+};
+
+static DEFINE_CLK(gpio27, &clk_gpio27_ops);
+
+static struct clk_lookup sa11xx_clkregs[] = {
+       CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27),
+       CLKDEV_INIT("sa1100-rtc", NULL, NULL),
+};
+
+static int __init sa11xx_clk_init(void)
 {
-       return 3686400;
+       clkdev_add_table(sa11xx_clkregs, ARRAY_SIZE(sa11xx_clkregs));
+       return 0;
 }
-EXPORT_SYMBOL(clk_get_rate);
+core_initcall(sa11xx_clk_init);
index fd56521..48885b7 100644 (file)
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/ucb1x00.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/timer.h>
 #include <linux/gpio.h>
 #include <linux/pda_power.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/setup.h>
 #include <mach/collie.h>
 #include <asm/mach/sharpsl_param.h>
 #include <asm/hardware/locomo.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
 static struct resource collie_scoop_resources[] = {
-       [0] = {
-               .start          = 0x40800000,
-               .end            = 0x40800fff,
-               .flags          = IORESOURCE_MEM,
-       },
+       [0] = DEFINE_RES_MEM(0x40800000, SZ_4K),
 };
 
 static struct scoop_config collie_scoop_setup = {
@@ -85,10 +84,14 @@ static struct scoop_pcmcia_config collie_pcmcia_config = {
        .num_devs       = 1,
 };
 
+static struct ucb1x00_plat_data collie_ucb1x00_data = {
+       .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+};
+
 static struct mcp_plat_data collie_mcp_data = {
        .mccr0          = MCCR0_ADM | MCCR0_ExtClk,
        .sclk_rate      = 9216000,
-       .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+       .codec_pdata    = &collie_ucb1x00_data,
 };
 
 /*
@@ -221,16 +224,8 @@ device_initcall(collie_uart_init);
 
 
 static struct resource locomo_resources[] = {
-       [0] = {
-               .start          = 0x40000000,
-               .end            = 0x40001fff,
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start          = IRQ_GPIO25,
-               .end            = IRQ_GPIO25,
-               .flags          = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
+       [1] = DEFINE_RES_IRQ(IRQ_GPIO25),
 };
 
 static struct locomo_platform_data locomo_info = {
@@ -303,11 +298,21 @@ static struct flash_platform_data collie_flash_data = {
 };
 
 static struct resource collie_flash_resources[] = {
-       {
-               .start  = SA1100_CS0_PHYS,
-               .end    = SA1100_CS0_PHYS + SZ_32M - 1,
-               .flags  = IORESOURCE_MEM,
-       }
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
+};
+
+static struct sa1100fb_mach_info collie_lcd_info = {
+       .pixclock       = 171521,       .bpp            = 16,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 5,            .vsync_len      = 1,
+       .left_margin    = 11,           .upper_margin   = 2,
+       .right_margin   = 30,           .lower_margin   = 0,
+
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
 };
 
 static void __init collie_init(void)
@@ -341,6 +346,10 @@ static void __init collie_init(void)
 
        collie_power_resource[0].start = gpio_to_irq(COLLIE_GPIO_AC_IN);
        collie_power_resource[0].end = gpio_to_irq(COLLIE_GPIO_AC_IN);
+
+       sa11x0_ppc_configure_mcp();
+
+
        platform_scoop_config = &collie_pcmcia_config;
 
        ret = platform_add_devices(devices, ARRAY_SIZE(devices));
@@ -348,6 +357,7 @@ static void __init collie_init(void)
                printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
        }
 
+       sa11x0_register_lcd(&collie_lcd_info);
        sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
                            ARRAY_SIZE(collie_flash_resources));
        sa11x0_register_mcp(&collie_mcp_data);
@@ -383,6 +393,7 @@ static void __init collie_map_io(void)
 
 MACHINE_START(COLLIE, "Sharp-Collie")
        .map_io         = collie_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = collie_init,
diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c
deleted file mode 100644 (file)
index 56e1333..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * arch/arm/mach-sa1100/dma.c
- *
- * Support functions for the SA11x0 internal DMA channels.
- *
- * Copyright (C) 2000, 2001 by Nicolas Pitre
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-
-
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTK( s, arg... )  printk( "dma<%p>: " s, regs , ##arg )
-#else
-#define DPRINTK( x... )
-#endif
-
-
-typedef struct {
-       const char *device_id;          /* device name */
-       u_long device;                  /* this channel device, 0  if unused*/
-       dma_callback_t callback;        /* to call when DMA completes */
-       void *data;                     /* ... with private data ptr */
-} sa1100_dma_t;
-
-static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS];
-
-static DEFINE_SPINLOCK(dma_list_lock);
-
-
-static irqreturn_t dma_irq_handler(int irq, void *dev_id)
-{
-       dma_regs_t *dma_regs = dev_id;
-       sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7);
-       int status = dma_regs->RdDCSR;
-
-       if (status & (DCSR_ERROR)) {
-               printk(KERN_CRIT "DMA on \"%s\" caused an error\n", dma->device_id);
-               dma_regs->ClrDCSR = DCSR_ERROR;
-       }
-
-       dma_regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB);
-       if (dma->callback) {
-               if (status & DCSR_DONEA)
-                       dma->callback(dma->data);
-               if (status & DCSR_DONEB)
-                       dma->callback(dma->data);
-       }
-       return IRQ_HANDLED;
-}
-
-
-/**
- *     sa1100_request_dma - allocate one of the SA11x0's DMA channels
- *     @device: The SA11x0 peripheral targeted by this request
- *     @device_id: An ascii name for the claiming device
- *     @callback: Function to be called when the DMA completes
- *     @data: A cookie passed back to the callback function
- *     @dma_regs: Pointer to the location of the allocated channel's identifier
- *
- *     This function will search for a free DMA channel and returns the
- *     address of the hardware registers for that channel as the channel
- *     identifier. This identifier is written to the location pointed by
- *     @dma_regs. The list of possible values for @device are listed into
- *     arch/arm/mach-sa1100/include/mach/dma.h as a dma_device_t enum.
- *
- *     Note that reading from a port and writing to the same port are
- *     actually considered as two different streams requiring separate
- *     DMA registrations.
- *
- *     The @callback function is called from interrupt context when one
- *     of the two possible DMA buffers in flight has terminated. That
- *     function has to be small and efficient while posponing more complex
- *     processing to a lower priority execution context.
- *
- *     If no channels are available, or if the desired @device is already in
- *     use by another DMA channel, then an error code is returned.  This
- *     function must be called before any other DMA calls.
- **/
-
-int sa1100_request_dma (dma_device_t device, const char *device_id,
-                       dma_callback_t callback, void *data,
-                       dma_regs_t **dma_regs)
-{
-       sa1100_dma_t *dma = NULL;
-       dma_regs_t *regs;
-       int i, err;
-
-       *dma_regs = NULL;
-
-       err = 0;
-       spin_lock(&dma_list_lock);
-       for (i = 0; i < SA1100_DMA_CHANNELS; i++) {
-               if (dma_chan[i].device == device) {
-                       err = -EBUSY;
-                       break;
-               } else if (!dma_chan[i].device && !dma) {
-                       dma = &dma_chan[i];
-               }
-       }
-       if (!err) {
-               if (dma)
-                       dma->device = device;
-               else
-                       err = -ENOSR;
-       }
-       spin_unlock(&dma_list_lock);
-       if (err)
-               return err;
-
-       i = dma - dma_chan;
-       regs = (dma_regs_t *)&DDAR(i);
-       err = request_irq(IRQ_DMA0 + i, dma_irq_handler, IRQF_DISABLED,
-                         device_id, regs);
-       if (err) {
-               printk(KERN_ERR
-                      "%s: unable to request IRQ %d for %s\n",
-                      __func__, IRQ_DMA0 + i, device_id);
-               dma->device = 0;
-               return err;
-       }
-
-       *dma_regs = regs;
-       dma->device_id = device_id;
-       dma->callback = callback;
-       dma->data = data;
-
-       regs->ClrDCSR =
-               (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
-                DCSR_IE | DCSR_ERROR | DCSR_RUN);
-       regs->DDAR = device;
-
-       return 0;
-}
-
-
-/**
- *     sa1100_free_dma - free a SA11x0 DMA channel
- *     @regs: identifier for the channel to free
- *
- *     This clears all activities on a given DMA channel and releases it
- *     for future requests.  The @regs identifier is provided by a
- *     successful call to sa1100_request_dma().
- **/
-
-void sa1100_free_dma(dma_regs_t *regs)
-{
-       int i;
-
-       for (i = 0; i < SA1100_DMA_CHANNELS; i++)
-               if (regs == (dma_regs_t *)&DDAR(i))
-                       break;
-       if (i >= SA1100_DMA_CHANNELS) {
-               printk(KERN_ERR "%s: bad DMA identifier\n", __func__);
-               return;
-       }
-
-       if (!dma_chan[i].device) {
-               printk(KERN_ERR "%s: Trying to free free DMA\n", __func__);
-               return;
-       }
-
-       regs->ClrDCSR =
-               (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
-                DCSR_IE | DCSR_ERROR | DCSR_RUN);
-       free_irq(IRQ_DMA0 + i, regs);
-       dma_chan[i].device = 0;
-}
-
-
-/**
- *     sa1100_start_dma - submit a data buffer for DMA
- *     @regs: identifier for the channel to use
- *     @dma_ptr: buffer physical (or bus) start address
- *     @size: buffer size
- *
- *     This function hands the given data buffer to the hardware for DMA
- *     access. If another buffer is already in flight then this buffer
- *     will be queued so the DMA engine will switch to it automatically
- *     when the previous one is done.  The DMA engine is actually toggling
- *     between two buffers so at most 2 successful calls can be made before
- *     one of them terminates and the callback function is called.
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- *
- *     The @size must not be larger than %MAX_DMA_SIZE.  If a given buffer
- *     is larger than that then it's the caller's responsibility to split
- *     it into smaller chunks and submit them separately. If this is the
- *     case then a @size of %CUT_DMA_SIZE is recommended to avoid ending
- *     up with too small chunks. The callback function can be used to chain
- *     submissions of buffer chunks.
- *
- *     Error return values:
- *     %-EOVERFLOW:    Given buffer size is too big.
- *     %-EBUSY:        Both DMA buffers are already in use.
- *     %-EAGAIN:       Both buffers were busy but one of them just completed
- *                     but the interrupt handler has to execute first.
- *
- *     This function returs 0 on success.
- **/
-
-int sa1100_start_dma(dma_regs_t *regs, dma_addr_t dma_ptr, u_int size)
-{
-       unsigned long flags;
-       u_long status;
-       int ret;
-
-       if (dma_ptr & 3)
-               printk(KERN_WARNING "DMA: unaligned start address (0x%08lx)\n",
-                      (unsigned long)dma_ptr);
-
-       if (size > MAX_DMA_SIZE)
-               return -EOVERFLOW;
-
-       local_irq_save(flags);
-       status = regs->RdDCSR;
-
-       /* If both DMA buffers are started, there's nothing else we can do. */
-       if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) {
-               DPRINTK("start: st %#x busy\n", status);
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
-           (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) {
-               if (status & DCSR_DONEA) {
-                       /* give a chance for the interrupt to be processed */
-                       ret = -EAGAIN;
-                       goto out;
-               }
-               regs->DBSA = dma_ptr;
-               regs->DBTA = size;
-               regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN;
-               DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size);
-       } else {
-               if (status & DCSR_DONEB) {
-                       /* give a chance for the interrupt to be processed */
-                       ret = -EAGAIN;
-                       goto out;
-               }
-               regs->DBSB = dma_ptr;
-               regs->DBTB = size;
-               regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN;
-               DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size);
-       }
-       ret = 0;
-
-out:
-       local_irq_restore(flags);
-       return ret;
-}
-
-
-/**
- *     sa1100_get_dma_pos - return current DMA position
- *     @regs: identifier for the channel to use
- *
- *     This function returns the current physical (or bus) address for the
- *     given DMA channel.  If the channel is running i.e. not in a stopped
- *     state then the caller must disable interrupts prior calling this
- *     function and process the returned value before re-enabling them to
- *     prevent races with the completion interrupt handler and the callback
- *     function. The validation of the returned value is the caller's
- *     responsibility as well -- the hardware seems to return out of range
- *     values when the DMA engine completes a buffer.
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- **/
-
-dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs)
-{
-       int status;
-
-       /*
-        * We must determine whether buffer A or B is active.
-        * Two possibilities: either we are in the middle of
-        * a buffer, or the DMA controller just switched to the
-        * next toggle but the interrupt hasn't been serviced yet.
-        * The former case is straight forward.  In the later case,
-        * we'll do like if DMA is just at the end of the previous
-        * toggle since all registers haven't been reset yet.
-        * This goes around the edge case and since we're always
-        * a little behind anyways it shouldn't make a big difference.
-        * If DMA has been stopped prior calling this then the
-        * position is exact.
-        */
-       status = regs->RdDCSR;
-       if ((!(status & DCSR_BIU) &&  (status & DCSR_STRTA)) ||
-           ( (status & DCSR_BIU) && !(status & DCSR_STRTB)))
-               return regs->DBSA;
-       else
-               return regs->DBSB;
-}
-
-
-/**
- *     sa1100_reset_dma - reset a DMA channel
- *     @regs: identifier for the channel to use
- *
- *     This function resets and reconfigure the given DMA channel. This is
- *     particularly useful after a sleep/wakeup event.
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- **/
-
-void sa1100_reset_dma(dma_regs_t *regs)
-{
-       int i;
-
-       for (i = 0; i < SA1100_DMA_CHANNELS; i++)
-               if (regs == (dma_regs_t *)&DDAR(i))
-                       break;
-       if (i >= SA1100_DMA_CHANNELS) {
-               printk(KERN_ERR "%s: bad DMA identifier\n", __func__);
-               return;
-       }
-
-       regs->ClrDCSR =
-               (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
-                DCSR_IE | DCSR_ERROR | DCSR_RUN);
-       regs->DDAR = dma_chan[i].device;
-}
-
-
-EXPORT_SYMBOL(sa1100_request_dma);
-EXPORT_SYMBOL(sa1100_free_dma);
-EXPORT_SYMBOL(sa1100_start_dma);
-EXPORT_SYMBOL(sa1100_get_dma_pos);
-EXPORT_SYMBOL(sa1100_reset_dma);
-
index 9ad9469..7c524b4 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/pm.h>
 #include <linux/cpufreq.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 
+#include <video/sa1100fb.h>
+
 #include <asm/div64.h>
-#include <mach/hardware.h>
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
 #include <asm/irq.h>
 #include <asm/system_misc.h>
 
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
 #include "generic.h"
 
 unsigned int reset_status;
@@ -149,16 +154,8 @@ static void sa11x0_register_device(struct platform_device *dev, void *data)
 
 
 static struct resource sa11x0udc_resources[] = {
-       [0] = {
-               .start  = __PREG(Ser0UDCCR),
-               .end    = __PREG(Ser0UDCCR) + 0xffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_Ser0UDC,
-               .end    = IRQ_Ser0UDC,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(__PREG(Ser0UDCCR), SZ_64K),
+       [1] = DEFINE_RES_IRQ(IRQ_Ser0UDC),
 };
 
 static u64 sa11x0udc_dma_mask = 0xffffffffUL;
@@ -175,16 +172,8 @@ static struct platform_device sa11x0udc_device = {
 };
 
 static struct resource sa11x0uart1_resources[] = {
-       [0] = {
-               .start  = __PREG(Ser1UTCR0),
-               .end    = __PREG(Ser1UTCR0) + 0xffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_Ser1UART,
-               .end    = IRQ_Ser1UART,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(__PREG(Ser1UTCR0), SZ_64K),
+       [1] = DEFINE_RES_IRQ(IRQ_Ser1UART),
 };
 
 static struct platform_device sa11x0uart1_device = {
@@ -195,16 +184,8 @@ static struct platform_device sa11x0uart1_device = {
 };
 
 static struct resource sa11x0uart3_resources[] = {
-       [0] = {
-               .start  = __PREG(Ser3UTCR0),
-               .end    = __PREG(Ser3UTCR0) + 0xffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_Ser3UART,
-               .end    = IRQ_Ser3UART,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(__PREG(Ser3UTCR0), SZ_64K),
+       [1] = DEFINE_RES_IRQ(IRQ_Ser3UART),
 };
 
 static struct platform_device sa11x0uart3_device = {
@@ -215,16 +196,9 @@ static struct platform_device sa11x0uart3_device = {
 };
 
 static struct resource sa11x0mcp_resources[] = {
-       [0] = {
-               .start  = __PREG(Ser4MCCR0),
-               .end    = __PREG(Ser4MCCR0) + 0xffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_Ser4MCP,
-               .end    = IRQ_Ser4MCP,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(__PREG(Ser4MCCR0), SZ_64K),
+       [1] = DEFINE_RES_MEM(__PREG(Ser4MCCR1), 4),
+       [2] = DEFINE_RES_IRQ(IRQ_Ser4MCP),
 };
 
 static u64 sa11x0mcp_dma_mask = 0xffffffffUL;
@@ -240,22 +214,24 @@ static struct platform_device sa11x0mcp_device = {
        .resource       = sa11x0mcp_resources,
 };
 
+void __init sa11x0_ppc_configure_mcp(void)
+{
+       /* Setup the PPC unit for the MCP */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+}
+
 void sa11x0_register_mcp(struct mcp_plat_data *data)
 {
        sa11x0_register_device(&sa11x0mcp_device, data);
 }
 
 static struct resource sa11x0ssp_resources[] = {
-       [0] = {
-               .start  = 0x80070000,
-               .end    = 0x8007ffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_Ser4SSP,
-               .end    = IRQ_Ser4SSP,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(0x80070000, SZ_64K),
+       [1] = DEFINE_RES_IRQ(IRQ_Ser4SSP),
 };
 
 static u64 sa11x0ssp_dma_mask = 0xffffffffUL;
@@ -272,16 +248,8 @@ static struct platform_device sa11x0ssp_device = {
 };
 
 static struct resource sa11x0fb_resources[] = {
-       [0] = {
-               .start  = 0xb0100000,
-               .end    = 0xb010ffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_LCD,
-               .end    = IRQ_LCD,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(0xb0100000, SZ_64K),
+       [1] = DEFINE_RES_IRQ(IRQ_LCD),
 };
 
 static struct platform_device sa11x0fb_device = {
@@ -294,6 +262,11 @@ static struct platform_device sa11x0fb_device = {
        .resource       = sa11x0fb_resources,
 };
 
+void sa11x0_register_lcd(struct sa1100fb_mach_info *inf)
+{
+       sa11x0_register_device(&sa11x0fb_device, inf);
+}
+
 static struct platform_device sa11x0pcmcia_device = {
        .name           = "sa11x0-pcmcia",
        .id             = -1,
@@ -314,23 +287,10 @@ void sa11x0_register_mtd(struct flash_platform_data *flash,
 }
 
 static struct resource sa11x0ir_resources[] = {
-       {
-               .start  = __PREG(Ser2UTCR0),
-               .end    = __PREG(Ser2UTCR0) + 0x24 - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = __PREG(Ser2HSCR0),
-               .end    = __PREG(Ser2HSCR0) + 0x1c - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = __PREG(Ser2HSCR2),
-               .end    = __PREG(Ser2HSCR2) + 0x04 - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = IRQ_Ser2ICP,
-               .end    = IRQ_Ser2ICP,
-               .flags  = IORESOURCE_IRQ,
-       }
+       DEFINE_RES_MEM(__PREG(Ser2UTCR0), 0x24),
+       DEFINE_RES_MEM(__PREG(Ser2HSCR0), 0x1c),
+       DEFINE_RES_MEM(__PREG(Ser2HSCR2), 0x04),
+       DEFINE_RES_IRQ(IRQ_Ser2ICP),
 };
 
 static struct platform_device sa11x0ir_device = {
@@ -345,9 +305,40 @@ void sa11x0_register_irda(struct irda_platform_data *irda)
        sa11x0_register_device(&sa11x0ir_device, irda);
 }
 
+static struct resource sa1100_rtc_resources[] = {
+       DEFINE_RES_MEM(0x90010000, 0x9001003f),
+       DEFINE_RES_IRQ_NAMED(IRQ_RTC1Hz, "rtc 1Hz"),
+       DEFINE_RES_IRQ_NAMED(IRQ_RTCAlrm, "rtc alarm"),
+};
+
 static struct platform_device sa11x0rtc_device = {
        .name           = "sa1100-rtc",
        .id             = -1,
+       .num_resources  = ARRAY_SIZE(sa1100_rtc_resources),
+       .resource       = sa1100_rtc_resources,
+};
+
+static struct resource sa11x0dma_resources[] = {
+       DEFINE_RES_MEM(DMA_PHYS, DMA_SIZE),
+       DEFINE_RES_IRQ(IRQ_DMA0),
+       DEFINE_RES_IRQ(IRQ_DMA1),
+       DEFINE_RES_IRQ(IRQ_DMA2),
+       DEFINE_RES_IRQ(IRQ_DMA3),
+       DEFINE_RES_IRQ(IRQ_DMA4),
+       DEFINE_RES_IRQ(IRQ_DMA5),
+};
+
+static u64 sa11x0dma_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device sa11x0dma_device = {
+       .name           = "sa11x0-dma",
+       .id             = -1,
+       .dev = {
+               .dma_mask = &sa11x0dma_dma_mask,
+               .coherent_dma_mask = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(sa11x0dma_resources),
+       .resource       = sa11x0dma_resources,
 };
 
 static struct platform_device *sa11x0_devices[] __initdata = {
@@ -356,8 +347,8 @@ static struct platform_device *sa11x0_devices[] __initdata = {
        &sa11x0uart3_device,
        &sa11x0ssp_device,
        &sa11x0pcmcia_device,
-       &sa11x0fb_device,
        &sa11x0rtc_device,
+       &sa11x0dma_device,
 };
 
 static int __init sa1100_init(void)
@@ -368,12 +359,6 @@ static int __init sa1100_init(void)
 
 arch_initcall(sa1100_init);
 
-void (*sa1100fb_backlight_power)(int on);
-void (*sa1100fb_lcd_power)(int on);
-
-EXPORT_SYMBOL(sa1100fb_backlight_power);
-EXPORT_SYMBOL(sa1100fb_lcd_power);
-
 
 /*
  * Common I/O mapping:
@@ -428,7 +413,7 @@ void __init sa1100_map_io(void)
  * the MBGNT signal false to ensure the SA1111 doesn't own the
  * SDRAM bus.
  */
-void __init sa1110_mb_disable(void)
+void sa1110_mb_disable(void)
 {
        unsigned long flags;
 
@@ -447,7 +432,7 @@ void __init sa1110_mb_disable(void)
  * If the system is going to use the SA-1111 DMA engines, set up
  * the memory bus request/grant pins.
  */
-void __devinit sa1110_mb_enable(void)
+void sa1110_mb_enable(void)
 {
        unsigned long flags;
 
index 33268cf..9eb3b3c 100644 (file)
@@ -16,9 +16,6 @@ extern void sa11x0_restart(char, const char *);
        mi->bank[__nr].start = (__start), \
        mi->bank[__nr].size = (__size)
 
-extern void (*sa1100fb_backlight_power)(int on);
-extern void (*sa1100fb_lcd_power)(int on);
-
 extern void sa1110_mb_enable(void);
 extern void sa1110_mb_disable(void);
 
@@ -39,4 +36,8 @@ struct irda_platform_data;
 void sa11x0_register_irda(struct irda_platform_data *irda);
 
 struct mcp_plat_data;
+void sa11x0_ppc_configure_mcp(void);
 void sa11x0_register_mcp(struct mcp_plat_data *data);
+
+struct sa1100fb_mach_info;
+void sa11x0_register_lcd(struct sa1100fb_mach_info *inf);
index 1e6b3c1..b2e8d0f 100644 (file)
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 
+#include <video/sa1100fb.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irda.h>
 
 #include <mach/h3xxx.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -36,13 +39,28 @@ static void h3100_lcd_power(int enable)
        }
 }
 
+static struct sa1100fb_mach_info h3100_lcd_info = {
+       .pixclock       = 406977,       .bpp            = 4,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 26,           .vsync_len      = 41,
+       .left_margin    = 4,            .upper_margin   = 0,
+       .right_margin   = 4,            .lower_margin   = 0,
+
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       .cmap_greyscale = 1,
+       .cmap_inverse   = 1,
+
+       .lccr0          = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+
+       .lcd_power = h3100_lcd_power,
+};
 
 static void __init h3100_map_io(void)
 {
        h3xxx_map_io();
 
-       sa1100fb_lcd_power = h3100_lcd_power;
-
        /* Older bootldrs put GPIO2-9 in alternate mode on the
           assumption that they are used for video */
        GAFR &= ~0x000001fb;
@@ -80,12 +98,15 @@ static void __init h3100_mach_init(void)
 {
        h3xxx_init_gpio(h3100_default_gpio, ARRAY_SIZE(h3100_default_gpio));
        h3xxx_mach_init();
+
+       sa11x0_register_lcd(&h3100_lcd_info);
        sa11x0_register_irda(&h3100_irda_data);
 }
 
 MACHINE_START(H3100, "Compaq iPAQ H3100")
        .atag_offset    = 0x100,
        .map_io         = h3100_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = h3100_mach_init,
index 6b58e74..cb6659f 100644 (file)
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 
+#include <video/sa1100fb.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irda.h>
 
 #include <mach/h3xxx.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -56,11 +59,35 @@ err2:       gpio_free(H3XXX_EGPIO_LCD_ON);
 err1:  return;
 }
 
+static const struct sa1100fb_rgb h3600_rgb_16 = {
+       .red    = { .offset = 12, .length = 4, },
+       .green  = { .offset = 7,  .length = 4, },
+       .blue   = { .offset = 1,  .length = 4, },
+       .transp = { .offset = 0,  .length = 0, },
+};
+
+static struct sa1100fb_mach_info h3600_lcd_info = {
+       .pixclock       = 174757,       .bpp            = 16,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 3,            .vsync_len      = 3,
+       .left_margin    = 12,           .upper_margin   = 10,
+       .right_margin   = 17,           .lower_margin   = 1,
+
+       .cmap_static    = 1,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+
+       .rgb[RGB_16] = &h3600_rgb_16,
+
+       .lcd_power = h3600_lcd_power,
+};
+
+
 static void __init h3600_map_io(void)
 {
        h3xxx_map_io();
-
-       sa1100fb_lcd_power = h3600_lcd_power;
 }
 
 /*
@@ -121,12 +148,15 @@ static void __init h3600_mach_init(void)
 {
        h3xxx_init_gpio(h3600_default_gpio, ARRAY_SIZE(h3600_default_gpio));
        h3xxx_mach_init();
+
+       sa11x0_register_lcd(&h3600_lcd_info);
        sa11x0_register_irda(&h3600_irda_data);
 }
 
 MACHINE_START(H3600, "Compaq iPAQ H3600")
        .atag_offset    = 0x100,
        .map_io         = h3600_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = h3600_mach_init,
index b0784c9..63150e1 100644 (file)
@@ -109,11 +109,8 @@ static struct flash_platform_data h3xxx_flash_data = {
        .nr_parts       = ARRAY_SIZE(h3xxx_partitions),
 };
 
-static struct resource h3xxx_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource h3xxx_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 
 /*
@@ -186,11 +183,7 @@ static struct sa1100_port_fns h3xxx_port_fns __initdata = {
  */
 
 static struct resource egpio_resources[] = {
-       [0] = {
-               .start  = H3600_EGPIO_PHYS,
-               .end    = H3600_EGPIO_PHYS + 0x4 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
+       [0] = DEFINE_RES_MEM(H3600_EGPIO_PHYS, 0x4),
 };
 
 static struct htc_egpio_chip egpio_chips[] = {
index c01bb36..5535475 100644 (file)
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/irq.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
@@ -35,6 +33,9 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/serial_sa1100.h>
 
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
 #include "generic.h"
 
 /**********************************************************************
@@ -179,11 +180,8 @@ static struct flash_platform_data hackkit_flash_data = {
        .nr_parts       = ARRAY_SIZE(hackkit_partitions),
 };
 
-static struct resource hackkit_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_32M,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource hackkit_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 static void __init hackkit_init(void)
 {
@@ -197,6 +195,7 @@ static void __init hackkit_init(void)
 MACHINE_START(HACKKIT, "HackKit Cpu Board")
        .atag_offset    = 0x100,
        .map_io         = hackkit_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = hackkit_init,
index bae8296..3f2d1b6 100644 (file)
 
 /*
  * Direct Memory Access (DMA) control registers
- *
- * Registers
- *    DDAR0            Direct Memory Access (DMA) Device Address Register
- *                     channel 0 (read/write).
- *    DCSR0            Direct Memory Access (DMA) Control and Status
- *                     Register channel 0 (read/write).
- *    DBSA0            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 0 (read/write).
- *    DBTA0            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 0 (read/write).
- *    DBSB0            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 0 (read/write).
- *    DBTB0            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 0 (read/write).
- *
- *    DDAR1            Direct Memory Access (DMA) Device Address Register
- *                     channel 1 (read/write).
- *    DCSR1            Direct Memory Access (DMA) Control and Status
- *                     Register channel 1 (read/write).
- *    DBSA1            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 1 (read/write).
- *    DBTA1            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 1 (read/write).
- *    DBSB1            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 1 (read/write).
- *    DBTB1            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 1 (read/write).
- *
- *    DDAR2            Direct Memory Access (DMA) Device Address Register
- *                     channel 2 (read/write).
- *    DCSR2            Direct Memory Access (DMA) Control and Status
- *                     Register channel 2 (read/write).
- *    DBSA2            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 2 (read/write).
- *    DBTA2            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 2 (read/write).
- *    DBSB2            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 2 (read/write).
- *    DBTB2            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 2 (read/write).
- *
- *    DDAR3            Direct Memory Access (DMA) Device Address Register
- *                     channel 3 (read/write).
- *    DCSR3            Direct Memory Access (DMA) Control and Status
- *                     Register channel 3 (read/write).
- *    DBSA3            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 3 (read/write).
- *    DBTA3            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 3 (read/write).
- *    DBSB3            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 3 (read/write).
- *    DBTB3            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 3 (read/write).
- *
- *    DDAR4            Direct Memory Access (DMA) Device Address Register
- *                     channel 4 (read/write).
- *    DCSR4            Direct Memory Access (DMA) Control and Status
- *                     Register channel 4 (read/write).
- *    DBSA4            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 4 (read/write).
- *    DBTA4            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 4 (read/write).
- *    DBSB4            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 4 (read/write).
- *    DBTB4            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 4 (read/write).
- *
- *    DDAR5            Direct Memory Access (DMA) Device Address Register
- *                     channel 5 (read/write).
- *    DCSR5            Direct Memory Access (DMA) Control and Status
- *                     Register channel 5 (read/write).
- *    DBSA5            Direct Memory Access (DMA) Buffer Start address
- *                     register A channel 5 (read/write).
- *    DBTA5            Direct Memory Access (DMA) Buffer Transfer count
- *                     register A channel 5 (read/write).
- *    DBSB5            Direct Memory Access (DMA) Buffer Start address
- *                     register B channel 5 (read/write).
- *    DBTB5            Direct Memory Access (DMA) Buffer Transfer count
- *                     register B channel 5 (read/write).
  */
-
-#define DMASp          0x00000020      /* DMA control reg. Space [byte]   */
-
-#define DDAR(Nb)       __REG(0xB0000000 + (Nb)*DMASp)  /* DMA Device Address Reg. channel [0..5] */
-#define SetDCSR(Nb)    __REG(0xB0000004 + (Nb)*DMASp)  /* Set DMA Control & Status Reg. channel [0..5] (write) */
-#define ClrDCSR(Nb)    __REG(0xB0000008 + (Nb)*DMASp)  /* Clear DMA Control & Status Reg. channel [0..5] (write) */
-#define RdDCSR(Nb)     __REG(0xB000000C + (Nb)*DMASp)  /* Read DMA Control & Status Reg. channel [0..5] (read) */
-#define DBSA(Nb)       __REG(0xB0000010 + (Nb)*DMASp)  /* DMA Buffer Start address reg. A channel [0..5] */
-#define DBTA(Nb)       __REG(0xB0000014 + (Nb)*DMASp)  /* DMA Buffer Transfer count reg. A channel [0..5] */
-#define DBSB(Nb)       __REG(0xB0000018 + (Nb)*DMASp)  /* DMA Buffer Start address reg. B channel [0..5] */
-#define DBTB(Nb)       __REG(0xB000001C + (Nb)*DMASp)  /* DMA Buffer Transfer count reg. B channel [0..5] */
-
-#define DDAR_RW        0x00000001      /* device data Read/Write          */
-#define DDAR_DevWr     (DDAR_RW*0)     /*  Device data Write              */
-                                       /*  (memory -> device)             */
-#define DDAR_DevRd     (DDAR_RW*1)     /*  Device data Read               */
-                                       /*  (device -> memory)             */
-#define DDAR_E         0x00000002      /* big/little Endian device        */
-#define DDAR_LtlEnd    (DDAR_E*0)      /*  Little Endian device           */
-#define DDAR_BigEnd    (DDAR_E*1)      /*  Big Endian device              */
-#define DDAR_BS        0x00000004      /* device Burst Size               */
-#define DDAR_Brst4     (DDAR_BS*0)     /*  Burst-of-4 device              */
-#define DDAR_Brst8     (DDAR_BS*1)     /*  Burst-of-8 device              */
-#define DDAR_DW        0x00000008      /* device Data Width               */
-#define DDAR_8BitDev   (DDAR_DW*0)     /*  8-Bit Device                   */
-#define DDAR_16BitDev  (DDAR_DW*1)     /*  16-Bit Device                  */
-#define DDAR_DS        Fld (4, 4)      /* Device Select                   */
-#define DDAR_Ser0UDCTr                 /*  Ser. port 0 UDC Transmit       */ \
-                       (0x0 << FShft (DDAR_DS))
-#define DDAR_Ser0UDCRc                 /*  Ser. port 0 UDC Receive        */ \
-                       (0x1 << FShft (DDAR_DS))
-#define DDAR_Ser1SDLCTr                        /*  Ser. port 1 SDLC Transmit      */ \
-                       (0x2 << FShft (DDAR_DS))
-#define DDAR_Ser1SDLCRc                        /*  Ser. port 1 SDLC Receive       */ \
-                       (0x3 << FShft (DDAR_DS))
-#define DDAR_Ser1UARTTr                        /*  Ser. port 1 UART Transmit      */ \
-                       (0x4 << FShft (DDAR_DS))
-#define DDAR_Ser1UARTRc                        /*  Ser. port 1 UART Receive       */ \
-                       (0x5 << FShft (DDAR_DS))
-#define DDAR_Ser2ICPTr                 /*  Ser. port 2 ICP Transmit       */ \
-                       (0x6 << FShft (DDAR_DS))
-#define DDAR_Ser2ICPRc                 /*  Ser. port 2 ICP Receive        */ \
-                       (0x7 << FShft (DDAR_DS))
-#define DDAR_Ser3UARTTr                        /*  Ser. port 3 UART Transmit      */ \
-                       (0x8 << FShft (DDAR_DS))
-#define DDAR_Ser3UARTRc                        /*  Ser. port 3 UART Receive       */ \
-                       (0x9 << FShft (DDAR_DS))
-#define DDAR_Ser4MCP0Tr                        /*  Ser. port 4 MCP 0 Transmit     */ \
-                                       /*  (audio)                        */ \
-                       (0xA << FShft (DDAR_DS))
-#define DDAR_Ser4MCP0Rc                        /*  Ser. port 4 MCP 0 Receive      */ \
-                                       /*  (audio)                        */ \
-                       (0xB << FShft (DDAR_DS))
-#define DDAR_Ser4MCP1Tr                        /*  Ser. port 4 MCP 1 Transmit     */ \
-                                       /*  (telecom)                      */ \
-                       (0xC << FShft (DDAR_DS))
-#define DDAR_Ser4MCP1Rc                        /*  Ser. port 4 MCP 1 Receive      */ \
-                                       /*  (telecom)                      */ \
-                       (0xD << FShft (DDAR_DS))
-#define DDAR_Ser4SSPTr                 /*  Ser. port 4 SSP Transmit       */ \
-                       (0xE << FShft (DDAR_DS))
-#define DDAR_Ser4SSPRc                 /*  Ser. port 4 SSP Receive        */ \
-                       (0xF << FShft (DDAR_DS))
-#define DDAR_DA        Fld (24, 8)     /* Device Address                  */
-#define DDAR_DevAdd(Add)               /*  Device Address                 */ \
-                       (((Add) & 0xF0000000) | \
-                        (((Add) & 0X003FFFFC) << (FShft (DDAR_DA) - 2)))
-#define DDAR_Ser0UDCWr                 /* Ser. port 0 UDC Write           */ \
-                       (DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \
-                        DDAR_Ser0UDCTr + DDAR_DevAdd (__PREG(Ser0UDCDR)))
-#define DDAR_Ser0UDCRd                 /* Ser. port 0 UDC Read            */ \
-                       (DDAR_DevRd + DDAR_Brst8 + DDAR_8BitDev + \
-                        DDAR_Ser0UDCRc + DDAR_DevAdd (__PREG(Ser0UDCDR)))
-#define DDAR_Ser1UARTWr                        /* Ser. port 1 UART Write          */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser1UARTTr + DDAR_DevAdd (__PREG(Ser1UTDR)))
-#define DDAR_Ser1UARTRd                        /* Ser. port 1 UART Read           */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser1UARTRc + DDAR_DevAdd (__PREG(Ser1UTDR)))
-#define DDAR_Ser1SDLCWr                        /* Ser. port 1 SDLC Write          */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser1SDLCTr + DDAR_DevAdd (__PREG(Ser1SDDR)))
-#define DDAR_Ser1SDLCRd                        /* Ser. port 1 SDLC Read           */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser1SDLCRc + DDAR_DevAdd (__PREG(Ser1SDDR)))
-#define DDAR_Ser2UARTWr                        /* Ser. port 2 UART Write          */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser2ICPTr + DDAR_DevAdd (__PREG(Ser2UTDR)))
-#define DDAR_Ser2UARTRd                        /* Ser. port 2 UART Read           */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser2ICPRc + DDAR_DevAdd (__PREG(Ser2UTDR)))
-#define DDAR_Ser2HSSPWr                        /* Ser. port 2 HSSP Write          */ \
-                       (DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \
-                        DDAR_Ser2ICPTr + DDAR_DevAdd (__PREG(Ser2HSDR)))
-#define DDAR_Ser2HSSPRd                        /* Ser. port 2 HSSP Read           */ \
-                       (DDAR_DevRd + DDAR_Brst8 + DDAR_8BitDev + \
-                        DDAR_Ser2ICPRc + DDAR_DevAdd (__PREG(Ser2HSDR)))
-#define DDAR_Ser3UARTWr                        /* Ser. port 3 UART Write          */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser3UARTTr + DDAR_DevAdd (__PREG(Ser3UTDR)))
-#define DDAR_Ser3UARTRd                        /* Ser. port 3 UART Read           */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev + \
-                        DDAR_Ser3UARTRc + DDAR_DevAdd (__PREG(Ser3UTDR)))
-#define DDAR_Ser4MCP0Wr                        /* Ser. port 4 MCP 0 Write (audio) */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4MCP0Tr + DDAR_DevAdd (__PREG(Ser4MCDR0)))
-#define DDAR_Ser4MCP0Rd                        /* Ser. port 4 MCP 0 Read (audio)  */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4MCP0Rc + DDAR_DevAdd (__PREG(Ser4MCDR0)))
-#define DDAR_Ser4MCP1Wr                        /* Ser. port 4 MCP 1 Write         */ \
-                                       /* (telecom)                       */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4MCP1Tr + DDAR_DevAdd (__PREG(Ser4MCDR1)))
-#define DDAR_Ser4MCP1Rd                        /* Ser. port 4 MCP 1 Read          */ \
-                                       /* (telecom)                       */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4MCP1Rc + DDAR_DevAdd (__PREG(Ser4MCDR1)))
-#define DDAR_Ser4SSPWr                 /* Ser. port 4 SSP Write (16 bits) */ \
-                       (DDAR_DevWr + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4SSPTr + DDAR_DevAdd (__PREG(Ser4SSDR)))
-#define DDAR_Ser4SSPRd                 /* Ser. port 4 SSP Read (16 bits)  */ \
-                       (DDAR_DevRd + DDAR_Brst4 + DDAR_16BitDev + \
-                        DDAR_Ser4SSPRc + DDAR_DevAdd (__PREG(Ser4SSDR)))
-
-#define DCSR_RUN       0x00000001      /* DMA running                     */
-#define DCSR_IE        0x00000002      /* DMA Interrupt Enable            */
-#define DCSR_ERROR     0x00000004      /* DMA ERROR                       */
-#define DCSR_DONEA     0x00000008      /* DONE DMA transfer buffer A      */
-#define DCSR_STRTA     0x00000010      /* STaRTed DMA transfer buffer A   */
-#define DCSR_DONEB     0x00000020      /* DONE DMA transfer buffer B      */
-#define DCSR_STRTB     0x00000040      /* STaRTed DMA transfer buffer B   */
-#define DCSR_BIU       0x00000080      /* DMA Buffer In Use               */
-#define DCSR_BufA      (DCSR_BIU*0)    /*  DMA Buffer A in use            */
-#define DCSR_BufB      (DCSR_BIU*1)    /*  DMA Buffer B in use            */
-
-#define DBT_TC         Fld (13, 0)     /* Transfer Count                  */
-#define DBTA_TCA       DBT_TC          /* Transfer Count buffer A         */
-#define DBTB_TCB       DBT_TC          /* Transfer Count buffer B         */
+#define DMA_SIZE       (6 * 0x20)
+#define DMA_PHYS       0xb0000000
 
 
 /*
 #define LCD_Int100_0A  0xF             /* LCD Intensity = 100.0% =  1     */
                                        /* (Alternative)                   */
 
-#define LCCR0          __REG(0xB0100000)  /* LCD Control Reg. 0 */
-#define LCSR           __REG(0xB0100004)  /* LCD Status Reg. */
-#define DBAR1          __REG(0xB0100010)  /* LCD DMA Base Address Reg. channel 1 */
-#define DCAR1          __REG(0xB0100014)  /* LCD DMA Current Address Reg. channel 1 */
-#define DBAR2          __REG(0xB0100018)  /* LCD DMA Base Address Reg.  channel 2 */
-#define DCAR2          __REG(0xB010001C)  /* LCD DMA Current Address Reg. channel 2 */
-#define LCCR1          __REG(0xB0100020)  /* LCD Control Reg. 1 */
-#define LCCR2          __REG(0xB0100024)  /* LCD Control Reg. 2 */
-#define LCCR3          __REG(0xB0100028)  /* LCD Control Reg. 3 */
-
 #define LCCR0_LEN      0x00000001      /* LCD ENable                      */
 #define LCCR0_CMS      0x00000002      /* Color/Monochrome display Select */
 #define LCCR0_Color    (LCCR0_CMS*0)   /*  Color display                  */
index 28c2cf5..3073914 100644 (file)
@@ -85,21 +85,18 @@ extern void ASSABET_BCR_frob(unsigned int mask, unsigned int set);
 #define ASSABET_BSR_RAD_RI     (1 << 31)
 
 
-/* GPIOs for which the generic definition doesn't say much */
+/* GPIOs (bitmasks) for which the generic definition doesn't say much */
 #define ASSABET_GPIO_RADIO_IRQ         GPIO_GPIO (14)  /* Radio interrupt request  */
 #define ASSABET_GPIO_PS_MODE_SYNC      GPIO_GPIO (16)  /* Power supply mode/sync   */
 #define ASSABET_GPIO_STEREO_64FS_CLK   GPIO_GPIO (19)  /* SSP UDA1341 clock input  */
-#define ASSABET_GPIO_CF_IRQ            GPIO_GPIO (21)  /* CF IRQ   */
-#define ASSABET_GPIO_CF_CD             GPIO_GPIO (22)  /* CF CD */
-#define ASSABET_GPIO_CF_BVD2           GPIO_GPIO (24)  /* CF BVD */
 #define ASSABET_GPIO_GFX_IRQ           GPIO_GPIO (24)  /* Graphics IRQ */
-#define ASSABET_GPIO_CF_BVD1           GPIO_GPIO (25)  /* CF BVD */
 #define ASSABET_GPIO_BATT_LOW          GPIO_GPIO (26)  /* Low battery */
 #define ASSABET_GPIO_RCLK              GPIO_GPIO (26)  /* CCLK/2  */
 
-#define ASSABET_IRQ_GPIO_CF_IRQ                IRQ_GPIO21
-#define ASSABET_IRQ_GPIO_CF_CD         IRQ_GPIO22
-#define ASSABET_IRQ_GPIO_CF_BVD2       IRQ_GPIO24
-#define ASSABET_IRQ_GPIO_CF_BVD1       IRQ_GPIO25
+/* These are gpiolib GPIO numbers, not bitmasks */
+#define ASSABET_GPIO_CF_IRQ            21      /* CF IRQ */
+#define ASSABET_GPIO_CF_CD             22      /* CF CD  */
+#define ASSABET_GPIO_CF_BVD2           24      /* CF BVD / IOSPKR */
+#define ASSABET_GPIO_CF_BVD1           25      /* CF BVD / IOSTSCHG */
 
 #endif
index c3ac3d0..88fd9c0 100644 (file)
 #define CERF_ETH_IO                    0xf0000000
 #define CERF_ETH_IRQ IRQ_GPIO26
 
-#define CERF_GPIO_CF_BVD2              GPIO_GPIO (19)
-#define CERF_GPIO_CF_BVD1              GPIO_GPIO (20)
-#define CERF_GPIO_CF_RESET             GPIO_GPIO (21)
-#define CERF_GPIO_CF_IRQ               GPIO_GPIO (22)
-#define CERF_GPIO_CF_CD                        GPIO_GPIO (23)
-
-#define CERF_IRQ_GPIO_CF_BVD2          IRQ_GPIO19
-#define CERF_IRQ_GPIO_CF_BVD1          IRQ_GPIO20
-#define CERF_IRQ_GPIO_CF_IRQ           IRQ_GPIO22
-#define CERF_IRQ_GPIO_CF_CD            IRQ_GPIO23
+#define CERF_GPIO_CF_BVD2              19
+#define CERF_GPIO_CF_BVD1              20
+#define CERF_GPIO_CF_RESET             21
+#define CERF_GPIO_CF_IRQ               22
+#define CERF_GPIO_CF_CD                        23
 
 #endif // _INCLUDE_CERF_H_
diff --git a/arch/arm/mach-sa1100/include/mach/dma.h b/arch/arm/mach-sa1100/include/mach/dma.h
deleted file mode 100644 (file)
index dda1b35..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * arch/arm/mach-sa1100/include/mach/dma.h
- *
- * Generic SA1100 DMA support
- *
- * Copyright (C) 2000 Nicolas Pitre
- *
- */
-
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#include "hardware.h"
-
-
-/*
- * The SA1100 has six internal DMA channels.
- */
-#define SA1100_DMA_CHANNELS    6
-
-/*
- * Maximum physical DMA buffer size
- */
-#define MAX_DMA_SIZE           0x1fff
-#define CUT_DMA_SIZE           0x1000
-
-/*
- * All possible SA1100 devices a DMA channel can be attached to.
- */
-typedef enum {
-       DMA_Ser0UDCWr  = DDAR_Ser0UDCWr,   /* Ser. port 0 UDC Write */
-       DMA_Ser0UDCRd  = DDAR_Ser0UDCRd,   /* Ser. port 0 UDC Read */
-       DMA_Ser1UARTWr = DDAR_Ser1UARTWr,  /* Ser. port 1 UART Write */
-       DMA_Ser1UARTRd = DDAR_Ser1UARTRd,  /* Ser. port 1 UART Read */
-       DMA_Ser1SDLCWr = DDAR_Ser1SDLCWr,  /* Ser. port 1 SDLC Write */
-       DMA_Ser1SDLCRd = DDAR_Ser1SDLCRd,  /* Ser. port 1 SDLC Read */
-       DMA_Ser2UARTWr = DDAR_Ser2UARTWr,  /* Ser. port 2 UART Write */
-       DMA_Ser2UARTRd = DDAR_Ser2UARTRd,  /* Ser. port 2 UART Read */
-       DMA_Ser2HSSPWr = DDAR_Ser2HSSPWr,  /* Ser. port 2 HSSP Write */
-       DMA_Ser2HSSPRd = DDAR_Ser2HSSPRd,  /* Ser. port 2 HSSP Read */
-       DMA_Ser3UARTWr = DDAR_Ser3UARTWr,  /* Ser. port 3 UART Write */
-       DMA_Ser3UARTRd = DDAR_Ser3UARTRd,  /* Ser. port 3 UART Read */
-       DMA_Ser4MCP0Wr = DDAR_Ser4MCP0Wr,  /* Ser. port 4 MCP 0 Write (audio) */
-       DMA_Ser4MCP0Rd = DDAR_Ser4MCP0Rd,  /* Ser. port 4 MCP 0 Read (audio) */
-       DMA_Ser4MCP1Wr = DDAR_Ser4MCP1Wr,  /* Ser. port 4 MCP 1 Write */
-       DMA_Ser4MCP1Rd = DDAR_Ser4MCP1Rd,  /* Ser. port 4 MCP 1 Read */
-       DMA_Ser4SSPWr  = DDAR_Ser4SSPWr,   /* Ser. port 4 SSP Write (16 bits) */
-       DMA_Ser4SSPRd  = DDAR_Ser4SSPRd    /* Ser. port 4 SSP Read (16 bits) */
-} dma_device_t;
-
-typedef struct {
-       volatile u_long DDAR;
-       volatile u_long SetDCSR;
-       volatile u_long ClrDCSR;
-       volatile u_long RdDCSR;
-       volatile dma_addr_t DBSA;
-       volatile u_long DBTA;
-       volatile dma_addr_t DBSB;
-       volatile u_long DBTB;
-} dma_regs_t;
-
-typedef void (*dma_callback_t)(void *data);
-
-/*
- * DMA function prototypes
- */
-
-extern int sa1100_request_dma( dma_device_t device, const char *device_id,
-                              dma_callback_t callback, void *data,
-                              dma_regs_t **regs );
-extern void sa1100_free_dma( dma_regs_t *regs );
-extern int sa1100_start_dma( dma_regs_t *regs, dma_addr_t dma_ptr, u_int size );
-extern dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs);
-extern void sa1100_reset_dma(dma_regs_t *regs);
-
-/**
- *     sa1100_stop_dma - stop DMA in progress
- *     @regs: identifier for the channel to use
- *
- *     This stops DMA without clearing buffer pointers. Unlike
- *     sa1100_clear_dma() this allows subsequent use of sa1100_resume_dma()
- *     or sa1100_get_dma_pos().
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- **/
-
-#define sa1100_stop_dma(regs)  ((regs)->ClrDCSR = DCSR_IE|DCSR_RUN)
-
-/**
- *     sa1100_resume_dma - resume DMA on a stopped channel
- *     @regs: identifier for the channel to use
- *
- *     This resumes DMA on a channel previously stopped with
- *     sa1100_stop_dma().
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- **/
-
-#define sa1100_resume_dma(regs)        ((regs)->SetDCSR = DCSR_IE|DCSR_RUN)
-
-/**
- *     sa1100_clear_dma - clear DMA pointers
- *     @regs: identifier for the channel to use
- *
- *     This clear any DMA state so the DMA engine is ready to restart
- *     with new buffers through sa1100_start_dma(). Any buffers in flight
- *     are discarded.
- *
- *     The @regs identifier is provided by a successful call to
- *     sa1100_request_dma().
- **/
-
-#define sa1100_clear_dma(regs) ((regs)->ClrDCSR = DCSR_IE|DCSR_RUN|DCSR_STRTA|DCSR_STRTB)
-
-#endif /* _ASM_ARCH_DMA_H */
index 6aa13c4..8cf7630 100644 (file)
@@ -8,17 +8,11 @@
  * warranty of any kind, whether express or implied.
  */
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                mov     \base, #0xfa000000              @ ICIP = 0xfa050000
                add     \base, \base, #0x00050000
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \irqstat, [\base]               @ get irqs
                ldr     \irqnr, [\base, #4]             @ ICMR = 0xfa050004
index d18f21a..3790298 100644 (file)
 /*
  * Figure out the MAX IRQ number.
  *
- * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1.
- * If we have an LoCoMo, the max IRQ is IRQ_BOARD_START + 4
- * Otherwise, we have the standard IRQs only.
+ * Neponset, SA1111 and UCB1x00 are sparse IRQ aware, so can dynamically
+ * allocate their IRQs above NR_IRQS.
+ *
+ * LoCoMo has 4 additional IRQs, but is not sparse IRQ aware, and so has
+ * to be included in the NR_IRQS calculation.
  */
-#ifdef CONFIG_SA1111
-#define NR_IRQS                        (IRQ_BOARD_END + 55)
-#elif defined(CONFIG_SHARP_LOCOMO)
-#define NR_IRQS                        (IRQ_BOARD_START + 4)
+#ifdef CONFIG_SHARP_LOCOMO
+#define NR_IRQS_LOCOMO         4
 #else
-#define NR_IRQS                        (IRQ_BOARD_START)
+#define NR_IRQS_LOCOMO         0
 #endif
 
-/*
- * Board specific IRQs.  Define them here.
- * Do not surround them with ifdefs.
- */
-#define IRQ_NEPONSET_SMC9196   (IRQ_BOARD_START + 0)
-#define IRQ_NEPONSET_USAR      (IRQ_BOARD_START + 1)
-#define IRQ_NEPONSET_SA1111    (IRQ_BOARD_START + 2)
+#ifndef NR_IRQS
+#define NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
+#endif
+#define SA1100_NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
index ed1a331..4b2860a 100644 (file)
@@ -16,7 +16,7 @@ struct mcp_plat_data {
        u32 mccr0;
        u32 mccr1;
        unsigned int sclk_rate;
-       int gpio_base;
+       void *codec_pdata;
 };
 
 #endif
index 14f8382..5ebd469 100644 (file)
 
 #include <mach/irqs.h>
 
-#define GPIO_PC_READY0 GPIO_GPIO(11) /* ready for socket 0 (active high)*/
-#define GPIO_PC_READY1 GPIO_GPIO(12) /* ready for socket 1 (active high) */
-#define GPIO_PC_CD0    GPIO_GPIO(13) /* detect for socket 0 (active low) */
-#define GPIO_PC_CD1    GPIO_GPIO(14) /* detect for socket 1 (active low) */
-#define GPIO_PC_RESET0 GPIO_GPIO(15) /* reset socket 0 */
-#define GPIO_PC_RESET1 GPIO_GPIO(16) /* reset socket 1 */
+#define GPIO_PC_READY0 11 /* ready for socket 0 (active high)*/
+#define GPIO_PC_READY1 12 /* ready for socket 1 (active high) */
+#define GPIO_PC_CD0    13 /* detect for socket 0 (active low) */
+#define GPIO_PC_CD1    14 /* detect for socket 1 (active low) */
+#define GPIO_PC_RESET0 15 /* reset socket 0 */
+#define GPIO_PC_RESET1 16 /* reset socket 1 */
 
 #define NANOENGINE_IRQ_GPIO_PCI                IRQ_GPIO0
 #define NANOENGINE_IRQ_GPIO_PC_READY0  IRQ_GPIO11
index ffe2bc4..5516a52 100644 (file)
 /*
  * Neponset definitions: 
  */
-
-#define NEPONSET_CPLD_BASE      (0x10000000)
-#define Nep_p2v( x )            ((x) - NEPONSET_CPLD_BASE + 0xf3000000)
-#define Nep_v2p( x )            ((x) - 0xf3000000 + NEPONSET_CPLD_BASE)
-
-#define _IRR                    0x10000024      /* Interrupt Reason Register */
-#define _AUD_CTL                0x100000c0      /* Audio controls (RW)       */
-#define _MDM_CTL_0              0x100000b0      /* Modem control 0 (RW)      */
-#define _MDM_CTL_1              0x100000b4      /* Modem control 1 (RW)      */
-#define _NCR_0                 0x100000a0      /* Control Register (RW)     */
-#define _KP_X_OUT               0x10000090      /* Keypad row write (RW)     */
-#define _KP_Y_IN                0x10000080      /* Keypad column read (RO)   */
-#define _SWPK                   0x10000020      /* Switch pack (RO)          */
-#define _WHOAMI                 0x10000000      /* System ID Register (RO)   */
-
-#define _LEDS                   0x10000010      /* LEDs [31:0] (WO)          */
-
-#define IRR                     (*((volatile u_char *) Nep_p2v(_IRR)))
-#define AUD_CTL                 (*((volatile u_char *) Nep_p2v(_AUD_CTL)))
-#define MDM_CTL_0               (*((volatile u_char *) Nep_p2v(_MDM_CTL_0)))
-#define MDM_CTL_1               (*((volatile u_char *) Nep_p2v(_MDM_CTL_1)))
-#define NCR_0                  (*((volatile u_char *) Nep_p2v(_NCR_0)))
-#define KP_X_OUT                (*((volatile u_char *) Nep_p2v(_KP_X_OUT)))
-#define KP_Y_IN                 (*((volatile u_char *) Nep_p2v(_KP_Y_IN)))
-#define SWPK                    (*((volatile u_char *) Nep_p2v(_SWPK)))
-#define WHOAMI                  (*((volatile u_char *) Nep_p2v(_WHOAMI)))
-
-#define LEDS                    (*((volatile Word   *) Nep_p2v(_LEDS)))
-
-#define IRR_ETHERNET           (1<<0)
-#define IRR_USAR               (1<<1)
-#define IRR_SA1111             (1<<2)
-
-#define AUD_SEL_1341            (1<<0)
-#define AUD_MUTE_1341           (1<<1)
-
-#define MDM_CTL0_RTS1          (1 << 0)
-#define MDM_CTL0_DTR1          (1 << 1)
-#define MDM_CTL0_RTS2          (1 << 2)
-#define MDM_CTL0_DTR2          (1 << 3)
-
-#define MDM_CTL1_CTS1          (1 << 0)
-#define MDM_CTL1_DSR1          (1 << 1)
-#define MDM_CTL1_DCD1          (1 << 2)
-#define MDM_CTL1_CTS2          (1 << 3)
-#define MDM_CTL1_DSR2          (1 << 4)
-#define MDM_CTL1_DCD2          (1 << 5)
-
 #define NCR_GP01_OFF           (1<<0)
 #define NCR_TP_PWR_EN          (1<<1)
 #define NCR_MS_PWR_EN          (1<<2)
@@ -71,4 +23,8 @@
 #define NCR_A0VPP              (1<<5)
 #define NCR_A1VPP              (1<<6)
 
+void neponset_ncr_frob(unsigned int, unsigned int);
+#define neponset_ncr_set(v)    neponset_ncr_frob(0, v)
+#define neponset_ncr_clear(v)  neponset_ncr_frob(v, 0)
+
 #endif
index ec27d6e..fff39e0 100644 (file)
 #define SHANNON_GPIO_U3_RTS            GPIO_GPIO (19)  /* ?? */
 #define SHANNON_GPIO_U3_CTS            GPIO_GPIO (20)  /* ?? */
 #define SHANNON_GPIO_SENSE_12V         GPIO_GPIO (21)  /* Input, 12v flash unprotect detected */
-#define SHANNON_GPIO_DISP_EN           GPIO_GPIO (22)  /* out */
+#define SHANNON_GPIO_DISP_EN           22              /* out */
 /* XXX GPIO 23 unaccounted for */
-#define SHANNON_GPIO_EJECT_0           GPIO_GPIO (24)  /* in */
-#define SHANNON_IRQ_GPIO_EJECT_0       IRQ_GPIO24
-#define SHANNON_GPIO_EJECT_1           GPIO_GPIO (25)  /* in */
-#define SHANNON_IRQ_GPIO_EJECT_1       IRQ_GPIO25
-#define SHANNON_GPIO_RDY_0             GPIO_GPIO (26)  /* in */
-#define SHANNON_IRQ_GPIO_RDY_0         IRQ_GPIO26
-#define SHANNON_GPIO_RDY_1             GPIO_GPIO (27)  /* in */
-#define SHANNON_IRQ_GPIO_RDY_1         IRQ_GPIO27
+#define SHANNON_GPIO_EJECT_0           24              /* in */
+#define SHANNON_GPIO_EJECT_1           25              /* in */
+#define SHANNON_GPIO_RDY_0             26              /* in */
+#define SHANNON_GPIO_RDY_1             27              /* in */
 
 /* MCP UCB codec GPIO pins... */
 
index db28118..cdea671 100644 (file)
 
 
 /*---  PCMCIA  ---*/
-#define GPIO_CF_CD              GPIO_GPIO24
-#define GPIO_CF_IRQ             GPIO_GPIO1
-#define IRQ_GPIO_CF_IRQ         IRQ_GPIO1
-#define IRQ_GPIO_CF_CD          IRQ_GPIO24
+#define GPIO_CF_CD              24
+#define GPIO_CF_IRQ             1
 
 /*--- SmartCard ---*/
 #define GPIO_SMART_CARD                GPIO_GPIO10
diff --git a/arch/arm/mach-sa1100/include/mach/system.h b/arch/arm/mach-sa1100/include/mach/system.h
deleted file mode 100644 (file)
index e17b208..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * arch/arm/mach-sa1100/include/mach/system.h
- *
- * Copyright (c) 1999 Nicolas Pitre <nico@fluxnic.net>
- */
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
index dfbf824..516ccc2 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/syscore_ops.h>
 
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <asm/mach/irq.h>
 
 #include "generic.h"
@@ -221,11 +222,8 @@ static struct irq_chip sa1100_normal_chip = {
        .irq_set_wake   = sa1100_set_wake,
 };
 
-static struct resource irq_resource = {
-       .name   = "irqs",
-       .start  = 0x90050000,
-       .end    = 0x9005ffff,
-};
+static struct resource irq_resource =
+       DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs");
 
 static struct sa1100irq_state {
        unsigned int    saved;
index ee121d6..ca7a7e8 100644 (file)
@@ -23,9 +23,7 @@
 #include <linux/mtd/partitions.h>
 #include <video/s1d13xxxfb.h>
 
-#include <mach/hardware.h>
 #include <asm/hardware/sa1111.h>
-#include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
@@ -34,6 +32,9 @@
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
 #include "generic.h"
 
 /*
@@ -46,7 +47,7 @@
 
 /* memory space (line 52 of HP's doc) */
 #define SA1111REGSTART 0x40000000
-#define SA1111REGLEN   0x00001fff
+#define SA1111REGLEN   0x00002000
 #define EPSONREGSTART  0x48000000
 #define EPSONREGLEN    0x00100000
 #define EPSONFBSTART   0x48200000
@@ -174,16 +175,8 @@ static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
 };
 
 static struct resource s1d13xxxfb_resources[] = {
-       [0] = {
-               .start  = EPSONFBSTART,
-               .end    = EPSONFBSTART + EPSONFBLEN,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = EPSONREGSTART,
-               .end    = EPSONREGSTART + EPSONREGLEN,
-               .flags  = IORESOURCE_MEM,
-       }
+       [0] = DEFINE_RES_MEM(EPSONFBSTART, EPSONFBLEN),
+       [1] = DEFINE_RES_MEM(EPSONREGSTART, EPSONREGLEN),
 };
 
 static struct platform_device s1d13xxxfb_device = {
@@ -197,20 +190,12 @@ static struct platform_device s1d13xxxfb_device = {
 };
 
 static struct resource sa1111_resources[] = {
-       [0] = {
-               .start          = SA1111REGSTART,
-               .end            = SA1111REGSTART + SA1111REGLEN,
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start          = IRQ_GPIO1,
-               .end            = IRQ_GPIO1,
-               .flags          = IORESOURCE_IRQ,
-       },
+       [0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN),
+       [1] = DEFINE_RES_IRQ(IRQ_GPIO1),
 };
 
 static struct sa1111_platform_data sa1111_info = {
-       .irq_base       = IRQ_BOARD_END,
+       .disable_devs   = SA1111_DEVID_PS2_MSE,
 };
 
 static u64 sa1111_dmamask = 0xffffffffUL;
@@ -284,11 +269,6 @@ static struct map_desc jornada720_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(EPSONFBSTART),
                .length         = EPSONFBLEN,
                .type           = MT_DEVICE
-       }, {    /* SA-1111 */
-               .virtual        = 0xf4000000,
-               .pfn            = __phys_to_pfn(SA1111REGSTART),
-               .length         = SA1111REGLEN,
-               .type           = MT_DEVICE
        }
 };
 
@@ -352,11 +332,8 @@ static struct flash_platform_data jornada720_flash_data = {
        .nr_parts       = ARRAY_SIZE(jornada720_partitions),
 };
 
-static struct resource jornada720_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_32M - 1,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource jornada720_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
 static void __init jornada720_mach_init(void)
 {
@@ -367,6 +344,7 @@ MACHINE_START(JORNADA720, "HP Jornada 720")
        /* Maintainer: Kristoffer Ericson <Kristoffer.Ericson@gmail.com> */
        .atag_offset    = 0x100,
        .map_io         = jornada720_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = jornada720_mach_init,
index af4e276..eb6534e 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/kernel.h>
 #include <linux/tty.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -15,6 +17,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 #include <mach/mcp.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -26,8 +29,86 @@ static struct mcp_plat_data lart_mcp_data = {
        .sclk_rate      = 11981000,
 };
 
+#ifdef LART_GREY_LCD
+static struct sa1100fb_mach_info lart_grey_info = {
+       .pixclock       = 150000,       .bpp            = 4,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 1,            .vsync_len      = 1,
+       .left_margin    = 4,            .upper_margin   = 0,
+       .right_margin   = 2,            .lower_margin   = 0,
+
+       .cmap_greyscale = 1,
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+       .lccr0          = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_COLOR_LCD
+static struct sa1100fb_mach_info lart_color_info = {
+       .pixclock       = 150000,       .bpp            = 16,
+       .xres           = 320,          .yres           = 240,
+
+       .hsync_len      = 2,            .vsync_len      = 3,
+       .left_margin    = 69,           .upper_margin   = 14,
+       .right_margin   = 8,            .lower_margin   = 4,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_VIDEO_OUT
+static struct sa1100fb_mach_info lart_video_info = {
+       .pixclock       = 39721,        .bpp            = 16,
+       .xres           = 640,          .yres           = 480,
+
+       .hsync_len      = 95,           .vsync_len      = 2,
+       .left_margin    = 40,           .upper_margin   = 32,
+       .right_margin   = 24,           .lower_margin   = 11,
+
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+
+#ifdef LART_KIT01_LCD
+static struct sa1100fb_mach_info lart_kit01_info = {
+       .pixclock       = 63291,        .bpp            = 16,
+       .xres           = 640,          .yres           = 480,
+
+       .hsync_len      = 64,           .vsync_len      = 3,
+       .left_margin    = 122,          .upper_margin   = 45,
+       .right_margin   = 10,           .lower_margin   = 10,
+
+       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lccr3          = LCCR3_OutEnH | LCCR3_PixFlEdg
+};
+#endif
+
 static void __init lart_init(void)
 {
+       struct sa1100fb_mach_info *inf = NULL;
+
+#ifdef LART_GREY_LCD
+       inf = &lart_grey_info;
+#endif
+#ifdef LART_COLOR_LCD
+       inf = &lart_color_info;
+#endif
+#ifdef LART_VIDEO_OUT
+       inf = &lart_video_info;
+#endif
+#ifdef LART_KIT01_LCD
+       inf = &lart_kit01_info;
+#endif
+
+       if (inf)
+               sa11x0_register_lcd(inf);
+
+       sa11x0_ppc_configure_mcp();
        sa11x0_register_mcp(&lart_mcp_data);
 }
 
@@ -63,6 +144,7 @@ static void __init lart_map_io(void)
 MACHINE_START(LART, "LART")
        .atag_offset    = 0x100,
        .map_io         = lart_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .init_machine   = lart_init,
        .timer          = &sa1100_timer,
index 85f6ee6..8f6446b 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <mach/hardware.h>
 #include <mach/nanoengine.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -58,15 +59,8 @@ static struct flash_platform_data nanoengine_flash_data = {
 };
 
 static struct resource nanoengine_flash_resources[] = {
-       {
-               .start  = SA1100_CS0_PHYS,
-               .end    = SA1100_CS0_PHYS + SZ_32M - 1,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = SA1100_CS1_PHYS,
-               .end    = SA1100_CS1_PHYS + SZ_32M - 1,
-               .flags  = IORESOURCE_MEM,
-       }
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
+       DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M),
 };
 
 static struct map_desc nanoengine_io_desc[] __initdata = {
@@ -114,6 +108,7 @@ static void __init nanoengine_init(void)
 MACHINE_START(NANOENGINE, "BSE nanoEngine")
        .atag_offset    = 0x100,
        .map_io         = nanoengine_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = nanoengine_init,
index b4fa53a..6c58f01 100644 (file)
 /*
  * linux/arch/arm/mach-sa1100/neponset.c
- *
  */
-#include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/init.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
-#include <linux/serial_core.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 #include <asm/mach/map.h>
-#include <asm/mach/irq.h>
 #include <asm/mach/serial_sa1100.h>
-#include <mach/assabet.h>
-#include <mach/neponset.h>
 #include <asm/hardware/sa1111.h>
 #include <asm/sizes.h>
 
-/*
- * Install handler for Neponset IRQ.  Note that we have to loop here
- * since the ETHERNET and USAR IRQs are level based, and we need to
- * ensure that the IRQ signal is deasserted before returning.  This
- * is rather unfortunate.
- */
-static void
-neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       unsigned int irr;
-
-       while (1) {
-               /*
-                * Acknowledge the parent IRQ.
-                */
-               desc->irq_data.chip->irq_ack(&desc->irq_data);
-
-               /*
-                * Read the interrupt reason register.  Let's have all
-                * active IRQ bits high.  Note: there is a typo in the
-                * Neponset user's guide for the SA1111 IRR level.
-                */
-               irr = IRR ^ (IRR_ETHERNET | IRR_USAR);
-
-               if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
-                       break;
-
-               /*
-                * Since there is no individual mask, we have to
-                * mask the parent IRQ.  This is safe, since we'll
-                * recheck the register for any pending IRQs.
-                */
-               if (irr & (IRR_ETHERNET | IRR_USAR)) {
-                       desc->irq_data.chip->irq_mask(&desc->irq_data);
-
-                       /*
-                        * Ack the interrupt now to prevent re-entering
-                        * this neponset handler.  Again, this is safe
-                        * since we'll check the IRR register prior to
-                        * leaving.
-                        */
-                       desc->irq_data.chip->irq_ack(&desc->irq_data);
+#include <mach/hardware.h>
+#include <mach/assabet.h>
+#include <mach/neponset.h>
+#include <mach/irqs.h>
+
+#define NEP_IRQ_SMC91X 0
+#define NEP_IRQ_USAR   1
+#define NEP_IRQ_SA1111 2
+#define NEP_IRQ_NR     3
+
+#define WHOAMI         0x00
+#define LEDS           0x10
+#define SWPK           0x20
+#define IRR            0x24
+#define KP_Y_IN                0x80
+#define KP_X_OUT       0x90
+#define NCR_0          0xa0
+#define MDM_CTL_0      0xb0
+#define MDM_CTL_1      0xb4
+#define AUD_CTL                0xc0
+
+#define IRR_ETHERNET   (1 << 0)
+#define IRR_USAR       (1 << 1)
+#define IRR_SA1111     (1 << 2)
+
+#define MDM_CTL0_RTS1  (1 << 0)
+#define MDM_CTL0_DTR1  (1 << 1)
+#define MDM_CTL0_RTS2  (1 << 2)
+#define MDM_CTL0_DTR2  (1 << 3)
+
+#define MDM_CTL1_CTS1  (1 << 0)
+#define MDM_CTL1_DSR1  (1 << 1)
+#define MDM_CTL1_DCD1  (1 << 2)
+#define MDM_CTL1_CTS2  (1 << 3)
+#define MDM_CTL1_DSR2  (1 << 4)
+#define MDM_CTL1_DCD2  (1 << 5)
+
+#define AUD_SEL_1341   (1 << 0)
+#define AUD_MUTE_1341  (1 << 1)
 
-                       if (irr & IRR_ETHERNET) {
-                               generic_handle_irq(IRQ_NEPONSET_SMC9196);
-                       }
+extern void sa1110_mb_disable(void);
 
-                       if (irr & IRR_USAR) {
-                               generic_handle_irq(IRQ_NEPONSET_USAR);
-                       }
+struct neponset_drvdata {
+       void __iomem *base;
+       struct platform_device *sa1111;
+       struct platform_device *smc91x;
+       unsigned irq_base;
+#ifdef CONFIG_PM_SLEEP
+       u32 ncr0;
+       u32 mdm_ctl_0;
+#endif
+};
 
-                       desc->irq_data.chip->irq_unmask(&desc->irq_data);
-               }
+static void __iomem *nep_base;
 
-               if (irr & IRR_SA1111) {
-                       generic_handle_irq(IRQ_NEPONSET_SA1111);
-               }
+void neponset_ncr_frob(unsigned int mask, unsigned int val)
+{
+       void __iomem *base = nep_base;
+
+       if (base) {
+               unsigned long flags;
+               unsigned v;
+
+               local_irq_save(flags);
+               v = readb_relaxed(base + NCR_0);
+               writeb_relaxed((v & ~mask) | val, base + NCR_0);
+               local_irq_restore(flags);
+       } else {
+               WARN(1, "nep_base unset\n");
        }
 }
 
 static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
 {
-       u_int mdm_ctl0 = MDM_CTL_0;
+       void __iomem *base = nep_base;
+       u_int mdm_ctl0;
 
+       if (!base)
+               return;
+
+       mdm_ctl0 = readb_relaxed(base + MDM_CTL_0);
        if (port->mapbase == _Ser1UTCR0) {
                if (mctrl & TIOCM_RTS)
                        mdm_ctl0 &= ~MDM_CTL0_RTS2;
@@ -106,14 +121,19 @@ static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
                        mdm_ctl0 |= MDM_CTL0_DTR1;
        }
 
-       MDM_CTL_0 = mdm_ctl0;
+       writeb_relaxed(mdm_ctl0, base + MDM_CTL_0);
 }
 
 static u_int neponset_get_mctrl(struct uart_port *port)
 {
+       void __iomem *base = nep_base;
        u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
-       u_int mdm_ctl1 = MDM_CTL_1;
+       u_int mdm_ctl1;
+
+       if (!base)
+               return ret;
 
+       mdm_ctl1 = readb_relaxed(base + MDM_CTL_1);
        if (port->mapbase == _Ser1UTCR0) {
                if (mdm_ctl1 & MDM_CTL1_DCD2)
                        ret &= ~TIOCM_CD;
@@ -138,209 +158,278 @@ static struct sa1100_port_fns neponset_port_fns __devinitdata = {
        .get_mctrl      = neponset_get_mctrl,
 };
 
-static int __devinit neponset_probe(struct platform_device *dev)
+/*
+ * Install handler for Neponset IRQ.  Note that we have to loop here
+ * since the ETHERNET and USAR IRQs are level based, and we need to
+ * ensure that the IRQ signal is deasserted before returning.  This
+ * is rather unfortunate.
+ */
+static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-       sa1100_register_uart_fns(&neponset_port_fns);
+       struct neponset_drvdata *d = irq_desc_get_handler_data(desc);
+       unsigned int irr;
 
-       /*
-        * Install handler for GPIO25.
-        */
-       irq_set_irq_type(IRQ_GPIO25, IRQ_TYPE_EDGE_RISING);
-       irq_set_chained_handler(IRQ_GPIO25, neponset_irq_handler);
+       while (1) {
+               /*
+                * Acknowledge the parent IRQ.
+                */
+               desc->irq_data.chip->irq_ack(&desc->irq_data);
 
-       /*
-        * We would set IRQ_GPIO25 to be a wake-up IRQ, but
-        * unfortunately something on the Neponset activates
-        * this IRQ on sleep (ethernet?)
-        */
-#if 0
-       enable_irq_wake(IRQ_GPIO25);
-#endif
+               /*
+                * Read the interrupt reason register.  Let's have all
+                * active IRQ bits high.  Note: there is a typo in the
+                * Neponset user's guide for the SA1111 IRR level.
+                */
+               irr = readb_relaxed(d->base + IRR);
+               irr ^= IRR_ETHERNET | IRR_USAR;
 
-       /*
-        * Setup other Neponset IRQs.  SA1111 will be done by the
-        * generic SA1111 code.
-        */
-       irq_set_handler(IRQ_NEPONSET_SMC9196, handle_simple_irq);
-       set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE);
-       irq_set_handler(IRQ_NEPONSET_USAR, handle_simple_irq);
-       set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE);
+               if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
+                       break;
 
-       /*
-        * Disable GPIO 0/1 drivers so the buttons work on the module.
-        */
-       NCR_0 = NCR_GP01_OFF;
+               /*
+                * Since there is no individual mask, we have to
+                * mask the parent IRQ.  This is safe, since we'll
+                * recheck the register for any pending IRQs.
+                */
+               if (irr & (IRR_ETHERNET | IRR_USAR)) {
+                       desc->irq_data.chip->irq_mask(&desc->irq_data);
 
-       return 0;
-}
+                       /*
+                        * Ack the interrupt now to prevent re-entering
+                        * this neponset handler.  Again, this is safe
+                        * since we'll check the IRR register prior to
+                        * leaving.
+                        */
+                       desc->irq_data.chip->irq_ack(&desc->irq_data);
 
-#ifdef CONFIG_PM
+                       if (irr & IRR_ETHERNET)
+                               generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X);
 
-/*
- * LDM power management.
- */
-static unsigned int neponset_saved_state;
+                       if (irr & IRR_USAR)
+                               generic_handle_irq(d->irq_base + NEP_IRQ_USAR);
 
-static int neponset_suspend(struct platform_device *dev, pm_message_t state)
-{
-       /*
-        * Save state.
-        */
-       neponset_saved_state = NCR_0;
+                       desc->irq_data.chip->irq_unmask(&desc->irq_data);
+               }
 
-       return 0;
+               if (irr & IRR_SA1111)
+                       generic_handle_irq(d->irq_base + NEP_IRQ_SA1111);
+       }
 }
 
-static int neponset_resume(struct platform_device *dev)
+/* Yes, we really do not have any kind of masking or unmasking */
+static void nochip_noop(struct irq_data *irq)
 {
-       NCR_0 = neponset_saved_state;
-
-       return 0;
 }
 
-#else
-#define neponset_suspend NULL
-#define neponset_resume  NULL
-#endif
-
-static struct platform_driver neponset_device_driver = {
-       .probe          = neponset_probe,
-       .suspend        = neponset_suspend,
-       .resume         = neponset_resume,
-       .driver         = {
-               .name   = "neponset",
-       },
-};
-
-static struct resource neponset_resources[] = {
-       [0] = {
-               .start  = 0x10000000,
-               .end    = 0x17ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device neponset_device = {
-       .name           = "neponset",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(neponset_resources),
-       .resource       = neponset_resources,
-};
-
-static struct resource sa1111_resources[] = {
-       [0] = {
-               .start  = 0x40000000,
-               .end    = 0x40001fff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_NEPONSET_SA1111,
-               .end    = IRQ_NEPONSET_SA1111,
-               .flags  = IORESOURCE_IRQ,
-       },
+static struct irq_chip nochip = {
+       .name = "neponset",
+       .irq_ack = nochip_noop,
+       .irq_mask = nochip_noop,
+       .irq_unmask = nochip_noop,
 };
 
 static struct sa1111_platform_data sa1111_info = {
-       .irq_base       = IRQ_BOARD_END,
+       .disable_devs   = SA1111_DEVID_PS2_MSE,
 };
 
-static u64 sa1111_dmamask = 0xffffffffUL;
+static int __devinit neponset_probe(struct platform_device *dev)
+{
+       struct neponset_drvdata *d;
+       struct resource *nep_res, *sa1111_res, *smc91x_res;
+       struct resource sa1111_resources[] = {
+               DEFINE_RES_MEM(0x40000000, SZ_8K),
+               { .flags = IORESOURCE_IRQ },
+       };
+       struct platform_device_info sa1111_devinfo = {
+               .parent = &dev->dev,
+               .name = "sa1111",
+               .id = 0,
+               .res = sa1111_resources,
+               .num_res = ARRAY_SIZE(sa1111_resources),
+               .data = &sa1111_info,
+               .size_data = sizeof(sa1111_info),
+               .dma_mask = 0xffffffffUL,
+       };
+       struct resource smc91x_resources[] = {
+               DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS,
+                       0x02000000, "smc91x-regs"),
+               DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
+                       0x02000000, "smc91x-attrib"),
+               { .flags = IORESOURCE_IRQ },
+       };
+       struct platform_device_info smc91x_devinfo = {
+               .parent = &dev->dev,
+               .name = "smc91x",
+               .id = 0,
+               .res = smc91x_resources,
+               .num_res = ARRAY_SIZE(smc91x_resources),
+       };
+       int ret, irq;
+
+       if (nep_base)
+               return -EBUSY;
+
+       irq = ret = platform_get_irq(dev, 0);
+       if (ret < 0)
+               goto err_alloc;
+
+       nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+       sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2);
+       if (!nep_res || !smc91x_res || !sa1111_res) {
+               ret = -ENXIO;
+               goto err_alloc;
+       }
 
-static struct platform_device sa1111_device = {
-       .name           = "sa1111",
-       .id             = 0,
-       .dev            = {
-               .dma_mask = &sa1111_dmamask,
-               .coherent_dma_mask = 0xffffffff,
-               .platform_data = &sa1111_info,
-       },
-       .num_resources  = ARRAY_SIZE(sa1111_resources),
-       .resource       = sa1111_resources,
-};
+       d = kzalloc(sizeof(*d), GFP_KERNEL);
+       if (!d) {
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
 
-static struct resource smc91x_resources[] = {
-       [0] = {
-               .name   = "smc91x-regs",
-               .start  = SA1100_CS3_PHYS,
-               .end    = SA1100_CS3_PHYS + 0x01ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_NEPONSET_SMC9196,
-               .end    = IRQ_NEPONSET_SMC9196,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .name   = "smc91x-attrib",
-               .start  = SA1100_CS3_PHYS + 0x02000000,
-               .end    = SA1100_CS3_PHYS + 0x03ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
+       d->base = ioremap(nep_res->start, SZ_4K);
+       if (!d->base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
 
-static struct platform_device smc91x_device = {
-       .name           = "smc91x",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(smc91x_resources),
-       .resource       = smc91x_resources,
-};
+       if (readb_relaxed(d->base + WHOAMI) != 0x11) {
+               dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n",
+                        readb_relaxed(d->base + WHOAMI));
+               ret = -ENODEV;
+               goto err_id;
+       }
 
-static struct platform_device *devices[] __initdata = {
-       &neponset_device,
-       &sa1111_device,
-       &smc91x_device,
-};
+       ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1);
+       if (ret <= 0) {
+               dev_err(&dev->dev, "unable to allocate %u irqs: %d\n",
+                       NEP_IRQ_NR, ret);
+               if (ret == 0)
+                       ret = -ENOMEM;
+               goto err_irq_alloc;
+       }
 
-extern void sa1110_mb_disable(void);
+       d->irq_base = ret;
 
-static int __init neponset_init(void)
-{
-       platform_driver_register(&neponset_device_driver);
+       irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip,
+               handle_simple_irq);
+       set_irq_flags(d->irq_base + NEP_IRQ_SMC91X, IRQF_VALID | IRQF_PROBE);
+       irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip,
+               handle_simple_irq);
+       set_irq_flags(d->irq_base + NEP_IRQ_USAR, IRQF_VALID | IRQF_PROBE);
+       irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip);
 
-       /*
-        * The Neponset is only present on the Assabet machine type.
-        */
-       if (!machine_is_assabet())
-               return -ENODEV;
+       irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+       irq_set_handler_data(irq, d);
+       irq_set_chained_handler(irq, neponset_irq_handler);
 
        /*
-        * Ensure that the memory bus request/grant signals are setup,
-        * and the grant is held in its inactive state, whether or not
-        * we actually have a Neponset attached.
+        * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
+        * something on the Neponset activates this IRQ on sleep (eth?)
         */
+#if 0
+       enable_irq_wake(irq);
+#endif
+
+       dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n",
+                d->irq_base, d->irq_base + NEP_IRQ_NR - 1);
+       nep_base = d->base;
+
+       sa1100_register_uart_fns(&neponset_port_fns);
+
+       /* Ensure that the memory bus request/grant signals are setup */
        sa1110_mb_disable();
 
-       if (!machine_has_neponset()) {
-               printk(KERN_DEBUG "Neponset expansion board not present\n");
-               return -ENODEV;
-       }
+       /* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
+       writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0);
 
-       if (WHOAMI != 0x11) {
-               printk(KERN_WARNING "Neponset board detected, but "
-                       "wrong ID: %02x\n", WHOAMI);
-               return -ENODEV;
-       }
+       sa1111_resources[0].parent = sa1111_res;
+       sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111;
+       sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111;
+       d->sa1111 = platform_device_register_full(&sa1111_devinfo);
+
+       smc91x_resources[0].parent = smc91x_res;
+       smc91x_resources[1].parent = smc91x_res;
+       smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X;
+       smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X;
+       d->smc91x = platform_device_register_full(&smc91x_devinfo);
+
+       platform_set_drvdata(dev, d);
 
-       return platform_add_devices(devices, ARRAY_SIZE(devices));
+       return 0;
+
+ err_irq_alloc:
+ err_id:
+       iounmap(d->base);
+ err_ioremap:
+       kfree(d);
+ err_alloc:
+       return ret;
 }
 
-subsys_initcall(neponset_init);
+static int __devexit neponset_remove(struct platform_device *dev)
+{
+       struct neponset_drvdata *d = platform_get_drvdata(dev);
+       int irq = platform_get_irq(dev, 0);
+
+       if (!IS_ERR(d->sa1111))
+               platform_device_unregister(d->sa1111);
+       if (!IS_ERR(d->smc91x))
+               platform_device_unregister(d->smc91x);
+       irq_set_chained_handler(irq, NULL);
+       irq_free_descs(d->irq_base, NEP_IRQ_NR);
+       nep_base = NULL;
+       iounmap(d->base);
+       kfree(d);
 
-static struct map_desc neponset_io_desc[] __initdata = {
-       {       /* System Registers */
-               .virtual        =  0xf3000000,
-               .pfn            = __phys_to_pfn(0x10000000),
-               .length         = SZ_1M,
-               .type           = MT_DEVICE
-       }, {    /* SA-1111 */
-               .virtual        =  0xf4000000,
-               .pfn            = __phys_to_pfn(0x40000000),
-               .length         = SZ_1M,
-               .type           = MT_DEVICE
-       }
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int neponset_suspend(struct device *dev)
+{
+       struct neponset_drvdata *d = dev_get_drvdata(dev);
+
+       d->ncr0 = readb_relaxed(d->base + NCR_0);
+       d->mdm_ctl_0 = readb_relaxed(d->base + MDM_CTL_0);
+
+       return 0;
+}
+
+static int neponset_resume(struct device *dev)
+{
+       struct neponset_drvdata *d = dev_get_drvdata(dev);
+
+       writeb_relaxed(d->ncr0, d->base + NCR_0);
+       writeb_relaxed(d->mdm_ctl_0, d->base + MDM_CTL_0);
+
+       return 0;
+}
+
+static const struct dev_pm_ops neponset_pm_ops = {
+       .suspend_noirq = neponset_suspend,
+       .resume_noirq = neponset_resume,
+       .freeze_noirq = neponset_suspend,
+       .restore_noirq = neponset_resume,
+};
+#define PM_OPS &neponset_pm_ops
+#else
+#define PM_OPS NULL
+#endif
+
+static struct platform_driver neponset_device_driver = {
+       .probe          = neponset_probe,
+       .remove         = __devexit_p(neponset_remove),
+       .driver         = {
+               .name   = "neponset",
+               .owner  = THIS_MODULE,
+               .pm     = PM_OPS,
+       },
 };
 
-void __init neponset_map_io(void)
+static int __init neponset_init(void)
 {
-       iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc));
+       return platform_driver_register(&neponset_device_driver);
 }
+
+subsys_initcall(neponset_init);
index 0d01ca7..b49108b 100644 (file)
@@ -135,12 +135,8 @@ struct pci_bus * __init pci_nanoengine_scan_bus(int nr, struct pci_sys_data *sys
                                 &sys->resources);
 }
 
-static struct resource pci_io_ports = {
-       .name   = "PCI IO",
-       .start  = 0x400,
-       .end    = 0x7FF,
-       .flags  = IORESOURCE_IO,
-};
+static struct resource pci_io_ports =
+       DEFINE_RES_IO_NAMED(0x400, 0x400, "PCI IO");
 
 static struct resource pci_non_prefetchable_memory = {
        .name   = "PCI non-prefetchable",
@@ -244,9 +240,11 @@ static int __init pci_nanoengine_setup_resources(struct pci_sys_data *sys)
                printk(KERN_ERR "PCI: unable to allocate prefetchable\n");
                return -EBUSY;
        }
-       pci_add_resource(&sys->resources, &pci_io_ports);
-       pci_add_resource(&sys->resources, &pci_non_prefetchable_memory);
-       pci_add_resource(&sys->resources, &pci_prefetchable_memory);
+       pci_add_resource_offset(&sys->resources, &pci_io_ports, sys->io_offset);
+       pci_add_resource_offset(&sys->resources,
+                               &pci_non_prefetchable_memory, sys->mem_offset);
+       pci_add_resource_offset(&sys->resources,
+                               &pci_prefetchable_memory, sys->mem_offset);
 
        return 1;
 }
index 9307df0..1602575 100644 (file)
 #define IRQ_GPIO_ETH0_IRQ      IRQ_GPIO21
 
 static struct resource smc91x_resources[] = {
-       [0] = {
-               .start  = PLEB_ETH0_P,
-               .end    = PLEB_ETH0_P | 0x03ffffff,
-               .flags  = IORESOURCE_MEM,
-       },
+       [0] = DEFINE_RES_MEM(PLEB_ETH0_P, 0x04000000),
 #if 0 /* Autoprobe instead, to get rising/falling edge characteristic right */
-       [1] = {
-               .start  = IRQ_GPIO_ETH0_IRQ,
-               .end    = IRQ_GPIO_ETH0_IRQ,
-               .flags  = IORESOURCE_IRQ,
-       },
+       [1] = DEFINE_RES_IRQ(IRQ_GPIO_ETH0_IRQ),
 #endif
 };
 
@@ -70,16 +62,8 @@ static struct platform_device *devices[] __initdata = {
  * the two SA1100 lowest chip select outputs.
  */
 static struct resource pleb_flash_resources[] = {
-       [0] = {
-               .start = SA1100_CS0_PHYS,
-               .end   = SA1100_CS0_PHYS + SZ_8M - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = SA1100_CS1_PHYS,
-               .end   = SA1100_CS1_PHYS + SZ_8M - 1,
-               .flags = IORESOURCE_MEM,
-       }
+       [0] = DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_8M),
+       [1] = DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_8M),
 };
 
 
@@ -147,6 +131,7 @@ static void __init pleb_map_io(void)
 
 MACHINE_START(PLEB, "PLEB")
        .map_io         = pleb_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = pleb_init,
index 318b2b7..ca8bf59 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
@@ -19,6 +21,7 @@
 #include <asm/mach/serial_sa1100.h>
 #include <mach/mcp.h>
 #include <mach/shannon.h>
+#include <mach/irqs.h>
 
 #include "generic.h"
 
@@ -46,19 +49,32 @@ static struct flash_platform_data shannon_flash_data = {
        .nr_parts       = ARRAY_SIZE(shannon_partitions),
 };
 
-static struct resource shannon_flash_resource = {
-       .start          = SA1100_CS0_PHYS,
-       .end            = SA1100_CS0_PHYS + SZ_4M - 1,
-       .flags          = IORESOURCE_MEM,
-};
+static struct resource shannon_flash_resource =
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_4M);
 
 static struct mcp_plat_data shannon_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
 };
 
+static struct sa1100fb_mach_info shannon_lcd_info = {
+       .pixclock       = 152500,       .bpp            = 8,
+       .xres           = 640,          .yres           = 480,
+
+       .hsync_len      = 4,            .vsync_len      = 3,
+       .left_margin    = 2,            .upper_margin   = 0,
+       .right_margin   = 1,            .lower_margin   = 0,
+
+       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+       .lccr0          = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+       .lccr3          = LCCR3_ACBsDiv(512),
+};
+
 static void __init shannon_init(void)
 {
+       sa11x0_ppc_configure_mcp();
+       sa11x0_register_lcd(&shannon_lcd_info);
        sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
        sa11x0_register_mcp(&shannon_mcp_data);
 }
@@ -84,6 +100,7 @@ static void __init shannon_map_io(void)
 MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
        .atag_offset    = 0x100,
        .map_io         = shannon_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .init_machine   = shannon_init,
index e17c04d..3efae03 100644 (file)
@@ -7,15 +7,15 @@
 #include <linux/kernel.h>
 #include <linux/tty.h>
 #include <linux/proc_fs.h>
-#include <linux/string.h> 
+#include <linux/string.h>
 #include <linux/pm.h>
 #include <linux/platform_device.h>
+#include <linux/mfd/ucb1x00.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/setup.h>
 
@@ -26,6 +26,7 @@
 #include <asm/mach/serial_sa1100.h>
 #include <mach/mcp.h>
 #include <mach/simpad.h>
+#include <mach/irqs.h>
 
 #include <linux/serial_core.h>
 #include <linux/ioport.h>
@@ -176,21 +177,18 @@ static struct flash_platform_data simpad_flash_data = {
 
 
 static struct resource simpad_flash_resources [] = {
-       {
-               .start     = SA1100_CS0_PHYS,
-               .end       = SA1100_CS0_PHYS + SZ_16M -1,
-               .flags     = IORESOURCE_MEM,
-       }, {
-               .start     = SA1100_CS1_PHYS,
-               .end       = SA1100_CS1_PHYS + SZ_16M -1,
-               .flags     = IORESOURCE_MEM,
-       }
+       DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_16M),
+       DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_16M),
+};
+
+static struct ucb1x00_plat_data simpad_ucb1x00_data = {
+       .gpio_base      = SIMPAD_UCB1X00_GPIO_BASE,
 };
 
 static struct mcp_plat_data simpad_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
-       .gpio_base      = SIMPAD_UCB1X00_GPIO_BASE,
+       .codec_pdata    = &simpad_ucb1x00_data,
 };
 
 
@@ -376,6 +374,7 @@ static int __init simpad_init(void)
 
        pm_power_off = simpad_power_off;
 
+       sa11x0_ppc_configure_mcp();
        sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
                              ARRAY_SIZE(simpad_flash_resources));
        sa11x0_register_mcp(&simpad_mcp_data);
@@ -394,6 +393,7 @@ MACHINE_START(SIMPAD, "Simpad")
        /* Maintainer: Holger Freyther */
        .atag_offset    = 0x100,
        .map_io         = simpad_map_io,
+       .nr_irqs        = SA1100_NR_IRQS,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
        .restart        = sa11x0_restart,
index e822331..30cc672 100644 (file)
  *
  * Causes sa11x0 to enter sleep state
  *
+ * Must be aligned to a cacheline.
  */
-
+       .balign 32
 ENTRY(sa1100_finish_suspend)
        @ disable clock switching
        mcr     p15, 0, r1, c15, c2, 2
 
-        @ Adjust memory timing before lowering CPU clock
-       @ Clock speed adjustment without changing memory timing makes
-       @ CPU hang in some cases
-        ldr     r0, =MDREFR
-        ldr     r1, [r0]
-        orr     r1, r1, #MDREFR_K1DB2
-        str     r1, [r0]
+       ldr     r6, =MDREFR
+       ldr     r4, [r6]
+       orr     r4, r4, #MDREFR_K1DB2
+       ldr     r5, =PPCR
+
+       @ Pre-load __udelay into the I-cache
+       mov     r0, #1
+       bl      __udelay
+       mov     r0, r0
+
+       @ The following must all exist in a single cache line to
+       @ avoid accessing memory until this sequence is complete,
+       @ otherwise we occasionally hang.
+
+       @ Adjust memory timing before lowering CPU clock
+       str     r4, [r6]
 
        @ delay 90us and set CPU PLL to lowest speed
        @ fixes resume problem on high speed SA1110
        mov     r0, #90
        bl      __udelay
-       ldr     r0, =PPCR
        mov     r1, #0
-       str     r1, [r0]
+       str     r1, [r5]
        mov     r0, #90
        bl      __udelay
 
@@ -85,12 +94,10 @@ ENTRY(sa1100_finish_suspend)
        bic     r5, r5, #FMsk(MSC_RT)
        bic     r5, r5, #FMsk(MSC_RT)<<16
 
-       ldr     r6, =MDREFR
-
        ldr     r7, [r6]
-bic    r7, r7, #0x0000FF00
-bic    r7, r7, #0x000000F0
-orr    r8, r7, #MDREFR_SLFRSH
+       bic     r7, r7, #0x0000FF00
+       bic     r7, r7, #0x000000F0
+       orr     r8, r7, #MDREFR_SLFRSH
 
        ldr     r9, =MDCNFG
        ldr     r10, [r9]
index b20ff93..e22fca9 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/init.h>
 #include <linux/io.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <asm/hardware/ssp.h>
 
 #define TIMEOUT 100000
index 69e3353..6af26e8 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/mach/time.h>
 #include <asm/sched_clock.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 static u32 notrace sa1100_read_sched_clock(void)
 {
index a851c25..6a2a7f2 100644 (file)
@@ -149,10 +149,16 @@ static struct sys_timer shark_timer = {
        .init           = shark_timer_init,
 };
 
+static void shark_init_early(void)
+{
+       disable_hlt();
+}
+
 MACHINE_START(SHARK, "Shark")
        /* Maintainer: Alexander Schulz */
        .atag_offset    = 0x3000,
        .map_io         = shark_map_io,
+       .init_early     = shark_init_early,
        .init_irq       = shark_init_irq,
        .timer          = &shark_timer,
        .dma_zone_size  = SZ_4M,
index 0bb6cc6..5901b09 100644 (file)
@@ -7,16 +7,10 @@
  * License version 2. This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  */
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                mov     \base, #0xe0000000
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 
                mov     \irqstat, #0x0C
diff --git a/arch/arm/mach-shark/include/mach/system.h b/arch/arm/mach-shark/include/mach/system.h
deleted file mode 100644 (file)
index 1b2f2c5..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-shark/include/mach/system.h
- *
- * by Alexander Schulz
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-}
-
-#endif
index 7ad6954..e7c2590 100644 (file)
@@ -16,7 +16,6 @@ obj-$(CONFIG_ARCH_R8A7779)    += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o
 # SMP objects
 smp-y                          := platsmp.o headsmp.o
 smp-$(CONFIG_HOTPLUG_CPU)      += hotplug.o
-smp-$(CONFIG_LOCAL_TIMERS)     += localtimer.o
 smp-$(CONFIG_ARCH_SH73A0)      += smp-sh73a0.o
 smp-$(CONFIG_ARCH_R8A7779)     += smp-r8a7779.o
 
index 12c431f..f50d7c8 100644 (file)
@@ -47,8 +47,6 @@
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/traps.h>
@@ -477,27 +475,6 @@ static struct platform_device *ag5evm_devices[] __initdata = {
        &sdhi1_device,
 };
 
-static struct map_desc ag5evm_io_desc[] __initdata = {
-       /* create a 1:1 entity map for 0xe6xxxxxx
-        * used by CPGA, INTC and PFC.
-        */
-       {
-               .virtual        = 0xe6000000,
-               .pfn            = __phys_to_pfn(0xe6000000),
-               .length         = 256 << 20,
-               .type           = MT_DEVICE_NONSHARED
-       },
-};
-
-static void __init ag5evm_map_io(void)
-{
-       iotable_init(ag5evm_io_desc, ARRAY_SIZE(ag5evm_io_desc));
-
-       /* setup early devices and console here as well */
-       sh73a0_add_early_devices();
-       shmobile_setup_console();
-}
-
 static void __init ag5evm_init(void)
 {
        sh73a0_pinmux_init();
@@ -613,22 +590,12 @@ static void __init ag5evm_init(void)
        platform_add_devices(ag5evm_devices, ARRAY_SIZE(ag5evm_devices));
 }
 
-static void __init ag5evm_timer_init(void)
-{
-       sh73a0_clock_init();
-       shmobile_timer.init();
-       return;
-}
-
-struct sys_timer ag5evm_timer = {
-       .init   = ag5evm_timer_init,
-};
-
 MACHINE_START(AG5EVM, "ag5evm")
-       .map_io         = ag5evm_map_io,
+       .map_io         = sh73a0_map_io,
+       .init_early     = sh73a0_add_early_devices,
        .nr_irqs        = NR_IRQS_LEGACY,
        .init_irq       = sh73a0_init_irq,
        .handle_irq     = gic_handle_irq,
        .init_machine   = ag5evm_init,
-       .timer          = &ag5evm_timer,
+       .timer          = &shmobile_timer,
 MACHINE_END
index f90ba5b..b56dde2 100644 (file)
@@ -61,8 +61,6 @@
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
 #include <asm/setup.h>
 
 /*
@@ -1188,26 +1186,6 @@ static struct i2c_board_info i2c1_devices[] = {
        },
 };
 
-static struct map_desc ap4evb_io_desc[] __initdata = {
-       /* create a 1:1 entity map for 0xe6xxxxxx
-        * used by CPGA, INTC and PFC.
-        */
-       {
-               .virtual        = 0xe6000000,
-               .pfn            = __phys_to_pfn(0xe6000000),
-               .length         = 256 << 20,
-               .type           = MT_DEVICE_NONSHARED
-       },
-};
-
-static void __init ap4evb_map_io(void)
-{
-       iotable_init(ap4evb_io_desc, ARRAY_SIZE(ap4evb_io_desc));
-
-       /* setup early devices and console here as well */
-       sh7372_add_early_devices();
-       shmobile_setup_console();
-}
 
 #define GPIO_PORT9CR   0xE6051009
 #define GPIO_PORT10CR  0xE605100A
@@ -1217,6 +1195,9 @@ static void __init ap4evb_init(void)
        u32 srcr4;
        struct clk *clk;
 
+       /* External clock source */
+       clk_set_rate(&sh7372_dv_clki_clk, 27000000);
+
        sh7372_pinmux_init();
 
        /* enable SCIFA0 */
@@ -1453,23 +1434,11 @@ static void __init ap4evb_init(void)
        pm_clk_add(&lcdc1_device.dev, "hdmi");
 }
 
-static void __init ap4evb_timer_init(void)
-{
-       sh7372_clock_init();
-       shmobile_timer.init();
-
-       /* External clock source */
-       clk_set_rate(&sh7372_dv_clki_clk, 27000000);
-}
-
-static struct sys_timer ap4evb_timer = {
-       .init           = ap4evb_timer_init,
-};
-
 MACHINE_START(AP4EVB, "ap4evb")
-       .map_io         = ap4evb_map_io,
+       .map_io         = sh7372_map_io,
+       .init_early     = sh7372_add_early_devices,
        .init_irq       = sh7372_init_irq,
        .handle_irq     = shmobile_handle_irq_intc,
        .init_machine   = ap4evb_init,
-       .timer          = &ap4evb_timer,
+       .timer          = &shmobile_timer,
 MACHINE_END
index c79baa9..8b2124d 100644 (file)
@@ -328,28 +328,6 @@ static struct platform_device *bonito_base_devices[] __initdata = {
  * map I/O
  */
 static struct map_desc bonito_io_desc[] __initdata = {
-        /*
-         * for CPGA/INTC/PFC
-         * 0xe6000000-0xefffffff -> 0xe6000000-0xefffffff
-         */
-       {
-               .virtual        = 0xe6000000,
-               .pfn            = __phys_to_pfn(0xe6000000),
-               .length         = 160 << 20,
-               .type           = MT_DEVICE_NONSHARED
-       },
-#ifdef CONFIG_CACHE_L2X0
-       /*
-        * for l2x0_init()
-        * 0xf0100000-0xf0101000 -> 0xf0002000-0xf0003000
-        */
-       {
-               .virtual        = 0xf0002000,
-               .pfn            = __phys_to_pfn(0xf0100000),
-               .length         = PAGE_SIZE,
-               .type           = MT_DEVICE_NONSHARED
-       },
-#endif
        /*
         * for FPGA (0x1800000-0x19ffffff)
         * 0x18000000-0x18002000 -> 0xf0003000-0xf0005000
@@ -364,11 +342,8 @@ static struct map_desc bonito_io_desc[] __initdata = {
 
 static void __init bonito_map_io(void)
 {
+       r8a7740_map_io();
        iotable_init(bonito_io_desc, ARRAY_SIZE(bonito_io_desc));
-
-       /* setup early devices and console here as well */
-       r8a7740_add_early_devices();
-       shmobile_setup_console();
 }
 
 /*
@@ -492,7 +467,7 @@ static void __init bonito_init(void)
        }
 }
 
-static void __init bonito_timer_init(void)
+static void __init bonito_earlytimer_init(void)
 {
        u16 val;
        u8 md_ck = 0;
@@ -507,17 +482,22 @@ static void __init bonito_timer_init(void)
                md_ck |= MD_CK0;
 
        r8a7740_clock_init(md_ck);
-       shmobile_timer.init();
+       shmobile_earlytimer_init();
 }
 
-struct sys_timer bonito_timer = {
-       .init   = bonito_timer_init,
-};
+void __init bonito_add_early_devices(void)
+{
+       r8a7740_add_early_devices();
+
+       /* override timer setup with board-specific code */
+       shmobile_timer.init = bonito_earlytimer_init;
+}
 
 MACHINE_START(BONITO, "bonito")
        .map_io         = bonito_map_io,
+       .init_early     = bonito_add_early_devices,
        .init_irq       = r8a7740_init_irq,
        .handle_irq     = shmobile_handle_irq_intc,
        .init_machine   = bonito_init,
-       .timer          = &bonito_timer,
+       .timer          = &shmobile_timer,
 MACHINE_END
index 72d5572..b627e89 100644 (file)
@@ -37,8 +37,6 @@
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
 
 /*
  * IrDA
@@ -246,27 +244,6 @@ static struct platform_device *g3evm_devices[] __initdata = {
        &irda_device,
 };
 
-static struct map_desc g3evm_io_desc[] __initdata = {
-       /* create a 1:1 entity map for 0xe6xxxxxx
-        * used by CPGA, INTC and PFC.
-        */
-       {
-               .virtual        = 0xe6000000,
-               .pfn            = __phys_to_pfn(0xe6000000),
-               .length         = 256 << 20,
-               .type           = MT_DEVICE_NONSHARED
-       },
-};
-
-static void __init g3evm_map_io(void)
-{
-       iotable_init(g3evm_io_desc, ARRAY_SIZE(g3evm_io_desc));
-
-       /* setup early devices and console here as well */
-       sh7367_add_early_devices();
-       shmobile_setup_console();
-}
-
 static void __init g3evm_init(void)
 {
        sh7367_pinmux_init();
@@ -354,20 +331,11 @@ static void __init g3evm_init(void)
        platform_add_devices(g3evm_devices, ARRAY_SIZE(g3evm_devices));
 }
 
-static void __init g3evm_timer_init(void)
-{
-       sh7367_clock_init();
-       shmobile_timer.init();
-}
-
-static struct sys_timer g3evm_timer = {
-       .init           = g3evm_timer_init,
-};
-
 MACHINE_START(G3EVM, "g3evm")
-       .map_io         = g3evm_map_io,
+       .map_io         = sh7367_map_io,
+       .init_early     = sh7367_add_early_devices,
        .init_irq       = sh7367_init_irq,
        .handle_irq     = shmobile_handle_irq_intc,
        .init_machine   = g3evm_init,
-       .timer          = &g3evm_timer,
+       .timer          = &shmobile_timer,
 MACHINE_END
index 2220b88..46d757d 100644 (file)
@@ -38,8 +38,6 @@
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
 
 /*
  * SDHI
@@ -260,27 +258,6 @@ static struct platform_device *g4evm_devices[] __initdata = {
        &sdhi1_device,
 };
 
-static struct map_desc g4evm_io_desc[] __initdata = {
-       /* create a 1:1 entity map for 0xe6xxxxxx
-        * used by CPGA, INTC and PFC.
-        */
-       {
-               .virtual        = 0xe6000000,
-               .pfn            = __phys_to_pfn(0xe6000000),
-               .length         = 256 << 20,
-               .type           = MT_DEVICE_NONSHARED
-       },
-};
-
-static void __init g4evm_map_io(void)
-{
-       iotable_init(g4evm_io_desc, ARRAY_SIZE(g4evm_io_desc));
-
-       /* setup early devices and console here as well */
-       sh7377_add_early_devices();
-       shmobile_setup_console();
-}
-
 #define GPIO_SDHID0_D0 0xe60520fc
 #define GPIO_SDHID0_D1 0xe60520fd
 #define GPIO_SDHID0_D2 0xe60520fe
@@ -397,20 +374,11 @@ static void __init g4evm_init(void)
        platform_add_devices(g4evm_devices, ARRAY_SIZE(g4evm_devices));
 }
 
-static void __init g4evm_timer_init(void)
-{
-       sh7377_clock_init();
-       shmobile_timer.init();
-}
-
-static struct sys_timer g4evm_timer = {
-       .init           = g4evm_timer_init,
-};
-
 MACHINE_START(G4EVM, "g4evm")
-       .map_io         = g4evm_map_io,
+       .map_io         = sh7377_map_io,
+       .init_early     = sh7377_add_early_devices,
        .init_irq       = sh7377_init_irq,
        .handle_irq     = shmobile_handle_irq_intc,
        .init_machine   = g4evm_init,
-       .timer          = &g4evm_timer,
+       .timer          = &shmobile_timer,
 MACHINE_END
index c8e7ca2..61c0672 100644 (file)
@@ -43,7 +43,6 @@
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -409,27 +408,6 @@ static struct platform_device *kota2_devices[] __initdata = {
        &sdhi1_device,
 };
 
-static struct map_desc kota2_io_desc[] __initdata = {
-       /* create a 1:1 entity map for 0xe6xxxxxx
-        * used by CPGA, INTC and PFC.
-        */
-       {
-               .virtual        = 0xe6000000,
-               .pfn            = __phys_to_pfn(0xe6000000),
-               .length         = 256 << 20,
-               .type           = MT_DEVICE_NONSHARED
-       },
-};
-
-static void __init kota2_map_io(void)
-{
-       iotable_init(kota2_io_desc, ARRAY_SIZE(kota2_io_desc));
-
-       /* setup early devices and console here as well */
-       sh73a0_add_early_devices();
-       shmobile_setup_console();
-}
-
 static void __init kota2_init(void)
 {
        sh73a0_pinmux_init();
@@ -535,22 +513,12 @@ static void __init kota2_init(void)
        platform_add_devices(kota2_devices, ARRAY_SIZE(kota2_devices));
 }
 
-static void __init kota2_timer_init(void)
-{
-       sh73a0_clock_init();
-       shmobile_timer.init();
-       return;
-}
-
-struct sys_timer kota2_timer = {
-       .init   = kota2_timer_init,
-};
-
 MACHINE_START(KOTA2, "kota2")
-       .map_io         = kota2_map_io,
+       .map_io         = sh73a0_map_io,
+       .init_early     = sh73a0_add_early_devices,
        .nr_irqs        = NR_IRQS_LEGACY,
        .init_irq       = sh73a0_init_irq,
        .handle_irq     = gic_handle_irq,
        .init_machine   = kota2_init,
-       .timer          = &kota2_timer,
+       .timer          = &shmobile_timer,
 MACHINE_END
index 865d56d..ca60950 100644 (file)
@@ -57,8 +57,6 @@
 #include <mach/sh7372.h>
 
 #include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-#include <asm/mach/map.h>
 #include <asm/mach-types.h>
 
 /*
@@ -1329,31 +1327,6 @@ static struct i2c_board_info i2c1_devices[] = {
        },
 };
 
-static struct map_desc mackerel_io_desc[] __initdata = {
-       /* create a 1:1 entity map for 0xe6xxxxxx
-        * used by CPGA, INTC and PFC.
-        */
-       {
-               .virtual        = 0xe6000000,
-               .pfn            = __phys_to_pfn(0xe6000000),
-               .length         = 256 << 20,
-               .type           = MT_DEVICE_NONSHARED
-       },
-};
-
-static void __init mackerel_map_io(void)
-{
-       iotable_init(mackerel_io_desc, ARRAY_SIZE(mackerel_io_desc));
-       /* DMA memory at 0xff200000 - 0xffdfffff. The default 2MB size isn't
-        * enough to allocate the frame buffer memory.
-        */
-       init_consistent_dma_size(12 << 20);
-
-       /* setup early devices and console here as well */
-       sh7372_add_early_devices();
-       shmobile_setup_console();
-}
-
 #define GPIO_PORT9CR   0xE6051009
 #define GPIO_PORT10CR  0xE605100A
 #define GPIO_PORT167CR 0xE60520A7
@@ -1366,6 +1339,9 @@ static void __init mackerel_init(void)
        struct clk *clk;
        int ret;
 
+       /* External clock source */
+       clk_set_rate(&sh7372_dv_clki_clk, 27000000);
+
        sh7372_pinmux_init();
 
        /* enable SCIFA0 */
@@ -1569,23 +1545,11 @@ static void __init mackerel_init(void)
        pm_clk_add(&hdmi_lcdc_device.dev, "hdmi");
 }
 
-static void __init mackerel_timer_init(void)
-{
-       sh7372_clock_init();
-       shmobile_timer.init();
-
-       /* External clock source */
-       clk_set_rate(&sh7372_dv_clki_clk, 27000000);
-}
-
-static struct sys_timer mackerel_timer = {
-       .init           = mackerel_timer_init,
-};
-
 MACHINE_START(MACKEREL, "mackerel")
-       .map_io         = mackerel_map_io,
+       .map_io         = sh7372_map_io,
+       .init_early     = sh7372_add_early_devices,
        .init_irq       = sh7372_init_irq,
        .handle_irq     = shmobile_handle_irq_intc,
        .init_machine   = mackerel_init,
-       .timer          = &mackerel_timer,
+       .timer          = &shmobile_timer,
 MACHINE_END
index f0e02c0..cbd5e4c 100644 (file)
@@ -33,8 +33,6 @@
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
 #include <asm/hardware/gic.h>
 #include <asm/traps.h>
 
@@ -72,49 +70,6 @@ static struct platform_device *marzen_devices[] __initdata = {
        &eth_device,
 };
 
-static struct map_desc marzen_io_desc[] __initdata = {
-       /* 2M entity map for 0xf0000000 (MPCORE) */
-       {
-               .virtual        = 0xf0000000,
-               .pfn            = __phys_to_pfn(0xf0000000),
-               .length         = SZ_2M,
-               .type           = MT_DEVICE_NONSHARED
-       },
-       /* 16M entity map for 0xfexxxxxx (DMAC-S/HPBREG/INTC2/LRAM/DBSC) */
-       {
-               .virtual        = 0xfe000000,
-               .pfn            = __phys_to_pfn(0xfe000000),
-               .length         = SZ_16M,
-               .type           = MT_DEVICE_NONSHARED
-       },
-};
-
-static void __init marzen_map_io(void)
-{
-       iotable_init(marzen_io_desc, ARRAY_SIZE(marzen_io_desc));
-}
-
-static void __init marzen_init_early(void)
-{
-       r8a7779_add_early_devices();
-
-       /* Early serial console setup is not included here due to
-        * memory map collisions. The SCIF serial ports in r8a7779
-        * are difficult to entity map 1:1 due to collision with the
-        * virtual memory range used by the coherent DMA code on ARM.
-        *
-        * Anyone wanting to debug early can remove UPF_IOREMAP from
-        * the sh-sci serial console platform data, adjust mapbase
-        * to a static M:N virt:phys mapping that needs to be added to
-        * the mappings passed with iotable_init() above.
-        *
-        * Then add a call to shmobile_setup_console() from this function.
-        *
-        * As a final step pass earlyprint=sh-sci.2,115200 on the kernel
-        * command line.
-        */
-}
-
 static void __init marzen_init(void)
 {
        r8a7779_pinmux_init();
@@ -135,23 +90,12 @@ static void __init marzen_init(void)
        platform_add_devices(marzen_devices, ARRAY_SIZE(marzen_devices));
 }
 
-static void __init marzen_timer_init(void)
-{
-       r8a7779_clock_init();
-       shmobile_timer.init();
-       return;
-}
-
-struct sys_timer marzen_timer = {
-       .init   = marzen_timer_init,
-};
-
 MACHINE_START(MARZEN, "marzen")
-       .map_io         = marzen_map_io,
-       .init_early     = marzen_init_early,
+       .map_io         = r8a7779_map_io,
+       .init_early     = r8a7779_add_early_devices,
        .nr_irqs        = NR_IRQS_LEGACY,
        .init_irq       = r8a7779_init_irq,
        .handle_irq     = gic_handle_irq,
        .init_machine   = marzen_init,
-       .timer          = &marzen_timer,
+       .timer          = &shmobile_timer,
 MACHINE_END
index 3b35b9a..99c4d74 100644 (file)
@@ -93,7 +93,7 @@ static unsigned long div_recalc(struct clk *clk)
        return clk->parent->rate / (int)(clk->priv);
 }
 
-static struct clk_ops div_clk_ops = {
+static struct sh_clk_ops div_clk_ops = {
        .recalc = div_recalc,
 };
 
@@ -125,7 +125,7 @@ static struct clk extal2_div2_clk = {
        .parent = &extal2_clk,
 };
 
-static struct clk_ops followparent_clk_ops = {
+static struct sh_clk_ops followparent_clk_ops = {
        .recalc = followparent_recalc,
 };
 
@@ -156,7 +156,7 @@ static unsigned long pllc01_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc01_clk_ops = {
+static struct sh_clk_ops pllc01_clk_ops = {
        .recalc         = pllc01_recalc,
 };
 
@@ -376,7 +376,7 @@ void __init r8a7740_clock_init(u8 md_ck)
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        if (!ret)
-               clk_init();
+               shmobile_clk_init();
        else
                panic("failed to setup r8a7740 clocks\n");
 }
index b4b0e8c..7d6e9fe 100644 (file)
@@ -107,7 +107,7 @@ static unsigned long mul4_recalc(struct clk *clk)
        return clk->parent->rate * 4;
 }
 
-static struct clk_ops mul4_clk_ops = {
+static struct sh_clk_ops mul4_clk_ops = {
        .recalc         = mul4_recalc,
 };
 
@@ -170,7 +170,7 @@ void __init r8a7779_clock_init(void)
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        if (!ret)
-               clk_init();
+               shmobile_clk_init();
        else
                panic("failed to setup r8a7779 clocks\n");
 }
index 5218c34..006e7b5 100644 (file)
@@ -74,7 +74,7 @@ static unsigned long div2_recalc(struct clk *clk)
        return clk->parent->rate / 2;
 }
 
-static struct clk_ops div2_clk_ops = {
+static struct sh_clk_ops div2_clk_ops = {
        .recalc         = div2_recalc,
 };
 
@@ -101,7 +101,7 @@ static unsigned long pllc1_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc1_clk_ops = {
+static struct sh_clk_ops pllc1_clk_ops = {
        .recalc         = pllc1_recalc,
 };
 
@@ -128,7 +128,7 @@ static unsigned long pllc2_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc2_clk_ops = {
+static struct sh_clk_ops pllc2_clk_ops = {
        .recalc         = pllc2_recalc,
 };
 
@@ -349,7 +349,7 @@ void __init sh7367_clock_init(void)
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        if (!ret)
-               clk_init();
+               shmobile_clk_init();
        else
                panic("failed to setup sh7367 clocks\n");
 }
index 293456d..de243e3 100644 (file)
@@ -89,7 +89,7 @@ static unsigned long div2_recalc(struct clk *clk)
        return clk->parent->rate / 2;
 }
 
-static struct clk_ops div2_clk_ops = {
+static struct sh_clk_ops div2_clk_ops = {
        .recalc         = div2_recalc,
 };
 
@@ -128,7 +128,7 @@ static unsigned long pllc01_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc01_clk_ops = {
+static struct sh_clk_ops pllc01_clk_ops = {
        .recalc         = pllc01_recalc,
 };
 
@@ -276,7 +276,7 @@ static int pllc2_set_parent(struct clk *clk, struct clk *parent)
        return 0;
 }
 
-static struct clk_ops pllc2_clk_ops = {
+static struct sh_clk_ops pllc2_clk_ops = {
        .recalc         = pllc2_recalc,
        .round_rate     = pllc2_round_rate,
        .set_rate       = pllc2_set_rate,
@@ -468,7 +468,7 @@ static int fsidiv_set_rate(struct clk *clk, unsigned long rate)
        return 0;
 }
 
-static struct clk_ops fsidiv_clk_ops = {
+static struct sh_clk_ops fsidiv_clk_ops = {
        .recalc         = fsidiv_recalc,
        .round_rate     = fsidiv_round_rate,
        .set_rate       = fsidiv_set_rate,
@@ -710,7 +710,7 @@ void __init sh7372_clock_init(void)
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        if (!ret)
-               clk_init();
+               shmobile_clk_init();
        else
                panic("failed to setup sh7372 clocks\n");
 
index 8cee7b1..0798a15 100644 (file)
@@ -77,7 +77,7 @@ static unsigned long div2_recalc(struct clk *clk)
        return clk->parent->rate / 2;
 }
 
-static struct clk_ops div2_clk_ops = {
+static struct sh_clk_ops div2_clk_ops = {
        .recalc         = div2_recalc,
 };
 
@@ -110,7 +110,7 @@ static unsigned long pllc1_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc1_clk_ops = {
+static struct sh_clk_ops pllc1_clk_ops = {
        .recalc         = pllc1_recalc,
 };
 
@@ -137,7 +137,7 @@ static unsigned long pllc2_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops pllc2_clk_ops = {
+static struct sh_clk_ops pllc2_clk_ops = {
        .recalc         = pllc2_recalc,
 };
 
@@ -360,7 +360,7 @@ void __init sh7377_clock_init(void)
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        if (!ret)
-               clk_init();
+               shmobile_clk_init();
        else
                panic("failed to setup sh7377 clocks\n");
 }
index 7727cca..472d1f5 100644 (file)
@@ -88,7 +88,7 @@ static unsigned long div2_recalc(struct clk *clk)
        return clk->parent->rate / 2;
 }
 
-static struct clk_ops div2_clk_ops = {
+static struct sh_clk_ops div2_clk_ops = {
        .recalc         = div2_recalc,
 };
 
@@ -97,7 +97,7 @@ static unsigned long div7_recalc(struct clk *clk)
        return clk->parent->rate / 7;
 }
 
-static struct clk_ops div7_clk_ops = {
+static struct sh_clk_ops div7_clk_ops = {
        .recalc         = div7_recalc,
 };
 
@@ -106,7 +106,7 @@ static unsigned long div13_recalc(struct clk *clk)
        return clk->parent->rate / 13;
 }
 
-static struct clk_ops div13_clk_ops = {
+static struct sh_clk_ops div13_clk_ops = {
        .recalc         = div13_recalc,
 };
 
@@ -122,7 +122,7 @@ static struct clk extal2_div2_clk = {
        .parent         = &sh73a0_extal2_clk,
 };
 
-static struct clk_ops main_clk_ops = {
+static struct sh_clk_ops main_clk_ops = {
        .recalc         = followparent_recalc,
 };
 
@@ -156,7 +156,7 @@ static unsigned long pll_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
        .recalc         = pll_recalc,
 };
 
@@ -438,7 +438,7 @@ static int dsiphy_set_rate(struct clk *clk, unsigned long rate)
        return 0;
 }
 
-static struct clk_ops dsiphy_clk_ops = {
+static struct sh_clk_ops dsiphy_clk_ops = {
        .recalc         = dsiphy_recalc,
        .round_rate     = dsiphy_round_rate,
        .set_rate       = dsiphy_set_rate,
@@ -620,7 +620,7 @@ void __init sh73a0_clock_init(void)
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        if (!ret)
-               clk_init();
+               shmobile_clk_init();
        else
                panic("failed to setup sh73a0 clocks\n");
 }
index 31654d7..e816ca9 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/sh_clk.h>
 #include <linux/export.h>
 
-int __init clk_init(void)
+int __init shmobile_clk_init(void)
 {
        /* Kick the child clocks.. */
        recalculate_root_clocks();
index e4b945e..83ad3fe 100644 (file)
@@ -1,12 +1,15 @@
 #ifndef __ARCH_MACH_COMMON_H
 #define __ARCH_MACH_COMMON_H
 
+extern void shmobile_earlytimer_init(void);
 extern struct sys_timer shmobile_timer;
+struct twd_local_timer;
+void shmobile_twd_init(struct twd_local_timer *twd_local_timer);
 extern void shmobile_setup_console(void);
 extern void shmobile_secondary_vector(void);
 extern int shmobile_platform_cpu_kill(unsigned int cpu);
 struct clk;
-extern int clk_init(void);
+extern int shmobile_clk_init(void);
 extern void shmobile_handle_irq_intc(struct pt_regs *);
 extern struct platform_suspend_ops shmobile_suspend_ops;
 struct cpuidle_driver;
@@ -14,6 +17,7 @@ extern void (*shmobile_cpuidle_modes[])(void);
 extern void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);
 
 extern void sh7367_init_irq(void);
+extern void sh7367_map_io(void);
 extern void sh7367_add_early_devices(void);
 extern void sh7367_add_standard_devices(void);
 extern void sh7367_clock_init(void);
@@ -22,6 +26,7 @@ extern struct clk sh7367_extalb1_clk;
 extern struct clk sh7367_extal2_clk;
 
 extern void sh7377_init_irq(void);
+extern void sh7377_map_io(void);
 extern void sh7377_add_early_devices(void);
 extern void sh7377_add_standard_devices(void);
 extern void sh7377_clock_init(void);
@@ -30,6 +35,7 @@ extern struct clk sh7377_extalc1_clk;
 extern struct clk sh7377_extal2_clk;
 
 extern void sh7372_init_irq(void);
+extern void sh7372_map_io(void);
 extern void sh7372_add_early_devices(void);
 extern void sh7372_add_standard_devices(void);
 extern void sh7372_clock_init(void);
@@ -41,6 +47,7 @@ extern struct clk sh7372_extal1_clk;
 extern struct clk sh7372_extal2_clk;
 
 extern void sh73a0_init_irq(void);
+extern void sh73a0_map_io(void);
 extern void sh73a0_add_early_devices(void);
 extern void sh73a0_add_standard_devices(void);
 extern void sh73a0_clock_init(void);
@@ -56,12 +63,14 @@ extern int sh73a0_boot_secondary(unsigned int cpu);
 extern void sh73a0_smp_prepare_cpus(void);
 
 extern void r8a7740_init_irq(void);
+extern void r8a7740_map_io(void);
 extern void r8a7740_add_early_devices(void);
 extern void r8a7740_add_standard_devices(void);
 extern void r8a7740_clock_init(u8 md_ck);
 extern void r8a7740_pinmux_init(void);
 
 extern void r8a7779_init_irq(void);
+extern void r8a7779_map_io(void);
 extern void r8a7779_add_early_devices(void);
 extern void r8a7779_add_standard_devices(void);
 extern void r8a7779_clock_init(void);
diff --git a/arch/arm/mach-shmobile/include/mach/entry-macro.S b/arch/arm/mach-shmobile/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 2a57b29..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2010  Paul Mundt
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
index 9204270..540eaff 100644 (file)
@@ -3,11 +3,6 @@
 
 #include <asm/system_misc.h>
 
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
 static inline void arch_reset(char mode, const char *cmd)
 {
        soft_restart(0);
diff --git a/arch/arm/mach-shmobile/localtimer.c b/arch/arm/mach-shmobile/localtimer.c
deleted file mode 100644 (file)
index ad9ccc9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * SMP support for R-Mobile / SH-Mobile - local timer portion
- *
- * Copyright (C) 2010  Magnus Damm
- *
- * Based on vexpress, Copyright (C) 2002 ARM Ltd, All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       evt->irq = 29;
-       twd_timer_setup(evt);
-       return 0;
-}
index 9933812..45fa392 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/smp.h>
 #include <linux/io.h>
 #include <asm/hardware/gic.h>
-#include <asm/localtimer.h>
 #include <asm/mach-types.h>
 #include <mach/common.h>
 
index 986dca6..74e5234 100644 (file)
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <mach/r8a7740.h>
+#include <mach/common.h>
 #include <asm/mach-types.h>
+#include <asm/mach/map.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+static struct map_desc r8a7740_io_desc[] __initdata = {
+        /*
+         * for CPGA/INTC/PFC
+         * 0xe6000000-0xefffffff -> 0xe6000000-0xefffffff
+         */
+       {
+               .virtual        = 0xe6000000,
+               .pfn            = __phys_to_pfn(0xe6000000),
+               .length         = 160 << 20,
+               .type           = MT_DEVICE_NONSHARED
+       },
+#ifdef CONFIG_CACHE_L2X0
+       /*
+        * for l2x0_init()
+        * 0xf0100000-0xf0101000 -> 0xf0002000-0xf0003000
+        */
+       {
+               .virtual        = 0xf0002000,
+               .pfn            = __phys_to_pfn(0xf0100000),
+               .length         = PAGE_SIZE,
+               .type           = MT_DEVICE_NONSHARED
+       },
+#endif
+};
+
+void __init r8a7740_map_io(void)
+{
+       iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc));
+}
 
 /* SCIFA0 */
 static struct plat_sci_port scif0_platform_data = {
@@ -345,8 +378,20 @@ void __init r8a7740_add_standard_devices(void)
                             ARRAY_SIZE(r8a7740_late_devices));
 }
 
+static void __init r8a7740_earlytimer_init(void)
+{
+       r8a7740_clock_init(0);
+       shmobile_earlytimer_init();
+}
+
 void __init r8a7740_add_early_devices(void)
 {
        early_platform_add_devices(r8a7740_early_devices,
                                   ARRAY_SIZE(r8a7740_early_devices));
+
+       /* setup early console here as well */
+       shmobile_setup_console();
+
+       /* override timer setup with soc-specific code */
+       shmobile_timer.init = r8a7740_earlytimer_init;
 }
index 4725663..6820d78 100644 (file)
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/cache-l2x0.h>
+
+static struct map_desc r8a7779_io_desc[] __initdata = {
+       /* 2M entity map for 0xf0000000 (MPCORE) */
+       {
+               .virtual        = 0xf0000000,
+               .pfn            = __phys_to_pfn(0xf0000000),
+               .length         = SZ_2M,
+               .type           = MT_DEVICE_NONSHARED
+       },
+       /* 16M entity map for 0xfexxxxxx (DMAC-S/HPBREG/INTC2/LRAM/DBSC) */
+       {
+               .virtual        = 0xfe000000,
+               .pfn            = __phys_to_pfn(0xfe000000),
+               .length         = SZ_16M,
+               .type           = MT_DEVICE_NONSHARED
+       },
+};
+
+void __init r8a7779_map_io(void)
+{
+       iotable_init(r8a7779_io_desc, ARRAY_SIZE(r8a7779_io_desc));
+}
 
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xffe40000,
@@ -219,6 +244,10 @@ static struct platform_device *r8a7779_late_devices[] __initdata = {
 
 void __init r8a7779_add_standard_devices(void)
 {
+#ifdef CONFIG_CACHE_L2X0
+       /* Early BRESP enable, Shared attribute override enable, 64K*16way */
+       l2x0_init((void __iomem __force *)(0xf0100000), 0x40470000, 0x82000fff);
+#endif
        r8a7779_pm_init();
 
        r8a7779_init_pm_domain(&r8a7779_sh4a);
@@ -232,8 +261,33 @@ void __init r8a7779_add_standard_devices(void)
                            ARRAY_SIZE(r8a7779_late_devices));
 }
 
+static void __init r8a7779_earlytimer_init(void)
+{
+       r8a7779_clock_init();
+       shmobile_earlytimer_init();
+}
+
 void __init r8a7779_add_early_devices(void)
 {
        early_platform_add_devices(r8a7779_early_devices,
                                   ARRAY_SIZE(r8a7779_early_devices));
+
+       /* Early serial console setup is not included here due to
+        * memory map collisions. The SCIF serial ports in r8a7779
+        * are difficult to entity map 1:1 due to collision with the
+        * virtual memory range used by the coherent DMA code on ARM.
+        *
+        * Anyone wanting to debug early can remove UPF_IOREMAP from
+        * the sh-sci serial console platform data, adjust mapbase
+        * to a static M:N virt:phys mapping that needs to be added to
+        * the mappings passed with iotable_init() above.
+        *
+        * Then add a call to shmobile_setup_console() from this function.
+        *
+        * As a final step pass earlyprint=sh-sci.2,115200 on the kernel
+        * command line in case of the marzen board.
+        */
+
+       /* override timer setup with soc-specific code */
+       shmobile_timer.init = r8a7779_earlytimer_init;
 }
index e546017..a51e1a1 100644 (file)
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <mach/hardware.h>
+#include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+static struct map_desc sh7367_io_desc[] __initdata = {
+       /* create a 1:1 entity map for 0xe6xxxxxx
+        * used by CPGA, INTC and PFC.
+        */
+       {
+               .virtual        = 0xe6000000,
+               .pfn            = __phys_to_pfn(0xe6000000),
+               .length         = 256 << 20,
+               .type           = MT_DEVICE_NONSHARED
+       },
+};
+
+void __init sh7367_map_io(void)
+{
+       iotable_init(sh7367_io_desc, ARRAY_SIZE(sh7367_io_desc));
+}
 
 /* SCIFA0 */
 static struct plat_sci_port scif0_platform_data = {
@@ -435,6 +455,12 @@ void __init sh7367_add_standard_devices(void)
                            ARRAY_SIZE(sh7367_devices));
 }
 
+static void __init sh7367_earlytimer_init(void)
+{
+       sh7367_clock_init();
+       shmobile_earlytimer_init();
+}
+
 #define SYMSTPCR2 0xe6158048
 #define SYMSTPCR2_CMT1 (1 << 29)
 
@@ -445,4 +471,10 @@ void __init sh7367_add_early_devices(void)
 
        early_platform_add_devices(sh7367_early_devices,
                                   ARRAY_SIZE(sh7367_early_devices));
+
+       /* setup early console here as well */
+       shmobile_setup_console();
+
+       /* override timer setup with soc-specific code */
+       shmobile_timer.init = sh7367_earlytimer_init;
 }
index cccf91b..4e818b7 100644 (file)
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
 #include <linux/pm_domain.h>
+#include <linux/dma-mapping.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
+#include <mach/common.h>
+#include <asm/mach/map.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+static struct map_desc sh7372_io_desc[] __initdata = {
+       /* create a 1:1 entity map for 0xe6xxxxxx
+        * used by CPGA, INTC and PFC.
+        */
+       {
+               .virtual        = 0xe6000000,
+               .pfn            = __phys_to_pfn(0xe6000000),
+               .length         = 256 << 20,
+               .type           = MT_DEVICE_NONSHARED
+       },
+};
+
+void __init sh7372_map_io(void)
+{
+       iotable_init(sh7372_io_desc, ARRAY_SIZE(sh7372_io_desc));
+
+       /*
+        * DMA memory at 0xff200000 - 0xffdfffff. The default 2MB size isn't
+        * enough to allocate the frame buffer memory.
+        */
+       init_consistent_dma_size(12 << 20);
+}
 
 /* SCIFA0 */
 static struct plat_sci_port scif0_platform_data = {
@@ -1047,8 +1074,20 @@ void __init sh7372_add_standard_devices(void)
        sh7372_add_device_to_domain(&sh7372_a4r, &tmu01_device);
 }
 
+static void __init sh7372_earlytimer_init(void)
+{
+       sh7372_clock_init();
+       shmobile_earlytimer_init();
+}
+
 void __init sh7372_add_early_devices(void)
 {
        early_platform_add_devices(sh7372_early_devices,
                                   ARRAY_SIZE(sh7372_early_devices));
+
+       /* setup early console here as well */
+       shmobile_setup_console();
+
+       /* override timer setup with soc-specific code */
+       shmobile_timer.init = sh7372_earlytimer_init;
 }
index bb405b8..9f14609 100644 (file)
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
 #include <mach/hardware.h>
+#include <mach/common.h>
+#include <asm/mach/map.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+static struct map_desc sh7377_io_desc[] __initdata = {
+       /* create a 1:1 entity map for 0xe6xxxxxx
+        * used by CPGA, INTC and PFC.
+        */
+       {
+               .virtual        = 0xe6000000,
+               .pfn            = __phys_to_pfn(0xe6000000),
+               .length         = 256 << 20,
+               .type           = MT_DEVICE_NONSHARED
+       },
+};
+
+void __init sh7377_map_io(void)
+{
+       iotable_init(sh7377_io_desc, ARRAY_SIZE(sh7377_io_desc));
+}
 
 /* SCIFA0 */
 static struct plat_sci_port scif0_platform_data = {
@@ -456,6 +476,12 @@ void __init sh7377_add_standard_devices(void)
                            ARRAY_SIZE(sh7377_devices));
 }
 
+static void __init sh7377_earlytimer_init(void)
+{
+       sh7377_clock_init();
+       shmobile_earlytimer_init();
+}
+
 #define SMSTPCR3 0xe615013c
 #define SMSTPCR3_CMT1 (1 << 29)
 
@@ -466,4 +492,10 @@ void __init sh7377_add_early_devices(void)
 
        early_platform_add_devices(sh7377_early_devices,
                                   ARRAY_SIZE(sh7377_early_devices));
+
+       /* setup early console here as well */
+       shmobile_setup_console();
+
+       /* override timer setup with soc-specific code */
+       shmobile_timer.init = sh7377_earlytimer_init;
 }
index 20e71e5..b6a0734 100644 (file)
 #include <linux/sh_timer.h>
 #include <mach/hardware.h>
 #include <mach/sh73a0.h>
+#include <mach/common.h>
 #include <asm/mach-types.h>
+#include <asm/mach/map.h>
 #include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+static struct map_desc sh73a0_io_desc[] __initdata = {
+       /* create a 1:1 entity map for 0xe6xxxxxx
+        * used by CPGA, INTC and PFC.
+        */
+       {
+               .virtual        = 0xe6000000,
+               .pfn            = __phys_to_pfn(0xe6000000),
+               .length         = 256 << 20,
+               .type           = MT_DEVICE_NONSHARED
+       },
+};
+
+void __init sh73a0_map_io(void)
+{
+       iotable_init(sh73a0_io_desc, ARRAY_SIZE(sh73a0_io_desc));
+}
 
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xe6c40000,
@@ -667,8 +687,20 @@ void __init sh73a0_add_standard_devices(void)
                            ARRAY_SIZE(sh73a0_late_devices));
 }
 
+static void __init sh73a0_earlytimer_init(void)
+{
+       sh73a0_clock_init();
+       shmobile_earlytimer_init();
+}
+
 void __init sh73a0_add_early_devices(void)
 {
        early_platform_add_devices(sh73a0_early_devices,
                                   ARRAY_SIZE(sh73a0_early_devices));
+
+       /* setup early console here as well */
+       shmobile_setup_console();
+
+       /* override timer setup with soc-specific code */
+       shmobile_timer.init = sh73a0_earlytimer_init;
 }
index 4fe2e9e..9bb7b85 100644 (file)
@@ -64,6 +64,8 @@ static void __iomem *scu_base_addr(void)
 static DEFINE_SPINLOCK(scu_lock);
 static unsigned long tmp;
 
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29);
+
 static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
 {
        void __iomem *scu_base = scu_base_addr();
@@ -82,11 +84,7 @@ unsigned int __init r8a7779_get_core_count(void)
 {
        void __iomem *scu_base = scu_base_addr();
 
-#ifdef CONFIG_HAVE_ARM_TWD
-       /* twd_base needs to be initialized before percpu_timer_setup() */
-       twd_base = (void __iomem *)0xf0000600;
-#endif
-
+       shmobile_twd_init(&twd_local_timer);
        return scu_get_core_count(scu_base);
 }
 
index 2d0d421..c0a9093 100644 (file)
@@ -42,6 +42,8 @@ static void __iomem *scu_base_addr(void)
 static DEFINE_SPINLOCK(scu_lock);
 static unsigned long tmp;
 
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29);
+
 static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
 {
        void __iomem *scu_base = scu_base_addr();
@@ -60,11 +62,7 @@ unsigned int __init sh73a0_get_core_count(void)
 {
        void __iomem *scu_base = scu_base_addr();
 
-#ifdef CONFIG_HAVE_ARM_TWD
-       /* twd_base needs to be initialized before percpu_timer_setup() */
-       twd_base = (void __iomem *)0xf0000600;
-#endif
-
+       shmobile_twd_init(&twd_local_timer);
        return scu_get_core_count(scu_base);
 }
 
index 895794b..2fba5f3 100644 (file)
@@ -20,6 +20,7 @@
  */
 #include <linux/platform_device.h>
 #include <asm/mach/time.h>
+#include <asm/smp_twd.h>
 
 static void __init shmobile_late_time_init(void)
 {
@@ -36,11 +37,24 @@ static void __init shmobile_late_time_init(void)
        early_platform_driver_probe("earlytimer", 2, 0);
 }
 
-static void __init shmobile_timer_init(void)
+void __init shmobile_earlytimer_init(void)
 {
        late_time_init = shmobile_late_time_init;
 }
 
+static void __init shmobile_timer_init(void)
+{
+}
+
+void __init shmobile_twd_init(struct twd_local_timer *twd_local_timer)
+{
+#ifdef CONFIG_HAVE_ARM_TWD
+       int err = twd_local_timer_register(twd_local_timer);
+       if (err)
+               pr_err("twd_local_timer_register failed %d\n", err);
+#endif
+}
+
 struct sys_timer shmobile_timer = {
        .init           = shmobile_timer_init,
 };
diff --git a/arch/arm/mach-spear3xx/include/mach/entry-macro.S b/arch/arm/mach-spear3xx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index de3bb41..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for SPEAr3xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-spear3xx/include/mach/system.h b/arch/arm/mach-spear3xx/include/mach/system.h
deleted file mode 100644 (file)
index 92cee63..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/system.h
- *
- * SPEAr3xx Machine family specific architecture functions
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __MACH_SYSTEM_H
-#define __MACH_SYSTEM_H
-
-#include <plat/system.h>
-
-#endif /* __MACH_SYSTEM_H */
index 4f7f518..f7db668 100644 (file)
@@ -430,18 +430,8 @@ static struct pl061_platform_data gpio1_plat_data = {
        .irq_base       = SPEAR300_GPIO1_INT_BASE,
 };
 
-struct amba_device spear300_gpio1_device = {
-       .dev = {
-               .init_name = "gpio1",
-               .platform_data = &gpio1_plat_data,
-       },
-       .res = {
-               .start = SPEAR300_GPIO_BASE,
-               .end = SPEAR300_GPIO_BASE + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {SPEAR300_VIRQ_GPIO1, NO_IRQ},
-};
+AMBA_APB_DEVICE(spear300_gpio1, "gpio1", 0, SPEAR300_GPIO_BASE,
+       {SPEAR300_VIRQ_GPIO1}, &gpio1_plat_data);
 
 /* spear300 routines */
 void __init spear300_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
index 10af45d..b1733c3 100644 (file)
@@ -28,31 +28,12 @@ static struct pl061_platform_data gpio_plat_data = {
        .irq_base       = SPEAR3XX_GPIO_INT_BASE,
 };
 
-struct amba_device spear3xx_gpio_device = {
-       .dev = {
-               .init_name = "gpio",
-               .platform_data = &gpio_plat_data,
-       },
-       .res = {
-               .start = SPEAR3XX_ICM3_GPIO_BASE,
-               .end = SPEAR3XX_ICM3_GPIO_BASE + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {SPEAR3XX_IRQ_BASIC_GPIO, NO_IRQ},
-};
+AMBA_APB_DEVICE(spear3xx_gpio, "gpio", 0, SPEAR3XX_ICM3_GPIO_BASE,
+       {SPEAR3XX_IRQ_BASIC_GPIO}, &gpio_plat_data);
 
 /* uart device registration */
-struct amba_device spear3xx_uart_device = {
-       .dev = {
-               .init_name = "uart",
-       },
-       .res = {
-               .start = SPEAR3XX_ICM1_UART_BASE,
-               .end = SPEAR3XX_ICM1_UART_BASE + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {SPEAR3XX_IRQ_UART, NO_IRQ},
-};
+AMBA_APB_DEVICE(spear3xx_uart, "uart", 0, SPEAR3XX_ICM1_UART_BASE,
+       {SPEAR3XX_IRQ_UART}, NULL);
 
 /* Do spear3xx familiy common initialization part here */
 void __init spear3xx_init(void)
index ff4ae5b..fbe298b 100644 (file)
@@ -5,11 +5,12 @@
 if ARCH_SPEAR6XX
 
 menu "SPEAr6xx Implementations"
-config BOARD_SPEAR600_EVB
-       bool "SPEAr600 Evaluation Board"
+config BOARD_SPEAR600_DT
+       bool "SPEAr600 generic board configured via device-tree"
        select MACH_SPEAR600
+       select USE_OF
        help
-         Supports ST SPEAr600 Evaluation Board
+         Supports ST SPEAr600 boards configured via the device-tree
 
 endmenu
 
index cc1a4d8..76e5750 100644 (file)
@@ -4,9 +4,3 @@
 
 # common files
 obj-y  += clock.o spear6xx.o
-
-# spear600 specific files
-obj-$(CONFIG_MACH_SPEAR600) += spear600.o
-
-# spear600 boards files
-obj-$(CONFIG_BOARD_SPEAR600_EVB) += spear600_evb.o
index ac70e0d..358f280 100644 (file)
@@ -641,8 +641,8 @@ static struct clk_lookup spear_clk_lookups[] = {
        { .con_id = "gpt0_synth_clk",   .clk = &gpt0_synth_clk},
        { .con_id = "gpt2_synth_clk",   .clk = &gpt2_synth_clk},
        { .con_id = "gpt3_synth_clk",   .clk = &gpt3_synth_clk},
-       { .dev_id = "uart0",            .clk = &uart0_clk},
-       { .dev_id = "uart1",            .clk = &uart1_clk},
+       { .dev_id = "d0000000.serial",  .clk = &uart0_clk},
+       { .dev_id = "d0080000.serial",  .clk = &uart1_clk},
        { .dev_id = "firda",            .clk = &firda_clk},
        { .dev_id = "clcd",             .clk = &clcd_clk},
        { .dev_id = "gpt0",             .clk = &gpt0_clk},
@@ -655,20 +655,20 @@ static struct clk_lookup spear_clk_lookups[] = {
        { .con_id = "usbh.1_clk",       .clk = &usbh1_clk},
        /* clock derived from ahb clk */
        { .con_id = "apb_clk",          .clk = &apb_clk},
-       { .dev_id = "i2c_designware.0", .clk = &i2c_clk},
+       { .dev_id = "d0200000.i2c",     .clk = &i2c_clk},
        { .dev_id = "dma",              .clk = &dma_clk},
        { .dev_id = "jpeg",             .clk = &jpeg_clk},
        { .dev_id = "gmac",             .clk = &gmac_clk},
        { .dev_id = "smi",              .clk = &smi_clk},
-       { .con_id = "fsmc",             .clk = &fsmc_clk},
+       { .dev_id = "fsmc-nand",        .clk = &fsmc_clk},
        /* clock derived from apb clk */
        { .dev_id = "adc",              .clk = &adc_clk},
        { .dev_id = "ssp-pl022.0",      .clk = &ssp0_clk},
        { .dev_id = "ssp-pl022.1",      .clk = &ssp1_clk},
        { .dev_id = "ssp-pl022.2",      .clk = &ssp2_clk},
-       { .dev_id = "gpio0",            .clk = &gpio0_clk},
-       { .dev_id = "gpio1",            .clk = &gpio1_clk},
-       { .dev_id = "gpio2",            .clk = &gpio2_clk},
+       { .dev_id = "f0100000.gpio",    .clk = &gpio0_clk},
+       { .dev_id = "fc980000.gpio",    .clk = &gpio1_clk},
+       { .dev_id = "d8100000.gpio",    .clk = &gpio2_clk},
 };
 
 void __init spear6xx_clk_init(void)
diff --git a/arch/arm/mach-spear6xx/include/mach/entry-macro.S b/arch/arm/mach-spear6xx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index d490a91..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/mach-spear6xx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for SPEAr6xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-spear6xx/include/mach/system.h b/arch/arm/mach-spear6xx/include/mach/system.h
deleted file mode 100644 (file)
index 0b1d2be..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-spear6xx/include/mach/system.h
- *
- * SPEAr6xx Machine family specific architecture functions
- *
- * Copyright (C) 2009 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __MACH_SYSTEM_H
-#define __MACH_SYSTEM_H
-
-#include <plat/system.h>
-
-#endif /* __MACH_SYSTEM_H */
diff --git a/arch/arm/mach-spear6xx/spear600.c b/arch/arm/mach-spear6xx/spear600.c
deleted file mode 100644 (file)
index d0e6eea..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * arch/arm/mach-spear6xx/spear600.c
- *
- * SPEAr600 machine source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/ptrace.h>
-#include <asm/irq.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* Add spear600 specific devices here */
-
-void __init spear600_init(void)
-{
-       /* call spear6xx family common init function */
-       spear6xx_init();
-}
diff --git a/arch/arm/mach-spear6xx/spear600_evb.c b/arch/arm/mach-spear6xx/spear600_evb.c
deleted file mode 100644 (file)
index c6e4254..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * arch/arm/mach-spear6xx/spear600_evb.c
- *
- * SPEAr600 evaluation board source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <asm/hardware/vic.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
-
-static struct amba_device *amba_devs[] __initdata = {
-       &gpio_device[0],
-       &gpio_device[1],
-       &gpio_device[2],
-       &uart_device[0],
-       &uart_device[1],
-};
-
-static struct platform_device *plat_devs[] __initdata = {
-};
-
-static void __init spear600_evb_init(void)
-{
-       unsigned int i;
-
-       /* call spear600 machine init function */
-       spear600_init();
-
-       /* Add Platform Devices */
-       platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
-
-       /* Add Amba Devices */
-       for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
-               amba_device_register(amba_devs[i], &iomem_resource);
-}
-
-MACHINE_START(SPEAR600, "ST-SPEAR600-EVB")
-       .atag_offset    =       0x100,
-       .map_io         =       spear6xx_map_io,
-       .init_irq       =       spear6xx_init_irq,
-       .handle_irq     =       vic_handle_irq,
-       .timer          =       &spear6xx_timer,
-       .init_machine   =       spear600_evb_init,
-       .restart        =       spear_restart,
-MACHINE_END
index e0f6628..2ed8b14 100644 (file)
  * Copyright (C) 2009 ST Microelectronics
  * Rajeev Kumar<rajeev-dlh.kumar@st.com>
  *
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
  * 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/types.h>
-#include <linux/amba/pl061.h>
-#include <linux/ptrace.h>
-#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
 #include <asm/hardware/vic.h>
-#include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <mach/generic.h>
 #include <mach/hardware.h>
-#include <mach/irqs.h>
-
-/* Add spear6xx machines common devices here */
-/* uart device registration */
-struct amba_device uart_device[] = {
-       {
-               .dev = {
-                       .init_name = "uart0",
-               },
-               .res = {
-                       .start = SPEAR6XX_ICM1_UART0_BASE,
-                       .end = SPEAR6XX_ICM1_UART0_BASE + SZ_4K - 1,
-                       .flags = IORESOURCE_MEM,
-               },
-               .irq = {IRQ_UART_0, NO_IRQ},
-       }, {
-               .dev = {
-                       .init_name = "uart1",
-               },
-               .res = {
-                       .start = SPEAR6XX_ICM1_UART1_BASE,
-                       .end = SPEAR6XX_ICM1_UART1_BASE + SZ_4K - 1,
-                       .flags = IORESOURCE_MEM,
-               },
-               .irq = {IRQ_UART_1, NO_IRQ},
-       }
-};
-
-/* gpio device registration */
-static struct pl061_platform_data gpio_plat_data[] = {
-       {
-               .gpio_base      = 0,
-               .irq_base       = SPEAR_GPIO0_INT_BASE,
-       }, {
-               .gpio_base      = 8,
-               .irq_base       = SPEAR_GPIO1_INT_BASE,
-       }, {
-               .gpio_base      = 16,
-               .irq_base       = SPEAR_GPIO2_INT_BASE,
-       },
-};
-
-struct amba_device gpio_device[] = {
-       {
-               .dev = {
-                       .init_name = "gpio0",
-                       .platform_data = &gpio_plat_data[0],
-               },
-               .res = {
-                       .start = SPEAR6XX_CPU_GPIO_BASE,
-                       .end = SPEAR6XX_CPU_GPIO_BASE + SZ_4K - 1,
-                       .flags = IORESOURCE_MEM,
-               },
-               .irq = {IRQ_LOCAL_GPIO, NO_IRQ},
-       }, {
-               .dev = {
-                       .init_name = "gpio1",
-                       .platform_data = &gpio_plat_data[1],
-               },
-               .res = {
-                       .start = SPEAR6XX_ICM3_GPIO_BASE,
-                       .end = SPEAR6XX_ICM3_GPIO_BASE + SZ_4K - 1,
-                       .flags = IORESOURCE_MEM,
-               },
-               .irq = {IRQ_BASIC_GPIO, NO_IRQ},
-       }, {
-               .dev = {
-                       .init_name = "gpio2",
-                       .platform_data = &gpio_plat_data[2],
-               },
-               .res = {
-                       .start = SPEAR6XX_ICM2_GPIO_BASE,
-                       .end = SPEAR6XX_ICM2_GPIO_BASE + SZ_4K - 1,
-                       .flags = IORESOURCE_MEM,
-               },
-               .irq = {IRQ_APPL_GPIO, NO_IRQ},
-       }
-};
-
-/* This will add devices, and do machine specific tasks */
-void __init spear6xx_init(void)
-{
-       /* nothing to do for now */
-}
-
-/* This will initialize vic */
-void __init spear6xx_init_irq(void)
-{
-       vic_init((void __iomem *)VA_SPEAR6XX_CPU_VIC_PRI_BASE, 0, ~0, 0);
-       vic_init((void __iomem *)VA_SPEAR6XX_CPU_VIC_SEC_BASE, 32, ~0, 0);
-}
 
 /* Following will create static virtual/physical mappings */
 static struct map_desc spear6xx_io_desc[] __initdata = {
@@ -181,3 +91,33 @@ static void __init spear6xx_timer_init(void)
 struct sys_timer spear6xx_timer = {
        .init = spear6xx_timer_init,
 };
+
+static void __init spear600_dt_init(void)
+{
+       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *spear600_dt_board_compat[] = {
+       "st,spear600",
+       NULL
+};
+
+static const struct of_device_id vic_of_match[] __initconst = {
+       { .compatible = "arm,pl190-vic", .data = vic_of_init, },
+       { /* Sentinel */ }
+};
+
+static void __init spear6xx_dt_init_irq(void)
+{
+       of_irq_init(vic_of_match);
+}
+
+DT_MACHINE_START(SPEAR600_DT, "ST SPEAr600 (Flattened Device Tree)")
+       .map_io         =       spear6xx_map_io,
+       .init_irq       =       spear6xx_dt_init_irq,
+       .handle_irq     =       vic_handle_irq,
+       .timer          =       &spear6xx_timer,
+       .init_machine   =       spear600_dt_init,
+       .restart        =       spear_restart,
+       .dt_compat      =       spear600_dt_board_compat,
+MACHINE_END
index 32b420a..d0f2546 100644 (file)
@@ -10,8 +10,16 @@ config ARCH_TEGRA_2x_SOC
        select PINCTRL
        select PINCTRL_TEGRA20
        select USB_ARCH_HAS_EHCI if USB_SUPPORT
-       select USB_ULPI if USB_SUPPORT
+       select USB_ULPI if USB
        select USB_ULPI_VIEWPORT if USB_SUPPORT
+       select ARM_ERRATA_720789
+       select ARM_ERRATA_742230
+       select ARM_ERRATA_751472
+       select ARM_ERRATA_754327
+       select ARM_ERRATA_764369
+       select PL310_ERRATA_727915 if CACHE_L2X0
+       select PL310_ERRATA_769419 if CACHE_L2X0
+       select CPU_FREQ_TABLE if CPU_FREQ
        help
          Support for NVIDIA Tegra AP20 and T20 processors, based on the
          ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -24,9 +32,15 @@ config ARCH_TEGRA_3x_SOC
        select PINCTRL
        select PINCTRL_TEGRA30
        select USB_ARCH_HAS_EHCI if USB_SUPPORT
-       select USB_ULPI if USB_SUPPORT
+       select USB_ULPI if USB
        select USB_ULPI_VIEWPORT if USB_SUPPORT
        select USE_OF
+       select ARM_ERRATA_743622
+       select ARM_ERRATA_751472
+       select ARM_ERRATA_754322
+       select ARM_ERRATA_764369
+       select PL310_ERRATA_769419 if CACHE_L2X0
+       select CPU_FREQ_TABLE if CPU_FREQ
        help
          Support for NVIDIA Tegra T30 processor family, based on the
          ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
index e120ff5..d87d968 100644 (file)
@@ -7,15 +7,21 @@ obj-y                                   += clock.o
 obj-y                                   += timer.o
 obj-y                                   += pinmux.o
 obj-y                                  += fuse.o
+obj-y                                  += pmc.o
+obj-y                                  += flowctrl.o
+obj-$(CONFIG_CPU_IDLE)                 += cpuidle.o
+obj-$(CONFIG_CPU_IDLE)                 += sleep.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += powergate.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_clocks.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += tegra2_emc.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += pinmux-tegra20-tables.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)                += pinmux-tegra30-tables.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)                += board-dt-tegra30.o
-obj-$(CONFIG_SMP)                       += platsmp.o localtimer.o headsmp.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)                += tegra30_clocks.o
+obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o
+obj-$(CONFIG_SMP)                       += reset.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
-obj-$(CONFIG_TEGRA_SYSTEM_DMA)         += dma.o
+obj-$(CONFIG_TEGRA_SYSTEM_DMA)         += dma.o apbio.o
 obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
 obj-$(CONFIG_TEGRA_PCI)                        += pcie.o
 obj-$(CONFIG_USB_SUPPORT)              += usb_phy.o
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
new file mode 100644 (file)
index 0000000..e75451e
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010 NVIDIA Corporation.
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+
+#include <mach/dma.h>
+#include <mach/iomap.h>
+
+#include "apbio.h"
+
+static DEFINE_MUTEX(tegra_apb_dma_lock);
+
+static struct tegra_dma_channel *tegra_apb_dma;
+static u32 *tegra_apb_bb;
+static dma_addr_t tegra_apb_bb_phys;
+static DECLARE_COMPLETION(tegra_apb_wait);
+
+bool tegra_apb_init(void)
+{
+       struct tegra_dma_channel *ch;
+
+       mutex_lock(&tegra_apb_dma_lock);
+
+       /* Check to see if we raced to setup */
+       if (tegra_apb_dma)
+               goto out;
+
+       ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
+               TEGRA_DMA_SHARED);
+
+       if (!ch)
+               goto out_fail;
+
+       tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
+               &tegra_apb_bb_phys, GFP_KERNEL);
+       if (!tegra_apb_bb) {
+               pr_err("%s: can not allocate bounce buffer\n", __func__);
+               tegra_dma_free_channel(ch);
+               goto out_fail;
+       }
+
+       tegra_apb_dma = ch;
+out:
+       mutex_unlock(&tegra_apb_dma_lock);
+       return true;
+
+out_fail:
+       mutex_unlock(&tegra_apb_dma_lock);
+       return false;
+}
+
+static void apb_dma_complete(struct tegra_dma_req *req)
+{
+       complete(&tegra_apb_wait);
+}
+
+u32 tegra_apb_readl(unsigned long offset)
+{
+       struct tegra_dma_req req;
+       int ret;
+
+       if (!tegra_apb_dma && !tegra_apb_init())
+               return readl(IO_TO_VIRT(offset));
+
+       mutex_lock(&tegra_apb_dma_lock);
+       req.complete = apb_dma_complete;
+       req.to_memory = 1;
+       req.dest_addr = tegra_apb_bb_phys;
+       req.dest_bus_width = 32;
+       req.dest_wrap = 1;
+       req.source_addr = offset;
+       req.source_bus_width = 32;
+       req.source_wrap = 4;
+       req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
+       req.size = 4;
+
+       INIT_COMPLETION(tegra_apb_wait);
+
+       tegra_dma_enqueue_req(tegra_apb_dma, &req);
+
+       ret = wait_for_completion_timeout(&tegra_apb_wait,
+               msecs_to_jiffies(50));
+
+       if (WARN(ret == 0, "apb read dma timed out")) {
+               tegra_dma_dequeue_req(tegra_apb_dma, &req);
+               *(u32 *)tegra_apb_bb = 0;
+       }
+
+       mutex_unlock(&tegra_apb_dma_lock);
+       return *((u32 *)tegra_apb_bb);
+}
+
+void tegra_apb_writel(u32 value, unsigned long offset)
+{
+       struct tegra_dma_req req;
+       int ret;
+
+       if (!tegra_apb_dma && !tegra_apb_init()) {
+               writel(value, IO_TO_VIRT(offset));
+               return;
+       }
+
+       mutex_lock(&tegra_apb_dma_lock);
+       *((u32 *)tegra_apb_bb) = value;
+       req.complete = apb_dma_complete;
+       req.to_memory = 0;
+       req.dest_addr = offset;
+       req.dest_wrap = 4;
+       req.dest_bus_width = 32;
+       req.source_addr = tegra_apb_bb_phys;
+       req.source_bus_width = 32;
+       req.source_wrap = 1;
+       req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
+       req.size = 4;
+
+       INIT_COMPLETION(tegra_apb_wait);
+
+       tegra_dma_enqueue_req(tegra_apb_dma, &req);
+
+       ret = wait_for_completion_timeout(&tegra_apb_wait,
+               msecs_to_jiffies(50));
+
+       if (WARN(ret == 0, "apb write dma timed out"))
+               tegra_dma_dequeue_req(tegra_apb_dma, &req);
+
+       mutex_unlock(&tegra_apb_dma_lock);
+}
diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h
new file mode 100644 (file)
index 0000000..8b49e8c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 NVIDIA Corporation.
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_APBIO_H
+#define __MACH_TEGRA_APBIO_H
+
+#ifdef CONFIG_TEGRA_SYSTEM_DMA
+
+u32 tegra_apb_readl(unsigned long offset);
+void tegra_apb_writel(u32 value, unsigned long offset);
+
+#else
+#include <asm/io.h>
+#include <mach/io.h>
+
+static inline u32 tegra_apb_readl(unsigned long offset)
+{
+        return readl(IO_TO_VIRT(offset));
+}
+
+static inline void tegra_apb_writel(u32 value, unsigned long offset)
+{
+        writel(value, IO_TO_VIRT(offset));
+}
+#endif
+
+#endif
index 7a95e0b..e20b419 100644 (file)
@@ -131,11 +131,7 @@ static void __init tegra_dt_init(void)
 }
 
 static const char *tegra20_dt_board_compat[] = {
-       "compulab,trimslice",
-       "nvidia,harmony",
-       "compal,paz00",
-       "nvidia,seaboard",
-       "nvidia,ventana",
+       "nvidia,tegra20",
        NULL
 };
 
index 3c197e2..5f7c03e 100644 (file)
 #include <asm/hardware/gic.h>
 
 #include "board.h"
+#include "clock.h"
 
 static struct of_device_id tegra_dt_match_table[] __initdata = {
        { .compatible = "simple-bus", },
        {}
 };
 
+struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000200, "sdhci-tegra.1", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000400, "sdhci-tegra.2", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000600, "sdhci-tegra.3", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C000, "tegra-i2c.0", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C400, "tegra-i2c.1", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL),
+       {}
+};
+
+static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
+       /* name         parent          rate            enabled */
+       { "uarta",      "pll_p",        408000000,      true },
+       { NULL,         NULL,           0,              0},
+};
+
 static void __init tegra30_dt_init(void)
 {
+       tegra_clk_init_from_table(tegra_dt_clk_init_table);
+
        of_platform_populate(NULL, tegra_dt_match_table,
-                               NULL, NULL);
+                               tegra30_auxdata_lookup, NULL);
 }
 
 static const char *tegra30_dt_board_compat[] = {
-       "nvidia,cardhu",
+       "nvidia,tegra30",
        NULL
 };
 
index 465808c..1af85bc 100644 (file)
@@ -53,7 +53,7 @@ static struct tegra_pingroup_config harmony_pinmux[] = {
        {TEGRA_PINGROUP_GME,   TEGRA_MUX_SDIO4,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_GPU,   TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_GPU7,  TEGRA_MUX_RTCK,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
-       {TEGRA_PINGROUP_GPV,   TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_GPV,   TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI,          TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_I2CP,  TEGRA_MUX_I2C,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_IRRX,  TEGRA_MUX_UARTA,         TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
@@ -112,10 +112,10 @@ static struct tegra_pingroup_config harmony_pinmux[] = {
        {TEGRA_PINGROUP_SDC,   TEGRA_MUX_PWM,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_SDD,   TEGRA_MUX_PWM,           TEGRA_PUPD_PULL_UP,   TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-       {TEGRA_PINGROUP_SLXA,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SLXA,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_SLXC,  TEGRA_MUX_SPDIF,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SLXD,  TEGRA_MUX_SPDIF,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
-       {TEGRA_PINGROUP_SLXK,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
+       {TEGRA_PINGROUP_SLXK,  TEGRA_MUX_PCIE,          TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
        {TEGRA_PINGROUP_SPDI,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SPDO,  TEGRA_MUX_RSVD2,         TEGRA_PUPD_NORMAL,    TEGRA_TRI_TRISTATE},
        {TEGRA_PINGROUP_SPIA,  TEGRA_MUX_GMI,           TEGRA_PUPD_NORMAL,    TEGRA_TRI_NORMAL},
index 21d1285..82f3230 100644 (file)
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
-#include <linux/io.h>
 #include <linux/regulator/machine.h>
 #include <linux/mfd/tps6586x.h>
 
-#include <mach/iomap.h>
 #include <mach/irqs.h>
 
 #include "board-harmony.h"
 
-#define PMC_CTRL               0x0
-#define PMC_CTRL_INTR_LOW      (1 << 17)
-
 static struct regulator_consumer_supply tps658621_ldo0_supply[] = {
        REGULATOR_SUPPLY("pex_clk", NULL),
 };
 
 static struct regulator_init_data ldo0_data = {
        .constraints = {
-               .min_uV = 1250 * 1000,
+               .min_uV = 3300 * 1000,
                .max_uV = 3300 * 1000,
                .valid_modes_mask = (REGULATOR_MODE_NORMAL |
                                     REGULATOR_MODE_STANDBY),
                .valid_ops_mask = (REGULATOR_CHANGE_MODE |
                                   REGULATOR_CHANGE_STATUS |
                                   REGULATOR_CHANGE_VOLTAGE),
+               .apply_uV = 1,
        },
        .num_consumer_supplies = ARRAY_SIZE(tps658621_ldo0_supply),
        .consumer_supplies = tps658621_ldo0_supply,
@@ -114,16 +110,6 @@ static struct i2c_board_info __initdata harmony_regulators[] = {
 
 int __init harmony_regulator_init(void)
 {
-       void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
-       u32 pmc_ctrl;
-
-       /*
-        * Configure the power management controller to trigger PMU
-        * interrupts when low
-        */
-       pmc_ctrl = readl(pmc + PMC_CTRL);
-       writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);
-
        i2c_register_board_info(3, harmony_regulators, 1);
 
        return 0;
index 789bdc9..c00aadb 100644 (file)
@@ -101,7 +101,6 @@ static struct wm8903_platform_data harmony_wm8903_pdata = {
 static struct i2c_board_info __initdata wm8903_board_info = {
        I2C_BOARD_INFO("wm8903", 0x1a),
        .platform_data = &harmony_wm8903_pdata,
-       .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
 };
 
 static void __init harmony_i2c_init(void)
@@ -111,6 +110,7 @@ static void __init harmony_i2c_init(void)
        platform_device_register(&tegra_i2c_device3);
        platform_device_register(&tegra_i2c_device4);
 
+       wm8903_board_info.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
        i2c_register_board_info(0, &wm8903_board_info, 1);
 }
 
index ebac65f..d669847 100644 (file)
@@ -159,7 +159,6 @@ static struct platform_device *seaboard_devices[] __initdata = {
 
 static struct i2c_board_info __initdata isl29018_device = {
        I2C_BOARD_INFO("isl29018", 0x44),
-       .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_ISL29018_IRQ),
 };
 
 static struct i2c_board_info __initdata adt7461_device = {
@@ -183,7 +182,6 @@ static struct wm8903_platform_data wm8903_pdata = {
 static struct i2c_board_info __initdata wm8903_device = {
        I2C_BOARD_INFO("wm8903", 0x1a),
        .platform_data = &wm8903_pdata,
-       .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
 };
 
 static int seaboard_ehci_init(void)
@@ -214,7 +212,10 @@ static void __init seaboard_i2c_init(void)
        gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018");
        gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ);
 
+       isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ);
        i2c_register_board_info(0, &isl29018_device, 1);
+
+       wm8903_device.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
        i2c_register_board_info(0, &wm8903_device, 1);
 
        i2c_register_board_info(3, &adt7461_device, 1);
index 8337068..8dad8d1 100644 (file)
@@ -399,6 +399,28 @@ void tegra_periph_reset_assert(struct clk *c)
 }
 EXPORT_SYMBOL(tegra_periph_reset_assert);
 
+/* Several extended clock configuration bits (e.g., clock routing, clock
+ * phase control) are included in PLL and peripheral clock source
+ * registers. */
+int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->spinlock, flags);
+
+       if (!c->ops || !c->ops->clk_cfg_ex) {
+               ret = -ENOSYS;
+               goto out;
+       }
+       ret = c->ops->clk_cfg_ex(c, p, setting);
+
+out:
+       spin_unlock_irqrestore(&c->spinlock, flags);
+
+       return ret;
+}
+
 #ifdef CONFIG_DEBUG_FS
 
 static int __clk_lock_all_spinlocks(void)
index 5c44106..bc30065 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
+#include <mach/clk.h>
+
 #define DIV_BUS                        (1 << 0)
 #define DIV_U71                        (1 << 1)
 #define DIV_U71_FIXED          (1 << 2)
 #define PERIPH_MANUAL_RESET    (1 << 12)
 #define PLL_ALT_MISC_REG       (1 << 13)
 #define PLLU                   (1 << 14)
+#define PLLX                    (1 << 15)
+#define MUX_PWM                 (1 << 16)
+#define MUX8                    (1 << 17)
+#define DIV_U71_UART            (1 << 18)
+#define MUX_CLK_OUT             (1 << 19)
+#define PLLM                    (1 << 20)
+#define DIV_U71_INT             (1 << 21)
+#define DIV_U71_IDLE            (1 << 22)
 #define ENABLE_ON_INIT         (1 << 28)
+#define PERIPH_ON_APB           (1 << 29)
 
 struct clk;
 
@@ -65,6 +76,8 @@ struct clk_ops {
        int             (*set_rate)(struct clk *, unsigned long);
        long            (*round_rate)(struct clk *, unsigned long);
        void            (*reset)(struct clk *, bool);
+       int             (*clk_cfg_ex)(struct clk *,
+                               enum tegra_clk_ex_param, u32);
 };
 
 enum clk_state {
@@ -114,6 +127,7 @@ struct clk {
                        unsigned long                   vco_max;
                        const struct clk_pll_freq_table *freq_table;
                        int                             lock_delay;
+                       unsigned long                   fixed_rate;
                } pll;
                struct {
                        u32                             sel;
@@ -146,6 +160,7 @@ struct tegra_clk_init_table {
 };
 
 void tegra2_init_clocks(void);
+void tegra30_init_clocks(void);
 void clk_init(struct clk *clk);
 struct clk *tegra_get_clock_by_name(const char *name);
 int clk_reparent(struct clk *c, struct clk *parent);
index a2eb901..22df10f 100644 (file)
 #include <asm/hardware/gic.h>
 
 #include <mach/iomap.h>
-#include <mach/system.h>
+#include <mach/powergate.h>
 
 #include "board.h"
 #include "clock.h"
 #include "fuse.h"
+#include "pmc.h"
+
+/*
+ * Storage for debug-macro.S's state.
+ *
+ * This must be in .data not .bss so that it gets initialized each time the
+ * kernel is loaded. The data is declared here rather than debug-macro.S so
+ * that multiple inclusions of debug-macro.S point at the same data.
+ */
+#define TEGRA_DEBUG_UART_OFFSET (TEGRA_DEBUG_UART_BASE & 0xFFFF)
+u32 tegra_uart_config[3] = {
+       /* Debug UART initialization required */
+       1,
+       /* Debug UART physical address */
+       (u32)(IO_APB_PHYS + TEGRA_DEBUG_UART_OFFSET),
+       /* Debug UART virtual address */
+       (u32)(IO_APB_VIRT + TEGRA_DEBUG_UART_OFFSET),
+};
 
 #ifdef CONFIG_OF
 static const struct of_device_id tegra_dt_irq_match[] __initconst = {
@@ -100,11 +118,17 @@ void __init tegra20_init_early(void)
        tegra2_init_clocks();
        tegra_clk_init_from_table(tegra20_clk_init_table);
        tegra_init_cache(0x331, 0x441);
+       tegra_pmc_init();
+       tegra_powergate_init();
 }
 #endif
 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
 void __init tegra30_init_early(void)
 {
+       tegra_init_fuse();
+       tegra30_init_clocks();
        tegra_init_cache(0x441, 0x551);
+       tegra_pmc_init();
+       tegra_powergate_init();
 }
 #endif
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
new file mode 100644 (file)
index 0000000..d83a8c0
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * arch/arm/mach-tegra/cpuidle.c
+ *
+ * CPU idle driver for Tegra CPUs
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2011 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *         Gary King <gking@nvidia.com>
+ *
+ * Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/cpuidle.h>
+#include <linux/hrtimer.h>
+
+#include <mach/iomap.h>
+
+extern void tegra_cpu_wfi(void);
+
+static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv, int index);
+
+struct cpuidle_driver tegra_idle_driver = {
+       .name = "tegra_idle",
+       .owner = THIS_MODULE,
+       .state_count = 1,
+       .states = {
+               [0] = {
+                       .enter                  = tegra_idle_enter_lp3,
+                       .exit_latency           = 10,
+                       .target_residency       = 10,
+                       .power_usage            = 600,
+                       .flags                  = CPUIDLE_FLAG_TIME_VALID,
+                       .name                   = "LP3",
+                       .desc                   = "CPU flow-controlled",
+               },
+       },
+};
+
+static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
+
+static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
+       struct cpuidle_driver *drv, int index)
+{
+       ktime_t enter, exit;
+       s64 us;
+
+       local_irq_disable();
+       local_fiq_disable();
+
+       enter = ktime_get();
+
+       tegra_cpu_wfi();
+
+       exit = ktime_sub(ktime_get(), enter);
+       us = ktime_to_us(exit);
+
+       local_fiq_enable();
+       local_irq_enable();
+
+       dev->last_residency = us;
+
+       return index;
+}
+
+static int __init tegra_cpuidle_init(void)
+{
+       int ret;
+       unsigned int cpu;
+       struct cpuidle_device *dev;
+       struct cpuidle_driver *drv = &tegra_idle_driver;
+
+       ret = cpuidle_register_driver(&tegra_idle_driver);
+       if (ret) {
+               pr_err("CPUidle driver registration failed\n");
+               return ret;
+       }
+
+       for_each_possible_cpu(cpu) {
+               dev = &per_cpu(tegra_idle_device, cpu);
+               dev->cpu = cpu;
+
+               dev->state_count = drv->state_count;
+               ret = cpuidle_register_device(dev);
+               if (ret) {
+                       pr_err("CPU%u: CPUidle device registration failed\n",
+                               cpu);
+                       return ret;
+               }
+       }
+       return 0;
+}
+device_initcall(tegra_cpuidle_init);
index c0cf967..abea4f6 100644 (file)
@@ -33,6 +33,8 @@
 #include <mach/iomap.h>
 #include <mach/suspend.h>
 
+#include "apbio.h"
+
 #define APB_DMA_GEN                            0x000
 #define GEN_ENABLE                             (1<<31)
 
@@ -50,8 +52,6 @@
 #define CSR_ONCE                               (1<<27)
 #define CSR_FLOW                               (1<<21)
 #define CSR_REQ_SEL_SHIFT                      16
-#define CSR_REQ_SEL_MASK                       (0x1F<<CSR_REQ_SEL_SHIFT)
-#define CSR_REQ_SEL_INVALID                    (31<<CSR_REQ_SEL_SHIFT)
 #define CSR_WCOUNT_SHIFT                       2
 #define CSR_WCOUNT_MASK                                0xFFFC
 
@@ -133,6 +133,7 @@ struct tegra_dma_channel {
 
 static bool tegra_dma_initialized;
 static DEFINE_MUTEX(tegra_dma_lock);
+static DEFINE_SPINLOCK(enable_lock);
 
 static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
 static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
@@ -180,36 +181,94 @@ static void tegra_dma_stop(struct tegra_dma_channel *ch)
 
 static int tegra_dma_cancel(struct tegra_dma_channel *ch)
 {
-       u32 csr;
        unsigned long irq_flags;
 
        spin_lock_irqsave(&ch->lock, irq_flags);
        while (!list_empty(&ch->list))
                list_del(ch->list.next);
 
-       csr = readl(ch->addr + APB_DMA_CHAN_CSR);
-       csr &= ~CSR_REQ_SEL_MASK;
-       csr |= CSR_REQ_SEL_INVALID;
-       writel(csr, ch->addr + APB_DMA_CHAN_CSR);
-
        tegra_dma_stop(ch);
 
        spin_unlock_irqrestore(&ch->lock, irq_flags);
        return 0;
 }
 
+static unsigned int get_channel_status(struct tegra_dma_channel *ch,
+                       struct tegra_dma_req *req, bool is_stop_dma)
+{
+       void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+       unsigned int status;
+
+       if (is_stop_dma) {
+               /*
+                * STOP the DMA and get the transfer count.
+                * Getting the transfer count is tricky.
+                *  - Globally disable DMA on all channels
+                *  - Read the channel's status register to know the number
+                *    of pending bytes to be transfered.
+                *  - Stop the dma channel
+                *  - Globally re-enable DMA to resume other transfers
+                */
+               spin_lock(&enable_lock);
+               writel(0, addr + APB_DMA_GEN);
+               udelay(20);
+               status = readl(ch->addr + APB_DMA_CHAN_STA);
+               tegra_dma_stop(ch);
+               writel(GEN_ENABLE, addr + APB_DMA_GEN);
+               spin_unlock(&enable_lock);
+               if (status & STA_ISE_EOC) {
+                       pr_err("Got Dma Int here clearing");
+                       writel(status, ch->addr + APB_DMA_CHAN_STA);
+               }
+               req->status = TEGRA_DMA_REQ_ERROR_ABORTED;
+       } else {
+               status = readl(ch->addr + APB_DMA_CHAN_STA);
+       }
+       return status;
+}
+
+/* should be called with the channel lock held */
+static unsigned int dma_active_count(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *req, unsigned int status)
+{
+       unsigned int to_transfer;
+       unsigned int req_transfer_count;
+       unsigned int bytes_transferred;
+
+       to_transfer = ((status & STA_COUNT_MASK) >> STA_COUNT_SHIFT) + 1;
+       req_transfer_count = ch->req_transfer_count + 1;
+       bytes_transferred = req_transfer_count;
+       if (status & STA_BUSY)
+               bytes_transferred -= to_transfer;
+       /*
+        * In continuous transfer mode, DMA only tracks the count of the
+        * half DMA buffer. So, if the DMA already finished half the DMA
+        * then add the half buffer to the completed count.
+        */
+       if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) {
+               if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
+                       bytes_transferred += req_transfer_count;
+               if (status & STA_ISE_EOC)
+                       bytes_transferred += req_transfer_count;
+       }
+       bytes_transferred *= 4;
+       return bytes_transferred;
+}
+
 int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
        struct tegra_dma_req *_req)
 {
-       unsigned int csr;
        unsigned int status;
        struct tegra_dma_req *req = NULL;
        int found = 0;
        unsigned long irq_flags;
-       int to_transfer;
-       int req_transfer_count;
+       int stop = 0;
 
        spin_lock_irqsave(&ch->lock, irq_flags);
+
+       if (list_entry(ch->list.next, struct tegra_dma_req, node) == _req)
+               stop = 1;
+
        list_for_each_entry(req, &ch->list, node) {
                if (req == _req) {
                        list_del(&req->node);
@@ -222,47 +281,12 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
                return 0;
        }
 
-       /* STOP the DMA and get the transfer count.
-        * Getting the transfer count is tricky.
-        *  - Change the source selector to invalid to stop the DMA from
-        *    FIFO to memory.
-        *  - Read the status register to know the number of pending
-        *    bytes to be transferred.
-        *  - Finally stop or program the DMA to the next buffer in the
-        *    list.
-        */
-       csr = readl(ch->addr + APB_DMA_CHAN_CSR);
-       csr &= ~CSR_REQ_SEL_MASK;
-       csr |= CSR_REQ_SEL_INVALID;
-       writel(csr, ch->addr + APB_DMA_CHAN_CSR);
-
-       /* Get the transfer count */
-       status = readl(ch->addr + APB_DMA_CHAN_STA);
-       to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT;
-       req_transfer_count = ch->req_transfer_count;
-       req_transfer_count += 1;
-       to_transfer += 1;
-
-       req->bytes_transferred = req_transfer_count;
-
-       if (status & STA_BUSY)
-               req->bytes_transferred -= to_transfer;
-
-       /* In continuous transfer mode, DMA only tracks the count of the
-        * half DMA buffer. So, if the DMA already finished half the DMA
-        * then add the half buffer to the completed count.
-        *
-        *      FIXME: There can be a race here. What if the req to
-        *      dequue happens at the same time as the DMA just moved to
-        *      the new buffer and SW didn't yet received the interrupt?
-        */
-       if (ch->mode & TEGRA_DMA_MODE_CONTINOUS)
-               if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
-                       req->bytes_transferred += req_transfer_count;
+       if (!stop)
+               goto skip_stop_dma;
 
-       req->bytes_transferred *= 4;
+       status = get_channel_status(ch, req, true);
+       req->bytes_transferred = dma_active_count(ch, req, status);
 
-       tegra_dma_stop(ch);
        if (!list_empty(&ch->list)) {
                /* if the list is not empty, queue the next request */
                struct tegra_dma_req *next_req;
@@ -270,6 +294,8 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
                        typeof(*next_req), node);
                tegra_dma_update_hw(ch, next_req);
        }
+
+skip_stop_dma:
        req->status = -TEGRA_DMA_REQ_ERROR_ABORTED;
 
        spin_unlock_irqrestore(&ch->lock, irq_flags);
@@ -357,7 +383,7 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
        int channel;
        struct tegra_dma_channel *ch = NULL;
 
-       if (WARN_ON(!tegra_dma_initialized))
+       if (!tegra_dma_initialized)
                return NULL;
 
        mutex_lock(&tegra_dma_lock);
diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c
new file mode 100644 (file)
index 0000000..fef66a7
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * arch/arm/mach-tegra/flowctrl.c
+ *
+ * functions and macros to control the flowcontroller
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ *
+ * 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 that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include <mach/iomap.h>
+
+#include "flowctrl.h"
+
+u8 flowctrl_offset_halt_cpu[] = {
+       FLOW_CTRL_HALT_CPU0_EVENTS,
+       FLOW_CTRL_HALT_CPU1_EVENTS,
+       FLOW_CTRL_HALT_CPU1_EVENTS + 8,
+       FLOW_CTRL_HALT_CPU1_EVENTS + 16,
+};
+
+u8 flowctrl_offset_cpu_csr[] = {
+       FLOW_CTRL_CPU0_CSR,
+       FLOW_CTRL_CPU1_CSR,
+       FLOW_CTRL_CPU1_CSR + 8,
+       FLOW_CTRL_CPU1_CSR + 16,
+};
+
+static void flowctrl_update(u8 offset, u32 value)
+{
+       void __iomem *addr = IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + offset;
+
+       writel(value, addr);
+
+       /* ensure the update has reached the flow controller */
+       wmb();
+       readl_relaxed(addr);
+}
+
+void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
+{
+       return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
+}
+
+void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
+{
+       return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
+}
diff --git a/arch/arm/mach-tegra/flowctrl.h b/arch/arm/mach-tegra/flowctrl.h
new file mode 100644 (file)
index 0000000..1942817
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * arch/arm/mach-tegra/flowctrl.h
+ *
+ * functions and macros to control the flowcontroller
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ *
+ * 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 that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA_FLOWCTRL_H
+#define __MACH_TEGRA_FLOWCTRL_H
+
+#define FLOW_CTRL_HALT_CPU0_EVENTS     0x0
+#define FLOW_CTRL_WAITEVENT            (2 << 29)
+#define FLOW_CTRL_WAIT_FOR_INTERRUPT   (4 << 29)
+#define FLOW_CTRL_JTAG_RESUME          (1 << 28)
+#define FLOW_CTRL_HALT_CPU_IRQ         (1 << 10)
+#define        FLOW_CTRL_HALT_CPU_FIQ          (1 << 8)
+#define FLOW_CTRL_CPU0_CSR             0x8
+#define        FLOW_CTRL_CSR_INTR_FLAG         (1 << 15)
+#define FLOW_CTRL_CSR_EVENT_FLAG       (1 << 14)
+#define FLOW_CTRL_CSR_ENABLE           (1 << 0)
+#define FLOW_CTRL_HALT_CPU1_EVENTS     0x14
+#define FLOW_CTRL_CPU1_CSR             0x18
+
+#ifndef __ASSEMBLY__
+void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value);
+void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value);
+#endif
+
+#endif
index ea49bd9..f946d12 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 #include <mach/iomap.h>
 
 #include "fuse.h"
+#include "apbio.h"
 
 #define FUSE_UID_LOW           0x108
 #define FUSE_UID_HIGH          0x10c
 #define FUSE_SKU_INFO          0x110
 #define FUSE_SPARE_BIT         0x200
 
-static inline u32 fuse_readl(unsigned long offset)
+int tegra_sku_id;
+int tegra_cpu_process_id;
+int tegra_core_process_id;
+int tegra_chip_id;
+enum tegra_revision tegra_revision;
+
+/* The BCT to use at boot is specified by board straps that can be read
+ * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
+ */
+int tegra_bct_strapping;
+
+#define STRAP_OPT 0x008
+#define GMI_AD0 (1 << 4)
+#define GMI_AD1 (1 << 5)
+#define RAM_ID_MASK (GMI_AD0 | GMI_AD1)
+#define RAM_CODE_SHIFT 4
+
+static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
+       [TEGRA_REVISION_UNKNOWN] = "unknown",
+       [TEGRA_REVISION_A01]     = "A01",
+       [TEGRA_REVISION_A02]     = "A02",
+       [TEGRA_REVISION_A03]     = "A03",
+       [TEGRA_REVISION_A03p]    = "A03 prime",
+       [TEGRA_REVISION_A04]     = "A04",
+};
+
+static inline u32 tegra_fuse_readl(unsigned long offset)
 {
-       return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+       return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
 }
 
-static inline void fuse_writel(u32 value, unsigned long offset)
+static inline bool get_spare_fuse(int bit)
 {
-       writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+       return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
+}
+
+static enum tegra_revision tegra_get_revision(u32 id)
+{
+       u32 minor_rev = (id >> 16) & 0xf;
+
+       switch (minor_rev) {
+       case 1:
+               return TEGRA_REVISION_A01;
+       case 2:
+               return TEGRA_REVISION_A02;
+       case 3:
+               if (tegra_chip_id == TEGRA20 &&
+                       (get_spare_fuse(18) || get_spare_fuse(19)))
+                       return TEGRA_REVISION_A03p;
+               else
+                       return TEGRA_REVISION_A03;
+       case 4:
+               return TEGRA_REVISION_A04;
+       default:
+               return TEGRA_REVISION_UNKNOWN;
+       }
 }
 
 void tegra_init_fuse(void)
 {
+       u32 id;
+
        u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
        reg |= 1 << 28;
        writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
 
-       pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n",
-               tegra_sku_id(), tegra_cpu_process_id(),
-               tegra_core_process_id());
+       reg = tegra_fuse_readl(FUSE_SKU_INFO);
+       tegra_sku_id = reg & 0xFF;
+
+       reg = tegra_fuse_readl(FUSE_SPARE_BIT);
+       tegra_cpu_process_id = (reg >> 6) & 3;
+
+       reg = tegra_fuse_readl(FUSE_SPARE_BIT);
+       tegra_core_process_id = (reg >> 12) & 3;
+
+       reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
+       tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
+
+       id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
+       tegra_chip_id = (id >> 8) & 0xff;
+
+       tegra_revision = tegra_get_revision(id);
+
+       pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
+               tegra_revision_name[tegra_revision],
+               tegra_sku_id, tegra_cpu_process_id,
+               tegra_core_process_id);
 }
 
 unsigned long long tegra_chip_uid(void)
 {
        unsigned long long lo, hi;
 
-       lo = fuse_readl(FUSE_UID_LOW);
-       hi = fuse_readl(FUSE_UID_HIGH);
+       lo = tegra_fuse_readl(FUSE_UID_LOW);
+       hi = tegra_fuse_readl(FUSE_UID_HIGH);
        return (hi << 32ull) | lo;
 }
 EXPORT_SYMBOL(tegra_chip_uid);
-
-int tegra_sku_id(void)
-{
-       int sku_id;
-       u32 reg = fuse_readl(FUSE_SKU_INFO);
-       sku_id = reg & 0xFF;
-       return sku_id;
-}
-
-int tegra_cpu_process_id(void)
-{
-       int cpu_process_id;
-       u32 reg = fuse_readl(FUSE_SPARE_BIT);
-       cpu_process_id = (reg >> 6) & 3;
-       return cpu_process_id;
-}
-
-int tegra_core_process_id(void)
-{
-       int core_process_id;
-       u32 reg = fuse_readl(FUSE_SPARE_BIT);
-       core_process_id = (reg >> 12) & 3;
-       return core_process_id;
-}
index 584b2e2..d2107b2 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * arch/arm/mach-tegra/fuse.c
- *
  * Copyright (C) 2010 Google, Inc.
  *
  * Author:
  *
  */
 
+#ifndef __MACH_TEGRA_FUSE_H
+#define __MACH_TEGRA_FUSE_H
+
+enum tegra_revision {
+       TEGRA_REVISION_UNKNOWN = 0,
+       TEGRA_REVISION_A01,
+       TEGRA_REVISION_A02,
+       TEGRA_REVISION_A03,
+       TEGRA_REVISION_A03p,
+       TEGRA_REVISION_A04,
+       TEGRA_REVISION_MAX,
+};
+
+#define SKU_ID_T20     8
+#define SKU_ID_T25SE   20
+#define SKU_ID_AP25    23
+#define SKU_ID_T25     24
+#define SKU_ID_AP25E   27
+#define SKU_ID_T25E    28
+
+#define TEGRA20                0x20
+#define TEGRA30                0x30
+
+extern int tegra_sku_id;
+extern int tegra_cpu_process_id;
+extern int tegra_core_process_id;
+extern int tegra_chip_id;
+extern enum tegra_revision tegra_revision;
+
+extern int tegra_bct_strapping;
+
 unsigned long long tegra_chip_uid(void);
-int tegra_sku_id(void);
-int tegra_cpu_process_id(void);
-int tegra_core_process_id(void);
 void tegra_init_fuse(void);
+
+#endif
index b5349b2..fef9c2c 100644 (file)
@@ -1,6 +1,23 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 
+#include <asm/cache.h>
+
+#include <mach/iomap.h>
+
+#include "flowctrl.h"
+#include "reset.h"
+
+#define APB_MISC_GP_HIDREV     0x804
+#define PMC_SCRATCH41  0x140
+
+#define RESET_DATA(x)  ((TEGRA_RESET_##x)*4)
+
+       .macro mov32, reg, val
+       movw    \reg, #:lower16:\val
+       movt    \reg, #:upper16:\val
+       .endm
+
         .section ".text.head", "ax"
        __CPUINIT
 
@@ -47,15 +64,149 @@ ENTRY(v7_invalidate_l1)
         mov     pc, lr
 ENDPROC(v7_invalidate_l1)
 
+
 ENTRY(tegra_secondary_startup)
-       msr     cpsr_fsxc, #0xd3
         bl      v7_invalidate_l1
-       mrc     p15, 0, r0, c0, c0, 5
-        and    r0, r0, #15
-        ldr     r1, =0x6000f100
-        str     r0, [r1]
-1:      ldr     r2, [r1]
-        cmp     r0, r2
-        beq     1b
+       /* Enable coresight */
+       mov32   r0, 0xC5ACCE55
+       mcr     p14, 0, r0, c7, c12, 6
         b       secondary_startup
 ENDPROC(tegra_secondary_startup)
+
+       .align L1_CACHE_SHIFT
+ENTRY(__tegra_cpu_reset_handler_start)
+
+/*
+ * __tegra_cpu_reset_handler:
+ *
+ * Common handler for all CPU reset events.
+ *
+ * Register usage within the reset handler:
+ *
+ *      R7  = CPU present (to the OS) mask
+ *      R8  = CPU in LP1 state mask
+ *      R9  = CPU in LP2 state mask
+ *      R10 = CPU number
+ *      R11 = CPU mask
+ *      R12 = pointer to reset handler data
+ *
+ * NOTE: This code is copied to IRAM. All code and data accesses
+ *       must be position-independent.
+ */
+
+       .align L1_CACHE_SHIFT
+ENTRY(__tegra_cpu_reset_handler)
+
+       cpsid   aif, 0x13                       @ SVC mode, interrupts disabled
+       mrc     p15, 0, r10, c0, c0, 5          @ MPIDR
+       and     r10, r10, #0x3                  @ R10 = CPU number
+       mov     r11, #1
+       mov     r11, r11, lsl r10               @ R11 = CPU mask
+       adr     r12, __tegra_cpu_reset_handler_data
+
+#ifdef CONFIG_SMP
+       /* Does the OS know about this CPU? */
+       ldr     r7, [r12, #RESET_DATA(MASK_PRESENT)]
+       tst     r7, r11                         @ if !present
+       bleq    __die                           @ CPU not present (to OS)
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+       /* Are we on Tegra20? */
+       mov32   r6, TEGRA_APB_MISC_BASE
+       ldr     r0, [r6, #APB_MISC_GP_HIDREV]
+       and     r0, r0, #0xff00
+       cmp     r0, #(0x20 << 8)
+       bne     1f
+       /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
+       mov32   r6, TEGRA_PMC_BASE
+       mov     r0, #0
+       cmp     r10, #0
+       strne   r0, [r6, #PMC_SCRATCH41]
+1:
+#endif
+
+#ifdef CONFIG_SMP
+       /*
+        * Can only be secondary boot (initial or hotplug) but CPU 0
+        * cannot be here.
+        */
+       cmp     r10, #0
+       bleq    __die                           @ CPU0 cannot be here
+       ldr     lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
+       cmp     lr, #0
+       bleq    __die                           @ no secondary startup handler
+       bx      lr
+#endif
+
+/*
+ * We don't know why the CPU reset. Just kill it.
+ * The LR register will contain the address we died at + 4.
+ */
+
+__die:
+       sub     lr, lr, #4
+       mov32   r7, TEGRA_PMC_BASE
+       str     lr, [r7, #PMC_SCRATCH41]
+
+       mov32   r7, TEGRA_CLK_RESET_BASE
+
+       /* Are we on Tegra20? */
+       mov32   r6, TEGRA_APB_MISC_BASE
+       ldr     r0, [r6, #APB_MISC_GP_HIDREV]
+       and     r0, r0, #0xff00
+       cmp     r0, #(0x20 << 8)
+       bne     1f
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+       mov32   r0, 0x1111
+       mov     r1, r0, lsl r10
+       str     r1, [r7, #0x340]                @ CLK_RST_CPU_CMPLX_SET
+#endif
+1:
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+       mov32   r6, TEGRA_FLOW_CTRL_BASE
+
+       cmp     r10, #0
+       moveq   r1, #FLOW_CTRL_HALT_CPU0_EVENTS
+       moveq   r2, #FLOW_CTRL_CPU0_CSR
+       movne   r1, r10, lsl #3
+       addne   r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
+       addne   r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
+
+       /* Clear CPU "event" and "interrupt" flags and power gate
+          it when halting but not before it is in the "WFI" state. */
+       ldr     r0, [r6, +r2]
+       orr     r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+       orr     r0, r0, #FLOW_CTRL_CSR_ENABLE
+       str     r0, [r6, +r2]
+
+       /* Unconditionally halt this CPU */
+       mov     r0, #FLOW_CTRL_WAITEVENT
+       str     r0, [r6, +r1]
+       ldr     r0, [r6, +r1]                   @ memory barrier
+
+       dsb
+       isb
+       wfi                                     @ CPU should be power gated here
+
+       /* If the CPU didn't power gate above just kill it's clock. */
+
+       mov     r0, r11, lsl #8
+       str     r0, [r7, #348]                  @ CLK_CPU_CMPLX_SET
+#endif
+
+       /* If the CPU still isn't dead, just spin here. */
+       b       .
+ENDPROC(__tegra_cpu_reset_handler)
+
+       .align L1_CACHE_SHIFT
+       .type   __tegra_cpu_reset_handler_data, %object
+       .globl  __tegra_cpu_reset_handler_data
+__tegra_cpu_reset_handler_data:
+       .rept   TEGRA_RESET_DATA_SIZE
+       .long   0
+       .endr
+       .align L1_CACHE_SHIFT
+
+ENTRY(__tegra_cpu_reset_handler_end)
index fc3ecb6..d97e403 100644 (file)
 
 struct clk;
 
+enum tegra_clk_ex_param {
+       TEGRA_CLK_VI_INP_SEL,
+       TEGRA_CLK_DTV_INVERT,
+       TEGRA_CLK_NAND_PAD_DIV2_ENB,
+       TEGRA_CLK_PLLD_CSI_OUT_ENB,
+       TEGRA_CLK_PLLD_DSI_OUT_ENB,
+       TEGRA_CLK_PLLD_MIPI_MUX_SEL,
+};
+
 void tegra_periph_reset_deassert(struct clk *c);
 void tegra_periph_reset_assert(struct clk *c);
 
 unsigned long clk_get_rate_all_locked(struct clk *c);
 void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
+int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
 
 #endif
index 619abc6..90069ab 100644 (file)
@@ -1,11 +1,17 @@
 /*
  * arch/arm/mach-tegra/include/mach/debug-macro.S
  *
- * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2010,2011 Google, Inc.
+ * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
  *
  * Author:
  *     Colin Cross <ccross@google.com>
  *     Erik Gilling <konkers@google.com>
+ *     Doug Anderson <dianders@chromium.org>
+ *     Stephen Warren <swarren@nvidia.com>
+ *
+ * Portions based on mach-omap2's debug-macro.S
+ * Copyright (C) 1994-1999 Russell King
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
  *
  */
 
+#include <linux/serial_reg.h>
+
 #include <mach/io.h>
 #include <mach/iomap.h>
+#include <mach/irammap.h>
+
+               .macro  addruart, rp, rv, tmp
+               adr     \rp, 99f                @ actual addr of 99f
+               ldr     \rv, [\rp]              @ linked addr is stored there
+               sub     \rv, \rv, \rp           @ offset between the two
+               ldr     \rp, [\rp, #4]          @ linked tegra_uart_config
+               sub     \tmp, \rp, \rv          @ actual tegra_uart_config
+               ldr     \rp, [\tmp]             @ Load tegra_uart_config
+               cmp     \rp, #1                 @ needs intitialization?
+               bne     100f                    @ no; go load the addresses
+               mov     \rv, #0                 @ yes; record init is done
+               str     \rv, [\tmp]
+               mov     \rp, #TEGRA_IRAM_BASE   @ See if cookie is in IRAM
+               ldr     \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET]
+               movw    \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE & 0xffff
+               movt    \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE >> 16
+               cmp     \rv, \rp                @ Cookie present?
+               bne     100f                    @ No, use default UART
+               mov     \rp, #TEGRA_IRAM_BASE   @ Load UART address from IRAM
+               ldr     \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET + 4]
+               str     \rv, [\tmp, #4]         @ Store in tegra_uart_phys
+               sub     \rv, \rv, #IO_APB_PHYS  @ Calculate virt address
+               add     \rv, \rv, #IO_APB_VIRT
+               str     \rv, [\tmp, #8]         @ Store in tegra_uart_virt
+               b       100f
+
+               .align
+99:            .word   .
+               .word   tegra_uart_config
+               .ltorg
+
+100:           ldr     \rp, [\tmp, #4]         @ Load tegra_uart_phys
+               ldr     \rv, [\tmp, #8]         @ Load tegra_uart_virt
+               .endm
+
+#define UART_SHIFT 2
+
+/*
+ * Code below is swiped from <asm/hardware/debug-8250.S>, but add an extra
+ * check to make sure that we aren't in the CONFIG_TEGRA_DEBUG_UART_NONE case.
+ * We use the fact that all 5 valid UART addresses all have something in the
+ * 2nd-to-lowest byte.
+ */
 
-       .macro  addruart, rp, rv, tmp
-        ldr     \rp, =IO_APB_PHYS       @ physical
-        ldr     \rv, =IO_APB_VIRT        @ virtual
-       orr     \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF)
-       orr     \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
-       orr     \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF)
-       orr     \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
-       .endm
+               .macro  senduart, rd, rx
+               tst     \rx, #0x0000ff00
+               strneb  \rd, [\rx, #UART_TX << UART_SHIFT]
+1001:
+               .endm
 
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
+               .macro  busyuart, rd, rx
+               tst     \rx, #0x0000ff00
+               beq     1002f
+1001:          ldrb    \rd, [\rx, #UART_LSR << UART_SHIFT]
+               and     \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
+               teq     \rd, #UART_LSR_TEMT | UART_LSR_THRE
+               bne     1001b
+1002:
+               .endm
 
+               .macro  waituart, rd, rx
+#ifdef FLOW_CONTROL
+               tst     \rx, #0x0000ff00
+               beq     1002f
+1001:          ldrb    \rd, [\rx, #UART_MSR << UART_SHIFT]
+               tst     \rd, #UART_MSR_CTS
+               beq     1001b
+1002:
+#endif
+               .endm
diff --git a/arch/arm/mach-tegra/include/mach/entry-macro.S b/arch/arm/mach-tegra/include/mach/entry-macro.S
deleted file mode 100644 (file)
index e577cfe..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* arch/arm/mach-tegra/include/mach/entry-macro.S
- *
- * Copyright (C) 2009 Palm, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
index 87d37fd..6140820 100644 (file)
@@ -25,8 +25,6 @@
 
 #define TEGRA_NR_GPIOS         INT_GPIO_NR
 
-#define TEGRA_GPIO_TO_IRQ(gpio) (INT_GPIO_BASE + (gpio))
-
 struct tegra_gpio_table {
        int     gpio;   /* GPIO number */
        bool    enable; /* Enable for GPIO at init? */
index 19dec3a..cff672a 100644 (file)
@@ -74,6 +74,9 @@
 #define TEGRA_QUATERNARY_ICTLR_BASE    0x60004300
 #define TEGRA_QUATERNARY_ICTLR_SIZE    SZ_64
 
+#define TEGRA_QUINARY_ICTLR_BASE       0x60004400
+#define TEGRA_QUINARY_ICTLR_SIZE       SZ_64
+
 #define TEGRA_TMR1_BASE                        0x60005000
 #define TEGRA_TMR1_SIZE                        SZ_8
 
 #define TEGRA_AHB_GIZMO_BASE           0x6000C004
 #define TEGRA_AHB_GIZMO_SIZE           0x10C
 
+#define TEGRA_SB_BASE                  0x6000C200
+#define TEGRA_SB_SIZE                  256
+
 #define TEGRA_STATMON_BASE             0x6000C400
 #define TEGRA_STATMON_SIZE             SZ_1K
 
diff --git a/arch/arm/mach-tegra/include/mach/irammap.h b/arch/arm/mach-tegra/include/mach/irammap.h
new file mode 100644 (file)
index 0000000..0cbe632
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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/>.
+ */
+
+#ifndef __MACH_TEGRA_IRAMMAP_H
+#define __MACH_TEGRA_IRAMMAP_H
+
+#include <asm/sizes.h>
+
+/* The first 1K of IRAM is permanently reserved for the CPU reset handler */
+#define TEGRA_IRAM_RESET_HANDLER_OFFSET        0
+#define TEGRA_IRAM_RESET_HANDLER_SIZE  SZ_1K
+
+/*
+ * These locations are written to by uncompress.h, and read by debug-macro.S.
+ * The first word holds the cookie value if the data is valid. The second
+ * word holds the UART physical address.
+ */
+#define TEGRA_IRAM_DEBUG_UART_OFFSET   SZ_1K
+#define TEGRA_IRAM_DEBUG_UART_SIZE     8
+#define TEGRA_IRAM_DEBUG_UART_COOKIE   0x55415254
+
+#endif
index a2146cd..aad1a2c 100644 (file)
 #define INT_QUAD_RES_30                        (INT_QUAD_BASE + 30)
 #define INT_QUAD_RES_31                        (INT_QUAD_BASE + 31)
 
-#define INT_MAIN_NR                    (INT_QUAD_BASE + 32 - INT_PRI_BASE)
-
+/* Tegra30 has 5 banks of 32 IRQs */
+#define INT_MAIN_NR                    (32 * 5)
 #define INT_GPIO_BASE                  (INT_PRI_BASE + INT_MAIN_NR)
 
-#define INT_GPIO_NR                    (28 * 8)
+/* Tegra30 has 8 banks of 32 GPIOs */
+#define INT_GPIO_NR                    (32 * 8)
 
 #define TEGRA_NR_IRQS                  (INT_GPIO_BASE + INT_GPIO_NR)
 
index 39c396d..4752b1a 100644 (file)
 #define TEGRA_POWERGATE_VDEC   4
 #define TEGRA_POWERGATE_L2     5
 #define TEGRA_POWERGATE_MPE    6
-#define TEGRA_NUM_POWERGATE    7
+#define TEGRA_POWERGATE_HEG    7
+#define TEGRA_POWERGATE_SATA   8
+#define TEGRA_POWERGATE_CPU1   9
+#define TEGRA_POWERGATE_CPU2   10
+#define TEGRA_POWERGATE_CPU3   11
+#define TEGRA_POWERGATE_CELP   12
+#define TEGRA_POWERGATE_3D1    13
 
+#define TEGRA_POWERGATE_CPU0   TEGRA_POWERGATE_CPU
+#define TEGRA_POWERGATE_3D0    TEGRA_POWERGATE_3D
+
+int  __init tegra_powergate_init(void);
+
+int tegra_cpu_powergate_id(int cpuid);
+int tegra_powergate_is_powered(int id);
 int tegra_powergate_power_on(int id);
 int tegra_powergate_power_off(int id);
 int tegra_powergate_remove_clamping(int id);
diff --git a/arch/arm/mach-tegra/include/mach/smmu.h b/arch/arm/mach-tegra/include/mach/smmu.h
new file mode 100644 (file)
index 0000000..dad403a
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * IOMMU API for SMMU in Tegra30
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef        MACH_SMMU_H
+#define        MACH_SMMU_H
+
+enum smmu_hwgrp {
+       HWGRP_AFI,
+       HWGRP_AVPC,
+       HWGRP_DC,
+       HWGRP_DCB,
+       HWGRP_EPP,
+       HWGRP_G2,
+       HWGRP_HC,
+       HWGRP_HDA,
+       HWGRP_ISP,
+       HWGRP_MPE,
+       HWGRP_NV,
+       HWGRP_NV2,
+       HWGRP_PPCS,
+       HWGRP_SATA,
+       HWGRP_VDE,
+       HWGRP_VI,
+
+       HWGRP_COUNT,
+
+       HWGRP_END = ~0,
+};
+
+#define HWG_AFI                (1 << HWGRP_AFI)
+#define HWG_AVPC       (1 << HWGRP_AVPC)
+#define HWG_DC         (1 << HWGRP_DC)
+#define HWG_DCB                (1 << HWGRP_DCB)
+#define HWG_EPP                (1 << HWGRP_EPP)
+#define HWG_G2         (1 << HWGRP_G2)
+#define HWG_HC         (1 << HWGRP_HC)
+#define HWG_HDA                (1 << HWGRP_HDA)
+#define HWG_ISP                (1 << HWGRP_ISP)
+#define HWG_MPE                (1 << HWGRP_MPE)
+#define HWG_NV         (1 << HWGRP_NV)
+#define HWG_NV2                (1 << HWGRP_NV2)
+#define HWG_PPCS       (1 << HWGRP_PPCS)
+#define HWG_SATA       (1 << HWGRP_SATA)
+#define HWG_VDE                (1 << HWGRP_VDE)
+#define HWG_VI         (1 << HWGRP_VI)
+
+#endif /* MACH_SMMU_H */
diff --git a/arch/arm/mach-tegra/include/mach/system.h b/arch/arm/mach-tegra/include/mach/system.h
deleted file mode 100644 (file)
index a312988..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/system.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *     Colin Cross <ccross@google.com>
- *     Erik Gilling <konkers@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __MACH_TEGRA_SYSTEM_H
-#define __MACH_TEGRA_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-}
-
-#endif
index 4e83237..5a440f3 100644 (file)
@@ -2,10 +2,14 @@
  * arch/arm/mach-tegra/include/mach/uncompress.h
  *
  * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
  *
  * Author:
  *     Colin Cross <ccross@google.com>
  *     Erik Gilling <konkers@google.com>
+ *     Doug Anderson <dianders@chromium.org>
+ *     Stephen Warren <swarren@nvidia.com>
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
 #include <linux/serial_reg.h>
 
 #include <mach/iomap.h>
+#include <mach/irammap.h>
+
+#define BIT(x) (1 << (x))
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define DEBUG_UART_SHIFT 2
+
+volatile u8 *uart;
 
 static void putc(int c)
 {
-       volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
-       int shift = 2;
-
        if (uart == NULL)
                return;
 
-       while (!(uart[UART_LSR << shift] & UART_LSR_THRE))
+       while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE))
                barrier();
-       uart[UART_TX << shift] = c;
+       uart[UART_TX << DEBUG_UART_SHIFT] = c;
 }
 
 static inline void flush(void)
 {
 }
 
+static inline void save_uart_address(void)
+{
+       u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET);
+
+       if (uart) {
+               buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE;
+               buf[1] = (u32)uart;
+       } else
+               buf[0] = 0;
+}
+
+/*
+ * Setup before decompression.  This is where we do UART selection for
+ * earlyprintk and init the uart_base register.
+ */
 static inline void arch_decomp_setup(void)
 {
-       volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
-       int shift = 2;
+       static const struct {
+               u32 base;
+               u32 reset_reg;
+               u32 clock_reg;
+               u32 bit;
+       } uarts[] = {
+               {
+                       TEGRA_UARTA_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x04,
+                       TEGRA_CLK_RESET_BASE + 0x10,
+                       6,
+               },
+               {
+                       TEGRA_UARTB_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x04,
+                       TEGRA_CLK_RESET_BASE + 0x10,
+                       7,
+               },
+               {
+                       TEGRA_UARTC_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x08,
+                       TEGRA_CLK_RESET_BASE + 0x14,
+                       23,
+               },
+               {
+                       TEGRA_UARTD_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x0c,
+                       TEGRA_CLK_RESET_BASE + 0x18,
+                       1,
+               },
+               {
+                       TEGRA_UARTE_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x0c,
+                       TEGRA_CLK_RESET_BASE + 0x18,
+                       2,
+               },
+       };
+       int i;
+       volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
+       u32 chip, div;
+
+       /*
+        * Look for the first UART that:
+        * a) Is not in reset.
+        * b) Is clocked.
+        * c) Has a 'D' in the scratchpad register.
+        *
+        * Note that on Tegra30, the first two conditions are required, since
+        * if not true, accesses to the UART scratch register will hang.
+        * Tegra20 doesn't have this issue.
+        *
+        * The intent is that the bootloader will tell the kernel which UART
+        * to use by setting up those conditions. If nothing found, we'll fall
+        * back to what's specified in TEGRA_DEBUG_UART_BASE.
+        */
+       for (i = 0; i < ARRAY_SIZE(uarts); i++) {
+               if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
+                       continue;
 
+               if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
+                       continue;
+
+               uart = (volatile u8 *)uarts[i].base;
+               if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D')
+                       continue;
+
+               break;
+       }
+       if (i == ARRAY_SIZE(uarts))
+               uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
+       save_uart_address();
        if (uart == NULL)
                return;
 
-       uart[UART_LCR << shift] |= UART_LCR_DLAB;
-       uart[UART_DLL << shift] = 0x75;
-       uart[UART_DLM << shift] = 0x0;
-       uart[UART_LCR << shift] = 3;
+       chip = (apb_misc[0x804 / 4] >> 8) & 0xff;
+       if (chip == 0x20)
+               div = 0x0075;
+       else
+               div = 0x00dd;
+
+       uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB;
+       uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff;
+       uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8;
+       uart[UART_LCR << DEBUG_UART_SHIFT] = 3;
 }
 
 static inline void arch_decomp_wdog(void)
index 4e1afcd..2f5bd2d 100644 (file)
 #define ICTLR_COP_IER_CLR      0x38
 #define ICTLR_COP_IEP_CLASS    0x3c
 
-#define NUM_ICTLRS 4
 #define FIRST_LEGACY_IRQ 32
 
+static int num_ictlrs;
+
 static void __iomem *ictlr_reg_base[] = {
        IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
        IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
        IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
        IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
+       IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
 };
 
 static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
@@ -60,7 +62,7 @@ static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
        u32 mask;
 
        BUG_ON(irq < FIRST_LEGACY_IRQ ||
-               irq >= FIRST_LEGACY_IRQ + NUM_ICTLRS * 32);
+               irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32);
 
        base = ictlr_reg_base[(irq - FIRST_LEGACY_IRQ) / 32];
        mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
@@ -113,8 +115,18 @@ static int tegra_retrigger(struct irq_data *d)
 void __init tegra_init_irq(void)
 {
        int i;
+       void __iomem *distbase;
+
+       distbase = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE);
+       num_ictlrs = readl_relaxed(distbase + GIC_DIST_CTR) & 0x1f;
+
+       if (num_ictlrs > ARRAY_SIZE(ictlr_reg_base)) {
+               WARN(1, "Too many (%d) interrupt controllers found. Maximum is %d.",
+                       num_ictlrs, ARRAY_SIZE(ictlr_reg_base));
+               num_ictlrs = ARRAY_SIZE(ictlr_reg_base);
+       }
 
-       for (i = 0; i < NUM_ICTLRS; i++) {
+       for (i = 0; i < num_ictlrs; i++) {
                void __iomem *ictlr = ictlr_reg_base[i];
                writel(~0, ictlr + ICTLR_CPU_IER_CLR);
                writel(0, ictlr + ICTLR_CPU_IEP_CLASS);
@@ -131,6 +143,6 @@ void __init tegra_init_irq(void)
         * initialized elsewhere under DT.
         */
        if (!of_have_populated_dt())
-               gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
+               gic_init(0, 29, distbase,
                        IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
 }
diff --git a/arch/arm/mach-tegra/localtimer.c b/arch/arm/mach-tegra/localtimer.c
deleted file mode 100644 (file)
index e91d681..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  arch/arm/mach-tegra/localtimer.c
- *
- *  Copyright (C) 2002 ARM Ltd.
- *  All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-#include <asm/irq.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       evt->irq = IRQ_LOCALTIMER;
-       twd_timer_setup(evt);
-       return 0;
-}
index af8b634..54a816f 100644 (file)
@@ -408,7 +408,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        pp->res[0].flags = IORESOURCE_IO;
        if (request_resource(&ioport_resource, &pp->res[0]))
                panic("Request PCIe IO resource failed\n");
-       pci_add_resource(&sys->resources, &pp->res[0]);
+       pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
 
        /*
         * IORESOURCE_MEM
@@ -427,7 +427,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        pp->res[1].flags = IORESOURCE_MEM;
        if (request_resource(&iomem_resource, &pp->res[1]))
                panic("Request PCIe Memory resource failed\n");
-       pci_add_resource(&sys->resources, &pp->res[1]);
+       pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
        /*
         * IORESOURCE_MEM | IORESOURCE_PREFETCH
@@ -446,7 +446,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
        if (request_resource(&iomem_resource, &pp->res[2]))
                panic("Request PCIe Prefetch Memory resource failed\n");
-       pci_add_resource(&sys->resources, &pp->res[2]);
+       pci_add_resource_offset(&sys->resources, &pp->res[2], sys->mem_offset);
 
        return 1;
 }
@@ -585,10 +585,10 @@ static void tegra_pcie_setup_translations(void)
        afi_writel(0, AFI_MSI_BAR_SZ);
 }
 
-static void tegra_pcie_enable_controller(void)
+static int tegra_pcie_enable_controller(void)
 {
        u32 val, reg;
-       int i;
+       int i, timeout;
 
        /* Enable slot clock and pulse the reset signals */
        for (i = 0, reg = AFI_PEX0_CTRL; i < 2; i++, reg += 0x8) {
@@ -639,8 +639,14 @@ static void tegra_pcie_enable_controller(void)
        pads_writel(0xfa5cfa5c, 0xc8);
 
        /* Wait for the PLL to lock */
+       timeout = 300;
        do {
                val = pads_readl(PADS_PLL_CTL);
+               usleep_range(1000, 1000);
+               if (--timeout == 0) {
+                       pr_err("Tegra PCIe error: timeout waiting for PLL\n");
+                       return -EBUSY;
+               }
        } while (!(val & PADS_PLL_CTL_LOCKDET));
 
        /* turn off IDDQ override */
@@ -671,7 +677,7 @@ static void tegra_pcie_enable_controller(void)
        /* Disable all execptions */
        afi_writel(0, AFI_FPCI_ERROR_MASKS);
 
-       return;
+       return 0;
 }
 
 static void tegra_pcie_xclk_clamp(bool clamp)
@@ -921,7 +927,9 @@ int __init tegra_pcie_init(bool init_port0, bool init_port1)
        if (err)
                return err;
 
-       tegra_pcie_enable_controller();
+       err = tegra_pcie_enable_controller();
+       if (err)
+               return err;
 
        /* setup the AFI address translations */
        tegra_pcie_setup_translations();
index 7d2b5d0..1a208db 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/smp_scu.h>
 
+#include <mach/clk.h>
 #include <mach/iomap.h>
+#include <mach/powergate.h>
+
+#include "fuse.h"
+#include "flowctrl.h"
+#include "reset.h"
 
 extern void tegra_secondary_startup(void);
 
-static DEFINE_SPINLOCK(boot_lock);
 static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
 
 #define EVP_CPU_RESET_VECTOR \
        (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
 #define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \
        (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c)
+#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
 #define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
        (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
+#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x34c)
+
+#define CPU_CLOCK(cpu) (0x1<<(8+cpu))
+#define CPU_RESET(cpu) (0x1111ul<<(cpu))
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
@@ -47,63 +59,106 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
         */
        gic_secondary_init(0);
 
-       /*
-        * Synchronise with the boot thread.
-        */
-       spin_lock(&boot_lock);
-       spin_unlock(&boot_lock);
 }
 
-int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+static int tegra20_power_up_cpu(unsigned int cpu)
 {
-       unsigned long old_boot_vector;
-       unsigned long boot_vector;
-       unsigned long timeout;
        u32 reg;
 
-       /*
-        * set synchronisation state between this boot processor
-        * and the secondary one
-        */
-       spin_lock(&boot_lock);
+       /* Enable the CPU clock. */
+       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+       writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+       barrier();
+       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
 
+       /* Clear flow controller CSR. */
+       flowctrl_write_cpu_csr(cpu, 0);
 
-       /* set the reset vector to point to the secondary_startup routine */
+       return 0;
+}
 
-       boot_vector = virt_to_phys(tegra_secondary_startup);
-       old_boot_vector = readl(EVP_CPU_RESET_VECTOR);
-       writel(boot_vector, EVP_CPU_RESET_VECTOR);
+static int tegra30_power_up_cpu(unsigned int cpu)
+{
+       u32 reg;
+       int ret, pwrgateid;
+       unsigned long timeout;
 
-       /* enable cpu clock on cpu1 */
-       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-       writel(reg & ~(1<<9), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+       pwrgateid = tegra_cpu_powergate_id(cpu);
+       if (pwrgateid < 0)
+               return pwrgateid;
+
+       /* If this is the first boot, toggle powergates directly. */
+       if (!tegra_powergate_is_powered(pwrgateid)) {
+               ret = tegra_powergate_power_on(pwrgateid);
+               if (ret)
+                       return ret;
+
+               /* Wait for the power to come up. */
+               timeout = jiffies + 10*HZ;
+               while (tegra_powergate_is_powered(pwrgateid)) {
+                       if (time_after(jiffies, timeout))
+                               return -ETIMEDOUT;
+                       udelay(10);
+               }
+       }
 
-       reg = (1<<13) | (1<<9) | (1<<5) | (1<<1);
-       writel(reg, CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+       /* CPU partition is powered. Enable the CPU clock. */
+       writel(CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+       udelay(10);
 
-       smp_wmb();
-       flush_cache_all();
+       /* Remove I/O clamps. */
+       ret = tegra_powergate_remove_clamping(pwrgateid);
+       udelay(10);
 
-       /* unhalt the cpu */
-       writel(0, IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x14);
+       /* Clear flow controller CSR. */
+       flowctrl_write_cpu_csr(cpu, 0);
 
-       timeout = jiffies + (1 * HZ);
-       while (time_before(jiffies, timeout)) {
-               if (readl(EVP_CPU_RESET_VECTOR) != boot_vector)
-                       break;
-               udelay(10);
-       }
+       return 0;
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+       int status;
 
-       /* put the old boot vector back */
-       writel(old_boot_vector, EVP_CPU_RESET_VECTOR);
+       /*
+        * Force the CPU into reset. The CPU must remain in reset when the
+        * flow controller state is cleared (which will cause the flow
+        * controller to stop driving reset if the CPU has been power-gated
+        * via the flow controller). This will have no effect on first boot
+        * of the CPU since it should already be in reset.
+        */
+       writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+       dmb();
 
        /*
-        * now the secondary core is starting up let it run its
-        * calibrations, then wait for it to finish
+        * Unhalt the CPU. If the flow controller was used to power-gate the
+        * CPU this will cause the flow controller to stop driving reset.
+        * The CPU will remain in reset because the clock and reset block
+        * is now driving reset.
         */
-       spin_unlock(&boot_lock);
+       flowctrl_write_cpu_halt(cpu, 0);
+
+       switch (tegra_chip_id) {
+       case TEGRA20:
+               status = tegra20_power_up_cpu(cpu);
+               break;
+       case TEGRA30:
+               status = tegra30_power_up_cpu(cpu);
+               break;
+       default:
+               status = -EINVAL;
+               break;
+       }
 
-       return 0;
+       if (status)
+               goto done;
+
+       /* Take the CPU out of reset. */
+       writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+       wmb();
+done:
+       return status;
 }
 
 /*
@@ -128,6 +183,6 @@ void __init smp_init_cpus(void)
 
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
 {
-
+       tegra_cpu_reset_handler_init();
        scu_enable(scu_base);
 }
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
new file mode 100644 (file)
index 0000000..7af6a54
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <mach/iomap.h>
+
+#define PMC_CTRL               0x0
+#define PMC_CTRL_INTR_LOW      (1 << 17)
+
+static inline u32 tegra_pmc_readl(u32 reg)
+{
+       return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg));
+}
+
+static inline void tegra_pmc_writel(u32 val, u32 reg)
+{
+       writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg));
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id matches[] __initconst = {
+       { .compatible = "nvidia,tegra20-pmc" },
+       { }
+};
+#endif
+
+void __init tegra_pmc_init(void)
+{
+       /*
+        * For now, Harmony is the only board that uses the PMC, and it wants
+        * the signal inverted. Seaboard would too if it used the PMC.
+        * Hopefully by the time other boards want to use the PMC, everything
+        * will be device-tree, or they also want it inverted.
+        */
+       bool invert_interrupt = true;
+       u32 val;
+
+#ifdef CONFIG_OF
+       if (of_have_populated_dt()) {
+               struct device_node *np;
+
+               invert_interrupt = false;
+
+               np = of_find_matching_node(NULL, matches);
+               if (np) {
+                       if (of_find_property(np, "nvidia,invert-interrupt",
+                                               NULL))
+                               invert_interrupt = true;
+               }
+       }
+#endif
+
+       val = tegra_pmc_readl(PMC_CTRL);
+       if (invert_interrupt)
+               val |= PMC_CTRL_INTR_LOW;
+       else
+               val &= ~PMC_CTRL_INTR_LOW;
+       tegra_pmc_writel(val, PMC_CTRL);
+}
diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h
new file mode 100644 (file)
index 0000000..8995ee4
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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/>.
+ *
+ */
+
+#ifndef __MACH_TEGRA_PMC_H
+#define __MACH_TEGRA_PMC_H
+
+void tegra_pmc_init(void);
+
+#endif
index 9483064..c238699 100644 (file)
@@ -31,6 +31,8 @@
 #include <mach/iomap.h>
 #include <mach/powergate.h>
 
+#include "fuse.h"
+
 #define PWRGATE_TOGGLE         0x30
 #define  PWRGATE_TOGGLE_START  (1 << 8)
 
 
 #define PWRGATE_STATUS         0x38
 
+static int tegra_num_powerdomains;
+static int tegra_num_cpu_domains;
+static u8 *tegra_cpu_domains;
+static u8 tegra30_cpu_domains[] = {
+       TEGRA_POWERGATE_CPU0,
+       TEGRA_POWERGATE_CPU1,
+       TEGRA_POWERGATE_CPU2,
+       TEGRA_POWERGATE_CPU3,
+};
+
 static DEFINE_SPINLOCK(tegra_powergate_lock);
 
 static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
@@ -75,7 +87,7 @@ static int tegra_powergate_set(int id, bool new_state)
 
 int tegra_powergate_power_on(int id)
 {
-       if (id < 0 || id >= TEGRA_NUM_POWERGATE)
+       if (id < 0 || id >= tegra_num_powerdomains)
                return -EINVAL;
 
        return tegra_powergate_set(id, true);
@@ -83,17 +95,18 @@ int tegra_powergate_power_on(int id)
 
 int tegra_powergate_power_off(int id)
 {
-       if (id < 0 || id >= TEGRA_NUM_POWERGATE)
+       if (id < 0 || id >= tegra_num_powerdomains)
                return -EINVAL;
 
        return tegra_powergate_set(id, false);
 }
 
-static bool tegra_powergate_is_powered(int id)
+int tegra_powergate_is_powered(int id)
 {
        u32 status;
 
-       WARN_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
+       if (id < 0 || id >= tegra_num_powerdomains)
+               return -EINVAL;
 
        status = pmc_read(PWRGATE_STATUS) & (1 << id);
        return !!status;
@@ -103,7 +116,7 @@ int tegra_powergate_remove_clamping(int id)
 {
        u32 mask;
 
-       if (id < 0 || id >= TEGRA_NUM_POWERGATE)
+       if (id < 0 || id >= tegra_num_powerdomains)
                return -EINVAL;
 
        /*
@@ -156,6 +169,34 @@ err_power:
        return ret;
 }
 
+int tegra_cpu_powergate_id(int cpuid)
+{
+       if (cpuid > 0 && cpuid < tegra_num_cpu_domains)
+               return tegra_cpu_domains[cpuid];
+
+       return -EINVAL;
+}
+
+int __init tegra_powergate_init(void)
+{
+       switch (tegra_chip_id) {
+       case TEGRA20:
+               tegra_num_powerdomains = 7;
+               break;
+       case TEGRA30:
+               tegra_num_powerdomains = 14;
+               tegra_num_cpu_domains = 4;
+               tegra_cpu_domains = tegra30_cpu_domains;
+               break;
+       default:
+               /* Unknown Tegra variant. Disable powergating */
+               tegra_num_powerdomains = 0;
+               break;
+       }
+
+       return 0;
+}
+
 #ifdef CONFIG_DEBUG_FS
 
 static const char * const powergate_name[] = {
@@ -175,7 +216,7 @@ static int powergate_show(struct seq_file *s, void *data)
        seq_printf(s, " powergate powered\n");
        seq_printf(s, "------------------\n");
 
-       for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
+       for (i = 0; i < tegra_num_powerdomains; i++)
                seq_printf(s, " %9s %7s\n", powergate_name[i],
                        tegra_powergate_is_powered(i) ? "yes" : "no");
        return 0;
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
new file mode 100644 (file)
index 0000000..4d6a2ee
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/mach-tegra/reset.c
+ *
+ * Copyright (C) 2011,2012 NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/init.h>
+#include <linux/io.h>
+#include <linux/cpumask.h>
+#include <linux/bitops.h>
+
+#include <asm/cacheflush.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include <mach/iomap.h>
+#include <mach/irammap.h>
+
+#include "reset.h"
+#include "fuse.h"
+
+#define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \
+                               TEGRA_IRAM_RESET_HANDLER_OFFSET)
+
+static bool is_enabled;
+
+static void tegra_cpu_reset_handler_enable(void)
+{
+       void __iomem *iram_base = IO_ADDRESS(TEGRA_IRAM_RESET_BASE);
+       void __iomem *evp_cpu_reset =
+               IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE + 0x100);
+       void __iomem *sb_ctrl = IO_ADDRESS(TEGRA_SB_BASE);
+       u32 reg;
+
+       BUG_ON(is_enabled);
+       BUG_ON(tegra_cpu_reset_handler_size > TEGRA_IRAM_RESET_HANDLER_SIZE);
+
+       memcpy(iram_base, (void *)__tegra_cpu_reset_handler_start,
+                       tegra_cpu_reset_handler_size);
+
+       /*
+        * NOTE: This must be the one and only write to the EVP CPU reset
+        *       vector in the entire system.
+        */
+       writel(TEGRA_IRAM_RESET_BASE + tegra_cpu_reset_handler_offset,
+                       evp_cpu_reset);
+       wmb();
+       reg = readl(evp_cpu_reset);
+
+       /*
+        * Prevent further modifications to the physical reset vector.
+        *  NOTE: Has no effect on chips prior to Tegra30.
+        */
+       if (tegra_chip_id != TEGRA20) {
+               reg = readl(sb_ctrl);
+               reg |= 2;
+               writel(reg, sb_ctrl);
+               wmb();
+       }
+
+       is_enabled = true;
+}
+
+void __init tegra_cpu_reset_handler_init(void)
+{
+
+#ifdef CONFIG_SMP
+       __tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
+               *((u32 *)cpu_present_mask);
+       __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] =
+               virt_to_phys((void *)tegra_secondary_startup);
+#endif
+
+       tegra_cpu_reset_handler_enable();
+}
diff --git a/arch/arm/mach-tegra/reset.h b/arch/arm/mach-tegra/reset.h
new file mode 100644 (file)
index 0000000..de88bf8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * arch/arm/mach-tegra/reset.h
+ *
+ * CPU reset dispatcher.
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_RESET_H
+#define __MACH_TEGRA_RESET_H
+
+#define TEGRA_RESET_MASK_PRESENT       0
+#define TEGRA_RESET_MASK_LP1           1
+#define TEGRA_RESET_MASK_LP2           2
+#define TEGRA_RESET_STARTUP_SECONDARY  3
+#define TEGRA_RESET_STARTUP_LP2                4
+#define TEGRA_RESET_STARTUP_LP1                5
+#define TEGRA_RESET_DATA_SIZE          6
+
+#ifndef __ASSEMBLY__
+
+extern unsigned long __tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE];
+
+void __tegra_cpu_reset_handler_start(void);
+void __tegra_cpu_reset_handler(void);
+void __tegra_cpu_reset_handler_end(void);
+void tegra_secondary_startup(void);
+
+#define tegra_cpu_reset_handler_offset \
+               ((u32)__tegra_cpu_reset_handler - \
+                (u32)__tegra_cpu_reset_handler_start)
+
+#define tegra_cpu_reset_handler_size \
+               (__tegra_cpu_reset_handler_end - \
+                __tegra_cpu_reset_handler_start)
+
+void __init tegra_cpu_reset_handler_init(void);
+
+#endif
+#endif
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
new file mode 100644 (file)
index 0000000..8f9fde1
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/mach-tegra/sleep.S
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ * Copyright (c) 2011, Google, Inc.
+ *
+ * Author: Colin Cross <ccross@android.com>
+ *         Gary King <gking@nvidia.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 <linux/linkage.h>
+#include <mach/io.h>
+#include <mach/iomap.h>
+
+#include "flowctrl.h"
+
+#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
+                                       + IO_PPSB_VIRT)
+
+/* returns the offset of the flow controller halt register for a cpu */
+.macro cpu_to_halt_reg rd, rcpu
+       cmp     \rcpu, #0
+       subne   \rd, \rcpu, #1
+       movne   \rd, \rd, lsl #3
+       addne   \rd, \rd, #0x14
+       moveq   \rd, #0
+.endm
+
+/* returns the offset of the flow controller csr register for a cpu */
+.macro cpu_to_csr_reg rd, rcpu
+       cmp     \rcpu, #0
+       subne   \rd, \rcpu, #1
+       movne   \rd, \rd, lsl #3
+       addne   \rd, \rd, #0x18
+       moveq   \rd, #8
+.endm
+
+/* returns the ID of the current processor */
+.macro cpu_id, rd
+       mrc     p15, 0, \rd, c0, c0, 5
+       and     \rd, \rd, #0xF
+.endm
+
+/* loads a 32-bit value into a register without a data access */
+.macro mov32, reg, val
+       movw    \reg, #:lower16:\val
+       movt    \reg, #:upper16:\val
+.endm
+
+/*
+ * tegra_cpu_wfi
+ *
+ * puts current CPU in clock-gated wfi using the flow controller
+ *
+ * corrupts r0-r3
+ * must be called with MMU on
+ */
+
+ENTRY(tegra_cpu_wfi)
+       cpu_id  r0
+       cpu_to_halt_reg r1, r0
+       cpu_to_csr_reg r2, r0
+       mov32   r0, TEGRA_FLOW_CTRL_VIRT
+       mov     r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+       str     r3, [r0, r2]    @ clear event & interrupt status
+       mov     r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT | FLOW_CTRL_JTAG_RESUME
+       str     r3, [r0, r1]    @ put flow controller in wait irq mode
+       dsb
+       wfi
+       mov     r3, #0
+       str     r3, [r0, r1]    @ clear flow controller halt status
+       mov     r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+       str     r3, [r0, r2]    @ clear event & interrupt status
+       dsb
+       mov     pc, lr
+ENDPROC(tegra_cpu_wfi)
+
index ff9e6b6..592a4ee 100644 (file)
@@ -720,7 +720,7 @@ static void tegra2_pllx_clk_init(struct clk *c)
 {
        tegra2_pll_clk_init(c);
 
-       if (tegra_sku_id() == 7)
+       if (tegra_sku_id == 7)
                c->max_rate = 750000000;
 }
 
@@ -1143,15 +1143,35 @@ static void tegra2_emc_clk_init(struct clk *c)
 
 static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
 {
-       long new_rate = rate;
+       long emc_rate;
+       long clk_rate;
 
-       new_rate = tegra_emc_round_rate(new_rate);
-       if (new_rate < 0)
+       /*
+        * The slowest entry in the EMC clock table that is at least as
+        * fast as rate.
+        */
+       emc_rate = tegra_emc_round_rate(rate);
+       if (emc_rate < 0)
                return c->max_rate;
 
-       BUG_ON(new_rate != tegra2_periph_clk_round_rate(c, new_rate));
+       /*
+        * The fastest rate the PLL will generate that is at most the
+        * requested rate.
+        */
+       clk_rate = tegra2_periph_clk_round_rate(c, emc_rate);
+
+       /*
+        * If this fails, and emc_rate > clk_rate, it's because the maximum
+        * rate in the EMC tables is larger than the maximum rate of the EMC
+        * clock. The EMC clock's max rate is the rate it was running when the
+        * kernel booted. Such a mismatch is probably due to using the wrong
+        * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
+        */
+       WARN_ONCE(emc_rate != clk_rate,
+               "emc_rate %ld != clk_rate %ld",
+               emc_rate, clk_rate);
 
-       return new_rate;
+       return emc_rate;
 }
 
 static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
index 0f7ae6e..5070d83 100644 (file)
  */
 
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/tegra_emc.h>
 
 #include <mach/iomap.h>
 
 #include "tegra2_emc.h"
+#include "fuse.h"
 
 #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
 static bool emc_enable = true;
@@ -32,18 +37,17 @@ static bool emc_enable;
 #endif
 module_param(emc_enable, bool, 0644);
 
-static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE);
-static const struct tegra_emc_table *tegra_emc_table;
-static int tegra_emc_table_size;
+static struct platform_device *emc_pdev;
+static void __iomem *emc_regbase;
 
 static inline void emc_writel(u32 val, unsigned long addr)
 {
-       writel(val, emc + addr);
+       writel(val, emc_regbase + addr);
 }
 
 static inline u32 emc_readl(unsigned long addr)
 {
-       return readl(emc + addr);
+       return readl(emc_regbase + addr);
 }
 
 static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
@@ -98,15 +102,15 @@ static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
 /* Select the closest EMC rate that is higher than the requested rate */
 long tegra_emc_round_rate(unsigned long rate)
 {
+       struct tegra_emc_pdata *pdata;
        int i;
        int best = -1;
        unsigned long distance = ULONG_MAX;
 
-       if (!tegra_emc_table)
+       if (!emc_pdev)
                return -EINVAL;
 
-       if (!emc_enable)
-               return -EINVAL;
+       pdata = emc_pdev->dev.platform_data;
 
        pr_debug("%s: %lu\n", __func__, rate);
 
@@ -116,10 +120,10 @@ long tegra_emc_round_rate(unsigned long rate)
         */
        rate = rate / 2 / 1000;
 
-       for (i = 0; i < tegra_emc_table_size; i++) {
-               if (tegra_emc_table[i].rate >= rate &&
-                   (tegra_emc_table[i].rate - rate) < distance) {
-                       distance = tegra_emc_table[i].rate - rate;
+       for (i = 0; i < pdata->num_tables; i++) {
+               if (pdata->tables[i].rate >= rate &&
+                   (pdata->tables[i].rate - rate) < distance) {
+                       distance = pdata->tables[i].rate - rate;
                        best = i;
                }
        }
@@ -127,9 +131,9 @@ long tegra_emc_round_rate(unsigned long rate)
        if (best < 0)
                return -EINVAL;
 
-       pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate);
+       pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate);
 
-       return tegra_emc_table[best].rate * 2 * 1000;
+       return pdata->tables[best].rate * 2 * 1000;
 }
 
 /*
@@ -142,37 +146,211 @@ long tegra_emc_round_rate(unsigned long rate)
  */
 int tegra_emc_set_rate(unsigned long rate)
 {
+       struct tegra_emc_pdata *pdata;
        int i;
        int j;
 
-       if (!tegra_emc_table)
+       if (!emc_pdev)
                return -EINVAL;
 
+       pdata = emc_pdev->dev.platform_data;
+
        /*
         * The EMC clock rate is twice the bus rate, and the bus rate is
         * measured in kHz
         */
        rate = rate / 2 / 1000;
 
-       for (i = 0; i < tegra_emc_table_size; i++)
-               if (tegra_emc_table[i].rate == rate)
+       for (i = 0; i < pdata->num_tables; i++)
+               if (pdata->tables[i].rate == rate)
                        break;
 
-       if (i >= tegra_emc_table_size)
+       if (i >= pdata->num_tables)
                return -EINVAL;
 
        pr_debug("%s: setting to %lu\n", __func__, rate);
 
        for (j = 0; j < TEGRA_EMC_NUM_REGS; j++)
-               emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]);
+               emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]);
 
-       emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]);
+       emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]);
 
        return 0;
 }
 
-void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
+#ifdef CONFIG_OF
+static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np)
+{
+       struct device_node *iter;
+       u32 reg;
+
+       for_each_child_of_node(np, iter) {
+               if (of_property_read_u32(np, "nvidia,ram-code", &reg))
+                       continue;
+               if (reg == tegra_bct_strapping)
+                       return of_node_get(iter);
+       }
+
+       return NULL;
+}
+
+static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
+               struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *tnp, *iter;
+       struct tegra_emc_pdata *pdata;
+       int ret, i, num_tables;
+
+       if (!np)
+               return NULL;
+
+       if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
+               tnp = tegra_emc_ramcode_devnode(np);
+               if (!tnp)
+                       dev_warn(&pdev->dev,
+                                "can't find emc table for ram-code 0x%02x\n",
+                                tegra_bct_strapping);
+       } else
+               tnp = of_node_get(np);
+
+       if (!tnp)
+               return NULL;
+
+       num_tables = 0;
+       for_each_child_of_node(tnp, iter)
+               if (of_device_is_compatible(iter, "nvidia,tegra20-emc-table"))
+                       num_tables++;
+
+       if (!num_tables) {
+               pdata = NULL;
+               goto out;
+       }
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       pdata->tables = devm_kzalloc(&pdev->dev,
+                                    sizeof(*pdata->tables) * num_tables,
+                                    GFP_KERNEL);
+
+       i = 0;
+       for_each_child_of_node(tnp, iter) {
+               u32 prop;
+
+               ret = of_property_read_u32(iter, "clock-frequency", &prop);
+               if (ret) {
+                       dev_err(&pdev->dev, "no clock-frequency in %s\n",
+                               iter->full_name);
+                       continue;
+               }
+               pdata->tables[i].rate = prop;
+
+               ret = of_property_read_u32_array(iter, "nvidia,emc-registers",
+                                                pdata->tables[i].regs,
+                                                TEGRA_EMC_NUM_REGS);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "malformed emc-registers property in %s\n",
+                               iter->full_name);
+                       continue;
+               }
+
+               i++;
+       }
+       pdata->num_tables = i;
+
+out:
+       of_node_put(tnp);
+       return pdata;
+}
+#else
+static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
+               struct platform_device *pdev)
+{
+       return NULL;
+}
+#endif
+
+static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_device *pdev)
+{
+       struct clk *c = clk_get_sys(NULL, "emc");
+       struct tegra_emc_pdata *pdata;
+       unsigned long khz;
+       int i;
+
+       WARN_ON(pdev->dev.platform_data);
+       BUG_ON(IS_ERR_OR_NULL(c));
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables),
+                                    GFP_KERNEL);
+
+       pdata->tables[0].rate = clk_get_rate(c) / 2 / 1000;
+
+       for (i = 0; i < TEGRA_EMC_NUM_REGS; i++)
+               pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]);
+
+       pdata->num_tables = 1;
+
+       khz = pdata->tables[0].rate;
+       dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, "
+                "%ld kHz mem\n", khz * 2, khz);
+
+       return pdata;
+}
+
+static int __devinit tegra_emc_probe(struct platform_device *pdev)
+{
+       struct tegra_emc_pdata *pdata;
+       struct resource *res;
+
+       if (!emc_enable) {
+               dev_err(&pdev->dev, "disabled per module parameter\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "missing register base\n");
+               return -ENOMEM;
+       }
+
+       emc_regbase = devm_request_and_ioremap(&pdev->dev, res);
+       if (!emc_regbase) {
+               dev_err(&pdev->dev, "failed to remap registers\n");
+               return -ENOMEM;
+       }
+
+       pdata = pdev->dev.platform_data;
+
+       if (!pdata)
+               pdata = tegra_emc_dt_parse_pdata(pdev);
+
+       if (!pdata)
+               pdata = tegra_emc_fill_pdata(pdev);
+
+       pdev->dev.platform_data = pdata;
+
+       emc_pdev = pdev;
+
+       return 0;
+}
+
+static struct of_device_id tegra_emc_of_match[] __devinitdata = {
+       { .compatible = "nvidia,tegra20-emc", },
+       { },
+};
+
+static struct platform_driver tegra_emc_driver = {
+       .driver         = {
+               .name   = "tegra-emc",
+               .owner  = THIS_MODULE,
+               .of_match_table = tegra_emc_of_match,
+       },
+       .probe          = tegra_emc_probe,
+};
+
+static int __init tegra_emc_init(void)
 {
-       tegra_emc_table = table;
-       tegra_emc_table_size = table_size;
+       return platform_driver_register(&tegra_emc_driver);
 }
+device_initcall(tegra_emc_init);
index 19f08cb..f61409b 100644 (file)
  *
  */
 
-#define TEGRA_EMC_NUM_REGS 46
-
-struct tegra_emc_table {
-       unsigned long rate;
-       u32 regs[TEGRA_EMC_NUM_REGS];
-};
+#ifndef __MACH_TEGRA_TEGRA2_EMC_H_
+#define __MACH_TEGRA_TEGRA2_EMC_H
 
 int tegra_emc_set_rate(unsigned long rate);
 long tegra_emc_round_rate(unsigned long rate);
-void tegra_init_emc(const struct tegra_emc_table *table, int table_size);
+
+#endif
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
new file mode 100644 (file)
index 0000000..6d08b53
--- /dev/null
@@ -0,0 +1,3099 @@
+/*
+ * arch/arm/mach-tegra/tegra30_clocks.c
+ *
+ * Copyright (c) 2010-2011 NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/syscore_ops.h>
+
+#include <asm/clkdev.h>
+
+#include <mach/iomap.h>
+
+#include "clock.h"
+#include "fuse.h"
+
+#define USE_PLL_LOCK_BITS 0
+
+#define RST_DEVICES_L                  0x004
+#define RST_DEVICES_H                  0x008
+#define RST_DEVICES_U                  0x00C
+#define RST_DEVICES_V                  0x358
+#define RST_DEVICES_W                  0x35C
+#define RST_DEVICES_SET_L              0x300
+#define RST_DEVICES_CLR_L              0x304
+#define RST_DEVICES_SET_V              0x430
+#define RST_DEVICES_CLR_V              0x434
+#define RST_DEVICES_NUM                        5
+
+#define CLK_OUT_ENB_L                  0x010
+#define CLK_OUT_ENB_H                  0x014
+#define CLK_OUT_ENB_U                  0x018
+#define CLK_OUT_ENB_V                  0x360
+#define CLK_OUT_ENB_W                  0x364
+#define CLK_OUT_ENB_SET_L              0x320
+#define CLK_OUT_ENB_CLR_L              0x324
+#define CLK_OUT_ENB_SET_V              0x440
+#define CLK_OUT_ENB_CLR_V              0x444
+#define CLK_OUT_ENB_NUM                        5
+
+#define RST_DEVICES_V_SWR_CPULP_RST_DIS        (0x1 << 1)
+#define CLK_OUT_ENB_V_CLK_ENB_CPULP_EN (0x1 << 1)
+
+#define PERIPH_CLK_TO_BIT(c)           (1 << (c->u.periph.clk_num % 32))
+#define PERIPH_CLK_TO_RST_REG(c)       \
+       periph_clk_to_reg((c), RST_DEVICES_L, RST_DEVICES_V, 4)
+#define PERIPH_CLK_TO_RST_SET_REG(c)   \
+       periph_clk_to_reg((c), RST_DEVICES_SET_L, RST_DEVICES_SET_V, 8)
+#define PERIPH_CLK_TO_RST_CLR_REG(c)   \
+       periph_clk_to_reg((c), RST_DEVICES_CLR_L, RST_DEVICES_CLR_V, 8)
+
+#define PERIPH_CLK_TO_ENB_REG(c)       \
+       periph_clk_to_reg((c), CLK_OUT_ENB_L, CLK_OUT_ENB_V, 4)
+#define PERIPH_CLK_TO_ENB_SET_REG(c)   \
+       periph_clk_to_reg((c), CLK_OUT_ENB_SET_L, CLK_OUT_ENB_SET_V, 8)
+#define PERIPH_CLK_TO_ENB_CLR_REG(c)   \
+       periph_clk_to_reg((c), CLK_OUT_ENB_CLR_L, CLK_OUT_ENB_CLR_V, 8)
+
+#define CLK_MASK_ARM                   0x44
+#define MISC_CLK_ENB                   0x48
+
+#define OSC_CTRL                       0x50
+#define OSC_CTRL_OSC_FREQ_MASK         (0xF<<28)
+#define OSC_CTRL_OSC_FREQ_13MHZ                (0x0<<28)
+#define OSC_CTRL_OSC_FREQ_19_2MHZ      (0x4<<28)
+#define OSC_CTRL_OSC_FREQ_12MHZ                (0x8<<28)
+#define OSC_CTRL_OSC_FREQ_26MHZ                (0xC<<28)
+#define OSC_CTRL_OSC_FREQ_16_8MHZ      (0x1<<28)
+#define OSC_CTRL_OSC_FREQ_38_4MHZ      (0x5<<28)
+#define OSC_CTRL_OSC_FREQ_48MHZ                (0x9<<28)
+#define OSC_CTRL_MASK                  (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
+
+#define OSC_CTRL_PLL_REF_DIV_MASK      (3<<26)
+#define OSC_CTRL_PLL_REF_DIV_1         (0<<26)
+#define OSC_CTRL_PLL_REF_DIV_2         (1<<26)
+#define OSC_CTRL_PLL_REF_DIV_4         (2<<26)
+
+#define OSC_FREQ_DET                   0x58
+#define OSC_FREQ_DET_TRIG              (1<<31)
+
+#define OSC_FREQ_DET_STATUS            0x5C
+#define OSC_FREQ_DET_BUSY              (1<<31)
+#define OSC_FREQ_DET_CNT_MASK          0xFFFF
+
+#define PERIPH_CLK_SOURCE_I2S1         0x100
+#define PERIPH_CLK_SOURCE_EMC          0x19c
+#define PERIPH_CLK_SOURCE_OSC          0x1fc
+#define PERIPH_CLK_SOURCE_NUM1 \
+       ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
+
+#define PERIPH_CLK_SOURCE_G3D2         0x3b0
+#define PERIPH_CLK_SOURCE_SE           0x42c
+#define PERIPH_CLK_SOURCE_NUM2 \
+       ((PERIPH_CLK_SOURCE_SE - PERIPH_CLK_SOURCE_G3D2) / 4 + 1)
+
+#define AUDIO_DLY_CLK                  0x49c
+#define AUDIO_SYNC_CLK_SPDIF           0x4b4
+#define PERIPH_CLK_SOURCE_NUM3 \
+       ((AUDIO_SYNC_CLK_SPDIF - AUDIO_DLY_CLK) / 4 + 1)
+
+#define PERIPH_CLK_SOURCE_NUM          (PERIPH_CLK_SOURCE_NUM1 + \
+                                        PERIPH_CLK_SOURCE_NUM2 + \
+                                        PERIPH_CLK_SOURCE_NUM3)
+
+#define CPU_SOFTRST_CTRL               0x380
+
+#define PERIPH_CLK_SOURCE_DIVU71_MASK  0xFF
+#define PERIPH_CLK_SOURCE_DIVU16_MASK  0xFFFF
+#define PERIPH_CLK_SOURCE_DIV_SHIFT    0
+#define PERIPH_CLK_SOURCE_DIVIDLE_SHIFT        8
+#define PERIPH_CLK_SOURCE_DIVIDLE_VAL  50
+#define PERIPH_CLK_UART_DIV_ENB                (1<<24)
+#define PERIPH_CLK_VI_SEL_EX_SHIFT     24
+#define PERIPH_CLK_VI_SEL_EX_MASK      (0x3<<PERIPH_CLK_VI_SEL_EX_SHIFT)
+#define PERIPH_CLK_NAND_DIV_EX_ENB     (1<<8)
+#define PERIPH_CLK_DTV_POLARITY_INV    (1<<25)
+
+#define AUDIO_SYNC_SOURCE_MASK         0x0F
+#define AUDIO_SYNC_DISABLE_BIT         0x10
+#define AUDIO_SYNC_TAP_NIBBLE_SHIFT(c) ((c->reg_shift - 24) * 4)
+
+#define PLL_BASE                       0x0
+#define PLL_BASE_BYPASS                        (1<<31)
+#define PLL_BASE_ENABLE                        (1<<30)
+#define PLL_BASE_REF_ENABLE            (1<<29)
+#define PLL_BASE_OVERRIDE              (1<<28)
+#define PLL_BASE_LOCK                  (1<<27)
+#define PLL_BASE_DIVP_MASK             (0x7<<20)
+#define PLL_BASE_DIVP_SHIFT            20
+#define PLL_BASE_DIVN_MASK             (0x3FF<<8)
+#define PLL_BASE_DIVN_SHIFT            8
+#define PLL_BASE_DIVM_MASK             (0x1F)
+#define PLL_BASE_DIVM_SHIFT            0
+
+#define PLL_OUT_RATIO_MASK             (0xFF<<8)
+#define PLL_OUT_RATIO_SHIFT            8
+#define PLL_OUT_OVERRIDE               (1<<2)
+#define PLL_OUT_CLKEN                  (1<<1)
+#define PLL_OUT_RESET_DISABLE          (1<<0)
+
+#define PLL_MISC(c)                    \
+       (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
+#define PLL_MISC_LOCK_ENABLE(c)        \
+       (((c)->flags & (PLLU | PLLD)) ? (1<<22) : (1<<18))
+
+#define PLL_MISC_DCCON_SHIFT           20
+#define PLL_MISC_CPCON_SHIFT           8
+#define PLL_MISC_CPCON_MASK            (0xF<<PLL_MISC_CPCON_SHIFT)
+#define PLL_MISC_LFCON_SHIFT           4
+#define PLL_MISC_LFCON_MASK            (0xF<<PLL_MISC_LFCON_SHIFT)
+#define PLL_MISC_VCOCON_SHIFT          0
+#define PLL_MISC_VCOCON_MASK           (0xF<<PLL_MISC_VCOCON_SHIFT)
+#define PLLD_MISC_CLKENABLE            (1<<30)
+
+#define PLLU_BASE_POST_DIV             (1<<20)
+
+#define PLLD_BASE_DSIB_MUX_SHIFT       25
+#define PLLD_BASE_DSIB_MUX_MASK                (1<<PLLD_BASE_DSIB_MUX_SHIFT)
+#define PLLD_BASE_CSI_CLKENABLE                (1<<26)
+#define PLLD_MISC_DSI_CLKENABLE                (1<<30)
+#define PLLD_MISC_DIV_RST              (1<<23)
+#define PLLD_MISC_DCCON_SHIFT          12
+
+#define PLLDU_LFCON_SET_DIVN           600
+
+/* FIXME: OUT_OF_TABLE_CPCON per pll */
+#define OUT_OF_TABLE_CPCON             0x8
+
+#define SUPER_CLK_MUX                  0x00
+#define SUPER_STATE_SHIFT              28
+#define SUPER_STATE_MASK               (0xF << SUPER_STATE_SHIFT)
+#define SUPER_STATE_STANDBY            (0x0 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IDLE               (0x1 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_RUN                        (0x2 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IRQ                        (0x3 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_FIQ                        (0x4 << SUPER_STATE_SHIFT)
+#define SUPER_LP_DIV2_BYPASS           (0x1 << 16)
+#define SUPER_SOURCE_MASK              0xF
+#define        SUPER_FIQ_SOURCE_SHIFT          12
+#define        SUPER_IRQ_SOURCE_SHIFT          8
+#define        SUPER_RUN_SOURCE_SHIFT          4
+#define        SUPER_IDLE_SOURCE_SHIFT         0
+
+#define SUPER_CLK_DIVIDER              0x04
+#define SUPER_CLOCK_DIV_U71_SHIFT      16
+#define SUPER_CLOCK_DIV_U71_MASK       (0xff << SUPER_CLOCK_DIV_U71_SHIFT)
+/* guarantees safe cpu backup */
+#define SUPER_CLOCK_DIV_U71_MIN                0x2
+
+#define BUS_CLK_DISABLE                        (1<<3)
+#define BUS_CLK_DIV_MASK               0x3
+
+#define PMC_CTRL                       0x0
+ #define PMC_CTRL_BLINK_ENB            (1 << 7)
+
+#define PMC_DPD_PADS_ORIDE             0x1c
+ #define PMC_DPD_PADS_ORIDE_BLINK_ENB  (1 << 20)
+
+#define PMC_BLINK_TIMER_DATA_ON_SHIFT  0
+#define PMC_BLINK_TIMER_DATA_ON_MASK   0x7fff
+#define PMC_BLINK_TIMER_ENB            (1 << 15)
+#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
+#define PMC_BLINK_TIMER_DATA_OFF_MASK  0xffff
+
+#define PMC_PLLP_WB0_OVERRIDE                          0xf8
+#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE              (1 << 12)
+
+#define UTMIP_PLL_CFG2                                 0x488
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x)                 (((x) & 0xfff) << 6)
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x)             (((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN       (1 << 0)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN       (1 << 2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN       (1 << 4)
+
+#define UTMIP_PLL_CFG1                                 0x484
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x)             (((x) & 0x1f) << 27)
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x)              (((x) & 0xfff) << 0)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN      (1 << 14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN      (1 << 12)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN            (1 << 16)
+
+#define PLLE_BASE_CML_ENABLE           (1<<31)
+#define PLLE_BASE_ENABLE               (1<<30)
+#define PLLE_BASE_DIVCML_SHIFT         24
+#define PLLE_BASE_DIVCML_MASK          (0xf<<PLLE_BASE_DIVCML_SHIFT)
+#define PLLE_BASE_DIVP_SHIFT           16
+#define PLLE_BASE_DIVP_MASK            (0x3f<<PLLE_BASE_DIVP_SHIFT)
+#define PLLE_BASE_DIVN_SHIFT           8
+#define PLLE_BASE_DIVN_MASK            (0xFF<<PLLE_BASE_DIVN_SHIFT)
+#define PLLE_BASE_DIVM_SHIFT           0
+#define PLLE_BASE_DIVM_MASK            (0xFF<<PLLE_BASE_DIVM_SHIFT)
+#define PLLE_BASE_DIV_MASK             \
+       (PLLE_BASE_DIVCML_MASK | PLLE_BASE_DIVP_MASK | \
+        PLLE_BASE_DIVN_MASK | PLLE_BASE_DIVM_MASK)
+#define PLLE_BASE_DIV(m, n, p, cml)            \
+        (((cml)<<PLLE_BASE_DIVCML_SHIFT) | ((p)<<PLLE_BASE_DIVP_SHIFT) | \
+         ((n)<<PLLE_BASE_DIVN_SHIFT) | ((m)<<PLLE_BASE_DIVM_SHIFT))
+
+#define PLLE_MISC_SETUP_BASE_SHIFT     16
+#define PLLE_MISC_SETUP_BASE_MASK      (0xFFFF<<PLLE_MISC_SETUP_BASE_SHIFT)
+#define PLLE_MISC_READY                        (1<<15)
+#define PLLE_MISC_LOCK                 (1<<11)
+#define PLLE_MISC_LOCK_ENABLE          (1<<9)
+#define PLLE_MISC_SETUP_EX_SHIFT       2
+#define PLLE_MISC_SETUP_EX_MASK                (0x3<<PLLE_MISC_SETUP_EX_SHIFT)
+#define PLLE_MISC_SETUP_MASK           \
+         (PLLE_MISC_SETUP_BASE_MASK | PLLE_MISC_SETUP_EX_MASK)
+#define PLLE_MISC_SETUP_VALUE          \
+         ((0x7<<PLLE_MISC_SETUP_BASE_SHIFT) | (0x0<<PLLE_MISC_SETUP_EX_SHIFT))
+
+#define PLLE_SS_CTRL                   0x68
+#define        PLLE_SS_INCINTRV_SHIFT          24
+#define        PLLE_SS_INCINTRV_MASK           (0x3f<<PLLE_SS_INCINTRV_SHIFT)
+#define        PLLE_SS_INC_SHIFT               16
+#define        PLLE_SS_INC_MASK                (0xff<<PLLE_SS_INC_SHIFT)
+#define        PLLE_SS_MAX_SHIFT               0
+#define        PLLE_SS_MAX_MASK                (0x1ff<<PLLE_SS_MAX_SHIFT)
+#define PLLE_SS_COEFFICIENTS_MASK      \
+       (PLLE_SS_INCINTRV_MASK | PLLE_SS_INC_MASK | PLLE_SS_MAX_MASK)
+#define PLLE_SS_COEFFICIENTS_12MHZ     \
+       ((0x18<<PLLE_SS_INCINTRV_SHIFT) | (0x1<<PLLE_SS_INC_SHIFT) | \
+        (0x24<<PLLE_SS_MAX_SHIFT))
+#define PLLE_SS_DISABLE                        ((1<<12) | (1<<11) | (1<<10))
+
+#define PLLE_AUX                       0x48c
+#define PLLE_AUX_PLLP_SEL              (1<<2)
+#define PLLE_AUX_CML_SATA_ENABLE       (1<<1)
+#define PLLE_AUX_CML_PCIE_ENABLE       (1<<0)
+
+#define        PMC_SATA_PWRGT                  0x1ac
+#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE (1<<5)
+#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL (1<<4)
+
+#define ROUND_DIVIDER_UP       0
+#define ROUND_DIVIDER_DOWN     1
+
+/* FIXME: recommended safety delay after lock is detected */
+#define PLL_POST_LOCK_DELAY            100
+
+/**
+* Structure defining the fields for USB UTMI clocks Parameters.
+*/
+struct utmi_clk_param {
+       /* Oscillator Frequency in KHz */
+       u32 osc_frequency;
+       /* UTMIP PLL Enable Delay Count  */
+       u8 enable_delay_count;
+       /* UTMIP PLL Stable count */
+       u8 stable_count;
+       /*  UTMIP PLL Active delay count */
+       u8 active_delay_count;
+       /* UTMIP PLL Xtal frequency count */
+       u8 xtal_freq_count;
+};
+
+static const struct utmi_clk_param utmi_parameters[] = {
+       {
+               .osc_frequency = 13000000,
+               .enable_delay_count = 0x02,
+               .stable_count = 0x33,
+               .active_delay_count = 0x05,
+               .xtal_freq_count = 0x7F
+       },
+       {
+               .osc_frequency = 19200000,
+               .enable_delay_count = 0x03,
+               .stable_count = 0x4B,
+               .active_delay_count = 0x06,
+               .xtal_freq_count = 0xBB},
+       {
+               .osc_frequency = 12000000,
+               .enable_delay_count = 0x02,
+               .stable_count = 0x2F,
+               .active_delay_count = 0x04,
+               .xtal_freq_count = 0x76
+       },
+       {
+               .osc_frequency = 26000000,
+               .enable_delay_count = 0x04,
+               .stable_count = 0x66,
+               .active_delay_count = 0x09,
+               .xtal_freq_count = 0xFE
+       },
+       {
+               .osc_frequency = 16800000,
+               .enable_delay_count = 0x03,
+               .stable_count = 0x41,
+               .active_delay_count = 0x0A,
+               .xtal_freq_count = 0xA4
+       },
+};
+
+static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+
+#define MISC_GP_HIDREV                  0x804
+
+/*
+ * Some peripheral clocks share an enable bit, so refcount the enable bits
+ * in registers CLK_ENABLE_L, ... CLK_ENABLE_W
+ */
+static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 32];
+
+#define clk_writel(value, reg) \
+       __raw_writel(value, (u32)reg_clk_base + (reg))
+#define clk_readl(reg) \
+       __raw_readl((u32)reg_clk_base + (reg))
+#define pmc_writel(value, reg) \
+       __raw_writel(value, (u32)reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+       __raw_readl((u32)reg_pmc_base + (reg))
+#define chipid_readl() \
+       __raw_readl((u32)misc_gp_hidrev_base + MISC_GP_HIDREV)
+
+#define clk_writel_delay(value, reg)                                   \
+       do {                                                            \
+               __raw_writel((value), (u32)reg_clk_base + (reg));       \
+               udelay(2);                                              \
+       } while (0)
+
+
+static inline int clk_set_div(struct clk *c, u32 n)
+{
+       return clk_set_rate(c, (clk_get_rate(c->parent) + n-1) / n);
+}
+
+static inline u32 periph_clk_to_reg(
+       struct clk *c, u32 reg_L, u32 reg_V, int offs)
+{
+       u32 reg = c->u.periph.clk_num / 32;
+       BUG_ON(reg >= RST_DEVICES_NUM);
+       if (reg < 3)
+               reg = reg_L + (reg * offs);
+       else
+               reg = reg_V + ((reg - 3) * offs);
+       return reg;
+}
+
+static unsigned long clk_measure_input_freq(void)
+{
+       u32 clock_autodetect;
+       clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
+       do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
+       clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
+       if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
+               return 12000000;
+       } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
+               return 13000000;
+       } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
+               return 19200000;
+       } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
+               return 26000000;
+       } else if (clock_autodetect >= 1025 - 3 && clock_autodetect <= 1025 + 3) {
+               return 16800000;
+       } else if (clock_autodetect >= 2344 - 3 && clock_autodetect <= 2344 + 3) {
+               return 38400000;
+       } else if (clock_autodetect >= 2928 - 3 && clock_autodetect <= 2928 + 3) {
+               return 48000000;
+       } else {
+               pr_err("%s: Unexpected clock autodetect value %d", __func__,
+                       clock_autodetect);
+               BUG();
+               return 0;
+       }
+}
+
+static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate,
+                                u32 flags, u32 round_mode)
+{
+       s64 divider_u71 = parent_rate;
+       if (!rate)
+               return -EINVAL;
+
+       if (!(flags & DIV_U71_INT))
+               divider_u71 *= 2;
+       if (round_mode == ROUND_DIVIDER_UP)
+               divider_u71 += rate - 1;
+       do_div(divider_u71, rate);
+       if (flags & DIV_U71_INT)
+               divider_u71 *= 2;
+
+       if (divider_u71 - 2 < 0)
+               return 0;
+
+       if (divider_u71 - 2 > 255)
+               return -EINVAL;
+
+       return divider_u71 - 2;
+}
+
+static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
+{
+       s64 divider_u16;
+
+       divider_u16 = parent_rate;
+       if (!rate)
+               return -EINVAL;
+       divider_u16 += rate - 1;
+       do_div(divider_u16, rate);
+
+       if (divider_u16 - 1 < 0)
+               return 0;
+
+       if (divider_u16 - 1 > 0xFFFF)
+               return -EINVAL;
+
+       return divider_u16 - 1;
+}
+
+/* clk_m functions */
+static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
+{
+       u32 osc_ctrl = clk_readl(OSC_CTRL);
+       u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
+       u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK;
+
+       c->rate = clk_measure_input_freq();
+       switch (c->rate) {
+       case 12000000:
+               auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
+               BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+               break;
+       case 13000000:
+               auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
+               BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+               break;
+       case 19200000:
+               auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
+               BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+               break;
+       case 26000000:
+               auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
+               BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+               break;
+       case 16800000:
+               auto_clock_control |= OSC_CTRL_OSC_FREQ_16_8MHZ;
+               BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+               break;
+       case 38400000:
+               auto_clock_control |= OSC_CTRL_OSC_FREQ_38_4MHZ;
+               BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2);
+               break;
+       case 48000000:
+               auto_clock_control |= OSC_CTRL_OSC_FREQ_48MHZ;
+               BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4);
+               break;
+       default:
+               pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
+               BUG();
+       }
+       clk_writel(auto_clock_control, OSC_CTRL);
+       return c->rate;
+}
+
+static void tegra30_clk_m_init(struct clk *c)
+{
+       pr_debug("%s on clock %s\n", __func__, c->name);
+       tegra30_clk_m_autodetect_rate(c);
+}
+
+static int tegra30_clk_m_enable(struct clk *c)
+{
+       pr_debug("%s on clock %s\n", __func__, c->name);
+       return 0;
+}
+
+static void tegra30_clk_m_disable(struct clk *c)
+{
+       pr_debug("%s on clock %s\n", __func__, c->name);
+       WARN(1, "Attempting to disable main SoC clock\n");
+}
+
+static struct clk_ops tegra_clk_m_ops = {
+       .init           = tegra30_clk_m_init,
+       .enable         = tegra30_clk_m_enable,
+       .disable        = tegra30_clk_m_disable,
+};
+
+static struct clk_ops tegra_clk_m_div_ops = {
+       .enable         = tegra30_clk_m_enable,
+};
+
+/* PLL reference divider functions */
+static void tegra30_pll_ref_init(struct clk *c)
+{
+       u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK;
+       pr_debug("%s on clock %s\n", __func__, c->name);
+
+       switch (pll_ref_div) {
+       case OSC_CTRL_PLL_REF_DIV_1:
+               c->div = 1;
+               break;
+       case OSC_CTRL_PLL_REF_DIV_2:
+               c->div = 2;
+               break;
+       case OSC_CTRL_PLL_REF_DIV_4:
+               c->div = 4;
+               break;
+       default:
+               pr_err("%s: Invalid pll ref divider %d", __func__, pll_ref_div);
+               BUG();
+       }
+       c->mul = 1;
+       c->state = ON;
+}
+
+static struct clk_ops tegra_pll_ref_ops = {
+       .init           = tegra30_pll_ref_init,
+       .enable         = tegra30_clk_m_enable,
+       .disable        = tegra30_clk_m_disable,
+};
+
+/* super clock functions */
+/* "super clocks" on tegra30 have two-stage muxes, fractional 7.1 divider and
+ * clock skipping super divider.  We will ignore the clock skipping divider,
+ * since we can't lower the voltage when using the clock skip, but we can if
+ * we lower the PLL frequency. We will use 7.1 divider for CPU super-clock
+ * only when its parent is a fixed rate PLL, since we can't change PLL rate
+ * in this case.
+ */
+static void tegra30_super_clk_init(struct clk *c)
+{
+       u32 val;
+       int source;
+       int shift;
+       const struct clk_mux_sel *sel;
+       val = clk_readl(c->reg + SUPER_CLK_MUX);
+       c->state = ON;
+       BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+               ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+       shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+               SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+       source = (val >> shift) & SUPER_SOURCE_MASK;
+       if (c->flags & DIV_2)
+               source |= val & SUPER_LP_DIV2_BYPASS;
+       for (sel = c->inputs; sel->input != NULL; sel++) {
+               if (sel->value == source)
+                       break;
+       }
+       BUG_ON(sel->input == NULL);
+       c->parent = sel->input;
+
+       if (c->flags & DIV_U71) {
+               /* Init safe 7.1 divider value (does not affect PLLX path) */
+               clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT,
+                          c->reg + SUPER_CLK_DIVIDER);
+               c->mul = 2;
+               c->div = 2;
+               if (!(c->parent->flags & PLLX))
+                       c->div += SUPER_CLOCK_DIV_U71_MIN;
+       } else
+               clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
+}
+
+static int tegra30_super_clk_enable(struct clk *c)
+{
+       return 0;
+}
+
+static void tegra30_super_clk_disable(struct clk *c)
+{
+       /* since tegra 3 has 2 CPU super clocks - low power lp-mode clock and
+          geared up g-mode super clock - mode switch may request to disable
+          either of them; accept request with no affect on h/w */
+}
+
+static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
+{
+       u32 val;
+       const struct clk_mux_sel *sel;
+       int shift;
+
+       val = clk_readl(c->reg + SUPER_CLK_MUX);
+       BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+               ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+       shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+               SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+       for (sel = c->inputs; sel->input != NULL; sel++) {
+               if (sel->input == p) {
+                       /* For LP mode super-clock switch between PLLX direct
+                          and divided-by-2 outputs is allowed only when other
+                          than PLLX clock source is current parent */
+                       if ((c->flags & DIV_2) && (p->flags & PLLX) &&
+                           ((sel->value ^ val) & SUPER_LP_DIV2_BYPASS)) {
+                               if (c->parent->flags & PLLX)
+                                       return -EINVAL;
+                               val ^= SUPER_LP_DIV2_BYPASS;
+                               clk_writel_delay(val, c->reg);
+                       }
+                       val &= ~(SUPER_SOURCE_MASK << shift);
+                       val |= (sel->value & SUPER_SOURCE_MASK) << shift;
+
+                       /* 7.1 divider for CPU super-clock does not affect
+                          PLLX path */
+                       if (c->flags & DIV_U71) {
+                               u32 div = 0;
+                               if (!(p->flags & PLLX)) {
+                                       div = clk_readl(c->reg +
+                                                       SUPER_CLK_DIVIDER);
+                                       div &= SUPER_CLOCK_DIV_U71_MASK;
+                                       div >>= SUPER_CLOCK_DIV_U71_SHIFT;
+                               }
+                               c->div = div + 2;
+                               c->mul = 2;
+                       }
+
+                       if (c->refcnt)
+                               clk_enable(p);
+
+                       clk_writel_delay(val, c->reg);
+
+                       if (c->refcnt && c->parent)
+                               clk_disable(c->parent);
+
+                       clk_reparent(c, p);
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+/*
+ * Do not use super clocks "skippers", since dividing using a clock skipper
+ * does not allow the voltage to be scaled down. Instead adjust the rate of
+ * the parent clock. This requires that the parent of a super clock have no
+ * other children, otherwise the rate will change underneath the other
+ * children. Special case: if fixed rate PLL is CPU super clock parent the
+ * rate of this PLL can't be changed, and it has many other children. In
+ * this case use 7.1 fractional divider to adjust the super clock rate.
+ */
+static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate)
+{
+       if ((c->flags & DIV_U71) && (c->parent->flags & PLL_FIXED)) {
+               int div = clk_div71_get_divider(c->parent->u.pll.fixed_rate,
+                                       rate, c->flags, ROUND_DIVIDER_DOWN);
+               div = max(div, SUPER_CLOCK_DIV_U71_MIN);
+
+               clk_writel(div << SUPER_CLOCK_DIV_U71_SHIFT,
+                          c->reg + SUPER_CLK_DIVIDER);
+               c->div = div + 2;
+               c->mul = 2;
+               return 0;
+       }
+       return clk_set_rate(c->parent, rate);
+}
+
+static struct clk_ops tegra_super_ops = {
+       .init                   = tegra30_super_clk_init,
+       .enable                 = tegra30_super_clk_enable,
+       .disable                = tegra30_super_clk_disable,
+       .set_parent             = tegra30_super_clk_set_parent,
+       .set_rate               = tegra30_super_clk_set_rate,
+};
+
+static int tegra30_twd_clk_set_rate(struct clk *c, unsigned long rate)
+{
+       /* The input value 'rate' is the clock rate of the CPU complex. */
+       c->rate = (rate * c->mul) / c->div;
+       return 0;
+}
+
+static struct clk_ops tegra30_twd_ops = {
+       .set_rate       = tegra30_twd_clk_set_rate,
+};
+
+/* Blink output functions */
+
+static void tegra30_blink_clk_init(struct clk *c)
+{
+       u32 val;
+
+       val = pmc_readl(PMC_CTRL);
+       c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
+       c->mul = 1;
+       val = pmc_readl(c->reg);
+
+       if (val & PMC_BLINK_TIMER_ENB) {
+               unsigned int on_off;
+
+               on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
+                       PMC_BLINK_TIMER_DATA_ON_MASK;
+               val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+               val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+               on_off += val;
+               /* each tick in the blink timer is 4 32KHz clocks */
+               c->div = on_off * 4;
+       } else {
+               c->div = 1;
+       }
+}
+
+static int tegra30_blink_clk_enable(struct clk *c)
+{
+       u32 val;
+
+       val = pmc_readl(PMC_DPD_PADS_ORIDE);
+       pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+
+       val = pmc_readl(PMC_CTRL);
+       pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+       return 0;
+}
+
+static void tegra30_blink_clk_disable(struct clk *c)
+{
+       u32 val;
+
+       val = pmc_readl(PMC_CTRL);
+       pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+       val = pmc_readl(PMC_DPD_PADS_ORIDE);
+       pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+}
+
+static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(c->parent);
+       if (rate >= parent_rate) {
+               c->div = 1;
+               pmc_writel(0, c->reg);
+       } else {
+               unsigned int on_off;
+               u32 val;
+
+               on_off = DIV_ROUND_UP(parent_rate / 8, rate);
+               c->div = on_off * 8;
+
+               val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
+                       PMC_BLINK_TIMER_DATA_ON_SHIFT;
+               on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+               on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+               val |= on_off;
+               val |= PMC_BLINK_TIMER_ENB;
+               pmc_writel(val, c->reg);
+       }
+
+       return 0;
+}
+
+static struct clk_ops tegra_blink_clk_ops = {
+       .init                   = &tegra30_blink_clk_init,
+       .enable                 = &tegra30_blink_clk_enable,
+       .disable                = &tegra30_blink_clk_disable,
+       .set_rate               = &tegra30_blink_clk_set_rate,
+};
+
+/* PLL Functions */
+static int tegra30_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg,
+                                        u32 lock_bit)
+{
+#if USE_PLL_LOCK_BITS
+       int i;
+       for (i = 0; i < c->u.pll.lock_delay; i++) {
+               if (clk_readl(lock_reg) & lock_bit) {
+                       udelay(PLL_POST_LOCK_DELAY);
+                       return 0;
+               }
+               udelay(2);              /* timeout = 2 * lock time */
+       }
+       pr_err("Timed out waiting for lock bit on pll %s", c->name);
+       return -1;
+#endif
+       udelay(c->u.pll.lock_delay);
+
+       return 0;
+}
+
+
+static void tegra30_utmi_param_configure(struct clk *c)
+{
+       u32 reg;
+       int i;
+       unsigned long main_rate =
+               clk_get_rate(c->parent->parent);
+
+       for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+               if (main_rate == utmi_parameters[i].osc_frequency)
+                       break;
+       }
+
+       if (i >= ARRAY_SIZE(utmi_parameters)) {
+               pr_err("%s: Unexpected main rate %lu\n", __func__, main_rate);
+               return;
+       }
+
+       reg = clk_readl(UTMIP_PLL_CFG2);
+
+       /* Program UTMIP PLL stable and active counts */
+       /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
+       reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+       reg |= UTMIP_PLL_CFG2_STABLE_COUNT(
+                       utmi_parameters[i].stable_count);
+
+       reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+
+       reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
+                       utmi_parameters[i].active_delay_count);
+
+       /* Remove power downs from UTMIP PLL control bits */
+       reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+       reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+       reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+
+       clk_writel(reg, UTMIP_PLL_CFG2);
+
+       /* Program UTMIP PLL delay and oscillator frequency counts */
+       reg = clk_readl(UTMIP_PLL_CFG1);
+       reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+
+       reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
+               utmi_parameters[i].enable_delay_count);
+
+       reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+       reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
+               utmi_parameters[i].xtal_freq_count);
+
+       /* Remove power downs from UTMIP PLL control bits */
+       reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+       reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+       reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+
+       clk_writel(reg, UTMIP_PLL_CFG1);
+}
+
+static void tegra30_pll_clk_init(struct clk *c)
+{
+       u32 val = clk_readl(c->reg + PLL_BASE);
+
+       c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
+
+       if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
+               const struct clk_pll_freq_table *sel;
+               unsigned long input_rate = clk_get_rate(c->parent);
+               for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+                       if (sel->input_rate == input_rate &&
+                               sel->output_rate == c->u.pll.fixed_rate) {
+                               c->mul = sel->n;
+                               c->div = sel->m * sel->p;
+                               return;
+                       }
+               }
+               pr_err("Clock %s has unknown fixed frequency\n", c->name);
+               BUG();
+       } else if (val & PLL_BASE_BYPASS) {
+               c->mul = 1;
+               c->div = 1;
+       } else {
+               c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+               c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+               if (c->flags & PLLU)
+                       c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+               else
+                       c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
+                                       PLL_BASE_DIVP_SHIFT));
+               if (c->flags & PLL_FIXED) {
+                       unsigned long rate = clk_get_rate_locked(c);
+                       BUG_ON(rate != c->u.pll.fixed_rate);
+               }
+       }
+
+       if (c->flags & PLLU)
+               tegra30_utmi_param_configure(c);
+}
+
+static int tegra30_pll_clk_enable(struct clk *c)
+{
+       u32 val;
+       pr_debug("%s on clock %s\n", __func__, c->name);
+
+#if USE_PLL_LOCK_BITS
+       val = clk_readl(c->reg + PLL_MISC(c));
+       val |= PLL_MISC_LOCK_ENABLE(c);
+       clk_writel(val, c->reg + PLL_MISC(c));
+#endif
+       val = clk_readl(c->reg + PLL_BASE);
+       val &= ~PLL_BASE_BYPASS;
+       val |= PLL_BASE_ENABLE;
+       clk_writel(val, c->reg + PLL_BASE);
+
+       if (c->flags & PLLM) {
+               val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+               val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+               pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
+       }
+
+       tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_BASE, PLL_BASE_LOCK);
+
+       return 0;
+}
+
+static void tegra30_pll_clk_disable(struct clk *c)
+{
+       u32 val;
+       pr_debug("%s on clock %s\n", __func__, c->name);
+
+       val = clk_readl(c->reg);
+       val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+       clk_writel(val, c->reg);
+
+       if (c->flags & PLLM) {
+               val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+               val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+               pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
+       }
+}
+
+static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+       u32 val, p_div, old_base;
+       unsigned long input_rate;
+       const struct clk_pll_freq_table *sel;
+       struct clk_pll_freq_table cfg;
+
+       pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+       if (c->flags & PLL_FIXED) {
+               int ret = 0;
+               if (rate != c->u.pll.fixed_rate) {
+                       pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
+                              __func__, c->name, c->u.pll.fixed_rate, rate);
+                       ret = -EINVAL;
+               }
+               return ret;
+       }
+
+       if (c->flags & PLLM) {
+               if (rate != clk_get_rate_locked(c)) {
+                       pr_err("%s: Can not change memory %s rate in flight\n",
+                              __func__, c->name);
+                       return -EINVAL;
+               }
+               return 0;
+       }
+
+       p_div = 0;
+       input_rate = clk_get_rate(c->parent);
+
+       /* Check if the target rate is tabulated */
+       for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+               if (sel->input_rate == input_rate && sel->output_rate == rate) {
+                       if (c->flags & PLLU) {
+                               BUG_ON(sel->p < 1 || sel->p > 2);
+                               if (sel->p == 1)
+                                       p_div = PLLU_BASE_POST_DIV;
+                       } else {
+                               BUG_ON(sel->p < 1);
+                               for (val = sel->p; val > 1; val >>= 1)
+                                       p_div++;
+                               p_div <<= PLL_BASE_DIVP_SHIFT;
+                       }
+                       break;
+               }
+       }
+
+       /* Configure out-of-table rate */
+       if (sel->input_rate == 0) {
+               unsigned long cfreq;
+               BUG_ON(c->flags & PLLU);
+               sel = &cfg;
+
+               switch (input_rate) {
+               case 12000000:
+               case 26000000:
+                       cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
+                       break;
+               case 13000000:
+                       cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
+                       break;
+               case 16800000:
+               case 19200000:
+                       cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
+                       break;
+               default:
+                       pr_err("%s: Unexpected reference rate %lu\n",
+                              __func__, input_rate);
+                       BUG();
+               }
+
+               /* Raise VCO to guarantee 0.5% accuracy */
+               for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq;
+                     cfg.output_rate <<= 1)
+                       p_div++;
+
+               cfg.p = 0x1 << p_div;
+               cfg.m = input_rate / cfreq;
+               cfg.n = cfg.output_rate / cfreq;
+               cfg.cpcon = OUT_OF_TABLE_CPCON;
+
+               if ((cfg.m > (PLL_BASE_DIVM_MASK >> PLL_BASE_DIVM_SHIFT)) ||
+                   (cfg.n > (PLL_BASE_DIVN_MASK >> PLL_BASE_DIVN_SHIFT)) ||
+                   (p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) ||
+                   (cfg.output_rate > c->u.pll.vco_max)) {
+                       pr_err("%s: Failed to set %s out-of-table rate %lu\n",
+                              __func__, c->name, rate);
+                       return -EINVAL;
+               }
+               p_div <<= PLL_BASE_DIVP_SHIFT;
+       }
+
+       c->mul = sel->n;
+       c->div = sel->m * sel->p;
+
+       old_base = val = clk_readl(c->reg + PLL_BASE);
+       val &= ~(PLL_BASE_DIVM_MASK | PLL_BASE_DIVN_MASK |
+                ((c->flags & PLLU) ? PLLU_BASE_POST_DIV : PLL_BASE_DIVP_MASK));
+       val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
+               (sel->n << PLL_BASE_DIVN_SHIFT) | p_div;
+       if (val == old_base)
+               return 0;
+
+       if (c->state == ON) {
+               tegra30_pll_clk_disable(c);
+               val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+       }
+       clk_writel(val, c->reg + PLL_BASE);
+
+       if (c->flags & PLL_HAS_CPCON) {
+               val = clk_readl(c->reg + PLL_MISC(c));
+               val &= ~PLL_MISC_CPCON_MASK;
+               val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
+               if (c->flags & (PLLU | PLLD)) {
+                       val &= ~PLL_MISC_LFCON_MASK;
+                       if (sel->n >= PLLDU_LFCON_SET_DIVN)
+                               val |= 0x1 << PLL_MISC_LFCON_SHIFT;
+               } else if (c->flags & (PLLX | PLLM)) {
+                       val &= ~(0x1 << PLL_MISC_DCCON_SHIFT);
+                       if (rate >= (c->u.pll.vco_max >> 1))
+                               val |= 0x1 << PLL_MISC_DCCON_SHIFT;
+               }
+               clk_writel(val, c->reg + PLL_MISC(c));
+       }
+
+       if (c->state == ON)
+               tegra30_pll_clk_enable(c);
+
+       return 0;
+}
+
+static struct clk_ops tegra_pll_ops = {
+       .init                   = tegra30_pll_clk_init,
+       .enable                 = tegra30_pll_clk_enable,
+       .disable                = tegra30_pll_clk_disable,
+       .set_rate               = tegra30_pll_clk_set_rate,
+};
+
+static int
+tegra30_plld_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+       u32 val, mask, reg;
+
+       switch (p) {
+       case TEGRA_CLK_PLLD_CSI_OUT_ENB:
+               mask = PLLD_BASE_CSI_CLKENABLE;
+               reg = c->reg + PLL_BASE;
+               break;
+       case TEGRA_CLK_PLLD_DSI_OUT_ENB:
+               mask = PLLD_MISC_DSI_CLKENABLE;
+               reg = c->reg + PLL_MISC(c);
+               break;
+       case TEGRA_CLK_PLLD_MIPI_MUX_SEL:
+               if (!(c->flags & PLL_ALT_MISC_REG)) {
+                       mask = PLLD_BASE_DSIB_MUX_MASK;
+                       reg = c->reg + PLL_BASE;
+                       break;
+               }
+       /* fall through - error since PLLD2 does not have MUX_SEL control */
+       default:
+               return -EINVAL;
+       }
+
+       val = clk_readl(reg);
+       if (setting)
+               val |= mask;
+       else
+               val &= ~mask;
+       clk_writel(val, reg);
+       return 0;
+}
+
+static struct clk_ops tegra_plld_ops = {
+       .init                   = tegra30_pll_clk_init,
+       .enable                 = tegra30_pll_clk_enable,
+       .disable                = tegra30_pll_clk_disable,
+       .set_rate               = tegra30_pll_clk_set_rate,
+       .clk_cfg_ex             = tegra30_plld_clk_cfg_ex,
+};
+
+static void tegra30_plle_clk_init(struct clk *c)
+{
+       u32 val;
+
+       val = clk_readl(PLLE_AUX);
+       c->parent = (val & PLLE_AUX_PLLP_SEL) ?
+               tegra_get_clock_by_name("pll_p") :
+               tegra_get_clock_by_name("pll_ref");
+
+       val = clk_readl(c->reg + PLL_BASE);
+       c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF;
+       c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
+       c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
+       c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
+}
+
+static void tegra30_plle_clk_disable(struct clk *c)
+{
+       u32 val;
+       pr_debug("%s on clock %s\n", __func__, c->name);
+
+       val = clk_readl(c->reg + PLL_BASE);
+       val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
+       clk_writel(val, c->reg + PLL_BASE);
+}
+
+static void tegra30_plle_training(struct clk *c)
+{
+       u32 val;
+
+       /* PLLE is already disabled, and setup cleared;
+        * create falling edge on PLLE IDDQ input */
+       val = pmc_readl(PMC_SATA_PWRGT);
+       val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
+       pmc_writel(val, PMC_SATA_PWRGT);
+
+       val = pmc_readl(PMC_SATA_PWRGT);
+       val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
+       pmc_writel(val, PMC_SATA_PWRGT);
+
+       val = pmc_readl(PMC_SATA_PWRGT);
+       val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
+       pmc_writel(val, PMC_SATA_PWRGT);
+
+       do {
+               val = clk_readl(c->reg + PLL_MISC(c));
+       } while (!(val & PLLE_MISC_READY));
+}
+
+static int tegra30_plle_configure(struct clk *c, bool force_training)
+{
+       u32 val;
+       const struct clk_pll_freq_table *sel;
+       unsigned long rate = c->u.pll.fixed_rate;
+       unsigned long input_rate = clk_get_rate(c->parent);
+
+       for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+               if (sel->input_rate == input_rate && sel->output_rate == rate)
+                       break;
+       }
+
+       if (sel->input_rate == 0)
+               return -ENOSYS;
+
+       /* disable PLLE, clear setup fiels */
+       tegra30_plle_clk_disable(c);
+
+       val = clk_readl(c->reg + PLL_MISC(c));
+       val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
+       clk_writel(val, c->reg + PLL_MISC(c));
+
+       /* training */
+       val = clk_readl(c->reg + PLL_MISC(c));
+       if (force_training || (!(val & PLLE_MISC_READY)))
+               tegra30_plle_training(c);
+
+       /* configure dividers, setup, disable SS */
+       val = clk_readl(c->reg + PLL_BASE);
+       val &= ~PLLE_BASE_DIV_MASK;
+       val |= PLLE_BASE_DIV(sel->m, sel->n, sel->p, sel->cpcon);
+       clk_writel(val, c->reg + PLL_BASE);
+       c->mul = sel->n;
+       c->div = sel->m * sel->p;
+
+       val = clk_readl(c->reg + PLL_MISC(c));
+       val |= PLLE_MISC_SETUP_VALUE;
+       val |= PLLE_MISC_LOCK_ENABLE;
+       clk_writel(val, c->reg + PLL_MISC(c));
+
+       val = clk_readl(PLLE_SS_CTRL);
+       val |= PLLE_SS_DISABLE;
+       clk_writel(val, PLLE_SS_CTRL);
+
+       /* enable and lock PLLE*/
+       val = clk_readl(c->reg + PLL_BASE);
+       val |= (PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
+       clk_writel(val, c->reg + PLL_BASE);
+
+       tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_MISC(c), PLLE_MISC_LOCK);
+
+       return 0;
+}
+
+static int tegra30_plle_clk_enable(struct clk *c)
+{
+       pr_debug("%s on clock %s\n", __func__, c->name);
+       return tegra30_plle_configure(c, !c->set);
+}
+
+static struct clk_ops tegra_plle_ops = {
+       .init                   = tegra30_plle_clk_init,
+       .enable                 = tegra30_plle_clk_enable,
+       .disable                = tegra30_plle_clk_disable,
+};
+
+/* Clock divider ops */
+static void tegra30_pll_div_clk_init(struct clk *c)
+{
+       if (c->flags & DIV_U71) {
+               u32 divu71;
+               u32 val = clk_readl(c->reg);
+               val >>= c->reg_shift;
+               c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
+               if (!(val & PLL_OUT_RESET_DISABLE))
+                       c->state = OFF;
+
+               divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
+               c->div = (divu71 + 2);
+               c->mul = 2;
+       } else if (c->flags & DIV_2) {
+               c->state = ON;
+               if (c->flags & (PLLD | PLLX)) {
+                       c->div = 2;
+                       c->mul = 1;
+               } else
+                       BUG();
+       } else {
+               c->state = ON;
+               c->div = 1;
+               c->mul = 1;
+       }
+}
+
+static int tegra30_pll_div_clk_enable(struct clk *c)
+{
+       u32 val;
+       u32 new_val;
+
+       pr_debug("%s: %s\n", __func__, c->name);
+       if (c->flags & DIV_U71) {
+               val = clk_readl(c->reg);
+               new_val = val >> c->reg_shift;
+               new_val &= 0xFFFF;
+
+               new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+
+               val &= ~(0xFFFF << c->reg_shift);
+               val |= new_val << c->reg_shift;
+               clk_writel_delay(val, c->reg);
+               return 0;
+       } else if (c->flags & DIV_2) {
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static void tegra30_pll_div_clk_disable(struct clk *c)
+{
+       u32 val;
+       u32 new_val;
+
+       pr_debug("%s: %s\n", __func__, c->name);
+       if (c->flags & DIV_U71) {
+               val = clk_readl(c->reg);
+               new_val = val >> c->reg_shift;
+               new_val &= 0xFFFF;
+
+               new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
+
+               val &= ~(0xFFFF << c->reg_shift);
+               val |= new_val << c->reg_shift;
+               clk_writel_delay(val, c->reg);
+       }
+}
+
+static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
+{
+       u32 val;
+       u32 new_val;
+       int divider_u71;
+       unsigned long parent_rate = clk_get_rate(c->parent);
+
+       pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+       if (c->flags & DIV_U71) {
+               divider_u71 = clk_div71_get_divider(
+                       parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+               if (divider_u71 >= 0) {
+                       val = clk_readl(c->reg);
+                       new_val = val >> c->reg_shift;
+                       new_val &= 0xFFFF;
+                       if (c->flags & DIV_U71_FIXED)
+                               new_val |= PLL_OUT_OVERRIDE;
+                       new_val &= ~PLL_OUT_RATIO_MASK;
+                       new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
+
+                       val &= ~(0xFFFF << c->reg_shift);
+                       val |= new_val << c->reg_shift;
+                       clk_writel_delay(val, c->reg);
+                       c->div = divider_u71 + 2;
+                       c->mul = 2;
+                       return 0;
+               }
+       } else if (c->flags & DIV_2)
+               return clk_set_rate(c->parent, rate * 2);
+
+       return -EINVAL;
+}
+
+static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
+{
+       int divider;
+       unsigned long parent_rate = clk_get_rate(c->parent);
+       pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+       if (c->flags & DIV_U71) {
+               divider = clk_div71_get_divider(
+                       parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+               if (divider < 0)
+                       return divider;
+               return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+       } else if (c->flags & DIV_2)
+               /* no rounding - fixed DIV_2 dividers pass rate to parent PLL */
+               return rate;
+
+       return -EINVAL;
+}
+
+static struct clk_ops tegra_pll_div_ops = {
+       .init                   = tegra30_pll_div_clk_init,
+       .enable                 = tegra30_pll_div_clk_enable,
+       .disable                = tegra30_pll_div_clk_disable,
+       .set_rate               = tegra30_pll_div_clk_set_rate,
+       .round_rate             = tegra30_pll_div_clk_round_rate,
+};
+
+/* Periph clk ops */
+static inline u32 periph_clk_source_mask(struct clk *c)
+{
+       if (c->flags & MUX8)
+               return 7 << 29;
+       else if (c->flags & MUX_PWM)
+               return 3 << 28;
+       else if (c->flags & MUX_CLK_OUT)
+               return 3 << (c->u.periph.clk_num + 4);
+       else if (c->flags & PLLD)
+               return PLLD_BASE_DSIB_MUX_MASK;
+       else
+               return 3 << 30;
+}
+
+static inline u32 periph_clk_source_shift(struct clk *c)
+{
+       if (c->flags & MUX8)
+               return 29;
+       else if (c->flags & MUX_PWM)
+               return 28;
+       else if (c->flags & MUX_CLK_OUT)
+               return c->u.periph.clk_num + 4;
+       else if (c->flags & PLLD)
+               return PLLD_BASE_DSIB_MUX_SHIFT;
+       else
+               return 30;
+}
+
+static void tegra30_periph_clk_init(struct clk *c)
+{
+       u32 val = clk_readl(c->reg);
+       const struct clk_mux_sel *mux = 0;
+       const struct clk_mux_sel *sel;
+       if (c->flags & MUX) {
+               for (sel = c->inputs; sel->input != NULL; sel++) {
+                       if (((val & periph_clk_source_mask(c)) >>
+                           periph_clk_source_shift(c)) == sel->value)
+                               mux = sel;
+               }
+               BUG_ON(!mux);
+
+               c->parent = mux->input;
+       } else {
+               c->parent = c->inputs[0].input;
+       }
+
+       if (c->flags & DIV_U71) {
+               u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
+               if ((c->flags & DIV_U71_UART) &&
+                   (!(val & PERIPH_CLK_UART_DIV_ENB))) {
+                       divu71 = 0;
+               }
+               if (c->flags & DIV_U71_IDLE) {
+                       val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
+                               PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+                       val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
+                               PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+                       clk_writel(val, c->reg);
+               }
+               c->div = divu71 + 2;
+               c->mul = 2;
+       } else if (c->flags & DIV_U16) {
+               u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+               c->div = divu16 + 1;
+               c->mul = 1;
+       } else {
+               c->div = 1;
+               c->mul = 1;
+       }
+
+       c->state = ON;
+       if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
+               c->state = OFF;
+       if (!(c->flags & PERIPH_NO_RESET))
+               if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))
+                       c->state = OFF;
+}
+
+static int tegra30_periph_clk_enable(struct clk *c)
+{
+       pr_debug("%s on clock %s\n", __func__, c->name);
+
+       tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
+       if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
+               return 0;
+
+       clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_SET_REG(c));
+       if (!(c->flags & PERIPH_NO_RESET) &&
+                !(c->flags & PERIPH_MANUAL_RESET)) {
+               if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) &
+                        PERIPH_CLK_TO_BIT(c)) {
+                       udelay(5);      /* reset propagation delay */
+                       clk_writel(PERIPH_CLK_TO_BIT(c),
+                                PERIPH_CLK_TO_RST_CLR_REG(c));
+               }
+       }
+       return 0;
+}
+
+static void tegra30_periph_clk_disable(struct clk *c)
+{
+       unsigned long val;
+       pr_debug("%s on clock %s\n", __func__, c->name);
+
+       if (c->refcnt)
+               tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+
+       if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0) {
+               /* If peripheral is in the APB bus then read the APB bus to
+                * flush the write operation in apb bus. This will avoid the
+                * peripheral access after disabling clock*/
+               if (c->flags & PERIPH_ON_APB)
+                       val = chipid_readl();
+
+               clk_writel_delay(
+                       PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
+       }
+}
+
+static void tegra30_periph_clk_reset(struct clk *c, bool assert)
+{
+       unsigned long val;
+       pr_debug("%s %s on clock %s\n", __func__,
+                assert ? "assert" : "deassert", c->name);
+
+       if (!(c->flags & PERIPH_NO_RESET)) {
+               if (assert) {
+                       /* If peripheral is in the APB bus then read the APB
+                        * bus to flush the write operation in apb bus. This
+                        * will avoid the peripheral access after disabling
+                        * clock */
+                       if (c->flags & PERIPH_ON_APB)
+                               val = chipid_readl();
+
+                       clk_writel(PERIPH_CLK_TO_BIT(c),
+                                  PERIPH_CLK_TO_RST_SET_REG(c));
+               } else
+                       clk_writel(PERIPH_CLK_TO_BIT(c),
+                                  PERIPH_CLK_TO_RST_CLR_REG(c));
+       }
+}
+
+static int tegra30_periph_clk_set_parent(struct clk *c, struct clk *p)
+{
+       u32 val;
+       const struct clk_mux_sel *sel;
+       pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+       if (!(c->flags & MUX))
+               return (p == c->parent) ? 0 : (-EINVAL);
+
+       for (sel = c->inputs; sel->input != NULL; sel++) {
+               if (sel->input == p) {
+                       val = clk_readl(c->reg);
+                       val &= ~periph_clk_source_mask(c);
+                       val |= (sel->value << periph_clk_source_shift(c));
+
+                       if (c->refcnt)
+                               clk_enable(p);
+
+                       clk_writel_delay(val, c->reg);
+
+                       if (c->refcnt && c->parent)
+                               clk_disable(c->parent);
+
+                       clk_reparent(c, p);
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
+{
+       u32 val;
+       int divider;
+       unsigned long parent_rate = clk_get_rate(c->parent);
+
+       if (c->flags & DIV_U71) {
+               divider = clk_div71_get_divider(
+                       parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+               if (divider >= 0) {
+                       val = clk_readl(c->reg);
+                       val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
+                       val |= divider;
+                       if (c->flags & DIV_U71_UART) {
+                               if (divider)
+                                       val |= PERIPH_CLK_UART_DIV_ENB;
+                               else
+                                       val &= ~PERIPH_CLK_UART_DIV_ENB;
+                       }
+                       clk_writel_delay(val, c->reg);
+                       c->div = divider + 2;
+                       c->mul = 2;
+                       return 0;
+               }
+       } else if (c->flags & DIV_U16) {
+               divider = clk_div16_get_divider(parent_rate, rate);
+               if (divider >= 0) {
+                       val = clk_readl(c->reg);
+                       val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
+                       val |= divider;
+                       clk_writel_delay(val, c->reg);
+                       c->div = divider + 1;
+                       c->mul = 1;
+                       return 0;
+               }
+       } else if (parent_rate <= rate) {
+               c->div = 1;
+               c->mul = 1;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static long tegra30_periph_clk_round_rate(struct clk *c,
+       unsigned long rate)
+{
+       int divider;
+       unsigned long parent_rate = clk_get_rate(c->parent);
+       pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+       if (c->flags & DIV_U71) {
+               divider = clk_div71_get_divider(
+                       parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+               if (divider < 0)
+                       return divider;
+
+               return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+       } else if (c->flags & DIV_U16) {
+               divider = clk_div16_get_divider(parent_rate, rate);
+               if (divider < 0)
+                       return divider;
+               return DIV_ROUND_UP(parent_rate, divider + 1);
+       }
+       return -EINVAL;
+}
+
+static struct clk_ops tegra_periph_clk_ops = {
+       .init                   = &tegra30_periph_clk_init,
+       .enable                 = &tegra30_periph_clk_enable,
+       .disable                = &tegra30_periph_clk_disable,
+       .set_parent             = &tegra30_periph_clk_set_parent,
+       .set_rate               = &tegra30_periph_clk_set_rate,
+       .round_rate             = &tegra30_periph_clk_round_rate,
+       .reset                  = &tegra30_periph_clk_reset,
+};
+
+
+/* Periph extended clock configuration ops */
+static int
+tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+       if (p == TEGRA_CLK_VI_INP_SEL) {
+               u32 val = clk_readl(c->reg);
+               val &= ~PERIPH_CLK_VI_SEL_EX_MASK;
+               val |= (setting << PERIPH_CLK_VI_SEL_EX_SHIFT) &
+                       PERIPH_CLK_VI_SEL_EX_MASK;
+               clk_writel(val, c->reg);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static struct clk_ops tegra_vi_clk_ops = {
+       .init                   = &tegra30_periph_clk_init,
+       .enable                 = &tegra30_periph_clk_enable,
+       .disable                = &tegra30_periph_clk_disable,
+       .set_parent             = &tegra30_periph_clk_set_parent,
+       .set_rate               = &tegra30_periph_clk_set_rate,
+       .round_rate             = &tegra30_periph_clk_round_rate,
+       .clk_cfg_ex             = &tegra30_vi_clk_cfg_ex,
+       .reset                  = &tegra30_periph_clk_reset,
+};
+
+static int
+tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+       if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) {
+               u32 val = clk_readl(c->reg);
+               if (setting)
+                       val |= PERIPH_CLK_NAND_DIV_EX_ENB;
+               else
+                       val &= ~PERIPH_CLK_NAND_DIV_EX_ENB;
+               clk_writel(val, c->reg);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static struct clk_ops tegra_nand_clk_ops = {
+       .init                   = &tegra30_periph_clk_init,
+       .enable                 = &tegra30_periph_clk_enable,
+       .disable                = &tegra30_periph_clk_disable,
+       .set_parent             = &tegra30_periph_clk_set_parent,
+       .set_rate               = &tegra30_periph_clk_set_rate,
+       .round_rate             = &tegra30_periph_clk_round_rate,
+       .clk_cfg_ex             = &tegra30_nand_clk_cfg_ex,
+       .reset                  = &tegra30_periph_clk_reset,
+};
+
+
+static int
+tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+       if (p == TEGRA_CLK_DTV_INVERT) {
+               u32 val = clk_readl(c->reg);
+               if (setting)
+                       val |= PERIPH_CLK_DTV_POLARITY_INV;
+               else
+                       val &= ~PERIPH_CLK_DTV_POLARITY_INV;
+               clk_writel(val, c->reg);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static struct clk_ops tegra_dtv_clk_ops = {
+       .init                   = &tegra30_periph_clk_init,
+       .enable                 = &tegra30_periph_clk_enable,
+       .disable                = &tegra30_periph_clk_disable,
+       .set_parent             = &tegra30_periph_clk_set_parent,
+       .set_rate               = &tegra30_periph_clk_set_rate,
+       .round_rate             = &tegra30_periph_clk_round_rate,
+       .clk_cfg_ex             = &tegra30_dtv_clk_cfg_ex,
+       .reset                  = &tegra30_periph_clk_reset,
+};
+
+static int tegra30_dsib_clk_set_parent(struct clk *c, struct clk *p)
+{
+       const struct clk_mux_sel *sel;
+       struct clk *d = tegra_get_clock_by_name("pll_d");
+
+       pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+       for (sel = c->inputs; sel->input != NULL; sel++) {
+               if (sel->input == p) {
+                       if (c->refcnt)
+                               clk_enable(p);
+
+                       /* The DSIB parent selection bit is in PLLD base
+                          register - can not do direct r-m-w, must be
+                          protected by PLLD lock */
+                       tegra_clk_cfg_ex(
+                               d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, sel->value);
+
+                       if (c->refcnt && c->parent)
+                               clk_disable(c->parent);
+
+                       clk_reparent(c, p);
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static struct clk_ops tegra_dsib_clk_ops = {
+       .init                   = &tegra30_periph_clk_init,
+       .enable                 = &tegra30_periph_clk_enable,
+       .disable                = &tegra30_periph_clk_disable,
+       .set_parent             = &tegra30_dsib_clk_set_parent,
+       .set_rate               = &tegra30_periph_clk_set_rate,
+       .round_rate             = &tegra30_periph_clk_round_rate,
+       .reset                  = &tegra30_periph_clk_reset,
+};
+
+/* pciex clock support only reset function */
+static struct clk_ops tegra_pciex_clk_ops = {
+       .reset    = tegra30_periph_clk_reset,
+};
+
+/* Output clock ops */
+
+static DEFINE_SPINLOCK(clk_out_lock);
+
+static void tegra30_clk_out_init(struct clk *c)
+{
+       const struct clk_mux_sel *mux = 0;
+       const struct clk_mux_sel *sel;
+       u32 val = pmc_readl(c->reg);
+
+       c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF;
+       c->mul = 1;
+       c->div = 1;
+
+       for (sel = c->inputs; sel->input != NULL; sel++) {
+               if (((val & periph_clk_source_mask(c)) >>
+                    periph_clk_source_shift(c)) == sel->value)
+                       mux = sel;
+       }
+       BUG_ON(!mux);
+       c->parent = mux->input;
+}
+
+static int tegra30_clk_out_enable(struct clk *c)
+{
+       u32 val;
+       unsigned long flags;
+
+       pr_debug("%s on clock %s\n", __func__, c->name);
+
+       spin_lock_irqsave(&clk_out_lock, flags);
+       val = pmc_readl(c->reg);
+       val |= (0x1 << c->u.periph.clk_num);
+       pmc_writel(val, c->reg);
+       spin_unlock_irqrestore(&clk_out_lock, flags);
+
+       return 0;
+}
+
+static void tegra30_clk_out_disable(struct clk *c)
+{
+       u32 val;
+       unsigned long flags;
+
+       pr_debug("%s on clock %s\n", __func__, c->name);
+
+       spin_lock_irqsave(&clk_out_lock, flags);
+       val = pmc_readl(c->reg);
+       val &= ~(0x1 << c->u.periph.clk_num);
+       pmc_writel(val, c->reg);
+       spin_unlock_irqrestore(&clk_out_lock, flags);
+}
+
+static int tegra30_clk_out_set_parent(struct clk *c, struct clk *p)
+{
+       u32 val;
+       unsigned long flags;
+       const struct clk_mux_sel *sel;
+
+       pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+       for (sel = c->inputs; sel->input != NULL; sel++) {
+               if (sel->input == p) {
+                       if (c->refcnt)
+                               clk_enable(p);
+
+                       spin_lock_irqsave(&clk_out_lock, flags);
+                       val = pmc_readl(c->reg);
+                       val &= ~periph_clk_source_mask(c);
+                       val |= (sel->value << periph_clk_source_shift(c));
+                       pmc_writel(val, c->reg);
+                       spin_unlock_irqrestore(&clk_out_lock, flags);
+
+                       if (c->refcnt && c->parent)
+                               clk_disable(c->parent);
+
+                       clk_reparent(c, p);
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+static struct clk_ops tegra_clk_out_ops = {
+       .init                   = &tegra30_clk_out_init,
+       .enable                 = &tegra30_clk_out_enable,
+       .disable                = &tegra30_clk_out_disable,
+       .set_parent             = &tegra30_clk_out_set_parent,
+};
+
+
+/* Clock doubler ops */
+static void tegra30_clk_double_init(struct clk *c)
+{
+       u32 val = clk_readl(c->reg);
+       c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
+       c->div = 1;
+       c->state = ON;
+       if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
+               c->state = OFF;
+};
+
+static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
+{
+       u32 val;
+       unsigned long parent_rate = clk_get_rate(c->parent);
+       if (rate == parent_rate) {
+               val = clk_readl(c->reg) | (0x1 << c->reg_shift);
+               clk_writel(val, c->reg);
+               c->mul = 1;
+               c->div = 1;
+               return 0;
+       } else if (rate == 2 * parent_rate) {
+               val = clk_readl(c->reg) & (~(0x1 << c->reg_shift));
+               clk_writel(val, c->reg);
+               c->mul = 2;
+               c->div = 1;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static struct clk_ops tegra_clk_double_ops = {
+       .init                   = &tegra30_clk_double_init,
+       .enable                 = &tegra30_periph_clk_enable,
+       .disable                = &tegra30_periph_clk_disable,
+       .set_rate               = &tegra30_clk_double_set_rate,
+};
+
+/* Audio sync clock ops */
+static int tegra30_sync_source_set_rate(struct clk *c, unsigned long rate)
+{
+       c->rate = rate;
+       return 0;
+}
+
+static struct clk_ops tegra_sync_source_ops = {
+       .set_rate               = &tegra30_sync_source_set_rate,
+};
+
+static void tegra30_audio_sync_clk_init(struct clk *c)
+{
+       int source;
+       const struct clk_mux_sel *sel;
+       u32 val = clk_readl(c->reg);
+       c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON;
+       source = val & AUDIO_SYNC_SOURCE_MASK;
+       for (sel = c->inputs; sel->input != NULL; sel++)
+               if (sel->value == source)
+                       break;
+       BUG_ON(sel->input == NULL);
+       c->parent = sel->input;
+}
+
+static int tegra30_audio_sync_clk_enable(struct clk *c)
+{
+       u32 val = clk_readl(c->reg);
+       clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg);
+       return 0;
+}
+
+static void tegra30_audio_sync_clk_disable(struct clk *c)
+{
+       u32 val = clk_readl(c->reg);
+       clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg);
+}
+
+static int tegra30_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
+{
+       u32 val;
+       const struct clk_mux_sel *sel;
+       for (sel = c->inputs; sel->input != NULL; sel++) {
+               if (sel->input == p) {
+                       val = clk_readl(c->reg);
+                       val &= ~AUDIO_SYNC_SOURCE_MASK;
+                       val |= sel->value;
+
+                       if (c->refcnt)
+                               clk_enable(p);
+
+                       clk_writel(val, c->reg);
+
+                       if (c->refcnt && c->parent)
+                               clk_disable(c->parent);
+
+                       clk_reparent(c, p);
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static struct clk_ops tegra_audio_sync_clk_ops = {
+       .init       = tegra30_audio_sync_clk_init,
+       .enable     = tegra30_audio_sync_clk_enable,
+       .disable    = tegra30_audio_sync_clk_disable,
+       .set_parent = tegra30_audio_sync_clk_set_parent,
+};
+
+/* cml0 (pcie), and cml1 (sata) clock ops */
+static void tegra30_cml_clk_init(struct clk *c)
+{
+       u32 val = clk_readl(c->reg);
+       c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF;
+}
+
+static int tegra30_cml_clk_enable(struct clk *c)
+{
+       u32 val = clk_readl(c->reg);
+       val |= (0x1 << c->u.periph.clk_num);
+       clk_writel(val, c->reg);
+       return 0;
+}
+
+static void tegra30_cml_clk_disable(struct clk *c)
+{
+       u32 val = clk_readl(c->reg);
+       val &= ~(0x1 << c->u.periph.clk_num);
+       clk_writel(val, c->reg);
+}
+
+static struct clk_ops tegra_cml_clk_ops = {
+       .init                   = &tegra30_cml_clk_init,
+       .enable                 = &tegra30_cml_clk_enable,
+       .disable                = &tegra30_cml_clk_disable,
+};
+
+/* Clock definitions */
+static struct clk tegra_clk_32k = {
+       .name = "clk_32k",
+       .rate = 32768,
+       .ops  = NULL,
+       .max_rate = 32768,
+};
+
+static struct clk tegra_clk_m = {
+       .name      = "clk_m",
+       .flags     = ENABLE_ON_INIT,
+       .ops       = &tegra_clk_m_ops,
+       .reg       = 0x1fc,
+       .reg_shift = 28,
+       .max_rate  = 48000000,
+};
+
+static struct clk tegra_clk_m_div2 = {
+       .name      = "clk_m_div2",
+       .ops       = &tegra_clk_m_div_ops,
+       .parent    = &tegra_clk_m,
+       .mul       = 1,
+       .div       = 2,
+       .state     = ON,
+       .max_rate  = 24000000,
+};
+
+static struct clk tegra_clk_m_div4 = {
+       .name      = "clk_m_div4",
+       .ops       = &tegra_clk_m_div_ops,
+       .parent    = &tegra_clk_m,
+       .mul       = 1,
+       .div       = 4,
+       .state     = ON,
+       .max_rate  = 12000000,
+};
+
+static struct clk tegra_pll_ref = {
+       .name      = "pll_ref",
+       .flags     = ENABLE_ON_INIT,
+       .ops       = &tegra_pll_ref_ops,
+       .parent    = &tegra_clk_m,
+       .max_rate  = 26000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
+       { 12000000, 1040000000, 520,  6, 1, 8},
+       { 13000000, 1040000000, 480,  6, 1, 8},
+       { 16800000, 1040000000, 495,  8, 1, 8},         /* actual: 1039.5 MHz */
+       { 19200000, 1040000000, 325,  6, 1, 6},
+       { 26000000, 1040000000, 520, 13, 1, 8},
+
+       { 12000000, 832000000, 416,  6, 1, 8},
+       { 13000000, 832000000, 832, 13, 1, 8},
+       { 16800000, 832000000, 396,  8, 1, 8},          /* actual: 831.6 MHz */
+       { 19200000, 832000000, 260,  6, 1, 8},
+       { 26000000, 832000000, 416, 13, 1, 8},
+
+       { 12000000, 624000000, 624, 12, 1, 8},
+       { 13000000, 624000000, 624, 13, 1, 8},
+       { 16800000, 600000000, 520, 14, 1, 8},
+       { 19200000, 624000000, 520, 16, 1, 8},
+       { 26000000, 624000000, 624, 26, 1, 8},
+
+       { 12000000, 600000000, 600, 12, 1, 8},
+       { 13000000, 600000000, 600, 13, 1, 8},
+       { 16800000, 600000000, 500, 14, 1, 8},
+       { 19200000, 600000000, 375, 12, 1, 6},
+       { 26000000, 600000000, 600, 26, 1, 8},
+
+       { 12000000, 520000000, 520, 12, 1, 8},
+       { 13000000, 520000000, 520, 13, 1, 8},
+       { 16800000, 520000000, 495, 16, 1, 8},          /* actual: 519.75 MHz */
+       { 19200000, 520000000, 325, 12, 1, 6},
+       { 26000000, 520000000, 520, 26, 1, 8},
+
+       { 12000000, 416000000, 416, 12, 1, 8},
+       { 13000000, 416000000, 416, 13, 1, 8},
+       { 16800000, 416000000, 396, 16, 1, 8},          /* actual: 415.8 MHz */
+       { 19200000, 416000000, 260, 12, 1, 6},
+       { 26000000, 416000000, 416, 26, 1, 8},
+       { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_c = {
+       .name      = "pll_c",
+       .flags     = PLL_HAS_CPCON,
+       .ops       = &tegra_pll_ops,
+       .reg       = 0x80,
+       .parent    = &tegra_pll_ref,
+       .max_rate  = 1400000000,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 31000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 20000000,
+               .vco_max   = 1400000000,
+               .freq_table = tegra_pll_c_freq_table,
+               .lock_delay = 300,
+       },
+};
+
+static struct clk tegra_pll_c_out1 = {
+       .name      = "pll_c_out1",
+       .ops       = &tegra_pll_div_ops,
+       .flags     = DIV_U71,
+       .parent    = &tegra_pll_c,
+       .reg       = 0x84,
+       .reg_shift = 0,
+       .max_rate  = 700000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
+       { 12000000, 666000000, 666, 12, 1, 8},
+       { 13000000, 666000000, 666, 13, 1, 8},
+       { 16800000, 666000000, 555, 14, 1, 8},
+       { 19200000, 666000000, 555, 16, 1, 8},
+       { 26000000, 666000000, 666, 26, 1, 8},
+       { 12000000, 600000000, 600, 12, 1, 8},
+       { 13000000, 600000000, 600, 13, 1, 8},
+       { 16800000, 600000000, 500, 14, 1, 8},
+       { 19200000, 600000000, 375, 12, 1, 6},
+       { 26000000, 600000000, 600, 26, 1, 8},
+       { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_m = {
+       .name      = "pll_m",
+       .flags     = PLL_HAS_CPCON | PLLM,
+       .ops       = &tegra_pll_ops,
+       .reg       = 0x90,
+       .parent    = &tegra_pll_ref,
+       .max_rate  = 800000000,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 31000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 20000000,
+               .vco_max   = 1200000000,
+               .freq_table = tegra_pll_m_freq_table,
+               .lock_delay = 300,
+       },
+};
+
+static struct clk tegra_pll_m_out1 = {
+       .name      = "pll_m_out1",
+       .ops       = &tegra_pll_div_ops,
+       .flags     = DIV_U71,
+       .parent    = &tegra_pll_m,
+       .reg       = 0x94,
+       .reg_shift = 0,
+       .max_rate  = 600000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
+       { 12000000, 216000000, 432, 12, 2, 8},
+       { 13000000, 216000000, 432, 13, 2, 8},
+       { 16800000, 216000000, 360, 14, 2, 8},
+       { 19200000, 216000000, 360, 16, 2, 8},
+       { 26000000, 216000000, 432, 26, 2, 8},
+       { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_p = {
+       .name      = "pll_p",
+       .flags     = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
+       .ops       = &tegra_pll_ops,
+       .reg       = 0xa0,
+       .parent    = &tegra_pll_ref,
+       .max_rate  = 432000000,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 31000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 20000000,
+               .vco_max   = 1400000000,
+               .freq_table = tegra_pll_p_freq_table,
+               .lock_delay = 300,
+               .fixed_rate = 408000000,
+       },
+};
+
+static struct clk tegra_pll_p_out1 = {
+       .name      = "pll_p_out1",
+       .ops       = &tegra_pll_div_ops,
+       .flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+       .parent    = &tegra_pll_p,
+       .reg       = 0xa4,
+       .reg_shift = 0,
+       .max_rate  = 432000000,
+};
+
+static struct clk tegra_pll_p_out2 = {
+       .name      = "pll_p_out2",
+       .ops       = &tegra_pll_div_ops,
+       .flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+       .parent    = &tegra_pll_p,
+       .reg       = 0xa4,
+       .reg_shift = 16,
+       .max_rate  = 432000000,
+};
+
+static struct clk tegra_pll_p_out3 = {
+       .name      = "pll_p_out3",
+       .ops       = &tegra_pll_div_ops,
+       .flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+       .parent    = &tegra_pll_p,
+       .reg       = 0xa8,
+       .reg_shift = 0,
+       .max_rate  = 432000000,
+};
+
+static struct clk tegra_pll_p_out4 = {
+       .name      = "pll_p_out4",
+       .ops       = &tegra_pll_div_ops,
+       .flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+       .parent    = &tegra_pll_p,
+       .reg       = 0xa8,
+       .reg_shift = 16,
+       .max_rate  = 432000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
+       { 9600000, 564480000, 294, 5, 1, 4},
+       { 9600000, 552960000, 288, 5, 1, 4},
+       { 9600000, 24000000,  5,   2, 1, 1},
+
+       { 28800000, 56448000, 49, 25, 1, 1},
+       { 28800000, 73728000, 64, 25, 1, 1},
+       { 28800000, 24000000,  5,  6, 1, 1},
+       { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_a = {
+       .name      = "pll_a",
+       .flags     = PLL_HAS_CPCON,
+       .ops       = &tegra_pll_ops,
+       .reg       = 0xb0,
+       .parent    = &tegra_pll_p_out1,
+       .max_rate  = 700000000,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 31000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 20000000,
+               .vco_max   = 1400000000,
+               .freq_table = tegra_pll_a_freq_table,
+               .lock_delay = 300,
+       },
+};
+
+static struct clk tegra_pll_a_out0 = {
+       .name      = "pll_a_out0",
+       .ops       = &tegra_pll_div_ops,
+       .flags     = DIV_U71,
+       .parent    = &tegra_pll_a,
+       .reg       = 0xb4,
+       .reg_shift = 0,
+       .max_rate  = 100000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
+       { 12000000, 216000000, 216, 12, 1, 4},
+       { 13000000, 216000000, 216, 13, 1, 4},
+       { 16800000, 216000000, 180, 14, 1, 4},
+       { 19200000, 216000000, 180, 16, 1, 4},
+       { 26000000, 216000000, 216, 26, 1, 4},
+
+       { 12000000, 594000000, 594, 12, 1, 8},
+       { 13000000, 594000000, 594, 13, 1, 8},
+       { 16800000, 594000000, 495, 14, 1, 8},
+       { 19200000, 594000000, 495, 16, 1, 8},
+       { 26000000, 594000000, 594, 26, 1, 8},
+
+       { 12000000, 1000000000, 1000, 12, 1, 12},
+       { 13000000, 1000000000, 1000, 13, 1, 12},
+       { 19200000, 1000000000, 625,  12, 1, 8},
+       { 26000000, 1000000000, 1000, 26, 1, 12},
+
+       { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_d = {
+       .name      = "pll_d",
+       .flags     = PLL_HAS_CPCON | PLLD,
+       .ops       = &tegra_plld_ops,
+       .reg       = 0xd0,
+       .parent    = &tegra_pll_ref,
+       .max_rate  = 1000000000,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 40000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 40000000,
+               .vco_max   = 1000000000,
+               .freq_table = tegra_pll_d_freq_table,
+               .lock_delay = 1000,
+       },
+};
+
+static struct clk tegra_pll_d_out0 = {
+       .name      = "pll_d_out0",
+       .ops       = &tegra_pll_div_ops,
+       .flags     = DIV_2 | PLLD,
+       .parent    = &tegra_pll_d,
+       .max_rate  = 500000000,
+};
+
+static struct clk tegra_pll_d2 = {
+       .name      = "pll_d2",
+       .flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD,
+       .ops       = &tegra_plld_ops,
+       .reg       = 0x4b8,
+       .parent    = &tegra_pll_ref,
+       .max_rate  = 1000000000,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 40000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 40000000,
+               .vco_max   = 1000000000,
+               .freq_table = tegra_pll_d_freq_table,
+               .lock_delay = 1000,
+       },
+};
+
+static struct clk tegra_pll_d2_out0 = {
+       .name      = "pll_d2_out0",
+       .ops       = &tegra_pll_div_ops,
+       .flags     = DIV_2 | PLLD,
+       .parent    = &tegra_pll_d2,
+       .max_rate  = 500000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
+       { 12000000, 480000000, 960, 12, 2, 12},
+       { 13000000, 480000000, 960, 13, 2, 12},
+       { 16800000, 480000000, 400, 7,  2, 5},
+       { 19200000, 480000000, 200, 4,  2, 3},
+       { 26000000, 480000000, 960, 26, 2, 12},
+       { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_u = {
+       .name      = "pll_u",
+       .flags     = PLL_HAS_CPCON | PLLU,
+       .ops       = &tegra_pll_ops,
+       .reg       = 0xc0,
+       .parent    = &tegra_pll_ref,
+       .max_rate  = 480000000,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 40000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 480000000,
+               .vco_max   = 960000000,
+               .freq_table = tegra_pll_u_freq_table,
+               .lock_delay = 1000,
+       },
+};
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
+       /* 1.7 GHz */
+       { 12000000, 1700000000, 850,  6,  1, 8},
+       { 13000000, 1700000000, 915,  7,  1, 8},        /* actual: 1699.2 MHz */
+       { 16800000, 1700000000, 708,  7,  1, 8},        /* actual: 1699.2 MHz */
+       { 19200000, 1700000000, 885,  10, 1, 8},        /* actual: 1699.2 MHz */
+       { 26000000, 1700000000, 850,  13, 1, 8},
+
+       /* 1.6 GHz */
+       { 12000000, 1600000000, 800,  6,  1, 8},
+       { 13000000, 1600000000, 738,  6,  1, 8},        /* actual: 1599.0 MHz */
+       { 16800000, 1600000000, 857,  9,  1, 8},        /* actual: 1599.7 MHz */
+       { 19200000, 1600000000, 500,  6,  1, 8},
+       { 26000000, 1600000000, 800,  13, 1, 8},
+
+       /* 1.5 GHz */
+       { 12000000, 1500000000, 750,  6,  1, 8},
+       { 13000000, 1500000000, 923,  8,  1, 8},        /* actual: 1499.8 MHz */
+       { 16800000, 1500000000, 625,  7,  1, 8},
+       { 19200000, 1500000000, 625,  8,  1, 8},
+       { 26000000, 1500000000, 750,  13, 1, 8},
+
+       /* 1.4 GHz */
+       { 12000000, 1400000000, 700,  6,  1, 8},
+       { 13000000, 1400000000, 969,  9,  1, 8},        /* actual: 1399.7 MHz */
+       { 16800000, 1400000000, 1000, 12, 1, 8},
+       { 19200000, 1400000000, 875,  12, 1, 8},
+       { 26000000, 1400000000, 700,  13, 1, 8},
+
+       /* 1.3 GHz */
+       { 12000000, 1300000000, 975,  9,  1, 8},
+       { 13000000, 1300000000, 1000, 10, 1, 8},
+       { 16800000, 1300000000, 928,  12, 1, 8},        /* actual: 1299.2 MHz */
+       { 19200000, 1300000000, 812,  12, 1, 8},        /* actual: 1299.2 MHz */
+       { 26000000, 1300000000, 650,  13, 1, 8},
+
+       /* 1.2 GHz */
+       { 12000000, 1200000000, 1000, 10, 1, 8},
+       { 13000000, 1200000000, 923,  10, 1, 8},        /* actual: 1199.9 MHz */
+       { 16800000, 1200000000, 1000, 14, 1, 8},
+       { 19200000, 1200000000, 1000, 16, 1, 8},
+       { 26000000, 1200000000, 600,  13, 1, 8},
+
+       /* 1.1 GHz */
+       { 12000000, 1100000000, 825,  9,  1, 8},
+       { 13000000, 1100000000, 846,  10, 1, 8},        /* actual: 1099.8 MHz */
+       { 16800000, 1100000000, 982,  15, 1, 8},        /* actual: 1099.8 MHz */
+       { 19200000, 1100000000, 859,  15, 1, 8},        /* actual: 1099.5 MHz */
+       { 26000000, 1100000000, 550,  13, 1, 8},
+
+       /* 1 GHz */
+       { 12000000, 1000000000, 1000, 12, 1, 8},
+       { 13000000, 1000000000, 1000, 13, 1, 8},
+       { 16800000, 1000000000, 833,  14, 1, 8},        /* actual: 999.6 MHz */
+       { 19200000, 1000000000, 625,  12, 1, 8},
+       { 26000000, 1000000000, 1000, 26, 1, 8},
+
+       { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_x = {
+       .name      = "pll_x",
+       .flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX,
+       .ops       = &tegra_pll_ops,
+       .reg       = 0xe0,
+       .parent    = &tegra_pll_ref,
+       .max_rate  = 1700000000,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 31000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 20000000,
+               .vco_max   = 1700000000,
+               .freq_table = tegra_pll_x_freq_table,
+               .lock_delay = 300,
+       },
+};
+
+static struct clk tegra_pll_x_out0 = {
+       .name      = "pll_x_out0",
+       .ops       = &tegra_pll_div_ops,
+       .flags     = DIV_2 | PLLX,
+       .parent    = &tegra_pll_x,
+       .max_rate  = 850000000,
+};
+
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
+       /* PLLE special case: use cpcon field to store cml divider value */
+       { 12000000,  100000000, 150, 1,  18, 11},
+       { 216000000, 100000000, 200, 18, 24, 13},
+       { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_e = {
+       .name      = "pll_e",
+       .flags     = PLL_ALT_MISC_REG,
+       .ops       = &tegra_plle_ops,
+       .reg       = 0xe8,
+       .max_rate  = 100000000,
+       .u.pll = {
+               .input_min = 12000000,
+               .input_max = 216000000,
+               .cf_min    = 12000000,
+               .cf_max    = 12000000,
+               .vco_min   = 1200000000,
+               .vco_max   = 2400000000U,
+               .freq_table = tegra_pll_e_freq_table,
+               .lock_delay = 300,
+               .fixed_rate = 100000000,
+       },
+};
+
+static struct clk tegra_cml0_clk = {
+       .name      = "cml0",
+       .parent    = &tegra_pll_e,
+       .ops       = &tegra_cml_clk_ops,
+       .reg       = PLLE_AUX,
+       .max_rate  = 100000000,
+       .u.periph  = {
+               .clk_num = 0,
+       },
+};
+
+static struct clk tegra_cml1_clk = {
+       .name      = "cml1",
+       .parent    = &tegra_pll_e,
+       .ops       = &tegra_cml_clk_ops,
+       .reg       = PLLE_AUX,
+       .max_rate  = 100000000,
+       .u.periph  = {
+               .clk_num   = 1,
+       },
+};
+
+static struct clk tegra_pciex_clk = {
+       .name      = "pciex",
+       .parent    = &tegra_pll_e,
+       .ops       = &tegra_pciex_clk_ops,
+       .max_rate  = 100000000,
+       .u.periph  = {
+               .clk_num   = 74,
+       },
+};
+
+/* Audio sync clocks */
+#define SYNC_SOURCE(_id)                               \
+       {                                               \
+               .name      = #_id "_sync",              \
+               .rate      = 24000000,                  \
+               .max_rate  = 24000000,                  \
+               .ops       = &tegra_sync_source_ops     \
+       }
+static struct clk tegra_sync_source_list[] = {
+       SYNC_SOURCE(spdif_in),
+       SYNC_SOURCE(i2s0),
+       SYNC_SOURCE(i2s1),
+       SYNC_SOURCE(i2s2),
+       SYNC_SOURCE(i2s3),
+       SYNC_SOURCE(i2s4),
+       SYNC_SOURCE(vimclk),
+};
+
+static struct clk_mux_sel mux_audio_sync_clk[] = {
+       { .input = &tegra_sync_source_list[0],  .value = 0},
+       { .input = &tegra_sync_source_list[1],  .value = 1},
+       { .input = &tegra_sync_source_list[2],  .value = 2},
+       { .input = &tegra_sync_source_list[3],  .value = 3},
+       { .input = &tegra_sync_source_list[4],  .value = 4},
+       { .input = &tegra_sync_source_list[5],  .value = 5},
+       { .input = &tegra_pll_a_out0,           .value = 6},
+       { .input = &tegra_sync_source_list[6],  .value = 7},
+       { 0, 0 }
+};
+
+#define AUDIO_SYNC_CLK(_id, _index)                    \
+       {                                               \
+               .name      = #_id,                      \
+               .inputs    = mux_audio_sync_clk,        \
+               .reg       = 0x4A0 + (_index) * 4,      \
+               .max_rate  = 24000000,                  \
+               .ops       = &tegra_audio_sync_clk_ops  \
+       }
+static struct clk tegra_clk_audio_list[] = {
+       AUDIO_SYNC_CLK(audio0, 0),
+       AUDIO_SYNC_CLK(audio1, 1),
+       AUDIO_SYNC_CLK(audio2, 2),
+       AUDIO_SYNC_CLK(audio3, 3),
+       AUDIO_SYNC_CLK(audio4, 4),
+       AUDIO_SYNC_CLK(audio, 5),       /* SPDIF */
+};
+
+#define AUDIO_SYNC_2X_CLK(_id, _index)                         \
+       {                                                       \
+               .name      = #_id "_2x",                        \
+               .flags     = PERIPH_NO_RESET,                   \
+               .max_rate  = 48000000,                          \
+               .ops       = &tegra_clk_double_ops,             \
+               .reg       = 0x49C,                             \
+               .reg_shift = 24 + (_index),                     \
+               .parent    = &tegra_clk_audio_list[(_index)],   \
+               .u.periph = {                                   \
+                       .clk_num = 113 + (_index),              \
+               },                                              \
+       }
+static struct clk tegra_clk_audio_2x_list[] = {
+       AUDIO_SYNC_2X_CLK(audio0, 0),
+       AUDIO_SYNC_2X_CLK(audio1, 1),
+       AUDIO_SYNC_2X_CLK(audio2, 2),
+       AUDIO_SYNC_2X_CLK(audio3, 3),
+       AUDIO_SYNC_2X_CLK(audio4, 4),
+       AUDIO_SYNC_2X_CLK(audio, 5),    /* SPDIF */
+};
+
+#define MUX_I2S_SPDIF(_id, _index)                                     \
+static struct clk_mux_sel mux_pllaout0_##_id##_2x_pllp_clkm[] = {      \
+       {.input = &tegra_pll_a_out0, .value = 0},                       \
+       {.input = &tegra_clk_audio_2x_list[(_index)], .value = 1},      \
+       {.input = &tegra_pll_p, .value = 2},                            \
+       {.input = &tegra_clk_m, .value = 3},                            \
+       { 0, 0},                                                        \
+}
+MUX_I2S_SPDIF(audio0, 0);
+MUX_I2S_SPDIF(audio1, 1);
+MUX_I2S_SPDIF(audio2, 2);
+MUX_I2S_SPDIF(audio3, 3);
+MUX_I2S_SPDIF(audio4, 4);
+MUX_I2S_SPDIF(audio, 5);               /* SPDIF */
+
+/* External clock outputs (through PMC) */
+#define MUX_EXTERN_OUT(_id)                                            \
+static struct clk_mux_sel mux_clkm_clkm2_clkm4_extern##_id[] = {       \
+       {.input = &tegra_clk_m,         .value = 0},                    \
+       {.input = &tegra_clk_m_div2,    .value = 1},                    \
+       {.input = &tegra_clk_m_div4,    .value = 2},                    \
+       {.input = NULL,                 .value = 3}, /* placeholder */  \
+       { 0, 0},                                                        \
+}
+MUX_EXTERN_OUT(1);
+MUX_EXTERN_OUT(2);
+MUX_EXTERN_OUT(3);
+
+static struct clk_mux_sel *mux_extern_out_list[] = {
+       mux_clkm_clkm2_clkm4_extern1,
+       mux_clkm_clkm2_clkm4_extern2,
+       mux_clkm_clkm2_clkm4_extern3,
+};
+
+#define CLK_OUT_CLK(_id)                                       \
+       {                                                       \
+               .name      = "clk_out_" #_id,                   \
+               .lookup    = {                                  \
+                       .dev_id    = "clk_out_" #_id,           \
+                       .con_id    = "extern" #_id,             \
+               },                                              \
+               .ops       = &tegra_clk_out_ops,                \
+               .reg       = 0x1a8,                             \
+               .inputs    = mux_clkm_clkm2_clkm4_extern##_id,  \
+               .flags     = MUX_CLK_OUT,                       \
+               .max_rate  = 216000000,                         \
+               .u.periph = {                                   \
+                       .clk_num   = (_id - 1) * 8 + 2,         \
+               },                                              \
+       }
+static struct clk tegra_clk_out_list[] = {
+       CLK_OUT_CLK(1),
+       CLK_OUT_CLK(2),
+       CLK_OUT_CLK(3),
+};
+
+/* called after peripheral external clocks are initialized */
+static void init_clk_out_mux(void)
+{
+       int i;
+       struct clk *c;
+
+       /* output clock con_id is the name of peripheral
+          external clock connected to input 3 of the output mux */
+       for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) {
+               c = tegra_get_clock_by_name(
+                       tegra_clk_out_list[i].lookup.con_id);
+               if (!c)
+                       pr_err("%s: could not find clk %s\n", __func__,
+                              tegra_clk_out_list[i].lookup.con_id);
+               mux_extern_out_list[i][3].input = c;
+       }
+}
+
+/* Peripheral muxes */
+static struct clk_mux_sel mux_sclk[] = {
+       { .input = &tegra_clk_m,        .value = 0},
+       { .input = &tegra_pll_c_out1,   .value = 1},
+       { .input = &tegra_pll_p_out4,   .value = 2},
+       { .input = &tegra_pll_p_out3,   .value = 3},
+       { .input = &tegra_pll_p_out2,   .value = 4},
+       /* { .input = &tegra_clk_d,     .value = 5}, - no use on tegra30 */
+       { .input = &tegra_clk_32k,      .value = 6},
+       { .input = &tegra_pll_m_out1,   .value = 7},
+       { 0, 0},
+};
+
+static struct clk tegra_clk_sclk = {
+       .name   = "sclk",
+       .inputs = mux_sclk,
+       .reg    = 0x28,
+       .ops    = &tegra_super_ops,
+       .max_rate = 334000000,
+       .min_rate = 40000000,
+};
+
+static struct clk tegra_clk_blink = {
+       .name           = "blink",
+       .parent         = &tegra_clk_32k,
+       .reg            = 0x40,
+       .ops            = &tegra_blink_clk_ops,
+       .max_rate       = 32768,
+};
+
+static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
+       { .input = &tegra_pll_m, .value = 0},
+       { .input = &tegra_pll_c, .value = 1},
+       { .input = &tegra_pll_p, .value = 2},
+       { .input = &tegra_pll_a_out0, .value = 3},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
+       { .input = &tegra_pll_p, .value = 0},
+       { .input = &tegra_pll_c, .value = 1},
+       { .input = &tegra_pll_m, .value = 2},
+       { .input = &tegra_clk_m, .value = 3},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_clkm[] = {
+       { .input = &tegra_pll_p, .value = 0},
+       { .input = &tegra_clk_m, .value = 3},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
+       {.input = &tegra_pll_p, .value = 0},
+       {.input = &tegra_pll_d_out0, .value = 1},
+       {.input = &tegra_pll_c, .value = 2},
+       {.input = &tegra_clk_m, .value = 3},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
+       {.input = &tegra_pll_p, .value = 0},
+       {.input = &tegra_pll_m, .value = 1},
+       {.input = &tegra_pll_d_out0, .value = 2},
+       {.input = &tegra_pll_a_out0, .value = 3},
+       {.input = &tegra_pll_c, .value = 4},
+       {.input = &tegra_pll_d2_out0, .value = 5},
+       {.input = &tegra_clk_m, .value = 6},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_plla_pllc_pllp_clkm[] = {
+       { .input = &tegra_pll_a_out0, .value = 0},
+       /* { .input = &tegra_pll_c, .value = 1}, no use on tegra30 */
+       { .input = &tegra_pll_p, .value = 2},
+       { .input = &tegra_clk_m, .value = 3},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_clk32_clkm[] = {
+       {.input = &tegra_pll_p,     .value = 0},
+       {.input = &tegra_pll_c,     .value = 1},
+       {.input = &tegra_clk_32k,   .value = 2},
+       {.input = &tegra_clk_m,     .value = 3},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_clkm_clk32[] = {
+       {.input = &tegra_pll_p,     .value = 0},
+       {.input = &tegra_pll_c,     .value = 1},
+       {.input = &tegra_clk_m,     .value = 2},
+       {.input = &tegra_clk_32k,   .value = 3},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
+       {.input = &tegra_pll_p,     .value = 0},
+       {.input = &tegra_pll_c,     .value = 1},
+       {.input = &tegra_pll_m,     .value = 2},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_clk_m[] = {
+       { .input = &tegra_clk_m, .value = 0},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_out3[] = {
+       { .input = &tegra_pll_p_out3, .value = 0},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_plld_out0[] = {
+       { .input = &tegra_pll_d_out0, .value = 0},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_plld_out0_plld2_out0[] = {
+       { .input = &tegra_pll_d_out0,  .value = 0},
+       { .input = &tegra_pll_d2_out0, .value = 1},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_clk_32k[] = {
+       { .input = &tegra_clk_32k, .value = 0},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_plla_clk32_pllp_clkm_plle[] = {
+       { .input = &tegra_pll_a_out0, .value = 0},
+       { .input = &tegra_clk_32k,    .value = 1},
+       { .input = &tegra_pll_p,      .value = 2},
+       { .input = &tegra_clk_m,      .value = 3},
+       { .input = &tegra_pll_e,      .value = 4},
+       { 0, 0},
+};
+
+static struct clk_mux_sel mux_cclk_g[] = {
+       { .input = &tegra_clk_m,        .value = 0},
+       { .input = &tegra_pll_c,        .value = 1},
+       { .input = &tegra_clk_32k,      .value = 2},
+       { .input = &tegra_pll_m,        .value = 3},
+       { .input = &tegra_pll_p,        .value = 4},
+       { .input = &tegra_pll_p_out4,   .value = 5},
+       { .input = &tegra_pll_p_out3,   .value = 6},
+       { .input = &tegra_pll_x,        .value = 8},
+       { 0, 0},
+};
+
+static struct clk tegra_clk_cclk_g = {
+       .name   = "cclk_g",
+       .flags  = DIV_U71 | DIV_U71_INT,
+       .inputs = mux_cclk_g,
+       .reg    = 0x368,
+       .ops    = &tegra_super_ops,
+       .max_rate = 1700000000,
+};
+
+static struct clk tegra30_clk_twd = {
+       .parent   = &tegra_clk_cclk_g,
+       .name     = "twd",
+       .ops      = &tegra30_twd_ops,
+       .max_rate = 1400000000, /* Same as tegra_clk_cpu_cmplx.max_rate */
+       .mul      = 1,
+       .div      = 2,
+};
+
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
+       {                                               \
+               .name      = _name,                     \
+               .lookup    = {                          \
+                       .dev_id    = _dev,              \
+                       .con_id    = _con,              \
+               },                                      \
+               .ops       = &tegra_periph_clk_ops,     \
+               .reg       = _reg,                      \
+               .inputs    = _inputs,                   \
+               .flags     = _flags,                    \
+               .max_rate  = _max,                      \
+               .u.periph = {                           \
+                       .clk_num   = _clk_num,          \
+               },                                      \
+       }
+
+#define PERIPH_CLK_EX(_name, _dev, _con, _clk_num, _reg, _max, _inputs,        \
+                       _flags, _ops)                                   \
+       {                                               \
+               .name      = _name,                     \
+               .lookup    = {                          \
+                       .dev_id    = _dev,              \
+                       .con_id    = _con,              \
+               },                                      \
+               .ops       = _ops,                      \
+               .reg       = _reg,                      \
+               .inputs    = _inputs,                   \
+               .flags     = _flags,                    \
+               .max_rate  = _max,                      \
+               .u.periph = {                           \
+                       .clk_num   = _clk_num,          \
+               },                                      \
+       }
+
+#define SHARED_CLK(_name, _dev, _con, _parent, _id, _div, _mode)\
+       {                                               \
+               .name      = _name,                     \
+               .lookup    = {                          \
+                       .dev_id    = _dev,              \
+                       .con_id    = _con,              \
+               },                                      \
+               .ops       = &tegra_clk_shared_bus_ops, \
+               .parent = _parent,                      \
+               .u.shared_bus_user = {                  \
+                       .client_id = _id,               \
+                       .client_div = _div,             \
+                       .mode = _mode,                  \
+               },                                      \
+       }
+struct clk tegra_list_clks[] = {
+       PERIPH_CLK("apbdma",    "tegra-dma",            NULL,   34,     0,      26000000,  mux_clk_m,                   0),
+       PERIPH_CLK("rtc",       "rtc-tegra",            NULL,   4,      0,      32768,     mux_clk_32k,                 PERIPH_NO_RESET | PERIPH_ON_APB),
+       PERIPH_CLK("kbc",       "tegra-kbc",            NULL,   36,     0,      32768,     mux_clk_32k,                 PERIPH_NO_RESET | PERIPH_ON_APB),
+       PERIPH_CLK("timer",     "timer",                NULL,   5,      0,      26000000,  mux_clk_m,                   0),
+       PERIPH_CLK("kfuse",     "kfuse-tegra",          NULL,   40,     0,      26000000,  mux_clk_m,                   0),
+       PERIPH_CLK("fuse",      "fuse-tegra",           "fuse", 39,     0,      26000000,  mux_clk_m,                   PERIPH_ON_APB),
+       PERIPH_CLK("fuse_burn", "fuse-tegra",           "fuse_burn",    39,     0,      26000000,  mux_clk_m,           PERIPH_ON_APB),
+       PERIPH_CLK("apbif",     "tegra30-ahub",         "apbif", 107,   0,      26000000,  mux_clk_m,                   0),
+       PERIPH_CLK("i2s0",      "tegra30-i2s.0",        NULL,   30,     0x1d8,  26000000,  mux_pllaout0_audio0_2x_pllp_clkm,    MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("i2s1",      "tegra30-i2s.1",        NULL,   11,     0x100,  26000000,  mux_pllaout0_audio1_2x_pllp_clkm,    MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("i2s2",      "tegra30-i2s.2",        NULL,   18,     0x104,  26000000,  mux_pllaout0_audio2_2x_pllp_clkm,    MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("i2s3",      "tegra30-i2s.3",        NULL,   101,    0x3bc,  26000000,  mux_pllaout0_audio3_2x_pllp_clkm,    MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("i2s4",      "tegra30-i2s.4",        NULL,   102,    0x3c0,  26000000,  mux_pllaout0_audio4_2x_pllp_clkm,    MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("spdif_out", "tegra30-spdif",        "spdif_out",    10,     0x108,  100000000, mux_pllaout0_audio_2x_pllp_clkm,     MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("spdif_in",  "tegra30-spdif",        "spdif_in",     10,     0x10c,  100000000, mux_pllp_pllc_pllm,          MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("pwm",       "pwm",                  NULL,   17,     0x110,  432000000, mux_pllp_pllc_clk32_clkm,    MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("d_audio",   "tegra30-ahub",         "d_audio", 106, 0x3d0,  48000000,  mux_plla_pllc_pllp_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("dam0",      "tegra30-dam.0",        NULL,   108,    0x3d8,  48000000,  mux_plla_pllc_pllp_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("dam1",      "tegra30-dam.1",        NULL,   109,    0x3dc,  48000000,  mux_plla_pllc_pllp_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("dam2",      "tegra30-dam.2",        NULL,   110,    0x3e0,  48000000,  mux_plla_pllc_pllp_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("hda",       "tegra30-hda",          "hda",   125,   0x428,  108000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("hda2codec_2x",      "tegra30-hda",  "hda2codec",   111,     0x3e4,  48000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("hda2hdmi",  "tegra30-hda",          "hda2hdmi",     128,    0,      48000000,  mux_clk_m,                   0),
+       PERIPH_CLK("sbc1",      "spi_tegra.0",          NULL,   41,     0x134,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("sbc2",      "spi_tegra.1",          NULL,   44,     0x118,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("sbc3",      "spi_tegra.2",          NULL,   46,     0x11c,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("sbc4",      "spi_tegra.3",          NULL,   68,     0x1b4,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("sbc5",      "spi_tegra.4",          NULL,   104,    0x3c8,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("sbc6",      "spi_tegra.5",          NULL,   105,    0x3cc,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("sata_oob",  "tegra_sata_oob",       NULL,   123,    0x420,  216000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("sata",      "tegra_sata",           NULL,   124,    0x424,  216000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("sata_cold", "tegra_sata_cold",      NULL,   129,    0,      48000000,  mux_clk_m,                   0),
+       PERIPH_CLK_EX("ndflash", "tegra_nand",          NULL,   13,     0x160,  240000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71,  &tegra_nand_clk_ops),
+       PERIPH_CLK("ndspeed",   "tegra_nand_speed",     NULL,   80,     0x3f8,  240000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("vfir",      "vfir",                 NULL,   7,      0x168,  72000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("sdmmc1",    "sdhci-tegra.0",        NULL,   14,     0x150,  208000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
+       PERIPH_CLK("sdmmc2",    "sdhci-tegra.1",        NULL,   9,      0x154,  104000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
+       PERIPH_CLK("sdmmc3",    "sdhci-tegra.2",        NULL,   69,     0x1bc,  208000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
+       PERIPH_CLK("sdmmc4",    "sdhci-tegra.3",        NULL,   15,     0x164,  104000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
+       PERIPH_CLK("vcp",       "tegra-avp",            "vcp",  29,     0,      250000000, mux_clk_m,                   0),
+       PERIPH_CLK("bsea",      "tegra-avp",            "bsea", 62,     0,      250000000, mux_clk_m,                   0),
+       PERIPH_CLK("bsev",      "tegra-aes",            "bsev", 63,     0,      250000000, mux_clk_m,                   0),
+       PERIPH_CLK("vde",       "vde",                  NULL,   61,     0x1c8,  520000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | DIV_U71_INT),
+       PERIPH_CLK("csite",     "csite",                NULL,   73,     0x1d4,  144000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* max rate ??? */
+       PERIPH_CLK("la",        "la",                   NULL,   76,     0x1f8,  26000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
+       PERIPH_CLK("owr",       "tegra_w1",             NULL,   71,     0x1cc,  26000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("nor",       "nor",                  NULL,   42,     0x1d0,  127000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* requires min voltage */
+       PERIPH_CLK("mipi",      "mipi",                 NULL,   50,     0x174,  60000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | PERIPH_ON_APB), /* scales with voltage */
+       PERIPH_CLK("i2c1",      "tegra-i2c.0",          NULL,   12,     0x124,  26000000,  mux_pllp_clkm,               MUX | DIV_U16 | PERIPH_ON_APB),
+       PERIPH_CLK("i2c2",      "tegra-i2c.1",          NULL,   54,     0x198,  26000000,  mux_pllp_clkm,               MUX | DIV_U16 | PERIPH_ON_APB),
+       PERIPH_CLK("i2c3",      "tegra-i2c.2",          NULL,   67,     0x1b8,  26000000,  mux_pllp_clkm,               MUX | DIV_U16 | PERIPH_ON_APB),
+       PERIPH_CLK("i2c4",      "tegra-i2c.3",          NULL,   103,    0x3c4,  26000000,  mux_pllp_clkm,               MUX | DIV_U16 | PERIPH_ON_APB),
+       PERIPH_CLK("i2c5",      "tegra-i2c.4",          NULL,   47,     0x128,  26000000,  mux_pllp_clkm,               MUX | DIV_U16 | PERIPH_ON_APB),
+       PERIPH_CLK("uarta",     "tegra_uart.0",         NULL,   6,      0x178,  800000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+       PERIPH_CLK("uartb",     "tegra_uart.1",         NULL,   7,      0x17c,  800000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+       PERIPH_CLK("uartc",     "tegra_uart.2",         NULL,   55,     0x1a0,  800000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+       PERIPH_CLK("uartd",     "tegra_uart.3",         NULL,   65,     0x1c0,  800000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+       PERIPH_CLK("uarte",     "tegra_uart.4",         NULL,   66,     0x1c4,  800000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+       PERIPH_CLK("uarta_dbg", "serial8250.0",         "uarta", 6,     0x178,  800000000, mux_pllp_clkm,               MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+       PERIPH_CLK("uartb_dbg", "serial8250.0",         "uartb", 7,     0x17c,  800000000, mux_pllp_clkm,               MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+       PERIPH_CLK("uartc_dbg", "serial8250.0",         "uartc", 55,    0x1a0,  800000000, mux_pllp_clkm,               MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+       PERIPH_CLK("uartd_dbg", "serial8250.0",         "uartd", 65,    0x1c0,  800000000, mux_pllp_clkm,               MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+       PERIPH_CLK("uarte_dbg", "serial8250.0",         "uarte", 66,    0x1c4,  800000000, mux_pllp_clkm,               MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+       PERIPH_CLK_EX("vi",     "tegra_camera",         "vi",   20,     0x148,  425000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | DIV_U71_INT,    &tegra_vi_clk_ops),
+       PERIPH_CLK("3d",        "3d",                   NULL,   24,     0x158,  520000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
+       PERIPH_CLK("3d2",       "3d2",                  NULL,   98,     0x3b0,  520000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
+       PERIPH_CLK("2d",        "2d",                   NULL,   21,     0x15c,  520000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE),
+       PERIPH_CLK("vi_sensor", "tegra_camera",         "vi_sensor",    20,     0x1a8,  150000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | PERIPH_NO_RESET),
+       PERIPH_CLK("epp",       "epp",                  NULL,   19,     0x16c,  520000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | DIV_U71_INT),
+       PERIPH_CLK("mpe",       "mpe",                  NULL,   60,     0x170,  520000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | DIV_U71_INT),
+       PERIPH_CLK("host1x",    "host1x",               NULL,   28,     0x180,  260000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | DIV_U71_INT),
+       PERIPH_CLK("cve",       "cve",                  NULL,   49,     0x140,  250000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* requires min voltage */
+       PERIPH_CLK("tvo",       "tvo",                  NULL,   49,     0x188,  250000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* requires min voltage */
+       PERIPH_CLK_EX("dtv",    "dtv",                  NULL,   79,     0x1dc,  250000000, mux_clk_m,                   0,              &tegra_dtv_clk_ops),
+       PERIPH_CLK("hdmi",      "hdmi",                 NULL,   51,     0x18c,  148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,     MUX | MUX8 | DIV_U71),
+       PERIPH_CLK("tvdac",     "tvdac",                NULL,   53,     0x194,  220000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* requires min voltage */
+       PERIPH_CLK("disp1",     "tegradc.0",            NULL,   27,     0x138,  600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,     MUX | MUX8),
+       PERIPH_CLK("disp2",     "tegradc.1",            NULL,   26,     0x13c,  600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm,     MUX | MUX8),
+       PERIPH_CLK("usbd",      "fsl-tegra-udc",        NULL,   22,     0,      480000000, mux_clk_m,                   0), /* requires min voltage */
+       PERIPH_CLK("usb2",      "tegra-ehci.1",         NULL,   58,     0,      480000000, mux_clk_m,                   0), /* requires min voltage */
+       PERIPH_CLK("usb3",      "tegra-ehci.2",         NULL,   59,     0,      480000000, mux_clk_m,                   0), /* requires min voltage */
+       PERIPH_CLK("dsia",      "tegradc.0",            "dsia", 48,     0,      500000000, mux_plld_out0,               0),
+       PERIPH_CLK_EX("dsib",   "tegradc.1",            "dsib", 82,     0xd0,   500000000, mux_plld_out0_plld2_out0,    MUX | PLLD,     &tegra_dsib_clk_ops),
+       PERIPH_CLK("csi",       "tegra_camera",         "csi",  52,     0,      102000000, mux_pllp_out3,               0),
+       PERIPH_CLK("isp",       "tegra_camera",         "isp",  23,     0,      150000000, mux_clk_m,                   0), /* same frequency as VI */
+       PERIPH_CLK("csus",      "tegra_camera",         "csus", 92,     0,      150000000, mux_clk_m,                   PERIPH_NO_RESET),
+
+       PERIPH_CLK("tsensor",   "tegra-tsensor",        NULL,   100,    0x3b8,  216000000, mux_pllp_pllc_clkm_clk32,    MUX | DIV_U71),
+       PERIPH_CLK("actmon",    "actmon",               NULL,   119,    0x3e8,  216000000, mux_pllp_pllc_clk32_clkm,    MUX | DIV_U71),
+       PERIPH_CLK("extern1",   "extern1",              NULL,   120,    0x3ec,  216000000, mux_plla_clk32_pllp_clkm_plle,       MUX | MUX8 | DIV_U71),
+       PERIPH_CLK("extern2",   "extern2",              NULL,   121,    0x3f0,  216000000, mux_plla_clk32_pllp_clkm_plle,       MUX | MUX8 | DIV_U71),
+       PERIPH_CLK("extern3",   "extern3",              NULL,   122,    0x3f4,  216000000, mux_plla_clk32_pllp_clkm_plle,       MUX | MUX8 | DIV_U71),
+       PERIPH_CLK("i2cslow",   "i2cslow",              NULL,   81,     0x3fc,  26000000,  mux_pllp_pllc_clk32_clkm,    MUX | DIV_U71 | PERIPH_ON_APB),
+       PERIPH_CLK("pcie",      "tegra-pcie",           "pcie", 70,     0,      250000000, mux_clk_m,                   0),
+       PERIPH_CLK("afi",       "tegra-pcie",           "afi",  72,     0,      250000000, mux_clk_m,                   0),
+       PERIPH_CLK("se",        "se",                   NULL,   127,    0x42c,  520000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71 | DIV_U71_INT),
+};
+
+#define CLK_DUPLICATE(_name, _dev, _con)               \
+       {                                               \
+               .name   = _name,                        \
+               .lookup = {                             \
+                       .dev_id = _dev,                 \
+                       .con_id         = _con,         \
+               },                                      \
+       }
+
+/* Some clocks may be used by different drivers depending on the board
+ * configuration.  List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+struct clk_duplicate tegra_clk_duplicates[] = {
+       CLK_DUPLICATE("usbd", "utmip-pad", NULL),
+       CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
+       CLK_DUPLICATE("usbd", "tegra-otg", NULL),
+       CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
+       CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
+       CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
+       CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
+       CLK_DUPLICATE("pwm", "tegra_pwm.0", NULL),
+       CLK_DUPLICATE("pwm", "tegra_pwm.1", NULL),
+       CLK_DUPLICATE("pwm", "tegra_pwm.2", NULL),
+       CLK_DUPLICATE("pwm", "tegra_pwm.3", NULL),
+       CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
+       CLK_DUPLICATE("bsev", "nvavp", "bsev"),
+       CLK_DUPLICATE("vde", "tegra-aes", "vde"),
+       CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
+       CLK_DUPLICATE("bsea", "nvavp", "bsea"),
+       CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
+       CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
+       CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
+       CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
+       CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
+       CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
+       CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
+       CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
+       CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
+       CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
+       CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
+       CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
+       CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
+       CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
+       CLK_DUPLICATE("twd", "smp_twd", NULL),
+       CLK_DUPLICATE("vcp", "nvavp", "vcp"),
+};
+
+struct clk *tegra_ptr_clks[] = {
+       &tegra_clk_32k,
+       &tegra_clk_m,
+       &tegra_clk_m_div2,
+       &tegra_clk_m_div4,
+       &tegra_pll_ref,
+       &tegra_pll_m,
+       &tegra_pll_m_out1,
+       &tegra_pll_c,
+       &tegra_pll_c_out1,
+       &tegra_pll_p,
+       &tegra_pll_p_out1,
+       &tegra_pll_p_out2,
+       &tegra_pll_p_out3,
+       &tegra_pll_p_out4,
+       &tegra_pll_a,
+       &tegra_pll_a_out0,
+       &tegra_pll_d,
+       &tegra_pll_d_out0,
+       &tegra_pll_d2,
+       &tegra_pll_d2_out0,
+       &tegra_pll_u,
+       &tegra_pll_x,
+       &tegra_pll_x_out0,
+       &tegra_pll_e,
+       &tegra_clk_cclk_g,
+       &tegra_cml0_clk,
+       &tegra_cml1_clk,
+       &tegra_pciex_clk,
+       &tegra_clk_sclk,
+       &tegra_clk_blink,
+       &tegra30_clk_twd,
+};
+
+
+static void tegra30_init_one_clock(struct clk *c)
+{
+       clk_init(c);
+       INIT_LIST_HEAD(&c->shared_bus_list);
+       if (!c->lookup.dev_id && !c->lookup.con_id)
+               c->lookup.con_id = c->name;
+       c->lookup.clk = c;
+       clkdev_add(&c->lookup);
+}
+
+void __init tegra30_init_clocks(void)
+{
+       int i;
+       struct clk *c;
+
+       for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
+               tegra30_init_one_clock(tegra_ptr_clks[i]);
+
+       for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
+               tegra30_init_one_clock(&tegra_list_clks[i]);
+
+       for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
+               c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
+               if (!c) {
+                       pr_err("%s: Unknown duplicate clock %s\n", __func__,
+                               tegra_clk_duplicates[i].name);
+                       continue;
+               }
+
+               tegra_clk_duplicates[i].lookup.clk = c;
+               clkdev_add(&tegra_clk_duplicates[i].lookup);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
+               tegra30_init_one_clock(&tegra_sync_source_list[i]);
+       for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
+               tegra30_init_one_clock(&tegra_clk_audio_list[i]);
+       for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
+               tegra30_init_one_clock(&tegra_clk_audio_2x_list[i]);
+
+       init_clk_out_mux();
+       for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
+               tegra30_init_one_clock(&tegra_clk_out_list[i]);
+
+}
index 1d1acda..1eed8d4 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/io.h>
 
 #include <asm/mach/time.h>
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 #include <asm/sched_clock.h>
 
 #include <mach/iomap.h>
@@ -162,6 +162,21 @@ static struct irqaction tegra_timer_irq = {
        .irq            = INT_TMR3,
 };
 
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
+                             TEGRA_ARM_PERIF_BASE + 0x600,
+                             IRQ_LOCALTIMER);
+
+static void __init tegra_twd_init(void)
+{
+       int err = twd_local_timer_register(&twd_local_timer);
+       if (err)
+               pr_err("twd_local_timer_register failed %d\n", err);
+}
+#else
+#define tegra_twd_init()       do {} while(0)
+#endif
+
 static void __init tegra_init_timer(void)
 {
        struct clk *clk;
@@ -188,10 +203,6 @@ static void __init tegra_init_timer(void)
        else
                clk_enable(clk);
 
-#ifdef CONFIG_HAVE_ARM_TWD
-       twd_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x600);
-#endif
-
        switch (rate) {
        case 12000000:
                timer_writel(0x000b, TIMERUS_USEC_CFG);
@@ -231,6 +242,7 @@ static void __init tegra_init_timer(void)
        tegra_clockevent.cpumask = cpu_all_mask;
        tegra_clockevent.irq = tegra_timer_irq.irq;
        clockevents_register_device(&tegra_clockevent);
+       tegra_twd_init();
 }
 
 struct sys_timer tegra_timer = {
index ad321f9..c5b2ac0 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
@@ -730,6 +731,7 @@ err0:
        kfree(phy);
        return ERR_PTR(err);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
 
 int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
 {
@@ -738,6 +740,7 @@ int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
        else
                return utmi_phy_power_on(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_power_on);
 
 void tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
 {
@@ -746,18 +749,21 @@ void tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
        else
                utmi_phy_power_off(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_power_off);
 
 void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
 {
        if (!phy_is_ulpi(phy))
                utmi_phy_preresume(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume);
 
 void tegra_usb_phy_postresume(struct tegra_usb_phy *phy)
 {
        if (!phy_is_ulpi(phy))
                utmi_phy_postresume(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume);
 
 void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
                                 enum tegra_usb_phy_port_speed port_speed)
@@ -765,24 +771,28 @@ void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
        if (!phy_is_ulpi(phy))
                utmi_phy_restore_start(phy, port_speed);
 }
+EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start);
 
 void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
 {
        if (!phy_is_ulpi(phy))
                utmi_phy_restore_end(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
 
 void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
 {
        if (!phy_is_ulpi(phy))
                utmi_phy_clk_disable(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable);
 
 void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
 {
        if (!phy_is_ulpi(phy))
                utmi_phy_clk_enable(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable);
 
 void tegra_usb_phy_close(struct tegra_usb_phy *phy)
 {
@@ -794,3 +804,4 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy)
        clk_put(phy->pll_u);
        kfree(phy);
 }
+EXPORT_SYMBOL_GPL(tegra_usb_phy_close);
index 2855381..fd3a5c3 100644 (file)
@@ -8,7 +8,6 @@ obj-n           :=
 obj-           :=
 
 obj-$(CONFIG_ARCH_U300)                  += u300.o
-obj-$(CONFIG_MMC)                 += mmc.o
 obj-$(CONFIG_SPI_PL022)           += spi.o
 obj-$(CONFIG_MACH_U300_SPIDUMMY)  += dummyspichip.o
 obj-$(CONFIG_I2C_STU300)          += i2c.o
index a7b3f36..8b90c44 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/termios.h>
 #include <linux/dmaengine.h>
 #include <linux/amba/bus.h>
+#include <linux/amba/mmci.h>
 #include <linux/amba/serial.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
@@ -44,9 +45,9 @@
 #include <mach/gpio-u300.h>
 
 #include "clock.h"
-#include "mmc.h"
 #include "spi.h"
 #include "i2c.h"
+#include "u300-gpio.h"
 
 /*
  * Static I/O mappings that are needed for booting the U300 platforms. The
@@ -95,19 +96,9 @@ static struct amba_pl011_data uart0_plat_data = {
 #endif
 };
 
-static struct amba_device uart0_device = {
-       .dev = {
-               .coherent_dma_mask = ~0,
-               .init_name = "uart0", /* Slow device at 0x3000 offset */
-               .platform_data = &uart0_plat_data,
-       },
-       .res = {
-               .start = U300_UART0_BASE,
-               .end   = U300_UART0_BASE + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = { IRQ_U300_UART0, NO_IRQ },
-};
+/* Slow device at 0x3000 offset */
+static AMBA_APB_DEVICE(uart0, "uart0", 0, U300_UART0_BASE,
+       { IRQ_U300_UART0 }, &uart0_plat_data);
 
 /* The U335 have an additional UART1 on the APP CPU */
 #ifdef CONFIG_MACH_U300_BS335
@@ -119,72 +110,42 @@ static struct amba_pl011_data uart1_plat_data = {
 #endif
 };
 
-static struct amba_device uart1_device = {
-       .dev = {
-               .coherent_dma_mask = ~0,
-               .init_name = "uart1", /* Fast device at 0x7000 offset */
-               .platform_data = &uart1_plat_data,
-       },
-       .res = {
-               .start = U300_UART1_BASE,
-               .end   = U300_UART1_BASE + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = { IRQ_U300_UART1, NO_IRQ },
-};
+/* Fast device at 0x7000 offset */
+static AMBA_APB_DEVICE(uart1, "uart1", 0, U300_UART1_BASE,
+       { IRQ_U300_UART1 }, &uart1_plat_data);
 #endif
 
-static struct amba_device pl172_device = {
-       .dev = {
-               .init_name = "pl172", /* AHB device at 0x4000 offset */
-               .platform_data = NULL,
-       },
-       .res = {
-               .start = U300_EMIF_CFG_BASE,
-               .end   = U300_EMIF_CFG_BASE + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       },
-};
+/* AHB device at 0x4000 offset */
+static AMBA_APB_DEVICE(pl172, "pl172", 0, U300_EMIF_CFG_BASE, { }, NULL);
 
+/* Fast device at 0x6000 offset */
+static AMBA_APB_DEVICE(pl022, "pl022", 0, U300_SPI_BASE,
+       { IRQ_U300_SPI }, NULL);
 
-/*
- * Everything within this next ifdef deals with external devices connected to
- * the APP SPI bus.
- */
-static struct amba_device pl022_device = {
-       .dev = {
-               .coherent_dma_mask = ~0,
-               .init_name = "pl022", /* Fast device at 0x6000 offset */
-       },
-       .res = {
-               .start = U300_SPI_BASE,
-               .end   = U300_SPI_BASE + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {IRQ_U300_SPI, NO_IRQ },
-       /*
-        * This device has a DMA channel but the Linux driver does not use
-        * it currently.
-        */
-};
+/* Fast device at 0x1000 offset */
+#define U300_MMCSD_IRQS        { IRQ_U300_MMCSD_MCIINTR0, IRQ_U300_MMCSD_MCIINTR1 }
 
-static struct amba_device mmcsd_device = {
-       .dev = {
-               .init_name = "mmci", /* Fast device at 0x1000 offset */
-               .platform_data = NULL, /* Added later */
-       },
-       .res = {
-               .start = U300_MMCSD_BASE,
-               .end   = U300_MMCSD_BASE + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       .irq = {IRQ_U300_MMCSD_MCIINTR0, IRQ_U300_MMCSD_MCIINTR1 },
+static struct mmci_platform_data mmcsd_platform_data = {
        /*
-        * This device has a DMA channel but the Linux driver does not use
-        * it currently.
+        * Do not set ocr_mask or voltage translation function,
+        * we have a regulator we can control instead.
         */
+       .f_max = 24000000,
+       .gpio_wp = -1,
+       .gpio_cd = U300_GPIO_PIN_MMC_CD,
+       .cd_invert = true,
+       .capabilities = MMC_CAP_MMC_HIGHSPEED |
+       MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+#ifdef CONFIG_COH901318
+       .dma_filter = coh901318_filter_id,
+       .dma_rx_param = (void *) U300_DMA_MMCSD_RX_TX,
+       /* Don't specify a TX channel, this RX channel is bidirectional */
+#endif
 };
 
+static AMBA_APB_DEVICE(mmcsd, "mmci", 0, U300_MMCSD_BASE,
+       U300_MMCSD_IRQS, &mmcsd_platform_data);
+
 /*
  * The order of device declaration may be important, since some devices
  * have dependencies on other devices being initialized first.
@@ -1883,16 +1844,6 @@ void __init u300_init_devices(void)
        writew(val, U300_SYSCON_VBASE + U300_SYSCON_SMCR);
 }
 
-static int core_module_init(void)
-{
-       /*
-        * This needs to be initialized later: it needs the input framework
-        * to be initialized first.
-        */
-       return mmc_init(&mmcsd_device);
-}
-module_init(core_module_init);
-
 /* Forward declare this function from the watchdog */
 void coh901327_watchdog_reset(void);
 
diff --git a/arch/arm/mach-u300/include/mach/entry-macro.S b/arch/arm/mach-u300/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 7181d6a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *
- * arch-arm/mach-u300/include/mach/entry-macro.S
- *
- *
- * Copyright (C) 2006-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Low-level IRQ helper macros for ST-Ericsson U300
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
diff --git a/arch/arm/mach-u300/include/mach/system.h b/arch/arm/mach-u300/include/mach/system.h
deleted file mode 100644 (file)
index 574d46e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/include/mach/system.h
- *
- *
- * Copyright (C) 2007-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * System shutdown and reset functions.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c
deleted file mode 100644 (file)
index 05abd6a..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/mmc.c
- *
- *
- * Copyright (C) 2009 ST-Ericsson SA
- * License terms: GNU General Public License (GPL) version 2
- *
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- * Author: Johan Lundin
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- */
-#include <linux/device.h>
-#include <linux/amba/bus.h>
-#include <linux/mmc/host.h>
-#include <linux/dmaengine.h>
-#include <linux/amba/mmci.h>
-#include <linux/slab.h>
-#include <mach/coh901318.h>
-#include <mach/dma_channels.h>
-
-#include "u300-gpio.h"
-#include "mmc.h"
-
-static struct mmci_platform_data mmc0_plat_data = {
-       /*
-        * Do not set ocr_mask or voltage translation function,
-        * we have a regulator we can control instead.
-        */
-       /* Nominally 2.85V on our platform */
-       .f_max = 24000000,
-       .gpio_wp = -1,
-       .gpio_cd = U300_GPIO_PIN_MMC_CD,
-       .cd_invert = true,
-       .capabilities = MMC_CAP_MMC_HIGHSPEED |
-       MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
-#ifdef CONFIG_COH901318
-       .dma_filter = coh901318_filter_id,
-       .dma_rx_param = (void *) U300_DMA_MMCSD_RX_TX,
-       /* Don't specify a TX channel, this RX channel is bidirectional */
-#endif
-};
-
-int __devinit mmc_init(struct amba_device *adev)
-{
-       struct device *mmcsd_device = &adev->dev;
-       int ret = 0;
-
-       mmcsd_device->platform_data = &mmc0_plat_data;
-
-       return ret;
-}
diff --git a/arch/arm/mach-u300/mmc.h b/arch/arm/mach-u300/mmc.h
deleted file mode 100644 (file)
index 92b8512..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/mmc.h
- *
- *
- * Copyright (C) 2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- *
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- */
-#ifndef MMC_H
-#define MMC_H
-
-#include <linux/amba/bus.h>
-
-int __devinit mmc_init(struct amba_device *adev);
-
-#endif
index c59e8b8..880d02e 100644 (file)
@@ -8,47 +8,62 @@ config UX500_SOC_COMMON
        select PL310_ERRATA_753970
        select ARM_ERRATA_754322
        select ARM_ERRATA_764369
-
-menu "Ux500 SoC"
+       select CACHE_L2X0
 
 config UX500_SOC_DB5500
-       bool "DB5500"
+       bool
        select MFD_DB5500_PRCMU
 
 config UX500_SOC_DB8500
-       bool "DB8500"
+       bool
        select MFD_DB8500_PRCMU
        select REGULATOR_DB8500_PRCMU
-
-endmenu
+       select CPU_FREQ_TABLE if CPU_FREQ
 
 menu "Ux500 target platform (boards)"
 
-config MACH_U8500
-       bool "U8500 Development platform"
-       depends on UX500_SOC_DB8500
-       select TPS6105X
+config MACH_MOP500
+       bool "U8500 Development platform, MOP500 versions"
+       select UX500_SOC_DB8500
+       select I2C
+       select I2C_NOMADIK
+       select SOC_BUS
        help
-         Include support for the mop500 development platform.
+         Include support for the MOP500 development platform.
 
 config MACH_HREFV60
-       bool "U85000 Development platform, HREFv60 version"
-       depends on UX500_SOC_DB8500
-       help
-         Include support for the HREFv60 new development platform.
+       bool "U8500 Development platform, HREFv60 version"
+       select MACH_MOP500
+       help
+         Include support for the HREFv60 new development platform.
+         Includes HREFv70, v71 etc.
 
 config MACH_SNOWBALL
        bool "U8500 Snowball platform"
-       depends on UX500_SOC_DB8500
-       select MACH_U8500
+       select MACH_MOP500
        help
          Include support for the snowball development platform.
 
 config MACH_U5500
        bool "U5500 Development platform"
-       depends on UX500_SOC_DB5500
+       select UX500_SOC_DB5500
        help
          Include support for the U5500 development platform.
+
+config UX500_AUTO_PLATFORM
+       def_bool y
+       depends on !MACH_U5500
+       select MACH_MOP500
+       help
+         At least one platform needs to be selected in order to build
+         a working kernel. If everything else is disabled, this
+         automatically enables MACH_MOP500.
+
+config MACH_UX500_DT
+       bool "Generic U8500 support using device tree"
+       depends on MACH_MOP500
+       select USE_OF
+
 endmenu
 
 config UX500_DEBUG_UART
index 6bd2f45..465b9ec 100644 (file)
@@ -7,7 +7,7 @@ obj-y                           := clock.o cpu.o devices.o devices-common.o \
 obj-$(CONFIG_CACHE_L2X0)       += cache-l2x0.o
 obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
 obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
-obj-$(CONFIG_MACH_U8500)       += board-mop500.o board-mop500-sdi.o \
+obj-$(CONFIG_MACH_MOP500)      += board-mop500.o board-mop500-sdi.o \
                                board-mop500-regulators.o \
                                board-mop500-uib.o board-mop500-stuib.o \
                                board-mop500-u8500uib.o \
@@ -15,7 +15,6 @@ obj-$(CONFIG_MACH_U8500)      += board-mop500.o board-mop500-sdi.o \
 obj-$(CONFIG_MACH_U5500)       += board-u5500.o board-u5500-sdi.o
 obj-$(CONFIG_SMP)              += platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)      += hotplug.o
-obj-$(CONFIG_LOCAL_TIMERS)     += localtimer.o
 obj-$(CONFIG_U5500_MODEM_IRQ)  += modem-irq-db5500.o
 obj-$(CONFIG_U5500_MBOX)       += mbox-db5500.o
 
index ff0a4b5..dd5cd00 100644 (file)
@@ -2,3 +2,4 @@
 params_phys-y  := 0x00000100
 initrd_phys-y  := 0x00800000
 
+dtb-$(CONFIG_MACH_SNOWBALL) += snowball.dtb
index 74bfcff..f5413dc 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/bug.h>
 
 #include <asm/mach-types.h>
 #include <plat/pincfg.h>
index 2735d03..52426a4 100644 (file)
@@ -74,6 +74,26 @@ static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
        REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
 };
 
+static struct regulator_consumer_supply ab8500_vaud_consumers[] = {
+       /* AB8500 audio-codec main supply */
+       REGULATOR_SUPPLY("vaud", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vamic1_consumers[] = {
+       /* AB8500 audio-codec Mic1 supply */
+       REGULATOR_SUPPLY("vamic1", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vamic2_consumers[] = {
+       /* AB8500 audio-codec Mic2 supply */
+       REGULATOR_SUPPLY("vamic2", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vdmic_consumers[] = {
+       /* AB8500 audio-codec DMic supply */
+       REGULATOR_SUPPLY("vdmic", "ab8500-codec.0"),
+};
+
 static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
        /* SoC core supply, no device */
        REGULATOR_SUPPLY("v-intcore", NULL),
@@ -323,6 +343,8 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
                        .name = "V-AUD",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
                },
+               .num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
+               .consumer_supplies = ab8500_vaud_consumers,
        },
        /* supply for v-anamic1 VAMic1-LDO */
        [AB8500_LDO_ANAMIC1] = {
@@ -330,6 +352,8 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
                        .name = "V-AMIC1",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
                },
+               .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
+               .consumer_supplies = ab8500_vamic1_consumers,
        },
        /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
        [AB8500_LDO_ANAMIC2] = {
@@ -337,6 +361,8 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
                        .name = "V-AMIC2",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
                },
+               .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
+               .consumer_supplies = ab8500_vamic2_consumers,
        },
        /* supply for v-dmic, VDMIC LDO */
        [AB8500_LDO_DMIC] = {
@@ -344,6 +370,8 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
                        .name = "V-DMIC",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
                },
+               .num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers),
+               .consumer_supplies = ab8500_vdmic_consumers,
        },
        /* supply for v-intcore12, VINTCORE12 LDO */
        [AB8500_LDO_INTCORE] = {
index 5dde4d4..920251c 100644 (file)
  * SDI 0 (MicroSD slot)
  */
 
-/* MMCIPOWER bits */
-#define MCI_DATA2DIREN         (1 << 2)
-#define MCI_CMDDIREN           (1 << 3)
-#define MCI_DATA0DIREN         (1 << 4)
-#define MCI_DATA31DIREN                (1 << 5)
-#define MCI_FBCLKEN            (1 << 7)
-
 /* GPIO pins used by the sdi0 level shifter */
 static int sdi0_en = -1;
 static int sdi0_vsel = -1;
 
-static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd,
-                                  unsigned char power_mode)
+static int mop500_sdi0_ios_handler(struct device *dev, struct mmc_ios *ios)
 {
-       switch (power_mode) {
+       switch (ios->power_mode) {
        case MMC_POWER_UP:
        case MMC_POWER_ON:
                /*
@@ -65,8 +57,7 @@ static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd,
                break;
        }
 
-       return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN |
-              MCI_DATA2DIREN | MCI_DATA31DIREN;
+       return 0;
 }
 
 #ifdef CONFIG_STE_DMA40
@@ -90,13 +81,17 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = {
 #endif
 
 static struct mmci_platform_data mop500_sdi0_data = {
-       .vdd_handler    = mop500_sdi0_vdd_handler,
+       .ios_handler    = mop500_sdi0_ios_handler,
        .ocr_mask       = MMC_VDD_29_30,
        .f_max          = 50000000,
        .capabilities   = MMC_CAP_4_BIT_DATA |
                                MMC_CAP_SD_HIGHSPEED |
                                MMC_CAP_MMC_HIGHSPEED,
        .gpio_wp        = -1,
+       .sigdir         = MCI_ST_FBCLKEN |
+                               MCI_ST_CMDDIREN |
+                               MCI_ST_DATA0DIREN |
+                               MCI_ST_DATA2DIREN,
 #ifdef CONFIG_STE_DMA40
        .dma_filter     = stedma40_filter,
        .dma_rx_param   = &mop500_sdi0_dma_cfg_rx,
@@ -104,7 +99,7 @@ static struct mmci_platform_data mop500_sdi0_data = {
 #endif
 };
 
-static void sdi0_configure(void)
+static void sdi0_configure(struct device *parent)
 {
        int ret;
 
@@ -123,15 +118,15 @@ static void sdi0_configure(void)
        gpio_direction_output(sdi0_en, 1);
 
        /* Add the device, force v2 to subrevision 1 */
-       db8500_add_sdi0(&mop500_sdi0_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi0(parent, &mop500_sdi0_data, U8500_SDI_V2_PERIPHID);
 }
 
-void mop500_sdi_tc35892_init(void)
+void mop500_sdi_tc35892_init(struct device *parent)
 {
        mop500_sdi0_data.gpio_cd = GPIO_SDMMC_CD;
        sdi0_en = GPIO_SDMMC_EN;
        sdi0_vsel = GPIO_SDMMC_1V8_3V_SEL;
-       sdi0_configure();
+       sdi0_configure(parent);
 }
 
 /*
@@ -246,12 +241,13 @@ static struct mmci_platform_data mop500_sdi4_data = {
 #endif
 };
 
-void __init mop500_sdi_init(void)
+void __init mop500_sdi_init(struct device *parent)
 {
        /* PoP:ed eMMC */
-       db8500_add_sdi2(&mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi2(parent, &mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
        /* On-board eMMC */
-       db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+
        /*
         * On boards with the TC35892 GPIO expander, sdi0 will finally
         * be added when the TC35892 initializes and calls
@@ -259,31 +255,31 @@ void __init mop500_sdi_init(void)
         */
 }
 
-void __init snowball_sdi_init(void)
+void __init snowball_sdi_init(struct device *parent)
 {
        /* On Snowball MMC_CAP_SD_HIGHSPEED isn't supported (Hardware issue?) */
        mop500_sdi0_data.capabilities &= ~MMC_CAP_SD_HIGHSPEED;
        /* On-board eMMC */
-       db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
        /* External Micro SD slot */
        mop500_sdi0_data.gpio_cd = SNOWBALL_SDMMC_CD_GPIO;
        mop500_sdi0_data.cd_invert = true;
        sdi0_en = SNOWBALL_SDMMC_EN_GPIO;
        sdi0_vsel = SNOWBALL_SDMMC_1V8_3V_GPIO;
-       sdi0_configure();
+       sdi0_configure(parent);
 }
 
-void __init hrefv60_sdi_init(void)
+void __init hrefv60_sdi_init(struct device *parent)
 {
        /* PoP:ed eMMC */
-       db8500_add_sdi2(&mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi2(parent, &mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
        /* On-board eMMC */
-       db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
        /* External Micro SD slot */
        mop500_sdi0_data.gpio_cd = HREFV60_SDMMC_CD_GPIO;
        sdi0_en = HREFV60_SDMMC_EN_GPIO;
        sdi0_vsel = HREFV60_SDMMC_1V8_3V_GPIO;
-       sdi0_configure();
+       sdi0_configure(parent);
        /* WLAN SDIO channel */
-       db8500_add_sdi1(&mop500_sdi1_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi1(parent, &mop500_sdi1_data, U8500_SDI_V2_PERIPHID);
 }
index feb5744..ead91c9 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/tc3589x.h>
 #include <linux/input/matrix_keypad.h>
index 5c00712..77d03c1 100644 (file)
@@ -30,6 +30,9 @@
 #include <linux/gpio_keys.h>
 #include <linux/delay.h>
 
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
 #include <linux/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -72,7 +75,7 @@ static struct platform_device snowball_led_dev = {
 };
 
 static struct ab8500_gpio_platform_data ab8500_gpio_pdata = {
-       .gpio_base              = MOP500_AB8500_GPIO(0),
+       .gpio_base              = MOP500_AB8500_PIN_GPIO(1),
        .irq_base               = MOP500_AB8500_VIR_GPIO_IRQ_BASE,
        /* config_reg is the initial configuration of ab8500 pins.
         * The pins can be configured as GPIO or alt functions based
@@ -226,7 +229,12 @@ static struct tps6105x_platform_data mop500_tps61052_data = {
 
 static void mop500_tc35892_init(struct tc3589x *tc3589x, unsigned int base)
 {
-       mop500_sdi_tc35892_init();
+       struct device *parent = NULL;
+#if 0
+       /* FIXME: Is the sdi actually part of tc3589x? */
+       parent = tc3589x->dev;
+#endif
+       mop500_sdi_tc35892_init(parent);
 }
 
 static struct tc3589x_gpio_platform_data mop500_tc35892_gpio_data = {
@@ -353,12 +361,12 @@ U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 U8500_I2C_CONTROLLER(2,        0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 U8500_I2C_CONTROLLER(3,        0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 
-static void __init mop500_i2c_init(void)
+static void __init mop500_i2c_init(struct device *parent)
 {
-       db8500_add_i2c0(&u8500_i2c0_data);
-       db8500_add_i2c1(&u8500_i2c1_data);
-       db8500_add_i2c2(&u8500_i2c2_data);
-       db8500_add_i2c3(&u8500_i2c3_data);
+       db8500_add_i2c0(parent, &u8500_i2c0_data);
+       db8500_add_i2c1(parent, &u8500_i2c1_data);
+       db8500_add_i2c2(parent, &u8500_i2c2_data);
+       db8500_add_i2c3(parent, &u8500_i2c3_data);
 }
 
 static struct gpio_keys_button mop500_gpio_keys[] = {
@@ -435,7 +443,7 @@ static struct stedma40_chan_cfg ssp0_dma_cfg_tx = {
 };
 #endif
 
-static struct pl022_ssp_controller ssp0_platform_data = {
+static struct pl022_ssp_controller ssp0_plat = {
        .bus_id = 0,
 #ifdef CONFIG_STE_DMA40
        .enable_dma = 1,
@@ -451,9 +459,9 @@ static struct pl022_ssp_controller ssp0_platform_data = {
        .num_chipselect = 5,
 };
 
-static void __init mop500_spi_init(void)
+static void __init mop500_spi_init(struct device *parent)
 {
-       db8500_add_ssp0(&ssp0_platform_data);
+       db8500_add_ssp0(parent, &ssp0_plat);
 }
 
 #ifdef CONFIG_STE_DMA40
@@ -587,11 +595,11 @@ static struct amba_pl011_data uart2_plat = {
 #endif
 };
 
-static void __init mop500_uart_init(void)
+static void __init mop500_uart_init(struct device *parent)
 {
-       db8500_add_uart0(&uart0_plat);
-       db8500_add_uart1(&uart1_plat);
-       db8500_add_uart2(&uart2_plat);
+       db8500_add_uart0(parent, &uart0_plat);
+       db8500_add_uart1(parent, &uart1_plat);
+       db8500_add_uart2(parent, &uart2_plat);
 }
 
 static struct platform_device *snowball_platform_devs[] __initdata = {
@@ -603,21 +611,27 @@ static struct platform_device *snowball_platform_devs[] __initdata = {
 
 static void __init mop500_init_machine(void)
 {
+       struct device *parent = NULL;
        int i2c0_devs;
+       int i;
 
        mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
 
-       u8500_init_devices();
+       parent = u8500_init_devices();
 
        mop500_pins_init();
 
+       /* FIXME: parent of ab8500 should be prcmu */
+       for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
+               mop500_platform_devs[i]->dev.parent = parent;
+
        platform_add_devices(mop500_platform_devs,
                        ARRAY_SIZE(mop500_platform_devs));
 
-       mop500_i2c_init();
-       mop500_sdi_init();
-       mop500_spi_init();
-       mop500_uart_init();
+       mop500_i2c_init(parent);
+       mop500_sdi_init(parent);
+       mop500_spi_init(parent);
+       mop500_uart_init(parent);
 
        i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
 
@@ -631,19 +645,24 @@ static void __init mop500_init_machine(void)
 
 static void __init snowball_init_machine(void)
 {
+       struct device *parent = NULL;
        int i2c0_devs;
+       int i;
 
-       u8500_init_devices();
+       parent = u8500_init_devices();
 
        snowball_pins_init();
 
+       for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++)
+               snowball_platform_devs[i]->dev.parent = parent;
+
        platform_add_devices(snowball_platform_devs,
                        ARRAY_SIZE(snowball_platform_devs));
 
-       mop500_i2c_init();
-       snowball_sdi_init();
-       mop500_spi_init();
-       mop500_uart_init();
+       mop500_i2c_init(parent);
+       snowball_sdi_init(parent);
+       mop500_spi_init(parent);
+       mop500_uart_init(parent);
 
        i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
        i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
@@ -656,7 +675,9 @@ static void __init snowball_init_machine(void)
 
 static void __init hrefv60_init_machine(void)
 {
+       struct device *parent = NULL;
        int i2c0_devs;
+       int i;
 
        /*
         * The HREFv60 board removed a GPIO expander and routed
@@ -665,17 +686,20 @@ static void __init hrefv60_init_machine(void)
         */
        mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
 
-       u8500_init_devices();
+       parent = u8500_init_devices();
 
        hrefv60_pins_init();
 
+       for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
+               mop500_platform_devs[i]->dev.parent = parent;
+
        platform_add_devices(mop500_platform_devs,
                        ARRAY_SIZE(mop500_platform_devs));
 
-       mop500_i2c_init();
-       hrefv60_sdi_init();
-       mop500_spi_init();
-       mop500_uart_init();
+       mop500_i2c_init(parent);
+       hrefv60_sdi_init(parent);
+       mop500_spi_init(parent);
+       mop500_uart_init(parent);
 
        i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
 
@@ -718,3 +742,94 @@ MACHINE_START(SNOWBALL, "Calao Systems Snowball platform")
        .handle_irq     = gic_handle_irq,
        .init_machine   = snowball_init_machine,
 MACHINE_END
+
+#ifdef CONFIG_MACH_UX500_DT
+
+struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
+       OF_DEV_AUXDATA("arm,pl011", 0x80120000, "uart0", &uart0_plat),
+       OF_DEV_AUXDATA("arm,pl011", 0x80121000, "uart1", &uart1_plat),
+       OF_DEV_AUXDATA("arm,pl011", 0x80007000, "uart2", &uart2_plat),
+       OF_DEV_AUXDATA("arm,pl022", 0x80002000, "ssp0",  &ssp0_plat),
+       {},
+};
+
+static const struct of_device_id u8500_soc_node[] = {
+       /* only create devices below soc node */
+       { .compatible = "stericsson,db8500", },
+       { },
+};
+
+static void __init u8500_init_machine(void)
+{
+       struct device *parent = NULL;
+       int i2c0_devs;
+       int i;
+
+       parent = u8500_init_devices();
+       i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
+
+       for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
+               mop500_platform_devs[i]->dev.parent = parent;
+       for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++)
+               snowball_platform_devs[i]->dev.parent = parent;
+
+       /* automatically probe child nodes of db8500 device */
+       of_platform_populate(NULL, u8500_soc_node, u8500_auxdata_lookup, parent);
+
+       if (of_machine_is_compatible("st-ericsson,mop500")) {
+               mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
+               mop500_pins_init();
+
+               platform_add_devices(mop500_platform_devs,
+                               ARRAY_SIZE(mop500_platform_devs));
+
+               mop500_sdi_init(parent);
+       } else if (of_machine_is_compatible("calaosystems,snowball-a9500")) {
+               snowball_pins_init();
+               platform_add_devices(snowball_platform_devs,
+                               ARRAY_SIZE(snowball_platform_devs));
+
+               snowball_sdi_init(parent);
+       } else if (of_machine_is_compatible("st-ericsson,hrefv60+")) {
+               /*
+                * The HREFv60 board removed a GPIO expander and routed
+                * all these GPIO pins to the internal GPIO controller
+                * instead.
+                */
+               mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
+               i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES;
+               hrefv60_pins_init();
+               platform_add_devices(mop500_platform_devs,
+                               ARRAY_SIZE(mop500_platform_devs));
+
+               hrefv60_sdi_init(parent);
+       }
+       mop500_i2c_init(parent);
+
+       i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
+       i2c_register_board_info(2, mop500_i2c2_devices,
+                               ARRAY_SIZE(mop500_i2c2_devices));
+
+       /* This board has full regulator constraints */
+       regulator_has_full_constraints();
+}
+
+static const char * u8500_dt_board_compat[] = {
+       "calaosystems,snowball-a9500",
+       "st-ericsson,hrefv60+",
+       "st-ericsson,u8500",
+       "st-ericsson,mop500",
+       NULL,
+};
+
+
+DT_MACHINE_START(U8500_DT, "ST-Ericsson U8500 platform (Device Tree Support)")
+       .map_io         = u8500_map_io,
+       .init_irq       = ux500_init_irq,
+       /* we re-use nomadik timer here */
+       .timer          = &ux500_timer,
+       .handle_irq     = gic_handle_irq,
+       .init_machine   = u8500_init_machine,
+       .dt_compat      = u8500_dt_board_compat,
+MACHINE_END
+#endif
index f926d3d..fdcfa87 100644 (file)
@@ -63,7 +63,7 @@
  * because the AB8500 GPIO pins are enumbered starting from 1, so the value in
  * parens matches the GPIO pin number in the data sheet.
  */
-#define MOP500_AB8500_GPIO(x)          (MOP500_EGPIO_END + (x) - 1)
+#define MOP500_AB8500_PIN_GPIO(x)      (MOP500_EGPIO_END + (x) - 1)
 /*Snowball AB8500 GPIO */
 #define SNOWBALL_VSMPS2_1V8_GPIO       MOP500_AB8500_PIN_GPIO(1)       /* SYSCLKREQ2/GPIO1 */
 #define SNOWBALL_PM_GPIO1_GPIO         MOP500_AB8500_PIN_GPIO(2)       /* SYSCLKREQ3/GPIO2 */
 
 struct i2c_board_info;
 
-extern void mop500_sdi_init(void);
-extern void snowball_sdi_init(void);
-extern void hrefv60_sdi_init(void);
-extern void mop500_sdi_tc35892_init(void);
+extern void mop500_sdi_init(struct device *parent);
+extern void snowball_sdi_init(struct device *parent);
+extern void hrefv60_sdi_init(struct device *parent);
+extern void mop500_sdi_tc35892_init(struct device *parent);
 void __init mop500_u8500uib_init(void);
 void __init mop500_stuib_init(void);
 void __init mop500_pins_init(void);
index 63c3f80..836112e 100644 (file)
@@ -66,9 +66,9 @@ static struct mmci_platform_data u5500_sdi0_data = {
 #endif
 };
 
-void __init u5500_sdi_init(void)
+void __init u5500_sdi_init(struct device *parent)
 {
        nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins));
 
-       db5500_add_sdi0(&u5500_sdi0_data);
+       db5500_add_sdi0(parent, &u5500_sdi0_data);
 }
index 9de9e9c..0ff4be7 100644 (file)
@@ -97,9 +97,9 @@ static struct i2c_board_info __initdata u5500_i2c2_devices[] = {
        },
 };
 
-static void __init u5500_i2c_init(void)
+static void __init u5500_i2c_init(struct device *parent)
 {
-       db5500_add_i2c2(&u5500_i2c2_data);
+       db5500_add_i2c2(parent, &u5500_i2c2_data);
        i2c_register_board_info(2, ARRAY_AND_SIZE(u5500_i2c2_devices));
 }
 
@@ -126,20 +126,27 @@ static struct platform_device *u5500_platform_devices[] __initdata = {
        &ab5500_device,
 };
 
-static void __init u5500_uart_init(void)
+static void __init u5500_uart_init(struct device *parent)
 {
-       db5500_add_uart0(NULL);
-       db5500_add_uart1(NULL);
-       db5500_add_uart2(NULL);
+       db5500_add_uart0(parent, NULL);
+       db5500_add_uart1(parent, NULL);
+       db5500_add_uart2(parent, NULL);
 }
 
 static void __init u5500_init_machine(void)
 {
-       u5500_init_devices();
+       struct device *parent = NULL;
+       int i;
+
+       parent = u5500_init_devices();
        nmk_config_pins(u5500_pins, ARRAY_SIZE(u5500_pins));
-       u5500_i2c_init();
-       u5500_sdi_init();
-       u5500_uart_init();
+
+       u5500_i2c_init(parent);
+       u5500_sdi_init(parent);
+       u5500_uart_init(parent);
+
+       for (i = 0; i < ARRAY_SIZE(u5500_platform_devices); i++)
+               u5500_platform_devices[i]->dev.parent = parent;
 
        platform_add_devices(u5500_platform_devices,
                ARRAY_SIZE(u5500_platform_devices));
index da5569d..77a75ed 100644 (file)
@@ -5,6 +5,8 @@
  */
 
 #include <linux/io.h>
+#include <linux/of.h>
+
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <mach/hardware.h>
@@ -45,7 +47,10 @@ static int __init ux500_l2x0_init(void)
        ux500_l2x0_unlock();
 
        /* 64KB way size, 8 way associativity, force WA */
-       l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
+       if (of_have_populated_dt())
+               l2x0_of_init(0x3e060000, 0xc0000fff);
+       else
+               l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
 
        /*
         * We can't disable l2 as we are in non secure mode, currently
index 7379075..ec35f0a 100644 (file)
@@ -223,6 +223,13 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL(clk_set_rate);
 
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       /*TODO*/
+       return -ENOSYS;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
 static void clk_prcmu_enable(struct clk *clk)
 {
        void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE)
index 0744907..d776ada 100644 (file)
@@ -21,6 +21,7 @@ struct clkops {
        void (*enable) (struct clk *);
        void (*disable) (struct clk *);
        unsigned long (*get_rate) (struct clk *);
+       int (*set_parent)(struct clk *, struct clk *);
 };
 
 /**
index 18aa5c0..bca47f3 100644 (file)
@@ -147,13 +147,13 @@ static resource_size_t __initdata db5500_gpio_base[] = {
        U5500_GPIOBANK7_BASE,
 };
 
-static void __init db5500_add_gpios(void)
+static void __init db5500_add_gpios(struct device *parent)
 {
        struct nmk_gpio_platform_data pdata = {
                /* No custom data yet */
        };
 
-       dbx500_add_gpios(ARRAY_AND_SIZE(db5500_gpio_base),
+       dbx500_add_gpios(parent, ARRAY_AND_SIZE(db5500_gpio_base),
                         IRQ_DB5500_GPIO0, &pdata);
 }
 
@@ -212,14 +212,36 @@ static int usb_db5500_tx_dma_cfg[] = {
        DB5500_DMA_DEV38_USB_OTG_OEP_8
 };
 
-void __init u5500_init_devices(void)
+static const char *db5500_read_soc_id(void)
 {
-       db5500_add_gpios();
+       return kasprintf(GFP_KERNEL, "u5500 currently unsupported\n");
+}
+
+static struct device * __init db5500_soc_device_init(void)
+{
+       const char *soc_id = db5500_read_soc_id();
+
+       return ux500_soc_device_init(soc_id);
+}
+
+struct device * __init u5500_init_devices(void)
+{
+       struct device *parent;
+       int i;
+
+       parent = db5500_soc_device_init();
+
+       db5500_add_gpios(parent);
        db5500_pmu_init();
-       db5500_dma_init();
-       db5500_add_rtc();
-       db5500_add_usb(usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg);
+       db5500_dma_init(parent);
+       db5500_add_rtc(parent);
+       db5500_add_usb(parent, usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg);
+
+       for (i = 0; i < ARRAY_SIZE(db5500_platform_devs); i++)
+               db5500_platform_devs[i]->dev.parent = parent;
 
        platform_add_devices(db5500_platform_devs,
                             ARRAY_SIZE(db5500_platform_devs));
+
+       return parent;
 }
index 7176ee7..9bd8163 100644 (file)
@@ -24,6 +24,7 @@
 #include <mach/setup.h>
 #include <mach/devices.h>
 #include <mach/usb.h>
+#include <mach/db8500-regs.h>
 
 #include "devices-db8500.h"
 #include "ste-dma40-db8500.h"
@@ -132,13 +133,13 @@ static resource_size_t __initdata db8500_gpio_base[] = {
        U8500_GPIOBANK8_BASE,
 };
 
-static void __init db8500_add_gpios(void)
+static void __init db8500_add_gpios(struct device *parent)
 {
        struct nmk_gpio_platform_data pdata = {
                .supports_sleepmode = true,
        };
 
-       dbx500_add_gpios(ARRAY_AND_SIZE(db8500_gpio_base),
+       dbx500_add_gpios(parent, ARRAY_AND_SIZE(db8500_gpio_base),
                         IRQ_DB8500_GPIO0, &pdata);
 }
 
@@ -164,17 +165,44 @@ static int usb_db8500_tx_dma_cfg[] = {
        DB8500_DMA_DEV39_USB_OTG_OEP_8
 };
 
+static const char *db8500_read_soc_id(void)
+{
+       void __iomem *uid = __io_address(U8500_BB_UID_BASE);
+
+       return kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x",
+                        readl((u32 *)uid+1),
+                        readl((u32 *)uid+1), readl((u32 *)uid+2),
+                        readl((u32 *)uid+3), readl((u32 *)uid+4));
+}
+
+static struct device * __init db8500_soc_device_init(void)
+{
+       const char *soc_id = db8500_read_soc_id();
+
+       return ux500_soc_device_init(soc_id);
+}
+
 /*
  * This function is called from the board init
  */
-void __init u8500_init_devices(void)
+struct device * __init u8500_init_devices(void)
 {
-       db8500_add_rtc();
-       db8500_add_gpios();
-       db8500_add_usb(usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
+       struct device *parent;
+       int i;
+
+       parent = db8500_soc_device_init();
+
+       db8500_add_rtc(parent);
+       db8500_add_gpios(parent);
+       db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
+
+       platform_device_register_data(parent,
+               "cpufreq-u8500", -1, NULL, 0);
+
+       for (i = 0; i < ARRAY_SIZE(platform_devs); i++)
+               platform_devs[i]->dev.parent = parent;
 
-       platform_device_register_simple("cpufreq-u8500", -1, NULL, 0);
        platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
 
-       return ;
+       return parent;
 }
index f418574..d11f389 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (C) ST-Ericsson SA 2010
  *
  * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson
  * License terms: GNU General Public License (GPL) version 2
  */
 
 #include <linux/mfd/db8500-prcmu.h>
 #include <linux/mfd/db5500-prcmu.h>
 #include <linux/clksrc-dbx500-prcmu.h>
+#include <linux/sys_soc.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
 
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
-#include <asm/localtimer.h>
 
 #include <mach/hardware.h>
 #include <mach/setup.h>
 
 void __iomem *_PRCMU_BASE;
 
+static const struct of_device_id ux500_dt_irq_match[] = {
+       { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+       {},
+};
+
 void __init ux500_init_irq(void)
 {
        void __iomem *dist_base;
@@ -38,7 +49,12 @@ void __init ux500_init_irq(void)
        } else
                ux500_unknown_soc();
 
-       gic_init(0, 29, dist_base, cpu_base);
+#ifdef CONFIG_OF
+       if (of_have_populated_dt())
+               of_irq_init(ux500_dt_irq_match);
+       else
+#endif
+               gic_init(0, 29, dist_base, cpu_base);
 
        /*
         * Init clocks here so that they are available for system timer
@@ -50,3 +66,73 @@ void __init ux500_init_irq(void)
                db8500_prcmu_early_init();
        clk_init();
 }
+
+static const char * __init ux500_get_machine(void)
+{
+       return kasprintf(GFP_KERNEL, "DB%4x", dbx500_partnumber());
+}
+
+static const char * __init ux500_get_family(void)
+{
+       return kasprintf(GFP_KERNEL, "ux500");
+}
+
+static const char * __init ux500_get_revision(void)
+{
+       unsigned int rev = dbx500_revision();
+
+       if (rev == 0x01)
+               return kasprintf(GFP_KERNEL, "%s", "ED");
+       else if (rev >= 0xA0)
+               return kasprintf(GFP_KERNEL, "%d.%d",
+                                (rev >> 4) - 0xA + 1, rev & 0xf);
+
+       return kasprintf(GFP_KERNEL, "%s", "Unknown");
+}
+
+static ssize_t ux500_get_process(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       if (dbx500_id.process == 0x00)
+               return sprintf(buf, "Standard\n");
+
+       return sprintf(buf, "%02xnm\n", dbx500_id.process);
+}
+
+static void __init soc_info_populate(struct soc_device_attribute *soc_dev_attr,
+                                    const char *soc_id)
+{
+       soc_dev_attr->soc_id   = soc_id;
+       soc_dev_attr->machine  = ux500_get_machine();
+       soc_dev_attr->family   = ux500_get_family();
+       soc_dev_attr->revision = ux500_get_revision();
+}
+
+struct device_attribute ux500_soc_attr =
+       __ATTR(process,  S_IRUGO, ux500_get_process,  NULL);
+
+struct device * __init ux500_soc_device_init(const char *soc_id)
+{
+       struct device *parent;
+       struct soc_device *soc_dev;
+       struct soc_device_attribute *soc_dev_attr;
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return ERR_PTR(-ENOMEM);
+
+       soc_info_populate(soc_dev_attr, soc_id);
+
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR_OR_NULL(soc_dev)) {
+               kfree(soc_dev_attr);
+               return NULL;
+       }
+
+       parent = soc_device_to_device(soc_dev);
+       if (!IS_ERR_OR_NULL(parent))
+               device_create_file(parent, &ux500_soc_attr);
+
+       return parent;
+}
index c563e54..c5312a4 100644 (file)
 #include "devices-common.h"
 
 struct amba_device *
-dbx500_add_amba_device(const char *name, resource_size_t base,
-                      int irq, void *pdata, unsigned int periphid)
+dbx500_add_amba_device(struct device *parent, const char *name,
+                      resource_size_t base, int irq, void *pdata,
+                      unsigned int periphid)
 {
        struct amba_device *dev;
        int ret;
 
-       dev = kzalloc(sizeof *dev, GFP_KERNEL);
+       dev = amba_device_alloc(name, base, SZ_4K);
        if (!dev)
                return ERR_PTR(-ENOMEM);
 
-       dev->dev.init_name = name;
-
-       dev->res.start = base;
-       dev->res.end = base + SZ_4K - 1;
-       dev->res.flags = IORESOURCE_MEM;
-
        dev->dma_mask = DMA_BIT_MASK(32);
        dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 
        dev->irq[0] = irq;
-       dev->irq[1] = NO_IRQ;
 
        dev->periphid = periphid;
 
        dev->dev.platform_data = pdata;
 
-       ret = amba_device_register(dev, &iomem_resource);
+       dev->dev.parent = parent;
+
+       ret = amba_device_add(dev, &iomem_resource);
        if (ret) {
-               kfree(dev);
+               amba_device_put(dev);
                return ERR_PTR(ret);
        }
 
@@ -56,60 +52,7 @@ dbx500_add_amba_device(const char *name, resource_size_t base,
 }
 
 static struct platform_device *
-dbx500_add_platform_device(const char *name, int id, void *pdata,
-                          struct resource *res, int resnum)
-{
-       struct platform_device *dev;
-       int ret;
-
-       dev = platform_device_alloc(name, id);
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-       dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
-
-       ret = platform_device_add_resources(dev, res, resnum);
-       if (ret)
-               goto out_free;
-
-       dev->dev.platform_data = pdata;
-
-       ret = platform_device_add(dev);
-       if (ret)
-               goto out_free;
-
-       return dev;
-
-out_free:
-       platform_device_put(dev);
-       return ERR_PTR(ret);
-}
-
-struct platform_device *
-dbx500_add_platform_device_4k1irq(const char *name, int id,
-                                 resource_size_t base,
-                                 int irq, void *pdata)
-{
-       struct resource resources[] = {
-               [0] = {
-                       .start  = base,
-                       .end    = base + SZ_4K - 1,
-                       .flags  = IORESOURCE_MEM,
-               },
-               [1] = {
-                       .start  = irq,
-                       .end    = irq,
-                       .flags  = IORESOURCE_IRQ,
-               }
-       };
-
-       return dbx500_add_platform_device(name, id, pdata, resources,
-                                         ARRAY_SIZE(resources));
-}
-
-static struct platform_device *
-dbx500_add_gpio(int id, resource_size_t addr, int irq,
+dbx500_add_gpio(struct device *parent, int id, resource_size_t addr, int irq,
                struct nmk_gpio_platform_data *pdata)
 {
        struct resource resources[] = {
@@ -125,13 +68,18 @@ dbx500_add_gpio(int id, resource_size_t addr, int irq,
                }
        };
 
-       return platform_device_register_resndata(NULL, "gpio", id,
-                               resources, ARRAY_SIZE(resources),
-                               pdata, sizeof(*pdata));
+       return platform_device_register_resndata(
+               parent,
+               "gpio",
+               id,
+               resources,
+               ARRAY_SIZE(resources),
+               pdata,
+               sizeof(*pdata));
 }
 
-void dbx500_add_gpios(resource_size_t *base, int num, int irq,
-                     struct nmk_gpio_platform_data *pdata)
+void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num,
+                     int irq, struct nmk_gpio_platform_data *pdata)
 {
        int first = 0;
        int i;
@@ -141,6 +89,6 @@ void dbx500_add_gpios(resource_size_t *base, int num, int irq,
                pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first);
                pdata->num_gpio = 32;
 
-               dbx500_add_gpio(i, base[i], irq, pdata);
+               dbx500_add_gpio(parent, i, base[i], irq, pdata);
        }
 }
index 7825705..39c74ec 100644 (file)
@@ -8,80 +8,89 @@
 #ifndef __DEVICES_COMMON_H
 #define __DEVICES_COMMON_H
 
-extern struct amba_device *
-dbx500_add_amba_device(const char *name, resource_size_t base,
-                      int irq, void *pdata, unsigned int periphid);
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/sys_soc.h>
+#include <plat/i2c.h>
 
-extern struct platform_device *
-dbx500_add_platform_device_4k1irq(const char *name, int id,
-                                 resource_size_t base,
-                                 int irq, void *pdata);
+extern struct amba_device *
+dbx500_add_amba_device(struct device *parent, const char *name,
+                      resource_size_t base, int irq, void *pdata,
+                      unsigned int periphid);
 
 struct spi_master_cntlr;
 
 static inline struct amba_device *
-dbx500_add_msp_spi(const char *name, resource_size_t base, int irq,
+dbx500_add_msp_spi(struct device *parent, const char *name,
+                  resource_size_t base, int irq,
                   struct spi_master_cntlr *pdata)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, 0);
+       return dbx500_add_amba_device(parent, name, base, irq,
+                                     pdata, 0);
 }
 
 static inline struct amba_device *
-dbx500_add_spi(const char *name, resource_size_t base, int irq,
-              struct spi_master_cntlr *pdata,
+dbx500_add_spi(struct device *parent, const char *name, resource_size_t base,
+              int irq, struct spi_master_cntlr *pdata,
               u32 periphid)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, periphid);
+       return dbx500_add_amba_device(parent, name, base, irq,
+                                     pdata, periphid);
 }
 
 struct mmci_platform_data;
 
 static inline struct amba_device *
-dbx500_add_sdi(const char *name, resource_size_t base, int irq,
-              struct mmci_platform_data *pdata,
-              u32 periphid)
+dbx500_add_sdi(struct device *parent, const char *name, resource_size_t base,
+              int irq, struct mmci_platform_data *pdata, u32 periphid)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, periphid);
+       return dbx500_add_amba_device(parent, name, base, irq,
+                                     pdata, periphid);
 }
 
 struct amba_pl011_data;
 
 static inline struct amba_device *
-dbx500_add_uart(const char *name, resource_size_t base, int irq,
-               struct amba_pl011_data *pdata)
+dbx500_add_uart(struct device *parent, const char *name, resource_size_t base,
+               int irq, struct amba_pl011_data *pdata)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, 0);
+       return dbx500_add_amba_device(parent, name, base, irq, pdata, 0);
 }
 
 struct nmk_i2c_controller;
 
 static inline struct platform_device *
-dbx500_add_i2c(int id, resource_size_t base, int irq,
-              struct nmk_i2c_controller *pdata)
-{
-       return dbx500_add_platform_device_4k1irq("nmk-i2c", id, base, irq,
-                                                pdata);
-}
-
-struct msp_i2s_platform_data;
-
-static inline struct platform_device *
-dbx500_add_msp_i2s(int id, resource_size_t base, int irq,
-                  struct msp_i2s_platform_data *pdata)
+dbx500_add_i2c(struct device *parent, int id, resource_size_t base, int irq,
+              struct nmk_i2c_controller *data)
 {
-       return dbx500_add_platform_device_4k1irq("MSP_I2S", id, base, irq,
-                                                pdata);
+       struct resource res[] = {
+               DEFINE_RES_MEM(base, SZ_4K),
+               DEFINE_RES_IRQ(irq),
+       };
+
+       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);
 }
 
 static inline struct amba_device *
-dbx500_add_rtc(resource_size_t base, int irq)
+dbx500_add_rtc(struct device *parent, resource_size_t base, int irq)
 {
-       return dbx500_add_amba_device("rtc-pl031", base, irq, NULL, 0);
+       return dbx500_add_amba_device(parent, "rtc-pl031", base, irq, NULL, 0);
 }
 
 struct nmk_gpio_platform_data;
 
-void dbx500_add_gpios(resource_size_t *base, int num, int irq,
-                     struct nmk_gpio_platform_data *pdata);
+void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num,
+                     int irq, struct nmk_gpio_platform_data *pdata);
 
 #endif
index 0c4bccd..e709555 100644 (file)
 
 #include "devices-common.h"
 
-#define db5500_add_i2c1(pdata) \
-       dbx500_add_i2c(1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata)
-#define db5500_add_i2c2(pdata) \
-       dbx500_add_i2c(2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata)
-#define db5500_add_i2c3(pdata) \
-       dbx500_add_i2c(3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata)
+#define db5500_add_i2c1(parent, pdata) \
+       dbx500_add_i2c(parent, 1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata)
+#define db5500_add_i2c2(parent, pdata) \
+       dbx500_add_i2c(parent, 2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata)
+#define db5500_add_i2c3(parent, pdata) \
+       dbx500_add_i2c(parent, 3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata)
 
-#define db5500_add_msp0_i2s(pdata) \
-       dbx500_add_msp_i2s(0, U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata)
-#define db5500_add_msp1_i2s(pdata) \
-       dbx500_add_msp_i2s(1, U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata)
-#define db5500_add_msp2_i2s(pdata) \
-       dbx500_add_msp_i2s(2, U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata)
+#define db5500_add_msp0_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \
+                          IRQ_DB5500_MSP0, pdata)
+#define db5500_add_msp1_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \
+                          IRQ_DB5500_MSP1, pdata)
+#define db5500_add_msp2_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \
+                          IRQ_DB5500_MSP2, pdata)
 
-#define db5500_add_msp0_spi(pdata) \
-       dbx500_add_msp_spi("msp0", U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata)
-#define db5500_add_msp1_spi(pdata) \
-       dbx500_add_msp_spi("msp1", U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata)
-#define db5500_add_msp2_spi(pdata) \
-       dbx500_add_msp_spi("msp2", U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata)
+#define db5500_add_msp0_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \
+                         IRQ_DB5500_MSP0, pdata)
+#define db5500_add_msp1_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \
+                         IRQ_DB5500_MSP1, pdata)
+#define db5500_add_msp2_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \
+                         IRQ_DB5500_MSP2, pdata)
 
-#define db5500_add_rtc() \
-       dbx500_add_rtc(U5500_RTC_BASE, IRQ_DB5500_RTC);
+#define db5500_add_rtc(parent) \
+       dbx500_add_rtc(parent, U5500_RTC_BASE, IRQ_DB5500_RTC);
 
-#define db5500_add_usb(rx_cfg, tx_cfg) \
-       ux500_add_usb(U5500_USBOTG_BASE, IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
+#define db5500_add_usb(parent, rx_cfg, tx_cfg) \
+       ux500_add_usb(parent, U5500_USBOTG_BASE, \
+                     IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
 
-#define db5500_add_sdi0(pdata) \
-       dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata, \
+#define db5500_add_sdi0(parent, pdata) \
+       dbx500_add_sdi(parent, "sdi0", U5500_SDI0_BASE, \
+                      IRQ_DB5500_SDMMC0, pdata,        \
                       0x10480180)
-#define db5500_add_sdi1(pdata) \
-       dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata, \
+#define db5500_add_sdi1(parent, pdata) \
+       dbx500_add_sdi(parent, "sdi1", U5500_SDI1_BASE, \
+                      IRQ_DB5500_SDMMC1, pdata,        \
                       0x10480180)
-#define db5500_add_sdi2(pdata) \
-       dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata \
+#define db5500_add_sdi2(parent, pdata) \
+       dbx500_add_sdi(parent, "sdi2", U5500_SDI2_BASE, \
+                      IRQ_DB5500_SDMMC2, pdata         \
                       0x10480180)
-#define db5500_add_sdi3(pdata) \
-       dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata \
+#define db5500_add_sdi3(parent, pdata) \
+       dbx500_add_sdi(parent, "sdi3", U5500_SDI3_BASE, \
+                      IRQ_DB5500_SDMMC3, pdata         \
                       0x10480180)
-#define db5500_add_sdi4(pdata) \
-       dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata \
+#define db5500_add_sdi4(parent, pdata) \
+       dbx500_add_sdi(parent, "sdi4", U5500_SDI4_BASE, \
+                      IRQ_DB5500_SDMMC4, pdata         \
                       0x10480180)
 
 /* This one has a bad peripheral ID in the U5500 silicon */
-#define db5500_add_spi0(pdata) \
-       dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata, \
+#define db5500_add_spi0(parent, pdata) \
+       dbx500_add_spi(parent, "spi0", U5500_SPI0_BASE, \
+                      IRQ_DB5500_SPI0, pdata,          \
                       0x10080023)
-#define db5500_add_spi1(pdata) \
-       dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata, \
+#define db5500_add_spi1(parent, pdata) \
+       dbx500_add_spi(parent, "spi1", U5500_SPI1_BASE, \
+                      IRQ_DB5500_SPI1, pdata,          \
                       0x10080023)
-#define db5500_add_spi2(pdata) \
-       dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata \
+#define db5500_add_spi2(parent, pdata) \
+       dbx500_add_spi(parent, "spi2", U5500_SPI2_BASE, \
+                      IRQ_DB5500_SPI2, pdata           \
                       0x10080023)
-#define db5500_add_spi3(pdata) \
-       dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata \
+#define db5500_add_spi3(parent, pdata) \
+       dbx500_add_spi(parent, "spi3", U5500_SPI3_BASE, \
+                      IRQ_DB5500_SPI3, pdata           \
                       0x10080023)
 
-#define db5500_add_uart0(plat) \
-       dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0, plat)
-#define db5500_add_uart1(plat) \
-       dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1, plat)
-#define db5500_add_uart2(plat) \
-       dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2, plat)
-#define db5500_add_uart3(plat) \
-       dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3, plat)
+#define db5500_add_uart0(parent, plat) \
+       dbx500_add_uart(parent, "uart0", U5500_UART0_BASE, \
+                       IRQ_DB5500_UART0, plat)
+#define db5500_add_uart1(parent, plat) \
+       dbx500_add_uart(parent, "uart1", U5500_UART1_BASE, \
+                       IRQ_DB5500_UART1, plat)
+#define db5500_add_uart2(parent, plat) \
+       dbx500_add_uart(parent, "uart2", U5500_UART2_BASE, \
+                       IRQ_DB5500_UART2, plat)
+#define db5500_add_uart3(parent, plat) \
+       dbx500_add_uart(parent, "uart3", U5500_UART3_BASE, \
+                       IRQ_DB5500_UART3, plat)
 
 #endif
index a7c6cdc..6e66d37 100644 (file)
@@ -101,6 +101,9 @@ static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV] = {
        [DB8500_DMA_DEV41_SD_MM3_TX] = -1,
        [DB8500_DMA_DEV42_SD_MM4_TX] = -1,
        [DB8500_DMA_DEV43_SD_MM5_TX] = -1,
+       [DB8500_DMA_DEV14_MSP2_TX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
+       [DB8500_DMA_DEV30_MSP1_TX] = U8500_MSP1_BASE + MSP_TX_RX_REG_OFFSET,
+       [DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
 };
 
 /* Mapping between source event lines and physical device address */
@@ -133,6 +136,9 @@ static const dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV] = {
        [DB8500_DMA_DEV41_SD_MM3_RX] = -1,
        [DB8500_DMA_DEV42_SD_MM4_RX] = -1,
        [DB8500_DMA_DEV43_SD_MM5_RX] = -1,
+       [DB8500_DMA_DEV14_MSP2_RX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
+       [DB8500_DMA_DEV30_MSP3_RX] = U8500_MSP3_BASE + MSP_TX_RX_REG_OFFSET,
+       [DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
 };
 
 /* Reserved event lines for memcpy only */
index cbd4a9a..9fd93e9 100644 (file)
@@ -14,88 +14,114 @@ struct ske_keypad_platform_data;
 struct pl022_ssp_controller;
 
 static inline struct platform_device *
-db8500_add_ske_keypad(struct ske_keypad_platform_data *pdata)
+db8500_add_ske_keypad(struct device *parent,
+                     struct ske_keypad_platform_data *pdata,
+                     size_t size)
 {
-       return dbx500_add_platform_device_4k1irq("nmk-ske-keypad", -1,
-                                                U8500_SKE_BASE,
-                                                IRQ_DB8500_KB, pdata);
+       struct resource resources[] = {
+               DEFINE_RES_MEM(U8500_SKE_BASE, SZ_4K),
+               DEFINE_RES_IRQ(IRQ_DB8500_KB),
+       };
+
+       return platform_device_register_resndata(parent, "nmk-ske-keypad", -1,
+                                                resources, 2, pdata, size);
 }
 
 static inline struct amba_device *
-db8500_add_ssp(const char *name, resource_size_t base, int irq,
-              struct pl022_ssp_controller *pdata)
+db8500_add_ssp(struct device *parent, const char *name, resource_size_t base,
+              int irq, struct pl022_ssp_controller *pdata)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, 0);
+       return dbx500_add_amba_device(parent, name, base, irq, pdata, 0);
 }
 
 
-#define db8500_add_i2c0(pdata) \
-       dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
-#define db8500_add_i2c1(pdata) \
-       dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)
-#define db8500_add_i2c2(pdata) \
-       dbx500_add_i2c(2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata)
-#define db8500_add_i2c3(pdata) \
-       dbx500_add_i2c(3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata)
-#define db8500_add_i2c4(pdata) \
-       dbx500_add_i2c(4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata)
-
-#define db8500_add_msp0_i2s(pdata) \
-       dbx500_add_msp_i2s(0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
-#define db8500_add_msp1_i2s(pdata) \
-       dbx500_add_msp_i2s(1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
-#define db8500_add_msp2_i2s(pdata) \
-       dbx500_add_msp_i2s(2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
-#define db8500_add_msp3_i2s(pdata) \
-       dbx500_add_msp_i2s(3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
-
-#define db8500_add_msp0_spi(pdata) \
-       dbx500_add_msp_spi("msp0", U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
-#define db8500_add_msp1_spi(pdata) \
-       dbx500_add_msp_spi("msp1", U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
-#define db8500_add_msp2_spi(pdata) \
-       dbx500_add_msp_spi("msp2", U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
-#define db8500_add_msp3_spi(pdata) \
-       dbx500_add_msp_spi("msp3", U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
-
-#define db8500_add_rtc() \
-       dbx500_add_rtc(U8500_RTC_BASE, IRQ_DB8500_RTC);
-
-#define db8500_add_usb(rx_cfg, tx_cfg) \
-       ux500_add_usb(U8500_USBOTG_BASE, IRQ_DB8500_USBOTG, rx_cfg, tx_cfg)
-
-#define db8500_add_sdi0(pdata, pid) \
-       dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata, pid)
-#define db8500_add_sdi1(pdata, pid) \
-       dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata, pid)
-#define db8500_add_sdi2(pdata, pid) \
-       dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata, pid)
-#define db8500_add_sdi3(pdata, pid) \
-       dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata, pid)
-#define db8500_add_sdi4(pdata, pid) \
-       dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata, pid)
-#define db8500_add_sdi5(pdata, pid) \
-       dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata, pid)
-
-#define db8500_add_ssp0(pdata) \
-       db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata)
-#define db8500_add_ssp1(pdata) \
-       db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata)
-
-#define db8500_add_spi0(pdata) \
-       dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata, 0)
-#define db8500_add_spi1(pdata) \
-       dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata, 0)
-#define db8500_add_spi2(pdata) \
-       dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata, 0)
-#define db8500_add_spi3(pdata) \
-       dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata, 0)
-
-#define db8500_add_uart0(pdata) \
-       dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0, pdata)
-#define db8500_add_uart1(pdata) \
-       dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1, pdata)
-#define db8500_add_uart2(pdata) \
-       dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2, pdata)
+#define db8500_add_i2c0(parent, pdata) \
+       dbx500_add_i2c(parent, 0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
+#define db8500_add_i2c1(parent, pdata) \
+       dbx500_add_i2c(parent, 1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)
+#define db8500_add_i2c2(parent, pdata) \
+       dbx500_add_i2c(parent, 2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata)
+#define db8500_add_i2c3(parent, pdata) \
+       dbx500_add_i2c(parent, 3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata)
+#define db8500_add_i2c4(parent, pdata) \
+       dbx500_add_i2c(parent, 4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata)
+
+#define db8500_add_msp0_i2s(parent, pdata) \
+       dbx500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
+#define db8500_add_msp1_i2s(parent, pdata) \
+       dbx500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
+#define db8500_add_msp2_i2s(parent, pdata) \
+       dbx500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
+#define db8500_add_msp3_i2s(parent, pdata) \
+       dbx500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
+
+#define db8500_add_msp0_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp0", U8500_MSP0_BASE, \
+                          IRQ_DB8500_MSP0, pdata)
+#define db8500_add_msp1_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp1", U8500_MSP1_BASE, \
+                          IRQ_DB8500_MSP1, pdata)
+#define db8500_add_msp2_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp2", U8500_MSP2_BASE, \
+                          IRQ_DB8500_MSP2, pdata)
+#define db8500_add_msp3_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp3", U8500_MSP3_BASE, \
+                          IRQ_DB8500_MSP1, pdata)
+
+#define db8500_add_rtc(parent) \
+       dbx500_add_rtc(parent, U8500_RTC_BASE, IRQ_DB8500_RTC);
+
+#define db8500_add_usb(parent, rx_cfg, tx_cfg) \
+       ux500_add_usb(parent, U8500_USBOTG_BASE, \
+                     IRQ_DB8500_USBOTG, rx_cfg, tx_cfg)
+
+#define db8500_add_sdi0(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi0", U8500_SDI0_BASE, \
+                      IRQ_DB8500_SDMMC0, pdata, pid)
+#define db8500_add_sdi1(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi1", U8500_SDI1_BASE, \
+                      IRQ_DB8500_SDMMC1, pdata, pid)
+#define db8500_add_sdi2(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi2", U8500_SDI2_BASE, \
+                      IRQ_DB8500_SDMMC2, pdata, pid)
+#define db8500_add_sdi3(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi3", U8500_SDI3_BASE, \
+                      IRQ_DB8500_SDMMC3, pdata, pid)
+#define db8500_add_sdi4(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi4", U8500_SDI4_BASE, \
+                      IRQ_DB8500_SDMMC4, pdata, pid)
+#define db8500_add_sdi5(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi5", U8500_SDI5_BASE, \
+                      IRQ_DB8500_SDMMC5, pdata, pid)
+
+#define db8500_add_ssp0(parent, pdata) \
+       db8500_add_ssp(parent, "ssp0", U8500_SSP0_BASE, \
+                      IRQ_DB8500_SSP0, pdata)
+#define db8500_add_ssp1(parent, pdata) \
+       db8500_add_ssp(parent, "ssp1", U8500_SSP1_BASE, \
+                      IRQ_DB8500_SSP1, pdata)
+
+#define db8500_add_spi0(parent, pdata) \
+       dbx500_add_spi(parent, "spi0", U8500_SPI0_BASE, \
+                      IRQ_DB8500_SPI0, pdata, 0)
+#define db8500_add_spi1(parent, pdata) \
+       dbx500_add_spi(parent, "spi1", U8500_SPI1_BASE, \
+                      IRQ_DB8500_SPI1, pdata, 0)
+#define db8500_add_spi2(parent, pdata) \
+       dbx500_add_spi(parent, "spi2", U8500_SPI2_BASE, \
+                      IRQ_DB8500_SPI2, pdata, 0)
+#define db8500_add_spi3(parent, pdata) \
+       dbx500_add_spi(parent, "spi3", U8500_SPI3_BASE, \
+                      IRQ_DB8500_SPI3, pdata, 0)
+
+#define db8500_add_uart0(parent, pdata) \
+       dbx500_add_uart(parent, "uart0", U8500_UART0_BASE, \
+                       IRQ_DB8500_UART0, pdata)
+#define db8500_add_uart1(parent, pdata) \
+       dbx500_add_uart(parent, "uart1", U8500_UART1_BASE, \
+                       IRQ_DB8500_UART1, pdata)
+#define db8500_add_uart2(parent, pdata) \
+       dbx500_add_uart(parent, "uart2", U8500_UART2_BASE, \
+                       IRQ_DB8500_UART2, pdata)
 
 #endif
index 1cfab68..41e9470 100644 (file)
@@ -125,10 +125,11 @@ static struct platform_device dma40_device = {
        .resource       = dma40_resources
 };
 
-void __init db5500_dma_init(void)
+void __init db5500_dma_init(struct device *parent)
 {
        int ret;
 
+       dma40_device.dev.parent = parent;
        ret = platform_device_register(&dma40_device);
        if (ret)
                dev_err(&dma40_device.dev, "unable to register device: %d\n", ret);
index 80e10f5..9ec20b9 100644 (file)
 #define U8500_MODEM_BASE       0xe000000
 #define U8500_APE_BASE         0x6000000
 
+/* SoC identification number information */
+#define U8500_BB_UID_BASE      (U8500_BACKUPRAM1_BASE + 0xFC0)
+
 #endif
diff --git a/arch/arm/mach-ux500/include/mach/entry-macro.S b/arch/arm/mach-ux500/include/mach/entry-macro.S
deleted file mode 100644 (file)
index e16299e..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Low-level IRQ helper macros for U8500 platforms
- *
- * Copyright (C) 2009 ST-Ericsson.
- *
- * This file is a copy of ARM Realview platform.
- *     -just satisfied checkpatch script.
- *
- * 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.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index b6ba26a..d93d6db 100644 (file)
@@ -30,6 +30,8 @@
 #include <mach/db8500-regs.h>
 #include <mach/db5500-regs.h>
 
+#define MSP_TX_RX_REG_OFFSET   0
+
 #ifndef __ASSEMBLY__
 
 #include <mach/id.h>
index d2d4131..7d34c52 100644 (file)
@@ -13,7 +13,7 @@
 
 #define MOP500_AB8500_IRQ_BASE         IRQ_BOARD_START
 #define MOP500_AB8500_IRQ_END          (MOP500_AB8500_IRQ_BASE \
-                                        + AB8500_NR_IRQS)
+                                        + AB8500_MAX_NR_IRQS)
 
 /* TC35892 */
 #define TC35892_NR_INTERNAL_IRQS       8
index 9db68d2..c23a6b5 100644 (file)
@@ -43,7 +43,7 @@
 /* This will be overridden by board-specific irq headers */
 #define IRQ_BOARD_END          IRQ_BOARD_START
 
-#ifdef CONFIG_MACH_U8500
+#ifdef CONFIG_MACH_MOP500
 #include <mach/irqs-board-mop500.h>
 #endif
 
index a7d363f..3dc00ff 100644 (file)
@@ -18,17 +18,16 @@ void __init ux500_map_io(void);
 extern void __init u5500_map_io(void);
 extern void __init u8500_map_io(void);
 
-extern void __init u5500_init_devices(void);
-extern void __init u8500_init_devices(void);
+extern struct device * __init u5500_init_devices(void);
+extern struct device * __init u8500_init_devices(void);
 
 extern void __init ux500_init_irq(void);
 
-extern void __init u5500_sdi_init(void);
+extern void __init u5500_sdi_init(struct device *parent);
 
-extern void __init db5500_dma_init(void);
+extern void __init db5500_dma_init(struct device *parent);
 
-/* We re-use nomadik_timer for this platform */
-extern void nmdk_timer_init(void);
+extern struct device *ux500_soc_device_init(const char *soc_id);
 
 struct amba_device;
 extern void __init amba_add_devices(struct amba_device *devs[], int num);
diff --git a/arch/arm/mach-ux500/include/mach/system.h b/arch/arm/mach-ux500/include/mach/system.h
deleted file mode 100644 (file)
index 258e5c9..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2009 ST-Ericsson.
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       /*
-        * This should do all the clock switching
-        * and wait for interrupt tricks
-        */
-       cpu_do_idle();
-}
-
-#endif
index d3739d4..4c1cc50 100644 (file)
@@ -20,6 +20,6 @@ struct ux500_musb_board_data {
        bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
 };
 
-void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
-       int *dma_tx_cfg);
+void ux500_add_usb(struct device *parent, resource_size_t base,
+                  int irq, int *dma_rx_cfg, int *dma_tx_cfg);
 #endif
diff --git a/arch/arm/mach-ux500/localtimer.c b/arch/arm/mach-ux500/localtimer.c
deleted file mode 100644 (file)
index 5ba1133..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2008-2009 ST-Ericsson
- * Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
- *
- * This file is heavily based on relaview platform, almost a copy.
- *
- * Copyright (C) 2002 ARM Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-
-#include <asm/irq.h>
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       evt->irq = IRQ_LOCALTIMER;
-       twd_timer_setup(evt);
-       return 0;
-}
index aea467d..d37df98 100644 (file)
@@ -7,29 +7,52 @@
 #include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/clksrc-dbx500-prcmu.h>
+#include <linux/of.h>
 
-#include <asm/localtimer.h>
+#include <asm/smp_twd.h>
 
 #include <plat/mtu.h>
 
 #include <mach/setup.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
+
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(u5500_twd_local_timer,
+                             U5500_TWD_BASE, IRQ_LOCALTIMER);
+static DEFINE_TWD_LOCAL_TIMER(u8500_twd_local_timer,
+                             U8500_TWD_BASE, IRQ_LOCALTIMER);
+
+static void __init ux500_twd_init(void)
+{
+       struct twd_local_timer *twd_local_timer;
+       int err;
+
+       twd_local_timer = cpu_is_u5500() ? &u5500_twd_local_timer :
+                                          &u8500_twd_local_timer;
+
+       if (of_have_populated_dt())
+               twd_local_timer_of_register();
+       else {
+               err = twd_local_timer_register(twd_local_timer);
+               if (err)
+                       pr_err("twd_local_timer_register failed %d\n", err);
+       }
+}
+#else
+#define ux500_twd_init()       do { } while(0)
+#endif
 
 static void __init ux500_timer_init(void)
 {
+       void __iomem *mtu_timer_base;
        void __iomem *prcmu_timer_base;
 
        if (cpu_is_u5500()) {
-#ifdef CONFIG_LOCAL_TIMERS
-               twd_base = __io_address(U5500_TWD_BASE);
-#endif
-               mtu_base = __io_address(U5500_MTU0_BASE);
+               mtu_timer_base = __io_address(U5500_MTU0_BASE);
                prcmu_timer_base = __io_address(U5500_PRCMU_TIMER_3_BASE);
        } else if (cpu_is_u8500()) {
-#ifdef CONFIG_LOCAL_TIMERS
-               twd_base = __io_address(U8500_TWD_BASE);
-#endif
-               mtu_base = __io_address(U8500_MTU0_BASE);
+               mtu_timer_base = __io_address(U8500_MTU0_BASE);
                prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
        } else {
                ux500_unknown_soc();
@@ -52,8 +75,9 @@ static void __init ux500_timer_init(void)
         *
         */
 
-       nmdk_timer_init();
+       nmdk_timer_init(mtu_timer_base);
        clksrc_dbx500_prcmu_init(prcmu_timer_base);
+       ux500_twd_init();
 }
 
 static void ux500_timer_reset(void)
index 9f9e1c2..a74af38 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/platform_device.h>
 #include <linux/usb/musb.h>
 #include <linux/dma-mapping.h>
+
 #include <plat/ste_dma40.h>
 #include <mach/hardware.h>
 #include <mach/usb.h>
@@ -140,8 +141,8 @@ static inline void ux500_usb_dma_update_tx_ch_config(int *dst_dev_type)
                musb_dma_tx_ch[idx].dst_dev_type = dst_dev_type[idx];
 }
 
-void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
-       int *dma_tx_cfg)
+void ux500_add_usb(struct device *parent, resource_size_t base, int irq,
+                  int *dma_rx_cfg, int *dma_tx_cfg)
 {
        ux500_musb_device.resource[0].start = base;
        ux500_musb_device.resource[0].end = base + SZ_64K - 1;
@@ -151,5 +152,7 @@ void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
        ux500_usb_dma_update_rx_ch_config(dma_rx_cfg);
        ux500_usb_dma_update_tx_ch_config(dma_tx_cfg);
 
+       ux500_musb_device.dev.parent = parent;
+
        platform_device_register(&ux500_musb_device);
 }
index 4cf7061..6bbd74e 100644 (file)
@@ -584,58 +584,58 @@ static struct pl022_ssp_controller ssp0_plat_data = {
        .num_chipselect = 1,
 };
 
-#define AACI_IRQ       { IRQ_AACI, NO_IRQ }
+#define AACI_IRQ       { IRQ_AACI }
 #define MMCI0_IRQ      { IRQ_MMCI0A,IRQ_SIC_MMCI0B }
-#define KMI0_IRQ       { IRQ_SIC_KMI0, NO_IRQ }
-#define KMI1_IRQ       { IRQ_SIC_KMI1, NO_IRQ }
+#define KMI0_IRQ       { IRQ_SIC_KMI0 }
+#define KMI1_IRQ       { IRQ_SIC_KMI1 }
 
 /*
  * These devices are connected directly to the multi-layer AHB switch
  */
-#define SMC_IRQ                { NO_IRQ, NO_IRQ }
-#define MPMC_IRQ       { NO_IRQ, NO_IRQ }
-#define CLCD_IRQ       { IRQ_CLCDINT, NO_IRQ }
-#define DMAC_IRQ       { IRQ_DMAINT, NO_IRQ }
+#define SMC_IRQ                { }
+#define MPMC_IRQ       { }
+#define CLCD_IRQ       { IRQ_CLCDINT }
+#define DMAC_IRQ       { IRQ_DMAINT }
 
 /*
  * These devices are connected via the core APB bridge
  */
-#define SCTL_IRQ       { NO_IRQ, NO_IRQ }
-#define WATCHDOG_IRQ   { IRQ_WDOGINT, NO_IRQ }
-#define GPIO0_IRQ      { IRQ_GPIOINT0, NO_IRQ }
-#define GPIO1_IRQ      { IRQ_GPIOINT1, NO_IRQ }
-#define RTC_IRQ                { IRQ_RTCINT, NO_IRQ }
+#define SCTL_IRQ       { }
+#define WATCHDOG_IRQ   { IRQ_WDOGINT }
+#define GPIO0_IRQ      { IRQ_GPIOINT0 }
+#define GPIO1_IRQ      { IRQ_GPIOINT1 }
+#define RTC_IRQ                { IRQ_RTCINT }
 
 /*
  * These devices are connected via the DMA APB bridge
  */
-#define SCI_IRQ                { IRQ_SCIINT, NO_IRQ }
-#define UART0_IRQ      { IRQ_UARTINT0, NO_IRQ }
-#define UART1_IRQ      { IRQ_UARTINT1, NO_IRQ }
-#define UART2_IRQ      { IRQ_UARTINT2, NO_IRQ }
-#define SSP_IRQ                { IRQ_SSPINT, NO_IRQ }
+#define SCI_IRQ                { IRQ_SCIINT }
+#define UART0_IRQ      { IRQ_UARTINT0 }
+#define UART1_IRQ      { IRQ_UARTINT1 }
+#define UART2_IRQ      { IRQ_UARTINT2 }
+#define SSP_IRQ                { IRQ_SSPINT }
 
 /* FPGA Primecells */
-AMBA_DEVICE(aaci,  "fpga:04", AACI,     NULL);
-AMBA_DEVICE(mmc0,  "fpga:05", MMCI0,    &mmc0_plat_data);
-AMBA_DEVICE(kmi0,  "fpga:06", KMI0,     NULL);
-AMBA_DEVICE(kmi1,  "fpga:07", KMI1,     NULL);
+APB_DEVICE(aaci,  "fpga:04", AACI,     NULL);
+APB_DEVICE(mmc0,  "fpga:05", MMCI0,    &mmc0_plat_data);
+APB_DEVICE(kmi0,  "fpga:06", KMI0,     NULL);
+APB_DEVICE(kmi1,  "fpga:07", KMI1,     NULL);
 
 /* DevChip Primecells */
-AMBA_DEVICE(smc,   "dev:00",  SMC,      NULL);
-AMBA_DEVICE(mpmc,  "dev:10",  MPMC,     NULL);
-AMBA_DEVICE(clcd,  "dev:20",  CLCD,     &clcd_plat_data);
-AMBA_DEVICE(dmac,  "dev:30",  DMAC,     NULL);
-AMBA_DEVICE(sctl,  "dev:e0",  SCTL,     NULL);
-AMBA_DEVICE(wdog,  "dev:e1",  WATCHDOG, NULL);
-AMBA_DEVICE(gpio0, "dev:e4",  GPIO0,    &gpio0_plat_data);
-AMBA_DEVICE(gpio1, "dev:e5",  GPIO1,    &gpio1_plat_data);
-AMBA_DEVICE(rtc,   "dev:e8",  RTC,      NULL);
-AMBA_DEVICE(sci0,  "dev:f0",  SCI,      NULL);
-AMBA_DEVICE(uart0, "dev:f1",  UART0,    NULL);
-AMBA_DEVICE(uart1, "dev:f2",  UART1,    NULL);
-AMBA_DEVICE(uart2, "dev:f3",  UART2,    NULL);
-AMBA_DEVICE(ssp0,  "dev:f4",  SSP,      &ssp0_plat_data);
+AHB_DEVICE(smc,   "dev:00",  SMC,      NULL);
+AHB_DEVICE(mpmc,  "dev:10",  MPMC,     NULL);
+AHB_DEVICE(clcd,  "dev:20",  CLCD,     &clcd_plat_data);
+AHB_DEVICE(dmac,  "dev:30",  DMAC,     NULL);
+APB_DEVICE(sctl,  "dev:e0",  SCTL,     NULL);
+APB_DEVICE(wdog,  "dev:e1",  WATCHDOG, NULL);
+APB_DEVICE(gpio0, "dev:e4",  GPIO0,    &gpio0_plat_data);
+APB_DEVICE(gpio1, "dev:e5",  GPIO1,    &gpio1_plat_data);
+APB_DEVICE(rtc,   "dev:e8",  RTC,      NULL);
+APB_DEVICE(sci0,  "dev:f0",  SCI,      NULL);
+APB_DEVICE(uart0, "dev:f1",  UART0,    NULL);
+APB_DEVICE(uart1, "dev:f2",  UART1,    NULL);
+APB_DEVICE(uart2, "dev:f3",  UART2,    NULL);
+APB_DEVICE(ssp0,  "dev:f4",  SSP,      &ssp0_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
        &dmac_device,
index 2ef2f55..683e607 100644 (file)
@@ -36,20 +36,10 @@ extern unsigned int mmc_status(struct device *dev);
 extern struct of_dev_auxdata versatile_auxdata_lookup[];
 #endif
 
-#define AMBA_DEVICE(name,busid,base,plat)                      \
-static struct amba_device name##_device = {                    \
-       .dev            = {                                     \
-               .coherent_dma_mask = ~0,                        \
-               .init_name = busid,                             \
-               .platform_data = plat,                          \
-       },                                                      \
-       .res            = {                                     \
-               .start  = VERSATILE_##base##_BASE,              \
-               .end    = (VERSATILE_##base##_BASE) + SZ_4K - 1,\
-               .flags  = IORESOURCE_MEM,                       \
-       },                                                      \
-       .dma_mask       = ~0,                                   \
-       .irq            = base##_IRQ,                           \
-}
+#define APB_DEVICE(name, busid, base, plat)    \
+static AMBA_APB_DEVICE(name, busid, 0, VERSATILE_##base##_BASE, base##_IRQ, plat)
+
+#define AHB_DEVICE(name, busid, base, plat)    \
+static AMBA_AHB_DEVICE(name, busid, 0, VERSATILE_##base##_BASE, base##_IRQ, plat)
 
 #endif
diff --git a/arch/arm/mach-versatile/include/mach/entry-macro.S b/arch/arm/mach-versatile/include/mach/entry-macro.S
deleted file mode 100644 (file)
index b6f0dbf..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * arch/arm/mach-versatile/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for Versatile platforms
- *
- * 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.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-versatile/include/mach/system.h b/arch/arm/mach-versatile/include/mach/system.h
deleted file mode 100644 (file)
index f3fa347..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-versatile/include/mach/system.h
- *
- *  Copyright (C) 2003 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       /*
-        * This should do all the clock switching
-        * and wait for interrupt tricks
-        */
-       cpu_do_idle();
-}
-
-#endif
index 787cf5f..a6e23f4 100644 (file)
@@ -218,9 +218,9 @@ static int __init pci_versatile_setup_resources(struct list_head *resources)
         * the mem resource for this bus
         * the prefetch mem resource for this bus
         */
-       pci_add_resource(resources, &io_mem);
-       pci_add_resource(resources, &non_mem);
-       pci_add_resource(resources, &pre_mem);
+       pci_add_resource_offset(resources, &io_mem, sys->io_offset);
+       pci_add_resource_offset(resources, &non_mem, sys->mem_offset);
+       pci_add_resource_offset(resources, &pre_mem, sys->mem_offset);
 
        goto out;
 
index 9581c19..1973833 100644 (file)
@@ -58,28 +58,28 @@ static struct pl061_platform_data gpio3_plat_data = {
        .irq_base       = IRQ_GPIO3_START,
 };
 
-#define UART3_IRQ      { IRQ_SIC_UART3, NO_IRQ }
-#define SCI1_IRQ       { IRQ_SIC_SCI3, NO_IRQ }
+#define UART3_IRQ      { IRQ_SIC_UART3 }
+#define SCI1_IRQ       { IRQ_SIC_SCI3 }
 #define MMCI1_IRQ      { IRQ_MMCI1A, IRQ_SIC_MMCI1B }
 
 /*
  * These devices are connected via the core APB bridge
  */
-#define GPIO2_IRQ      { IRQ_GPIOINT2, NO_IRQ }
-#define GPIO3_IRQ      { IRQ_GPIOINT3, NO_IRQ }
+#define GPIO2_IRQ      { IRQ_GPIOINT2 }
+#define GPIO3_IRQ      { IRQ_GPIOINT3 }
 
 /*
  * These devices are connected via the DMA APB bridge
  */
 
 /* FPGA Primecells */
-AMBA_DEVICE(uart3, "fpga:09", UART3,    NULL);
-AMBA_DEVICE(sci1,  "fpga:0a", SCI1,     NULL);
-AMBA_DEVICE(mmc1,  "fpga:0b", MMCI1,    &mmc1_plat_data);
+APB_DEVICE(uart3, "fpga:09", UART3,    NULL);
+APB_DEVICE(sci1,  "fpga:0a", SCI1,     NULL);
+APB_DEVICE(mmc1,  "fpga:0b", MMCI1,    &mmc1_plat_data);
 
 /* DevChip Primecells */
-AMBA_DEVICE(gpio2, "dev:e6",  GPIO2,    &gpio2_plat_data);
-AMBA_DEVICE(gpio3, "dev:e7",  GPIO3,    &gpio3_plat_data);
+APB_DEVICE(gpio2, "dev:e6",  GPIO2,    &gpio2_plat_data);
+APB_DEVICE(gpio3, "dev:e7",  GPIO3,    &gpio3_plat_data);
 
 static struct amba_device *amba_devs[] __initdata = {
        &uart3_device,
index 88c3ba1..cf8730d 100644 (file)
@@ -1,14 +1,55 @@
 menu "Versatile Express platform type"
        depends on ARCH_VEXPRESS
 
+config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
+       bool
+       select ARM_ERRATA_720789
+       select ARM_ERRATA_751472
+       select PL310_ERRATA_753970 if CACHE_PL310
+       help
+         Provides common dependencies for Versatile Express platforms
+         based on Cortex-A5 and Cortex-A9 processors. In order to
+         build a working kernel, you must also enable relevant core
+         tile support or Flattened Device Tree based support options.
+
 config ARCH_VEXPRESS_CA9X4
        bool "Versatile Express Cortex-A9x4 tile"
+       select ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
+       select ARM_GIC
        select CPU_V7
+       select HAVE_SMP
+       select MIGHT_HAVE_CACHE_L2X0
+
+config ARCH_VEXPRESS_DT
+       bool "Device Tree support for Versatile Express platforms"
+       select ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
        select ARM_GIC
-       select ARM_ERRATA_720789
-       select ARM_ERRATA_751472
-       select PL310_ERRATA_753970
+       select ARM_PATCH_PHYS_VIRT
+       select AUTO_ZRELADDR
+       select CPU_V7
        select HAVE_SMP
        select MIGHT_HAVE_CACHE_L2X0
+       select USE_OF
+       help
+         New Versatile Express platforms require Flattened Device Tree to
+         be passed to the kernel.
+
+         This option enables support for systems using Cortex processor based
+         ARM core and logic (FPGA) tiles on the Versatile Express motherboard,
+         for example:
+
+         - CoreTile Express A5x2 (V2P-CA5s)
+         - CoreTile Express A9x4 (V2P-CA9)
+         - CoreTile Express A15x2 (V2P-CA15)
+         - LogicTile Express 13MG (V2F-2XV6) with A5, A7, A9 or A15 SMMs
+           (Soft Macrocell Models)
+         - Versatile Express RTSMs (Models)
+
+         You must boot using a Flattened Device Tree in order to use these
+         platforms. The traditional (ATAGs) boot method is not usable on
+         these boards with this option.
+
+         If your bootloader supports Flattened Device Tree based booting,
+         say Y here.
 
 endmenu
index 8630b3d..909f85e 100644 (file)
@@ -1,3 +1,9 @@
+# Those numbers are used only by the non-DT V2P-CA9 platform
+# The DT-enabled ones require CONFIG_AUTO_ZRELADDR=y
    zreladdr-y  += 0x60008000
 params_phys-y  := 0x60000100
 initrd_phys-y  := 0x60800000
+
+dtb-$(CONFIG_ARCH_VEXPRESS_DT) += vexpress-v2p-ca5s.dtb \
+                                  vexpress-v2p-ca9.dtb \
+                                  vexpress-v2p-ca15-tc1.dtb
index f439715..a3a4980 100644 (file)
@@ -1,19 +1,7 @@
-#define __MMIO_P2V(x)  (((x) & 0xfffff) | (((x) & 0x0f000000) >> 4) | 0xf8000000)
-#define MMIO_P2V(x)    ((void __iomem *)__MMIO_P2V(x))
+/* 2MB large area for motherboard's peripherals static mapping */
+#define V2M_PERIPH 0xf8000000
 
-#define AMBA_DEVICE(name,busid,base,plat)      \
-struct amba_device name##_device = {           \
-       .dev            = {                     \
-               .coherent_dma_mask = ~0UL,      \
-               .init_name = busid,             \
-               .platform_data = plat,          \
-       },                                      \
-       .res            = {                     \
-               .start  = base,                 \
-               .end    = base + SZ_4K - 1,     \
-               .flags  = IORESOURCE_MEM,       \
-       },                                      \
-       .dma_mask       = ~0UL,                 \
-       .irq            = IRQ_##base,           \
-       /* .dma         = DMA_##base,*/         \
-}
+/* Tile's peripherals static mappings should start here */
+#define V2T_PERIPH 0xf8200000
+
+void vexpress_dt_smp_map_io(void);
index b1e87c1..c65cc3b 100644 (file)
 
 #include <plat/clcd.h>
 
-#define V2M_PA_CS7     0x10000000
-
 static struct map_desc ct_ca9x4_io_desc[] __initdata = {
        {
-               .virtual        = __MMIO_P2V(CT_CA9X4_MPIC),
-               .pfn            = __phys_to_pfn(CT_CA9X4_MPIC),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = __MMIO_P2V(CT_CA9X4_SP804_TIMER),
-               .pfn            = __phys_to_pfn(CT_CA9X4_SP804_TIMER),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = __MMIO_P2V(CT_CA9X4_L2CC),
-               .pfn            = __phys_to_pfn(CT_CA9X4_L2CC),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
+               .virtual        = V2T_PERIPH,
+               .pfn            = __phys_to_pfn(CT_CA9X4_MPIC),
+               .length         = SZ_8K,
+               .type           = MT_DEVICE,
        },
 };
 
 static void __init ct_ca9x4_map_io(void)
 {
-#ifdef CONFIG_LOCAL_TIMERS
-       twd_base = MMIO_P2V(A9_MPCORE_TWD);
-#endif
        iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
 }
 
-static void __init ct_ca9x4_init_irq(void)
+#ifdef CONFIG_HAVE_ARM_TWD
+static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, A9_MPCORE_TWD, IRQ_LOCALTIMER);
+
+static void __init ca9x4_twd_init(void)
 {
-       gic_init(0, 29, MMIO_P2V(A9_MPCORE_GIC_DIST),
-                MMIO_P2V(A9_MPCORE_GIC_CPU));
+       int err = twd_local_timer_register(&twd_local_timer);
+       if (err)
+               pr_err("twd_local_timer_register failed %d\n", err);
 }
+#else
+#define ca9x4_twd_init()       do {} while(0)
+#endif
 
-#if 0
-static void __init ct_ca9x4_timer_init(void)
+static void __init ct_ca9x4_init_irq(void)
 {
-       writel(0, MMIO_P2V(CT_CA9X4_TIMER0) + TIMER_CTRL);
-       writel(0, MMIO_P2V(CT_CA9X4_TIMER1) + TIMER_CTRL);
-
-       sp804_clocksource_init(MMIO_P2V(CT_CA9X4_TIMER1), "ct-timer1");
-       sp804_clockevents_init(MMIO_P2V(CT_CA9X4_TIMER0), IRQ_CT_CA9X4_TIMER0,
-               "ct-timer0");
+       gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K),
+                ioremap(A9_MPCORE_GIC_CPU, SZ_256));
+       ca9x4_twd_init();
 }
 
-static struct sys_timer ct_ca9x4_timer = {
-       .init   = ct_ca9x4_timer_init,
-};
-#endif
-
 static void ct_ca9x4_clcd_enable(struct clcd_fb *fb)
 {
        v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE_DB1, 0);
@@ -109,10 +92,10 @@ static struct clcd_board ct_ca9x4_clcd_data = {
        .remove         = versatile_clcd_remove_dma,
 };
 
-static AMBA_DEVICE(clcd, "ct:clcd", CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data);
-static AMBA_DEVICE(dmc, "ct:dmc", CT_CA9X4_DMC, NULL);
-static AMBA_DEVICE(smc, "ct:smc", CT_CA9X4_SMC, NULL);
-static AMBA_DEVICE(gpio, "ct:gpio", CT_CA9X4_GPIO, NULL);
+static AMBA_AHB_DEVICE(clcd, "ct:clcd", 0, CT_CA9X4_CLCDC, IRQ_CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data);
+static AMBA_APB_DEVICE(dmc, "ct:dmc", 0, CT_CA9X4_DMC, IRQ_CT_CA9X4_DMC, NULL);
+static AMBA_APB_DEVICE(smc, "ct:smc", 0, CT_CA9X4_SMC, IRQ_CT_CA9X4_SMC, NULL);
+static AMBA_APB_DEVICE(gpio, "ct:gpio", 0, CT_CA9X4_GPIO, IRQ_CT_CA9X4_GPIO, NULL);
 
 static struct amba_device *ct_ca9x4_amba_devs[] __initdata = {
        &clcd_device,
@@ -201,7 +184,7 @@ static void __init ct_ca9x4_init(void)
        int i;
 
 #ifdef CONFIG_CACHE_L2X0
-       void __iomem *l2x0_base = MMIO_P2V(CT_CA9X4_L2CC);
+       void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K);
 
        /* set RAM latencies to 1 cycle for this core tile. */
        writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL);
@@ -217,9 +200,17 @@ static void __init ct_ca9x4_init(void)
 }
 
 #ifdef CONFIG_SMP
+static void *ct_ca9x4_scu_base __initdata;
+
 static void __init ct_ca9x4_init_cpu_map(void)
 {
-       int i, ncores = scu_get_core_count(MMIO_P2V(A9_MPCORE_SCU));
+       int i, ncores;
+
+       ct_ca9x4_scu_base = ioremap(A9_MPCORE_SCU, SZ_128);
+       if (WARN_ON(!ct_ca9x4_scu_base))
+               return;
+
+       ncores = scu_get_core_count(ct_ca9x4_scu_base);
 
        if (ncores > nr_cpu_ids) {
                pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
@@ -235,7 +226,7 @@ static void __init ct_ca9x4_init_cpu_map(void)
 
 static void __init ct_ca9x4_smp_enable(unsigned int max_cpus)
 {
-       scu_enable(MMIO_P2V(A9_MPCORE_SCU));
+       scu_enable(ct_ca9x4_scu_base);
 }
 #endif
 
index a34d3d4..84acf84 100644 (file)
@@ -22,9 +22,6 @@
 #define CT_CA9X4_SYSWDT                (0x1e007000)
 #define CT_CA9X4_L2CC          (0x1e00a000)
 
-#define CT_CA9X4_TIMER0                (CT_CA9X4_SP804_TIMER + 0x000)
-#define CT_CA9X4_TIMER1                (CT_CA9X4_SP804_TIMER + 0x020)
-
 #define A9_MPCORE_SCU          (CT_CA9X4_MPIC + 0x0000)
 #define A9_MPCORE_GIC_CPU      (CT_CA9X4_MPIC + 0x0100)
 #define A9_MPCORE_GIT          (CT_CA9X4_MPIC + 0x0200)
@@ -35,7 +32,7 @@
  * Interrupts.  Those in {} are for AMBA devices
  */
 #define IRQ_CT_CA9X4_CLCDC     { 76 }
-#define IRQ_CT_CA9X4_DMC       { -1 }
+#define IRQ_CT_CA9X4_DMC       { 0 }
 #define IRQ_CT_CA9X4_SMC       { 77, 78 }
 #define IRQ_CT_CA9X4_TIMER0    80
 #define IRQ_CT_CA9X4_TIMER1    81
index fd9e6c7..fa82247 100644 (file)
  * published by the Free Software Foundation.
  */
 
-#define DEBUG_LL_UART_OFFSET   0x00009000
+#define DEBUG_LL_PHYS_BASE             0x10000000
+#define DEBUG_LL_UART_OFFSET           0x00009000
+
+#define DEBUG_LL_PHYS_BASE_RS1         0x1c000000
+#define DEBUG_LL_UART_OFFSET_RS1       0x00090000
+
+#define DEBUG_LL_VIRT_BASE             0xf8000000
 
                .macro  addruart,rp,rv,tmp
-               mov     \rp, #DEBUG_LL_UART_OFFSET
-               orr     \rv, \rp, #0xf8000000   @ virtual base
-               orr     \rp, \rp, #0x10000000   @ physical base
+
+               @ Make an educated guess regarding the memory map:
+               @ - the original A9 core tile, which has MPCore peripherals
+               @   located at 0x1e000000, should use UART at 0x10009000
+               @ - all other (RS1 complaint) tiles use UART mapped
+               @   at 0x1c090000
+               mrc     p15, 4, \tmp, c15, c0, 0
+               cmp     \tmp, #0x1e000000
+
+               @ Original memory map
+               moveq   \rp, #DEBUG_LL_UART_OFFSET
+               orreq   \rv, \rp, #DEBUG_LL_VIRT_BASE
+               orreq   \rp, \rp, #DEBUG_LL_PHYS_BASE
+
+               @ RS1 memory map
+               movne   \rp, #DEBUG_LL_UART_OFFSET_RS1
+               orrne   \rv, \rp, #DEBUG_LL_VIRT_BASE
+               orrne   \rp, \rp, #DEBUG_LL_PHYS_BASE_RS1
+
                .endm
 
 #include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-vexpress/include/mach/entry-macro.S b/arch/arm/mach-vexpress/include/mach/entry-macro.S
deleted file mode 100644 (file)
index a14f9e6..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
index 7054cbf..4b10ee7 100644 (file)
@@ -1,4 +1,4 @@
 #define IRQ_LOCALTIMER         29
 #define IRQ_LOCALWDOG          30
 
-#define NR_IRQS        128
+#define NR_IRQS        256
index 0a3a375..31a9289 100644 (file)
 #define V2M_CF                 (V2M_PA_CS7 + 0x0001a000)
 #define V2M_CLCD               (V2M_PA_CS7 + 0x0001f000)
 
-#define V2M_SYS_ID             (V2M_SYSREGS + 0x000)
-#define V2M_SYS_SW             (V2M_SYSREGS + 0x004)
-#define V2M_SYS_LED            (V2M_SYSREGS + 0x008)
-#define V2M_SYS_100HZ          (V2M_SYSREGS + 0x024)
-#define V2M_SYS_FLAGS          (V2M_SYSREGS + 0x030)
-#define V2M_SYS_FLAGSSET       (V2M_SYSREGS + 0x030)
-#define V2M_SYS_FLAGSCLR       (V2M_SYSREGS + 0x034)
-#define V2M_SYS_NVFLAGS                (V2M_SYSREGS + 0x038)
-#define V2M_SYS_NVFLAGSSET     (V2M_SYSREGS + 0x038)
-#define V2M_SYS_NVFLAGSCLR     (V2M_SYSREGS + 0x03c)
-#define V2M_SYS_MCI            (V2M_SYSREGS + 0x048)
-#define V2M_SYS_FLASH          (V2M_SYSREGS + 0x03c)
-#define V2M_SYS_CFGSW          (V2M_SYSREGS + 0x058)
-#define V2M_SYS_24MHZ          (V2M_SYSREGS + 0x05c)
-#define V2M_SYS_MISC           (V2M_SYSREGS + 0x060)
-#define V2M_SYS_DMA            (V2M_SYSREGS + 0x064)
-#define V2M_SYS_PROCID0                (V2M_SYSREGS + 0x084)
-#define V2M_SYS_PROCID1                (V2M_SYSREGS + 0x088)
-#define V2M_SYS_CFGDATA                (V2M_SYSREGS + 0x0a0)
-#define V2M_SYS_CFGCTRL                (V2M_SYSREGS + 0x0a4)
-#define V2M_SYS_CFGSTAT                (V2M_SYSREGS + 0x0a8)
-
-#define V2M_TIMER0             (V2M_TIMER01 + 0x000)
-#define V2M_TIMER1             (V2M_TIMER01 + 0x020)
-
-#define V2M_TIMER2             (V2M_TIMER23 + 0x000)
-#define V2M_TIMER3             (V2M_TIMER23 + 0x020)
+/*
+ * Offsets from SYSREGS base
+ */
+#define V2M_SYS_ID             0x000
+#define V2M_SYS_SW             0x004
+#define V2M_SYS_LED            0x008
+#define V2M_SYS_100HZ          0x024
+#define V2M_SYS_FLAGS          0x030
+#define V2M_SYS_FLAGSSET       0x030
+#define V2M_SYS_FLAGSCLR       0x034
+#define V2M_SYS_NVFLAGS                0x038
+#define V2M_SYS_NVFLAGSSET     0x038
+#define V2M_SYS_NVFLAGSCLR     0x03c
+#define V2M_SYS_MCI            0x048
+#define V2M_SYS_FLASH          0x03c
+#define V2M_SYS_CFGSW          0x058
+#define V2M_SYS_24MHZ          0x05c
+#define V2M_SYS_MISC           0x060
+#define V2M_SYS_DMA            0x064
+#define V2M_SYS_PROCID0                0x084
+#define V2M_SYS_PROCID1                0x088
+#define V2M_SYS_CFGDATA                0x0a0
+#define V2M_SYS_CFGCTRL                0x0a4
+#define V2M_SYS_CFGSTAT                0x0a8
 
 
 /*
 
 int v2m_cfg_write(u32 devfn, u32 data);
 int v2m_cfg_read(u32 devfn, u32 *data);
+void v2m_flags_set(u32 data);
+
+/*
+ * Miscellaneous
+ */
+#define SYS_MISC_MASTERSITE    (1 << 14)
+#define SYS_PROCIDx_HBI_MASK   0xfff
 
 /*
  * Core tile IDs
diff --git a/arch/arm/mach-vexpress/include/mach/system.h b/arch/arm/mach-vexpress/include/mach/system.h
deleted file mode 100644 (file)
index f653a8e..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-vexpress/include/mach/system.h
- *
- *  Copyright (C) 2003 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       /*
-        * This should do all the clock switching
-        * and wait for interrupt tricks
-        */
-       cpu_do_idle();
-}
-
-#endif
index 7972c57..7dab559 100644 (file)
 #define AMBA_UART_CR(base)     (*(volatile unsigned char *)((base) + 0x30))
 #define AMBA_UART_FR(base)     (*(volatile unsigned char *)((base) + 0x18))
 
-#define get_uart_base()        (0x10000000 + 0x00009000)
+#define UART_BASE      0x10009000
+#define UART_BASE_RS1  0x1c090000
+
+static unsigned long get_uart_base(void)
+{
+       unsigned long mpcore_periph;
+
+       /*
+        * Make an educated guess regarding the memory map:
+        * - the original A9 core tile, which has MPCore peripherals
+        *   located at 0x1e000000, should use UART at 0x10009000
+        * - all other (RS1 complaint) tiles use UART mapped
+        *   at 0x1c090000
+        */
+       asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (mpcore_periph));
+
+       if (mpcore_periph == 0x1e000000)
+               return UART_BASE;
+       else
+               return UART_BASE_RS1;
+}
 
 /*
  * This does not append a newline
index 124ffb1..14ba112 100644 (file)
 #include <linux/errno.h>
 #include <linux/smp.h>
 #include <linux/io.h>
+#include <linux/of_fdt.h>
+
+#include <asm/smp_scu.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
 
 #include <mach/motherboard.h>
-#define V2M_PA_CS7 0x10000000
 
 #include "core.h"
 
 extern void versatile_secondary_startup(void);
 
+#if defined(CONFIG_OF)
+
+static enum {
+       GENERIC_SCU,
+       CORTEX_A9_SCU,
+} vexpress_dt_scu __initdata = GENERIC_SCU;
+
+static struct map_desc vexpress_dt_cortex_a9_scu_map __initdata = {
+       .virtual        = V2T_PERIPH,
+       /* .pfn set in vexpress_dt_init_cortex_a9_scu() */
+       .length         = SZ_128,
+       .type           = MT_DEVICE,
+};
+
+static void *vexpress_dt_cortex_a9_scu_base __initdata;
+
+const static char *vexpress_dt_cortex_a9_match[] __initconst = {
+       "arm,cortex-a5-scu",
+       "arm,cortex-a9-scu",
+       NULL
+};
+
+static int __init vexpress_dt_find_scu(unsigned long node,
+               const char *uname, int depth, void *data)
+{
+       if (of_flat_dt_match(node, vexpress_dt_cortex_a9_match)) {
+               phys_addr_t phys_addr;
+               __be32 *reg = of_get_flat_dt_prop(node, "reg", NULL);
+
+               if (WARN_ON(!reg))
+                       return -EINVAL;
+
+               phys_addr = be32_to_cpup(reg);
+               vexpress_dt_scu = CORTEX_A9_SCU;
+
+               vexpress_dt_cortex_a9_scu_map.pfn = __phys_to_pfn(phys_addr);
+               iotable_init(&vexpress_dt_cortex_a9_scu_map, 1);
+               vexpress_dt_cortex_a9_scu_base = ioremap(phys_addr, SZ_256);
+               if (WARN_ON(!vexpress_dt_cortex_a9_scu_base))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+void __init vexpress_dt_smp_map_io(void)
+{
+       if (initial_boot_params)
+               WARN_ON(of_scan_flat_dt(vexpress_dt_find_scu, NULL));
+}
+
+static int __init vexpress_dt_cpus_num(unsigned long node, const char *uname,
+               int depth, void *data)
+{
+       static int prev_depth = -1;
+       static int nr_cpus = -1;
+
+       if (prev_depth > depth && nr_cpus > 0)
+               return nr_cpus;
+
+       if (nr_cpus < 0 && strcmp(uname, "cpus") == 0)
+               nr_cpus = 0;
+
+       if (nr_cpus >= 0) {
+               const char *device_type = of_get_flat_dt_prop(node,
+                               "device_type", NULL);
+
+               if (device_type && strcmp(device_type, "cpu") == 0)
+                       nr_cpus++;
+       }
+
+       prev_depth = depth;
+
+       return 0;
+}
+
+static void __init vexpress_dt_smp_init_cpus(void)
+{
+       int ncores = 0, i;
+
+       switch (vexpress_dt_scu) {
+       case GENERIC_SCU:
+               ncores = of_scan_flat_dt(vexpress_dt_cpus_num, NULL);
+               break;
+       case CORTEX_A9_SCU:
+               ncores = scu_get_core_count(vexpress_dt_cortex_a9_scu_base);
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       if (ncores < 2)
+               return;
+
+       if (ncores > nr_cpu_ids) {
+               pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
+                               ncores, nr_cpu_ids);
+               ncores = nr_cpu_ids;
+       }
+
+       for (i = 0; i < ncores; ++i)
+               set_cpu_possible(i, true);
+
+       set_smp_cross_call(gic_raise_softirq);
+}
+
+static void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
+{
+       int i;
+
+       switch (vexpress_dt_scu) {
+       case GENERIC_SCU:
+               for (i = 0; i < max_cpus; i++)
+                       set_cpu_present(i, true);
+               break;
+       case CORTEX_A9_SCU:
+               scu_enable(vexpress_dt_cortex_a9_scu_base);
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+}
+
+#else
+
+static void __init vexpress_dt_smp_init_cpus(void)
+{
+       WARN_ON(1);
+}
+
+void __init vexpress_dt_smp_prepare_cpus(unsigned int max_cpus)
+{
+       WARN_ON(1);
+}
+
+#endif
+
 /*
  * Initialise the CPU possible map early - this describes the CPUs
  * which may be present or become present in the system.
  */
 void __init smp_init_cpus(void)
 {
-       ct_desc->init_cpu_map();
+       if (ct_desc)
+               ct_desc->init_cpu_map();
+       else
+               vexpress_dt_smp_init_cpus();
+
 }
 
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
@@ -35,7 +182,10 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
         * Initialise the present map, which describes the set of CPUs
         * actually populated at the present time.
         */
-       ct_desc->smp_enable(max_cpus);
+       if (ct_desc)
+               ct_desc->smp_enable(max_cpus);
+       else
+               vexpress_dt_smp_prepare_cpus(max_cpus);
 
        /*
         * Write the address of secondary startup into the
@@ -43,7 +193,5 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
         * until it receives a soft interrupt, and then the
         * secondary CPU branches to this address.
         */
-       writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR));
-       writel(virt_to_phys(versatile_secondary_startup),
-               MMIO_P2V(V2M_SYS_FLAGSSET));
+       v2m_flags_set(virt_to_phys(versatile_secondary_startup));
 }
index b4a28ca..47cdcca 100644 (file)
@@ -6,6 +6,10 @@
 #include <linux/amba/mmci.h>
 #include <linux/io.h>
 #include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/ata_platform.h>
 #include <linux/smsc911x.h>
@@ -21,6 +25,8 @@
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 #include <asm/hardware/arm_timer.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/hardware/gic.h>
 #include <asm/hardware/timer-sp.h>
 #include <asm/hardware/sp810.h>
 #include <asm/hardware/gic.h>
 
 static struct map_desc v2m_io_desc[] __initdata = {
        {
-               .virtual        = __MMIO_P2V(V2M_PA_CS7),
+               .virtual        = V2M_PERIPH,
                .pfn            = __phys_to_pfn(V2M_PA_CS7),
                .length         = SZ_128K,
                .type           = MT_DEVICE,
        },
 };
 
-static void __init v2m_timer_init(void)
+static void __iomem *v2m_sysreg_base;
+
+static void __init v2m_sysctl_init(void __iomem *base)
 {
        u32 scctrl;
 
+       if (WARN_ON(!base))
+               return;
+
        /* Select 1MHz TIMCLK as the reference clock for SP804 timers */
-       scctrl = readl(MMIO_P2V(V2M_SYSCTL + SCCTRL));
+       scctrl = readl(base + SCCTRL);
        scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
        scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK;
-       writel(scctrl, MMIO_P2V(V2M_SYSCTL + SCCTRL));
+       writel(scctrl, base + SCCTRL);
+}
+
+static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
+{
+       if (WARN_ON(!base || irq == NO_IRQ))
+               return;
+
+       writel(0, base + TIMER_1_BASE + TIMER_CTRL);
+       writel(0, base + TIMER_2_BASE + TIMER_CTRL);
 
-       writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL);
-       writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL);
+       sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1");
+       sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0");
+}
 
-       sp804_clocksource_init(MMIO_P2V(V2M_TIMER1), "v2m-timer1");
-       sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0,
-               "v2m-timer0");
+static void __init v2m_timer_init(void)
+{
+       v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
+       v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
 }
 
 static struct sys_timer v2m_timer = {
@@ -82,14 +104,14 @@ int v2m_cfg_write(u32 devfn, u32 data)
        devfn |= SYS_CFG_START | SYS_CFG_WRITE;
 
        spin_lock(&v2m_cfg_lock);
-       val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
-       writel(val & ~SYS_CFG_COMPLETE, MMIO_P2V(V2M_SYS_CFGSTAT));
+       val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
+       writel(val & ~SYS_CFG_COMPLETE, v2m_sysreg_base + V2M_SYS_CFGSTAT);
 
-       writel(data, MMIO_P2V(V2M_SYS_CFGDATA));
-       writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL));
+       writel(data, v2m_sysreg_base +  V2M_SYS_CFGDATA);
+       writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
 
        do {
-               val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
+               val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
        } while (val == 0);
        spin_unlock(&v2m_cfg_lock);
 
@@ -103,22 +125,28 @@ int v2m_cfg_read(u32 devfn, u32 *data)
        devfn |= SYS_CFG_START;
 
        spin_lock(&v2m_cfg_lock);
-       writel(0, MMIO_P2V(V2M_SYS_CFGSTAT));
-       writel(devfn, MMIO_P2V(V2M_SYS_CFGCTRL));
+       writel(0, v2m_sysreg_base + V2M_SYS_CFGSTAT);
+       writel(devfn, v2m_sysreg_base + V2M_SYS_CFGCTRL);
 
        mb();
 
        do {
                cpu_relax();
-               val = readl(MMIO_P2V(V2M_SYS_CFGSTAT));
+               val = readl(v2m_sysreg_base + V2M_SYS_CFGSTAT);
        } while (val == 0);
 
-       *data = readl(MMIO_P2V(V2M_SYS_CFGDATA));
+       *data = readl(v2m_sysreg_base + V2M_SYS_CFGDATA);
        spin_unlock(&v2m_cfg_lock);
 
        return !!(val & SYS_CFG_ERR);
 }
 
+void __init v2m_flags_set(u32 data)
+{
+       writel(~0, v2m_sysreg_base + V2M_SYS_FLAGSCLR);
+       writel(data, v2m_sysreg_base + V2M_SYS_FLAGSSET);
+}
+
 
 static struct resource v2m_pcie_i2c_resource = {
        .start  = V2M_SERIAL_BUS_PCI,
@@ -204,7 +232,7 @@ static struct platform_device v2m_usb_device = {
 
 static void v2m_flash_set_vpp(struct platform_device *pdev, int on)
 {
-       writel(on != 0, MMIO_P2V(V2M_SYS_FLASH));
+       writel(on != 0, v2m_sysreg_base + V2M_SYS_FLASH);
 }
 
 static struct physmap_flash_data v2m_flash_data = {
@@ -258,7 +286,7 @@ static struct platform_device v2m_cf_device = {
 
 static unsigned int v2m_mmci_status(struct device *dev)
 {
-       return readl(MMIO_P2V(V2M_SYS_MCI)) & (1 << 0);
+       return readl(v2m_sysreg_base + V2M_SYS_MCI) & (1 << 0);
 }
 
 static struct mmci_platform_data v2m_mmci_data = {
@@ -266,16 +294,16 @@ static struct mmci_platform_data v2m_mmci_data = {
        .status         = v2m_mmci_status,
 };
 
-static AMBA_DEVICE(aaci,  "mb:aaci",  V2M_AACI, NULL);
-static AMBA_DEVICE(mmci,  "mb:mmci",  V2M_MMCI, &v2m_mmci_data);
-static AMBA_DEVICE(kmi0,  "mb:kmi0",  V2M_KMI0, NULL);
-static AMBA_DEVICE(kmi1,  "mb:kmi1",  V2M_KMI1, NULL);
-static AMBA_DEVICE(uart0, "mb:uart0", V2M_UART0, NULL);
-static AMBA_DEVICE(uart1, "mb:uart1", V2M_UART1, NULL);
-static AMBA_DEVICE(uart2, "mb:uart2", V2M_UART2, NULL);
-static AMBA_DEVICE(uart3, "mb:uart3", V2M_UART3, NULL);
-static AMBA_DEVICE(wdt,   "mb:wdt",   V2M_WDT, NULL);
-static AMBA_DEVICE(rtc,   "mb:rtc",   V2M_RTC, NULL);
+static AMBA_APB_DEVICE(aaci,  "mb:aaci",  0, V2M_AACI, IRQ_V2M_AACI, NULL);
+static AMBA_APB_DEVICE(mmci,  "mb:mmci",  0, V2M_MMCI, IRQ_V2M_MMCI, &v2m_mmci_data);
+static AMBA_APB_DEVICE(kmi0,  "mb:kmi0",  0, V2M_KMI0, IRQ_V2M_KMI0, NULL);
+static AMBA_APB_DEVICE(kmi1,  "mb:kmi1",  0, V2M_KMI1, IRQ_V2M_KMI1, NULL);
+static AMBA_APB_DEVICE(uart0, "mb:uart0", 0, V2M_UART0, IRQ_V2M_UART0, NULL);
+static AMBA_APB_DEVICE(uart1, "mb:uart1", 0, V2M_UART1, IRQ_V2M_UART1, NULL);
+static AMBA_APB_DEVICE(uart2, "mb:uart2", 0, V2M_UART2, IRQ_V2M_UART2, NULL);
+static AMBA_APB_DEVICE(uart3, "mb:uart3", 0, V2M_UART3, IRQ_V2M_UART3, NULL);
+static AMBA_APB_DEVICE(wdt,   "mb:wdt",   0, V2M_WDT, IRQ_V2M_WDT, NULL);
+static AMBA_APB_DEVICE(rtc,   "mb:rtc",   0, V2M_RTC, IRQ_V2M_RTC, NULL);
 
 static struct amba_device *v2m_amba_devs[] __initdata = {
        &aaci_device,
@@ -371,7 +399,7 @@ static void __init v2m_init_early(void)
 {
        ct_desc->init_early();
        clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups));
-       versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
+       versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
 }
 
 static void v2m_power_off(void)
@@ -400,20 +428,23 @@ static void __init v2m_populate_ct_desc(void)
        u32 current_tile_id;
 
        ct_desc = NULL;
-       current_tile_id = readl(MMIO_P2V(V2M_SYS_PROCID0)) & V2M_CT_ID_MASK;
+       current_tile_id = readl(v2m_sysreg_base + V2M_SYS_PROCID0)
+                               & V2M_CT_ID_MASK;
 
        for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i)
                if (ct_descs[i]->id == current_tile_id)
                        ct_desc = ct_descs[i];
 
        if (!ct_desc)
-               panic("vexpress: failed to populate core tile description "
-                     "for tile ID 0x%8x\n", current_tile_id);
+               panic("vexpress: this kernel does not support core tile ID 0x%08x when booting via ATAGs.\n"
+                     "You may need a device tree blob or a different kernel to boot on this board.\n",
+                     current_tile_id);
 }
 
 static void __init v2m_map_io(void)
 {
        iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
+       v2m_sysreg_base = ioremap(V2M_SYSREGS, SZ_4K);
        v2m_populate_ct_desc();
        ct_desc->map_io();
 }
@@ -452,3 +483,205 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express")
        .init_machine   = v2m_init,
        .restart        = v2m_restart,
 MACHINE_END
+
+#if defined(CONFIG_ARCH_VEXPRESS_DT)
+
+static struct map_desc v2m_rs1_io_desc __initdata = {
+       .virtual        = V2M_PERIPH,
+       .pfn            = __phys_to_pfn(0x1c000000),
+       .length         = SZ_2M,
+       .type           = MT_DEVICE,
+};
+
+static int __init v2m_dt_scan_memory_map(unsigned long node, const char *uname,
+               int depth, void *data)
+{
+       const char **map = data;
+
+       if (strcmp(uname, "motherboard") != 0)
+               return 0;
+
+       *map = of_get_flat_dt_prop(node, "arm,v2m-memory-map", NULL);
+
+       return 1;
+}
+
+void __init v2m_dt_map_io(void)
+{
+       const char *map = NULL;
+
+       of_scan_flat_dt(v2m_dt_scan_memory_map, &map);
+
+       if (map && strcmp(map, "rs1") == 0)
+               iotable_init(&v2m_rs1_io_desc, 1);
+       else
+               iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
+
+#if defined(CONFIG_SMP)
+       vexpress_dt_smp_map_io();
+#endif
+}
+
+static struct clk_lookup v2m_dt_lookups[] = {
+       {       /* AMBA bus clock */
+               .con_id         = "apb_pclk",
+               .clk            = &dummy_apb_pclk,
+       }, {    /* SP804 timers */
+               .dev_id         = "sp804",
+               .con_id         = "v2m-timer0",
+               .clk            = &v2m_sp804_clk,
+       }, {    /* SP804 timers */
+               .dev_id         = "sp804",
+               .con_id         = "v2m-timer1",
+               .clk            = &v2m_sp804_clk,
+       }, {    /* PL180 MMCI */
+               .dev_id         = "mb:mmci", /* 10005000.mmci */
+               .clk            = &osc2_clk,
+       }, {    /* PL050 KMI0 */
+               .dev_id         = "10006000.kmi",
+               .clk            = &osc2_clk,
+       }, {    /* PL050 KMI1 */
+               .dev_id         = "10007000.kmi",
+               .clk            = &osc2_clk,
+       }, {    /* PL011 UART0 */
+               .dev_id         = "10009000.uart",
+               .clk            = &osc2_clk,
+       }, {    /* PL011 UART1 */
+               .dev_id         = "1000a000.uart",
+               .clk            = &osc2_clk,
+       }, {    /* PL011 UART2 */
+               .dev_id         = "1000b000.uart",
+               .clk            = &osc2_clk,
+       }, {    /* PL011 UART3 */
+               .dev_id         = "1000c000.uart",
+               .clk            = &osc2_clk,
+       }, {    /* SP805 WDT */
+               .dev_id         = "1000f000.wdt",
+               .clk            = &v2m_ref_clk,
+       }, {    /* PL111 CLCD */
+               .dev_id         = "1001f000.clcd",
+               .clk            = &osc1_clk,
+       },
+       /* RS1 memory map */
+       {       /* PL180 MMCI */
+               .dev_id         = "mb:mmci", /* 1c050000.mmci */
+               .clk            = &osc2_clk,
+       }, {    /* PL050 KMI0 */
+               .dev_id         = "1c060000.kmi",
+               .clk            = &osc2_clk,
+       }, {    /* PL050 KMI1 */
+               .dev_id         = "1c070000.kmi",
+               .clk            = &osc2_clk,
+       }, {    /* PL011 UART0 */
+               .dev_id         = "1c090000.uart",
+               .clk            = &osc2_clk,
+       }, {    /* PL011 UART1 */
+               .dev_id         = "1c0a0000.uart",
+               .clk            = &osc2_clk,
+       }, {    /* PL011 UART2 */
+               .dev_id         = "1c0b0000.uart",
+               .clk            = &osc2_clk,
+       }, {    /* PL011 UART3 */
+               .dev_id         = "1c0c0000.uart",
+               .clk            = &osc2_clk,
+       }, {    /* SP805 WDT */
+               .dev_id         = "1c0f0000.wdt",
+               .clk            = &v2m_ref_clk,
+       }, {    /* PL111 CLCD */
+               .dev_id         = "1c1f0000.clcd",
+               .clk            = &osc1_clk,
+       },
+};
+
+void __init v2m_dt_init_early(void)
+{
+       struct device_node *node;
+       u32 dt_hbi;
+
+       node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
+       v2m_sysreg_base = of_iomap(node, 0);
+       if (WARN_ON(!v2m_sysreg_base))
+               return;
+
+       /* Confirm board type against DT property, if available */
+       if (of_property_read_u32(allnodes, "arm,hbi", &dt_hbi) == 0) {
+               u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC);
+               u32 id = readl(v2m_sysreg_base + (misc & SYS_MISC_MASTERSITE ?
+                               V2M_SYS_PROCID1 : V2M_SYS_PROCID0));
+               u32 hbi = id & SYS_PROCIDx_HBI_MASK;
+
+               if (WARN_ON(dt_hbi != hbi))
+                       pr_warning("vexpress: DT HBI (%x) is not matching "
+                                       "hardware (%x)!\n", dt_hbi, hbi);
+       }
+
+       clkdev_add_table(v2m_dt_lookups, ARRAY_SIZE(v2m_dt_lookups));
+       versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
+}
+
+static  struct of_device_id vexpress_irq_match[] __initdata = {
+       { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+       {}
+};
+
+static void __init v2m_dt_init_irq(void)
+{
+       of_irq_init(vexpress_irq_match);
+}
+
+static void __init v2m_dt_timer_init(void)
+{
+       struct device_node *node;
+       const char *path;
+       int err;
+
+       node = of_find_compatible_node(NULL, NULL, "arm,sp810");
+       v2m_sysctl_init(of_iomap(node, 0));
+
+       err = of_property_read_string(of_aliases, "arm,v2m_timer", &path);
+       if (WARN_ON(err))
+               return;
+       node = of_find_node_by_path(path);
+       v2m_sp804_init(of_iomap(node, 0), irq_of_parse_and_map(node, 0));
+}
+
+static struct sys_timer v2m_dt_timer = {
+       .init = v2m_dt_timer_init,
+};
+
+static struct of_dev_auxdata v2m_dt_auxdata_lookup[] __initdata = {
+       OF_DEV_AUXDATA("arm,vexpress-flash", V2M_NOR0, "physmap-flash",
+                       &v2m_flash_data),
+       OF_DEV_AUXDATA("arm,primecell", V2M_MMCI, "mb:mmci", &v2m_mmci_data),
+       /* RS1 memory map */
+       OF_DEV_AUXDATA("arm,vexpress-flash", 0x08000000, "physmap-flash",
+                       &v2m_flash_data),
+       OF_DEV_AUXDATA("arm,primecell", 0x1c050000, "mb:mmci", &v2m_mmci_data),
+       {}
+};
+
+static void __init v2m_dt_init(void)
+{
+       l2x0_of_init(0x00400000, 0xfe0fffff);
+       of_platform_populate(NULL, of_default_bus_match_table,
+                       v2m_dt_auxdata_lookup, NULL);
+       pm_power_off = v2m_power_off;
+}
+
+const static char *v2m_dt_match[] __initconst = {
+       "arm,vexpress",
+       NULL,
+};
+
+DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
+       .dt_compat      = v2m_dt_match,
+       .map_io         = v2m_dt_map_io,
+       .init_early     = v2m_dt_init_early,
+       .init_irq       = v2m_dt_init_irq,
+       .timer          = &v2m_dt_timer,
+       .init_machine   = v2m_dt_init,
+       .handle_irq     = gic_handle_irq,
+       .restart        = v2m_restart,
+MACHINE_END
+
+#endif
index 92684c7..367d1b5 100644 (file)
@@ -8,18 +8,12 @@
  * warranty of any kind, whether express or implied.
  */
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        @ physical 0xd8140000 is virtual 0xf8140000
        mov     \base, #0xf8000000
        orr     \base, \base, #0x00140000
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
        ldr     \irqnr, [\base]
        cmp     \irqnr, #63 @ may be false positive, check interrupt status
index d6c757e..58fa801 100644 (file)
@@ -7,11 +7,6 @@
 /* PM Software Reset request register */
 #define VT8500_PMSR_VIRT       0xf8130060
 
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
 static inline void arch_reset(char mode, const char *cmd)
 {
        writel(1, VT8500_PMSR_VIRT);
index 78110be..db82568 100644 (file)
@@ -530,6 +530,7 @@ static struct platform_device *nuc900_public_dev[] __initdata = {
 
 void __init nuc900_board_init(struct platform_device **device, int size)
 {
+       disable_hlt();
        platform_add_devices(device, size);
        platform_add_devices(nuc900_public_dev, ARRAY_SIZE(nuc900_public_dev));
        spi_register_board_info(nuc900_spi_board_info,
index d39aca5..e286dac 100644 (file)
@@ -15,9 +15,6 @@
        .macro  get_irqnr_preamble, base, tmp
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 
                mov     \base, #AIC_BA
@@ -27,8 +24,3 @@
                cmp     \irqnr, #0
 
        .endm
-
-       /* currently don't need an disable_fiq macro */
-
-       .macro  disable_fiq
-       .endm
diff --git a/arch/arm/mach-w90x900/include/mach/system.h b/arch/arm/mach-w90x900/include/mach/system.h
deleted file mode 100644 (file)
index 2aaeb93..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-w90x900/include/mach/system.h
- *
- * Copyright (c) 2008 Nuvoton technology corporation
- * All rights reserved.
- *
- * Wan ZongShun <mcuos.com@gmail.com>
- *
- * Based on arch/arm/mach-s3c2410/include/mach/system.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-static void arch_idle(void)
-{
-}
diff --git a/arch/arm/mach-zynq/include/mach/entry-macro.S b/arch/arm/mach-zynq/include/mach/entry-macro.S
deleted file mode 100644 (file)
index d621fb7..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-zynq/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros
- *
- *  Copyright (C) 2011 Xilinx
- *
- * based on arch/plat-mxc/include/mach/entry-macro.S
- *
- *  Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
- *  Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * 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.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-zynq/include/mach/system.h b/arch/arm/mach-zynq/include/mach/system.h
deleted file mode 100644 (file)
index 8e88e0b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* arch/arm/mach-zynq/include/mach/system.h
- *
- *  Copyright (C) 2011 Xilinx
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MACH_SYSTEM_H__
-#define __MACH_SYSTEM_H__
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
index e62956e..4614208 100644 (file)
@@ -32,9 +32,6 @@ EXPORT_SYMBOL(pcibios_min_io);
 unsigned long pcibios_min_mem = 0x01000000;
 EXPORT_SYMBOL(pcibios_min_mem);
 
-unsigned int pci_flags = PCI_REASSIGN_ALL_RSRC;
-EXPORT_SYMBOL(pci_flags);
-
 void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 {
        if ((unsigned long)addr >= VMALLOC_START &&
index bb26981..0da4205 100644 (file)
@@ -214,8 +214,8 @@ int iop3xx_pci_setup(int nr, struct pci_sys_data *sys)
        sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0;
        sys->io_offset  = IOP3XX_PCI_LOWER_IO_PA - *IOP3XX_OIOWTVR;
 
-       pci_add_resource(&sys->resources, &res[0]);
-       pci_add_resource(&sys->resources, &res[1]);
+       pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
+       pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
        return 1;
 }
index 55f1569..689f81f 100644 (file)
@@ -60,7 +60,7 @@ static int avic_irq_set_priority(unsigned char irq, unsigned char prio)
        unsigned int mask = 0x0F << irq % 8 * 4;
 
        if (irq >= AVIC_NUM_IRQS)
-               return -EINVAL;;
+               return -EINVAL;
 
        temp = __raw_readl(avic_base + AVIC_NIPRIORITY(irq / 8));
        temp &= ~mask;
index f5b7e0f..220dd6f 100644 (file)
@@ -1,5 +1,6 @@
 
 #include <linux/module.h>
+#include <linux/io.h>
 #include <mach/hardware.h>
 
 unsigned int __mxc_cpu_type;
@@ -18,3 +19,26 @@ void imx_print_silicon_rev(const char *cpu, int srev)
                pr_info("CPU identified as %s, silicon rev %d.%d\n",
                                cpu, (srev >> 4) & 0xf, srev & 0xf);
 }
+
+void __init imx_set_aips(void __iomem *base)
+{
+       unsigned int reg;
+/*
+ * Set all MPROTx to be non-bufferable, trusted for R/W,
+ * not forced to user-mode.
+ */
+       __raw_writel(0x77777777, base + 0x0);
+       __raw_writel(0x77777777, base + 0x4);
+
+/*
+ * Set all OPACRx to be non-bufferable, to not require
+ * supervisor privilege level for access, allow for
+ * write access and untrusted master access.
+ */
+       __raw_writel(0x0, base + 0x40);
+       __raw_writel(0x0, base + 0x44);
+       __raw_writel(0x0, base + 0x48);
+       __raw_writel(0x0, base + 0x4C);
+       reg = __raw_readl(base + 0x50) & 0x00FFFFFF;
+       __raw_writel(reg, base + 0x50);
+}
index d8a56ae..ade4a1c 100644 (file)
@@ -60,9 +60,9 @@ static int imx_sata_init(struct device *dev, void __iomem *addr)
                dev_err(dev, "no sata clock.\n");
                return PTR_ERR(sata_clk);
        }
-       ret = clk_enable(sata_clk);
+       ret = clk_prepare_enable(sata_clk);
        if (ret) {
-               dev_err(dev, "can't enable sata clock.\n");
+               dev_err(dev, "can't prepare/enable sata clock.\n");
                goto put_sata_clk;
        }
 
@@ -73,9 +73,9 @@ static int imx_sata_init(struct device *dev, void __iomem *addr)
                ret = PTR_ERR(sata_ref_clk);
                goto release_sata_clk;
        }
-       ret = clk_enable(sata_ref_clk);
+       ret = clk_prepare_enable(sata_ref_clk);
        if (ret) {
-               dev_err(dev, "can't enable sata ref clock.\n");
+               dev_err(dev, "can't prepare/enable sata ref clock.\n");
                goto put_sata_ref_clk;
        }
 
@@ -104,11 +104,11 @@ static int imx_sata_init(struct device *dev, void __iomem *addr)
        return 0;
 
 release_sata_ref_clk:
-       clk_disable(sata_ref_clk);
+       clk_disable_unprepare(sata_ref_clk);
 put_sata_ref_clk:
        clk_put(sata_ref_clk);
 release_sata_clk:
-       clk_disable(sata_clk);
+       clk_disable_unprepare(sata_clk);
 put_sata_clk:
        clk_put(sata_clk);
 
@@ -117,10 +117,10 @@ put_sata_clk:
 
 static void imx_sata_exit(struct device *dev)
 {
-       clk_disable(sata_ref_clk);
+       clk_disable_unprepare(sata_ref_clk);
        clk_put(sata_ref_clk);
 
-       clk_disable(sata_clk);
+       clk_disable_unprepare(sata_clk);
        clk_put(sata_clk);
 
 }
index b3f4828..11eace9 100644 (file)
@@ -62,3 +62,21 @@ struct platform_device *__init imx_add_mx2_camera(
                        res, data->iobaseemmaprp ? 4 : 2,
                        pdata, sizeof(*pdata), DMA_BIT_MASK(32));
 }
+
+struct platform_device *__init imx_add_mx2_emmaprp(
+               const struct imx_mx2_camera_data *data)
+{
+       struct resource res[] = {
+               {
+                       .start = data->iobaseemmaprp,
+                       .end = data->iobaseemmaprp + data->iosizeemmaprp - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = data->irqemmaprp,
+                       .end = data->irqemmaprp,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+       return imx_add_platform_device_dmamask("m2m-emmaprp", 0,
+                       res, 2, NULL, 0, DMA_BIT_MASK(32));
+}
index d3467f8..9129c9e 100644 (file)
@@ -203,7 +203,7 @@ static int __init epit_clockevent_init(struct clk *timer_clk)
 
 void __init epit_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
 {
-       clk_enable(timer_clk);
+       clk_prepare_enable(timer_clk);
 
        timer_base = base;
 
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31ads.h b/arch/arm/plat-mxc/include/mach/board-mx31ads.h
deleted file mode 100644 (file)
index 94b60dd..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_MXC_BOARD_MX31ADS_H__
-#define __ASM_ARCH_MXC_BOARD_MX31ADS_H__
-
-#include <mach/hardware.h>
-
-/*
- * These symbols are used by drivers/net/cs89x0.c.
- * This is ugly as hell, but we have to provide them until
- * someone fixed the driver.
- */
-
-/* Base address of PBC controller */
-#define PBC_BASE_ADDRESS        MX31_CS4_BASE_ADDR_VIRT
-/* Offsets for the PBC Controller register */
-
-/* Ethernet Controller IO base address */
-#define PBC_CS8900A_IOBASE      0x020000
-
-#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
-
-#define EXPIO_INT_ENET_INT     (MXC_EXP_IO_BASE + 8)
-
-#endif /* __ASM_ARCH_MXC_BOARD_MX31ADS_H__ */
index 1bf0df8..0319c4a 100644 (file)
@@ -65,6 +65,7 @@ extern int mx51_clocks_init(unsigned long ckil, unsigned long osc,
                        unsigned long ckih1, unsigned long ckih2);
 extern int mx53_clocks_init(unsigned long ckil, unsigned long osc,
                        unsigned long ckih1, unsigned long ckih2);
+extern int mx27_clocks_init_dt(void);
 extern int mx51_clocks_init_dt(void);
 extern int mx53_clocks_init_dt(void);
 extern int mx6q_clocks_init(void);
@@ -75,6 +76,7 @@ extern void mxc_restart(char, const char *);
 extern void mxc_arch_reset_init(void __iomem *);
 extern int mx53_revision(void);
 extern int mx53_display_revision(void);
+extern void imx_set_aips(void __iomem *);
 
 enum mxc_cpu_pwr_mode {
        WAIT_CLOCKED,           /* wfi only */
@@ -84,6 +86,14 @@ enum mxc_cpu_pwr_mode {
        STOP_POWER_OFF,         /* STOP + SRPG */
 };
 
+enum mx3_cpu_pwr_mode {
+       MX3_RUN,
+       MX3_WAIT,
+       MX3_DOZE,
+       MX3_SLEEP,
+};
+
+extern void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode);
 extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode);
 extern void imx_print_silicon_rev(const char *cpu, int srev);
 
index 6e192c4..8ddda36 100644 (file)
@@ -24,7 +24,7 @@
 #define UART_PADDR     MX51_UART1_BASE_ADDR
 #elif defined (CONFIG_DEBUG_IMX50_IMX53_UART)
 #define UART_PADDR     MX53_UART1_BASE_ADDR
-#elif defined (CONFIG_DEBUG_IMX6Q_UART)
+#elif defined (CONFIG_DEBUG_IMX6Q_UART4)
 #define UART_PADDR     MX6Q_UART4_BASE_ADDR
 #endif
 
index def9ba5..1b2258d 100644 (file)
@@ -223,6 +223,8 @@ struct imx_mx2_camera_data {
 struct platform_device *__init imx_add_mx2_camera(
                const struct imx_mx2_camera_data *data,
                const struct mx2_camera_platform_data *pdata);
+struct platform_device *__init imx_add_mx2_emmaprp(
+               const struct imx_mx2_camera_data *data);
 
 #include <mach/mxc_ehci.h>
 struct imx_mxc_ehci_data {
index 233d0a5..1b90803 100644 (file)
@@ -60,8 +60,7 @@ static inline int imx_dma_is_ipu(struct dma_chan *chan)
 
 static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
 {
-       return !strcmp(dev_name(chan->device->dev), "imx31-sdma") ||
-               !strcmp(dev_name(chan->device->dev), "imx35-sdma") ||
+       return strstr(dev_name(chan->device->dev), "sdma") ||
                !strcmp(dev_name(chan->device->dev), "imx-dma");
 }
 
diff --git a/arch/arm/plat-mxc/include/mach/entry-macro.S b/arch/arm/plat-mxc/include/mach/entry-macro.S
deleted file mode 100644 (file)
index def5d30..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
- *  Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
index f0726d4..c61ec0f 100644 (file)
 #define MX25_PAD_NFRB__GPIO_3_31       IOMUX_PAD(0x27c, 0x084, 0x15, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_D15__D15              IOMUX_PAD(0x280, 0x088, 0x00, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_D15__LD16             IOMUX_PAD(0x280, 0x088, 0x01, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_D15__LD16             IOMUX_PAD(0x280, 0x088, 0x01, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_D15__GPIO_4_5         IOMUX_PAD(0x280, 0x088, 0x05, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_D14__D14              IOMUX_PAD(0x284, 0x08c, 0x00, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_D14__LD17             IOMUX_PAD(0x284, 0x08c, 0x01, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_D14__LD17             IOMUX_PAD(0x284, 0x08c, 0x01, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_D14__GPIO_4_6         IOMUX_PAD(0x284, 0x08c, 0x05, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_D13__D13              IOMUX_PAD(0x288, 0x090, 0x00, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_D13__LD18             IOMUX_PAD(0x288, 0x090, 0x01, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_D13__LD18             IOMUX_PAD(0x288, 0x090, 0x01, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_D13__GPIO_4_7         IOMUX_PAD(0x288, 0x090, 0x05, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_D12__D12              IOMUX_PAD(0x28c, 0x094, 0x00, 0, 0, NO_PAD_CTRL)
 #define MX25_PAD_D0__D0                        IOMUX_PAD(0x2bc, 0x0c4, 0x00, 0, 0, NO_PAD_CTRL)
 #define MX25_PAD_D0__GPIO_4_20         IOMUX_PAD(0x2bc, 0x0c4, 0x05, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD0__LD0              IOMUX_PAD(0x2c0, 0x0c8, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD0__LD0              IOMUX_PAD(0x2c0, 0x0c8, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD0__CSI_D0           IOMUX_PAD(0x2c0, 0x0c8, 0x12, 0x488, 0, NO_PAD_CTRL)
 #define MX25_PAD_LD0__GPIO_2_15                IOMUX_PAD(0x2c0, 0x0c8, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD1__LD1              IOMUX_PAD(0x2c4, 0x0cc, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD1__LD1              IOMUX_PAD(0x2c4, 0x0cc, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD1__CSI_D1           IOMUX_PAD(0x2c4, 0x0cc, 0x12, 0x48c, 0, NO_PAD_CTRL)
 #define MX25_PAD_LD1__GPIO_2_16                IOMUX_PAD(0x2c4, 0x0cc, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD2__LD2              IOMUX_PAD(0x2c8, 0x0d0, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD2__LD2              IOMUX_PAD(0x2c8, 0x0d0, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD2__GPIO_2_17                IOMUX_PAD(0x2c8, 0x0d0, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD3__LD3              IOMUX_PAD(0x2cc, 0x0d4, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD3__LD3              IOMUX_PAD(0x2cc, 0x0d4, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD3__GPIO_2_18                IOMUX_PAD(0x2cc, 0x0d4, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD4__LD4              IOMUX_PAD(0x2d0, 0x0d8, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD4__LD4              IOMUX_PAD(0x2d0, 0x0d8, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD4__GPIO_2_19                IOMUX_PAD(0x2d0, 0x0d8, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD5__LD5              IOMUX_PAD(0x2d4, 0x0dc, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD5__LD5              IOMUX_PAD(0x2d4, 0x0dc, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD5__GPIO_1_19                IOMUX_PAD(0x2d4, 0x0dc, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD6__LD6              IOMUX_PAD(0x2d8, 0x0e0, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD6__LD6              IOMUX_PAD(0x2d8, 0x0e0, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD6__GPIO_1_20                IOMUX_PAD(0x2d8, 0x0e0, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD7__LD7              IOMUX_PAD(0x2dc, 0x0e4, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD7__LD7              IOMUX_PAD(0x2dc, 0x0e4, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD7__GPIO_1_21                IOMUX_PAD(0x2dc, 0x0e4, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD8__LD8              IOMUX_PAD(0x2e0, 0x0e8, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD8__LD8              IOMUX_PAD(0x2e0, 0x0e8, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD8__FEC_TX_ERR       IOMUX_PAD(0x2e0, 0x0e8, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD9__LD9              IOMUX_PAD(0x2e4, 0x0ec, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD9__LD9              IOMUX_PAD(0x2e4, 0x0ec, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD9__FEC_COL          IOMUX_PAD(0x2e4, 0x0ec, 0x15, 0x504, 1, NO_PAD_CTRL)
 
-#define MX25_PAD_LD10__LD10            IOMUX_PAD(0x2e8, 0x0f0, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD10__LD10            IOMUX_PAD(0x2e8, 0x0f0, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD10__FEC_RX_ER       IOMUX_PAD(0x2e8, 0x0f0, 0x15, 0x518, 1, NO_PAD_CTRL)
 
-#define MX25_PAD_LD11__LD11            IOMUX_PAD(0x2ec, 0x0f4, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD11__LD11            IOMUX_PAD(0x2ec, 0x0f4, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD11__FEC_RDATA2      IOMUX_PAD(0x2ec, 0x0f4, 0x15, 0x50c, 1, NO_PAD_CTRL)
 
-#define MX25_PAD_LD12__LD12            IOMUX_PAD(0x2f0, 0x0f8, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD12__LD12            IOMUX_PAD(0x2f0, 0x0f8, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD12__FEC_RDATA3      IOMUX_PAD(0x2f0, 0x0f8, 0x15, 0x510, 1, NO_PAD_CTRL)
 
-#define MX25_PAD_LD13__LD13            IOMUX_PAD(0x2f4, 0x0fc, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD13__LD13            IOMUX_PAD(0x2f4, 0x0fc, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD13__FEC_TDATA2      IOMUX_PAD(0x2f4, 0x0fc, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD14__LD14            IOMUX_PAD(0x2f8, 0x100, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD14__LD14            IOMUX_PAD(0x2f8, 0x100, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD14__FEC_TDATA3      IOMUX_PAD(0x2f8, 0x100, 0x15, 0, 0, NO_PAD_CTRL)
 
-#define MX25_PAD_LD15__LD15            IOMUX_PAD(0x2fc, 0x104, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_LD15__LD15            IOMUX_PAD(0x2fc, 0x104, 0x10, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_LD15__FEC_RX_CLK      IOMUX_PAD(0x2fc, 0x104, 0x15, 0x514, 1, NO_PAD_CTRL)
 
 #define MX25_PAD_HSYNC__HSYNC          IOMUX_PAD(0x300, 0x108, 0x10, 0, 0, NO_PAD_CTRL)
 #define MX25_PAD_GPIO_C__CAN2_TX       IOMUX_PAD(0x3f8, 0x1fc, 0x16, 0, 0, PAD_CTL_PUS_22K_UP)
 
 #define MX25_PAD_GPIO_D__GPIO_D                IOMUX_PAD(0x3fc, 0x200, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_GPIO_E__LD16          IOMUX_PAD(0x400, 0x204, 0x02, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_GPIO_E__LD16          IOMUX_PAD(0x400, 0x204, 0x02, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_GPIO_D__CAN2_RX       IOMUX_PAD(0x3fc, 0x200, 0x16, 0x484, 1, PAD_CTL_PUS_22K_UP)
 
 #define MX25_PAD_GPIO_E__GPIO_E                IOMUX_PAD(0x400, 0x204, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_GPIO_F__LD17          IOMUX_PAD(0x404, 0x208, 0x02, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_GPIO_F__LD17          IOMUX_PAD(0x404, 0x208, 0x02, 0, 0, PAD_CTL_SRE_FAST)
 #define MX25_PAD_GPIO_E__AUD7_TXD      IOMUX_PAD(0x400, 0x204, 0x14, 0, 0, NO_PAD_CTRL)
 
 #define MX25_PAD_GPIO_F__GPIO_F                IOMUX_PAD(0x404, 0x208, 0x10, 0, 0, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/system.h b/arch/arm/plat-mxc/include/mach/system.h
deleted file mode 100644 (file)
index 13ad0df..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *  Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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.
- */
-
-#ifndef __ASM_ARCH_MXC_SYSTEM_H__
-#define __ASM_ARCH_MXC_SYSTEM_H__
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif /* __ASM_ARCH_MXC_SYSTEM_H__ */
index e032717..c0cab22 100644 (file)
@@ -132,7 +132,7 @@ int pwm_enable(struct pwm_device *pwm)
        int rc = 0;
 
        if (!pwm->clk_enabled) {
-               rc = clk_enable(pwm->clk);
+               rc = clk_prepare_enable(pwm->clk);
                if (!rc)
                        pwm->clk_enabled = 1;
        }
@@ -145,7 +145,7 @@ void pwm_disable(struct pwm_device *pwm)
        writel(0, pwm->mmio_base + MX3_PWMCR);
 
        if (pwm->clk_enabled) {
-               clk_disable(pwm->clk);
+               clk_disable_unprepare(pwm->clk);
                pwm->clk_enabled = 0;
        }
 }
index c195d6d..1996c3e 100644 (file)
@@ -48,7 +48,7 @@ void mxc_restart(char mode, const char *cmd)
 
                clk = clk_get_sys("imx2-wdt.0", NULL);
                if (!IS_ERR(clk))
-                       clk_enable(clk);
+                       clk_prepare_enable(clk);
                wcr_enable = (1 << 2);
        }
 
index 1c96cdb..7daf7c9 100644 (file)
@@ -283,7 +283,7 @@ void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
 {
        uint32_t tctl_val;
 
-       clk_enable(timer_clk);
+       clk_prepare_enable(timer_clk);
 
        timer_base = base;
 
index 6508e76..582641f 100644 (file)
@@ -1,9 +1,7 @@
 #ifndef __PLAT_MTU_H
 #define __PLAT_MTU_H
 
-/* should be set by the platform code */
-extern void __iomem *mtu_base;
-
+void nmdk_timer_init(void __iomem *base);
 void nmdk_clkevt_reset(void);
 void nmdk_clksrc_reset(void);
 
index ad1b45b..9222e55 100644 (file)
 #include <asm/sched_clock.h>
 
 /*
- * Guaranteed runtime conversion range in seconds for
- * the clocksource and clockevent.
- */
-#define MTU_MIN_RANGE 4
-
-/*
  * The MTU device hosts four different counters, with 4 set of
  * registers. These are register names.
  */
 #define MTU_PCELL2     0xff8
 #define MTU_PCELL3     0xffC
 
+static void __iomem *mtu_base;
 static bool clkevt_periodic;
 static u32 clk_prescale;
 static u32 nmdk_cycle;         /* write-once */
 
-void __iomem *mtu_base; /* Assigned by machine code */
-
 #ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK
 /*
  * Override the global weak sched_clock symbol with this
@@ -103,7 +96,6 @@ static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev)
 void nmdk_clkevt_reset(void)
 {
        if (clkevt_periodic) {
-
                /* Timer: configure load and background-load, and fire it up */
                writel(nmdk_cycle, mtu_base + MTU_LR(1));
                writel(nmdk_cycle, mtu_base + MTU_BGLR(1));
@@ -121,7 +113,6 @@ void nmdk_clkevt_reset(void)
 static void nmdk_clkevt_mode(enum clock_event_mode mode,
                             struct clock_event_device *dev)
 {
-
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
                clkevt_periodic = true;
@@ -183,15 +174,16 @@ void nmdk_clksrc_reset(void)
               mtu_base + MTU_CR(0));
 }
 
-void __init nmdk_timer_init(void)
+void __init nmdk_timer_init(void __iomem *base)
 {
        unsigned long rate;
        struct clk *clk0;
 
+       mtu_base = base;
        clk0 = clk_get_sys("mtu0", NULL);
        BUG_ON(IS_ERR(clk0));
-
-       clk_enable(clk0);
+       BUG_ON(clk_prepare(clk0) < 0);
+       BUG_ON(clk_enable(clk0) < 0);
 
        /*
         * Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz
@@ -224,17 +216,8 @@ void __init nmdk_timer_init(void)
        setup_sched_clock(nomadik_read_sched_clock, 32, rate);
 #endif
 
-       /* Timer 1 is used for events */
-
-       clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE);
-
-       nmdk_clkevt.max_delta_ns =
-               clockevent_delta2ns(0xffffffff, &nmdk_clkevt);
-       nmdk_clkevt.min_delta_ns =
-               clockevent_delta2ns(0x00000002, &nmdk_clkevt);
-       nmdk_clkevt.cpumask     = cpumask_of(0);
-
-       /* Register irq and clockevents */
+       /* Timer 1 is used for events, register irq and clockevents */
        setup_irq(IRQ_MTU0, &nmdk_timer_irq);
-       clockevents_register_device(&nmdk_clkevt);
+       nmdk_clkevt.cpumask = cpumask_of(0);
+       clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU);
 }
index 8f81503..ce1e9b9 100644 (file)
@@ -14,6 +14,7 @@ config ARCH_OMAP1
        select CLKDEV_LOOKUP
        select CLKSRC_MMIO
        select GENERIC_IRQ_CHIP
+       select IRQ_DOMAIN
        select HAVE_IDE
        select NEED_MACH_MEMORY_H
        help
@@ -24,6 +25,8 @@ config ARCH_OMAP2PLUS
        select CLKDEV_LOOKUP
        select GENERIC_IRQ_CHIP
        select OMAP_DM_TIMER
+       select USE_OF
+       select PROC_DEVICETREE if PROC_FS
        help
          "Systems based on OMAP2, OMAP3 or OMAP4"
 
index 567e4b5..56b6f8b 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/clk.h>
 #include <linux/mutex.h>
 #include <linux/cpufreq.h>
-#include <linux/debugfs.h>
 #include <linux/io.h>
 
 #include <plat/clock.h>
index 5f0f229..5068fe5 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <asm/sched_clock.h>
 
+#include <plat/hardware.h>
 #include <plat/common.h>
 #include <plat/board.h>
 
index dbb1049..ecdb3da 100644 (file)
@@ -163,6 +163,8 @@ static inline void set_gdma_dev(int req, int dev)
 }
 #else
 #define set_gdma_dev(req, dev) do {} while (0)
+#define omap_readl(reg)                0
+#define omap_writel(val, reg)  do {} while (0)
 #endif
 
 void omap_set_dma_priority(int lch, int dst_port, int priority)
@@ -2124,7 +2126,7 @@ static int __devexit omap_system_dma_remove(struct platform_device *pdev)
 
 static struct platform_driver omap_system_dma_driver = {
        .probe          = omap_system_dma_probe,
-       .remove         = omap_system_dma_remove,
+       .remove         = __devexit_p(omap_system_dma_remove),
        .driver         = {
                .name   = "omap_dma_system"
        },
index af3b92b..652139c 100644 (file)
@@ -43,6 +43,8 @@
 
 #include <plat/dmtimer.h>
 
+#include <mach/hardware.h>
+
 static LIST_HEAD(omap_timer_list);
 static DEFINE_SPINLOCK(dm_timer_lock);
 
@@ -80,9 +82,9 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 
 static void omap_timer_restore_context(struct omap_dm_timer *timer)
 {
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
-                               timer->context.tiocp_cfg);
-       if (timer->revision > 1)
+       __raw_writel(timer->context.tiocp_cfg,
+                       timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET);
+       if (timer->revision == 1)
                __raw_writel(timer->context.tistat, timer->sys_stat);
 
        __raw_writel(timer->context.tisr, timer->irq_stat);
@@ -357,6 +359,19 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer)
 
        __omap_dm_timer_stop(timer, timer->posted, rate);
 
+       if (timer->loses_context && timer->get_context_loss_count)
+               timer->ctx_loss_count =
+                       timer->get_context_loss_count(&timer->pdev->dev);
+
+       /*
+        * Since the register values are computed and written within
+        * __omap_dm_timer_stop, we need to use read to retrieve the
+        * context.
+        */
+       timer->context.tclr =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       timer->context.tisr = __raw_readl(timer->irq_stat);
+       omap_dm_timer_disable(timer);
        return 0;
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
index 51b102d..ad6f865 100644 (file)
 
 #if defined (CONFIG_MACH_AMS_DELTA)
 
-#define AMS_DELTA_LATCH1_PHYS          0x01000000
-#define AMS_DELTA_LATCH1_VIRT          0xEA000000
-#define AMS_DELTA_MODEM_PHYS           0x04000000
-#define AMS_DELTA_MODEM_VIRT           0xEB000000
-#define AMS_DELTA_LATCH2_PHYS          0x08000000
-#define AMS_DELTA_LATCH2_VIRT          0xEC000000
-
-#define AMS_DELTA_LATCH1_LED_CAMERA    0x01
-#define AMS_DELTA_LATCH1_LED_ADVERT    0x02
-#define AMS_DELTA_LATCH1_LED_EMAIL     0x04
-#define AMS_DELTA_LATCH1_LED_HANDSFREE 0x08
-#define AMS_DELTA_LATCH1_LED_VOICEMAIL 0x10
-#define AMS_DELTA_LATCH1_LED_VOICE     0x20
-
-#define AMS_DELTA_LATCH2_LCD_VBLEN     0x0001
-#define AMS_DELTA_LATCH2_LCD_NDISP     0x0002
-#define AMS_DELTA_LATCH2_NAND_NCE      0x0004
-#define AMS_DELTA_LATCH2_NAND_NRE      0x0008
-#define AMS_DELTA_LATCH2_NAND_NWP      0x0010
-#define AMS_DELTA_LATCH2_NAND_NWE      0x0020
-#define AMS_DELTA_LATCH2_NAND_ALE      0x0040
-#define AMS_DELTA_LATCH2_NAND_CLE      0x0080
-#define AMD_DELTA_LATCH2_KEYBRD_PWR    0x0100
-#define AMD_DELTA_LATCH2_KEYBRD_DATA   0x0200
 #define AMD_DELTA_LATCH2_SCARD_RSTIN   0x0400
 #define AMD_DELTA_LATCH2_SCARD_CMDVCC  0x0800
-#define AMS_DELTA_LATCH2_MODEM_NRESET  0x1000
 #define AMS_DELTA_LATCH2_MODEM_CODEC   0x2000
 
 #define AMS_DELTA_GPIO_PIN_KEYBRD_DATA 0
 #define AMS_DELTA_GPIO_PIN_CONFIG      11
 #define AMS_DELTA_GPIO_PIN_NAND_RB     12
 
+#define AMS_DELTA_GPIO_PIN_LCD_VBLEN           240
+#define AMS_DELTA_GPIO_PIN_LCD_NDISP           241
+#define AMS_DELTA_GPIO_PIN_NAND_NCE            242
+#define AMS_DELTA_GPIO_PIN_NAND_NRE            243
+#define AMS_DELTA_GPIO_PIN_NAND_NWP            244
+#define AMS_DELTA_GPIO_PIN_NAND_NWE            245
+#define AMS_DELTA_GPIO_PIN_NAND_ALE            246
+#define AMS_DELTA_GPIO_PIN_NAND_CLE            247
+#define AMS_DELTA_GPIO_PIN_KEYBRD_PWR          248
+#define AMS_DELTA_GPIO_PIN_KEYBRD_DATAOUT      249
+#define AMS_DELTA_GPIO_PIN_SCARD_RSTIN         250
+#define AMS_DELTA_GPIO_PIN_SCARD_CMDVCC                251
+#define AMS_DELTA_GPIO_PIN_MODEM_NRESET                252
+#define AMS_DELTA_GPIO_PIN_MODEM_CODEC         253
+
+#define AMS_DELTA_LATCH2_GPIO_BASE     AMS_DELTA_GPIO_PIN_LCD_VBLEN
+#define AMS_DELTA_LATCH2_NGPIO         16
+
 #ifndef __ASSEMBLY__
-void ams_delta_latch1_write(u8 mask, u8 value);
-void ams_delta_latch2_write(u16 mask, u16 value);
+void ams_delta_latch_write(int base, int ngpio, u16 mask, u16 value);
+#define ams_delta_latch2_write(mask, value) \
+       ams_delta_latch_write(AMS_DELTA_LATCH2_GPIO_BASE, \
+                       AMS_DELTA_LATCH2_NGPIO, (mask), (value))
 #endif
 
 #endif /* CONFIG_MACH_AMS_DELTA */
index 6b51086..dc6a86b 100644 (file)
@@ -250,7 +250,6 @@ IS_AM_SUBCLASS(335x, 0x335)
  * cpu_is_omap2423():  True for OMAP2423
  * cpu_is_omap2430():  True for OMAP2430
  * cpu_is_omap3430():  True for OMAP3430
- * cpu_is_omap4430():  True for OMAP4430
  * cpu_is_omap3505():  True for OMAP3505
  * cpu_is_omap3517():  True for OMAP3517
  */
@@ -299,7 +298,6 @@ IS_OMAP_TYPE(3517, 0x3517)
 #define cpu_is_omap3505()              0
 #define cpu_is_omap3517()              0
 #define cpu_is_omap3430()              0
-#define cpu_is_omap4430()              0
 #define cpu_is_omap3630()              0
 
 /*
@@ -451,7 +449,12 @@ IS_OMAP_TYPE(3517, 0x3517)
 #define OMAP447X_CLASS         0x44700044
 #define OMAP4470_REV_ES1_0     (OMAP447X_CLASS | (0x10 << 8))
 
-void omap2_check_revision(void);
+void omap2xxx_check_revision(void);
+void omap3xxx_check_revision(void);
+void omap4xxx_check_revision(void);
+void omap3xxx_check_features(void);
+void ti81xx_check_features(void);
+void omap4xxx_check_features(void);
 
 /*
  * Runtime detection of OMAP3 features
index 9e86ee0..b8a96c6 100644 (file)
                                 IH_MPUIO_BASE + ((nr) & 0x0f) : \
                                 IH_GPIO_BASE + (nr))
 
-#define METHOD_MPUIO           0
-#define METHOD_GPIO_1510       1
-#define METHOD_GPIO_1610       2
-#define METHOD_GPIO_7XX                3
-#define METHOD_GPIO_24XX       5
-#define METHOD_GPIO_44XX       6
-
 struct omap_gpio_dev_attr {
        int bank_width;         /* GPIO bank width */
        bool dbck_flag;         /* dbck required or not - True for OMAP3&4 */
@@ -184,10 +177,21 @@ struct omap_gpio_reg_offs {
        u16 irqstatus;
        u16 irqstatus2;
        u16 irqenable;
+       u16 irqenable2;
        u16 set_irqenable;
        u16 clr_irqenable;
        u16 debounce;
        u16 debounce_en;
+       u16 ctrl;
+       u16 wkup_en;
+       u16 leveldetect0;
+       u16 leveldetect1;
+       u16 risingdetect;
+       u16 fallingdetect;
+       u16 irqctrl;
+       u16 edgectrl1;
+       u16 edgectrl2;
+       u16 pinctrl;
 
        bool irqenable_inv;
 };
@@ -198,45 +202,30 @@ struct omap_gpio_platform_data {
        int bank_width;         /* GPIO bank width */
        int bank_stride;        /* Only needed for omap1 MPUIO */
        bool dbck_flag;         /* dbck required or not - True for OMAP3&4 */
+       bool loses_context;     /* whether the bank would ever lose context */
+       bool is_mpuio;          /* whether the bank is of type MPUIO */
+       u32 non_wakeup_gpios;
 
        struct omap_gpio_reg_offs *regs;
-};
 
-/* TODO: Analyze removing gpio_bank_count usage from driver code */
-extern int gpio_bank_count;
+       /* Return context loss count due to PM states changing */
+       int (*get_context_loss_count)(struct device *dev);
+};
 
 extern void omap2_gpio_prepare_for_idle(int off_mode);
 extern void omap2_gpio_resume_after_idle(void);
 extern void omap_set_gpio_debounce(int gpio, int enable);
 extern void omap_set_gpio_debounce_time(int gpio, int enable);
-extern void omap_gpio_save_context(void);
-extern void omap_gpio_restore_context(void);
 /*-------------------------------------------------------------------------*/
 
-/* Wrappers for "new style" GPIO calls, using the new infrastructure
+/*
+ * Wrappers for "new style" GPIO calls, using the new infrastructure
  * which lets us plug in FPGA, I2C, and other implementations.
- * *
+ *
  * The original OMAP-specific calls should eventually be removed.
  */
 
 #include <linux/errno.h>
 #include <asm-generic/gpio.h>
 
-static inline int irq_to_gpio(unsigned irq)
-{
-       int tmp;
-
-       /* omap1 SOC mpuio */
-       if (cpu_class_is_omap1() && (irq < (IH_MPUIO_BASE + 16)))
-               return (irq - IH_MPUIO_BASE) + OMAP_MAX_GPIO_LINES;
-
-       /* SOC gpio */
-       tmp = irq - IH_GPIO_BASE;
-       if (tmp < OMAP_MAX_GPIO_LINES)
-               return tmp;
-
-       /* we don't supply reverse mappings for non-SOC gpios */
-       return -EIO;
-}
-
 #endif
index e897978..537b05a 100644 (file)
 #endif
 #include <plat/serial.h>
 
+#ifdef __ASSEMBLER__
+#define IOMEM(x)               (x)
+#else
+#define IOMEM(x)               ((void __force __iomem *)(x))
+#endif
+
 /*
  * ---------------------------------------------------------------------------
  * Common definitions for all OMAP processors
diff --git a/arch/arm/plat-omap/include/plat/io.h b/arch/arm/plat-omap/include/plat/io.h
deleted file mode 100644 (file)
index 0696bae..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/io.h
- *
- * IO definitions for TI OMAP processors and boards
- *
- * Copied from arch/arm/mach-sa1100/include/mach/io.h
- * Copyright (C) 1997-1999 Russell King
- *
- * Copyright (C) 2009 Texas Instruments
- * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License 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.
- *
- * Modifications:
- *  06-12-1997 RMK     Created.
- *  07-04-1999 RMK     Major cleanup
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#include <mach/hardware.h>
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * We don't actually have real ISA nor PCI buses, but there is so many
- * drivers out there that might just work if we fake them...
- */
-#define __io(a)                __typesafe_io(a)
-#define __mem_pci(a)   (a)
-
-/*
- * ----------------------------------------------------------------------------
- * I/O mapping
- * ----------------------------------------------------------------------------
- */
-
-#ifdef __ASSEMBLER__
-#define IOMEM(x)               (x)
-#else
-#define IOMEM(x)               ((void __force __iomem *)(x))
-#endif
-
-#define OMAP1_IO_OFFSET                0x01000000      /* Virtual IO = 0xfefb0000 */
-#define OMAP1_IO_ADDRESS(pa)   IOMEM((pa) - OMAP1_IO_OFFSET)
-
-#define OMAP2_L3_IO_OFFSET     0x90000000
-#define OMAP2_L3_IO_ADDRESS(pa)        IOMEM((pa) + OMAP2_L3_IO_OFFSET) /* L3 */
-
-
-#define OMAP2_L4_IO_OFFSET     0xb2000000
-#define OMAP2_L4_IO_ADDRESS(pa)        IOMEM((pa) + OMAP2_L4_IO_OFFSET) /* L4 */
-
-#define OMAP4_L3_IO_OFFSET     0xb4000000
-#define OMAP4_L3_IO_ADDRESS(pa)        IOMEM((pa) + OMAP4_L3_IO_OFFSET) /* L3 */
-
-#define AM33XX_L4_WK_IO_OFFSET 0xb5000000
-#define AM33XX_L4_WK_IO_ADDRESS(pa)    IOMEM((pa) + AM33XX_L4_WK_IO_OFFSET)
-
-#define OMAP4_L3_PER_IO_OFFSET 0xb1100000
-#define OMAP4_L3_PER_IO_ADDRESS(pa)    IOMEM((pa) + OMAP4_L3_PER_IO_OFFSET)
-
-#define OMAP4_GPMC_IO_OFFSET           0xa9000000
-#define OMAP4_GPMC_IO_ADDRESS(pa)      IOMEM((pa) + OMAP4_GPMC_IO_OFFSET)
-
-#define OMAP2_EMU_IO_OFFSET            0xaa800000      /* Emulation */
-#define OMAP2_EMU_IO_ADDRESS(pa)       IOMEM((pa) + OMAP2_EMU_IO_OFFSET)
-
-/*
- * ----------------------------------------------------------------------------
- * Omap1 specific IO mapping
- * ----------------------------------------------------------------------------
- */
-
-#define OMAP1_IO_PHYS          0xFFFB0000
-#define OMAP1_IO_SIZE          0x40000
-#define OMAP1_IO_VIRT          (OMAP1_IO_PHYS - OMAP1_IO_OFFSET)
-
-/*
- * ----------------------------------------------------------------------------
- * Omap2 specific IO mapping
- * ----------------------------------------------------------------------------
- */
-
-/* We map both L3 and L4 on OMAP2 */
-#define L3_24XX_PHYS   L3_24XX_BASE    /* 0x68000000 --> 0xf8000000*/
-#define L3_24XX_VIRT   (L3_24XX_PHYS + OMAP2_L3_IO_OFFSET)
-#define L3_24XX_SIZE   SZ_1M           /* 44kB of 128MB used, want 1MB sect */
-#define L4_24XX_PHYS   L4_24XX_BASE    /* 0x48000000 --> 0xfa000000 */
-#define L4_24XX_VIRT   (L4_24XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_24XX_SIZE   SZ_1M           /* 1MB of 128MB used, want 1MB sect */
-
-#define L4_WK_243X_PHYS                L4_WK_243X_BASE /* 0x49000000 --> 0xfb000000 */
-#define L4_WK_243X_VIRT                (L4_WK_243X_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_WK_243X_SIZE                SZ_1M
-#define OMAP243X_GPMC_PHYS     OMAP243X_GPMC_BASE
-#define OMAP243X_GPMC_VIRT     (OMAP243X_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
-                                               /* 0x6e000000 --> 0xfe000000 */
-#define OMAP243X_GPMC_SIZE     SZ_1M
-#define OMAP243X_SDRC_PHYS     OMAP243X_SDRC_BASE
-                                               /* 0x6D000000 --> 0xfd000000 */
-#define OMAP243X_SDRC_VIRT     (OMAP243X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
-#define OMAP243X_SDRC_SIZE     SZ_1M
-#define OMAP243X_SMS_PHYS      OMAP243X_SMS_BASE
-                                               /* 0x6c000000 --> 0xfc000000 */
-#define OMAP243X_SMS_VIRT      (OMAP243X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
-#define OMAP243X_SMS_SIZE      SZ_1M
-
-/* 2420 IVA */
-#define DSP_MEM_2420_PHYS      OMAP2420_DSP_MEM_BASE
-                                               /* 0x58000000 --> 0xfc100000 */
-#define DSP_MEM_2420_VIRT      0xfc100000
-#define DSP_MEM_2420_SIZE      0x28000
-#define DSP_IPI_2420_PHYS      OMAP2420_DSP_IPI_BASE
-                                               /* 0x59000000 --> 0xfc128000 */
-#define DSP_IPI_2420_VIRT      0xfc128000
-#define DSP_IPI_2420_SIZE      SZ_4K
-#define DSP_MMU_2420_PHYS      OMAP2420_DSP_MMU_BASE
-                                               /* 0x5a000000 --> 0xfc129000 */
-#define DSP_MMU_2420_VIRT      0xfc129000
-#define DSP_MMU_2420_SIZE      SZ_4K
-
-/* 2430 IVA2.1 - currently unmapped */
-
-/*
- * ----------------------------------------------------------------------------
- * Omap3 specific IO mapping
- * ----------------------------------------------------------------------------
- */
-
-/* We map both L3 and L4 on OMAP3 */
-#define L3_34XX_PHYS           L3_34XX_BASE    /* 0x68000000 --> 0xf8000000 */
-#define L3_34XX_VIRT           (L3_34XX_PHYS + OMAP2_L3_IO_OFFSET)
-#define L3_34XX_SIZE           SZ_1M   /* 44kB of 128MB used, want 1MB sect */
-
-#define L4_34XX_PHYS           L4_34XX_BASE    /* 0x48000000 --> 0xfa000000 */
-#define L4_34XX_VIRT           (L4_34XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_34XX_SIZE           SZ_4M   /* 1MB of 128MB used, want 1MB sect */
-
-/*
- * ----------------------------------------------------------------------------
- * AM33XX specific IO mapping
- * ----------------------------------------------------------------------------
- */
-#define L4_WK_AM33XX_PHYS      L4_WK_AM33XX_BASE
-#define L4_WK_AM33XX_VIRT      (L4_WK_AM33XX_PHYS + AM33XX_L4_WK_IO_OFFSET)
-#define L4_WK_AM33XX_SIZE      SZ_4M   /* 1MB of 128MB used, want 1MB sect */
-
-/*
- * Need to look at the Size 4M for L4.
- * VPOM3430 was not working for Int controller
- */
-
-#define L4_PER_34XX_PHYS       L4_PER_34XX_BASE
-                                               /* 0x49000000 --> 0xfb000000 */
-#define L4_PER_34XX_VIRT       (L4_PER_34XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_PER_34XX_SIZE       SZ_1M
-
-#define L4_EMU_34XX_PHYS       L4_EMU_34XX_BASE
-                                               /* 0x54000000 --> 0xfe800000 */
-#define L4_EMU_34XX_VIRT       (L4_EMU_34XX_PHYS + OMAP2_EMU_IO_OFFSET)
-#define L4_EMU_34XX_SIZE       SZ_8M
-
-#define OMAP34XX_GPMC_PHYS     OMAP34XX_GPMC_BASE
-                                               /* 0x6e000000 --> 0xfe000000 */
-#define OMAP34XX_GPMC_VIRT     (OMAP34XX_GPMC_PHYS + OMAP2_L3_IO_OFFSET)
-#define OMAP34XX_GPMC_SIZE     SZ_1M
-
-#define OMAP343X_SMS_PHYS      OMAP343X_SMS_BASE
-                                               /* 0x6c000000 --> 0xfc000000 */
-#define OMAP343X_SMS_VIRT      (OMAP343X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
-#define OMAP343X_SMS_SIZE      SZ_1M
-
-#define OMAP343X_SDRC_PHYS     OMAP343X_SDRC_BASE
-                                               /* 0x6D000000 --> 0xfd000000 */
-#define OMAP343X_SDRC_VIRT     (OMAP343X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
-#define OMAP343X_SDRC_SIZE     SZ_1M
-
-/* 3430 IVA - currently unmapped */
-
-/*
- * ----------------------------------------------------------------------------
- * Omap4 specific IO mapping
- * ----------------------------------------------------------------------------
- */
-
-/* We map both L3 and L4 on OMAP4 */
-#define L3_44XX_PHYS           L3_44XX_BASE    /* 0x44000000 --> 0xf8000000 */
-#define L3_44XX_VIRT           (L3_44XX_PHYS + OMAP4_L3_IO_OFFSET)
-#define L3_44XX_SIZE           SZ_1M
-
-#define L4_44XX_PHYS           L4_44XX_BASE    /* 0x4a000000 --> 0xfc000000 */
-#define L4_44XX_VIRT           (L4_44XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_44XX_SIZE           SZ_4M
-
-#define L4_PER_44XX_PHYS       L4_PER_44XX_BASE
-                                               /* 0x48000000 --> 0xfa000000 */
-#define L4_PER_44XX_VIRT       (L4_PER_44XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_PER_44XX_SIZE       SZ_4M
-
-#define L4_ABE_44XX_PHYS       L4_ABE_44XX_BASE
-                                               /* 0x49000000 --> 0xfb000000 */
-#define L4_ABE_44XX_VIRT       (L4_ABE_44XX_PHYS + OMAP2_L4_IO_OFFSET)
-#define L4_ABE_44XX_SIZE       SZ_1M
-
-#define L4_EMU_44XX_PHYS       L4_EMU_44XX_BASE
-                                               /* 0x54000000 --> 0xfe800000 */
-#define L4_EMU_44XX_VIRT       (L4_EMU_44XX_PHYS + OMAP2_EMU_IO_OFFSET)
-#define L4_EMU_44XX_SIZE       SZ_8M
-
-#define OMAP44XX_GPMC_PHYS     OMAP44XX_GPMC_BASE
-                                               /* 0x50000000 --> 0xf9000000 */
-#define OMAP44XX_GPMC_VIRT     (OMAP44XX_GPMC_PHYS + OMAP4_GPMC_IO_OFFSET)
-#define OMAP44XX_GPMC_SIZE     SZ_1M
-
-
-#define OMAP44XX_EMIF1_PHYS    OMAP44XX_EMIF1_BASE
-                                               /* 0x4c000000 --> 0xfd100000 */
-#define OMAP44XX_EMIF1_VIRT    (OMAP44XX_EMIF1_PHYS + OMAP4_L3_PER_IO_OFFSET)
-#define OMAP44XX_EMIF1_SIZE    SZ_1M
-
-#define OMAP44XX_EMIF2_PHYS    OMAP44XX_EMIF2_BASE
-                                               /* 0x4d000000 --> 0xfd200000 */
-#define OMAP44XX_EMIF2_SIZE    SZ_1M
-#define OMAP44XX_EMIF2_VIRT    (OMAP44XX_EMIF1_VIRT + OMAP44XX_EMIF1_SIZE)
-
-#define OMAP44XX_DMM_PHYS      OMAP44XX_DMM_BASE
-                                               /* 0x4e000000 --> 0xfd300000 */
-#define OMAP44XX_DMM_SIZE      SZ_1M
-#define OMAP44XX_DMM_VIRT      (OMAP44XX_EMIF2_VIRT + OMAP44XX_EMIF2_SIZE)
-/*
- * ----------------------------------------------------------------------------
- * Omap specific register access
- * ----------------------------------------------------------------------------
- */
-
-#ifndef __ASSEMBLER__
-
-/*
- * NOTE: Please use ioremap + __raw_read/write where possible instead of these
- */
-
-extern u8 omap_readb(u32 pa);
-extern u16 omap_readw(u32 pa);
-extern u32 omap_readl(u32 pa);
-extern void omap_writeb(u8 v, u32 pa);
-extern void omap_writew(u16 v, u32 pa);
-extern void omap_writel(u32 v, u32 pa);
-
-struct omap_sdrc_params;
-extern void omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
-                                     struct omap_sdrc_params *sdrc_cs1);
-
-extern void __init omap_init_consistent_dma_size(void);
-
-#endif
-
-#endif
index 793ce9d..a6b21ed 100644 (file)
@@ -12,6 +12,8 @@
 
 #ifndef CONFIG_ARCH_OMAP1
 #warning Please update the board to use matrix-keypad driver
+#define omap_readw(reg)                0
+#define omap_writew(val, reg)  do {} while (0)
 #endif
 #include <linux/input/matrix_keypad.h>
 
index 3d51b18..a357eb2 100644 (file)
@@ -18,9 +18,6 @@ struct omap2_mcspi_dev_attr {
 
 struct omap2_mcspi_device_config {
        unsigned turbo_mode:1;
-
-       /* Do we want one channel enabled at the same time? */
-       unsigned single_channel:1;
 };
 
 #endif
index 51423d2..4327b2c 100644 (file)
@@ -36,7 +36,7 @@
 
 #include <plat/omap_hwmod.h>
 
-extern struct device omap_device_parent;
+extern struct dev_pm_domain omap_device_pm_domain;
 
 /* omap_device._state values */
 #define OMAP_DEVICE_STATE_UNKNOWN      0
@@ -100,6 +100,13 @@ struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
                                         struct omap_device_pm_latency *pm_lats,
                                         int pm_lats_cnt, int is_early_device);
 
+struct omap_device *omap_device_alloc(struct platform_device *pdev,
+                                     struct omap_hwmod **ohs, int oh_cnt,
+                                     struct omap_device_pm_latency *pm_lats,
+                                     int pm_lats_cnt);
+void omap_device_delete(struct omap_device *od);
+int omap_device_register(struct platform_device *pdev);
+
 void __iomem *omap_device_get_rt_va(struct omap_device *od);
 struct device *omap_device_get_by_hwmod_name(const char *oh_name);
 
index 6470101..9e8e63d 100644 (file)
@@ -484,7 +484,6 @@ struct omap_hwmod_class {
  * @main_clk: main clock: OMAP clock name
  * @_clk: pointer to the main struct clk (filled in at runtime)
  * @opt_clks: other device clocks that drivers can request (0..*)
- * @vdd_name: voltage domain name
  * @voltdm: pointer to voltage domain (filled in at runtime)
  * @masters: ptr to array of OCP ifs that this hwmod can initiate on
  * @slaves: ptr to array of OCP ifs that this hwmod can respond on
@@ -528,7 +527,6 @@ struct omap_hwmod {
        struct omap_hwmod_opt_clk       *opt_clks;
        char                            *clkdm_name;
        struct clockdomain              *clkdm;
-       char                            *vdd_name;
        struct omap_hwmod_ocp_if        **masters; /* connect to *_IA */
        struct omap_hwmod_ocp_if        **slaves;  /* connect to *_TA */
        void                            *dev_attr;
diff --git a/arch/arm/plat-omap/include/plat/remoteproc.h b/arch/arm/plat-omap/include/plat/remoteproc.h
new file mode 100644 (file)
index 0000000..b10eac8
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Remote Processor - omap-specific bits
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _PLAT_REMOTEPROC_H
+#define _PLAT_REMOTEPROC_H
+
+struct rproc_ops;
+struct platform_device;
+
+/*
+ * struct omap_rproc_pdata - omap remoteproc's platform data
+ * @name: the remoteproc's name
+ * @oh_name: omap hwmod device
+ * @oh_name_opt: optional, secondary omap hwmod device
+ * @firmware: name of firmware file to load
+ * @mbox_name: name of omap mailbox device to use with this rproc
+ * @ops: start/stop rproc handlers
+ * @device_enable: omap-specific handler for enabling a device
+ * @device_shutdown: omap-specific handler for shutting down a device
+ */
+struct omap_rproc_pdata {
+       const char *name;
+       const char *oh_name;
+       const char *oh_name_opt;
+       const char *firmware;
+       const char *mbox_name;
+       const struct rproc_ops *ops;
+       int (*device_enable) (struct platform_device *pdev);
+       int (*device_shutdown) (struct platform_device *pdev);
+};
+
+#if defined(CONFIG_OMAP_REMOTEPROC) || defined(CONFIG_OMAP_REMOTEPROC_MODULE)
+
+void __init omap_rproc_reserve_cma(void);
+
+#else
+
+void __init omap_rproc_reserve_cma(void)
+{
+}
+
+#endif
+
+#endif /* _PLAT_REMOTEPROC_H */
index 198d1e6..b073e5f 100644 (file)
@@ -110,7 +110,6 @@ struct omap_board_data;
 struct omap_uart_port_info;
 
 extern void omap_serial_init(void);
-extern int omap_uart_can_sleep(void);
 extern void omap_serial_board_init(struct omap_uart_port_info *platform_data);
 extern void omap_serial_init_port(struct omap_board_data *bdata,
                struct omap_uart_port_info *platform_data);
index 75aa1b2..227ae26 100644 (file)
@@ -101,4 +101,5 @@ static inline void omap_push_sram_idle(void) {}
 #else
 #define OMAP4_SRAM_PA          0x40300000
 #endif
+#define AM33XX_SRAM_PA         0x40300000
 #endif
diff --git a/arch/arm/plat-omap/include/plat/system.h b/arch/arm/plat-omap/include/plat/system.h
deleted file mode 100644 (file)
index 8e5ebd7..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copied from arch/arm/mach-sa1100/include/mach/system.h
- * Copyright (c) 1999 Nicolas Pitre <nico@fluxnic.net>
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <asm/proc-fns.h>
-
-static inline void arch_idle(void)
-{
-       cpu_do_idle();
-}
-
-#endif
index d2fcd78..1b4b2da 100644 (file)
 #define EMIFS_CCS(n)           (EMIFS_CS0_CONFIG + (4 * (n)))
 #define EMIFS_ACS(n)           (EMIFS_ACS0 + (4 * (n)))
 
-/* Almost all documentation for chip and board memory maps assumes
- * BM is clear.  Most devel boards have a switch to control booting
- * from NOR flash (using external chipselect 3) rather than mask ROM,
- * which uses BM to interchange the physical CS0 and CS3 addresses.
- */
-static inline u32 omap_cs0_phys(void)
-{
-       return (omap_readl(EMIFS_CONFIG) & OMAP_EMIFS_CONFIG_BM)
-                       ?  OMAP_CS3_PHYS : 0;
-}
-
-static inline u32 omap_cs3_phys(void)
-{
-       return (omap_readl(EMIFS_CONFIG) & OMAP_EMIFS_CONFIG_BM)
-                       ? 0 : OMAP_CS3_PHYS;
-}
-
 #endif /* __ASSEMBLER__ */
 
 #endif /* __ASM_ARCH_TC_H */
index 6ee9049..cc3f11b 100644 (file)
@@ -160,6 +160,7 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
                DEBUG_LL_OMAP3(3, igep0020);
                DEBUG_LL_OMAP3(3, igep0030);
                DEBUG_LL_OMAP3(3, nokia_rm680);
+               DEBUG_LL_OMAP3(3, nokia_rm696);
                DEBUG_LL_OMAP3(3, nokia_rx51);
                DEBUG_LL_OMAP3(3, omap3517evm);
                DEBUG_LL_OMAP3(3, omap3_beagle);
index dc864b5..d0fc9f4 100644 (file)
@@ -3,6 +3,7 @@
 #ifndef        __ASM_ARCH_OMAP_USB_H
 #define        __ASM_ARCH_OMAP_USB_H
 
+#include <linux/io.h>
 #include <linux/usb/musb.h>
 #include <plat/board.h>
 
@@ -105,6 +106,46 @@ extern int omap4430_phy_set_clk(struct device *dev, int on);
 extern int omap4430_phy_init(struct device *dev);
 extern int omap4430_phy_exit(struct device *dev);
 extern int omap4430_phy_suspend(struct device *dev, int suspend);
+
+/*
+ * NOTE: Please update omap USB drivers to use ioremap + read/write
+ */
+
+#define OMAP2_L4_IO_OFFSET     0xb2000000
+#define IOMEM(x)               ((void __force __iomem *)(x))
+#define OMAP2_L4_IO_ADDRESS(pa)        IOMEM((pa) + OMAP2_L4_IO_OFFSET)
+
+static inline u8 omap_readb(u32 pa)
+{
+       return __raw_readb(OMAP2_L4_IO_ADDRESS(pa));
+}
+
+static inline u16 omap_readw(u32 pa)
+{
+       return __raw_readw(OMAP2_L4_IO_ADDRESS(pa));
+}
+
+static inline u32 omap_readl(u32 pa)
+{
+       return __raw_readl(OMAP2_L4_IO_ADDRESS(pa));
+}
+
+static inline void omap_writeb(u8 v, u32 pa)
+{
+       __raw_writeb(v, OMAP2_L4_IO_ADDRESS(pa));
+}
+
+
+static inline void omap_writew(u16 v, u32 pa)
+{
+       __raw_writew(v, OMAP2_L4_IO_ADDRESS(pa));
+}
+
+static inline void omap_writel(u32 v, u32 pa)
+{
+       __raw_writel(v, OMAP2_L4_IO_ADDRESS(pa));
+}
+
 #endif
 
 extern void am35x_musb_reset(void);
index ad80112..ad32621 100644 (file)
@@ -307,7 +307,7 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
        if (!--mbox->use_count) {
                free_irq(mbox->irq, mbox);
                tasklet_kill(&mbox->txq->tasklet);
-       flush_work_sync(&mbox->rxq->work);
+               flush_work_sync(&mbox->rxq->work);
                mbox_queue_free(mbox->txq);
                mbox_queue_free(mbox->rxq);
        }
index 976fc80..cff8712 100644 (file)
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
+
+#include <asm/system.h>
+
+#include <plat/cpu.h>
 #include <plat/mux.h>
 
 #ifdef CONFIG_OMAP_MUX
index 3dc3801..5a97b4d 100644 (file)
@@ -319,7 +319,7 @@ int omap_pm_get_dev_context_loss_count(struct device *dev)
        if (WARN_ON(!dev))
                return -ENODEV;
 
-       if (dev->parent == &omap_device_parent) {
+       if (dev->pm_domain == &omap_device_pm_domain) {
                count = omap_device_get_context_loss_count(pdev);
        } else {
                WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context loss counter; device %s should be converted to omap_device",
index e8d9869..d50cbc6 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * omap_device implementation
  *
 #define USE_WAKEUP_LAT                 0
 #define IGNORE_WAKEUP_LAT              1
 
-static int omap_device_register(struct platform_device *pdev);
 static int omap_early_device_register(struct platform_device *pdev);
-static struct omap_device *omap_device_alloc(struct platform_device *pdev,
-                                     struct omap_hwmod **ohs, int oh_cnt,
-                                     struct omap_device_pm_latency *pm_lats,
-                                     int pm_lats_cnt);
-static void omap_device_delete(struct omap_device *od);
-
 
 static struct omap_device_pm_latency omap_default_latency[] = {
        {
@@ -320,8 +314,6 @@ static void _add_hwmod_clocks_clkdev(struct omap_device *od,
 }
 
 
-static struct dev_pm_domain omap_device_pm_domain;
-
 /**
  * omap_device_build_from_dt - build an omap_device with multiple hwmods
  * @pdev_name: name of the platform_device driver to use
@@ -348,7 +340,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
 
        oh_cnt = of_property_count_strings(node, "ti,hwmods");
        if (!oh_cnt || IS_ERR_VALUE(oh_cnt)) {
-               dev_warn(&pdev->dev, "No 'hwmods' to build omap_device\n");
+               dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
                return -ENODEV;
        }
 
@@ -509,7 +501,7 @@ static int omap_device_fill_resources(struct omap_device *od,
  *
  * Returns an struct omap_device pointer or ERR_PTR() on error;
  */
-static struct omap_device *omap_device_alloc(struct platform_device *pdev,
+struct omap_device *omap_device_alloc(struct platform_device *pdev,
                                        struct omap_hwmod **ohs, int oh_cnt,
                                        struct omap_device_pm_latency *pm_lats,
                                        int pm_lats_cnt)
@@ -591,7 +583,7 @@ oda_exit1:
        return ERR_PTR(ret);
 }
 
-static void omap_device_delete(struct omap_device *od)
+void omap_device_delete(struct omap_device *od)
 {
        if (!od)
                return;
@@ -619,7 +611,7 @@ static void omap_device_delete(struct omap_device *od)
  * information.  Returns ERR_PTR(-EINVAL) if @oh is NULL; otherwise,
  * passes along the return value of omap_device_build_ss().
  */
-struct platform_device *omap_device_build(const char *pdev_name, int pdev_id,
+struct platform_device __init *omap_device_build(const char *pdev_name, int pdev_id,
                                      struct omap_hwmod *oh, void *pdata,
                                      int pdata_len,
                                      struct omap_device_pm_latency *pm_lats,
@@ -652,7 +644,7 @@ struct platform_device *omap_device_build(const char *pdev_name, int pdev_id,
  * platform_device record.  Returns an ERR_PTR() on error, or passes
  * along the return value of omap_device_register().
  */
-struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
+struct platform_device __init *omap_device_build_ss(const char *pdev_name, int pdev_id,
                                         struct omap_hwmod **ohs, int oh_cnt,
                                         void *pdata, int pdata_len,
                                         struct omap_device_pm_latency *pm_lats,
@@ -717,7 +709,7 @@ odbs_exit:
  * platform_early_add_device() on the underlying platform_device.
  * Returns 0 by default.
  */
-static int omap_early_device_register(struct platform_device *pdev)
+static int __init omap_early_device_register(struct platform_device *pdev)
 {
        struct platform_device *devices[1];
 
@@ -762,14 +754,12 @@ static int _od_suspend_noirq(struct device *dev)
        struct omap_device *od = to_omap_device(pdev);
        int ret;
 
-       if (od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND)
-               return pm_generic_suspend_noirq(dev);
-
        ret = pm_generic_suspend_noirq(dev);
 
        if (!ret && !pm_runtime_status_suspended(dev)) {
                if (pm_generic_runtime_suspend(dev) == 0) {
-                       omap_device_idle(pdev);
+                       if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND))
+                               omap_device_idle(pdev);
                        od->flags |= OMAP_DEVICE_SUSPENDED;
                }
        }
@@ -782,13 +772,11 @@ static int _od_resume_noirq(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_device *od = to_omap_device(pdev);
 
-       if (od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND)
-               return pm_generic_resume_noirq(dev);
-
        if ((od->flags & OMAP_DEVICE_SUSPENDED) &&
            !pm_runtime_status_suspended(dev)) {
                od->flags &= ~OMAP_DEVICE_SUSPENDED;
-               omap_device_enable(pdev);
+               if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND))
+                       omap_device_enable(pdev);
                pm_generic_runtime_resume(dev);
        }
 
@@ -799,7 +787,7 @@ static int _od_resume_noirq(struct device *dev)
 #define _od_resume_noirq NULL
 #endif
 
-static struct dev_pm_domain omap_device_pm_domain = {
+struct dev_pm_domain omap_device_pm_domain = {
        .ops = {
                SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
                                   _od_runtime_idle)
@@ -817,11 +805,10 @@ static struct dev_pm_domain omap_device_pm_domain = {
  * platform_device_register() on the underlying platform_device.
  * Returns the return value of platform_device_register().
  */
-static int omap_device_register(struct platform_device *pdev)
+int omap_device_register(struct platform_device *pdev)
 {
        pr_debug("omap_device: %s: registering\n", pdev->name);
 
-       pdev->dev.parent = &omap_device_parent;
        pdev->dev.pm_domain = &omap_device_pm_domain;
        return platform_device_add(pdev);
 }
@@ -1130,11 +1117,6 @@ int omap_device_enable_clocks(struct omap_device *od)
        return 0;
 }
 
-struct device omap_device_parent = {
-       .init_name      = "omap",
-       .parent         = &platform_bus,
-};
-
 static struct notifier_block platform_nb = {
        .notifier_call = _omap_device_notifier_call,
 };
@@ -1142,6 +1124,6 @@ static struct notifier_block platform_nb = {
 static int __init omap_device_init(void)
 {
        bus_register_notifier(&platform_bus_type, &platform_nb);
-       return device_register(&omap_device_parent);
+       return 0;
 }
 core_initcall(omap_device_init);
index 4243bdc..eec98af 100644 (file)
 
 #include "sram.h"
 
-/* XXX These "sideways" includes are a sign that something is wrong */
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-# include "../mach-omap2/prm2xxx_3xxx.h"
-# include "../mach-omap2/sdrc.h"
-#endif
+/* XXX These "sideways" includes will disappear when sram.c becomes a driver */
+#include "../mach-omap2/iomap.h"
+#include "../mach-omap2/prm2xxx_3xxx.h"
+#include "../mach-omap2/sdrc.h"
 
 #define OMAP1_SRAM_PA          0x20000000
 #define OMAP2_SRAM_PUB_PA      (OMAP2_SRAM_PA + 0xf800)
@@ -86,7 +85,7 @@ static int is_sram_locked(void)
                        __raw_writel(0xCFDE, OMAP24XX_VA_READPERM0);  /* all i-read */
                        __raw_writel(0xCFDE, OMAP24XX_VA_WRITEPERM0); /* all i-write */
                }
-               if (cpu_is_omap34xx()) {
+               if (cpu_is_omap34xx() && !cpu_is_am33xx()) {
                        __raw_writel(0xFFFF, OMAP34XX_VA_REQINFOPERM0); /* all q-vects */
                        __raw_writel(0xFFFF, OMAP34XX_VA_READPERM0);  /* all i-read */
                        __raw_writel(0xFFFF, OMAP34XX_VA_WRITEPERM0); /* all i-write */
@@ -124,7 +123,10 @@ static void __init omap_detect_sram(void)
                                omap_sram_size = 0x800; /* 2K */
                        }
                } else {
-                       if (cpu_is_omap34xx()) {
+                       if (cpu_is_am33xx()) {
+                               omap_sram_start = AM33XX_SRAM_PA;
+                               omap_sram_size = 0x10000; /* 64K */
+                       } else if (cpu_is_omap34xx()) {
                                omap_sram_start = OMAP3_SRAM_PA;
                                omap_sram_size = 0x10000; /* 64K */
                        } else if (cpu_is_omap44xx()) {
@@ -368,6 +370,11 @@ static inline int omap34xx_sram_init(void)
        return 0;
 }
 
+static inline int am33xx_sram_init(void)
+{
+       return 0;
+}
+
 int __init omap_sram_init(void)
 {
        omap_detect_sram();
@@ -379,6 +386,8 @@ int __init omap_sram_init(void)
                omap242x_sram_init();
        else if (cpu_is_omap2430())
                omap243x_sram_init();
+       else if (cpu_is_am33xx())
+               am33xx_sram_init();
        else if (cpu_is_omap34xx())
                omap34xx_sram_init();
 
index f357088..d2bbfd1 100644 (file)
 #include <plat/usb.h>
 #include <plat/board.h>
 
+#include <mach/hardware.h>
+
+#include "../mach-omap2/common.h"
+
 #ifdef CONFIG_ARCH_OMAP_OTG
 
 void __init
index 089899a..74daf5e 100644 (file)
@@ -21,6 +21,7 @@
 #include <plat/orion_wdt.h>
 #include <plat/mv_xor.h>
 #include <plat/ehci-orion.h>
+#include <mach/bridge-regs.h>
 
 /* Fill in the resources structure and link it into the platform
    device structure. There is always a memory region, and nearly
@@ -568,13 +569,17 @@ void __init orion_spi_1_init(unsigned long mapbase,
  ****************************************************************************/
 static struct orion_wdt_platform_data orion_wdt_data;
 
+static struct resource orion_wdt_resource =
+               DEFINE_RES_MEM(TIMER_VIRT_BASE, 0x28);
+
 static struct platform_device orion_wdt_device = {
        .name           = "orion_wdt",
        .id             = -1,
        .dev            = {
                .platform_data  = &orion_wdt_data,
        },
-       .num_resources  = 0,
+       .resource       = &orion_wdt_resource,
+       .num_resources  = 1,
 };
 
 void __init orion_wdt_init(unsigned long tclk)
index 885f8ab..d6a55bd 100644 (file)
@@ -2,7 +2,6 @@
 #define __PLAT_AUDIO_H
 
 struct kirkwood_asoc_platform_data {
-       u32 tclk;
        int burst;
 };
 #endif
index d8973ac..21bf6ad 100644 (file)
@@ -4,7 +4,7 @@
 
 config PLAT_S3C24XX
        bool
-       depends on ARCH_S3C2410
+       depends on ARCH_S3C24XX
        default y
        select NO_IOPORT
        select ARCH_REQUIRE_GPIOLIB
@@ -44,12 +44,6 @@ config S3C2410_CLOCK
          Clock code for the S3C2410, and similar processors which
          is currently includes the S3C2410, S3C2440, S3C2442.
 
-config S3C2443_CLOCK
-       bool
-       help
-         Clock code for the S3C2443 and similar processors, which includes
-         the S3C2416 and S3C2450.
-
 config S3C24XX_DCLK
        bool
        help
@@ -76,15 +70,9 @@ config S3C24XX_GPIO_EXTRA128
          Add an extra 128 gpio numbers to the available GPIO pool. This is
          available for boards that need extra gpios for external devices.
 
-config PM_SIMTEC
-       bool
-       help
-         Common power management code for systems that are
-         compatible with the Simtec style of power management
-
-config S3C2410_DMA
+config S3C24XX_DMA
        bool "S3C2410 DMA support"
-       depends on ARCH_S3C2410
+       depends on ARCH_S3C24XX
        select S3C_DMA
        help
          S3C2410 DMA support. This is needed for drivers like sound which
@@ -93,31 +81,11 @@ config S3C2410_DMA
 
 config S3C2410_DMA_DEBUG
        bool "S3C2410 DMA support debug"
-       depends on ARCH_S3C2410 && S3C2410_DMA
+       depends on ARCH_S3C24XX && S3C2410_DMA
        help
          Enable debugging output for the DMA code. This option sends info
          to the kernel log, at priority KERN_DEBUG.
 
-# SPI default pin configuration code
-
-config S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13
-       bool
-       help
-         SPI GPIO configuration code for BUS0 when connected to
-         GPE11, GPE12 and GPE13.
-
-config S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7
-       bool
-       help
-         SPI GPIO configuration code for BUS 1 when connected to
-         GPG5, GPG6 and GPG7.
-
-config S3C24XX_SPI_BUS1_GPD8_GPD9_GPD10
-       bool
-       help
-         SPI GPIO configuration code for BUS 1 when connected to
-         GPD8, GPD9 and GPD10.
-
 # common code for s3c24xx based machines, such as the SMDKs.
 
 # cpu frequency items common between s3c2410 and s3c2440/s3c2442
@@ -145,21 +113,4 @@ config S3C2412_IOTIMING
          Intel node to select io timing code that is common to the s3c2412
          and the s3c2443.
 
-config MACH_SMDK
-       bool
-       help
-         Common machine code for SMDK2410 and SMDK2440
-
-config S3C24XX_SIMTEC_AUDIO
-       bool
-       depends on (ARCH_BAST || MACH_VR1000 || MACH_OSIRIS || MACH_ANUBIS)
-       default y
-       help
-         Add audio devices for common Simtec S3C24XX boards
-
-config S3C2410_SETUP_TS
-       bool
-       help
-         Compile in platform device definition for Samsung TouchScreen.
-
 endif
index b2b0112..2467b80 100644 (file)
@@ -23,28 +23,11 @@ obj-$(CONFIG_CPU_FREQ_S3C24XX_DEBUGFS) += cpu-freq-debugfs.o
 
 # Architecture dependent builds
 
-obj-$(CONFIG_PM_SIMTEC)                += pm-simtec.o
 obj-$(CONFIG_PM)               += pm.o
 obj-$(CONFIG_PM)               += irq-pm.o
 obj-$(CONFIG_PM)               += sleep.o
 obj-$(CONFIG_S3C2410_CLOCK)    += s3c2410-clock.o
-obj-$(CONFIG_S3C2443_CLOCK)    += s3c2443-clock.o
-obj-$(CONFIG_S3C2410_DMA)      += dma.o
+obj-$(CONFIG_S3C24XX_DMA)      += dma.o
 obj-$(CONFIG_S3C2410_IOTIMING) += s3c2410-iotiming.o
 obj-$(CONFIG_S3C2412_IOTIMING) += s3c2412-iotiming.o
 obj-$(CONFIG_S3C2410_CPUFREQ_UTILS) += s3c2410-cpufreq-utils.o
-
-# device specific setup and/or initialisation
-obj-$(CONFIG_ARCH_S3C2410)     += setup-i2c.o
-obj-$(CONFIG_S3C2410_SETUP_TS) += setup-ts.o
-
-# SPI gpio central GPIO functions
-
-obj-$(CONFIG_S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13) += spi-bus0-gpe11_12_13.o
-obj-$(CONFIG_S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7)    += spi-bus1-gpg5_6_7.o
-obj-$(CONFIG_S3C24XX_SPI_BUS1_GPD8_GPD9_GPD10)  += spi-bus1-gpd8_9_10.o
-
-# machine common support
-
-obj-$(CONFIG_MACH_SMDK)                += common-smdk.o
-obj-$(CONFIG_S3C24XX_SIMTEC_AUDIO)     += simtec-audio.o
diff --git a/arch/arm/plat-s3c24xx/common-smdk.c b/arch/arm/plat-s3c24xx/common-smdk.c
deleted file mode 100644 (file)
index 084604b..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/common-smdk.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Common code for SMDK2410 and SMDK2440 boards
- *
- * http://www.fluff.org/ben/smdk2440/
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/leds-gpio.h>
-
-#include <plat/nand.h>
-
-#include <plat/common-smdk.h>
-#include <plat/gpio-cfg.h>
-#include <plat/devs.h>
-#include <plat/pm.h>
-
-/* LED devices */
-
-static struct s3c24xx_led_platdata smdk_pdata_led4 = {
-       .gpio           = S3C2410_GPF(4),
-       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
-       .name           = "led4",
-       .def_trigger    = "timer",
-};
-
-static struct s3c24xx_led_platdata smdk_pdata_led5 = {
-       .gpio           = S3C2410_GPF(5),
-       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
-       .name           = "led5",
-       .def_trigger    = "nand-disk",
-};
-
-static struct s3c24xx_led_platdata smdk_pdata_led6 = {
-       .gpio           = S3C2410_GPF(6),
-       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
-       .name           = "led6",
-};
-
-static struct s3c24xx_led_platdata smdk_pdata_led7 = {
-       .gpio           = S3C2410_GPF(7),
-       .flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
-       .name           = "led7",
-};
-
-static struct platform_device smdk_led4 = {
-       .name           = "s3c24xx_led",
-       .id             = 0,
-       .dev            = {
-               .platform_data = &smdk_pdata_led4,
-       },
-};
-
-static struct platform_device smdk_led5 = {
-       .name           = "s3c24xx_led",
-       .id             = 1,
-       .dev            = {
-               .platform_data = &smdk_pdata_led5,
-       },
-};
-
-static struct platform_device smdk_led6 = {
-       .name           = "s3c24xx_led",
-       .id             = 2,
-       .dev            = {
-               .platform_data = &smdk_pdata_led6,
-       },
-};
-
-static struct platform_device smdk_led7 = {
-       .name           = "s3c24xx_led",
-       .id             = 3,
-       .dev            = {
-               .platform_data = &smdk_pdata_led7,
-       },
-};
-
-/* NAND parititon from 2.4.18-swl5 */
-
-static struct mtd_partition smdk_default_nand_part[] = {
-       [0] = {
-               .name   = "Boot Agent",
-               .size   = SZ_16K,
-               .offset = 0,
-       },
-       [1] = {
-               .name   = "S3C2410 flash partition 1",
-               .offset = 0,
-               .size   = SZ_2M,
-       },
-       [2] = {
-               .name   = "S3C2410 flash partition 2",
-               .offset = SZ_4M,
-               .size   = SZ_4M,
-       },
-       [3] = {
-               .name   = "S3C2410 flash partition 3",
-               .offset = SZ_8M,
-               .size   = SZ_2M,
-       },
-       [4] = {
-               .name   = "S3C2410 flash partition 4",
-               .offset = SZ_1M * 10,
-               .size   = SZ_4M,
-       },
-       [5] = {
-               .name   = "S3C2410 flash partition 5",
-               .offset = SZ_1M * 14,
-               .size   = SZ_1M * 10,
-       },
-       [6] = {
-               .name   = "S3C2410 flash partition 6",
-               .offset = SZ_1M * 24,
-               .size   = SZ_1M * 24,
-       },
-       [7] = {
-               .name   = "S3C2410 flash partition 7",
-               .offset = SZ_1M * 48,
-               .size   = MTDPART_SIZ_FULL,
-       }
-};
-
-static struct s3c2410_nand_set smdk_nand_sets[] = {
-       [0] = {
-               .name           = "NAND",
-               .nr_chips       = 1,
-               .nr_partitions  = ARRAY_SIZE(smdk_default_nand_part),
-               .partitions     = smdk_default_nand_part,
-       },
-};
-
-/* choose a set of timings which should suit most 512Mbit
- * chips and beyond.
-*/
-
-static struct s3c2410_platform_nand smdk_nand_info = {
-       .tacls          = 20,
-       .twrph0         = 60,
-       .twrph1         = 20,
-       .nr_sets        = ARRAY_SIZE(smdk_nand_sets),
-       .sets           = smdk_nand_sets,
-};
-
-/* devices we initialise */
-
-static struct platform_device __initdata *smdk_devs[] = {
-       &s3c_device_nand,
-       &smdk_led4,
-       &smdk_led5,
-       &smdk_led6,
-       &smdk_led7,
-};
-
-void __init smdk_machine_init(void)
-{
-       /* Configure the LEDs (even if we have no LED support)*/
-
-       s3c_gpio_cfgpin(S3C2410_GPF(4), S3C2410_GPIO_OUTPUT);
-       s3c_gpio_cfgpin(S3C2410_GPF(5), S3C2410_GPIO_OUTPUT);
-       s3c_gpio_cfgpin(S3C2410_GPF(6), S3C2410_GPIO_OUTPUT);
-       s3c_gpio_cfgpin(S3C2410_GPF(7), S3C2410_GPIO_OUTPUT);
-
-       s3c2410_gpio_setpin(S3C2410_GPF(4), 1);
-       s3c2410_gpio_setpin(S3C2410_GPF(5), 1);
-       s3c2410_gpio_setpin(S3C2410_GPF(6), 1);
-       s3c2410_gpio_setpin(S3C2410_GPF(7), 1);
-
-       if (machine_is_smdk2443())
-               smdk_nand_info.twrph0 = 50;
-
-       s3c_nand_set_platdata(&smdk_nand_info);
-
-       platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));
-
-       s3c_pm_init();
-}
index ded6431..0db73ae 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/io.h>
 
 #include <mach/hardware.h>
+#include <mach/regs-clock.h>
 #include <asm/irq.h>
 #include <asm/cacheflush.h>
 #include <asm/system_info.h>
@@ -191,8 +192,34 @@ static unsigned long s3c24xx_read_idcode_v4(void)
        return __raw_readl(S3C2410_GSTATUS1);
 }
 
+static void s3c24xx_default_idle(void)
+{
+       unsigned long tmp;
+       int i;
+
+       /* idle the system by using the idle mode which will wait for an
+        * interrupt to happen before restarting the system.
+        */
+
+       /* Warning: going into idle state upsets jtag scanning */
+
+       __raw_writel(__raw_readl(S3C2410_CLKCON) | S3C2410_CLKCON_IDLE,
+                    S3C2410_CLKCON);
+
+       /* the samsung port seems to do a loop and then unset idle.. */
+       for (i = 0; i < 50; i++)
+               tmp += __raw_readl(S3C2410_CLKCON); /* ensure loop not optimised out */
+
+       /* this bit is not cleared on re-start... */
+
+       __raw_writel(__raw_readl(S3C2410_CLKCON) & ~S3C2410_CLKCON_IDLE,
+                    S3C2410_CLKCON);
+}
+
 void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
 {
+       arm_pm_idle = s3c24xx_default_idle;
+
        /* initialise the io descriptors we need for initialisation */
        iotable_init(mach_desc, size);
        iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
diff --git a/arch/arm/plat-s3c24xx/pm-simtec.c b/arch/arm/plat-s3c24xx/pm-simtec.c
deleted file mode 100644 (file)
index 699f931..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/pm-simtec.c
- *
- * Copyright 2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * http://armlinux.simtec.co.uk/
- *
- * Power Management helpers for Simtec S3C24XX implementations
- *
- * 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/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
-
-#include <mach/map.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-mem.h>
-
-#include <asm/mach-types.h>
-
-#include <plat/pm.h>
-
-#define COPYRIGHT ", Copyright 2005 Simtec Electronics"
-
-/* pm_simtec_init
- *
- * enable the power management functions
-*/
-
-static __init int pm_simtec_init(void)
-{
-       unsigned long gstatus4;
-
-       /* check which machine we are running on */
-
-       if (!machine_is_bast() && !machine_is_vr1000() &&
-           !machine_is_anubis() && !machine_is_osiris() &&
-           !machine_is_aml_m5900())
-               return 0;
-
-       printk(KERN_INFO "Simtec Board Power Management" COPYRIGHT "\n");
-
-       gstatus4  = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30;
-       gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28;
-       gstatus4 |= (__raw_readl(S3C2410_BANKSIZE) & S3C2410_BANKSIZE_MASK);
-
-       __raw_writel(gstatus4, S3C2410_GSTATUS4);
-
-       return s3c_pm_init();
-}
-
-arch_initcall(pm_simtec_init);
diff --git a/arch/arm/plat-s3c24xx/s3c2443-clock.c b/arch/arm/plat-s3c24xx/s3c2443-clock.c
deleted file mode 100644 (file)
index 95e6819..0000000
+++ /dev/null
@@ -1,636 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/s3c2443-clock.c
- *
- * Copyright (c) 2007, 2010 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2443 Clock control suport - common code
- */
-
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/regs-s3c2443-clock.h>
-
-#include <plat/s3c2443.h>
-#include <plat/clock.h>
-#include <plat/clock-clksrc.h>
-#include <plat/cpu.h>
-
-#include <plat/cpu-freq.h>
-
-
-static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
-{
-       u32 ctrlbit = clk->ctrlbit;
-       u32 con = __raw_readl(reg);
-
-       if (enable)
-               con |= ctrlbit;
-       else
-               con &= ~ctrlbit;
-
-       __raw_writel(con, reg);
-       return 0;
-}
-
-int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
-{
-       return s3c2443_gate(S3C2443_HCLKCON, clk, enable);
-}
-
-int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
-{
-       return s3c2443_gate(S3C2443_PCLKCON, clk, enable);
-}
-
-int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
-{
-       return s3c2443_gate(S3C2443_SCLKCON, clk, enable);
-}
-
-/* mpllref is a direct descendant of clk_xtal by default, but it is not
- * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as
- * such directly equating the two source clocks is impossible.
- */
-struct clk clk_mpllref = {
-       .name           = "mpllref",
-       .parent         = &clk_xtal,
-};
-
-static struct clk *clk_epllref_sources[] = {
-       [0] = &clk_mpllref,
-       [1] = &clk_mpllref,
-       [2] = &clk_xtal,
-       [3] = &clk_ext,
-};
-
-struct clksrc_clk clk_epllref = {
-       .clk    = {
-               .name           = "epllref",
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = clk_epllref_sources,
-               .nr_sources = ARRAY_SIZE(clk_epllref_sources),
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
-};
-
-/* esysclk
- *
- * this is sourced from either the EPLL or the EPLLref clock
-*/
-
-static struct clk *clk_sysclk_sources[] = {
-       [0] = &clk_epllref.clk,
-       [1] = &clk_epll,
-};
-
-struct clksrc_clk clk_esysclk = {
-       .clk    = {
-               .name           = "esysclk",
-               .parent         = &clk_epll,
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = clk_sysclk_sources,
-               .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
-};
-
-static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
-{
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long div = __raw_readl(S3C2443_CLKDIV0);
-
-       div  &= S3C2443_CLKDIV0_EXTDIV_MASK;
-       div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1);       /* x2 */
-
-       return parent_rate / (div + 1);
-}
-
-static struct clk clk_mdivclk = {
-       .name           = "mdivclk",
-       .parent         = &clk_mpllref,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2443_getrate_mdivclk,
-       },
-};
-
-static struct clk *clk_msysclk_sources[] = {
-       [0] = &clk_mpllref,
-       [1] = &clk_mpll,
-       [2] = &clk_mdivclk,
-       [3] = &clk_mpllref,
-};
-
-struct clksrc_clk clk_msysclk = {
-       .clk    = {
-               .name           = "msysclk",
-               .parent         = &clk_xtal,
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = clk_msysclk_sources,
-               .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
-};
-
-/* prediv
- *
- * this divides the msysclk down to pass to h/p/etc.
- */
-
-static unsigned long s3c2443_prediv_getrate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
-
-       clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
-       clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
-
-       return rate / (clkdiv0 + 1);
-}
-
-static struct clk clk_prediv = {
-       .name           = "prediv",
-       .parent         = &clk_msysclk.clk,
-       .ops            = &(struct clk_ops) {
-               .get_rate       = s3c2443_prediv_getrate,
-       },
-};
-
-/* armdiv
- *
- * this clock is sourced from msysclk and can have a number of
- * divider values applied to it to then be fed into armclk.
-*/
-
-static unsigned int *armdiv;
-static int nr_armdiv;
-static int armdivmask;
-
-static unsigned long s3c2443_armclk_roundrate(struct clk *clk,
-                                             unsigned long rate)
-{
-       unsigned long parent = clk_get_rate(clk->parent);
-       unsigned long calc;
-       unsigned best = 256; /* bigger than any value */
-       unsigned div;
-       int ptr;
-
-       if (!nr_armdiv)
-               return -EINVAL;
-
-       for (ptr = 0; ptr < nr_armdiv; ptr++) {
-               div = armdiv[ptr];
-               if (div) {
-                       /* cpufreq provides 266mhz as 266666000 not 266666666 */
-                       calc = (parent / div / 1000) * 1000;
-                       if (calc <= rate && div < best)
-                               best = div;
-               }
-       }
-
-       return parent / best;
-}
-
-static unsigned long s3c2443_armclk_getrate(struct clk *clk)
-{
-       unsigned long rate = clk_get_rate(clk->parent);
-       unsigned long clkcon0;
-       int val;
-
-       if (!nr_armdiv || !armdivmask)
-               return -EINVAL;
-
-       clkcon0 = __raw_readl(S3C2443_CLKDIV0);
-       clkcon0 &= armdivmask;
-       val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT;
-
-       return rate / armdiv[val];
-}
-
-static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
-{
-       unsigned long parent = clk_get_rate(clk->parent);
-       unsigned long calc;
-       unsigned div;
-       unsigned best = 256; /* bigger than any value */
-       int ptr;
-       int val = -1;
-
-       if (!nr_armdiv || !armdivmask)
-               return -EINVAL;
-
-       for (ptr = 0; ptr < nr_armdiv; ptr++) {
-               div = armdiv[ptr];
-               if (div) {
-                       /* cpufreq provides 266mhz as 266666000 not 266666666 */
-                       calc = (parent / div / 1000) * 1000;
-                       if (calc <= rate && div < best) {
-                               best = div;
-                               val = ptr;
-                       }
-               }
-       }
-
-       if (val >= 0) {
-               unsigned long clkcon0;
-
-               clkcon0 = __raw_readl(S3C2443_CLKDIV0);
-               clkcon0 &= ~armdivmask;
-               clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
-               __raw_writel(clkcon0, S3C2443_CLKDIV0);
-       }
-
-       return (val == -1) ? -EINVAL : 0;
-}
-
-static struct clk clk_armdiv = {
-       .name           = "armdiv",
-       .parent         = &clk_msysclk.clk,
-       .ops            = &(struct clk_ops) {
-               .round_rate = s3c2443_armclk_roundrate,
-               .get_rate = s3c2443_armclk_getrate,
-               .set_rate = s3c2443_armclk_setrate,
-       },
-};
-
-/* armclk
- *
- * this is the clock fed into the ARM core itself, from armdiv or from hclk.
- */
-
-static struct clk *clk_arm_sources[] = {
-       [0] = &clk_armdiv,
-       [1] = &clk_h,
-};
-
-static struct clksrc_clk clk_arm = {
-       .clk    = {
-               .name           = "armclk",
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = clk_arm_sources,
-               .nr_sources = ARRAY_SIZE(clk_arm_sources),
-       },
-       .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
-};
-
-/* usbhost
- *
- * usb host bus-clock, usually 48MHz to provide USB bus clock timing
-*/
-
-static struct clksrc_clk clk_usb_bus_host = {
-       .clk    = {
-               .name           = "usb-bus-host-parent",
-               .parent         = &clk_esysclk.clk,
-               .ctrlbit        = S3C2443_SCLKCON_USBHOST,
-               .enable         = s3c2443_clkcon_enable_s,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
-};
-
-/* common clksrc clocks */
-
-static struct clksrc_clk clksrc_clks[] = {
-       {
-               /* camera interface bus-clock, divided down from esysclk */
-               .clk    = {
-                       .name           = "camif-upll", /* same as 2440 name */
-                       .parent         = &clk_esysclk.clk,
-                       .ctrlbit        = S3C2443_SCLKCON_CAMCLK,
-                       .enable         = s3c2443_clkcon_enable_s,
-               },
-               .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
-       }, {
-               .clk    = {
-                       .name           = "display-if",
-                       .parent         = &clk_esysclk.clk,
-                       .ctrlbit        = S3C2443_SCLKCON_DISPCLK,
-                       .enable         = s3c2443_clkcon_enable_s,
-               },
-               .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
-       },
-};
-
-static struct clksrc_clk clk_esys_uart = {
-       /* ART baud-rate clock sourced from esysclk via a divisor */
-       .clk    = {
-               .name           = "uartclk",
-               .parent         = &clk_esysclk.clk,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
-};
-
-static struct clk clk_i2s_ext = {
-       .name           = "i2s-ext",
-};
-
-/* i2s_eplldiv
- *
- * This clock is the output from the I2S divisor of ESYSCLK, and is separate
- * from the mux that comes after it (cannot merge into one single clock)
-*/
-
-static struct clksrc_clk clk_i2s_eplldiv = {
-       .clk    = {
-               .name           = "i2s-eplldiv",
-               .parent         = &clk_esysclk.clk,
-       },
-       .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
-};
-
-/* i2s-ref
- *
- * i2s bus reference clock, selectable from external, esysclk or epllref
- *
- * Note, this used to be two clocks, but was compressed into one.
-*/
-
-static struct clk *clk_i2s_srclist[] = {
-       [0] = &clk_i2s_eplldiv.clk,
-       [1] = &clk_i2s_ext,
-       [2] = &clk_epllref.clk,
-       [3] = &clk_epllref.clk,
-};
-
-static struct clksrc_clk clk_i2s = {
-       .clk    = {
-               .name           = "i2s-if",
-               .ctrlbit        = S3C2443_SCLKCON_I2SCLK,
-               .enable         = s3c2443_clkcon_enable_s,
-
-       },
-       .sources = &(struct clksrc_sources) {
-               .sources = clk_i2s_srclist,
-               .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
-       },
-       .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
-};
-
-static struct clk init_clocks_off[] = {
-       {
-               .name           = "iis",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_IIS,
-       }, {
-               .name           = "hsspi",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_HSSPI,
-       }, {
-               .name           = "adc",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_ADC,
-       }, {
-               .name           = "i2c",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_IIC,
-       }
-};
-
-static struct clk init_clocks[] = {
-       {
-               .name           = "dma",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA0,
-       }, {
-               .name           = "dma",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA1,
-       }, {
-               .name           = "dma",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA2,
-       }, {
-               .name           = "dma",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA3,
-       }, {
-               .name           = "dma",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA4,
-       }, {
-               .name           = "dma",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_DMA5,
-       }, {
-               .name           = "gpio",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_GPIO,
-       }, {
-               .name           = "usb-host",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_USBH,
-       }, {
-               .name           = "usb-device",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_USBD,
-       }, {
-               .name           = "lcd",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_LCDC,
-
-       }, {
-               .name           = "timers",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_PWMT,
-       }, {
-               .name           = "cfc",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_CFC,
-       }, {
-               .name           = "ssmc",
-               .parent         = &clk_h,
-               .enable         = s3c2443_clkcon_enable_h,
-               .ctrlbit        = S3C2443_HCLKCON_SSMC,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2440-uart.0",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_UART0,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2440-uart.1",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_UART1,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2440-uart.2",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_UART2,
-       }, {
-               .name           = "uart",
-               .devname        = "s3c2440-uart.3",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_UART3,
-       }, {
-               .name           = "rtc",
-               .parent         = &clk_p,
-               .enable         = s3c2443_clkcon_enable_p,
-               .ctrlbit        = S3C2443_PCLKCON_RTC,
-       }, {
-               .name           = "watchdog",
-               .parent         = &clk_p,
-               .ctrlbit        = S3C2443_PCLKCON_WDT,
-       }, {
-               .name           = "ac97",
-               .parent         = &clk_p,
-               .ctrlbit        = S3C2443_PCLKCON_AC97,
-       }, {
-               .name           = "nand",
-               .parent         = &clk_h,
-       }, {
-               .name           = "usb-bus-host",
-               .parent         = &clk_usb_bus_host.clk,
-       }
-};
-
-static struct clk hsmmc1_clk = {
-       .name           = "hsmmc",
-       .devname        = "s3c-sdhci.1",
-       .parent         = &clk_h,
-       .enable         = s3c2443_clkcon_enable_h,
-       .ctrlbit        = S3C2443_HCLKCON_HSMMC,
-};
-
-static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
-{
-       clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
-
-       return clkcon0 + 1;
-}
-
-/* EPLLCON compatible enough to get on/off information */
-
-void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll)
-{
-       unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
-       unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
-       unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
-       struct clk *xtal_clk;
-       unsigned long xtal;
-       unsigned long pll;
-       unsigned long fclk;
-       unsigned long hclk;
-       unsigned long pclk;
-       int ptr;
-
-       xtal_clk = clk_get(NULL, "xtal");
-       xtal = clk_get_rate(xtal_clk);
-       clk_put(xtal_clk);
-
-       pll = get_mpll(mpllcon, xtal);
-       clk_msysclk.clk.rate = pll;
-
-       fclk = clk_get_rate(&clk_armdiv);
-       hclk = s3c2443_prediv_getrate(&clk_prediv);
-       hclk /= s3c2443_get_hdiv(clkdiv0);
-       pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
-
-       s3c24xx_setup_clocks(fclk, hclk, pclk);
-
-       printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
-              (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
-              print_mhz(pll), print_mhz(fclk),
-              print_mhz(hclk), print_mhz(pclk));
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++)
-               s3c_set_clksrc(&clksrc_clks[ptr], true);
-
-       /* ensure usb bus clock is within correct rate of 48MHz */
-
-       if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
-               printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
-               clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
-       }
-
-       printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
-              (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
-              print_mhz(clk_get_rate(&clk_epll)),
-              print_mhz(clk_get_rate(&clk_usb_bus)));
-}
-
-static struct clk *clks[] __initdata = {
-       &clk_prediv,
-       &clk_mpllref,
-       &clk_mdivclk,
-       &clk_ext,
-       &clk_epll,
-       &clk_usb_bus,
-       &clk_armdiv,
-       &hsmmc1_clk,
-};
-
-static struct clksrc_clk *clksrcs[] __initdata = {
-       &clk_i2s_eplldiv,
-       &clk_i2s,
-       &clk_usb_bus_host,
-       &clk_epllref,
-       &clk_esysclk,
-       &clk_msysclk,
-       &clk_arm,
-};
-
-static struct clk_lookup s3c2443_clk_lookup[] = {
-       CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
-       CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
-       CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk),
-       CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk),
-};
-
-void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
-                                      unsigned int *divs, int nr_divs,
-                                      int divmask)
-{
-       int ptr;
-
-       armdiv = divs;
-       nr_armdiv = nr_divs;
-       armdivmask = divmask;
-
-       /* s3c2443 parents h and p clocks from prediv */
-       clk_h.parent = &clk_prediv;
-       clk_p.parent = &clk_prediv;
-
-       clk_usb_bus.parent = &clk_usb_bus_host.clk;
-       clk_epll.parent = &clk_epllref.clk;
-
-       s3c24xx_register_baseclocks(xtal);
-       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-               s3c_register_clksrc(clksrcs[ptr], 1);
-
-       s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks));
-       s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
-
-       /* See s3c2443/etc notes on disabling clocks at init time */
-       s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-       s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
-       clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup));
-
-       s3c2443_common_setup_clocks(get_mpll);
-}
diff --git a/arch/arm/plat-s3c24xx/setup-i2c.c b/arch/arm/plat-s3c24xx/setup-i2c.c
deleted file mode 100644 (file)
index 9e90a7c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/setup-i2c.c
- *
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C24XX Base setup for i2c device
- *
- * 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/gpio.h>
-
-struct platform_device;
-
-#include <plat/gpio-cfg.h>
-#include <plat/iic.h>
-#include <mach/hardware.h>
-#include <mach/regs-gpio.h>
-
-void s3c_i2c0_cfg_gpio(struct platform_device *dev)
-{
-       s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
-       s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
-}
diff --git a/arch/arm/plat-s3c24xx/setup-ts.c b/arch/arm/plat-s3c24xx/setup-ts.c
deleted file mode 100644 (file)
index ed26386..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/setup-ts.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *                     http://www.samsung.com/
- *
- * Based on S3C24XX setup for i2c device
- *
- * 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/gpio.h>
-
-struct platform_device; /* don't need the contents */
-
-#include <mach/hardware.h>
-#include <mach/regs-gpio.h>
-
-/**
- * s3c24xx_ts_cfg_gpio - configure gpio for s3c2410 systems
- *
- * Configure the GPIO for the S3C2410 system, where we have external FETs
- * connected to the device (later systems such as the S3C2440 integrate
- * these into the device).
- */
-void s3c24xx_ts_cfg_gpio(struct platform_device *dev)
-{
-       s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON);
-       s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON);
-       s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON);
-       s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON);
-}
diff --git a/arch/arm/plat-s3c24xx/simtec-audio.c b/arch/arm/plat-s3c24xx/simtec-audio.c
deleted file mode 100644 (file)
index 6bc832e..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/simtec-audio.c
- *
- * Copyright (c) 2009 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Audio setup for various Simtec S3C24XX implementations
- *
- * 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/interrupt.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/io.h>
-
-#include <mach/bast-map.h>
-#include <mach/bast-irq.h>
-#include <mach/bast-cpld.h>
-
-#include <mach/hardware.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/audio-simtec.h>
-#include <plat/devs.h>
-
-/* platform ops for audio */
-
-static void simtec_audio_startup_lrroute(void)
-{
-       unsigned int tmp;
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       tmp = __raw_readb(BAST_VA_CTRL1);
-       tmp &= ~BAST_CPLD_CTRL1_LRMASK;
-       tmp |= BAST_CPLD_CTRL1_LRCDAC;
-       __raw_writeb(tmp, BAST_VA_CTRL1);
-
-       local_irq_restore(flags);
-}
-
-static struct s3c24xx_audio_simtec_pdata simtec_audio_platdata;
-static char our_name[32];
-
-static struct platform_device simtec_audio_dev = {
-       .name   = our_name,
-       .id     = -1,
-       .dev    = {
-               .parent         = &s3c_device_iis.dev,
-               .platform_data  = &simtec_audio_platdata,
-       },
-};
-
-int __init simtec_audio_add(const char *name, bool has_lr_routing,
-                           struct s3c24xx_audio_simtec_pdata *spd)
-{
-       if (!name)
-               name = "tlv320aic23";
-
-       snprintf(our_name, sizeof(our_name)-1, "s3c24xx-simtec-%s", name);
-
-       /* copy platform data so the source can be __initdata */
-       if (spd)
-               simtec_audio_platdata = *spd;
-
-       if (has_lr_routing)
-               simtec_audio_platdata.startup = simtec_audio_startup_lrroute;
-
-       platform_device_register(&s3c_device_iis);
-       platform_device_register(&simtec_audio_dev);
-       return 0;
-}
diff --git a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
deleted file mode 100644 (file)
index 704175b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
- *
- * Copyright (c) 2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C24XX SPI - gpio configuration for bus 0 on gpe11,12,13
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
-*/
-
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-
-#include <mach/spi.h>
-#include <mach/regs-gpio.h>
-
-void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
-                                         int enable)
-{
-       if (enable) {
-               s3c_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPE13_SPICLK0);
-               s3c_gpio_cfgpin(S3C2410_GPE(12), S3C2410_GPE12_SPIMOSI0);
-               s3c_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPE11_SPIMISO0);
-               s3c2410_gpio_pullup(S3C2410_GPE(11), 0);
-               s3c2410_gpio_pullup(S3C2410_GPE(13), 0);
-       } else {
-               s3c_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPIO_INPUT);
-               s3c_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPIO_INPUT);
-               s3c_gpio_setpull(S3C2410_GPE(11), S3C_GPIO_PULL_NONE);
-               s3c_gpio_setpull(S3C2410_GPE(12), S3C_GPIO_PULL_NONE);
-               s3c_gpio_setpull(S3C2410_GPE(13), S3C_GPIO_PULL_NONE);
-       }
-}
diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c b/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c
deleted file mode 100644 (file)
index 72457af..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpd8_9_10.c
- *
- * Copyright (c) 2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C24XX SPI - gpio configuration for bus 1 on gpd8,9,10
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
-*/
-
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-
-#include <mach/spi.h>
-#include <mach/regs-gpio.h>
-
-void s3c24xx_spi_gpiocfg_bus1_gpd8_9_10(struct s3c2410_spi_info *spi,
-                                       int enable)
-{
-
-       printk(KERN_INFO "%s(%d)\n", __func__, enable);
-       if (enable) {
-               s3c_gpio_cfgpin(S3C2410_GPD(10), S3C2440_GPD10_SPICLK1);
-               s3c_gpio_cfgpin(S3C2410_GPD(9), S3C2440_GPD9_SPIMOSI1);
-               s3c_gpio_cfgpin(S3C2410_GPD(8), S3C2440_GPD8_SPIMISO1);
-               s3c2410_gpio_pullup(S3C2410_GPD(10), 0);
-               s3c2410_gpio_pullup(S3C2410_GPD(9), 0);
-       } else {
-               s3c_gpio_cfgpin(S3C2410_GPD(8), S3C2410_GPIO_INPUT);
-               s3c_gpio_cfgpin(S3C2410_GPD(9), S3C2410_GPIO_INPUT);
-               s3c_gpio_setpull(S3C2410_GPD(10), S3C_GPIO_PULL_NONE);
-               s3c_gpio_setpull(S3C2410_GPD(9), S3C_GPIO_PULL_NONE);
-               s3c_gpio_setpull(S3C2410_GPD(8), S3C_GPIO_PULL_NONE);
-       }
-}
diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
deleted file mode 100644 (file)
index c3972b6..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpg5_6_7.c
- *
- * Copyright (c) 2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C24XX SPI - gpio configuration for bus 1 on gpg5,6,7
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
-*/
-
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-
-#include <mach/spi.h>
-#include <mach/regs-gpio.h>
-
-void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
-                                      int enable)
-{
-       if (enable) {
-               s3c_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPG7_SPICLK1);
-               s3c_gpio_cfgpin(S3C2410_GPG(6), S3C2410_GPG6_SPIMOSI1);
-               s3c_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPG5_SPIMISO1);
-               s3c2410_gpio_pullup(S3C2410_GPG(5), 0);
-               s3c2410_gpio_pullup(S3C2410_GPG(6), 0);
-       } else {
-               s3c_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPIO_INPUT);
-               s3c_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPIO_INPUT);
-               s3c_gpio_setpull(S3C2410_GPG(5), S3C_GPIO_PULL_NONE);
-               s3c_gpio_setpull(S3C2410_GPG(6), S3C_GPIO_PULL_NONE);
-               s3c_gpio_setpull(S3C2410_GPG(7), S3C_GPIO_PULL_NONE);
-       }
-}
index 8167ce6..96bea32 100644 (file)
@@ -9,8 +9,8 @@ config PLAT_S5P
        bool
        depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS)
        default y
-       select ARM_VIC if !ARCH_EXYNOS4
-       select ARM_GIC if ARCH_EXYNOS4
+       select ARM_VIC if !ARCH_EXYNOS
+       select ARM_GIC if ARCH_EXYNOS
        select GIC_NON_BANKED if ARCH_EXYNOS4
        select NO_IOPORT
        select ARCH_REQUIRE_GPIOLIB
@@ -40,6 +40,10 @@ config S5P_HRT
        help
          Use the High Resolution timer support
 
+config S5P_DEV_UART
+       def_bool y
+       depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210)
+
 config S5P_PM
        bool
        help
@@ -80,6 +84,16 @@ config S5P_DEV_FIMC3
        help
          Compile in platform device definitions for FIMC controller 3
 
+config S5P_DEV_JPEG
+       bool
+       help
+         Compile in platform device definitions for JPEG codec
+
+config S5P_DEV_G2D
+       bool
+       help
+         Compile in platform device definitions for G2D device
+
 config S5P_DEV_FIMD0
        bool
        help
index 30d8c30..4bd8241 100644 (file)
@@ -12,7 +12,6 @@ obj-                          :=
 
 # Core files
 
-obj-y                          += dev-uart.o
 obj-y                          += clock.o
 obj-y                          += irq.o
 obj-$(CONFIG_S5P_EXT_INT)      += irq-eint.o
@@ -23,5 +22,7 @@ obj-$(CONFIG_S5P_SLEEP)               += sleep.o
 obj-$(CONFIG_S5P_HRT)          += s5p-time.o
 
 # devices
+
+obj-$(CONFIG_S5P_DEV_UART)     += dev-uart.o
 obj-$(CONFIG_S5P_DEV_MFC)      += dev-mfc.o
 obj-$(CONFIG_S5P_SETUP_MIPIPHY)        += setup-mipiphy.o
index 963edea..f68a9bb 100644 (file)
@@ -61,6 +61,20 @@ struct clk clk_fout_apll = {
        .id             = -1,
 };
 
+/* BPLL clock output */
+
+struct clk clk_fout_bpll = {
+       .name           = "fout_bpll",
+       .id             = -1,
+};
+
+/* CPLL clock output */
+
+struct clk clk_fout_cpll = {
+       .name           = "fout_cpll",
+       .id             = -1,
+};
+
 /* MPLL clock output
  * No need .ctrlbit, this is always on
 */
@@ -101,6 +115,28 @@ struct clksrc_sources clk_src_apll = {
        .nr_sources     = ARRAY_SIZE(clk_src_apll_list),
 };
 
+/* Possible clock sources for BPLL Mux */
+static struct clk *clk_src_bpll_list[] = {
+       [0] = &clk_fin_bpll,
+       [1] = &clk_fout_bpll,
+};
+
+struct clksrc_sources clk_src_bpll = {
+       .sources        = clk_src_bpll_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_bpll_list),
+};
+
+/* Possible clock sources for CPLL Mux */
+static struct clk *clk_src_cpll_list[] = {
+       [0] = &clk_fin_cpll,
+       [1] = &clk_fout_cpll,
+};
+
+struct clksrc_sources clk_src_cpll = {
+       .sources        = clk_src_cpll_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_cpll_list),
+};
+
 /* Possible clock sources for MPLL Mux */
 static struct clk *clk_src_mpll_list[] = {
        [0] = &clk_fin_mpll,
index c496b35..139c050 100644 (file)
@@ -200,7 +200,7 @@ static struct irq_chip s5p_irq_vic_eint = {
 #endif
 };
 
-int __init s5p_init_irq_eint(void)
+static int __init s5p_init_irq_eint(void)
 {
        int irq;
 
index 1fdfaa4..82c7311 100644 (file)
@@ -41,7 +41,7 @@ struct s5p_gpioint_bank {
        void                    (*handler)(unsigned int, struct irq_desc *);
 };
 
-LIST_HEAD(banks);
+static LIST_HEAD(banks);
 
 static int s5p_gpioint_set_type(struct irq_data *d, unsigned int type)
 {
index 327acb3..d1bfeca 100644 (file)
@@ -39,19 +39,32 @@ unsigned long s3c_irqwake_eintallow = 0xffffffffL;
 int s3c_irq_wake(struct irq_data *data, unsigned int state)
 {
        unsigned long irqbit;
+       unsigned int irq_rtc_tic, irq_rtc_alarm;
+
+#ifdef CONFIG_ARCH_EXYNOS
+       if (soc_is_exynos5250()) {
+               irq_rtc_tic = EXYNOS5_IRQ_RTC_TIC;
+               irq_rtc_alarm = EXYNOS5_IRQ_RTC_ALARM;
+       } else {
+               irq_rtc_tic = EXYNOS4_IRQ_RTC_TIC;
+               irq_rtc_alarm = EXYNOS4_IRQ_RTC_ALARM;
+       }
+#else
+       irq_rtc_tic = IRQ_RTC_TIC;
+       irq_rtc_alarm = IRQ_RTC_ALARM;
+#endif
+
+       if (data->irq == irq_rtc_tic || data->irq == irq_rtc_alarm) {
+               irqbit = 1 << (data->irq + 1 - irq_rtc_alarm);
 
-       switch (data->irq) {
-       case IRQ_RTC_TIC:
-       case IRQ_RTC_ALARM:
-               irqbit = 1 << (data->irq + 1 - IRQ_RTC_ALARM);
                if (!state)
                        s3c_irqwake_intmask |= irqbit;
                else
                        s3c_irqwake_intmask &= ~irqbit;
-               break;
-       default:
+       } else {
                return -ENOENT;
        }
+
        return 0;
 }
 
index 0fd591b..006bd01 100644 (file)
 */
 
 #include <linux/linkage.h>
-#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/hardware/cache-l2x0.h>
 
-       .text
+/*
+ *      The following code is located into the .data section. This is to
+ *      allow l2x0_regs_phys to be accessed with a relative load while we
+ *      can't rely on any MMU translation. We could have put l2x0_regs_phys
+ *      in the .text section as well, but some setups might insist on it to
+ *      be truly read-only. (Reference from: arch/arm/kernel/sleep.S)
+ */
+       .data
+       .align
 
        /*
         * sleep magic, to allow the bootloader to check for an valid
         * s3c_cpu_resume
         *
         * resume code entry for bootloader to call
-        *
-        * we must put this code here in the data segment as we have no
-        * other way of restoring the stack pointer after sleep, and we
-        * must not write to the code segment (code is read-only)
         */
 
 ENTRY(s3c_cpu_resume)
+#ifdef CONFIG_CACHE_L2X0
+       adr     r0, l2x0_regs_phys
+       ldr     r0, [r0]
+       ldr     r1, [r0, #L2X0_R_PHY_BASE]
+       ldr     r2, [r1, #L2X0_CTRL]
+       tst     r2, #0x1
+       bne     resume_l2on
+       ldr     r2, [r0, #L2X0_R_AUX_CTRL]
+       str     r2, [r1, #L2X0_AUX_CTRL]
+       ldr     r2, [r0, #L2X0_R_TAG_LATENCY]
+       str     r2, [r1, #L2X0_TAG_LATENCY_CTRL]
+       ldr     r2, [r0, #L2X0_R_DATA_LATENCY]
+       str     r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+       ldr     r2, [r0, #L2X0_R_PREFETCH_CTRL]
+       str     r2, [r1, #L2X0_PREFETCH_CTRL]
+       ldr     r2, [r0, #L2X0_R_PWR_CTRL]
+       str     r2, [r1, #L2X0_POWER_CTRL]
+       mov     r2, #1
+       str     r2, [r1, #L2X0_CTRL]
+resume_l2on:
+#endif
        b       cpu_resume
+ENDPROC(s3c_cpu_resume)
+#ifdef CONFIG_CACHE_L2X0
+       .globl l2x0_regs_phys
+l2x0_regs_phys:
+       .long   0
+#endif
index 6a2abe6..71553f4 100644 (file)
@@ -205,7 +205,7 @@ config S3C_DEV_USB_HSOTG
 
 config S3C_DEV_WDT
        bool
-       default y if ARCH_S3C2410
+       default y if ARCH_S3C24XX
        help
          Complie in platform device definition for Watchdog Timer
 
@@ -264,7 +264,7 @@ config SAMSUNG_DEV_KEYPAD
 
 config SAMSUNG_DEV_PWM
        bool
-       default y if ARCH_S3C2410
+       default y if ARCH_S3C24XX
        help
          Compile in platform device definition for PWM Timer
 
index 10f7117..65c5eca 100644 (file)
@@ -84,31 +84,35 @@ static int clk_null_enable(struct clk *clk, int enable)
 
 int clk_enable(struct clk *clk)
 {
+       unsigned long flags;
+
        if (IS_ERR(clk) || clk == NULL)
                return -EINVAL;
 
        clk_enable(clk->parent);
 
-       spin_lock(&clocks_lock);
+       spin_lock_irqsave(&clocks_lock, flags);
 
        if ((clk->usage++) == 0)
                (clk->enable)(clk, 1);
 
-       spin_unlock(&clocks_lock);
+       spin_unlock_irqrestore(&clocks_lock, flags);
        return 0;
 }
 
 void clk_disable(struct clk *clk)
 {
+       unsigned long flags;
+
        if (IS_ERR(clk) || clk == NULL)
                return;
 
-       spin_lock(&clocks_lock);
+       spin_lock_irqsave(&clocks_lock, flags);
 
        if ((--clk->usage) == 0)
                (clk->enable)(clk, 0);
 
-       spin_unlock(&clocks_lock);
+       spin_unlock_irqrestore(&clocks_lock, flags);
        clk_disable(clk->parent);
 }
 
index a976c02..5f197dc 100644 (file)
@@ -77,7 +77,7 @@ static struct platform_device samsung_dfl_bl_device __initdata = {
  * @gpio_info: structure containing GPIO info for PWM timer
  * @bl_data:   structure containing Backlight control data
  */
-void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
+void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
        struct platform_pwm_backlight_data *bl_data)
 {
        int ret = 0;
@@ -115,6 +115,8 @@ void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
                samsung_bl_data->init = bl_data->init;
        if (bl_data->notify)
                samsung_bl_data->notify = bl_data->notify;
+       if (bl_data->notify_after)
+               samsung_bl_data->notify_after = bl_data->notify_after;
        if (bl_data->exit)
                samsung_bl_data->exit = bl_data->exit;
        if (bl_data->check_fb)
index d21d744..8b928f9 100644 (file)
@@ -57,6 +57,7 @@
 #include <plat/sdhci.h>
 #include <plat/ts.h>
 #include <plat/udc.h>
+#include <plat/udc-hs.h>
 #include <plat/usb-control.h>
 #include <plat/usb-phy.h>
 #include <plat/regs-iic.h>
@@ -267,6 +268,52 @@ struct platform_device s5p_device_fimc3 = {
 };
 #endif /* CONFIG_S5P_DEV_FIMC3 */
 
+/* G2D */
+
+#ifdef CONFIG_S5P_DEV_G2D
+static struct resource s5p_g2d_resource[] = {
+       [0] = {
+               .start  = S5P_PA_G2D,
+               .end    = S5P_PA_G2D + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_2D,
+               .end    = IRQ_2D,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device s5p_device_g2d = {
+       .name           = "s5p-g2d",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(s5p_g2d_resource),
+       .resource       = s5p_g2d_resource,
+       .dev            = {
+               .dma_mask               = &samsung_device_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+#endif /* CONFIG_S5P_DEV_G2D */
+
+#ifdef CONFIG_S5P_DEV_JPEG
+static struct resource s5p_jpeg_resource[] = {
+       [0] = DEFINE_RES_MEM(S5P_PA_JPEG, SZ_4K),
+       [1] = DEFINE_RES_IRQ(IRQ_JPEG),
+};
+
+struct platform_device s5p_device_jpeg = {
+       .name           = "s5p-jpeg",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(s5p_jpeg_resource),
+       .resource       = s5p_jpeg_resource,
+       .dev            = {
+               .dma_mask               = &samsung_device_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+#endif /*  CONFIG_S5P_DEV_JPEG */
+
 /* FIMD0 */
 
 #ifdef CONFIG_S5P_DEV_FIMD0
@@ -744,17 +791,6 @@ struct platform_device s3c_device_iis = {
 };
 #endif /* CONFIG_PLAT_S3C24XX */
 
-#ifdef CONFIG_CPU_S3C2440
-struct platform_device s3c2412_device_iis = {
-       .name           = "s3c2412-iis",
-       .id             = -1,
-       .dev            = {
-               .dma_mask               = &samsung_device_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       }
-};
-#endif /* CONFIG_CPU_S3C2440 */
-
 /* IDE CFCON */
 
 #ifdef CONFIG_SAMSUNG_DEV_IDE
@@ -769,7 +805,7 @@ struct platform_device s3c_device_cfcon = {
        .resource       = s3c_cfcon_resource,
 };
 
-void s3c_ide_set_platdata(struct s3c_ide_platdata *pdata)
+void __init s3c_ide_set_platdata(struct s3c_ide_platdata *pdata)
 {
        s3c_set_platdata(pdata, sizeof(struct s3c_ide_platdata),
                         &s3c_device_cfcon);
@@ -887,7 +923,7 @@ struct platform_device s5p_device_mfc_r = {
 
 #ifdef CONFIG_S5P_DEV_CSIS0
 static struct resource s5p_mipi_csis0_resource[] = {
-       [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS0, SZ_4K),
+       [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS0, SZ_16K),
        [1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS0),
 };
 
@@ -901,7 +937,7 @@ struct platform_device s5p_device_mipi_csis0 = {
 
 #ifdef CONFIG_S5P_DEV_CSIS1
 static struct resource s5p_mipi_csis1_resource[] = {
-       [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS1, SZ_4K),
+       [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS1, SZ_16K),
        [1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS1),
 };
 
@@ -1049,7 +1085,7 @@ struct platform_device s3c64xx_device_onenand1 = {
        .resource       = s3c64xx_onenand1_resources,
 };
 
-void s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata)
+void __init s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata)
 {
        s3c_set_platdata(pdata, sizeof(struct onenand_platform_data),
                         &s3c64xx_device_onenand1);
@@ -1078,7 +1114,7 @@ static struct resource s5p_pmu_resource[] = {
        DEFINE_RES_IRQ(IRQ_PMU)
 };
 
-struct platform_device s5p_device_pmu = {
+static struct platform_device s5p_device_pmu = {
        .name           = "arm-pmu",
        .id             = ARM_PMU_DEVICE_CPU,
        .num_resources  = ARRAY_SIZE(s5p_pmu_resource),
@@ -1423,6 +1459,19 @@ struct platform_device s3c_device_usb_hsotg = {
                .coherent_dma_mask      = DMA_BIT_MASK(32),
        },
 };
+
+void __init s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd)
+{
+       struct s3c_hsotg_plat *npd;
+
+       npd = s3c_set_platdata(pd, sizeof(struct s3c_hsotg_plat),
+                       &s3c_device_usb_hsotg);
+
+       if (!npd->phy_init)
+               npd->phy_init = s5p_usb_phy_init;
+       if (!npd->phy_exit)
+               npd->phy_exit = s5p_usb_phy_exit;
+}
 #endif /* CONFIG_S3C_DEV_USB_HSOTG */
 
 /* USB High Spped 2.0 Device (Gadget) */
index 0747c77..301d9c3 100644 (file)
@@ -116,7 +116,7 @@ static inline int samsung_dmadev_flush(unsigned ch)
        return dmaengine_terminate_all((struct dma_chan *)ch);
 }
 
-struct samsung_dma_ops dmadev_ops = {
+static struct samsung_dma_ops dmadev_ops = {
        .request        = samsung_dmadev_request,
        .release        = samsung_dmadev_release,
        .prepare        = samsung_dmadev_prepare,
index 5345364..376af52 100644 (file)
@@ -32,6 +32,3 @@ struct s3c24xx_audio_simtec_pdata {
 
        void    (*startup)(void);
 };
-
-extern int simtec_audio_add(const char *codec_name, bool has_lr_routing,
-                           struct s3c24xx_audio_simtec_pdata *pdata);
index 73c66d4..a62753d 100644 (file)
@@ -79,6 +79,10 @@ extern struct clk clk_epll;
 extern struct clk clk_xtal;
 extern struct clk clk_ext;
 
+/* S3C2443/S3C2416 specific clocks */
+extern struct clksrc_clk clk_epllref;
+extern struct clksrc_clk clk_esysclk;
+
 /* S3C64XX specific clocks */
 extern struct clk clk_h2;
 extern struct clk clk_27m;
@@ -114,7 +118,23 @@ extern void s3c24xx_setup_clocks(unsigned long fclk,
 extern void s3c2410_setup_clocks(void);
 extern void s3c2412_setup_clocks(void);
 extern void s3c244x_setup_clocks(void);
-extern void s3c2443_setup_clocks(void);
+
+/* S3C2410 specific clock functions */
+
+extern int s3c2410_baseclk_add(void);
+
+/* S3C2443/S3C2416 specific clock functions */
+
+typedef unsigned int (*pll_fn)(unsigned int reg, unsigned int base);
+
+extern void s3c2443_common_setup_clocks(pll_fn get_mpll);
+extern void s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
+                                      unsigned int *divs, int nr_divs,
+                                      int divmask);
+
+extern int s3c2443_clkcon_enable_h(struct clk *clk, int enable);
+extern int s3c2443_clkcon_enable_p(struct clk *clk, int enable);
+extern int s3c2443_clkcon_enable_s(struct clk *clk, int enable);
 
 /* S3C64XX specific functions and clocks */
 
index 73cb3cf..787ceac 100644 (file)
@@ -42,6 +42,9 @@ extern unsigned long samsung_cpu_id;
 #define EXYNOS4412_CPU_ID      0xE4412200
 #define EXYNOS4_CPU_MASK       0xFFFE0000
 
+#define EXYNOS5250_SOC_ID      0x43520000
+#define EXYNOS5_SOC_MASK       0xFFFFF000
+
 #define IS_SAMSUNG_CPU(name, id, mask)         \
 static inline int is_samsung_##name(void)      \
 {                                              \
@@ -58,6 +61,7 @@ IS_SAMSUNG_CPU(s5pv210, S5PV210_CPU_ID, S5PV210_CPU_MASK)
 IS_SAMSUNG_CPU(exynos4210, EXYNOS4210_CPU_ID, EXYNOS4_CPU_MASK)
 IS_SAMSUNG_CPU(exynos4212, EXYNOS4212_CPU_ID, EXYNOS4_CPU_MASK)
 IS_SAMSUNG_CPU(exynos4412, EXYNOS4412_CPU_ID, EXYNOS4_CPU_MASK)
+IS_SAMSUNG_CPU(exynos5250, EXYNOS5250_SOC_ID, EXYNOS5_SOC_MASK)
 
 #if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2412) || \
     defined(CONFIG_CPU_S3C2416) || defined(CONFIG_CPU_S3C2440) || \
@@ -120,6 +124,12 @@ IS_SAMSUNG_CPU(exynos4412, EXYNOS4412_CPU_ID, EXYNOS4_CPU_MASK)
 #define EXYNOS4210_REV_1_0     (0x10)
 #define EXYNOS4210_REV_1_1     (0x11)
 
+#if defined(CONFIG_SOC_EXYNOS5250)
+# define soc_is_exynos5250()   is_samsung_exynos5250()
+#else
+# define soc_is_exynos5250()   0
+#endif
+
 #define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
 
 #ifndef MHZ
index 4214ea0..2155d4a 100644 (file)
@@ -26,6 +26,8 @@ struct s3c24xx_uart_resources {
 extern struct s3c24xx_uart_resources s3c2410_uart_resources[];
 extern struct s3c24xx_uart_resources s3c64xx_uart_resources[];
 extern struct s3c24xx_uart_resources s5p_uart_resources[];
+extern struct s3c24xx_uart_resources exynos4_uart_resources[];
+extern struct s3c24xx_uart_resources exynos5_uart_resources[];
 
 extern struct platform_device *s3c24xx_uart_devs[];
 extern struct platform_device *s3c24xx_uart_src[];
@@ -79,6 +81,8 @@ extern struct platform_device s5p_device_fimc1;
 extern struct platform_device s5p_device_fimc2;
 extern struct platform_device s5p_device_fimc3;
 extern struct platform_device s5p_device_fimc_md;
+extern struct platform_device s5p_device_jpeg;
+extern struct platform_device s5p_device_g2d;
 extern struct platform_device s5p_device_fimd0;
 extern struct platform_device s5p_device_hdmi;
 extern struct platform_device s5p_device_i2c_hdmiphy;
index c5eaad5..0670f37 100644 (file)
@@ -82,6 +82,22 @@ enum dma_ch {
        DMACH_SLIMBUS4_TX,
        DMACH_SLIMBUS5_RX,
        DMACH_SLIMBUS5_TX,
+       DMACH_MIPI_HSI0,
+       DMACH_MIPI_HSI1,
+       DMACH_MIPI_HSI2,
+       DMACH_MIPI_HSI3,
+       DMACH_MIPI_HSI4,
+       DMACH_MIPI_HSI5,
+       DMACH_MIPI_HSI6,
+       DMACH_MIPI_HSI7,
+       DMACH_MTOM_0,
+       DMACH_MTOM_1,
+       DMACH_MTOM_2,
+       DMACH_MTOM_3,
+       DMACH_MTOM_4,
+       DMACH_MTOM_5,
+       DMACH_MTOM_6,
+       DMACH_MTOM_7,
        /* END Marker, also used to denote a reserved channel */
        DMACH_MAX,
 };
index 178bccb..a7d622e 100644 (file)
 #define S3C2412_DMAREQSEL_UART2_1      S3C2412_DMAREQSEL_SRC(24)
 #endif /* CONFIG_CPU_S3C2412 */
 
-#ifdef CONFIG_CPU_S3C2443
+#if defined(CONFIG_CPU_S3C2416) || defined(CONFIG_CPU_S3C2443)
 
 #define S3C2443_DMAREQSEL_SRC(x)       ((x) << 1)
 
index 30b7cc1..0f8263e 100644 (file)
 #define S3C2410_INTP_ALM       (1 << 1)
 #define S3C2410_INTP_TIC       (1 << 0)
 
-#define S3C2410_RTCCON       S3C2410_RTCREG(0x40)
-#define S3C2410_RTCCON_RTCEN  (1<<0)
-#define S3C2410_RTCCON_CLKSEL (1<<1)
-#define S3C2410_RTCCON_CNTSEL (1<<2)
-#define S3C2410_RTCCON_CLKRST (1<<3)
-#define S3C64XX_RTCCON_TICEN  (1<<8)
+#define S3C2410_RTCCON         S3C2410_RTCREG(0x40)
+#define S3C2410_RTCCON_RTCEN   (1 << 0)
+#define S3C2410_RTCCON_CNTSEL  (1 << 2)
+#define S3C2410_RTCCON_CLKRST  (1 << 3)
+#define S3C2443_RTCCON_TICSEL  (1 << 4)
+#define S3C64XX_RTCCON_TICEN   (1 << 8)
 
-#define S3C64XX_RTCCON_TICMSK (0xF<<7)
-#define S3C64XX_RTCCON_TICSHT (7)
+#define S3C2410_TICNT          S3C2410_RTCREG(0x44)
+#define S3C2410_TICNT_ENABLE   (1 << 7)
 
-#define S3C2410_TICNT        S3C2410_RTCREG(0x44)
-#define S3C2410_TICNT_ENABLE  (1<<7)
+/* S3C2443: tick count is 15 bit wide
+ * TICNT[6:0] contains upper 7 bits
+ * TICNT1[7:0] contains lower 8 bits
+ */
+#define S3C2443_TICNT_PART(x)  ((x & 0x7f00) >> 8)
+#define S3C2443_TICNT1         S3C2410_RTCREG(0x4C)
+#define S3C2443_TICNT1_PART(x) (x & 0xff)
 
-#define S3C2410_RTCALM       S3C2410_RTCREG(0x50)
-#define S3C2410_RTCALM_ALMEN  (1<<6)
-#define S3C2410_RTCALM_YEAREN (1<<5)
-#define S3C2410_RTCALM_MONEN  (1<<4)
-#define S3C2410_RTCALM_DAYEN  (1<<3)
-#define S3C2410_RTCALM_HOUREN (1<<2)
-#define S3C2410_RTCALM_MINEN  (1<<1)
-#define S3C2410_RTCALM_SECEN  (1<<0)
+/* S3C2416: tick count is 32 bit wide
+ * TICNT[6:0] contains bits [14:8]
+ * TICNT1[7:0] contains lower 8 bits
+ * TICNT2[16:0] contains upper 17 bits
+ */
+#define S3C2416_TICNT2         S3C2410_RTCREG(0x48)
+#define S3C2416_TICNT2_PART(x) ((x & 0xffff8000) >> 15)
 
-#define S3C2410_RTCALM_ALL \
-  S3C2410_RTCALM_ALMEN | S3C2410_RTCALM_YEAREN | S3C2410_RTCALM_MONEN |\
-  S3C2410_RTCALM_DAYEN | S3C2410_RTCALM_HOUREN | S3C2410_RTCALM_MINEN |\
-  S3C2410_RTCALM_SECEN
+#define S3C2410_RTCALM         S3C2410_RTCREG(0x50)
+#define S3C2410_RTCALM_ALMEN   (1 << 6)
+#define S3C2410_RTCALM_YEAREN  (1 << 5)
+#define S3C2410_RTCALM_MONEN   (1 << 4)
+#define S3C2410_RTCALM_DAYEN   (1 << 3)
+#define S3C2410_RTCALM_HOUREN  (1 << 2)
+#define S3C2410_RTCALM_MINEN   (1 << 1)
+#define S3C2410_RTCALM_SECEN   (1 << 0)
 
+#define S3C2410_ALMSEC         S3C2410_RTCREG(0x54)
+#define S3C2410_ALMMIN         S3C2410_RTCREG(0x58)
+#define S3C2410_ALMHOUR                S3C2410_RTCREG(0x5c)
 
-#define S3C2410_ALMSEC       S3C2410_RTCREG(0x54)
-#define S3C2410_ALMMIN       S3C2410_RTCREG(0x58)
-#define S3C2410_ALMHOUR              S3C2410_RTCREG(0x5c)
-
-#define S3C2410_ALMDATE              S3C2410_RTCREG(0x60)
-#define S3C2410_ALMMON       S3C2410_RTCREG(0x64)
-#define S3C2410_ALMYEAR              S3C2410_RTCREG(0x68)
-
-#define S3C2410_RTCRST       S3C2410_RTCREG(0x6c)
-
-#define S3C2410_RTCSEC       S3C2410_RTCREG(0x70)
-#define S3C2410_RTCMIN       S3C2410_RTCREG(0x74)
-#define S3C2410_RTCHOUR              S3C2410_RTCREG(0x78)
-#define S3C2410_RTCDATE              S3C2410_RTCREG(0x7c)
-#define S3C2410_RTCDAY       S3C2410_RTCREG(0x80)
-#define S3C2410_RTCMON       S3C2410_RTCREG(0x84)
-#define S3C2410_RTCYEAR              S3C2410_RTCREG(0x88)
+#define S3C2410_ALMDATE                S3C2410_RTCREG(0x60)
+#define S3C2410_ALMMON         S3C2410_RTCREG(0x64)
+#define S3C2410_ALMYEAR                S3C2410_RTCREG(0x68)
 
+#define S3C2410_RTCSEC         S3C2410_RTCREG(0x70)
+#define S3C2410_RTCMIN         S3C2410_RTCREG(0x74)
+#define S3C2410_RTCHOUR                S3C2410_RTCREG(0x78)
+#define S3C2410_RTCDATE                S3C2410_RTCREG(0x7c)
+#define S3C2410_RTCMON         S3C2410_RTCREG(0x84)
+#define S3C2410_RTCYEAR                S3C2410_RTCREG(0x88)
 
 #endif /* __ASM_ARCH_REGS_RTC_H */
index a111ad8..fcf2796 100644 (file)
@@ -25,8 +25,9 @@
 #define S3C_HSOTG_PHYREG(x)    ((x) + S3C_VA_USB_HSPHY)
 
 #define S3C_PHYPWR                             S3C_HSOTG_PHYREG(0x00)
-#define SRC_PHYPWR_OTG_DISABLE                 (1 << 4)
-#define SRC_PHYPWR_ANALOG_POWERDOWN            (1 << 3)
+#define S3C_PHYPWR_NORMAL_MASK                 (0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE                 (1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN            (1 << 3)
 #define SRC_PHYPWR_FORCE_SUSPEND               (1 << 1)
 
 #define S3C_PHYCLK                             S3C_HSOTG_PHYREG(0x04)
@@ -42,7 +43,7 @@
 
 #define S3C_RSTCON                             S3C_HSOTG_PHYREG(0x08)
 #define S3C_RSTCON_PHYCLK                      (1 << 2)
-#define S3C_RSTCON_HCLK                                (1 << 2)
+#define S3C_RSTCON_HCLK                                (1 << 1)
 #define S3C_RSTCON_PHY                         (1 << 0)
 
 #define S3C_PHYTUNE                            S3C_HSOTG_PHYREG(0x20)
diff --git a/arch/arm/plat-samsung/include/plat/rtc-core.h b/arch/arm/plat-samsung/include/plat/rtc-core.h
new file mode 100644 (file)
index 0000000..21d8594
--- /dev/null
@@ -0,0 +1,27 @@
+/* linux/arch/arm/plat-samsung/include/plat/rtc-core.h
+ *
+ * Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de>
+ *
+ * Samsung RTC Controller core functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_PLAT_RTC_CORE_H
+#define __ASM_PLAT_RTC_CORE_H __FILE__
+
+/* These functions are only for use with the core support code, such as
+ * the cpu specific initialisation code
+ */
+
+/* re-define device name depending on support. */
+static inline void s3c_rtc_setname(char *name)
+{
+#if defined(CONFIG_SAMSUNG_DEV_RTC) || defined(CONFIG_PLAT_S3C24XX)
+       s3c_device_rtc.name = name;
+#endif
+}
+
+#endif /* __ASM_PLAT_RTC_CORE_H */
index 3986497..55b0e5f 100644 (file)
@@ -29,5 +29,3 @@ extern void s3c2410_init_clocks(int xtal);
 #define s3c2410_init NULL
 #define s3c2410a_init NULL
 #endif
-
-extern int s3c2410_baseclk_add(void);
index dce05b4..a5b794f 100644 (file)
@@ -32,23 +32,3 @@ extern void s3c2443_restart(char mode, const char *cmd);
 #define s3c2443_init NULL
 #define s3c2443_restart NULL
 #endif
-
-/* common code used by s3c2443 and others.
- * note, not to be used outside of arch/arm/mach-s3c* */
-
-struct clk;    /* some files don't need clk.h otherwise */
-
-typedef unsigned int (*pll_fn)(unsigned int reg, unsigned int base);
-
-extern void s3c2443_common_setup_clocks(pll_fn get_mpll);
-extern void s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
-                                      unsigned int *divs, int nr_divs,
-                                      int divmask);
-
-extern int s3c2443_clkcon_enable_h(struct clk *clk, int enable);
-extern int s3c2443_clkcon_enable_p(struct clk *clk, int enable);
-extern int s3c2443_clkcon_enable_s(struct clk *clk, int enable);
-
-extern struct clksrc_clk clk_epllref;
-extern struct clksrc_clk clk_esysclk;
-extern struct clksrc_clk clk_msysclk;
index 984bf9e..1de4b32 100644 (file)
@@ -18,6 +18,8 @@
 #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
 
 #define clk_fin_apll clk_ext_xtal_mux
+#define clk_fin_bpll clk_ext_xtal_mux
+#define clk_fin_cpll clk_ext_xtal_mux
 #define clk_fin_mpll clk_ext_xtal_mux
 #define clk_fin_epll clk_ext_xtal_mux
 #define clk_fin_dpll clk_ext_xtal_mux
@@ -29,6 +31,8 @@ extern struct clk clk_xusbxti;
 extern struct clk clk_48m;
 extern struct clk s5p_clk_27m;
 extern struct clk clk_fout_apll;
+extern struct clk clk_fout_bpll;
+extern struct clk clk_fout_cpll;
 extern struct clk clk_fout_mpll;
 extern struct clk clk_fout_epll;
 extern struct clk clk_fout_dpll;
@@ -37,6 +41,8 @@ extern struct clk clk_arm;
 extern struct clk clk_vpll;
 
 extern struct clksrc_sources clk_src_apll;
+extern struct clksrc_sources clk_src_bpll;
+extern struct clksrc_sources clk_src_cpll;
 extern struct clksrc_sources clk_src_mpll;
 extern struct clksrc_sources clk_src_epll;
 extern struct clksrc_sources clk_src_dpll;
index f82f888..317e246 100644 (file)
@@ -40,6 +40,7 @@ enum clk_types {
  * struct s3c_sdhci_platdata() - Platform device data for Samsung SDHCI
  * @max_width: The maximum number of data bits supported.
  * @host_caps: Standard MMC host capabilities bit field.
+ * @host_caps2: The second standard MMC host capabilities bit field.
  * @cd_type: Type of Card Detection method (see cd_types enum above)
  * @clk_type: Type of clock divider method (see clk_types enum above)
  * @ext_cd_init: Initialize external card detect subsystem. Called on
@@ -63,6 +64,7 @@ enum clk_types {
 struct s3c_sdhci_platdata {
        unsigned int    max_width;
        unsigned int    host_caps;
+       unsigned int    host_caps2;
        unsigned int    pm_caps;
        enum cd_types   cd_type;
        enum clk_types  clk_type;
index a22a4f2..c9e3667 100644 (file)
@@ -26,4 +26,9 @@ enum s3c_hsotg_dmamode {
 struct s3c_hsotg_plat {
        enum s3c_hsotg_dmamode  dma;
        unsigned int            is_osc : 1;
+
+       int (*phy_init)(struct platform_device *pdev, int type);
+       int (*phy_exit)(struct platform_device *pdev, int type);
 };
+
+extern void s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd);
index ee48e12..7e068d1 100644 (file)
@@ -37,7 +37,9 @@ static void arch_detect_cpu(void);
 /* how many bytes we allow into the FIFO at a time in FIFO mode */
 #define FIFO_MAX        (14)
 
+#ifdef S3C_PA_UART
 #define uart_base S3C_PA_UART + (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT)
+#endif
 
 static __inline__ void
 uart_wr(unsigned int reg, unsigned int val)
index 51583cd..f980cf3 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 
 #include <mach/map.h>
+#include <plat/cpu.h>
 #include <plat/irq-vic-timer.h>
 #include <plat/regs-timer.h>
 
@@ -57,6 +58,21 @@ void __init s3c_init_vic_timer_irq(unsigned int num, unsigned int timer_irq)
        struct irq_chip_type *ct;
        unsigned int i;
 
+#ifdef CONFIG_ARCH_EXYNOS
+       if (soc_is_exynos5250()) {
+               pirq[0] = EXYNOS5_IRQ_TIMER0_VIC;
+               pirq[1] = EXYNOS5_IRQ_TIMER1_VIC;
+               pirq[2] = EXYNOS5_IRQ_TIMER2_VIC;
+               pirq[3] = EXYNOS5_IRQ_TIMER3_VIC;
+               pirq[4] = EXYNOS5_IRQ_TIMER4_VIC;
+       } else {
+               pirq[0] = EXYNOS4_IRQ_TIMER0_VIC;
+               pirq[1] = EXYNOS4_IRQ_TIMER1_VIC;
+               pirq[2] = EXYNOS4_IRQ_TIMER2_VIC;
+               pirq[3] = EXYNOS4_IRQ_TIMER3_VIC;
+               pirq[4] = EXYNOS4_IRQ_TIMER4_VIC;
+       }
+#endif
        s3c_tgc = irq_alloc_generic_chip("s3c-timer", 1, timer_irq,
                                         S3C64XX_TINT_CSTAT, handle_level_irq);
 
index 0f70718..fa78aa7 100644 (file)
@@ -53,6 +53,8 @@ void s3c_sdhci_set_platdata(struct s3c_sdhci_platdata *pd,
                set->cfg_gpio = pd->cfg_gpio;
        if (pd->host_caps)
                set->host_caps |= pd->host_caps;
+       if (pd->host_caps2)
+               set->host_caps2 |= pd->host_caps2;
        if (pd->pm_caps)
                set->pm_caps |= pd->pm_caps;
        if (pd->clk_type)
diff --git a/arch/arm/plat-spear/include/plat/system.h b/arch/arm/plat-spear/include/plat/system.h
deleted file mode 100644 (file)
index 86c6f83..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * arch/arm/plat-spear/include/plat/system.h
- *
- * SPEAr platform specific architecture functions
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __PLAT_SYSTEM_H
-#define __PLAT_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-       /*
-        * This should do all the clock switching
-        * and wait for interrupt tricks
-        */
-       cpu_do_idle();
-}
-
-#endif /* __PLAT_SYSTEM_H */
index 69714db..a5cb194 100644 (file)
@@ -1,5 +1,4 @@
 obj-y  := clock.o
-obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
 obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o
 obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o
 obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o
diff --git a/arch/arm/plat-versatile/localtimer.c b/arch/arm/plat-versatile/localtimer.c
deleted file mode 100644 (file)
index 0fb3961..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  linux/arch/arm/plat-versatile/localtimer.c
- *
- *  Copyright (C) 2002 ARM Ltd.
- *  All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/clockchips.h>
-
-#include <asm/smp_twd.h>
-#include <asm/localtimer.h>
-#include <mach/irqs.h>
-
-/*
- * Setup the local clock events for a CPU.
- */
-int __cpuinit local_timer_setup(struct clock_event_device *evt)
-{
-       evt->irq = IRQ_LOCALTIMER;
-       twd_timer_setup(evt);
-       return 0;
-}
index 7c756fb..afeae89 100644 (file)
@@ -97,6 +97,7 @@ static struct atmel_nand_data atngw100mkii_nand_data __initdata = {
        .rdy_pin        = GPIO_PIN_PB(28),
        .enable_pin     = GPIO_PIN_PE(23),
        .bus_width_16   = true,
+       .ecc_mode       = NAND_ECC_SOFT,
        .parts          = nand_partitions,
        .num_parts      = ARRAY_SIZE(nand_partitions),
 };
index c56ddac..dc52633 100644 (file)
@@ -95,6 +95,7 @@ static struct atmel_nand_data atstk1006_nand_data __initdata = {
        .ale            = 22,
        .rdy_pin        = GPIO_PIN_PB(30),
        .enable_pin     = GPIO_PIN_PB(29),
+       .ecc_mode       = NAND_ECC_SOFT,
        .parts          = nand_partitions,
        .num_parts      = ARRAY_SIZE(num_partitions),
 };
index 22c97ef..cf60d0a 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __ASM_AVR32_IO_H
 #define __ASM_AVR32_IO_H
 
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/types.h>
index 402a7bb..889c544 100644 (file)
@@ -1055,8 +1055,6 @@ struct platform_device *__init at32_add_device_usart(unsigned int id)
        return at32_usarts[id];
 }
 
-struct platform_device *atmel_default_console_device;
-
 void __init at32_setup_serial_console(unsigned int usart_id)
 {
        atmel_default_console_device = at32_usarts[usart_id];
index 67b111c..7173386 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/types.h>
 #include <linux/serial.h>
 #include <linux/platform_data/macb.h>
+#include <linux/platform_data/atmel_nand.h>
 
 #define GPIO_PIN_NONE  (-1)
 
@@ -116,18 +117,6 @@ struct platform_device *
 at32_add_device_cf(unsigned int id, unsigned int extint,
                struct cf_platform_data *data);
 
-/* NAND / SmartMedia */
-struct atmel_nand_data {
-       int     enable_pin;     /* chip enable */
-       int     det_pin;        /* card detect */
-       int     rdy_pin;        /* ready/busy */
-       u8      rdy_pin_active_low;     /* rdy_pin value is inverted */
-       u8      ale;            /* address line number connected to ALE */
-       u8      cle;            /* address line number connected to CLE */
-       u8      bus_width_16;   /* buswidth is 16 bit */
-       struct mtd_partition *parts;
-       unsigned int    num_parts;
-};
 struct platform_device *
 at32_add_device_nand(unsigned int id, struct atmel_nand_data *data);
 
index 8181293..16a24b1 100644 (file)
@@ -30,9 +30,6 @@
 #define cpu_is_at91sam9261()   (0)
 #define cpu_is_at91sam9263()   (0)
 #define cpu_is_at91sam9rl()    (0)
-#define cpu_is_at91cap9()      (0)
-#define cpu_is_at91cap9_revB() (0)
-#define cpu_is_at91cap9_revC() (0)
 #define cpu_is_at91sam9g10()   (0)
 #define cpu_is_at91sam9g20()   (0)
 #define cpu_is_at91sam9g45()   (0)
index abe5a9e..c1269a1 100644 (file)
@@ -36,6 +36,7 @@ config BLACKFIN
        select GENERIC_ATOMIC64
        select GENERIC_IRQ_PROBE
        select IRQ_PER_CPU if SMP
+       select HAVE_NMI_WATCHDOG if NMI_WATCHDOG
 
 config GENERIC_CSUM
        def_bool y
index 12f4060..89de539 100644 (file)
@@ -38,8 +38,4 @@
 
 #include <asm-generic/irq.h>
 
-#ifdef CONFIG_NMI_WATCHDOG
-# define ARCH_HAS_NMI_WATCHDOG
-#endif
-
 #endif                         /* _BFIN_IRQ_H_ */
index 68c8af4..38a4312 100644 (file)
@@ -73,9 +73,6 @@ extern unsigned long empty_zero_page;
 #define pgtable_cache_init()   do { } while (0)
 #define io_remap_pfn_range      remap_pfn_range
 
-#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
-               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
-
 #include <asm-generic/pgtable.h>
 
 #endif /* _ASM_C6X_PGTABLE_H */
index b45be31..ecbab34 100644 (file)
@@ -192,12 +192,7 @@ static int handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka,
        if (rc)
                return rc;
 
-       spin_lock_irq(&current->sighand->siglock);
-       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-       if (!(ka->sa.sa_flags & SA_NODEFER))
-               sigaddset(&current->blocked, sig);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       block_sigmask(ka, sig);
 
        return 0;
 }
@@ -305,10 +300,7 @@ asmlinkage int sys_rt_sigreturn(void)
                goto badframe;
 
        sigdelsetmask(&blocked, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = blocked;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       set_current_blocked(&blocked);
 
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
                goto badframe;
index 16277c3..f212a45 100644 (file)
@@ -78,8 +78,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        /* MAYWRITE to allow gdb to COW and set breakpoints. */
        ret = install_special_mapping(mm, vdso_base, PAGE_SIZE,
                                      VM_READ|VM_EXEC|
-                                     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-                                     VM_ALWAYSDUMP,
+                                     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
                                      &vdso_page);
 
        if (ret)
index bc90c75..b9f82c8 100644 (file)
@@ -261,4 +261,8 @@ struct kvm_debug_exit_arch {
 struct kvm_guest_debug_arch {
 };
 
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
+
 #endif
index 2689ee5..e35b3a8 100644 (file)
@@ -459,6 +459,9 @@ struct kvm_sal_data {
        unsigned long boot_gp;
 };
 
+struct kvm_arch_memory_slot {
+};
+
 struct kvm_arch {
        spinlock_t dirty_log_lock;
 
index c5e6da9..5e04b59 100644 (file)
@@ -116,12 +116,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
        return (pci_domain_nr(bus) != 0);
 }
 
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-               struct pci_bus_region *region, struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
-               struct resource *res, struct pci_bus_region *region);
-
 static inline struct resource *
 pcibios_select_root(struct pci_dev *pdev, struct resource *res)
 {
index 93c6488..d1cc81e 100644 (file)
@@ -348,11 +348,11 @@ acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
 
        iosapic_override_isa_irq(p->source_irq, p->global_irq,
                                 ((p->inti_flags & ACPI_MADT_POLARITY_MASK) ==
-                                 ACPI_MADT_POLARITY_ACTIVE_HIGH) ?
-                                IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
+                                 ACPI_MADT_POLARITY_ACTIVE_LOW) ?
+                                IOSAPIC_POL_LOW : IOSAPIC_POL_HIGH,
                                 ((p->inti_flags & ACPI_MADT_TRIGGER_MASK) ==
-                                ACPI_MADT_TRIGGER_EDGE) ?
-                                IOSAPIC_EDGE : IOSAPIC_LEVEL);
+                                ACPI_MADT_TRIGGER_LEVEL) ?
+                                IOSAPIC_LEVEL : IOSAPIC_EDGE);
        return 0;
 }
 
index 4eed358..070e8ef 100644 (file)
@@ -157,7 +157,7 @@ void arch_crash_save_vmcoreinfo(void)
 #endif
 #ifdef CONFIG_PGTABLE_3
        VMCOREINFO_CONFIG(PGTABLE_3);
-#elif  CONFIG_PGTABLE_4
+#elif defined(CONFIG_PGTABLE_4)
        VMCOREINFO_CONFIG(PGTABLE_4);
 #endif
 }
index 9198a79..a39fe09 100644 (file)
@@ -1446,6 +1446,8 @@ out:
        /* Get the CMC error record and log it */
        ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
 
+       local_irq_disable();
+
        return IRQ_HANDLED;
 }
 
index 4050520..f5104b7 100644 (file)
@@ -809,10 +809,13 @@ static void kvm_build_io_pmt(struct kvm *kvm)
 #define GUEST_PHYSICAL_RR4     0x2739
 #define VMM_INIT_RR            0x1660
 
-int kvm_arch_init_vm(struct kvm *kvm)
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
        BUG_ON(!kvm);
 
+       if (type)
+               return -EINVAL;
+
        kvm->arch.is_sn2 = ia64_platform_is("sn2");
 
        kvm->arch.metaphysical_rr0 = GUEST_PHYSICAL_RR0;
@@ -1169,6 +1172,11 @@ out:
 
 #define PALE_RESET_ENTRY    0x80000000ffffffb0UL
 
+bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
+{
+       return irqchip_in_kernel(vcpu->kcm) == (vcpu->arch.apic != NULL);
+}
+
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
        struct kvm_vcpu *v;
@@ -1563,6 +1571,21 @@ out:
        return r;
 }
 
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+       return VM_FAULT_SIGBUS;
+}
+
+void kvm_arch_free_memslot(struct kvm_memory_slot *free,
+                          struct kvm_memory_slot *dont)
+{
+}
+
+int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
+{
+       return 0;
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                struct kvm_memory_slot *memslot,
                struct kvm_memory_slot old,
index 9462792..524df42 100644 (file)
@@ -319,7 +319,8 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
         * Ignore these tiny memory ranges */
        if (!((window->resource.flags & IORESOURCE_MEM) &&
              (window->resource.end - window->resource.start < 16)))
-               pci_add_resource(&info->resources, &window->resource);
+               pci_add_resource_offset(&info->resources, &window->resource,
+                                       window->offset);
 
        return AE_OK;
 }
@@ -394,54 +395,6 @@ out1:
        return NULL;
 }
 
-void pcibios_resource_to_bus(struct pci_dev *dev,
-               struct pci_bus_region *region, struct resource *res)
-{
-       struct pci_controller *controller = PCI_CONTROLLER(dev);
-       unsigned long offset = 0;
-       int i;
-
-       for (i = 0; i < controller->windows; i++) {
-               struct pci_window *window = &controller->window[i];
-               if (!(window->resource.flags & res->flags))
-                       continue;
-               if (window->resource.start > res->start)
-                       continue;
-               if (window->resource.end < res->end)
-                       continue;
-               offset = window->offset;
-               break;
-       }
-
-       region->start = res->start - offset;
-       region->end = res->end - offset;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *dev,
-               struct resource *res, struct pci_bus_region *region)
-{
-       struct pci_controller *controller = PCI_CONTROLLER(dev);
-       unsigned long offset = 0;
-       int i;
-
-       for (i = 0; i < controller->windows; i++) {
-               struct pci_window *window = &controller->window[i];
-               if (!(window->resource.flags & res->flags))
-                       continue;
-               if (window->resource.start - window->offset > region->start)
-                       continue;
-               if (window->resource.end - window->offset < region->end)
-                       continue;
-               offset = window->offset;
-               break;
-       }
-
-       res->start = region->start + offset;
-       res->end = region->end + offset;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
 static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
 {
        unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
@@ -463,15 +416,11 @@ static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
 static void __devinit
 pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
 {
-       struct pci_bus_region region;
        int i;
 
        for (i = start; i < limit; i++) {
                if (!dev->resource[i].flags)
                        continue;
-               region.start = dev->resource[i].start;
-               region.end = dev->resource[i].end;
-               pcibios_bus_to_resource(dev, &dev->resource[i], &region);
                if ((is_valid_resource(dev, i)))
                        pci_claim_resource(dev, i);
        }
index 08b0d9b..f925dec 100644 (file)
@@ -192,6 +192,7 @@ void hub_error_init(struct hubdev_info *hubdev_info)
                    hubdev_info);
                return;
        }
+       irq_set_handler(SGI_II_ERROR, handle_level_irq);
        sn_set_err_irq_affinity(SGI_II_ERROR);
 }
 
@@ -213,6 +214,7 @@ void ice_error_init(struct hubdev_info *hubdev_info)
                        hubdev_info);
                return;
        }
+       irq_set_handler(SGI_TIO_ERROR, handle_level_irq);
        sn_set_err_irq_affinity(SGI_TIO_ERROR);
 }
 
index 4433dd0..fbb5f2f 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/bootmem.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <asm/sn/types.h>
 #include <asm/sn/addrs.h>
index 0a36f08..238e2c5 100644 (file)
@@ -297,7 +297,8 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        s64 status = 0;
        struct pci_controller *controller;
        struct pcibus_bussoft *prom_bussoft_ptr;
-
+       LIST_HEAD(resources);
+       int i;
 
        status = sal_get_pcibus_info((u64) segment, (u64) busnum,
                                     (u64) ia64_tpa(&prom_bussoft_ptr));
@@ -315,7 +316,15 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
         */
        controller->platform_data = prom_bussoft_ptr;
 
-       bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+       sn_legacy_pci_window_fixup(controller,
+                                  prom_bussoft_ptr->bs_legacy_io,
+                                  prom_bussoft_ptr->bs_legacy_mem);
+       for (i = 0; i < controller->windows; i++)
+               pci_add_resource_offset(&resources,
+                                       &controller->window[i].resource,
+                                       controller->window[i].offset);
+       bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller,
+                               &resources);
        if (bus == NULL)
                goto error_return; /* error, or bus already scanned */
 
@@ -348,9 +357,6 @@ sn_bus_fixup(struct pci_bus *bus)
                        return;
                }
                sn_common_bus_fixup(bus, prom_bussoft_ptr);
-               sn_legacy_pci_window_fixup(PCI_CONTROLLER(bus),
-                                          prom_bussoft_ptr->bs_legacy_io,
-                                          prom_bussoft_ptr->bs_legacy_mem);
         }
         list_for_each_entry(pci_dev, &bus->devices, bus_list) {
                 sn_io_slot_fixup(pci_dev);
index dfac09a..62cf4dd 100644 (file)
@@ -352,6 +352,8 @@ void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info)
        spin_lock(&sn_irq_info_lock);
        list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
        reserve_irq_vector(sn_irq_info->irq_irq);
+       if (sn_irq_info->irq_int_bit != -1)
+               irq_set_handler(sn_irq_info->irq_irq, handle_level_irq);
        spin_unlock(&sn_irq_info_lock);
 
        register_intr_pda(sn_irq_info);
index 2de41d4..4554f68 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/export.h>
 #include <linux/vmalloc.h>
 #include <linux/seq_file.h>
 #include <linux/miscdevice.h>
index 26aeccb..14c1711 100644 (file)
@@ -190,6 +190,7 @@ cx_device_register(nasid_t nasid, int part_num, int mfg_num,
                   struct hubdev_info *hubdev, int bt)
 {
        struct cx_dev *cx_dev;
+       int r;
 
        cx_dev = kzalloc(sizeof(struct cx_dev), GFP_KERNEL);
        DBG("cx_dev= 0x%p\n", cx_dev);
@@ -206,7 +207,11 @@ cx_device_register(nasid_t nasid, int part_num, int mfg_num,
        cx_dev->dev.bus = &tiocx_bus_type;
        cx_dev->dev.release = tiocx_bus_release;
        dev_set_name(&cx_dev->dev, "%d", cx_dev->cx_id.nasid);
-       device_register(&cx_dev->dev);
+       r = device_register(&cx_dev->dev);
+       if (r) {
+               kfree(cx_dev);
+               return r;
+       }
        get_device(&cx_dev->dev);
 
        device_create_file(&cx_dev->dev, &dev_attr_cxdev_control);
index 8886a0b..8dbbef4 100644 (file)
@@ -146,6 +146,7 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
                printk(KERN_WARNING
                       "pcibr cannot allocate interrupt for error handler\n");
        }
+       irq_set_handler(SGI_PCIASIC_ERROR, handle_level_irq);
        sn_set_err_irq_affinity(SGI_PCIASIC_ERROR);
 
        /* 
index e77c477..a70b11f 100644 (file)
@@ -649,6 +649,7 @@ tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
                       __func__, SGI_TIOCA_ERROR,
                       (int)tioca_common->ca_common.bs_persist_busnum);
 
+       irq_set_handler(SGI_TIOCA_ERROR, handle_level_irq);
        sn_set_err_irq_affinity(SGI_TIOCA_ERROR);
 
        /* Setup locality information */
index 27faba0..46d3df4 100644 (file)
@@ -1037,6 +1037,7 @@ tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
                       tioce_common->ce_pcibus.bs_persist_segment,
                       tioce_common->ce_pcibus.bs_persist_busnum);
 
+       irq_set_handler(SGI_PCIASIC_ERROR, handle_level_irq);
        sn_set_err_irq_affinity(SGI_PCIASIC_ERROR);
        return tioce_common;
 }
index 11060fa..ac22dc7 100644 (file)
@@ -1,6 +1,7 @@
 config MICROBLAZE
        def_bool y
        select HAVE_MEMBLOCK
+       select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
        select HAVE_FUNCTION_GRAPH_TRACER
@@ -28,6 +29,12 @@ config SWAP
 config RWSEM_GENERIC_SPINLOCK
        def_bool y
 
+config ZONE_DMA
+       def_bool y
+
+config ARCH_POPULATES_NODE_MAP
+       def_bool y
+
 config RWSEM_XCHGADD_ALGORITHM
        bool
 
@@ -153,20 +160,18 @@ config XILINX_UNCACHED_SHADOW
          The feature requires the design to define the RAM memory controller
          window to be twice as large as the actual physical memory.
 
-config HIGHMEM_START_BOOL
-       bool "Set high memory pool address"
-       depends on ADVANCED_OPTIONS && HIGHMEM
+config HIGHMEM
+       bool "High memory support"
+       depends on MMU
        help
-         This option allows you to set the base address of the kernel virtual
-         area used to map high memory pages.  This can be useful in
-         optimizing the layout of kernel virtual memory.
+         The address space of Microblaze processors is only 4 Gigabytes large
+         and it has to accommodate user address space, kernel address
+         space as well as some memory mapped IO. That means that, if you
+         have a large amount of physical memory and/or IO, not all of the
+         memory can be "permanently mapped" by the kernel. The physical
+         memory that is not permanently mapped is called "high memory".
 
-         Say N here unless you know what you are doing.
-
-config HIGHMEM_START
-       hex "Virtual start address of high memory pool" if HIGHMEM_START_BOOL
-       depends on MMU
-       default "0xfe000000"
+         If unsure, say n.
 
 config LOWMEM_SIZE_BOOL
        bool "Set maximum low memory"
@@ -255,6 +260,10 @@ config MICROBLAZE_32K_PAGES
 
 endchoice
 
+config KERNEL_PAD
+       hex "Kernel PAD for unpacking" if ADVANCED_OPTIONS
+       default "0x80000" if MMU
+
 endmenu
 
 source "mm/Kconfig"
index 0c796cf..34940c8 100644 (file)
@@ -8,7 +8,7 @@ obj-y += linked_dtb.o
 
 targets := linux.bin linux.bin.gz simpleImage.%
 
-OBJCOPYFLAGS := -O binary
+OBJCOPYFLAGS := -R .note -R .comment -R .note.gnu.build-id -O binary
 
 # Ensure system.dtb exists
 $(obj)/linked_dtb.o: $(obj)/system.dtb
diff --git a/arch/microblaze/include/asm/fixmap.h b/arch/microblaze/include/asm/fixmap.h
new file mode 100644 (file)
index 0000000..f2b312e
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * fixmap.h: compile-time virtual memory allocation
+ *
+ * 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) 1998 Ingo Molnar
+ *
+ * Copyright 2008 Freescale Semiconductor Inc.
+ *   Port to powerpc added by Kumar Gala
+ *
+ * Copyright 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright 2011 PetaLogix Qld Pty Ltd
+ *   Port to Microblaze
+ */
+
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
+#ifndef __ASSEMBLY__
+#include <linux/kernel.h>
+#include <asm/page.h>
+#ifdef CONFIG_HIGHMEM
+#include <linux/threads.h>
+#include <asm/kmap_types.h>
+#endif
+
+#define FIXADDR_TOP    ((unsigned long)(-PAGE_SIZE))
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process. We allocate these special addresses
+ * from the end of virtual memory (0xfffff000) backwards.
+ * Also this lets us do fail-safe vmalloc(), we
+ * can guarantee that these special addresses and
+ * vmalloc()-ed addresses never overlap.
+ *
+ * these 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * highger than 1) use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ * TLB entries of such buffers will not be flushed across
+ * task switches.
+ */
+enum fixed_addresses {
+       FIX_HOLE,
+#ifdef CONFIG_HIGHMEM
+       FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
+       FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * num_possible_cpus()) - 1,
+#endif
+       __end_of_fixed_addresses
+};
+
+extern void __set_fixmap(enum fixed_addresses idx,
+                                       phys_addr_t phys, pgprot_t flags);
+
+#define set_fixmap(idx, phys) \
+               __set_fixmap(idx, phys, PAGE_KERNEL)
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys) \
+               __set_fixmap(idx, phys, PAGE_KERNEL_CI)
+
+#define clear_fixmap(idx) \
+               __set_fixmap(idx, 0, __pgprot(0))
+
+#define __FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START          (FIXADDR_TOP - __FIXADDR_SIZE)
+
+#define __fix_to_virt(x)       (FIXADDR_TOP - ((x) << PAGE_SHIFT))
+#define __virt_to_fix(x)       ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
+
+extern void __this_fixmap_does_not_exist(void);
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without tranlation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static __always_inline unsigned long fix_to_virt(const unsigned int idx)
+{
+       /*
+        * this branch gets completely eliminated after inlining,
+        * except when someone tries to use fixaddr indices in an
+        * illegal way. (such as mixing up address types or using
+        * out-of-range indices).
+        *
+        * If it doesn't get removed, the linker will complain
+        * loudly with a reasonably clear error message..
+        */
+       if (idx >= __end_of_fixed_addresses)
+               __this_fixmap_does_not_exist();
+
+       return __fix_to_virt(idx);
+}
+
+static inline unsigned long virt_to_fix(const unsigned long vaddr)
+{
+       BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
+       return __virt_to_fix(vaddr);
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif
diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h
new file mode 100644 (file)
index 0000000..2446a73
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * highmem.h: virtual kernel memory mappings for high memory
+ *
+ * Used in CONFIG_HIGHMEM systems for memory pages which
+ * are not addressable by direct kernel virtual addresses.
+ *
+ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
+ *                   Gerhard.Wichert@pdb.siemens.de
+ *
+ *
+ * Redesigned the x86 32-bit VM architecture to deal with
+ * up to 16 Terabyte physical memory. With current x86 CPUs
+ * we now support up to 64 Gigabytes physical RAM.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ */
+#ifndef _ASM_HIGHMEM_H
+#define _ASM_HIGHMEM_H
+
+#ifdef __KERNEL__
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <asm/fixmap.h>
+
+extern pte_t *kmap_pte;
+extern pgprot_t kmap_prot;
+extern pte_t *pkmap_page_table;
+
+/*
+ * Right now we initialize only a single pte table. It can be extended
+ * easily, subsequent pte tables have to be allocated in one physical
+ * chunk of RAM.
+ */
+/*
+ * We use one full pte table with 4K pages. And with 16K/64K/256K pages pte
+ * table covers enough memory (32MB/512MB/2GB resp.), so that both FIXMAP
+ * and PKMAP can be placed in a single pte table. We use 512 pages for PKMAP
+ * in case of 16K/64K/256K page sizes.
+ */
+
+#define PKMAP_ORDER    PTE_SHIFT
+#define LAST_PKMAP     (1 << PKMAP_ORDER)
+
+#define PKMAP_BASE     ((FIXADDR_START - PAGE_SIZE * (LAST_PKMAP + 1)) \
+                                                               & PMD_MASK)
+
+#define LAST_PKMAP_MASK        (LAST_PKMAP - 1)
+#define PKMAP_NR(virt)  ((virt - PKMAP_BASE) >> PAGE_SHIFT)
+#define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))
+
+extern void *kmap_high(struct page *page);
+extern void kunmap_high(struct page *page);
+extern void *kmap_atomic_prot(struct page *page, pgprot_t prot);
+extern void __kunmap_atomic(void *kvaddr);
+
+static inline void *kmap(struct page *page)
+{
+       might_sleep();
+       if (!PageHighMem(page))
+               return page_address(page);
+       return kmap_high(page);
+}
+
+static inline void kunmap(struct page *page)
+{
+       BUG_ON(in_interrupt());
+       if (!PageHighMem(page))
+               return;
+       kunmap_high(page);
+}
+
+static inline void *__kmap_atomic(struct page *page)
+{
+       return kmap_atomic_prot(page, kmap_prot);
+}
+
+static inline struct page *kmap_atomic_to_page(void *ptr)
+{
+       unsigned long idx, vaddr = (unsigned long) ptr;
+       pte_t *pte;
+
+       if (vaddr < FIXADDR_START)
+               return virt_to_page(ptr);
+
+       idx = virt_to_fix(vaddr);
+       pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
+       return pte_page(*pte);
+}
+
+#define flush_cache_kmaps()    { flush_icache(); flush_dcache(); }
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_HIGHMEM_H */
index 8d6a654..1f9eddd 100644 (file)
@@ -56,6 +56,12 @@ typedef struct _SEGREG {
 
 extern void _tlbie(unsigned long va);  /* invalidate a TLB entry */
 extern void _tlbia(void);              /* invalidate all TLB entries */
+
+/*
+ * tlb_skip size stores actual number skipped TLBs from TLB0 - every directy TLB
+ * mapping has to increase tlb_skip size.
+ */
+extern u32 tlb_skip;
 #   endif /* __ASSEMBLY__ */
 
 /*
@@ -69,6 +75,12 @@ extern void _tlbia(void);            /* invalidate all TLB entries */
 
 #  define MICROBLAZE_TLB_SIZE 64
 
+/* For cases when you want to skip some TLB entries */
+#  define MICROBLAZE_TLB_SKIP 0
+
+/* Use the last TLB for temporary access to LMB */
+#  define MICROBLAZE_LMB_TLB_ID 63
+
 /*
  * TLB entries are defined by a "high" tag portion and a "low" data
  * portion. The data portion is 32-bits.
index a25e6b5..287c548 100644 (file)
@@ -135,8 +135,10 @@ extern unsigned long min_low_pfn;
 extern unsigned long max_pfn;
 
 extern unsigned long memory_start;
-extern unsigned long memory_end;
 extern unsigned long memory_size;
+extern unsigned long lowmem_size;
+
+extern unsigned long kernel_tlb;
 
 extern int page_is_ram(unsigned long pfn);
 
index e9834b2..cb5d397 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/pci.h>
 #include <linux/list.h>
 #include <linux/ioport.h>
-#include <asm-generic/pci-bridge.h>
 
 struct device_node;
 
index 0331376..a0da88b 100644 (file)
@@ -94,14 +94,6 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
  */
 #define PCI_DMA_BUS_IS_PHYS     (1)
 
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-                       struct pci_bus_region *region,
-                       struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
-                       struct resource *res,
-                       struct pci_bus_region *region);
-
 static inline struct resource *pcibios_select_root(struct pci_dev *pdev,
                        struct resource *res)
 {
index b2af423..3ef7b9c 100644 (file)
@@ -94,8 +94,7 @@ static inline pte_t pte_mkspecial(pte_t pte)  { return pte; }
 /* Start and end of the vmalloc area. */
 /* Make sure to map the vmalloc area above the pinned kernel memory area
    of 32Mb.  */
-#define VMALLOC_START  (CONFIG_KERNEL_START + \
-                               max(32 * 1024 * 1024UL, memory_size))
+#define VMALLOC_START  (CONFIG_KERNEL_START + CONFIG_LOWMEM_SIZE)
 #define VMALLOC_END    ioremap_bot
 
 #endif /* __ASSEMBLY__ */
@@ -543,8 +542,6 @@ extern unsigned long iopa(unsigned long addr);
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
 #define kern_addr_valid(addr)  (1)
 
-#define io_remap_page_range remap_page_range
-
 /*
  * No page table caches to initialise
  */
index aa22511..0061aa1 100644 (file)
@@ -41,7 +41,8 @@ extern void of_platform_reset_gpio_probe(void);
 void time_init(void);
 void init_IRQ(void);
 void machine_early_init(const char *cmdline, unsigned int ram,
-                       unsigned int fdt, unsigned int msr);
+               unsigned int fdt, unsigned int msr, unsigned int tlb0,
+               unsigned int tlb1);
 
 void machine_restart(char *cmd);
 void machine_shutdown(void);
index 072b007..ef25f75 100644 (file)
@@ -80,7 +80,7 @@ extern unsigned long search_exception_table(unsigned long);
 static inline int ___range_ok(unsigned long addr, unsigned long size)
 {
        return ((addr < memory_start) ||
-               ((addr + size) > memory_end));
+               ((addr + size - 1) > (memory_start + memory_size - 1)));
 }
 
 #define __range_ok(addr, size) \
index 54194b2..eab6abf 100644 (file)
@@ -35,6 +35,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
        {"8.00.b", 0x13},
        {"8.10.a", 0x14},
        {"8.20.a", 0x15},
+       {"8.20.b", 0x16},
+       {"8.30.a", 0x17},
        {NULL, 0},
 };
 
index 8356e47..ec48587 100644 (file)
@@ -171,10 +171,24 @@ void __init remap_early_printk(void)
 {
        if (!early_console_initialized || !early_console)
                return;
-       printk(KERN_INFO "early_printk_console remaping from 0x%x to ",
+       printk(KERN_INFO "early_printk_console remapping from 0x%x to ",
                                                                base_addr);
        base_addr = (u32) ioremap(base_addr, PAGE_SIZE);
        printk(KERN_CONT "0x%x\n", base_addr);
+
+       /*
+        * Early console is on the top of skipped TLB entries
+        * decrease tlb_skip size ensure that hardcoded TLB entry will be
+        * used by generic algorithm
+        * FIXME check if early console mapping is on the top by rereading
+        * TLB entry and compare baseaddr
+        *  mts  rtlbx, (tlb_skip - 1)
+        *  nop
+        *  mfs  rX, rtlblo
+        *  nop
+        *  cmp rX, orig_base_addr
+        */
+       tlb_skip -= 1;
 }
 
 void __init disable_early_printk(void)
index 77320b8..98b17f9 100644 (file)
@@ -63,9 +63,7 @@ ENTRY(_start)
 real_start:
 #endif
 
-       mfs     r1, rmsr
-       andi    r1, r1, ~2
-       mts     rmsr, r1
+       mts     rmsr, r0
 /*
  * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
  * if the msrclr instruction is not enabled. We use this to detect
@@ -73,6 +71,7 @@ real_start:
  * r8 == 0 - msr instructions are implemented
  * r8 != 0 - msr instructions are not implemented
  */
+       mfs     r1, rmsr
        msrclr  r8, 0 /* clear nothing - just read msr for test */
        cmpu    r8, r8, r1 /* r1 must contain msr reg content */
 
@@ -96,7 +95,7 @@ big_endian:
 _prepare_copy_fdt:
        or      r11, r0, r0 /* incremment */
        ori     r4, r0, TOPHYS(_fdt_start)
-       ori     r3, r0, (0x4000 - 4)
+       ori     r3, r0, (0x8000 - 4)
 _copy_fdt:
        lw      r12, r7, r11 /* r12 = r7 + r11 */
        sw      r12, r4, r11 /* addr[r4 + r11] = r12 */
@@ -150,6 +149,7 @@ _copy_bram:
 _invalidate:
        mts     rtlbx, r3
        mts     rtlbhi, r0                      /* flush: ensure V is clear   */
+       mts     rtlblo, r0
        bgtid   r3, _invalidate         /* loop for all entries       */
        addik   r3, r3, -1
        /* sync */
@@ -169,6 +169,53 @@ _invalidate:
        addik   r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
        tophys(r4,r3)                   /* Load the kernel physical address */
 
+       /* start to do TLB calculation */
+       addik   r12, r0, _end
+       rsub    r12, r3, r12
+       addik   r12, r12, CONFIG_KERNEL_PAD /* that's the pad */
+
+       or r9, r0, r0 /* TLB0 = 0 */
+       or r10, r0, r0 /* TLB1 = 0 */
+
+       addik   r11, r12, -0x1000000
+       bgei    r11, GT16 /* size is greater than 16MB */
+       addik   r11, r12, -0x0800000
+       bgei    r11, GT8 /* size is greater than 8MB */
+       addik   r11, r12, -0x0400000
+       bgei    r11, GT4 /* size is greater than 4MB */
+       /* size is less than 4MB */
+       addik   r11, r12, -0x0200000
+       bgei    r11, GT2 /* size is greater than 2MB */
+       addik   r9, r0, 0x0100000 /* TLB0 must be 1MB */
+       addik   r11, r12, -0x0100000
+       bgei    r11, GT1 /* size is greater than 1MB */
+       /* TLB1 is 0 which is setup above */
+       bri tlb_end
+GT4: /* r11 contains the rest - will be either 1 or 4 */
+       ori r9, r0, 0x400000 /* TLB0 is 4MB */
+       bri TLB1
+GT16: /* TLB0 is 16MB */
+       addik   r9, r0, 0x1000000 /* means TLB0 is 16MB */
+TLB1:
+       /* must be used r2 because of substract if failed */
+       addik   r2, r11, -0x0400000
+       bgei    r2, GT20 /* size is greater than 16MB */
+       /* size is >16MB and <20MB */
+       addik   r11, r11, -0x0100000
+       bgei    r11, GT17 /* size is greater than 17MB */
+       /* kernel is >16MB and < 17MB */
+GT1:
+       addik   r10, r0, 0x0100000 /* means TLB1 is 1MB */
+       bri tlb_end
+GT2: /* TLB0 is 0 and TLB1 will be 4MB */
+GT17: /* TLB1 is 4MB - kernel size <20MB */
+       addik   r10, r0, 0x0400000 /* means TLB1 is 4MB */
+       bri tlb_end
+GT8: /* TLB0 is still zero that's why I can use only TLB1 */
+GT20: /* TLB1 is 16MB - kernel size >20MB */
+       addik   r10, r0, 0x1000000 /* means TLB1 is 16MB */
+tlb_end:
+
        /*
         * Configure and load two entries into TLB slots 0 and 1.
         * In case we are pinning TLBs, these are reserved in by the
@@ -178,28 +225,81 @@ _invalidate:
        andi    r4,r4,0xfffffc00        /* Mask off the real page number */
        ori     r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
 
+       /*
+        * TLB0 is always used - check if is not zero (r9 stores TLB0 value)
+        * if is use TLB1 value and clear it (r10 stores TLB1 value)
+        */
+       bnei    r9, tlb0_not_zero
+       add     r9, r10, r0
+       add     r10, r0, r0
+tlb0_not_zero:
+
+       /* look at the code below */
+       ori     r30, r0, 0x200
+       andi    r29, r9, 0x100000
+       bneid   r29, 1f
+       addik   r30, r30, 0x80
+       andi    r29, r9, 0x400000
+       bneid   r29, 1f
+       addik   r30, r30, 0x80
+       andi    r29, r9, 0x1000000
+       bneid   r29, 1f
+       addik   r30, r30, 0x80
+1:
        andi    r3,r3,0xfffffc00        /* Mask off the effective page number */
-       ori     r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M))
+       ori     r3,r3,(TLB_VALID)
+       or      r3, r3, r30
 
-       mts     rtlbx,r0                /* TLB slow 0 */
+       /* Load tlb_skip size value which is index to first unused TLB entry */
+       lwi     r11, r0, TOPHYS(tlb_skip)
+       mts     rtlbx,r11               /* TLB slow 0 */
 
        mts     rtlblo,r4               /* Load the data portion of the entry */
        mts     rtlbhi,r3               /* Load the tag portion of the entry */
 
-       addik   r4, r4, 0x01000000      /* Map next 16 M entries */
-       addik   r3, r3, 0x01000000
+       /* Increase tlb_skip size */
+       addik   r11, r11, 1
+       swi     r11, r0, TOPHYS(tlb_skip)
+
+       /* TLB1 can be zeroes that's why we not setup it */
+       beqi    r10, jump_over2
+
+       /* look at the code below */
+       ori     r30, r0, 0x200
+       andi    r29, r10, 0x100000
+       bneid   r29, 1f
+       addik   r30, r30, 0x80
+       andi    r29, r10, 0x400000
+       bneid   r29, 1f
+       addik   r30, r30, 0x80
+       andi    r29, r10, 0x1000000
+       bneid   r29, 1f
+       addik   r30, r30, 0x80
+1:
+       addk    r4, r4, r9      /* previous addr + TLB0 size */
+       addk    r3, r3, r9
 
-       ori     r6,r0,1                 /* TLB slot 1 */
-       mts     rtlbx,r6
+       andi    r3,r3,0xfffffc00        /* Mask off the effective page number */
+       ori     r3,r3,(TLB_VALID)
+       or      r3, r3, r30
+
+       lwi     r11, r0, TOPHYS(tlb_skip)
+       mts     rtlbx, r11              /* r11 is used from TLB0 */
 
        mts     rtlblo,r4               /* Load the data portion of the entry */
        mts     rtlbhi,r3               /* Load the tag portion of the entry */
 
+       /* Increase tlb_skip size */
+       addik   r11, r11, 1
+       swi     r11, r0, TOPHYS(tlb_skip)
+
+jump_over2:
        /*
         * Load a TLB entry for LMB, since we need access to
         * the exception vectors, using a 4k real==virtual mapping.
         */
-       ori     r6,r0,3                 /* TLB slot 3 */
+       /* Use temporary TLB_ID for LMB - clear this temporary mapping later */
+       ori     r6, r0, MICROBLAZE_LMB_TLB_ID
        mts     rtlbx,r6
 
        ori     r4,r0,(TLB_WR | TLB_EX)
@@ -238,8 +338,8 @@ start_here:
         * Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
         * the function.
         */
-       addik   r9, r0, machine_early_init
-       brald   r15, r9
+       addik   r11, r0, machine_early_init
+       brald   r15, r11
        nop
 
 #ifndef CONFIG_MMU
@@ -268,8 +368,7 @@ start_here:
 
        /* Load up the kernel context */
 kernel_load_context:
-       # Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away.
-       ori     r5,r0,3
+       ori     r5, r0, MICROBLAZE_LMB_TLB_ID
        mts     rtlbx,r5
        nop
        mts     rtlbhi,r0
index e62be83..aa510f4 100644 (file)
@@ -820,19 +820,26 @@ ex_handler_done:
  *     Upon exit, we reload everything and RFI.
  * A common place to load the TLB.
  */
+.section .data
+.align 4
+.global tlb_skip
+       tlb_skip:
+               .long   MICROBLAZE_TLB_SKIP
        tlb_index:
-               .long   1 /* MS: storing last used tlb index */
+               /* MS: storing last used tlb index */
+               .long   MICROBLAZE_TLB_SIZE/2
+.previous
        finish_tlb_load:
                /* MS: load the last used TLB index. */
                lwi     r5, r0, TOPHYS(tlb_index)
                addik   r5, r5, 1 /* MS: inc tlb_index -> use next one */
 
 /* MS: FIXME this is potential fault, because this is mask not count */
-               andi    r5, r5, (MICROBLAZE_TLB_SIZE-1)
+               andi    r5, r5, MICROBLAZE_TLB_SIZE - 1
                ori     r6, r0, 1
                cmp     r31, r5, r6
                blti    r31, ex12
-               addik   r5, r6, 1
+               lwi     r5, r0, TOPHYS(tlb_skip)
        ex12:
                /* MS: save back current TLB index */
                swi     r5, r0, TOPHYS(tlb_index)
index ad12067..6c54d4d 100644 (file)
@@ -151,8 +151,8 @@ void __init init_IRQ(void)
 #ifdef CONFIG_SELFMOD_INTC
        selfmod_function((int *) arr_func, intc_baseaddr);
 #endif
-       printk(KERN_INFO "XPS intc #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
-               intc_baseaddr, nr_irq, intr_mask);
+       printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
+               intc->name, intc_baseaddr, nr_irq, intr_mask);
 
        /*
         * Disable all external interrupts until they are
index 206da3d..1dafdde 100644 (file)
 .type  _tlbia, @function
 .align 4;
 _tlbia:
-       addik   r12, r0, MICROBLAZE_TLB_SIZE - 1 /* flush all entries (63 - 3) */
+       lwi     r12, r0, tlb_skip;
        /* isync */
 _tlbia_1:
        mts     rtlbx, r12
        nop
        mts     rtlbhi, r0 /* flush: ensure V is clear */
        nop
-       addik   r11, r12, -2
+       rsubi   r11, r12, MICROBLAZE_TLB_SIZE - 1
        bneid   r11, _tlbia_1 /* loop for all entries */
-       addik   r12, r12, -1
+       addik   r12, r12, 1
        /* sync */
        rtsd    r15, 8
        nop
@@ -75,7 +75,7 @@ early_console_reg_tlb_alloc:
         * Load a TLB entry for the UART, so that microblaze_progress() can use
         * the UARTs nice and early.  We use a 4k real==virtual mapping.
         */
-       ori     r4, r0, MICROBLAZE_TLB_SIZE - 1
+       lwi     r4, r0, tlb_skip
        mts     rtlbx, r4 /* TLB slot 63 */
 
        or      r4,r5,r0
@@ -89,6 +89,11 @@ early_console_reg_tlb_alloc:
        nop
        mts     rtlbhi,r5 /* Load the tag portion of the entry */
        nop
+
+       lwi     r5, r0, tlb_skip
+       addik   r5, r5, 1
+       swi     r5, r0, tlb_skip
+
        rtsd    r15, 8
        nop
 
index 7a9f39e..71af974 100644 (file)
@@ -94,8 +94,11 @@ inline unsigned get_romfs_len(unsigned *addr)
 }
 #endif /* CONFIG_MTD_UCLINUX_EBSS */
 
+unsigned long kernel_tlb;
+
 void __init machine_early_init(const char *cmdline, unsigned int ram,
-               unsigned int fdt, unsigned int msr)
+               unsigned int fdt, unsigned int msr, unsigned int tlb0,
+               unsigned int tlb1)
 {
        unsigned long *src, *dst;
        unsigned int offset = 0;
@@ -142,6 +145,12 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
        setup_early_printk(NULL);
 #endif
 
+       /* setup kernel_tlb after BSS cleaning
+        * Maybe worth to move to asm code */
+       kernel_tlb = tlb0 + tlb1;
+       /* printk("TLB1 0x%08x, TLB0 0x%08x, tlb 0x%x\n", tlb0,
+                                                       tlb1, kernel_tlb); */
+
        printk("Ramdisk addr 0x%08x, ", ram);
        if (fdt)
                printk("FDT at 0x%08x\n", fdt);
@@ -196,6 +205,19 @@ static int microblaze_debugfs_init(void)
        return of_debugfs_root == NULL;
 }
 arch_initcall(microblaze_debugfs_init);
+
+static int __init debugfs_tlb(void)
+{
+       struct dentry *d;
+
+       if (!of_debugfs_root)
+               return -ENODEV;
+
+       d = debugfs_create_u32("tlb_skip", S_IRUGO, of_debugfs_root, &tlb_skip);
+       if (!d)
+               return -ENOMEM;
+}
+device_initcall(debugfs_tlb);
 #endif
 
 static int dflt_bus_notify(struct notifier_block *nb,
index d3a38ec..522defa 100644 (file)
@@ -78,7 +78,7 @@ static inline void microblaze_timer0_start_periodic(unsigned long load_val)
         * !PWMA - disable pwm
         * TINT - clear interrupt status
         * ENT- enable timer itself
-        * EINT - enable interrupt
+        * ENIT - enable interrupt
         * !LOAD - clear the bit to let go
         * ARHT - auto reload
         * !CAPT - no external trigger
@@ -273,8 +273,8 @@ void __init time_init(void)
 #ifdef CONFIG_SELFMOD_TIMER
        selfmod_function((int *) arr_func, timer_baseaddr);
 #endif
-       printk(KERN_INFO "XPS timer #0 at 0x%08x, irq=%d\n",
-               timer_baseaddr, irq);
+       printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
+               timer->name, timer_baseaddr, irq);
 
        /* If there is clock-frequency property than use it */
        prop = of_get_property(timer, "clock-frequency", NULL);
index ac0e1a5..109e9d8 100644 (file)
@@ -44,7 +44,7 @@ SECTIONS {
        __fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) {
                _fdt_start = . ;                /* place for fdt blob */
                *(__fdt_blob) ;                 /* Any link-placed DTB */
-               . = _fdt_start + 0x4000;        /* Pad up to 16kbyte */
+               . = _fdt_start + 0x8000;        /* Pad up to 32kbyte */
                _fdt_end = . ;
        }
 
index 09c49ed..7313bd8 100644 (file)
@@ -5,3 +5,4 @@
 obj-y := consistent.o init.o
 
 obj-$(CONFIG_MMU) += pgtable.o mmu_context.o fault.o
+obj-$(CONFIG_HIGHMEM) += highmem.o
diff --git a/arch/microblaze/mm/highmem.c b/arch/microblaze/mm/highmem.c
new file mode 100644 (file)
index 0000000..7d78838
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * highmem.c: virtual kernel memory mappings for high memory
+ *
+ * PowerPC version, stolen from the i386 version.
+ *
+ * Used in CONFIG_HIGHMEM systems for memory pages which
+ * are not addressable by direct kernel virtual addresses.
+ *
+ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
+ *                   Gerhard.Wichert@pdb.siemens.de
+ *
+ *
+ * Redesigned the x86 32-bit VM architecture to deal with
+ * up to 16 Terrabyte physical memory. With current x86 CPUs
+ * we now support up to 64 Gigabytes physical RAM.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ *
+ * Reworked for PowerPC by various contributors. Moved from
+ * highmem.h by Benjamin Herrenschmidt (c) 2009 IBM Corp.
+ */
+
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+/*
+ * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
+ * gives a more generic (and caching) interface. But kmap_atomic can
+ * be used in IRQ contexts, so in some (very limited) cases we need
+ * it.
+ */
+#include <asm/tlbflush.h>
+
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
+{
+
+       unsigned long vaddr;
+       int idx, type;
+
+       /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+       pagefault_disable();
+       if (!PageHighMem(page))
+               return page_address(page);
+
+
+       type = kmap_atomic_idx_push();
+       idx = type + KM_TYPE_NR*smp_processor_id();
+       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+#ifdef CONFIG_DEBUG_HIGHMEM
+       BUG_ON(!pte_none(*(kmap_pte-idx)));
+#endif
+       set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
+       local_flush_tlb_page(NULL, vaddr);
+
+       return (void *) vaddr;
+}
+EXPORT_SYMBOL(kmap_atomic_prot);
+
+void __kunmap_atomic(void *kvaddr)
+{
+       unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
+       int type;
+
+       if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
+               pagefault_enable();
+               return;
+       }
+
+       type = kmap_atomic_idx();
+#ifdef CONFIG_DEBUG_HIGHMEM
+       {
+               unsigned int idx;
+
+               idx = type + KM_TYPE_NR * smp_processor_id();
+               BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+
+               /*
+                * force other mappings to Oops if they'll try to access
+                * this pte without first remap it
+                */
+               pte_clear(&init_mm, vaddr, kmap_pte-idx);
+               local_flush_tlb_page(NULL, vaddr);
+       }
+#endif
+       kmap_atomic_idx_pop();
+       pagefault_enable();
+}
+EXPORT_SYMBOL(__kunmap_atomic);
index 565d193..ce80823 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
 #include <asm/tlb.h>
+#include <asm/fixmap.h>
 
 /* Use for MMU and noMMU because of PCI generic code */
 int mem_init_done;
@@ -44,9 +45,56 @@ char *klimit = _end;
  */
 unsigned long memory_start;
 EXPORT_SYMBOL(memory_start);
-unsigned long memory_end; /* due to mm/nommu.c */
 unsigned long memory_size;
 EXPORT_SYMBOL(memory_size);
+unsigned long lowmem_size;
+
+#ifdef CONFIG_HIGHMEM
+pte_t *kmap_pte;
+EXPORT_SYMBOL(kmap_pte);
+pgprot_t kmap_prot;
+EXPORT_SYMBOL(kmap_prot);
+
+static inline pte_t *virt_to_kpte(unsigned long vaddr)
+{
+       return pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr),
+                       vaddr), vaddr);
+}
+
+static void __init highmem_init(void)
+{
+       pr_debug("%x\n", (u32)PKMAP_BASE);
+       map_page(PKMAP_BASE, 0, 0);     /* XXX gross */
+       pkmap_page_table = virt_to_kpte(PKMAP_BASE);
+
+       kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN));
+       kmap_prot = PAGE_KERNEL;
+}
+
+static unsigned long highmem_setup(void)
+{
+       unsigned long pfn;
+       unsigned long reservedpages = 0;
+
+       for (pfn = max_low_pfn; pfn < max_pfn; ++pfn) {
+               struct page *page = pfn_to_page(pfn);
+
+               /* FIXME not sure about */
+               if (memblock_is_reserved(pfn << PAGE_SHIFT))
+                       continue;
+               ClearPageReserved(page);
+               init_page_count(page);
+               __free_page(page);
+               totalhigh_pages++;
+               reservedpages++;
+       }
+       totalram_pages += totalhigh_pages;
+       printk(KERN_INFO "High memory: %luk\n",
+                                       totalhigh_pages << (PAGE_SHIFT-10));
+
+       return reservedpages;
+}
+#endif /* CONFIG_HIGHMEM */
 
 /*
  * paging_init() sets up the page tables - in fact we've already done this.
@@ -54,17 +102,28 @@ EXPORT_SYMBOL(memory_size);
 static void __init paging_init(void)
 {
        unsigned long zones_size[MAX_NR_ZONES];
+#ifdef CONFIG_MMU
+       int idx;
+
+       /* Setup fixmaps */
+       for (idx = 0; idx < __end_of_fixed_addresses; idx++)
+               clear_fixmap(idx);
+#endif
 
        /* Clean every zones */
        memset(zones_size, 0, sizeof(zones_size));
 
-       /*
-        * old: we can DMA to/from any address.put all page into ZONE_DMA
-        * We use only ZONE_NORMAL
-        */
-       zones_size[ZONE_NORMAL] = max_mapnr;
+#ifdef CONFIG_HIGHMEM
+       highmem_init();
 
-       free_area_init(zones_size);
+       zones_size[ZONE_DMA] = max_low_pfn;
+       zones_size[ZONE_HIGHMEM] = max_pfn;
+#else
+       zones_size[ZONE_DMA] = max_pfn;
+#endif
+
+       /* We don't have holes in memory map */
+       free_area_init_nodes(zones_size);
 }
 
 void __init setup_memory(void)
@@ -78,32 +137,31 @@ void __init setup_memory(void)
        /* Find main memory where is the kernel */
        for_each_memblock(memory, reg) {
                memory_start = (u32)reg->base;
-               memory_end = (u32) reg->base + reg->size;
+               lowmem_size = reg->size;
                if ((memory_start <= (u32)_text) &&
-                                       ((u32)_text <= memory_end)) {
-                       memory_size = memory_end - memory_start;
+                       ((u32)_text <= (memory_start + lowmem_size - 1))) {
+                       memory_size = lowmem_size;
                        PAGE_OFFSET = memory_start;
-                       printk(KERN_INFO "%s: Main mem: 0x%x-0x%x, "
+                       printk(KERN_INFO "%s: Main mem: 0x%x, "
                                "size 0x%08x\n", __func__, (u32) memory_start,
-                                       (u32) memory_end, (u32) memory_size);
+                                       (u32) memory_size);
                        break;
                }
        }
 
-       if (!memory_start || !memory_end) {
-               panic("%s: Missing memory setting 0x%08x-0x%08x\n",
-                       __func__, (u32) memory_start, (u32) memory_end);
+       if (!memory_start || !memory_size) {
+               panic("%s: Missing memory setting 0x%08x, size=0x%08x\n",
+                       __func__, (u32) memory_start, (u32) memory_size);
        }
 
        /* reservation of region where is the kernel */
        kernel_align_start = PAGE_DOWN((u32)_text);
        /* ALIGN can be remove because _end in vmlinux.lds.S is align */
        kernel_align_size = PAGE_UP((u32)klimit) - kernel_align_start;
-       memblock_reserve(kernel_align_start, kernel_align_size);
-       printk(KERN_INFO "%s: kernel addr=0x%08x-0x%08x size=0x%08x\n",
+       printk(KERN_INFO "%s: kernel addr:0x%08x-0x%08x size=0x%08x\n",
                __func__, kernel_align_start, kernel_align_start
                        + kernel_align_size, kernel_align_size);
-
+       memblock_reserve(kernel_align_start, kernel_align_size);
 #endif
        /*
         * Kernel:
@@ -120,11 +178,13 @@ void __init setup_memory(void)
        min_low_pfn = memory_start >> PAGE_SHIFT; /* minimum for allocation */
        /* RAM is assumed contiguous */
        num_physpages = max_mapnr = memory_size >> PAGE_SHIFT;
-       max_pfn = max_low_pfn = memory_end >> PAGE_SHIFT;
+       max_low_pfn = ((u64)memory_start + (u64)lowmem_size) >> PAGE_SHIFT;
+       max_pfn = ((u64)memory_start + (u64)memory_size) >> PAGE_SHIFT;
 
        printk(KERN_INFO "%s: max_mapnr: %#lx\n", __func__, max_mapnr);
        printk(KERN_INFO "%s: min_low_pfn: %#lx\n", __func__, min_low_pfn);
        printk(KERN_INFO "%s: max_low_pfn: %#lx\n", __func__, max_low_pfn);
+       printk(KERN_INFO "%s: max_pfn: %#lx\n", __func__, max_pfn);
 
        /*
         * Find an area to use for the bootmem bitmap.
@@ -137,15 +197,39 @@ void __init setup_memory(void)
                PFN_UP(TOPHYS((u32)klimit)), min_low_pfn, max_low_pfn);
        memblock_reserve(PFN_UP(TOPHYS((u32)klimit)) << PAGE_SHIFT, map_size);
 
+       /* Add active regions with valid PFNs */
+       for_each_memblock(memory, reg) {
+               unsigned long start_pfn, end_pfn;
+
+               start_pfn = memblock_region_memory_base_pfn(reg);
+               end_pfn = memblock_region_memory_end_pfn(reg);
+               memblock_set_node(start_pfn << PAGE_SHIFT,
+                                       (end_pfn - start_pfn) << PAGE_SHIFT, 0);
+       }
+
        /* free bootmem is whole main memory */
-       free_bootmem(memory_start, memory_size);
+       free_bootmem_with_active_regions(0, max_low_pfn);
 
        /* reserve allocate blocks */
        for_each_memblock(reserved, reg) {
-               pr_debug("reserved - 0x%08x-0x%08x\n",
-                        (u32) reg->base, (u32) reg->size);
-               reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+               unsigned long top = reg->base + reg->size - 1;
+
+               pr_debug("reserved - 0x%08x-0x%08x, %lx, %lx\n",
+                        (u32) reg->base, (u32) reg->size, top,
+                                               memory_start + lowmem_size - 1);
+
+               if (top <= (memory_start + lowmem_size - 1)) {
+                       reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+               } else if (reg->base < (memory_start + lowmem_size - 1)) {
+                       unsigned long trunc_size = memory_start + lowmem_size -
+                                                               reg->base;
+                       reserve_bootmem(reg->base, trunc_size, BOOTMEM_DEFAULT);
+               }
        }
+
+       /* XXX need to clip this if using highmem? */
+       sparse_memory_present_with_active_regions(0);
+
 #ifdef CONFIG_MMU
        init_bootmem_done = 1;
 #endif
@@ -190,13 +274,58 @@ void free_initmem(void)
 
 void __init mem_init(void)
 {
-       high_memory = (void *)__va(memory_end);
+       pg_data_t *pgdat;
+       unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
+
+       high_memory = (void *)__va(memory_start + lowmem_size - 1);
+
        /* this will put all memory onto the freelists */
        totalram_pages += free_all_bootmem();
 
-       printk(KERN_INFO "Memory: %luk/%luk available\n",
-              nr_free_pages() << (PAGE_SHIFT-10),
-              num_physpages << (PAGE_SHIFT-10));
+       for_each_online_pgdat(pgdat) {
+               unsigned long i;
+               struct page *page;
+
+               for (i = 0; i < pgdat->node_spanned_pages; i++) {
+                       if (!pfn_valid(pgdat->node_start_pfn + i))
+                               continue;
+                       page = pgdat_page_nr(pgdat, i);
+                       if (PageReserved(page))
+                               reservedpages++;
+               }
+       }
+
+#ifdef CONFIG_HIGHMEM
+       reservedpages -= highmem_setup();
+#endif
+
+       codesize = (unsigned long)&_sdata - (unsigned long)&_stext;
+       datasize = (unsigned long)&_edata - (unsigned long)&_sdata;
+       initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
+       bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;
+
+       pr_info("Memory: %luk/%luk available (%luk kernel code, "
+               "%luk reserved, %luk data, %luk bss, %luk init)\n",
+               nr_free_pages() << (PAGE_SHIFT-10),
+               num_physpages << (PAGE_SHIFT-10),
+               codesize >> 10,
+               reservedpages << (PAGE_SHIFT-10),
+               datasize >> 10,
+               bsssize >> 10,
+               initsize >> 10);
+
+#ifdef CONFIG_MMU
+       pr_info("Kernel virtual memory layout:\n");
+       pr_info("  * 0x%08lx..0x%08lx  : fixmap\n", FIXADDR_START, FIXADDR_TOP);
+#ifdef CONFIG_HIGHMEM
+       pr_info("  * 0x%08lx..0x%08lx  : highmem PTEs\n",
+               PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP));
+#endif /* CONFIG_HIGHMEM */
+       pr_info("  * 0x%08lx..0x%08lx  : early ioremap\n",
+               ioremap_bot, ioremap_base);
+       pr_info("  * 0x%08lx..0x%08lx  : vmalloc & ioremap\n",
+               (unsigned long)VMALLOC_START, VMALLOC_END);
+#endif
        mem_init_done = 1;
 }
 
@@ -226,7 +355,6 @@ static void mm_cmdline_setup(void)
                maxmem = memparse(p, &p);
                if (maxmem && memory_size > maxmem) {
                        memory_size = maxmem;
-                       memory_end = memory_start + memory_size;
                        memblock.memory.regions[0].size = memory_size;
                }
        }
@@ -270,15 +398,26 @@ asmlinkage void __init mmu_init(void)
                machine_restart(NULL);
        }
 
-       if ((u32) memblock.memory.regions[0].size < 0x1000000) {
-               printk(KERN_EMERG "Memory must be greater than 16MB\n");
+       if ((u32) memblock.memory.regions[0].size < 0x400000) {
+               printk(KERN_EMERG "Memory must be greater than 4MB\n");
+               machine_restart(NULL);
+       }
+
+       if ((u32) memblock.memory.regions[0].size < kernel_tlb) {
+               printk(KERN_EMERG "Kernel size is greater than memory node\n");
                machine_restart(NULL);
        }
+
        /* Find main memory where the kernel is */
        memory_start = (u32) memblock.memory.regions[0].base;
-       memory_end = (u32) memblock.memory.regions[0].base +
-                               (u32) memblock.memory.regions[0].size;
-       memory_size = memory_end - memory_start;
+       lowmem_size = memory_size = (u32) memblock.memory.regions[0].size;
+
+       if (lowmem_size > CONFIG_LOWMEM_SIZE) {
+               lowmem_size = CONFIG_LOWMEM_SIZE;
+#ifndef CONFIG_HIGHMEM
+               memory_size = lowmem_size;
+#endif
+       }
 
        mm_cmdline_setup(); /* FIXME parse args from command line - not used */
 
@@ -305,15 +444,20 @@ asmlinkage void __init mmu_init(void)
        /* Map in all of RAM starting at CONFIG_KERNEL_START */
        mapin_ram();
 
-#ifdef CONFIG_HIGHMEM_START_BOOL
-       ioremap_base = CONFIG_HIGHMEM_START;
+       /* Extend vmalloc and ioremap area as big as possible */
+#ifdef CONFIG_HIGHMEM
+       ioremap_base = ioremap_bot = PKMAP_BASE;
 #else
-       ioremap_base = 0xfe000000UL;    /* for now, could be 0xfffff000 */
-#endif /* CONFIG_HIGHMEM_START_BOOL */
-       ioremap_bot = ioremap_base;
+       ioremap_base = ioremap_bot = FIXADDR_START;
+#endif
 
        /* Initialize the context management stuff */
        mmu_context_init();
+
+       /* Shortly after that, the entire linear mapping will be available */
+       /* This will also cause that unflatten device tree will be allocated
+        * inside 768MB limit */
+       memblock_set_current_limit(memory_start + lowmem_size - 1);
 }
 
 /* This is only called until mem_init is done. */
@@ -324,11 +468,11 @@ void __init *early_get_page(void)
                p = alloc_bootmem_pages(PAGE_SIZE);
        } else {
                /*
-                * Mem start + 32MB -> here is limit
+                * Mem start + kernel_tlb -> here is limit
                 * because of mem mapping from head.S
                 */
                p = __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE,
-                                       memory_start + 0x2000000));
+                                       memory_start + kernel_tlb));
        }
        return p;
 }
index 59bf233..d1c06d0 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/io.h>
 #include <asm/mmu.h>
 #include <asm/sections.h>
+#include <asm/fixmap.h>
 
 #define flush_HPTE(X, va, pg)  _tlbie(va)
 
@@ -44,11 +45,6 @@ unsigned long ioremap_base;
 unsigned long ioremap_bot;
 EXPORT_SYMBOL(ioremap_bot);
 
-/* The maximum lowmem defaults to 768Mb, but this can be configured to
- * another value.
- */
-#define MAX_LOW_MEM    CONFIG_LOWMEM_SIZE
-
 #ifndef CONFIG_SMP
 struct pgtable_cache_struct quicklists;
 #endif
@@ -80,7 +76,7 @@ static void __iomem *__ioremap(phys_addr_t addr, unsigned long size,
                !(p >= virt_to_phys((unsigned long)&__bss_stop) &&
                p < virt_to_phys((unsigned long)__bss_stop))) {
                printk(KERN_WARNING "__ioremap(): phys addr "PTE_FMT
-                       " is RAM lr %p\n", (unsigned long)p,
+                       " is RAM lr %pf\n", (unsigned long)p,
                        __builtin_return_address(0));
                return NULL;
        }
@@ -171,7 +167,7 @@ void __init mapin_ram(void)
 
        v = CONFIG_KERNEL_START;
        p = memory_start;
-       for (s = 0; s < memory_size; s += PAGE_SIZE) {
+       for (s = 0; s < lowmem_size; s += PAGE_SIZE) {
                f = _PAGE_PRESENT | _PAGE_ACCESSED |
                                _PAGE_SHARED | _PAGE_HWEXEC;
                if ((char *) v < _stext || (char *) v >= _etext)
@@ -254,3 +250,13 @@ __init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
        }
        return pte;
 }
+
+void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
+{
+       unsigned long address = __fix_to_virt(idx);
+
+       if (idx >= __end_of_fixed_addresses)
+               BUG();
+
+       map_page(address, phys, pgprot_val(flags));
+}
index 85f2ac1..d10403d 100644 (file)
@@ -46,9 +46,6 @@ static int global_phb_number;         /* Global phb counter */
 /* ISA Memory physical address */
 resource_size_t isa_mem_base;
 
-/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */
-unsigned int pci_flags;
-
 static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
 
 unsigned long isa_io_base;
@@ -833,64 +830,7 @@ int pci_proc_domain(struct pci_bus *bus)
 {
        struct pci_controller *hose = pci_bus_to_host(bus);
 
-       if (!(pci_flags & PCI_ENABLE_PROC_DOMAINS))
-               return 0;
-       if (pci_flags & PCI_COMPAT_DOMAIN_0)
-               return hose->global_number != 0;
-       return 1;
-}
-
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                            struct resource *res)
-{
-       resource_size_t offset = 0, mask = (resource_size_t)-1;
-       struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
-       if (!hose)
-               return;
-       if (res->flags & IORESOURCE_IO) {
-               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-               mask = 0xffffffffu;
-       } else if (res->flags & IORESOURCE_MEM)
-               offset = hose->pci_mem_offset;
-
-       region->start = (res->start - offset) & mask;
-       region->end = (res->end - offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                            struct pci_bus_region *region)
-{
-       resource_size_t offset = 0, mask = (resource_size_t)-1;
-       struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
-       if (!hose)
-               return;
-       if (res->flags & IORESOURCE_IO) {
-               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-               mask = 0xffffffffu;
-       } else if (res->flags & IORESOURCE_MEM)
-               offset = hose->pci_mem_offset;
-       res->start = (region->start + offset) & mask;
-       res->end = (region->end + offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/* Fixup a bus resource into a linux resource */
-static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
-{
-       struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       resource_size_t offset = 0, mask = (resource_size_t)-1;
-
-       if (res->flags & IORESOURCE_IO) {
-               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-               mask = 0xffffffffu;
-       } else if (res->flags & IORESOURCE_MEM)
-               offset = hose->pci_mem_offset;
-
-       res->start = (res->start + offset) & mask;
-       res->end = (res->end + offset) & mask;
+       return 0;
 }
 
 /* This header fixup will do the resource fixup for all devices as they are
@@ -910,13 +850,7 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
                struct resource *res = dev->resource + i;
                if (!res->flags)
                        continue;
-               /* On platforms that have PCI_PROBE_ONLY set, we don't
-                * consider 0 as an unassigned BAR value. It's technically
-                * a valid value, but linux doesn't like it... so when we can
-                * re-assign things, we do so, but if we can't, we keep it
-                * around and hope for the best...
-                */
-               if (res->start == 0 && !(pci_flags & PCI_PROBE_ONLY)) {
+               if (res->start == 0) {
                        pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]" \
                                                        "is unassigned\n",
                                 pci_name(dev), i,
@@ -929,18 +863,11 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
                        continue;
                }
 
-               pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n",
+               pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]\n",
                         pci_name(dev), i,
                         (unsigned long long)res->start,\
                         (unsigned long long)res->end,
                         (unsigned int)res->flags);
-
-               fixup_resource(res, dev);
-
-               pr_debug("PCI:%s            %016llx-%016llx\n",
-                        pci_name(dev),
-                        (unsigned long long)res->start,
-                        (unsigned long long)res->end);
        }
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
@@ -959,10 +886,6 @@ static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
        u16 command;
        int i;
 
-       /* We don't do anything if PCI_PROBE_ONLY is set */
-       if (pci_flags & PCI_PROBE_ONLY)
-               return 0;
-
        /* Job is a bit different between memory and IO */
        if (res->flags & IORESOURCE_MEM) {
                /* If the BAR is non-0 (res != pci_mem_offset) then it's
@@ -1037,9 +960,6 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
                         (unsigned long long)res->end,
                         (unsigned int)res->flags);
 
-               /* Perform fixup */
-               fixup_resource(res, dev);
-
                /* Try to detect uninitialized P2P bridge resources,
                 * and clear them out so they get re-assigned later
                 */
@@ -1107,9 +1027,6 @@ EXPORT_SYMBOL(pcibios_fixup_bus);
 
 static int skip_isa_ioresource_align(struct pci_dev *dev)
 {
-       if ((pci_flags & PCI_CAN_SKIP_ISA_ALIGN) &&
-           !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
-               return 1;
        return 0;
 }
 
@@ -1236,8 +1153,6 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus)
                         * and as such ensure proper re-allocation
                         * later.
                         */
-                       if (pci_flags & PCI_REASSIGN_ALL_RSRC)
-                               goto clear_resource;
                        pr = pci_find_parent_resource(bus->self, res);
                        if (pr == res) {
                                /* this happens when the generic PCI
@@ -1422,27 +1337,19 @@ void __init pcibios_resource_survey(void)
        list_for_each_entry(b, &pci_root_buses, node)
                pcibios_allocate_bus_resources(b);
 
-       if (!(pci_flags & PCI_REASSIGN_ALL_RSRC)) {
-               pcibios_allocate_resources(0);
-               pcibios_allocate_resources(1);
-       }
+       pcibios_allocate_resources(0);
+       pcibios_allocate_resources(1);
 
        /* Before we start assigning unassigned resource, we try to reserve
         * the low IO area and the VGA memory area if they intersect the
         * bus available resources to avoid allocating things on top of them
         */
-       if (!(pci_flags & PCI_PROBE_ONLY)) {
-               list_for_each_entry(b, &pci_root_buses, node)
-                       pcibios_reserve_legacy_regions(b);
-       }
+       list_for_each_entry(b, &pci_root_buses, node)
+               pcibios_reserve_legacy_regions(b);
 
-       /* Now, if the platform didn't decide to blindly trust the firmware,
-        * we proceed to assigning things that were left unassigned
-        */
-       if (!(pci_flags & PCI_PROBE_ONLY)) {
-               pr_debug("PCI: Assigning unassigned resources...\n");
-               pci_assign_unassigned_resources();
-       }
+       /* Now proceed to assigning things that were left unassigned */
+       pr_debug("PCI: Assigning unassigned resources...\n");
+       pci_assign_unassigned_resources();
 }
 
 #ifdef CONFIG_HOTPLUG
@@ -1535,7 +1442,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
                res->end = res->start + IO_SPACE_LIMIT;
                res->flags = IORESOURCE_IO;
        }
-       pci_add_resource(resources, res);
+       pci_add_resource_offset(resources, res, hose->io_base_virt - _IO_BASE);
 
        pr_debug("PCI: PHB IO resource    = %016llx-%016llx [%lx]\n",
                 (unsigned long long)res->start,
@@ -1558,7 +1465,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
                        res->flags = IORESOURCE_MEM;
 
                }
-               pci_add_resource(resources, res);
+               pci_add_resource_offset(resources, res, hose->pci_mem_offset);
 
                pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n",
                        i, (unsigned long long)res->start,
index 9fdf07e..c0122a1 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
  */
+#include <linux/bug.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
index 788060a..54a33c7 100644 (file)
@@ -11,6 +11,7 @@
  *
  * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
  */
+#include <linux/bug.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
index 785b4ea..46d3da0 100644 (file)
 #define MADV_HUGEPAGE  14              /* Worth backing with hugepages */
 #define MADV_NOHUGEPAGE        15              /* Not worth backing with hugepages */
 
+#define MADV_DONTDUMP   16             /* Explicity exclude from the core dump,
+                                          overrides the coredump filter bits */
+#define MADV_DODUMP    17              /* Clear the MADV_NODUMP flag */
+
 /* compatibility flags */
 #define MAP_FILE       0
 
index 576397c..fcd4060 100644 (file)
@@ -92,6 +92,7 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 #include <asm/scatterlist.h>
 #include <linux/string.h>
 #include <asm/io.h>
+#include <asm-generic/pci-bridge.h>
 
 struct pci_dev;
 
@@ -112,12 +113,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 }
 #endif
 
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-       struct pci_bus_region *region, struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                                   struct pci_bus_region *region);
-
 #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
 
 static inline int pci_proc_domain(struct pci_bus *bus)
@@ -145,8 +140,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 #define arch_setup_msi_irqs arch_setup_msi_irqs
 #endif
 
-extern int pci_probe_only;
-
 extern char * (*pcibios_plat_setup)(char *str);
 
 #endif /* _ASM_PCI_H */
index e5cdfd6..0f1af58 100644 (file)
@@ -88,8 +88,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 
        ret = install_special_mapping(mm, addr, PAGE_SIZE,
                                      VM_READ|VM_EXEC|
-                                     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-                                     VM_ALWAYSDUMP,
+                                     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
                                      &vdso_page);
 
        if (ret)
index acacd14..9553b14 100644 (file)
@@ -51,67 +51,6 @@ 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 __devinit cobalt_legacy_ide_resource_fixup(struct pci_dev *dev,
-                                                      struct resource *res)
-{
-       struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
-       unsigned long offset = hose->io_offset;
-       struct resource orig = *res;
-
-       if (!(res->flags & IORESOURCE_IO) ||
-           !(res->flags & IORESOURCE_PCI_FIXED))
-               return;
-
-       res->start -= offset;
-       res->end -= offset;
-       dev_printk(KERN_DEBUG, &dev->dev, "converted legacy %pR to bus %pR\n",
-                  &orig, res);
-}
-
-static void __devinit cobalt_legacy_ide_fixup(struct pci_dev *dev)
-{
-       u32 class;
-       u8 progif;
-
-       /*
-        * If the IDE controller is in legacy mode, pci_setup_device() fills in
-        * the resources with the legacy addresses that normally appear on the
-        * PCI bus, just as if we had read them from a BAR.
-        *
-        * However, with the GT-64111, those legacy addresses, e.g., 0x1f0,
-        * will never appear on the PCI bus because it converts memory accesses
-        * in the PCI I/O region (which is never at address zero) into I/O port
-        * accesses with no address translation.
-        *
-        * For example, if GT_DEF_PCI0_IO_BASE is 0x10000000, a load or store
-        * to physical address 0x100001f0 will become a PCI access to I/O port
-        * 0x100001f0.  There's no way to generate an access to I/O port 0x1f0,
-        * but the VT82C586 IDE controller does respond at 0x100001f0 because
-        * it only decodes the low 24 bits of the address.
-        *
-        * When this quirk runs, the pci_dev resources should contain bus
-        * addresses, not Linux I/O port numbers, so convert legacy addresses
-        * like 0x1f0 to bus addresses like 0x100001f0.  Later, we'll convert
-        * them back with pcibios_fixup_bus() or pcibios_bus_to_resource().
-        */
-       class = dev->class >> 8;
-       if (class != PCI_CLASS_STORAGE_IDE)
-               return;
-
-       pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-       if ((progif & 1) == 0) {
-               cobalt_legacy_ide_resource_fixup(dev, &dev->resource[0]);
-               cobalt_legacy_ide_resource_fixup(dev, &dev->resource[1]);
-       }
-       if ((progif & 4) == 0) {
-               cobalt_legacy_ide_resource_fixup(dev, &dev->resource[2]);
-               cobalt_legacy_ide_resource_fixup(dev, &dev->resource[3]);
-       }
-}
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
-         cobalt_legacy_ide_fixup);
-
 static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
 {
        unsigned short cfgword;
index af8c319..37b52dc 100644 (file)
@@ -204,7 +204,7 @@ static int __init bcm1480_pcibios_init(void)
        uint64_t reg;
 
        /* CFE will assign PCI resources */
-       pci_probe_only = 1;
+       pci_set_flags(PCI_PROBE_ONLY);
 
        /* Avoid ISA compat ranges.  */
        PCIBIOS_MIN_IO = 0x00008000UL;
index 193e949..0fbe4c0 100644 (file)
@@ -50,7 +50,7 @@ int __cpuinit bridge_probe(nasid_t nasid, int widget_id, int masterwid)
        bridge_t *bridge;
        int slot;
 
-       pci_probe_only = 1;
+       pci_set_flags(PCI_PROBE_ONLY);
 
        printk("a bridge\n");
 
index be1e1af..030c77e 100644 (file)
@@ -270,7 +270,8 @@ static int __devinit ltq_pci_probe(struct platform_device *pdev)
 {
        struct ltq_pci_data *ltq_pci_data =
                (struct ltq_pci_data *) pdev->dev.platform_data;
-       pci_probe_only = 0;
+
+       pci_clear_flags(PCI_PROBE_ONLY);
        ltq_pci_irq_map = ltq_pci_data->irq;
        ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE);
        ltq_pci_mapped_cfg =
index 1711e8e..dd97f3a 100644 (file)
@@ -213,7 +213,7 @@ static int __init sb1250_pcibios_init(void)
        uint64_t reg;
 
        /* CFE will assign PCI resources */
-       pci_probe_only = 1;
+       pci_set_flags(PCI_PROBE_ONLY);
 
        /* Avoid ISA compat ranges.  */
        PCIBIOS_MIN_IO = 0x00008000UL;
index 3d701a9..1644805 100644 (file)
@@ -292,7 +292,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 static int __init pcibios_init(void)
 {
        /* PSB assigns PCI resources */
-       pci_probe_only = 1;
+       pci_set_flags(PCI_PROBE_ONLY);
        pci_config_base = ioremap(DEFAULT_PCI_CONFIG_BASE, 16 << 20);
 
        /* Extend IO port for memory mapped io */
index 1552150..0514866 100644 (file)
 #include <asm/cpu-info.h>
 
 /*
- * Indicate whether we respect the PCI setup left by the firmware.
- *
- * Make this long-lived  so that we know when shutting down
- * whether we probed only or not.
+ * If PCI_PROBE_ONLY in pci_flags is set, we don't change any PCI resource
+ * assignments.
  */
-int pci_probe_only;
-
-#define PCI_ASSIGN_ALL_BUSSES  1
-
-unsigned int pci_probe = PCI_ASSIGN_ALL_BUSSES;
 
 /*
  * The PCI controller list.
@@ -92,11 +85,12 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)
        if (!hose->iommu)
                PCI_DMA_BUS_IS_PHYS = 1;
 
-       if (hose->get_busno && pci_probe_only)
+       if (hose->get_busno && pci_has_flag(PCI_PROBE_ONLY))
                next_busno = (*hose->get_busno)();
 
-       pci_add_resource(&resources, hose->mem_resource);
-       pci_add_resource(&resources, hose->io_resource);
+       pci_add_resource_offset(&resources,
+                               hose->mem_resource, hose->mem_offset);
+       pci_add_resource_offset(&resources, hose->io_resource, hose->io_offset);
        bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
                                &resources);
        if (!bus)
@@ -115,7 +109,7 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)
                        need_domain_info = 1;
                }
 
-               if (!pci_probe_only) {
+               if (!pci_has_flag(PCI_PROBE_ONLY)) {
                        pci_bus_size_bridges(bus);
                        pci_bus_assign_resources(bus);
                        pci_enable_bridges(bus);
@@ -241,7 +235,7 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask)
 
 unsigned int pcibios_assign_all_busses(void)
 {
-       return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
+       return 1;
 }
 
 int pcibios_enable_device(struct pci_dev *dev, int mask)
@@ -254,42 +248,13 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return pcibios_plat_dev_init(dev);
 }
 
-static void pcibios_fixup_device_resources(struct pci_dev *dev,
-       struct pci_bus *bus)
-{
-       /* Update device resources.  */
-       struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
-       unsigned long offset = 0;
-       int i;
-
-       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-               if (!dev->resource[i].start)
-                       continue;
-               if (dev->resource[i].flags & IORESOURCE_IO)
-                       offset = hose->io_offset;
-               else if (dev->resource[i].flags & IORESOURCE_MEM)
-                       offset = hose->mem_offset;
-
-               dev->resource[i].start += offset;
-               dev->resource[i].end += offset;
-       }
-}
-
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
-       /* Propagate hose info into the subordinate devices.  */
-
        struct pci_dev *dev = bus->self;
 
-       if (pci_probe_only && dev &&
+       if (pci_has_flag(PCI_PROBE_ONLY) && dev &&
            (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
                pci_read_bridge_bases(bus);
-               pcibios_fixup_device_resources(dev, bus);
-       }
-
-       list_for_each_entry(dev, &bus->devices, bus_list) {
-               if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
-                       pcibios_fixup_device_resources(dev, bus);
        }
 }
 
@@ -299,40 +264,7 @@ pcibios_update_irq(struct pci_dev *dev, int irq)
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                        struct resource *res)
-{
-       struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
-       unsigned long offset = 0;
-
-       if (res->flags & IORESOURCE_IO)
-               offset = hose->io_offset;
-       else if (res->flags & IORESOURCE_MEM)
-               offset = hose->mem_offset;
-
-       region->start = res->start - offset;
-       region->end = res->end - offset;
-}
-
-void __devinit
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                       struct pci_bus_region *region)
-{
-       struct pci_controller *hose = (struct pci_controller *)dev->sysdata;
-       unsigned long offset = 0;
-
-       if (res->flags & IORESOURCE_IO)
-               offset = hose->io_offset;
-       else if (res->flags & IORESOURCE_MEM)
-               offset = hose->mem_offset;
-
-       res->start = region->start + offset;
-       res->end = region->end + offset;
-}
-
 #ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
 EXPORT_SYMBOL(PCIBIOS_MIN_IO);
 EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
 #endif
index 8f1c40d..3aa3de0 100644 (file)
@@ -5,6 +5,7 @@ config MN10300
        select GENERIC_IRQ_SHOW
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_KGDB
+       select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
 
 config AM33_2
        def_bool n
index 6095a28..8137c25 100644 (file)
@@ -85,22 +85,6 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
 
-/**
- * pcibios_resource_to_bus - convert resource to PCI bus address
- * @dev: device which owns this resource
- * @region: converted bus-centric region (start,end)
- * @res: resource to convert
- *
- * Convert a resource to a PCI device bus address or bus window.
- */
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-                                   struct pci_bus_region *region,
-                                   struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
-                                   struct resource *res,
-                                   struct pci_bus_region *region);
-
 static inline struct resource *
 pcibios_select_root(struct pci_dev *pdev, struct resource *res)
 {
index 10c7502..8ca2a42 100644 (file)
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_MN10300_WD_TIMER
-#define ARCH_HAS_NMI_WATCHDOG          /* See include/linux/nmi.h */
-#endif
-
 /*
  * watchdog timer registers
  */
index a7c5f08..6dce9fc 100644 (file)
@@ -32,8 +32,7 @@ struct pci_ops *pci_root_ops;
  * insert specific PCI bus resources instead of using the platform-level bus
  * resources directly for the PCI root bus.
  *
- * These are configured and inserted by pcibios_init() and are attached to the
- * root bus by pcibios_fixup_bus().
+ * These are configured and inserted by pcibios_init().
  */
 static struct resource pci_ioport_resource = {
        .name   = "PCI IO",
@@ -78,52 +77,6 @@ static inline int __query(const struct pci_bus *bus, unsigned int devfn)
 }
 
 /*
- * translate Linuxcentric addresses to PCI bus addresses
- */
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                            struct resource *res)
-{
-       if (res->flags & IORESOURCE_IO) {
-               region->start = (res->start & 0x00ffffff);
-               region->end   = (res->end   & 0x00ffffff);
-       }
-
-       if (res->flags & IORESOURCE_MEM) {
-               region->start = (res->start & 0x03ffffff) | MEM_PAGING_REG;
-               region->end   = (res->end   & 0x03ffffff) | MEM_PAGING_REG;
-       }
-
-#if 0
-       printk(KERN_DEBUG "RES->BUS: %lx-%lx => %lx-%lx\n",
-              res->start, res->end, region->start, region->end);
-#endif
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-/*
- * translate PCI bus addresses to Linuxcentric addresses
- */
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                            struct pci_bus_region *region)
-{
-       if (res->flags & IORESOURCE_IO) {
-               res->start = (region->start & 0x00ffffff) | 0xbe000000;
-               res->end   = (region->end   & 0x00ffffff) | 0xbe000000;
-       }
-
-       if (res->flags & IORESOURCE_MEM) {
-               res->start = (region->start & 0x03ffffff) | 0xb8000000;
-               res->end   = (region->end   & 0x03ffffff) | 0xb8000000;
-       }
-
-#if 0
-       printk(KERN_INFO "BUS->RES: %lx-%lx => %lx-%lx\n",
-              region->start, region->end, res->start, res->end);
-#endif
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/*
  *
  */
 static int pci_ampci_read_config_byte(struct pci_bus *bus, unsigned int devfn,
@@ -364,9 +317,6 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
                if (!dev->resource[i].flags)
                        continue;
 
-               region.start = dev->resource[i].start;
-               region.end = dev->resource[i].end;
-               pcibios_bus_to_resource(dev, &dev->resource[i], &region);
                if (is_valid_resource(dev, i))
                        pci_claim_resource(dev, i);
        }
@@ -397,6 +347,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
  */
 static int __init pcibios_init(void)
 {
+       resource_size_t io_offset, mem_offset;
        LIST_HEAD(resources);
 
        ioport_resource.start   = 0xA0000000;
@@ -420,8 +371,13 @@ static int __init pcibios_init(void)
        printk(KERN_INFO "PCI: Probing PCI hardware [mempage %08x]\n",
               MEM_PAGING_REG);
 
-       pci_add_resource(&resources, &pci_ioport_resource);
-       pci_add_resource(&resources, &pci_iomem_resource);
+       io_offset = pci_ioport_resource.start -
+           (pci_ioport_resource.start & 0x00ffffff);
+       mem_offset = pci_iomem_resource.start -
+           ((pci_iomem_resource.start & 0x03ffffff) | MEM_PAGING_REG);
+
+       pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset);
+       pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset);
        pci_root_bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL,
                                         &resources);
 
index bc428b5..a478719 100644 (file)
@@ -16,6 +16,7 @@ config OPENRISC
        select GENERIC_IRQ_SHOW
        select GENERIC_IOMAP
        select GENERIC_CPU_DEVICES
+       select GENERIC_ATOMIC64
 
 config MMU
        def_bool y
index b041b34..108906f 100644 (file)
@@ -71,9 +71,6 @@ typedef struct page *pgtable_t;
 #define __pgd(x)       ((pgd_t) { (x) })
 #define __pgprot(x)    ((pgprot_t) { (x) })
 
-extern unsigned long memory_start;
-extern unsigned long memory_end;
-
 #endif /* !__ASSEMBLY__ */
 
 
@@ -94,8 +91,7 @@ extern unsigned long memory_end;
 
 #define pfn_valid(pfn)          ((pfn) < max_mapnr)
 
-#define virt_addr_valid(kaddr)  (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
-                               ((void *)(kaddr) < (void *)memory_end))
+#define virt_addr_valid(kaddr) (pfn_valid(virt_to_pfn(kaddr)))
 
 #endif /* __ASSEMBLY__ */
 
index 043505d..14c900c 100644 (file)
@@ -455,7 +455,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
  * No page table caches to initialise
  */
 #define pgtable_cache_init()           do { } while (0)
-#define io_remap_page_range            remap_page_range
 
 typedef pte_t *pte_addr_t;
 
index bb54c97..f7516fa 100644 (file)
@@ -81,8 +81,8 @@ extern inline void prepare_to_copy(struct task_struct *tsk)
 #define INIT_THREAD  { }
 
 
-#define KSTK_EIP(tsk)   (task_pt_regs(tsk)->pc);
-#define KSTK_ESP(tsk)   (task_pt_regs(tsk)->sp);
+#define KSTK_EIP(tsk)   (task_pt_regs(tsk)->pc)
+#define KSTK_ESP(tsk)   (task_pt_regs(tsk)->sp)
 
 
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
index e612ce4..4651a73 100644 (file)
@@ -73,9 +73,13 @@ struct pt_regs {
                };
        };
        long  pc;
+       /* For restarting system calls:
+        * Set to syscall number for syscall exceptions,
+        * -1 for all other exceptions.
+        */
        long  orig_gpr11;       /* For restarting system calls */
-       long  syscallno;        /* Syscall number (used by strace) */
        long dummy;             /* Cheap alignment fix */
+       long dummy2;            /* Cheap alignment fix */
 };
 
 /* TODO: Rename this to REDZONE because that's what it is */
index 9f03370..b752bb6 100644 (file)
@@ -25,7 +25,7 @@
 static inline int
 syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
 {
-       return regs->syscallno ? regs->syscallno : -1;
+       return regs->orig_gpr11;
 }
 
 static inline void
@@ -50,10 +50,7 @@ static inline void
 syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
                         int error, long val)
 {
-       if (error)
-               regs->gpr[11] = -error;
-       else
-               regs->gpr[11] = val;
+       regs->gpr[11] = (long) error ?: val;
 }
 
 static inline void
index c310e45..f5abaa0 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/thread_info.h>
 #include <linux/prefetch.h>
 #include <linux/string.h>
-#include <linux/thread_info.h>
 #include <asm/page.h>
 
 #define VERIFY_READ    0
index d5f9c35..6e61af8 100644 (file)
@@ -95,7 +95,6 @@ handler:                                                      ;\
        /* r1, EPCR, ESR a already saved */                     ;\
        l.sw    PT_GPR2(r1),r2                                  ;\
        l.sw    PT_GPR3(r1),r3                                  ;\
-       l.sw    PT_ORIG_GPR11(r1),r11                           ;\
        /* r4 already save */                                   ;\
        l.sw    PT_GPR5(r1),r5                                  ;\
        l.sw    PT_GPR6(r1),r6                                  ;\
@@ -125,7 +124,9 @@ handler:                                                    ;\
        /* r30 already save */                                  ;\
 /*        l.sw    PT_GPR30(r1),r30*/                                   ;\
        l.sw    PT_GPR31(r1),r31                                        ;\
-       l.sw    PT_SYSCALLNO(r1),r0
+       /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\
+       l.addi  r30,r0,-1                                       ;\
+       l.sw    PT_ORIG_GPR11(r1),r30
 
 #define UNHANDLED_EXCEPTION(handler,vector)                    \
        .global handler                                         ;\
@@ -133,7 +134,6 @@ handler:                                                    ;\
        /* r1, EPCR, ESR already saved */                       ;\
        l.sw    PT_GPR2(r1),r2                                  ;\
        l.sw    PT_GPR3(r1),r3                                  ;\
-       l.sw    PT_ORIG_GPR11(r1),r11                           ;\
        l.sw    PT_GPR5(r1),r5                                  ;\
        l.sw    PT_GPR6(r1),r6                                  ;\
        l.sw    PT_GPR7(r1),r7                                  ;\
@@ -162,7 +162,9 @@ handler:                                                    ;\
        /* r31 already saved */                                 ;\
        l.sw    PT_GPR30(r1),r30                                        ;\
 /*        l.sw    PT_GPR31(r1),r31     */                              ;\
-       l.sw    PT_SYSCALLNO(r1),r0                             ;\
+       /* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\
+       l.addi  r30,r0,-1                                       ;\
+       l.sw    PT_ORIG_GPR11(r1),r30                           ;\
        l.addi  r3,r1,0                                         ;\
        /* r4 is exception EA */                                ;\
        l.addi  r5,r0,vector                                    ;\
@@ -554,6 +556,7 @@ ENTRY(_sys_call_handler)
        l.sw    PT_GPR9(r1),r9
        /* r10 already saved */
        l.sw    PT_GPR11(r1),r11
+       /* orig_gpr11 must be set for syscalls */
        l.sw    PT_ORIG_GPR11(r1),r11
        /* r12,r13 already saved */
 
@@ -567,9 +570,6 @@ ENTRY(_sys_call_handler)
        /* r30 is the only register we clobber in the fast path */
        /* r30 already saved */
 /*     l.sw    PT_GPR30(r1),r30 */
-       /* This is used by do_signal to determine whether to check for
-        * syscall restart or not */
-       l.sw    PT_SYSCALLNO(r1),r11
 
 _syscall_check_trace_enter:
        /* If TIF_SYSCALL_TRACE is set, then we want to do syscall tracing */
@@ -731,7 +731,7 @@ _syscall_trace_enter:
         * so that we can do the syscall for real and return to the syscall
         * hot path.
         */
-       l.lwz   r11,PT_SYSCALLNO(r1)
+       l.lwz   r11,PT_GPR11(r1)
        l.lwz   r3,PT_GPR3(r1)
        l.lwz   r4,PT_GPR4(r1)
        l.lwz   r5,PT_GPR5(r1)
index c75018d..1088b5f 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/cache.h>
 #include <asm/spr_defs.h>
 #include <asm/asm-offsets.h>
+#include <linux/of_fdt.h>
 
 #define tophys(rd,rs)                          \
        l.movhi rd,hi(-KERNELBASE)              ;\
@@ -440,6 +441,9 @@ _dispatch_do_ipage_fault:
        __HEAD
        .global _start
 _start:
+       /* save kernel parameters */
+       l.or    r25,r0,r3       /* pointer to fdt */
+
        /*
         * ensure a deterministic start
         */
@@ -471,7 +475,6 @@ _start:
        CLEAR_GPR(r22)
        CLEAR_GPR(r23)
        CLEAR_GPR(r24)
-       CLEAR_GPR(r25)
        CLEAR_GPR(r26)
        CLEAR_GPR(r27)
        CLEAR_GPR(r28)
@@ -565,6 +568,18 @@ enable_mmu:
        // reset the simulation counters
        l.nop 5
 
+       /* check fdt header magic word */
+       l.lwz   r3,0(r25)       /* load magic from fdt into r3 */
+       l.movhi r4,hi(OF_DT_HEADER)
+       l.ori   r4,r4,lo(OF_DT_HEADER)
+       l.sfeq  r3,r4
+       l.bf    _fdt_found
+        l.nop
+       /* magic number mismatch, set fdt pointer to null */
+       l.or    r25,r0,r0
+_fdt_found:
+       /* pass fdt pointer to or32_early_setup in r3 */
+       l.or    r3,r0,r25
        LOAD_SYMBOL_2_GPR(r24, or32_early_setup)
        l.jalr r24
         l.nop
index 967d499..e71781d 100644 (file)
@@ -187,11 +187,11 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
                 */
                ret = -1L;
 
-       audit_syscall_entry(audit_arch(), regs->syscallno,
+       audit_syscall_entry(audit_arch(), regs->gpr[11],
                            regs->gpr[3], regs->gpr[4],
                            regs->gpr[5], regs->gpr[6]);
 
-       return ret ? : regs->syscallno;
+       return ret ? : regs->gpr[11];
 }
 
 asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
index ad2c290..f4d5bed 100644 (file)
@@ -206,18 +206,18 @@ void __init setup_cpuinfo(void)
  * Handles the pointer to the device tree that this kernel is to use
  * for establishing the available platform devices.
  *
- * For now, this is limited to using the built-in device tree.  In the future,
- * it is intended that this function will take a pointer to the device tree
- * that is potentially built-in, but potentially also passed in by the
- * bootloader, or discovered by some equally clever means...
+ * Falls back on built-in device tree in case null pointer is passed.
  */
 
-void __init or32_early_setup(void)
+void __init or32_early_setup(unsigned int fdt)
 {
-
-       early_init_devtree(__dtb_start);
-
-       printk(KERN_INFO "Compiled-in FDT at 0x%p\n", __dtb_start);
+       if (fdt) {
+               early_init_devtree((void*) fdt);
+               printk(KERN_INFO "FDT at 0x%08x\n", fdt);
+       } else {
+               early_init_devtree(__dtb_start);
+               printk(KERN_INFO "Compiled-in FDT at %p\n", __dtb_start);
+       }
 }
 
 static int __init openrisc_device_probe(void)
index 95207ab..e970743 100644 (file)
@@ -102,10 +102,7 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs)
                goto badframe;
 
        sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       current->blocked = set;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       set_current_blocked(&set);
 
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
                goto badframe;
@@ -189,8 +186,8 @@ static inline void __user *get_sigframe(struct k_sigaction *ka,
  * trampoline which performs the syscall sigreturn, or a provided
  * user-mode trampoline.
  */
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-                          sigset_t *set, struct pt_regs *regs)
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+                         sigset_t *set, struct pt_regs *regs)
 {
        struct rt_sigframe *frame;
        unsigned long return_ip;
@@ -247,31 +244,27 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        /* actually move the usp to reflect the stacked frame */
        regs->sp = (unsigned long)frame;
 
-       return;
+       return 0;
 
 give_sigsegv:
-       if (sig == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
+       force_sigsegv(sig, current);
+       return -EFAULT;
 }
 
-static inline void
+static inline int
 handle_signal(unsigned long sig,
              siginfo_t *info, struct k_sigaction *ka,
              sigset_t *oldset, struct pt_regs *regs)
 {
-       setup_rt_frame(sig, ka, info, oldset, regs);
+       int ret;
 
-       if (ka->sa.sa_flags & SA_ONESHOT)
-               ka->sa.sa_handler = SIG_DFL;
+       ret = setup_rt_frame(sig, ka, info, oldset, regs);
+       if (ret)
+               return ret;
 
-       spin_lock_irq(&current->sighand->siglock);
-       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-       if (!(ka->sa.sa_flags & SA_NODEFER))
-               sigaddset(&current->blocked, sig);
-       recalc_sigpending();
+       block_sigmask(ka, sig);
 
-       spin_unlock_irq(&current->sighand->siglock);
+       return 0;
 }
 
 /*
@@ -312,7 +305,7 @@ void do_signal(struct pt_regs *regs)
         * below mean that the syscall executed to completion and no
         * restart is necessary.
         */
-       if (regs->syscallno) {
+       if (regs->orig_gpr11) {
                int restart = 0;
 
                switch (regs->gpr[11]) {
@@ -360,13 +353,13 @@ void do_signal(struct pt_regs *regs)
                        oldset = &current->blocked;
 
                /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &info, &ka, oldset, regs);
-               /* a signal was successfully delivered; the saved
-                * sigmask will have been stored in the signal frame,
-                * and will be restored by sigreturn, so we can simply
-                * clear the TIF_RESTORE_SIGMASK flag */
-               if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               if (!handle_signal(signr, &info, &ka, oldset, regs)) {
+                       /* a signal was successfully delivered; the saved
+                        * sigmask will have been stored in the signal frame,
+                        * and will be restored by sigreturn, so we can simply
+                        * clear the TIF_RESTORE_SIGMASK flag */
                        clear_thread_flag(TIF_RESTORE_SIGMASK);
+               }
 
                tracehook_signal_handler(signr, &info, &ka, regs,
                                         test_thread_flag(TIF_SINGLESTEP));
index bd946ef..7c52e94 100644 (file)
@@ -125,16 +125,13 @@ irqreturn_t __irq_entry timer_interrupt(struct pt_regs *regs)
 
 static __init void openrisc_clockevent_init(void)
 {
-       clockevents_calc_mult_shift(&clockevent_openrisc_timer,
-                                   cpuinfo.clock_frequency, 4);
+       clockevent_openrisc_timer.cpumask = cpumask_of(0);
 
        /* We only have 28 bits */
-       clockevent_openrisc_timer.max_delta_ns =
-           clockevent_delta2ns((u32) 0x0fffffff, &clockevent_openrisc_timer);
-       clockevent_openrisc_timer.min_delta_ns =
-           clockevent_delta2ns(1, &clockevent_openrisc_timer);
-       clockevent_openrisc_timer.cpumask = cpumask_of(0);
-       clockevents_register_device(&clockevent_openrisc_timer);
+       clockevents_config_and_register(&clockevent_openrisc_timer,
+                                       cpuinfo.clock_frequency,
+                                       100, 0x0fffffff);
+
 }
 
 /**
index 52ca32b..5cce396 100644 (file)
@@ -114,6 +114,7 @@ void dump_stack(void)
 
        show_stack(current, &stack);
 }
+EXPORT_SYMBOL(dump_stack);
 
 void show_registers(struct pt_regs *regs)
 {
@@ -144,8 +145,8 @@ void show_registers(struct pt_regs *regs)
               regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
        printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
               regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
-       printk("  RES: %08lx oGPR11: %08lx syscallno: %08lx\n",
-              regs->gpr[11], regs->orig_gpr11, regs->syscallno);
+       printk("  RES: %08lx oGPR11: %08lx\n",
+              regs->gpr[11], regs->orig_gpr11);
 
        printk("Process %s (pid: %d, stackpage=%08lx)\n",
               current->comm, current->pid, (unsigned long)current);
@@ -206,8 +207,8 @@ void nommu_dump_state(struct pt_regs *regs,
               regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
        printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
               regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
-       printk("  RES: %08lx oGPR11: %08lx syscallno: %08lx\n",
-              regs->gpr[11], regs->orig_gpr11, regs->syscallno);
+       printk("  RES: %08lx oGPR11: %08lx\n",
+              regs->gpr[11], regs->orig_gpr11);
 
        printk("Process %s (pid: %d, stackpage=%08lx)\n",
               ((struct task_struct *)(__pa(current)))->comm,
index 1cf3a8a..79dea97 100644 (file)
@@ -221,8 +221,7 @@ void __init mem_init(void)
 {
        int codesize, reservedpages, datasize, initsize;
 
-       if (!mem_map)
-               BUG();
+       BUG_ON(!mem_map);
 
        set_max_mapnr_init();
 
index f5b7bf5..12219eb 100644 (file)
 #define MADV_HUGEPAGE  67              /* Worth backing with hugepages */
 #define MADV_NOHUGEPAGE        68              /* Not worth backing with hugepages */
 
+#define MADV_DONTDUMP   69             /* Explicity exclude from the core dump,
+                                          overrides the coredump filter bits */
+#define MADV_DODUMP    70              /* Clear the MADV_NODUMP flag */
+
 /* compatibility flags */
 #define MAP_FILE       0
 #define MAP_VARIABLE   0
index 2242a5c..3234f49 100644 (file)
@@ -82,38 +82,8 @@ struct pci_hba_data {
 
 #ifdef CONFIG_64BIT
 #define PCI_F_EXTEND           0xffffffff00000000UL
-#define PCI_IS_LMMIO(hba,a)    pci_is_lmmio(hba,a)
-
-/* We need to know if an address is LMMMIO or GMMIO.
- * LMMIO requires mangling and GMMIO we must use as-is.
- */
-static __inline__  int pci_is_lmmio(struct pci_hba_data *hba, unsigned long a)
-{
-       return(((a) & PCI_F_EXTEND) == PCI_F_EXTEND);
-}
-
-/*
-** Convert between PCI (IO_VIEW) addresses and processor (PA_VIEW) addresses.
-** See pci.c for more conversions used by Generic PCI code.
-**
-** Platform characteristics/firmware guarantee that
-**     (1) PA_VIEW - IO_VIEW = lmmio_offset for both LMMIO and ELMMIO
-**     (2) PA_VIEW == IO_VIEW for GMMIO
-*/
-#define PCI_BUS_ADDR(hba,a)    (PCI_IS_LMMIO(hba,a)    \
-               ?  ((a) - hba->lmmio_space_offset)      /* mangle LMMIO */ \
-               : (a))                                  /* GMMIO */
-#define PCI_HOST_ADDR(hba,a)   (((a) & PCI_F_EXTEND) == 0 \
-               ? (a) + hba->lmmio_space_offset \
-               : (a))
-
 #else  /* !CONFIG_64BIT */
-
-#define PCI_BUS_ADDR(hba,a)    (a)
-#define PCI_HOST_ADDR(hba,a)   (a)
 #define PCI_F_EXTEND           0UL
-#define PCI_IS_LMMIO(hba,a)    (1)     /* 32-bit doesn't support GMMIO */
-
 #endif /* !CONFIG_64BIT */
 
 /*
@@ -245,14 +215,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 }
 #endif
 
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                        struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                       struct pci_bus_region *region);
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
        /* We don't need to penalize isa irq's */
index 4f0cf0c..24644ac 100644 (file)
@@ -194,58 +194,6 @@ void __init pcibios_init_bus(struct pci_bus *bus)
        pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bridge_ctl);
 }
 
-/* called by drivers/pci/setup-bus.c:pci_setup_bridge().  */
-void __devinit pcibios_resource_to_bus(struct pci_dev *dev,
-               struct pci_bus_region *region, struct resource *res)
-{
-#ifdef CONFIG_64BIT
-       struct pci_hba_data *hba = HBA_DATA(dev->bus->bridge->platform_data);
-#endif
-
-       if (res->flags & IORESOURCE_IO) {
-               /*
-               ** I/O space may see busnumbers here. Something
-               ** in the form of 0xbbxxxx where bb is the bus num
-               ** and xxxx is the I/O port space address.
-               ** Remaining address translation are done in the
-               ** PCI Host adapter specific code - ie dino_out8.
-               */
-               region->start = PCI_PORT_ADDR(res->start);
-               region->end   = PCI_PORT_ADDR(res->end);
-       } else if (res->flags & IORESOURCE_MEM) {
-               /* Convert MMIO addr to PCI addr (undo global virtualization) */
-               region->start = PCI_BUS_ADDR(hba, res->start);
-               region->end   = PCI_BUS_ADDR(hba, res->end);
-       }
-
-       DBG_RES("pcibios_resource_to_bus(%02x %s [%lx,%lx])\n",
-               dev->bus->number, res->flags & IORESOURCE_IO ? "IO" : "MEM",
-               region->start, region->end);
-}
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                             struct pci_bus_region *region)
-{
-#ifdef CONFIG_64BIT
-       struct pci_hba_data *hba = HBA_DATA(dev->bus->bridge->platform_data);
-#endif
-
-       if (res->flags & IORESOURCE_MEM) {
-               res->start = PCI_HOST_ADDR(hba, region->start);
-               res->end = PCI_HOST_ADDR(hba, region->end);
-       }
-
-       if (res->flags & IORESOURCE_IO) {
-               res->start = region->start;
-               res->end = region->end;
-       }
-}
-
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-#endif
-
 /*
  * pcibios align resources() is called every time generic PCI code
  * wants to generate a new address. The process of looking for
index 6e28f9f..673b73e 100644 (file)
@@ -50,6 +50,7 @@
 #define FPUDEBUG 0
 
 #include "float.h"
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <asm/processor.h>
 /* #include <sys/debug.h> */
index 12da77e..1c1aadc 100644 (file)
@@ -27,7 +27,6 @@ zImage.bin.*
 zImage.chrp
 zImage.coff
 zImage.holly
-zImage.iseries
 zImage.*lds
 zImage.miboot
 zImage.pmac
index edfc980..957a83f 100644 (file)
@@ -112,7 +112,6 @@ extern void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
                             struct dma_attrs *attrs);
 
 extern void iommu_init_early_pSeries(void);
-extern void iommu_init_early_iSeries(void);
 extern void iommu_init_early_dart(void);
 extern void iommu_init_early_pasemi(void);
 
index fe0b09d..cf417e5 100644 (file)
@@ -27,12 +27,6 @@ extern atomic_t ppc_n_lost_interrupts;
 /* This number is used when no interrupt has been assigned */
 #define NO_IRQ                 (0)
 
-/* This is a special irq number to return from get_irq() to tell that
- * no interrupt happened _and_ ignore it (don't count it as bad). Some
- * platforms like iSeries rely on that.
- */
-#define NO_IRQ_IGNORE          ((unsigned int)-1)
-
 /* Total number of virq in the platform */
 #define NR_IRQS                CONFIG_NR_IRQS
 
index f7727d9..b921c3f 100644 (file)
@@ -265,12 +265,9 @@ struct kvm_debug_exit_arch {
 struct kvm_guest_debug_arch {
 };
 
-#define KVM_REG_MASK           0x001f
-#define KVM_REG_EXT_MASK       0xffe0
-#define KVM_REG_GPR            0x0000
-#define KVM_REG_FPR            0x0020
-#define KVM_REG_QPR            0x0040
-#define KVM_REG_FQPR           0x0060
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
 
 #define KVM_INTERRUPT_SET      -1U
 #define KVM_INTERRUPT_UNSET    -2U
@@ -292,4 +289,41 @@ struct kvm_allocate_rma {
        __u64 rma_size;
 };
 
+struct kvm_book3e_206_tlb_entry {
+       __u32 mas8;
+       __u32 mas1;
+       __u64 mas2;
+       __u64 mas7_3;
+};
+
+struct kvm_book3e_206_tlb_params {
+       /*
+        * For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
+        *
+        * - The number of ways of TLB0 must be a power of two between 2 and
+        *   16.
+        * - TLB1 must be fully associative.
+        * - The size of TLB0 must be a multiple of the number of ways, and
+        *   the number of sets must be a power of two.
+        * - The size of TLB1 may not exceed 64 entries.
+        * - TLB0 supports 4 KiB pages.
+        * - The page sizes supported by TLB1 are as indicated by
+        *   TLB1CFG (if MMUCFG[MAVN] = 0) or TLB1PS (if MMUCFG[MAVN] = 1)
+        *   as returned by KVM_GET_SREGS.
+        * - TLB2 and TLB3 are reserved, and their entries in tlb_sizes[]
+        *   and tlb_ways[] must be zero.
+        *
+        * tlb_ways[n] = tlb_sizes[n] means the array is fully associative.
+        *
+        * KVM will adjust TLBnCFG based on the sizes configured here,
+        * though arrays greater than 2048 entries will have TLBnCFG[NENTRY]
+        * set to zero.
+        */
+       __u32 tlb_sizes[4];
+       __u32 tlb_ways[4];
+       __u32 reserved[8];
+};
+
+#define KVM_REG_PPC_HIOR       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
+
 #endif /* __LINUX_KVM_POWERPC_H */
index 69c7377..aa795cc 100644 (file)
@@ -90,6 +90,8 @@ struct kvmppc_vcpu_book3s {
 #endif
        int context_id[SID_CONTEXTS];
 
+       bool hior_explicit;             /* HIOR is set by ioctl, not PVR */
+
        struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
        struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
        struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
@@ -119,6 +121,11 @@ extern void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu);
 extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte);
 extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr);
 extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu);
+extern int kvmppc_book3s_hv_page_fault(struct kvm_run *run,
+                       struct kvm_vcpu *vcpu, unsigned long addr,
+                       unsigned long status);
+extern long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr,
+                       unsigned long slb_v, unsigned long valid);
 
 extern void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte);
 extern struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu);
@@ -138,6 +145,21 @@ extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
 extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
 extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
 extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
+extern void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev,
+                       unsigned long *rmap, long pte_index, int realmode);
+extern void kvmppc_invalidate_hpte(struct kvm *kvm, unsigned long *hptep,
+                       unsigned long pte_index);
+void kvmppc_clear_ref_hpte(struct kvm *kvm, unsigned long *hptep,
+                       unsigned long pte_index);
+extern void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long addr,
+                       unsigned long *nb_ret);
+extern void kvmppc_unpin_guest_page(struct kvm *kvm, void *addr);
+extern long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
+                       long pte_index, unsigned long pteh, unsigned long ptel);
+extern long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
+                       long pte_index, unsigned long pteh, unsigned long ptel);
+extern long kvmppc_hv_get_dirty_log(struct kvm *kvm,
+                       struct kvm_memory_slot *memslot);
 
 extern void kvmppc_entry_trampoline(void);
 extern void kvmppc_hv_entry_trampoline(void);
@@ -183,7 +205,9 @@ static inline void kvmppc_update_int_pending(struct kvm_vcpu *vcpu,
 static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
 {
        if ( num < 14 ) {
-               to_svcpu(vcpu)->gpr[num] = val;
+               struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+               svcpu->gpr[num] = val;
+               svcpu_put(svcpu);
                to_book3s(vcpu)->shadow_vcpu->gpr[num] = val;
        } else
                vcpu->arch.gpr[num] = val;
@@ -191,80 +215,120 @@ static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
 
 static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
 {
-       if ( num < 14 )
-               return to_svcpu(vcpu)->gpr[num];
-       else
+       if ( num < 14 ) {
+               struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+               ulong r = svcpu->gpr[num];
+               svcpu_put(svcpu);
+               return r;
+       } else
                return vcpu->arch.gpr[num];
 }
 
 static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
 {
-       to_svcpu(vcpu)->cr = val;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       svcpu->cr = val;
+       svcpu_put(svcpu);
        to_book3s(vcpu)->shadow_vcpu->cr = val;
 }
 
 static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
 {
-       return to_svcpu(vcpu)->cr;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       u32 r;
+       r = svcpu->cr;
+       svcpu_put(svcpu);
+       return r;
 }
 
 static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
 {
-       to_svcpu(vcpu)->xer = val;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       svcpu->xer = val;
        to_book3s(vcpu)->shadow_vcpu->xer = val;
+       svcpu_put(svcpu);
 }
 
 static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
 {
-       return to_svcpu(vcpu)->xer;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       u32 r;
+       r = svcpu->xer;
+       svcpu_put(svcpu);
+       return r;
 }
 
 static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
 {
-       to_svcpu(vcpu)->ctr = val;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       svcpu->ctr = val;
+       svcpu_put(svcpu);
 }
 
 static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
 {
-       return to_svcpu(vcpu)->ctr;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       ulong r;
+       r = svcpu->ctr;
+       svcpu_put(svcpu);
+       return r;
 }
 
 static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
 {
-       to_svcpu(vcpu)->lr = val;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       svcpu->lr = val;
+       svcpu_put(svcpu);
 }
 
 static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
 {
-       return to_svcpu(vcpu)->lr;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       ulong r;
+       r = svcpu->lr;
+       svcpu_put(svcpu);
+       return r;
 }
 
 static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
 {
-       to_svcpu(vcpu)->pc = val;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       svcpu->pc = val;
+       svcpu_put(svcpu);
 }
 
 static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
 {
-       return to_svcpu(vcpu)->pc;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       ulong r;
+       r = svcpu->pc;
+       svcpu_put(svcpu);
+       return r;
 }
 
 static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
 {
        ulong pc = kvmppc_get_pc(vcpu);
-       struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu);
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       u32 r;
 
        /* Load the instruction manually if it failed to do so in the
         * exit path */
        if (svcpu->last_inst == KVM_INST_FETCH_FAILED)
                kvmppc_ld(vcpu, &pc, sizeof(u32), &svcpu->last_inst, false);
 
-       return svcpu->last_inst;
+       r = svcpu->last_inst;
+       svcpu_put(svcpu);
+       return r;
 }
 
 static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
 {
-       return to_svcpu(vcpu)->fault_dar;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       ulong r;
+       r = svcpu->fault_dar;
+       svcpu_put(svcpu);
+       return r;
 }
 
 static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu)
index de604db..38040ff 100644 (file)
 #ifndef __ASM_KVM_BOOK3S_32_H__
 #define __ASM_KVM_BOOK3S_32_H__
 
-static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu)
+static inline struct kvmppc_book3s_shadow_vcpu *svcpu_get(struct kvm_vcpu *vcpu)
 {
        return to_book3s(vcpu)->shadow_vcpu;
 }
 
+static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
+{
+}
+
 #define PTE_SIZE       12
 #define VSID_ALL       0
 #define SR_INVALID     0x00000001      /* VSID 1 should always be unused */
index d0ac94f..b0c08b1 100644 (file)
 #define __ASM_KVM_BOOK3S_64_H__
 
 #ifdef CONFIG_KVM_BOOK3S_PR
-static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu)
+static inline struct kvmppc_book3s_shadow_vcpu *svcpu_get(struct kvm_vcpu *vcpu)
 {
+       preempt_disable();
        return &get_paca()->shadow_vcpu;
 }
+
+static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
+{
+       preempt_enable();
+}
 #endif
 
 #define SPAPR_TCE_SHIFT                12
 
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+/* For now use fixed-size 16MB page table */
+#define HPT_ORDER      24
+#define HPT_NPTEG      (1ul << (HPT_ORDER - 7))        /* 128B per pteg */
+#define HPT_NPTE       (HPT_NPTEG << 3)                /* 8 PTEs per PTEG */
+#define HPT_HASH_MASK  (HPT_NPTEG - 1)
+#endif
+
+#define VRMA_VSID      0x1ffffffUL     /* 1TB VSID reserved for VRMA */
+
+/*
+ * We use a lock bit in HPTE dword 0 to synchronize updates and
+ * accesses to each HPTE, and another bit to indicate non-present
+ * HPTEs.
+ */
+#define HPTE_V_HVLOCK  0x40UL
+#define HPTE_V_ABSENT  0x20UL
+
+static inline long try_lock_hpte(unsigned long *hpte, unsigned long bits)
+{
+       unsigned long tmp, old;
+
+       asm volatile("  ldarx   %0,0,%2\n"
+                    "  and.    %1,%0,%3\n"
+                    "  bne     2f\n"
+                    "  ori     %0,%0,%4\n"
+                    "  stdcx.  %0,0,%2\n"
+                    "  beq+    2f\n"
+                    "  li      %1,%3\n"
+                    "2:        isync"
+                    : "=&r" (tmp), "=&r" (old)
+                    : "r" (hpte), "r" (bits), "i" (HPTE_V_HVLOCK)
+                    : "cc", "memory");
+       return old == 0;
+}
+
 static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
                                             unsigned long pte_index)
 {
@@ -62,4 +104,140 @@ static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r,
        return rb;
 }
 
+static inline unsigned long hpte_page_size(unsigned long h, unsigned long l)
+{
+       /* only handle 4k, 64k and 16M pages for now */
+       if (!(h & HPTE_V_LARGE))
+               return 1ul << 12;               /* 4k page */
+       if ((l & 0xf000) == 0x1000 && cpu_has_feature(CPU_FTR_ARCH_206))
+               return 1ul << 16;               /* 64k page */
+       if ((l & 0xff000) == 0)
+               return 1ul << 24;               /* 16M page */
+       return 0;                               /* error */
+}
+
+static inline unsigned long hpte_rpn(unsigned long ptel, unsigned long psize)
+{
+       return ((ptel & HPTE_R_RPN) & ~(psize - 1)) >> PAGE_SHIFT;
+}
+
+static inline int hpte_is_writable(unsigned long ptel)
+{
+       unsigned long pp = ptel & (HPTE_R_PP0 | HPTE_R_PP);
+
+       return pp != PP_RXRX && pp != PP_RXXX;
+}
+
+static inline unsigned long hpte_make_readonly(unsigned long ptel)
+{
+       if ((ptel & HPTE_R_PP0) || (ptel & HPTE_R_PP) == PP_RWXX)
+               ptel = (ptel & ~HPTE_R_PP) | PP_RXXX;
+       else
+               ptel |= PP_RXRX;
+       return ptel;
+}
+
+static inline int hpte_cache_flags_ok(unsigned long ptel, unsigned long io_type)
+{
+       unsigned int wimg = ptel & HPTE_R_WIMG;
+
+       /* Handle SAO */
+       if (wimg == (HPTE_R_W | HPTE_R_I | HPTE_R_M) &&
+           cpu_has_feature(CPU_FTR_ARCH_206))
+               wimg = HPTE_R_M;
+
+       if (!io_type)
+               return wimg == HPTE_R_M;
+
+       return (wimg & (HPTE_R_W | HPTE_R_I)) == io_type;
+}
+
+/*
+ * Lock and read a linux PTE.  If it's present and writable, atomically
+ * set dirty and referenced bits and return the PTE, otherwise return 0.
+ */
+static inline pte_t kvmppc_read_update_linux_pte(pte_t *p, int writing)
+{
+       pte_t pte, tmp;
+
+       /* wait until _PAGE_BUSY is clear then set it atomically */
+       __asm__ __volatile__ (
+               "1:     ldarx   %0,0,%3\n"
+               "       andi.   %1,%0,%4\n"
+               "       bne-    1b\n"
+               "       ori     %1,%0,%4\n"
+               "       stdcx.  %1,0,%3\n"
+               "       bne-    1b"
+               : "=&r" (pte), "=&r" (tmp), "=m" (*p)
+               : "r" (p), "i" (_PAGE_BUSY)
+               : "cc");
+
+       if (pte_present(pte)) {
+               pte = pte_mkyoung(pte);
+               if (writing && pte_write(pte))
+                       pte = pte_mkdirty(pte);
+       }
+
+       *p = pte;       /* clears _PAGE_BUSY */
+
+       return pte;
+}
+
+/* Return HPTE cache control bits corresponding to Linux pte bits */
+static inline unsigned long hpte_cache_bits(unsigned long pte_val)
+{
+#if _PAGE_NO_CACHE == HPTE_R_I && _PAGE_WRITETHRU == HPTE_R_W
+       return pte_val & (HPTE_R_W | HPTE_R_I);
+#else
+       return ((pte_val & _PAGE_NO_CACHE) ? HPTE_R_I : 0) +
+               ((pte_val & _PAGE_WRITETHRU) ? HPTE_R_W : 0);
+#endif
+}
+
+static inline bool hpte_read_permission(unsigned long pp, unsigned long key)
+{
+       if (key)
+               return PP_RWRX <= pp && pp <= PP_RXRX;
+       return 1;
+}
+
+static inline bool hpte_write_permission(unsigned long pp, unsigned long key)
+{
+       if (key)
+               return pp == PP_RWRW;
+       return pp <= PP_RWRW;
+}
+
+static inline int hpte_get_skey_perm(unsigned long hpte_r, unsigned long amr)
+{
+       unsigned long skey;
+
+       skey = ((hpte_r & HPTE_R_KEY_HI) >> 57) |
+               ((hpte_r & HPTE_R_KEY_LO) >> 9);
+       return (amr >> (62 - 2 * skey)) & 3;
+}
+
+static inline void lock_rmap(unsigned long *rmap)
+{
+       do {
+               while (test_bit(KVMPPC_RMAP_LOCK_BIT, rmap))
+                       cpu_relax();
+       } while (test_and_set_bit_lock(KVMPPC_RMAP_LOCK_BIT, rmap));
+}
+
+static inline void unlock_rmap(unsigned long *rmap)
+{
+       __clear_bit_unlock(KVMPPC_RMAP_LOCK_BIT, rmap);
+}
+
+static inline bool slot_is_aligned(struct kvm_memory_slot *memslot,
+                                  unsigned long pagesize)
+{
+       unsigned long mask = (pagesize >> PAGE_SHIFT) - 1;
+
+       if (pagesize <= PAGE_SIZE)
+               return 1;
+       return !(memslot->base_gfn & mask) && !(memslot->npages & mask);
+}
+
 #endif /* __ASM_KVM_BOOK3S_64_H__ */
index adbfca9..8cd50a5 100644 (file)
 #define E500_PID_NUM   3
 #define E500_TLB_NUM   2
 
-struct tlbe{
-       u32 mas1;
-       u32 mas2;
-       u32 mas3;
-       u32 mas7;
-};
-
 #define E500_TLB_VALID 1
 #define E500_TLB_DIRTY 2
 
-struct tlbe_priv {
+struct tlbe_ref {
        pfn_t pfn;
        unsigned int flags; /* E500_TLB_* */
 };
 
+struct tlbe_priv {
+       struct tlbe_ref ref; /* TLB0 only -- TLB1 uses tlb_refs */
+};
+
 struct vcpu_id_table;
 
+struct kvmppc_e500_tlb_params {
+       int entries, ways, sets;
+};
+
 struct kvmppc_vcpu_e500 {
-       /* Unmodified copy of the guest's TLB. */
-       struct tlbe *gtlb_arch[E500_TLB_NUM];
+       /* Unmodified copy of the guest's TLB -- shared with host userspace. */
+       struct kvm_book3e_206_tlb_entry *gtlb_arch;
+
+       /* Starting entry number in gtlb_arch[] */
+       int gtlb_offset[E500_TLB_NUM];
 
        /* KVM internal information associated with each guest TLB entry */
        struct tlbe_priv *gtlb_priv[E500_TLB_NUM];
 
-       unsigned int gtlb_size[E500_TLB_NUM];
+       struct kvmppc_e500_tlb_params gtlb_params[E500_TLB_NUM];
+
        unsigned int gtlb_nv[E500_TLB_NUM];
 
+       /*
+        * information associated with each host TLB entry --
+        * TLB1 only for now.  If/when guest TLB1 entries can be
+        * mapped with host TLB0, this will be used for that too.
+        *
+        * We don't want to use this for guest TLB0 because then we'd
+        * have the overhead of doing the translation again even if
+        * the entry is still in the guest TLB (e.g. we swapped out
+        * and back, and our host TLB entries got evicted).
+        */
+       struct tlbe_ref *tlb_refs[E500_TLB_NUM];
+       unsigned int host_tlb1_nv;
+
        u32 host_pid[E500_PID_NUM];
        u32 pid[E500_PID_NUM];
        u32 svr;
 
-       u32 mas0;
-       u32 mas1;
-       u32 mas2;
-       u32 mas3;
-       u32 mas4;
-       u32 mas5;
-       u32 mas6;
-       u32 mas7;
-
        /* vcpu id table */
        struct vcpu_id_table *idt;
 
@@ -73,6 +82,9 @@ struct kvmppc_vcpu_e500 {
        u32 tlb1cfg;
        u64 mcar;
 
+       struct page **shared_tlb_pages;
+       int num_shared_tlb_pages;
+
        struct kvm_vcpu vcpu;
 };
 
index bf8af5d..52eb9c1 100644 (file)
 #include <linux/atomic.h>
 #include <asm/kvm_asm.h>
 #include <asm/processor.h>
+#include <asm/page.h>
 
 #define KVM_MAX_VCPUS          NR_CPUS
 #define KVM_MAX_VCORES         NR_CPUS
 #define KVM_MEMORY_SLOTS 32
 /* memory slots that does not exposed to userspace */
 #define KVM_PRIVATE_MEM_SLOTS 4
+#define KVM_MEM_SLOTS_NUM (KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS)
 
 #ifdef CONFIG_KVM_MMIO
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 #endif
 
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+#include <linux/mmu_notifier.h>
+
+#define KVM_ARCH_WANT_MMU_NOTIFIER
+
+struct kvm;
+extern int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+extern int kvm_age_hva(struct kvm *kvm, unsigned long hva);
+extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
+extern void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
+
+#endif
+
 /* We don't currently support large pages. */
 #define KVM_HPAGE_GFN_SHIFT(x) 0
 #define KVM_NR_PAGE_SIZES      1
@@ -158,34 +173,72 @@ struct kvmppc_spapr_tce_table {
        struct page *pages[0];
 };
 
-struct kvmppc_rma_info {
+struct kvmppc_linear_info {
        void            *base_virt;
        unsigned long    base_pfn;
        unsigned long    npages;
        struct list_head list;
-       atomic_t         use_count;
+       atomic_t         use_count;
+       int              type;
+};
+
+/*
+ * The reverse mapping array has one entry for each HPTE,
+ * which stores the guest's view of the second word of the HPTE
+ * (including the guest physical address of the mapping),
+ * plus forward and backward pointers in a doubly-linked ring
+ * of HPTEs that map the same host page.  The pointers in this
+ * ring are 32-bit HPTE indexes, to save space.
+ */
+struct revmap_entry {
+       unsigned long guest_rpte;
+       unsigned int forw, back;
+};
+
+/*
+ * We use the top bit of each memslot->rmap entry as a lock bit,
+ * and bit 32 as a present flag.  The bottom 32 bits are the
+ * index in the guest HPT of a HPTE that points to the page.
+ */
+#define KVMPPC_RMAP_LOCK_BIT   63
+#define KVMPPC_RMAP_RC_SHIFT   32
+#define KVMPPC_RMAP_REFERENCED (HPTE_R_R << KVMPPC_RMAP_RC_SHIFT)
+#define KVMPPC_RMAP_CHANGED    (HPTE_R_C << KVMPPC_RMAP_RC_SHIFT)
+#define KVMPPC_RMAP_PRESENT    0x100000000ul
+#define KVMPPC_RMAP_INDEX      0xfffffffful
+
+/* Low-order bits in kvm->arch.slot_phys[][] */
+#define KVMPPC_PAGE_ORDER_MASK 0x1f
+#define KVMPPC_PAGE_NO_CACHE   HPTE_R_I        /* 0x20 */
+#define KVMPPC_PAGE_WRITETHRU  HPTE_R_W        /* 0x40 */
+#define KVMPPC_GOT_PAGE                0x80
+
+struct kvm_arch_memory_slot {
 };
 
 struct kvm_arch {
 #ifdef CONFIG_KVM_BOOK3S_64_HV
        unsigned long hpt_virt;
-       unsigned long ram_npages;
-       unsigned long ram_psize;
-       unsigned long ram_porder;
-       struct kvmppc_pginfo *ram_pginfo;
+       struct revmap_entry *revmap;
        unsigned int lpid;
        unsigned int host_lpid;
        unsigned long host_lpcr;
        unsigned long sdr1;
        unsigned long host_sdr1;
        int tlbie_lock;
-       int n_rma_pages;
        unsigned long lpcr;
        unsigned long rmor;
-       struct kvmppc_rma_info *rma;
+       struct kvmppc_linear_info *rma;
+       unsigned long vrma_slb_v;
+       int rma_setup_done;
+       int using_mmu_notifiers;
        struct list_head spapr_tce_tables;
+       spinlock_t slot_phys_lock;
+       unsigned long *slot_phys[KVM_MEM_SLOTS_NUM];
+       int slot_npages[KVM_MEM_SLOTS_NUM];
        unsigned short last_vcpu[NR_CPUS];
        struct kvmppc_vcore *vcores[KVM_MAX_VCORES];
+       struct kvmppc_linear_info *hpt_li;
 #endif /* CONFIG_KVM_BOOK3S_64_HV */
 };
 
@@ -318,10 +371,6 @@ struct kvm_vcpu_arch {
        u32 vrsave; /* also USPRG0 */
        u32 mmucr;
        ulong shadow_msr;
-       ulong sprg4;
-       ulong sprg5;
-       ulong sprg6;
-       ulong sprg7;
        ulong csrr0;
        ulong csrr1;
        ulong dsrr0;
@@ -329,16 +378,14 @@ struct kvm_vcpu_arch {
        ulong mcsrr0;
        ulong mcsrr1;
        ulong mcsr;
-       ulong esr;
        u32 dec;
        u32 decar;
        u32 tbl;
        u32 tbu;
        u32 tcr;
-       u32 tsr;
+       ulong tsr; /* we need to perform set/clr_bits() which requires ulong */
        u32 ivor[64];
        ulong ivpr;
-       u32 pir;
        u32 pvr;
 
        u32 shadow_pid;
@@ -427,9 +474,14 @@ struct kvm_vcpu_arch {
 #ifdef CONFIG_KVM_BOOK3S_64_HV
        struct kvm_vcpu_arch_shared shregs;
 
+       unsigned long pgfault_addr;
+       long pgfault_index;
+       unsigned long pgfault_hpte[2];
+
        struct list_head run_list;
        struct task_struct *run_task;
        struct kvm_run *kvm_run;
+       pgd_t *pgdir;
 #endif
 };
 
@@ -438,4 +490,12 @@ struct kvm_vcpu_arch {
 #define KVMPPC_VCPU_BUSY_IN_HOST       1
 #define KVMPPC_VCPU_RUNNABLE           2
 
+/* Values for vcpu->arch.io_gpr */
+#define KVM_MMIO_REG_MASK      0x001f
+#define KVM_MMIO_REG_EXT_MASK  0xffe0
+#define KVM_MMIO_REG_GPR       0x0000
+#define KVM_MMIO_REG_FPR       0x0020
+#define KVM_MMIO_REG_QPR       0x0040
+#define KVM_MMIO_REG_FQPR      0x0060
+
 #endif /* __POWERPC_KVM_HOST_H__ */
index 50533f9..7b754e7 100644 (file)
 
 #include <linux/types.h>
 
+/*
+ * Additions to this struct must only occur at the end, and should be
+ * accompanied by a KVM_MAGIC_FEAT flag to advertise that they are present
+ * (albeit not necessarily relevant to the current target hardware platform).
+ *
+ * Struct fields are always 32 or 64 bit aligned, depending on them being 32
+ * or 64 bit wide respectively.
+ *
+ * See Documentation/virtual/kvm/ppc-pv.txt
+ */
 struct kvm_vcpu_arch_shared {
        __u64 scratch1;
        __u64 scratch2;
@@ -33,11 +43,35 @@ struct kvm_vcpu_arch_shared {
        __u64 sprg3;
        __u64 srr0;
        __u64 srr1;
-       __u64 dar;
+       __u64 dar;              /* dear on BookE */
        __u64 msr;
        __u32 dsisr;
        __u32 int_pending;      /* Tells the guest if we have an interrupt */
        __u32 sr[16];
+       __u32 mas0;
+       __u32 mas1;
+       __u64 mas7_3;
+       __u64 mas2;
+       __u32 mas4;
+       __u32 mas6;
+       __u32 esr;
+       __u32 pir;
+
+       /*
+        * SPRG4-7 are user-readable, so we can only keep these consistent
+        * between the shared area and the real registers when there's an
+        * intervening exit to KVM.  This also applies to SPRG3 on some
+        * chips.
+        *
+        * This suffices for access by guest userspace, since in PR-mode
+        * KVM, an exit must occur when changing the guest's MSR[PR].
+        * If the guest kernel writes to SPRG3-7 via the shared area, it
+        * must also use the shared area for reading while in kernel space.
+        */
+       __u64 sprg4;
+       __u64 sprg5;
+       __u64 sprg6;
+       __u64 sprg7;
 };
 
 #define KVM_SC_MAGIC_R0                0x4b564d21 /* "KVM!" */
@@ -47,7 +81,10 @@ struct kvm_vcpu_arch_shared {
 
 #define KVM_FEATURE_MAGIC_PAGE 1
 
-#define KVM_MAGIC_FEAT_SR      (1 << 0)
+#define KVM_MAGIC_FEAT_SR              (1 << 0)
+
+/* MASn, ESR, PIR, and high SPRGs */
+#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7   (1 << 1)
 
 #ifdef __KERNEL__
 
index 46efd1a..9d6dee0 100644 (file)
@@ -66,6 +66,7 @@ extern int kvmppc_emulate_instruction(struct kvm_run *run,
 extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
 extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
 extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb);
+extern void kvmppc_decrementer_func(unsigned long data);
 extern int kvmppc_sanity_check(struct kvm_vcpu *vcpu);
 
 /* Core-specific hooks */
@@ -94,7 +95,7 @@ extern int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
 extern void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
 extern void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu);
 
-extern void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu);
+extern void kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu);
 extern int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu);
 extern void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags);
 extern void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu);
@@ -120,15 +121,17 @@ extern long kvmppc_alloc_hpt(struct kvm *kvm);
 extern void kvmppc_free_hpt(struct kvm *kvm);
 extern long kvmppc_prepare_vrma(struct kvm *kvm,
                                struct kvm_userspace_memory_region *mem);
-extern void kvmppc_map_vrma(struct kvm *kvm,
-                           struct kvm_userspace_memory_region *mem);
+extern void kvmppc_map_vrma(struct kvm_vcpu *vcpu,
+                       struct kvm_memory_slot *memslot, unsigned long porder);
 extern int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu);
 extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
                                struct kvm_create_spapr_tce *args);
 extern long kvm_vm_ioctl_allocate_rma(struct kvm *kvm,
                                struct kvm_allocate_rma *rma);
-extern struct kvmppc_rma_info *kvm_alloc_rma(void);
-extern void kvm_release_rma(struct kvmppc_rma_info *ri);
+extern struct kvmppc_linear_info *kvm_alloc_rma(void);
+extern void kvm_release_rma(struct kvmppc_linear_info *ri);
+extern struct kvmppc_linear_info *kvm_alloc_hpt(void);
+extern void kvm_release_hpt(struct kvmppc_linear_info *li);
 extern int kvmppc_core_init_vm(struct kvm *kvm);
 extern void kvmppc_core_destroy_vm(struct kvm *kvm);
 extern int kvmppc_core_prepare_memory_region(struct kvm *kvm,
@@ -175,6 +178,9 @@ int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
 void kvmppc_get_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
 int kvmppc_set_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
 
+int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg);
+int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg);
+
 void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid);
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
@@ -183,14 +189,19 @@ static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
        paca[cpu].kvm_hstate.xics_phys = addr;
 }
 
-extern void kvm_rma_init(void);
+extern void kvm_linear_init(void);
 
 #else
 static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
 {}
 
-static inline void kvm_rma_init(void)
+static inline void kvm_linear_init(void)
 {}
 #endif
 
+int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
+                             struct kvm_config_tlb *cfg);
+int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
+                            struct kvm_dirty_tlb *cfg);
+
 #endif /* __POWERPC_KVM_PPC_H__ */
index bf37931..42ce570 100644 (file)
@@ -99,9 +99,7 @@ struct machdep_calls {
 
        void            (*init_IRQ)(void);
 
-       /* Return an irq, or NO_IRQ to indicate there are none pending.
-        * If for some reason there is no irq, but the interrupt
-        * shouldn't be counted as spurious, return NO_IRQ_IGNORE. */
+       /* Return an irq, or NO_IRQ to indicate there are none pending. */
        unsigned int    (*get_irq)(void);
 
        /* PCI stuff */
index f5f89ca..cdb5421 100644 (file)
 /* MAS registers bit definitions */
 
 #define MAS0_TLBSEL(x)         (((x) << 28) & 0x30000000)
-#define MAS0_ESEL(x)           (((x) << 16) & 0x0FFF0000)
-#define MAS0_NV(x)             ((x) & 0x00000FFF)
 #define MAS0_ESEL_MASK         0x0FFF0000
+#define MAS0_ESEL_SHIFT                16
+#define MAS0_ESEL(x)           (((x) << MAS0_ESEL_SHIFT) & MAS0_ESEL_MASK)
+#define MAS0_NV(x)             ((x) & 0x00000FFF)
 #define MAS0_HES               0x00004000
 #define MAS0_WQ_ALLWAYS                0x00000000
 #define MAS0_WQ_COND           0x00001000
 #define TLBnCFG_MAXSIZE                0x000f0000      /* Maximum Page Size (v1.0) */
 #define TLBnCFG_MAXSIZE_SHIFT  16
 #define TLBnCFG_ASSOC          0xff000000      /* Associativity */
+#define TLBnCFG_ASSOC_SHIFT    24
 
 /* TLBnPS encoding */
 #define TLBnPS_4K              0x00000004
index 412ba49..1c65a59 100644 (file)
@@ -108,11 +108,11 @@ extern char initial_stab[];
 #define HPTE_V_VRMA_MASK       ASM_CONST(0x4001ffffff000000)
 
 /* Values for PP (assumes Ks=0, Kp=1) */
-/* pp0 will always be 0 for linux     */
 #define PP_RWXX        0       /* Supervisor read/write, User none */
 #define PP_RWRX 1      /* Supervisor read/write, User read */
 #define PP_RWRW 2      /* Supervisor read/write, User read/write */
 #define PP_RXRX 3      /* Supervisor read,       User read */
+#define PP_RXXX        (HPTE_R_PP0 | 2)        /* Supervisor read, user none */
 
 #ifndef __ASSEMBLY__
 
@@ -267,7 +267,6 @@ extern void demote_segment_4k(struct mm_struct *mm, unsigned long addr);
 
 extern void hpte_init_native(void);
 extern void hpte_init_lpar(void);
-extern void hpte_init_iSeries(void);
 extern void hpte_init_beat(void);
 extern void hpte_init_beat_v3(void);
 
@@ -325,9 +324,6 @@ extern void slb_set_size(u16 size);
  * WARNING - If you change these you must make sure the asm
  * implementations in slb_allocate (slb_low.S), do_stab_bolted
  * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
- *
- * You'll also need to change the precomputed VSID values in head.S
- * which are used by the iSeries firmware.
  */
 
 #define VSID_MULTIPLIER_256M   ASM_CONST(200730139)    /* 28-bit prime */
@@ -484,14 +480,6 @@ static inline unsigned long get_vsid(unsigned long context, unsigned long ea,
                             | (ea >> SID_SHIFT_1T), 1T);
 }
 
-/*
- * This is only used on legacy iSeries in lparmap.c,
- * hence the 256MB segment assumption.
- */
-#define VSID_SCRAMBLE(pvsid)   (((pvsid) * VSID_MULTIPLIER_256M) %     \
-                                VSID_MODULUS_256M)
-#define KERNEL_VSID(ea)                VSID_SCRAMBLE(GET_ESID(ea))
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_MMU_HASH64_H_ */
index 5d48765..ac39e6a 100644 (file)
@@ -155,14 +155,7 @@ struct pci_dn {
 
        struct  pci_dev *pcidev;        /* back-pointer to the pci device */
 #ifdef CONFIG_EEH
-       int     class_code;             /* pci device class */
-       int     eeh_mode;               /* See eeh.h for possible EEH_MODEs */
-       int     eeh_config_addr;
-       int     eeh_pe_config_addr; /* new-style partition endpoint address */
-       int     eeh_check_count;        /* # times driver ignored error */
-       int     eeh_freeze_count;       /* # times this device froze up. */
-       int     eeh_false_positives;    /* # times this device reported #ff's */
-       u32     config_space[16];       /* saved PCI config space */
+       struct eeh_dev *edev;           /* eeh device */
 #endif
 #define IODA_INVALID_PE                (-1)
 #ifdef CONFIG_PPC_POWERNV
@@ -185,6 +178,13 @@ static inline int pci_device_from_OF_node(struct device_node *np,
        return 0;
 }
 
+#if defined(CONFIG_EEH)
+static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
+{
+       return PCI_DN(dn)->edev;
+}
+#endif
+
 /** Find the bus corresponding to the indicated device node */
 extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn);
 
index f54b3d2..6653f27 100644 (file)
@@ -154,14 +154,6 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
 
 #endif /* CONFIG_PPC64 */
 
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-                       struct pci_bus_region *region,
-                       struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
-                       struct resource *res,
-                       struct pci_bus_region *region);
-
 extern void pcibios_claim_one_bus(struct pci_bus *b);
 
 extern void pcibios_finish_adding_to_bus(struct pci_bus *bus);
@@ -190,6 +182,7 @@ extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
                                 const struct resource *rsrc,
                                 resource_size_t *start, resource_size_t *end);
 
+extern resource_size_t pcibios_io_space_offset(struct pci_controller *hose);
 extern void pcibios_setup_bus_devices(struct pci_bus *bus);
 extern void pcibios_setup_bus_self(struct pci_bus *bus);
 extern void pcibios_setup_phb_io_space(struct pci_controller *hose);
index 1a8093f..078019b 100644 (file)
@@ -47,6 +47,8 @@ struct power_pmu {
  */
 #define PPMU_LIMITED_PMC5_6    1       /* PMC5/6 have limited function */
 #define PPMU_ALT_SIPR          2       /* uses alternate posn for SIPR/HV */
+#define PPMU_NO_SIPR           4       /* no SIPR/HV in MMCRA at all */
+#define PPMU_NO_CONT_SAMPLING  8       /* no continuous sampling */
 
 /*
  * Values for flags to get_alternatives()
index e980faa..d81f994 100644 (file)
@@ -45,6 +45,7 @@
 #define PPC_INST_MFSPR_DSCR_MASK       0xfc1fffff
 #define PPC_INST_MTSPR_DSCR            0x7c1103a6
 #define PPC_INST_MTSPR_DSCR_MASK       0xfc1fffff
+#define PPC_INST_SLBFEE                        0x7c0007a7
 
 #define PPC_INST_STRING                        0x7c00042a
 #define PPC_INST_STRING_MASK           0xfc0007fe
                                        __PPC_RS(t) | __PPC_RA(a) | __PPC_RB(b))
 #define PPC_ERATSX_DOT(t, a, w)        stringify_in_c(.long PPC_INST_ERATSX_DOT | \
                                        __PPC_RS(t) | __PPC_RA(a) | __PPC_RB(b))
-
+#define PPC_SLBFEE_DOT(t, b)   stringify_in_c(.long PPC_INST_SLBFEE | \
+                                       __PPC_RT(t) | __PPC_RB(b))
 
 /*
  * Define what the VSX XX1 form instructions will look like, then add
index e660b37..80fa704 100644 (file)
@@ -45,8 +45,6 @@ extern void init_pci_config_tokens (void);
 extern unsigned long get_phb_buid (struct device_node *);
 extern int rtas_setup_phb(struct pci_controller *phb);
 
-extern unsigned long pci_probe_only;
-
 #ifdef CONFIG_EEH
 
 void pci_addr_cache_build(void);
index b1a215e..9d7f0fb 100644 (file)
 #define   DSISR_ISSTORE                0x02000000      /* access was a store */
 #define   DSISR_DABRMATCH      0x00400000      /* hit data breakpoint */
 #define   DSISR_NOSEGMENT      0x00200000      /* STAB/SLB miss */
+#define   DSISR_KEYFAULT       0x00200000      /* Key fault */
 #define SPRN_TBRL      0x10C   /* Time Base Read Lower Register (user, R/O) */
 #define SPRN_TBRU      0x10D   /* Time Base Read Upper Register (user, R/O) */
 #define SPRN_TBWL      0x11C   /* Time Base Lower Register (super, R/W) */
 #define   LPCR_ISL     (1ul << (63-2))
 #define   LPCR_VC_SH   (63-2)
 #define   LPCR_DPFD_SH (63-11)
+#define   LPCR_VRMASD  (0x1ful << (63-16))
 #define   LPCR_VRMA_L  (1ul << (63-12))
 #define   LPCR_VRMA_LP0        (1ul << (63-15))
 #define   LPCR_VRMA_LP1        (1ul << (63-16))
 #define SPRN_SPRG7     0x117   /* Special Purpose Register General 7 */
 #define SPRN_SRR0      0x01A   /* Save/Restore Register 0 */
 #define SPRN_SRR1      0x01B   /* Save/Restore Register 1 */
+#define   SRR1_ISI_NOPT                0x40000000 /* ISI: Not found in hash */
+#define   SRR1_ISI_N_OR_G      0x10000000 /* ISI: Access is no-exec or G */
+#define   SRR1_ISI_PROT                0x08000000 /* ISI: Other protection fault */
 #define   SRR1_WAKEMASK                0x00380000 /* reason for wakeup */
 #define   SRR1_WAKESYSERR      0x00300000 /* System error */
 #define   SRR1_WAKEEE          0x00200000 /* External interrupt */
index 9d6c37a..557cff8 100644 (file)
@@ -74,7 +74,6 @@ struct rtas_suspend_me_data {
 /* RTAS event classes */
 #define RTAS_INTERNAL_ERROR            0x80000000 /* set bit 0 */
 #define RTAS_EPOW_WARNING              0x40000000 /* set bit 1 */
-#define RTAS_POWERMGM_EVENTS           0x20000000 /* set bit 2 */
 #define RTAS_HOTPLUG_EVENTS            0x10000000 /* set bit 3 */
 #define RTAS_IO_EVENTS                 0x08000000 /* set bit 4 */
 #define RTAS_EVENT_SCAN_ALL_EVENTS     0xffffffff
@@ -204,6 +203,39 @@ struct rtas_ext_event_log_v6 {
                                        /* Variable length.             */
 };
 
+/* pSeries event log format */
+
+/* Two bytes ASCII section IDs */
+#define PSERIES_ELOG_SECT_ID_PRIV_HDR          (('P' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_USER_HDR          (('U' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_PRIMARY_SRC       (('P' << 8) | 'S')
+#define PSERIES_ELOG_SECT_ID_EXTENDED_UH       (('E' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_FAILING_MTMS      (('M' << 8) | 'T')
+#define PSERIES_ELOG_SECT_ID_SECONDARY_SRC     (('S' << 8) | 'S')
+#define PSERIES_ELOG_SECT_ID_DUMP_LOCATOR      (('D' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_FW_ERROR          (('S' << 8) | 'W')
+#define PSERIES_ELOG_SECT_ID_IMPACT_PART_ID    (('L' << 8) | 'P')
+#define PSERIES_ELOG_SECT_ID_LOGIC_RESOURCE_ID (('L' << 8) | 'R')
+#define PSERIES_ELOG_SECT_ID_HMC_ID            (('H' << 8) | 'M')
+#define PSERIES_ELOG_SECT_ID_EPOW              (('E' << 8) | 'P')
+#define PSERIES_ELOG_SECT_ID_IO_EVENT          (('I' << 8) | 'E')
+#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO     (('M' << 8) | 'I')
+#define PSERIES_ELOG_SECT_ID_CALL_HOME         (('C' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_USER_DEF          (('U' << 8) | 'D')
+
+/* Vendor specific Platform Event Log Format, Version 6, section header */
+struct pseries_errorlog {
+       uint16_t id;                    /* 0x00 2-byte ASCII section ID */
+       uint16_t length;                /* 0x02 Section length in bytes */
+       uint8_t version;                /* 0x04 Section version         */
+       uint8_t subtype;                /* 0x05 Section subtype         */
+       uint16_t creator_component;     /* 0x06 Creator component ID    */
+       uint8_t data[];                 /* 0x08 Start of section data   */
+};
+
+struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
+                                             uint16_t section_id);
+
 /*
  * This can be set by the rtas_flash module so that it can get called
  * as the absolutely last thing before the kernel terminates.
index adba970..ebc24dc 100644 (file)
@@ -122,7 +122,6 @@ extern void smp_muxed_ipi_set_data(int cpu, unsigned long data);
 extern void smp_muxed_ipi_message_pass(int cpu, int msg);
 extern irqreturn_t smp_ipi_demux(void);
 
-void smp_init_iSeries(void);
 void smp_init_pSeries(void);
 void smp_init_cell(void);
 void smp_init_celleb(void);
index 8338aef..b303881 100644 (file)
@@ -44,7 +44,6 @@ extern void __init udbg_init_debug_lpar_hvsi(void);
 extern void __init udbg_init_pmac_realmode(void);
 extern void __init udbg_init_maple_realmode(void);
 extern void __init udbg_init_pas_realmode(void);
-extern void __init udbg_init_iseries(void);
 extern void __init udbg_init_rtas_panel(void);
 extern void __init udbg_init_rtas_console(void);
 extern void __init udbg_init_debug_beat(void);
index 0a290a1..6bfd5ff 100644 (file)
@@ -69,6 +69,7 @@ struct vio_dev {
 };
 
 struct vio_driver {
+       const char *name;
        const struct vio_device_id *id_table;
        int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
        int (*remove)(struct vio_dev *dev);
@@ -76,10 +77,17 @@ struct vio_driver {
         * be loaded in a CMO environment if it uses DMA.
         */
        unsigned long (*get_desired_dma)(struct vio_dev *dev);
+       const struct dev_pm_ops *pm;
        struct device_driver driver;
 };
 
-extern int vio_register_driver(struct vio_driver *drv);
+extern int __vio_register_driver(struct vio_driver *drv, struct module *owner,
+                                const char *mod_name);
+/*
+ * vio_register_driver must be a macro so that KBUILD_MODNAME can be expanded
+ */
+#define vio_register_driver(driver)            \
+       __vio_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
 extern void vio_unregister_driver(struct vio_driver *drv);
 
 extern int vio_cmo_entitlement_update(size_t);
index cc492e4..34b8afe 100644 (file)
@@ -412,16 +412,23 @@ int main(void)
        DEFINE(VCPU_SPRG2, offsetof(struct kvm_vcpu, arch.shregs.sprg2));
        DEFINE(VCPU_SPRG3, offsetof(struct kvm_vcpu, arch.shregs.sprg3));
 #endif
-       DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4));
-       DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
-       DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6));
-       DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7));
+       DEFINE(VCPU_SHARED_SPRG4, offsetof(struct kvm_vcpu_arch_shared, sprg4));
+       DEFINE(VCPU_SHARED_SPRG5, offsetof(struct kvm_vcpu_arch_shared, sprg5));
+       DEFINE(VCPU_SHARED_SPRG6, offsetof(struct kvm_vcpu_arch_shared, sprg6));
+       DEFINE(VCPU_SHARED_SPRG7, offsetof(struct kvm_vcpu_arch_shared, sprg7));
        DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid));
        DEFINE(VCPU_SHADOW_PID1, offsetof(struct kvm_vcpu, arch.shadow_pid1));
        DEFINE(VCPU_SHARED, offsetof(struct kvm_vcpu, arch.shared));
        DEFINE(VCPU_SHARED_MSR, offsetof(struct kvm_vcpu_arch_shared, msr));
        DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr));
 
+       DEFINE(VCPU_SHARED_MAS0, offsetof(struct kvm_vcpu_arch_shared, mas0));
+       DEFINE(VCPU_SHARED_MAS1, offsetof(struct kvm_vcpu_arch_shared, mas1));
+       DEFINE(VCPU_SHARED_MAS2, offsetof(struct kvm_vcpu_arch_shared, mas2));
+       DEFINE(VCPU_SHARED_MAS7_3, offsetof(struct kvm_vcpu_arch_shared, mas7_3));
+       DEFINE(VCPU_SHARED_MAS4, offsetof(struct kvm_vcpu_arch_shared, mas4));
+       DEFINE(VCPU_SHARED_MAS6, offsetof(struct kvm_vcpu_arch_shared, mas6));
+
        /* book3s */
 #ifdef CONFIG_KVM_BOOK3S_64_HV
        DEFINE(KVM_LPID, offsetof(struct kvm, arch.lpid));
@@ -434,6 +441,7 @@ int main(void)
        DEFINE(KVM_LAST_VCPU, offsetof(struct kvm, arch.last_vcpu));
        DEFINE(KVM_LPCR, offsetof(struct kvm, arch.lpcr));
        DEFINE(KVM_RMOR, offsetof(struct kvm, arch.rmor));
+       DEFINE(KVM_VRMA_SLB_V, offsetof(struct kvm, arch.vrma_slb_v));
        DEFINE(VCPU_DSISR, offsetof(struct kvm_vcpu, arch.shregs.dsisr));
        DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar));
 #endif
index 2d0868a..cb705fd 100644 (file)
@@ -101,14 +101,14 @@ data_access_not_stab:
 END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
 #endif
        EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD,
-                                KVMTEST_PR, 0x300)
+                                KVMTEST, 0x300)
 
        . = 0x380
        .globl data_access_slb_pSeries
 data_access_slb_pSeries:
        HMT_MEDIUM
        SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x380)
+       EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380)
        std     r3,PACA_EXSLB+EX_R3(r13)
        mfspr   r3,SPRN_DAR
 #ifdef __DISABLED__
@@ -330,8 +330,8 @@ do_stab_bolted_pSeries:
        EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD)
 #endif /* CONFIG_POWER4_ONLY */
 
-       KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_STD, 0x300)
-       KVM_HANDLER_PR_SKIP(PACA_EXSLB, EXC_STD, 0x380)
+       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300)
+       KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380)
        KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x400)
        KVM_HANDLER_PR(PACA_EXSLB, EXC_STD, 0x480)
        KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x900)
index 2c5635d..243dbab 100644 (file)
@@ -208,8 +208,8 @@ notrace void arch_local_irq_restore(unsigned long en)
         * we are checking the "new" CPU instead of the old one. This
         * is only a problem if an event happened on the "old" CPU.
         *
-        * External interrupt events on non-iseries will have caused
-        * interrupts to be hard-disabled, so there is no problem, we
+        * External interrupt events will have caused interrupts to
+        * be hard-disabled, so there is no problem, we
         * cannot have preempted.
         */
        irq_happened = get_irq_happened();
@@ -445,9 +445,9 @@ void do_IRQ(struct pt_regs *regs)
        may_hard_irq_enable();
 
        /* And finally process it */
-       if (irq != NO_IRQ && irq != NO_IRQ_IGNORE)
+       if (irq != NO_IRQ)
                handle_one_irq(irq);
-       else if (irq != NO_IRQ_IGNORE)
+       else
                __get_cpu_var(irq_stat).spurious_irqs++;
 
        irq_exit();
index 2985338..62bdf23 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved.
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
  *
  * Authors:
  *     Alexander Graf <agraf@suse.de>
@@ -29,6 +30,7 @@
 #include <asm/sections.h>
 #include <asm/cacheflush.h>
 #include <asm/disassemble.h>
+#include <asm/ppc-opcode.h>
 
 #define KVM_MAGIC_PAGE         (-4096L)
 #define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x)
 #define KVM_INST_B             0x48000000
 #define KVM_INST_B_MASK                0x03ffffff
 #define KVM_INST_B_MAX         0x01ffffff
+#define KVM_INST_LI            0x38000000
 
 #define KVM_MASK_RT            0x03e00000
 #define KVM_RT_30              0x03c00000
 #define KVM_MASK_RB            0x0000f800
 #define KVM_INST_MFMSR         0x7c0000a6
-#define KVM_INST_MFSPR_SPRG0   0x7c1042a6
-#define KVM_INST_MFSPR_SPRG1   0x7c1142a6
-#define KVM_INST_MFSPR_SPRG2   0x7c1242a6
-#define KVM_INST_MFSPR_SPRG3   0x7c1342a6
-#define KVM_INST_MFSPR_SRR0    0x7c1a02a6
-#define KVM_INST_MFSPR_SRR1    0x7c1b02a6
-#define KVM_INST_MFSPR_DAR     0x7c1302a6
-#define KVM_INST_MFSPR_DSISR   0x7c1202a6
-
-#define KVM_INST_MTSPR_SPRG0   0x7c1043a6
-#define KVM_INST_MTSPR_SPRG1   0x7c1143a6
-#define KVM_INST_MTSPR_SPRG2   0x7c1243a6
-#define KVM_INST_MTSPR_SPRG3   0x7c1343a6
-#define KVM_INST_MTSPR_SRR0    0x7c1a03a6
-#define KVM_INST_MTSPR_SRR1    0x7c1b03a6
-#define KVM_INST_MTSPR_DAR     0x7c1303a6
-#define KVM_INST_MTSPR_DSISR   0x7c1203a6
+
+#define SPR_FROM               0
+#define SPR_TO                 0x100
+
+#define KVM_INST_SPR(sprn, moveto) (0x7c0002a6 | \
+                                   (((sprn) & 0x1f) << 16) | \
+                                   (((sprn) & 0x3e0) << 6) | \
+                                   (moveto))
+
+#define KVM_INST_MFSPR(sprn)   KVM_INST_SPR(sprn, SPR_FROM)
+#define KVM_INST_MTSPR(sprn)   KVM_INST_SPR(sprn, SPR_TO)
 
 #define KVM_INST_TLBSYNC       0x7c00046c
 #define KVM_INST_MTMSRD_L0     0x7c000164
 #define KVM_INST_MTMSRD_L1     0x7c010164
 #define KVM_INST_MTMSR         0x7c000124
 
+#define KVM_INST_WRTEE         0x7c000106
 #define KVM_INST_WRTEEI_0      0x7c000146
 #define KVM_INST_WRTEEI_1      0x7c008146
 
@@ -270,26 +268,27 @@ static void kvm_patch_ins_mtmsr(u32 *inst, u32 rt)
 
 #ifdef CONFIG_BOOKE
 
-extern u32 kvm_emulate_wrteei_branch_offs;
-extern u32 kvm_emulate_wrteei_ee_offs;
-extern u32 kvm_emulate_wrteei_len;
-extern u32 kvm_emulate_wrteei[];
+extern u32 kvm_emulate_wrtee_branch_offs;
+extern u32 kvm_emulate_wrtee_reg_offs;
+extern u32 kvm_emulate_wrtee_orig_ins_offs;
+extern u32 kvm_emulate_wrtee_len;
+extern u32 kvm_emulate_wrtee[];
 
-static void kvm_patch_ins_wrteei(u32 *inst)
+static void kvm_patch_ins_wrtee(u32 *inst, u32 rt, int imm_one)
 {
        u32 *p;
        int distance_start;
        int distance_end;
        ulong next_inst;
 
-       p = kvm_alloc(kvm_emulate_wrteei_len * 4);
+       p = kvm_alloc(kvm_emulate_wrtee_len * 4);
        if (!p)
                return;
 
        /* Find out where we are and put everything there */
        distance_start = (ulong)p - (ulong)inst;
        next_inst = ((ulong)inst + 4);
-       distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_branch_offs];
+       distance_end = next_inst - (ulong)&p[kvm_emulate_wrtee_branch_offs];
 
        /* Make sure we only write valid b instructions */
        if (distance_start > KVM_INST_B_MAX) {
@@ -298,10 +297,65 @@ static void kvm_patch_ins_wrteei(u32 *inst)
        }
 
        /* Modify the chunk to fit the invocation */
-       memcpy(p, kvm_emulate_wrteei, kvm_emulate_wrteei_len * 4);
-       p[kvm_emulate_wrteei_branch_offs] |= distance_end & KVM_INST_B_MASK;
-       p[kvm_emulate_wrteei_ee_offs] |= (*inst & MSR_EE);
-       flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_len * 4);
+       memcpy(p, kvm_emulate_wrtee, kvm_emulate_wrtee_len * 4);
+       p[kvm_emulate_wrtee_branch_offs] |= distance_end & KVM_INST_B_MASK;
+
+       if (imm_one) {
+               p[kvm_emulate_wrtee_reg_offs] =
+                       KVM_INST_LI | __PPC_RT(30) | MSR_EE;
+       } else {
+               /* Make clobbered registers work too */
+               switch (get_rt(rt)) {
+               case 30:
+                       kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs],
+                                        magic_var(scratch2), KVM_RT_30);
+                       break;
+               case 31:
+                       kvm_patch_ins_ll(&p[kvm_emulate_wrtee_reg_offs],
+                                        magic_var(scratch1), KVM_RT_30);
+                       break;
+               default:
+                       p[kvm_emulate_wrtee_reg_offs] |= rt;
+                       break;
+               }
+       }
+
+       p[kvm_emulate_wrtee_orig_ins_offs] = *inst;
+       flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrtee_len * 4);
+
+       /* Patch the invocation */
+       kvm_patch_ins_b(inst, distance_start);
+}
+
+extern u32 kvm_emulate_wrteei_0_branch_offs;
+extern u32 kvm_emulate_wrteei_0_len;
+extern u32 kvm_emulate_wrteei_0[];
+
+static void kvm_patch_ins_wrteei_0(u32 *inst)
+{
+       u32 *p;
+       int distance_start;
+       int distance_end;
+       ulong next_inst;
+
+       p = kvm_alloc(kvm_emulate_wrteei_0_len * 4);
+       if (!p)
+               return;
+
+       /* Find out where we are and put everything there */
+       distance_start = (ulong)p - (ulong)inst;
+       next_inst = ((ulong)inst + 4);
+       distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_0_branch_offs];
+
+       /* Make sure we only write valid b instructions */
+       if (distance_start > KVM_INST_B_MAX) {
+               kvm_patching_worked = false;
+               return;
+       }
+
+       memcpy(p, kvm_emulate_wrteei_0, kvm_emulate_wrteei_0_len * 4);
+       p[kvm_emulate_wrteei_0_branch_offs] |= distance_end & KVM_INST_B_MASK;
+       flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_0_len * 4);
 
        /* Patch the invocation */
        kvm_patch_ins_b(inst, distance_start);
@@ -380,56 +434,191 @@ static void kvm_check_ins(u32 *inst, u32 features)
        case KVM_INST_MFMSR:
                kvm_patch_ins_ld(inst, magic_var(msr), inst_rt);
                break;
-       case KVM_INST_MFSPR_SPRG0:
+       case KVM_INST_MFSPR(SPRN_SPRG0):
                kvm_patch_ins_ld(inst, magic_var(sprg0), inst_rt);
                break;
-       case KVM_INST_MFSPR_SPRG1:
+       case KVM_INST_MFSPR(SPRN_SPRG1):
                kvm_patch_ins_ld(inst, magic_var(sprg1), inst_rt);
                break;
-       case KVM_INST_MFSPR_SPRG2:
+       case KVM_INST_MFSPR(SPRN_SPRG2):
                kvm_patch_ins_ld(inst, magic_var(sprg2), inst_rt);
                break;
-       case KVM_INST_MFSPR_SPRG3:
+       case KVM_INST_MFSPR(SPRN_SPRG3):
                kvm_patch_ins_ld(inst, magic_var(sprg3), inst_rt);
                break;
-       case KVM_INST_MFSPR_SRR0:
+       case KVM_INST_MFSPR(SPRN_SRR0):
                kvm_patch_ins_ld(inst, magic_var(srr0), inst_rt);
                break;
-       case KVM_INST_MFSPR_SRR1:
+       case KVM_INST_MFSPR(SPRN_SRR1):
                kvm_patch_ins_ld(inst, magic_var(srr1), inst_rt);
                break;
-       case KVM_INST_MFSPR_DAR:
+#ifdef CONFIG_BOOKE
+       case KVM_INST_MFSPR(SPRN_DEAR):
+#else
+       case KVM_INST_MFSPR(SPRN_DAR):
+#endif
                kvm_patch_ins_ld(inst, magic_var(dar), inst_rt);
                break;
-       case KVM_INST_MFSPR_DSISR:
+       case KVM_INST_MFSPR(SPRN_DSISR):
                kvm_patch_ins_lwz(inst, magic_var(dsisr), inst_rt);
                break;
 
+#ifdef CONFIG_PPC_BOOK3E_MMU
+       case KVM_INST_MFSPR(SPRN_MAS0):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_lwz(inst, magic_var(mas0), inst_rt);
+               break;
+       case KVM_INST_MFSPR(SPRN_MAS1):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_lwz(inst, magic_var(mas1), inst_rt);
+               break;
+       case KVM_INST_MFSPR(SPRN_MAS2):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_ld(inst, magic_var(mas2), inst_rt);
+               break;
+       case KVM_INST_MFSPR(SPRN_MAS3):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_lwz(inst, magic_var(mas7_3) + 4, inst_rt);
+               break;
+       case KVM_INST_MFSPR(SPRN_MAS4):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_lwz(inst, magic_var(mas4), inst_rt);
+               break;
+       case KVM_INST_MFSPR(SPRN_MAS6):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_lwz(inst, magic_var(mas6), inst_rt);
+               break;
+       case KVM_INST_MFSPR(SPRN_MAS7):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_lwz(inst, magic_var(mas7_3), inst_rt);
+               break;
+#endif /* CONFIG_PPC_BOOK3E_MMU */
+
+       case KVM_INST_MFSPR(SPRN_SPRG4):
+#ifdef CONFIG_BOOKE
+       case KVM_INST_MFSPR(SPRN_SPRG4R):
+#endif
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_ld(inst, magic_var(sprg4), inst_rt);
+               break;
+       case KVM_INST_MFSPR(SPRN_SPRG5):
+#ifdef CONFIG_BOOKE
+       case KVM_INST_MFSPR(SPRN_SPRG5R):
+#endif
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_ld(inst, magic_var(sprg5), inst_rt);
+               break;
+       case KVM_INST_MFSPR(SPRN_SPRG6):
+#ifdef CONFIG_BOOKE
+       case KVM_INST_MFSPR(SPRN_SPRG6R):
+#endif
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_ld(inst, magic_var(sprg6), inst_rt);
+               break;
+       case KVM_INST_MFSPR(SPRN_SPRG7):
+#ifdef CONFIG_BOOKE
+       case KVM_INST_MFSPR(SPRN_SPRG7R):
+#endif
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_ld(inst, magic_var(sprg7), inst_rt);
+               break;
+
+#ifdef CONFIG_BOOKE
+       case KVM_INST_MFSPR(SPRN_ESR):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_lwz(inst, magic_var(esr), inst_rt);
+               break;
+#endif
+
+       case KVM_INST_MFSPR(SPRN_PIR):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_lwz(inst, magic_var(pir), inst_rt);
+               break;
+
+
        /* Stores */
-       case KVM_INST_MTSPR_SPRG0:
+       case KVM_INST_MTSPR(SPRN_SPRG0):
                kvm_patch_ins_std(inst, magic_var(sprg0), inst_rt);
                break;
-       case KVM_INST_MTSPR_SPRG1:
+       case KVM_INST_MTSPR(SPRN_SPRG1):
                kvm_patch_ins_std(inst, magic_var(sprg1), inst_rt);
                break;
-       case KVM_INST_MTSPR_SPRG2:
+       case KVM_INST_MTSPR(SPRN_SPRG2):
                kvm_patch_ins_std(inst, magic_var(sprg2), inst_rt);
                break;
-       case KVM_INST_MTSPR_SPRG3:
+       case KVM_INST_MTSPR(SPRN_SPRG3):
                kvm_patch_ins_std(inst, magic_var(sprg3), inst_rt);
                break;
-       case KVM_INST_MTSPR_SRR0:
+       case KVM_INST_MTSPR(SPRN_SRR0):
                kvm_patch_ins_std(inst, magic_var(srr0), inst_rt);
                break;
-       case KVM_INST_MTSPR_SRR1:
+       case KVM_INST_MTSPR(SPRN_SRR1):
                kvm_patch_ins_std(inst, magic_var(srr1), inst_rt);
                break;
-       case KVM_INST_MTSPR_DAR:
+#ifdef CONFIG_BOOKE
+       case KVM_INST_MTSPR(SPRN_DEAR):
+#else
+       case KVM_INST_MTSPR(SPRN_DAR):
+#endif
                kvm_patch_ins_std(inst, magic_var(dar), inst_rt);
                break;
-       case KVM_INST_MTSPR_DSISR:
+       case KVM_INST_MTSPR(SPRN_DSISR):
                kvm_patch_ins_stw(inst, magic_var(dsisr), inst_rt);
                break;
+#ifdef CONFIG_PPC_BOOK3E_MMU
+       case KVM_INST_MTSPR(SPRN_MAS0):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_stw(inst, magic_var(mas0), inst_rt);
+               break;
+       case KVM_INST_MTSPR(SPRN_MAS1):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_stw(inst, magic_var(mas1), inst_rt);
+               break;
+       case KVM_INST_MTSPR(SPRN_MAS2):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_std(inst, magic_var(mas2), inst_rt);
+               break;
+       case KVM_INST_MTSPR(SPRN_MAS3):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_stw(inst, magic_var(mas7_3) + 4, inst_rt);
+               break;
+       case KVM_INST_MTSPR(SPRN_MAS4):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_stw(inst, magic_var(mas4), inst_rt);
+               break;
+       case KVM_INST_MTSPR(SPRN_MAS6):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_stw(inst, magic_var(mas6), inst_rt);
+               break;
+       case KVM_INST_MTSPR(SPRN_MAS7):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_stw(inst, magic_var(mas7_3), inst_rt);
+               break;
+#endif /* CONFIG_PPC_BOOK3E_MMU */
+
+       case KVM_INST_MTSPR(SPRN_SPRG4):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_std(inst, magic_var(sprg4), inst_rt);
+               break;
+       case KVM_INST_MTSPR(SPRN_SPRG5):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_std(inst, magic_var(sprg5), inst_rt);
+               break;
+       case KVM_INST_MTSPR(SPRN_SPRG6):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_std(inst, magic_var(sprg6), inst_rt);
+               break;
+       case KVM_INST_MTSPR(SPRN_SPRG7):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_std(inst, magic_var(sprg7), inst_rt);
+               break;
+
+#ifdef CONFIG_BOOKE
+       case KVM_INST_MTSPR(SPRN_ESR):
+               if (features & KVM_MAGIC_FEAT_MAS0_TO_SPRG7)
+                       kvm_patch_ins_stw(inst, magic_var(esr), inst_rt);
+               break;
+#endif
 
        /* Nops */
        case KVM_INST_TLBSYNC:
@@ -444,6 +633,11 @@ static void kvm_check_ins(u32 *inst, u32 features)
        case KVM_INST_MTMSRD_L0:
                kvm_patch_ins_mtmsr(inst, inst_rt);
                break;
+#ifdef CONFIG_BOOKE
+       case KVM_INST_WRTEE:
+               kvm_patch_ins_wrtee(inst, inst_rt, 0);
+               break;
+#endif
        }
 
        switch (inst_no_rt & ~KVM_MASK_RB) {
@@ -461,13 +655,19 @@ static void kvm_check_ins(u32 *inst, u32 features)
        switch (_inst) {
 #ifdef CONFIG_BOOKE
        case KVM_INST_WRTEEI_0:
+               kvm_patch_ins_wrteei_0(inst);
+               break;
+
        case KVM_INST_WRTEEI_1:
-               kvm_patch_ins_wrteei(inst);
+               kvm_patch_ins_wrtee(inst, 0, 1);
                break;
 #endif
        }
 }
 
+extern u32 kvm_template_start[];
+extern u32 kvm_template_end[];
+
 static void kvm_use_magic_page(void)
 {
        u32 *p;
@@ -488,8 +688,23 @@ static void kvm_use_magic_page(void)
        start = (void*)_stext;
        end = (void*)_etext;
 
-       for (p = start; p < end; p++)
+       /*
+        * Being interrupted in the middle of patching would
+        * be bad for SPRG4-7, which KVM can't keep in sync
+        * with emulated accesses because reads don't trap.
+        */
+       local_irq_disable();
+
+       for (p = start; p < end; p++) {
+               /* Avoid patching the template code */
+               if (p >= kvm_template_start && p < kvm_template_end) {
+                       p = kvm_template_end - 1;
+                       continue;
+               }
                kvm_check_ins(p, features);
+       }
+
+       local_irq_enable();
 
        printk(KERN_INFO "KVM: Live patching for a fast VM %s\n",
                         kvm_patching_worked ? "worked" : "failed");
index f2b1b25..e291cf3 100644 (file)
@@ -13,6 +13,7 @@
  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *
  * Copyright SUSE Linux Products GmbH 2010
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
  *
  * Authors: Alexander Graf <agraf@suse.de>
  */
@@ -65,6 +66,9 @@ kvm_hypercall_start:
           shared->critical == r1 and r2 is always != r1 */             \
        STL64(r2, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);
 
+.global kvm_template_start
+kvm_template_start:
+
 .global kvm_emulate_mtmsrd
 kvm_emulate_mtmsrd:
 
@@ -167,6 +171,9 @@ maybe_stay_in_guest:
 kvm_emulate_mtmsr_reg2:
        ori     r30, r0, 0
 
+       /* Put MSR into magic page because we don't call mtmsr */
+       STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
        /* Check if we have to fetch an interrupt */
        lwz     r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
        cmpwi   r31, 0
@@ -174,15 +181,10 @@ kvm_emulate_mtmsr_reg2:
 
        /* Check if we may trigger an interrupt */
        andi.   r31, r30, MSR_EE
-       beq     no_mtmsr
-
-       b       do_mtmsr
+       bne     do_mtmsr
 
 no_mtmsr:
 
-       /* Put MSR into magic page because we don't call mtmsr */
-       STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
-
        SCRATCH_RESTORE
 
        /* Go back to caller */
@@ -210,24 +212,80 @@ kvm_emulate_mtmsr_orig_ins_offs:
 kvm_emulate_mtmsr_len:
        .long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4
 
+/* also used for wrteei 1 */
+.global kvm_emulate_wrtee
+kvm_emulate_wrtee:
+
+       SCRATCH_SAVE
+
+       /* Fetch old MSR in r31 */
+       LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+       /* Insert new MSR[EE] */
+kvm_emulate_wrtee_reg:
+       ori     r30, r0, 0
+       rlwimi  r31, r30, 0, MSR_EE
+
+       /*
+        * If MSR[EE] is now set, check for a pending interrupt.
+        * We could skip this if MSR[EE] was already on, but that
+        * should be rare, so don't bother.
+        */
+       andi.   r30, r30, MSR_EE
+
+       /* Put MSR into magic page because we don't call wrtee */
+       STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+       beq     no_wrtee
+
+       /* Check if we have to fetch an interrupt */
+       lwz     r30, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
+       cmpwi   r30, 0
+       bne     do_wrtee
+
+no_wrtee:
+       SCRATCH_RESTORE
+
+       /* Go back to caller */
+kvm_emulate_wrtee_branch:
+       b       .
+
+do_wrtee:
+       SCRATCH_RESTORE
 
+       /* Just fire off the wrtee if it's critical */
+kvm_emulate_wrtee_orig_ins:
+       wrtee   r0
 
-.global kvm_emulate_wrteei
-kvm_emulate_wrteei:
+       b       kvm_emulate_wrtee_branch
 
+kvm_emulate_wrtee_end:
+
+.global kvm_emulate_wrtee_branch_offs
+kvm_emulate_wrtee_branch_offs:
+       .long (kvm_emulate_wrtee_branch - kvm_emulate_wrtee) / 4
+
+.global kvm_emulate_wrtee_reg_offs
+kvm_emulate_wrtee_reg_offs:
+       .long (kvm_emulate_wrtee_reg - kvm_emulate_wrtee) / 4
+
+.global kvm_emulate_wrtee_orig_ins_offs
+kvm_emulate_wrtee_orig_ins_offs:
+       .long (kvm_emulate_wrtee_orig_ins - kvm_emulate_wrtee) / 4
+
+.global kvm_emulate_wrtee_len
+kvm_emulate_wrtee_len:
+       .long (kvm_emulate_wrtee_end - kvm_emulate_wrtee) / 4
+
+.global kvm_emulate_wrteei_0
+kvm_emulate_wrteei_0:
        SCRATCH_SAVE
 
        /* Fetch old MSR in r31 */
        LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
 
        /* Remove MSR_EE from old MSR */
-       li      r30, 0
-       ori     r30, r30, MSR_EE
-       andc    r31, r31, r30
-
-       /* OR new MSR_EE onto the old MSR */
-kvm_emulate_wrteei_ee:
-       ori     r31, r31, 0
+       rlwinm  r31, r31, 0, ~MSR_EE
 
        /* Write new MSR value back */
        STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
@@ -235,22 +293,17 @@ kvm_emulate_wrteei_ee:
        SCRATCH_RESTORE
 
        /* Go back to caller */
-kvm_emulate_wrteei_branch:
+kvm_emulate_wrteei_0_branch:
        b       .
-kvm_emulate_wrteei_end:
-
-.global kvm_emulate_wrteei_branch_offs
-kvm_emulate_wrteei_branch_offs:
-       .long (kvm_emulate_wrteei_branch - kvm_emulate_wrteei) / 4
+kvm_emulate_wrteei_0_end:
 
-.global kvm_emulate_wrteei_ee_offs
-kvm_emulate_wrteei_ee_offs:
-       .long (kvm_emulate_wrteei_ee - kvm_emulate_wrteei) / 4
-
-.global kvm_emulate_wrteei_len
-kvm_emulate_wrteei_len:
-       .long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4
+.global kvm_emulate_wrteei_0_branch_offs
+kvm_emulate_wrteei_0_branch_offs:
+       .long (kvm_emulate_wrteei_0_branch - kvm_emulate_wrteei_0) / 4
 
+.global kvm_emulate_wrteei_0_len
+kvm_emulate_wrteei_0_len:
+       .long (kvm_emulate_wrteei_0_end - kvm_emulate_wrteei_0) / 4
 
 .global kvm_emulate_mtsrin
 kvm_emulate_mtsrin:
@@ -300,3 +353,6 @@ kvm_emulate_mtsrin_orig_ins_offs:
 .global kvm_emulate_mtsrin_len
 kvm_emulate_mtsrin_len:
        .long (kvm_emulate_mtsrin_end - kvm_emulate_mtsrin) / 4
+
+.global kvm_template_end
+kvm_template_end:
index d0373bc..8e78e93 100644 (file)
@@ -49,9 +49,6 @@ static int global_phb_number;         /* Global phb counter */
 /* ISA Memory physical address */
 resource_size_t isa_mem_base;
 
-/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */
-unsigned int pci_flags = 0;
-
 
 static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
 
@@ -834,60 +831,6 @@ int pci_proc_domain(struct pci_bus *bus)
        return 1;
 }
 
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                            struct resource *res)
-{
-       resource_size_t offset = 0, mask = (resource_size_t)-1;
-       struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
-       if (!hose)
-               return;
-       if (res->flags & IORESOURCE_IO) {
-               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-               mask = 0xffffffffu;
-       } else if (res->flags & IORESOURCE_MEM)
-               offset = hose->pci_mem_offset;
-
-       region->start = (res->start - offset) & mask;
-       region->end = (res->end - offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                            struct pci_bus_region *region)
-{
-       resource_size_t offset = 0, mask = (resource_size_t)-1;
-       struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
-       if (!hose)
-               return;
-       if (res->flags & IORESOURCE_IO) {
-               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-               mask = 0xffffffffu;
-       } else if (res->flags & IORESOURCE_MEM)
-               offset = hose->pci_mem_offset;
-       res->start = (region->start + offset) & mask;
-       res->end = (region->end + offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/* Fixup a bus resource into a linux resource */
-static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
-{
-       struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       resource_size_t offset = 0, mask = (resource_size_t)-1;
-
-       if (res->flags & IORESOURCE_IO) {
-               offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-               mask = 0xffffffffu;
-       } else if (res->flags & IORESOURCE_MEM)
-               offset = hose->pci_mem_offset;
-
-       res->start = (res->start + offset) & mask;
-       res->end = (res->end + offset) & mask;
-}
-
-
 /* This header fixup will do the resource fixup for all devices as they are
  * probed, but not for bridge ranges
  */
@@ -927,18 +870,11 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
                        continue;
                }
 
-               pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n",
+               pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]\n",
                         pci_name(dev), i,
                         (unsigned long long)res->start,\
                         (unsigned long long)res->end,
                         (unsigned int)res->flags);
-
-               fixup_resource(res, dev);
-
-               pr_debug("PCI:%s            %016llx-%016llx\n",
-                        pci_name(dev),
-                        (unsigned long long)res->start,
-                        (unsigned long long)res->end);
        }
 
        /* Call machine specific resource fixup */
@@ -1040,27 +976,18 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
                        continue;
                }
 
-               pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
+               pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x]\n",
                         pci_name(dev), i,
                         (unsigned long long)res->start,\
                         (unsigned long long)res->end,
                         (unsigned int)res->flags);
 
-               /* Perform fixup */
-               fixup_resource(res, dev);
-
                /* Try to detect uninitialized P2P bridge resources,
                 * and clear them out so they get re-assigned later
                 */
                if (pcibios_uninitialized_bridge_resource(bus, res)) {
                        res->flags = 0;
                        pr_debug("PCI:%s            (unassigned)\n", pci_name(dev));
-               } else {
-
-                       pr_debug("PCI:%s            %016llx-%016llx\n",
-                                pci_name(dev),
-                                (unsigned long long)res->start,
-                                (unsigned long long)res->end);
                }
        }
 }
@@ -1550,6 +1477,11 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return pci_enable_resources(dev, mask);
 }
 
+resource_size_t pcibios_io_space_offset(struct pci_controller *hose)
+{
+       return (unsigned long) hose->io_base_virt - _IO_BASE;
+}
+
 static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
 {
        struct resource *res;
@@ -1574,7 +1506,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
                 (unsigned long long)res->start,
                 (unsigned long long)res->end,
                 (unsigned long)res->flags);
-       pci_add_resource(resources, res);
+       pci_add_resource_offset(resources, res, pcibios_io_space_offset(hose));
 
        /* Hookup PHB Memory resources */
        for (i = 0; i < 3; ++i) {
@@ -1597,7 +1529,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
                         (unsigned long long)res->start,
                         (unsigned long long)res->end,
                         (unsigned long)res->flags);
-               pci_add_resource(resources, res);
+               pci_add_resource_offset(resources, res, hose->pci_mem_offset);
        }
 
        pr_debug("PCI: PHB MEM offset     = %016llx\n",
index fdd1a3d..4b06ec5 100644 (file)
@@ -219,9 +219,9 @@ void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
        struct resource *res = &hose->io_resource;
 
        /* Fixup IO space offset */
-       io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
-       res->start = (res->start + io_offset) & 0xffffffffu;
-       res->end = (res->end + io_offset) & 0xffffffffu;
+       io_offset = pcibios_io_space_offset(hose);
+       res->start += io_offset;
+       res->end += io_offset;
 }
 
 static int __init pcibios_init(void)
index 3318d39..94a54f6 100644 (file)
@@ -33,8 +33,6 @@
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
 
-unsigned long pci_probe_only = 1;
-
 /* pci_io_base -- the base address from which io bars are offsets.
  * This is the lowest I/O base address (so bar values are always positive),
  * and it *must* be the start of ISA space if an ISA bus exists because
@@ -55,9 +53,6 @@ static int __init pcibios_init(void)
         */
        ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
 
-       if (pci_probe_only)
-               pci_add_flags(PCI_PROBE_ONLY);
-
        /* On ppc64, we always enable PCI domains and we keep domain 0
         * backward compatible in /proc for video cards
         */
@@ -173,7 +168,7 @@ static int __devinit pcibios_map_phb_io_space(struct pci_controller *hose)
                return -ENOMEM;
 
        /* Fixup hose IO resource */
-       io_virt_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+       io_virt_offset = pcibios_io_space_offset(hose);
        hose->io_resource.start += io_virt_offset;
        hose->io_resource.end += io_virt_offset;
 
index b37d0b5..89dde17 100644 (file)
@@ -75,6 +75,7 @@ static void of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev)
 {
        u64 base, size;
        unsigned int flags;
+       struct pci_bus_region region;
        struct resource *res;
        const u32 *addrs;
        u32 i;
@@ -106,10 +107,11 @@ static void of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev)
                        printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);
                        continue;
                }
-               res->start = base;
-               res->end = base + size - 1;
                res->flags = flags;
                res->name = pci_name(dev);
+               region.start = base;
+               region.end = base + size - 1;
+               pcibios_bus_to_resource(dev, res, &region);
        }
 }
 
@@ -209,6 +211,7 @@ void __devinit of_scan_pci_bridge(struct pci_dev *dev)
        struct pci_bus *bus;
        const u32 *busrange, *ranges;
        int len, i, mode;
+       struct pci_bus_region region;
        struct resource *res;
        unsigned int flags;
        u64 size;
@@ -270,9 +273,10 @@ void __devinit of_scan_pci_bridge(struct pci_dev *dev)
                        res = bus->resource[i];
                        ++i;
                }
-               res->start = of_read_number(&ranges[1], 2);
-               res->end = res->start + size - 1;
                res->flags = flags;
+               region.start = of_read_number(&ranges[1], 2);
+               region.end = region.start + size - 1;
+               pcibios_bus_to_resource(dev, res, &region);
        }
        sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
                bus->number);
index a841a9d..58eaa3d 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <linux/errno.h>
+#include <linux/bug.h>
 #include <linux/spinlock.h>
 #include <linux/export.h>
 
index b2aae21..9986027 100644 (file)
@@ -446,7 +446,7 @@ static void __init __attribute__((noreturn)) prom_panic(const char *reason)
        if (RELOC(of_platform) == PLATFORM_POWERMAC)
                asm("trap\n");
 
-       /* ToDo: should put up an SRC here on p/iSeries */
+       /* ToDo: should put up an SRC here on pSeries */
        call_prom("exit", 0, 0);
 
        for (;;)                        /* should never get here */
index 3dc6799..fcec382 100644 (file)
@@ -867,6 +867,40 @@ int rtas_ibm_suspend_me(struct rtas_args *args)
 }
 #endif
 
+/**
+ * Find a specific pseries error log in an RTAS extended event log.
+ * @log: RTAS error/event log
+ * @section_id: two character section identifier
+ *
+ * Returns a pointer to the specified errorlog or NULL if not found.
+ */
+struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
+                                             uint16_t section_id)
+{
+       struct rtas_ext_event_log_v6 *ext_log =
+               (struct rtas_ext_event_log_v6 *)log->buffer;
+       struct pseries_errorlog *sect;
+       unsigned char *p, *log_end;
+
+       /* Check that we understand the format */
+       if (log->extended_log_length < sizeof(struct rtas_ext_event_log_v6) ||
+           ext_log->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
+           ext_log->company_id != RTAS_V6EXT_COMPANY_ID_IBM)
+               return NULL;
+
+       log_end = log->buffer + log->extended_log_length;
+       p = ext_log->vendor_log;
+
+       while (p < log_end) {
+               sect = (struct pseries_errorlog *)p;
+               if (sect->id == section_id)
+                       return sect;
+               p += sect->length;
+       }
+
+       return NULL;
+}
+
 asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 {
        struct rtas_args args;
index 517bd86..179af90 100644 (file)
@@ -279,7 +279,7 @@ void __init find_and_init_phbs(void)
        eeh_dev_phb_init();
 
        /*
-        * pci_probe_only and pci_assign_all_buses can be set via properties
+        * PCI_PROBE_ONLY and PCI_REASSIGN_ALL_BUS can be set via properties
         * in chosen.
         */
        if (of_chosen) {
@@ -287,8 +287,12 @@ void __init find_and_init_phbs(void)
 
                prop = of_get_property(of_chosen,
                                "linux,pci-probe-only", NULL);
-               if (prop)
-                       pci_probe_only = *prop;
+               if (prop) {
+                       if (*prop)
+                               pci_add_flags(PCI_PROBE_ONLY);
+                       else
+                               pci_clear_flags(PCI_PROBE_ONLY);
+               }
 
 #ifdef CONFIG_PPC32 /* Will be made generic soon */
                prop = of_get_property(of_chosen,
index 6d639b2..389bd4f 100644 (file)
@@ -597,7 +597,7 @@ void __init setup_arch(char **cmdline_p)
        /* Initialize the MMU context management stuff */
        mmu_context_init();
 
-       kvm_rma_init();
+       kvm_linear_init();
 
        ppc64_boot_msg(0x15, "Setup Done");
 }
index 57fa2c0..c39c1ca 100644 (file)
@@ -46,9 +46,6 @@ void __init udbg_early_init(void)
 #elif defined(CONFIG_PPC_EARLY_DEBUG_MAPLE)
        /* Maple real mode debug */
        udbg_init_maple_realmode();
-#elif defined(CONFIG_PPC_EARLY_DEBUG_ISERIES)
-       /* For iSeries - hit Ctrl-x Ctrl-x to see the output */
-       udbg_init_iseries();
 #elif defined(CONFIG_PPC_EARLY_DEBUG_BEAT)
        udbg_init_debug_beat();
 #elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE)
index 1ce1ec4..9eb5b9b 100644 (file)
@@ -262,17 +262,11 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
         * the "data" page of the vDSO or you'll stop getting kernel updates
         * and your nice userland gettimeofday will be totally dead.
         * It's fine to use that for setting breakpoints in the vDSO code
-        * pages though
-        *
-        * Make sure the vDSO gets into every core dump.
-        * Dumping its contents makes post-mortem fully interpretable later
-        * without matching up the same kernel and hardware config to see
-        * what PC values meant.
+        * pages though.
         */
        rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT,
                                     VM_READ|VM_EXEC|
-                                    VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-                                    VM_ALWAYSDUMP,
+                                    VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
                                     vdso_pagelist);
        if (rc) {
                current->mm->context.vdso_base = 0;
@@ -726,10 +720,10 @@ static int __init vdso_init(void)
        vdso_data->version.minor = SYSTEMCFG_MINOR;
        vdso_data->processor = mfspr(SPRN_PVR);
        /*
-        * Fake the old platform number for pSeries and iSeries and add
+        * Fake the old platform number for pSeries and add
         * in LPAR bit if necessary
         */
-       vdso_data->platform = machine_is(iseries) ? 0x200 : 0x100;
+       vdso_data->platform = 0x100;
        if (firmware_has_feature(FW_FEATURE_LPAR))
                vdso_data->platform |= 1;
        vdso_data->physicalMemorySize = memblock_phys_mem_size();
index bca3fc4..b2f7c84 100644 (file)
@@ -1159,17 +1159,21 @@ static int vio_bus_remove(struct device *dev)
  * vio_register_driver: - Register a new vio driver
  * @drv:       The vio_driver structure to be registered.
  */
-int vio_register_driver(struct vio_driver *viodrv)
+int __vio_register_driver(struct vio_driver *viodrv, struct module *owner,
+                         const char *mod_name)
 {
-       printk(KERN_DEBUG "%s: driver %s registering\n", __func__,
-               viodrv->driver.name);
+       pr_debug("%s: driver %s registering\n", __func__, viodrv->name);
 
        /* fill in 'struct driver' fields */
+       viodrv->driver.name = viodrv->name;
+       viodrv->driver.pm = viodrv->pm;
        viodrv->driver.bus = &vio_bus_type;
+       viodrv->driver.owner = owner;
+       viodrv->driver.mod_name = mod_name;
 
        return driver_register(&viodrv->driver);
 }
-EXPORT_SYMBOL(vio_register_driver);
+EXPORT_SYMBOL(__vio_register_driver);
 
 /**
  * vio_unregister_driver - Remove registration of vio driver.
index 78133de..8f64709 100644 (file)
@@ -69,6 +69,7 @@ config KVM_BOOK3S_64
 config KVM_BOOK3S_64_HV
        bool "KVM support for POWER7 and PPC970 using hypervisor mode in host"
        depends on KVM_BOOK3S_64
+       select MMU_NOTIFIER
        ---help---
          Support running unmodified book3s_64 guest kernels in
          virtual machines on POWER7 and PPC970 processors that have
index e41ac6f..7d54f4e 100644 (file)
@@ -258,7 +258,7 @@ static bool clear_irqprio(struct kvm_vcpu *vcpu, unsigned int priority)
        return true;
 }
 
-void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
+void kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
 {
        unsigned long *pending = &vcpu->arch.pending_exceptions;
        unsigned long old_pending = vcpu->arch.pending_exceptions;
@@ -423,10 +423,10 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        regs->sprg1 = vcpu->arch.shared->sprg1;
        regs->sprg2 = vcpu->arch.shared->sprg2;
        regs->sprg3 = vcpu->arch.shared->sprg3;
-       regs->sprg4 = vcpu->arch.sprg4;
-       regs->sprg5 = vcpu->arch.sprg5;
-       regs->sprg6 = vcpu->arch.sprg6;
-       regs->sprg7 = vcpu->arch.sprg7;
+       regs->sprg4 = vcpu->arch.shared->sprg4;
+       regs->sprg5 = vcpu->arch.shared->sprg5;
+       regs->sprg6 = vcpu->arch.shared->sprg6;
+       regs->sprg7 = vcpu->arch.shared->sprg7;
 
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
                regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
@@ -450,10 +450,10 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        vcpu->arch.shared->sprg1 = regs->sprg1;
        vcpu->arch.shared->sprg2 = regs->sprg2;
        vcpu->arch.shared->sprg3 = regs->sprg3;
-       vcpu->arch.sprg4 = regs->sprg4;
-       vcpu->arch.sprg5 = regs->sprg5;
-       vcpu->arch.sprg6 = regs->sprg6;
-       vcpu->arch.sprg7 = regs->sprg7;
+       vcpu->arch.shared->sprg4 = regs->sprg4;
+       vcpu->arch.shared->sprg5 = regs->sprg5;
+       vcpu->arch.shared->sprg6 = regs->sprg6;
+       vcpu->arch.shared->sprg7 = regs->sprg7;
 
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
                kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
@@ -477,41 +477,10 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
        return 0;
 }
 
-/*
- * Get (and clear) the dirty memory log for a memory slot.
- */
-int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
-                                     struct kvm_dirty_log *log)
+void kvmppc_decrementer_func(unsigned long data)
 {
-       struct kvm_memory_slot *memslot;
-       struct kvm_vcpu *vcpu;
-       ulong ga, ga_end;
-       int is_dirty = 0;
-       int r;
-       unsigned long n;
-
-       mutex_lock(&kvm->slots_lock);
-
-       r = kvm_get_dirty_log(kvm, log, &is_dirty);
-       if (r)
-               goto out;
-
-       /* If nothing is dirty, don't bother messing with page tables. */
-       if (is_dirty) {
-               memslot = id_to_memslot(kvm->memslots, log->slot);
+       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
 
-               ga = memslot->base_gfn << PAGE_SHIFT;
-               ga_end = ga + (memslot->npages << PAGE_SHIFT);
-
-               kvm_for_each_vcpu(n, vcpu, kvm)
-                       kvmppc_mmu_pte_pflush(vcpu, ga, ga_end);
-
-               n = kvm_dirty_bitmap_bytes(memslot);
-               memset(memslot->dirty_bitmap, 0, n);
-       }
-
-       r = 0;
-out:
-       mutex_unlock(&kvm->slots_lock);
-       return r;
+       kvmppc_core_queue_dec(vcpu);
+       kvm_vcpu_kick(vcpu);
 }
index 9fecbfb..f922c29 100644 (file)
@@ -151,13 +151,15 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
        bool primary = false;
        bool evict = false;
        struct hpte_cache *pte;
+       int r = 0;
 
        /* Get host physical address for gpa */
        hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT);
        if (is_error_pfn(hpaddr)) {
                printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n",
                                 orig_pte->eaddr);
-               return -EINVAL;
+               r = -EINVAL;
+               goto out;
        }
        hpaddr <<= PAGE_SHIFT;
 
@@ -249,7 +251,8 @@ next_pteg:
 
        kvmppc_mmu_hpte_cache_map(vcpu, pte);
 
-       return 0;
+out:
+       return r;
 }
 
 static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
@@ -297,12 +300,14 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
        u64 gvsid;
        u32 sr;
        struct kvmppc_sid_map *map;
-       struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu);
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       int r = 0;
 
        if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) {
                /* Invalidate an entry */
                svcpu->sr[esid] = SR_INVALID;
-               return -ENOENT;
+               r = -ENOENT;
+               goto out;
        }
 
        map = find_sid_vsid(vcpu, gvsid);
@@ -315,17 +320,21 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
 
        dprintk_sr("MMU: mtsr %d, 0x%x\n", esid, sr);
 
-       return 0;
+out:
+       svcpu_put(svcpu);
+       return r;
 }
 
 void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
 {
        int i;
-       struct kvmppc_book3s_shadow_vcpu *svcpu = to_svcpu(vcpu);
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
 
        dprintk_sr("MMU: flushing all segments (%d)\n", ARRAY_SIZE(svcpu->sr));
        for (i = 0; i < ARRAY_SIZE(svcpu->sr); i++)
                svcpu->sr[i] = SR_INVALID;
+
+       svcpu_put(svcpu);
 }
 
 void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
index fa2f084..6f87f39 100644 (file)
@@ -88,12 +88,14 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
        int vflags = 0;
        int attempt = 0;
        struct kvmppc_sid_map *map;
+       int r = 0;
 
        /* Get host physical address for gpa */
        hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT);
        if (is_error_pfn(hpaddr)) {
                printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr);
-               return -EINVAL;
+               r = -EINVAL;
+               goto out;
        }
        hpaddr <<= PAGE_SHIFT;
        hpaddr |= orig_pte->raddr & (~0xfffULL & ~PAGE_MASK);
@@ -110,7 +112,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
                printk(KERN_ERR "KVM: Segment map for 0x%llx (0x%lx) failed\n",
                                vsid, orig_pte->eaddr);
                WARN_ON(true);
-               return -EINVAL;
+               r = -EINVAL;
+               goto out;
        }
 
        vsid = map->host_vsid;
@@ -131,8 +134,10 @@ map_again:
 
        /* In case we tried normal mapping already, let's nuke old entries */
        if (attempt > 1)
-               if (ppc_md.hpte_remove(hpteg) < 0)
-                       return -1;
+               if (ppc_md.hpte_remove(hpteg) < 0) {
+                       r = -1;
+                       goto out;
+               }
 
        ret = ppc_md.hpte_insert(hpteg, va, hpaddr, rflags, vflags, MMU_PAGE_4K, MMU_SEGSIZE_256M);
 
@@ -162,7 +167,8 @@ map_again:
                kvmppc_mmu_hpte_cache_map(vcpu, pte);
        }
 
-       return 0;
+out:
+       return r;
 }
 
 static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
@@ -207,25 +213,30 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
 
 static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid)
 {
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
        int i;
        int max_slb_size = 64;
        int found_inval = -1;
        int r;
 
-       if (!to_svcpu(vcpu)->slb_max)
-               to_svcpu(vcpu)->slb_max = 1;
+       if (!svcpu->slb_max)
+               svcpu->slb_max = 1;
 
        /* Are we overwriting? */
-       for (i = 1; i < to_svcpu(vcpu)->slb_max; i++) {
-               if (!(to_svcpu(vcpu)->slb[i].esid & SLB_ESID_V))
+       for (i = 1; i < svcpu->slb_max; i++) {
+               if (!(svcpu->slb[i].esid & SLB_ESID_V))
                        found_inval = i;
-               else if ((to_svcpu(vcpu)->slb[i].esid & ESID_MASK) == esid)
-                       return i;
+               else if ((svcpu->slb[i].esid & ESID_MASK) == esid) {
+                       r = i;
+                       goto out;
+               }
        }
 
        /* Found a spare entry that was invalidated before */
-       if (found_inval > 0)
-               return found_inval;
+       if (found_inval > 0) {
+               r = found_inval;
+               goto out;
+       }
 
        /* No spare invalid entry, so create one */
 
@@ -233,30 +244,35 @@ static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid)
                max_slb_size = mmu_slb_size;
 
        /* Overflowing -> purge */
-       if ((to_svcpu(vcpu)->slb_max) == max_slb_size)
+       if ((svcpu->slb_max) == max_slb_size)
                kvmppc_mmu_flush_segments(vcpu);
 
-       r = to_svcpu(vcpu)->slb_max;
-       to_svcpu(vcpu)->slb_max++;
+       r = svcpu->slb_max;
+       svcpu->slb_max++;
 
+out:
+       svcpu_put(svcpu);
        return r;
 }
 
 int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
 {
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
        u64 esid = eaddr >> SID_SHIFT;
        u64 slb_esid = (eaddr & ESID_MASK) | SLB_ESID_V;
        u64 slb_vsid = SLB_VSID_USER;
        u64 gvsid;
        int slb_index;
        struct kvmppc_sid_map *map;
+       int r = 0;
 
        slb_index = kvmppc_mmu_next_segment(vcpu, eaddr & ESID_MASK);
 
        if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) {
                /* Invalidate an entry */
-               to_svcpu(vcpu)->slb[slb_index].esid = 0;
-               return -ENOENT;
+               svcpu->slb[slb_index].esid = 0;
+               r = -ENOENT;
+               goto out;
        }
 
        map = find_sid_vsid(vcpu, gvsid);
@@ -269,18 +285,22 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
        slb_vsid &= ~SLB_VSID_KP;
        slb_esid |= slb_index;
 
-       to_svcpu(vcpu)->slb[slb_index].esid = slb_esid;
-       to_svcpu(vcpu)->slb[slb_index].vsid = slb_vsid;
+       svcpu->slb[slb_index].esid = slb_esid;
+       svcpu->slb[slb_index].vsid = slb_vsid;
 
        trace_kvm_book3s_slbmte(slb_vsid, slb_esid);
 
-       return 0;
+out:
+       svcpu_put(svcpu);
+       return r;
 }
 
 void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
 {
-       to_svcpu(vcpu)->slb_max = 1;
-       to_svcpu(vcpu)->slb[0].esid = 0;
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       svcpu->slb_max = 1;
+       svcpu->slb[0].esid = 0;
+       svcpu_put(svcpu);
 }
 
 void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
index bc3a2ea..ddc485a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/gfp.h>
 #include <linux/slab.h>
 #include <linux/hugetlb.h>
+#include <linux/vmalloc.h>
 
 #include <asm/tlbflush.h>
 #include <asm/kvm_ppc.h>
 #include <asm/ppc-opcode.h>
 #include <asm/cputable.h>
 
-/* For now use fixed-size 16MB page table */
-#define HPT_ORDER      24
-#define HPT_NPTEG      (1ul << (HPT_ORDER - 7))        /* 128B per pteg */
-#define HPT_HASH_MASK  (HPT_NPTEG - 1)
-
-/* Pages in the VRMA are 16MB pages */
-#define VRMA_PAGE_ORDER        24
-#define VRMA_VSID      0x1ffffffUL     /* 1TB VSID reserved for VRMA */
-
 /* POWER7 has 10-bit LPIDs, PPC970 has 6-bit LPIDs */
 #define MAX_LPID_970   63
 #define NR_LPIDS       (LPID_RSVD + 1)
@@ -51,21 +43,41 @@ long kvmppc_alloc_hpt(struct kvm *kvm)
 {
        unsigned long hpt;
        unsigned long lpid;
+       struct revmap_entry *rev;
+       struct kvmppc_linear_info *li;
+
+       /* Allocate guest's hashed page table */
+       li = kvm_alloc_hpt();
+       if (li) {
+               /* using preallocated memory */
+               hpt = (ulong)li->base_virt;
+               kvm->arch.hpt_li = li;
+       } else {
+               /* using dynamic memory */
+               hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_REPEAT|
+                                      __GFP_NOWARN, HPT_ORDER - PAGE_SHIFT);
+       }
 
-       hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_REPEAT|__GFP_NOWARN,
-                              HPT_ORDER - PAGE_SHIFT);
        if (!hpt) {
                pr_err("kvm_alloc_hpt: Couldn't alloc HPT\n");
                return -ENOMEM;
        }
        kvm->arch.hpt_virt = hpt;
 
+       /* Allocate reverse map array */
+       rev = vmalloc(sizeof(struct revmap_entry) * HPT_NPTE);
+       if (!rev) {
+               pr_err("kvmppc_alloc_hpt: Couldn't alloc reverse map array\n");
+               goto out_freehpt;
+       }
+       kvm->arch.revmap = rev;
+
+       /* Allocate the guest's logical partition ID */
        do {
                lpid = find_first_zero_bit(lpid_inuse, NR_LPIDS);
                if (lpid >= NR_LPIDS) {
                        pr_err("kvm_alloc_hpt: No LPIDs free\n");
-                       free_pages(hpt, HPT_ORDER - PAGE_SHIFT);
-                       return -ENOMEM;
+                       goto out_freeboth;
                }
        } while (test_and_set_bit(lpid, lpid_inuse));
 
@@ -74,37 +86,64 @@ long kvmppc_alloc_hpt(struct kvm *kvm)
 
        pr_info("KVM guest htab at %lx, LPID %lx\n", hpt, lpid);
        return 0;
+
+ out_freeboth:
+       vfree(rev);
+ out_freehpt:
+       free_pages(hpt, HPT_ORDER - PAGE_SHIFT);
+       return -ENOMEM;
 }
 
 void kvmppc_free_hpt(struct kvm *kvm)
 {
        clear_bit(kvm->arch.lpid, lpid_inuse);
-       free_pages(kvm->arch.hpt_virt, HPT_ORDER - PAGE_SHIFT);
+       vfree(kvm->arch.revmap);
+       if (kvm->arch.hpt_li)
+               kvm_release_hpt(kvm->arch.hpt_li);
+       else
+               free_pages(kvm->arch.hpt_virt, HPT_ORDER - PAGE_SHIFT);
+}
+
+/* Bits in first HPTE dword for pagesize 4k, 64k or 16M */
+static inline unsigned long hpte0_pgsize_encoding(unsigned long pgsize)
+{
+       return (pgsize > 0x1000) ? HPTE_V_LARGE : 0;
+}
+
+/* Bits in second HPTE dword for pagesize 4k, 64k or 16M */
+static inline unsigned long hpte1_pgsize_encoding(unsigned long pgsize)
+{
+       return (pgsize == 0x10000) ? 0x1000 : 0;
 }
 
-void kvmppc_map_vrma(struct kvm *kvm, struct kvm_userspace_memory_region *mem)
+void kvmppc_map_vrma(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
+                    unsigned long porder)
 {
        unsigned long i;
-       unsigned long npages = kvm->arch.ram_npages;
-       unsigned long pfn;
-       unsigned long *hpte;
-       unsigned long hash;
-       struct kvmppc_pginfo *pginfo = kvm->arch.ram_pginfo;
+       unsigned long npages;
+       unsigned long hp_v, hp_r;
+       unsigned long addr, hash;
+       unsigned long psize;
+       unsigned long hp0, hp1;
+       long ret;
 
-       if (!pginfo)
-               return;
+       psize = 1ul << porder;
+       npages = memslot->npages >> (porder - PAGE_SHIFT);
 
        /* VRMA can't be > 1TB */
-       if (npages > 1ul << (40 - kvm->arch.ram_porder))
-               npages = 1ul << (40 - kvm->arch.ram_porder);
+       if (npages > 1ul << (40 - porder))
+               npages = 1ul << (40 - porder);
        /* Can't use more than 1 HPTE per HPTEG */
        if (npages > HPT_NPTEG)
                npages = HPT_NPTEG;
 
+       hp0 = HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16)) |
+               HPTE_V_BOLTED | hpte0_pgsize_encoding(psize);
+       hp1 = hpte1_pgsize_encoding(psize) |
+               HPTE_R_R | HPTE_R_C | HPTE_R_M | PP_RWXX;
+
        for (i = 0; i < npages; ++i) {
-               pfn = pginfo[i].pfn;
-               if (!pfn)
-                       break;
+               addr = i << porder;
                /* can't use hpt_hash since va > 64 bits */
                hash = (i ^ (VRMA_VSID ^ (VRMA_VSID << 25))) & HPT_HASH_MASK;
                /*
@@ -113,15 +152,15 @@ void kvmppc_map_vrma(struct kvm *kvm, struct kvm_userspace_memory_region *mem)
                 * at most one HPTE per HPTEG, we just assume entry 7
                 * is available and use it.
                 */
-               hpte = (unsigned long *) (kvm->arch.hpt_virt + (hash << 7));
-               hpte += 7 * 2;
-               /* HPTE low word - RPN, protection, etc. */
-               hpte[1] = (pfn << PAGE_SHIFT) | HPTE_R_R | HPTE_R_C |
-                       HPTE_R_M | PP_RWXX;
-               wmb();
-               hpte[0] = HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16)) |
-                       (i << (VRMA_PAGE_ORDER - 16)) | HPTE_V_BOLTED |
-                       HPTE_V_LARGE | HPTE_V_VALID;
+               hash = (hash << 3) + 7;
+               hp_v = hp0 | ((addr >> 16) & ~0x7fUL);
+               hp_r = hp1 | addr;
+               ret = kvmppc_virtmode_h_enter(vcpu, H_EXACT, hash, hp_v, hp_r);
+               if (ret != H_SUCCESS) {
+                       pr_err("KVM: map_vrma at %lx failed, ret=%ld\n",
+                              addr, ret);
+                       break;
+               }
        }
 }
 
@@ -158,10 +197,814 @@ static void kvmppc_mmu_book3s_64_hv_reset_msr(struct kvm_vcpu *vcpu)
        kvmppc_set_msr(vcpu, MSR_SF | MSR_ME);
 }
 
+/*
+ * This is called to get a reference to a guest page if there isn't
+ * one already in the kvm->arch.slot_phys[][] arrays.
+ */
+static long kvmppc_get_guest_page(struct kvm *kvm, unsigned long gfn,
+                                 struct kvm_memory_slot *memslot,
+                                 unsigned long psize)
+{
+       unsigned long start;
+       long np, err;
+       struct page *page, *hpage, *pages[1];
+       unsigned long s, pgsize;
+       unsigned long *physp;
+       unsigned int is_io, got, pgorder;
+       struct vm_area_struct *vma;
+       unsigned long pfn, i, npages;
+
+       physp = kvm->arch.slot_phys[memslot->id];
+       if (!physp)
+               return -EINVAL;
+       if (physp[gfn - memslot->base_gfn])
+               return 0;
+
+       is_io = 0;
+       got = 0;
+       page = NULL;
+       pgsize = psize;
+       err = -EINVAL;
+       start = gfn_to_hva_memslot(memslot, gfn);
+
+       /* Instantiate and get the page we want access to */
+       np = get_user_pages_fast(start, 1, 1, pages);
+       if (np != 1) {
+               /* Look up the vma for the page */
+               down_read(&current->mm->mmap_sem);
+               vma = find_vma(current->mm, start);
+               if (!vma || vma->vm_start > start ||
+                   start + psize > vma->vm_end ||
+                   !(vma->vm_flags & VM_PFNMAP))
+                       goto up_err;
+               is_io = hpte_cache_bits(pgprot_val(vma->vm_page_prot));
+               pfn = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
+               /* check alignment of pfn vs. requested page size */
+               if (psize > PAGE_SIZE && (pfn & ((psize >> PAGE_SHIFT) - 1)))
+                       goto up_err;
+               up_read(&current->mm->mmap_sem);
+
+       } else {
+               page = pages[0];
+               got = KVMPPC_GOT_PAGE;
+
+               /* See if this is a large page */
+               s = PAGE_SIZE;
+               if (PageHuge(page)) {
+                       hpage = compound_head(page);
+                       s <<= compound_order(hpage);
+                       /* Get the whole large page if slot alignment is ok */
+                       if (s > psize && slot_is_aligned(memslot, s) &&
+                           !(memslot->userspace_addr & (s - 1))) {
+                               start &= ~(s - 1);
+                               pgsize = s;
+                               page = hpage;
+                       }
+               }
+               if (s < psize)
+                       goto out;
+               pfn = page_to_pfn(page);
+       }
+
+       npages = pgsize >> PAGE_SHIFT;
+       pgorder = __ilog2(npages);
+       physp += (gfn - memslot->base_gfn) & ~(npages - 1);
+       spin_lock(&kvm->arch.slot_phys_lock);
+       for (i = 0; i < npages; ++i) {
+               if (!physp[i]) {
+                       physp[i] = ((pfn + i) << PAGE_SHIFT) +
+                               got + is_io + pgorder;
+                       got = 0;
+               }
+       }
+       spin_unlock(&kvm->arch.slot_phys_lock);
+       err = 0;
+
+ out:
+       if (got) {
+               if (PageHuge(page))
+                       page = compound_head(page);
+               put_page(page);
+       }
+       return err;
+
+ up_err:
+       up_read(&current->mm->mmap_sem);
+       return err;
+}
+
+/*
+ * We come here on a H_ENTER call from the guest when we are not
+ * using mmu notifiers and we don't have the requested page pinned
+ * already.
+ */
+long kvmppc_virtmode_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
+                       long pte_index, unsigned long pteh, unsigned long ptel)
+{
+       struct kvm *kvm = vcpu->kvm;
+       unsigned long psize, gpa, gfn;
+       struct kvm_memory_slot *memslot;
+       long ret;
+
+       if (kvm->arch.using_mmu_notifiers)
+               goto do_insert;
+
+       psize = hpte_page_size(pteh, ptel);
+       if (!psize)
+               return H_PARAMETER;
+
+       pteh &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
+
+       /* Find the memslot (if any) for this address */
+       gpa = (ptel & HPTE_R_RPN) & ~(psize - 1);
+       gfn = gpa >> PAGE_SHIFT;
+       memslot = gfn_to_memslot(kvm, gfn);
+       if (memslot && !(memslot->flags & KVM_MEMSLOT_INVALID)) {
+               if (!slot_is_aligned(memslot, psize))
+                       return H_PARAMETER;
+               if (kvmppc_get_guest_page(kvm, gfn, memslot, psize) < 0)
+                       return H_PARAMETER;
+       }
+
+ do_insert:
+       /* Protect linux PTE lookup from page table destruction */
+       rcu_read_lock_sched();  /* this disables preemption too */
+       vcpu->arch.pgdir = current->mm->pgd;
+       ret = kvmppc_h_enter(vcpu, flags, pte_index, pteh, ptel);
+       rcu_read_unlock_sched();
+       if (ret == H_TOO_HARD) {
+               /* this can't happen */
+               pr_err("KVM: Oops, kvmppc_h_enter returned too hard!\n");
+               ret = H_RESOURCE;       /* or something */
+       }
+       return ret;
+
+}
+
+static struct kvmppc_slb *kvmppc_mmu_book3s_hv_find_slbe(struct kvm_vcpu *vcpu,
+                                                        gva_t eaddr)
+{
+       u64 mask;
+       int i;
+
+       for (i = 0; i < vcpu->arch.slb_nr; i++) {
+               if (!(vcpu->arch.slb[i].orige & SLB_ESID_V))
+                       continue;
+
+               if (vcpu->arch.slb[i].origv & SLB_VSID_B_1T)
+                       mask = ESID_MASK_1T;
+               else
+                       mask = ESID_MASK;
+
+               if (((vcpu->arch.slb[i].orige ^ eaddr) & mask) == 0)
+                       return &vcpu->arch.slb[i];
+       }
+       return NULL;
+}
+
+static unsigned long kvmppc_mmu_get_real_addr(unsigned long v, unsigned long r,
+                       unsigned long ea)
+{
+       unsigned long ra_mask;
+
+       ra_mask = hpte_page_size(v, r) - 1;
+       return (r & HPTE_R_RPN & ~ra_mask) | (ea & ra_mask);
+}
+
 static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
-                               struct kvmppc_pte *gpte, bool data)
+                       struct kvmppc_pte *gpte, bool data)
+{
+       struct kvm *kvm = vcpu->kvm;
+       struct kvmppc_slb *slbe;
+       unsigned long slb_v;
+       unsigned long pp, key;
+       unsigned long v, gr;
+       unsigned long *hptep;
+       int index;
+       int virtmode = vcpu->arch.shregs.msr & (data ? MSR_DR : MSR_IR);
+
+       /* Get SLB entry */
+       if (virtmode) {
+               slbe = kvmppc_mmu_book3s_hv_find_slbe(vcpu, eaddr);
+               if (!slbe)
+                       return -EINVAL;
+               slb_v = slbe->origv;
+       } else {
+               /* real mode access */
+               slb_v = vcpu->kvm->arch.vrma_slb_v;
+       }
+
+       /* Find the HPTE in the hash table */
+       index = kvmppc_hv_find_lock_hpte(kvm, eaddr, slb_v,
+                                        HPTE_V_VALID | HPTE_V_ABSENT);
+       if (index < 0)
+               return -ENOENT;
+       hptep = (unsigned long *)(kvm->arch.hpt_virt + (index << 4));
+       v = hptep[0] & ~HPTE_V_HVLOCK;
+       gr = kvm->arch.revmap[index].guest_rpte;
+
+       /* Unlock the HPTE */
+       asm volatile("lwsync" : : : "memory");
+       hptep[0] = v;
+
+       gpte->eaddr = eaddr;
+       gpte->vpage = ((v & HPTE_V_AVPN) << 4) | ((eaddr >> 12) & 0xfff);
+
+       /* Get PP bits and key for permission check */
+       pp = gr & (HPTE_R_PP0 | HPTE_R_PP);
+       key = (vcpu->arch.shregs.msr & MSR_PR) ? SLB_VSID_KP : SLB_VSID_KS;
+       key &= slb_v;
+
+       /* Calculate permissions */
+       gpte->may_read = hpte_read_permission(pp, key);
+       gpte->may_write = hpte_write_permission(pp, key);
+       gpte->may_execute = gpte->may_read && !(gr & (HPTE_R_N | HPTE_R_G));
+
+       /* Storage key permission check for POWER7 */
+       if (data && virtmode && cpu_has_feature(CPU_FTR_ARCH_206)) {
+               int amrfield = hpte_get_skey_perm(gr, vcpu->arch.amr);
+               if (amrfield & 1)
+                       gpte->may_read = 0;
+               if (amrfield & 2)
+                       gpte->may_write = 0;
+       }
+
+       /* Get the guest physical address */
+       gpte->raddr = kvmppc_mmu_get_real_addr(v, gr, eaddr);
+       return 0;
+}
+
+/*
+ * Quick test for whether an instruction is a load or a store.
+ * If the instruction is a load or a store, then this will indicate
+ * which it is, at least on server processors.  (Embedded processors
+ * have some external PID instructions that don't follow the rule
+ * embodied here.)  If the instruction isn't a load or store, then
+ * this doesn't return anything useful.
+ */
+static int instruction_is_store(unsigned int instr)
+{
+       unsigned int mask;
+
+       mask = 0x10000000;
+       if ((instr & 0xfc000000) == 0x7c000000)
+               mask = 0x100;           /* major opcode 31 */
+       return (instr & mask) != 0;
+}
+
+static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                                 unsigned long gpa, int is_store)
+{
+       int ret;
+       u32 last_inst;
+       unsigned long srr0 = kvmppc_get_pc(vcpu);
+
+       /* We try to load the last instruction.  We don't let
+        * emulate_instruction do it as it doesn't check what
+        * kvmppc_ld returns.
+        * If we fail, we just return to the guest and try executing it again.
+        */
+       if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) {
+               ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
+               if (ret != EMULATE_DONE || last_inst == KVM_INST_FETCH_FAILED)
+                       return RESUME_GUEST;
+               vcpu->arch.last_inst = last_inst;
+       }
+
+       /*
+        * WARNING: We do not know for sure whether the instruction we just
+        * read from memory is the same that caused the fault in the first
+        * place.  If the instruction we read is neither an load or a store,
+        * then it can't access memory, so we don't need to worry about
+        * enforcing access permissions.  So, assuming it is a load or
+        * store, we just check that its direction (load or store) is
+        * consistent with the original fault, since that's what we
+        * checked the access permissions against.  If there is a mismatch
+        * we just return and retry the instruction.
+        */
+
+       if (instruction_is_store(vcpu->arch.last_inst) != !!is_store)
+               return RESUME_GUEST;
+
+       /*
+        * Emulated accesses are emulated by looking at the hash for
+        * translation once, then performing the access later. The
+        * translation could be invalidated in the meantime in which
+        * point performing the subsequent memory access on the old
+        * physical address could possibly be a security hole for the
+        * guest (but not the host).
+        *
+        * This is less of an issue for MMIO stores since they aren't
+        * globally visible. It could be an issue for MMIO loads to
+        * a certain extent but we'll ignore it for now.
+        */
+
+       vcpu->arch.paddr_accessed = gpa;
+       return kvmppc_emulate_mmio(run, vcpu);
+}
+
+int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
+                               unsigned long ea, unsigned long dsisr)
+{
+       struct kvm *kvm = vcpu->kvm;
+       unsigned long *hptep, hpte[3], r;
+       unsigned long mmu_seq, psize, pte_size;
+       unsigned long gfn, hva, pfn;
+       struct kvm_memory_slot *memslot;
+       unsigned long *rmap;
+       struct revmap_entry *rev;
+       struct page *page, *pages[1];
+       long index, ret, npages;
+       unsigned long is_io;
+       unsigned int writing, write_ok;
+       struct vm_area_struct *vma;
+       unsigned long rcbits;
+
+       /*
+        * Real-mode code has already searched the HPT and found the
+        * entry we're interested in.  Lock the entry and check that
+        * it hasn't changed.  If it has, just return and re-execute the
+        * instruction.
+        */
+       if (ea != vcpu->arch.pgfault_addr)
+               return RESUME_GUEST;
+       index = vcpu->arch.pgfault_index;
+       hptep = (unsigned long *)(kvm->arch.hpt_virt + (index << 4));
+       rev = &kvm->arch.revmap[index];
+       preempt_disable();
+       while (!try_lock_hpte(hptep, HPTE_V_HVLOCK))
+               cpu_relax();
+       hpte[0] = hptep[0] & ~HPTE_V_HVLOCK;
+       hpte[1] = hptep[1];
+       hpte[2] = r = rev->guest_rpte;
+       asm volatile("lwsync" : : : "memory");
+       hptep[0] = hpte[0];
+       preempt_enable();
+
+       if (hpte[0] != vcpu->arch.pgfault_hpte[0] ||
+           hpte[1] != vcpu->arch.pgfault_hpte[1])
+               return RESUME_GUEST;
+
+       /* Translate the logical address and get the page */
+       psize = hpte_page_size(hpte[0], r);
+       gfn = hpte_rpn(r, psize);
+       memslot = gfn_to_memslot(kvm, gfn);
+
+       /* No memslot means it's an emulated MMIO region */
+       if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) {
+               unsigned long gpa = (gfn << PAGE_SHIFT) | (ea & (psize - 1));
+               return kvmppc_hv_emulate_mmio(run, vcpu, gpa,
+                                             dsisr & DSISR_ISSTORE);
+       }
+
+       if (!kvm->arch.using_mmu_notifiers)
+               return -EFAULT;         /* should never get here */
+
+       /* used to check for invalidations in progress */
+       mmu_seq = kvm->mmu_notifier_seq;
+       smp_rmb();
+
+       is_io = 0;
+       pfn = 0;
+       page = NULL;
+       pte_size = PAGE_SIZE;
+       writing = (dsisr & DSISR_ISSTORE) != 0;
+       /* If writing != 0, then the HPTE must allow writing, if we get here */
+       write_ok = writing;
+       hva = gfn_to_hva_memslot(memslot, gfn);
+       npages = get_user_pages_fast(hva, 1, writing, pages);
+       if (npages < 1) {
+               /* Check if it's an I/O mapping */
+               down_read(&current->mm->mmap_sem);
+               vma = find_vma(current->mm, hva);
+               if (vma && vma->vm_start <= hva && hva + psize <= vma->vm_end &&
+                   (vma->vm_flags & VM_PFNMAP)) {
+                       pfn = vma->vm_pgoff +
+                               ((hva - vma->vm_start) >> PAGE_SHIFT);
+                       pte_size = psize;
+                       is_io = hpte_cache_bits(pgprot_val(vma->vm_page_prot));
+                       write_ok = vma->vm_flags & VM_WRITE;
+               }
+               up_read(&current->mm->mmap_sem);
+               if (!pfn)
+                       return -EFAULT;
+       } else {
+               page = pages[0];
+               if (PageHuge(page)) {
+                       page = compound_head(page);
+                       pte_size <<= compound_order(page);
+               }
+               /* if the guest wants write access, see if that is OK */
+               if (!writing && hpte_is_writable(r)) {
+                       pte_t *ptep, pte;
+
+                       /*
+                        * We need to protect against page table destruction
+                        * while looking up and updating the pte.
+                        */
+                       rcu_read_lock_sched();
+                       ptep = find_linux_pte_or_hugepte(current->mm->pgd,
+                                                        hva, NULL);
+                       if (ptep && pte_present(*ptep)) {
+                               pte = kvmppc_read_update_linux_pte(ptep, 1);
+                               if (pte_write(pte))
+                                       write_ok = 1;
+                       }
+                       rcu_read_unlock_sched();
+               }
+               pfn = page_to_pfn(page);
+       }
+
+       ret = -EFAULT;
+       if (psize > pte_size)
+               goto out_put;
+
+       /* Check WIMG vs. the actual page we're accessing */
+       if (!hpte_cache_flags_ok(r, is_io)) {
+               if (is_io)
+                       return -EFAULT;
+               /*
+                * Allow guest to map emulated device memory as
+                * uncacheable, but actually make it cacheable.
+                */
+               r = (r & ~(HPTE_R_W|HPTE_R_I|HPTE_R_G)) | HPTE_R_M;
+       }
+
+       /* Set the HPTE to point to pfn */
+       r = (r & ~(HPTE_R_PP0 - pte_size)) | (pfn << PAGE_SHIFT);
+       if (hpte_is_writable(r) && !write_ok)
+               r = hpte_make_readonly(r);
+       ret = RESUME_GUEST;
+       preempt_disable();
+       while (!try_lock_hpte(hptep, HPTE_V_HVLOCK))
+               cpu_relax();
+       if ((hptep[0] & ~HPTE_V_HVLOCK) != hpte[0] || hptep[1] != hpte[1] ||
+           rev->guest_rpte != hpte[2])
+               /* HPTE has been changed under us; let the guest retry */
+               goto out_unlock;
+       hpte[0] = (hpte[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID;
+
+       rmap = &memslot->rmap[gfn - memslot->base_gfn];
+       lock_rmap(rmap);
+
+       /* Check if we might have been invalidated; let the guest retry if so */
+       ret = RESUME_GUEST;
+       if (mmu_notifier_retry(vcpu, mmu_seq)) {
+               unlock_rmap(rmap);
+               goto out_unlock;
+       }
+
+       /* Only set R/C in real HPTE if set in both *rmap and guest_rpte */
+       rcbits = *rmap >> KVMPPC_RMAP_RC_SHIFT;
+       r &= rcbits | ~(HPTE_R_R | HPTE_R_C);
+
+       if (hptep[0] & HPTE_V_VALID) {
+               /* HPTE was previously valid, so we need to invalidate it */
+               unlock_rmap(rmap);
+               hptep[0] |= HPTE_V_ABSENT;
+               kvmppc_invalidate_hpte(kvm, hptep, index);
+               /* don't lose previous R and C bits */
+               r |= hptep[1] & (HPTE_R_R | HPTE_R_C);
+       } else {
+               kvmppc_add_revmap_chain(kvm, rev, rmap, index, 0);
+       }
+
+       hptep[1] = r;
+       eieio();
+       hptep[0] = hpte[0];
+       asm volatile("ptesync" : : : "memory");
+       preempt_enable();
+       if (page && hpte_is_writable(r))
+               SetPageDirty(page);
+
+ out_put:
+       if (page)
+               put_page(page);
+       return ret;
+
+ out_unlock:
+       hptep[0] &= ~HPTE_V_HVLOCK;
+       preempt_enable();
+       goto out_put;
+}
+
+static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
+                         int (*handler)(struct kvm *kvm, unsigned long *rmapp,
+                                        unsigned long gfn))
+{
+       int ret;
+       int retval = 0;
+       struct kvm_memslots *slots;
+       struct kvm_memory_slot *memslot;
+
+       slots = kvm_memslots(kvm);
+       kvm_for_each_memslot(memslot, slots) {
+               unsigned long start = memslot->userspace_addr;
+               unsigned long end;
+
+               end = start + (memslot->npages << PAGE_SHIFT);
+               if (hva >= start && hva < end) {
+                       gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT;
+
+                       ret = handler(kvm, &memslot->rmap[gfn_offset],
+                                     memslot->base_gfn + gfn_offset);
+                       retval |= ret;
+               }
+       }
+
+       return retval;
+}
+
+static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
+                          unsigned long gfn)
+{
+       struct revmap_entry *rev = kvm->arch.revmap;
+       unsigned long h, i, j;
+       unsigned long *hptep;
+       unsigned long ptel, psize, rcbits;
+
+       for (;;) {
+               lock_rmap(rmapp);
+               if (!(*rmapp & KVMPPC_RMAP_PRESENT)) {
+                       unlock_rmap(rmapp);
+                       break;
+               }
+
+               /*
+                * To avoid an ABBA deadlock with the HPTE lock bit,
+                * we can't spin on the HPTE lock while holding the
+                * rmap chain lock.
+                */
+               i = *rmapp & KVMPPC_RMAP_INDEX;
+               hptep = (unsigned long *) (kvm->arch.hpt_virt + (i << 4));
+               if (!try_lock_hpte(hptep, HPTE_V_HVLOCK)) {
+                       /* unlock rmap before spinning on the HPTE lock */
+                       unlock_rmap(rmapp);
+                       while (hptep[0] & HPTE_V_HVLOCK)
+                               cpu_relax();
+                       continue;
+               }
+               j = rev[i].forw;
+               if (j == i) {
+                       /* chain is now empty */
+                       *rmapp &= ~(KVMPPC_RMAP_PRESENT | KVMPPC_RMAP_INDEX);
+               } else {
+                       /* remove i from chain */
+                       h = rev[i].back;
+                       rev[h].forw = j;
+                       rev[j].back = h;
+                       rev[i].forw = rev[i].back = i;
+                       *rmapp = (*rmapp & ~KVMPPC_RMAP_INDEX) | j;
+               }
+
+               /* Now check and modify the HPTE */
+               ptel = rev[i].guest_rpte;
+               psize = hpte_page_size(hptep[0], ptel);
+               if ((hptep[0] & HPTE_V_VALID) &&
+                   hpte_rpn(ptel, psize) == gfn) {
+                       hptep[0] |= HPTE_V_ABSENT;
+                       kvmppc_invalidate_hpte(kvm, hptep, i);
+                       /* Harvest R and C */
+                       rcbits = hptep[1] & (HPTE_R_R | HPTE_R_C);
+                       *rmapp |= rcbits << KVMPPC_RMAP_RC_SHIFT;
+                       rev[i].guest_rpte = ptel | rcbits;
+               }
+               unlock_rmap(rmapp);
+               hptep[0] &= ~HPTE_V_HVLOCK;
+       }
+       return 0;
+}
+
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
+{
+       if (kvm->arch.using_mmu_notifiers)
+               kvm_handle_hva(kvm, hva, kvm_unmap_rmapp);
+       return 0;
+}
+
+static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+                        unsigned long gfn)
+{
+       struct revmap_entry *rev = kvm->arch.revmap;
+       unsigned long head, i, j;
+       unsigned long *hptep;
+       int ret = 0;
+
+ retry:
+       lock_rmap(rmapp);
+       if (*rmapp & KVMPPC_RMAP_REFERENCED) {
+               *rmapp &= ~KVMPPC_RMAP_REFERENCED;
+               ret = 1;
+       }
+       if (!(*rmapp & KVMPPC_RMAP_PRESENT)) {
+               unlock_rmap(rmapp);
+               return ret;
+       }
+
+       i = head = *rmapp & KVMPPC_RMAP_INDEX;
+       do {
+               hptep = (unsigned long *) (kvm->arch.hpt_virt + (i << 4));
+               j = rev[i].forw;
+
+               /* If this HPTE isn't referenced, ignore it */
+               if (!(hptep[1] & HPTE_R_R))
+                       continue;
+
+               if (!try_lock_hpte(hptep, HPTE_V_HVLOCK)) {
+                       /* unlock rmap before spinning on the HPTE lock */
+                       unlock_rmap(rmapp);
+                       while (hptep[0] & HPTE_V_HVLOCK)
+                               cpu_relax();
+                       goto retry;
+               }
+
+               /* Now check and modify the HPTE */
+               if ((hptep[0] & HPTE_V_VALID) && (hptep[1] & HPTE_R_R)) {
+                       kvmppc_clear_ref_hpte(kvm, hptep, i);
+                       rev[i].guest_rpte |= HPTE_R_R;
+                       ret = 1;
+               }
+               hptep[0] &= ~HPTE_V_HVLOCK;
+       } while ((i = j) != head);
+
+       unlock_rmap(rmapp);
+       return ret;
+}
+
+int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+       if (!kvm->arch.using_mmu_notifiers)
+               return 0;
+       return kvm_handle_hva(kvm, hva, kvm_age_rmapp);
+}
+
+static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+                             unsigned long gfn)
+{
+       struct revmap_entry *rev = kvm->arch.revmap;
+       unsigned long head, i, j;
+       unsigned long *hp;
+       int ret = 1;
+
+       if (*rmapp & KVMPPC_RMAP_REFERENCED)
+               return 1;
+
+       lock_rmap(rmapp);
+       if (*rmapp & KVMPPC_RMAP_REFERENCED)
+               goto out;
+
+       if (*rmapp & KVMPPC_RMAP_PRESENT) {
+               i = head = *rmapp & KVMPPC_RMAP_INDEX;
+               do {
+                       hp = (unsigned long *)(kvm->arch.hpt_virt + (i << 4));
+                       j = rev[i].forw;
+                       if (hp[1] & HPTE_R_R)
+                               goto out;
+               } while ((i = j) != head);
+       }
+       ret = 0;
+
+ out:
+       unlock_rmap(rmapp);
+       return ret;
+}
+
+int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+       if (!kvm->arch.using_mmu_notifiers)
+               return 0;
+       return kvm_handle_hva(kvm, hva, kvm_test_age_rmapp);
+}
+
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
 {
-       return -ENOENT;
+       if (!kvm->arch.using_mmu_notifiers)
+               return;
+       kvm_handle_hva(kvm, hva, kvm_unmap_rmapp);
+}
+
+static int kvm_test_clear_dirty(struct kvm *kvm, unsigned long *rmapp)
+{
+       struct revmap_entry *rev = kvm->arch.revmap;
+       unsigned long head, i, j;
+       unsigned long *hptep;
+       int ret = 0;
+
+ retry:
+       lock_rmap(rmapp);
+       if (*rmapp & KVMPPC_RMAP_CHANGED) {
+               *rmapp &= ~KVMPPC_RMAP_CHANGED;
+               ret = 1;
+       }
+       if (!(*rmapp & KVMPPC_RMAP_PRESENT)) {
+               unlock_rmap(rmapp);
+               return ret;
+       }
+
+       i = head = *rmapp & KVMPPC_RMAP_INDEX;
+       do {
+               hptep = (unsigned long *) (kvm->arch.hpt_virt + (i << 4));
+               j = rev[i].forw;
+
+               if (!(hptep[1] & HPTE_R_C))
+                       continue;
+
+               if (!try_lock_hpte(hptep, HPTE_V_HVLOCK)) {
+                       /* unlock rmap before spinning on the HPTE lock */
+                       unlock_rmap(rmapp);
+                       while (hptep[0] & HPTE_V_HVLOCK)
+                               cpu_relax();
+                       goto retry;
+               }
+
+               /* Now check and modify the HPTE */
+               if ((hptep[0] & HPTE_V_VALID) && (hptep[1] & HPTE_R_C)) {
+                       /* need to make it temporarily absent to clear C */
+                       hptep[0] |= HPTE_V_ABSENT;
+                       kvmppc_invalidate_hpte(kvm, hptep, i);
+                       hptep[1] &= ~HPTE_R_C;
+                       eieio();
+                       hptep[0] = (hptep[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID;
+                       rev[i].guest_rpte |= HPTE_R_C;
+                       ret = 1;
+               }
+               hptep[0] &= ~HPTE_V_HVLOCK;
+       } while ((i = j) != head);
+
+       unlock_rmap(rmapp);
+       return ret;
+}
+
+long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
+{
+       unsigned long i;
+       unsigned long *rmapp, *map;
+
+       preempt_disable();
+       rmapp = memslot->rmap;
+       map = memslot->dirty_bitmap;
+       for (i = 0; i < memslot->npages; ++i) {
+               if (kvm_test_clear_dirty(kvm, rmapp))
+                       __set_bit_le(i, map);
+               ++rmapp;
+       }
+       preempt_enable();
+       return 0;
+}
+
+void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long gpa,
+                           unsigned long *nb_ret)
+{
+       struct kvm_memory_slot *memslot;
+       unsigned long gfn = gpa >> PAGE_SHIFT;
+       struct page *page, *pages[1];
+       int npages;
+       unsigned long hva, psize, offset;
+       unsigned long pa;
+       unsigned long *physp;
+
+       memslot = gfn_to_memslot(kvm, gfn);
+       if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
+               return NULL;
+       if (!kvm->arch.using_mmu_notifiers) {
+               physp = kvm->arch.slot_phys[memslot->id];
+               if (!physp)
+                       return NULL;
+               physp += gfn - memslot->base_gfn;
+               pa = *physp;
+               if (!pa) {
+                       if (kvmppc_get_guest_page(kvm, gfn, memslot,
+                                                 PAGE_SIZE) < 0)
+                               return NULL;
+                       pa = *physp;
+               }
+               page = pfn_to_page(pa >> PAGE_SHIFT);
+       } else {
+               hva = gfn_to_hva_memslot(memslot, gfn);
+               npages = get_user_pages_fast(hva, 1, 1, pages);
+               if (npages < 1)
+                       return NULL;
+               page = pages[0];
+       }
+       psize = PAGE_SIZE;
+       if (PageHuge(page)) {
+               page = compound_head(page);
+               psize <<= compound_order(page);
+       }
+       if (!kvm->arch.using_mmu_notifiers)
+               get_page(page);
+       offset = gpa & (psize - 1);
+       if (nb_ret)
+               *nb_ret = psize - offset;
+       return page_address(page) + offset;
+}
+
+void kvmppc_unpin_guest_page(struct kvm *kvm, void *va)
+{
+       struct page *page = virt_to_page(va);
+
+       page = compound_head(page);
+       put_page(page);
 }
 
 void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu)
index 0c9dc62..f1950d1 100644 (file)
@@ -230,9 +230,12 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
                        r = kvmppc_st(vcpu, &addr, 32, zeros, true);
                        if ((r == -ENOENT) || (r == -EPERM)) {
+                               struct kvmppc_book3s_shadow_vcpu *svcpu;
+
+                               svcpu = svcpu_get(vcpu);
                                *advance = 0;
                                vcpu->arch.shared->dar = vaddr;
-                               to_svcpu(vcpu)->fault_dar = vaddr;
+                               svcpu->fault_dar = vaddr;
 
                                dsisr = DSISR_ISSTORE;
                                if (r == -ENOENT)
@@ -241,7 +244,8 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                                        dsisr |= DSISR_PROTFAULT;
 
                                vcpu->arch.shared->dsisr = dsisr;
-                               to_svcpu(vcpu)->fault_dsisr = dsisr;
+                               svcpu->fault_dsisr = dsisr;
+                               svcpu_put(svcpu);
 
                                kvmppc_book3s_queue_irqprio(vcpu,
                                        BOOK3S_INTERRUPT_DATA_STORAGE);
index ab42677..01294a5 100644 (file)
 #include <linux/gfp.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
-
-/*
- * For now, limit memory to 64GB and require it to be large pages.
- * This value is chosen because it makes the ram_pginfo array be
- * 64kB in size, which is about as large as we want to be trying
- * to allocate with kmalloc.
- */
-#define MAX_MEM_ORDER          36
-
-#define LARGE_PAGE_ORDER       24      /* 16MB pages */
+#include <linux/hugetlb.h>
 
 /* #define EXIT_DEBUG */
 /* #define EXIT_DEBUG_SIMPLE */
 /* #define EXIT_DEBUG_INT */
 
 static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
+static int kvmppc_hv_setup_rma(struct kvm_vcpu *vcpu);
 
 void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
@@ -147,10 +139,10 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu,
                                       unsigned long vcpuid, unsigned long vpa)
 {
        struct kvm *kvm = vcpu->kvm;
-       unsigned long pg_index, ra, len;
-       unsigned long pg_offset;
+       unsigned long len, nb;
        void *va;
        struct kvm_vcpu *tvcpu;
+       int err = H_PARAMETER;
 
        tvcpu = kvmppc_find_vcpu(kvm, vcpuid);
        if (!tvcpu)
@@ -163,45 +155,41 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu,
        if (flags < 4) {
                if (vpa & 0x7f)
                        return H_PARAMETER;
+               if (flags >= 2 && !tvcpu->arch.vpa)
+                       return H_RESOURCE;
                /* registering new area; convert logical addr to real */
-               pg_index = vpa >> kvm->arch.ram_porder;
-               pg_offset = vpa & (kvm->arch.ram_psize - 1);
-               if (pg_index >= kvm->arch.ram_npages)
+               va = kvmppc_pin_guest_page(kvm, vpa, &nb);
+               if (va == NULL)
                        return H_PARAMETER;
-               if (kvm->arch.ram_pginfo[pg_index].pfn == 0)
-                       return H_PARAMETER;
-               ra = kvm->arch.ram_pginfo[pg_index].pfn << PAGE_SHIFT;
-               ra |= pg_offset;
-               va = __va(ra);
                if (flags <= 1)
                        len = *(unsigned short *)(va + 4);
                else
                        len = *(unsigned int *)(va + 4);
-               if (pg_offset + len > kvm->arch.ram_psize)
-                       return H_PARAMETER;
+               if (len > nb)
+                       goto out_unpin;
                switch (flags) {
                case 1:         /* register VPA */
                        if (len < 640)
-                               return H_PARAMETER;
+                               goto out_unpin;
+                       if (tvcpu->arch.vpa)
+                               kvmppc_unpin_guest_page(kvm, vcpu->arch.vpa);
                        tvcpu->arch.vpa = va;
                        init_vpa(vcpu, va);
                        break;
                case 2:         /* register DTL */
                        if (len < 48)
-                               return H_PARAMETER;
-                       if (!tvcpu->arch.vpa)
-                               return H_RESOURCE;
+                               goto out_unpin;
                        len -= len % 48;
+                       if (tvcpu->arch.dtl)
+                               kvmppc_unpin_guest_page(kvm, vcpu->arch.dtl);
                        tvcpu->arch.dtl = va;
                        tvcpu->arch.dtl_end = va + len;
                        break;
                case 3:         /* register SLB shadow buffer */
-                       if (len < 8)
-                               return H_PARAMETER;
-                       if (!tvcpu->arch.vpa)
-                               return H_RESOURCE;
-                       tvcpu->arch.slb_shadow = va;
-                       len = (len - 16) / 16;
+                       if (len < 16)
+                               goto out_unpin;
+                       if (tvcpu->arch.slb_shadow)
+                               kvmppc_unpin_guest_page(kvm, vcpu->arch.slb_shadow);
                        tvcpu->arch.slb_shadow = va;
                        break;
                }
@@ -210,17 +198,30 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu,
                case 5:         /* unregister VPA */
                        if (tvcpu->arch.slb_shadow || tvcpu->arch.dtl)
                                return H_RESOURCE;
+                       if (!tvcpu->arch.vpa)
+                               break;
+                       kvmppc_unpin_guest_page(kvm, tvcpu->arch.vpa);
                        tvcpu->arch.vpa = NULL;
                        break;
                case 6:         /* unregister DTL */
+                       if (!tvcpu->arch.dtl)
+                               break;
+                       kvmppc_unpin_guest_page(kvm, tvcpu->arch.dtl);
                        tvcpu->arch.dtl = NULL;
                        break;
                case 7:         /* unregister SLB shadow buffer */
+                       if (!tvcpu->arch.slb_shadow)
+                               break;
+                       kvmppc_unpin_guest_page(kvm, tvcpu->arch.slb_shadow);
                        tvcpu->arch.slb_shadow = NULL;
                        break;
                }
        }
        return H_SUCCESS;
+
+ out_unpin:
+       kvmppc_unpin_guest_page(kvm, va);
+       return err;
 }
 
 int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
@@ -230,6 +231,12 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
        struct kvm_vcpu *tvcpu;
 
        switch (req) {
+       case H_ENTER:
+               ret = kvmppc_virtmode_h_enter(vcpu, kvmppc_get_gpr(vcpu, 4),
+                                             kvmppc_get_gpr(vcpu, 5),
+                                             kvmppc_get_gpr(vcpu, 6),
+                                             kvmppc_get_gpr(vcpu, 7));
+               break;
        case H_CEDE:
                break;
        case H_PROD:
@@ -319,20 +326,19 @@ static int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                break;
        }
        /*
-        * We get these next two if the guest does a bad real-mode access,
-        * as we have enabled VRMA (virtualized real mode area) mode in the
-        * LPCR.  We just generate an appropriate DSI/ISI to the guest.
+        * We get these next two if the guest accesses a page which it thinks
+        * it has mapped but which is not actually present, either because
+        * it is for an emulated I/O device or because the corresonding
+        * host page has been paged out.  Any other HDSI/HISI interrupts
+        * have been handled already.
         */
        case BOOK3S_INTERRUPT_H_DATA_STORAGE:
-               vcpu->arch.shregs.dsisr = vcpu->arch.fault_dsisr;
-               vcpu->arch.shregs.dar = vcpu->arch.fault_dar;
-               kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE, 0);
-               r = RESUME_GUEST;
+               r = kvmppc_book3s_hv_page_fault(run, vcpu,
+                               vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
                break;
        case BOOK3S_INTERRUPT_H_INST_STORAGE:
-               kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_INST_STORAGE,
-                                       0x08000000);
-               r = RESUME_GUEST;
+               r = kvmppc_book3s_hv_page_fault(run, vcpu,
+                               kvmppc_get_pc(vcpu), 0);
                break;
        /*
         * This occurs if the guest executes an illegal instruction.
@@ -392,6 +398,42 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+       int r = -EINVAL;
+
+       switch (reg->id) {
+       case KVM_REG_PPC_HIOR:
+               r = put_user(0, (u64 __user *)reg->addr);
+               break;
+       default:
+               break;
+       }
+
+       return r;
+}
+
+int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+       int r = -EINVAL;
+
+       switch (reg->id) {
+       case KVM_REG_PPC_HIOR:
+       {
+               u64 hior;
+               /* Only allow this to be set to zero */
+               r = get_user(hior, (u64 __user *)reg->addr);
+               if (!r && (hior != 0))
+                       r = -EINVAL;
+               break;
+       }
+       default:
+               break;
+       }
+
+       return r;
+}
+
 int kvmppc_core_check_processor_compat(void)
 {
        if (cpu_has_feature(CPU_FTR_HVMODE))
@@ -411,7 +453,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
                goto out;
 
        err = -ENOMEM;
-       vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
+       vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
        if (!vcpu)
                goto out;
 
@@ -463,15 +505,21 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
        return vcpu;
 
 free_vcpu:
-       kfree(vcpu);
+       kmem_cache_free(kvm_vcpu_cache, vcpu);
 out:
        return ERR_PTR(err);
 }
 
 void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
 {
+       if (vcpu->arch.dtl)
+               kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.dtl);
+       if (vcpu->arch.slb_shadow)
+               kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.slb_shadow);
+       if (vcpu->arch.vpa)
+               kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.vpa);
        kvm_vcpu_uninit(vcpu);
-       kfree(vcpu);
+       kmem_cache_free(kvm_vcpu_cache, vcpu);
 }
 
 static void kvmppc_set_timer(struct kvm_vcpu *vcpu)
@@ -482,7 +530,7 @@ static void kvmppc_set_timer(struct kvm_vcpu *vcpu)
        if (now > vcpu->arch.dec_expires) {
                /* decrementer has already gone negative */
                kvmppc_core_queue_dec(vcpu);
-               kvmppc_core_deliver_interrupts(vcpu);
+               kvmppc_core_prepare_to_enter(vcpu);
                return;
        }
        dec_nsec = (vcpu->arch.dec_expires - now) * NSEC_PER_SEC
@@ -797,7 +845,7 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
                list_for_each_entry_safe(v, vn, &vc->runnable_threads,
                                         arch.run_list) {
-                       kvmppc_core_deliver_interrupts(v);
+                       kvmppc_core_prepare_to_enter(v);
                        if (signal_pending(v->arch.run_task)) {
                                kvmppc_remove_runnable(vc, v);
                                v->stat.signal_exits++;
@@ -836,20 +884,26 @@ int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
                return -EINVAL;
        }
 
+       kvmppc_core_prepare_to_enter(vcpu);
+
        /* No need to go into the guest when all we'll do is come back out */
        if (signal_pending(current)) {
                run->exit_reason = KVM_EXIT_INTR;
                return -EINTR;
        }
 
-       /* On PPC970, check that we have an RMA region */
-       if (!vcpu->kvm->arch.rma && cpu_has_feature(CPU_FTR_ARCH_201))
-               return -EPERM;
+       /* On the first time here, set up VRMA or RMA */
+       if (!vcpu->kvm->arch.rma_setup_done) {
+               r = kvmppc_hv_setup_rma(vcpu);
+               if (r)
+                       return r;
+       }
 
        flush_fp_to_thread(current);
        flush_altivec_to_thread(current);
        flush_vsx_to_thread(current);
        vcpu->arch.wqp = &vcpu->arch.vcore->wq;
+       vcpu->arch.pgdir = current->mm->pgd;
 
        do {
                r = kvmppc_run_vcpu(run, vcpu);
@@ -857,7 +911,7 @@ int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
                if (run->exit_reason == KVM_EXIT_PAPR_HCALL &&
                    !(vcpu->arch.shregs.msr & MSR_PR)) {
                        r = kvmppc_pseries_do_hcall(vcpu);
-                       kvmppc_core_deliver_interrupts(vcpu);
+                       kvmppc_core_prepare_to_enter(vcpu);
                }
        } while (r == RESUME_GUEST);
        return r;
@@ -1001,7 +1055,7 @@ static inline int lpcr_rmls(unsigned long rma_size)
 
 static int kvm_rma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
-       struct kvmppc_rma_info *ri = vma->vm_file->private_data;
+       struct kvmppc_linear_info *ri = vma->vm_file->private_data;
        struct page *page;
 
        if (vmf->pgoff >= ri->npages)
@@ -1026,7 +1080,7 @@ static int kvm_rma_mmap(struct file *file, struct vm_area_struct *vma)
 
 static int kvm_rma_release(struct inode *inode, struct file *filp)
 {
-       struct kvmppc_rma_info *ri = filp->private_data;
+       struct kvmppc_linear_info *ri = filp->private_data;
 
        kvm_release_rma(ri);
        return 0;
@@ -1039,7 +1093,7 @@ static struct file_operations kvm_rma_fops = {
 
 long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *ret)
 {
-       struct kvmppc_rma_info *ri;
+       struct kvmppc_linear_info *ri;
        long fd;
 
        ri = kvm_alloc_rma();
@@ -1054,89 +1108,189 @@ long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *ret)
        return fd;
 }
 
-static struct page *hva_to_page(unsigned long addr)
+/*
+ * Get (and clear) the dirty memory log for a memory slot.
+ */
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 {
-       struct page *page[1];
-       int npages;
+       struct kvm_memory_slot *memslot;
+       int r;
+       unsigned long n;
 
-       might_sleep();
+       mutex_lock(&kvm->slots_lock);
 
-       npages = get_user_pages_fast(addr, 1, 1, page);
+       r = -EINVAL;
+       if (log->slot >= KVM_MEMORY_SLOTS)
+               goto out;
 
-       if (unlikely(npages != 1))
-               return 0;
+       memslot = id_to_memslot(kvm->memslots, log->slot);
+       r = -ENOENT;
+       if (!memslot->dirty_bitmap)
+               goto out;
+
+       n = kvm_dirty_bitmap_bytes(memslot);
+       memset(memslot->dirty_bitmap, 0, n);
+
+       r = kvmppc_hv_get_dirty_log(kvm, memslot);
+       if (r)
+               goto out;
 
-       return page[0];
+       r = -EFAULT;
+       if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
+               goto out;
+
+       r = 0;
+out:
+       mutex_unlock(&kvm->slots_lock);
+       return r;
+}
+
+static unsigned long slb_pgsize_encoding(unsigned long psize)
+{
+       unsigned long senc = 0;
+
+       if (psize > 0x1000) {
+               senc = SLB_VSID_L;
+               if (psize == 0x10000)
+                       senc |= SLB_VSID_LP_01;
+       }
+       return senc;
 }
 
 int kvmppc_core_prepare_memory_region(struct kvm *kvm,
                                struct kvm_userspace_memory_region *mem)
 {
-       unsigned long psize, porder;
-       unsigned long i, npages, totalpages;
-       unsigned long pg_ix;
-       struct kvmppc_pginfo *pginfo;
-       unsigned long hva;
-       struct kvmppc_rma_info *ri = NULL;
+       unsigned long npages;
+       unsigned long *phys;
+
+       /* Allocate a slot_phys array */
+       phys = kvm->arch.slot_phys[mem->slot];
+       if (!kvm->arch.using_mmu_notifiers && !phys) {
+               npages = mem->memory_size >> PAGE_SHIFT;
+               phys = vzalloc(npages * sizeof(unsigned long));
+               if (!phys)
+                       return -ENOMEM;
+               kvm->arch.slot_phys[mem->slot] = phys;
+               kvm->arch.slot_npages[mem->slot] = npages;
+       }
+
+       return 0;
+}
+
+static void unpin_slot(struct kvm *kvm, int slot_id)
+{
+       unsigned long *physp;
+       unsigned long j, npages, pfn;
        struct page *page;
 
-       /* For now, only allow 16MB pages */
-       porder = LARGE_PAGE_ORDER;
-       psize = 1ul << porder;
-       if ((mem->memory_size & (psize - 1)) ||
-           (mem->guest_phys_addr & (psize - 1))) {
-               pr_err("bad memory_size=%llx @ %llx\n",
-                      mem->memory_size, mem->guest_phys_addr);
-               return -EINVAL;
+       physp = kvm->arch.slot_phys[slot_id];
+       npages = kvm->arch.slot_npages[slot_id];
+       if (physp) {
+               spin_lock(&kvm->arch.slot_phys_lock);
+               for (j = 0; j < npages; j++) {
+                       if (!(physp[j] & KVMPPC_GOT_PAGE))
+                               continue;
+                       pfn = physp[j] >> PAGE_SHIFT;
+                       page = pfn_to_page(pfn);
+                       if (PageHuge(page))
+                               page = compound_head(page);
+                       SetPageDirty(page);
+                       put_page(page);
+               }
+               kvm->arch.slot_phys[slot_id] = NULL;
+               spin_unlock(&kvm->arch.slot_phys_lock);
+               vfree(physp);
        }
+}
 
-       npages = mem->memory_size >> porder;
-       totalpages = (mem->guest_phys_addr + mem->memory_size) >> porder;
+void kvmppc_core_commit_memory_region(struct kvm *kvm,
+                               struct kvm_userspace_memory_region *mem)
+{
+}
 
-       /* More memory than we have space to track? */
-       if (totalpages > (1ul << (MAX_MEM_ORDER - LARGE_PAGE_ORDER)))
-               return -EINVAL;
+static int kvmppc_hv_setup_rma(struct kvm_vcpu *vcpu)
+{
+       int err = 0;
+       struct kvm *kvm = vcpu->kvm;
+       struct kvmppc_linear_info *ri = NULL;
+       unsigned long hva;
+       struct kvm_memory_slot *memslot;
+       struct vm_area_struct *vma;
+       unsigned long lpcr, senc;
+       unsigned long psize, porder;
+       unsigned long rma_size;
+       unsigned long rmls;
+       unsigned long *physp;
+       unsigned long i, npages;
 
-       /* Do we already have an RMA registered? */
-       if (mem->guest_phys_addr == 0 && kvm->arch.rma)
-               return -EINVAL;
+       mutex_lock(&kvm->lock);
+       if (kvm->arch.rma_setup_done)
+               goto out;       /* another vcpu beat us to it */
 
-       if (totalpages > kvm->arch.ram_npages)
-               kvm->arch.ram_npages = totalpages;
+       /* Look up the memslot for guest physical address 0 */
+       memslot = gfn_to_memslot(kvm, 0);
+
+       /* We must have some memory at 0 by now */
+       err = -EINVAL;
+       if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
+               goto out;
+
+       /* Look up the VMA for the start of this memory slot */
+       hva = memslot->userspace_addr;
+       down_read(&current->mm->mmap_sem);
+       vma = find_vma(current->mm, hva);
+       if (!vma || vma->vm_start > hva || (vma->vm_flags & VM_IO))
+               goto up_out;
+
+       psize = vma_kernel_pagesize(vma);
+       porder = __ilog2(psize);
 
        /* Is this one of our preallocated RMAs? */
-       if (mem->guest_phys_addr == 0) {
-               struct vm_area_struct *vma;
-
-               down_read(&current->mm->mmap_sem);
-               vma = find_vma(current->mm, mem->userspace_addr);
-               if (vma && vma->vm_file &&
-                   vma->vm_file->f_op == &kvm_rma_fops &&
-                   mem->userspace_addr == vma->vm_start)
-                       ri = vma->vm_file->private_data;
-               up_read(&current->mm->mmap_sem);
-               if (!ri && cpu_has_feature(CPU_FTR_ARCH_201)) {
-                       pr_err("CPU requires an RMO\n");
-                       return -EINVAL;
+       if (vma->vm_file && vma->vm_file->f_op == &kvm_rma_fops &&
+           hva == vma->vm_start)
+               ri = vma->vm_file->private_data;
+
+       up_read(&current->mm->mmap_sem);
+
+       if (!ri) {
+               /* On POWER7, use VRMA; on PPC970, give up */
+               err = -EPERM;
+               if (cpu_has_feature(CPU_FTR_ARCH_201)) {
+                       pr_err("KVM: CPU requires an RMO\n");
+                       goto out;
                }
-       }
 
-       if (ri) {
-               unsigned long rma_size;
-               unsigned long lpcr;
-               long rmls;
+               /* We can handle 4k, 64k or 16M pages in the VRMA */
+               err = -EINVAL;
+               if (!(psize == 0x1000 || psize == 0x10000 ||
+                     psize == 0x1000000))
+                       goto out;
+
+               /* Update VRMASD field in the LPCR */
+               senc = slb_pgsize_encoding(psize);
+               kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T |
+                       (VRMA_VSID << SLB_VSID_SHIFT_1T);
+               lpcr = kvm->arch.lpcr & ~LPCR_VRMASD;
+               lpcr |= senc << (LPCR_VRMASD_SH - 4);
+               kvm->arch.lpcr = lpcr;
 
-               rma_size = ri->npages << PAGE_SHIFT;
-               if (rma_size > mem->memory_size)
-                       rma_size = mem->memory_size;
+               /* Create HPTEs in the hash page table for the VRMA */
+               kvmppc_map_vrma(vcpu, memslot, porder);
+
+       } else {
+               /* Set up to use an RMO region */
+               rma_size = ri->npages;
+               if (rma_size > memslot->npages)
+                       rma_size = memslot->npages;
+               rma_size <<= PAGE_SHIFT;
                rmls = lpcr_rmls(rma_size);
+               err = -EINVAL;
                if (rmls < 0) {
-                       pr_err("Can't use RMA of 0x%lx bytes\n", rma_size);
-                       return -EINVAL;
+                       pr_err("KVM: Can't use RMA of 0x%lx bytes\n", rma_size);
+                       goto out;
                }
                atomic_inc(&ri->use_count);
                kvm->arch.rma = ri;
-               kvm->arch.n_rma_pages = rma_size >> porder;
 
                /* Update LPCR and RMOR */
                lpcr = kvm->arch.lpcr;
@@ -1156,53 +1310,35 @@ int kvmppc_core_prepare_memory_region(struct kvm *kvm,
                        kvm->arch.rmor = kvm->arch.rma->base_pfn << PAGE_SHIFT;
                }
                kvm->arch.lpcr = lpcr;
-               pr_info("Using RMO at %lx size %lx (LPCR = %lx)\n",
+               pr_info("KVM: Using RMO at %lx size %lx (LPCR = %lx)\n",
                        ri->base_pfn << PAGE_SHIFT, rma_size, lpcr);
-       }
 
-       pg_ix = mem->guest_phys_addr >> porder;
-       pginfo = kvm->arch.ram_pginfo + pg_ix;
-       for (i = 0; i < npages; ++i, ++pg_ix) {
-               if (ri && pg_ix < kvm->arch.n_rma_pages) {
-                       pginfo[i].pfn = ri->base_pfn +
-                               (pg_ix << (porder - PAGE_SHIFT));
-                       continue;
-               }
-               hva = mem->userspace_addr + (i << porder);
-               page = hva_to_page(hva);
-               if (!page) {
-                       pr_err("oops, no pfn for hva %lx\n", hva);
-                       goto err;
-               }
-               /* Check it's a 16MB page */
-               if (!PageHead(page) ||
-                   compound_order(page) != (LARGE_PAGE_ORDER - PAGE_SHIFT)) {
-                       pr_err("page at %lx isn't 16MB (o=%d)\n",
-                              hva, compound_order(page));
-                       goto err;
-               }
-               pginfo[i].pfn = page_to_pfn(page);
+               /* Initialize phys addrs of pages in RMO */
+               npages = ri->npages;
+               porder = __ilog2(npages);
+               physp = kvm->arch.slot_phys[memslot->id];
+               spin_lock(&kvm->arch.slot_phys_lock);
+               for (i = 0; i < npages; ++i)
+                       physp[i] = ((ri->base_pfn + i) << PAGE_SHIFT) + porder;
+               spin_unlock(&kvm->arch.slot_phys_lock);
        }
 
-       return 0;
-
- err:
-       return -EINVAL;
-}
+       /* Order updates to kvm->arch.lpcr etc. vs. rma_setup_done */
+       smp_wmb();
+       kvm->arch.rma_setup_done = 1;
+       err = 0;
+ out:
+       mutex_unlock(&kvm->lock);
+       return err;
 
-void kvmppc_core_commit_memory_region(struct kvm *kvm,
-                               struct kvm_userspace_memory_region *mem)
-{
-       if (mem->guest_phys_addr == 0 && mem->memory_size != 0 &&
-           !kvm->arch.rma)
-               kvmppc_map_vrma(kvm, mem);
+ up_out:
+       up_read(&current->mm->mmap_sem);
+       goto out;
 }
 
 int kvmppc_core_init_vm(struct kvm *kvm)
 {
        long r;
-       unsigned long npages = 1ul << (MAX_MEM_ORDER - LARGE_PAGE_ORDER);
-       long err = -ENOMEM;
        unsigned long lpcr;
 
        /* Allocate hashed page table */
@@ -1212,19 +1348,7 @@ int kvmppc_core_init_vm(struct kvm *kvm)
 
        INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
 
-       kvm->arch.ram_pginfo = kzalloc(npages * sizeof(struct kvmppc_pginfo),
-                                      GFP_KERNEL);
-       if (!kvm->arch.ram_pginfo) {
-               pr_err("kvmppc_core_init_vm: couldn't alloc %lu bytes\n",
-                      npages * sizeof(struct kvmppc_pginfo));
-               goto out_free;
-       }
-
-       kvm->arch.ram_npages = 0;
-       kvm->arch.ram_psize = 1ul << LARGE_PAGE_ORDER;
-       kvm->arch.ram_porder = LARGE_PAGE_ORDER;
        kvm->arch.rma = NULL;
-       kvm->arch.n_rma_pages = 0;
 
        kvm->arch.host_sdr1 = mfspr(SPRN_SDR1);
 
@@ -1242,30 +1366,25 @@ int kvmppc_core_init_vm(struct kvm *kvm)
                kvm->arch.host_lpcr = lpcr = mfspr(SPRN_LPCR);
                lpcr &= LPCR_PECE | LPCR_LPES;
                lpcr |= (4UL << LPCR_DPFD_SH) | LPCR_HDICE |
-                       LPCR_VPM0 | LPCR_VRMA_L;
+                       LPCR_VPM0 | LPCR_VPM1;
+               kvm->arch.vrma_slb_v = SLB_VSID_B_1T |
+                       (VRMA_VSID << SLB_VSID_SHIFT_1T);
        }
        kvm->arch.lpcr = lpcr;
 
+       kvm->arch.using_mmu_notifiers = !!cpu_has_feature(CPU_FTR_ARCH_206);
+       spin_lock_init(&kvm->arch.slot_phys_lock);
        return 0;
-
- out_free:
-       kvmppc_free_hpt(kvm);
-       return err;
 }
 
 void kvmppc_core_destroy_vm(struct kvm *kvm)
 {
-       struct kvmppc_pginfo *pginfo;
        unsigned long i;
 
-       if (kvm->arch.ram_pginfo) {
-               pginfo = kvm->arch.ram_pginfo;
-               kvm->arch.ram_pginfo = NULL;
-               for (i = kvm->arch.n_rma_pages; i < kvm->arch.ram_npages; ++i)
-                       if (pginfo[i].pfn)
-                               put_page(pfn_to_page(pginfo[i].pfn));
-               kfree(pginfo);
-       }
+       if (!kvm->arch.using_mmu_notifiers)
+               for (i = 0; i < KVM_MEM_SLOTS_NUM; i++)
+                       unpin_slot(kvm, i);
+
        if (kvm->arch.rma) {
                kvm_release_rma(kvm->arch.rma);
                kvm->arch.rma = NULL;
index a795a13..bed1279 100644 (file)
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
 
+#define KVM_LINEAR_RMA         0
+#define KVM_LINEAR_HPT         1
+
+static void __init kvm_linear_init_one(ulong size, int count, int type);
+static struct kvmppc_linear_info *kvm_alloc_linear(int type);
+static void kvm_release_linear(struct kvmppc_linear_info *ri);
+
+/*************** RMA *************/
+
 /*
  * This maintains a list of RMAs (real mode areas) for KVM guests to use.
  * Each RMA has to be physically contiguous and of a size that the
 static unsigned long kvm_rma_size = 64 << 20;  /* 64MB */
 static unsigned long kvm_rma_count;
 
-static int __init early_parse_rma_size(char *p)
-{
-       if (!p)
-               return 1;
-
-       kvm_rma_size = memparse(p, &p);
-
-       return 0;
-}
-early_param("kvm_rma_size", early_parse_rma_size);
-
-static int __init early_parse_rma_count(char *p)
-{
-       if (!p)
-               return 1;
-
-       kvm_rma_count = simple_strtoul(p, NULL, 0);
-
-       return 0;
-}
-early_param("kvm_rma_count", early_parse_rma_count);
-
-static struct kvmppc_rma_info *rma_info;
-static LIST_HEAD(free_rmas);
-static DEFINE_SPINLOCK(rma_lock);
-
 /* Work out RMLS (real mode limit selector) field value for a given RMA size.
    Assumes POWER7 or PPC970. */
 static inline int lpcr_rmls(unsigned long rma_size)
@@ -81,45 +64,106 @@ static inline int lpcr_rmls(unsigned long rma_size)
        }
 }
 
+static int __init early_parse_rma_size(char *p)
+{
+       if (!p)
+               return 1;
+
+       kvm_rma_size = memparse(p, &p);
+
+       return 0;
+}
+early_param("kvm_rma_size", early_parse_rma_size);
+
+static int __init early_parse_rma_count(char *p)
+{
+       if (!p)
+               return 1;
+
+       kvm_rma_count = simple_strtoul(p, NULL, 0);
+
+       return 0;
+}
+early_param("kvm_rma_count", early_parse_rma_count);
+
+struct kvmppc_linear_info *kvm_alloc_rma(void)
+{
+       return kvm_alloc_linear(KVM_LINEAR_RMA);
+}
+EXPORT_SYMBOL_GPL(kvm_alloc_rma);
+
+void kvm_release_rma(struct kvmppc_linear_info *ri)
+{
+       kvm_release_linear(ri);
+}
+EXPORT_SYMBOL_GPL(kvm_release_rma);
+
+/*************** HPT *************/
+
 /*
- * Called at boot time while the bootmem allocator is active,
- * to allocate contiguous physical memory for the real memory
- * areas for guests.
+ * This maintains a list of big linear HPT tables that contain the GVA->HPA
+ * memory mappings. If we don't reserve those early on, we might not be able
+ * to get a big (usually 16MB) linear memory region from the kernel anymore.
  */
-void __init kvm_rma_init(void)
+
+static unsigned long kvm_hpt_count;
+
+static int __init early_parse_hpt_count(char *p)
+{
+       if (!p)
+               return 1;
+
+       kvm_hpt_count = simple_strtoul(p, NULL, 0);
+
+       return 0;
+}
+early_param("kvm_hpt_count", early_parse_hpt_count);
+
+struct kvmppc_linear_info *kvm_alloc_hpt(void)
+{
+       return kvm_alloc_linear(KVM_LINEAR_HPT);
+}
+EXPORT_SYMBOL_GPL(kvm_alloc_hpt);
+
+void kvm_release_hpt(struct kvmppc_linear_info *li)
+{
+       kvm_release_linear(li);
+}
+EXPORT_SYMBOL_GPL(kvm_release_hpt);
+
+/*************** generic *************/
+
+static LIST_HEAD(free_linears);
+static DEFINE_SPINLOCK(linear_lock);
+
+static void __init kvm_linear_init_one(ulong size, int count, int type)
 {
        unsigned long i;
        unsigned long j, npages;
-       void *rma;
+       void *linear;
        struct page *pg;
+       const char *typestr;
+       struct kvmppc_linear_info *linear_info;
 
-       /* Only do this on PPC970 in HV mode */
-       if (!cpu_has_feature(CPU_FTR_HVMODE) ||
-           !cpu_has_feature(CPU_FTR_ARCH_201))
-               return;
-
-       if (!kvm_rma_size || !kvm_rma_count)
+       if (!count)
                return;
 
-       /* Check that the requested size is one supported in hardware */
-       if (lpcr_rmls(kvm_rma_size) < 0) {
-               pr_err("RMA size of 0x%lx not supported\n", kvm_rma_size);
-               return;
-       }
-
-       npages = kvm_rma_size >> PAGE_SHIFT;
-       rma_info = alloc_bootmem(kvm_rma_count * sizeof(struct kvmppc_rma_info));
-       for (i = 0; i < kvm_rma_count; ++i) {
-               rma = alloc_bootmem_align(kvm_rma_size, kvm_rma_size);
-               pr_info("Allocated KVM RMA at %p (%ld MB)\n", rma,
-                       kvm_rma_size >> 20);
-               rma_info[i].base_virt = rma;
-               rma_info[i].base_pfn = __pa(rma) >> PAGE_SHIFT;
-               rma_info[i].npages = npages;
-               list_add_tail(&rma_info[i].list, &free_rmas);
-               atomic_set(&rma_info[i].use_count, 0);
-
-               pg = pfn_to_page(rma_info[i].base_pfn);
+       typestr = (type == KVM_LINEAR_RMA) ? "RMA" : "HPT";
+
+       npages = size >> PAGE_SHIFT;
+       linear_info = alloc_bootmem(count * sizeof(struct kvmppc_linear_info));
+       for (i = 0; i < count; ++i) {
+               linear = alloc_bootmem_align(size, size);
+               pr_info("Allocated KVM %s at %p (%ld MB)\n", typestr, linear,
+                       size >> 20);
+               linear_info[i].base_virt = linear;
+               linear_info[i].base_pfn = __pa(linear) >> PAGE_SHIFT;
+               linear_info[i].npages = npages;
+               linear_info[i].type = type;
+               list_add_tail(&linear_info[i].list, &free_linears);
+               atomic_set(&linear_info[i].use_count, 0);
+
+               pg = pfn_to_page(linear_info[i].base_pfn);
                for (j = 0; j < npages; ++j) {
                        atomic_inc(&pg->_count);
                        ++pg;
@@ -127,30 +171,59 @@ void __init kvm_rma_init(void)
        }
 }
 
-struct kvmppc_rma_info *kvm_alloc_rma(void)
+static struct kvmppc_linear_info *kvm_alloc_linear(int type)
 {
-       struct kvmppc_rma_info *ri;
+       struct kvmppc_linear_info *ri;
 
        ri = NULL;
-       spin_lock(&rma_lock);
-       if (!list_empty(&free_rmas)) {
-               ri = list_first_entry(&free_rmas, struct kvmppc_rma_info, list);
+       spin_lock(&linear_lock);
+       list_for_each_entry(ri, &free_linears, list) {
+               if (ri->type != type)
+                       continue;
+
                list_del(&ri->list);
                atomic_inc(&ri->use_count);
+               break;
        }
-       spin_unlock(&rma_lock);
+       spin_unlock(&linear_lock);
+       memset(ri->base_virt, 0, ri->npages << PAGE_SHIFT);
        return ri;
 }
-EXPORT_SYMBOL_GPL(kvm_alloc_rma);
 
-void kvm_release_rma(struct kvmppc_rma_info *ri)
+static void kvm_release_linear(struct kvmppc_linear_info *ri)
 {
        if (atomic_dec_and_test(&ri->use_count)) {
-               spin_lock(&rma_lock);
-               list_add_tail(&ri->list, &free_rmas);
-               spin_unlock(&rma_lock);
+               spin_lock(&linear_lock);
+               list_add_tail(&ri->list, &free_linears);
+               spin_unlock(&linear_lock);
 
        }
 }
-EXPORT_SYMBOL_GPL(kvm_release_rma);
 
+/*
+ * Called at boot time while the bootmem allocator is active,
+ * to allocate contiguous physical memory for the hash page
+ * tables for guests.
+ */
+void __init kvm_linear_init(void)
+{
+       /* HPT */
+       kvm_linear_init_one(1 << HPT_ORDER, kvm_hpt_count, KVM_LINEAR_HPT);
+
+       /* RMA */
+       /* Only do this on PPC970 in HV mode */
+       if (!cpu_has_feature(CPU_FTR_HVMODE) ||
+           !cpu_has_feature(CPU_FTR_ARCH_201))
+               return;
+
+       if (!kvm_rma_size || !kvm_rma_count)
+               return;
+
+       /* Check that the requested size is one supported in hardware */
+       if (lpcr_rmls(kvm_rma_size) < 0) {
+               pr_err("RMA size of 0x%lx not supported\n", kvm_rma_size);
+               return;
+       }
+
+       kvm_linear_init_one(kvm_rma_size, kvm_rma_count, KVM_LINEAR_RMA);
+}
index bacb0cf..def880a 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/hugetlb.h>
+#include <linux/module.h>
 
 #include <asm/tlbflush.h>
 #include <asm/kvm_ppc.h>
 #include <asm/synch.h>
 #include <asm/ppc-opcode.h>
 
-/* For now use fixed-size 16MB page table */
-#define HPT_ORDER      24
-#define HPT_NPTEG      (1ul << (HPT_ORDER - 7))        /* 128B per pteg */
-#define HPT_HASH_MASK  (HPT_NPTEG - 1)
+/* Translate address of a vmalloc'd thing to a linear map address */
+static void *real_vmalloc_addr(void *x)
+{
+       unsigned long addr = (unsigned long) x;
+       pte_t *p;
 
-#define HPTE_V_HVLOCK  0x40UL
+       p = find_linux_pte(swapper_pg_dir, addr);
+       if (!p || !pte_present(*p))
+               return NULL;
+       /* assume we don't have huge pages in vmalloc space... */
+       addr = (pte_pfn(*p) << PAGE_SHIFT) | (addr & ~PAGE_MASK);
+       return __va(addr);
+}
 
-static inline long lock_hpte(unsigned long *hpte, unsigned long bits)
+/*
+ * Add this HPTE into the chain for the real page.
+ * Must be called with the chain locked; it unlocks the chain.
+ */
+void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev,
+                            unsigned long *rmap, long pte_index, int realmode)
 {
-       unsigned long tmp, old;
+       struct revmap_entry *head, *tail;
+       unsigned long i;
 
-       asm volatile("  ldarx   %0,0,%2\n"
-                    "  and.    %1,%0,%3\n"
-                    "  bne     2f\n"
-                    "  ori     %0,%0,%4\n"
-                    "  stdcx.  %0,0,%2\n"
-                    "  beq+    2f\n"
-                    "  li      %1,%3\n"
-                    "2:        isync"
-                    : "=&r" (tmp), "=&r" (old)
-                    : "r" (hpte), "r" (bits), "i" (HPTE_V_HVLOCK)
-                    : "cc", "memory");
-       return old == 0;
+       if (*rmap & KVMPPC_RMAP_PRESENT) {
+               i = *rmap & KVMPPC_RMAP_INDEX;
+               head = &kvm->arch.revmap[i];
+               if (realmode)
+                       head = real_vmalloc_addr(head);
+               tail = &kvm->arch.revmap[head->back];
+               if (realmode)
+                       tail = real_vmalloc_addr(tail);
+               rev->forw = i;
+               rev->back = head->back;
+               tail->forw = pte_index;
+               head->back = pte_index;
+       } else {
+               rev->forw = rev->back = pte_index;
+               i = pte_index;
+       }
+       smp_wmb();
+       *rmap = i | KVMPPC_RMAP_REFERENCED | KVMPPC_RMAP_PRESENT; /* unlock */
+}
+EXPORT_SYMBOL_GPL(kvmppc_add_revmap_chain);
+
+/* Remove this HPTE from the chain for a real page */
+static void remove_revmap_chain(struct kvm *kvm, long pte_index,
+                               struct revmap_entry *rev,
+                               unsigned long hpte_v, unsigned long hpte_r)
+{
+       struct revmap_entry *next, *prev;
+       unsigned long gfn, ptel, head;
+       struct kvm_memory_slot *memslot;
+       unsigned long *rmap;
+       unsigned long rcbits;
+
+       rcbits = hpte_r & (HPTE_R_R | HPTE_R_C);
+       ptel = rev->guest_rpte |= rcbits;
+       gfn = hpte_rpn(ptel, hpte_page_size(hpte_v, ptel));
+       memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+       if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
+               return;
+
+       rmap = real_vmalloc_addr(&memslot->rmap[gfn - memslot->base_gfn]);
+       lock_rmap(rmap);
+
+       head = *rmap & KVMPPC_RMAP_INDEX;
+       next = real_vmalloc_addr(&kvm->arch.revmap[rev->forw]);
+       prev = real_vmalloc_addr(&kvm->arch.revmap[rev->back]);
+       next->back = rev->back;
+       prev->forw = rev->forw;
+       if (head == pte_index) {
+               head = rev->forw;
+               if (head == pte_index)
+                       *rmap &= ~(KVMPPC_RMAP_PRESENT | KVMPPC_RMAP_INDEX);
+               else
+                       *rmap = (*rmap & ~KVMPPC_RMAP_INDEX) | head;
+       }
+       *rmap |= rcbits << KVMPPC_RMAP_RC_SHIFT;
+       unlock_rmap(rmap);
+}
+
+static pte_t lookup_linux_pte(struct kvm_vcpu *vcpu, unsigned long hva,
+                             int writing, unsigned long *pte_sizep)
+{
+       pte_t *ptep;
+       unsigned long ps = *pte_sizep;
+       unsigned int shift;
+
+       ptep = find_linux_pte_or_hugepte(vcpu->arch.pgdir, hva, &shift);
+       if (!ptep)
+               return __pte(0);
+       if (shift)
+               *pte_sizep = 1ul << shift;
+       else
+               *pte_sizep = PAGE_SIZE;
+       if (ps > *pte_sizep)
+               return __pte(0);
+       if (!pte_present(*ptep))
+               return __pte(0);
+       return kvmppc_read_update_linux_pte(ptep, writing);
+}
+
+static inline void unlock_hpte(unsigned long *hpte, unsigned long hpte_v)
+{
+       asm volatile(PPC_RELEASE_BARRIER "" : : : "memory");
+       hpte[0] = hpte_v;
 }
 
 long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
                    long pte_index, unsigned long pteh, unsigned long ptel)
 {
-       unsigned long porder;
        struct kvm *kvm = vcpu->kvm;
-       unsigned long i, lpn, pa;
+       unsigned long i, pa, gpa, gfn, psize;
+       unsigned long slot_fn, hva;
        unsigned long *hpte;
+       struct revmap_entry *rev;
+       unsigned long g_ptel = ptel;
+       struct kvm_memory_slot *memslot;
+       unsigned long *physp, pte_size;
+       unsigned long is_io;
+       unsigned long *rmap;
+       pte_t pte;
+       unsigned int writing;
+       unsigned long mmu_seq;
+       unsigned long rcbits;
+       bool realmode = vcpu->arch.vcore->vcore_state == VCORE_RUNNING;
 
-       /* only handle 4k, 64k and 16M pages for now */
-       porder = 12;
-       if (pteh & HPTE_V_LARGE) {
-               if (cpu_has_feature(CPU_FTR_ARCH_206) &&
-                   (ptel & 0xf000) == 0x1000) {
-                       /* 64k page */
-                       porder = 16;
-               } else if ((ptel & 0xff000) == 0) {
-                       /* 16M page */
-                       porder = 24;
-                       /* lowest AVA bit must be 0 for 16M pages */
-                       if (pteh & 0x80)
-                               return H_PARAMETER;
-               } else
+       psize = hpte_page_size(pteh, ptel);
+       if (!psize)
+               return H_PARAMETER;
+       writing = hpte_is_writable(ptel);
+       pteh &= ~(HPTE_V_HVLOCK | HPTE_V_ABSENT | HPTE_V_VALID);
+
+       /* used later to detect if we might have been invalidated */
+       mmu_seq = kvm->mmu_notifier_seq;
+       smp_rmb();
+
+       /* Find the memslot (if any) for this address */
+       gpa = (ptel & HPTE_R_RPN) & ~(psize - 1);
+       gfn = gpa >> PAGE_SHIFT;
+       memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
+       pa = 0;
+       is_io = ~0ul;
+       rmap = NULL;
+       if (!(memslot && !(memslot->flags & KVM_MEMSLOT_INVALID))) {
+               /* PPC970 can't do emulated MMIO */
+               if (!cpu_has_feature(CPU_FTR_ARCH_206))
                        return H_PARAMETER;
+               /* Emulated MMIO - mark this with key=31 */
+               pteh |= HPTE_V_ABSENT;
+               ptel |= HPTE_R_KEY_HI | HPTE_R_KEY_LO;
+               goto do_insert;
        }
-       lpn = (ptel & HPTE_R_RPN) >> kvm->arch.ram_porder;
-       if (lpn >= kvm->arch.ram_npages || porder > kvm->arch.ram_porder)
-               return H_PARAMETER;
-       pa = kvm->arch.ram_pginfo[lpn].pfn << PAGE_SHIFT;
-       if (!pa)
+
+       /* Check if the requested page fits entirely in the memslot. */
+       if (!slot_is_aligned(memslot, psize))
                return H_PARAMETER;
-       /* Check WIMG */
-       if ((ptel & HPTE_R_WIMG) != HPTE_R_M &&
-           (ptel & HPTE_R_WIMG) != (HPTE_R_W | HPTE_R_I | HPTE_R_M))
+       slot_fn = gfn - memslot->base_gfn;
+       rmap = &memslot->rmap[slot_fn];
+
+       if (!kvm->arch.using_mmu_notifiers) {
+               physp = kvm->arch.slot_phys[memslot->id];
+               if (!physp)
+                       return H_PARAMETER;
+               physp += slot_fn;
+               if (realmode)
+                       physp = real_vmalloc_addr(physp);
+               pa = *physp;
+               if (!pa)
+                       return H_TOO_HARD;
+               is_io = pa & (HPTE_R_I | HPTE_R_W);
+               pte_size = PAGE_SIZE << (pa & KVMPPC_PAGE_ORDER_MASK);
+               pa &= PAGE_MASK;
+       } else {
+               /* Translate to host virtual address */
+               hva = gfn_to_hva_memslot(memslot, gfn);
+
+               /* Look up the Linux PTE for the backing page */
+               pte_size = psize;
+               pte = lookup_linux_pte(vcpu, hva, writing, &pte_size);
+               if (pte_present(pte)) {
+                       if (writing && !pte_write(pte))
+                               /* make the actual HPTE be read-only */
+                               ptel = hpte_make_readonly(ptel);
+                       is_io = hpte_cache_bits(pte_val(pte));
+                       pa = pte_pfn(pte) << PAGE_SHIFT;
+               }
+       }
+       if (pte_size < psize)
                return H_PARAMETER;
-       pteh &= ~0x60UL;
-       ptel &= ~(HPTE_R_PP0 - kvm->arch.ram_psize);
+       if (pa && pte_size > psize)
+               pa |= gpa & (pte_size - 1);
+
+       ptel &= ~(HPTE_R_PP0 - psize);
        ptel |= pa;
-       if (pte_index >= (HPT_NPTEG << 3))
+
+       if (pa)
+               pteh |= HPTE_V_VALID;
+       else
+               pteh |= HPTE_V_ABSENT;
+
+       /* Check WIMG */
+       if (is_io != ~0ul && !hpte_cache_flags_ok(ptel, is_io)) {
+               if (is_io)
+                       return H_PARAMETER;
+               /*
+                * Allow guest to map emulated device memory as
+                * uncacheable, but actually make it cacheable.
+                */
+               ptel &= ~(HPTE_R_W|HPTE_R_I|HPTE_R_G);
+               ptel |= HPTE_R_M;
+       }
+
+       /* Find and lock the HPTEG slot to use */
+ do_insert:
+       if (pte_index >= HPT_NPTE)
                return H_PARAMETER;
        if (likely((flags & H_EXACT) == 0)) {
                pte_index &= ~7UL;
                hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
-               for (i = 0; ; ++i) {
-                       if (i == 8)
-                               return H_PTEG_FULL;
+               for (i = 0; i < 8; ++i) {
                        if ((*hpte & HPTE_V_VALID) == 0 &&
-                           lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID))
+                           try_lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID |
+                                         HPTE_V_ABSENT))
                                break;
                        hpte += 2;
                }
+               if (i == 8) {
+                       /*
+                        * Since try_lock_hpte doesn't retry (not even stdcx.
+                        * failures), it could be that there is a free slot
+                        * but we transiently failed to lock it.  Try again,
+                        * actually locking each slot and checking it.
+                        */
+                       hpte -= 16;
+                       for (i = 0; i < 8; ++i) {
+                               while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
+                                       cpu_relax();
+                               if (!(*hpte & (HPTE_V_VALID | HPTE_V_ABSENT)))
+                                       break;
+                               *hpte &= ~HPTE_V_HVLOCK;
+                               hpte += 2;
+                       }
+                       if (i == 8)
+                               return H_PTEG_FULL;
+               }
+               pte_index += i;
        } else {
-               i = 0;
                hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
-               if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID))
-                       return H_PTEG_FULL;
+               if (!try_lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID |
+                                  HPTE_V_ABSENT)) {
+                       /* Lock the slot and check again */
+                       while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
+                               cpu_relax();
+                       if (*hpte & (HPTE_V_VALID | HPTE_V_ABSENT)) {
+                               *hpte &= ~HPTE_V_HVLOCK;
+                               return H_PTEG_FULL;
+                       }
+               }
        }
+
+       /* Save away the guest's idea of the second HPTE dword */
+       rev = &kvm->arch.revmap[pte_index];
+       if (realmode)
+               rev = real_vmalloc_addr(rev);
+       if (rev)
+               rev->guest_rpte = g_ptel;
+
+       /* Link HPTE into reverse-map chain */
+       if (pteh & HPTE_V_VALID) {
+               if (realmode)
+                       rmap = real_vmalloc_addr(rmap);
+               lock_rmap(rmap);
+               /* Check for pending invalidations under the rmap chain lock */
+               if (kvm->arch.using_mmu_notifiers &&
+                   mmu_notifier_retry(vcpu, mmu_seq)) {
+                       /* inval in progress, write a non-present HPTE */
+                       pteh |= HPTE_V_ABSENT;
+                       pteh &= ~HPTE_V_VALID;
+                       unlock_rmap(rmap);
+               } else {
+                       kvmppc_add_revmap_chain(kvm, rev, rmap, pte_index,
+                                               realmode);
+                       /* Only set R/C in real HPTE if already set in *rmap */
+                       rcbits = *rmap >> KVMPPC_RMAP_RC_SHIFT;
+                       ptel &= rcbits | ~(HPTE_R_R | HPTE_R_C);
+               }
+       }
+
        hpte[1] = ptel;
+
+       /* Write the first HPTE dword, unlocking the HPTE and making it valid */
        eieio();
        hpte[0] = pteh;
        asm volatile("ptesync" : : : "memory");
-       atomic_inc(&kvm->arch.ram_pginfo[lpn].refcnt);
-       vcpu->arch.gpr[4] = pte_index + i;
+
+       vcpu->arch.gpr[4] = pte_index;
        return H_SUCCESS;
 }
+EXPORT_SYMBOL_GPL(kvmppc_h_enter);
 
 #define LOCK_TOKEN     (*(u32 *)(&get_paca()->lock_token))
 
@@ -137,37 +350,46 @@ long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags,
        struct kvm *kvm = vcpu->kvm;
        unsigned long *hpte;
        unsigned long v, r, rb;
+       struct revmap_entry *rev;
 
-       if (pte_index >= (HPT_NPTEG << 3))
+       if (pte_index >= HPT_NPTE)
                return H_PARAMETER;
        hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
-       while (!lock_hpte(hpte, HPTE_V_HVLOCK))
+       while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
                cpu_relax();
-       if ((hpte[0] & HPTE_V_VALID) == 0 ||
+       if ((hpte[0] & (HPTE_V_ABSENT | HPTE_V_VALID)) == 0 ||
            ((flags & H_AVPN) && (hpte[0] & ~0x7fUL) != avpn) ||
            ((flags & H_ANDCOND) && (hpte[0] & avpn) != 0)) {
                hpte[0] &= ~HPTE_V_HVLOCK;
                return H_NOT_FOUND;
        }
-       if (atomic_read(&kvm->online_vcpus) == 1)
-               flags |= H_LOCAL;
-       vcpu->arch.gpr[4] = v = hpte[0] & ~HPTE_V_HVLOCK;
-       vcpu->arch.gpr[5] = r = hpte[1];
-       rb = compute_tlbie_rb(v, r, pte_index);
-       hpte[0] = 0;
-       if (!(flags & H_LOCAL)) {
-               while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
-                       cpu_relax();
-               asm volatile("ptesync" : : : "memory");
-               asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
-                            : : "r" (rb), "r" (kvm->arch.lpid));
-               asm volatile("ptesync" : : : "memory");
-               kvm->arch.tlbie_lock = 0;
-       } else {
-               asm volatile("ptesync" : : : "memory");
-               asm volatile("tlbiel %0" : : "r" (rb));
-               asm volatile("ptesync" : : : "memory");
+
+       rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
+       v = hpte[0] & ~HPTE_V_HVLOCK;
+       if (v & HPTE_V_VALID) {
+               hpte[0] &= ~HPTE_V_VALID;
+               rb = compute_tlbie_rb(v, hpte[1], pte_index);
+               if (!(flags & H_LOCAL) && atomic_read(&kvm->online_vcpus) > 1) {
+                       while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
+                               cpu_relax();
+                       asm volatile("ptesync" : : : "memory");
+                       asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
+                                    : : "r" (rb), "r" (kvm->arch.lpid));
+                       asm volatile("ptesync" : : : "memory");
+                       kvm->arch.tlbie_lock = 0;
+               } else {
+                       asm volatile("ptesync" : : : "memory");
+                       asm volatile("tlbiel %0" : : "r" (rb));
+                       asm volatile("ptesync" : : : "memory");
+               }
+               /* Read PTE low word after tlbie to get final R/C values */
+               remove_revmap_chain(kvm, pte_index, rev, v, hpte[1]);
        }
+       r = rev->guest_rpte;
+       unlock_hpte(hpte, 0);
+
+       vcpu->arch.gpr[4] = v;
+       vcpu->arch.gpr[5] = r;
        return H_SUCCESS;
 }
 
@@ -175,78 +397,117 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu)
 {
        struct kvm *kvm = vcpu->kvm;
        unsigned long *args = &vcpu->arch.gpr[4];
-       unsigned long *hp, tlbrb[4];
-       long int i, found;
-       long int n_inval = 0;
-       unsigned long flags, req, pte_index;
+       unsigned long *hp, *hptes[4], tlbrb[4];
+       long int i, j, k, n, found, indexes[4];
+       unsigned long flags, req, pte_index, rcbits;
        long int local = 0;
        long int ret = H_SUCCESS;
+       struct revmap_entry *rev, *revs[4];
 
        if (atomic_read(&kvm->online_vcpus) == 1)
                local = 1;
-       for (i = 0; i < 4; ++i) {
-               pte_index = args[i * 2];
-               flags = pte_index >> 56;
-               pte_index &= ((1ul << 56) - 1);
-               req = flags >> 6;
-               flags &= 3;
-               if (req == 3)
-                       break;
-               if (req != 1 || flags == 3 ||
-                   pte_index >= (HPT_NPTEG << 3)) {
-                       /* parameter error */
-                       args[i * 2] = ((0xa0 | flags) << 56) + pte_index;
-                       ret = H_PARAMETER;
-                       break;
-               }
-               hp = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
-               while (!lock_hpte(hp, HPTE_V_HVLOCK))
-                       cpu_relax();
-               found = 0;
-               if (hp[0] & HPTE_V_VALID) {
-                       switch (flags & 3) {
-                       case 0:         /* absolute */
-                               found = 1;
+       for (i = 0; i < 4 && ret == H_SUCCESS; ) {
+               n = 0;
+               for (; i < 4; ++i) {
+                       j = i * 2;
+                       pte_index = args[j];
+                       flags = pte_index >> 56;
+                       pte_index &= ((1ul << 56) - 1);
+                       req = flags >> 6;
+                       flags &= 3;
+                       if (req == 3) {         /* no more requests */
+                               i = 4;
                                break;
-                       case 1:         /* andcond */
-                               if (!(hp[0] & args[i * 2 + 1]))
-                                       found = 1;
+                       }
+                       if (req != 1 || flags == 3 || pte_index >= HPT_NPTE) {
+                               /* parameter error */
+                               args[j] = ((0xa0 | flags) << 56) + pte_index;
+                               ret = H_PARAMETER;
                                break;
-                       case 2:         /* AVPN */
-                               if ((hp[0] & ~0x7fUL) == args[i * 2 + 1])
+                       }
+                       hp = (unsigned long *)
+                               (kvm->arch.hpt_virt + (pte_index << 4));
+                       /* to avoid deadlock, don't spin except for first */
+                       if (!try_lock_hpte(hp, HPTE_V_HVLOCK)) {
+                               if (n)
+                                       break;
+                               while (!try_lock_hpte(hp, HPTE_V_HVLOCK))
+                                       cpu_relax();
+                       }
+                       found = 0;
+                       if (hp[0] & (HPTE_V_ABSENT | HPTE_V_VALID)) {
+                               switch (flags & 3) {
+                               case 0:         /* absolute */
                                        found = 1;
-                               break;
+                                       break;
+                               case 1:         /* andcond */
+                                       if (!(hp[0] & args[j + 1]))
+                                               found = 1;
+                                       break;
+                               case 2:         /* AVPN */
+                                       if ((hp[0] & ~0x7fUL) == args[j + 1])
+                                               found = 1;
+                                       break;
+                               }
+                       }
+                       if (!found) {
+                               hp[0] &= ~HPTE_V_HVLOCK;
+                               args[j] = ((0x90 | flags) << 56) + pte_index;
+                               continue;
                        }
+
+                       args[j] = ((0x80 | flags) << 56) + pte_index;
+                       rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
+
+                       if (!(hp[0] & HPTE_V_VALID)) {
+                               /* insert R and C bits from PTE */
+                               rcbits = rev->guest_rpte & (HPTE_R_R|HPTE_R_C);
+                               args[j] |= rcbits << (56 - 5);
+                               continue;
+                       }
+
+                       hp[0] &= ~HPTE_V_VALID;         /* leave it locked */
+                       tlbrb[n] = compute_tlbie_rb(hp[0], hp[1], pte_index);
+                       indexes[n] = j;
+                       hptes[n] = hp;
+                       revs[n] = rev;
+                       ++n;
+               }
+
+               if (!n)
+                       break;
+
+               /* Now that we've collected a batch, do the tlbies */
+               if (!local) {
+                       while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
+                               cpu_relax();
+                       asm volatile("ptesync" : : : "memory");
+                       for (k = 0; k < n; ++k)
+                               asm volatile(PPC_TLBIE(%1,%0) : :
+                                            "r" (tlbrb[k]),
+                                            "r" (kvm->arch.lpid));
+                       asm volatile("eieio; tlbsync; ptesync" : : : "memory");
+                       kvm->arch.tlbie_lock = 0;
+               } else {
+                       asm volatile("ptesync" : : : "memory");
+                       for (k = 0; k < n; ++k)
+                               asm volatile("tlbiel %0" : : "r" (tlbrb[k]));
+                       asm volatile("ptesync" : : : "memory");
                }
-               if (!found) {
-                       hp[0] &= ~HPTE_V_HVLOCK;
-                       args[i * 2] = ((0x90 | flags) << 56) + pte_index;
-                       continue;
+
+               /* Read PTE low words after tlbie to get final R/C values */
+               for (k = 0; k < n; ++k) {
+                       j = indexes[k];
+                       pte_index = args[j] & ((1ul << 56) - 1);
+                       hp = hptes[k];
+                       rev = revs[k];
+                       remove_revmap_chain(kvm, pte_index, rev, hp[0], hp[1]);
+                       rcbits = rev->guest_rpte & (HPTE_R_R|HPTE_R_C);
+                       args[j] |= rcbits << (56 - 5);
+                       hp[0] = 0;
                }
-               /* insert R and C bits from PTE */
-               flags |= (hp[1] >> 5) & 0x0c;
-               args[i * 2] = ((0x80 | flags) << 56) + pte_index;
-               tlbrb[n_inval++] = compute_tlbie_rb(hp[0], hp[1], pte_index);
-               hp[0] = 0;
-       }
-       if (n_inval == 0)
-               return ret;
-
-       if (!local) {
-               while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
-                       cpu_relax();
-               asm volatile("ptesync" : : : "memory");
-               for (i = 0; i < n_inval; ++i)
-                       asm volatile(PPC_TLBIE(%1,%0)
-                                    : : "r" (tlbrb[i]), "r" (kvm->arch.lpid));
-               asm volatile("eieio; tlbsync; ptesync" : : : "memory");
-               kvm->arch.tlbie_lock = 0;
-       } else {
-               asm volatile("ptesync" : : : "memory");
-               for (i = 0; i < n_inval; ++i)
-                       asm volatile("tlbiel %0" : : "r" (tlbrb[i]));
-               asm volatile("ptesync" : : : "memory");
        }
+
        return ret;
 }
 
@@ -256,40 +517,55 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
 {
        struct kvm *kvm = vcpu->kvm;
        unsigned long *hpte;
-       unsigned long v, r, rb;
+       struct revmap_entry *rev;
+       unsigned long v, r, rb, mask, bits;
 
-       if (pte_index >= (HPT_NPTEG << 3))
+       if (pte_index >= HPT_NPTE)
                return H_PARAMETER;
+
        hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
-       while (!lock_hpte(hpte, HPTE_V_HVLOCK))
+       while (!try_lock_hpte(hpte, HPTE_V_HVLOCK))
                cpu_relax();
-       if ((hpte[0] & HPTE_V_VALID) == 0 ||
+       if ((hpte[0] & (HPTE_V_ABSENT | HPTE_V_VALID)) == 0 ||
            ((flags & H_AVPN) && (hpte[0] & ~0x7fUL) != avpn)) {
                hpte[0] &= ~HPTE_V_HVLOCK;
                return H_NOT_FOUND;
        }
+
        if (atomic_read(&kvm->online_vcpus) == 1)
                flags |= H_LOCAL;
        v = hpte[0];
-       r = hpte[1] & ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
-                       HPTE_R_KEY_HI | HPTE_R_KEY_LO);
-       r |= (flags << 55) & HPTE_R_PP0;
-       r |= (flags << 48) & HPTE_R_KEY_HI;
-       r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
-       rb = compute_tlbie_rb(v, r, pte_index);
-       hpte[0] = v & ~HPTE_V_VALID;
-       if (!(flags & H_LOCAL)) {
-               while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
-                       cpu_relax();
-               asm volatile("ptesync" : : : "memory");
-               asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
-                            : : "r" (rb), "r" (kvm->arch.lpid));
-               asm volatile("ptesync" : : : "memory");
-               kvm->arch.tlbie_lock = 0;
-       } else {
-               asm volatile("ptesync" : : : "memory");
-               asm volatile("tlbiel %0" : : "r" (rb));
-               asm volatile("ptesync" : : : "memory");
+       bits = (flags << 55) & HPTE_R_PP0;
+       bits |= (flags << 48) & HPTE_R_KEY_HI;
+       bits |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
+
+       /* Update guest view of 2nd HPTE dword */
+       mask = HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
+               HPTE_R_KEY_HI | HPTE_R_KEY_LO;
+       rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
+       if (rev) {
+               r = (rev->guest_rpte & ~mask) | bits;
+               rev->guest_rpte = r;
+       }
+       r = (hpte[1] & ~mask) | bits;
+
+       /* Update HPTE */
+       if (v & HPTE_V_VALID) {
+               rb = compute_tlbie_rb(v, r, pte_index);
+               hpte[0] = v & ~HPTE_V_VALID;
+               if (!(flags & H_LOCAL)) {
+                       while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
+                               cpu_relax();
+                       asm volatile("ptesync" : : : "memory");
+                       asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
+                                    : : "r" (rb), "r" (kvm->arch.lpid));
+                       asm volatile("ptesync" : : : "memory");
+                       kvm->arch.tlbie_lock = 0;
+               } else {
+                       asm volatile("ptesync" : : : "memory");
+                       asm volatile("tlbiel %0" : : "r" (rb));
+                       asm volatile("ptesync" : : : "memory");
+               }
        }
        hpte[1] = r;
        eieio();
@@ -298,40 +574,243 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
        return H_SUCCESS;
 }
 
-static unsigned long reverse_xlate(struct kvm *kvm, unsigned long realaddr)
-{
-       long int i;
-       unsigned long offset, rpn;
-
-       offset = realaddr & (kvm->arch.ram_psize - 1);
-       rpn = (realaddr - offset) >> PAGE_SHIFT;
-       for (i = 0; i < kvm->arch.ram_npages; ++i)
-               if (rpn == kvm->arch.ram_pginfo[i].pfn)
-                       return (i << PAGE_SHIFT) + offset;
-       return HPTE_R_RPN;      /* all 1s in the RPN field */
-}
-
 long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags,
                   unsigned long pte_index)
 {
        struct kvm *kvm = vcpu->kvm;
-       unsigned long *hpte, r;
+       unsigned long *hpte, v, r;
        int i, n = 1;
+       struct revmap_entry *rev = NULL;
 
-       if (pte_index >= (HPT_NPTEG << 3))
+       if (pte_index >= HPT_NPTE)
                return H_PARAMETER;
        if (flags & H_READ_4) {
                pte_index &= ~3;
                n = 4;
        }
+       rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]);
        for (i = 0; i < n; ++i, ++pte_index) {
                hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4));
+               v = hpte[0] & ~HPTE_V_HVLOCK;
                r = hpte[1];
-               if ((flags & H_R_XLATE) && (hpte[0] & HPTE_V_VALID))
-                       r = reverse_xlate(kvm, r & HPTE_R_RPN) |
-                               (r & ~HPTE_R_RPN);
-               vcpu->arch.gpr[4 + i * 2] = hpte[0];
+               if (v & HPTE_V_ABSENT) {
+                       v &= ~HPTE_V_ABSENT;
+                       v |= HPTE_V_VALID;
+               }
+               if (v & HPTE_V_VALID)
+                       r = rev[i].guest_rpte | (r & (HPTE_R_R | HPTE_R_C));
+               vcpu->arch.gpr[4 + i * 2] = v;
                vcpu->arch.gpr[5 + i * 2] = r;
        }
        return H_SUCCESS;
 }
+
+void kvmppc_invalidate_hpte(struct kvm *kvm, unsigned long *hptep,
+                       unsigned long pte_index)
+{
+       unsigned long rb;
+
+       hptep[0] &= ~HPTE_V_VALID;
+       rb = compute_tlbie_rb(hptep[0], hptep[1], pte_index);
+       while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
+               cpu_relax();
+       asm volatile("ptesync" : : : "memory");
+       asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
+                    : : "r" (rb), "r" (kvm->arch.lpid));
+       asm volatile("ptesync" : : : "memory");
+       kvm->arch.tlbie_lock = 0;
+}
+EXPORT_SYMBOL_GPL(kvmppc_invalidate_hpte);
+
+void kvmppc_clear_ref_hpte(struct kvm *kvm, unsigned long *hptep,
+                          unsigned long pte_index)
+{
+       unsigned long rb;
+       unsigned char rbyte;
+
+       rb = compute_tlbie_rb(hptep[0], hptep[1], pte_index);
+       rbyte = (hptep[1] & ~HPTE_R_R) >> 8;
+       /* modify only the second-last byte, which contains the ref bit */
+       *((char *)hptep + 14) = rbyte;
+       while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
+               cpu_relax();
+       asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
+                    : : "r" (rb), "r" (kvm->arch.lpid));
+       asm volatile("ptesync" : : : "memory");
+       kvm->arch.tlbie_lock = 0;
+}
+EXPORT_SYMBOL_GPL(kvmppc_clear_ref_hpte);
+
+static int slb_base_page_shift[4] = {
+       24,     /* 16M */
+       16,     /* 64k */
+       34,     /* 16G */
+       20,     /* 1M, unsupported */
+};
+
+long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr, unsigned long slb_v,
+                             unsigned long valid)
+{
+       unsigned int i;
+       unsigned int pshift;
+       unsigned long somask;
+       unsigned long vsid, hash;
+       unsigned long avpn;
+       unsigned long *hpte;
+       unsigned long mask, val;
+       unsigned long v, r;
+
+       /* Get page shift, work out hash and AVPN etc. */
+       mask = SLB_VSID_B | HPTE_V_AVPN | HPTE_V_SECONDARY;
+       val = 0;
+       pshift = 12;
+       if (slb_v & SLB_VSID_L) {
+               mask |= HPTE_V_LARGE;
+               val |= HPTE_V_LARGE;
+               pshift = slb_base_page_shift[(slb_v & SLB_VSID_LP) >> 4];
+       }
+       if (slb_v & SLB_VSID_B_1T) {
+               somask = (1UL << 40) - 1;
+               vsid = (slb_v & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T;
+               vsid ^= vsid << 25;
+       } else {
+               somask = (1UL << 28) - 1;
+               vsid = (slb_v & ~SLB_VSID_B) >> SLB_VSID_SHIFT;
+       }
+       hash = (vsid ^ ((eaddr & somask) >> pshift)) & HPT_HASH_MASK;
+       avpn = slb_v & ~(somask >> 16); /* also includes B */
+       avpn |= (eaddr & somask) >> 16;
+
+       if (pshift >= 24)
+               avpn &= ~((1UL << (pshift - 16)) - 1);
+       else
+               avpn &= ~0x7fUL;
+       val |= avpn;
+
+       for (;;) {
+               hpte = (unsigned long *)(kvm->arch.hpt_virt + (hash << 7));
+
+               for (i = 0; i < 16; i += 2) {
+                       /* Read the PTE racily */
+                       v = hpte[i] & ~HPTE_V_HVLOCK;
+
+                       /* Check valid/absent, hash, segment size and AVPN */
+                       if (!(v & valid) || (v & mask) != val)
+                               continue;
+
+                       /* Lock the PTE and read it under the lock */
+                       while (!try_lock_hpte(&hpte[i], HPTE_V_HVLOCK))
+                               cpu_relax();
+                       v = hpte[i] & ~HPTE_V_HVLOCK;
+                       r = hpte[i+1];
+
+                       /*
+                        * Check the HPTE again, including large page size
+                        * Since we don't currently allow any MPSS (mixed
+                        * page-size segment) page sizes, it is sufficient
+                        * to check against the actual page size.
+                        */
+                       if ((v & valid) && (v & mask) == val &&
+                           hpte_page_size(v, r) == (1ul << pshift))
+                               /* Return with the HPTE still locked */
+                               return (hash << 3) + (i >> 1);
+
+                       /* Unlock and move on */
+                       hpte[i] = v;
+               }
+
+               if (val & HPTE_V_SECONDARY)
+                       break;
+               val |= HPTE_V_SECONDARY;
+               hash = hash ^ HPT_HASH_MASK;
+       }
+       return -1;
+}
+EXPORT_SYMBOL(kvmppc_hv_find_lock_hpte);
+
+/*
+ * Called in real mode to check whether an HPTE not found fault
+ * is due to accessing a paged-out page or an emulated MMIO page,
+ * or if a protection fault is due to accessing a page that the
+ * guest wanted read/write access to but which we made read-only.
+ * Returns a possibly modified status (DSISR) value if not
+ * (i.e. pass the interrupt to the guest),
+ * -1 to pass the fault up to host kernel mode code, -2 to do that
+ * and also load the instruction word (for MMIO emulation),
+ * or 0 if we should make the guest retry the access.
+ */
+long kvmppc_hpte_hv_fault(struct kvm_vcpu *vcpu, unsigned long addr,
+                         unsigned long slb_v, unsigned int status, bool data)
+{
+       struct kvm *kvm = vcpu->kvm;
+       long int index;
+       unsigned long v, r, gr;
+       unsigned long *hpte;
+       unsigned long valid;
+       struct revmap_entry *rev;
+       unsigned long pp, key;
+
+       /* For protection fault, expect to find a valid HPTE */
+       valid = HPTE_V_VALID;
+       if (status & DSISR_NOHPTE)
+               valid |= HPTE_V_ABSENT;
+
+       index = kvmppc_hv_find_lock_hpte(kvm, addr, slb_v, valid);
+       if (index < 0) {
+               if (status & DSISR_NOHPTE)
+                       return status;  /* there really was no HPTE */
+               return 0;               /* for prot fault, HPTE disappeared */
+       }
+       hpte = (unsigned long *)(kvm->arch.hpt_virt + (index << 4));
+       v = hpte[0] & ~HPTE_V_HVLOCK;
+       r = hpte[1];
+       rev = real_vmalloc_addr(&kvm->arch.revmap[index]);
+       gr = rev->guest_rpte;
+
+       unlock_hpte(hpte, v);
+
+       /* For not found, if the HPTE is valid by now, retry the instruction */
+       if ((status & DSISR_NOHPTE) && (v & HPTE_V_VALID))
+               return 0;
+
+       /* Check access permissions to the page */
+       pp = gr & (HPTE_R_PP0 | HPTE_R_PP);
+       key = (vcpu->arch.shregs.msr & MSR_PR) ? SLB_VSID_KP : SLB_VSID_KS;
+       status &= ~DSISR_NOHPTE;        /* DSISR_NOHPTE == SRR1_ISI_NOPT */
+       if (!data) {
+               if (gr & (HPTE_R_N | HPTE_R_G))
+                       return status | SRR1_ISI_N_OR_G;
+               if (!hpte_read_permission(pp, slb_v & key))
+                       return status | SRR1_ISI_PROT;
+       } else if (status & DSISR_ISSTORE) {
+               /* check write permission */
+               if (!hpte_write_permission(pp, slb_v & key))
+                       return status | DSISR_PROTFAULT;
+       } else {
+               if (!hpte_read_permission(pp, slb_v & key))
+                       return status | DSISR_PROTFAULT;
+       }
+
+       /* Check storage key, if applicable */
+       if (data && (vcpu->arch.shregs.msr & MSR_DR)) {
+               unsigned int perm = hpte_get_skey_perm(gr, vcpu->arch.amr);
+               if (status & DSISR_ISSTORE)
+                       perm >>= 1;
+               if (perm & 1)
+                       return status | DSISR_KEYFAULT;
+       }
+
+       /* Save HPTE info for virtual-mode handler */
+       vcpu->arch.pgfault_addr = addr;
+       vcpu->arch.pgfault_index = index;
+       vcpu->arch.pgfault_hpte[0] = v;
+       vcpu->arch.pgfault_hpte[1] = r;
+
+       /* Check the storage key to see if it is possibly emulated MMIO */
+       if (data && (vcpu->arch.shregs.msr & MSR_IR) &&
+           (r & (HPTE_R_KEY_HI | HPTE_R_KEY_LO)) ==
+           (HPTE_R_KEY_HI | HPTE_R_KEY_LO))
+               return -2;      /* MMIO emulation - load instr word */
+
+       return -1;              /* send fault up to host kernel mode */
+}
index 5c8b261..b70bf22 100644 (file)
@@ -601,6 +601,30 @@ kvmppc_interrupt:
 
        stw     r12,VCPU_TRAP(r9)
 
+       /* Save HEIR (HV emulation assist reg) in last_inst
+          if this is an HEI (HV emulation interrupt, e40) */
+       li      r3,KVM_INST_FETCH_FAILED
+BEGIN_FTR_SECTION
+       cmpwi   r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
+       bne     11f
+       mfspr   r3,SPRN_HEIR
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+11:    stw     r3,VCPU_LAST_INST(r9)
+
+       /* these are volatile across C function calls */
+       mfctr   r3
+       mfxer   r4
+       std     r3, VCPU_CTR(r9)
+       stw     r4, VCPU_XER(r9)
+
+BEGIN_FTR_SECTION
+       /* If this is a page table miss then see if it's theirs or ours */
+       cmpwi   r12, BOOK3S_INTERRUPT_H_DATA_STORAGE
+       beq     kvmppc_hdsi
+       cmpwi   r12, BOOK3S_INTERRUPT_H_INST_STORAGE
+       beq     kvmppc_hisi
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+
        /* See if this is a leftover HDEC interrupt */
        cmpwi   r12,BOOK3S_INTERRUPT_HV_DECREMENTER
        bne     2f
@@ -608,7 +632,7 @@ kvmppc_interrupt:
        cmpwi   r3,0
        bge     ignore_hdec
 2:
-       /* See if this is something we can handle in real mode */
+       /* See if this is an hcall we can handle in real mode */
        cmpwi   r12,BOOK3S_INTERRUPT_SYSCALL
        beq     hcall_try_real_mode
 
@@ -624,6 +648,7 @@ BEGIN_FTR_SECTION
 1:
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 
+nohpte_cont:
 hcall_real_cont:               /* r9 = vcpu, r12 = trap, r13 = paca */
        /* Save DEC */
        mfspr   r5,SPRN_DEC
@@ -632,36 +657,21 @@ hcall_real_cont:          /* r9 = vcpu, r12 = trap, r13 = paca */
        add     r5,r5,r6
        std     r5,VCPU_DEC_EXPIRES(r9)
 
-       /* Save HEIR (HV emulation assist reg) in last_inst
-          if this is an HEI (HV emulation interrupt, e40) */
-       li      r3,-1
-BEGIN_FTR_SECTION
-       cmpwi   r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST
-       bne     11f
-       mfspr   r3,SPRN_HEIR
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-11:    stw     r3,VCPU_LAST_INST(r9)
-
        /* Save more register state  */
-       mfxer   r5
        mfdar   r6
        mfdsisr r7
-       mfctr   r8
-
-       stw     r5, VCPU_XER(r9)
        std     r6, VCPU_DAR(r9)
        stw     r7, VCPU_DSISR(r9)
-       std     r8, VCPU_CTR(r9)
-       /* grab HDAR & HDSISR if HV data storage interrupt (HDSI) */
 BEGIN_FTR_SECTION
+       /* don't overwrite fault_dar/fault_dsisr if HDSI */
        cmpwi   r12,BOOK3S_INTERRUPT_H_DATA_STORAGE
        beq     6f
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-7:     std     r6, VCPU_FAULT_DAR(r9)
+       std     r6, VCPU_FAULT_DAR(r9)
        stw     r7, VCPU_FAULT_DSISR(r9)
 
        /* Save guest CTRL register, set runlatch to 1 */
-       mfspr   r6,SPRN_CTRLF
+6:     mfspr   r6,SPRN_CTRLF
        stw     r6,VCPU_CTRL(r9)
        andi.   r0,r6,1
        bne     4f
@@ -1094,9 +1104,131 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        mtspr   SPRN_HSRR1, r7
        ba      0x500
 
-6:     mfspr   r6,SPRN_HDAR
-       mfspr   r7,SPRN_HDSISR
-       b       7b
+/*
+ * Check whether an HDSI is an HPTE not found fault or something else.
+ * If it is an HPTE not found fault that is due to the guest accessing
+ * a page that they have mapped but which we have paged out, then
+ * we continue on with the guest exit path.  In all other cases,
+ * reflect the HDSI to the guest as a DSI.
+ */
+kvmppc_hdsi:
+       mfspr   r4, SPRN_HDAR
+       mfspr   r6, SPRN_HDSISR
+       /* HPTE not found fault or protection fault? */
+       andis.  r0, r6, (DSISR_NOHPTE | DSISR_PROTFAULT)@h
+       beq     1f                      /* if not, send it to the guest */
+       andi.   r0, r11, MSR_DR         /* data relocation enabled? */
+       beq     3f
+       clrrdi  r0, r4, 28
+       PPC_SLBFEE_DOT(r5, r0)          /* if so, look up SLB */
+       bne     1f                      /* if no SLB entry found */
+4:     std     r4, VCPU_FAULT_DAR(r9)
+       stw     r6, VCPU_FAULT_DSISR(r9)
+
+       /* Search the hash table. */
+       mr      r3, r9                  /* vcpu pointer */
+       li      r7, 1                   /* data fault */
+       bl      .kvmppc_hpte_hv_fault
+       ld      r9, HSTATE_KVM_VCPU(r13)
+       ld      r10, VCPU_PC(r9)
+       ld      r11, VCPU_MSR(r9)
+       li      r12, BOOK3S_INTERRUPT_H_DATA_STORAGE
+       cmpdi   r3, 0                   /* retry the instruction */
+       beq     6f
+       cmpdi   r3, -1                  /* handle in kernel mode */
+       beq     nohpte_cont
+       cmpdi   r3, -2                  /* MMIO emulation; need instr word */
+       beq     2f
+
+       /* Synthesize a DSI for the guest */
+       ld      r4, VCPU_FAULT_DAR(r9)
+       mr      r6, r3
+1:     mtspr   SPRN_DAR, r4
+       mtspr   SPRN_DSISR, r6
+       mtspr   SPRN_SRR0, r10
+       mtspr   SPRN_SRR1, r11
+       li      r10, BOOK3S_INTERRUPT_DATA_STORAGE
+       li      r11, (MSR_ME << 1) | 1  /* synthesize MSR_SF | MSR_ME */
+       rotldi  r11, r11, 63
+6:     ld      r7, VCPU_CTR(r9)
+       lwz     r8, VCPU_XER(r9)
+       mtctr   r7
+       mtxer   r8
+       mr      r4, r9
+       b       fast_guest_return
+
+3:     ld      r5, VCPU_KVM(r9)        /* not relocated, use VRMA */
+       ld      r5, KVM_VRMA_SLB_V(r5)
+       b       4b
+
+       /* If this is for emulated MMIO, load the instruction word */
+2:     li      r8, KVM_INST_FETCH_FAILED       /* In case lwz faults */
+
+       /* Set guest mode to 'jump over instruction' so if lwz faults
+        * we'll just continue at the next IP. */
+       li      r0, KVM_GUEST_MODE_SKIP
+       stb     r0, HSTATE_IN_GUEST(r13)
+
+       /* Do the access with MSR:DR enabled */
+       mfmsr   r3
+       ori     r4, r3, MSR_DR          /* Enable paging for data */
+       mtmsrd  r4
+       lwz     r8, 0(r10)
+       mtmsrd  r3
+
+       /* Store the result */
+       stw     r8, VCPU_LAST_INST(r9)
+
+       /* Unset guest mode. */
+       li      r0, KVM_GUEST_MODE_NONE
+       stb     r0, HSTATE_IN_GUEST(r13)
+       b       nohpte_cont
+
+/*
+ * Similarly for an HISI, reflect it to the guest as an ISI unless
+ * it is an HPTE not found fault for a page that we have paged out.
+ */
+kvmppc_hisi:
+       andis.  r0, r11, SRR1_ISI_NOPT@h
+       beq     1f
+       andi.   r0, r11, MSR_IR         /* instruction relocation enabled? */
+       beq     3f
+       clrrdi  r0, r10, 28
+       PPC_SLBFEE_DOT(r5, r0)          /* if so, look up SLB */
+       bne     1f                      /* if no SLB entry found */
+4:
+       /* Search the hash table. */
+       mr      r3, r9                  /* vcpu pointer */
+       mr      r4, r10
+       mr      r6, r11
+       li      r7, 0                   /* instruction fault */
+       bl      .kvmppc_hpte_hv_fault
+       ld      r9, HSTATE_KVM_VCPU(r13)
+       ld      r10, VCPU_PC(r9)
+       ld      r11, VCPU_MSR(r9)
+       li      r12, BOOK3S_INTERRUPT_H_INST_STORAGE
+       cmpdi   r3, 0                   /* retry the instruction */
+       beq     6f
+       cmpdi   r3, -1                  /* handle in kernel mode */
+       beq     nohpte_cont
+
+       /* Synthesize an ISI for the guest */
+       mr      r11, r3
+1:     mtspr   SPRN_SRR0, r10
+       mtspr   SPRN_SRR1, r11
+       li      r10, BOOK3S_INTERRUPT_INST_STORAGE
+       li      r11, (MSR_ME << 1) | 1  /* synthesize MSR_SF | MSR_ME */
+       rotldi  r11, r11, 63
+6:     ld      r7, VCPU_CTR(r9)
+       lwz     r8, VCPU_XER(r9)
+       mtctr   r7
+       mtxer   r8
+       mr      r4, r9
+       b       fast_guest_return
+
+3:     ld      r6, VCPU_KVM(r9)        /* not relocated, use VRMA */
+       ld      r5, KVM_VRMA_SLB_V(r6)
+       b       4b
 
 /*
  * Try to handle an hcall in real mode.
index 7b0ee96..e70ef2d 100644 (file)
@@ -196,7 +196,8 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
                kvmppc_inject_pf(vcpu, addr, false);
                goto done_load;
        } else if (r == EMULATE_DO_MMIO) {
-               emulated = kvmppc_handle_load(run, vcpu, KVM_REG_FPR | rs, len, 1);
+               emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
+                                             len, 1);
                goto done_load;
        }
 
@@ -286,11 +287,13 @@ static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
                kvmppc_inject_pf(vcpu, addr, false);
                goto done_load;
        } else if ((r == EMULATE_DO_MMIO) && w) {
-               emulated = kvmppc_handle_load(run, vcpu, KVM_REG_FPR | rs, 4, 1);
+               emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FPR | rs,
+                                             4, 1);
                vcpu->arch.qpr[rs] = tmp[1];
                goto done_load;
        } else if (r == EMULATE_DO_MMIO) {
-               emulated = kvmppc_handle_load(run, vcpu, KVM_REG_FQPR | rs, 8, 1);
+               emulated = kvmppc_handle_load(run, vcpu, KVM_MMIO_REG_FQPR | rs,
+                                             8, 1);
                goto done_load;
        }
 
index 220fcdf..7340e10 100644 (file)
@@ -51,15 +51,19 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
 #define MSR_USER32 MSR_USER
 #define MSR_USER64 MSR_USER
 #define HW_PAGE_SIZE PAGE_SIZE
+#define __hard_irq_disable local_irq_disable
+#define __hard_irq_enable local_irq_enable
 #endif
 
 void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 #ifdef CONFIG_PPC_BOOK3S_64
-       memcpy(to_svcpu(vcpu)->slb, to_book3s(vcpu)->slb_shadow, sizeof(to_svcpu(vcpu)->slb));
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       memcpy(svcpu->slb, to_book3s(vcpu)->slb_shadow, sizeof(svcpu->slb));
        memcpy(&get_paca()->shadow_vcpu, to_book3s(vcpu)->shadow_vcpu,
               sizeof(get_paca()->shadow_vcpu));
-       to_svcpu(vcpu)->slb_max = to_book3s(vcpu)->slb_shadow_max;
+       svcpu->slb_max = to_book3s(vcpu)->slb_shadow_max;
+       svcpu_put(svcpu);
 #endif
 
 #ifdef CONFIG_PPC_BOOK3S_32
@@ -70,10 +74,12 @@ void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
 {
 #ifdef CONFIG_PPC_BOOK3S_64
-       memcpy(to_book3s(vcpu)->slb_shadow, to_svcpu(vcpu)->slb, sizeof(to_svcpu(vcpu)->slb));
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       memcpy(to_book3s(vcpu)->slb_shadow, svcpu->slb, sizeof(svcpu->slb));
        memcpy(to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu,
               sizeof(get_paca()->shadow_vcpu));
-       to_book3s(vcpu)->slb_shadow_max = to_svcpu(vcpu)->slb_max;
+       to_book3s(vcpu)->slb_shadow_max = svcpu->slb_max;
+       svcpu_put(svcpu);
 #endif
 
        kvmppc_giveup_ext(vcpu, MSR_FP);
@@ -151,14 +157,16 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
 #ifdef CONFIG_PPC_BOOK3S_64
        if ((pvr >= 0x330000) && (pvr < 0x70330000)) {
                kvmppc_mmu_book3s_64_init(vcpu);
-               to_book3s(vcpu)->hior = 0xfff00000;
+               if (!to_book3s(vcpu)->hior_explicit)
+                       to_book3s(vcpu)->hior = 0xfff00000;
                to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL;
                vcpu->arch.cpu_type = KVM_CPU_3S_64;
        } else
 #endif
        {
                kvmppc_mmu_book3s_32_init(vcpu);
-               to_book3s(vcpu)->hior = 0;
+               if (!to_book3s(vcpu)->hior_explicit)
+                       to_book3s(vcpu)->hior = 0;
                to_book3s(vcpu)->msr_mask = 0xffffffffULL;
                vcpu->arch.cpu_type = KVM_CPU_3S_32;
        }
@@ -308,19 +316,22 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
        if (page_found == -ENOENT) {
                /* Page not found in guest PTE entries */
+               struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
                vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
-               vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr;
+               vcpu->arch.shared->dsisr = svcpu->fault_dsisr;
                vcpu->arch.shared->msr |=
-                       (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
+                       (svcpu->shadow_srr1 & 0x00000000f8000000ULL);
+               svcpu_put(svcpu);
                kvmppc_book3s_queue_irqprio(vcpu, vec);
        } else if (page_found == -EPERM) {
                /* Storage protection */
+               struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
                vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
-               vcpu->arch.shared->dsisr =
-                       to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE;
+               vcpu->arch.shared->dsisr = svcpu->fault_dsisr & ~DSISR_NOHPTE;
                vcpu->arch.shared->dsisr |= DSISR_PROTFAULT;
                vcpu->arch.shared->msr |=
-                       (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
+                       svcpu->shadow_srr1 & 0x00000000f8000000ULL;
+               svcpu_put(svcpu);
                kvmppc_book3s_queue_irqprio(vcpu, vec);
        } else if (page_found == -EINVAL) {
                /* Page not found in guest SLB */
@@ -517,24 +528,29 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        run->ready_for_interrupt_injection = 1;
 
        trace_kvm_book3s_exit(exit_nr, vcpu);
+       preempt_enable();
        kvm_resched(vcpu);
        switch (exit_nr) {
        case BOOK3S_INTERRUPT_INST_STORAGE:
+       {
+               struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+               ulong shadow_srr1 = svcpu->shadow_srr1;
                vcpu->stat.pf_instruc++;
 
 #ifdef CONFIG_PPC_BOOK3S_32
                /* We set segments as unused segments when invalidating them. So
                 * treat the respective fault as segment fault. */
-               if (to_svcpu(vcpu)->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT]
-                   == SR_INVALID) {
+               if (svcpu->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT] == SR_INVALID) {
                        kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
                        r = RESUME_GUEST;
+                       svcpu_put(svcpu);
                        break;
                }
 #endif
+               svcpu_put(svcpu);
 
                /* only care about PTEG not found errors, but leave NX alone */
-               if (to_svcpu(vcpu)->shadow_srr1 & 0x40000000) {
+               if (shadow_srr1 & 0x40000000) {
                        r = kvmppc_handle_pagefault(run, vcpu, kvmppc_get_pc(vcpu), exit_nr);
                        vcpu->stat.sp_instruc++;
                } else if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
@@ -547,33 +563,37 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
                        r = RESUME_GUEST;
                } else {
-                       vcpu->arch.shared->msr |=
-                               to_svcpu(vcpu)->shadow_srr1 & 0x58000000;
+                       vcpu->arch.shared->msr |= shadow_srr1 & 0x58000000;
                        kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
                        r = RESUME_GUEST;
                }
                break;
+       }
        case BOOK3S_INTERRUPT_DATA_STORAGE:
        {
                ulong dar = kvmppc_get_fault_dar(vcpu);
+               struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+               u32 fault_dsisr = svcpu->fault_dsisr;
                vcpu->stat.pf_storage++;
 
 #ifdef CONFIG_PPC_BOOK3S_32
                /* We set segments as unused segments when invalidating them. So
                 * treat the respective fault as segment fault. */
-               if ((to_svcpu(vcpu)->sr[dar >> SID_SHIFT]) == SR_INVALID) {
+               if ((svcpu->sr[dar >> SID_SHIFT]) == SR_INVALID) {
                        kvmppc_mmu_map_segment(vcpu, dar);
                        r = RESUME_GUEST;
+                       svcpu_put(svcpu);
                        break;
                }
 #endif
+               svcpu_put(svcpu);
 
                /* The only case we need to handle is missing shadow PTEs */
-               if (to_svcpu(vcpu)->fault_dsisr & DSISR_NOHPTE) {
+               if (fault_dsisr & DSISR_NOHPTE) {
                        r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr);
                } else {
                        vcpu->arch.shared->dar = dar;
-                       vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr;
+                       vcpu->arch.shared->dsisr = fault_dsisr;
                        kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
                        r = RESUME_GUEST;
                }
@@ -609,10 +629,13 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        case BOOK3S_INTERRUPT_PROGRAM:
        {
                enum emulation_result er;
+               struct kvmppc_book3s_shadow_vcpu *svcpu;
                ulong flags;
 
 program_interrupt:
-               flags = to_svcpu(vcpu)->shadow_srr1 & 0x1f0000ull;
+               svcpu = svcpu_get(vcpu);
+               flags = svcpu->shadow_srr1 & 0x1f0000ull;
+               svcpu_put(svcpu);
 
                if (vcpu->arch.shared->msr & MSR_PR) {
 #ifdef EXIT_DEBUG
@@ -740,20 +763,33 @@ program_interrupt:
                r = RESUME_GUEST;
                break;
        default:
+       {
+               struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+               ulong shadow_srr1 = svcpu->shadow_srr1;
+               svcpu_put(svcpu);
                /* Ugh - bork here! What did we get? */
                printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n",
-                       exit_nr, kvmppc_get_pc(vcpu), to_svcpu(vcpu)->shadow_srr1);
+                       exit_nr, kvmppc_get_pc(vcpu), shadow_srr1);
                r = RESUME_HOST;
                BUG();
                break;
        }
-
+       }
 
        if (!(r & RESUME_HOST)) {
                /* To avoid clobbering exit_reason, only check for signals if
                 * we aren't already exiting to userspace for some other
                 * reason. */
+
+               /*
+                * Interrupts could be timers for the guest which we have to
+                * inject again, so let's postpone them until we're in the guest
+                * and if we really did time things so badly, then we just exit
+                * again due to a host external interrupt.
+                */
+               __hard_irq_disable();
                if (signal_pending(current)) {
+                       __hard_irq_enable();
 #ifdef EXIT_DEBUG
                        printk(KERN_EMERG "KVM: Going back to host\n");
 #endif
@@ -761,10 +797,12 @@ program_interrupt:
                        run->exit_reason = KVM_EXIT_INTR;
                        r = -EINTR;
                } else {
+                       preempt_disable();
+
                        /* In case an interrupt came in that was triggered
                         * from userspace (like DEC), we need to check what
                         * to inject now! */
-                       kvmppc_core_deliver_interrupts(vcpu);
+                       kvmppc_core_prepare_to_enter(vcpu);
                }
        }
 
@@ -836,6 +874,38 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+       int r = -EINVAL;
+
+       switch (reg->id) {
+       case KVM_REG_PPC_HIOR:
+               r = put_user(to_book3s(vcpu)->hior, (u64 __user *)reg->addr);
+               break;
+       default:
+               break;
+       }
+
+       return r;
+}
+
+int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+       int r = -EINVAL;
+
+       switch (reg->id) {
+       case KVM_REG_PPC_HIOR:
+               r = get_user(to_book3s(vcpu)->hior, (u64 __user *)reg->addr);
+               if (!r)
+                       to_book3s(vcpu)->hior_explicit = true;
+               break;
+       default:
+               break;
+       }
+
+       return r;
+}
+
 int kvmppc_core_check_processor_compat(void)
 {
        return 0;
@@ -923,16 +993,31 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 #endif
        ulong ext_msr;
 
+       preempt_disable();
+
        /* Check if we can run the vcpu at all */
        if (!vcpu->arch.sane) {
                kvm_run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
+       kvmppc_core_prepare_to_enter(vcpu);
+
+       /*
+        * Interrupts could be timers for the guest which we have to inject
+        * again, so let's postpone them until we're in the guest and if we
+        * really did time things so badly, then we just exit again due to
+        * a host external interrupt.
+        */
+       __hard_irq_disable();
+
        /* No need to go into the guest when all we do is going out */
        if (signal_pending(current)) {
+               __hard_irq_enable();
                kvm_run->exit_reason = KVM_EXIT_INTR;
-               return -EINTR;
+               ret = -EINTR;
+               goto out;
        }
 
        /* Save FPU state in stack */
@@ -974,8 +1059,6 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
        kvm_guest_exit();
 
-       local_irq_disable();
-
        current->thread.regs->msr = ext_msr;
 
        /* Make sure we save the guest FPU/Altivec/VSX state */
@@ -1002,9 +1085,50 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        current->thread.used_vsr = used_vsr;
 #endif
 
+out:
+       preempt_enable();
        return ret;
 }
 
+/*
+ * Get (and clear) the dirty memory log for a memory slot.
+ */
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
+                                     struct kvm_dirty_log *log)
+{
+       struct kvm_memory_slot *memslot;
+       struct kvm_vcpu *vcpu;
+       ulong ga, ga_end;
+       int is_dirty = 0;
+       int r;
+       unsigned long n;
+
+       mutex_lock(&kvm->slots_lock);
+
+       r = kvm_get_dirty_log(kvm, log, &is_dirty);
+       if (r)
+               goto out;
+
+       /* If nothing is dirty, don't bother messing with page tables. */
+       if (is_dirty) {
+               memslot = id_to_memslot(kvm->memslots, log->slot);
+
+               ga = memslot->base_gfn << PAGE_SHIFT;
+               ga_end = ga + (memslot->npages << PAGE_SHIFT);
+
+               kvm_for_each_vcpu(n, vcpu, kvm)
+                       kvmppc_mmu_pte_pflush(vcpu, ga, ga_end);
+
+               n = kvm_dirty_bitmap_bytes(memslot);
+               memset(memslot->dirty_bitmap, 0, n);
+       }
+
+       r = 0;
+out:
+       mutex_unlock(&kvm->slots_lock);
+       return r;
+}
+
 int kvmppc_core_prepare_memory_region(struct kvm *kvm,
                                      struct kvm_userspace_memory_region *mem)
 {
index bb6c988..ee9e1ee 100644 (file)
@@ -124,12 +124,6 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
        vcpu->arch.shared->msr = new_msr;
 
        kvmppc_mmu_msr_notify(vcpu, old_msr);
-
-       if (vcpu->arch.shared->msr & MSR_WE) {
-               kvm_vcpu_block(vcpu);
-               kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS);
-       };
-
        kvmppc_vcpu_sync_spe(vcpu);
 }
 
@@ -258,9 +252,11 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
                allowed = vcpu->arch.shared->msr & MSR_ME;
                msr_mask = 0;
                break;
-       case BOOKE_IRQPRIO_EXTERNAL:
        case BOOKE_IRQPRIO_DECREMENTER:
        case BOOKE_IRQPRIO_FIT:
+               keep_irq = true;
+               /* fall through */
+       case BOOKE_IRQPRIO_EXTERNAL:
                allowed = vcpu->arch.shared->msr & MSR_EE;
                allowed = allowed && !crit;
                msr_mask = MSR_CE|MSR_ME|MSR_DE;
@@ -276,7 +272,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
                vcpu->arch.shared->srr1 = vcpu->arch.shared->msr;
                vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority];
                if (update_esr == true)
-                       vcpu->arch.esr = vcpu->arch.queued_esr;
+                       vcpu->arch.shared->esr = vcpu->arch.queued_esr;
                if (update_dear == true)
                        vcpu->arch.shared->dar = vcpu->arch.queued_dear;
                kvmppc_set_msr(vcpu, vcpu->arch.shared->msr & msr_mask);
@@ -288,13 +284,26 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
        return allowed;
 }
 
-/* Check pending exceptions and deliver one, if possible. */
-void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
+static void update_timer_ints(struct kvm_vcpu *vcpu)
+{
+       if ((vcpu->arch.tcr & TCR_DIE) && (vcpu->arch.tsr & TSR_DIS))
+               kvmppc_core_queue_dec(vcpu);
+       else
+               kvmppc_core_dequeue_dec(vcpu);
+}
+
+static void kvmppc_core_check_exceptions(struct kvm_vcpu *vcpu)
 {
        unsigned long *pending = &vcpu->arch.pending_exceptions;
-       unsigned long old_pending = vcpu->arch.pending_exceptions;
        unsigned int priority;
 
+       if (vcpu->requests) {
+               if (kvm_check_request(KVM_REQ_PENDING_TIMER, vcpu)) {
+                       smp_mb();
+                       update_timer_ints(vcpu);
+               }
+       }
+
        priority = __ffs(*pending);
        while (priority <= BOOKE_IRQPRIO_MAX) {
                if (kvmppc_booke_irqprio_deliver(vcpu, priority))
@@ -306,10 +315,24 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
        }
 
        /* Tell the guest about our interrupt status */
-       if (*pending)
-               vcpu->arch.shared->int_pending = 1;
-       else if (old_pending)
-               vcpu->arch.shared->int_pending = 0;
+       vcpu->arch.shared->int_pending = !!*pending;
+}
+
+/* Check pending exceptions and deliver one, if possible. */
+void kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
+{
+       WARN_ON_ONCE(!irqs_disabled());
+
+       kvmppc_core_check_exceptions(vcpu);
+
+       if (vcpu->arch.shared->msr & MSR_WE) {
+               local_irq_enable();
+               kvm_vcpu_block(vcpu);
+               local_irq_disable();
+
+               kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS);
+               kvmppc_core_check_exceptions(vcpu);
+       };
 }
 
 int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
@@ -322,11 +345,21 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        }
 
        local_irq_disable();
+
+       kvmppc_core_prepare_to_enter(vcpu);
+
+       if (signal_pending(current)) {
+               kvm_run->exit_reason = KVM_EXIT_INTR;
+               ret = -EINTR;
+               goto out;
+       }
+
        kvm_guest_enter();
        ret = __kvmppc_vcpu_run(kvm_run, vcpu);
        kvm_guest_exit();
-       local_irq_enable();
 
+out:
+       local_irq_enable();
        return ret;
 }
 
@@ -603,7 +636,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
        local_irq_disable();
 
-       kvmppc_core_deliver_interrupts(vcpu);
+       kvmppc_core_prepare_to_enter(vcpu);
 
        if (!(r & RESUME_HOST)) {
                /* To avoid clobbering exit_reason, only check for signals if
@@ -628,6 +661,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        vcpu->arch.pc = 0;
        vcpu->arch.shared->msr = 0;
        vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS;
+       vcpu->arch.shared->pir = vcpu->vcpu_id;
        kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */
 
        vcpu->arch.shadow_pid = 1;
@@ -662,10 +696,10 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        regs->sprg1 = vcpu->arch.shared->sprg1;
        regs->sprg2 = vcpu->arch.shared->sprg2;
        regs->sprg3 = vcpu->arch.shared->sprg3;
-       regs->sprg4 = vcpu->arch.sprg4;
-       regs->sprg5 = vcpu->arch.sprg5;
-       regs->sprg6 = vcpu->arch.sprg6;
-       regs->sprg7 = vcpu->arch.sprg7;
+       regs->sprg4 = vcpu->arch.shared->sprg4;
+       regs->sprg5 = vcpu->arch.shared->sprg5;
+       regs->sprg6 = vcpu->arch.shared->sprg6;
+       regs->sprg7 = vcpu->arch.shared->sprg7;
 
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
                regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
@@ -690,10 +724,10 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        vcpu->arch.shared->sprg1 = regs->sprg1;
        vcpu->arch.shared->sprg2 = regs->sprg2;
        vcpu->arch.shared->sprg3 = regs->sprg3;
-       vcpu->arch.sprg4 = regs->sprg4;
-       vcpu->arch.sprg5 = regs->sprg5;
-       vcpu->arch.sprg6 = regs->sprg6;
-       vcpu->arch.sprg7 = regs->sprg7;
+       vcpu->arch.shared->sprg4 = regs->sprg4;
+       vcpu->arch.shared->sprg5 = regs->sprg5;
+       vcpu->arch.shared->sprg6 = regs->sprg6;
+       vcpu->arch.shared->sprg7 = regs->sprg7;
 
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
                kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
@@ -711,7 +745,7 @@ static void get_sregs_base(struct kvm_vcpu *vcpu,
        sregs->u.e.csrr0 = vcpu->arch.csrr0;
        sregs->u.e.csrr1 = vcpu->arch.csrr1;
        sregs->u.e.mcsr = vcpu->arch.mcsr;
-       sregs->u.e.esr = vcpu->arch.esr;
+       sregs->u.e.esr = vcpu->arch.shared->esr;
        sregs->u.e.dear = vcpu->arch.shared->dar;
        sregs->u.e.tsr = vcpu->arch.tsr;
        sregs->u.e.tcr = vcpu->arch.tcr;
@@ -729,28 +763,19 @@ static int set_sregs_base(struct kvm_vcpu *vcpu,
        vcpu->arch.csrr0 = sregs->u.e.csrr0;
        vcpu->arch.csrr1 = sregs->u.e.csrr1;
        vcpu->arch.mcsr = sregs->u.e.mcsr;
-       vcpu->arch.esr = sregs->u.e.esr;
+       vcpu->arch.shared->esr = sregs->u.e.esr;
        vcpu->arch.shared->dar = sregs->u.e.dear;
        vcpu->arch.vrsave = sregs->u.e.vrsave;
-       vcpu->arch.tcr = sregs->u.e.tcr;
+       kvmppc_set_tcr(vcpu, sregs->u.e.tcr);
 
-       if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_DEC)
+       if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_DEC) {
                vcpu->arch.dec = sregs->u.e.dec;
-
-       kvmppc_emulate_dec(vcpu);
+               kvmppc_emulate_dec(vcpu);
+       }
 
        if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) {
-               /*
-                * FIXME: existing KVM timer handling is incomplete.
-                * TSR cannot be read by the guest, and its value in
-                * vcpu->arch is always zero.  For now, just handle
-                * the case where the caller is trying to inject a
-                * decrementer interrupt.
-                */
-
-               if ((sregs->u.e.tsr & TSR_DIS) &&
-                   (vcpu->arch.tcr & TCR_DIE))
-                       kvmppc_core_queue_dec(vcpu);
+               vcpu->arch.tsr = sregs->u.e.tsr;
+               update_timer_ints(vcpu);
        }
 
        return 0;
@@ -761,7 +786,7 @@ static void get_sregs_arch206(struct kvm_vcpu *vcpu,
 {
        sregs->u.e.features |= KVM_SREGS_E_ARCH206;
 
-       sregs->u.e.pir = 0;
+       sregs->u.e.pir = vcpu->vcpu_id;
        sregs->u.e.mcsrr0 = vcpu->arch.mcsrr0;
        sregs->u.e.mcsrr1 = vcpu->arch.mcsrr1;
        sregs->u.e.decar = vcpu->arch.decar;
@@ -774,7 +799,7 @@ static int set_sregs_arch206(struct kvm_vcpu *vcpu,
        if (!(sregs->u.e.features & KVM_SREGS_E_ARCH206))
                return 0;
 
-       if (sregs->u.e.pir != 0)
+       if (sregs->u.e.pir != vcpu->vcpu_id)
                return -EINVAL;
 
        vcpu->arch.mcsrr0 = sregs->u.e.mcsrr0;
@@ -862,6 +887,16 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        return kvmppc_core_set_sregs(vcpu, sregs);
 }
 
+int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+       return -EINVAL;
+}
+
+int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
+{
+       return -EINVAL;
+}
+
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
        return -ENOTSUPP;
@@ -906,6 +941,33 @@ void kvmppc_core_destroy_vm(struct kvm *kvm)
 {
 }
 
+void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr)
+{
+       vcpu->arch.tcr = new_tcr;
+       update_timer_ints(vcpu);
+}
+
+void kvmppc_set_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
+{
+       set_bits(tsr_bits, &vcpu->arch.tsr);
+       smp_wmb();
+       kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
+       kvm_vcpu_kick(vcpu);
+}
+
+void kvmppc_clr_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
+{
+       clear_bits(tsr_bits, &vcpu->arch.tsr);
+       update_timer_ints(vcpu);
+}
+
+void kvmppc_decrementer_func(unsigned long data)
+{
+       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
+
+       kvmppc_set_tsr_bits(vcpu, TSR_DIS);
+}
+
 int __init kvmppc_booke_init(void)
 {
        unsigned long ivor[16];
index 8e1fe33..2fe2027 100644 (file)
@@ -55,6 +55,10 @@ extern unsigned long kvmppc_booke_handlers;
 void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr);
 void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr);
 
+void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr);
+void kvmppc_set_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits);
+void kvmppc_clr_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits);
+
 int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                             unsigned int inst, int *advance);
 int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt);
index 1260f5f..3e652da 100644 (file)
@@ -13,6 +13,7 @@
  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *
  * Copyright IBM Corp. 2008
+ * Copyright 2011 Freescale Semiconductor, Inc.
  *
  * Authors: Hollis Blanchard <hollisb@us.ibm.com>
  */
@@ -107,7 +108,7 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
        case SPRN_DEAR:
                vcpu->arch.shared->dar = spr_val; break;
        case SPRN_ESR:
-               vcpu->arch.esr = spr_val; break;
+               vcpu->arch.shared->esr = spr_val; break;
        case SPRN_DBCR0:
                vcpu->arch.dbcr0 = spr_val; break;
        case SPRN_DBCR1:
@@ -115,23 +116,23 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
        case SPRN_DBSR:
                vcpu->arch.dbsr &= ~spr_val; break;
        case SPRN_TSR:
-               vcpu->arch.tsr &= ~spr_val; break;
+               kvmppc_clr_tsr_bits(vcpu, spr_val);
+               break;
        case SPRN_TCR:
-               vcpu->arch.tcr = spr_val;
-               kvmppc_emulate_dec(vcpu);
+               kvmppc_set_tcr(vcpu, spr_val);
                break;
 
        /* Note: SPRG4-7 are user-readable. These values are
         * loaded into the real SPRGs when resuming the
         * guest. */
        case SPRN_SPRG4:
-               vcpu->arch.sprg4 = spr_val; break;
+               vcpu->arch.shared->sprg4 = spr_val; break;
        case SPRN_SPRG5:
-               vcpu->arch.sprg5 = spr_val; break;
+               vcpu->arch.shared->sprg5 = spr_val; break;
        case SPRN_SPRG6:
-               vcpu->arch.sprg6 = spr_val; break;
+               vcpu->arch.shared->sprg6 = spr_val; break;
        case SPRN_SPRG7:
-               vcpu->arch.sprg7 = spr_val; break;
+               vcpu->arch.shared->sprg7 = spr_val; break;
 
        case SPRN_IVPR:
                vcpu->arch.ivpr = spr_val;
@@ -202,13 +203,17 @@ int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
        case SPRN_DEAR:
                kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dar); break;
        case SPRN_ESR:
-               kvmppc_set_gpr(vcpu, rt, vcpu->arch.esr); break;
+               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->esr); break;
        case SPRN_DBCR0:
                kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbcr0); break;
        case SPRN_DBCR1:
                kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbcr1); break;
        case SPRN_DBSR:
                kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbsr); break;
+       case SPRN_TSR:
+               kvmppc_set_gpr(vcpu, rt, vcpu->arch.tsr); break;
+       case SPRN_TCR:
+               kvmppc_set_gpr(vcpu, rt, vcpu->arch.tcr); break;
 
        case SPRN_IVOR0:
                kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL]);
index 42f2fb1..10d8ef6 100644 (file)
@@ -402,19 +402,25 @@ lightweight_exit:
        /* Save vcpu pointer for the exception handlers. */
        mtspr   SPRN_SPRG_WVCPU, r4
 
+       lwz     r5, VCPU_SHARED(r4)
+
        /* Can't switch the stack pointer until after IVPR is switched,
         * because host interrupt handlers would get confused. */
        lwz     r1, VCPU_GPR(r1)(r4)
 
-       /* Host interrupt handlers may have clobbered these guest-readable
-        * SPRGs, so we need to reload them here with the guest's values. */
-       lwz     r3, VCPU_SPRG4(r4)
+       /*
+        * Host interrupt handlers may have clobbered these
+        * guest-readable SPRGs, or the guest kernel may have
+        * written directly to the shared area, so we
+        * need to reload them here with the guest's values.
+        */
+       lwz     r3, VCPU_SHARED_SPRG4(r5)
        mtspr   SPRN_SPRG4W, r3
-       lwz     r3, VCPU_SPRG5(r4)
+       lwz     r3, VCPU_SHARED_SPRG5(r5)
        mtspr   SPRN_SPRG5W, r3
-       lwz     r3, VCPU_SPRG6(r4)
+       lwz     r3, VCPU_SHARED_SPRG6(r5)
        mtspr   SPRN_SPRG6W, r3
-       lwz     r3, VCPU_SPRG7(r4)
+       lwz     r3, VCPU_SHARED_SPRG7(r5)
        mtspr   SPRN_SPRG7W, r3
 
 #ifdef CONFIG_KVM_EXIT_TIMING
index 8c0d45a..ddcd896 100644 (file)
@@ -71,9 +71,6 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
        vcpu->arch.pvr = mfspr(SPRN_PVR);
        vcpu_e500->svr = mfspr(SPRN_SVR);
 
-       /* Since booke kvm only support one core, update all vcpus' PIR to 0 */
-       vcpu->vcpu_id = 0;
-
        vcpu->arch.cpu_type = KVM_CPU_E500V2;
 
        return 0;
@@ -118,12 +115,12 @@ void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
        sregs->u.e.impl.fsl.hid0 = vcpu_e500->hid0;
        sregs->u.e.impl.fsl.mcar = vcpu_e500->mcar;
 
-       sregs->u.e.mas0 = vcpu_e500->mas0;
-       sregs->u.e.mas1 = vcpu_e500->mas1;
-       sregs->u.e.mas2 = vcpu_e500->mas2;
-       sregs->u.e.mas7_3 = ((u64)vcpu_e500->mas7 << 32) | vcpu_e500->mas3;
-       sregs->u.e.mas4 = vcpu_e500->mas4;
-       sregs->u.e.mas6 = vcpu_e500->mas6;
+       sregs->u.e.mas0 = vcpu->arch.shared->mas0;
+       sregs->u.e.mas1 = vcpu->arch.shared->mas1;
+       sregs->u.e.mas2 = vcpu->arch.shared->mas2;
+       sregs->u.e.mas7_3 = vcpu->arch.shared->mas7_3;
+       sregs->u.e.mas4 = vcpu->arch.shared->mas4;
+       sregs->u.e.mas6 = vcpu->arch.shared->mas6;
 
        sregs->u.e.mmucfg = mfspr(SPRN_MMUCFG);
        sregs->u.e.tlbcfg[0] = vcpu_e500->tlb0cfg;
@@ -151,13 +148,12 @@ int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
        }
 
        if (sregs->u.e.features & KVM_SREGS_E_ARCH206_MMU) {
-               vcpu_e500->mas0 = sregs->u.e.mas0;
-               vcpu_e500->mas1 = sregs->u.e.mas1;
-               vcpu_e500->mas2 = sregs->u.e.mas2;
-               vcpu_e500->mas7 = sregs->u.e.mas7_3 >> 32;
-               vcpu_e500->mas3 = (u32)sregs->u.e.mas7_3;
-               vcpu_e500->mas4 = sregs->u.e.mas4;
-               vcpu_e500->mas6 = sregs->u.e.mas6;
+               vcpu->arch.shared->mas0 = sregs->u.e.mas0;
+               vcpu->arch.shared->mas1 = sregs->u.e.mas1;
+               vcpu->arch.shared->mas2 = sregs->u.e.mas2;
+               vcpu->arch.shared->mas7_3 = sregs->u.e.mas7_3;
+               vcpu->arch.shared->mas4 = sregs->u.e.mas4;
+               vcpu->arch.shared->mas6 = sregs->u.e.mas6;
        }
 
        if (!(sregs->u.e.features & KVM_SREGS_E_IVOR))
@@ -233,6 +229,10 @@ static int __init kvmppc_e500_init(void)
        unsigned long ivor[3];
        unsigned long max_ivor = 0;
 
+       r = kvmppc_core_check_processor_compat();
+       if (r)
+               return r;
+
        r = kvmppc_booke_init();
        if (r)
                return r;
index d48ae39..6d0b2bd 100644 (file)
@@ -89,19 +89,23 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
                        return EMULATE_FAIL;
                vcpu_e500->pid[2] = spr_val; break;
        case SPRN_MAS0:
-               vcpu_e500->mas0 = spr_val; break;
+               vcpu->arch.shared->mas0 = spr_val; break;
        case SPRN_MAS1:
-               vcpu_e500->mas1 = spr_val; break;
+               vcpu->arch.shared->mas1 = spr_val; break;
        case SPRN_MAS2:
-               vcpu_e500->mas2 = spr_val; break;
+               vcpu->arch.shared->mas2 = spr_val; break;
        case SPRN_MAS3:
-               vcpu_e500->mas3 = spr_val; break;
+               vcpu->arch.shared->mas7_3 &= ~(u64)0xffffffff;
+               vcpu->arch.shared->mas7_3 |= spr_val;
+               break;
        case SPRN_MAS4:
-               vcpu_e500->mas4 = spr_val; break;
+               vcpu->arch.shared->mas4 = spr_val; break;
        case SPRN_MAS6:
-               vcpu_e500->mas6 = spr_val; break;
+               vcpu->arch.shared->mas6 = spr_val; break;
        case SPRN_MAS7:
-               vcpu_e500->mas7 = spr_val; break;
+               vcpu->arch.shared->mas7_3 &= (u64)0xffffffff;
+               vcpu->arch.shared->mas7_3 |= (u64)spr_val << 32;
+               break;
        case SPRN_L1CSR0:
                vcpu_e500->l1csr0 = spr_val;
                vcpu_e500->l1csr0 &= ~(L1CSR0_DCFI | L1CSR0_CLFC);
@@ -143,6 +147,7 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
        int emulated = EMULATE_DONE;
+       unsigned long val;
 
        switch (sprn) {
        case SPRN_PID:
@@ -152,20 +157,23 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
        case SPRN_PID2:
                kvmppc_set_gpr(vcpu, rt, vcpu_e500->pid[2]); break;
        case SPRN_MAS0:
-               kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas0); break;
+               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->mas0); break;
        case SPRN_MAS1:
-               kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas1); break;
+               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->mas1); break;
        case SPRN_MAS2:
-               kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas2); break;
+               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->mas2); break;
        case SPRN_MAS3:
-               kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas3); break;
+               val = (u32)vcpu->arch.shared->mas7_3;
+               kvmppc_set_gpr(vcpu, rt, val);
+               break;
        case SPRN_MAS4:
-               kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas4); break;
+               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->mas4); break;
        case SPRN_MAS6:
-               kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas6); break;
+               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->mas6); break;
        case SPRN_MAS7:
-               kvmppc_set_gpr(vcpu, rt, vcpu_e500->mas7); break;
-
+               val = vcpu->arch.shared->mas7_3 >> 32;
+               kvmppc_set_gpr(vcpu, rt, val);
+               break;
        case SPRN_TLB0CFG:
                kvmppc_set_gpr(vcpu, rt, vcpu_e500->tlb0cfg); break;
        case SPRN_TLB1CFG:
index 13c432e..6e53e41 100644 (file)
  * published by the Free Software Foundation.
  */
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/highmem.h>
+#include <linux/log2.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/rwsem.h>
+#include <linux/vmalloc.h>
+#include <linux/hugetlb.h>
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_e500.h>
 
@@ -26,7 +33,7 @@
 #include "trace.h"
 #include "timing.h"
 
-#define to_htlb1_esel(esel) (tlb1_entry_num - (esel) - 1)
+#define to_htlb1_esel(esel) (host_tlb_params[1].entries - (esel) - 1)
 
 struct id {
        unsigned long val;
@@ -63,7 +70,14 @@ static DEFINE_PER_CPU(struct pcpu_id_table, pcpu_sids);
  * The valid range of shadow ID is [1..255] */
 static DEFINE_PER_CPU(unsigned long, pcpu_last_used_sid);
 
-static unsigned int tlb1_entry_num;
+static struct kvmppc_e500_tlb_params host_tlb_params[E500_TLB_NUM];
+
+static struct kvm_book3e_206_tlb_entry *get_entry(
+       struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel, int entry)
+{
+       int offset = vcpu_e500->gtlb_offset[tlbsel];
+       return &vcpu_e500->gtlb_arch[offset + entry];
+}
 
 /*
  * Allocate a free shadow id and setup a valid sid mapping in given entry.
@@ -116,13 +130,11 @@ static inline int local_sid_lookup(struct id *entry)
        return -1;
 }
 
-/* Invalidate all id mappings on local core */
+/* Invalidate all id mappings on local core -- call with preempt disabled */
 static inline void local_sid_destroy_all(void)
 {
-       preempt_disable();
        __get_cpu_var(pcpu_last_used_sid) = 0;
        memset(&__get_cpu_var(pcpu_sids), 0, sizeof(__get_cpu_var(pcpu_sids)));
-       preempt_enable();
 }
 
 static void *kvmppc_e500_id_table_alloc(struct kvmppc_vcpu_e500 *vcpu_e500)
@@ -218,34 +230,13 @@ void kvmppc_e500_recalc_shadow_pid(struct kvmppc_vcpu_e500 *vcpu_e500)
        preempt_enable();
 }
 
-void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
-{
-       struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-       struct tlbe *tlbe;
-       int i, tlbsel;
-
-       printk("| %8s | %8s | %8s | %8s | %8s |\n",
-                       "nr", "mas1", "mas2", "mas3", "mas7");
-
-       for (tlbsel = 0; tlbsel < 2; tlbsel++) {
-               printk("Guest TLB%d:\n", tlbsel);
-               for (i = 0; i < vcpu_e500->gtlb_size[tlbsel]; i++) {
-                       tlbe = &vcpu_e500->gtlb_arch[tlbsel][i];
-                       if (tlbe->mas1 & MAS1_VALID)
-                               printk(" G[%d][%3d] |  %08X | %08X | %08X | %08X |\n",
-                                       tlbsel, i, tlbe->mas1, tlbe->mas2,
-                                       tlbe->mas3, tlbe->mas7);
-               }
-       }
-}
-
-static inline unsigned int tlb0_get_next_victim(
+static inline unsigned int gtlb0_get_next_victim(
                struct kvmppc_vcpu_e500 *vcpu_e500)
 {
        unsigned int victim;
 
        victim = vcpu_e500->gtlb_nv[0]++;
-       if (unlikely(vcpu_e500->gtlb_nv[0] >= KVM_E500_TLB0_WAY_NUM))
+       if (unlikely(vcpu_e500->gtlb_nv[0] >= vcpu_e500->gtlb_params[0].ways))
                vcpu_e500->gtlb_nv[0] = 0;
 
        return victim;
@@ -254,12 +245,12 @@ static inline unsigned int tlb0_get_next_victim(
 static inline unsigned int tlb1_max_shadow_size(void)
 {
        /* reserve one entry for magic page */
-       return tlb1_entry_num - tlbcam_index - 1;
+       return host_tlb_params[1].entries - tlbcam_index - 1;
 }
 
-static inline int tlbe_is_writable(struct tlbe *tlbe)
+static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)
 {
-       return tlbe->mas3 & (MAS3_SW|MAS3_UW);
+       return tlbe->mas7_3 & (MAS3_SW|MAS3_UW);
 }
 
 static inline u32 e500_shadow_mas3_attrib(u32 mas3, int usermode)
@@ -290,40 +281,66 @@ static inline u32 e500_shadow_mas2_attrib(u32 mas2, int usermode)
 /*
  * writing shadow tlb entry to host TLB
  */
-static inline void __write_host_tlbe(struct tlbe *stlbe, uint32_t mas0)
+static inline void __write_host_tlbe(struct kvm_book3e_206_tlb_entry *stlbe,
+                                    uint32_t mas0)
 {
        unsigned long flags;
 
        local_irq_save(flags);
        mtspr(SPRN_MAS0, mas0);
        mtspr(SPRN_MAS1, stlbe->mas1);
-       mtspr(SPRN_MAS2, stlbe->mas2);
-       mtspr(SPRN_MAS3, stlbe->mas3);
-       mtspr(SPRN_MAS7, stlbe->mas7);
+       mtspr(SPRN_MAS2, (unsigned long)stlbe->mas2);
+       mtspr(SPRN_MAS3, (u32)stlbe->mas7_3);
+       mtspr(SPRN_MAS7, (u32)(stlbe->mas7_3 >> 32));
        asm volatile("isync; tlbwe" : : : "memory");
        local_irq_restore(flags);
+
+       trace_kvm_booke206_stlb_write(mas0, stlbe->mas8, stlbe->mas1,
+                                     stlbe->mas2, stlbe->mas7_3);
+}
+
+/*
+ * Acquire a mas0 with victim hint, as if we just took a TLB miss.
+ *
+ * We don't care about the address we're searching for, other than that it's
+ * in the right set and is not present in the TLB.  Using a zero PID and a
+ * userspace address means we don't have to set and then restore MAS5, or
+ * calculate a proper MAS6 value.
+ */
+static u32 get_host_mas0(unsigned long eaddr)
+{
+       unsigned long flags;
+       u32 mas0;
+
+       local_irq_save(flags);
+       mtspr(SPRN_MAS6, 0);
+       asm volatile("tlbsx 0, %0" : : "b" (eaddr & ~CONFIG_PAGE_OFFSET));
+       mas0 = mfspr(SPRN_MAS0);
+       local_irq_restore(flags);
+
+       return mas0;
 }
 
+/* sesel is for tlb1 only */
 static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
-               int tlbsel, int esel, struct tlbe *stlbe)
+               int tlbsel, int sesel, struct kvm_book3e_206_tlb_entry *stlbe)
 {
+       u32 mas0;
+
        if (tlbsel == 0) {
-               __write_host_tlbe(stlbe,
-                                 MAS0_TLBSEL(0) |
-                                 MAS0_ESEL(esel & (KVM_E500_TLB0_WAY_NUM - 1)));
+               mas0 = get_host_mas0(stlbe->mas2);
+               __write_host_tlbe(stlbe, mas0);
        } else {
                __write_host_tlbe(stlbe,
                                  MAS0_TLBSEL(1) |
-                                 MAS0_ESEL(to_htlb1_esel(esel)));
+                                 MAS0_ESEL(to_htlb1_esel(sesel)));
        }
-       trace_kvm_stlb_write(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2,
-                            stlbe->mas3, stlbe->mas7);
 }
 
 void kvmppc_map_magic(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-       struct tlbe magic;
+       struct kvm_book3e_206_tlb_entry magic;
        ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
        unsigned int stid;
        pfn_t pfn;
@@ -337,9 +354,9 @@ void kvmppc_map_magic(struct kvm_vcpu *vcpu)
        magic.mas1 = MAS1_VALID | MAS1_TS | MAS1_TID(stid) |
                     MAS1_TSIZE(BOOK3E_PAGESZ_4K);
        magic.mas2 = vcpu->arch.magic_page_ea | MAS2_M;
-       magic.mas3 = (pfn << PAGE_SHIFT) |
-                    MAS3_SW | MAS3_SR | MAS3_UW | MAS3_UR;
-       magic.mas7 = pfn >> (32 - PAGE_SHIFT);
+       magic.mas7_3 = ((u64)pfn << PAGE_SHIFT) |
+                      MAS3_SW | MAS3_SR | MAS3_UW | MAS3_UR;
+       magic.mas8 = 0;
 
        __write_host_tlbe(&magic, MAS0_TLBSEL(1) | MAS0_ESEL(tlbcam_index));
        preempt_enable();
@@ -357,10 +374,11 @@ void kvmppc_e500_tlb_put(struct kvm_vcpu *vcpu)
 {
 }
 
-static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500,
-                                        int tlbsel, int esel)
+static void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500,
+                               int tlbsel, int esel)
 {
-       struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
+       struct kvm_book3e_206_tlb_entry *gtlbe =
+               get_entry(vcpu_e500, tlbsel, esel);
        struct vcpu_id_table *idt = vcpu_e500->idt;
        unsigned int pr, tid, ts, pid;
        u32 val, eaddr;
@@ -414,25 +432,57 @@ static void kvmppc_e500_stlbe_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500,
        preempt_enable();
 }
 
+static int tlb0_set_base(gva_t addr, int sets, int ways)
+{
+       int set_base;
+
+       set_base = (addr >> PAGE_SHIFT) & (sets - 1);
+       set_base *= ways;
+
+       return set_base;
+}
+
+static int gtlb0_set_base(struct kvmppc_vcpu_e500 *vcpu_e500, gva_t addr)
+{
+       return tlb0_set_base(addr, vcpu_e500->gtlb_params[0].sets,
+                            vcpu_e500->gtlb_params[0].ways);
+}
+
+static unsigned int get_tlb_esel(struct kvm_vcpu *vcpu, int tlbsel)
+{
+       struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+       int esel = get_tlb_esel_bit(vcpu);
+
+       if (tlbsel == 0) {
+               esel &= vcpu_e500->gtlb_params[0].ways - 1;
+               esel += gtlb0_set_base(vcpu_e500, vcpu->arch.shared->mas2);
+       } else {
+               esel &= vcpu_e500->gtlb_params[tlbsel].entries - 1;
+       }
+
+       return esel;
+}
+
 /* Search the guest TLB for a matching entry. */
 static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500,
                gva_t eaddr, int tlbsel, unsigned int pid, int as)
 {
-       int size = vcpu_e500->gtlb_size[tlbsel];
-       int set_base;
+       int size = vcpu_e500->gtlb_params[tlbsel].entries;
+       unsigned int set_base, offset;
        int i;
 
        if (tlbsel == 0) {
-               int mask = size / KVM_E500_TLB0_WAY_NUM - 1;
-               set_base = (eaddr >> PAGE_SHIFT) & mask;
-               set_base *= KVM_E500_TLB0_WAY_NUM;
-               size = KVM_E500_TLB0_WAY_NUM;
+               set_base = gtlb0_set_base(vcpu_e500, eaddr);
+               size = vcpu_e500->gtlb_params[0].ways;
        } else {
                set_base = 0;
        }
 
+       offset = vcpu_e500->gtlb_offset[tlbsel];
+
        for (i = 0; i < size; i++) {
-               struct tlbe *tlbe = &vcpu_e500->gtlb_arch[tlbsel][set_base + i];
+               struct kvm_book3e_206_tlb_entry *tlbe =
+                       &vcpu_e500->gtlb_arch[offset + set_base + i];
                unsigned int tid;
 
                if (eaddr < get_tlb_eaddr(tlbe))
@@ -457,27 +507,55 @@ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500,
        return -1;
 }
 
-static inline void kvmppc_e500_priv_setup(struct tlbe_priv *priv,
-                                         struct tlbe *gtlbe,
-                                         pfn_t pfn)
+static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
+                                        struct kvm_book3e_206_tlb_entry *gtlbe,
+                                        pfn_t pfn)
 {
-       priv->pfn = pfn;
-       priv->flags = E500_TLB_VALID;
+       ref->pfn = pfn;
+       ref->flags = E500_TLB_VALID;
 
        if (tlbe_is_writable(gtlbe))
-               priv->flags |= E500_TLB_DIRTY;
+               ref->flags |= E500_TLB_DIRTY;
 }
 
-static inline void kvmppc_e500_priv_release(struct tlbe_priv *priv)
+static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
 {
-       if (priv->flags & E500_TLB_VALID) {
-               if (priv->flags & E500_TLB_DIRTY)
-                       kvm_release_pfn_dirty(priv->pfn);
+       if (ref->flags & E500_TLB_VALID) {
+               if (ref->flags & E500_TLB_DIRTY)
+                       kvm_release_pfn_dirty(ref->pfn);
                else
-                       kvm_release_pfn_clean(priv->pfn);
+                       kvm_release_pfn_clean(ref->pfn);
+
+               ref->flags = 0;
+       }
+}
+
+static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+       int tlbsel = 0;
+       int i;
+
+       for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) {
+               struct tlbe_ref *ref =
+                       &vcpu_e500->gtlb_priv[tlbsel][i].ref;
+               kvmppc_e500_ref_release(ref);
+       }
+}
+
+static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+       int stlbsel = 1;
+       int i;
+
+       kvmppc_e500_id_table_reset_all(vcpu_e500);
 
-               priv->flags = 0;
+       for (i = 0; i < host_tlb_params[stlbsel].entries; i++) {
+               struct tlbe_ref *ref =
+                       &vcpu_e500->tlb_refs[stlbsel][i];
+               kvmppc_e500_ref_release(ref);
        }
+
+       clear_tlb_privs(vcpu_e500);
 }
 
 static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
@@ -488,59 +566,54 @@ static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
        int tlbsel;
 
        /* since we only have two TLBs, only lower bit is used. */
-       tlbsel = (vcpu_e500->mas4 >> 28) & 0x1;
-       victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0;
-       pidsel = (vcpu_e500->mas4 >> 16) & 0xf;
-       tsized = (vcpu_e500->mas4 >> 7) & 0x1f;
+       tlbsel = (vcpu->arch.shared->mas4 >> 28) & 0x1;
+       victim = (tlbsel == 0) ? gtlb0_get_next_victim(vcpu_e500) : 0;
+       pidsel = (vcpu->arch.shared->mas4 >> 16) & 0xf;
+       tsized = (vcpu->arch.shared->mas4 >> 7) & 0x1f;
 
-       vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim)
+       vcpu->arch.shared->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim)
                | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
-       vcpu_e500->mas1 = MAS1_VALID | (as ? MAS1_TS : 0)
+       vcpu->arch.shared->mas1 = MAS1_VALID | (as ? MAS1_TS : 0)
                | MAS1_TID(vcpu_e500->pid[pidsel])
                | MAS1_TSIZE(tsized);
-       vcpu_e500->mas2 = (eaddr & MAS2_EPN)
-               | (vcpu_e500->mas4 & MAS2_ATTRIB_MASK);
-       vcpu_e500->mas3 &= MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3;
-       vcpu_e500->mas6 = (vcpu_e500->mas6 & MAS6_SPID1)
+       vcpu->arch.shared->mas2 = (eaddr & MAS2_EPN)
+               | (vcpu->arch.shared->mas4 & MAS2_ATTRIB_MASK);
+       vcpu->arch.shared->mas7_3 &= MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3;
+       vcpu->arch.shared->mas6 = (vcpu->arch.shared->mas6 & MAS6_SPID1)
                | (get_cur_pid(vcpu) << 16)
                | (as ? MAS6_SAS : 0);
-       vcpu_e500->mas7 = 0;
 }
 
-static inline void kvmppc_e500_setup_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
-                                          struct tlbe *gtlbe, int tsize,
-                                          struct tlbe_priv *priv,
-                                          u64 gvaddr, struct tlbe *stlbe)
+/* TID must be supplied by the caller */
+static inline void kvmppc_e500_setup_stlbe(
+       struct kvmppc_vcpu_e500 *vcpu_e500,
+       struct kvm_book3e_206_tlb_entry *gtlbe,
+       int tsize, struct tlbe_ref *ref, u64 gvaddr,
+       struct kvm_book3e_206_tlb_entry *stlbe)
 {
-       pfn_t pfn = priv->pfn;
-       unsigned int stid;
+       pfn_t pfn = ref->pfn;
 
-       stid = kvmppc_e500_get_sid(vcpu_e500, get_tlb_ts(gtlbe),
-                                  get_tlb_tid(gtlbe),
-                                  get_cur_pr(&vcpu_e500->vcpu), 0);
+       BUG_ON(!(ref->flags & E500_TLB_VALID));
 
        /* Force TS=1 IPROT=0 for all guest mappings. */
-       stlbe->mas1 = MAS1_TSIZE(tsize)
-               | MAS1_TID(stid) | MAS1_TS | MAS1_VALID;
+       stlbe->mas1 = MAS1_TSIZE(tsize) | MAS1_TS | MAS1_VALID;
        stlbe->mas2 = (gvaddr & MAS2_EPN)
                | e500_shadow_mas2_attrib(gtlbe->mas2,
                                vcpu_e500->vcpu.arch.shared->msr & MSR_PR);
-       stlbe->mas3 = ((pfn << PAGE_SHIFT) & MAS3_RPN)
-               | e500_shadow_mas3_attrib(gtlbe->mas3,
+       stlbe->mas7_3 = ((u64)pfn << PAGE_SHIFT)
+               | e500_shadow_mas3_attrib(gtlbe->mas7_3,
                                vcpu_e500->vcpu.arch.shared->msr & MSR_PR);
-       stlbe->mas7 = (pfn >> (32 - PAGE_SHIFT)) & MAS7_RPN;
 }
 
-
 static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
-       u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, int tlbsel, int esel,
-       struct tlbe *stlbe)
+       u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
+       int tlbsel, struct kvm_book3e_206_tlb_entry *stlbe,
+       struct tlbe_ref *ref)
 {
        struct kvm_memory_slot *slot;
        unsigned long pfn, hva;
        int pfnmap = 0;
        int tsize = BOOK3E_PAGESZ_4K;
-       struct tlbe_priv *priv;
 
        /*
         * Translate guest physical to true physical, acquiring
@@ -621,12 +694,31 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                                pfn &= ~(tsize_pages - 1);
                                break;
                        }
+               } else if (vma && hva >= vma->vm_start &&
+                          (vma->vm_flags & VM_HUGETLB)) {
+                       unsigned long psize = vma_kernel_pagesize(vma);
+
+                       tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >>
+                               MAS1_TSIZE_SHIFT;
+
+                       /*
+                        * Take the largest page size that satisfies both host
+                        * and guest mapping
+                        */
+                       tsize = min(__ilog2(psize) - 10, tsize);
+
+                       /*
+                        * e500 doesn't implement the lowest tsize bit,
+                        * or 1K pages.
+                        */
+                       tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1);
                }
 
                up_read(&current->mm->mmap_sem);
        }
 
        if (likely(!pfnmap)) {
+               unsigned long tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT);
                pfn = gfn_to_pfn_memslot(vcpu_e500->vcpu.kvm, slot, gfn);
                if (is_error_pfn(pfn)) {
                        printk(KERN_ERR "Couldn't get real page for gfn %lx!\n",
@@ -634,45 +726,52 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                        kvm_release_pfn_clean(pfn);
                        return;
                }
+
+               /* Align guest and physical address to page map boundaries */
+               pfn &= ~(tsize_pages - 1);
+               gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
        }
 
-       /* Drop old priv and setup new one. */
-       priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
-       kvmppc_e500_priv_release(priv);
-       kvmppc_e500_priv_setup(priv, gtlbe, pfn);
+       /* Drop old ref and setup new one. */
+       kvmppc_e500_ref_release(ref);
+       kvmppc_e500_ref_setup(ref, gtlbe, pfn);
 
-       kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, tsize, priv, gvaddr, stlbe);
+       kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, tsize, ref, gvaddr, stlbe);
 }
 
 /* XXX only map the one-one case, for now use TLB0 */
-static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500,
-                               int esel, struct tlbe *stlbe)
+static void kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500,
+                                int esel,
+                                struct kvm_book3e_206_tlb_entry *stlbe)
 {
-       struct tlbe *gtlbe;
+       struct kvm_book3e_206_tlb_entry *gtlbe;
+       struct tlbe_ref *ref;
 
-       gtlbe = &vcpu_e500->gtlb_arch[0][esel];
+       gtlbe = get_entry(vcpu_e500, 0, esel);
+       ref = &vcpu_e500->gtlb_priv[0][esel].ref;
 
        kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe),
                        get_tlb_raddr(gtlbe) >> PAGE_SHIFT,
-                       gtlbe, 0, esel, stlbe);
-
-       return esel;
+                       gtlbe, 0, stlbe, ref);
 }
 
 /* Caller must ensure that the specified guest TLB entry is safe to insert into
  * the shadow TLB. */
 /* XXX for both one-one and one-to-many , for now use TLB1 */
 static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,
-               u64 gvaddr, gfn_t gfn, struct tlbe *gtlbe, struct tlbe *stlbe)
+               u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
+               struct kvm_book3e_206_tlb_entry *stlbe)
 {
+       struct tlbe_ref *ref;
        unsigned int victim;
 
-       victim = vcpu_e500->gtlb_nv[1]++;
+       victim = vcpu_e500->host_tlb1_nv++;
 
-       if (unlikely(vcpu_e500->gtlb_nv[1] >= tlb1_max_shadow_size()))
-               vcpu_e500->gtlb_nv[1] = 0;
+       if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size()))
+               vcpu_e500->host_tlb1_nv = 0;
 
-       kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, victim, stlbe);
+       ref = &vcpu_e500->tlb_refs[1][victim];
+       kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe, ref);
 
        return victim;
 }
@@ -689,7 +788,8 @@ static inline int kvmppc_e500_gtlbe_invalidate(
                                struct kvmppc_vcpu_e500 *vcpu_e500,
                                int tlbsel, int esel)
 {
-       struct tlbe *gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
+       struct kvm_book3e_206_tlb_entry *gtlbe =
+               get_entry(vcpu_e500, tlbsel, esel);
 
        if (unlikely(get_tlb_iprot(gtlbe)))
                return -1;
@@ -704,10 +804,10 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500, ulong value)
        int esel;
 
        if (value & MMUCSR0_TLB0FI)
-               for (esel = 0; esel < vcpu_e500->gtlb_size[0]; esel++)
+               for (esel = 0; esel < vcpu_e500->gtlb_params[0].entries; esel++)
                        kvmppc_e500_gtlbe_invalidate(vcpu_e500, 0, esel);
        if (value & MMUCSR0_TLB1FI)
-               for (esel = 0; esel < vcpu_e500->gtlb_size[1]; esel++)
+               for (esel = 0; esel < vcpu_e500->gtlb_params[1].entries; esel++)
                        kvmppc_e500_gtlbe_invalidate(vcpu_e500, 1, esel);
 
        /* Invalidate all vcpu id mappings */
@@ -732,7 +832,8 @@ int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb)
 
        if (ia) {
                /* invalidate all entries */
-               for (esel = 0; esel < vcpu_e500->gtlb_size[tlbsel]; esel++)
+               for (esel = 0; esel < vcpu_e500->gtlb_params[tlbsel].entries;
+                    esel++)
                        kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
        } else {
                ea &= 0xfffff000;
@@ -752,18 +853,17 @@ int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
        int tlbsel, esel;
-       struct tlbe *gtlbe;
+       struct kvm_book3e_206_tlb_entry *gtlbe;
 
-       tlbsel = get_tlb_tlbsel(vcpu_e500);
-       esel = get_tlb_esel(vcpu_e500, tlbsel);
+       tlbsel = get_tlb_tlbsel(vcpu);
+       esel = get_tlb_esel(vcpu, tlbsel);
 
-       gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
-       vcpu_e500->mas0 &= ~MAS0_NV(~0);
-       vcpu_e500->mas0 |= MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
-       vcpu_e500->mas1 = gtlbe->mas1;
-       vcpu_e500->mas2 = gtlbe->mas2;
-       vcpu_e500->mas3 = gtlbe->mas3;
-       vcpu_e500->mas7 = gtlbe->mas7;
+       gtlbe = get_entry(vcpu_e500, tlbsel, esel);
+       vcpu->arch.shared->mas0 &= ~MAS0_NV(~0);
+       vcpu->arch.shared->mas0 |= MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
+       vcpu->arch.shared->mas1 = gtlbe->mas1;
+       vcpu->arch.shared->mas2 = gtlbe->mas2;
+       vcpu->arch.shared->mas7_3 = gtlbe->mas7_3;
 
        return EMULATE_DONE;
 }
@@ -771,10 +871,10 @@ int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu)
 int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-       int as = !!get_cur_sas(vcpu_e500);
-       unsigned int pid = get_cur_spid(vcpu_e500);
+       int as = !!get_cur_sas(vcpu);
+       unsigned int pid = get_cur_spid(vcpu);
        int esel, tlbsel;
-       struct tlbe *gtlbe = NULL;
+       struct kvm_book3e_206_tlb_entry *gtlbe = NULL;
        gva_t ea;
 
        ea = kvmppc_get_gpr(vcpu, rb);
@@ -782,70 +882,90 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb)
        for (tlbsel = 0; tlbsel < 2; tlbsel++) {
                esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, as);
                if (esel >= 0) {
-                       gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
+                       gtlbe = get_entry(vcpu_e500, tlbsel, esel);
                        break;
                }
        }
 
        if (gtlbe) {
-               vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(esel)
+               esel &= vcpu_e500->gtlb_params[tlbsel].ways - 1;
+
+               vcpu->arch.shared->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(esel)
                        | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
-               vcpu_e500->mas1 = gtlbe->mas1;
-               vcpu_e500->mas2 = gtlbe->mas2;
-               vcpu_e500->mas3 = gtlbe->mas3;
-               vcpu_e500->mas7 = gtlbe->mas7;
+               vcpu->arch.shared->mas1 = gtlbe->mas1;
+               vcpu->arch.shared->mas2 = gtlbe->mas2;
+               vcpu->arch.shared->mas7_3 = gtlbe->mas7_3;
        } else {
                int victim;
 
                /* since we only have two TLBs, only lower bit is used. */
-               tlbsel = vcpu_e500->mas4 >> 28 & 0x1;
-               victim = (tlbsel == 0) ? tlb0_get_next_victim(vcpu_e500) : 0;
+               tlbsel = vcpu->arch.shared->mas4 >> 28 & 0x1;
+               victim = (tlbsel == 0) ? gtlb0_get_next_victim(vcpu_e500) : 0;
 
-               vcpu_e500->mas0 = MAS0_TLBSEL(tlbsel) | MAS0_ESEL(victim)
+               vcpu->arch.shared->mas0 = MAS0_TLBSEL(tlbsel)
+                       | MAS0_ESEL(victim)
                        | MAS0_NV(vcpu_e500->gtlb_nv[tlbsel]);
-               vcpu_e500->mas1 = (vcpu_e500->mas6 & MAS6_SPID0)
-                       | (vcpu_e500->mas6 & (MAS6_SAS ? MAS1_TS : 0))
-                       | (vcpu_e500->mas4 & MAS4_TSIZED(~0));
-               vcpu_e500->mas2 &= MAS2_EPN;
-               vcpu_e500->mas2 |= vcpu_e500->mas4 & MAS2_ATTRIB_MASK;
-               vcpu_e500->mas3 &= MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3;
-               vcpu_e500->mas7 = 0;
+               vcpu->arch.shared->mas1 =
+                         (vcpu->arch.shared->mas6 & MAS6_SPID0)
+                       | (vcpu->arch.shared->mas6 & (MAS6_SAS ? MAS1_TS : 0))
+                       | (vcpu->arch.shared->mas4 & MAS4_TSIZED(~0));
+               vcpu->arch.shared->mas2 &= MAS2_EPN;
+               vcpu->arch.shared->mas2 |= vcpu->arch.shared->mas4 &
+                                          MAS2_ATTRIB_MASK;
+               vcpu->arch.shared->mas7_3 &= MAS3_U0 | MAS3_U1 |
+                                            MAS3_U2 | MAS3_U3;
        }
 
        kvmppc_set_exit_type(vcpu, EMULATED_TLBSX_EXITS);
        return EMULATE_DONE;
 }
 
+/* sesel is for tlb1 only */
+static void write_stlbe(struct kvmppc_vcpu_e500 *vcpu_e500,
+                       struct kvm_book3e_206_tlb_entry *gtlbe,
+                       struct kvm_book3e_206_tlb_entry *stlbe,
+                       int stlbsel, int sesel)
+{
+       int stid;
+
+       preempt_disable();
+       stid = kvmppc_e500_get_sid(vcpu_e500, get_tlb_ts(gtlbe),
+                                  get_tlb_tid(gtlbe),
+                                  get_cur_pr(&vcpu_e500->vcpu), 0);
+
+       stlbe->mas1 |= MAS1_TID(stid);
+       write_host_tlbe(vcpu_e500, stlbsel, sesel, stlbe);
+       preempt_enable();
+}
+
 int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-       struct tlbe *gtlbe;
+       struct kvm_book3e_206_tlb_entry *gtlbe;
        int tlbsel, esel;
 
-       tlbsel = get_tlb_tlbsel(vcpu_e500);
-       esel = get_tlb_esel(vcpu_e500, tlbsel);
+       tlbsel = get_tlb_tlbsel(vcpu);
+       esel = get_tlb_esel(vcpu, tlbsel);
 
-       gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
+       gtlbe = get_entry(vcpu_e500, tlbsel, esel);
 
        if (get_tlb_v(gtlbe))
-               kvmppc_e500_stlbe_invalidate(vcpu_e500, tlbsel, esel);
+               inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
 
-       gtlbe->mas1 = vcpu_e500->mas1;
-       gtlbe->mas2 = vcpu_e500->mas2;
-       gtlbe->mas3 = vcpu_e500->mas3;
-       gtlbe->mas7 = vcpu_e500->mas7;
+       gtlbe->mas1 = vcpu->arch.shared->mas1;
+       gtlbe->mas2 = vcpu->arch.shared->mas2;
+       gtlbe->mas7_3 = vcpu->arch.shared->mas7_3;
 
-       trace_kvm_gtlb_write(vcpu_e500->mas0, gtlbe->mas1, gtlbe->mas2,
-                            gtlbe->mas3, gtlbe->mas7);
+       trace_kvm_booke206_gtlb_write(vcpu->arch.shared->mas0, gtlbe->mas1,
+                                     gtlbe->mas2, gtlbe->mas7_3);
 
        /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
        if (tlbe_is_host_safe(vcpu, gtlbe)) {
-               struct tlbe stlbe;
+               struct kvm_book3e_206_tlb_entry stlbe;
                int stlbsel, sesel;
                u64 eaddr;
                u64 raddr;
 
-               preempt_disable();
                switch (tlbsel) {
                case 0:
                        /* TLB0 */
@@ -853,7 +973,8 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
                        gtlbe->mas1 |= MAS1_TSIZE(BOOK3E_PAGESZ_4K);
 
                        stlbsel = 0;
-                       sesel = kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
+                       kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
+                       sesel = 0; /* unused */
 
                        break;
 
@@ -874,8 +995,8 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
                default:
                        BUG();
                }
-               write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe);
-               preempt_enable();
+
+               write_stlbe(vcpu_e500, gtlbe, &stlbe, stlbsel, sesel);
        }
 
        kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS);
@@ -914,9 +1035,11 @@ gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int index,
                        gva_t eaddr)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
-       struct tlbe *gtlbe =
-               &vcpu_e500->gtlb_arch[tlbsel_of(index)][esel_of(index)];
-       u64 pgmask = get_tlb_bytes(gtlbe) - 1;
+       struct kvm_book3e_206_tlb_entry *gtlbe;
+       u64 pgmask;
+
+       gtlbe = get_entry(vcpu_e500, tlbsel_of(index), esel_of(index));
+       pgmask = get_tlb_bytes(gtlbe) - 1;
 
        return get_tlb_raddr(gtlbe) | (eaddr & pgmask);
 }
@@ -930,22 +1053,21 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
        struct tlbe_priv *priv;
-       struct tlbe *gtlbe, stlbe;
+       struct kvm_book3e_206_tlb_entry *gtlbe, stlbe;
        int tlbsel = tlbsel_of(index);
        int esel = esel_of(index);
        int stlbsel, sesel;
 
-       gtlbe = &vcpu_e500->gtlb_arch[tlbsel][esel];
+       gtlbe = get_entry(vcpu_e500, tlbsel, esel);
 
-       preempt_disable();
        switch (tlbsel) {
        case 0:
                stlbsel = 0;
-               sesel = esel;
-               priv = &vcpu_e500->gtlb_priv[stlbsel][sesel];
+               sesel = 0; /* unused */
+               priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
 
                kvmppc_e500_setup_stlbe(vcpu_e500, gtlbe, BOOK3E_PAGESZ_4K,
-                                       priv, eaddr, &stlbe);
+                                       &priv->ref, eaddr, &stlbe);
                break;
 
        case 1: {
@@ -962,8 +1084,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
                break;
        }
 
-       write_host_tlbe(vcpu_e500, stlbsel, sesel, &stlbe);
-       preempt_enable();
+       write_stlbe(vcpu_e500, gtlbe, &stlbe, stlbsel, sesel);
 }
 
 int kvmppc_e500_tlb_search(struct kvm_vcpu *vcpu,
@@ -993,85 +1114,279 @@ void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid)
 
 void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
-       struct tlbe *tlbe;
+       struct kvm_book3e_206_tlb_entry *tlbe;
 
        /* Insert large initial mapping for guest. */
-       tlbe = &vcpu_e500->gtlb_arch[1][0];
+       tlbe = get_entry(vcpu_e500, 1, 0);
        tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_256M);
        tlbe->mas2 = 0;
-       tlbe->mas3 = E500_TLB_SUPER_PERM_MASK;
-       tlbe->mas7 = 0;
+       tlbe->mas7_3 = E500_TLB_SUPER_PERM_MASK;
 
        /* 4K map for serial output. Used by kernel wrapper. */
-       tlbe = &vcpu_e500->gtlb_arch[1][1];
+       tlbe = get_entry(vcpu_e500, 1, 1);
        tlbe->mas1 = MAS1_VALID | MAS1_TSIZE(BOOK3E_PAGESZ_4K);
        tlbe->mas2 = (0xe0004500 & 0xFFFFF000) | MAS2_I | MAS2_G;
-       tlbe->mas3 = (0xe0004500 & 0xFFFFF000) | E500_TLB_SUPER_PERM_MASK;
-       tlbe->mas7 = 0;
+       tlbe->mas7_3 = (0xe0004500 & 0xFFFFF000) | E500_TLB_SUPER_PERM_MASK;
+}
+
+static void free_gtlb(struct kvmppc_vcpu_e500 *vcpu_e500)
+{
+       int i;
+
+       clear_tlb_refs(vcpu_e500);
+       kfree(vcpu_e500->gtlb_priv[0]);
+       kfree(vcpu_e500->gtlb_priv[1]);
+
+       if (vcpu_e500->shared_tlb_pages) {
+               vfree((void *)(round_down((uintptr_t)vcpu_e500->gtlb_arch,
+                                         PAGE_SIZE)));
+
+               for (i = 0; i < vcpu_e500->num_shared_tlb_pages; i++) {
+                       set_page_dirty_lock(vcpu_e500->shared_tlb_pages[i]);
+                       put_page(vcpu_e500->shared_tlb_pages[i]);
+               }
+
+               vcpu_e500->num_shared_tlb_pages = 0;
+               vcpu_e500->shared_tlb_pages = NULL;
+       } else {
+               kfree(vcpu_e500->gtlb_arch);
+       }
+
+       vcpu_e500->gtlb_arch = NULL;
+}
+
+int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
+                             struct kvm_config_tlb *cfg)
+{
+       struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+       struct kvm_book3e_206_tlb_params params;
+       char *virt;
+       struct page **pages;
+       struct tlbe_priv *privs[2] = {};
+       size_t array_len;
+       u32 sets;
+       int num_pages, ret, i;
+
+       if (cfg->mmu_type != KVM_MMU_FSL_BOOKE_NOHV)
+               return -EINVAL;
+
+       if (copy_from_user(&params, (void __user *)(uintptr_t)cfg->params,
+                          sizeof(params)))
+               return -EFAULT;
+
+       if (params.tlb_sizes[1] > 64)
+               return -EINVAL;
+       if (params.tlb_ways[1] != params.tlb_sizes[1])
+               return -EINVAL;
+       if (params.tlb_sizes[2] != 0 || params.tlb_sizes[3] != 0)
+               return -EINVAL;
+       if (params.tlb_ways[2] != 0 || params.tlb_ways[3] != 0)
+               return -EINVAL;
+
+       if (!is_power_of_2(params.tlb_ways[0]))
+               return -EINVAL;
+
+       sets = params.tlb_sizes[0] >> ilog2(params.tlb_ways[0]);
+       if (!is_power_of_2(sets))
+               return -EINVAL;
+
+       array_len = params.tlb_sizes[0] + params.tlb_sizes[1];
+       array_len *= sizeof(struct kvm_book3e_206_tlb_entry);
+
+       if (cfg->array_len < array_len)
+               return -EINVAL;
+
+       num_pages = DIV_ROUND_UP(cfg->array + array_len - 1, PAGE_SIZE) -
+                   cfg->array / PAGE_SIZE;
+       pages = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
+       if (!pages)
+               return -ENOMEM;
+
+       ret = get_user_pages_fast(cfg->array, num_pages, 1, pages);
+       if (ret < 0)
+               goto err_pages;
+
+       if (ret != num_pages) {
+               num_pages = ret;
+               ret = -EFAULT;
+               goto err_put_page;
+       }
+
+       virt = vmap(pages, num_pages, VM_MAP, PAGE_KERNEL);
+       if (!virt)
+               goto err_put_page;
+
+       privs[0] = kzalloc(sizeof(struct tlbe_priv) * params.tlb_sizes[0],
+                          GFP_KERNEL);
+       privs[1] = kzalloc(sizeof(struct tlbe_priv) * params.tlb_sizes[1],
+                          GFP_KERNEL);
+
+       if (!privs[0] || !privs[1])
+               goto err_put_page;
+
+       free_gtlb(vcpu_e500);
+
+       vcpu_e500->gtlb_priv[0] = privs[0];
+       vcpu_e500->gtlb_priv[1] = privs[1];
+
+       vcpu_e500->gtlb_arch = (struct kvm_book3e_206_tlb_entry *)
+               (virt + (cfg->array & (PAGE_SIZE - 1)));
+
+       vcpu_e500->gtlb_params[0].entries = params.tlb_sizes[0];
+       vcpu_e500->gtlb_params[1].entries = params.tlb_sizes[1];
+
+       vcpu_e500->gtlb_offset[0] = 0;
+       vcpu_e500->gtlb_offset[1] = params.tlb_sizes[0];
+
+       vcpu_e500->tlb0cfg &= ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
+       if (params.tlb_sizes[0] <= 2048)
+               vcpu_e500->tlb0cfg |= params.tlb_sizes[0];
+       vcpu_e500->tlb0cfg |= params.tlb_ways[0] << TLBnCFG_ASSOC_SHIFT;
+
+       vcpu_e500->tlb1cfg &= ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
+       vcpu_e500->tlb1cfg |= params.tlb_sizes[1];
+       vcpu_e500->tlb1cfg |= params.tlb_ways[1] << TLBnCFG_ASSOC_SHIFT;
+
+       vcpu_e500->shared_tlb_pages = pages;
+       vcpu_e500->num_shared_tlb_pages = num_pages;
+
+       vcpu_e500->gtlb_params[0].ways = params.tlb_ways[0];
+       vcpu_e500->gtlb_params[0].sets = sets;
+
+       vcpu_e500->gtlb_params[1].ways = params.tlb_sizes[1];
+       vcpu_e500->gtlb_params[1].sets = 1;
+
+       return 0;
+
+err_put_page:
+       kfree(privs[0]);
+       kfree(privs[1]);
+
+       for (i = 0; i < num_pages; i++)
+               put_page(pages[i]);
+
+err_pages:
+       kfree(pages);
+       return ret;
+}
+
+int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
+                            struct kvm_dirty_tlb *dirty)
+{
+       struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+
+       clear_tlb_refs(vcpu_e500);
+       return 0;
 }
 
 int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
-       tlb1_entry_num = mfspr(SPRN_TLB1CFG) & 0xFFF;
-
-       vcpu_e500->gtlb_size[0] = KVM_E500_TLB0_SIZE;
-       vcpu_e500->gtlb_arch[0] =
-               kzalloc(sizeof(struct tlbe) * KVM_E500_TLB0_SIZE, GFP_KERNEL);
-       if (vcpu_e500->gtlb_arch[0] == NULL)
-               goto err_out;
-
-       vcpu_e500->gtlb_size[1] = KVM_E500_TLB1_SIZE;
-       vcpu_e500->gtlb_arch[1] =
-               kzalloc(sizeof(struct tlbe) * KVM_E500_TLB1_SIZE, GFP_KERNEL);
-       if (vcpu_e500->gtlb_arch[1] == NULL)
-               goto err_out_guest0;
-
-       vcpu_e500->gtlb_priv[0] = (struct tlbe_priv *)
-               kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB0_SIZE, GFP_KERNEL);
-       if (vcpu_e500->gtlb_priv[0] == NULL)
-               goto err_out_guest1;
-       vcpu_e500->gtlb_priv[1] = (struct tlbe_priv *)
-               kzalloc(sizeof(struct tlbe_priv) * KVM_E500_TLB1_SIZE, GFP_KERNEL);
-
-       if (vcpu_e500->gtlb_priv[1] == NULL)
-               goto err_out_priv0;
+       int entry_size = sizeof(struct kvm_book3e_206_tlb_entry);
+       int entries = KVM_E500_TLB0_SIZE + KVM_E500_TLB1_SIZE;
+
+       host_tlb_params[0].entries = mfspr(SPRN_TLB0CFG) & TLBnCFG_N_ENTRY;
+       host_tlb_params[1].entries = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
+
+       /*
+        * This should never happen on real e500 hardware, but is
+        * architecturally possible -- e.g. in some weird nested
+        * virtualization case.
+        */
+       if (host_tlb_params[0].entries == 0 ||
+           host_tlb_params[1].entries == 0) {
+               pr_err("%s: need to know host tlb size\n", __func__);
+               return -ENODEV;
+       }
+
+       host_tlb_params[0].ways = (mfspr(SPRN_TLB0CFG) & TLBnCFG_ASSOC) >>
+                                 TLBnCFG_ASSOC_SHIFT;
+       host_tlb_params[1].ways = host_tlb_params[1].entries;
+
+       if (!is_power_of_2(host_tlb_params[0].entries) ||
+           !is_power_of_2(host_tlb_params[0].ways) ||
+           host_tlb_params[0].entries < host_tlb_params[0].ways ||
+           host_tlb_params[0].ways == 0) {
+               pr_err("%s: bad tlb0 host config: %u entries %u ways\n",
+                      __func__, host_tlb_params[0].entries,
+                      host_tlb_params[0].ways);
+               return -ENODEV;
+       }
+
+       host_tlb_params[0].sets =
+               host_tlb_params[0].entries / host_tlb_params[0].ways;
+       host_tlb_params[1].sets = 1;
+
+       vcpu_e500->gtlb_params[0].entries = KVM_E500_TLB0_SIZE;
+       vcpu_e500->gtlb_params[1].entries = KVM_E500_TLB1_SIZE;
+
+       vcpu_e500->gtlb_params[0].ways = KVM_E500_TLB0_WAY_NUM;
+       vcpu_e500->gtlb_params[0].sets =
+               KVM_E500_TLB0_SIZE / KVM_E500_TLB0_WAY_NUM;
+
+       vcpu_e500->gtlb_params[1].ways = KVM_E500_TLB1_SIZE;
+       vcpu_e500->gtlb_params[1].sets = 1;
+
+       vcpu_e500->gtlb_arch = kmalloc(entries * entry_size, GFP_KERNEL);
+       if (!vcpu_e500->gtlb_arch)
+               return -ENOMEM;
+
+       vcpu_e500->gtlb_offset[0] = 0;
+       vcpu_e500->gtlb_offset[1] = KVM_E500_TLB0_SIZE;
+
+       vcpu_e500->tlb_refs[0] =
+               kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[0].entries,
+                       GFP_KERNEL);
+       if (!vcpu_e500->tlb_refs[0])
+               goto err;
+
+       vcpu_e500->tlb_refs[1] =
+               kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[1].entries,
+                       GFP_KERNEL);
+       if (!vcpu_e500->tlb_refs[1])
+               goto err;
+
+       vcpu_e500->gtlb_priv[0] = kzalloc(sizeof(struct tlbe_ref) *
+                                         vcpu_e500->gtlb_params[0].entries,
+                                         GFP_KERNEL);
+       if (!vcpu_e500->gtlb_priv[0])
+               goto err;
+
+       vcpu_e500->gtlb_priv[1] = kzalloc(sizeof(struct tlbe_ref) *
+                                         vcpu_e500->gtlb_params[1].entries,
+                                         GFP_KERNEL);
+       if (!vcpu_e500->gtlb_priv[1])
+               goto err;
 
        if (kvmppc_e500_id_table_alloc(vcpu_e500) == NULL)
-               goto err_out_priv1;
+               goto err;
 
        /* Init TLB configuration register */
-       vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) & ~0xfffUL;
-       vcpu_e500->tlb0cfg |= vcpu_e500->gtlb_size[0];
-       vcpu_e500->tlb1cfg = mfspr(SPRN_TLB1CFG) & ~0xfffUL;
-       vcpu_e500->tlb1cfg |= vcpu_e500->gtlb_size[1];
+       vcpu_e500->tlb0cfg = mfspr(SPRN_TLB0CFG) &
+                            ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
+       vcpu_e500->tlb0cfg |= vcpu_e500->gtlb_params[0].entries;
+       vcpu_e500->tlb0cfg |=
+               vcpu_e500->gtlb_params[0].ways << TLBnCFG_ASSOC_SHIFT;
+
+       vcpu_e500->tlb1cfg = mfspr(SPRN_TLB1CFG) &
+                            ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC);
+       vcpu_e500->tlb0cfg |= vcpu_e500->gtlb_params[1].entries;
+       vcpu_e500->tlb0cfg |=
+               vcpu_e500->gtlb_params[1].ways << TLBnCFG_ASSOC_SHIFT;
 
        return 0;
 
-err_out_priv1:
-       kfree(vcpu_e500->gtlb_priv[1]);
-err_out_priv0:
-       kfree(vcpu_e500->gtlb_priv[0]);
-err_out_guest1:
-       kfree(vcpu_e500->gtlb_arch[1]);
-err_out_guest0:
-       kfree(vcpu_e500->gtlb_arch[0]);
-err_out:
+err:
+       free_gtlb(vcpu_e500);
+       kfree(vcpu_e500->tlb_refs[0]);
+       kfree(vcpu_e500->tlb_refs[1]);
        return -1;
 }
 
 void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
-       int stlbsel, i;
-
-       /* release all privs */
-       for (stlbsel = 0; stlbsel < 2; stlbsel++)
-               for (i = 0; i < vcpu_e500->gtlb_size[stlbsel]; i++) {
-                       struct tlbe_priv *priv =
-                               &vcpu_e500->gtlb_priv[stlbsel][i];
-                       kvmppc_e500_priv_release(priv);
-               }
-
+       free_gtlb(vcpu_e500);
        kvmppc_e500_id_table_free(vcpu_e500);
-       kfree(vcpu_e500->gtlb_arch[1]);
-       kfree(vcpu_e500->gtlb_arch[0]);
+
+       kfree(vcpu_e500->tlb_refs[0]);
+       kfree(vcpu_e500->tlb_refs[1]);
 }
index 59b88e9..5c6d2d7 100644 (file)
 #include <asm/tlb.h>
 #include <asm/kvm_e500.h>
 
-#define KVM_E500_TLB0_WAY_SIZE_BIT     7       /* Fixed */
-#define KVM_E500_TLB0_WAY_SIZE         (1UL << KVM_E500_TLB0_WAY_SIZE_BIT)
-#define KVM_E500_TLB0_WAY_SIZE_MASK    (KVM_E500_TLB0_WAY_SIZE - 1)
-
-#define KVM_E500_TLB0_WAY_NUM_BIT      1       /* No greater than 7 */
-#define KVM_E500_TLB0_WAY_NUM          (1UL << KVM_E500_TLB0_WAY_NUM_BIT)
-#define KVM_E500_TLB0_WAY_NUM_MASK     (KVM_E500_TLB0_WAY_NUM - 1)
+/* This geometry is the legacy default -- can be overridden by userspace */
+#define KVM_E500_TLB0_WAY_SIZE         128
+#define KVM_E500_TLB0_WAY_NUM          2
 
 #define KVM_E500_TLB0_SIZE  (KVM_E500_TLB0_WAY_SIZE * KVM_E500_TLB0_WAY_NUM)
 #define KVM_E500_TLB1_SIZE  16
@@ -58,50 +54,54 @@ extern void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *);
 extern void kvmppc_e500_recalc_shadow_pid(struct kvmppc_vcpu_e500 *);
 
 /* TLB helper functions */
-static inline unsigned int get_tlb_size(const struct tlbe *tlbe)
+static inline unsigned int
+get_tlb_size(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
        return (tlbe->mas1 >> 7) & 0x1f;
 }
 
-static inline gva_t get_tlb_eaddr(const struct tlbe *tlbe)
+static inline gva_t get_tlb_eaddr(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
        return tlbe->mas2 & 0xfffff000;
 }
 
-static inline u64 get_tlb_bytes(const struct tlbe *tlbe)
+static inline u64 get_tlb_bytes(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
        unsigned int pgsize = get_tlb_size(tlbe);
        return 1ULL << 10 << pgsize;
 }
 
-static inline gva_t get_tlb_end(const struct tlbe *tlbe)
+static inline gva_t get_tlb_end(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
        u64 bytes = get_tlb_bytes(tlbe);
        return get_tlb_eaddr(tlbe) + bytes - 1;
 }
 
-static inline u64 get_tlb_raddr(const struct tlbe *tlbe)
+static inline u64 get_tlb_raddr(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
-       u64 rpn = tlbe->mas7;
-       return (rpn << 32) | (tlbe->mas3 & 0xfffff000);
+       return tlbe->mas7_3 & ~0xfffULL;
 }
 
-static inline unsigned int get_tlb_tid(const struct tlbe *tlbe)
+static inline unsigned int
+get_tlb_tid(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
        return (tlbe->mas1 >> 16) & 0xff;
 }
 
-static inline unsigned int get_tlb_ts(const struct tlbe *tlbe)
+static inline unsigned int
+get_tlb_ts(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
        return (tlbe->mas1 >> 12) & 0x1;
 }
 
-static inline unsigned int get_tlb_v(const struct tlbe *tlbe)
+static inline unsigned int
+get_tlb_v(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
        return (tlbe->mas1 >> 31) & 0x1;
 }
 
-static inline unsigned int get_tlb_iprot(const struct tlbe *tlbe)
+static inline unsigned int
+get_tlb_iprot(const struct kvm_book3e_206_tlb_entry *tlbe)
 {
        return (tlbe->mas1 >> 30) & 0x1;
 }
@@ -121,59 +121,37 @@ static inline unsigned int get_cur_pr(struct kvm_vcpu *vcpu)
        return !!(vcpu->arch.shared->msr & MSR_PR);
 }
 
-static inline unsigned int get_cur_spid(
-               const struct kvmppc_vcpu_e500 *vcpu_e500)
+static inline unsigned int get_cur_spid(const struct kvm_vcpu *vcpu)
 {
-       return (vcpu_e500->mas6 >> 16) & 0xff;
+       return (vcpu->arch.shared->mas6 >> 16) & 0xff;
 }
 
-static inline unsigned int get_cur_sas(
-               const struct kvmppc_vcpu_e500 *vcpu_e500)
+static inline unsigned int get_cur_sas(const struct kvm_vcpu *vcpu)
 {
-       return vcpu_e500->mas6 & 0x1;
+       return vcpu->arch.shared->mas6 & 0x1;
 }
 
-static inline unsigned int get_tlb_tlbsel(
-               const struct kvmppc_vcpu_e500 *vcpu_e500)
+static inline unsigned int get_tlb_tlbsel(const struct kvm_vcpu *vcpu)
 {
        /*
         * Manual says that tlbsel has 2 bits wide.
         * Since we only have two TLBs, only lower bit is used.
         */
-       return (vcpu_e500->mas0 >> 28) & 0x1;
-}
-
-static inline unsigned int get_tlb_nv_bit(
-               const struct kvmppc_vcpu_e500 *vcpu_e500)
-{
-       return vcpu_e500->mas0 & 0xfff;
+       return (vcpu->arch.shared->mas0 >> 28) & 0x1;
 }
 
-static inline unsigned int get_tlb_esel_bit(
-               const struct kvmppc_vcpu_e500 *vcpu_e500)
+static inline unsigned int get_tlb_nv_bit(const struct kvm_vcpu *vcpu)
 {
-       return (vcpu_e500->mas0 >> 16) & 0xfff;
+       return vcpu->arch.shared->mas0 & 0xfff;
 }
 
-static inline unsigned int get_tlb_esel(
-               const struct kvmppc_vcpu_e500 *vcpu_e500,
-               int tlbsel)
+static inline unsigned int get_tlb_esel_bit(const struct kvm_vcpu *vcpu)
 {
-       unsigned int esel = get_tlb_esel_bit(vcpu_e500);
-
-       if (tlbsel == 0) {
-               esel &= KVM_E500_TLB0_WAY_NUM_MASK;
-               esel |= ((vcpu_e500->mas2 >> 12) & KVM_E500_TLB0_WAY_SIZE_MASK)
-                               << KVM_E500_TLB0_WAY_NUM_BIT;
-       } else {
-               esel &= KVM_E500_TLB1_SIZE - 1;
-       }
-
-       return esel;
+       return (vcpu->arch.shared->mas0 >> 16) & 0xfff;
 }
 
 static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
-                       const struct tlbe *tlbe)
+                       const struct kvm_book3e_206_tlb_entry *tlbe)
 {
        gpa_t gpa;
 
index 141dce3..968f401 100644 (file)
@@ -13,6 +13,7 @@
  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *
  * Copyright IBM Corp. 2007
+ * Copyright 2011 Freescale Semiconductor, Inc.
  *
  * Authors: Hollis Blanchard <hollisb@us.ibm.com>
  */
 #define OP_STH  44
 #define OP_STHU 45
 
-#ifdef CONFIG_PPC_BOOK3S
-static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu)
-{
-       return 1;
-}
-#else
-static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.tcr & TCR_DIE;
-}
-#endif
-
 void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
 {
        unsigned long dec_nsec;
+       unsigned long long dec_time;
 
        pr_debug("mtDEC: %x\n", vcpu->arch.dec);
+       hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
+
 #ifdef CONFIG_PPC_BOOK3S
        /* mtdec lowers the interrupt line when positive. */
        kvmppc_core_dequeue_dec(vcpu);
 
        /* POWER4+ triggers a dec interrupt if the value is < 0 */
        if (vcpu->arch.dec & 0x80000000) {
-               hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
                kvmppc_core_queue_dec(vcpu);
                return;
        }
 #endif
-       if (kvmppc_dec_enabled(vcpu)) {
-               /* The decrementer ticks at the same rate as the timebase, so
-                * that's how we convert the guest DEC value to the number of
-                * host ticks. */
-
-               hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
-               dec_nsec = vcpu->arch.dec;
-               dec_nsec *= 1000;
-               dec_nsec /= tb_ticks_per_usec;
-               hrtimer_start(&vcpu->arch.dec_timer, ktime_set(0, dec_nsec),
-                             HRTIMER_MODE_REL);
-               vcpu->arch.dec_jiffies = get_tb();
-       } else {
-               hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
-       }
+
+#ifdef CONFIG_BOOKE
+       /* On BOOKE, DEC = 0 is as good as decrementer not enabled */
+       if (vcpu->arch.dec == 0)
+               return;
+#endif
+
+       /*
+        * The decrementer ticks at the same rate as the timebase, so
+        * that's how we convert the guest DEC value to the number of
+        * host ticks.
+        */
+
+       dec_time = vcpu->arch.dec;
+       dec_time *= 1000;
+       do_div(dec_time, tb_ticks_per_usec);
+       dec_nsec = do_div(dec_time, NSEC_PER_SEC);
+       hrtimer_start(&vcpu->arch.dec_timer,
+               ktime_set(dec_time, dec_nsec), HRTIMER_MODE_REL);
+       vcpu->arch.dec_jiffies = get_tb();
 }
 
 u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb)
 {
        u64 jd = tb - vcpu->arch.dec_jiffies;
+
+#ifdef CONFIG_BOOKE
+       if (vcpu->arch.dec < jd)
+               return 0;
+#endif
+
        return vcpu->arch.dec - jd;
 }
 
@@ -159,7 +161,8 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
        case OP_TRAP_64:
                kvmppc_core_queue_program(vcpu, SRR1_PROGTRAP);
 #else
-               kvmppc_core_queue_program(vcpu, vcpu->arch.esr | ESR_PTR);
+               kvmppc_core_queue_program(vcpu,
+                                         vcpu->arch.shared->esr | ESR_PTR);
 #endif
                advance = 0;
                break;
index 607fbdf..00d7e34 100644 (file)
@@ -39,7 +39,8 @@
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
        return !(v->arch.shared->msr & MSR_WE) ||
-              !!(v->arch.pending_exceptions);
+              !!(v->arch.pending_exceptions) ||
+              v->requests;
 }
 
 int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
@@ -66,7 +67,7 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
                vcpu->arch.magic_page_pa = param1;
                vcpu->arch.magic_page_ea = param2;
 
-               r2 = KVM_MAGIC_FEAT_SR;
+               r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7;
 
                r = HC_EV_SUCCESS;
                break;
@@ -171,8 +172,11 @@ void kvm_arch_check_processor_compat(void *rtn)
        *(int *)rtn = kvmppc_core_check_processor_compat();
 }
 
-int kvm_arch_init_vm(struct kvm *kvm)
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
+       if (type)
+               return -EINVAL;
+
        return kvmppc_core_init_vm(kvm);
 }
 
@@ -208,17 +212,22 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_PPC_BOOKE_SREGS:
 #else
        case KVM_CAP_PPC_SEGSTATE:
+       case KVM_CAP_PPC_HIOR:
        case KVM_CAP_PPC_PAPR:
 #endif
        case KVM_CAP_PPC_UNSET_IRQ:
        case KVM_CAP_PPC_IRQ_LEVEL:
        case KVM_CAP_ENABLE_CAP:
+       case KVM_CAP_ONE_REG:
                r = 1;
                break;
 #ifndef CONFIG_KVM_BOOK3S_64_HV
        case KVM_CAP_PPC_PAIRED_SINGLES:
        case KVM_CAP_PPC_OSI:
        case KVM_CAP_PPC_GET_PVINFO:
+#ifdef CONFIG_KVM_E500
+       case KVM_CAP_SW_TLB:
+#endif
                r = 1;
                break;
        case KVM_CAP_COALESCED_MMIO:
@@ -238,7 +247,26 @@ int kvm_dev_ioctl_check_extension(long ext)
                if (cpu_has_feature(CPU_FTR_ARCH_201))
                        r = 2;
                break;
+       case KVM_CAP_SYNC_MMU:
+               r = cpu_has_feature(CPU_FTR_ARCH_206) ? 1 : 0;
+               break;
 #endif
+       case KVM_CAP_NR_VCPUS:
+               /*
+                * Recommending a number of CPUs is somewhat arbitrary; we
+                * return the number of present CPUs for -HV (since a host
+                * will have secondary threads "offline"), and for other KVM
+                * implementations just count online CPUs.
+                */
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+               r = num_present_cpus();
+#else
+               r = num_online_cpus();
+#endif
+               break;
+       case KVM_CAP_MAX_VCPUS:
+               r = KVM_MAX_VCPUS;
+               break;
        default:
                r = 0;
                break;
@@ -253,6 +281,16 @@ long kvm_arch_dev_ioctl(struct file *filp,
        return -EINVAL;
 }
 
+void kvm_arch_free_memslot(struct kvm_memory_slot *free,
+                          struct kvm_memory_slot *dont)
+{
+}
+
+int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
+{
+       return 0;
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                    struct kvm_memory_slot *memslot,
                                    struct kvm_memory_slot old,
@@ -279,9 +317,10 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 {
        struct kvm_vcpu *vcpu;
        vcpu = kvmppc_core_vcpu_create(kvm, id);
-       vcpu->arch.wqp = &vcpu->wq;
-       if (!IS_ERR(vcpu))
+       if (!IS_ERR(vcpu)) {
+               vcpu->arch.wqp = &vcpu->wq;
                kvmppc_create_vcpu_debugfs(vcpu, id);
+       }
        return vcpu;
 }
 
@@ -305,18 +344,6 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
        return kvmppc_core_pending_dec(vcpu);
 }
 
-static void kvmppc_decrementer_func(unsigned long data)
-{
-       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
-
-       kvmppc_core_queue_dec(vcpu);
-
-       if (waitqueue_active(vcpu->arch.wqp)) {
-               wake_up_interruptible(vcpu->arch.wqp);
-               vcpu->stat.halt_wakeup++;
-       }
-}
-
 /*
  * low level hrtimer wake routine. Because this runs in hardirq context
  * we schedule a tasklet to do the real work.
@@ -431,20 +458,20 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
 
        kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
 
-       switch (vcpu->arch.io_gpr & KVM_REG_EXT_MASK) {
-       case KVM_REG_GPR:
+       switch (vcpu->arch.io_gpr & KVM_MMIO_REG_EXT_MASK) {
+       case KVM_MMIO_REG_GPR:
                kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
                break;
-       case KVM_REG_FPR:
-               vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
+       case KVM_MMIO_REG_FPR:
+               vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
                break;
 #ifdef CONFIG_PPC_BOOK3S
-       case KVM_REG_QPR:
-               vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
+       case KVM_MMIO_REG_QPR:
+               vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
                break;
-       case KVM_REG_FQPR:
-               vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
-               vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_REG_MASK] = gpr;
+       case KVM_MMIO_REG_FQPR:
+               vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
+               vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
                break;
 #endif
        default:
@@ -553,8 +580,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                vcpu->arch.hcall_needed = 0;
        }
 
-       kvmppc_core_deliver_interrupts(vcpu);
-
        r = kvmppc_vcpu_run(run, vcpu);
 
        if (vcpu->sigset_active)
@@ -563,6 +588,21 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
        return r;
 }
 
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
+{
+       int me;
+       int cpu = vcpu->cpu;
+
+       me = get_cpu();
+       if (waitqueue_active(vcpu->arch.wqp)) {
+               wake_up_interruptible(vcpu->arch.wqp);
+               vcpu->stat.halt_wakeup++;
+       } else if (cpu != me && cpu != -1) {
+               smp_send_reschedule(vcpu->cpu);
+       }
+       put_cpu();
+}
+
 int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
 {
        if (irq->irq == KVM_INTERRUPT_UNSET) {
@@ -571,13 +611,7 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
        }
 
        kvmppc_core_queue_external(vcpu, irq);
-
-       if (waitqueue_active(vcpu->arch.wqp)) {
-               wake_up_interruptible(vcpu->arch.wqp);
-               vcpu->stat.halt_wakeup++;
-       } else if (vcpu->cpu != -1) {
-               smp_send_reschedule(vcpu->cpu);
-       }
+       kvm_vcpu_kick(vcpu);
 
        return 0;
 }
@@ -599,6 +633,19 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
                r = 0;
                vcpu->arch.papr_enabled = true;
                break;
+#ifdef CONFIG_KVM_E500
+       case KVM_CAP_SW_TLB: {
+               struct kvm_config_tlb cfg;
+               void __user *user_ptr = (void __user *)(uintptr_t)cap->args[0];
+
+               r = -EFAULT;
+               if (copy_from_user(&cfg, user_ptr, sizeof(cfg)))
+                       break;
+
+               r = kvm_vcpu_ioctl_config_tlb(vcpu, &cfg);
+               break;
+       }
+#endif
        default:
                r = -EINVAL;
                break;
@@ -648,6 +695,32 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
                break;
        }
+
+       case KVM_SET_ONE_REG:
+       case KVM_GET_ONE_REG:
+       {
+               struct kvm_one_reg reg;
+               r = -EFAULT;
+               if (copy_from_user(&reg, argp, sizeof(reg)))
+                       goto out;
+               if (ioctl == KVM_SET_ONE_REG)
+                       r = kvm_vcpu_ioctl_set_one_reg(vcpu, &reg);
+               else
+                       r = kvm_vcpu_ioctl_get_one_reg(vcpu, &reg);
+               break;
+       }
+
+#ifdef CONFIG_KVM_E500
+       case KVM_DIRTY_TLB: {
+               struct kvm_dirty_tlb dirty;
+               r = -EFAULT;
+               if (copy_from_user(&dirty, argp, sizeof(dirty)))
+                       goto out;
+               r = kvm_vcpu_ioctl_dirty_tlb(vcpu, &dirty);
+               break;
+       }
+#endif
+
        default:
                r = -EINVAL;
        }
@@ -656,6 +729,11 @@ out:
        return r;
 }
 
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+       return VM_FAULT_SIGBUS;
+}
+
 static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
 {
        u32 inst_lis = 0x3c000000;
index b135d3d..877186b 100644 (file)
@@ -118,11 +118,14 @@ TRACE_EVENT(kvm_book3s_exit,
        ),
 
        TP_fast_assign(
+               struct kvmppc_book3s_shadow_vcpu *svcpu;
                __entry->exit_nr        = exit_nr;
                __entry->pc             = kvmppc_get_pc(vcpu);
                __entry->dar            = kvmppc_get_fault_dar(vcpu);
                __entry->msr            = vcpu->arch.shared->msr;
-               __entry->srr1           = to_svcpu(vcpu)->shadow_srr1;
+               svcpu = svcpu_get(vcpu);
+               __entry->srr1           = svcpu->shadow_srr1;
+               svcpu_put(svcpu);
        ),
 
        TP_printk("exit=0x%x | pc=0x%lx | msr=0x%lx | dar=0x%lx | srr1=0x%lx",
@@ -337,6 +340,63 @@ TRACE_EVENT(kvm_book3s_slbmte,
 
 #endif /* CONFIG_PPC_BOOK3S */
 
+
+/*************************************************************************
+ *                         Book3E trace points                           *
+ *************************************************************************/
+
+#ifdef CONFIG_BOOKE
+
+TRACE_EVENT(kvm_booke206_stlb_write,
+       TP_PROTO(__u32 mas0, __u32 mas8, __u32 mas1, __u64 mas2, __u64 mas7_3),
+       TP_ARGS(mas0, mas8, mas1, mas2, mas7_3),
+
+       TP_STRUCT__entry(
+               __field(        __u32,  mas0            )
+               __field(        __u32,  mas8            )
+               __field(        __u32,  mas1            )
+               __field(        __u64,  mas2            )
+               __field(        __u64,  mas7_3          )
+       ),
+
+       TP_fast_assign(
+               __entry->mas0           = mas0;
+               __entry->mas8           = mas8;
+               __entry->mas1           = mas1;
+               __entry->mas2           = mas2;
+               __entry->mas7_3         = mas7_3;
+       ),
+
+       TP_printk("mas0=%x mas8=%x mas1=%x mas2=%llx mas7_3=%llx",
+               __entry->mas0, __entry->mas8, __entry->mas1,
+               __entry->mas2, __entry->mas7_3)
+);
+
+TRACE_EVENT(kvm_booke206_gtlb_write,
+       TP_PROTO(__u32 mas0, __u32 mas1, __u64 mas2, __u64 mas7_3),
+       TP_ARGS(mas0, mas1, mas2, mas7_3),
+
+       TP_STRUCT__entry(
+               __field(        __u32,  mas0            )
+               __field(        __u32,  mas1            )
+               __field(        __u64,  mas2            )
+               __field(        __u64,  mas7_3          )
+       ),
+
+       TP_fast_assign(
+               __entry->mas0           = mas0;
+               __entry->mas1           = mas1;
+               __entry->mas2           = mas2;
+               __entry->mas7_3         = mas7_3;
+       ),
+
+       TP_printk("mas0=%x mas1=%x mas2=%llx mas7_3=%llx",
+               __entry->mas0, __entry->mas1,
+               __entry->mas2, __entry->mas7_3)
+);
+
+#endif
+
 #endif /* _TRACE_KVM_H */
 
 /* This part must be outside protection */
index 57c7465..fb05b12 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/hugetlb.h>
+#include <linux/export.h>
 #include <linux/of_fdt.h>
 #include <linux/memblock.h>
 #include <linux/bootmem.h>
@@ -103,6 +104,7 @@ pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift
                *shift = hugepd_shift(*hpdp);
        return hugepte_offset(hpdp, ea, pdshift);
 }
+EXPORT_SYMBOL_GPL(find_linux_pte_or_hugepte);
 
 pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
 {
@@ -310,7 +312,8 @@ void __init reserve_hugetlb_gpages(void)
        int i;
 
        strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE);
-       parse_args("hugetlb gpages", cmdline, NULL, 0, &do_gpage_early_setup);
+       parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0,
+                       &do_gpage_early_setup);
 
        /*
         * Walk gpage list in reverse, allocating larger page sizes first.
index c2e27ed..02aee03 100644 (file)
@@ -116,14 +116,45 @@ static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
                *addrp = mfspr(SPRN_SDAR);
 }
 
+static inline u32 perf_flags_from_msr(struct pt_regs *regs)
+{
+       if (regs->msr & MSR_PR)
+               return PERF_RECORD_MISC_USER;
+       if ((regs->msr & MSR_HV) && freeze_events_kernel != MMCR0_FCHV)
+               return PERF_RECORD_MISC_HYPERVISOR;
+       return PERF_RECORD_MISC_KERNEL;
+}
+
 static inline u32 perf_get_misc_flags(struct pt_regs *regs)
 {
        unsigned long mmcra = regs->dsisr;
        unsigned long sihv = MMCRA_SIHV;
        unsigned long sipr = MMCRA_SIPR;
 
+       /* Not a PMU interrupt: Make up flags from regs->msr */
        if (TRAP(regs) != 0xf00)
-               return 0;       /* not a PMU interrupt */
+               return perf_flags_from_msr(regs);
+
+       /*
+        * If we don't support continuous sampling and this
+        * is not a marked event, same deal
+        */
+       if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) &&
+           !(mmcra & MMCRA_SAMPLE_ENABLE))
+               return perf_flags_from_msr(regs);
+
+       /*
+        * If we don't have flags in MMCRA, rather than using
+        * the MSR, we intuit the flags from the address in
+        * SIAR which should give slightly more reliable
+        * results
+        */
+       if (ppmu->flags & PPMU_NO_SIPR) {
+               unsigned long siar = mfspr(SPRN_SIAR);
+               if (siar >= PAGE_OFFSET)
+                       return PERF_RECORD_MISC_KERNEL;
+               return PERF_RECORD_MISC_USER;
+       }
 
        if (ppmu->flags & PPMU_ALT_SIPR) {
                sihv = POWER6_MMCRA_SIHV;
@@ -1299,13 +1330,18 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
  */
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
 {
-       unsigned long ip;
+       unsigned long mmcra = regs->dsisr;
 
+       /* Not a PMU interrupt */
        if (TRAP(regs) != 0xf00)
-               return regs->nip;       /* not a PMU interrupt */
+               return regs->nip;
+
+       /* Processor doesn't support sampling non marked events */
+       if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) &&
+           !(mmcra & MMCRA_SAMPLE_ENABLE))
+               return regs->nip;
 
-       ip = mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
-       return ip;
+       return mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
 }
 
 static bool pmc_overflow(unsigned long val)
index b4f1dda..9103a1d 100644 (file)
@@ -607,6 +607,7 @@ static struct power_pmu power4_pmu = {
        .n_generic              = ARRAY_SIZE(p4_generic_events),
        .generic_events         = p4_generic_events,
        .cache_events           = &power4_cache_events,
+       .flags                  = PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
 };
 
 static int __init init_power4_pmu(void)
index 111eb25..20139ce 100644 (file)
@@ -487,6 +487,7 @@ static struct power_pmu ppc970_pmu = {
        .n_generic              = ARRAY_SIZE(ppc970_generic_events),
        .generic_events         = ppc970_generic_events,
        .cache_events           = &ppc970_cache_events,
+       .flags                  = PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
 };
 
 static int __init init_ppc970_pmu(void)
index 2516c1c..943c9d3 100644 (file)
@@ -95,7 +95,6 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group,
        unsigned long lpar_rc;
        u64 hpte_v, hpte_r, slot;
 
-       /* same as iseries */
        if (vflags & HPTE_V_SECONDARY)
                return -1;
 
@@ -319,7 +318,6 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group,
        unsigned long lpar_rc;
        u64 hpte_v, hpte_r, slot;
 
-       /* same as iseries */
        if (vflags & HPTE_V_SECONDARY)
                return -1;
 
index 401e3f3..465ee8f 100644 (file)
@@ -620,7 +620,7 @@ void __init maple_pci_init(void)
        }
 
        /* Tell pci.c to not change any resource allocations.  */
-       pci_probe_only = 1;
+       pci_add_flags(PCI_PROBE_ONLY);
 }
 
 int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
index b6a0ec4..aa86271 100644 (file)
@@ -229,9 +229,6 @@ void __init pas_pci_init(void)
 
        /* Setup the linkage between OF nodes and PHBs */
        pci_devs_phb_init();
-
-       /* Use the common resource allocation mechanism */
-       pci_probe_only = 1;
 }
 
 void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset)
index 31a7d3a..43bbe1b 100644 (file)
@@ -1059,9 +1059,6 @@ void __init pmac_pci_init(void)
        }
        /* pmac_check_ht_link(); */
 
-       /* We can allocate missing resources if any */
-       pci_probe_only = 0;
-
 #else /* CONFIG_PPC64 */
        init_p2pbridge();
        init_second_ohare();
index 5e155df..fbdd74d 100644 (file)
@@ -1299,15 +1299,14 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np)
        /* Setup MSI support */
        pnv_pci_init_ioda_msis(phb);
 
-       /* We set both probe_only and PCI_REASSIGN_ALL_RSRC. This is an
+       /* We set both PCI_PROBE_ONLY and PCI_REASSIGN_ALL_RSRC. This is an
         * odd combination which essentially means that we skip all resource
         * fixups and assignments in the generic code, and do it all
         * ourselves here
         */
-       pci_probe_only = 1;
        ppc_md.pcibios_fixup_phb = pnv_pci_ioda_fixup_phb;
        ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook;
-       pci_add_flags(PCI_REASSIGN_ALL_RSRC);
+       pci_add_flags(PCI_PROBE_ONLY | PCI_REASSIGN_ALL_RSRC);
 
        /* Reset IODA tables to a clean state */
        rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET);
index 214478d..be3cfc5 100644 (file)
@@ -562,10 +562,7 @@ void __init pnv_pci_init(void)
 {
        struct device_node *np;
 
-       pci_set_flags(PCI_CAN_SKIP_ISA_ALIGN);
-
-       /* We do not want to just probe */
-       pci_probe_only = 0;
+       pci_add_flags(PCI_CAN_SKIP_ISA_ALIGN);
 
        /* OPAL absent, try POPAL first then RTAS detection of PHBs */
        if (!firmware_has_feature(FW_FEATURE_OPAL)) {
index 8011088..309d38e 100644 (file)
@@ -984,7 +984,8 @@ int __exit eeh_ops_unregister(const char *name)
  */
 void __init eeh_init(void)
 {
-       struct device_node *phb, *np;
+       struct pci_controller *hose, *tmp;
+       struct device_node *phb;
        int ret;
 
        /* call platform initialization function */
@@ -1000,19 +1001,9 @@ void __init eeh_init(void)
 
        raw_spin_lock_init(&confirm_error_lock);
 
-       np = of_find_node_by_path("/rtas");
-       if (np == NULL)
-               return;
-
-       /* Enable EEH for all adapters.  Note that eeh requires buid's */
-       for (phb = of_find_node_by_name(NULL, "pci"); phb;
-            phb = of_find_node_by_name(phb, "pci")) {
-               unsigned long buid;
-
-               buid = get_phb_buid(phb);
-               if (buid == 0 || !of_node_to_eeh_dev(phb))
-                       continue;
-
+       /* Enable EEH for all adapters */
+       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+               phb = hose->dn;
                traverse_pci_devices(phb, eeh_early_enable, NULL);
        }
 
index f3aed7d..c4507d0 100644 (file)
@@ -62,7 +62,7 @@ void * __devinit eeh_dev_init(struct device_node *dn, void *data)
        }
 
        /* Associate EEH device with OF node */
-       dn->edev  = edev;
+       PCI_DN(dn)->edev = edev;
        edev->dn  = dn;
        edev->phb = phb;
 
index 1a709bc..ef9d9d8 100644 (file)
@@ -63,73 +63,9 @@ EXPORT_SYMBOL_GPL(pseries_ioei_notifier_list);
 
 static int ioei_check_exception_token;
 
-/* pSeries event log format */
-
-/* Two bytes ASCII section IDs */
-#define PSERIES_ELOG_SECT_ID_PRIV_HDR          (('P' << 8) | 'H')
-#define PSERIES_ELOG_SECT_ID_USER_HDR          (('U' << 8) | 'H')
-#define PSERIES_ELOG_SECT_ID_PRIMARY_SRC       (('P' << 8) | 'S')
-#define PSERIES_ELOG_SECT_ID_EXTENDED_UH       (('E' << 8) | 'H')
-#define PSERIES_ELOG_SECT_ID_FAILING_MTMS      (('M' << 8) | 'T')
-#define PSERIES_ELOG_SECT_ID_SECONDARY_SRC     (('S' << 8) | 'S')
-#define PSERIES_ELOG_SECT_ID_DUMP_LOCATOR      (('D' << 8) | 'H')
-#define PSERIES_ELOG_SECT_ID_FW_ERROR          (('S' << 8) | 'W')
-#define PSERIES_ELOG_SECT_ID_IMPACT_PART_ID    (('L' << 8) | 'P')
-#define PSERIES_ELOG_SECT_ID_LOGIC_RESOURCE_ID (('L' << 8) | 'R')
-#define PSERIES_ELOG_SECT_ID_HMC_ID            (('H' << 8) | 'M')
-#define PSERIES_ELOG_SECT_ID_EPOW              (('E' << 8) | 'P')
-#define PSERIES_ELOG_SECT_ID_IO_EVENT          (('I' << 8) | 'E')
-#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO     (('M' << 8) | 'I')
-#define PSERIES_ELOG_SECT_ID_CALL_HOME         (('C' << 8) | 'H')
-#define PSERIES_ELOG_SECT_ID_USER_DEF          (('U' << 8) | 'D')
-
-/* Vendor specific Platform Event Log Format, Version 6, section header */
-struct pseries_elog_section {
-       uint16_t id;                    /* 0x00 2-byte ASCII section ID */
-       uint16_t length;                /* 0x02 Section length in bytes */
-       uint8_t version;                /* 0x04 Section version         */
-       uint8_t subtype;                /* 0x05 Section subtype         */
-       uint16_t creator_component;     /* 0x06 Creator component ID    */
-       uint8_t data[];                 /* 0x08 Start of section data   */
-};
-
 static char ioei_rtas_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
 
 /**
- * Find data portion of a specific section in RTAS extended event log.
- * @elog: RTAS error/event log.
- * @sect_id: secsion ID.
- *
- * Return:
- *     pointer to the section data of the specified section
- *     NULL if not found
- */
-static struct pseries_elog_section *find_xelog_section(struct rtas_error_log *elog,
-                                                      uint16_t sect_id)
-{
-       struct rtas_ext_event_log_v6 *xelog =
-               (struct rtas_ext_event_log_v6 *) elog->buffer;
-       struct pseries_elog_section *sect;
-       unsigned char *p, *log_end;
-
-       /* Check that we understand the format */
-       if (elog->extended_log_length < sizeof(struct rtas_ext_event_log_v6) ||
-           xelog->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
-           xelog->company_id != RTAS_V6EXT_COMPANY_ID_IBM)
-               return NULL;
-
-       log_end = elog->buffer + elog->extended_log_length;
-       p = xelog->vendor_log;
-       while (p < log_end) {
-               sect = (struct pseries_elog_section *)p;
-               if (sect->id == sect_id)
-                       return sect;
-               p += sect->length;
-       }
-       return NULL;
-}
-
-/**
  * Find the data portion of an IO Event section from event log.
  * @elog: RTAS error/event log.
  *
@@ -138,7 +74,7 @@ static struct pseries_elog_section *find_xelog_section(struct rtas_error_log *el
  */
 static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)
 {
-       struct pseries_elog_section *sect;
+       struct pseries_errorlog *sect;
 
        /* We should only ever get called for io-event interrupts, but if
         * we do get called for another type then something went wrong so
@@ -152,7 +88,7 @@ static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)
                return NULL;
        }
 
-       sect = find_xelog_section(elog, PSERIES_ELOG_SECT_ID_IO_EVENT);
+       sect = get_pseries_errorlog(elog, PSERIES_ELOG_SECT_ID_IO_EVENT);
        if (unlikely(!sect)) {
                printk_once(KERN_WARNING "io_event_irq: RTAS extended event "
                            "log does not contain an IO Event section. "
index c442f2b..0915b1a 100644 (file)
@@ -809,8 +809,7 @@ machine_arch_initcall(pseries, find_existing_ddw_windows);
 static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail,
                        struct ddw_query_response *query)
 {
-       struct device_node *dn;
-       struct pci_dn *pcidn;
+       struct eeh_dev *edev;
        u32 cfg_addr;
        u64 buid;
        int ret;
@@ -821,12 +820,12 @@ static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail,
         * Retrieve them from the pci device, not the node with the
         * dma-window property
         */
-       dn = pci_device_to_OF_node(dev);
-       pcidn = PCI_DN(dn);
-       cfg_addr = pcidn->eeh_config_addr;
-       if (pcidn->eeh_pe_config_addr)
-               cfg_addr = pcidn->eeh_pe_config_addr;
-       buid = pcidn->phb->buid;
+       edev = pci_dev_to_eeh_dev(dev);
+       cfg_addr = edev->config_addr;
+       if (edev->pe_config_addr)
+               cfg_addr = edev->pe_config_addr;
+       buid = edev->phb->buid;
+
        ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query,
                  cfg_addr, BUID_HI(buid), BUID_LO(buid));
        dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x"
@@ -839,8 +838,7 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail,
                        struct ddw_create_response *create, int page_shift,
                        int window_shift)
 {
-       struct device_node *dn;
-       struct pci_dn *pcidn;
+       struct eeh_dev *edev;
        u32 cfg_addr;
        u64 buid;
        int ret;
@@ -851,12 +849,11 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail,
         * Retrieve them from the pci device, not the node with the
         * dma-window property
         */
-       dn = pci_device_to_OF_node(dev);
-       pcidn = PCI_DN(dn);
-       cfg_addr = pcidn->eeh_config_addr;
-       if (pcidn->eeh_pe_config_addr)
-               cfg_addr = pcidn->eeh_pe_config_addr;
-       buid = pcidn->phb->buid;
+       edev = pci_dev_to_eeh_dev(dev);
+       cfg_addr = edev->config_addr;
+       if (edev->pe_config_addr)
+               cfg_addr = edev->pe_config_addr;
+       buid = edev->phb->buid;
 
        do {
                /* extra outputs are LIOBN and dma-addr (hi, lo) */
index fbb21fc..8b7bafa 100644 (file)
@@ -84,7 +84,7 @@ void pcibios_remove_pci_devices(struct pci_bus *bus)
        list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
                pr_debug("     * Removing %s...\n", pci_name(dev));
                eeh_remove_bus_device(dev);
-               pci_remove_bus_device(dev);
+               pci_stop_and_remove_bus_device(dev);
        }
 }
 EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
index 9e248ef..c4dfccd 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-/* Change Activity:
- * 2001/09/21 : engebret : Created with minimal EPOW and HW exception support.
- * End Change Activity
- */
-
-#include <linux/errno.h>
-#include <linux/threads.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
-#include <linux/init.h>
-#include <linux/delay.h>
 #include <linux/irq.h>
-#include <linux/random.h>
-#include <linux/sysrq.h>
-#include <linux/bitops.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/cache.h>
-#include <asm/prom.h>
-#include <asm/ptrace.h>
+#include <linux/of.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+
 #include <asm/machdep.h>
 #include <asm/rtas.h>
-#include <asm/udbg.h>
 #include <asm/firmware.h>
 
 #include "pseries.h"
@@ -56,7 +35,6 @@ static DEFINE_SPINLOCK(ras_log_buf_lock);
 static char global_mce_data_buf[RTAS_ERROR_LOG_MAX];
 static DEFINE_PER_CPU(__u64, mce_data_buf);
 
-static int ras_get_sensor_state_token;
 static int ras_check_exception_token;
 
 #define EPOW_SENSOR_TOKEN      9
@@ -74,7 +52,6 @@ static int __init init_ras_IRQ(void)
 {
        struct device_node *np;
 
-       ras_get_sensor_state_token = rtas_token("get-sensor-state");
        ras_check_exception_token = rtas_token("check-exception");
 
        /* Internal Errors */
@@ -94,26 +71,126 @@ static int __init init_ras_IRQ(void)
 
        return 0;
 }
-__initcall(init_ras_IRQ);
+subsys_initcall(init_ras_IRQ);
 
-/*
- * Handle power subsystem events (EPOW).
- *
- * Presently we just log the event has occurred.  This should be fixed
- * to examine the type of power failure and take appropriate action where
- * the time horizon permits something useful to be done.
- */
+#define EPOW_SHUTDOWN_NORMAL                           1
+#define EPOW_SHUTDOWN_ON_UPS                           2
+#define EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS       3
+#define EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH     4
+
+static void handle_system_shutdown(char event_modifier)
+{
+       switch (event_modifier) {
+       case EPOW_SHUTDOWN_NORMAL:
+               pr_emerg("Firmware initiated power off");
+               orderly_poweroff(1);
+               break;
+
+       case EPOW_SHUTDOWN_ON_UPS:
+               pr_emerg("Loss of power reported by firmware, system is "
+                       "running on UPS/battery");
+               break;
+
+       case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS:
+               pr_emerg("Loss of system critical functions reported by "
+                       "firmware");
+               pr_emerg("Check RTAS error log for details");
+               orderly_poweroff(1);
+               break;
+
+       case EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH:
+               pr_emerg("Ambient temperature too high reported by firmware");
+               pr_emerg("Check RTAS error log for details");
+               orderly_poweroff(1);
+               break;
+
+       default:
+               pr_err("Unknown power/cooling shutdown event (modifier %d)",
+                       event_modifier);
+       }
+}
+
+struct epow_errorlog {
+       unsigned char sensor_value;
+       unsigned char event_modifier;
+       unsigned char extended_modifier;
+       unsigned char reserved;
+       unsigned char platform_reason;
+};
+
+#define EPOW_RESET                     0
+#define EPOW_WARN_COOLING              1
+#define EPOW_WARN_POWER                        2
+#define EPOW_SYSTEM_SHUTDOWN           3
+#define EPOW_SYSTEM_HALT               4
+#define EPOW_MAIN_ENCLOSURE            5
+#define EPOW_POWER_OFF                 7
+
+void rtas_parse_epow_errlog(struct rtas_error_log *log)
+{
+       struct pseries_errorlog *pseries_log;
+       struct epow_errorlog *epow_log;
+       char action_code;
+       char modifier;
+
+       pseries_log = get_pseries_errorlog(log, PSERIES_ELOG_SECT_ID_EPOW);
+       if (pseries_log == NULL)
+               return;
+
+       epow_log = (struct epow_errorlog *)pseries_log->data;
+       action_code = epow_log->sensor_value & 0xF;     /* bottom 4 bits */
+       modifier = epow_log->event_modifier & 0xF;      /* bottom 4 bits */
+
+       switch (action_code) {
+       case EPOW_RESET:
+               pr_err("Non critical power or cooling issue cleared");
+               break;
+
+       case EPOW_WARN_COOLING:
+               pr_err("Non critical cooling issue reported by firmware");
+               pr_err("Check RTAS error log for details");
+               break;
+
+       case EPOW_WARN_POWER:
+               pr_err("Non critical power issue reported by firmware");
+               pr_err("Check RTAS error log for details");
+               break;
+
+       case EPOW_SYSTEM_SHUTDOWN:
+               handle_system_shutdown(epow_log->event_modifier);
+               break;
+
+       case EPOW_SYSTEM_HALT:
+               pr_emerg("Firmware initiated power off");
+               orderly_poweroff(1);
+               break;
+
+       case EPOW_MAIN_ENCLOSURE:
+       case EPOW_POWER_OFF:
+               pr_emerg("Critical power/cooling issue reported by firmware");
+               pr_emerg("Check RTAS error log for details");
+               pr_emerg("Immediate power off");
+               emergency_sync();
+               kernel_power_off();
+               break;
+
+       default:
+               pr_err("Unknown power/cooling event (action code %d)",
+                       action_code);
+       }
+}
+
+/* Handle environmental and power warning (EPOW) interrupts. */
 static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
 {
-       int status = 0xdeadbeef;
-       int state = 0;
+       int status;
+       int state;
        int critical;
 
-       status = rtas_call(ras_get_sensor_state_token, 2, 2, &state,
-                          EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX);
+       status = rtas_get_sensor(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, &state);
 
        if (state > 3)
-               critical = 1;  /* Time Critical */
+               critical = 1;           /* Time Critical */
        else
                critical = 0;
 
@@ -122,18 +199,14 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
        status = rtas_call(ras_check_exception_token, 6, 1, NULL,
                           RTAS_VECTOR_EXTERNAL_INTERRUPT,
                           virq_to_hw(irq),
-                          RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS,
+                          RTAS_EPOW_WARNING,
                           critical, __pa(&ras_log_buf),
                                rtas_get_error_log_max());
 
-       udbg_printf("EPOW <0x%lx 0x%x 0x%x>\n",
-                   *((unsigned long *)&ras_log_buf), status, state);
-       printk(KERN_WARNING "EPOW <0x%lx 0x%x 0x%x>\n",
-              *((unsigned long *)&ras_log_buf), status, state);
-
-       /* format and print the extended information */
        log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);
 
+       rtas_parse_epow_errlog((struct rtas_error_log *)ras_log_buf);
+
        spin_unlock(&ras_log_buf_lock);
        return IRQ_HANDLED;
 }
@@ -149,7 +222,7 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
 static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
 {
        struct rtas_error_log *rtas_elog;
-       int status = 0xdeadbeef;
+       int status;
        int fatal;
 
        spin_lock(&ras_log_buf_lock);
@@ -157,7 +230,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
        status = rtas_call(ras_check_exception_token, 6, 1, NULL,
                           RTAS_VECTOR_EXTERNAL_INTERRUPT,
                           virq_to_hw(irq),
-                          RTAS_INTERNAL_ERROR, 1 /*Time Critical */,
+                          RTAS_INTERNAL_ERROR, 1 /* Time Critical */,
                           __pa(&ras_log_buf),
                                rtas_get_error_log_max());
 
@@ -172,24 +245,13 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
        log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal);
 
        if (fatal) {
-               udbg_printf("Fatal HW Error <0x%lx 0x%x>\n",
-                           *((unsigned long *)&ras_log_buf), status);
-               printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%x>\n",
-                      *((unsigned long *)&ras_log_buf), status);
-
-#ifndef DEBUG_RTAS_POWER_OFF
-               /* Don't actually power off when debugging so we can test
-                * without actually failing while injecting errors.
-                * Error data will not be logged to syslog.
-                */
-               ppc_md.power_off();
-#endif
+               pr_emerg("Fatal hardware error reported by firmware");
+               pr_emerg("Check RTAS error log for details");
+               pr_emerg("Immediate power off");
+               emergency_sync();
+               kernel_power_off();
        } else {
-               udbg_printf("Recoverable HW Error <0x%lx 0x%x>\n",
-                           *((unsigned long *)&ras_log_buf), status);
-               printk(KERN_WARNING
-                      "Warning: Recoverable hardware error <0x%lx 0x%x>\n",
-                      *((unsigned long *)&ras_log_buf), status);
+               pr_err("Recoverable hardware error reported by firmware");
        }
 
        spin_unlock(&ras_log_buf_lock);
index 8f137af..51ecac9 100644 (file)
@@ -383,6 +383,9 @@ static void __init pSeries_setup_arch(void)
 
        fwnmi_init();
 
+       /* By default, only probe PCI (can be overriden by rtas_pci) */
+       pci_add_flags(PCI_PROBE_ONLY);
+
        /* Find and initialize PCI host bridges */
        init_pci_config_tokens();
        eeh_pseries_init();
index 3868794..1526551 100644 (file)
@@ -683,7 +683,6 @@ static int __init wsp_setup_one_phb(struct device_node *np)
        /* XXX Force re-assigning of everything for now */
        pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC |
                      PCI_ENABLE_PROC_DOMAINS);
-       pci_probe_only = 0;
 
        /* Calculate how the TCE space is divided */
        phb->dma32_base         = 0;
index af3780e..6845e91 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
+#include <linux/bug.h>
 #include "nonstdio.h"
 #include "ppc.h"
 
index 530df3d..7d37597 100644 (file)
@@ -19,6 +19,7 @@
    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include <linux/kernel.h>
+#include <linux/bug.h>
 #include "spu.h"
 
 /* This file holds the Spu opcode table */
index 6d99a5f..465d5be 100644 (file)
@@ -64,6 +64,7 @@ config ARCH_SUPPORTS_DEBUG_PAGEALLOC
 config S390
        def_bool y
        select USE_GENERIC_SMP_HELPERS if SMP
+       select GENERIC_CPU_DEVICES if !SMP
        select HAVE_SYSCALL_WRAPPERS
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h
new file mode 100644 (file)
index 0000000..e49db5d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * CPU-measurement facilities
+ *
+ *  Copyright IBM Corp. 2012
+ *  Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ *            Jan Glauber <jang@linux.vnet.ibm.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 only)
+ * as published by the Free Software Foundation.
+ */
+#ifndef _ASM_S390_CPU_MF_H
+#define _ASM_S390_CPU_MF_H
+
+#define CPU_MF_INT_SF_IAE      (1 << 31)       /* invalid entry address */
+#define CPU_MF_INT_SF_ISE      (1 << 30)       /* incorrect SDBT entry */
+#define CPU_MF_INT_SF_PRA      (1 << 29)       /* program request alert */
+#define CPU_MF_INT_SF_SACA     (1 << 23)       /* sampler auth. change alert */
+#define CPU_MF_INT_SF_LSDA     (1 << 22)       /* loss of sample data alert */
+#define CPU_MF_INT_CF_CACA     (1 <<  7)       /* counter auth. change alert */
+#define CPU_MF_INT_CF_LCDA     (1 <<  6)       /* loss of counter data alert */
+
+#define CPU_MF_INT_CF_MASK     (CPU_MF_INT_CF_CACA|CPU_MF_INT_CF_LCDA)
+#define CPU_MF_INT_SF_MASK     (CPU_MF_INT_SF_IAE|CPU_MF_INT_SF_ISE|   \
+                                CPU_MF_INT_SF_PRA|CPU_MF_INT_SF_SACA|  \
+                                CPU_MF_INT_SF_LSDA)
+
+/* CPU measurement facility support */
+static inline int cpum_cf_avail(void)
+{
+       return MACHINE_HAS_SPP && test_facility(67);
+}
+
+static inline int cpum_sf_avail(void)
+{
+       return MACHINE_HAS_SPP && test_facility(68);
+}
+
+
+struct cpumf_ctr_info {
+       u16   cfvn;
+       u16   auth_ctl;
+       u16   enable_ctl;
+       u16   act_ctl;
+       u16   max_cpu;
+       u16   csvn;
+       u16   max_cg;
+       u16   reserved1;
+       u32   reserved2[12];
+} __packed;
+
+/* Query counter information */
+static inline int qctri(struct cpumf_ctr_info *info)
+{
+       int rc = -EINVAL;
+
+       asm volatile (
+               "0:     .insn   s,0xb28e0000,%1\n"
+               "1:     lhi     %0,0\n"
+               "2:\n"
+               EX_TABLE(1b, 2b)
+               : "+d" (rc), "=Q" (*info));
+       return rc;
+}
+
+/* Load CPU-counter-set controls */
+static inline int lcctl(u64 ctl)
+{
+       int cc;
+
+       asm volatile (
+               "       .insn   s,0xb2840000,%1\n"
+               "       ipm     %0\n"
+               "       srl     %0,28\n"
+               : "=d" (cc) : "m" (ctl) : "cc");
+       return cc;
+}
+
+/* Extract CPU counter */
+static inline int ecctr(u64 ctr, u64 *val)
+{
+       register u64 content asm("4") = 0;
+       int cc;
+
+       asm volatile (
+               "       .insn   rre,0xb2e40000,%0,%2\n"
+               "       ipm     %1\n"
+               "       srl     %1,28\n"
+               : "=d" (content), "=d" (cc) : "d" (ctr) : "cc");
+       if (!cc)
+               *val = content;
+       return cc;
+}
+
+#endif /* _ASM_S390_CPU_MF_H */
index acee180..5289cac 100644 (file)
@@ -45,5 +45,7 @@ int register_external_interrupt(u16 code, ext_int_handler_t handler);
 int unregister_external_interrupt(u16 code, ext_int_handler_t handler);
 void service_subclass_irq_register(void);
 void service_subclass_irq_unregister(void);
+void measurement_alert_subclass_register(void);
+void measurement_alert_subclass_unregister(void);
 
 #endif /* _ASM_IRQ_H */
index 82b32a1..9607667 100644 (file)
@@ -41,4 +41,15 @@ struct kvm_debug_exit_arch {
 struct kvm_guest_debug_arch {
 };
 
+#define KVM_SYNC_PREFIX (1UL << 0)
+#define KVM_SYNC_GPRS   (1UL << 1)
+#define KVM_SYNC_ACRS   (1UL << 2)
+#define KVM_SYNC_CRS    (1UL << 3)
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+       __u64 prefix;   /* prefix register */
+       __u64 gprs[16]; /* general purpose registers */
+       __u32 acrs[16]; /* access registers */
+       __u64 crs[16];  /* control registers */
+};
 #endif
index b0c235c..7343872 100644 (file)
@@ -220,18 +220,17 @@ struct kvm_s390_float_interrupt {
        struct list_head list;
        atomic_t active;
        int next_rr_cpu;
-       unsigned long idle_mask [(64 + sizeof(long) - 1) / sizeof(long)];
-       struct kvm_s390_local_interrupt *local_int[64];
+       unsigned long idle_mask[(KVM_MAX_VCPUS + sizeof(long) - 1)
+                               / sizeof(long)];
+       struct kvm_s390_local_interrupt *local_int[KVM_MAX_VCPUS];
 };
 
 
 struct kvm_vcpu_arch {
        struct kvm_s390_sie_block *sie_block;
-       unsigned long     guest_gprs[16];
        s390_fp_regs      host_fpregs;
        unsigned int      host_acrs[NUM_ACRS];
        s390_fp_regs      guest_fpregs;
-       unsigned int      guest_acrs[NUM_ACRS];
        struct kvm_s390_local_interrupt local_int;
        struct hrtimer    ckc_timer;
        struct tasklet_struct tasklet;
@@ -246,6 +245,9 @@ struct kvm_vm_stat {
        u32 remote_tlb_flush;
 };
 
+struct kvm_arch_memory_slot {
+};
+
 struct kvm_arch{
        struct sca_block *sca;
        debug_info_t *dbf;
@@ -253,5 +255,5 @@ struct kvm_arch{
        struct gmap *gmap;
 };
 
-extern int sie64a(struct kvm_s390_sie_block *, unsigned long *);
+extern int sie64a(struct kvm_s390_sie_block *, u64 *);
 #endif
index 4eb444e..7941968 100644 (file)
@@ -1,8 +1,16 @@
 /*
  * Performance event support - s390 specific definitions.
  *
- * Copyright 2009 Martin Schwidefsky, IBM Corporation.
+ * Copyright IBM Corp. 2009, 2012
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *           Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  */
 
-/* Empty, just to avoid compiling error */
+#include <asm/cpu_mf.h>
 
+/* CPU-measurement counter facility */
+#define PERF_CPUM_CF_MAX_CTR           160
+
+/* Per-CPU flags for PMU states */
+#define PMU_F_RESERVED                 0x1000
+#define PMU_F_ENABLED                  0x2000
index 16b0b43..884b18a 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE)  += ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
 obj-$(CONFIG_FTRACE_SYSCALLS)  += ftrace.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
+obj-$(CONFIG_PERF_EVENTS)      += perf_event.o perf_cpum_cf.o
 
 # Kexec part
 S390_KEXEC_OBJS := machine_kexec.o crash.o
index 2429ecd..1c2cdd5 100644 (file)
@@ -255,3 +255,26 @@ void service_subclass_irq_unregister(void)
        spin_unlock(&sc_irq_lock);
 }
 EXPORT_SYMBOL(service_subclass_irq_unregister);
+
+static DEFINE_SPINLOCK(ma_subclass_lock);
+static int ma_subclass_refcount;
+
+void measurement_alert_subclass_register(void)
+{
+       spin_lock(&ma_subclass_lock);
+       if (!ma_subclass_refcount)
+               ctl_set_bit(0, 5);
+       ma_subclass_refcount++;
+       spin_unlock(&ma_subclass_lock);
+}
+EXPORT_SYMBOL(measurement_alert_subclass_register);
+
+void measurement_alert_subclass_unregister(void)
+{
+       spin_lock(&ma_subclass_lock);
+       ma_subclass_refcount--;
+       if (!ma_subclass_refcount)
+               ctl_clear_bit(0, 5);
+       spin_unlock(&ma_subclass_lock);
+}
+EXPORT_SYMBOL(measurement_alert_subclass_unregister);
diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c
new file mode 100644 (file)
index 0000000..8481ecf
--- /dev/null
@@ -0,0 +1,690 @@
+/*
+ * Performance event support for s390x - CPU-measurement Counter Facility
+ *
+ *  Copyright IBM Corp. 2012
+ *  Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.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 only)
+ * as published by the Free Software Foundation.
+ */
+#define KMSG_COMPONENT "cpum_cf"
+#define pr_fmt(fmt)    KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <linux/export.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/cpu_mf.h>
+
+/* CPU-measurement counter facility supports these CPU counter sets:
+ * For CPU counter sets:
+ *    Basic counter set:            0-31
+ *    Problem-state counter set:    32-63
+ *    Crypto-activity counter set:  64-127
+ *    Extented counter set:       128-159
+ */
+enum cpumf_ctr_set {
+       /* CPU counter sets */
+       CPUMF_CTR_SET_BASIC   = 0,
+       CPUMF_CTR_SET_USER    = 1,
+       CPUMF_CTR_SET_CRYPTO  = 2,
+       CPUMF_CTR_SET_EXT     = 3,
+
+       /* Maximum number of counter sets */
+       CPUMF_CTR_SET_MAX,
+};
+
+#define CPUMF_LCCTL_ENABLE_SHIFT    16
+#define CPUMF_LCCTL_ACTCTL_SHIFT     0
+static const u64 cpumf_state_ctl[CPUMF_CTR_SET_MAX] = {
+       [CPUMF_CTR_SET_BASIC]   = 0x02,
+       [CPUMF_CTR_SET_USER]    = 0x04,
+       [CPUMF_CTR_SET_CRYPTO]  = 0x08,
+       [CPUMF_CTR_SET_EXT]     = 0x01,
+};
+
+static void ctr_set_enable(u64 *state, int ctr_set)
+{
+       *state |= cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT;
+}
+static void ctr_set_disable(u64 *state, int ctr_set)
+{
+       *state &= ~(cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT);
+}
+static void ctr_set_start(u64 *state, int ctr_set)
+{
+       *state |= cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT;
+}
+static void ctr_set_stop(u64 *state, int ctr_set)
+{
+       *state &= ~(cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT);
+}
+
+/* Local CPUMF event structure */
+struct cpu_hw_events {
+       struct cpumf_ctr_info   info;
+       atomic_t                ctr_set[CPUMF_CTR_SET_MAX];
+       u64                     state, tx_state;
+       unsigned int            flags;
+};
+static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
+       .ctr_set = {
+               [CPUMF_CTR_SET_BASIC]  = ATOMIC_INIT(0),
+               [CPUMF_CTR_SET_USER]   = ATOMIC_INIT(0),
+               [CPUMF_CTR_SET_CRYPTO] = ATOMIC_INIT(0),
+               [CPUMF_CTR_SET_EXT]    = ATOMIC_INIT(0),
+       },
+       .state = 0,
+       .flags = 0,
+};
+
+static int get_counter_set(u64 event)
+{
+       int set = -1;
+
+       if (event < 32)
+               set = CPUMF_CTR_SET_BASIC;
+       else if (event < 64)
+               set = CPUMF_CTR_SET_USER;
+       else if (event < 128)
+               set = CPUMF_CTR_SET_CRYPTO;
+       else if (event < 160)
+               set = CPUMF_CTR_SET_EXT;
+
+       return set;
+}
+
+static int validate_event(const struct hw_perf_event *hwc)
+{
+       switch (hwc->config_base) {
+       case CPUMF_CTR_SET_BASIC:
+       case CPUMF_CTR_SET_USER:
+       case CPUMF_CTR_SET_CRYPTO:
+       case CPUMF_CTR_SET_EXT:
+               /* check for reserved counters */
+               if ((hwc->config >=  6 && hwc->config <=  31) ||
+                   (hwc->config >= 38 && hwc->config <=  63) ||
+                   (hwc->config >= 80 && hwc->config <= 127))
+                       return -EOPNOTSUPP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int validate_ctr_version(const struct hw_perf_event *hwc)
+{
+       struct cpu_hw_events *cpuhw;
+       int err = 0;
+
+       cpuhw = &get_cpu_var(cpu_hw_events);
+
+       /* check required version for counter sets */
+       switch (hwc->config_base) {
+       case CPUMF_CTR_SET_BASIC:
+       case CPUMF_CTR_SET_USER:
+               if (cpuhw->info.cfvn < 1)
+                       err = -EOPNOTSUPP;
+               break;
+       case CPUMF_CTR_SET_CRYPTO:
+       case CPUMF_CTR_SET_EXT:
+               if (cpuhw->info.csvn < 1)
+                       err = -EOPNOTSUPP;
+               break;
+       }
+
+       put_cpu_var(cpu_hw_events);
+       return err;
+}
+
+static int validate_ctr_auth(const struct hw_perf_event *hwc)
+{
+       struct cpu_hw_events *cpuhw;
+       u64 ctrs_state;
+       int err = 0;
+
+       cpuhw = &get_cpu_var(cpu_hw_events);
+
+       /* check authorization for cpu counter sets */
+       ctrs_state = cpumf_state_ctl[hwc->config_base];
+       if (!(ctrs_state & cpuhw->info.auth_ctl))
+               err = -EPERM;
+
+       put_cpu_var(cpu_hw_events);
+       return err;
+}
+
+/*
+ * Change the CPUMF state to active.
+ * Enable and activate the CPU-counter sets according
+ * to the per-cpu control state.
+ */
+static void cpumf_pmu_enable(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+       int err;
+
+       if (cpuhw->flags & PMU_F_ENABLED)
+               return;
+
+       err = lcctl(cpuhw->state);
+       if (err) {
+               pr_err("Enabling the performance measuring unit "
+                      "failed with rc=%lx\n", err);
+               return;
+       }
+
+       cpuhw->flags |= PMU_F_ENABLED;
+}
+
+/*
+ * Change the CPUMF state to inactive.
+ * Disable and enable (inactive) the CPU-counter sets according
+ * to the per-cpu control state.
+ */
+static void cpumf_pmu_disable(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+       int err;
+       u64 inactive;
+
+       if (!(cpuhw->flags & PMU_F_ENABLED))
+               return;
+
+       inactive = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1);
+       err = lcctl(inactive);
+       if (err) {
+               pr_err("Disabling the performance measuring unit "
+                      "failed with rc=%lx\n", err);
+               return;
+       }
+
+       cpuhw->flags &= ~PMU_F_ENABLED;
+}
+
+
+/* Number of perf events counting hardware events */
+static atomic_t num_events = ATOMIC_INIT(0);
+/* Used to avoid races in calling reserve/release_cpumf_hardware */
+static DEFINE_MUTEX(pmc_reserve_mutex);
+
+/* CPU-measurement alerts for the counter facility */
+static void cpumf_measurement_alert(struct ext_code ext_code,
+                                   unsigned int alert, unsigned long unused)
+{
+       struct cpu_hw_events *cpuhw;
+
+       if (!(alert & CPU_MF_INT_CF_MASK))
+               return;
+
+       kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
+       cpuhw = &__get_cpu_var(cpu_hw_events);
+
+       /* Measurement alerts are shared and might happen when the PMU
+        * is not reserved.  Ignore these alerts in this case. */
+       if (!(cpuhw->flags & PMU_F_RESERVED))
+               return;
+
+       /* counter authorization change alert */
+       if (alert & CPU_MF_INT_CF_CACA)
+               qctri(&cpuhw->info);
+
+       /* loss of counter data alert */
+       if (alert & CPU_MF_INT_CF_LCDA)
+               pr_err("CPU[%i] Counter data was lost\n", smp_processor_id());
+}
+
+#define PMC_INIT      0
+#define PMC_RELEASE   1
+static void setup_pmc_cpu(void *flags)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+       switch (*((int *) flags)) {
+       case PMC_INIT:
+               memset(&cpuhw->info, 0, sizeof(cpuhw->info));
+               qctri(&cpuhw->info);
+               cpuhw->flags |= PMU_F_RESERVED;
+               break;
+
+       case PMC_RELEASE:
+               cpuhw->flags &= ~PMU_F_RESERVED;
+               break;
+       }
+
+       /* Disable CPU counter sets */
+       lcctl(0);
+}
+
+/* Initialize the CPU-measurement facility */
+static int reserve_pmc_hardware(void)
+{
+       int flags = PMC_INIT;
+
+       on_each_cpu(setup_pmc_cpu, &flags, 1);
+       measurement_alert_subclass_register();
+
+       return 0;
+}
+
+/* Release the CPU-measurement facility */
+static void release_pmc_hardware(void)
+{
+       int flags = PMC_RELEASE;
+
+       on_each_cpu(setup_pmc_cpu, &flags, 1);
+       measurement_alert_subclass_unregister();
+}
+
+/* Release the PMU if event is the last perf event */
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+       if (!atomic_add_unless(&num_events, -1, 1)) {
+               mutex_lock(&pmc_reserve_mutex);
+               if (atomic_dec_return(&num_events) == 0)
+                       release_pmc_hardware();
+               mutex_unlock(&pmc_reserve_mutex);
+       }
+}
+
+/* CPUMF <-> perf event mappings for kernel+userspace (basic set) */
+static const int cpumf_generic_events_basic[] = {
+       [PERF_COUNT_HW_CPU_CYCLES]          = 0,
+       [PERF_COUNT_HW_INSTRUCTIONS]        = 1,
+       [PERF_COUNT_HW_CACHE_REFERENCES]    = -1,
+       [PERF_COUNT_HW_CACHE_MISSES]        = -1,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = -1,
+       [PERF_COUNT_HW_BRANCH_MISSES]       = -1,
+       [PERF_COUNT_HW_BUS_CYCLES]          = -1,
+};
+/* CPUMF <-> perf event mappings for userspace (problem-state set) */
+static const int cpumf_generic_events_user[] = {
+       [PERF_COUNT_HW_CPU_CYCLES]          = 32,
+       [PERF_COUNT_HW_INSTRUCTIONS]        = 33,
+       [PERF_COUNT_HW_CACHE_REFERENCES]    = -1,
+       [PERF_COUNT_HW_CACHE_MISSES]        = -1,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = -1,
+       [PERF_COUNT_HW_BRANCH_MISSES]       = -1,
+       [PERF_COUNT_HW_BUS_CYCLES]          = -1,
+};
+
+static int __hw_perf_event_init(struct perf_event *event)
+{
+       struct perf_event_attr *attr = &event->attr;
+       struct hw_perf_event *hwc = &event->hw;
+       int err;
+       u64 ev;
+
+       switch (attr->type) {
+       case PERF_TYPE_RAW:
+               /* Raw events are used to access counters directly,
+                * hence do not permit excludes */
+               if (attr->exclude_kernel || attr->exclude_user ||
+                   attr->exclude_hv)
+                       return -EOPNOTSUPP;
+               ev = attr->config;
+               break;
+
+       case PERF_TYPE_HARDWARE:
+               ev = attr->config;
+               /* Count user space (problem-state) only */
+               if (!attr->exclude_user && attr->exclude_kernel) {
+                       if (ev >= ARRAY_SIZE(cpumf_generic_events_user))
+                               return -EOPNOTSUPP;
+                       ev = cpumf_generic_events_user[ev];
+
+               /* No support for kernel space counters only */
+               } else if (!attr->exclude_kernel && attr->exclude_user) {
+                       return -EOPNOTSUPP;
+
+               /* Count user and kernel space */
+               } else {
+                       if (ev >= ARRAY_SIZE(cpumf_generic_events_basic))
+                               return -EOPNOTSUPP;
+                       ev = cpumf_generic_events_basic[ev];
+               }
+               break;
+
+       default:
+               return -ENOENT;
+       }
+
+       if (ev == -1)
+               return -ENOENT;
+
+       if (ev >= PERF_CPUM_CF_MAX_CTR)
+               return -EINVAL;
+
+       /* The CPU measurement counter facility does not have any interrupts
+        * to do sampling.  Sampling must be provided by external means,
+        * for example, by timers.
+        */
+       if (hwc->sample_period)
+               return -EINVAL;
+
+       /* Use the hardware perf event structure to store the counter number
+        * in 'config' member and the counter set to which the counter belongs
+        * in the 'config_base'.  The counter set (config_base) is then used
+        * to enable/disable the counters.
+        */
+       hwc->config = ev;
+       hwc->config_base = get_counter_set(ev);
+
+       /* Validate the counter that is assigned to this event.
+        * Because the counter facility can use numerous counters at the
+        * same time without constraints, it is not necessary to explicity
+        * validate event groups (event->group_leader != event).
+        */
+       err = validate_event(hwc);
+       if (err)
+               return err;
+
+       /* Initialize for using the CPU-measurement counter facility */
+       if (!atomic_inc_not_zero(&num_events)) {
+               mutex_lock(&pmc_reserve_mutex);
+               if (atomic_read(&num_events) == 0 && reserve_pmc_hardware())
+                       err = -EBUSY;
+               else
+                       atomic_inc(&num_events);
+               mutex_unlock(&pmc_reserve_mutex);
+       }
+       event->destroy = hw_perf_event_destroy;
+
+       /* Finally, validate version and authorization of the counter set */
+       err = validate_ctr_auth(hwc);
+       if (!err)
+               err = validate_ctr_version(hwc);
+
+       return err;
+}
+
+static int cpumf_pmu_event_init(struct perf_event *event)
+{
+       int err;
+
+       switch (event->attr.type) {
+       case PERF_TYPE_HARDWARE:
+       case PERF_TYPE_HW_CACHE:
+       case PERF_TYPE_RAW:
+               err = __hw_perf_event_init(event);
+               break;
+       default:
+               return -ENOENT;
+       }
+
+       if (unlikely(err) && event->destroy)
+               event->destroy(event);
+
+       return err;
+}
+
+static int hw_perf_event_reset(struct perf_event *event)
+{
+       u64 prev, new;
+       int err;
+
+       do {
+               prev = local64_read(&event->hw.prev_count);
+               err = ecctr(event->hw.config, &new);
+               if (err) {
+                       if (err != 3)
+                               break;
+                       /* The counter is not (yet) available. This
+                        * might happen if the counter set to which
+                        * this counter belongs is in the disabled
+                        * state.
+                        */
+                       new = 0;
+               }
+       } while (local64_cmpxchg(&event->hw.prev_count, prev, new) != prev);
+
+       return err;
+}
+
+static int hw_perf_event_update(struct perf_event *event)
+{
+       u64 prev, new, delta;
+       int err;
+
+       do {
+               prev = local64_read(&event->hw.prev_count);
+               err = ecctr(event->hw.config, &new);
+               if (err)
+                       goto out;
+       } while (local64_cmpxchg(&event->hw.prev_count, prev, new) != prev);
+
+       delta = (prev <= new) ? new - prev
+                             : (-1ULL - prev) + new + 1;        /* overflow */
+       local64_add(delta, &event->count);
+out:
+       return err;
+}
+
+static void cpumf_pmu_read(struct perf_event *event)
+{
+       if (event->hw.state & PERF_HES_STOPPED)
+               return;
+
+       hw_perf_event_update(event);
+}
+
+static void cpumf_pmu_start(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+               return;
+
+       if (WARN_ON_ONCE(hwc->config == -1))
+               return;
+
+       if (flags & PERF_EF_RELOAD)
+               WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+
+       hwc->state = 0;
+
+       /* (Re-)enable and activate the counter set */
+       ctr_set_enable(&cpuhw->state, hwc->config_base);
+       ctr_set_start(&cpuhw->state, hwc->config_base);
+
+       /* The counter set to which this counter belongs can be already active.
+        * Because all counters in a set are active, the event->hw.prev_count
+        * needs to be synchronized.  At this point, the counter set can be in
+        * the inactive or disabled state.
+        */
+       hw_perf_event_reset(event);
+
+       /* increment refcount for this counter set */
+       atomic_inc(&cpuhw->ctr_set[hwc->config_base]);
+}
+
+static void cpumf_pmu_stop(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!(hwc->state & PERF_HES_STOPPED)) {
+               /* Decrement reference count for this counter set and if this
+                * is the last used counter in the set, clear activation
+                * control and set the counter set state to inactive.
+                */
+               if (!atomic_dec_return(&cpuhw->ctr_set[hwc->config_base]))
+                       ctr_set_stop(&cpuhw->state, hwc->config_base);
+               event->hw.state |= PERF_HES_STOPPED;
+       }
+
+       if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+               hw_perf_event_update(event);
+               event->hw.state |= PERF_HES_UPTODATE;
+       }
+}
+
+static int cpumf_pmu_add(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+       /* Check authorization for the counter set to which this
+        * counter belongs.
+        * For group events transaction, the authorization check is
+        * done in cpumf_pmu_commit_txn().
+        */
+       if (!(cpuhw->flags & PERF_EVENT_TXN))
+               if (validate_ctr_auth(&event->hw))
+                       return -EPERM;
+
+       ctr_set_enable(&cpuhw->state, event->hw.config_base);
+       event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+       if (flags & PERF_EF_START)
+               cpumf_pmu_start(event, PERF_EF_RELOAD);
+
+       perf_event_update_userpage(event);
+
+       return 0;
+}
+
+static void cpumf_pmu_del(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+       cpumf_pmu_stop(event, PERF_EF_UPDATE);
+
+       /* Check if any counter in the counter set is still used.  If not used,
+        * change the counter set to the disabled state.  This also clears the
+        * content of all counters in the set.
+        *
+        * When a new perf event has been added but not yet started, this can
+        * clear enable control and resets all counters in a set.  Therefore,
+        * cpumf_pmu_start() always has to reenable a counter set.
+        */
+       if (!atomic_read(&cpuhw->ctr_set[event->hw.config_base]))
+               ctr_set_disable(&cpuhw->state, event->hw.config_base);
+
+       perf_event_update_userpage(event);
+}
+
+/*
+ * Start group events scheduling transaction.
+ * Set flags to perform a single test at commit time.
+ */
+static void cpumf_pmu_start_txn(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+       perf_pmu_disable(pmu);
+       cpuhw->flags |= PERF_EVENT_TXN;
+       cpuhw->tx_state = cpuhw->state;
+}
+
+/*
+ * Stop and cancel a group events scheduling tranctions.
+ * Assumes cpumf_pmu_del() is called for each successful added
+ * cpumf_pmu_add() during the transaction.
+ */
+static void cpumf_pmu_cancel_txn(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+
+       WARN_ON(cpuhw->tx_state != cpuhw->state);
+
+       cpuhw->flags &= ~PERF_EVENT_TXN;
+       perf_pmu_enable(pmu);
+}
+
+/*
+ * Commit the group events scheduling transaction.  On success, the
+ * transaction is closed.   On error, the transaction is kept open
+ * until cpumf_pmu_cancel_txn() is called.
+ */
+static int cpumf_pmu_commit_txn(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
+       u64 state;
+
+       /* check if the updated state can be scheduled */
+       state = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1);
+       state >>= CPUMF_LCCTL_ENABLE_SHIFT;
+       if ((state & cpuhw->info.auth_ctl) != state)
+               return -EPERM;
+
+       cpuhw->flags &= ~PERF_EVENT_TXN;
+       perf_pmu_enable(pmu);
+       return 0;
+}
+
+/* Performance monitoring unit for s390x */
+static struct pmu cpumf_pmu = {
+       .pmu_enable   = cpumf_pmu_enable,
+       .pmu_disable  = cpumf_pmu_disable,
+       .event_init   = cpumf_pmu_event_init,
+       .add          = cpumf_pmu_add,
+       .del          = cpumf_pmu_del,
+       .start        = cpumf_pmu_start,
+       .stop         = cpumf_pmu_stop,
+       .read         = cpumf_pmu_read,
+       .start_txn    = cpumf_pmu_start_txn,
+       .commit_txn   = cpumf_pmu_commit_txn,
+       .cancel_txn   = cpumf_pmu_cancel_txn,
+};
+
+static int __cpuinit cpumf_pmu_notifier(struct notifier_block *self,
+                                       unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (long) hcpu;
+       int flags;
+
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_ONLINE:
+               flags = PMC_INIT;
+               smp_call_function_single(cpu, setup_pmc_cpu, &flags, 1);
+               break;
+       case CPU_DOWN_PREPARE:
+               flags = PMC_RELEASE;
+               smp_call_function_single(cpu, setup_pmc_cpu, &flags, 1);
+               break;
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static int __init cpumf_pmu_init(void)
+{
+       int rc;
+
+       if (!cpum_cf_avail())
+               return -ENODEV;
+
+       /* clear bit 15 of cr0 to unauthorize problem-state to
+        * extract measurement counters */
+       ctl_clear_bit(0, 48);
+
+       /* register handler for measurement-alert interruptions */
+       rc = register_external_interrupt(0x1407, cpumf_measurement_alert);
+       if (rc) {
+               pr_err("Registering for CPU-measurement alerts "
+                      "failed with rc=%i\n", rc);
+               goto out;
+       }
+
+       rc = perf_pmu_register(&cpumf_pmu, "cpum_cf", PERF_TYPE_RAW);
+       if (rc) {
+               pr_err("Registering the cpum_cf PMU failed with rc=%i\n", rc);
+               unregister_external_interrupt(0x1407, cpumf_measurement_alert);
+               goto out;
+       }
+       perf_cpu_notifier(cpumf_pmu_notifier);
+out:
+       return rc;
+}
+early_initcall(cpumf_pmu_init);
diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c
new file mode 100644 (file)
index 0000000..609f985
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Performance event support for s390x
+ *
+ *  Copyright IBM Corp. 2012
+ *  Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.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 only)
+ * as published by the Free Software Foundation.
+ */
+#define KMSG_COMPONENT "perf"
+#define pr_fmt(fmt)    KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/export.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/cpu_mf.h>
+#include <asm/lowcore.h>
+#include <asm/processor.h>
+
+const char *perf_pmu_name(void)
+{
+       if (cpum_cf_avail() || cpum_sf_avail())
+               return "CPU-measurement facilities (CPUMF)";
+       return "pmu";
+}
+EXPORT_SYMBOL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+       int num = 0;
+
+       if (cpum_cf_avail())
+               num += PERF_CPUM_CF_MAX_CTR;
+
+       return num;
+}
+EXPORT_SYMBOL(perf_num_counters);
+
+void perf_event_print_debug(void)
+{
+       struct cpumf_ctr_info cf_info;
+       unsigned long flags;
+       int cpu;
+
+       if (!cpum_cf_avail())
+               return;
+
+       local_irq_save(flags);
+
+       cpu = smp_processor_id();
+       memset(&cf_info, 0, sizeof(cf_info));
+       if (!qctri(&cf_info)) {
+               pr_info("CPU[%i] CPUM_CF: ver=%u.%u A=%04x E=%04x C=%04x\n",
+                       cpu, cf_info.cfvn, cf_info.csvn,
+                       cf_info.auth_ctl, cf_info.enable_ctl, cf_info.act_ctl);
+               print_hex_dump_bytes("CPUMF Query: ", DUMP_PREFIX_OFFSET,
+                                    &cf_info, sizeof(cf_info));
+       }
+
+       local_irq_restore(flags);
+}
+
+/* See also arch/s390/kernel/traps.c */
+static unsigned long __store_trace(struct perf_callchain_entry *entry,
+                                  unsigned long sp,
+                                  unsigned long low, unsigned long high)
+{
+       struct stack_frame *sf;
+       struct pt_regs *regs;
+
+       while (1) {
+               sp = sp & PSW_ADDR_INSN;
+               if (sp < low || sp > high - sizeof(*sf))
+                       return sp;
+               sf = (struct stack_frame *) sp;
+               perf_callchain_store(entry, sf->gprs[8] & PSW_ADDR_INSN);
+               /* Follow the backchain. */
+               while (1) {
+                       low = sp;
+                       sp = sf->back_chain & PSW_ADDR_INSN;
+                       if (!sp)
+                               break;
+                       if (sp <= low || sp > high - sizeof(*sf))
+                               return sp;
+                       sf = (struct stack_frame *) sp;
+                       perf_callchain_store(entry,
+                                            sf->gprs[8] & PSW_ADDR_INSN);
+               }
+               /* Zero backchain detected, check for interrupt frame. */
+               sp = (unsigned long) (sf + 1);
+               if (sp <= low || sp > high - sizeof(*regs))
+                       return sp;
+               regs = (struct pt_regs *) sp;
+               perf_callchain_store(entry, sf->gprs[8] & PSW_ADDR_INSN);
+               low = sp;
+               sp = regs->gprs[15];
+       }
+}
+
+void perf_callchain_kernel(struct perf_callchain_entry *entry,
+                          struct pt_regs *regs)
+{
+       unsigned long head;
+       struct stack_frame *head_sf;
+
+       if (user_mode(regs))
+               return;
+
+       head = regs->gprs[15];
+       head_sf = (struct stack_frame *) head;
+
+       if (!head_sf || !head_sf->back_chain)
+               return;
+
+       head = head_sf->back_chain;
+       head = __store_trace(entry, head, S390_lowcore.async_stack - ASYNC_SIZE,
+                            S390_lowcore.async_stack);
+
+       __store_trace(entry, head, S390_lowcore.thread_info,
+                     S390_lowcore.thread_info + THREAD_SIZE);
+}
index d95427e..ea5590f 100644 (file)
@@ -241,17 +241,11 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
         * on the "data" page of the vDSO or you'll stop getting kernel
         * updates and your nice userland gettimeofday will be totally dead.
         * It's fine to use that for setting breakpoints in the vDSO code
-        * pages though
-        *
-        * Make sure the vDSO gets into every core dump.
-        * Dumping its contents makes post-mortem fully interpretable later
-        * without matching up the same kernel and hardware config to see
-        * what PC values meant.
+        * pages though.
         */
        rc = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT,
                                     VM_READ|VM_EXEC|
-                                    VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-                                    VM_ALWAYSDUMP,
+                                    VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
                                     vdso_pagelist);
        if (rc)
                current->mm->context.vdso_base = 0;
index a216341..78eb984 100644 (file)
@@ -34,6 +34,15 @@ config KVM
 
          If unsure, say N.
 
+config KVM_S390_UCONTROL
+       bool "Userspace controlled virtual machines"
+       depends on KVM
+       ---help---
+         Allow CAP_SYS_ADMIN users to create KVM virtual machines that are
+         controlled by userspace.
+
+         If unsure, say N.
+
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
 source drivers/vhost/Kconfig
index 8943e82..a353f0e 100644 (file)
@@ -20,8 +20,8 @@ static int diag_release_pages(struct kvm_vcpu *vcpu)
        unsigned long start, end;
        unsigned long prefix  = vcpu->arch.sie_block->prefix;
 
-       start = vcpu->arch.guest_gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4];
-       end = vcpu->arch.guest_gprs[vcpu->arch.sie_block->ipa & 0xf] + 4096;
+       start = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4];
+       end = vcpu->run->s.regs.gprs[vcpu->arch.sie_block->ipa & 0xf] + 4096;
 
        if (start & ~PAGE_MASK || end & ~PAGE_MASK || start > end
            || start < 2 * PAGE_SIZE)
@@ -56,7 +56,7 @@ static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
 static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
 {
        unsigned int reg = vcpu->arch.sie_block->ipa & 0xf;
-       unsigned long subcode = vcpu->arch.guest_gprs[reg] & 0xffff;
+       unsigned long subcode = vcpu->run->s.regs.gprs[reg] & 0xffff;
 
        VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode);
        switch (subcode) {
index 0243454..3614565 100644 (file)
@@ -36,7 +36,7 @@ static int handle_lctlg(struct kvm_vcpu *vcpu)
 
        useraddr = disp2;
        if (base2)
-               useraddr += vcpu->arch.guest_gprs[base2];
+               useraddr += vcpu->run->s.regs.gprs[base2];
 
        if (useraddr & 7)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -75,7 +75,7 @@ static int handle_lctl(struct kvm_vcpu *vcpu)
 
        useraddr = disp2;
        if (base2)
-               useraddr += vcpu->arch.guest_gprs[base2];
+               useraddr += vcpu->run->s.regs.gprs[base2];
 
        if (useraddr & 3)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -133,13 +133,6 @@ static int handle_stop(struct kvm_vcpu *vcpu)
 
        vcpu->stat.exit_stop_request++;
        spin_lock_bh(&vcpu->arch.local_int.lock);
-       if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) {
-               vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP;
-               rc = kvm_s390_vcpu_store_status(vcpu,
-                                                 KVM_S390_STORE_STATUS_NOADDR);
-               if (rc >= 0)
-                       rc = -EOPNOTSUPP;
-       }
 
        if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) {
                vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP;
@@ -155,7 +148,18 @@ static int handle_stop(struct kvm_vcpu *vcpu)
                rc = -EOPNOTSUPP;
        }
 
-       spin_unlock_bh(&vcpu->arch.local_int.lock);
+       if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) {
+               vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP;
+               /* store status must be called unlocked. Since local_int.lock
+                * only protects local_int.* and not guest memory we can give
+                * up the lock here */
+               spin_unlock_bh(&vcpu->arch.local_int.lock);
+               rc = kvm_s390_vcpu_store_status(vcpu,
+                                               KVM_S390_STORE_STATUS_NOADDR);
+               if (rc >= 0)
+                       rc = -EOPNOTSUPP;
+       } else
+               spin_unlock_bh(&vcpu->arch.local_int.lock);
        return rc;
 }
 
index f0647ce..2d9f9a7 100644 (file)
@@ -236,8 +236,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
                VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x",
                           inti->prefix.address);
                vcpu->stat.deliver_prefix_signal++;
-               vcpu->arch.sie_block->prefix = inti->prefix.address;
-               vcpu->arch.sie_block->ihcpu = 0xffff;
+               kvm_s390_set_prefix(vcpu, inti->prefix.address);
                break;
 
        case KVM_S390_RESTART:
index d56de16..217ce44 100644 (file)
@@ -129,6 +129,10 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_S390_PSW:
        case KVM_CAP_S390_GMAP:
        case KVM_CAP_SYNC_MMU:
+#ifdef CONFIG_KVM_S390_UCONTROL
+       case KVM_CAP_S390_UCONTROL:
+#endif
+       case KVM_CAP_SYNC_REGS:
                r = 1;
                break;
        default:
@@ -171,11 +175,22 @@ long kvm_arch_vm_ioctl(struct file *filp,
        return r;
 }
 
-int kvm_arch_init_vm(struct kvm *kvm)
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
        int rc;
        char debug_name[16];
 
+       rc = -EINVAL;
+#ifdef CONFIG_KVM_S390_UCONTROL
+       if (type & ~KVM_VM_S390_UCONTROL)
+               goto out_err;
+       if ((type & KVM_VM_S390_UCONTROL) && (!capable(CAP_SYS_ADMIN)))
+               goto out_err;
+#else
+       if (type)
+               goto out_err;
+#endif
+
        rc = s390_enable_sie();
        if (rc)
                goto out_err;
@@ -198,10 +213,13 @@ int kvm_arch_init_vm(struct kvm *kvm)
        debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
        VM_EVENT(kvm, 3, "%s", "vm created");
 
-       kvm->arch.gmap = gmap_alloc(current->mm);
-       if (!kvm->arch.gmap)
-               goto out_nogmap;
-
+       if (type & KVM_VM_S390_UCONTROL) {
+               kvm->arch.gmap = NULL;
+       } else {
+               kvm->arch.gmap = gmap_alloc(current->mm);
+               if (!kvm->arch.gmap)
+                       goto out_nogmap;
+       }
        return 0;
 out_nogmap:
        debug_unregister(kvm->arch.dbf);
@@ -214,11 +232,18 @@ out_err:
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
        VCPU_EVENT(vcpu, 3, "%s", "free cpu");
-       clear_bit(63 - vcpu->vcpu_id, (unsigned long *) &vcpu->kvm->arch.sca->mcn);
-       if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
-               (__u64) vcpu->arch.sie_block)
-               vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
+       if (!kvm_is_ucontrol(vcpu->kvm)) {
+               clear_bit(63 - vcpu->vcpu_id,
+                         (unsigned long *) &vcpu->kvm->arch.sca->mcn);
+               if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
+                   (__u64) vcpu->arch.sie_block)
+                       vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
+       }
        smp_mb();
+
+       if (kvm_is_ucontrol(vcpu->kvm))
+               gmap_free(vcpu->arch.gmap);
+
        free_page((unsigned long)(vcpu->arch.sie_block));
        kvm_vcpu_uninit(vcpu);
        kfree(vcpu);
@@ -249,13 +274,25 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
        kvm_free_vcpus(kvm);
        free_page((unsigned long)(kvm->arch.sca));
        debug_unregister(kvm->arch.dbf);
-       gmap_free(kvm->arch.gmap);
+       if (!kvm_is_ucontrol(kvm))
+               gmap_free(kvm->arch.gmap);
 }
 
 /* Section: vcpu related */
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
+       if (kvm_is_ucontrol(vcpu->kvm)) {
+               vcpu->arch.gmap = gmap_alloc(current->mm);
+               if (!vcpu->arch.gmap)
+                       return -ENOMEM;
+               return 0;
+       }
+
        vcpu->arch.gmap = vcpu->kvm->arch.gmap;
+       vcpu->run->kvm_valid_regs = KVM_SYNC_PREFIX |
+                                   KVM_SYNC_GPRS |
+                                   KVM_SYNC_ACRS |
+                                   KVM_SYNC_CRS;
        return 0;
 }
 
@@ -270,7 +307,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        save_access_regs(vcpu->arch.host_acrs);
        vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK;
        restore_fp_regs(&vcpu->arch.guest_fpregs);
-       restore_access_regs(vcpu->arch.guest_acrs);
+       restore_access_regs(vcpu->run->s.regs.acrs);
        gmap_enable(vcpu->arch.gmap);
        atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
 }
@@ -280,7 +317,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
        atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
        gmap_disable(vcpu->arch.gmap);
        save_fp_regs(&vcpu->arch.guest_fpregs);
-       save_access_regs(vcpu->arch.guest_acrs);
+       save_access_regs(vcpu->run->s.regs.acrs);
        restore_fp_regs(&vcpu->arch.host_fpregs);
        restore_access_regs(vcpu->arch.host_acrs);
 }
@@ -290,8 +327,7 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
        /* this equals initial cpu reset in pop, but we don't switch to ESA */
        vcpu->arch.sie_block->gpsw.mask = 0UL;
        vcpu->arch.sie_block->gpsw.addr = 0UL;
-       vcpu->arch.sie_block->prefix    = 0UL;
-       vcpu->arch.sie_block->ihcpu     = 0xffff;
+       kvm_s390_set_prefix(vcpu, 0);
        vcpu->arch.sie_block->cputm     = 0UL;
        vcpu->arch.sie_block->ckc       = 0UL;
        vcpu->arch.sie_block->todpr     = 0;
@@ -342,12 +378,19 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
                goto out_free_cpu;
 
        vcpu->arch.sie_block->icpua = id;
-       BUG_ON(!kvm->arch.sca);
-       if (!kvm->arch.sca->cpu[id].sda)
-               kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
-       vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32);
-       vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
-       set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
+       if (!kvm_is_ucontrol(kvm)) {
+               if (!kvm->arch.sca) {
+                       WARN_ON_ONCE(1);
+                       goto out_free_cpu;
+               }
+               if (!kvm->arch.sca->cpu[id].sda)
+                       kvm->arch.sca->cpu[id].sda =
+                               (__u64) vcpu->arch.sie_block;
+               vcpu->arch.sie_block->scaoh =
+                       (__u32)(((__u64)kvm->arch.sca) >> 32);
+               vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
+               set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
+       }
 
        spin_lock_init(&vcpu->arch.local_int.lock);
        INIT_LIST_HEAD(&vcpu->arch.local_int.list);
@@ -388,29 +431,29 @@ static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
 
 int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
-       memcpy(&vcpu->arch.guest_gprs, &regs->gprs, sizeof(regs->gprs));
+       memcpy(&vcpu->run->s.regs.gprs, &regs->gprs, sizeof(regs->gprs));
        return 0;
 }
 
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
-       memcpy(&regs->gprs, &vcpu->arch.guest_gprs, sizeof(regs->gprs));
+       memcpy(&regs->gprs, &vcpu->run->s.regs.gprs, sizeof(regs->gprs));
        return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
                                  struct kvm_sregs *sregs)
 {
-       memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs));
+       memcpy(&vcpu->run->s.regs.acrs, &sregs->acrs, sizeof(sregs->acrs));
        memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs));
-       restore_access_regs(vcpu->arch.guest_acrs);
+       restore_access_regs(vcpu->run->s.regs.acrs);
        return 0;
 }
 
 int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
                                  struct kvm_sregs *sregs)
 {
-       memcpy(&sregs->acrs, &vcpu->arch.guest_acrs, sizeof(sregs->acrs));
+       memcpy(&sregs->acrs, &vcpu->run->s.regs.acrs, sizeof(sregs->acrs));
        memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs));
        return 0;
 }
@@ -418,7 +461,7 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
 int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
        memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
-       vcpu->arch.guest_fpregs.fpc = fpu->fpc;
+       vcpu->arch.guest_fpregs.fpc = fpu->fpc & FPC_VALID_MASK;
        restore_fp_regs(&vcpu->arch.guest_fpregs);
        return 0;
 }
@@ -467,9 +510,11 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
        return -EINVAL; /* not implemented yet */
 }
 
-static void __vcpu_run(struct kvm_vcpu *vcpu)
+static int __vcpu_run(struct kvm_vcpu *vcpu)
 {
-       memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
+       int rc;
+
+       memcpy(&vcpu->arch.sie_block->gg14, &vcpu->run->s.regs.gprs[14], 16);
 
        if (need_resched())
                schedule();
@@ -477,7 +522,8 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
        if (test_thread_flag(TIF_MCCK_PENDING))
                s390_handle_mcck();
 
-       kvm_s390_deliver_pending_interrupts(vcpu);
+       if (!kvm_is_ucontrol(vcpu->kvm))
+               kvm_s390_deliver_pending_interrupts(vcpu);
 
        vcpu->arch.sie_block->icptcode = 0;
        local_irq_disable();
@@ -485,9 +531,15 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
        local_irq_enable();
        VCPU_EVENT(vcpu, 6, "entering sie flags %x",
                   atomic_read(&vcpu->arch.sie_block->cpuflags));
-       if (sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs)) {
-               VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
-               kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+       rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs);
+       if (rc) {
+               if (kvm_is_ucontrol(vcpu->kvm)) {
+                       rc = SIE_INTERCEPT_UCONTROL;
+               } else {
+                       VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
+                       kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+                       rc = 0;
+               }
        }
        VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
                   vcpu->arch.sie_block->icptcode);
@@ -495,7 +547,8 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
        kvm_guest_exit();
        local_irq_enable();
 
-       memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16);
+       memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16);
+       return rc;
 }
 
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -516,6 +569,7 @@ rerun_vcpu:
        case KVM_EXIT_UNKNOWN:
        case KVM_EXIT_INTR:
        case KVM_EXIT_S390_RESET:
+       case KVM_EXIT_S390_UCONTROL:
                break;
        default:
                BUG();
@@ -523,12 +577,26 @@ rerun_vcpu:
 
        vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask;
        vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr;
+       if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX) {
+               kvm_run->kvm_dirty_regs &= ~KVM_SYNC_PREFIX;
+               kvm_s390_set_prefix(vcpu, kvm_run->s.regs.prefix);
+       }
+       if (kvm_run->kvm_dirty_regs & KVM_SYNC_CRS) {
+               kvm_run->kvm_dirty_regs &= ~KVM_SYNC_CRS;
+               memcpy(&vcpu->arch.sie_block->gcr, &kvm_run->s.regs.crs, 128);
+               kvm_s390_set_prefix(vcpu, kvm_run->s.regs.prefix);
+       }
 
        might_fault();
 
        do {
-               __vcpu_run(vcpu);
-               rc = kvm_handle_sie_intercept(vcpu);
+               rc = __vcpu_run(vcpu);
+               if (rc)
+                       break;
+               if (kvm_is_ucontrol(vcpu->kvm))
+                       rc = -EOPNOTSUPP;
+               else
+                       rc = kvm_handle_sie_intercept(vcpu);
        } while (!signal_pending(current) && !rc);
 
        if (rc == SIE_INTERCEPT_RERUNVCPU)
@@ -539,6 +607,16 @@ rerun_vcpu:
                rc = -EINTR;
        }
 
+#ifdef CONFIG_KVM_S390_UCONTROL
+       if (rc == SIE_INTERCEPT_UCONTROL) {
+               kvm_run->exit_reason = KVM_EXIT_S390_UCONTROL;
+               kvm_run->s390_ucontrol.trans_exc_code =
+                       current->thread.gmap_addr;
+               kvm_run->s390_ucontrol.pgm_code = 0x10;
+               rc = 0;
+       }
+#endif
+
        if (rc == -EOPNOTSUPP) {
                /* intercept cannot be handled in-kernel, prepare kvm-run */
                kvm_run->exit_reason         = KVM_EXIT_S390_SIEIC;
@@ -556,6 +634,8 @@ rerun_vcpu:
 
        kvm_run->psw_mask     = vcpu->arch.sie_block->gpsw.mask;
        kvm_run->psw_addr     = vcpu->arch.sie_block->gpsw.addr;
+       kvm_run->s.regs.prefix = vcpu->arch.sie_block->prefix;
+       memcpy(&kvm_run->s.regs.crs, &vcpu->arch.sie_block->gcr, 128);
 
        if (vcpu->sigset_active)
                sigprocmask(SIG_SETMASK, &sigsaved, NULL);
@@ -602,7 +682,7 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
                return -EFAULT;
 
        if (__guestcopy(vcpu, addr + offsetof(struct save_area, gp_regs),
-                       vcpu->arch.guest_gprs, 128, prefix))
+                       vcpu->run->s.regs.gprs, 128, prefix))
                return -EFAULT;
 
        if (__guestcopy(vcpu, addr + offsetof(struct save_area, psw),
@@ -631,7 +711,7 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
                return -EFAULT;
 
        if (__guestcopy(vcpu, addr + offsetof(struct save_area, acc_regs),
-                       &vcpu->arch.guest_acrs, 64, prefix))
+                       &vcpu->run->s.regs.acrs, 64, prefix))
                return -EFAULT;
 
        if (__guestcopy(vcpu,
@@ -673,12 +753,77 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
        case KVM_S390_INITIAL_RESET:
                r = kvm_arch_vcpu_ioctl_initial_reset(vcpu);
                break;
+#ifdef CONFIG_KVM_S390_UCONTROL
+       case KVM_S390_UCAS_MAP: {
+               struct kvm_s390_ucas_mapping ucasmap;
+
+               if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) {
+                       r = -EFAULT;
+                       break;
+               }
+
+               if (!kvm_is_ucontrol(vcpu->kvm)) {
+                       r = -EINVAL;
+                       break;
+               }
+
+               r = gmap_map_segment(vcpu->arch.gmap, ucasmap.user_addr,
+                                    ucasmap.vcpu_addr, ucasmap.length);
+               break;
+       }
+       case KVM_S390_UCAS_UNMAP: {
+               struct kvm_s390_ucas_mapping ucasmap;
+
+               if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) {
+                       r = -EFAULT;
+                       break;
+               }
+
+               if (!kvm_is_ucontrol(vcpu->kvm)) {
+                       r = -EINVAL;
+                       break;
+               }
+
+               r = gmap_unmap_segment(vcpu->arch.gmap, ucasmap.vcpu_addr,
+                       ucasmap.length);
+               break;
+       }
+#endif
+       case KVM_S390_VCPU_FAULT: {
+               r = gmap_fault(arg, vcpu->arch.gmap);
+               if (!IS_ERR_VALUE(r))
+                       r = 0;
+               break;
+       }
        default:
-               r = -EINVAL;
+               r = -ENOTTY;
        }
        return r;
 }
 
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+#ifdef CONFIG_KVM_S390_UCONTROL
+       if ((vmf->pgoff == KVM_S390_SIE_PAGE_OFFSET)
+                && (kvm_is_ucontrol(vcpu->kvm))) {
+               vmf->page = virt_to_page(vcpu->arch.sie_block);
+               get_page(vmf->page);
+               return 0;
+       }
+#endif
+       return VM_FAULT_SIGBUS;
+}
+
+void kvm_arch_free_memslot(struct kvm_memory_slot *free,
+                          struct kvm_memory_slot *dont)
+{
+}
+
+int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
+{
+       return 0;
+}
+
 /* Section: memory related */
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                   struct kvm_memory_slot *memslot,
index 99b0b75..ff28f9d 100644 (file)
@@ -26,6 +26,7 @@ typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
 
 /* negativ values are error codes, positive values for internal conditions */
 #define SIE_INTERCEPT_RERUNVCPU                (1<<0)
+#define SIE_INTERCEPT_UCONTROL         (1<<1)
 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
 
 #define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
@@ -47,6 +48,23 @@ static inline int __cpu_is_stopped(struct kvm_vcpu *vcpu)
        return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOP_INT;
 }
 
+static inline int kvm_is_ucontrol(struct kvm *kvm)
+{
+#ifdef CONFIG_KVM_S390_UCONTROL
+       if (kvm->arch.gmap)
+               return 0;
+       return 1;
+#else
+       return 0;
+#endif
+}
+
+static inline void kvm_s390_set_prefix(struct kvm_vcpu *vcpu, u32 prefix)
+{
+       vcpu->arch.sie_block->prefix = prefix & 0x7fffe000u;
+       vcpu->arch.sie_block->ihcpu  = 0xffff;
+}
+
 int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
 enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
 void kvm_s390_tasklet(unsigned long parm);
index d026389..e5a45db 100644 (file)
@@ -33,7 +33,7 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu)
 
        operand2 = disp2;
        if (base2)
-               operand2 += vcpu->arch.guest_gprs[base2];
+               operand2 += vcpu->run->s.regs.gprs[base2];
 
        /* must be word boundary */
        if (operand2 & 3) {
@@ -56,8 +56,7 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu)
                goto out;
        }
 
-       vcpu->arch.sie_block->prefix = address;
-       vcpu->arch.sie_block->ihcpu = 0xffff;
+       kvm_s390_set_prefix(vcpu, address);
 
        VCPU_EVENT(vcpu, 5, "setting prefix to %x", address);
 out:
@@ -74,7 +73,7 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu)
        vcpu->stat.instruction_stpx++;
        operand2 = disp2;
        if (base2)
-               operand2 += vcpu->arch.guest_gprs[base2];
+               operand2 += vcpu->run->s.regs.gprs[base2];
 
        /* must be word boundary */
        if (operand2 & 3) {
@@ -106,7 +105,7 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
        vcpu->stat.instruction_stap++;
        useraddr = disp2;
        if (base2)
-               useraddr += vcpu->arch.guest_gprs[base2];
+               useraddr += vcpu->run->s.regs.gprs[base2];
 
        if (useraddr & 1) {
                kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -181,7 +180,7 @@ static int handle_stidp(struct kvm_vcpu *vcpu)
        vcpu->stat.instruction_stidp++;
        operand2 = disp2;
        if (base2)
-               operand2 += vcpu->arch.guest_gprs[base2];
+               operand2 += vcpu->run->s.regs.gprs[base2];
 
        if (operand2 & 7) {
                kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -232,9 +231,9 @@ static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem)
 
 static int handle_stsi(struct kvm_vcpu *vcpu)
 {
-       int fc = (vcpu->arch.guest_gprs[0] & 0xf0000000) >> 28;
-       int sel1 = vcpu->arch.guest_gprs[0] & 0xff;
-       int sel2 = vcpu->arch.guest_gprs[1] & 0xffff;
+       int fc = (vcpu->run->s.regs.gprs[0] & 0xf0000000) >> 28;
+       int sel1 = vcpu->run->s.regs.gprs[0] & 0xff;
+       int sel2 = vcpu->run->s.regs.gprs[1] & 0xffff;
        int base2 = vcpu->arch.sie_block->ipb >> 28;
        int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
        u64 operand2;
@@ -245,14 +244,14 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
 
        operand2 = disp2;
        if (base2)
-               operand2 += vcpu->arch.guest_gprs[base2];
+               operand2 += vcpu->run->s.regs.gprs[base2];
 
        if (operand2 & 0xfff && fc > 0)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
        switch (fc) {
        case 0:
-               vcpu->arch.guest_gprs[0] = 3 << 28;
+               vcpu->run->s.regs.gprs[0] = 3 << 28;
                vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
                return 0;
        case 1: /* same handling for 1 and 2 */
@@ -281,7 +280,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
        }
        free_page(mem);
        vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
-       vcpu->arch.guest_gprs[0] = 0;
+       vcpu->run->s.regs.gprs[0] = 0;
        return 0;
 out_mem:
        free_page(mem);
@@ -333,8 +332,8 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
        int disp1 = (vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16;
        int base2 = (vcpu->arch.sie_block->ipb & 0xf000) >> 12;
        int disp2 = vcpu->arch.sie_block->ipb & 0x0fff;
-       u64 address1 = disp1 + base1 ? vcpu->arch.guest_gprs[base1] : 0;
-       u64 address2 = disp2 + base2 ? vcpu->arch.guest_gprs[base2] : 0;
+       u64 address1 = disp1 + base1 ? vcpu->run->s.regs.gprs[base1] : 0;
+       u64 address2 = disp2 + base2 ? vcpu->run->s.regs.gprs[base2] : 0;
        struct vm_area_struct *vma;
        unsigned long user_address;
 
index 0a7941d..0ad4cf2 100644 (file)
@@ -48,7 +48,7 @@
 
 
 static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
-                       unsigned long *reg)
+                       u64 *reg)
 {
        struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
        int rc;
@@ -160,12 +160,15 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
        inti->type = KVM_S390_SIGP_STOP;
 
        spin_lock_bh(&li->lock);
+       if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED))
+               goto out;
        list_add_tail(&inti->list, &li->list);
        atomic_set(&li->active, 1);
        atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
        li->action_bits |= action;
        if (waitqueue_active(&li->wq))
                wake_up_interruptible(&li->wq);
+out:
        spin_unlock_bh(&li->lock);
 
        return 0; /* order accepted */
@@ -220,7 +223,7 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
 }
 
 static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
-                            unsigned long *reg)
+                            u64 *reg)
 {
        struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
        struct kvm_s390_local_interrupt *li = NULL;
@@ -278,7 +281,7 @@ out_fi:
 }
 
 static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
-                               unsigned long *reg)
+                               u64 *reg)
 {
        int rc;
        struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
@@ -309,6 +312,34 @@ static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
        return rc;
 }
 
+static int __sigp_restart(struct kvm_vcpu *vcpu, u16 cpu_addr)
+{
+       int rc = 0;
+       struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
+       struct kvm_s390_local_interrupt *li;
+
+       if (cpu_addr >= KVM_MAX_VCPUS)
+               return 3; /* not operational */
+
+       spin_lock(&fi->lock);
+       li = fi->local_int[cpu_addr];
+       if (li == NULL) {
+               rc = 3; /* not operational */
+               goto out;
+       }
+
+       spin_lock_bh(&li->lock);
+       if (li->action_bits & ACTION_STOP_ON_STOP)
+               rc = 2; /* busy */
+       else
+               VCPU_EVENT(vcpu, 4, "sigp restart %x to handle userspace",
+                       cpu_addr);
+       spin_unlock_bh(&li->lock);
+out:
+       spin_unlock(&fi->lock);
+       return rc;
+}
+
 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
 {
        int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
@@ -316,7 +347,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
        int base2 = vcpu->arch.sie_block->ipb >> 28;
        int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
        u32 parameter;
-       u16 cpu_addr = vcpu->arch.guest_gprs[r3];
+       u16 cpu_addr = vcpu->run->s.regs.gprs[r3];
        u8 order_code;
        int rc;
 
@@ -327,18 +358,18 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
 
        order_code = disp2;
        if (base2)
-               order_code += vcpu->arch.guest_gprs[base2];
+               order_code += vcpu->run->s.regs.gprs[base2];
 
        if (r1 % 2)
-               parameter = vcpu->arch.guest_gprs[r1];
+               parameter = vcpu->run->s.regs.gprs[r1];
        else
-               parameter = vcpu->arch.guest_gprs[r1 + 1];
+               parameter = vcpu->run->s.regs.gprs[r1 + 1];
 
        switch (order_code) {
        case SIGP_SENSE:
                vcpu->stat.instruction_sigp_sense++;
                rc = __sigp_sense(vcpu, cpu_addr,
-                                 &vcpu->arch.guest_gprs[r1]);
+                                 &vcpu->run->s.regs.gprs[r1]);
                break;
        case SIGP_EXTERNAL_CALL:
                vcpu->stat.instruction_sigp_external_call++;
@@ -354,7 +385,8 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
                break;
        case SIGP_STOP_STORE_STATUS:
                vcpu->stat.instruction_sigp_stop++;
-               rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP);
+               rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP |
+                                                ACTION_STOP_ON_STOP);
                break;
        case SIGP_SET_ARCH:
                vcpu->stat.instruction_sigp_arch++;
@@ -363,15 +395,18 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
        case SIGP_SET_PREFIX:
                vcpu->stat.instruction_sigp_prefix++;
                rc = __sigp_set_prefix(vcpu, cpu_addr, parameter,
-                                      &vcpu->arch.guest_gprs[r1]);
+                                      &vcpu->run->s.regs.gprs[r1]);
                break;
        case SIGP_SENSE_RUNNING:
                vcpu->stat.instruction_sigp_sense_running++;
                rc = __sigp_sense_running(vcpu, cpu_addr,
-                                         &vcpu->arch.guest_gprs[r1]);
+                                         &vcpu->run->s.regs.gprs[r1]);
                break;
        case SIGP_RESTART:
                vcpu->stat.instruction_sigp_restart++;
+               rc = __sigp_restart(vcpu, cpu_addr);
+               if (rc == 2) /* busy */
+                       break;
                /* user space must know about restart */
        default:
                return -EOPNOTSUPP;
index a0155c0..2857c48 100644 (file)
@@ -100,7 +100,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
                mm->unmap_area = arch_unmap_area_topdown;
        }
 }
-EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
 
 #else
 
@@ -175,6 +174,5 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
                mm->unmap_area = arch_unmap_area_topdown;
        }
 }
-EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
 
 #endif
index 59c9278..c6646de 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/oprofile.h>
 
 #include <asm/facility.h>
-#include <asm/lowcore.h>
+#include <asm/cpu_mf.h>
 #include <asm/irq.h>
 
 #include "hwsampler.h"
 #define ALERT_REQ_MASK   0x4000000000000000ul
 #define BUFFER_FULL_MASK 0x8000000000000000ul
 
-#define EI_IEA      (1 << 31)  /* invalid entry address              */
-#define EI_ISE      (1 << 30)  /* incorrect SDBT entry               */
-#define EI_PRA      (1 << 29)  /* program request alert              */
-#define EI_SACA     (1 << 23)  /* sampler authorization change alert */
-#define EI_LSDA     (1 << 22)  /* loss of sample data alert          */
-
 DECLARE_PER_CPU(struct hws_cpu_buffer, sampler_cpu_buffer);
 
 struct hws_execute_parms {
@@ -233,9 +227,20 @@ static inline unsigned long *trailer_entry_ptr(unsigned long v)
        return (unsigned long *) ret;
 }
 
-/* prototypes for external interrupt handler and worker */
 static void hws_ext_handler(struct ext_code ext_code,
-                           unsigned int param32, unsigned long param64);
+                           unsigned int param32, unsigned long param64)
+{
+       struct hws_cpu_buffer *cb = &__get_cpu_var(sampler_cpu_buffer);
+
+       if (!(param32 & CPU_MF_INT_SF_MASK))
+               return;
+
+       kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
+       atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
+
+       if (hws_wq)
+               queue_work(hws_wq, &cb->worker);
+}
 
 static void worker(struct work_struct *work);
 
@@ -674,18 +679,6 @@ int hwsampler_activate(unsigned int cpu)
        return rc;
 }
 
-static void hws_ext_handler(struct ext_code ext_code,
-                           unsigned int param32, unsigned long param64)
-{
-       struct hws_cpu_buffer *cb;
-
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
-       cb = &__get_cpu_var(sampler_cpu_buffer);
-       atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
-       if (hws_wq)
-               queue_work(hws_wq, &cb->worker);
-}
-
 static int check_qsi_on_setup(void)
 {
        int rc;
@@ -761,23 +754,23 @@ static int worker_check_error(unsigned int cpu, int ext_params)
        if (!sdbt || !*sdbt)
                return -EINVAL;
 
-       if (ext_params & EI_PRA)
+       if (ext_params & CPU_MF_INT_SF_PRA)
                cb->req_alert++;
 
-       if (ext_params & EI_LSDA)
+       if (ext_params & CPU_MF_INT_SF_LSDA)
                cb->loss_of_sample_data++;
 
-       if (ext_params & EI_IEA) {
+       if (ext_params & CPU_MF_INT_SF_IAE) {
                cb->invalid_entry_address++;
                rc = -EINVAL;
        }
 
-       if (ext_params & EI_ISE) {
+       if (ext_params & CPU_MF_INT_SF_ISE) {
                cb->incorrect_sdbt_entry++;
                rc = -EINVAL;
        }
 
-       if (ext_params & EI_SACA) {
+       if (ext_params & CPU_MF_INT_SF_SACA) {
                cb->sample_auth_change_alert++;
                rc = -EINVAL;
        }
@@ -1010,7 +1003,7 @@ int hwsampler_deallocate(void)
        if (hws_state != HWS_STOPPED)
                goto deallocate_exit;
 
-       ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+       measurement_alert_subclass_unregister();
        deallocate_sdbt();
 
        hws_state = HWS_DEALLOCATED;
@@ -1124,7 +1117,7 @@ int hwsampler_shutdown(void)
                mutex_lock(&hws_sem);
 
                if (hws_state == HWS_STOPPED) {
-                       ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+                       measurement_alert_subclass_unregister();
                        deallocate_sdbt();
                }
                if (hws_wq) {
@@ -1199,7 +1192,7 @@ start_all_exit:
        hws_oom = 1;
        hws_flush_all = 0;
        /* now let them in, 1407 CPUMF external interrupts */
-       ctl_set_bit(0, 5); /* set CR0 bit 58 */
+       measurement_alert_subclass_register();
 
        return 0;
 }
index 74b8db1..4a52590 100644 (file)
@@ -322,7 +322,7 @@ static void ivdr_clk_disable(struct clk *clk)
        __raw_writew(__raw_readw(PA_IVDRCTL) & ~(1 << IVDR_CK_ON), PA_IVDRCTL);
 }
 
-static struct clk_ops ivdr_clk_ops = {
+static struct sh_clk_ops ivdr_clk_ops = {
        .enable         = ivdr_clk_enable,
        .disable        = ivdr_clk_disable,
 };
index 486d1ac..27a2314 100644 (file)
@@ -167,7 +167,7 @@ static void sdk7786_pcie_clk_disable(struct clk *clk)
        fpga_write_reg(fpga_read_reg(PCIECR) & ~PCIECR_CLKEN, PCIECR);
 }
 
-static struct clk_ops sdk7786_pcie_clk_ops = {
+static struct sh_clk_ops sdk7786_pcie_clk_ops = {
        .enable         = sdk7786_pcie_clk_enable,
        .disable        = sdk7786_pcie_clk_disable,
 };
index 1e7b0e2..9d10a3c 100644 (file)
@@ -37,11 +37,20 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose)
        static int next_busno;
        static int need_domain_info;
        LIST_HEAD(resources);
+       struct resource *res;
+       resource_size_t offset;
        int i;
        struct pci_bus *bus;
 
-       for (i = 0; i < hose->nr_resources; i++)
-               pci_add_resource(&resources, hose->resources + i);
+       for (i = 0; i < hose->nr_resources; i++) {
+               res = hose->resources + i;
+               offset = 0;
+               if (res->flags & IORESOURCE_IO)
+                       offset = hose->io_offset;
+               else if (res->flags & IORESOURCE_MEM)
+                       offset = hose->mem_offset;
+               pci_add_resource_offset(&resources, res, offset);
+       }
 
        bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
                                &resources);
@@ -143,42 +152,12 @@ static int __init pcibios_init(void)
 }
 subsys_initcall(pcibios_init);
 
-static void pcibios_fixup_device_resources(struct pci_dev *dev,
-       struct pci_bus *bus)
-{
-       /* Update device resources.  */
-       struct pci_channel *hose = bus->sysdata;
-       unsigned long offset = 0;
-       int i;
-
-       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-               if (!dev->resource[i].start)
-                       continue;
-               if (dev->resource[i].flags & IORESOURCE_IO)
-                       offset = hose->io_offset;
-               else if (dev->resource[i].flags & IORESOURCE_MEM)
-                       offset = hose->mem_offset;
-
-               dev->resource[i].start += offset;
-               dev->resource[i].end += offset;
-       }
-}
-
 /*
  *  Called after each bus is probed, but before its children
  *  are examined.
  */
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
-       struct pci_dev *dev;
-       struct list_head *ln;
-
-       for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
-               dev = pci_dev_b(ln);
-
-               if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
-                       pcibios_fixup_device_resources(dev, bus);
-       }
 }
 
 /*
@@ -208,36 +187,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
        return start;
 }
 
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                            struct resource *res)
-{
-       struct pci_channel *hose = dev->sysdata;
-       unsigned long offset = 0;
-
-       if (res->flags & IORESOURCE_IO)
-               offset = hose->io_offset;
-       else if (res->flags & IORESOURCE_MEM)
-               offset = hose->mem_offset;
-
-       region->start = res->start - offset;
-       region->end = res->end - offset;
-}
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                            struct pci_bus_region *region)
-{
-       struct pci_channel *hose = dev->sysdata;
-       unsigned long offset = 0;
-
-       if (res->flags & IORESOURCE_IO)
-               offset = hose->io_offset;
-       else if (res->flags & IORESOURCE_MEM)
-               offset = hose->mem_offset;
-
-       res->start = region->start + offset;
-       res->end = region->end + offset;
-}
-
 int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
        return pci_enable_resources(dev, mask);
@@ -381,8 +330,6 @@ EXPORT_SYMBOL(pci_iounmap);
 #endif /* CONFIG_GENERIC_IOMAP */
 
 #ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-EXPORT_SYMBOL(pcibios_bus_to_resource);
 EXPORT_SYMBOL(PCIBIOS_MIN_IO);
 EXPORT_SYMBOL(PCIBIOS_MIN_MEM);
 #endif
index 803d4c7..0390a07 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/sh_clk.h>
 
 /* Should be defined by processor-specific code */
-void __deprecated arch_init_clk_ops(struct clk_ops **, int type);
+void __deprecated arch_init_clk_ops(struct sh_clk_ops **, int type);
 int __init arch_clk_init(void);
 
 /* arch/sh/kernel/cpu/clock-cpg.c */
index cb21e23..bff96c2 100644 (file)
@@ -114,12 +114,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 /* Board-specific fixup routines. */
 int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
-       struct pci_bus_region *region, struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                                   struct pci_bus_region *region);
-
 #define pci_domain_nr(bus) ((struct pci_channel *)(bus)->sysdata)->index
 
 static inline int pci_proc_domain(struct pci_bus *bus)
index 5b7f12e..e80252a 100644 (file)
@@ -28,7 +28,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= pll2_mult * pll1rate[(__raw_readw(FREQCR) >> 8) & 7];
 }
 
-static struct clk_ops sh7619_master_clk_ops = {
+static struct sh_clk_ops sh7619_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -38,7 +38,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7619_module_clk_ops = {
+static struct sh_clk_ops sh7619_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -47,22 +47,22 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / pll1rate[(__raw_readw(FREQCR) >> 8) & 7];
 }
 
-static struct clk_ops sh7619_bus_clk_ops = {
+static struct sh_clk_ops sh7619_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static struct clk_ops sh7619_cpu_clk_ops = {
+static struct sh_clk_ops sh7619_cpu_clk_ops = {
        .recalc         = followparent_recalc,
 };
 
-static struct clk_ops *sh7619_clk_ops[] = {
+static struct sh_clk_ops *sh7619_clk_ops[] = {
        &sh7619_master_clk_ops,
        &sh7619_module_clk_ops,
        &sh7619_bus_clk_ops,
        &sh7619_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (test_mode_pin(MODE_PIN2 | MODE_PIN0) ||
            test_mode_pin(MODE_PIN2 | MODE_PIN1))
index 1174e2d..532a36c 100644 (file)
@@ -30,7 +30,7 @@ static void master_clk_init(struct clk *clk)
               pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
 }
 
-static struct clk_ops sh7201_master_clk_ops = {
+static struct sh_clk_ops sh7201_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -40,7 +40,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7201_module_clk_ops = {
+static struct sh_clk_ops sh7201_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -50,7 +50,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7201_bus_clk_ops = {
+static struct sh_clk_ops sh7201_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -60,18 +60,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7201_cpu_clk_ops = {
+static struct sh_clk_ops sh7201_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7201_clk_ops[] = {
+static struct sh_clk_ops *sh7201_clk_ops[] = {
        &sh7201_master_clk_ops,
        &sh7201_module_clk_ops,
        &sh7201_bus_clk_ops,
        &sh7201_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (test_mode_pin(MODE_PIN1 | MODE_PIN0))
                pll2_mult = 1;
index 95a008e..529f719 100644 (file)
@@ -32,7 +32,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0003] * pll2_mult;
 }
 
-static struct clk_ops sh7203_master_clk_ops = {
+static struct sh_clk_ops sh7203_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -42,7 +42,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7203_module_clk_ops = {
+static struct sh_clk_ops sh7203_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -52,22 +52,22 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx-2];
 }
 
-static struct clk_ops sh7203_bus_clk_ops = {
+static struct sh_clk_ops sh7203_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static struct clk_ops sh7203_cpu_clk_ops = {
+static struct sh_clk_ops sh7203_cpu_clk_ops = {
        .recalc         = followparent_recalc,
 };
 
-static struct clk_ops *sh7203_clk_ops[] = {
+static struct sh_clk_ops *sh7203_clk_ops[] = {
        &sh7203_master_clk_ops,
        &sh7203_module_clk_ops,
        &sh7203_bus_clk_ops,
        &sh7203_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (test_mode_pin(MODE_PIN1))
                pll2_mult = 4;
index 3c314d7..1777898 100644 (file)
@@ -29,7 +29,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= pll2_mult * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
 }
 
-static struct clk_ops sh7206_master_clk_ops = {
+static struct sh_clk_ops sh7206_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -39,7 +39,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7206_module_clk_ops = {
+static struct sh_clk_ops sh7206_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -48,7 +48,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
 }
 
-static struct clk_ops sh7206_bus_clk_ops = {
+static struct sh_clk_ops sh7206_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -58,18 +58,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7206_cpu_clk_ops = {
+static struct sh_clk_ops sh7206_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7206_clk_ops[] = {
+static struct sh_clk_ops *sh7206_clk_ops[] = {
        &sh7206_master_clk_ops,
        &sh7206_module_clk_ops,
        &sh7206_bus_clk_ops,
        &sh7206_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (test_mode_pin(MODE_PIN2 | MODE_PIN1 | MODE_PIN0))
                pll2_mult = 1;
index b78384a..90faa44 100644 (file)
@@ -34,7 +34,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= pfc_divisors[idx];
 }
 
-static struct clk_ops sh3_master_clk_ops = {
+static struct sh_clk_ops sh3_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -46,7 +46,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh3_module_clk_ops = {
+static struct sh_clk_ops sh3_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -58,7 +58,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / stc_multipliers[idx];
 }
 
-static struct clk_ops sh3_bus_clk_ops = {
+static struct sh_clk_ops sh3_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -70,18 +70,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh3_cpu_clk_ops = {
+static struct sh_clk_ops sh3_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh3_clk_ops[] = {
+static struct sh_clk_ops *sh3_clk_ops[] = {
        &sh3_master_clk_ops,
        &sh3_module_clk_ops,
        &sh3_bus_clk_ops,
        &sh3_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (idx < ARRAY_SIZE(sh3_clk_ops))
                *ops = sh3_clk_ops[idx];
index 0ecea14..a8da4a9 100644 (file)
@@ -35,7 +35,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= pfc_divisors[__raw_readw(FRQCR) & 0x0003];
 }
 
-static struct clk_ops sh7705_master_clk_ops = {
+static struct sh_clk_ops sh7705_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -45,7 +45,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7705_module_clk_ops = {
+static struct sh_clk_ops sh7705_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -55,7 +55,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / stc_multipliers[idx];
 }
 
-static struct clk_ops sh7705_bus_clk_ops = {
+static struct sh_clk_ops sh7705_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -65,18 +65,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7705_cpu_clk_ops = {
+static struct sh_clk_ops sh7705_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7705_clk_ops[] = {
+static struct sh_clk_ops *sh7705_clk_ops[] = {
        &sh7705_master_clk_ops,
        &sh7705_module_clk_ops,
        &sh7705_bus_clk_ops,
        &sh7705_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (idx < ARRAY_SIZE(sh7705_clk_ops))
                *ops = sh7705_clk_ops[idx];
index 6f9ff8b..a4088e5 100644 (file)
@@ -30,7 +30,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= pfc_divisors[idx];
 }
 
-static struct clk_ops sh7706_master_clk_ops = {
+static struct sh_clk_ops sh7706_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -42,7 +42,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7706_module_clk_ops = {
+static struct sh_clk_ops sh7706_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -54,7 +54,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / stc_multipliers[idx];
 }
 
-static struct clk_ops sh7706_bus_clk_ops = {
+static struct sh_clk_ops sh7706_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -66,18 +66,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7706_cpu_clk_ops = {
+static struct sh_clk_ops sh7706_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7706_clk_ops[] = {
+static struct sh_clk_ops *sh7706_clk_ops[] = {
        &sh7706_master_clk_ops,
        &sh7706_module_clk_ops,
        &sh7706_bus_clk_ops,
        &sh7706_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (idx < ARRAY_SIZE(sh7706_clk_ops))
                *ops = sh7706_clk_ops[idx];
index f302ba0..54a6d4b 100644 (file)
@@ -30,7 +30,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= pfc_divisors[idx];
 }
 
-static struct clk_ops sh7709_master_clk_ops = {
+static struct sh_clk_ops sh7709_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -42,7 +42,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7709_module_clk_ops = {
+static struct sh_clk_ops sh7709_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -55,7 +55,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate * stc_multipliers[idx];
 }
 
-static struct clk_ops sh7709_bus_clk_ops = {
+static struct sh_clk_ops sh7709_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -67,18 +67,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7709_cpu_clk_ops = {
+static struct sh_clk_ops sh7709_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7709_clk_ops[] = {
+static struct sh_clk_ops *sh7709_clk_ops[] = {
        &sh7709_master_clk_ops,
        &sh7709_module_clk_ops,
        &sh7709_bus_clk_ops,
        &sh7709_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (idx < ARRAY_SIZE(sh7709_clk_ops))
                *ops = sh7709_clk_ops[idx];
index 29a87d8..ce601b2 100644 (file)
@@ -29,7 +29,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= md_table[__raw_readw(FRQCR) & 0x0007];
 }
 
-static struct clk_ops sh7710_master_clk_ops = {
+static struct sh_clk_ops sh7710_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -39,7 +39,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / md_table[idx];
 }
 
-static struct clk_ops sh7710_module_clk_ops = {
+static struct sh_clk_ops sh7710_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -49,7 +49,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / md_table[idx];
 }
 
-static struct clk_ops sh7710_bus_clk_ops = {
+static struct sh_clk_ops sh7710_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -59,18 +59,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / md_table[idx];
 }
 
-static struct clk_ops sh7710_cpu_clk_ops = {
+static struct sh_clk_ops sh7710_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7710_clk_ops[] = {
+static struct sh_clk_ops *sh7710_clk_ops[] = {
        &sh7710_master_clk_ops,
        &sh7710_module_clk_ops,
        &sh7710_bus_clk_ops,
        &sh7710_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (idx < ARRAY_SIZE(sh7710_clk_ops))
                *ops = sh7710_clk_ops[idx];
index b0d0c52..21438a9 100644 (file)
@@ -29,7 +29,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= multipliers[idx];
 }
 
-static struct clk_ops sh7712_master_clk_ops = {
+static struct sh_clk_ops sh7712_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -41,7 +41,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / divisors[idx];
 }
 
-static struct clk_ops sh7712_module_clk_ops = {
+static struct sh_clk_ops sh7712_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -53,17 +53,17 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / divisors[idx];
 }
 
-static struct clk_ops sh7712_cpu_clk_ops = {
+static struct sh_clk_ops sh7712_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7712_clk_ops[] = {
+static struct sh_clk_ops *sh7712_clk_ops[] = {
        &sh7712_master_clk_ops,
        &sh7712_module_clk_ops,
        &sh7712_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (idx < ARRAY_SIZE(sh7712_clk_ops))
                *ops = sh7712_clk_ops[idx];
index f4e262a..4b5bab5 100644 (file)
@@ -41,7 +41,7 @@ static inline int frqcr3_lookup(struct clk *clk, unsigned long rate)
        return 5;
 }
 
-static struct clk_ops sh4202_emi_clk_ops = {
+static struct sh_clk_ops sh4202_emi_clk_ops = {
        .recalc         = emi_clk_recalc,
 };
 
@@ -56,7 +56,7 @@ static unsigned long femi_clk_recalc(struct clk *clk)
        return clk->parent->rate / frqcr3_divisors[idx];
 }
 
-static struct clk_ops sh4202_femi_clk_ops = {
+static struct sh_clk_ops sh4202_femi_clk_ops = {
        .recalc         = femi_clk_recalc,
 };
 
@@ -130,7 +130,7 @@ static int shoc_clk_set_rate(struct clk *clk, unsigned long rate)
        return 0;
 }
 
-static struct clk_ops sh4202_shoc_clk_ops = {
+static struct sh_clk_ops sh4202_shoc_clk_ops = {
        .init           = shoc_clk_init,
        .recalc         = shoc_clk_recalc,
        .set_rate       = shoc_clk_set_rate,
index 5add75c..99e5ec8 100644 (file)
@@ -31,7 +31,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= pfc_divisors[__raw_readw(FRQCR) & 0x0007];
 }
 
-static struct clk_ops sh4_master_clk_ops = {
+static struct sh_clk_ops sh4_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -41,7 +41,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh4_module_clk_ops = {
+static struct sh_clk_ops sh4_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -51,7 +51,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / bfc_divisors[idx];
 }
 
-static struct clk_ops sh4_bus_clk_ops = {
+static struct sh_clk_ops sh4_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -61,18 +61,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh4_cpu_clk_ops = {
+static struct sh_clk_ops sh4_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh4_clk_ops[] = {
+static struct sh_clk_ops *sh4_clk_ops[] = {
        &sh4_master_clk_ops,
        &sh4_module_clk_ops,
        &sh4_bus_clk_ops,
        &sh4_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (idx < ARRAY_SIZE(sh4_clk_ops))
                *ops = sh4_clk_ops[idx];
index 70e45bd..ea01a72 100644 (file)
@@ -61,7 +61,7 @@ static unsigned long dll_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops dll_clk_ops = {
+static struct sh_clk_ops dll_clk_ops = {
        .recalc         = dll_recalc,
 };
 
@@ -81,7 +81,7 @@ static unsigned long pll_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
        .recalc         = pll_recalc,
 };
 
index 3c31650..7ac07b4 100644 (file)
@@ -61,7 +61,7 @@ static unsigned long dll_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops dll_clk_ops = {
+static struct sh_clk_ops dll_clk_ops = {
        .recalc         = dll_recalc,
 };
 
@@ -84,7 +84,7 @@ static unsigned long pll_recalc(struct clk *clk)
        return (clk->parent->rate * mult) / div;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
        .recalc         = pll_recalc,
 };
 
index 212c72e..8e1f970 100644 (file)
@@ -64,7 +64,7 @@ static unsigned long dll_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops dll_clk_ops = {
+static struct sh_clk_ops dll_clk_ops = {
        .recalc         = dll_recalc,
 };
 
@@ -87,7 +87,7 @@ static unsigned long pll_recalc(struct clk *clk)
        return (clk->parent->rate * mult) / div;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
        .recalc         = pll_recalc,
 };
 
index 2f8c917..35f75cf 100644 (file)
@@ -65,7 +65,7 @@ static unsigned long dll_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops dll_clk_ops = {
+static struct sh_clk_ops dll_clk_ops = {
        .recalc         = dll_recalc,
 };
 
@@ -88,7 +88,7 @@ static unsigned long pll_recalc(struct clk *clk)
        return (clk->parent->rate * mult) / div;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
        .recalc         = pll_recalc,
 };
 
index 70bd966..2a87901 100644 (file)
@@ -70,7 +70,7 @@ static unsigned long fll_recalc(struct clk *clk)
        return (clk->parent->rate * mult) / div;
 }
 
-static struct clk_ops fll_clk_ops = {
+static struct sh_clk_ops fll_clk_ops = {
        .recalc         = fll_recalc,
 };
 
@@ -90,7 +90,7 @@ static unsigned long pll_recalc(struct clk *clk)
        return clk->parent->rate * mult;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
        .recalc         = pll_recalc,
 };
 
@@ -105,7 +105,7 @@ static unsigned long div3_recalc(struct clk *clk)
        return clk->parent->rate / 3;
 }
 
-static struct clk_ops div3_clk_ops = {
+static struct sh_clk_ops div3_clk_ops = {
        .recalc         = div3_recalc,
 };
 
index 0bd21c8..5853989 100644 (file)
@@ -33,7 +33,7 @@ static unsigned long pll_recalc(struct clk *clk)
        return clk->parent->rate * multiplier;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
        .recalc         = pll_recalc,
 };
 
index 2d4c7fd..7707e35 100644 (file)
@@ -27,7 +27,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= p0fc_divisors[(__raw_readl(FRQCR) >> 4) & 0x07];
 }
 
-static struct clk_ops sh7763_master_clk_ops = {
+static struct sh_clk_ops sh7763_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -37,7 +37,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / p0fc_divisors[idx];
 }
 
-static struct clk_ops sh7763_module_clk_ops = {
+static struct sh_clk_ops sh7763_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -47,22 +47,22 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / bfc_divisors[idx];
 }
 
-static struct clk_ops sh7763_bus_clk_ops = {
+static struct sh_clk_ops sh7763_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
-static struct clk_ops sh7763_cpu_clk_ops = {
+static struct sh_clk_ops sh7763_cpu_clk_ops = {
        .recalc         = followparent_recalc,
 };
 
-static struct clk_ops *sh7763_clk_ops[] = {
+static struct sh_clk_ops *sh7763_clk_ops[] = {
        &sh7763_master_clk_ops,
        &sh7763_module_clk_ops,
        &sh7763_bus_clk_ops,
        &sh7763_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (idx < ARRAY_SIZE(sh7763_clk_ops))
                *ops = sh7763_clk_ops[idx];
@@ -74,7 +74,7 @@ static unsigned long shyway_clk_recalc(struct clk *clk)
        return clk->parent->rate / cfc_divisors[idx];
 }
 
-static struct clk_ops sh7763_shyway_clk_ops = {
+static struct sh_clk_ops sh7763_shyway_clk_ops = {
        .recalc         = shyway_clk_recalc,
 };
 
index 9e33543..5d36f33 100644 (file)
@@ -24,7 +24,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= pfc_divisors[(__raw_readl(FRQCR) >> 28) & 0x000f];
 }
 
-static struct clk_ops sh7770_master_clk_ops = {
+static struct sh_clk_ops sh7770_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -34,7 +34,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7770_module_clk_ops = {
+static struct sh_clk_ops sh7770_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -44,7 +44,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / bfc_divisors[idx];
 }
 
-static struct clk_ops sh7770_bus_clk_ops = {
+static struct sh_clk_ops sh7770_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -54,18 +54,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7770_cpu_clk_ops = {
+static struct sh_clk_ops sh7770_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7770_clk_ops[] = {
+static struct sh_clk_ops *sh7770_clk_ops[] = {
        &sh7770_master_clk_ops,
        &sh7770_module_clk_ops,
        &sh7770_bus_clk_ops,
        &sh7770_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (idx < ARRAY_SIZE(sh7770_clk_ops))
                *ops = sh7770_clk_ops[idx];
index 3b53348..793dae4 100644 (file)
@@ -27,7 +27,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= pfc_divisors[__raw_readl(FRQCR) & 0x0003];
 }
 
-static struct clk_ops sh7780_master_clk_ops = {
+static struct sh_clk_ops sh7780_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -37,7 +37,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / pfc_divisors[idx];
 }
 
-static struct clk_ops sh7780_module_clk_ops = {
+static struct sh_clk_ops sh7780_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -47,7 +47,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / bfc_divisors[idx];
 }
 
-static struct clk_ops sh7780_bus_clk_ops = {
+static struct sh_clk_ops sh7780_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -57,18 +57,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_divisors[idx];
 }
 
-static struct clk_ops sh7780_cpu_clk_ops = {
+static struct sh_clk_ops sh7780_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh7780_clk_ops[] = {
+static struct sh_clk_ops *sh7780_clk_ops[] = {
        &sh7780_master_clk_ops,
        &sh7780_module_clk_ops,
        &sh7780_bus_clk_ops,
        &sh7780_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        if (idx < ARRAY_SIZE(sh7780_clk_ops))
                *ops = sh7780_clk_ops[idx];
@@ -80,7 +80,7 @@ static unsigned long shyway_clk_recalc(struct clk *clk)
        return clk->parent->rate / cfc_divisors[idx];
 }
 
-static struct clk_ops sh7780_shyway_clk_ops = {
+static struct sh_clk_ops sh7780_shyway_clk_ops = {
        .recalc         = shyway_clk_recalc,
 };
 
index 2b31443..ab1c58f 100644 (file)
@@ -36,7 +36,7 @@ static unsigned long pll_recalc(struct clk *clk)
        return clk->parent->rate * multiplier;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
        .recalc         = pll_recalc,
 };
 
index f6c0c3d..4917094 100644 (file)
@@ -38,7 +38,7 @@ static unsigned long pll_recalc(struct clk *clk)
        return clk->parent->rate * multiplier;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
        .recalc         = pll_recalc,
 };
 
index bf2d00b..0f11b39 100644 (file)
@@ -32,7 +32,7 @@ static unsigned long pll_recalc(struct clk *clk)
        return clk->parent->rate * 72;
 }
 
-static struct clk_ops pll_clk_ops = {
+static struct sh_clk_ops pll_clk_ops = {
        .recalc         = pll_recalc,
 };
 
index 9cfc19b..c48b93d 100644 (file)
@@ -28,7 +28,7 @@ static void master_clk_init(struct clk *clk)
        clk->rate *= ifc_table[idx];
 }
 
-static struct clk_ops sh5_master_clk_ops = {
+static struct sh_clk_ops sh5_master_clk_ops = {
        .init           = master_clk_init,
 };
 
@@ -38,7 +38,7 @@ static unsigned long module_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_table[idx];
 }
 
-static struct clk_ops sh5_module_clk_ops = {
+static struct sh_clk_ops sh5_module_clk_ops = {
        .recalc         = module_clk_recalc,
 };
 
@@ -48,7 +48,7 @@ static unsigned long bus_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_table[idx];
 }
 
-static struct clk_ops sh5_bus_clk_ops = {
+static struct sh_clk_ops sh5_bus_clk_ops = {
        .recalc         = bus_clk_recalc,
 };
 
@@ -58,18 +58,18 @@ static unsigned long cpu_clk_recalc(struct clk *clk)
        return clk->parent->rate / ifc_table[idx];
 }
 
-static struct clk_ops sh5_cpu_clk_ops = {
+static struct sh_clk_ops sh5_cpu_clk_ops = {
        .recalc         = cpu_clk_recalc,
 };
 
-static struct clk_ops *sh5_clk_ops[] = {
+static struct sh_clk_ops *sh5_clk_ops[] = {
        &sh5_master_clk_ops,
        &sh5_module_clk_ops,
        &sh5_bus_clk_ops,
        &sh5_cpu_clk_ops,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
 {
        cprc_base = (unsigned long)ioremap_nocache(CPRC_BASE, 1024);
        BUG_ON(!cprc_base);
index 1d6d51a..5ca5797 100644 (file)
@@ -73,8 +73,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 
        ret = install_special_mapping(mm, addr, PAGE_SIZE,
                                      VM_READ | VM_EXEC |
-                                     VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC |
-                                     VM_ALWAYSDUMP,
+                                     VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
                                      syscall_pages);
        if (unlikely(ret))
                goto up_fail;
index ca5580e..1666de8 100644 (file)
@@ -29,6 +29,7 @@ config SPARC
        select GENERIC_IRQ_SHOW
        select USE_GENERIC_SMP_HELPERS if SMP
        select GENERIC_PCI_IOMAP
+       select HAVE_NMI_WATCHDOG if SPARC64
 
 config SPARC32
        def_bool !64BIT
index 16dcae6..abf6afe 100644 (file)
@@ -95,7 +95,6 @@ void arch_trigger_all_cpu_backtrace(void);
 extern void *hardirq_stack[NR_CPUS];
 extern void *softirq_stack[NR_CPUS];
 #define __ARCH_HAS_DO_SOFTIRQ
-#define ARCH_HAS_NMI_WATCHDOG
 
 #define NO_IRQ         0xffffffff
 
index 6de7f7b..dc50329 100644 (file)
@@ -52,14 +52,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
  * 64Kbytes by the Host controller.
  */
 
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                       struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                       struct pci_bus_region *region);
-
 static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 {
        return PCI_IRQ_NONE;
index 755a4bb..1633b71 100644 (file)
@@ -73,14 +73,6 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                               enum pci_mmap_state mmap_state,
                               int write_combine);
 
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                       struct resource *res);
-
-extern void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                       struct pci_bus_region *region);
-
 static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 {
        return PCI_IRQ_NONE;
index c69d5b2..ec0e996 100644 (file)
@@ -7,6 +7,7 @@
 #ifndef _LINUX_ASM_VGA_H_
 #define _LINUX_ASM_VGA_H_
 
+#include <linux/bug.h>
 #include <asm/types.h>
 
 #define VT_BUF_HAVE_RW
index 9d83d3b..432afa8 100644 (file)
@@ -284,6 +284,7 @@ struct vio_dev {
 };
 
 struct vio_driver {
+       const char                      *name;
        struct list_head                node;
        const struct vio_device_id      *id_table;
        int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
@@ -371,7 +372,13 @@ do {       if (vio->debug & VIO_DEBUG_##TYPE) \
                       vio->vdev->channel_id, ## a); \
 } while (0)
 
-extern int vio_register_driver(struct vio_driver *drv);
+extern int __vio_register_driver(struct vio_driver *drv, struct module *owner,
+                                const char *mod_name);
+/*
+ * vio_register_driver must be a macro so that KBUILD_MODNAME can be expanded
+ */
+#define vio_register_driver(driver)            \
+       __vio_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
 extern void vio_unregister_driver(struct vio_driver *drv);
 
 static inline struct vio_driver *to_vio_driver(struct device_driver *drv)
index 381edcd..fea13c7 100644 (file)
@@ -1244,10 +1244,7 @@ static struct vio_driver ds_driver = {
        .id_table       = ds_match,
        .probe          = ds_probe,
        .remove         = ds_remove,
-       .driver         = {
-               .name   = "ds",
-               .owner  = THIS_MODULE,
-       }
+       .name           = "ds",
 };
 
 static int __init ds_init(void)
index c7bec25..aba6b95 100644 (file)
 
 /* The LEON architecture does not rely on a BIOS or bootloader to setup
  * PCI for us. The Linux generic routines are used to setup resources,
- * reset values of confuration-space registers settings ae preseved.
+ * reset values of configuration-space register settings are preserved.
+ *
+ * PCI Memory and Prefetchable Memory is direct-mapped. However I/O Space is
+ * accessed through a Window which is translated to low 64KB in PCI space, the
+ * first 4KB is not used so 60KB is available.
  */
 void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
 {
        LIST_HEAD(resources);
        struct pci_bus *root_bus;
 
-       pci_add_resource(&resources, &info->io_space);
+       pci_add_resource_offset(&resources, &info->io_space,
+                               info->io_space.start - 0x1000);
        pci_add_resource(&resources, &info->mem_space);
 
        root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,
@@ -38,44 +43,6 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
        }
 }
 
-/* PCI Memory and Prefetchable Memory is direct-mapped. However I/O Space is
- * accessed through a Window which is translated to low 64KB in PCI space, the
- * first 4KB is not used so 60KB is available.
- *
- * This function is used by generic code to translate resource addresses into
- * PCI addresses.
- */
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                            struct resource *res)
-{
-       struct leon_pci_info *info = dev->bus->sysdata;
-
-       region->start = res->start;
-       region->end = res->end;
-
-       if (res->flags & IORESOURCE_IO) {
-               region->start -= (info->io_space.start - 0x1000);
-               region->end -= (info->io_space.start - 0x1000);
-       }
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-/* see pcibios_resource_to_bus() comment */
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                            struct pci_bus_region *region)
-{
-       struct leon_pci_info *info = dev->bus->sysdata;
-
-       res->start = region->start;
-       res->end = region->end;
-
-       if (res->flags & IORESOURCE_IO) {
-               res->start += (info->io_space.start - 0x1000);
-               res->end += (info->io_space.start - 0x1000);
-       }
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
 void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
 {
        struct leon_pci_info *info = pbus->sysdata;
index bb8bc2e..fdaf218 100644 (file)
@@ -375,13 +375,6 @@ static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
        *last_p = last;
 }
 
-static void pci_resource_adjust(struct resource *res,
-                               struct resource *root)
-{
-       res->start += root->start;
-       res->end += root->start;
-}
-
 /* For PCI bus devices which lack a 'ranges' property we interrogate
  * the config space values to set the resources, just like the generic
  * Linux PCI probing code does.
@@ -390,7 +383,8 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
                                          struct pci_bus *bus,
                                          struct pci_pbm_info *pbm)
 {
-       struct resource *res;
+       struct pci_bus_region region;
+       struct resource *res, res2;
        u8 io_base_lo, io_limit_lo;
        u16 mem_base_lo, mem_limit_lo;
        unsigned long base, limit;
@@ -412,11 +406,14 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
        res = bus->resource[0];
        if (base <= limit) {
                res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+               res2.flags = res->flags;
+               region.start = base;
+               region.end = limit + 0xfff;
+               pcibios_bus_to_resource(dev, &res2, &region);
                if (!res->start)
-                       res->start = base;
+                       res->start = res2.start;
                if (!res->end)
-                       res->end = limit + 0xfff;
-               pci_resource_adjust(res, &pbm->io_space);
+                       res->end = res2.end;
        }
 
        pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
@@ -428,9 +425,9 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
        if (base <= limit) {
                res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
                              IORESOURCE_MEM);
-               res->start = base;
-               res->end = limit + 0xfffff;
-               pci_resource_adjust(res, &pbm->mem_space);
+               region.start = base;
+               region.end = limit + 0xfffff;
+               pcibios_bus_to_resource(dev, res, &region);
        }
 
        pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
@@ -459,9 +456,9 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
        if (base <= limit) {
                res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
                              IORESOURCE_MEM | IORESOURCE_PREFETCH);
-               res->start = base;
-               res->end = limit + 0xfffff;
-               pci_resource_adjust(res, &pbm->mem_space);
+               region.start = base;
+               region.end = limit + 0xfffff;
+               pcibios_bus_to_resource(dev, res, &region);
        }
 }
 
@@ -472,6 +469,7 @@ static void __devinit apb_fake_ranges(struct pci_dev *dev,
                                      struct pci_bus *bus,
                                      struct pci_pbm_info *pbm)
 {
+       struct pci_bus_region region;
        struct resource *res;
        u32 first, last;
        u8 map;
@@ -479,18 +477,18 @@ static void __devinit apb_fake_ranges(struct pci_dev *dev,
        pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map);
        apb_calc_first_last(map, &first, &last);
        res = bus->resource[0];
-       res->start = (first << 21);
-       res->end = (last << 21) + ((1 << 21) - 1);
        res->flags = IORESOURCE_IO;
-       pci_resource_adjust(res, &pbm->io_space);
+       region.start = (first << 21);
+       region.end = (last << 21) + ((1 << 21) - 1);
+       pcibios_bus_to_resource(dev, res, &region);
 
        pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map);
        apb_calc_first_last(map, &first, &last);
        res = bus->resource[1];
-       res->start = (first << 21);
-       res->end = (last << 21) + ((1 << 21) - 1);
        res->flags = IORESOURCE_MEM;
-       pci_resource_adjust(res, &pbm->mem_space);
+       region.start = (first << 21);
+       region.end = (last << 21) + ((1 << 21) - 1);
+       pcibios_bus_to_resource(dev, res, &region);
 }
 
 static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
@@ -506,6 +504,7 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
        struct pci_bus *bus;
        const u32 *busrange, *ranges;
        int len, i, simba;
+       struct pci_bus_region region;
        struct resource *res;
        unsigned int flags;
        u64 size;
@@ -556,8 +555,6 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
        }
        i = 1;
        for (; len >= 32; len -= 32, ranges += 8) {
-               struct resource *root;
-
                flags = pci_parse_of_flags(ranges[0]);
                size = GET_64BIT(ranges, 6);
                if (flags == 0 || size == 0)
@@ -569,7 +566,6 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
                                       " for bridge %s\n", node->full_name);
                                continue;
                        }
-                       root = &pbm->io_space;
                } else {
                        if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) {
                                printk(KERN_ERR "PCI: too many memory ranges"
@@ -578,18 +574,12 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
                        }
                        res = bus->resource[i];
                        ++i;
-                       root = &pbm->mem_space;
                }
 
-               res->start = GET_64BIT(ranges, 1);
-               res->end = res->start + size - 1;
                res->flags = flags;
-
-               /* Another way to implement this would be to add an of_device
-                * layer routine that can calculate a resource for a given
-                * range property value in a PCI device.
-                */
-               pci_resource_adjust(res, root);
+               region.start = GET_64BIT(ranges, 1);
+               region.end = region.start + size - 1;
+               pcibios_bus_to_resource(dev, res, &region);
        }
 after_ranges:
        sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
@@ -691,8 +681,10 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
 
        printk("PCI: Scanning PBM %s\n", node->full_name);
 
-       pci_add_resource(&resources, &pbm->io_space);
-       pci_add_resource(&resources, &pbm->mem_space);
+       pci_add_resource_offset(&resources, &pbm->io_space,
+                               pbm->io_space.start);
+       pci_add_resource_offset(&resources, &pbm->mem_space,
+                               pbm->mem_space.start);
        bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
                                  pbm, &resources);
        if (!bus) {
@@ -755,46 +747,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return 0;
 }
 
-void pcibios_resource_to_bus(struct pci_dev *pdev, struct pci_bus_region *region,
-                            struct resource *res)
-{
-       struct pci_pbm_info *pbm = pdev->bus->sysdata;
-       struct resource zero_res, *root;
-
-       zero_res.start = 0;
-       zero_res.end = 0;
-       zero_res.flags = res->flags;
-
-       if (res->flags & IORESOURCE_IO)
-               root = &pbm->io_space;
-       else
-               root = &pbm->mem_space;
-
-       pci_resource_adjust(&zero_res, root);
-
-       region->start = res->start - zero_res.start;
-       region->end = res->end - zero_res.start;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res,
-                            struct pci_bus_region *region)
-{
-       struct pci_pbm_info *pbm = pdev->bus->sysdata;
-       struct resource *root;
-
-       res->start = region->start;
-       res->end = region->end;
-
-       if (res->flags & IORESOURCE_IO)
-               root = &pbm->io_space;
-       else
-               root = &pbm->mem_space;
-
-       pci_resource_adjust(res, root);
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
 char * __devinit pcibios_setup(char *str)
 {
        return str;
index f67e28e..5cffdc5 100644 (file)
@@ -119,13 +119,17 @@ static struct bus_type vio_bus_type = {
        .remove         = vio_device_remove,
 };
 
-int vio_register_driver(struct vio_driver *viodrv)
+int __vio_register_driver(struct vio_driver *viodrv, struct module *owner,
+                       const char *mod_name)
 {
        viodrv->driver.bus = &vio_bus_type;
+       viodrv->driver.name = viodrv->name;
+       viodrv->driver.owner = owner;
+       viodrv->driver.mod_name = mod_name;
 
        return driver_register(&viodrv->driver);
 }
-EXPORT_SYMBOL(vio_register_driver);
+EXPORT_SYMBOL(__vio_register_driver);
 
 void vio_unregister_driver(struct vio_driver *viodrv)
 {
index 33368d1..758b603 100644 (file)
@@ -118,17 +118,11 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
 
        /*
         * MAYWRITE to allow gdb to COW and set breakpoints
-        *
-        * Make sure the vDSO gets into every core dump.  Dumping its
-        * contents makes post-mortem fully interpretable later
-        * without matching up the same kernel and hardware config to
-        * see what PC values meant.
         */
        vdso_base = VDSO_BASE;
        retval = install_special_mapping(mm, vdso_base, PAGE_SIZE,
                                         VM_READ|VM_EXEC|
-                                        VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-                                        VM_ALWAYSDUMP,
+                                        VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
                                         vdso_pages);
 
 #ifndef __tilegx__
index b37ae70..20a49ba 100644 (file)
@@ -9,6 +9,7 @@ config UML
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
+       select GENERIC_IO
 
 config MMU
        bool
index 28688e6..55c0661 100644 (file)
@@ -28,6 +28,7 @@ ifeq ($(SUBARCH),i386)
 endif
 ifeq ($(SUBARCH),x86_64)
         HEADER_ARCH := x86
+       KBUILD_CFLAGS += -mcmodel=large
 endif
 
 HOST_DIR := arch/$(HEADER_ARCH)
@@ -50,7 +51,7 @@ KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/um
 #
 # These apply to USER_CFLAGS to.
 
-KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
+KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \
        $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap      \
        -Din6addr_loopback=kernel_in6addr_loopback \
        -Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr
@@ -99,7 +100,7 @@ KBUILD_KCONFIG := $(HOST_DIR)/um/Kconfig
 
 archheaders:
        $(Q)$(MAKE) -C '$(srctree)' KBUILD_SRC= \
-               ARCH=$(SUBARCH) O='$(objtree)' archheaders
+               ARCH=$(HEADER_ARCH) O='$(objtree)' archheaders
 
 archprepare: include/generated/user_constants.h
 
index 761f5e1..fdc97e2 100644 (file)
@@ -1,10 +1,8 @@
 #
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.24
-# Thu Feb  7 11:48:55 2008
+# Automatically generated file; DO NOT EDIT.
+# User Mode Linux/i386 3.3.0 Kernel Configuration
 #
 CONFIG_DEFCONFIG_LIST="arch/$ARCH/defconfig"
-CONFIG_GENERIC_HARDIRQS=y
 CONFIG_UML=y
 CONFIG_MMU=y
 CONFIG_NO_IOMEM=y
@@ -20,12 +18,10 @@ CONFIG_HZ=100
 #
 # UML-specific options
 #
-# CONFIG_STATIC_LINK is not set
 
 #
 # Host processor type and features
 #
-# CONFIG_M386 is not set
 # CONFIG_M486 is not set
 # CONFIG_M586 is not set
 # CONFIG_M586TSC is not set
@@ -41,17 +37,17 @@ CONFIG_M686=y
 # CONFIG_MCRUSOE is not set
 # CONFIG_MEFFICEON is not set
 # CONFIG_MWINCHIPC6 is not set
-# CONFIG_MWINCHIP2 is not set
 # CONFIG_MWINCHIP3D is not set
+# CONFIG_MELAN is not set
 # CONFIG_MGEODEGX1 is not set
 # CONFIG_MGEODE_LX is not set
 # CONFIG_MCYRIXIII is not set
 # CONFIG_MVIAC3_2 is not set
 # CONFIG_MVIAC7 is not set
-# CONFIG_MPSC is not set
 # CONFIG_MCORE2 is not set
-# CONFIG_GENERIC_CPU is not set
+# CONFIG_MATOM is not set
 # CONFIG_X86_GENERIC is not set
+CONFIG_X86_INTERNODE_CACHE_SHIFT=5
 CONFIG_X86_CMPXCHG=y
 CONFIG_X86_L1_CACHE_SHIFT=5
 CONFIG_X86_XADD=y
@@ -60,47 +56,59 @@ CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
-CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
 CONFIG_X86_TSC=y
+CONFIG_X86_CMPXCHG64=y
 CONFIG_X86_CMOV=y
-CONFIG_X86_MINIMUM_CPU_FAMILY=4
-CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=5
+CONFIG_CPU_SUP_INTEL=y
+CONFIG_CPU_SUP_CYRIX_32=y
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_TRANSMETA_32=y
+CONFIG_CPU_SUP_UMC_32=y
 CONFIG_UML_X86=y
-CONFIG_X86_32=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_64BIT is not set
-CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_X86_32=y
+# CONFIG_X86_64 is not set
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_3_LEVEL_PGTABLES is not set
 CONFIG_ARCH_HAS_SC_SIGNALS=y
 CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
 CONFIG_GENERIC_HWEIGHT=y
+# CONFIG_STATIC_LINK is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_COMPACTION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_NEED_PER_CPU_KM=y
+# CONFIG_CLEANCACHE is not set
 CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_LD_SCRIPT_DYN=y
 CONFIG_BINFMT_ELF=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_MISC=m
 CONFIG_HOSTFS=y
 # CONFIG_HPPFS is not set
 CONFIG_MCONSOLE=y
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_HIGHMEM is not set
 CONFIG_KERNEL_STACK_ORDER=0
+# CONFIG_MMAPPER is not set
+CONFIG_NO_DMA=y
 
 #
 # General setup
@@ -108,99 +116,169 @@ CONFIG_KERNEL_STACK_ORDER=0
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=128
+CONFIG_CROSS_COMPILE=""
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
+CONFIG_DEFAULT_HOSTNAME="(none)"
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_FHANDLE is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_PID_NS is not set
 # CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_SHOW=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TINY_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_TREE_RCU_TRACE is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+# CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED is not set
+# CONFIG_CGROUP_MEM_RES_CTLR_KMEM is not set
+CONFIG_CGROUP_SCHED=y
 CONFIG_FAIR_GROUP_SCHED=y
-CONFIG_FAIR_USER_SCHED=y
-# CONFIG_FAIR_CGROUP_SCHED is not set
+# CONFIG_CFS_BANDWIDTH is not set
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_BLK_CGROUP=m
+# CONFIG_DEBUG_BLK_CGROUP is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_NET_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_MM_OWNER=y
 CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_BLK_DEV_INITRD is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 # CONFIG_EXPERT is not set
 CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
-CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_EMBEDDED is not set
+
+#
+# Kernel Performance Events And Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
-# CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
-# CONFIG_HAVE_OPROFILE is not set
-# CONFIG_HAVE_KPROBES is not set
-CONFIG_PROC_PAGE_MONITOR=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
 
 #
 # IO Schedulers
 #
 CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
-# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=m
+# CONFIG_CFQ_GROUP_IOSCHED is not set
+CONFIG_DEFAULT_DEADLINE=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
-# CONFIG_PREEMPT_RCU is not set
-CONFIG_BLK_DEV=y
-CONFIG_BLK_DEV_UBD=y
-# CONFIG_BLK_DEV_UBD_SYNC is not set
-CONFIG_BLK_DEV_COW_COMMON=y
-CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_ATA_OVER_ETH is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+CONFIG_FREEZER=y
 
 #
-# Character Devices
+# UML Character Devices
 #
 CONFIG_STDERR_CONSOLE=y
 CONFIG_STDIO_CONSOLE=y
@@ -214,40 +292,191 @@ CONFIG_XTERM_CHAN=y
 CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
 CONFIG_CON_CHAN="xterm"
 CONFIG_SSL_CHAN="pts"
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-# CONFIG_RAW_DRIVER is not set
-CONFIG_LEGACY_PTY_COUNT=32
-# CONFIG_WATCHDOG is not set
 CONFIG_UML_SOUND=m
 CONFIG_SOUND=m
+CONFIG_SOUND_OSS_CORE=y
 CONFIG_HOSTAUDIO=m
-# CONFIG_HW_RANDOM is not set
-CONFIG_UML_RANDOM=y
-# CONFIG_MMAPPER is not set
+
+#
+# Device Drivers
+#
 
 #
 # Generic Driver Options
 #
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
+CONFIG_GENERIC_CPU_DEVICES=y
+# CONFIG_DMA_SHARED_BUFFER is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_UBD=y
+# CONFIG_BLK_DEV_UBD_SYNC is not set
+CONFIG_BLK_DEV_COW_COMMON=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_RBD is not set
+
+#
+# Misc devices
+#
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+
+#
+# Altera FPGA firmware download module
+#
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_CORE=y
+# CONFIG_BONDING is not set
+CONFIG_DUMMY=m
+# CONFIG_EQUALIZER is not set
+# CONFIG_MII is not set
+# CONFIG_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+
+#
+# CAIF transport drivers
+#
+CONFIG_ETHERNET=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_I825XX=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_8390=y
+# CONFIG_PHYLIB is not set
+CONFIG_PPP=m
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_SLIP=m
+CONFIG_SLHC=m
+# CONFIG_SLIP_COMPRESSED is not set
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+CONFIG_WLAN=y
+# CONFIG_HOSTAP is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+
+#
+# Character devices
+#
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=32
+# CONFIG_N_GSM is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVKMEM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_UML_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_NSC_GPIO is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+
+#
+# Enable Device Drivers -> PPS to see the PTP clock options.
+#
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_REGULATOR is not set
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_BALLOON is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+# CONFIG_STAGING is not set
 
 #
-# Networking
+# Hardware Spinlock drivers
 #
+CONFIG_IOMMU_SUPPORT=y
+# CONFIG_VIRT_DRIVERS is not set
+# CONFIG_PM_DEVFREQ is not set
 CONFIG_NET=y
 
 #
 # Networking options
 #
 CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
@@ -257,10 +486,9 @@ CONFIG_XFRM=y
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
 # CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
@@ -274,20 +502,23 @@ CONFIG_INET_XFRM_MODE_BEET=y
 # CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
+# CONFIG_INET_UDP_DIAG is not set
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
 # CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
+# CONFIG_L2TP is not set
 # CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
@@ -297,7 +528,14 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_NETPRIO_CGROUP is not set
+CONFIG_BQL=y
 
 #
 # Network testing
@@ -308,16 +546,19 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
 
 #
-# Wireless
+# CFG80211 needs to be enabled for MAC80211
 #
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
 
 #
 # UML Network Devices
@@ -331,76 +572,51 @@ CONFIG_UML_NET_DAEMON=y
 CONFIG_UML_NET_MCAST=y
 # CONFIG_UML_NET_PCAP is not set
 CONFIG_UML_NET_SLIRP=y
-CONFIG_NETDEVICES=y
-# CONFIG_NETDEVICES_MULTIQUEUE is not set
-CONFIG_DUMMY=m
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
-# CONFIG_VETH is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# CONFIG_WAN is not set
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-# CONFIG_PPP_ASYNC is not set
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPP_DEFLATE is not set
-# CONFIG_PPP_BSDCOMP is not set
-# CONFIG_PPP_MPPE is not set
-# CONFIG_PPPOE is not set
-# CONFIG_PPPOL2TP is not set
-CONFIG_SLIP=m
-# CONFIG_SLIP_COMPRESSED is not set
-CONFIG_SLHC=m
-# CONFIG_SLIP_SMART is not set
-# CONFIG_SLIP_MODE_SLIP6 is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_CONNECTOR is not set
 
 #
 # File systems
 #
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-# CONFIG_EXT4DEV_FS is not set
-CONFIG_JBD=y
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+CONFIG_EXT4_FS_XATTR=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_FS_MBCACHE=y
 CONFIG_REISERFS_FS=y
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_REISERFS_FS_XATTR is not set
 # CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
 # CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=y
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
 CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
 CONFIG_QUOTA=y
 # CONFIG_QUOTA_NETLINK_INTERFACE is not set
 CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
 # CONFIG_QFMT_V1 is not set
 # CONFIG_QFMT_V2 is not set
 CONFIG_QUOTACTL=y
-CONFIG_DNOTIFY=y
-CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=m
@@ -421,15 +637,14 @@ CONFIG_JOLIET=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -437,26 +652,26 @@ CONFIG_TMPFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 # CONFIG_NFS_FS is not set
 # CONFIG_NFSD is not set
-# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_CODEPAGE_437 is not set
@@ -497,119 +712,191 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
-# CONFIG_DLM is not set
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
 # CONFIG_SECURITY is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
 CONFIG_CRYPTO=y
-# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=m
 # CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_USER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
 # CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
 # CONFIG_CRYPTO_SHA1 is not set
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_CBC is not set
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_XTS is not set
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_FCRYPT is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_TWOFISH_586 is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
 # CONFIG_CRYPTO_AES_586 is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_CAST5 is not set
 # CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_SEED is not set
 # CONFIG_CRYPTO_SALSA20 is not set
 # CONFIG_CRYPTO_SALSA20_586 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_TWOFISH_586 is not set
+
+#
+# Compression
+#
 # CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_TEST is not set
-# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_ZLIB is not set
 # CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
 CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
 #
-CONFIG_BITREVERSE=m
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_IO=y
 # CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
 # CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=m
+CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
-CONFIG_PLIST=y
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA is not set
-# CONFIG_SCSI_NETLINK is not set
-# CONFIG_MD is not set
-# CONFIG_INPUT is not set
+# CONFIG_CRC8 is not set
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
 CONFIG_ENABLE_WARN_DEPRECATED=y
 CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_UNUSED_SYMBOLS is not set
 # CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
-CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_DETECT_HUNG_TASK is not set
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_INFO_REDUCED is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
 # CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
 # CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
 CONFIG_FRAME_POINTER=y
-CONFIG_FORCED_INLINING=y
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
 # CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
 # CONFIG_SAMPLES is not set
+# CONFIG_TEST_KSTRTOX is not set
 # CONFIG_GPROF is not set
 # CONFIG_GCOV is not set
-# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_EARLY_PRINTK=y
index 8df0fd9..02b5a76 100644 (file)
@@ -27,24 +27,24 @@ struct chan {
        void *data;
 };
 
-extern void chan_interrupt(struct list_head *chans, struct delayed_work *task,
+extern void chan_interrupt(struct line *line,
                           struct tty_struct *tty, int irq);
 extern int parse_chan_pair(char *str, struct line *line, int device,
                           const struct chan_opts *opts, char **error_out);
-extern int write_chan(struct list_head *chans, const char *buf, int len,
+extern int write_chan(struct chan *chan, const char *buf, int len,
                             int write_irq);
-extern int console_write_chan(struct list_head *chans, const char *buf, 
+extern int console_write_chan(struct chan *chan, const char *buf, 
                              int len);
 extern int console_open_chan(struct line *line, struct console *co);
-extern void deactivate_chan(struct list_head *chans, int irq);
-extern void reactivate_chan(struct list_head *chans, int irq);
-extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty);
+extern void deactivate_chan(struct chan *chan, int irq);
+extern void reactivate_chan(struct chan *chan, int irq);
+extern void chan_enable_winch(struct chan *chan, struct tty_struct *tty);
 extern int enable_chan(struct line *line);
-extern void close_chan(struct list_head *chans, int delay_free_irq);
-extern int chan_window_size(struct list_head *chans, 
+extern void close_chan(struct line *line);
+extern int chan_window_size(struct line *line, 
                             unsigned short *rows_out, 
                             unsigned short *cols_out);
-extern int chan_config_string(struct list_head *chans, char *str, int size,
+extern int chan_config_string(struct line *line, char *str, int size,
                              char **error_out);
 
 #endif
index 420e2c8..ca4c7eb 100644 (file)
@@ -140,18 +140,18 @@ static int open_chan(struct list_head *chans)
        return err;
 }
 
-void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
+void chan_enable_winch(struct chan *chan, struct tty_struct *tty)
 {
-       struct list_head *ele;
-       struct chan *chan;
+       if (chan && chan->primary && chan->ops->winch)
+               register_winch(chan->fd, tty);
+}
 
-       list_for_each(ele, chans) {
-               chan = list_entry(ele, struct chan, list);
-               if (chan->primary && chan->output && chan->ops->winch) {
-                       register_winch(chan->fd, tty);
-                       return;
-               }
-       }
+static void line_timer_cb(struct work_struct *work)
+{
+       struct line *line = container_of(work, struct line, task.work);
+
+       if (!line->throttled)
+               chan_interrupt(line, line->tty, line->driver->read_irq);
 }
 
 int enable_chan(struct line *line)
@@ -160,6 +160,8 @@ int enable_chan(struct line *line)
        struct chan *chan;
        int err;
 
+       INIT_DELAYED_WORK(&line->task, line_timer_cb);
+
        list_for_each(ele, &line->chan_list) {
                chan = list_entry(ele, struct chan, list);
                err = open_one_chan(chan);
@@ -183,7 +185,7 @@ int enable_chan(struct line *line)
        return 0;
 
  out_close:
-       close_chan(&line->chan_list, 0);
+       close_chan(line);
        return err;
 }
 
@@ -244,7 +246,7 @@ static void close_one_chan(struct chan *chan, int delay_free_irq)
        chan->fd = -1;
 }
 
-void close_chan(struct list_head *chans, int delay_free_irq)
+void close_chan(struct line *line)
 {
        struct chan *chan;
 
@@ -253,77 +255,50 @@ void close_chan(struct list_head *chans, int delay_free_irq)
         * state.  Then, the first one opened will have the original state,
         * so it must be the last closed.
         */
-       list_for_each_entry_reverse(chan, chans, list) {
-               close_one_chan(chan, delay_free_irq);
+       list_for_each_entry_reverse(chan, &line->chan_list, list) {
+               close_one_chan(chan, 0);
        }
 }
 
-void deactivate_chan(struct list_head *chans, int irq)
+void deactivate_chan(struct chan *chan, int irq)
 {
-       struct list_head *ele;
-
-       struct chan *chan;
-       list_for_each(ele, chans) {
-               chan = list_entry(ele, struct chan, list);
-
-               if (chan->enabled && chan->input)
-                       deactivate_fd(chan->fd, irq);
-       }
+       if (chan && chan->enabled)
+               deactivate_fd(chan->fd, irq);
 }
 
-void reactivate_chan(struct list_head *chans, int irq)
+void reactivate_chan(struct chan *chan, int irq)
 {
-       struct list_head *ele;
-       struct chan *chan;
-
-       list_for_each(ele, chans) {
-               chan = list_entry(ele, struct chan, list);
-
-               if (chan->enabled && chan->input)
-                       reactivate_fd(chan->fd, irq);
-       }
+       if (chan && chan->enabled)
+               reactivate_fd(chan->fd, irq);
 }
 
-int write_chan(struct list_head *chans, const char *buf, int len,
+int write_chan(struct chan *chan, const char *buf, int len,
               int write_irq)
 {
-       struct list_head *ele;
-       struct chan *chan = NULL;
        int n, ret = 0;
 
-       if (len == 0)
+       if (len == 0 || !chan || !chan->ops->write)
                return 0;
 
-       list_for_each(ele, chans) {
-               chan = list_entry(ele, struct chan, list);
-               if (!chan->output || (chan->ops->write == NULL))
-                       continue;
-
-               n = chan->ops->write(chan->fd, buf, len, chan->data);
-               if (chan->primary) {
-                       ret = n;
-                       if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
-                               reactivate_fd(chan->fd, write_irq);
-               }
+       n = chan->ops->write(chan->fd, buf, len, chan->data);
+       if (chan->primary) {
+               ret = n;
+               if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
+                       reactivate_fd(chan->fd, write_irq);
        }
        return ret;
 }
 
-int console_write_chan(struct list_head *chans, const char *buf, int len)
+int console_write_chan(struct chan *chan, const char *buf, int len)
 {
-       struct list_head *ele;
-       struct chan *chan;
        int n, ret = 0;
 
-       list_for_each(ele, chans) {
-               chan = list_entry(ele, struct chan, list);
-               if (!chan->output || (chan->ops->console_write == NULL))
-                       continue;
+       if (!chan || !chan->ops->console_write)
+               return 0;
 
-               n = chan->ops->console_write(chan->fd, buf, len);
-               if (chan->primary)
-                       ret = n;
-       }
+       n = chan->ops->console_write(chan->fd, buf, len);
+       if (chan->primary)
+               ret = n;
        return ret;
 }
 
@@ -340,20 +315,24 @@ int console_open_chan(struct line *line, struct console *co)
        return 0;
 }
 
-int chan_window_size(struct list_head *chans, unsigned short *rows_out,
+int chan_window_size(struct line *line, unsigned short *rows_out,
                      unsigned short *cols_out)
 {
-       struct list_head *ele;
        struct chan *chan;
 
-       list_for_each(ele, chans) {
-               chan = list_entry(ele, struct chan, list);
-               if (chan->primary) {
-                       if (chan->ops->window_size == NULL)
-                               return 0;
-                       return chan->ops->window_size(chan->fd, chan->data,
-                                                     rows_out, cols_out);
-               }
+       chan = line->chan_in;
+       if (chan && chan->primary) {
+               if (chan->ops->window_size == NULL)
+                       return 0;
+               return chan->ops->window_size(chan->fd, chan->data,
+                                             rows_out, cols_out);
+       }
+       chan = line->chan_out;
+       if (chan && chan->primary) {
+               if (chan->ops->window_size == NULL)
+                       return 0;
+               return chan->ops->window_size(chan->fd, chan->data,
+                                             rows_out, cols_out);
        }
        return 0;
 }
@@ -429,21 +408,15 @@ static int chan_pair_config_string(struct chan *in, struct chan *out,
        return n;
 }
 
-int chan_config_string(struct list_head *chans, char *str, int size,
+int chan_config_string(struct line *line, char *str, int size,
                       char **error_out)
 {
-       struct list_head *ele;
-       struct chan *chan, *in = NULL, *out = NULL;
+       struct chan *in = line->chan_in, *out = line->chan_out;
 
-       list_for_each(ele, chans) {
-               chan = list_entry(ele, struct chan, list);
-               if (!chan->primary)
-                       continue;
-               if (chan->input)
-                       in = chan;
-               if (chan->output)
-                       out = chan;
-       }
+       if (in && !in->primary)
+               in = NULL;
+       if (out && !out->primary)
+               out = NULL;
 
        return chan_pair_config_string(in, out, str, size, error_out);
 }
@@ -547,10 +520,14 @@ int parse_chan_pair(char *str, struct line *line, int device,
        char *in, *out;
 
        if (!list_empty(chans)) {
+               line->chan_in = line->chan_out = NULL;
                free_chan(chans);
                INIT_LIST_HEAD(chans);
        }
 
+       if (!str)
+               return 0;
+
        out = strchr(str, ',');
        if (out != NULL) {
                in = str;
@@ -562,6 +539,7 @@ int parse_chan_pair(char *str, struct line *line, int device,
 
                new->input = 1;
                list_add(&new->list, chans);
+               line->chan_in = new;
 
                new = parse_chan(line, out, device, opts, error_out);
                if (new == NULL)
@@ -569,6 +547,7 @@ int parse_chan_pair(char *str, struct line *line, int device,
 
                list_add(&new->list, chans);
                new->output = 1;
+               line->chan_out = new;
        }
        else {
                new = parse_chan(line, str, device, opts, error_out);
@@ -578,43 +557,42 @@ int parse_chan_pair(char *str, struct line *line, int device,
                list_add(&new->list, chans);
                new->input = 1;
                new->output = 1;
+               line->chan_in = line->chan_out = new;
        }
        return 0;
 }
 
-void chan_interrupt(struct list_head *chans, struct delayed_work *task,
-                   struct tty_struct *tty, int irq)
+void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
 {
-       struct list_head *ele, *next;
-       struct chan *chan;
+       struct chan *chan = line->chan_in;
        int err;
        char c;
 
-       list_for_each_safe(ele, next, chans) {
-               chan = list_entry(ele, struct chan, list);
-               if (!chan->input || (chan->ops->read == NULL))
-                       continue;
-               do {
-                       if (tty && !tty_buffer_request_room(tty, 1)) {
-                               schedule_delayed_work(task, 1);
-                               goto out;
-                       }
-                       err = chan->ops->read(chan->fd, &c, chan->data);
-                       if (err > 0)
-                               tty_receive_char(tty, c);
-               } while (err > 0);
-
-               if (err == 0)
-                       reactivate_fd(chan->fd, irq);
-               if (err == -EIO) {
-                       if (chan->primary) {
-                               if (tty != NULL)
-                                       tty_hangup(tty);
-                               close_chan(chans, 1);
-                               return;
-                       }
-                       else close_one_chan(chan, 1);
+       if (!chan || !chan->ops->read)
+               goto out;
+
+       do {
+               if (tty && !tty_buffer_request_room(tty, 1)) {
+                       schedule_delayed_work(&line->task, 1);
+                       goto out;
                }
+               err = chan->ops->read(chan->fd, &c, chan->data);
+               if (err > 0)
+                       tty_receive_char(tty, c);
+       } while (err > 0);
+
+       if (err == 0)
+               reactivate_fd(chan->fd, irq);
+       if (err == -EIO) {
+               if (chan->primary) {
+                       if (tty != NULL)
+                               tty_hangup(tty);
+                       if (line->chan_out != chan)
+                               close_one_chan(line->chan_out, 1);
+               }
+               close_one_chan(chan, 1);
+               if (chan->primary)
+                       return;
        }
  out:
        if (tty)
index 9b9ced8..6257b7a 100644 (file)
@@ -14,8 +14,6 @@ struct chan_opts {
        const int raw;
 };
 
-enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
-
 struct chan_ops {
        char *type;
        void *(*init)(char *, int, const struct chan_opts *);
index c1cf220..4ab0d9c 100644 (file)
@@ -21,19 +21,10 @@ static irqreturn_t line_interrupt(int irq, void *data)
        struct line *line = chan->line;
 
        if (line)
-               chan_interrupt(&line->chan_list, &line->task, line->tty, irq);
+               chan_interrupt(line, line->tty, irq);
        return IRQ_HANDLED;
 }
 
-static void line_timer_cb(struct work_struct *work)
-{
-       struct line *line = container_of(work, struct line, task.work);
-
-       if (!line->throttled)
-               chan_interrupt(&line->chan_list, &line->task, line->tty,
-                              line->driver->read_irq);
-}
-
 /*
  * Returns the free space inside the ring buffer of this line.
  *
@@ -145,7 +136,7 @@ static int flush_buffer(struct line *line)
                /* line->buffer + LINE_BUFSIZE is the end of the buffer! */
                count = line->buffer + LINE_BUFSIZE - line->head;
 
-               n = write_chan(&line->chan_list, line->head, count,
+               n = write_chan(line->chan_out, line->head, count,
                               line->driver->write_irq);
                if (n < 0)
                        return n;
@@ -162,7 +153,7 @@ static int flush_buffer(struct line *line)
        }
 
        count = line->tail - line->head;
-       n = write_chan(&line->chan_list, line->head, count,
+       n = write_chan(line->chan_out, line->head, count,
                       line->driver->write_irq);
 
        if (n < 0)
@@ -206,7 +197,7 @@ int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
        if (line->head != line->tail)
                ret = buffer_data(line, buf, len);
        else {
-               n = write_chan(&line->chan_list, buf, len,
+               n = write_chan(line->chan_out, buf, len,
                               line->driver->write_irq);
                if (n < 0) {
                        ret = n;
@@ -318,7 +309,7 @@ void line_throttle(struct tty_struct *tty)
 {
        struct line *line = tty->driver_data;
 
-       deactivate_chan(&line->chan_list, line->driver->read_irq);
+       deactivate_chan(line->chan_in, line->driver->read_irq);
        line->throttled = 1;
 }
 
@@ -327,8 +318,7 @@ void line_unthrottle(struct tty_struct *tty)
        struct line *line = tty->driver_data;
 
        line->throttled = 0;
-       chan_interrupt(&line->chan_list, &line->task, tty,
-                      line->driver->read_irq);
+       chan_interrupt(line, tty, line->driver->read_irq);
 
        /*
         * Maybe there is enough stuff pending that calling the interrupt
@@ -336,7 +326,7 @@ void line_unthrottle(struct tty_struct *tty)
         * again and we shouldn't turn the interrupt back on.
         */
        if (!line->throttled)
-               reactivate_chan(&line->chan_list, line->driver->read_irq);
+               reactivate_chan(line->chan_in, line->driver->read_irq);
 }
 
 static irqreturn_t line_write_interrupt(int irq, void *data)
@@ -347,13 +337,14 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
        int err;
 
        /*
-        * Interrupts are disabled here because we registered the interrupt with
-        * IRQF_DISABLED (see line_setup_irq).
+        * Interrupts are disabled here because genirq keep irqs disabled when
+        * calling the action handler.
         */
 
        spin_lock(&line->lock);
        err = flush_buffer(line);
        if (err == 0) {
+               spin_unlock(&line->lock);
                return IRQ_NONE;
        } else if (err < 0) {
                line->head = line->buffer;
@@ -371,7 +362,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
 int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
 {
        const struct line_driver *driver = line->driver;
-       int err = 0, flags = IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM;
+       int err = 0, flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM;
 
        if (input)
                err = um_request_irq(driver->read_irq, fd, IRQ_READ,
@@ -383,7 +374,6 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
                err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
                                        line_write_interrupt, flags,
                                        driver->write_irq_name, data);
-       line->have_irq = 1;
        return err;
 }
 
@@ -409,7 +399,7 @@ int line_open(struct line *lines, struct tty_struct *tty)
        struct line *line = &lines[tty->index];
        int err = -ENODEV;
 
-       spin_lock(&line->count_lock);
+       mutex_lock(&line->count_lock);
        if (!line->valid)
                goto out_unlock;
 
@@ -421,25 +411,19 @@ int line_open(struct line *lines, struct tty_struct *tty)
        tty->driver_data = line;
        line->tty = tty;
 
-       spin_unlock(&line->count_lock);
        err = enable_chan(line);
        if (err) /* line_close() will be called by our caller */
-               return err;
-
-       INIT_DELAYED_WORK(&line->task, line_timer_cb);
+               goto out_unlock;
 
        if (!line->sigio) {
-               chan_enable_winch(&line->chan_list, tty);
+               chan_enable_winch(line->chan_out, tty);
                line->sigio = 1;
        }
 
-       chan_window_size(&line->chan_list, &tty->winsize.ws_row,
+       chan_window_size(line, &tty->winsize.ws_row,
                         &tty->winsize.ws_col);
-
-       return 0;
-
 out_unlock:
-       spin_unlock(&line->count_lock);
+       mutex_unlock(&line->count_lock);
        return err;
 }
 
@@ -459,7 +443,7 @@ void line_close(struct tty_struct *tty, struct file * filp)
        /* We ignore the error anyway! */
        flush_buffer(line);
 
-       spin_lock(&line->count_lock);
+       mutex_lock(&line->count_lock);
        BUG_ON(!line->valid);
 
        if (--line->count)
@@ -468,17 +452,13 @@ void line_close(struct tty_struct *tty, struct file * filp)
        line->tty = NULL;
        tty->driver_data = NULL;
 
-       spin_unlock(&line->count_lock);
-
        if (line->sigio) {
                unregister_winch(tty);
                line->sigio = 0;
        }
 
-       return;
-
 out_unlock:
-       spin_unlock(&line->count_lock);
+       mutex_unlock(&line->count_lock);
 }
 
 void close_lines(struct line *lines, int nlines)
@@ -486,34 +466,60 @@ void close_lines(struct line *lines, int nlines)
        int i;
 
        for(i = 0; i < nlines; i++)
-               close_chan(&lines[i].chan_list, 0);
+               close_chan(&lines[i]);
 }
 
-static int setup_one_line(struct line *lines, int n, char *init, int init_prio,
-                         char **error_out)
+int setup_one_line(struct line *lines, int n, char *init,
+                  const struct chan_opts *opts, char **error_out)
 {
        struct line *line = &lines[n];
+       struct tty_driver *driver = line->driver->driver;
        int err = -EINVAL;
 
-       spin_lock(&line->count_lock);
+       mutex_lock(&line->count_lock);
 
        if (line->count) {
                *error_out = "Device is already open";
                goto out;
        }
 
-       if (line->init_pri <= init_prio) {
-               line->init_pri = init_prio;
-               if (!strcmp(init, "none"))
+       if (!strcmp(init, "none")) {
+               if (line->valid) {
+                       line->valid = 0;
+                       kfree(line->init_str);
+                       tty_unregister_device(driver, n);
+                       parse_chan_pair(NULL, line, n, opts, error_out);
+                       err = 0;
+               }
+       } else {
+               char *new = kstrdup(init, GFP_KERNEL);
+               if (!new) {
+                       *error_out = "Failed to allocate memory";
+                       return -ENOMEM;
+               }
+               if (line->valid) {
+                       tty_unregister_device(driver, n);
+                       kfree(line->init_str);
+               }
+               line->init_str = new;
+               line->valid = 1;
+               err = parse_chan_pair(new, line, n, opts, error_out);
+               if (!err) {
+                       struct device *d = tty_register_device(driver, n, NULL);
+                       if (IS_ERR(d)) {
+                               *error_out = "Failed to register device";
+                               err = PTR_ERR(d);
+                               parse_chan_pair(NULL, line, n, opts, error_out);
+                       }
+               }
+               if (err) {
+                       line->init_str = NULL;
                        line->valid = 0;
-               else {
-                       line->init_str = init;
-                       line->valid = 1;
+                       kfree(new);
                }
        }
-       err = 0;
 out:
-       spin_unlock(&line->count_lock);
+       mutex_unlock(&line->count_lock);
        return err;
 }
 
@@ -524,54 +530,43 @@ out:
  * @error_out is an error string in the case of failure;
  */
 
-int line_setup(struct line *lines, unsigned int num, char *init,
-              char **error_out)
+int line_setup(char **conf, unsigned int num, char **def,
+              char *init, char *name)
 {
-       int i, n, err;
-       char *end;
+       char *error;
 
        if (*init == '=') {
                /*
                 * We said con=/ssl= instead of con#=, so we are configuring all
                 * consoles at once.
                 */
-               n = -1;
-       }
-       else {
-               n = simple_strtoul(init, &end, 0);
+               *def = init + 1;
+       } else {
+               char *end;
+               unsigned n = simple_strtoul(init, &end, 0);
+
                if (*end != '=') {
-                       *error_out = "Couldn't parse device number";
-                       return -EINVAL;
+                       error = "Couldn't parse device number";
+                       goto out;
                }
-               init = end;
-       }
-       init++;
-
-       if (n >= (signed int) num) {
-               *error_out = "Device number out of range";
-               return -EINVAL;
-       }
-       else if (n >= 0) {
-               err = setup_one_line(lines, n, init, INIT_ONE, error_out);
-               if (err)
-                       return err;
-       }
-       else {
-               for(i = 0; i < num; i++) {
-                       err = setup_one_line(lines, i, init, INIT_ALL,
-                                            error_out);
-                       if (err)
-                               return err;
+               if (n >= num) {
+                       error = "Device number out of range";
+                       goto out;
                }
+               conf[n] = end + 1;
        }
-       return n == -1 ? num : n;
+       return 0;
+
+out:
+       printk(KERN_ERR "Failed to set up %s with "
+              "configuration string \"%s\" : %s\n", name, init, error);
+       return -EINVAL;
 }
 
 int line_config(struct line *lines, unsigned int num, char *str,
                const struct chan_opts *opts, char **error_out)
 {
-       struct line *line;
-       char *new;
+       char *end;
        int n;
 
        if (*str == '=') {
@@ -579,17 +574,17 @@ int line_config(struct line *lines, unsigned int num, char *str,
                return -EINVAL;
        }
 
-       new = kstrdup(str, GFP_KERNEL);
-       if (new == NULL) {
-               *error_out = "Failed to allocate memory";
-               return -ENOMEM;
+       n = simple_strtoul(str, &end, 0);
+       if (*end++ != '=') {
+               *error_out = "Couldn't parse device number";
+               return -EINVAL;
+       }
+       if (n >= num) {
+               *error_out = "Device number out of range";
+               return -EINVAL;
        }
-       n = line_setup(lines, num, new, error_out);
-       if (n < 0)
-               return n;
 
-       line = &lines[n];
-       return parse_chan_pair(line->init_str, line, n, opts, error_out);
+       return setup_one_line(lines, n, end, opts, error_out);
 }
 
 int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
@@ -612,13 +607,13 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
 
        line = &lines[dev];
 
-       spin_lock(&line->count_lock);
+       mutex_lock(&line->count_lock);
        if (!line->valid)
                CONFIG_CHUNK(str, size, n, "none", 1);
        else if (line->tty == NULL)
                CONFIG_CHUNK(str, size, n, line->init_str, 1);
-       else n = chan_config_string(&line->chan_list, str, size, error_out);
-       spin_unlock(&line->count_lock);
+       else n = chan_config_string(line, str, size, error_out);
+       mutex_unlock(&line->count_lock);
 
        return n;
 }
@@ -640,25 +635,23 @@ int line_id(char **str, int *start_out, int *end_out)
 
 int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
 {
-       int err;
-       char config[sizeof("conxxxx=none\0")];
-
-       sprintf(config, "%d=none", n);
-       err = line_setup(lines, num, config, error_out);
-       if (err >= 0)
-               err = 0;
-       return err;
+       if (n >= num) {
+               *error_out = "Device number out of range";
+               return -EINVAL;
+       }
+       return setup_one_line(lines, n, "none", NULL, error_out);
 }
 
-struct tty_driver *register_lines(struct line_driver *line_driver,
-                                 const struct tty_operations *ops,
-                                 struct line *lines, int nlines)
+int register_lines(struct line_driver *line_driver,
+                  const struct tty_operations *ops,
+                  struct line *lines, int nlines)
 {
-       int i;
        struct tty_driver *driver = alloc_tty_driver(nlines);
+       int err;
+       int i;
 
        if (!driver)
-               return NULL;
+               return -ENOMEM;
 
        driver->driver_name = line_driver->name;
        driver->name = line_driver->device_name;
@@ -666,54 +659,33 @@ struct tty_driver *register_lines(struct line_driver *line_driver,
        driver->minor_start = line_driver->minor_start;
        driver->type = line_driver->type;
        driver->subtype = line_driver->subtype;
-       driver->flags = TTY_DRIVER_REAL_RAW;
+       driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        driver->init_termios = tty_std_termios;
+       
+       for (i = 0; i < nlines; i++) {
+               spin_lock_init(&lines[i].lock);
+               mutex_init(&lines[i].count_lock);
+               lines[i].driver = line_driver;
+               INIT_LIST_HEAD(&lines[i].chan_list);
+       }
        tty_set_operations(driver, ops);
 
-       if (tty_register_driver(driver)) {
+       err = tty_register_driver(driver);
+       if (err) {
                printk(KERN_ERR "register_lines : can't register %s driver\n",
                       line_driver->name);
                put_tty_driver(driver);
-               return NULL;
-       }
-
-       for(i = 0; i < nlines; i++) {
-               if (!lines[i].valid)
-                       tty_unregister_device(driver, i);
+               return err;
        }
 
+       line_driver->driver = driver;
        mconsole_register_dev(&line_driver->mc);
-       return driver;
+       return 0;
 }
 
 static DEFINE_SPINLOCK(winch_handler_lock);
 static LIST_HEAD(winch_handlers);
 
-void lines_init(struct line *lines, int nlines, struct chan_opts *opts)
-{
-       struct line *line;
-       char *error;
-       int i;
-
-       for(i = 0; i < nlines; i++) {
-               line = &lines[i];
-               INIT_LIST_HEAD(&line->chan_list);
-
-               if (line->init_str == NULL)
-                       continue;
-
-               line->init_str = kstrdup(line->init_str, GFP_KERNEL);
-               if (line->init_str == NULL)
-                       printk(KERN_ERR "lines_init - kstrdup returned NULL\n");
-
-               if (parse_chan_pair(line->init_str, line, i, opts, &error)) {
-                       printk(KERN_ERR "parse_chan_pair failed for "
-                              "device %d : %s\n", i, error);
-                       line->valid = 0;
-               }
-       }
-}
-
 struct winch {
        struct list_head list;
        int fd;
@@ -777,7 +749,7 @@ static irqreturn_t winch_interrupt(int irq, void *data)
        if (tty != NULL) {
                line = tty->driver_data;
                if (line != NULL) {
-                       chan_window_size(&line->chan_list, &tty->winsize.ws_row,
+                       chan_window_size(line, &tty->winsize.ws_row,
                                         &tty->winsize.ws_col);
                        kill_pgrp(tty->pgrp, SIGWINCH, 1);
                }
@@ -807,7 +779,7 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty,
                                   .stack       = stack });
 
        if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
-                          IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+                          IRQF_SHARED | IRQF_SAMPLE_RANDOM,
                           "winch", winch) < 0) {
                printk(KERN_ERR "register_winch_irq - failed to register "
                       "IRQ\n");
index 63df3ca..0a18347 100644 (file)
@@ -15,7 +15,7 @@
 #include "chan_user.h"
 #include "mconsole_kern.h"
 
-/* There's only one modifiable field in this - .mc.list */
+/* There's only two modifiable fields in this - .mc.list and .driver */
 struct line_driver {
        const char *name;
        const char *device_name;
@@ -28,17 +28,18 @@ struct line_driver {
        const int write_irq;
        const char *write_irq_name;
        struct mc_device mc;
+       struct tty_driver *driver;
 };
 
 struct line {
        struct tty_struct *tty;
-       spinlock_t count_lock;
+       struct mutex count_lock;
        unsigned long count;
        int valid;
 
        char *init_str;
-       int init_pri;
        struct list_head chan_list;
+       struct chan *chan_in, *chan_out;
 
        /*This lock is actually, mostly, local to*/
        spinlock_t lock;
@@ -55,21 +56,12 @@ struct line {
        int sigio;
        struct delayed_work task;
        const struct line_driver *driver;
-       int have_irq;
 };
 
-#define LINE_INIT(str, d) \
-       { .count_lock = __SPIN_LOCK_UNLOCKED((str).count_lock), \
-         .init_str =   str,    \
-         .init_pri =   INIT_STATIC, \
-         .valid =      1, \
-         .lock =       __SPIN_LOCK_UNLOCKED((str).lock), \
-         .driver =     d }
-
 extern void line_close(struct tty_struct *tty, struct file * filp);
 extern int line_open(struct line *lines, struct tty_struct *tty);
-extern int line_setup(struct line *lines, unsigned int sizeof_lines,
-                     char *init, char **error_out);
+extern int line_setup(char **conf, unsigned nlines, char **def,
+                     char *init, char *name);
 extern int line_write(struct tty_struct *tty, const unsigned char *buf,
                      int len);
 extern int line_put_char(struct tty_struct *tty, unsigned char ch);
@@ -87,10 +79,11 @@ extern char *add_xterm_umid(char *base);
 extern int line_setup_irq(int fd, int input, int output, struct line *line,
                          void *data);
 extern void line_close_chan(struct line *line);
-extern struct tty_driver *register_lines(struct line_driver *line_driver,
-                                        const struct tty_operations *driver,
-                                        struct line *lines, int nlines);
-extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts);
+extern int register_lines(struct line_driver *line_driver,
+                         const struct tty_operations *driver,
+                         struct line *lines, int nlines);
+extern int setup_one_line(struct line *lines, int n, char *init,
+                         const struct chan_opts *opts, char **error_out);
 extern void close_lines(struct line *lines, int nlines);
 
 extern int line_config(struct line *lines, unsigned int sizeof_lines,
index c70e047..e672bd6 100644 (file)
@@ -773,7 +773,7 @@ static int __init mconsole_init(void)
        register_reboot_notifier(&reboot_notifier);
 
        err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
-                            IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+                            IRQF_SHARED | IRQF_SAMPLE_RANDOM,
                             "mconsole", (void *)sock);
        if (err) {
                printk(KERN_ERR "Failed to get IRQ for management console\n");
index d299618..95f4416 100644 (file)
@@ -161,7 +161,7 @@ static int uml_net_open(struct net_device *dev)
        }
 
        err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,
-                            IRQF_DISABLED | IRQF_SHARED, dev->name, dev);
+                            IRQF_SHARED, dev->name, dev);
        if (err != 0) {
                printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);
                err = -ENETUNREACH;
index a11573b..e31680e 100644 (file)
@@ -100,7 +100,7 @@ static int port_accept(struct port_list *port)
                  .port         = port });
 
        if (um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt,
-                         IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+                         IRQF_SHARED | IRQF_SAMPLE_RANDOM,
                          "telnetd", conn)) {
                printk(KERN_ERR "port_accept : failed to get IRQ for "
                       "telnetd\n");
@@ -184,7 +184,7 @@ void *port_data(int port_num)
        }
 
        if (um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt,
-                         IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+                         IRQF_SHARED | IRQF_SAMPLE_RANDOM,
                          "port", port)) {
                printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
                goto out_close;
index 981085a..b25296e 100644 (file)
@@ -131,7 +131,7 @@ static int __init rng_init (void)
        random_fd = err;
 
        err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt,
-                            IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "random",
+                            IRQF_SAMPLE_RANDOM, "random",
                             NULL);
        if (err)
                goto err_out_cleanup_hw;
index 9d8c20a..e09801a 100644 (file)
 
 static const int ssl_version = 1;
 
-/* Referenced only by tty_driver below - presumably it's locked correctly
- * by the tty driver.
- */
-
-static struct tty_driver *ssl_driver;
-
 #define NR_PORTS 64
 
 static void ssl_announce(char *dev_name, int dev)
@@ -71,8 +65,9 @@ static struct line_driver driver = {
 /* The array is initialized by line_init, at initcall time.  The
  * elements are locked individually as needed.
  */
-static struct line serial_lines[NR_PORTS] =
-       { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) };
+static char *conf[NR_PORTS];
+static char *def_conf = CONFIG_SSL_CHAN;
+static struct line serial_lines[NR_PORTS];
 
 static int ssl_config(char *str, char **error_out)
 {
@@ -156,14 +151,14 @@ static void ssl_console_write(struct console *c, const char *string,
        unsigned long flags;
 
        spin_lock_irqsave(&line->lock, flags);
-       console_write_chan(&line->chan_list, string, len);
+       console_write_chan(line->chan_out, string, len);
        spin_unlock_irqrestore(&line->lock, flags);
 }
 
 static struct tty_driver *ssl_console_device(struct console *c, int *index)
 {
        *index = c->index;
-       return ssl_driver;
+       return driver.driver;
 }
 
 static int ssl_console_setup(struct console *co, char *options)
@@ -186,17 +181,30 @@ static struct console ssl_cons = {
 static int ssl_init(void)
 {
        char *new_title;
+       int err;
+       int i;
 
        printk(KERN_INFO "Initializing software serial port version %d\n",
               ssl_version);
-       ssl_driver = register_lines(&driver, &ssl_ops, serial_lines,
+
+       err = register_lines(&driver, &ssl_ops, serial_lines,
                                    ARRAY_SIZE(serial_lines));
+       if (err)
+               return err;
 
        new_title = add_xterm_umid(opts.xterm_title);
        if (new_title != NULL)
                opts.xterm_title = new_title;
 
-       lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts);
+       for (i = 0; i < NR_PORTS; i++) {
+               char *error;
+               char *s = conf[i];
+               if (!s)
+                       s = def_conf;
+               if (setup_one_line(serial_lines, i, s, &opts, &error))
+                       printk(KERN_ERR "setup_one_line failed for "
+                              "device %d : %s\n", i, error);
+       }
 
        ssl_init_done = 1;
        register_console(&ssl_cons);
@@ -214,14 +222,7 @@ __uml_exitcall(ssl_exit);
 
 static int ssl_chan_setup(char *str)
 {
-       char *error;
-       int ret;
-
-       ret = line_setup(serial_lines, ARRAY_SIZE(serial_lines), str, &error);
-       if(ret < 0)
-               printk(KERN_ERR "Failed to set up serial line with "
-                      "configuration string \"%s\" : %s\n", str, error);
-
+       line_setup(conf, NR_PORTS, &def_conf, str, "serial line");
        return 1;
 }
 
index 088776f..7663541 100644 (file)
 
 #define MAX_TTYS (16)
 
-/* Referenced only by tty_driver below - presumably it's locked correctly
- * by the tty driver.
- */
-
-static struct tty_driver *console_driver;
-
 static void stdio_announce(char *dev_name, int dev)
 {
        printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
@@ -76,9 +70,9 @@ static struct line_driver driver = {
 /* The array is initialized by line_init, at initcall time.  The
  * elements are locked individually as needed.
  */
-static struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
-                                    [ 1 ... MAX_TTYS - 1 ] =
-                                    LINE_INIT(CONFIG_CON_CHAN, &driver) };
+static char *vt_conf[MAX_TTYS];
+static char *def_conf;
+static struct line vts[MAX_TTYS];
 
 static int con_config(char *str, char **error_out)
 {
@@ -130,14 +124,14 @@ static void uml_console_write(struct console *console, const char *string,
        unsigned long flags;
 
        spin_lock_irqsave(&line->lock, flags);
-       console_write_chan(&line->chan_list, string, len);
+       console_write_chan(line->chan_out, string, len);
        spin_unlock_irqrestore(&line->lock, flags);
 }
 
 static struct tty_driver *uml_console_device(struct console *c, int *index)
 {
        *index = c->index;
-       return console_driver;
+       return driver.driver;
 }
 
 static int uml_console_setup(struct console *co, char *options)
@@ -160,18 +154,31 @@ static struct console stdiocons = {
 static int stdio_init(void)
 {
        char *new_title;
+       int err;
+       int i;
 
-       console_driver = register_lines(&driver, &console_ops, vts,
+       err = register_lines(&driver, &console_ops, vts,
                                        ARRAY_SIZE(vts));
-       if (console_driver == NULL)
-               return -1;
+       if (err)
+               return err;
+
        printk(KERN_INFO "Initialized stdio console driver\n");
 
        new_title = add_xterm_umid(opts.xterm_title);
        if(new_title != NULL)
                opts.xterm_title = new_title;
 
-       lines_init(vts, ARRAY_SIZE(vts), &opts);
+       for (i = 0; i < MAX_TTYS; i++) {
+               char *error;
+               char *s = vt_conf[i];
+               if (!s)
+                       s = def_conf;
+               if (!s)
+                       s = i ? CONFIG_CON_CHAN : CONFIG_CON_ZERO_CHAN;
+               if (setup_one_line(vts, i, s, &opts, &error))
+                       printk(KERN_ERR "setup_one_line failed for "
+                              "device %d : %s\n", i, error);
+       }
 
        con_init_done = 1;
        register_console(&stdiocons);
@@ -189,14 +196,7 @@ __uml_exitcall(console_exit);
 
 static int console_chan_setup(char *str)
 {
-       char *error;
-       int ret;
-
-       ret = line_setup(vts, ARRAY_SIZE(vts), str, &error);
-       if(ret < 0)
-               printk(KERN_ERR "Failed to set up console with "
-                      "configuration string \"%s\" : %s\n", str, error);
-
+       line_setup(vt_conf, MAX_TTYS, &def_conf, str, "console");
        return 1;
 }
 __setup("con", console_chan_setup);
diff --git a/arch/um/drivers/ubd.h b/arch/um/drivers/ubd.h
new file mode 100644 (file)
index 0000000..3845051
--- /dev/null
@@ -0,0 +1,16 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_UBD_USER_H
+#define __UM_UBD_USER_H
+
+extern void ignore_sigwinch_sig(void);
+extern int start_io_thread(unsigned long sp, int *fds_out);
+extern int io_thread(void *arg);
+extern int kernel_fd;
+
+#endif
+
index 944453a..20505ca 100644 (file)
 
 #define UBD_SHIFT 4
 
-#include "linux/kernel.h"
-#include "linux/module.h"
-#include "linux/blkdev.h"
-#include "linux/ata.h"
-#include "linux/hdreg.h"
-#include "linux/init.h"
-#include "linux/cdrom.h"
-#include "linux/proc_fs.h"
-#include "linux/seq_file.h"
-#include "linux/ctype.h"
-#include "linux/capability.h"
-#include "linux/mm.h"
-#include "linux/slab.h"
-#include "linux/vmalloc.h"
-#include "linux/mutex.h"
-#include "linux/blkpg.h"
-#include "linux/genhd.h"
-#include "linux/spinlock.h"
-#include "linux/platform_device.h"
-#include "linux/scatterlist.h"
-#include "asm/segment.h"
-#include "asm/uaccess.h"
-#include "asm/irq.h"
-#include "asm/types.h"
-#include "asm/tlbflush.h"
-#include "mem_user.h"
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/ata.h>
+#include <linux/hdreg.h>
+#include <linux/cdrom.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <asm/tlbflush.h>
 #include "kern_util.h"
 #include "mconsole_kern.h"
 #include "init.h"
-#include "irq_user.h"
 #include "irq_kern.h"
-#include "ubd_user.h"
+#include "ubd.h"
 #include "os.h"
-#include "mem.h"
 #include "cow.h"
 
 enum ubd_req { UBD_READ, UBD_WRITE };
@@ -1115,7 +1101,7 @@ static int __init ubd_driver_init(void){
                return 0;
        }
        err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
-                            IRQF_DISABLED, "ubd", ubd_devs);
+                            0, "ubd", ubd_devs);
        if(err != 0)
                printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
        return 0;
index 007b94d..ffe02c4 100644 (file)
 #include <sys/socket.h>
 #include <sys/mman.h>
 #include <sys/param.h>
-#include "asm/types.h"
-#include "ubd_user.h"
-#include "os.h"
-#include "cow.h"
-
 #include <endian.h>
 #include <byteswap.h>
 
+#include "ubd.h"
+#include "os.h"
+
 void ignore_sigwinch_sig(void)
 {
        signal(SIGWINCH, SIG_IGN);
diff --git a/arch/um/drivers/ubd_user.h b/arch/um/drivers/ubd_user.h
deleted file mode 100644 (file)
index 3845051..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* 
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
- * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com)
- * Licensed under the GPL
- */
-
-#ifndef __UM_UBD_USER_H
-#define __UM_UBD_USER_H
-
-extern void ignore_sigwinch_sig(void);
-extern int start_io_thread(unsigned long sp, int *fds_out);
-extern int io_thread(void *arg);
-extern int kernel_fd;
-
-#endif
-
index b646bcc..8bd130f 100644 (file)
@@ -50,7 +50,7 @@ int xterm_fd(int socket, int *pid_out)
        init_completion(&data->ready);
 
        err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt,
-                            IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+                            IRQF_SHARED | IRQF_SAMPLE_RANDOM,
                             "xterm", data);
        if (err) {
                printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
index 451f451..8419f5c 100644 (file)
@@ -1,3 +1,3 @@
 generic-y += bug.h cputime.h device.h emergency-restart.h futex.h hardirq.h
 generic-y += hw_irq.h irq_regs.h kdebug.h percpu.h sections.h topology.h xor.h
-generic-y += ftrace.h
+generic-y += ftrace.h pci.h io.h param.h delay.h mutex.h current.h
diff --git a/arch/um/include/asm/asm-offsets.h b/arch/um/include/asm/asm-offsets.h
deleted file mode 100644 (file)
index d370ee3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <generated/asm-offsets.h>
diff --git a/arch/um/include/asm/auxvec.h b/arch/um/include/asm/auxvec.h
deleted file mode 100644 (file)
index 1e5e1c2..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef __UM_AUXVEC_H
-#define __UM_AUXVEC_H
-
-#endif
diff --git a/arch/um/include/asm/current.h b/arch/um/include/asm/current.h
deleted file mode 100644 (file)
index c2191d9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#ifndef __UM_CURRENT_H
-#define __UM_CURRENT_H
-
-#include "linux/thread_info.h"
-
-#define current (current_thread_info()->task)
-
-#endif
diff --git a/arch/um/include/asm/delay.h b/arch/um/include/asm/delay.h
deleted file mode 100644 (file)
index 8a5576d..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef __UM_DELAY_H
-#define __UM_DELAY_H
-
-/* Undefined on purpose */
-extern void __bad_udelay(void);
-extern void __bad_ndelay(void);
-
-extern void __udelay(unsigned long usecs);
-extern void __ndelay(unsigned long usecs);
-extern void __delay(unsigned long loops);
-
-#define udelay(n) ((__builtin_constant_p(n) && (n) > 20000) ? \
-       __bad_udelay() : __udelay(n))
-
-#define ndelay(n) ((__builtin_constant_p(n) && (n) > 20000) ? \
-       __bad_ndelay() : __ndelay(n))
-
-#endif
diff --git a/arch/um/include/asm/io.h b/arch/um/include/asm/io.h
deleted file mode 100644 (file)
index 44e8b8c..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef __UM_IO_H
-#define __UM_IO_H
-
-#include "asm/page.h"
-
-#define IO_SPACE_LIMIT 0xdeadbeef /* Sure hope nothing uses this */
-
-static inline int inb(unsigned long i) { return(0); }
-static inline void outb(char c, unsigned long i) { }
-
-/*
- * Change virtual addresses to physical addresses and vv.
- * These are pretty trivial
- */
-static inline unsigned long virt_to_phys(volatile void * address)
-{
-       return __pa((void *) address);
-}
-
-static inline void * phys_to_virt(unsigned long address)
-{
-       return __va(address);
-}
-
-/*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p)   __va(p)
-
-/*
- * Convert a virtual cached pointer to an uncached pointer
- */
-#define xlate_dev_kmem_ptr(p)  p
-
-static inline void writeb(unsigned char b, volatile void __iomem *addr)
-{
-       *(volatile unsigned char __force *) addr = b;
-}
-static inline void writew(unsigned short b, volatile void __iomem *addr)
-{
-       *(volatile unsigned short __force *) addr = b;
-}
-static inline void writel(unsigned int b, volatile void __iomem *addr)
-{
-       *(volatile unsigned int __force *) addr = b;
-}
-static inline void writeq(unsigned int b, volatile void __iomem *addr)
-{
-       *(volatile unsigned long long __force *) addr = b;
-}
-#define __raw_writeb writeb
-#define __raw_writew writew
-#define __raw_writel writel
-#define __raw_writeq writeq
-
-#endif
diff --git a/arch/um/include/asm/mutex.h b/arch/um/include/asm/mutex.h
deleted file mode 100644 (file)
index 458c1f7..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Pull in the generic implementation for the mutex fastpath.
- *
- * TODO: implement optimized primitives instead, or leave the generic
- * implementation in place, or pick the atomic_xchg() based generic
- * implementation. (see asm-generic/mutex-xchg.h for details)
- */
-
-#include <asm-generic/mutex-dec.h>
diff --git a/arch/um/include/asm/param.h b/arch/um/include/asm/param.h
deleted file mode 100644 (file)
index e44f4e6..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _UM_PARAM_H
-#define _UM_PARAM_H
-
-#define EXEC_PAGESIZE   4096
-
-#ifndef NOGROUP
-#define NOGROUP         (-1)
-#endif
-
-#define MAXHOSTNAMELEN  64      /* max length of hostname */
-
-#ifdef __KERNEL__
-#define HZ CONFIG_HZ
-#define USER_HZ        100        /* .. some user interfaces are in "ticks" */
-#define CLOCKS_PER_SEC (USER_HZ)  /* frequency at which times() counts */
-#else
-#define HZ 100
-#endif
-
-#endif
diff --git a/arch/um/include/asm/pci.h b/arch/um/include/asm/pci.h
deleted file mode 100644 (file)
index b44cf59..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __UM_PCI_H
-#define __UM_PCI_H
-
-#define PCI_DMA_BUS_IS_PHYS     (1)
-
-#endif
index 32c8ce4..bf90b2a 100644 (file)
@@ -8,8 +8,7 @@
 #ifndef __UM_PGALLOC_H
 #define __UM_PGALLOC_H
 
-#include "linux/mm.h"
-#include "asm/fixmap.h"
+#include <linux/mm.h>
 
 #define pmd_populate_kernel(mm, pmd, pte) \
        set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte)))
index 41474fb..6a3f984 100644 (file)
@@ -69,6 +69,8 @@ extern unsigned long end_iomem;
 #define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
 #define PAGE_KERNEL_EXEC       __pgprot(__PAGE_KERNEL_EXEC)
 
+#define io_remap_pfn_range     remap_pfn_range
+
 /*
  * The i386 can't do page protection for execute, and considers that the same
  * are read.
index f605d3c..e786a6a 100644 (file)
@@ -9,7 +9,6 @@
 #ifndef __ASSEMBLY__
 
 #include <asm/ptrace-abi.h>
-#include <asm/user.h>
 #include "sysdep/ptrace.h"
 
 struct pt_regs {
index d7fe563..40db8f7 100644 (file)
@@ -2,8 +2,6 @@
 
 DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
 
-OFFSET(HOST_TASK_PID, task_struct, pid);
-
 DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE);
 DEFINE(UM_KERN_PAGE_MASK, PAGE_MASK);
 DEFINE(UM_KERN_PAGE_SHIFT, PAGE_SHIFT);
index 0f14838..00965d0 100644 (file)
@@ -48,7 +48,7 @@ extern void do_uml_exitcalls(void);
  * GFP_ATOMIC.
  */
 extern int __cant_sleep(void);
-extern void *get_current(void);
+extern int get_current_pid(void);
 extern int copy_from_user_proc(void *to, void *from, int size);
 extern int cpu(void);
 extern char *uml_strdup(const char *string);
index bc49474..492bc4c 100644 (file)
@@ -3,7 +3,7 @@
 # Licensed under the GPL
 #
 
-CPPFLAGS_vmlinux.lds := -U$(SUBARCH) -DSTART=$(LDS_START) \
+CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START) \
                         -DELF_ARCH=$(LDS_ELF_ARCH)        \
                         -DELF_FORMAT=$(LDS_ELF_FORMAT)
 extra-y := vmlinux.lds
index 69f2490..f386d04 100644 (file)
@@ -126,9 +126,9 @@ void exit_thread(void)
 {
 }
 
-void *get_current(void)
+int get_current_pid(void)
 {
-       return current;
+       return task_pid_nr(current);
 }
 
 /*
index 2b272b6..2a16392 100644 (file)
@@ -25,7 +25,7 @@ int write_sigio_irq(int fd)
        int err;
 
        err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
-                            IRQF_DISABLED|IRQF_SAMPLE_RANDOM, "write sigio",
+                            IRQF_SAMPLE_RANDOM, "write sigio",
                             NULL);
        if (err) {
                printk(KERN_ERR "write_sigio_irq : um_request_irq failed, "
index e8b889d..fb12f4c 100644 (file)
@@ -65,21 +65,10 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
 #endif
                err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset);
 
-       if (err) {
-               spin_lock_irq(&current->sighand->siglock);
-               current->blocked = *oldset;
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
+       if (err)
                force_sigsegv(signr, current);
-       } else {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked, &current->blocked,
-                         &ka->sa.sa_mask);
-               if (!(ka->sa.sa_flags & SA_NODEFER))
-                       sigaddset(&current->blocked, signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       else
+               block_sigmask(ka, signr);
 
        return err;
 }
@@ -162,12 +151,11 @@ int do_signal(void)
  */
 long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
 {
+       sigset_t blocked;
+
        mask &= _BLOCKABLE;
-       spin_lock_irq(&current->sighand->siglock);
-       current->saved_sigmask = current->blocked;
-       siginitset(&current->blocked, mask);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       siginitset(&blocked, mask);
+       set_current_blocked(&blocked);
 
        current->state = TASK_INTERRUPTIBLE;
        schedule();
index 82a6e22..d1a23fb 100644 (file)
@@ -82,7 +82,7 @@ static void __init setup_itimer(void)
 {
        int err;
 
-       err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL);
+       err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL);
        if (err != 0)
                printk(KERN_ERR "register_timer : request_irq failed - "
                       "errno = %d\n", -err);
index dd76410..08ff509 100644 (file)
@@ -13,8 +13,6 @@ USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \
        main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \
        tty.o umid.o util.o
 
-CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
-
 HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \
        echo -DHAVE_AIO_ABI )
 CFLAGS_aio.o += $(HAVE_AIO_ABI)
index 45ffe46..73926fa 100644 (file)
@@ -45,7 +45,7 @@ EXPORT_SYMBOL(readdir64);
 extern void truncate64(void) __attribute__((weak));
 EXPORT_SYMBOL(truncate64);
 
-#ifdef SUBARCH_i386
+#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
 EXPORT_SYMBOL(vsyscall_ehdr);
 EXPORT_SYMBOL(vsyscall_end);
 #endif
index 2eb2843..d50270d 100644 (file)
@@ -9,8 +9,6 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
 
 $(USER_OBJS:.o=.%): \
        c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) -include user.h $(CFLAGS_$(basetarget).o)
-$(USER_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \
-       -Dunix -D__unix__ -D__$(SUBARCH)__ $(CF)
 
 # These are like USER_OBJS but filter USER_CFLAGS through unprofile instead of
 # using it directly.
@@ -18,8 +16,9 @@ UNPROFILE_OBJS := $(foreach file,$(UNPROFILE_OBJS),$(obj)/$(file))
 
 $(UNPROFILE_OBJS:.o=.%): \
        c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) $(CFLAGS_$(basetarget).o)
-$(UNPROFILE_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \
-       -Dunix -D__unix__ -D__$(SUBARCH)__ $(CF)
+
+$(USER_OBJS) $(UNPROFILE_OBJS): \
+       CHECKFLAGS := $(patsubst $(NOSTDINC_FLAGS),,$(CHECKFLAGS))
 
 # The stubs can't try to call mcount or update basic block data
 define unprofile
index dd38677..f5e108f 100644 (file)
@@ -14,6 +14,7 @@
 
 #ifdef __KERNEL__
 #include <asm-generic/pci-dma-compat.h>
+#include <asm-generic/pci-bridge.h>
 #include <asm-generic/pci.h>
 #include <mach/hardware.h> /* for PCIBIOS_MIN_* */
 
index a8f07fe..2fc2b1b 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/io.h>
 
 static int debug_pci;
-static int use_firmware;
 
 #define CONFIG_CMD(bus, devfn, where)  \
        (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
@@ -276,7 +275,7 @@ static int __init pci_common_init(void)
 
        pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq);
 
-       if (!use_firmware) {
+       if (!pci_has_flag(PCI_PROBE_ONLY)) {
                /*
                 * Size the bridge windows.
                 */
@@ -303,7 +302,7 @@ char * __devinit pcibios_setup(char *str)
                debug_pci = 1;
                return NULL;
        } else if (!strcmp(str, "firmware")) {
-               use_firmware = 1;
+               pci_add_flags(PCI_PROBE_ONLY);
                return NULL;
        }
        return str;
index 1b3f152..b6f0458 100644 (file)
@@ -380,7 +380,7 @@ int vectors_user_mapping(void)
        return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,
                                       VM_READ | VM_EXEC |
                                       VM_MAYREAD | VM_MAYEXEC |
-                                      VM_ALWAYSDUMP | VM_RESERVED,
+                                      VM_RESERVED,
                                       NULL);
 }
 
index 9019523..3ad653d 100644 (file)
@@ -2125,6 +2125,13 @@ config NET5501
        ---help---
          This option enables system support for the Soekris Engineering net5501.
 
+config GEOS
+       bool "Traverse Technologies GEOS System Support (LEDS, GPIO, etc)"
+       select GPIOLIB
+       depends on DMI
+       ---help---
+         This option enables system support for the Traverse Technologies GEOS.
+
 endif # X86_32
 
 config AMD_NB
index 36ddec6..4be406a 100644 (file)
@@ -8,15 +8,11 @@ ELF_ARCH              := i386
 ELF_FORMAT             := elf32-i386
 CHECKFLAGS     += -D__i386__
 
-ifeq ("$(origin SUBARCH)", "command line")
-ifneq ("$(shell uname -m | sed -e s/i.86/i386/)", "$(SUBARCH)")
 KBUILD_CFLAGS          += $(call cc-option,-m32)
 KBUILD_AFLAGS          += $(call cc-option,-m32)
 LINK-y                 += $(call cc-option,-m32)
 
 export LDFLAGS
-endif
-endif
 
 # First of all, tune CFLAGS for the specific CPU. This actually sets cflags-y.
 include $(srctree)/arch/x86/Makefile_32.cpu
index 3e02148..5a747dd 100644 (file)
@@ -37,9 +37,9 @@ setup-y               += video-bios.o
 targets                += $(setup-y)
 hostprogs-y    := mkcpustr tools/build
 
-HOSTCFLAGS_mkcpustr.o := -I$(srctree)/arch/$(SRCARCH)/include
-HOST_EXTRACFLAGS += -I$(objtree)/include -I$(srctree)/tools/include \
-                   -include $(srctree)/include/linux/kconfig.h
+HOST_EXTRACFLAGS += -I$(srctree)/tools/include $(LINUXINCLUDE) \
+                   -D__EXPORTED_HEADERS__
+
 $(obj)/cpu.o: $(obj)/cpustr.h
 
 quiet_cmd_cpustr = CPUSTR  $@
index b903d5e..2d91580 100644 (file)
  */
 #ifdef __KERNEL__
 
+#include <linux/bug.h>
+
 DECLARE_PER_CPU(unsigned long, cpu_dr7);
 
+#ifndef CONFIG_PARAVIRT
+/*
+ * These special macros can be used to get or set a debugging register
+ */
+#define get_debugreg(var, register)                            \
+       (var) = native_get_debugreg(register)
+#define set_debugreg(value, register)                          \
+       native_set_debugreg(register, value)
+#endif
+
+static inline unsigned long native_get_debugreg(int regno)
+{
+       unsigned long val = 0;  /* Damn you, gcc! */
+
+       switch (regno) {
+       case 0:
+               asm("mov %%db0, %0" :"=r" (val));
+               break;
+       case 1:
+               asm("mov %%db1, %0" :"=r" (val));
+               break;
+       case 2:
+               asm("mov %%db2, %0" :"=r" (val));
+               break;
+       case 3:
+               asm("mov %%db3, %0" :"=r" (val));
+               break;
+       case 6:
+               asm("mov %%db6, %0" :"=r" (val));
+               break;
+       case 7:
+               asm("mov %%db7, %0" :"=r" (val));
+               break;
+       default:
+               BUG();
+       }
+       return val;
+}
+
+static inline void native_set_debugreg(int regno, unsigned long value)
+{
+       switch (regno) {
+       case 0:
+               asm("mov %0, %%db0"     ::"r" (value));
+               break;
+       case 1:
+               asm("mov %0, %%db1"     ::"r" (value));
+               break;
+       case 2:
+               asm("mov %0, %%db2"     ::"r" (value));
+               break;
+       case 3:
+               asm("mov %0, %%db3"     ::"r" (value));
+               break;
+       case 6:
+               asm("mov %0, %%db6"     ::"r" (value));
+               break;
+       case 7:
+               asm("mov %0, %%db7"     ::"r" (value));
+               break;
+       default:
+               BUG();
+       }
+}
+
 static inline void hw_breakpoint_disable(void)
 {
        /* Zero the control register for HW Breakpoint */
index 77e95f5..332f98c 100644 (file)
@@ -64,11 +64,15 @@ enum regnames {
        GDB_PS,                 /* 17 */
        GDB_CS,                 /* 18 */
        GDB_SS,                 /* 19 */
+       GDB_DS,                 /* 20 */
+       GDB_ES,                 /* 21 */
+       GDB_FS,                 /* 22 */
+       GDB_GS,                 /* 23 */
 };
 #define GDB_ORIG_AX            57
-#define DBG_MAX_REG_NUM                20
-/* 17 64 bit regs and 3 32 bit regs */
-#define NUMREGBYTES            ((17 * 8) + (3 * 4))
+#define DBG_MAX_REG_NUM                24
+/* 17 64 bit regs and 5 32 bit regs */
+#define NUMREGBYTES            ((17 * 8) + (5 * 4))
 #endif /* ! CONFIG_X86_32 */
 
 static inline void arch_kgdb_breakpoint(void)
index 4d8dcbd..e7d1c19 100644 (file)
@@ -321,4 +321,8 @@ struct kvm_xcrs {
        __u64 padding[16];
 };
 
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
+
 #endif /* _ASM_X86_KVM_H */
index 7b9cfc4..c222e1a 100644 (file)
@@ -176,6 +176,7 @@ struct x86_emulate_ops {
        void (*set_idt)(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt);
        ulong (*get_cr)(struct x86_emulate_ctxt *ctxt, int cr);
        int (*set_cr)(struct x86_emulate_ctxt *ctxt, int cr, ulong val);
+       void (*set_rflags)(struct x86_emulate_ctxt *ctxt, ulong val);
        int (*cpl)(struct x86_emulate_ctxt *ctxt);
        int (*get_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong *dest);
        int (*set_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong value);
@@ -388,7 +389,7 @@ bool x86_page_table_writing_insn(struct x86_emulate_ctxt *ctxt);
 #define EMULATION_INTERCEPTED 2
 int x86_emulate_insn(struct x86_emulate_ctxt *ctxt);
 int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
-                        u16 tss_selector, int reason,
+                        u16 tss_selector, int idt_index, int reason,
                         bool has_error_code, u32 error_code);
 int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq);
 #endif /* _ASM_X86_KVM_X86_EMULATE_H */
index 52d6640..e216ba0 100644 (file)
@@ -29,7 +29,7 @@
 #include <asm/msr-index.h>
 
 #define KVM_MAX_VCPUS 254
-#define KVM_SOFT_MAX_VCPUS 64
+#define KVM_SOFT_MAX_VCPUS 160
 #define KVM_MEMORY_SLOTS 32
 /* memory slots that does not exposed to userspace */
 #define KVM_PRIVATE_MEM_SLOTS 4
@@ -181,13 +181,6 @@ struct kvm_mmu_memory_cache {
        void *objects[KVM_NR_MEM_OBJS];
 };
 
-#define NR_PTE_CHAIN_ENTRIES 5
-
-struct kvm_pte_chain {
-       u64 *parent_ptes[NR_PTE_CHAIN_ENTRIES];
-       struct hlist_node link;
-};
-
 /*
  * kvm_mmu_page_role, below, is defined as:
  *
@@ -427,12 +420,16 @@ struct kvm_vcpu_arch {
 
        u64 last_guest_tsc;
        u64 last_kernel_ns;
-       u64 last_tsc_nsec;
-       u64 last_tsc_write;
-       u32 virtual_tsc_khz;
+       u64 last_host_tsc;
+       u64 tsc_offset_adjustment;
+       u64 this_tsc_nsec;
+       u64 this_tsc_write;
+       u8  this_tsc_generation;
        bool tsc_catchup;
-       u32  tsc_catchup_mult;
-       s8   tsc_catchup_shift;
+       bool tsc_always_catchup;
+       s8 virtual_tsc_shift;
+       u32 virtual_tsc_mult;
+       u32 virtual_tsc_khz;
 
        atomic_t nmi_queued;  /* unprocessed asynchronous NMIs */
        unsigned nmi_pending; /* NMI queued after currently running handler */
@@ -478,6 +475,21 @@ struct kvm_vcpu_arch {
                u32 id;
                bool send_user_only;
        } apf;
+
+       /* OSVW MSRs (AMD only) */
+       struct {
+               u64 length;
+               u64 status;
+       } osvw;
+};
+
+struct kvm_lpage_info {
+       unsigned long rmap_pde;
+       int write_count;
+};
+
+struct kvm_arch_memory_slot {
+       struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
 };
 
 struct kvm_arch {
@@ -511,8 +523,12 @@ struct kvm_arch {
        s64 kvmclock_offset;
        raw_spinlock_t tsc_write_lock;
        u64 last_tsc_nsec;
-       u64 last_tsc_offset;
        u64 last_tsc_write;
+       u32 last_tsc_khz;
+       u64 cur_tsc_nsec;
+       u64 cur_tsc_write;
+       u64 cur_tsc_offset;
+       u8  cur_tsc_generation;
 
        struct kvm_xen_hvm_config xen_hvm_config;
 
@@ -644,7 +660,7 @@ struct kvm_x86_ops {
        u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio);
        int (*get_lpage_level)(void);
        bool (*rdtscp_supported)(void);
-       void (*adjust_tsc_offset)(struct kvm_vcpu *vcpu, s64 adjustment);
+       void (*adjust_tsc_offset)(struct kvm_vcpu *vcpu, s64 adjustment, bool host);
 
        void (*set_tdp_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
 
@@ -652,7 +668,7 @@ struct kvm_x86_ops {
 
        bool (*has_wbinvd_exit)(void);
 
-       void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz);
+       void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale);
        void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
 
        u64 (*compute_tsc_offset)(struct kvm_vcpu *vcpu, u64 target_tsc);
@@ -674,6 +690,17 @@ struct kvm_arch_async_pf {
 
 extern struct kvm_x86_ops *kvm_x86_ops;
 
+static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
+                                          s64 adjustment)
+{
+       kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, false);
+}
+
+static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
+{
+       kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, true);
+}
+
 int kvm_mmu_module_init(void);
 void kvm_mmu_module_exit(void);
 
@@ -741,8 +768,8 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu);
 void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
 int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg);
 
-int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
-                   bool has_error_code, u32 error_code);
+int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
+                   int reason, bool has_error_code, u32 error_code);
 
 int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
 int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
index c0180fd..aa0f913 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/paravirt_types.h>
 
 #ifndef __ASSEMBLY__
+#include <linux/bug.h>
 #include <linux/types.h>
 #include <linux/cpumask.h>
 
index e8fb2c7..2291895 100644 (file)
@@ -23,6 +23,7 @@
 #define ARCH_PERFMON_EVENTSEL_USR                      (1ULL << 16)
 #define ARCH_PERFMON_EVENTSEL_OS                       (1ULL << 17)
 #define ARCH_PERFMON_EVENTSEL_EDGE                     (1ULL << 18)
+#define ARCH_PERFMON_EVENTSEL_PIN_CONTROL              (1ULL << 19)
 #define ARCH_PERFMON_EVENTSEL_INT                      (1ULL << 20)
 #define ARCH_PERFMON_EVENTSEL_ANY                      (1ULL << 21)
 #define ARCH_PERFMON_EVENTSEL_ENABLE                   (1ULL << 22)
index 78e30ea..a19542c 100644 (file)
@@ -484,61 +484,6 @@ struct thread_struct {
        unsigned                io_bitmap_max;
 };
 
-static inline unsigned long native_get_debugreg(int regno)
-{
-       unsigned long val = 0;  /* Damn you, gcc! */
-
-       switch (regno) {
-       case 0:
-               asm("mov %%db0, %0" :"=r" (val));
-               break;
-       case 1:
-               asm("mov %%db1, %0" :"=r" (val));
-               break;
-       case 2:
-               asm("mov %%db2, %0" :"=r" (val));
-               break;
-       case 3:
-               asm("mov %%db3, %0" :"=r" (val));
-               break;
-       case 6:
-               asm("mov %%db6, %0" :"=r" (val));
-               break;
-       case 7:
-               asm("mov %%db7, %0" :"=r" (val));
-               break;
-       default:
-               BUG();
-       }
-       return val;
-}
-
-static inline void native_set_debugreg(int regno, unsigned long value)
-{
-       switch (regno) {
-       case 0:
-               asm("mov %0, %%db0"     ::"r" (value));
-               break;
-       case 1:
-               asm("mov %0, %%db1"     ::"r" (value));
-               break;
-       case 2:
-               asm("mov %0, %%db2"     ::"r" (value));
-               break;
-       case 3:
-               asm("mov %0, %%db3"     ::"r" (value));
-               break;
-       case 6:
-               asm("mov %0, %%db6"     ::"r" (value));
-               break;
-       case 7:
-               asm("mov %0, %%db7"     ::"r" (value));
-               break;
-       default:
-               BUG();
-       }
-}
-
 /*
  * Set IOPL bits in EFLAGS from given mask
  */
@@ -584,14 +529,6 @@ static inline void native_swapgs(void)
 #define __cpuid                        native_cpuid
 #define paravirt_enabled()     0
 
-/*
- * These special macros can be used to get or set a debugging register
- */
-#define get_debugreg(var, register)                            \
-       (var) = native_get_debugreg(register)
-#define set_debugreg(value, register)                          \
-       native_set_debugreg(register, value)
-
 static inline void load_sp0(struct tss_struct *tss,
                            struct thread_struct *thread)
 {
index 15d9915..c91e8b9 100644 (file)
@@ -61,7 +61,7 @@ extern void check_tsc_sync_source(int cpu);
 extern void check_tsc_sync_target(void);
 
 extern int notsc_setup(char *);
-extern void save_sched_clock_state(void);
-extern void restore_sched_clock_state(void);
+extern void tsc_save_sched_clock_state(void);
+extern void tsc_restore_sched_clock_state(void);
 
 #endif /* _ASM_X86_TSC_H */
index 517d476..baaca8d 100644 (file)
@@ -145,9 +145,11 @@ struct x86_init_ops {
 /**
  * struct x86_cpuinit_ops - platform specific cpu hotplug setups
  * @setup_percpu_clockev:      set up the per cpu clock event device
+ * @early_percpu_clock_init:   early init of the per cpu clock event device
  */
 struct x86_cpuinit_ops {
        void (*setup_percpu_clockev)(void);
+       void (*early_percpu_clock_init)(void);
        void (*fixup_cpu_id)(struct cpuinfo_x86 *c, int node);
 };
 
@@ -160,6 +162,8 @@ struct x86_cpuinit_ops {
  * @is_untracked_pat_range     exclude from PAT logic
  * @nmi_init                   enable NMI on cpus
  * @i8042_detect               pre-detect if i8042 controller exists
+ * @save_sched_clock_state:    save state for sched_clock() on suspend
+ * @restore_sched_clock_state: restore state for sched_clock() on resume
  */
 struct x86_platform_ops {
        unsigned long (*calibrate_tsc)(void);
@@ -171,6 +175,8 @@ struct x86_platform_ops {
        void (*nmi_init)(void);
        unsigned char (*get_nmi_reason)(void);
        int (*i8042_detect)(void);
+       void (*save_sched_clock_state)(void);
+       void (*restore_sched_clock_state)(void);
 };
 
 struct pci_dev;
index ade9c79..e494774 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/archrandom.h>
 #include <asm/hypervisor.h>
 #include <asm/processor.h>
+#include <asm/debugreg.h>
 #include <asm/sections.h>
 #include <linux/topology.h>
 #include <linux/cpumask.h>
index 0a18d16..fa2900c 100644 (file)
@@ -643,14 +643,14 @@ static bool __perf_sched_find_counter(struct perf_sched *sched)
        /* Prefer fixed purpose counters */
        if (x86_pmu.num_counters_fixed) {
                idx = X86_PMC_IDX_FIXED;
-               for_each_set_bit_cont(idx, c->idxmsk, X86_PMC_IDX_MAX) {
+               for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) {
                        if (!__test_and_set_bit(idx, sched->state.used))
                                goto done;
                }
        }
        /* Grab the first unused counter starting with idx */
        idx = sched->state.counter;
-       for_each_set_bit_cont(idx, c->idxmsk, X86_PMC_IDX_FIXED) {
+       for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_FIXED) {
                if (!__test_and_set_bit(idx, sched->state.used))
                        goto done;
        }
index 79d97e6..7b784f4 100644 (file)
 #endif
 .endm
 
-#ifdef CONFIG_VM86
-#define resume_userspace_sig   check_userspace
-#else
-#define resume_userspace_sig   resume_userspace
-#endif
-
 /*
  * User gs save/restore
  *
@@ -327,10 +321,19 @@ ret_from_exception:
        preempt_stop(CLBR_ANY)
 ret_from_intr:
        GET_THREAD_INFO(%ebp)
-check_userspace:
+resume_userspace_sig:
+#ifdef CONFIG_VM86
        movl PT_EFLAGS(%esp), %eax      # mix EFLAGS and CS
        movb PT_CS(%esp), %al
        andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax
+#else
+       /*
+        * We can be coming here from a syscall done in the kernel space,
+        * e.g. a failed kernel_execve().
+        */
+       movl PT_CS(%esp), %eax
+       andl $SEGMENT_RPL_MASK, %eax
+#endif
        cmpl $USER_RPL, %eax
        jb resume_kernel                # not returning to v8086 or userspace
 
index 99b85b4..6d5fc8c 100644 (file)
@@ -305,10 +305,10 @@ void __init native_init_IRQ(void)
         * us. (some of these will be overridden and become
         * 'special' SMP interrupts)
         */
-       for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
+       i = FIRST_EXTERNAL_VECTOR;
+       for_each_clear_bit_from(i, used_vectors, NR_VECTORS) {
                /* IA32_SYSCALL_VECTOR could be used in trap_init already. */
-               if (!test_bit(i, used_vectors))
-                       set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]);
+               set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]);
        }
 
        if (!acpi_ioapic && !of_ioapic)
index 4425a12..db6720e 100644 (file)
@@ -66,8 +66,6 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
        { "ss", 4, offsetof(struct pt_regs, ss) },
        { "ds", 4, offsetof(struct pt_regs, ds) },
        { "es", 4, offsetof(struct pt_regs, es) },
-       { "fs", 4, -1 },
-       { "gs", 4, -1 },
 #else
        { "ax", 8, offsetof(struct pt_regs, ax) },
        { "bx", 8, offsetof(struct pt_regs, bx) },
@@ -89,7 +87,11 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
        { "flags", 4, offsetof(struct pt_regs, flags) },
        { "cs", 4, offsetof(struct pt_regs, cs) },
        { "ss", 4, offsetof(struct pt_regs, ss) },
+       { "ds", 4, -1 },
+       { "es", 4, -1 },
 #endif
+       { "fs", 4, -1 },
+       { "gs", 4, -1 },
 };
 
 int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
index 44842d7..f8492da 100644 (file)
@@ -136,6 +136,15 @@ int kvm_register_clock(char *txt)
        return ret;
 }
 
+static void kvm_save_sched_clock_state(void)
+{
+}
+
+static void kvm_restore_sched_clock_state(void)
+{
+       kvm_register_clock("primary cpu clock, resume");
+}
+
 #ifdef CONFIG_X86_LOCAL_APIC
 static void __cpuinit kvm_setup_secondary_clock(void)
 {
@@ -144,8 +153,6 @@ static void __cpuinit kvm_setup_secondary_clock(void)
         * we shouldn't fail.
         */
        WARN_ON(kvm_register_clock("secondary cpu clock"));
-       /* ok, done with our trickery, call native */
-       setup_secondary_APIC_clock();
 }
 #endif
 
@@ -194,9 +201,11 @@ void __init kvmclock_init(void)
        x86_platform.get_wallclock = kvm_get_wallclock;
        x86_platform.set_wallclock = kvm_set_wallclock;
 #ifdef CONFIG_X86_LOCAL_APIC
-       x86_cpuinit.setup_percpu_clockev =
+       x86_cpuinit.early_percpu_clock_init =
                kvm_setup_secondary_clock;
 #endif
+       x86_platform.save_sched_clock_state = kvm_save_sched_clock_state;
+       x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state;
        machine_ops.shutdown  = kvm_shutdown;
 #ifdef CONFIG_KEXEC
        machine_ops.crash_shutdown  = kvm_crash_shutdown;
index 2b26485..ab13760 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <asm/bug.h>
 #include <asm/paravirt.h>
+#include <asm/debugreg.h>
 #include <asm/desc.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
index 1c4d769..28e5e06 100644 (file)
@@ -262,10 +262,11 @@ rootfs_initcall(pci_iommu_init);
 
 static __devinit void via_no_dac(struct pci_dev *dev)
 {
-       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
+       if (forbid_dac == 0) {
                dev_info(&dev->dev, "disabling DAC on VIA PCI bridge\n");
                forbid_dac = 1;
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID,
+                               PCI_CLASS_BRIDGE_PCI, 8, via_no_dac);
 #endif
index e578a79..5104a2b 100644 (file)
@@ -255,6 +255,7 @@ notrace static void __cpuinit start_secondary(void *unused)
         * most necessary things.
         */
        cpu_init();
+       x86_cpuinit.early_percpu_clock_init();
        preempt_disable();
        smp_callin();
 
index 183c592..899a03f 100644 (file)
@@ -630,7 +630,7 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
 
 static unsigned long long cyc2ns_suspend;
 
-void save_sched_clock_state(void)
+void tsc_save_sched_clock_state(void)
 {
        if (!sched_clock_stable)
                return;
@@ -646,7 +646,7 @@ void save_sched_clock_state(void)
  * that sched_clock() continues from the point where it was left off during
  * suspend.
  */
-void restore_sched_clock_state(void)
+void tsc_restore_sched_clock_state(void)
 {
        unsigned long long offset;
        unsigned long flags;
index 947a06c..e9f265f 100644 (file)
@@ -91,6 +91,7 @@ struct x86_init_ops x86_init __initdata = {
 };
 
 struct x86_cpuinit_ops x86_cpuinit __cpuinitdata = {
+       .early_percpu_clock_init        = x86_init_noop,
        .setup_percpu_clockev           = setup_secondary_APIC_clock,
        .fixup_cpu_id                   = x86_default_fixup_cpu_id,
 };
@@ -107,7 +108,9 @@ struct x86_platform_ops x86_platform = {
        .is_untracked_pat_range         = is_ISA_range,
        .nmi_init                       = default_nmi_init,
        .get_nmi_reason                 = default_get_nmi_reason,
-       .i8042_detect                   = default_i8042_detect
+       .i8042_detect                   = default_i8042_detect,
+       .save_sched_clock_state         = tsc_save_sched_clock_state,
+       .restore_sched_clock_state      = tsc_restore_sched_clock_state,
 };
 
 EXPORT_SYMBOL_GPL(x86_platform);
index 89b02bf..9fed5be 100644 (file)
@@ -236,7 +236,7 @@ static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        const u32 kvm_supported_word6_x86_features =
                F(LAHF_LM) | F(CMP_LEGACY) | 0 /*SVM*/ | 0 /* ExtApicSpace */ |
                F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) |
-               F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(XOP) |
+               F(3DNOWPREFETCH) | F(OSVW) | 0 /* IBS */ | F(XOP) |
                0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM);
 
        /* cpuid 0xC0000001.edx */
index 5b97e17..26d1fb4 100644 (file)
@@ -43,4 +43,12 @@ static inline bool guest_cpuid_has_fsgsbase(struct kvm_vcpu *vcpu)
        return best && (best->ebx & bit(X86_FEATURE_FSGSBASE));
 }
 
+static inline bool guest_cpuid_has_osvw(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpuid_entry2 *best;
+
+       best = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
+       return best && (best->ecx & bit(X86_FEATURE_OSVW));
+}
+
 #endif
index 0982507..8375622 100644 (file)
@@ -57,6 +57,7 @@
 #define OpDS              23ull  /* DS */
 #define OpFS              24ull  /* FS */
 #define OpGS              25ull  /* GS */
+#define OpMem8            26ull  /* 8-bit zero extended memory operand */
 
 #define OpBits             5  /* Width of operand field */
 #define OpMask             ((1ull << OpBits) - 1)
 #define SrcAcc      (OpAcc << SrcShift)
 #define SrcImmU16   (OpImmU16 << SrcShift)
 #define SrcDX       (OpDX << SrcShift)
+#define SrcMem8     (OpMem8 << SrcShift)
 #define SrcMask     (OpMask << SrcShift)
 #define BitOp       (1<<11)
 #define MemAbs      (1<<12)      /* Memory operand is absolute displacement */
@@ -858,8 +860,7 @@ static void write_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data,
 }
 
 static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
-                                   struct operand *op,
-                                   int inhibit_bytereg)
+                                   struct operand *op)
 {
        unsigned reg = ctxt->modrm_reg;
        int highbyte_regs = ctxt->rex_prefix == 0;
@@ -876,7 +877,7 @@ static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
        }
 
        op->type = OP_REG;
-       if ((ctxt->d & ByteOp) && !inhibit_bytereg) {
+       if (ctxt->d & ByteOp) {
                op->addr.reg = decode_register(reg, ctxt->regs, highbyte_regs);
                op->bytes = 1;
        } else {
@@ -1151,6 +1152,22 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
        return 1;
 }
 
+static int read_interrupt_descriptor(struct x86_emulate_ctxt *ctxt,
+                                    u16 index, struct desc_struct *desc)
+{
+       struct desc_ptr dt;
+       ulong addr;
+
+       ctxt->ops->get_idt(ctxt, &dt);
+
+       if (dt.size < index * 8 + 7)
+               return emulate_gp(ctxt, index << 3 | 0x2);
+
+       addr = dt.address + index * 8;
+       return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc,
+                                  &ctxt->exception);
+}
+
 static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
                                     u16 selector, struct desc_ptr *dt)
 {
@@ -1227,6 +1244,8 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                seg_desc.type = 3;
                seg_desc.p = 1;
                seg_desc.s = 1;
+               if (ctxt->mode == X86EMUL_MODE_VM86)
+                       seg_desc.dpl = 3;
                goto load;
        }
 
@@ -1891,6 +1910,17 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
        ss->p = 1;
 }
 
+static bool vendor_intel(struct x86_emulate_ctxt *ctxt)
+{
+       u32 eax, ebx, ecx, edx;
+
+       eax = ecx = 0;
+       return ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)
+               && ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx
+               && ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx
+               && edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx;
+}
+
 static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt)
 {
        struct x86_emulate_ops *ops = ctxt->ops;
@@ -2007,6 +2037,14 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
        if (ctxt->mode == X86EMUL_MODE_REAL)
                return emulate_gp(ctxt, 0);
 
+       /*
+        * Not recognized on AMD in compat mode (but is recognized in legacy
+        * mode).
+        */
+       if ((ctxt->mode == X86EMUL_MODE_PROT32) && (efer & EFER_LMA)
+           && !vendor_intel(ctxt))
+               return emulate_ud(ctxt);
+
        /* XXX sysenter/sysexit have not been tested in 64bit mode.
        * Therefore, we inject an #UD.
        */
@@ -2306,6 +2344,8 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
                return emulate_gp(ctxt, 0);
        ctxt->_eip = tss->eip;
        ctxt->eflags = tss->eflags | 2;
+
+       /* General purpose registers */
        ctxt->regs[VCPU_REGS_RAX] = tss->eax;
        ctxt->regs[VCPU_REGS_RCX] = tss->ecx;
        ctxt->regs[VCPU_REGS_RDX] = tss->edx;
@@ -2328,6 +2368,24 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
        set_segment_selector(ctxt, tss->gs, VCPU_SREG_GS);
 
        /*
+        * If we're switching between Protected Mode and VM86, we need to make
+        * sure to update the mode before loading the segment descriptors so
+        * that the selectors are interpreted correctly.
+        *
+        * Need to get rflags to the vcpu struct immediately because it
+        * influences the CPL which is checked at least when loading the segment
+        * descriptors and when pushing an error code to the new kernel stack.
+        *
+        * TODO Introduce a separate ctxt->ops->set_cpl callback
+        */
+       if (ctxt->eflags & X86_EFLAGS_VM)
+               ctxt->mode = X86EMUL_MODE_VM86;
+       else
+               ctxt->mode = X86EMUL_MODE_PROT32;
+
+       ctxt->ops->set_rflags(ctxt, ctxt->eflags);
+
+       /*
         * Now load segment descriptors. If fault happenes at this stage
         * it is handled in a context of new task
         */
@@ -2401,7 +2459,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
 }
 
 static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
-                                  u16 tss_selector, int reason,
+                                  u16 tss_selector, int idt_index, int reason,
                                   bool has_error_code, u32 error_code)
 {
        struct x86_emulate_ops *ops = ctxt->ops;
@@ -2423,12 +2481,35 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
 
        /* FIXME: check that next_tss_desc is tss */
 
-       if (reason != TASK_SWITCH_IRET) {
-               if ((tss_selector & 3) > next_tss_desc.dpl ||
-                   ops->cpl(ctxt) > next_tss_desc.dpl)
-                       return emulate_gp(ctxt, 0);
+       /*
+        * Check privileges. The three cases are task switch caused by...
+        *
+        * 1. jmp/call/int to task gate: Check against DPL of the task gate
+        * 2. Exception/IRQ/iret: No check is performed
+        * 3. jmp/call to TSS: Check agains DPL of the TSS
+        */
+       if (reason == TASK_SWITCH_GATE) {
+               if (idt_index != -1) {
+                       /* Software interrupts */
+                       struct desc_struct task_gate_desc;
+                       int dpl;
+
+                       ret = read_interrupt_descriptor(ctxt, idt_index,
+                                                       &task_gate_desc);
+                       if (ret != X86EMUL_CONTINUE)
+                               return ret;
+
+                       dpl = task_gate_desc.dpl;
+                       if ((tss_selector & 3) > dpl || ops->cpl(ctxt) > dpl)
+                               return emulate_gp(ctxt, (idt_index << 3) | 0x2);
+               }
+       } else if (reason != TASK_SWITCH_IRET) {
+               int dpl = next_tss_desc.dpl;
+               if ((tss_selector & 3) > dpl || ops->cpl(ctxt) > dpl)
+                       return emulate_gp(ctxt, tss_selector);
        }
 
+
        desc_limit = desc_limit_scaled(&next_tss_desc);
        if (!next_tss_desc.p ||
            ((desc_limit < 0x67 && (next_tss_desc.type & 8)) ||
@@ -2481,7 +2562,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
 }
 
 int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
-                        u16 tss_selector, int reason,
+                        u16 tss_selector, int idt_index, int reason,
                         bool has_error_code, u32 error_code)
 {
        int rc;
@@ -2489,7 +2570,7 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
        ctxt->_eip = ctxt->eip;
        ctxt->dst.type = OP_NONE;
 
-       rc = emulator_do_task_switch(ctxt, tss_selector, reason,
+       rc = emulator_do_task_switch(ctxt, tss_selector, idt_index, reason,
                                     has_error_code, error_code);
 
        if (rc == X86EMUL_CONTINUE)
@@ -3514,13 +3595,13 @@ static struct opcode twobyte_table[256] = {
        I(DstMem | SrcReg | ModRM | BitOp | Lock, em_btr),
        I(DstReg | SrcMemFAddr | ModRM | Src2FS, em_lseg),
        I(DstReg | SrcMemFAddr | ModRM | Src2GS, em_lseg),
-       D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
+       D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
        /* 0xB8 - 0xBF */
        N, N,
        G(BitOp, group8),
        I(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_btc),
        I(DstReg | SrcMem | ModRM, em_bsf), I(DstReg | SrcMem | ModRM, em_bsr),
-       D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
+       D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
        /* 0xC0 - 0xCF */
        D2bv(DstMem | SrcReg | ModRM | Lock),
        N, D(DstMem | SrcReg | ModRM | Mov),
@@ -3602,9 +3683,7 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op,
 
        switch (d) {
        case OpReg:
-               decode_register_operand(ctxt, op,
-                        op == &ctxt->dst &&
-                        ctxt->twobyte && (ctxt->b == 0xb6 || ctxt->b == 0xb7));
+               decode_register_operand(ctxt, op);
                break;
        case OpImmUByte:
                rc = decode_imm(ctxt, op, 1, false);
@@ -3656,6 +3735,9 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op,
        case OpImm:
                rc = decode_imm(ctxt, op, imm_size(ctxt), true);
                break;
+       case OpMem8:
+               ctxt->memop.bytes = 1;
+               goto mem_common;
        case OpMem16:
                ctxt->memop.bytes = 2;
                goto mem_common;
index b6a7353..81cf4fa 100644 (file)
@@ -307,6 +307,7 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
                if (val & 0x10) {
                        s->init4 = val & 1;
                        s->last_irr = 0;
+                       s->irr &= s->elcr;
                        s->imr = 0;
                        s->priority_add = 0;
                        s->special_mask = 0;
index 31bfc69..8584322 100644 (file)
@@ -433,7 +433,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                break;
 
        case APIC_DM_INIT:
-               if (level) {
+               if (!trig_mode || level) {
                        result = 1;
                        vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED;
                        kvm_make_request(KVM_REQ_EVENT, vcpu);
@@ -731,7 +731,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
                u64 guest_tsc, tscdeadline = apic->lapic_timer.tscdeadline;
                u64 ns = 0;
                struct kvm_vcpu *vcpu = apic->vcpu;
-               unsigned long this_tsc_khz = vcpu_tsc_khz(vcpu);
+               unsigned long this_tsc_khz = vcpu->arch.virtual_tsc_khz;
                unsigned long flags;
 
                if (unlikely(!tscdeadline || !this_tsc_khz))
index 224b02c..4cb1642 100644 (file)
@@ -688,9 +688,8 @@ static struct kvm_lpage_info *lpage_info_slot(gfn_t gfn,
 {
        unsigned long idx;
 
-       idx = (gfn >> KVM_HPAGE_GFN_SHIFT(level)) -
-             (slot->base_gfn >> KVM_HPAGE_GFN_SHIFT(level));
-       return &slot->lpage_info[level - 2][idx];
+       idx = gfn_to_index(gfn, slot->base_gfn, level);
+       return &slot->arch.lpage_info[level - 2][idx];
 }
 
 static void account_shadowed(struct kvm *kvm, gfn_t gfn)
@@ -946,7 +945,7 @@ static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn)
        }
 }
 
-static unsigned long *__gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int level,
+static unsigned long *__gfn_to_rmap(gfn_t gfn, int level,
                                    struct kvm_memory_slot *slot)
 {
        struct kvm_lpage_info *linfo;
@@ -966,7 +965,7 @@ static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int level)
        struct kvm_memory_slot *slot;
 
        slot = gfn_to_memslot(kvm, gfn);
-       return __gfn_to_rmap(kvm, gfn, level, slot);
+       return __gfn_to_rmap(gfn, level, slot);
 }
 
 static bool rmap_can_add(struct kvm_vcpu *vcpu)
@@ -988,7 +987,7 @@ static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
        return pte_list_add(vcpu, spte, rmapp);
 }
 
-static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
+static u64 *rmap_next(unsigned long *rmapp, u64 *spte)
 {
        return pte_list_next(rmapp, spte);
 }
@@ -1018,8 +1017,8 @@ int kvm_mmu_rmap_write_protect(struct kvm *kvm, u64 gfn,
        u64 *spte;
        int i, write_protected = 0;
 
-       rmapp = __gfn_to_rmap(kvm, gfn, PT_PAGE_TABLE_LEVEL, slot);
-       spte = rmap_next(kvm, rmapp, NULL);
+       rmapp = __gfn_to_rmap(gfn, PT_PAGE_TABLE_LEVEL, slot);
+       spte = rmap_next(rmapp, NULL);
        while (spte) {
                BUG_ON(!(*spte & PT_PRESENT_MASK));
                rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
@@ -1027,14 +1026,14 @@ int kvm_mmu_rmap_write_protect(struct kvm *kvm, u64 gfn,
                        mmu_spte_update(spte, *spte & ~PT_WRITABLE_MASK);
                        write_protected = 1;
                }
-               spte = rmap_next(kvm, rmapp, spte);
+               spte = rmap_next(rmapp, spte);
        }
 
        /* check for huge page mappings */
        for (i = PT_DIRECTORY_LEVEL;
             i < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++i) {
-               rmapp = __gfn_to_rmap(kvm, gfn, i, slot);
-               spte = rmap_next(kvm, rmapp, NULL);
+               rmapp = __gfn_to_rmap(gfn, i, slot);
+               spte = rmap_next(rmapp, NULL);
                while (spte) {
                        BUG_ON(!(*spte & PT_PRESENT_MASK));
                        BUG_ON(!is_large_pte(*spte));
@@ -1045,7 +1044,7 @@ int kvm_mmu_rmap_write_protect(struct kvm *kvm, u64 gfn,
                                spte = NULL;
                                write_protected = 1;
                        }
-                       spte = rmap_next(kvm, rmapp, spte);
+                       spte = rmap_next(rmapp, spte);
                }
        }
 
@@ -1066,7 +1065,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
        u64 *spte;
        int need_tlb_flush = 0;
 
-       while ((spte = rmap_next(kvm, rmapp, NULL))) {
+       while ((spte = rmap_next(rmapp, NULL))) {
                BUG_ON(!(*spte & PT_PRESENT_MASK));
                rmap_printk("kvm_rmap_unmap_hva: spte %p %llx\n", spte, *spte);
                drop_spte(kvm, spte);
@@ -1085,14 +1084,14 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
 
        WARN_ON(pte_huge(*ptep));
        new_pfn = pte_pfn(*ptep);
-       spte = rmap_next(kvm, rmapp, NULL);
+       spte = rmap_next(rmapp, NULL);
        while (spte) {
                BUG_ON(!is_shadow_present_pte(*spte));
                rmap_printk("kvm_set_pte_rmapp: spte %p %llx\n", spte, *spte);
                need_flush = 1;
                if (pte_write(*ptep)) {
                        drop_spte(kvm, spte);
-                       spte = rmap_next(kvm, rmapp, NULL);
+                       spte = rmap_next(rmapp, NULL);
                } else {
                        new_spte = *spte &~ (PT64_BASE_ADDR_MASK);
                        new_spte |= (u64)new_pfn << PAGE_SHIFT;
@@ -1102,7 +1101,7 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
                        new_spte &= ~shadow_accessed_mask;
                        mmu_spte_clear_track_bits(spte);
                        mmu_spte_set(spte, new_spte);
-                       spte = rmap_next(kvm, rmapp, spte);
+                       spte = rmap_next(rmapp, spte);
                }
        }
        if (need_flush)
@@ -1176,7 +1175,7 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
        if (!shadow_accessed_mask)
                return kvm_unmap_rmapp(kvm, rmapp, data);
 
-       spte = rmap_next(kvm, rmapp, NULL);
+       spte = rmap_next(rmapp, NULL);
        while (spte) {
                int _young;
                u64 _spte = *spte;
@@ -1186,7 +1185,7 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
                        young = 1;
                        clear_bit(PT_ACCESSED_SHIFT, (unsigned long *)spte);
                }
-               spte = rmap_next(kvm, rmapp, spte);
+               spte = rmap_next(rmapp, spte);
        }
        return young;
 }
@@ -1205,7 +1204,7 @@ static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
        if (!shadow_accessed_mask)
                goto out;
 
-       spte = rmap_next(kvm, rmapp, NULL);
+       spte = rmap_next(rmapp, NULL);
        while (spte) {
                u64 _spte = *spte;
                BUG_ON(!(_spte & PT_PRESENT_MASK));
@@ -1214,7 +1213,7 @@ static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
                        young = 1;
                        break;
                }
-               spte = rmap_next(kvm, rmapp, spte);
+               spte = rmap_next(rmapp, spte);
        }
 out:
        return young;
@@ -1391,11 +1390,6 @@ struct kvm_mmu_pages {
        unsigned int nr;
 };
 
-#define for_each_unsync_children(bitmap, idx)          \
-       for (idx = find_first_bit(bitmap, 512);         \
-            idx < 512;                                 \
-            idx = find_next_bit(bitmap, 512, idx+1))
-
 static int mmu_pages_add(struct kvm_mmu_pages *pvec, struct kvm_mmu_page *sp,
                         int idx)
 {
@@ -1417,7 +1411,7 @@ static int __mmu_unsync_walk(struct kvm_mmu_page *sp,
 {
        int i, ret, nr_unsync_leaf = 0;
 
-       for_each_unsync_children(sp->unsync_child_bitmap, i) {
+       for_each_set_bit(i, sp->unsync_child_bitmap, 512) {
                struct kvm_mmu_page *child;
                u64 ent = sp->spt[i];
 
@@ -1803,6 +1797,7 @@ static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep)
 {
        if (is_large_pte(*sptep)) {
                drop_spte(vcpu->kvm, sptep);
+               --vcpu->kvm->stat.lpages;
                kvm_flush_remote_tlbs(vcpu->kvm);
        }
 }
@@ -3190,15 +3185,14 @@ static bool sync_mmio_spte(u64 *sptep, gfn_t gfn, unsigned access,
 #undef PTTYPE
 
 static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
-                                 struct kvm_mmu *context,
-                                 int level)
+                                 struct kvm_mmu *context)
 {
        int maxphyaddr = cpuid_maxphyaddr(vcpu);
        u64 exb_bit_rsvd = 0;
 
        if (!context->nx)
                exb_bit_rsvd = rsvd_bits(63, 63);
-       switch (level) {
+       switch (context->root_level) {
        case PT32_ROOT_LEVEL:
                /* no rsvd bits for 2 level 4K page table entries */
                context->rsvd_bits_mask[0][1] = 0;
@@ -3256,8 +3250,9 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu,
                                        int level)
 {
        context->nx = is_nx(vcpu);
+       context->root_level = level;
 
-       reset_rsvds_bits_mask(vcpu, context, level);
+       reset_rsvds_bits_mask(vcpu, context);
 
        ASSERT(is_pae(vcpu));
        context->new_cr3 = paging_new_cr3;
@@ -3267,7 +3262,6 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu,
        context->invlpg = paging64_invlpg;
        context->update_pte = paging64_update_pte;
        context->free = paging_free;
-       context->root_level = level;
        context->shadow_root_level = level;
        context->root_hpa = INVALID_PAGE;
        context->direct_map = false;
@@ -3284,8 +3278,9 @@ static int paging32_init_context(struct kvm_vcpu *vcpu,
                                 struct kvm_mmu *context)
 {
        context->nx = false;
+       context->root_level = PT32_ROOT_LEVEL;
 
-       reset_rsvds_bits_mask(vcpu, context, PT32_ROOT_LEVEL);
+       reset_rsvds_bits_mask(vcpu, context);
 
        context->new_cr3 = paging_new_cr3;
        context->page_fault = paging32_page_fault;
@@ -3294,7 +3289,6 @@ static int paging32_init_context(struct kvm_vcpu *vcpu,
        context->sync_page = paging32_sync_page;
        context->invlpg = paging32_invlpg;
        context->update_pte = paging32_update_pte;
-       context->root_level = PT32_ROOT_LEVEL;
        context->shadow_root_level = PT32E_ROOT_LEVEL;
        context->root_hpa = INVALID_PAGE;
        context->direct_map = false;
@@ -3325,7 +3319,6 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
        context->get_cr3 = get_cr3;
        context->get_pdptr = kvm_pdptr_read;
        context->inject_page_fault = kvm_inject_page_fault;
-       context->nx = is_nx(vcpu);
 
        if (!is_paging(vcpu)) {
                context->nx = false;
@@ -3333,19 +3326,19 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
                context->root_level = 0;
        } else if (is_long_mode(vcpu)) {
                context->nx = is_nx(vcpu);
-               reset_rsvds_bits_mask(vcpu, context, PT64_ROOT_LEVEL);
-               context->gva_to_gpa = paging64_gva_to_gpa;
                context->root_level = PT64_ROOT_LEVEL;
+               reset_rsvds_bits_mask(vcpu, context);
+               context->gva_to_gpa = paging64_gva_to_gpa;
        } else if (is_pae(vcpu)) {
                context->nx = is_nx(vcpu);
-               reset_rsvds_bits_mask(vcpu, context, PT32E_ROOT_LEVEL);
-               context->gva_to_gpa = paging64_gva_to_gpa;
                context->root_level = PT32E_ROOT_LEVEL;
+               reset_rsvds_bits_mask(vcpu, context);
+               context->gva_to_gpa = paging64_gva_to_gpa;
        } else {
                context->nx = false;
-               reset_rsvds_bits_mask(vcpu, context, PT32_ROOT_LEVEL);
-               context->gva_to_gpa = paging32_gva_to_gpa;
                context->root_level = PT32_ROOT_LEVEL;
+               reset_rsvds_bits_mask(vcpu, context);
+               context->gva_to_gpa = paging32_gva_to_gpa;
        }
 
        return 0;
@@ -3408,18 +3401,18 @@ static int init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
                g_context->gva_to_gpa = nonpaging_gva_to_gpa_nested;
        } else if (is_long_mode(vcpu)) {
                g_context->nx = is_nx(vcpu);
-               reset_rsvds_bits_mask(vcpu, g_context, PT64_ROOT_LEVEL);
                g_context->root_level = PT64_ROOT_LEVEL;
+               reset_rsvds_bits_mask(vcpu, g_context);
                g_context->gva_to_gpa = paging64_gva_to_gpa_nested;
        } else if (is_pae(vcpu)) {
                g_context->nx = is_nx(vcpu);
-               reset_rsvds_bits_mask(vcpu, g_context, PT32E_ROOT_LEVEL);
                g_context->root_level = PT32E_ROOT_LEVEL;
+               reset_rsvds_bits_mask(vcpu, g_context);
                g_context->gva_to_gpa = paging64_gva_to_gpa_nested;
        } else {
                g_context->nx = false;
-               reset_rsvds_bits_mask(vcpu, g_context, PT32_ROOT_LEVEL);
                g_context->root_level = PT32_ROOT_LEVEL;
+               reset_rsvds_bits_mask(vcpu, g_context);
                g_context->gva_to_gpa = paging32_gva_to_gpa_nested;
        }
 
@@ -3555,7 +3548,7 @@ static u64 mmu_pte_write_fetch_gpte(struct kvm_vcpu *vcpu, gpa_t *gpa,
  * If we're seeing too many writes to a page, it may no longer be a page table,
  * or we may be forking, in which case it is better to unmap the page.
  */
-static bool detect_write_flooding(struct kvm_mmu_page *sp, u64 *spte)
+static bool detect_write_flooding(struct kvm_mmu_page *sp)
 {
        /*
         * Skip write-flooding detected for the sp whose level is 1, because
@@ -3664,10 +3657,8 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
 
        mask.cr0_wp = mask.cr4_pae = mask.nxe = 1;
        for_each_gfn_indirect_valid_sp(vcpu->kvm, sp, gfn, node) {
-               spte = get_written_sptes(sp, gpa, &npte);
-
                if (detect_write_misaligned(sp, gpa, bytes) ||
-                     detect_write_flooding(sp, spte)) {
+                     detect_write_flooding(sp)) {
                        zap_page |= !!kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
                                                     &invalid_list);
                        ++vcpu->kvm->stat.mmu_flooded;
index ea7b4fd..715da5a 100644 (file)
@@ -200,13 +200,13 @@ static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
        slot = gfn_to_memslot(kvm, sp->gfn);
        rmapp = &slot->rmap[sp->gfn - slot->base_gfn];
 
-       spte = rmap_next(kvm, rmapp, NULL);
+       spte = rmap_next(rmapp, NULL);
        while (spte) {
                if (is_writable_pte(*spte))
                        audit_printk(kvm, "shadow page has writable "
                                     "mappings: gfn %llx role %x\n",
                                     sp->gfn, sp->role.word);
-               spte = rmap_next(kvm, rmapp, spte);
+               spte = rmap_next(rmapp, spte);
        }
 }
 
index 7aad544..a73f0c1 100644 (file)
@@ -33,10 +33,11 @@ static struct kvm_arch_event_perf_mapping {
        [4] = { 0x2e, 0x41, PERF_COUNT_HW_CACHE_MISSES },
        [5] = { 0xc4, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
        [6] = { 0xc5, 0x00, PERF_COUNT_HW_BRANCH_MISSES },
+       [7] = { 0x00, 0x30, PERF_COUNT_HW_REF_CPU_CYCLES },
 };
 
 /* mapping between fixed pmc index and arch_events array */
-int fixed_pmc_events[] = {1, 0, 2};
+int fixed_pmc_events[] = {1, 0, 7};
 
 static bool pmc_is_gp(struct kvm_pmc *pmc)
 {
@@ -210,6 +211,9 @@ static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
        unsigned config, type = PERF_TYPE_RAW;
        u8 event_select, unit_mask;
 
+       if (eventsel & ARCH_PERFMON_EVENTSEL_PIN_CONTROL)
+               printk_once("kvm pmu: pin control bit is ignored\n");
+
        pmc->eventsel = eventsel;
 
        stop_counter(pmc);
@@ -220,7 +224,7 @@ static void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
        event_select = eventsel & ARCH_PERFMON_EVENTSEL_EVENT;
        unit_mask = (eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8;
 
-       if (!(event_select & (ARCH_PERFMON_EVENTSEL_EDGE |
+       if (!(eventsel & (ARCH_PERFMON_EVENTSEL_EDGE |
                                ARCH_PERFMON_EVENTSEL_INV |
                                ARCH_PERFMON_EVENTSEL_CMASK))) {
                config = find_arch_event(&pmc->vcpu->arch.pmu, event_select,
@@ -413,7 +417,7 @@ int kvm_pmu_read_pmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data)
        struct kvm_pmc *counters;
        u64 ctr;
 
-       pmc &= (3u << 30) - 1;
+       pmc &= ~(3u << 30);
        if (!fixed && pmc >= pmu->nr_arch_gp_counters)
                return 1;
        if (fixed && pmc >= pmu->nr_arch_fixed_counters)
index e385214..e334389 100644 (file)
@@ -111,6 +111,12 @@ struct nested_state {
 #define MSRPM_OFFSETS  16
 static u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly;
 
+/*
+ * Set osvw_len to higher value when updated Revision Guides
+ * are published and we know what the new status bits are
+ */
+static uint64_t osvw_len = 4, osvw_status;
+
 struct vcpu_svm {
        struct kvm_vcpu vcpu;
        struct vmcb *vmcb;
@@ -177,11 +183,13 @@ static bool npt_enabled = true;
 #else
 static bool npt_enabled;
 #endif
-static int npt = 1;
 
+/* allow nested paging (virtualized MMU) for all guests */
+static int npt = true;
 module_param(npt, int, S_IRUGO);
 
-static int nested = 1;
+/* allow nested virtualization in KVM/SVM */
+static int nested = true;
 module_param(nested, int, S_IRUGO);
 
 static void svm_flush_tlb(struct kvm_vcpu *vcpu);
@@ -557,6 +565,27 @@ static void svm_init_erratum_383(void)
        erratum_383_found = true;
 }
 
+static void svm_init_osvw(struct kvm_vcpu *vcpu)
+{
+       /*
+        * Guests should see errata 400 and 415 as fixed (assuming that
+        * HLT and IO instructions are intercepted).
+        */
+       vcpu->arch.osvw.length = (osvw_len >= 3) ? (osvw_len) : 3;
+       vcpu->arch.osvw.status = osvw_status & ~(6ULL);
+
+       /*
+        * By increasing VCPU's osvw.length to 3 we are telling the guest that
+        * all osvw.status bits inside that length, including bit 0 (which is
+        * reserved for erratum 298), are valid. However, if host processor's
+        * osvw_len is 0 then osvw_status[0] carries no information. We need to
+        * be conservative here and therefore we tell the guest that erratum 298
+        * is present (because we really don't know).
+        */
+       if (osvw_len == 0 && boot_cpu_data.x86 == 0x10)
+               vcpu->arch.osvw.status |= 1;
+}
+
 static int has_svm(void)
 {
        const char *msg;
@@ -623,6 +652,36 @@ static int svm_hardware_enable(void *garbage)
                __get_cpu_var(current_tsc_ratio) = TSC_RATIO_DEFAULT;
        }
 
+
+       /*
+        * Get OSVW bits.
+        *
+        * Note that it is possible to have a system with mixed processor
+        * revisions and therefore different OSVW bits. If bits are not the same
+        * on different processors then choose the worst case (i.e. if erratum
+        * is present on one processor and not on another then assume that the
+        * erratum is present everywhere).
+        */
+       if (cpu_has(&boot_cpu_data, X86_FEATURE_OSVW)) {
+               uint64_t len, status = 0;
+               int err;
+
+               len = native_read_msr_safe(MSR_AMD64_OSVW_ID_LENGTH, &err);
+               if (!err)
+                       status = native_read_msr_safe(MSR_AMD64_OSVW_STATUS,
+                                                     &err);
+
+               if (err)
+                       osvw_status = osvw_len = 0;
+               else {
+                       if (len < osvw_len)
+                               osvw_len = len;
+                       osvw_status |= status;
+                       osvw_status &= (1ULL << osvw_len) - 1;
+               }
+       } else
+               osvw_status = osvw_len = 0;
+
        svm_init_erratum_383();
 
        amd_pmu_enable_virt();
@@ -910,20 +969,25 @@ static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
        return _tsc;
 }
 
-static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        u64 ratio;
        u64 khz;
 
-       /* TSC scaling supported? */
-       if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR))
+       /* Guest TSC same frequency as host TSC? */
+       if (!scale) {
+               svm->tsc_ratio = TSC_RATIO_DEFAULT;
                return;
+       }
 
-       /* TSC-Scaling disabled or guest TSC same frequency as host TSC? */
-       if (user_tsc_khz == 0) {
-               vcpu->arch.virtual_tsc_khz = 0;
-               svm->tsc_ratio = TSC_RATIO_DEFAULT;
+       /* TSC scaling supported? */
+       if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
+               if (user_tsc_khz > tsc_khz) {
+                       vcpu->arch.tsc_catchup = 1;
+                       vcpu->arch.tsc_always_catchup = 1;
+               } else
+                       WARN(1, "user requested TSC rate below hardware speed\n");
                return;
        }
 
@@ -938,7 +1002,6 @@ static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
                                user_tsc_khz);
                return;
        }
-       vcpu->arch.virtual_tsc_khz = user_tsc_khz;
        svm->tsc_ratio             = ratio;
 }
 
@@ -958,10 +1021,14 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
        mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
 }
 
-static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
+static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool host)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       WARN_ON(adjustment < 0);
+       if (host)
+               adjustment = svm_scale_tsc(vcpu, adjustment);
+
        svm->vmcb->control.tsc_offset += adjustment;
        if (is_guest_mode(vcpu))
                svm->nested.hsave->control.tsc_offset += adjustment;
@@ -1191,6 +1258,8 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
        if (kvm_vcpu_is_bsp(&svm->vcpu))
                svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP;
 
+       svm_init_osvw(&svm->vcpu);
+
        return &svm->vcpu;
 
 free_page4:
@@ -1268,6 +1337,21 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
                wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
 }
 
+static void svm_update_cpl(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       int cpl;
+
+       if (!is_protmode(vcpu))
+               cpl = 0;
+       else if (svm->vmcb->save.rflags & X86_EFLAGS_VM)
+               cpl = 3;
+       else
+               cpl = svm->vmcb->save.cs.selector & 0x3;
+
+       svm->vmcb->save.cpl = cpl;
+}
+
 static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
 {
        return to_svm(vcpu)->vmcb->save.rflags;
@@ -1275,7 +1359,11 @@ static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
 
 static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
+       unsigned long old_rflags = to_svm(vcpu)->vmcb->save.rflags;
+
        to_svm(vcpu)->vmcb->save.rflags = rflags;
+       if ((old_rflags ^ rflags) & X86_EFLAGS_VM)
+               svm_update_cpl(vcpu);
 }
 
 static void svm_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg)
@@ -1543,9 +1631,7 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
                s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
        }
        if (seg == VCPU_SREG_CS)
-               svm->vmcb->save.cpl
-                       = (svm->vmcb->save.cs.attrib
-                          >> SVM_SELECTOR_DPL_SHIFT) & 3;
+               svm_update_cpl(vcpu);
 
        mark_dirty(svm->vmcb, VMCB_SEG);
 }
@@ -2735,7 +2821,10 @@ static int task_switch_interception(struct vcpu_svm *svm)
             (int_vec == OF_VECTOR || int_vec == BP_VECTOR)))
                skip_emulated_instruction(&svm->vcpu);
 
-       if (kvm_task_switch(&svm->vcpu, tss_selector, reason,
+       if (int_type != SVM_EXITINTINFO_TYPE_SOFT)
+               int_vec = -1;
+
+       if (kvm_task_switch(&svm->vcpu, tss_selector, int_vec, reason,
                                has_error_code, error_code) == EMULATE_FAIL) {
                svm->vcpu.run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                svm->vcpu.run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
index 246490f..280751c 100644 (file)
@@ -70,9 +70,6 @@ module_param(emulate_invalid_guest_state, bool, S_IRUGO);
 static bool __read_mostly vmm_exclusive = 1;
 module_param(vmm_exclusive, bool, S_IRUGO);
 
-static bool __read_mostly yield_on_hlt = 1;
-module_param(yield_on_hlt, bool, S_IRUGO);
-
 static bool __read_mostly fasteoi = 1;
 module_param(fasteoi, bool, S_IRUGO);
 
@@ -1655,17 +1652,6 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
        vmx_set_interrupt_shadow(vcpu, 0);
 }
 
-static void vmx_clear_hlt(struct kvm_vcpu *vcpu)
-{
-       /* Ensure that we clear the HLT state in the VMCS.  We don't need to
-        * explicitly skip the instruction because if the HLT state is set, then
-        * the instruction is already executing and RIP has already been
-        * advanced. */
-       if (!yield_on_hlt &&
-           vmcs_read32(GUEST_ACTIVITY_STATE) == GUEST_ACTIVITY_HLT)
-               vmcs_write32(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE);
-}
-
 /*
  * KVM wants to inject page-faults which it got to the guest. This function
  * checks whether in a nested guest, we need to inject them to L1 or L2.
@@ -1678,7 +1664,7 @@ static int nested_pf_handled(struct kvm_vcpu *vcpu)
        struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
 
        /* TODO: also check PFEC_MATCH/MASK, not just EB.PF. */
-       if (!(vmcs12->exception_bitmap & PF_VECTOR))
+       if (!(vmcs12->exception_bitmap & (1u << PF_VECTOR)))
                return 0;
 
        nested_vmx_vmexit(vcpu);
@@ -1718,7 +1704,6 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
                intr_info |= INTR_TYPE_HARD_EXCEPTION;
 
        vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info);
-       vmx_clear_hlt(vcpu);
 }
 
 static bool vmx_rdtscp_supported(void)
@@ -1817,13 +1802,19 @@ u64 vmx_read_l1_tsc(struct kvm_vcpu *vcpu)
 }
 
 /*
- * Empty call-back. Needs to be implemented when VMX enables the SET_TSC_KHZ
- * ioctl. In this case the call-back should update internal vmx state to make
- * the changes effective.
+ * Engage any workarounds for mis-matched TSC rates.  Currently limited to
+ * software catchup for faster rates on slower CPUs.
  */
-static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 {
-       /* Nothing to do here */
+       if (!scale)
+               return;
+
+       if (user_tsc_khz > tsc_khz) {
+               vcpu->arch.tsc_catchup = 1;
+               vcpu->arch.tsc_always_catchup = 1;
+       } else
+               WARN(1, "user requested TSC rate below hardware speed\n");
 }
 
 /*
@@ -1850,7 +1841,7 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
        }
 }
 
-static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
+static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool host)
 {
        u64 offset = vmcs_read64(TSC_OFFSET);
        vmcs_write64(TSC_OFFSET, offset + adjustment);
@@ -2219,6 +2210,9 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
                msr = find_msr_entry(vmx, msr_index);
                if (msr) {
                        msr->data = data;
+                       if (msr - vmx->guest_msrs < vmx->save_nmsrs)
+                               kvm_set_shared_msr(msr->index, msr->data,
+                                                  msr->mask);
                        break;
                }
                ret = kvm_set_msr_common(vcpu, msr_index, data);
@@ -2399,7 +2393,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
                                &_pin_based_exec_control) < 0)
                return -EIO;
 
-       min =
+       min = CPU_BASED_HLT_EXITING |
 #ifdef CONFIG_X86_64
              CPU_BASED_CR8_LOAD_EXITING |
              CPU_BASED_CR8_STORE_EXITING |
@@ -2414,9 +2408,6 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
              CPU_BASED_INVLPG_EXITING |
              CPU_BASED_RDPMC_EXITING;
 
-       if (yield_on_hlt)
-               min |= CPU_BASED_HLT_EXITING;
-
        opt = CPU_BASED_TPR_SHADOW |
              CPU_BASED_USE_MSR_BITMAPS |
              CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
@@ -4003,7 +3994,6 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu)
        } else
                intr |= INTR_TYPE_EXT_INTR;
        vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr);
-       vmx_clear_hlt(vcpu);
 }
 
 static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
@@ -4035,7 +4025,6 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
        }
        vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
                        INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR);
-       vmx_clear_hlt(vcpu);
 }
 
 static int vmx_nmi_allowed(struct kvm_vcpu *vcpu)
@@ -4672,9 +4661,10 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
        bool has_error_code = false;
        u32 error_code = 0;
        u16 tss_selector;
-       int reason, type, idt_v;
+       int reason, type, idt_v, idt_index;
 
        idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK);
+       idt_index = (vmx->idt_vectoring_info & VECTORING_INFO_VECTOR_MASK);
        type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK);
 
        exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
@@ -4712,8 +4702,9 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
                       type != INTR_TYPE_NMI_INTR))
                skip_emulated_instruction(vcpu);
 
-       if (kvm_task_switch(vcpu, tss_selector, reason,
-                               has_error_code, error_code) == EMULATE_FAIL) {
+       if (kvm_task_switch(vcpu, tss_selector,
+                           type == INTR_TYPE_SOFT_INTR ? idt_index : -1, reason,
+                           has_error_code, error_code) == EMULATE_FAIL) {
                vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
                vcpu->run->internal.ndata = 0;
index 54696b5..4044ce0 100644 (file)
@@ -97,6 +97,10 @@ EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
 u32  kvm_max_guest_tsc_khz;
 EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz);
 
+/* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */
+static u32 tsc_tolerance_ppm = 250;
+module_param(tsc_tolerance_ppm, uint, S_IRUGO | S_IWUSR);
+
 #define KVM_NR_SHARED_MSRS 16
 
 struct kvm_shared_msrs_global {
@@ -969,50 +973,51 @@ static inline u64 get_kernel_ns(void)
 static DEFINE_PER_CPU(unsigned long, cpu_tsc_khz);
 unsigned long max_tsc_khz;
 
-static inline int kvm_tsc_changes_freq(void)
+static inline u64 nsec_to_cycles(struct kvm_vcpu *vcpu, u64 nsec)
 {
-       int cpu = get_cpu();
-       int ret = !boot_cpu_has(X86_FEATURE_CONSTANT_TSC) &&
-                 cpufreq_quick_get(cpu) != 0;
-       put_cpu();
-       return ret;
+       return pvclock_scale_delta(nsec, vcpu->arch.virtual_tsc_mult,
+                                  vcpu->arch.virtual_tsc_shift);
 }
 
-u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu)
+static u32 adjust_tsc_khz(u32 khz, s32 ppm)
 {
-       if (vcpu->arch.virtual_tsc_khz)
-               return vcpu->arch.virtual_tsc_khz;
-       else
-               return __this_cpu_read(cpu_tsc_khz);
+       u64 v = (u64)khz * (1000000 + ppm);
+       do_div(v, 1000000);
+       return v;
 }
 
-static inline u64 nsec_to_cycles(struct kvm_vcpu *vcpu, u64 nsec)
+static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
 {
-       u64 ret;
-
-       WARN_ON(preemptible());
-       if (kvm_tsc_changes_freq())
-               printk_once(KERN_WARNING
-                "kvm: unreliable cycle conversion on adjustable rate TSC\n");
-       ret = nsec * vcpu_tsc_khz(vcpu);
-       do_div(ret, USEC_PER_SEC);
-       return ret;
-}
+       u32 thresh_lo, thresh_hi;
+       int use_scaling = 0;
 
-static void kvm_init_tsc_catchup(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
-{
        /* Compute a scale to convert nanoseconds in TSC cycles */
        kvm_get_time_scale(this_tsc_khz, NSEC_PER_SEC / 1000,
-                          &vcpu->arch.tsc_catchup_shift,
-                          &vcpu->arch.tsc_catchup_mult);
+                          &vcpu->arch.virtual_tsc_shift,
+                          &vcpu->arch.virtual_tsc_mult);
+       vcpu->arch.virtual_tsc_khz = this_tsc_khz;
+
+       /*
+        * Compute the variation in TSC rate which is acceptable
+        * within the range of tolerance and decide if the
+        * rate being applied is within that bounds of the hardware
+        * rate.  If so, no scaling or compensation need be done.
+        */
+       thresh_lo = adjust_tsc_khz(tsc_khz, -tsc_tolerance_ppm);
+       thresh_hi = adjust_tsc_khz(tsc_khz, tsc_tolerance_ppm);
+       if (this_tsc_khz < thresh_lo || this_tsc_khz > thresh_hi) {
+               pr_debug("kvm: requested TSC rate %u falls outside tolerance [%u,%u]\n", this_tsc_khz, thresh_lo, thresh_hi);
+               use_scaling = 1;
+       }
+       kvm_x86_ops->set_tsc_khz(vcpu, this_tsc_khz, use_scaling);
 }
 
 static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
 {
-       u64 tsc = pvclock_scale_delta(kernel_ns-vcpu->arch.last_tsc_nsec,
-                                     vcpu->arch.tsc_catchup_mult,
-                                     vcpu->arch.tsc_catchup_shift);
-       tsc += vcpu->arch.last_tsc_write;
+       u64 tsc = pvclock_scale_delta(kernel_ns-vcpu->arch.this_tsc_nsec,
+                                     vcpu->arch.virtual_tsc_mult,
+                                     vcpu->arch.virtual_tsc_shift);
+       tsc += vcpu->arch.this_tsc_write;
        return tsc;
 }
 
@@ -1021,48 +1026,88 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
        struct kvm *kvm = vcpu->kvm;
        u64 offset, ns, elapsed;
        unsigned long flags;
-       s64 sdiff;
+       s64 usdiff;
 
        raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
        offset = kvm_x86_ops->compute_tsc_offset(vcpu, data);
        ns = get_kernel_ns();
        elapsed = ns - kvm->arch.last_tsc_nsec;
-       sdiff = data - kvm->arch.last_tsc_write;
-       if (sdiff < 0)
-               sdiff = -sdiff;
+
+       /* n.b - signed multiplication and division required */
+       usdiff = data - kvm->arch.last_tsc_write;
+#ifdef CONFIG_X86_64
+       usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz;
+#else
+       /* do_div() only does unsigned */
+       asm("idivl %2; xor %%edx, %%edx"
+           : "=A"(usdiff)
+           : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz));
+#endif
+       do_div(elapsed, 1000);
+       usdiff -= elapsed;
+       if (usdiff < 0)
+               usdiff = -usdiff;
 
        /*
-        * Special case: close write to TSC within 5 seconds of
-        * another CPU is interpreted as an attempt to synchronize
-        * The 5 seconds is to accommodate host load / swapping as
-        * well as any reset of TSC during the boot process.
-        *
-        * In that case, for a reliable TSC, we can match TSC offsets,
-        * or make a best guest using elapsed value.
-        */
-       if (sdiff < nsec_to_cycles(vcpu, 5ULL * NSEC_PER_SEC) &&
-           elapsed < 5ULL * NSEC_PER_SEC) {
+        * Special case: TSC write with a small delta (1 second) of virtual
+        * cycle time against real time is interpreted as an attempt to
+        * synchronize the CPU.
+         *
+        * For a reliable TSC, we can match TSC offsets, and for an unstable
+        * TSC, we add elapsed time in this computation.  We could let the
+        * compensation code attempt to catch up if we fall behind, but
+        * it's better to try to match offsets from the beginning.
+         */
+       if (usdiff < USEC_PER_SEC &&
+           vcpu->arch.virtual_tsc_khz == kvm->arch.last_tsc_khz) {
                if (!check_tsc_unstable()) {
-                       offset = kvm->arch.last_tsc_offset;
+                       offset = kvm->arch.cur_tsc_offset;
                        pr_debug("kvm: matched tsc offset for %llu\n", data);
                } else {
                        u64 delta = nsec_to_cycles(vcpu, elapsed);
-                       offset += delta;
+                       data += delta;
+                       offset = kvm_x86_ops->compute_tsc_offset(vcpu, data);
                        pr_debug("kvm: adjusted tsc offset by %llu\n", delta);
                }
-               ns = kvm->arch.last_tsc_nsec;
+       } else {
+               /*
+                * We split periods of matched TSC writes into generations.
+                * For each generation, we track the original measured
+                * nanosecond time, offset, and write, so if TSCs are in
+                * sync, we can match exact offset, and if not, we can match
+                * exact software computaion in compute_guest_tsc()
+                *
+                * These values are tracked in kvm->arch.cur_xxx variables.
+                */
+               kvm->arch.cur_tsc_generation++;
+               kvm->arch.cur_tsc_nsec = ns;
+               kvm->arch.cur_tsc_write = data;
+               kvm->arch.cur_tsc_offset = offset;
+               pr_debug("kvm: new tsc generation %u, clock %llu\n",
+                        kvm->arch.cur_tsc_generation, data);
        }
+
+       /*
+        * We also track th most recent recorded KHZ, write and time to
+        * allow the matching interval to be extended at each write.
+        */
        kvm->arch.last_tsc_nsec = ns;
        kvm->arch.last_tsc_write = data;
-       kvm->arch.last_tsc_offset = offset;
-       kvm_x86_ops->write_tsc_offset(vcpu, offset);
-       raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
+       kvm->arch.last_tsc_khz = vcpu->arch.virtual_tsc_khz;
 
        /* Reset of TSC must disable overshoot protection below */
        vcpu->arch.hv_clock.tsc_timestamp = 0;
-       vcpu->arch.last_tsc_write = data;
-       vcpu->arch.last_tsc_nsec = ns;
+       vcpu->arch.last_guest_tsc = data;
+
+       /* Keep track of which generation this VCPU has synchronized to */
+       vcpu->arch.this_tsc_generation = kvm->arch.cur_tsc_generation;
+       vcpu->arch.this_tsc_nsec = kvm->arch.cur_tsc_nsec;
+       vcpu->arch.this_tsc_write = kvm->arch.cur_tsc_write;
+
+       kvm_x86_ops->write_tsc_offset(vcpu, offset);
+       raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
 }
+
 EXPORT_SYMBOL_GPL(kvm_write_tsc);
 
 static int kvm_guest_time_update(struct kvm_vcpu *v)
@@ -1078,7 +1123,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
        local_irq_save(flags);
        tsc_timestamp = kvm_x86_ops->read_l1_tsc(v);
        kernel_ns = get_kernel_ns();
-       this_tsc_khz = vcpu_tsc_khz(v);
+       this_tsc_khz = __get_cpu_var(cpu_tsc_khz);
        if (unlikely(this_tsc_khz == 0)) {
                local_irq_restore(flags);
                kvm_make_request(KVM_REQ_CLOCK_UPDATE, v);
@@ -1098,7 +1143,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
        if (vcpu->tsc_catchup) {
                u64 tsc = compute_guest_tsc(v, kernel_ns);
                if (tsc > tsc_timestamp) {
-                       kvm_x86_ops->adjust_tsc_offset(v, tsc - tsc_timestamp);
+                       adjust_tsc_offset_guest(v, tsc - tsc_timestamp);
                        tsc_timestamp = tsc;
                }
        }
@@ -1130,7 +1175,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
         * observed by the guest and ensure the new system time is greater.
         */
        max_kernel_ns = 0;
-       if (vcpu->hv_clock.tsc_timestamp && vcpu->last_guest_tsc) {
+       if (vcpu->hv_clock.tsc_timestamp) {
                max_kernel_ns = vcpu->last_guest_tsc -
                                vcpu->hv_clock.tsc_timestamp;
                max_kernel_ns = pvclock_scale_delta(max_kernel_ns,
@@ -1504,6 +1549,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
        case MSR_K7_HWCR:
                data &= ~(u64)0x40;     /* ignore flush filter disable */
                data &= ~(u64)0x100;    /* ignore ignne emulation enable */
+               data &= ~(u64)0x8;      /* ignore TLB cache disable */
                if (data != 0) {
                        pr_unimpl(vcpu, "unimplemented HWCR wrmsr: 0x%llx\n",
                                data);
@@ -1676,6 +1722,16 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
                 */
                pr_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n", msr, data);
                break;
+       case MSR_AMD64_OSVW_ID_LENGTH:
+               if (!guest_cpuid_has_osvw(vcpu))
+                       return 1;
+               vcpu->arch.osvw.length = data;
+               break;
+       case MSR_AMD64_OSVW_STATUS:
+               if (!guest_cpuid_has_osvw(vcpu))
+                       return 1;
+               vcpu->arch.osvw.status = data;
+               break;
        default:
                if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
                        return xen_hvm_config(vcpu, data);
@@ -1960,6 +2016,16 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
                 */
                data = 0xbe702111;
                break;
+       case MSR_AMD64_OSVW_ID_LENGTH:
+               if (!guest_cpuid_has_osvw(vcpu))
+                       return 1;
+               data = vcpu->arch.osvw.length;
+               break;
+       case MSR_AMD64_OSVW_STATUS:
+               if (!guest_cpuid_has_osvw(vcpu))
+                       return 1;
+               data = vcpu->arch.osvw.status;
+               break;
        default:
                if (kvm_pmu_msr(vcpu, msr))
                        return kvm_pmu_get_msr(vcpu, msr, pdata);
@@ -2080,6 +2146,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_XSAVE:
        case KVM_CAP_ASYNC_PF:
        case KVM_CAP_GET_TSC_KHZ:
+       case KVM_CAP_PCI_2_3:
                r = 1;
                break;
        case KVM_CAP_COALESCED_MMIO:
@@ -2214,19 +2281,23 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        }
 
        kvm_x86_ops->vcpu_load(vcpu, cpu);
-       if (unlikely(vcpu->cpu != cpu) || check_tsc_unstable()) {
-               /* Make sure TSC doesn't go backwards */
-               s64 tsc_delta;
-               u64 tsc;
 
-               tsc = kvm_x86_ops->read_l1_tsc(vcpu);
-               tsc_delta = !vcpu->arch.last_guest_tsc ? 0 :
-                            tsc - vcpu->arch.last_guest_tsc;
+       /* Apply any externally detected TSC adjustments (due to suspend) */
+       if (unlikely(vcpu->arch.tsc_offset_adjustment)) {
+               adjust_tsc_offset_host(vcpu, vcpu->arch.tsc_offset_adjustment);
+               vcpu->arch.tsc_offset_adjustment = 0;
+               set_bit(KVM_REQ_CLOCK_UPDATE, &vcpu->requests);
+       }
 
+       if (unlikely(vcpu->cpu != cpu) || check_tsc_unstable()) {
+               s64 tsc_delta = !vcpu->arch.last_host_tsc ? 0 :
+                               native_read_tsc() - vcpu->arch.last_host_tsc;
                if (tsc_delta < 0)
                        mark_tsc_unstable("KVM discovered backwards TSC");
                if (check_tsc_unstable()) {
-                       kvm_x86_ops->adjust_tsc_offset(vcpu, -tsc_delta);
+                       u64 offset = kvm_x86_ops->compute_tsc_offset(vcpu,
+                                               vcpu->arch.last_guest_tsc);
+                       kvm_x86_ops->write_tsc_offset(vcpu, offset);
                        vcpu->arch.tsc_catchup = 1;
                }
                kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
@@ -2243,7 +2314,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
        kvm_x86_ops->vcpu_put(vcpu);
        kvm_put_guest_fpu(vcpu);
-       vcpu->arch.last_guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu);
+       vcpu->arch.last_host_tsc = native_read_tsc();
 }
 
 static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
@@ -2785,26 +2856,21 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                u32 user_tsc_khz;
 
                r = -EINVAL;
-               if (!kvm_has_tsc_control)
-                       break;
-
                user_tsc_khz = (u32)arg;
 
                if (user_tsc_khz >= kvm_max_guest_tsc_khz)
                        goto out;
 
-               kvm_x86_ops->set_tsc_khz(vcpu, user_tsc_khz);
+               if (user_tsc_khz == 0)
+                       user_tsc_khz = tsc_khz;
+
+               kvm_set_tsc_khz(vcpu, user_tsc_khz);
 
                r = 0;
                goto out;
        }
        case KVM_GET_TSC_KHZ: {
-               r = -EIO;
-               if (check_tsc_unstable())
-                       goto out;
-
-               r = vcpu_tsc_khz(vcpu);
-
+               r = vcpu->arch.virtual_tsc_khz;
                goto out;
        }
        default:
@@ -2815,6 +2881,11 @@ out:
        return r;
 }
 
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+       return VM_FAULT_SIGBUS;
+}
+
 static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr)
 {
        int ret;
@@ -2998,6 +3069,8 @@ static void write_protect_slot(struct kvm *kvm,
                               unsigned long *dirty_bitmap,
                               unsigned long nr_dirty_pages)
 {
+       spin_lock(&kvm->mmu_lock);
+
        /* Not many dirty pages compared to # of shadow pages. */
        if (nr_dirty_pages < kvm->arch.n_used_mmu_pages) {
                unsigned long gfn_offset;
@@ -3005,16 +3078,13 @@ static void write_protect_slot(struct kvm *kvm,
                for_each_set_bit(gfn_offset, dirty_bitmap, memslot->npages) {
                        unsigned long gfn = memslot->base_gfn + gfn_offset;
 
-                       spin_lock(&kvm->mmu_lock);
                        kvm_mmu_rmap_write_protect(kvm, gfn, memslot);
-                       spin_unlock(&kvm->mmu_lock);
                }
                kvm_flush_remote_tlbs(kvm);
-       } else {
-               spin_lock(&kvm->mmu_lock);
+       } else
                kvm_mmu_slot_remove_write_access(kvm, memslot->id);
-               spin_unlock(&kvm->mmu_lock);
-       }
+
+       spin_unlock(&kvm->mmu_lock);
 }
 
 /*
@@ -3133,6 +3203,9 @@ long kvm_arch_vm_ioctl(struct file *filp,
                r = -EEXIST;
                if (kvm->arch.vpic)
                        goto create_irqchip_unlock;
+               r = -EINVAL;
+               if (atomic_read(&kvm->online_vcpus))
+                       goto create_irqchip_unlock;
                r = -ENOMEM;
                vpic = kvm_create_pic(kvm);
                if (vpic) {
@@ -4063,6 +4136,11 @@ static int emulator_set_cr(struct x86_emulate_ctxt *ctxt, int cr, ulong val)
        return res;
 }
 
+static void emulator_set_rflags(struct x86_emulate_ctxt *ctxt, ulong val)
+{
+       kvm_set_rflags(emul_to_vcpu(ctxt), val);
+}
+
 static int emulator_get_cpl(struct x86_emulate_ctxt *ctxt)
 {
        return kvm_x86_ops->get_cpl(emul_to_vcpu(ctxt));
@@ -4244,6 +4322,7 @@ static struct x86_emulate_ops emulate_ops = {
        .set_idt             = emulator_set_idt,
        .get_cr              = emulator_get_cr,
        .set_cr              = emulator_set_cr,
+       .set_rflags          = emulator_set_rflags,
        .cpl                 = emulator_get_cpl,
        .get_dr              = emulator_get_dr,
        .set_dr              = emulator_set_dr,
@@ -5288,6 +5367,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                profile_hit(KVM_PROFILING, (void *)rip);
        }
 
+       if (unlikely(vcpu->arch.tsc_always_catchup))
+               kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 
        kvm_lapic_sync_from_vapic(vcpu);
 
@@ -5587,15 +5668,15 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
        return 0;
 }
 
-int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
-                   bool has_error_code, u32 error_code)
+int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
+                   int reason, bool has_error_code, u32 error_code)
 {
        struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
        int ret;
 
        init_emulate_ctxt(vcpu);
 
-       ret = emulator_task_switch(ctxt, tss_selector, reason,
+       ret = emulator_task_switch(ctxt, tss_selector, idt_index, reason,
                                   has_error_code, error_code);
 
        if (ret)
@@ -5928,13 +6009,88 @@ int kvm_arch_hardware_enable(void *garbage)
        struct kvm *kvm;
        struct kvm_vcpu *vcpu;
        int i;
+       int ret;
+       u64 local_tsc;
+       u64 max_tsc = 0;
+       bool stable, backwards_tsc = false;
 
        kvm_shared_msr_cpu_online();
-       list_for_each_entry(kvm, &vm_list, vm_list)
-               kvm_for_each_vcpu(i, vcpu, kvm)
-                       if (vcpu->cpu == smp_processor_id())
-                               kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
-       return kvm_x86_ops->hardware_enable(garbage);
+       ret = kvm_x86_ops->hardware_enable(garbage);
+       if (ret != 0)
+               return ret;
+
+       local_tsc = native_read_tsc();
+       stable = !check_tsc_unstable();
+       list_for_each_entry(kvm, &vm_list, vm_list) {
+               kvm_for_each_vcpu(i, vcpu, kvm) {
+                       if (!stable && vcpu->cpu == smp_processor_id())
+                               set_bit(KVM_REQ_CLOCK_UPDATE, &vcpu->requests);
+                       if (stable && vcpu->arch.last_host_tsc > local_tsc) {
+                               backwards_tsc = true;
+                               if (vcpu->arch.last_host_tsc > max_tsc)
+                                       max_tsc = vcpu->arch.last_host_tsc;
+                       }
+               }
+       }
+
+       /*
+        * Sometimes, even reliable TSCs go backwards.  This happens on
+        * platforms that reset TSC during suspend or hibernate actions, but
+        * maintain synchronization.  We must compensate.  Fortunately, we can
+        * detect that condition here, which happens early in CPU bringup,
+        * before any KVM threads can be running.  Unfortunately, we can't
+        * bring the TSCs fully up to date with real time, as we aren't yet far
+        * enough into CPU bringup that we know how much real time has actually
+        * elapsed; our helper function, get_kernel_ns() will be using boot
+        * variables that haven't been updated yet.
+        *
+        * So we simply find the maximum observed TSC above, then record the
+        * adjustment to TSC in each VCPU.  When the VCPU later gets loaded,
+        * the adjustment will be applied.  Note that we accumulate
+        * adjustments, in case multiple suspend cycles happen before some VCPU
+        * gets a chance to run again.  In the event that no KVM threads get a
+        * chance to run, we will miss the entire elapsed period, as we'll have
+        * reset last_host_tsc, so VCPUs will not have the TSC adjusted and may
+        * loose cycle time.  This isn't too big a deal, since the loss will be
+        * uniform across all VCPUs (not to mention the scenario is extremely
+        * unlikely). It is possible that a second hibernate recovery happens
+        * much faster than a first, causing the observed TSC here to be
+        * smaller; this would require additional padding adjustment, which is
+        * why we set last_host_tsc to the local tsc observed here.
+        *
+        * N.B. - this code below runs only on platforms with reliable TSC,
+        * as that is the only way backwards_tsc is set above.  Also note
+        * that this runs for ALL vcpus, which is not a bug; all VCPUs should
+        * have the same delta_cyc adjustment applied if backwards_tsc
+        * is detected.  Note further, this adjustment is only done once,
+        * as we reset last_host_tsc on all VCPUs to stop this from being
+        * called multiple times (one for each physical CPU bringup).
+        *
+        * Platforms with unnreliable TSCs don't have to deal with this, they
+        * will be compensated by the logic in vcpu_load, which sets the TSC to
+        * catchup mode.  This will catchup all VCPUs to real time, but cannot
+        * guarantee that they stay in perfect synchronization.
+        */
+       if (backwards_tsc) {
+               u64 delta_cyc = max_tsc - local_tsc;
+               list_for_each_entry(kvm, &vm_list, vm_list) {
+                       kvm_for_each_vcpu(i, vcpu, kvm) {
+                               vcpu->arch.tsc_offset_adjustment += delta_cyc;
+                               vcpu->arch.last_host_tsc = local_tsc;
+                       }
+
+                       /*
+                        * We have to disable TSC offset matching.. if you were
+                        * booting a VM while issuing an S4 host suspend....
+                        * you may have some problem.  Solving this issue is
+                        * left as an exercise to the reader.
+                        */
+                       kvm->arch.last_tsc_nsec = 0;
+                       kvm->arch.last_tsc_write = 0;
+               }
+
+       }
+       return 0;
 }
 
 void kvm_arch_hardware_disable(void *garbage)
@@ -5958,6 +6114,11 @@ void kvm_arch_check_processor_compat(void *rtn)
        kvm_x86_ops->check_processor_compatibility(rtn);
 }
 
+bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
+{
+       return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
+}
+
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
        struct page *page;
@@ -5980,7 +6141,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
        }
        vcpu->arch.pio_data = page_address(page);
 
-       kvm_init_tsc_catchup(vcpu, max_tsc_khz);
+       kvm_set_tsc_khz(vcpu, max_tsc_khz);
 
        r = kvm_mmu_create(vcpu);
        if (r < 0)
@@ -6032,8 +6193,11 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
        free_page((unsigned long)vcpu->arch.pio_data);
 }
 
-int kvm_arch_init_vm(struct kvm *kvm)
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
+       if (type)
+               return -EINVAL;
+
        INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
        INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
 
@@ -6093,6 +6257,65 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
                put_page(kvm->arch.ept_identity_pagetable);
 }
 
+void kvm_arch_free_memslot(struct kvm_memory_slot *free,
+                          struct kvm_memory_slot *dont)
+{
+       int i;
+
+       for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
+               if (!dont || free->arch.lpage_info[i] != dont->arch.lpage_info[i]) {
+                       vfree(free->arch.lpage_info[i]);
+                       free->arch.lpage_info[i] = NULL;
+               }
+       }
+}
+
+int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
+{
+       int i;
+
+       for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
+               unsigned long ugfn;
+               int lpages;
+               int level = i + 2;
+
+               lpages = gfn_to_index(slot->base_gfn + npages - 1,
+                                     slot->base_gfn, level) + 1;
+
+               slot->arch.lpage_info[i] =
+                       vzalloc(lpages * sizeof(*slot->arch.lpage_info[i]));
+               if (!slot->arch.lpage_info[i])
+                       goto out_free;
+
+               if (slot->base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
+                       slot->arch.lpage_info[i][0].write_count = 1;
+               if ((slot->base_gfn + npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
+                       slot->arch.lpage_info[i][lpages - 1].write_count = 1;
+               ugfn = slot->userspace_addr >> PAGE_SHIFT;
+               /*
+                * If the gfn and userspace address are not aligned wrt each
+                * other, or if explicitly asked to, disable large page
+                * support for this slot
+                */
+               if ((slot->base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE(level) - 1) ||
+                   !kvm_largepages_enabled()) {
+                       unsigned long j;
+
+                       for (j = 0; j < lpages; ++j)
+                               slot->arch.lpage_info[i][j].write_count = 1;
+               }
+       }
+
+       return 0;
+
+out_free:
+       for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
+               vfree(slot->arch.lpage_info[i]);
+               slot->arch.lpage_info[i] = NULL;
+       }
+       return -ENOMEM;
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                struct kvm_memory_slot *memslot,
                                struct kvm_memory_slot old,
index 036efbe..aef7140 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #include "opcode.h"
index 49a5cb5..ed2835e 100644 (file)
@@ -416,7 +416,12 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
                kfree(sd);
        } else {
                get_current_resources(device, busnum, domain, &resources);
-               if (list_empty(&resources))
+
+               /*
+                * _CRS with no apertures is normal, so only fall back to
+                * defaults or native bridge info if we're ignoring _CRS.
+                */
+               if (!pci_use_crs)
                        x86_pci_root_bus_resources(busnum, &resources);
                bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd,
                                          &resources);
index 6dd8955..d0e6e40 100644 (file)
@@ -164,11 +164,11 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_
  */
 static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev)
 {
-       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
-           (dev->device & 0xff00) == 0x2400)
+       if ((dev->device & 0xff00) == 0x2400)
                dev->transparent = 1;
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
+                        PCI_CLASS_BRIDGE_PCI, 8, pci_fixup_transparent_bridge);
 
 /*
  * Fixup for C1 Halt Disconnect problem on nForce2 systems.
@@ -322,9 +322,6 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
        struct pci_bus *bus;
        u16 config;
 
-       if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
-               return;
-
        /* Is VGA routed to us? */
        bus = pdev->bus;
        while (bus) {
@@ -353,7 +350,8 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
                dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+                               PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
 
 
 static const struct dmi_system_id __devinitconst msi_k8t_dmi_table[] = {
index 91821a1..831971e 100644 (file)
 #include <asm/io_apic.h>
 
 
+/*
+ * This list of dynamic mappings is for temporarily maintaining
+ * original BIOS BAR addresses for possible reinstatement.
+ */
+struct pcibios_fwaddrmap {
+       struct list_head list;
+       struct pci_dev *dev;
+       resource_size_t fw_addr[DEVICE_COUNT_RESOURCE];
+};
+
+static LIST_HEAD(pcibios_fwaddrmappings);
+static DEFINE_SPINLOCK(pcibios_fwaddrmap_lock);
+
+/* Must be called with 'pcibios_fwaddrmap_lock' lock held. */
+static struct pcibios_fwaddrmap *pcibios_fwaddrmap_lookup(struct pci_dev *dev)
+{
+       struct pcibios_fwaddrmap *map;
+
+       WARN_ON(!spin_is_locked(&pcibios_fwaddrmap_lock));
+
+       list_for_each_entry(map, &pcibios_fwaddrmappings, list)
+               if (map->dev == dev)
+                       return map;
+
+       return NULL;
+}
+
+static void
+pcibios_save_fw_addr(struct pci_dev *dev, int idx, resource_size_t fw_addr)
+{
+       unsigned long flags;
+       struct pcibios_fwaddrmap *map;
+
+       spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+       map = pcibios_fwaddrmap_lookup(dev);
+       if (!map) {
+               spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+               map = kzalloc(sizeof(*map), GFP_KERNEL);
+               if (!map)
+                       return;
+
+               map->dev = pci_dev_get(dev);
+               map->fw_addr[idx] = fw_addr;
+               INIT_LIST_HEAD(&map->list);
+
+               spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+               list_add_tail(&map->list, &pcibios_fwaddrmappings);
+       } else
+               map->fw_addr[idx] = fw_addr;
+       spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+}
+
+resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
+{
+       unsigned long flags;
+       struct pcibios_fwaddrmap *map;
+       resource_size_t fw_addr = 0;
+
+       spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+       map = pcibios_fwaddrmap_lookup(dev);
+       if (map)
+               fw_addr = map->fw_addr[idx];
+       spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+
+       return fw_addr;
+}
+
+static void pcibios_fw_addr_list_del(void)
+{
+       unsigned long flags;
+       struct pcibios_fwaddrmap *entry, *next;
+
+       spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
+       list_for_each_entry_safe(entry, next, &pcibios_fwaddrmappings, list) {
+               list_del(&entry->list);
+               pci_dev_put(entry->dev);
+               kfree(entry);
+       }
+       spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
+}
+
 static int
 skip_isa_ioresource_align(struct pci_dev *dev) {
 
@@ -182,7 +263,8 @@ static void __init pcibios_allocate_resources(int pass)
                                        idx, r, disabled, pass);
                                if (pci_claim_resource(dev, idx) < 0) {
                                        /* We'll assign a new address later */
-                                       dev->fw_addr[idx] = r->start;
+                                       pcibios_save_fw_addr(dev,
+                                                       idx, r->start);
                                        r->end -= r->start;
                                        r->start = 0;
                                }
@@ -228,6 +310,7 @@ static int __init pcibios_assign_resources(void)
        }
 
        pci_assign_unassigned_resources();
+       pcibios_fw_addr_list_del();
 
        return 0;
 }
index cb29191..140942f 100644 (file)
@@ -43,6 +43,8 @@
 #define PCI_FIXED_BAR_4_SIZE   0x14
 #define PCI_FIXED_BAR_5_SIZE   0x1c
 
+static int pci_soc_mode = 0;
+
 /**
  * fixed_bar_cap - return the offset of the fixed BAR cap if found
  * @bus: PCI bus
@@ -148,7 +150,9 @@ static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg)
         */
        if (reg >= 0x100 || reg == PCI_STATUS || reg == PCI_HEADER_TYPE)
                return 0;
-       if (bus == 0 && (devfn == PCI_DEVFN(2, 0) || devfn == PCI_DEVFN(0, 0)))
+       if (bus == 0 && (devfn == PCI_DEVFN(2, 0)
+                               || devfn == PCI_DEVFN(0, 0)
+                               || devfn == PCI_DEVFN(3, 0)))
                return 1;
        return 0; /* langwell on others */
 }
@@ -231,14 +235,43 @@ struct pci_ops pci_mrst_ops = {
  */
 int __init pci_mrst_init(void)
 {
-       printk(KERN_INFO "Moorestown platform detected, using MRST PCI ops\n");
+       printk(KERN_INFO "Intel MID platform detected, using MID PCI ops\n");
        pci_mmcfg_late_init();
        pcibios_enable_irq = mrst_pci_irq_enable;
        pci_root_ops = pci_mrst_ops;
+       pci_soc_mode = 1;
        /* Continue with standard init */
        return 1;
 }
 
+/* Langwell devices are not true pci devices, they are not subject to 10 ms
+ * d3 to d0 delay required by pci spec.
+ */
+static void __devinit pci_d3delay_fixup(struct pci_dev *dev)
+{
+       /* PCI fixups are effectively decided compile time. If we have a dual
+          SoC/non-SoC kernel we don't want to mangle d3 on non SoC devices */
+        if (!pci_soc_mode)
+            return;
+       /* true pci devices in lincroft should allow type 1 access, the rest
+        * are langwell fake pci devices.
+        */
+       if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID))
+               return;
+       dev->d3_delay = 0;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup);
+
+static void __devinit mrst_power_off_unused_dev(struct pci_dev *dev)
+{
+       pci_set_power_state(dev, PCI_D3cold);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0801, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0809, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x080C, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0812, mrst_power_off_unused_dev);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mrst_power_off_unused_dev);
+
 /*
  * Langwell devices reside at fixed offsets, don't try to move them.
  */
@@ -248,6 +281,9 @@ static void __devinit pci_fixed_bar_fixup(struct pci_dev *dev)
        u32 size;
        int i;
 
+       if (!pci_soc_mode)
+               return;
+
        /* Must have extended configuration space */
        if (dev->cfg_size < PCIE_CAP_OFFSET + 4)
                return;
index e70be38..ce874f8 100644 (file)
                                        interrupts = <14 1>;
                                };
 
-                               gpio@b,1 {
+                               pcigpio: gpio@b,1 {
+                                       #gpio-cells = <2>;
+                                       #interrupt-cells = <2>;
                                        compatible = "pci8086,2e67.2",
                                                   "pci8086,2e67",
                                                   "pciclassff0000",
                                                   "pciclassff00";
 
-                                       #gpio-cells = <2>;
                                        reg = <0x15900 0x0 0x0 0x0 0x0>;
                                        interrupts = <15 1>;
+                                       interrupt-controller;
                                        gpio-controller;
+                                       intel,muxctl = <0>;
                                };
 
                                i2c-controller@b,2 {
index 246b788..5b51194 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ALIX)             += alix.o
 obj-$(CONFIG_NET5501)          += net5501.o
+obj-$(CONFIG_GEOS)             += geos.o
diff --git a/arch/x86/platform/geode/geos.c b/arch/x86/platform/geode/geos.c
new file mode 100644 (file)
index 0000000..c2e6d53
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * System Specific setup for Traverse Technologies GEOS.
+ * At the moment this means setup of GPIO control of LEDs.
+ *
+ * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
+ * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com>
+ *                and Philip Prindeville <philipp@redfish-solutions.com>
+ *
+ * TODO: There are large similarities with leds-net5501.c
+ * by Alessandro Zummo <a.zummo@towertech.it>
+ * In the future leds-net5501.c should be migrated over to platform
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/dmi.h>
+
+#include <asm/geode.h>
+
+static struct gpio_keys_button geos_gpio_buttons[] = {
+       {
+               .code = KEY_RESTART,
+               .gpio = 3,
+               .active_low = 1,
+               .desc = "Reset button",
+               .type = EV_KEY,
+               .wakeup = 0,
+               .debounce_interval = 100,
+               .can_disable = 0,
+       }
+};
+static struct gpio_keys_platform_data geos_buttons_data = {
+       .buttons = geos_gpio_buttons,
+       .nbuttons = ARRAY_SIZE(geos_gpio_buttons),
+       .poll_interval = 20,
+};
+
+static struct platform_device geos_buttons_dev = {
+       .name = "gpio-keys-polled",
+       .id = 1,
+       .dev = {
+               .platform_data = &geos_buttons_data,
+       }
+};
+
+static struct gpio_led geos_leds[] = {
+       {
+               .name = "geos:1",
+               .gpio = 6,
+               .default_trigger = "default-on",
+               .active_low = 1,
+       },
+       {
+               .name = "geos:2",
+               .gpio = 25,
+               .default_trigger = "default-off",
+               .active_low = 1,
+       },
+       {
+               .name = "geos:3",
+               .gpio = 27,
+               .default_trigger = "default-off",
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led_platform_data geos_leds_data = {
+       .num_leds = ARRAY_SIZE(geos_leds),
+       .leds = geos_leds,
+};
+
+static struct platform_device geos_leds_dev = {
+       .name = "leds-gpio",
+       .id = -1,
+       .dev.platform_data = &geos_leds_data,
+};
+
+static struct __initdata platform_device *geos_devs[] = {
+       &geos_buttons_dev,
+       &geos_leds_dev,
+};
+
+static void __init register_geos(void)
+{
+       /* Setup LED control through leds-gpio driver */
+       platform_add_devices(geos_devs, ARRAY_SIZE(geos_devs));
+}
+
+static int __init geos_init(void)
+{
+       const char *vendor, *product;
+
+       if (!is_geode())
+               return 0;
+
+       vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+       if (!vendor || strcmp(vendor, "Traverse Technologies"))
+               return 0;
+
+       product = dmi_get_system_info(DMI_PRODUCT_NAME);
+       if (!product || strcmp(product, "Geos"))
+               return 0;
+
+       printk(KERN_INFO "%s: system is recognized as \"%s %s\"\n",
+              KBUILD_MODNAME, vendor, product);
+
+       register_geos();
+
+       return 0;
+}
+
+module_init(geos_init);
+
+MODULE_AUTHOR("Philip Prindeville <philipp@redfish-solutions.com>");
+MODULE_DESCRIPTION("Traverse Technologies Geos System Setup");
+MODULE_LICENSE("GPL");
index 4889655..4793683 100644 (file)
@@ -115,7 +115,7 @@ static void __save_processor_state(struct saved_context *ctxt)
 void save_processor_state(void)
 {
        __save_processor_state(&saved_context);
-       save_sched_clock_state();
+       x86_platform.save_sched_clock_state();
 }
 #ifdef CONFIG_X86_32
 EXPORT_SYMBOL(save_processor_state);
@@ -231,8 +231,8 @@ static void __restore_processor_state(struct saved_context *ctxt)
 /* Needed by apm.c */
 void restore_processor_state(void)
 {
+       x86_platform.restore_sched_clock_state();
        __restore_processor_state(&saved_context);
-       restore_sched_clock_state();
 }
 #ifdef CONFIG_X86_32
 EXPORT_SYMBOL(restore_processor_state);
index ce98e28..e7e67cc 100644 (file)
 279    i386    mq_timedsend            sys_mq_timedsend                compat_sys_mq_timedsend
 280    i386    mq_timedreceive         sys_mq_timedreceive             compat_sys_mq_timedreceive
 281    i386    mq_notify               sys_mq_notify                   compat_sys_mq_notify
-282    i386    mq_getsetaddr           sys_mq_getsetattr               compat_sys_mq_getsetattr
+282    i386    mq_getsetattr           sys_mq_getsetattr               compat_sys_mq_getsetattr
 283    i386    kexec_load              sys_kexec_load                  compat_sys_kexec_load
 284    i386    waitid                  sys_waitid                      compat_sys_waitid
 # 285 sys_setaltroot
index b2b54d2..9926e11 100644 (file)
@@ -15,8 +15,8 @@ config UML_X86
        select GENERIC_FIND_FIRST_BIT
 
 config 64BIT
-       bool
-       default SUBARCH = "x86_64"
+       bool "64-bit kernel" if SUBARCH = "x86"
+       default SUBARCH != "i386"
 
 config X86_32
        def_bool !64BIT
index 2c32df6..04f82e0 100644 (file)
 #define ARCH_IS_STACKGROW(address) \
        (address + 65536 + 32 * sizeof(unsigned long) >= UPT_SP(&current->thread.regs.regs))
 
+#include <asm/user.h>
+
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+static inline void rep_nop(void)
+{
+       __asm__ __volatile__("rep;nop": : :"memory");
+}
+
+#define cpu_relax()    rep_nop()
+
 #include <asm/processor-generic.h>
 
 #endif
index 018f732..6c6689e 100644 (file)
@@ -45,16 +45,6 @@ static inline void arch_copy_thread(struct arch_thread *from,
         memcpy(&to->tls_array, &from->tls_array, sizeof(from->tls_array));
 }
 
-#include <asm/user.h>
-
-/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
-static inline void rep_nop(void)
-{
-       __asm__ __volatile__("rep;nop": : :"memory");
-}
-
-#define cpu_relax()    rep_nop()
-
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter"). Stolen
index 61de92d..4b02a84 100644 (file)
@@ -14,14 +14,6 @@ struct arch_thread {
         struct faultinfo faultinfo;
 };
 
-/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
-static inline void rep_nop(void)
-{
-       __asm__ __volatile__("rep;nop": : :"memory");
-}
-
-#define cpu_relax()   rep_nop()
-
 #define INIT_ARCH_THREAD { .debugregs                  = { [ 0 ... 7 ] = 0 }, \
                           .debugregs_seq       = 0, \
                           .fs                  = 0, \
@@ -37,8 +29,6 @@ static inline void arch_copy_thread(struct arch_thread *from,
        to->fs = from->fs;
 }
 
-#include <asm/user.h>
-
 #define current_text_addr() \
        ({ void *pc; __asm__("movq $1f,%0\n1:":"=g" (pc)); pc; })
 
index a1fba5f..17d88cf 100644 (file)
@@ -13,8 +13,6 @@
 static int host_has_cmov = 1;
 static jmp_buf cmov_test_return;
 
-#define TASK_PID(task) *((int *) &(((char *) (task))[HOST_TASK_PID]))
-
 static void cmov_sigill_test_handler(int sig)
 {
        host_has_cmov = 0;
@@ -51,7 +49,7 @@ void arch_examine_signal(int sig, struct uml_pt_regs *regs)
         * This is testing for a cmov (0x0f 0x4x) instruction causing a
         * SIGILL in init.
         */
-       if ((sig != SIGILL) || (TASK_PID(get_current()) != 1))
+       if ((sig != SIGILL) || (get_current_pid() != 1))
                return;
 
        if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) {
index 639900a..f40281e 100644 (file)
@@ -23,14 +23,6 @@ static int __init gate_vma_init(void)
        gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
        gate_vma.vm_page_prot = __P101;
 
-       /*
-        * Make sure the vDSO gets into every core dump.
-        * Dumping its contents makes post-mortem fully interpretable later
-        * without matching up the same kernel and hardware config to see
-        * what PC values meant.
-        */
-       gate_vma.vm_flags |= VM_ALWAYSDUMP;
-
        return 0;
 }
 __initcall(gate_vma_init);
index 91f4ec9..af91901 100644 (file)
@@ -64,8 +64,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 
        err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE,
                VM_READ|VM_EXEC|
-               VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-               VM_ALWAYSDUMP,
+               VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
                vdsop);
 
        up_write(&mm->mmap_sem);
index 468d591..a944020 100644 (file)
@@ -250,13 +250,7 @@ static int __init gate_vma_init(void)
        gate_vma.vm_end = FIXADDR_USER_END;
        gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
        gate_vma.vm_page_prot = __P101;
-       /*
-        * Make sure the vDSO gets into every core dump.
-        * Dumping its contents makes post-mortem fully interpretable later
-        * without matching up the same kernel and hardware config to see
-        * what PC values meant.
-        */
-       gate_vma.vm_flags |= VM_ALWAYSDUMP;
+
        return 0;
 }
 
@@ -343,17 +337,10 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        if (compat_uses_vma || !compat) {
                /*
                 * MAYWRITE to allow gdb to COW and set breakpoints
-                *
-                * Make sure the vDSO gets into every core dump.
-                * Dumping its contents makes post-mortem fully
-                * interpretable later without matching up the same
-                * kernel and hardware config to see what PC values
-                * meant.
                 */
                ret = install_special_mapping(mm, addr, PAGE_SIZE,
                                              VM_READ|VM_EXEC|
-                                             VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-                                             VM_ALWAYSDUMP,
+                                             VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
                                              vdso32_pages);
 
                if (ret)
index 153407c..17e1827 100644 (file)
@@ -124,8 +124,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 
        ret = install_special_mapping(mm, addr, vdso_size,
                                      VM_READ|VM_EXEC|
-                                     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-                                     VM_ALWAYSDUMP,
+                                     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
                                      vdso_pages);
        if (ret) {
                current->mm->context.vdso = NULL;
index 1236623..1ba8dff 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/pm.h>
 #include <linux/memblock.h>
 #include <linux/cpuidle.h>
+#include <linux/cpufreq.h>
 
 #include <asm/elf.h>
 #include <asm/vdso.h>
@@ -420,6 +421,7 @@ void __init xen_arch_setup(void)
        boot_cpu_data.hlt_works_ok = 1;
 #endif
        disable_cpuidle();
+       disable_cpufreq();
        WARN_ON(set_pm_idle_to_default());
        fiddle_vdso();
 }
index 315d8fa..02900e8 100644 (file)
@@ -75,8 +75,14 @@ static void __cpuinit cpu_bringup(void)
 
        xen_setup_cpu_clockevents();
 
+       notify_cpu_starting(cpu);
+
+       ipi_call_lock();
        set_cpu_online(cpu, true);
+       ipi_call_unlock();
+
        this_cpu_write(cpu_state, CPU_ONLINE);
+
        wmb();
 
        /* We can take interrupts now: we're officially "up". */
index 3078901..25bc6c1 100644 (file)
 #define MADV_HUGEPAGE  14              /* Worth backing with hugepages */
 #define MADV_NOHUGEPAGE        15              /* Not worth backing with hugepages */
 
+#define MADV_DONTDUMP   16             /* Explicity exclude from the core dump,
+                                          overrides the coredump filter bits */
+#define MADV_DODUMP    17              /* Clear the MADV_NODUMP flag */
+
 /* compatibility flags */
 #define MAP_FILE       0
 
index 61045c1..eb30e35 100644 (file)
@@ -153,7 +153,7 @@ static void __init pci_controller_apertures(struct pci_controller *pci_ctrl,
        }
        res->start += io_offset;
        res->end += io_offset;
-       pci_add_resource(resources, res);
+       pci_add_resource_offset(resources, res, io_offset);
 
        for (i = 0; i < 3; i++) {
                res = &pci_ctrl->mem_resources[i];
@@ -200,24 +200,9 @@ subsys_initcall(pcibios_init);
 
 void __init pcibios_fixup_bus(struct pci_bus *bus)
 {
-       struct pci_controller *pci_ctrl = bus->sysdata;
-       struct resource *res;
-       unsigned long io_offset;
-       int i;
-
-       io_offset = (unsigned long)pci_ctrl->io_space.base;
        if (bus->parent) {
                /* This is a subordinate bridge */
                pci_read_bridge_bases(bus);
-
-               for (i = 0; i < 4; i++) {
-                       if ((res = bus->resource[i]) == NULL || !res->flags)
-                               continue;
-                       if (io_offset && (res->flags & IORESOURCE_IO)) {
-                               res->start += io_offset;
-                               res->end += io_offset;
-                       }
-               }
        }
 }
 
index 6318edd..21ff9d0 100644 (file)
@@ -308,6 +308,7 @@ comment "Digest"
 config CRYPTO_CRC32C
        tristate "CRC32c CRC algorithm"
        select CRYPTO_HASH
+       select CRC32
        help
          Castagnoli, et al Cyclic Redundancy-Check Algorithm.  Used
          by iSCSI for header and data digests and by others.
index 3f9ad28..06f7018 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/crc32.h>
 
 #define CHKSUM_BLOCK_SIZE      1
 #define CHKSUM_DIGEST_SIZE     4
@@ -53,95 +54,6 @@ struct chksum_desc_ctx {
 };
 
 /*
- * This is the CRC-32C table
- * Generated with:
- * width = 32 bits
- * poly = 0x1EDC6F41
- * reflect input bytes = true
- * reflect output bytes = true
- */
-
-static const u32 crc32c_table[256] = {
-       0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
-       0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
-       0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
-       0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
-       0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
-       0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
-       0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
-       0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
-       0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
-       0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
-       0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
-       0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
-       0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
-       0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
-       0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
-       0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
-       0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
-       0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
-       0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
-       0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
-       0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
-       0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
-       0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
-       0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
-       0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
-       0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
-       0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
-       0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
-       0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
-       0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
-       0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
-       0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
-       0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
-       0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
-       0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
-       0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
-       0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
-       0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
-       0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
-       0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
-       0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
-       0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
-       0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
-       0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
-       0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
-       0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
-       0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
-       0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
-       0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
-       0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
-       0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
-       0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
-       0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
-       0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
-       0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
-       0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
-       0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
-       0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
-       0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
-       0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
-       0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
-       0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
-       0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
-       0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
-};
-
-/*
- * Steps through buffer one byte at at time, calculates reflected
- * crc using table.
- */
-
-static u32 crc32c(u32 crc, const u8 *data, unsigned int length)
-{
-       while (length--)
-               crc = crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8);
-
-       return crc;
-}
-
-/*
  * Steps through buffer one byte at at time, calculates reflected
  * crc using table.
  */
@@ -179,7 +91,7 @@ static int chksum_update(struct shash_desc *desc, const u8 *data,
 {
        struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
 
-       ctx->crc = crc32c(ctx->crc, data, length);
+       ctx->crc = __crc32c_le(ctx->crc, data, length);
        return 0;
 }
 
@@ -193,7 +105,7 @@ static int chksum_final(struct shash_desc *desc, u8 *out)
 
 static int __chksum_finup(u32 *crcp, const u8 *data, unsigned int len, u8 *out)
 {
-       *(__le32 *)out = ~cpu_to_le32(crc32c(*crcp, data, len));
+       *(__le32 *)out = ~cpu_to_le32(__crc32c_le(*crcp, data, len));
        return 0;
 }
 
index decf8e4..6f0459c 100644 (file)
@@ -130,6 +130,10 @@ source "drivers/clocksource/Kconfig"
 
 source "drivers/iommu/Kconfig"
 
+source "drivers/remoteproc/Kconfig"
+
+source "drivers/rpmsg/Kconfig"
+
 source "drivers/virt/Kconfig"
 
 source "drivers/devfreq/Kconfig"
index 932e8bf..262b19d 100644 (file)
@@ -125,6 +125,8 @@ obj-y                               += clk/
 obj-$(CONFIG_HWSPINLOCK)       += hwspinlock/
 obj-$(CONFIG_NFC)              += nfc/
 obj-$(CONFIG_IOMMU_SUPPORT)    += iommu/
+obj-$(CONFIG_REMOTEPROC)       += remoteproc/
+obj-$(CONFIG_RPMSG)            += rpmsg/
 
 # Virtualization drivers
 obj-$(CONFIG_VIRT_DRIVERS)     += virt/
index b19a18d..e37615f 100644 (file)
@@ -445,6 +445,16 @@ int ec_transaction(u8 command,
 
 EXPORT_SYMBOL(ec_transaction);
 
+/* Get the handle to the EC device */
+acpi_handle ec_get_handle(void)
+{
+       if (!first_ec)
+               return NULL;
+       return first_ec->handle;
+}
+
+EXPORT_SYMBOL(ec_get_handle);
+
 void acpi_ec_block_transactions(void)
 {
        struct acpi_ec *ec = first_ec;
index f3f0fe7..45d8097 100644 (file)
@@ -23,7 +23,7 @@
  * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
  * are available, video.ko should be used to handle the device.
  *
- * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi,
+ * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
  * sony_acpi,... can take care about backlight brightness.
  *
  * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
index 54eaf96..01c2cf4 100644 (file)
@@ -497,37 +497,22 @@ static void amba_device_release(struct device *dev)
 }
 
 /**
- *     amba_device_register - register an AMBA device
- *     @dev: AMBA device to register
- *     @parent: parent memory resource
+ *     amba_device_add - add a previously allocated AMBA device structure
+ *     @dev: AMBA device allocated by amba_device_alloc
+ *     @parent: resource parent for this devices resources
  *
- *     Setup the AMBA device, reading the cell ID if present.
- *     Claim the resource, and register the AMBA device with
- *     the Linux device manager.
+ *     Claim the resource, and read the device cell ID if not already
+ *     initialized.  Register the AMBA device with the Linux device
+ *     manager.
  */
-int amba_device_register(struct amba_device *dev, struct resource *parent)
+int amba_device_add(struct amba_device *dev, struct resource *parent)
 {
        u32 size;
        void __iomem *tmp;
        int i, ret;
 
-       device_initialize(&dev->dev);
-
-       /*
-        * Copy from device_add
-        */
-       if (dev->dev.init_name) {
-               dev_set_name(&dev->dev, "%s", dev->dev.init_name);
-               dev->dev.init_name = NULL;
-       }
-
-       dev->dev.release = amba_device_release;
-       dev->dev.bus = &amba_bustype;
-       dev->dev.dma_mask = &dev->dma_mask;
-       dev->res.name = dev_name(&dev->dev);
-
-       if (!dev->dev.coherent_dma_mask && dev->dma_mask)
-               dev_warn(&dev->dev, "coherent dma mask is unset\n");
+       WARN_ON(dev->irq[0] == (unsigned int)-1);
+       WARN_ON(dev->irq[1] == (unsigned int)-1);
 
        ret = request_resource(parent, &dev->res);
        if (ret)
@@ -582,9 +567,9 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
        if (ret)
                goto err_release;
 
-       if (dev->irq[0] != NO_IRQ)
+       if (dev->irq[0] && dev->irq[0] != NO_IRQ)
                ret = device_create_file(&dev->dev, &dev_attr_irq0);
-       if (ret == 0 && dev->irq[1] != NO_IRQ)
+       if (ret == 0 && dev->irq[1] && dev->irq[1] != NO_IRQ)
                ret = device_create_file(&dev->dev, &dev_attr_irq1);
        if (ret == 0)
                return ret;
@@ -596,6 +581,74 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
  err_out:
        return ret;
 }
+EXPORT_SYMBOL_GPL(amba_device_add);
+
+static void amba_device_initialize(struct amba_device *dev, const char *name)
+{
+       device_initialize(&dev->dev);
+       if (name)
+               dev_set_name(&dev->dev, "%s", name);
+       dev->dev.release = amba_device_release;
+       dev->dev.bus = &amba_bustype;
+       dev->dev.dma_mask = &dev->dma_mask;
+       dev->res.name = dev_name(&dev->dev);
+}
+
+/**
+ *     amba_device_alloc - allocate an AMBA device
+ *     @name: sysfs name of the AMBA device
+ *     @base: base of AMBA device
+ *     @size: size of AMBA device
+ *
+ *     Allocate and initialize an AMBA device structure.  Returns %NULL
+ *     on failure.
+ */
+struct amba_device *amba_device_alloc(const char *name, resource_size_t base,
+       size_t size)
+{
+       struct amba_device *dev;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev) {
+               amba_device_initialize(dev, name);
+               dev->res.start = base;
+               dev->res.end = base + size - 1;
+               dev->res.flags = IORESOURCE_MEM;
+       }
+
+       return dev;
+}
+EXPORT_SYMBOL_GPL(amba_device_alloc);
+
+/**
+ *     amba_device_register - register an AMBA device
+ *     @dev: AMBA device to register
+ *     @parent: parent memory resource
+ *
+ *     Setup the AMBA device, reading the cell ID if present.
+ *     Claim the resource, and register the AMBA device with
+ *     the Linux device manager.
+ */
+int amba_device_register(struct amba_device *dev, struct resource *parent)
+{
+       amba_device_initialize(dev, dev->dev.init_name);
+       dev->dev.init_name = NULL;
+
+       if (!dev->dev.coherent_dma_mask && dev->dma_mask)
+               dev_warn(&dev->dev, "coherent dma mask is unset\n");
+
+       return amba_device_add(dev, parent);
+}
+
+/**
+ *     amba_device_put - put an AMBA device
+ *     @dev: AMBA device to put
+ */
+void amba_device_put(struct amba_device *dev)
+{
+       put_device(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(amba_device_put);
 
 /**
  *     amba_device_unregister - unregister an AMBA device
index e38ad24..07cbbc6 100644 (file)
@@ -71,7 +71,7 @@ static inline int is_dma_buf_file(struct file *file)
  * ops, or error in allocating struct dma_buf, will return negative error.
  *
  */
-struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
+struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
                                size_t size, int flags)
 {
        struct dma_buf *dmabuf;
@@ -80,7 +80,9 @@ struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
        if (WARN_ON(!priv || !ops
                          || !ops->map_dma_buf
                          || !ops->unmap_dma_buf
-                         || !ops->release)) {
+                         || !ops->release
+                         || !ops->kmap_atomic
+                         || !ops->kmap)) {
                return ERR_PTR(-EINVAL);
        }
 
@@ -107,17 +109,18 @@ EXPORT_SYMBOL_GPL(dma_buf_export);
 /**
  * dma_buf_fd - returns a file descriptor for the given dma_buf
  * @dmabuf:    [in]    pointer to dma_buf for which fd is required.
+ * @flags:      [in]    flags to give to fd
  *
  * On success, returns an associated 'fd'. Else, returns error.
  */
-int dma_buf_fd(struct dma_buf *dmabuf)
+int dma_buf_fd(struct dma_buf *dmabuf, int flags)
 {
        int error, fd;
 
        if (!dmabuf || !dmabuf->file)
                return -EINVAL;
 
-       error = get_unused_fd();
+       error = get_unused_fd_flags(flags);
        if (error < 0)
                return error;
        fd = error;
@@ -185,17 +188,18 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
        struct dma_buf_attachment *attach;
        int ret;
 
-       if (WARN_ON(!dmabuf || !dev || !dmabuf->ops))
+       if (WARN_ON(!dmabuf || !dev))
                return ERR_PTR(-EINVAL);
 
        attach = kzalloc(sizeof(struct dma_buf_attachment), GFP_KERNEL);
        if (attach == NULL)
-               goto err_alloc;
-
-       mutex_lock(&dmabuf->lock);
+               return ERR_PTR(-ENOMEM);
 
        attach->dev = dev;
        attach->dmabuf = dmabuf;
+
+       mutex_lock(&dmabuf->lock);
+
        if (dmabuf->ops->attach) {
                ret = dmabuf->ops->attach(dmabuf, dev, attach);
                if (ret)
@@ -206,8 +210,6 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
        mutex_unlock(&dmabuf->lock);
        return attach;
 
-err_alloc:
-       return ERR_PTR(-ENOMEM);
 err_attach:
        kfree(attach);
        mutex_unlock(&dmabuf->lock);
@@ -224,7 +226,7 @@ EXPORT_SYMBOL_GPL(dma_buf_attach);
  */
 void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
 {
-       if (WARN_ON(!dmabuf || !attach || !dmabuf->ops))
+       if (WARN_ON(!dmabuf || !attach))
                return;
 
        mutex_lock(&dmabuf->lock);
@@ -255,13 +257,10 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
 
        might_sleep();
 
-       if (WARN_ON(!attach || !attach->dmabuf || !attach->dmabuf->ops))
+       if (WARN_ON(!attach || !attach->dmabuf))
                return ERR_PTR(-EINVAL);
 
-       mutex_lock(&attach->dmabuf->lock);
-       if (attach->dmabuf->ops->map_dma_buf)
-               sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
-       mutex_unlock(&attach->dmabuf->lock);
+       sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
 
        return sg_table;
 }
@@ -273,19 +272,137 @@ EXPORT_SYMBOL_GPL(dma_buf_map_attachment);
  * dma_buf_ops.
  * @attach:    [in]    attachment to unmap buffer from
  * @sg_table:  [in]    scatterlist info of the buffer to unmap
+ * @direction:  [in]    direction of DMA transfer
  *
  */
 void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
-                               struct sg_table *sg_table)
+                               struct sg_table *sg_table,
+                               enum dma_data_direction direction)
 {
-       if (WARN_ON(!attach || !attach->dmabuf || !sg_table
-                           || !attach->dmabuf->ops))
+       if (WARN_ON(!attach || !attach->dmabuf || !sg_table))
                return;
 
-       mutex_lock(&attach->dmabuf->lock);
-       if (attach->dmabuf->ops->unmap_dma_buf)
-               attach->dmabuf->ops->unmap_dma_buf(attach, sg_table);
-       mutex_unlock(&attach->dmabuf->lock);
-
+       attach->dmabuf->ops->unmap_dma_buf(attach, sg_table,
+                                               direction);
 }
 EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
+
+
+/**
+ * dma_buf_begin_cpu_access - Must be called before accessing a dma_buf from the
+ * cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific
+ * preparations. Coherency is only guaranteed in the specified range for the
+ * specified access direction.
+ * @dma_buf:   [in]    buffer to prepare cpu access for.
+ * @start:     [in]    start of range for cpu access.
+ * @len:       [in]    length of range for cpu access.
+ * @direction: [in]    length of range for cpu access.
+ *
+ * Can return negative error values, returns 0 on success.
+ */
+int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
+                            enum dma_data_direction direction)
+{
+       int ret = 0;
+
+       if (WARN_ON(!dmabuf))
+               return -EINVAL;
+
+       if (dmabuf->ops->begin_cpu_access)
+               ret = dmabuf->ops->begin_cpu_access(dmabuf, start, len, direction);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
+
+/**
+ * dma_buf_end_cpu_access - Must be called after accessing a dma_buf from the
+ * cpu in the kernel context. Calls end_cpu_access to allow exporter-specific
+ * actions. Coherency is only guaranteed in the specified range for the
+ * specified access direction.
+ * @dma_buf:   [in]    buffer to complete cpu access for.
+ * @start:     [in]    start of range for cpu access.
+ * @len:       [in]    length of range for cpu access.
+ * @direction: [in]    length of range for cpu access.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start, size_t len,
+                           enum dma_data_direction direction)
+{
+       WARN_ON(!dmabuf);
+
+       if (dmabuf->ops->end_cpu_access)
+               dmabuf->ops->end_cpu_access(dmabuf, start, len, direction);
+}
+EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
+
+/**
+ * dma_buf_kmap_atomic - Map a page of the buffer object into kernel address
+ * space. The same restrictions as for kmap_atomic and friends apply.
+ * @dma_buf:   [in]    buffer to map page from.
+ * @page_num:  [in]    page in PAGE_SIZE units to map.
+ *
+ * This call must always succeed, any necessary preparations that might fail
+ * need to be done in begin_cpu_access.
+ */
+void *dma_buf_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num)
+{
+       WARN_ON(!dmabuf);
+
+       return dmabuf->ops->kmap_atomic(dmabuf, page_num);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic);
+
+/**
+ * dma_buf_kunmap_atomic - Unmap a page obtained by dma_buf_kmap_atomic.
+ * @dma_buf:   [in]    buffer to unmap page from.
+ * @page_num:  [in]    page in PAGE_SIZE units to unmap.
+ * @vaddr:     [in]    kernel space pointer obtained from dma_buf_kmap_atomic.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_kunmap_atomic(struct dma_buf *dmabuf, unsigned long page_num,
+                          void *vaddr)
+{
+       WARN_ON(!dmabuf);
+
+       if (dmabuf->ops->kunmap_atomic)
+               dmabuf->ops->kunmap_atomic(dmabuf, page_num, vaddr);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic);
+
+/**
+ * dma_buf_kmap - Map a page of the buffer object into kernel address space. The
+ * same restrictions as for kmap and friends apply.
+ * @dma_buf:   [in]    buffer to map page from.
+ * @page_num:  [in]    page in PAGE_SIZE units to map.
+ *
+ * This call must always succeed, any necessary preparations that might fail
+ * need to be done in begin_cpu_access.
+ */
+void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num)
+{
+       WARN_ON(!dmabuf);
+
+       return dmabuf->ops->kmap(dmabuf, page_num);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kmap);
+
+/**
+ * dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap.
+ * @dma_buf:   [in]    buffer to unmap page from.
+ * @page_num:  [in]    page in PAGE_SIZE units to unmap.
+ * @vaddr:     [in]    kernel space pointer obtained from dma_buf_kmap.
+ *
+ * This call must always succeed.
+ */
+void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num,
+                   void *vaddr)
+{
+       WARN_ON(!dmabuf);
+
+       if (dmabuf->ops->kunmap)
+               dmabuf->ops->kunmap(dmabuf, page_num, vaddr);
+}
+EXPORT_SYMBOL_GPL(dma_buf_kunmap);
index 428e55e..869d7ff 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/io.h>
 #include <linux/pm.h>
 #include <linux/pm_clock.h>
index 4af7c1c..a14085c 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/pm_clock.h>
index 95706fa..ac993ea 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/cpufreq.h>
+#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
index 8d00615..483b06d 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/device.h>
 #include <linux/lzo.h>
 
 #include "internal.h"
@@ -341,7 +342,7 @@ static int regcache_lzo_sync(struct regmap *map, unsigned int min,
 
        lzo_blocks = map->cache;
        i = min;
-       for_each_set_bit_cont(i, lzo_blocks[0]->sync_bmp,
+       for_each_set_bit_from(i, lzo_blocks[0]->sync_bmp,
                              lzo_blocks[0]->sync_bmp_nbits) {
                if (i > max)
                        continue;
index 8d51916..5157fa0 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/device.h>
 #include <linux/debugfs.h>
 #include <linux/rbtree.h>
 #include <linux/seq_file.h>
index 938cb1d..87f54db 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/device.h>
 #include <trace/events/regmap.h>
 #include <linux/bsearch.h>
 #include <linux/sort.h>
index 372f81a..58517a5 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/mutex.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
+#include <linux/device.h>
 
 #include "internal.h"
 
index 428836f..1befaa7 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/export.h>
+#include <linux/device.h>
 #include <linux/regmap.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
index e09f9ce..abfaaca 100644 (file)
@@ -179,7 +179,7 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd)
        dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
 
        drbd_bcast_ev_helper(mdev, cmd);
-       ret = call_usermodehelper(usermode_helper, argv, envp, 1);
+       ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
        if (ret)
                dev_warn(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
                                usermode_helper, cmd, mb,
index a6278e7..013c7a5 100644 (file)
 
 #include "rbd_types.h"
 
-#define DRV_NAME "rbd"
-#define DRV_NAME_LONG "rbd (rados block device)"
+/*
+ * The basic unit of block I/O is a sector.  It is interpreted in a
+ * number of contexts in Linux (blk, bio, genhd), but the default is
+ * universally 512 bytes.  These symbols are just slightly more
+ * meaningful than the bare numbers they represent.
+ */
+#define        SECTOR_SHIFT    9
+#define        SECTOR_SIZE     (1ULL << SECTOR_SHIFT)
+
+#define RBD_DRV_NAME "rbd"
+#define RBD_DRV_NAME_LONG "rbd (rados block device)"
 
 #define RBD_MINORS_PER_MAJOR   256             /* max minors per blkdev */
 
-#define RBD_MAX_MD_NAME_LEN    (96 + sizeof(RBD_SUFFIX))
+#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
 
 #define RBD_SNAP_HEAD_NAME     "-"
 
+/*
+ * An RBD device name will be "rbd#", where the "rbd" comes from
+ * RBD_DRV_NAME above, and # is a unique integer identifier.
+ * MAX_INT_FORMAT_WIDTH is used in ensuring DEV_NAME_LEN is big
+ * enough to hold all possible device names.
+ */
 #define DEV_NAME_LEN           32
+#define MAX_INT_FORMAT_WIDTH   ((5 * sizeof (int)) / 2 + 1)
 
 #define RBD_NOTIFY_TIMEOUT_DEFAULT 10
 
@@ -66,7 +82,6 @@ struct rbd_image_header {
        __u8 obj_order;
        __u8 crypt_type;
        __u8 comp_type;
-       struct rw_semaphore snap_rwsem;
        struct ceph_snap_context *snapc;
        size_t snap_names_len;
        u64 snap_seq;
@@ -83,7 +98,7 @@ struct rbd_options {
 };
 
 /*
- * an instance of the client.  multiple devices may share a client.
+ * an instance of the client.  multiple devices may share an rbd client.
  */
 struct rbd_client {
        struct ceph_client      *client;
@@ -92,20 +107,9 @@ struct rbd_client {
        struct list_head        node;
 };
 
-struct rbd_req_coll;
-
 /*
- * a single io request
+ * a request completion status
  */
-struct rbd_request {
-       struct request          *rq;            /* blk layer request */
-       struct bio              *bio;           /* cloned bio */
-       struct page             **pages;        /* list of used pages */
-       u64                     len;
-       int                     coll_index;
-       struct rbd_req_coll     *coll;
-};
-
 struct rbd_req_status {
        int done;
        int rc;
@@ -122,6 +126,18 @@ struct rbd_req_coll {
        struct rbd_req_status   status[0];
 };
 
+/*
+ * a single io request
+ */
+struct rbd_request {
+       struct request          *rq;            /* blk layer request */
+       struct bio              *bio;           /* cloned bio */
+       struct page             **pages;        /* list of used pages */
+       u64                     len;
+       int                     coll_index;
+       struct rbd_req_coll     *coll;
+};
+
 struct rbd_snap {
        struct  device          dev;
        const char              *name;
@@ -140,7 +156,6 @@ struct rbd_device {
        struct gendisk          *disk;          /* blkdev's gendisk and rq */
        struct request_queue    *q;
 
-       struct ceph_client      *client;
        struct rbd_client       *rbd_client;
 
        char                    name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */
@@ -157,6 +172,8 @@ struct rbd_device {
        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];
        u32 cur_snap;   /* index+1 of current snapshot within snap context
                           0 - for the head */
@@ -171,15 +188,13 @@ struct rbd_device {
        struct device           dev;
 };
 
-static struct bus_type rbd_bus_type = {
-       .name           = "rbd",
-};
-
-static spinlock_t node_lock;      /* protects client get/put */
-
 static DEFINE_MUTEX(ctl_mutex);          /* Serialize open/close/setup/teardown */
+
 static LIST_HEAD(rbd_dev_list);    /* devices */
-static LIST_HEAD(rbd_client_list);      /* clients */
+static DEFINE_SPINLOCK(rbd_dev_list_lock);
+
+static LIST_HEAD(rbd_client_list);             /* clients */
+static DEFINE_SPINLOCK(rbd_client_list_lock);
 
 static int __rbd_init_snaps_header(struct rbd_device *rbd_dev);
 static void rbd_dev_release(struct device *dev);
@@ -190,12 +205,32 @@ static ssize_t rbd_snap_add(struct device *dev,
 static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
                                  struct rbd_snap *snap);
 
+static ssize_t rbd_add(struct bus_type *bus, const char *buf,
+                      size_t count);
+static ssize_t rbd_remove(struct bus_type *bus, const char *buf,
+                         size_t count);
 
-static struct rbd_device *dev_to_rbd(struct device *dev)
+static struct bus_attribute rbd_bus_attrs[] = {
+       __ATTR(add, S_IWUSR, NULL, rbd_add),
+       __ATTR(remove, S_IWUSR, NULL, rbd_remove),
+       __ATTR_NULL
+};
+
+static struct bus_type rbd_bus_type = {
+       .name           = "rbd",
+       .bus_attrs      = rbd_bus_attrs,
+};
+
+static void rbd_root_dev_release(struct device *dev)
 {
-       return container_of(dev, struct rbd_device, dev);
 }
 
+static struct device rbd_root_dev = {
+       .init_name =    "rbd",
+       .release =      rbd_root_dev_release,
+};
+
+
 static struct device *rbd_get_dev(struct rbd_device *rbd_dev)
 {
        return get_device(&rbd_dev->dev);
@@ -210,8 +245,7 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev);
 
 static int rbd_open(struct block_device *bdev, fmode_t mode)
 {
-       struct gendisk *disk = bdev->bd_disk;
-       struct rbd_device *rbd_dev = disk->private_data;
+       struct rbd_device *rbd_dev = bdev->bd_disk->private_data;
 
        rbd_get_dev(rbd_dev);
 
@@ -256,9 +290,11 @@ static struct rbd_client *rbd_client_create(struct ceph_options *opt,
        kref_init(&rbdc->kref);
        INIT_LIST_HEAD(&rbdc->node);
 
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
        rbdc->client = ceph_create_client(opt, rbdc, 0, 0);
        if (IS_ERR(rbdc->client))
-               goto out_rbdc;
+               goto out_mutex;
        opt = NULL; /* Now rbdc->client is responsible for opt */
 
        ret = ceph_open_session(rbdc->client);
@@ -267,16 +303,19 @@ static struct rbd_client *rbd_client_create(struct ceph_options *opt,
 
        rbdc->rbd_opts = rbd_opts;
 
-       spin_lock(&node_lock);
+       spin_lock(&rbd_client_list_lock);
        list_add_tail(&rbdc->node, &rbd_client_list);
-       spin_unlock(&node_lock);
+       spin_unlock(&rbd_client_list_lock);
+
+       mutex_unlock(&ctl_mutex);
 
        dout("rbd_client_create created %p\n", rbdc);
        return rbdc;
 
 out_err:
        ceph_destroy_client(rbdc->client);
-out_rbdc:
+out_mutex:
+       mutex_unlock(&ctl_mutex);
        kfree(rbdc);
 out_opt:
        if (opt)
@@ -324,7 +363,7 @@ static int parse_rbd_opts_token(char *c, void *private)
        substring_t argstr[MAX_OPT_ARGS];
        int token, intval, ret;
 
-       token = match_token((char *)c, rbdopt_tokens, argstr);
+       token = match_token(c, rbdopt_tokens, argstr);
        if (token < 0)
                return -EINVAL;
 
@@ -357,58 +396,54 @@ static int parse_rbd_opts_token(char *c, void *private)
  * Get a ceph client with specific addr and configuration, if one does
  * not exist create it.
  */
-static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr,
-                         char *options)
+static struct rbd_client *rbd_get_client(const char *mon_addr,
+                                        size_t mon_addr_len,
+                                        char *options)
 {
        struct rbd_client *rbdc;
        struct ceph_options *opt;
-       int ret;
        struct rbd_options *rbd_opts;
 
        rbd_opts = kzalloc(sizeof(*rbd_opts), GFP_KERNEL);
        if (!rbd_opts)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        rbd_opts->notify_timeout = RBD_NOTIFY_TIMEOUT_DEFAULT;
 
-       ret = ceph_parse_options(&opt, options, mon_addr,
-                                mon_addr + strlen(mon_addr), parse_rbd_opts_token, rbd_opts);
-       if (ret < 0)
-               goto done_err;
+       opt = ceph_parse_options(options, mon_addr,
+                               mon_addr + mon_addr_len,
+                               parse_rbd_opts_token, rbd_opts);
+       if (IS_ERR(opt)) {
+               kfree(rbd_opts);
+               return ERR_CAST(opt);
+       }
 
-       spin_lock(&node_lock);
+       spin_lock(&rbd_client_list_lock);
        rbdc = __rbd_client_find(opt);
        if (rbdc) {
+               /* using an existing client */
+               kref_get(&rbdc->kref);
+               spin_unlock(&rbd_client_list_lock);
+
                ceph_destroy_options(opt);
                kfree(rbd_opts);
 
-               /* using an existing client */
-               kref_get(&rbdc->kref);
-               rbd_dev->rbd_client = rbdc;
-               rbd_dev->client = rbdc->client;
-               spin_unlock(&node_lock);
-               return 0;
+               return rbdc;
        }
-       spin_unlock(&node_lock);
+       spin_unlock(&rbd_client_list_lock);
 
        rbdc = rbd_client_create(opt, rbd_opts);
-       if (IS_ERR(rbdc)) {
-               ret = PTR_ERR(rbdc);
-               goto done_err;
-       }
 
-       rbd_dev->rbd_client = rbdc;
-       rbd_dev->client = rbdc->client;
-       return 0;
-done_err:
-       kfree(rbd_opts);
-       return ret;
+       if (IS_ERR(rbdc))
+               kfree(rbd_opts);
+
+       return rbdc;
 }
 
 /*
  * Destroy ceph client
  *
- * Caller must hold node_lock.
+ * Caller must hold rbd_client_list_lock.
  */
 static void rbd_client_release(struct kref *kref)
 {
@@ -428,11 +463,10 @@ static void rbd_client_release(struct kref *kref)
  */
 static void rbd_put_client(struct rbd_device *rbd_dev)
 {
-       spin_lock(&node_lock);
+       spin_lock(&rbd_client_list_lock);
        kref_put(&rbd_dev->rbd_client->kref, rbd_client_release);
-       spin_unlock(&node_lock);
+       spin_unlock(&rbd_client_list_lock);
        rbd_dev->rbd_client = NULL;
-       rbd_dev->client = NULL;
 }
 
 /*
@@ -457,21 +491,19 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
                                 gfp_t gfp_flags)
 {
        int i;
-       u32 snap_count = le32_to_cpu(ondisk->snap_count);
-       int ret = -ENOMEM;
+       u32 snap_count;
 
-       if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT))) {
+       if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT)))
                return -ENXIO;
-       }
 
-       init_rwsem(&header->snap_rwsem);
-       header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
+       snap_count = le32_to_cpu(ondisk->snap_count);
        header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
-                               snap_count *
-                                sizeof(struct rbd_image_snap_ondisk),
+                               snap_count * sizeof (*ondisk),
                                gfp_flags);
        if (!header->snapc)
                return -ENOMEM;
+
+       header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
        if (snap_count) {
                header->snap_names = kmalloc(header->snap_names_len,
                                             GFP_KERNEL);
@@ -498,8 +530,7 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
        header->snapc->num_snaps = snap_count;
        header->total_snaps = snap_count;
 
-       if (snap_count &&
-           allocated_snaps == snap_count) {
+       if (snap_count && allocated_snaps == snap_count) {
                for (i = 0; i < snap_count; i++) {
                        header->snapc->snaps[i] =
                                le64_to_cpu(ondisk->snaps[i].id);
@@ -518,7 +549,7 @@ err_names:
        kfree(header->snap_names);
 err_snapc:
        kfree(header->snapc);
-       return ret;
+       return -ENOMEM;
 }
 
 static int snap_index(struct rbd_image_header *header, int snap_num)
@@ -542,35 +573,34 @@ static int snap_by_name(struct rbd_image_header *header, const char *snap_name,
        int i;
        char *p = header->snap_names;
 
-       for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) {
-               if (strcmp(snap_name, p) == 0)
-                       break;
-       }
-       if (i == header->total_snaps)
-               return -ENOENT;
-       if (seq)
-               *seq = header->snapc->snaps[i];
+       for (i = 0; i < header->total_snaps; i++) {
+               if (!strcmp(snap_name, p)) {
 
-       if (size)
-               *size = header->snap_sizes[i];
+                       /* Found it.  Pass back its id and/or size */
 
-       return i;
+                       if (seq)
+                               *seq = header->snapc->snaps[i];
+                       if (size)
+                               *size = header->snap_sizes[i];
+                       return i;
+               }
+               p += strlen(p) + 1;     /* Skip ahead to the next name */
+       }
+       return -ENOENT;
 }
 
-static int rbd_header_set_snap(struct rbd_device *dev,
-                              const char *snap_name,
-                              u64 *size)
+static int rbd_header_set_snap(struct rbd_device *dev, u64 *size)
 {
        struct rbd_image_header *header = &dev->header;
        struct ceph_snap_context *snapc = header->snapc;
        int ret = -ENOENT;
 
-       down_write(&header->snap_rwsem);
+       BUILD_BUG_ON(sizeof (dev->snap_name) < sizeof (RBD_SNAP_HEAD_NAME));
 
-       if (!snap_name ||
-           !*snap_name ||
-           strcmp(snap_name, "-") == 0 ||
-           strcmp(snap_name, RBD_SNAP_HEAD_NAME) == 0) {
+       down_write(&dev->header_rwsem);
+
+       if (!memcmp(dev->snap_name, RBD_SNAP_HEAD_NAME,
+                   sizeof (RBD_SNAP_HEAD_NAME))) {
                if (header->total_snaps)
                        snapc->seq = header->snap_seq;
                else
@@ -580,7 +610,7 @@ static int rbd_header_set_snap(struct rbd_device *dev,
                if (size)
                        *size = header->image_size;
        } else {
-               ret = snap_by_name(header, snap_name, &snapc->seq, size);
+               ret = snap_by_name(header, dev->snap_name, &snapc->seq, size);
                if (ret < 0)
                        goto done;
 
@@ -590,7 +620,7 @@ static int rbd_header_set_snap(struct rbd_device *dev,
 
        ret = 0;
 done:
-       up_write(&header->snap_rwsem);
+       up_write(&dev->header_rwsem);
        return ret;
 }
 
@@ -717,7 +747,7 @@ static struct bio *bio_chain_clone(struct bio **old, struct bio **next,
 
                        /* split the bio. We'll release it either in the next
                           call, or it will have to be released outside */
-                       bp = bio_split(old_chain, (len - total) / 512ULL);
+                       bp = bio_split(old_chain, (len - total) / SECTOR_SIZE);
                        if (!bp)
                                goto err_out;
 
@@ -857,7 +887,7 @@ static int rbd_do_request(struct request *rq,
        struct timespec mtime = CURRENT_TIME;
        struct rbd_request *req_data;
        struct ceph_osd_request_head *reqhead;
-       struct rbd_image_header *header = &dev->header;
+       struct ceph_osd_client *osdc;
 
        req_data = kzalloc(sizeof(*req_data), GFP_NOIO);
        if (!req_data) {
@@ -874,15 +904,13 @@ static int rbd_do_request(struct request *rq,
 
        dout("rbd_do_request obj=%s ofs=%lld len=%lld\n", obj, len, ofs);
 
-       down_read(&header->snap_rwsem);
+       down_read(&dev->header_rwsem);
 
-       req = ceph_osdc_alloc_request(&dev->client->osdc, flags,
-                                     snapc,
-                                     ops,
-                                     false,
-                                     GFP_NOIO, pages, bio);
+       osdc = &dev->rbd_client->client->osdc;
+       req = ceph_osdc_alloc_request(osdc, flags, snapc, ops,
+                                       false, GFP_NOIO, pages, bio);
        if (!req) {
-               up_read(&header->snap_rwsem);
+               up_read(&dev->header_rwsem);
                ret = -ENOMEM;
                goto done_pages;
        }
@@ -909,27 +937,27 @@ static int rbd_do_request(struct request *rq,
        layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
        layout->fl_pg_preferred = cpu_to_le32(-1);
        layout->fl_pg_pool = cpu_to_le32(dev->poolid);
-       ceph_calc_raw_layout(&dev->client->osdc, layout, snapid,
-                            ofs, &len, &bno, req, ops);
+       ceph_calc_raw_layout(osdc, layout, snapid, ofs, &len, &bno,
+                               req, ops);
 
        ceph_osdc_build_request(req, ofs, &len,
                                ops,
                                snapc,
                                &mtime,
                                req->r_oid, req->r_oid_len);
-       up_read(&header->snap_rwsem);
+       up_read(&dev->header_rwsem);
 
        if (linger_req) {
-               ceph_osdc_set_request_linger(&dev->client->osdc, req);
+               ceph_osdc_set_request_linger(osdc, req);
                *linger_req = req;
        }
 
-       ret = ceph_osdc_start_request(&dev->client->osdc, req, false);
+       ret = ceph_osdc_start_request(osdc, req, false);
        if (ret < 0)
                goto done_err;
 
        if (!rbd_cb) {
-               ret = ceph_osdc_wait_request(&dev->client->osdc, req);
+               ret = ceph_osdc_wait_request(osdc, req);
                if (ver)
                        *ver = le64_to_cpu(req->r_reassert_version.version);
                dout("reassert_ver=%lld\n",
@@ -1213,8 +1241,8 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
        rc = __rbd_update_snaps(dev);
        mutex_unlock(&ctl_mutex);
        if (rc)
-               pr_warning(DRV_NAME "%d got notification but failed to update"
-                          " snaps: %d\n", dev->major, rc);
+               pr_warning(RBD_DRV_NAME "%d got notification but failed to "
+                          " update snaps: %d\n", dev->major, rc);
 
        rbd_req_sync_notify_ack(dev, ver, notify_id, dev->obj_md_name);
 }
@@ -1227,7 +1255,7 @@ static int rbd_req_sync_watch(struct rbd_device *dev,
                              u64 ver)
 {
        struct ceph_osd_req_op *ops;
-       struct ceph_osd_client *osdc = &dev->client->osdc;
+       struct ceph_osd_client *osdc = &dev->rbd_client->client->osdc;
 
        int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_WATCH, 0);
        if (ret < 0)
@@ -1314,7 +1342,7 @@ static int rbd_req_sync_notify(struct rbd_device *dev,
                          const char *obj)
 {
        struct ceph_osd_req_op *ops;
-       struct ceph_osd_client *osdc = &dev->client->osdc;
+       struct ceph_osd_client *osdc = &dev->rbd_client->client->osdc;
        struct ceph_osd_event *event;
        struct rbd_notify_info info;
        int payload_len = sizeof(u32) + sizeof(u32);
@@ -1421,9 +1449,7 @@ static void rbd_rq_fn(struct request_queue *q)
        struct request *rq;
        struct bio_pair *bp = NULL;
 
-       rq = blk_fetch_request(q);
-
-       while (1) {
+       while ((rq = blk_fetch_request(q))) {
                struct bio *bio;
                struct bio *rq_bio, *next_bio = NULL;
                bool do_write;
@@ -1441,32 +1467,32 @@ static void rbd_rq_fn(struct request_queue *q)
                /* filter out block requests we don't understand */
                if ((rq->cmd_type != REQ_TYPE_FS)) {
                        __blk_end_request_all(rq, 0);
-                       goto next;
+                       continue;
                }
 
                /* deduce our operation (read, write) */
                do_write = (rq_data_dir(rq) == WRITE);
 
                size = blk_rq_bytes(rq);
-               ofs = blk_rq_pos(rq) * 512ULL;
+               ofs = blk_rq_pos(rq) * SECTOR_SIZE;
                rq_bio = rq->bio;
                if (do_write && rbd_dev->read_only) {
                        __blk_end_request_all(rq, -EROFS);
-                       goto next;
+                       continue;
                }
 
                spin_unlock_irq(q->queue_lock);
 
                dout("%s 0x%x bytes at 0x%llx\n",
                     do_write ? "write" : "read",
-                    size, blk_rq_pos(rq) * 512ULL);
+                    size, 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);
-                       goto next;
+                       continue;
                }
 
                do {
@@ -1512,8 +1538,6 @@ next_seg:
                if (bp)
                        bio_pair_release(bp);
                spin_lock_irq(q->queue_lock);
-next:
-               rq = blk_fetch_request(q);
        }
 }
 
@@ -1526,13 +1550,17 @@ static int rbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd,
                          struct bio_vec *bvec)
 {
        struct rbd_device *rbd_dev = q->queuedata;
-       unsigned int chunk_sectors = 1 << (rbd_dev->header.obj_order - 9);
-       sector_t sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev);
-       unsigned int bio_sectors = bmd->bi_size >> 9;
+       unsigned int chunk_sectors;
+       sector_t sector;
+       unsigned int bio_sectors;
        int max;
 
+       chunk_sectors = 1 << (rbd_dev->header.obj_order - SECTOR_SHIFT);
+       sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev);
+       bio_sectors = bmd->bi_size >> SECTOR_SHIFT;
+
        max =  (chunk_sectors - ((sector & (chunk_sectors - 1))
-                                + bio_sectors)) << 9;
+                                + bio_sectors)) << SECTOR_SHIFT;
        if (max < 0)
                max = 0; /* bio_add cannot handle a negative return */
        if (max <= bvec->bv_len && bio_sectors == 0)
@@ -1565,15 +1593,16 @@ static int rbd_read_header(struct rbd_device *rbd_dev,
        ssize_t rc;
        struct rbd_image_header_ondisk *dh;
        int snap_count = 0;
-       u64 snap_names_len = 0;
        u64 ver;
+       size_t len;
 
+       /*
+        * First reads the fixed-size header to determine the number
+        * of snapshots, then re-reads it, along with all snapshot
+        * records as well as their stored names.
+        */
+       len = sizeof (*dh);
        while (1) {
-               int len = sizeof(*dh) +
-                         snap_count * sizeof(struct rbd_image_snap_ondisk) +
-                         snap_names_len;
-
-               rc = -ENOMEM;
                dh = kmalloc(len, GFP_KERNEL);
                if (!dh)
                        return -ENOMEM;
@@ -1588,21 +1617,22 @@ static int rbd_read_header(struct rbd_device *rbd_dev,
 
                rc = rbd_header_from_disk(header, dh, snap_count, GFP_KERNEL);
                if (rc < 0) {
-                       if (rc == -ENXIO) {
+                       if (rc == -ENXIO)
                                pr_warning("unrecognized header format"
                                           " for image %s", rbd_dev->obj);
-                       }
                        goto out_dh;
                }
 
-               if (snap_count != header->total_snaps) {
-                       snap_count = header->total_snaps;
-                       snap_names_len = header->snap_names_len;
-                       rbd_header_free(header);
-                       kfree(dh);
-                       continue;
-               }
-               break;
+               if (snap_count == header->total_snaps)
+                       break;
+
+               snap_count = header->total_snaps;
+               len = sizeof (*dh) +
+                       snap_count * sizeof(struct rbd_image_snap_ondisk) +
+                       header->snap_names_len;
+
+               rbd_header_free(header);
+               kfree(dh);
        }
        header->obj_version = ver;
 
@@ -1623,13 +1653,14 @@ static int rbd_header_add_snap(struct rbd_device *dev,
        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->cur_snap)
                return -EINVAL;
 
-       ret = ceph_monc_create_snapid(&dev->client->monc, dev->poolid,
-                                     &new_snapid);
+       monc = &dev->rbd_client->client->monc;
+       ret = ceph_monc_create_snapid(monc, dev->poolid, &new_snapid);
        dout("created snapid=%lld\n", new_snapid);
        if (ret < 0)
                return ret;
@@ -1684,9 +1715,9 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev)
                return ret;
 
        /* resized? */
-       set_capacity(rbd_dev->disk, h.image_size / 512ULL);
+       set_capacity(rbd_dev->disk, h.image_size / SECTOR_SIZE);
 
-       down_write(&rbd_dev->header.snap_rwsem);
+       down_write(&rbd_dev->header_rwsem);
 
        snap_seq = rbd_dev->header.snapc->seq;
        if (rbd_dev->header.total_snaps &&
@@ -1711,7 +1742,7 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev)
 
        ret = __rbd_init_snaps_header(rbd_dev);
 
-       up_write(&rbd_dev->header.snap_rwsem);
+       up_write(&rbd_dev->header_rwsem);
 
        return ret;
 }
@@ -1721,6 +1752,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        struct gendisk *disk;
        struct request_queue *q;
        int rc;
+       u64 segment_size;
        u64 total_size = 0;
 
        /* contact OSD, request size info about the object being mapped */
@@ -1733,7 +1765,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        if (rc)
                return rc;
 
-       rc = rbd_header_set_snap(rbd_dev, rbd_dev->snap_name, &total_size);
+       rc = rbd_header_set_snap(rbd_dev, &total_size);
        if (rc)
                return rc;
 
@@ -1743,7 +1775,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        if (!disk)
                goto out;
 
-       snprintf(disk->disk_name, sizeof(disk->disk_name), DRV_NAME "%d",
+       snprintf(disk->disk_name, sizeof(disk->disk_name), RBD_DRV_NAME "%d",
                 rbd_dev->id);
        disk->major = rbd_dev->major;
        disk->first_minor = 0;
@@ -1756,11 +1788,15 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        if (!q)
                goto out_disk;
 
+       /* We use the default size, but let's be explicit about it. */
+       blk_queue_physical_block_size(q, SECTOR_SIZE);
+
        /* set io sizes to object size */
-       blk_queue_max_hw_sectors(q, rbd_obj_bytes(&rbd_dev->header) / 512ULL);
-       blk_queue_max_segment_size(q, rbd_obj_bytes(&rbd_dev->header));
-       blk_queue_io_min(q, rbd_obj_bytes(&rbd_dev->header));
-       blk_queue_io_opt(q, rbd_obj_bytes(&rbd_dev->header));
+       segment_size = rbd_obj_bytes(&rbd_dev->header);
+       blk_queue_max_hw_sectors(q, segment_size / SECTOR_SIZE);
+       blk_queue_max_segment_size(q, segment_size);
+       blk_queue_io_min(q, segment_size);
+       blk_queue_io_opt(q, segment_size);
 
        blk_queue_merge_bvec(q, rbd_merge_bvec);
        disk->queue = q;
@@ -1771,7 +1807,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        rbd_dev->q = q;
 
        /* finally, announce the disk to the world */
-       set_capacity(disk, total_size / 512ULL);
+       set_capacity(disk, total_size / SECTOR_SIZE);
        add_disk(disk);
 
        pr_info("%s: added with size 0x%llx\n",
@@ -1788,10 +1824,15 @@ out:
   sysfs
 */
 
+static struct rbd_device *dev_to_rbd_dev(struct device *dev)
+{
+       return container_of(dev, struct rbd_device, dev);
+}
+
 static ssize_t rbd_size_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
-       struct rbd_device *rbd_dev = dev_to_rbd(dev);
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
        return sprintf(buf, "%llu\n", (unsigned long long)rbd_dev->header.image_size);
 }
@@ -1799,7 +1840,7 @@ static ssize_t rbd_size_show(struct device *dev,
 static ssize_t rbd_major_show(struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
-       struct rbd_device *rbd_dev = dev_to_rbd(dev);
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
        return sprintf(buf, "%d\n", rbd_dev->major);
 }
@@ -1807,15 +1848,16 @@ static ssize_t rbd_major_show(struct device *dev,
 static ssize_t rbd_client_id_show(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
-       struct rbd_device *rbd_dev = dev_to_rbd(dev);
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-       return sprintf(buf, "client%lld\n", ceph_client_id(rbd_dev->client));
+       return sprintf(buf, "client%lld\n",
+                       ceph_client_id(rbd_dev->rbd_client->client));
 }
 
 static ssize_t rbd_pool_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
-       struct rbd_device *rbd_dev = dev_to_rbd(dev);
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
        return sprintf(buf, "%s\n", rbd_dev->pool_name);
 }
@@ -1823,7 +1865,7 @@ static ssize_t rbd_pool_show(struct device *dev,
 static ssize_t rbd_name_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
-       struct rbd_device *rbd_dev = dev_to_rbd(dev);
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
        return sprintf(buf, "%s\n", rbd_dev->obj);
 }
@@ -1832,7 +1874,7 @@ static ssize_t rbd_snap_show(struct device *dev,
                             struct device_attribute *attr,
                             char *buf)
 {
-       struct rbd_device *rbd_dev = dev_to_rbd(dev);
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
        return sprintf(buf, "%s\n", rbd_dev->snap_name);
 }
@@ -1842,7 +1884,7 @@ static ssize_t rbd_image_refresh(struct device *dev,
                                 const char *buf,
                                 size_t size)
 {
-       struct rbd_device *rbd_dev = dev_to_rbd(dev);
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
        int rc;
        int ret = size;
 
@@ -1907,7 +1949,7 @@ static ssize_t rbd_snap_size_show(struct device *dev,
 {
        struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
 
-       return sprintf(buf, "%lld\n", (long long)snap->size);
+       return sprintf(buf, "%zd\n", snap->size);
 }
 
 static ssize_t rbd_snap_id_show(struct device *dev,
@@ -1916,7 +1958,7 @@ static ssize_t rbd_snap_id_show(struct device *dev,
 {
        struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
 
-       return sprintf(buf, "%lld\n", (long long)snap->id);
+       return sprintf(buf, "%llu\n", (unsigned long long) snap->id);
 }
 
 static DEVICE_ATTR(snap_size, S_IRUGO, rbd_snap_size_show, NULL);
@@ -2088,19 +2130,9 @@ static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
        return 0;
 }
 
-
-static void rbd_root_dev_release(struct device *dev)
-{
-}
-
-static struct device rbd_root_dev = {
-       .init_name =    "rbd",
-       .release =      rbd_root_dev_release,
-};
-
 static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
 {
-       int ret = -ENOMEM;
+       int ret;
        struct device *dev;
        struct rbd_snap *snap;
 
@@ -2114,7 +2146,7 @@ static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
        dev_set_name(dev, "%d", rbd_dev->id);
        ret = device_register(dev);
        if (ret < 0)
-               goto done_free;
+               goto out;
 
        list_for_each_entry(snap, &rbd_dev->snaps, node) {
                ret = rbd_register_snap_dev(rbd_dev, snap,
@@ -2122,10 +2154,7 @@ static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
                if (ret < 0)
                        break;
        }
-
-       mutex_unlock(&ctl_mutex);
-       return 0;
-done_free:
+out:
        mutex_unlock(&ctl_mutex);
        return ret;
 }
@@ -2154,104 +2183,250 @@ static int rbd_init_watch_dev(struct rbd_device *rbd_dev)
        return ret;
 }
 
+static atomic64_t rbd_id_max = ATOMIC64_INIT(0);
+
+/*
+ * Get a unique rbd identifier for the given new rbd_dev, and add
+ * the rbd_dev to the global list.  The minimum rbd id is 1.
+ */
+static void rbd_id_get(struct rbd_device *rbd_dev)
+{
+       rbd_dev->id = atomic64_inc_return(&rbd_id_max);
+
+       spin_lock(&rbd_dev_list_lock);
+       list_add_tail(&rbd_dev->node, &rbd_dev_list);
+       spin_unlock(&rbd_dev_list_lock);
+}
+
+/*
+ * Remove an rbd_dev from the global list, and record that its
+ * identifier is no longer in use.
+ */
+static void rbd_id_put(struct rbd_device *rbd_dev)
+{
+       struct list_head *tmp;
+       int rbd_id = rbd_dev->id;
+       int max_id;
+
+       BUG_ON(rbd_id < 1);
+
+       spin_lock(&rbd_dev_list_lock);
+       list_del_init(&rbd_dev->node);
+
+       /*
+        * If the id being "put" is not the current maximum, there
+        * is nothing special we need to do.
+        */
+       if (rbd_id != atomic64_read(&rbd_id_max)) {
+               spin_unlock(&rbd_dev_list_lock);
+               return;
+       }
+
+       /*
+        * We need to update the current maximum id.  Search the
+        * list to find out what it is.  We're more likely to find
+        * the maximum at the end, so search the list backward.
+        */
+       max_id = 0;
+       list_for_each_prev(tmp, &rbd_dev_list) {
+               struct rbd_device *rbd_dev;
+
+               rbd_dev = list_entry(tmp, struct rbd_device, node);
+               if (rbd_id > max_id)
+                       max_id = rbd_id;
+       }
+       spin_unlock(&rbd_dev_list_lock);
+
+       /*
+        * The max id could have been updated by rbd_id_get(), in
+        * which case it now accurately reflects the new maximum.
+        * Be careful not to overwrite the maximum value in that
+        * case.
+        */
+       atomic64_cmpxchg(&rbd_id_max, rbd_id, max_id);
+}
+
+/*
+ * Skips over white space at *buf, and updates *buf to point to the
+ * first found non-space character (if any). Returns the length of
+ * the token (string of non-white space characters) found.  Note
+ * that *buf must be terminated with '\0'.
+ */
+static inline size_t next_token(const char **buf)
+{
+        /*
+        * These are the characters that produce nonzero for
+        * isspace() in the "C" and "POSIX" locales.
+        */
+        const char *spaces = " \f\n\r\t\v";
+
+        *buf += strspn(*buf, spaces);  /* Find start of token */
+
+       return strcspn(*buf, spaces);   /* Return token length */
+}
+
+/*
+ * Finds the next token in *buf, and if the provided token buffer is
+ * big enough, copies the found token into it.  The result, if
+ * copied, is guaranteed to be terminated with '\0'.  Note that *buf
+ * must be terminated with '\0' on entry.
+ *
+ * Returns the length of the token found (not including the '\0').
+ * Return value will be 0 if no token is found, and it will be >=
+ * token_size if the token would not fit.
+ *
+ * The *buf pointer will be updated to point beyond the end of the
+ * found token.  Note that this occurs even if the token buffer is
+ * too small to hold it.
+ */
+static inline size_t copy_token(const char **buf,
+                               char *token,
+                               size_t token_size)
+{
+        size_t len;
+
+       len = next_token(buf);
+       if (len < token_size) {
+               memcpy(token, *buf, len);
+               *(token + len) = '\0';
+       }
+       *buf += len;
+
+        return len;
+}
+
+/*
+ * This fills in the pool_name, obj, obj_len, snap_name, obj_len,
+ * 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.
+ */
+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  len;
+
+       /* The first four tokens are required */
+
+       len = next_token(&buf);
+       if (!len)
+               return -EINVAL;
+       *mon_addrs_size = len + 1;
+       *mon_addrs = buf;
+
+       buf += len;
+
+       len = copy_token(&buf, options, options_size);
+       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;
+
+       /* We have the object length in hand, save it. */
+
+       rbd_dev->obj_len = len;
+
+       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);
+
+       /*
+        * The snapshot name is optional, but it's an error if it's
+        * too long.  If no snapshot is supplied, fill in the default.
+        */
+       len = copy_token(&buf, rbd_dev->snap_name, sizeof (rbd_dev->snap_name));
+       if (!len)
+               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;
+}
+
 static ssize_t rbd_add(struct bus_type *bus,
                       const char *buf,
                       size_t count)
 {
-       struct ceph_osd_client *osdc;
        struct rbd_device *rbd_dev;
-       ssize_t rc = -ENOMEM;
-       int irc, new_id = 0;
-       struct list_head *tmp;
-       char *mon_dev_name;
-       char *options;
+       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;
 
-       mon_dev_name = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL);
-       if (!mon_dev_name)
-               goto err_out_mod;
-
-       options = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL);
-       if (!options)
-               goto err_mon_dev;
-
-       /* new rbd_device object */
        rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL);
        if (!rbd_dev)
-               goto err_out_opt;
+               goto err_nomem;
+       options = kmalloc(count, GFP_KERNEL);
+       if (!options)
+               goto err_nomem;
 
        /* static rbd_device initialization */
        spin_lock_init(&rbd_dev->lock);
        INIT_LIST_HEAD(&rbd_dev->node);
        INIT_LIST_HEAD(&rbd_dev->snaps);
+       init_rwsem(&rbd_dev->header_rwsem);
 
-       init_rwsem(&rbd_dev->header.snap_rwsem);
+       init_rwsem(&rbd_dev->header_rwsem);
 
        /* generate unique id: find highest unique id, add one */
-       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
-       list_for_each(tmp, &rbd_dev_list) {
-               struct rbd_device *rbd_dev;
+       rbd_id_get(rbd_dev);
 
-               rbd_dev = list_entry(tmp, struct rbd_device, node);
-               if (rbd_dev->id >= new_id)
-                       new_id = rbd_dev->id + 1;
-       }
-
-       rbd_dev->id = new_id;
-
-       /* add to global list */
-       list_add_tail(&rbd_dev->node, &rbd_dev_list);
+       /* 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);
 
        /* parse add command */
-       if (sscanf(buf, "%" __stringify(RBD_MAX_OPT_LEN) "s "
-                  "%" __stringify(RBD_MAX_OPT_LEN) "s "
-                  "%" __stringify(RBD_MAX_POOL_NAME_LEN) "s "
-                  "%" __stringify(RBD_MAX_OBJ_NAME_LEN) "s"
-                  "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
-                  mon_dev_name, options, rbd_dev->pool_name,
-                  rbd_dev->obj, rbd_dev->snap_name) < 4) {
-               rc = -EINVAL;
-               goto err_out_slot;
-       }
-
-       if (rbd_dev->snap_name[0] == 0)
-               rbd_dev->snap_name[0] = '-';
-
-       rbd_dev->obj_len = strlen(rbd_dev->obj);
-       snprintf(rbd_dev->obj_md_name, sizeof(rbd_dev->obj_md_name), "%s%s",
-                rbd_dev->obj, RBD_SUFFIX);
-
-       /* initialize rest of new object */
-       snprintf(rbd_dev->name, DEV_NAME_LEN, DRV_NAME "%d", rbd_dev->id);
-       rc = rbd_get_client(rbd_dev, mon_dev_name, options);
-       if (rc < 0)
-               goto err_out_slot;
+       rc = rbd_add_parse_args(rbd_dev, buf, &mon_addrs, &mon_addrs_size,
+                               options, count);
+       if (rc)
+               goto err_put_id;
 
-       mutex_unlock(&ctl_mutex);
+       rbd_dev->rbd_client = rbd_get_client(mon_addrs, mon_addrs_size - 1,
+                                               options);
+       if (IS_ERR(rbd_dev->rbd_client)) {
+               rc = PTR_ERR(rbd_dev->rbd_client);
+               goto err_put_id;
+       }
 
        /* pick the pool */
-       osdc = &rbd_dev->client->osdc;
+       osdc = &rbd_dev->rbd_client->client->osdc;
        rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->pool_name);
        if (rc < 0)
                goto err_out_client;
        rbd_dev->poolid = rc;
 
        /* register our block device */
-       irc = register_blkdev(0, rbd_dev->name);
-       if (irc < 0) {
-               rc = irc;
+       rc = register_blkdev(0, rbd_dev->name);
+       if (rc < 0)
                goto err_out_client;
-       }
-       rbd_dev->major = irc;
+       rbd_dev->major = rc;
 
        rc = rbd_bus_add_dev(rbd_dev);
        if (rc)
                goto err_out_blkdev;
 
-       /* set up and announce blkdev mapping */
+       /*
+        * At this point cleanup in the event of an error is the job
+        * of the sysfs code (initiated by rbd_bus_del_dev()).
+        *
+        * Set up and announce blkdev mapping.
+        */
        rc = rbd_init_disk(rbd_dev);
        if (rc)
                goto err_out_bus;
@@ -2263,35 +2438,26 @@ static ssize_t rbd_add(struct bus_type *bus,
        return count;
 
 err_out_bus:
-       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-       list_del_init(&rbd_dev->node);
-       mutex_unlock(&ctl_mutex);
-
        /* this will also clean up rest of rbd_dev stuff */
 
        rbd_bus_del_dev(rbd_dev);
        kfree(options);
-       kfree(mon_dev_name);
        return rc;
 
 err_out_blkdev:
        unregister_blkdev(rbd_dev->major, rbd_dev->name);
 err_out_client:
        rbd_put_client(rbd_dev);
-       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-err_out_slot:
-       list_del_init(&rbd_dev->node);
-       mutex_unlock(&ctl_mutex);
-
-       kfree(rbd_dev);
-err_out_opt:
+err_put_id:
+       rbd_id_put(rbd_dev);
+err_nomem:
        kfree(options);
-err_mon_dev:
-       kfree(mon_dev_name);
-err_out_mod:
+       kfree(rbd_dev);
+
        dout("Error adding device %s\n", buf);
        module_put(THIS_MODULE);
-       return rc;
+
+       return (ssize_t) rc;
 }
 
 static struct rbd_device *__rbd_get_dev(unsigned long id)
@@ -2299,22 +2465,28 @@ static struct rbd_device *__rbd_get_dev(unsigned long id)
        struct list_head *tmp;
        struct rbd_device *rbd_dev;
 
+       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->id == id) {
+                       spin_unlock(&rbd_dev_list_lock);
                        return rbd_dev;
+               }
        }
+       spin_unlock(&rbd_dev_list_lock);
        return NULL;
 }
 
 static void rbd_dev_release(struct device *dev)
 {
-       struct rbd_device *rbd_dev =
-                       container_of(dev, struct rbd_device, dev);
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-       if (rbd_dev->watch_request)
-               ceph_osdc_unregister_linger_request(&rbd_dev->client->osdc,
+       if (rbd_dev->watch_request) {
+               struct ceph_client *client = rbd_dev->rbd_client->client;
+
+               ceph_osdc_unregister_linger_request(&client->osdc,
                                                    rbd_dev->watch_request);
+       }
        if (rbd_dev->watch_event)
                rbd_req_sync_unwatch(rbd_dev, rbd_dev->obj_md_name);
 
@@ -2323,6 +2495,9 @@ static void rbd_dev_release(struct device *dev)
        /* clean up and free blkdev */
        rbd_free_disk(rbd_dev);
        unregister_blkdev(rbd_dev->major, rbd_dev->name);
+
+       /* done with the id, and with the rbd_dev */
+       rbd_id_put(rbd_dev);
        kfree(rbd_dev);
 
        /* release module ref */
@@ -2355,8 +2530,6 @@ static ssize_t rbd_remove(struct bus_type *bus,
                goto done;
        }
 
-       list_del_init(&rbd_dev->node);
-
        __rbd_remove_all_snaps(rbd_dev);
        rbd_bus_del_dev(rbd_dev);
 
@@ -2370,7 +2543,7 @@ static ssize_t rbd_snap_add(struct device *dev,
                            const char *buf,
                            size_t count)
 {
-       struct rbd_device *rbd_dev = dev_to_rbd(dev);
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
        int ret;
        char *name = kmalloc(count + 1, GFP_KERNEL);
        if (!name)
@@ -2406,12 +2579,6 @@ err_unlock:
        return ret;
 }
 
-static struct bus_attribute rbd_bus_attrs[] = {
-       __ATTR(add, S_IWUSR, NULL, rbd_add),
-       __ATTR(remove, S_IWUSR, NULL, rbd_remove),
-       __ATTR_NULL
-};
-
 /*
  * create control files in sysfs
  * /sys/bus/rbd/...
@@ -2420,21 +2587,21 @@ static int rbd_sysfs_init(void)
 {
        int ret;
 
-       rbd_bus_type.bus_attrs = rbd_bus_attrs;
-
-       ret = bus_register(&rbd_bus_type);
-        if (ret < 0)
+       ret = device_register(&rbd_root_dev);
+       if (ret < 0)
                return ret;
 
-       ret = device_register(&rbd_root_dev);
+       ret = bus_register(&rbd_bus_type);
+       if (ret < 0)
+               device_unregister(&rbd_root_dev);
 
        return ret;
 }
 
 static void rbd_sysfs_cleanup(void)
 {
-       device_unregister(&rbd_root_dev);
        bus_unregister(&rbd_bus_type);
+       device_unregister(&rbd_root_dev);
 }
 
 int __init rbd_init(void)
@@ -2444,8 +2611,7 @@ int __init rbd_init(void)
        rc = rbd_sysfs_init();
        if (rc)
                return rc;
-       spin_lock_init(&node_lock);
-       pr_info("loaded " DRV_NAME_LONG "\n");
+       pr_info("loaded " RBD_DRV_NAME_LONG "\n");
        return 0;
 }
 
index fc6c678..9507086 100644 (file)
 #define RBD_HEADER_SIGNATURE   "RBD"
 #define RBD_HEADER_VERSION     "001.005"
 
-struct rbd_info {
-       __le64 max_id;
-} __attribute__ ((packed));
-
 struct rbd_image_snap_ondisk {
        __le64 id;
        __le64 image_size;
index 48e8fee..9dcf76a 100644 (file)
@@ -839,10 +839,7 @@ static struct vio_driver vdc_port_driver = {
        .id_table       = vdc_port_match,
        .probe          = vdc_port_probe,
        .remove         = vdc_port_remove,
-       .driver         = {
-               .name   = "vdc_port",
-               .owner  = THIS_MODULE,
-       }
+       .name           = "vdc_port",
 };
 
 static int __init vdc_init(void)
index 2f22874..d5e1ab9 100644 (file)
@@ -1475,6 +1475,9 @@ static int __init xlblk_init(void)
        if (!xen_domain())
                return -ENODEV;
 
+       if (!xen_platform_pci_unplug)
+               return -ENODEV;
+
        if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
                printk(KERN_WARNING "xen_blk: can't get major %d with name %s\n",
                       XENVBD_MAJOR, DEV_NAME);
index 3d3c1e6..96de024 100644 (file)
@@ -107,17 +107,6 @@ static struct amba_driver nmk_rng_driver = {
        .id_table = nmk_rng_ids,
 };
 
-static int __init nmk_rng_init(void)
-{
-       return amba_driver_register(&nmk_rng_driver);
-}
-
-static void __devexit nmk_rng_exit(void)
-{
-       amba_driver_unregister(&nmk_rng_driver);
-}
-
-module_init(nmk_rng_init);
-module_exit(nmk_rng_exit);
+module_amba_driver(nmk_rng_driver);
 
 MODULE_LICENSE("GPL");
index b757fac..a07a5ca 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <asm/io.h>
 
+#include <plat/cpu.h>
+
 #define RNG_OUT_REG            0x00            /* Output register */
 #define RNG_STAT_REG           0x04            /* Status register
                                                        [0] = STAT_BUSY */
index 34767a6..020a6ae 100644 (file)
 #endif
 
 static DEFINE_MUTEX(ipmi_watchdog_mutex);
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 static ipmi_user_t watchdog_user;
 static int watchdog_ifnum;
@@ -320,7 +320,7 @@ module_param(start_now, int, 0444);
 MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as"
                 "soon as the driver is loaded.");
 
-module_param(nowayout, int, 0644);
+module_param(nowayout, bool, 0644);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
                 "(default=CONFIG_WATCHDOG_NOWAYOUT)");
 
index 9b3cd08..165e1fe 100644 (file)
@@ -8,3 +8,40 @@ config HAVE_CLK_PREPARE
 
 config HAVE_MACH_CLKDEV
        bool
+
+config COMMON_CLK
+       bool
+       select HAVE_CLK_PREPARE
+       ---help---
+         The common clock framework is a single definition of struct
+         clk, useful across many platforms, as well as an
+         implementation of the clock API in include/linux/clk.h.
+         Architectures utilizing the common struct clk should select
+         this option.
+
+menu "Common Clock Framework"
+       depends on COMMON_CLK
+
+config COMMON_CLK_DISABLE_UNUSED
+       bool "Disabled unused clocks at boot"
+       depends on COMMON_CLK
+       ---help---
+         Traverses the entire clock tree and disables any clocks that are
+         enabled in hardware but have not been enabled by any device drivers.
+         This saves power and keeps the software model of the clock in line
+         with reality.
+
+         If in doubt, say "N".
+
+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
+         tree structure.  Each directory contains read-only members
+         that export information specific to that clk node: clk_rate,
+         clk_flags, clk_prepare_count, clk_enable_count &
+         clk_notifier_count.
+
+endmenu
index 07613fa..1f736bc 100644 (file)
@@ -1,2 +1,4 @@
 
 obj-$(CONFIG_CLKDEV_LOOKUP)    += clkdev.o
+obj-$(CONFIG_COMMON_CLK)       += clk.o clk-fixed-rate.o clk-gate.o \
+                                  clk-mux.o clk-divider.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
new file mode 100644 (file)
index 0000000..d5ac6a7
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Adjustable divider clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/string.h>
+
+/*
+ * DOC: basic adjustable divider clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is adjustable.  clk->rate = parent->rate / divisor
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+
+#define div_mask(d)    ((1 << (d->width)) - 1)
+
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       unsigned int div;
+
+       div = readl(divider->reg) >> divider->shift;
+       div &= div_mask(divider);
+
+       if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
+               div++;
+
+       return parent_rate / div;
+}
+EXPORT_SYMBOL_GPL(clk_divider_recalc_rate);
+
+/*
+ * The reverse of DIV_ROUND_UP: The maximum number which
+ * divided by m is r
+ */
+#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
+
+static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
+               unsigned long *best_parent_rate)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       int i, bestdiv = 0;
+       unsigned long parent_rate, best = 0, now, maxdiv;
+
+       if (!rate)
+               rate = 1;
+
+       maxdiv = (1 << divider->width);
+
+       if (divider->flags & CLK_DIVIDER_ONE_BASED)
+               maxdiv--;
+
+       if (!best_parent_rate) {
+               parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
+               bestdiv = DIV_ROUND_UP(parent_rate, rate);
+               bestdiv = bestdiv == 0 ? 1 : bestdiv;
+               bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
+               return bestdiv;
+       }
+
+       /*
+        * The maximum divider we can use without overflowing
+        * unsigned long in rate * i below
+        */
+       maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+       for (i = 1; i <= maxdiv; i++) {
+               parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
+                               MULT_ROUND_UP(rate, i));
+               now = parent_rate / i;
+               if (now <= rate && now > best) {
+                       bestdiv = i;
+                       best = now;
+                       *best_parent_rate = parent_rate;
+               }
+       }
+
+       if (!bestdiv) {
+               bestdiv = (1 << divider->width);
+               if (divider->flags & CLK_DIVIDER_ONE_BASED)
+                       bestdiv--;
+               *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
+       }
+
+       return bestdiv;
+}
+
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long *prate)
+{
+       int div;
+       div = clk_divider_bestdiv(hw, rate, prate);
+
+       if (prate)
+               return *prate / div;
+       else {
+               unsigned long r;
+               r = __clk_get_rate(__clk_get_parent(hw->clk));
+               return r / div;
+       }
+}
+EXPORT_SYMBOL_GPL(clk_divider_round_rate);
+
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       unsigned int div;
+       unsigned long flags = 0;
+       u32 val;
+
+       div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate;
+
+       if (!(divider->flags & CLK_DIVIDER_ONE_BASED))
+               div--;
+
+       if (div > div_mask(divider))
+               div = div_mask(divider);
+
+       if (divider->lock)
+               spin_lock_irqsave(divider->lock, flags);
+
+       val = readl(divider->reg);
+       val &= ~(div_mask(divider) << divider->shift);
+       val |= div << divider->shift;
+       writel(val, divider->reg);
+
+       if (divider->lock)
+               spin_unlock_irqrestore(divider->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(clk_divider_set_rate);
+
+struct clk_ops clk_divider_ops = {
+       .recalc_rate = clk_divider_recalc_rate,
+       .round_rate = clk_divider_round_rate,
+       .set_rate = clk_divider_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_divider_ops);
+
+struct clk *clk_register_divider(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 shift, u8 width,
+               u8 clk_divider_flags, spinlock_t *lock)
+{
+       struct clk_divider *div;
+       struct clk *clk;
+
+       div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
+
+       if (!div) {
+               pr_err("%s: could not allocate divider clk\n", __func__);
+               return NULL;
+       }
+
+       /* struct clk_divider assignments */
+       div->reg = reg;
+       div->shift = shift;
+       div->width = width;
+       div->flags = clk_divider_flags;
+       div->lock = lock;
+
+       if (parent_name) {
+               div->parent[0] = kstrdup(parent_name, GFP_KERNEL);
+               if (!div->parent[0])
+                       goto out;
+       }
+
+       clk = clk_register(dev, name,
+                       &clk_divider_ops, &div->hw,
+                       div->parent,
+                       (parent_name ? 1 : 0),
+                       flags);
+       if (clk)
+               return clk;
+
+out:
+       kfree(div->parent[0]);
+       kfree(div);
+
+       return NULL;
+}
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
new file mode 100644 (file)
index 0000000..90c79fb
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Fixed rate clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+/*
+ * DOC: basic fixed-rate clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parents are prepared
+ * enable - clk_enable only ensures parents are enabled
+ * rate - rate is always a fixed value.  No clk_set_rate support
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
+
+static unsigned long clk_fixed_rate_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       return to_clk_fixed_rate(hw)->fixed_rate;
+}
+EXPORT_SYMBOL_GPL(clk_fixed_rate_recalc_rate);
+
+struct clk_ops clk_fixed_rate_ops = {
+       .recalc_rate = clk_fixed_rate_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fixed_rate_ops);
+
+struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               unsigned long fixed_rate)
+{
+       struct clk_fixed_rate *fixed;
+       char **parent_names = NULL;
+       u8 len;
+
+       fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
+
+       if (!fixed) {
+               pr_err("%s: could not allocate fixed clk\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       /* struct clk_fixed_rate assignments */
+       fixed->fixed_rate = fixed_rate;
+
+       if (parent_name) {
+               parent_names = kmalloc(sizeof(char *), GFP_KERNEL);
+
+               if (! parent_names)
+                       goto out;
+
+               len = sizeof(char) * strlen(parent_name);
+
+               parent_names[0] = kmalloc(len, GFP_KERNEL);
+
+               if (!parent_names[0])
+                       goto out;
+
+               strncpy(parent_names[0], parent_name, len);
+       }
+
+out:
+       return clk_register(dev, name,
+                       &clk_fixed_rate_ops, &fixed->hw,
+                       parent_names,
+                       (parent_name ? 1 : 0),
+                       flags);
+}
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
new file mode 100644 (file)
index 0000000..b5902e2
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Gated clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/string.h>
+
+/**
+ * DOC: basic gatable clock which can gate and ungate it's ouput
+ *
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable and clk_disable are functional & control gating
+ * rate - inherits rate from parent.  No clk_set_rate support
+ * parent - fixed parent.  No clk_set_parent support
+ */
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+
+static void clk_gate_set_bit(struct clk_gate *gate)
+{
+       u32 reg;
+       unsigned long flags = 0;
+
+       if (gate->lock)
+               spin_lock_irqsave(gate->lock, flags);
+
+       reg = readl(gate->reg);
+       reg |= BIT(gate->bit_idx);
+       writel(reg, gate->reg);
+
+       if (gate->lock)
+               spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static void clk_gate_clear_bit(struct clk_gate *gate)
+{
+       u32 reg;
+       unsigned long flags = 0;
+
+       if (gate->lock)
+               spin_lock_irqsave(gate->lock, flags);
+
+       reg = readl(gate->reg);
+       reg &= ~BIT(gate->bit_idx);
+       writel(reg, gate->reg);
+
+       if (gate->lock)
+               spin_unlock_irqrestore(gate->lock, flags);
+}
+
+static int clk_gate_enable(struct clk_hw *hw)
+{
+       struct clk_gate *gate = to_clk_gate(hw);
+
+       if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+               clk_gate_clear_bit(gate);
+       else
+               clk_gate_set_bit(gate);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(clk_gate_enable);
+
+static void clk_gate_disable(struct clk_hw *hw)
+{
+       struct clk_gate *gate = to_clk_gate(hw);
+
+       if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+               clk_gate_set_bit(gate);
+       else
+               clk_gate_clear_bit(gate);
+}
+EXPORT_SYMBOL_GPL(clk_gate_disable);
+
+static int clk_gate_is_enabled(struct clk_hw *hw)
+{
+       u32 reg;
+       struct clk_gate *gate = to_clk_gate(hw);
+
+       reg = readl(gate->reg);
+
+       /* if a set bit disables this clk, flip it before masking */
+       if (gate->flags & CLK_GATE_SET_TO_DISABLE)
+               reg ^= BIT(gate->bit_idx);
+
+       reg &= BIT(gate->bit_idx);
+
+       return reg ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
+
+struct clk_ops clk_gate_ops = {
+       .enable = clk_gate_enable,
+       .disable = clk_gate_disable,
+       .is_enabled = clk_gate_is_enabled,
+};
+EXPORT_SYMBOL_GPL(clk_gate_ops);
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock)
+{
+       struct clk_gate *gate;
+       struct clk *clk;
+
+       gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+
+       if (!gate) {
+               pr_err("%s: could not allocate gated clk\n", __func__);
+               return NULL;
+       }
+
+       /* struct clk_gate assignments */
+       gate->reg = reg;
+       gate->bit_idx = bit_idx;
+       gate->flags = clk_gate_flags;
+       gate->lock = lock;
+
+       if (parent_name) {
+               gate->parent[0] = kstrdup(parent_name, GFP_KERNEL);
+               if (!gate->parent[0])
+                       goto out;
+       }
+
+       clk = clk_register(dev, name,
+                       &clk_gate_ops, &gate->hw,
+                       gate->parent,
+                       (parent_name ? 1 : 0),
+                       flags);
+       if (clk)
+               return clk;
+out:
+       kfree(gate->parent[0]);
+       kfree(gate);
+
+       return NULL;
+}
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
new file mode 100644 (file)
index 0000000..c71ad1f
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Simple multiplexer clock implementation
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+/*
+ * DOC: basic adjustable multiplexer clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is only affected by parent switching.  No clk_set_rate support
+ * parent - parent is adjustable through clk_set_parent
+ */
+
+#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
+
+static u8 clk_mux_get_parent(struct clk_hw *hw)
+{
+       struct clk_mux *mux = to_clk_mux(hw);
+       u32 val;
+
+       /*
+        * FIXME need a mux-specific flag to determine if val is bitwise or numeric
+        * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
+        * to 0x7 (index starts at one)
+        * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
+        * val = 0x4 really means "bit 2, index starts at bit 0"
+        */
+       val = readl(mux->reg) >> mux->shift;
+       val &= (1 << mux->width) - 1;
+
+       if (val && (mux->flags & CLK_MUX_INDEX_BIT))
+               val = ffs(val) - 1;
+
+       if (val && (mux->flags & CLK_MUX_INDEX_ONE))
+               val--;
+
+       if (val >= __clk_get_num_parents(hw->clk))
+               return -EINVAL;
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(clk_mux_get_parent);
+
+static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct clk_mux *mux = to_clk_mux(hw);
+       u32 val;
+       unsigned long flags = 0;
+
+       if (mux->flags & CLK_MUX_INDEX_BIT)
+               index = (1 << ffs(index));
+
+       if (mux->flags & CLK_MUX_INDEX_ONE)
+               index++;
+
+       if (mux->lock)
+               spin_lock_irqsave(mux->lock, flags);
+
+       val = readl(mux->reg);
+       val &= ~(((1 << mux->width) - 1) << mux->shift);
+       val |= index << mux->shift;
+       writel(val, mux->reg);
+
+       if (mux->lock)
+               spin_unlock_irqrestore(mux->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(clk_mux_set_parent);
+
+struct clk_ops clk_mux_ops = {
+       .get_parent = clk_mux_get_parent,
+       .set_parent = clk_mux_set_parent,
+};
+EXPORT_SYMBOL_GPL(clk_mux_ops);
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+               char **parent_names, u8 num_parents, unsigned long flags,
+               void __iomem *reg, u8 shift, u8 width,
+               u8 clk_mux_flags, spinlock_t *lock)
+{
+       struct clk_mux *mux;
+
+       mux = kmalloc(sizeof(struct clk_mux), GFP_KERNEL);
+
+       if (!mux) {
+               pr_err("%s: could not allocate mux clk\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       /* struct clk_mux assignments */
+       mux->reg = reg;
+       mux->shift = shift;
+       mux->width = width;
+       mux->flags = clk_mux_flags;
+       mux->lock = lock;
+
+       return clk_register(dev, name, &clk_mux_ops, &mux->hw,
+                       parent_names, num_parents, flags);
+}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644 (file)
index 0000000..9cf6f59
--- /dev/null
@@ -0,0 +1,1461 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
+ * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ *
+ * Standard functionality for the common clock API.  See Documentation/clk.txt
+ */
+
+#include <linux/clk-private.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+static DEFINE_SPINLOCK(enable_lock);
+static DEFINE_MUTEX(prepare_lock);
+
+static HLIST_HEAD(clk_root_list);
+static HLIST_HEAD(clk_orphan_list);
+static LIST_HEAD(clk_notifier_list);
+
+/***        debugfs support        ***/
+
+#ifdef CONFIG_COMMON_CLK_DEBUG
+#include <linux/debugfs.h>
+
+static struct dentry *rootdir;
+static struct dentry *orphandir;
+static int inited = 0;
+
+/* caller must hold prepare_lock */
+static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
+{
+       struct dentry *d;
+       int ret = -ENOMEM;
+
+       if (!clk || !pdentry) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       d = debugfs_create_dir(clk->name, pdentry);
+       if (!d)
+               goto out;
+
+       clk->dentry = d;
+
+       d = debugfs_create_u32("clk_rate", S_IRUGO, clk->dentry,
+                       (u32 *)&clk->rate);
+       if (!d)
+               goto err_out;
+
+       d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry,
+                       (u32 *)&clk->flags);
+       if (!d)
+               goto err_out;
+
+       d = debugfs_create_u32("clk_prepare_count", S_IRUGO, clk->dentry,
+                       (u32 *)&clk->prepare_count);
+       if (!d)
+               goto err_out;
+
+       d = debugfs_create_u32("clk_enable_count", S_IRUGO, clk->dentry,
+                       (u32 *)&clk->enable_count);
+       if (!d)
+               goto err_out;
+
+       d = debugfs_create_u32("clk_notifier_count", S_IRUGO, clk->dentry,
+                       (u32 *)&clk->notifier_count);
+       if (!d)
+               goto err_out;
+
+       ret = 0;
+       goto out;
+
+err_out:
+       debugfs_remove(clk->dentry);
+out:
+       return ret;
+}
+
+/* caller must hold prepare_lock */
+static int clk_debug_create_subtree(struct clk *clk, struct dentry *pdentry)
+{
+       struct clk *child;
+       struct hlist_node *tmp;
+       int ret = -EINVAL;;
+
+       if (!clk || !pdentry)
+               goto out;
+
+       ret = clk_debug_create_one(clk, pdentry);
+
+       if (ret)
+               goto out;
+
+       hlist_for_each_entry(child, tmp, &clk->children, child_node)
+               clk_debug_create_subtree(child, clk->dentry);
+
+       ret = 0;
+out:
+       return ret;
+}
+
+/**
+ * clk_debug_register - add a clk node to the debugfs clk tree
+ * @clk: the clk being added to the debugfs clk tree
+ *
+ * Dynamically adds a clk to the debugfs clk tree if debugfs has been
+ * initialized.  Otherwise it bails out early since the debugfs clk tree
+ * will be created lazily by clk_debug_init as part of a late_initcall.
+ *
+ * Caller must hold prepare_lock.  Only clk_init calls this function (so
+ * far) so this is taken care.
+ */
+static int clk_debug_register(struct clk *clk)
+{
+       struct clk *parent;
+       struct dentry *pdentry;
+       int ret = 0;
+
+       if (!inited)
+               goto out;
+
+       parent = clk->parent;
+
+       /*
+        * Check to see if a clk is a root clk.  Also check that it is
+        * safe to add this clk to debugfs
+        */
+       if (!parent)
+               if (clk->flags & CLK_IS_ROOT)
+                       pdentry = rootdir;
+               else
+                       pdentry = orphandir;
+       else
+               if (parent->dentry)
+                       pdentry = parent->dentry;
+               else
+                       goto out;
+
+       ret = clk_debug_create_subtree(clk, pdentry);
+
+out:
+       return ret;
+}
+
+/**
+ * clk_debug_init - lazily create the debugfs clk tree visualization
+ *
+ * clks are often initialized very early during boot before memory can
+ * be dynamically allocated and well before debugfs is setup.
+ * clk_debug_init walks the clk tree hierarchy while holding
+ * prepare_lock and creates the topology as part of a late_initcall,
+ * thus insuring that clks initialized very early will still be
+ * represented in the debugfs clk tree.  This function should only be
+ * called once at boot-time, and all other clks added dynamically will
+ * be done so with clk_debug_register.
+ */
+static int __init clk_debug_init(void)
+{
+       struct clk *clk;
+       struct hlist_node *tmp;
+
+       rootdir = debugfs_create_dir("clk", NULL);
+
+       if (!rootdir)
+               return -ENOMEM;
+
+       orphandir = debugfs_create_dir("orphans", rootdir);
+
+       if (!orphandir)
+               return -ENOMEM;
+
+       mutex_lock(&prepare_lock);
+
+       hlist_for_each_entry(clk, tmp, &clk_root_list, child_node)
+               clk_debug_create_subtree(clk, rootdir);
+
+       hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node)
+               clk_debug_create_subtree(clk, orphandir);
+
+       inited = 1;
+
+       mutex_unlock(&prepare_lock);
+
+       return 0;
+}
+late_initcall(clk_debug_init);
+#else
+static inline int clk_debug_register(struct clk *clk) { return 0; }
+#endif /* CONFIG_COMMON_CLK_DEBUG */
+
+#ifdef CONFIG_COMMON_CLK_DISABLE_UNUSED
+/* caller must hold prepare_lock */
+static void clk_disable_unused_subtree(struct clk *clk)
+{
+       struct clk *child;
+       struct hlist_node *tmp;
+       unsigned long flags;
+
+       if (!clk)
+               goto out;
+
+       hlist_for_each_entry(child, tmp, &clk->children, child_node)
+               clk_disable_unused_subtree(child);
+
+       spin_lock_irqsave(&enable_lock, flags);
+
+       if (clk->enable_count)
+               goto unlock_out;
+
+       if (clk->flags & CLK_IGNORE_UNUSED)
+               goto unlock_out;
+
+       if (__clk_is_enabled(clk) && clk->ops->disable)
+               clk->ops->disable(clk->hw);
+
+unlock_out:
+       spin_unlock_irqrestore(&enable_lock, flags);
+
+out:
+       return;
+}
+
+static int clk_disable_unused(void)
+{
+       struct clk *clk;
+       struct hlist_node *tmp;
+
+       mutex_lock(&prepare_lock);
+
+       hlist_for_each_entry(clk, tmp, &clk_root_list, child_node)
+               clk_disable_unused_subtree(clk);
+
+       hlist_for_each_entry(clk, tmp, &clk_orphan_list, child_node)
+               clk_disable_unused_subtree(clk);
+
+       mutex_unlock(&prepare_lock);
+
+       return 0;
+}
+late_initcall(clk_disable_unused);
+#else
+static inline int clk_disable_unused(struct clk *clk) { return 0; }
+#endif /* CONFIG_COMMON_CLK_DISABLE_UNUSED */
+
+/***    helper functions   ***/
+
+inline const char *__clk_get_name(struct clk *clk)
+{
+       return !clk ? NULL : clk->name;
+}
+
+inline struct clk_hw *__clk_get_hw(struct clk *clk)
+{
+       return !clk ? NULL : clk->hw;
+}
+
+inline u8 __clk_get_num_parents(struct clk *clk)
+{
+       return !clk ? -EINVAL : clk->num_parents;
+}
+
+inline struct clk *__clk_get_parent(struct clk *clk)
+{
+       return !clk ? NULL : clk->parent;
+}
+
+inline int __clk_get_enable_count(struct clk *clk)
+{
+       return !clk ? -EINVAL : clk->enable_count;
+}
+
+inline int __clk_get_prepare_count(struct clk *clk)
+{
+       return !clk ? -EINVAL : clk->prepare_count;
+}
+
+unsigned long __clk_get_rate(struct clk *clk)
+{
+       unsigned long ret;
+
+       if (!clk) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = clk->rate;
+
+       if (clk->flags & CLK_IS_ROOT)
+               goto out;
+
+       if (!clk->parent)
+               ret = -ENODEV;
+
+out:
+       return ret;
+}
+
+inline unsigned long __clk_get_flags(struct clk *clk)
+{
+       return !clk ? -EINVAL : clk->flags;
+}
+
+int __clk_is_enabled(struct clk *clk)
+{
+       int ret;
+
+       if (!clk)
+               return -EINVAL;
+
+       /*
+        * .is_enabled is only mandatory for clocks that gate
+        * fall back to software usage counter if .is_enabled is missing
+        */
+       if (!clk->ops->is_enabled) {
+               ret = clk->enable_count ? 1 : 0;
+               goto out;
+       }
+
+       ret = clk->ops->is_enabled(clk->hw);
+out:
+       return ret;
+}
+
+static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
+{
+       struct clk *child;
+       struct clk *ret;
+       struct hlist_node *tmp;
+
+       if (!strcmp(clk->name, name))
+               return clk;
+
+       hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+               ret = __clk_lookup_subtree(name, child);
+               if (ret)
+                       return ret;
+       }
+
+       return NULL;
+}
+
+struct clk *__clk_lookup(const char *name)
+{
+       struct clk *root_clk;
+       struct clk *ret;
+       struct hlist_node *tmp;
+
+       if (!name)
+               return NULL;
+
+       /* search the 'proper' clk tree first */
+       hlist_for_each_entry(root_clk, tmp, &clk_root_list, child_node) {
+               ret = __clk_lookup_subtree(name, root_clk);
+               if (ret)
+                       return ret;
+       }
+
+       /* if not found, then search the orphan tree */
+       hlist_for_each_entry(root_clk, tmp, &clk_orphan_list, child_node) {
+               ret = __clk_lookup_subtree(name, root_clk);
+               if (ret)
+                       return ret;
+       }
+
+       return NULL;
+}
+
+/***        clk api        ***/
+
+void __clk_unprepare(struct clk *clk)
+{
+       if (!clk)
+               return;
+
+       if (WARN_ON(clk->prepare_count == 0))
+               return;
+
+       if (--clk->prepare_count > 0)
+               return;
+
+       WARN_ON(clk->enable_count > 0);
+
+       if (clk->ops->unprepare)
+               clk->ops->unprepare(clk->hw);
+
+       __clk_unprepare(clk->parent);
+}
+
+/**
+ * clk_unprepare - undo preparation of a clock source
+ * @clk: the clk being unprepare
+ *
+ * clk_unprepare may sleep, which differentiates it from clk_disable.  In a
+ * simple case, clk_unprepare can be used instead of clk_disable to gate a clk
+ * if the operation may sleep.  One example is a clk which is accessed over
+ * I2c.  In the complex case a clk gate operation may require a fast and a slow
+ * part.  It is this reason that clk_unprepare and clk_disable are not mutually
+ * exclusive.  In fact clk_disable must be called before clk_unprepare.
+ */
+void clk_unprepare(struct clk *clk)
+{
+       mutex_lock(&prepare_lock);
+       __clk_unprepare(clk);
+       mutex_unlock(&prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int __clk_prepare(struct clk *clk)
+{
+       int ret = 0;
+
+       if (!clk)
+               return 0;
+
+       if (clk->prepare_count == 0) {
+               ret = __clk_prepare(clk->parent);
+               if (ret)
+                       return ret;
+
+               if (clk->ops->prepare) {
+                       ret = clk->ops->prepare(clk->hw);
+                       if (ret) {
+                               __clk_unprepare(clk->parent);
+                               return ret;
+                       }
+               }
+       }
+
+       clk->prepare_count++;
+
+       return 0;
+}
+
+/**
+ * clk_prepare - prepare a clock source
+ * @clk: the clk being prepared
+ *
+ * clk_prepare may sleep, which differentiates it from clk_enable.  In a simple
+ * case, clk_prepare can be used instead of clk_enable to ungate a clk if the
+ * operation may sleep.  One example is a clk which is accessed over I2c.  In
+ * the complex case a clk ungate operation may require a fast and a slow part.
+ * It is this reason that clk_prepare and clk_enable are not mutually
+ * exclusive.  In fact clk_prepare must be called before clk_enable.
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_prepare(struct clk *clk)
+{
+       int ret;
+
+       mutex_lock(&prepare_lock);
+       ret = __clk_prepare(clk);
+       mutex_unlock(&prepare_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+static void __clk_disable(struct clk *clk)
+{
+       if (!clk)
+               return;
+
+       if (WARN_ON(clk->enable_count == 0))
+               return;
+
+       if (--clk->enable_count > 0)
+               return;
+
+       if (clk->ops->disable)
+               clk->ops->disable(clk->hw);
+
+       __clk_disable(clk->parent);
+}
+
+/**
+ * clk_disable - gate a clock
+ * @clk: the clk being gated
+ *
+ * clk_disable must not sleep, which differentiates it from clk_unprepare.  In
+ * a simple case, clk_disable can be used instead of clk_unprepare to gate a
+ * clk if the operation is fast and will never sleep.  One example is a
+ * SoC-internal clk which is controlled via simple register writes.  In the
+ * complex case a clk gate operation may require a fast and a slow part.  It is
+ * this reason that clk_unprepare and clk_disable are not mutually exclusive.
+ * In fact clk_disable must be called before clk_unprepare.
+ */
+void clk_disable(struct clk *clk)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&enable_lock, flags);
+       __clk_disable(clk);
+       spin_unlock_irqrestore(&enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+static int __clk_enable(struct clk *clk)
+{
+       int ret = 0;
+
+       if (!clk)
+               return 0;
+
+       if (WARN_ON(clk->prepare_count == 0))
+               return -ESHUTDOWN;
+
+       if (clk->enable_count == 0) {
+               ret = __clk_enable(clk->parent);
+
+               if (ret)
+                       return ret;
+
+               if (clk->ops->enable) {
+                       ret = clk->ops->enable(clk->hw);
+                       if (ret) {
+                               __clk_disable(clk->parent);
+                               return ret;
+                       }
+               }
+       }
+
+       clk->enable_count++;
+       return 0;
+}
+
+/**
+ * clk_enable - ungate a clock
+ * @clk: the clk being ungated
+ *
+ * clk_enable must not sleep, which differentiates it from clk_prepare.  In a
+ * simple case, clk_enable can be used instead of clk_prepare to ungate a clk
+ * if the operation will never sleep.  One example is a SoC-internal clk which
+ * is controlled via simple register writes.  In the complex case a clk ungate
+ * operation may require a fast and a slow part.  It is this reason that
+ * clk_enable and clk_prepare are not mutually exclusive.  In fact clk_prepare
+ * must be called before clk_enable.  Returns 0 on success, -EERROR
+ * otherwise.
+ */
+int clk_enable(struct clk *clk)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&enable_lock, flags);
+       ret = __clk_enable(clk);
+       spin_unlock_irqrestore(&enable_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+/**
+ * clk_get_rate - return the rate of clk
+ * @clk: the clk whose rate is being returned
+ *
+ * Simply returns the cached rate of the clk.  Does not query the hardware.  If
+ * clk is NULL then returns -EINVAL.
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+       unsigned long rate;
+
+       mutex_lock(&prepare_lock);
+       rate = __clk_get_rate(clk);
+       mutex_unlock(&prepare_lock);
+
+       return rate;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+/**
+ * __clk_round_rate - round the given rate for a clk
+ * @clk: round the rate of this clock
+ *
+ * Caller must hold prepare_lock.  Useful for clk_ops such as .set_rate
+ */
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned long unused;
+
+       if (!clk)
+               return -EINVAL;
+
+       if (!clk->ops->round_rate)
+               return clk->rate;
+
+       if (clk->flags & CLK_SET_RATE_PARENT)
+               return clk->ops->round_rate(clk->hw, rate, &unused);
+       else
+               return clk->ops->round_rate(clk->hw, rate, NULL);
+}
+
+/**
+ * clk_round_rate - round the given rate for a clk
+ * @clk: the clk for which we are rounding a rate
+ * @rate: the rate which is to be rounded
+ *
+ * Takes in a rate as input and rounds it to a rate that the clk can actually
+ * use which is then returned.  If clk doesn't support round_rate operation
+ * then the parent rate is returned.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned long ret;
+
+       mutex_lock(&prepare_lock);
+       ret = __clk_round_rate(clk, rate);
+       mutex_unlock(&prepare_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+/**
+ * __clk_notify - call clk notifier chain
+ * @clk: struct clk * that is changing rate
+ * @msg: clk notifier type (see include/linux/clk.h)
+ * @old_rate: old clk rate
+ * @new_rate: new clk rate
+ *
+ * Triggers a notifier call chain on the clk rate-change notification
+ * for 'clk'.  Passes a pointer to the struct clk and the previous
+ * and current rates to the notifier callback.  Intended to be called by
+ * internal clock code only.  Returns NOTIFY_DONE from the last driver
+ * called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
+ * a driver returns that.
+ */
+static int __clk_notify(struct clk *clk, unsigned long msg,
+               unsigned long old_rate, unsigned long new_rate)
+{
+       struct clk_notifier *cn;
+       struct clk_notifier_data cnd;
+       int ret = NOTIFY_DONE;
+
+       cnd.clk = clk;
+       cnd.old_rate = old_rate;
+       cnd.new_rate = new_rate;
+
+       list_for_each_entry(cn, &clk_notifier_list, node) {
+               if (cn->clk == clk) {
+                       ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
+                                       &cnd);
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+/**
+ * __clk_recalc_rates
+ * @clk: first clk in the subtree
+ * @msg: notification type (see include/linux/clk.h)
+ *
+ * Walks the subtree of clks starting with clk and recalculates rates as it
+ * goes.  Note that if a clk does not implement the .recalc_rate callback then
+ * it is assumed that the clock will take on the rate of it's parent.
+ *
+ * clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
+ * if necessary.
+ *
+ * Caller must hold prepare_lock.
+ */
+static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
+{
+       unsigned long old_rate;
+       unsigned long parent_rate = 0;
+       struct hlist_node *tmp;
+       struct clk *child;
+
+       old_rate = clk->rate;
+
+       if (clk->parent)
+               parent_rate = clk->parent->rate;
+
+       if (clk->ops->recalc_rate)
+               clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate);
+       else
+               clk->rate = parent_rate;
+
+       /*
+        * ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE
+        * & ABORT_RATE_CHANGE notifiers
+        */
+       if (clk->notifier_count && msg)
+               __clk_notify(clk, msg, old_rate, clk->rate);
+
+       hlist_for_each_entry(child, tmp, &clk->children, child_node)
+               __clk_recalc_rates(child, msg);
+}
+
+/**
+ * __clk_speculate_rates
+ * @clk: first clk in the subtree
+ * @parent_rate: the "future" rate of clk's parent
+ *
+ * Walks the subtree of clks starting with clk, speculating rates as it
+ * goes and firing off PRE_RATE_CHANGE notifications as necessary.
+ *
+ * Unlike clk_recalc_rates, clk_speculate_rates exists only for sending
+ * pre-rate change notifications and returns early if no clks in the
+ * subtree have subscribed to the notifications.  Note that if a clk does not
+ * implement the .recalc_rate callback then it is assumed that the clock will
+ * take on the rate of it's parent.
+ *
+ * Caller must hold prepare_lock.
+ */
+static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
+{
+       struct hlist_node *tmp;
+       struct clk *child;
+       unsigned long new_rate;
+       int ret = NOTIFY_DONE;
+
+       if (clk->ops->recalc_rate)
+               new_rate = clk->ops->recalc_rate(clk->hw, parent_rate);
+       else
+               new_rate = parent_rate;
+
+       /* abort the rate change if a driver returns NOTIFY_BAD */
+       if (clk->notifier_count)
+               ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
+
+       if (ret == NOTIFY_BAD)
+               goto out;
+
+       hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+               ret = __clk_speculate_rates(child, new_rate);
+               if (ret == NOTIFY_BAD)
+                       break;
+       }
+
+out:
+       return ret;
+}
+
+static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
+{
+       struct clk *child;
+       struct hlist_node *tmp;
+
+       clk->new_rate = new_rate;
+
+       hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+               if (child->ops->recalc_rate)
+                       child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
+               else
+                       child->new_rate = new_rate;
+               clk_calc_subtree(child, child->new_rate);
+       }
+}
+
+/*
+ * calculate the new rates returning the topmost clock that has to be
+ * changed.
+ */
+static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
+{
+       struct clk *top = clk;
+       unsigned long best_parent_rate = clk->parent->rate;
+       unsigned long new_rate;
+
+       if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) {
+               clk->new_rate = clk->rate;
+               return NULL;
+       }
+
+       if (!clk->ops->round_rate && (clk->flags & CLK_SET_RATE_PARENT)) {
+               top = clk_calc_new_rates(clk->parent, rate);
+               new_rate = clk->new_rate = clk->parent->new_rate;
+
+               goto out;
+       }
+
+       if (clk->flags & CLK_SET_RATE_PARENT)
+               new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
+       else
+               new_rate = clk->ops->round_rate(clk->hw, rate, NULL);
+
+       if (best_parent_rate != clk->parent->rate) {
+               top = clk_calc_new_rates(clk->parent, best_parent_rate);
+
+               goto out;
+       }
+
+out:
+       clk_calc_subtree(clk, new_rate);
+
+       return top;
+}
+
+/*
+ * Notify about rate changes in a subtree. Always walk down the whole tree
+ * so that in case of an error we can walk down the whole tree again and
+ * abort the change.
+ */
+static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
+{
+       struct hlist_node *tmp;
+       struct clk *child, *fail_clk = NULL;
+       int ret = NOTIFY_DONE;
+
+       if (clk->rate == clk->new_rate)
+               return 0;
+
+       if (clk->notifier_count) {
+               ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
+               if (ret == NOTIFY_BAD)
+                       fail_clk = clk;
+       }
+
+       hlist_for_each_entry(child, tmp, &clk->children, child_node) {
+               clk = clk_propagate_rate_change(child, event);
+               if (clk)
+                       fail_clk = clk;
+       }
+
+       return fail_clk;
+}
+
+/*
+ * walk down a subtree and set the new rates notifying the rate
+ * change on the way
+ */
+static void clk_change_rate(struct clk *clk)
+{
+       struct clk *child;
+       unsigned long old_rate;
+       struct hlist_node *tmp;
+
+       old_rate = clk->rate;
+
+       if (clk->ops->set_rate)
+               clk->ops->set_rate(clk->hw, clk->new_rate);
+
+       if (clk->ops->recalc_rate)
+               clk->rate = clk->ops->recalc_rate(clk->hw,
+                               clk->parent->rate);
+       else
+               clk->rate = clk->parent->rate;
+
+       if (clk->notifier_count && old_rate != clk->rate)
+               __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
+
+       hlist_for_each_entry(child, tmp, &clk->children, child_node)
+               clk_change_rate(child);
+}
+
+/**
+ * clk_set_rate - specify a new rate for clk
+ * @clk: the clk whose rate is being changed
+ * @rate: the new rate for clk
+ *
+ * In the simplest case clk_set_rate will only change the rate of clk.
+ *
+ * If clk has the CLK_SET_RATE_GATE flag set and it is enabled this call
+ * will fail; only when the clk is disabled will it be able to change
+ * its rate.
+ *
+ * Setting the CLK_SET_RATE_PARENT flag allows clk_set_rate to
+ * recursively propagate up to clk's parent; whether or not this happens
+ * depends on the outcome of clk's .round_rate implementation.  If
+ * *parent_rate is 0 after calling .round_rate then upstream parent
+ * propagation is ignored.  If *parent_rate comes back with a new rate
+ * for clk's parent then we propagate up to clk's parent and set it's
+ * rate.  Upward propagation will continue until either a clk does not
+ * support the CLK_SET_RATE_PARENT flag or .round_rate stops requesting
+ * changes to clk's parent_rate.  If there is a failure during upstream
+ * propagation then clk_set_rate will unwind and restore each clk's rate
+ * that had been successfully changed.  Afterwards a rate change abort
+ * notification will be propagated downstream, starting from the clk
+ * that failed.
+ *
+ * At the end of all of the rate setting, clk_set_rate internally calls
+ * __clk_recalc_rates and propagates the rate changes downstream,
+ * starting from the highest clk whose rate was changed.  This has the
+ * added benefit of propagating post-rate change notifiers.
+ *
+ * Note that while post-rate change and rate change abort notifications
+ * are guaranteed to be sent to a clk only once per call to
+ * clk_set_rate, pre-change notifications will be sent for every clk
+ * whose rate is changed.  Stacking pre-change notifications is noisy
+ * for the drivers subscribed to them, but this allows drivers to react
+ * to intermediate clk rate changes up until the point where the final
+ * rate is achieved at the end of upstream propagation.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       struct clk *top, *fail_clk;
+       int ret = 0;
+
+       /* prevent racing with updates to the clock topology */
+       mutex_lock(&prepare_lock);
+
+       /* bail early if nothing to do */
+       if (rate == clk->rate)
+               goto out;
+
+       /* calculate new rates and get the topmost changed clock */
+       top = clk_calc_new_rates(clk, rate);
+       if (!top) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* notify that we are about to change rates */
+       fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
+       if (fail_clk) {
+               pr_warn("%s: failed to set %s rate\n", __func__,
+                               fail_clk->name);
+               clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
+               ret = -EBUSY;
+               goto out;
+       }
+
+       /* change the rates */
+       clk_change_rate(top);
+
+       mutex_unlock(&prepare_lock);
+
+       return 0;
+out:
+       mutex_unlock(&prepare_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+/**
+ * clk_get_parent - return the parent of a clk
+ * @clk: the clk whose parent gets returned
+ *
+ * Simply returns clk->parent.  Returns NULL if clk is NULL.
+ */
+struct clk *clk_get_parent(struct clk *clk)
+{
+       struct clk *parent;
+
+       mutex_lock(&prepare_lock);
+       parent = __clk_get_parent(clk);
+       mutex_unlock(&prepare_lock);
+
+       return parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+/*
+ * .get_parent is mandatory for clocks with multiple possible parents.  It is
+ * optional for single-parent clocks.  Always call .get_parent if it is
+ * available and WARN if it is missing for multi-parent clocks.
+ *
+ * For single-parent clocks without .get_parent, first check to see if the
+ * .parents array exists, and if so use it to avoid an expensive tree
+ * traversal.  If .parents does not exist then walk the tree with __clk_lookup.
+ */
+static struct clk *__clk_init_parent(struct clk *clk)
+{
+       struct clk *ret = NULL;
+       u8 index;
+
+       /* handle the trivial cases */
+
+       if (!clk->num_parents)
+               goto out;
+
+       if (clk->num_parents == 1) {
+               if (IS_ERR_OR_NULL(clk->parent))
+                       ret = clk->parent = __clk_lookup(clk->parent_names[0]);
+               ret = clk->parent;
+               goto out;
+       }
+
+       if (!clk->ops->get_parent) {
+               WARN(!clk->ops->get_parent,
+                       "%s: multi-parent clocks must implement .get_parent\n",
+                       __func__);
+               goto out;
+       };
+
+       /*
+        * Do our best to cache parent clocks in clk->parents.  This prevents
+        * unnecessary and expensive calls to __clk_lookup.  We don't set
+        * clk->parent here; that is done by the calling function
+        */
+
+       index = clk->ops->get_parent(clk->hw);
+
+       if (!clk->parents)
+               clk->parents =
+                       kmalloc((sizeof(struct clk*) * clk->num_parents),
+                                       GFP_KERNEL);
+
+       if (!clk->parents)
+               ret = __clk_lookup(clk->parent_names[index]);
+       else if (!clk->parents[index])
+               ret = clk->parents[index] =
+                       __clk_lookup(clk->parent_names[index]);
+       else
+               ret = clk->parents[index];
+
+out:
+       return ret;
+}
+
+void __clk_reparent(struct clk *clk, struct clk *new_parent)
+{
+#ifdef CONFIG_COMMON_CLK_DEBUG
+       struct dentry *d;
+       struct dentry *new_parent_d;
+#endif
+
+       if (!clk || !new_parent)
+               return;
+
+       hlist_del(&clk->child_node);
+
+       if (new_parent)
+               hlist_add_head(&clk->child_node, &new_parent->children);
+       else
+               hlist_add_head(&clk->child_node, &clk_orphan_list);
+
+#ifdef CONFIG_COMMON_CLK_DEBUG
+       if (!inited)
+               goto out;
+
+       if (new_parent)
+               new_parent_d = new_parent->dentry;
+       else
+               new_parent_d = orphandir;
+
+       d = debugfs_rename(clk->dentry->d_parent, clk->dentry,
+                       new_parent_d, clk->name);
+       if (d)
+               clk->dentry = d;
+       else
+               pr_debug("%s: failed to rename debugfs entry for %s\n",
+                               __func__, clk->name);
+out:
+#endif
+
+       clk->parent = new_parent;
+
+       __clk_recalc_rates(clk, POST_RATE_CHANGE);
+}
+
+static int __clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       struct clk *old_parent;
+       unsigned long flags;
+       int ret = -EINVAL;
+       u8 i;
+
+       old_parent = clk->parent;
+
+       /* find index of new parent clock using cached parent ptrs */
+       for (i = 0; i < clk->num_parents; i++)
+               if (clk->parents[i] == parent)
+                       break;
+
+       /*
+        * find index of new parent clock using string name comparison
+        * also try to cache the parent to avoid future calls to __clk_lookup
+        */
+       if (i == clk->num_parents)
+               for (i = 0; i < clk->num_parents; i++)
+                       if (!strcmp(clk->parent_names[i], parent->name)) {
+                               clk->parents[i] = __clk_lookup(parent->name);
+                               break;
+                       }
+
+       if (i == clk->num_parents) {
+               pr_debug("%s: clock %s is not a possible parent of clock %s\n",
+                               __func__, parent->name, clk->name);
+               goto out;
+       }
+
+       /* migrate prepare and enable */
+       if (clk->prepare_count)
+               __clk_prepare(parent);
+
+       /* FIXME replace with clk_is_enabled(clk) someday */
+       spin_lock_irqsave(&enable_lock, flags);
+       if (clk->enable_count)
+               __clk_enable(parent);
+       spin_unlock_irqrestore(&enable_lock, flags);
+
+       /* change clock input source */
+       ret = clk->ops->set_parent(clk->hw, i);
+
+       /* clean up old prepare and enable */
+       spin_lock_irqsave(&enable_lock, flags);
+       if (clk->enable_count)
+               __clk_disable(old_parent);
+       spin_unlock_irqrestore(&enable_lock, flags);
+
+       if (clk->prepare_count)
+               __clk_unprepare(old_parent);
+
+out:
+       return ret;
+}
+
+/**
+ * clk_set_parent - switch the parent of a mux clk
+ * @clk: the mux clk whose input we are switching
+ * @parent: the new input to clk
+ *
+ * Re-parent clk to use parent as it's new input source.  If clk has the
+ * CLK_SET_PARENT_GATE flag set then clk must be gated for this
+ * operation to succeed.  After successfully changing clk's parent
+ * clk_set_parent will update the clk topology, sysfs topology and
+ * propagate rate recalculation via __clk_recalc_rates.  Returns 0 on
+ * success, -EERROR otherwise.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       int ret = 0;
+
+       if (!clk || !clk->ops)
+               return -EINVAL;
+
+       if (!clk->ops->set_parent)
+               return -ENOSYS;
+
+       /* prevent racing with updates to the clock topology */
+       mutex_lock(&prepare_lock);
+
+       if (clk->parent == parent)
+               goto out;
+
+       /* propagate PRE_RATE_CHANGE notifications */
+       if (clk->notifier_count)
+               ret = __clk_speculate_rates(clk, parent->rate);
+
+       /* abort if a driver objects */
+       if (ret == NOTIFY_STOP)
+               goto out;
+
+       /* only re-parent if the clock is not in use */
+       if ((clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count)
+               ret = -EBUSY;
+       else
+               ret = __clk_set_parent(clk, parent);
+
+       /* propagate ABORT_RATE_CHANGE if .set_parent failed */
+       if (ret) {
+               __clk_recalc_rates(clk, ABORT_RATE_CHANGE);
+               goto out;
+       }
+
+       /* propagate rate recalculation downstream */
+       __clk_reparent(clk, parent);
+
+out:
+       mutex_unlock(&prepare_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+/**
+ * __clk_init - initialize the data structures in a struct clk
+ * @dev:       device initializing this clk, placeholder for now
+ * @clk:       clk being initialized
+ *
+ * Initializes the lists in struct clk, queries the hardware for the
+ * parent and rate and sets them both.
+ *
+ * Any struct clk passed into __clk_init must have the following members
+ * populated:
+ *     .name
+ *     .ops
+ *     .hw
+ *     .parent_names
+ *     .num_parents
+ *     .flags
+ *
+ * Essentially, everything that would normally be passed into clk_register is
+ * assumed to be initialized already in __clk_init.  The other members may be
+ * populated, but are optional.
+ *
+ * __clk_init is only exposed via clk-private.h and is intended for use with
+ * very large numbers of clocks that need to be statically initialized.  It is
+ * a layering violation to include clk-private.h from any code which implements
+ * a clock's .ops; as such any statically initialized clock data MUST be in a
+ * separate C file from the logic that implements it's operations.
+ */
+void __clk_init(struct device *dev, struct clk *clk)
+{
+       int i;
+       struct clk *orphan;
+       struct hlist_node *tmp, *tmp2;
+
+       if (!clk)
+               return;
+
+       mutex_lock(&prepare_lock);
+
+       /* check to see if a clock with this name is already registered */
+       if (__clk_lookup(clk->name))
+               goto out;
+
+       /* throw a WARN if any entries in parent_names are NULL */
+       for (i = 0; i < clk->num_parents; i++)
+               WARN(!clk->parent_names[i],
+                               "%s: invalid NULL in %s's .parent_names\n",
+                               __func__, clk->name);
+
+       /*
+        * Allocate an array of struct clk *'s to avoid unnecessary string
+        * look-ups of clk's possible parents.  This can fail for clocks passed
+        * in to clk_init during early boot; thus any access to clk->parents[]
+        * must always check for a NULL pointer and try to populate it if
+        * necessary.
+        *
+        * If clk->parents is not NULL we skip this entire block.  This allows
+        * for clock drivers to statically initialize clk->parents.
+        */
+       if (clk->num_parents && !clk->parents) {
+               clk->parents = kmalloc((sizeof(struct clk*) * clk->num_parents),
+                               GFP_KERNEL);
+               /*
+                * __clk_lookup returns NULL for parents that have not been
+                * clk_init'd; thus any access to clk->parents[] must check
+                * for a NULL pointer.  We can always perform lazy lookups for
+                * missing parents later on.
+                */
+               if (clk->parents)
+                       for (i = 0; i < clk->num_parents; i++)
+                               clk->parents[i] =
+                                       __clk_lookup(clk->parent_names[i]);
+       }
+
+       clk->parent = __clk_init_parent(clk);
+
+       /*
+        * Populate clk->parent if parent has already been __clk_init'd.  If
+        * parent has not yet been __clk_init'd then place clk in the orphan
+        * list.  If clk has set the CLK_IS_ROOT flag then place it in the root
+        * clk list.
+        *
+        * Every time a new clk is clk_init'd then we walk the list of orphan
+        * clocks and re-parent any that are children of the clock currently
+        * being clk_init'd.
+        */
+       if (clk->parent)
+               hlist_add_head(&clk->child_node,
+                               &clk->parent->children);
+       else if (clk->flags & CLK_IS_ROOT)
+               hlist_add_head(&clk->child_node, &clk_root_list);
+       else
+               hlist_add_head(&clk->child_node, &clk_orphan_list);
+
+       /*
+        * Set clk's rate.  The preferred method is to use .recalc_rate.  For
+        * simple clocks and lazy developers the default fallback is to use the
+        * parent's rate.  If a clock doesn't have a parent (or is orphaned)
+        * then rate is set to zero.
+        */
+       if (clk->ops->recalc_rate)
+               clk->rate = clk->ops->recalc_rate(clk->hw,
+                               __clk_get_rate(clk->parent));
+       else if (clk->parent)
+               clk->rate = clk->parent->rate;
+       else
+               clk->rate = 0;
+
+       /*
+        * walk the list of orphan clocks and reparent any that are children of
+        * this clock
+        */
+       hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node)
+               for (i = 0; i < orphan->num_parents; i++)
+                       if (!strcmp(clk->name, orphan->parent_names[i])) {
+                               __clk_reparent(orphan, clk);
+                               break;
+                       }
+
+       /*
+        * optional platform-specific magic
+        *
+        * The .init callback is not used by any of the basic clock types, but
+        * exists for weird hardware that must perform initialization magic.
+        * Please consider other ways of solving initialization problems before
+        * using this callback, as it's use is discouraged.
+        */
+       if (clk->ops->init)
+               clk->ops->init(clk->hw);
+
+       clk_debug_register(clk);
+
+out:
+       mutex_unlock(&prepare_lock);
+
+       return;
+}
+
+/**
+ * clk_register - allocate a new clock, register it and return an opaque cookie
+ * @dev: device that is registering this clock
+ * @name: clock name
+ * @ops: operations this clock supports
+ * @hw: link to hardware-specific clock data
+ * @parent_names: array of string names for all possible parents
+ * @num_parents: number of possible parents
+ * @flags: framework-level hints and quirks
+ *
+ * clk_register is the primary interface for populating the clock tree with new
+ * clock nodes.  It returns a pointer to the newly allocated struct clk which
+ * cannot be dereferenced by driver code but may be used in conjuction with the
+ * rest of the clock API.
+ */
+struct clk *clk_register(struct device *dev, const char *name,
+               const struct clk_ops *ops, struct clk_hw *hw,
+               char **parent_names, u8 num_parents, unsigned long flags)
+{
+       struct clk *clk;
+
+       clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+       if (!clk)
+               return NULL;
+
+       clk->name = name;
+       clk->ops = ops;
+       clk->hw = hw;
+       clk->flags = flags;
+       clk->parent_names = parent_names;
+       clk->num_parents = num_parents;
+       hw->clk = clk;
+
+       __clk_init(dev, clk);
+
+       return clk;
+}
+EXPORT_SYMBOL_GPL(clk_register);
+
+/***        clk rate change notifiers        ***/
+
+/**
+ * clk_notifier_register - add a clk rate change notifier
+ * @clk: struct clk * to watch
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request notification when clk's rate changes.  This uses an SRCU
+ * notifier because we want it to block and notifier unregistrations are
+ * uncommon.  The callbacks associated with the notifier must not
+ * re-enter into the clk framework by calling any top-level clk APIs;
+ * this will cause a nested prepare_lock mutex.
+ *
+ * Pre-change notifier callbacks will be passed the current, pre-change
+ * rate of the clk via struct clk_notifier_data.old_rate.  The new,
+ * post-change rate of the clk is passed via struct
+ * clk_notifier_data.new_rate.
+ *
+ * Post-change notifiers will pass the now-current, post-change rate of
+ * the clk in both struct clk_notifier_data.old_rate and struct
+ * clk_notifier_data.new_rate.
+ *
+ * Abort-change notifiers are effectively the opposite of pre-change
+ * notifiers: the original pre-change clk rate is passed in via struct
+ * clk_notifier_data.new_rate and the failed post-change rate is passed
+ * in via struct clk_notifier_data.old_rate.
+ *
+ * clk_notifier_register() must be called from non-atomic context.
+ * Returns -EINVAL if called with null arguments, -ENOMEM upon
+ * allocation failure; otherwise, passes along the return value of
+ * srcu_notifier_chain_register().
+ */
+int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
+{
+       struct clk_notifier *cn;
+       int ret = -ENOMEM;
+
+       if (!clk || !nb)
+               return -EINVAL;
+
+       mutex_lock(&prepare_lock);
+
+       /* search the list of notifiers for this clk */
+       list_for_each_entry(cn, &clk_notifier_list, node)
+               if (cn->clk == clk)
+                       break;
+
+       /* if clk wasn't in the notifier list, allocate new clk_notifier */
+       if (cn->clk != clk) {
+               cn = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
+               if (!cn)
+                       goto out;
+
+               cn->clk = clk;
+               srcu_init_notifier_head(&cn->notifier_head);
+
+               list_add(&cn->node, &clk_notifier_list);
+       }
+
+       ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
+
+       clk->notifier_count++;
+
+out:
+       mutex_unlock(&prepare_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_notifier_register);
+
+/**
+ * clk_notifier_unregister - remove a clk rate change notifier
+ * @clk: struct clk *
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request no further notification for changes to 'clk' and frees memory
+ * allocated in clk_notifier_register.
+ *
+ * Returns -EINVAL if called with null arguments; otherwise, passes
+ * along the return value of srcu_notifier_chain_unregister().
+ */
+int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
+{
+       struct clk_notifier *cn = NULL;
+       int ret = -EINVAL;
+
+       if (!clk || !nb)
+               return -EINVAL;
+
+       mutex_lock(&prepare_lock);
+
+       list_for_each_entry(cn, &clk_notifier_list, node)
+               if (cn->clk == clk)
+                       break;
+
+       if (cn->clk == clk) {
+               ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
+
+               clk->notifier_count--;
+
+               /* XXX the notifier code should handle this better */
+               if (!cn->notifier_head.head) {
+                       srcu_cleanup_notifier_head(&cn->notifier_head);
+                       kfree(cn);
+               }
+
+       } else {
+               ret = -ENOENT;
+       }
+
+       mutex_unlock(&prepare_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_notifier_unregister);
index 55d0f95..32cb929 100644 (file)
@@ -19,6 +19,8 @@
  *   - Two channels combine to create a free-running 32 bit counter
  *     with a base rate of 5+ MHz, packaged as a clocksource (with
  *     resolution better than 200 nsec).
+ *   - Some chips support 32 bit counter. A single channel is used for
+ *     this 32 bit free-running counter. the second channel is not used.
  *
  *   - The third channel may be used to provide a 16-bit clockevent
  *     source, used in either periodic or oneshot mode.  This runs
@@ -54,6 +56,11 @@ static cycle_t tc_get_cycles(struct clocksource *cs)
        return (upper << 16) | lower;
 }
 
+static cycle_t tc_get_cycles32(struct clocksource *cs)
+{
+       return __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
+}
+
 static struct clocksource clksrc = {
        .name           = "tcb_clksrc",
        .rating         = 200,
@@ -209,6 +216,48 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
 
 #endif
 
+static void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx)
+{
+       /* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
+       __raw_writel(mck_divisor_idx                    /* likely divide-by-8 */
+                       | ATMEL_TC_WAVE
+                       | ATMEL_TC_WAVESEL_UP           /* free-run */
+                       | ATMEL_TC_ACPA_SET             /* TIOA0 rises at 0 */
+                       | ATMEL_TC_ACPC_CLEAR,          /* (duty cycle 50%) */
+                       tcaddr + ATMEL_TC_REG(0, CMR));
+       __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
+       __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
+       __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));      /* no irqs */
+       __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
+
+       /* channel 1:  waveform mode, input TIOA0 */
+       __raw_writel(ATMEL_TC_XC1                       /* input: TIOA0 */
+                       | ATMEL_TC_WAVE
+                       | ATMEL_TC_WAVESEL_UP,          /* free-run */
+                       tcaddr + ATMEL_TC_REG(1, CMR));
+       __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));      /* no irqs */
+       __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
+
+       /* chain channel 0 to channel 1*/
+       __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
+       /* then reset all the timers */
+       __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+}
+
+static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_idx)
+{
+       /* channel 0:  waveform mode, input mclk/8 */
+       __raw_writel(mck_divisor_idx                    /* likely divide-by-8 */
+                       | ATMEL_TC_WAVE
+                       | ATMEL_TC_WAVESEL_UP,          /* free-run */
+                       tcaddr + ATMEL_TC_REG(0, CMR));
+       __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));      /* no irqs */
+       __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
+
+       /* then reset all the timers */
+       __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+}
+
 static int __init tcb_clksrc_init(void)
 {
        static char bootinfo[] __initdata
@@ -260,34 +309,19 @@ static int __init tcb_clksrc_init(void)
                        divided_rate / 1000000,
                        ((divided_rate + 500000) % 1000000) / 1000);
 
-       /* tclib will give us three clocks no matter what the
-        * underlying platform supports.
-        */
-       clk_enable(tc->clk[1]);
-
-       /* channel 0:  waveform mode, input mclk/8, clock TIOA0 on overflow */
-       __raw_writel(best_divisor_idx                   /* likely divide-by-8 */
-                       | ATMEL_TC_WAVE
-                       | ATMEL_TC_WAVESEL_UP           /* free-run */
-                       | ATMEL_TC_ACPA_SET             /* TIOA0 rises at 0 */
-                       | ATMEL_TC_ACPC_CLEAR,          /* (duty cycle 50%) */
-                       tcaddr + ATMEL_TC_REG(0, CMR));
-       __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
-       __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
-       __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR));      /* no irqs */
-       __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
-
-       /* channel 1:  waveform mode, input TIOA0 */
-       __raw_writel(ATMEL_TC_XC1                       /* input: TIOA0 */
-                       | ATMEL_TC_WAVE
-                       | ATMEL_TC_WAVESEL_UP,          /* free-run */
-                       tcaddr + ATMEL_TC_REG(1, CMR));
-       __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR));      /* no irqs */
-       __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
-
-       /* chain channel 0 to channel 1, then reset all the timers */
-       __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
-       __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+       if (tc->tcb_config && tc->tcb_config->counter_width == 32) {
+               /* use apropriate function to read 32 bit counter */
+               clksrc.read = tc_get_cycles32;
+               /* setup ony channel 0 */
+               tcb_setup_single_chan(tc, best_divisor_idx);
+       } else {
+               /* tclib will give us three clocks no matter what the
+                * underlying platform supports.
+                */
+               clk_enable(tc->clk[1]);
+               /* setup both channel 0 & 1 */
+               tcb_setup_dual_chan(tc, best_divisor_idx);
+       }
 
        /* and away we go! */
        clocksource_register_hz(&clksrc, divided_rate);
index e0664fe..32d790d 100644 (file)
@@ -2,6 +2,33 @@
 # ARM CPU Frequency scaling drivers
 #
 
+config ARM_OMAP2PLUS_CPUFREQ
+       bool "TI OMAP2+"
+       default ARCH_OMAP2PLUS
+       select CPU_FREQ_TABLE
+
+config ARM_S3C2416_CPUFREQ
+       bool "S3C2416 CPU Frequency scaling support"
+       depends on CPU_S3C2416
+       help
+         This adds the CPUFreq driver for the Samsung S3C2416 and
+         S3C2450 SoC. The S3C2416 supports changing the rate of the
+         armdiv clock source and also entering a so called dynamic
+         voltage scaling mode in which it is possible to reduce the
+         core voltage of the cpu.
+
+         If in doubt, say N.
+
+config ARM_S3C2416_CPUFREQ_VCORESCALE
+       bool "Allow voltage scaling for S3C2416 arm core (EXPERIMENTAL)"
+       depends on ARM_S3C2416_CPUFREQ && REGULATOR && EXPERIMENTAL
+       help
+         Enable CPU voltage scaling when entering the dvs mode.
+         It uses information gathered through existing hardware and
+         tests but not documented in any datasheet.
+
+         If in doubt, say N.
+
 config ARM_S3C64XX_CPUFREQ
        bool "Samsung S3C64XX"
        depends on CPU_S3C6410
@@ -25,6 +52,8 @@ config ARM_EXYNOS_CPUFREQ
        bool "SAMSUNG EXYNOS SoCs"
        depends on ARCH_EXYNOS
        select ARM_EXYNOS4210_CPUFREQ if CPU_EXYNOS4210
+       select ARM_EXYNOS4X12_CPUFREQ if (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+       select ARM_EXYNOS5250_CPUFREQ if SOC_EXYNOS5250
        default y
        help
          This adds the CPUFreq driver common part for Samsung
@@ -34,6 +63,19 @@ config ARM_EXYNOS_CPUFREQ
 
 config ARM_EXYNOS4210_CPUFREQ
        bool "Samsung EXYNOS4210"
+       depends on ARCH_EXYNOS
        help
          This adds the CPUFreq driver for Samsung EXYNOS4210
          SoC (S5PV310 or S5PC210).
+
+config ARM_EXYNOS4X12_CPUFREQ
+       bool "Samsung EXYNOS4X12"
+       help
+         This adds the CPUFreq driver for Samsung EXYNOS4X12
+         SoC (EXYNOS4212 or EXYNOS4412).
+
+config ARM_EXYNOS5250_CPUFREQ
+       bool "Samsung EXYNOS5250"
+       help
+         This adds the CPUFreq driver for Samsung EXYNOS5250
+         SoC.
index ac000fa..9531fc2 100644 (file)
@@ -40,11 +40,14 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2)   += cpufreq-nforce2.o
 ##################################################################################
 # ARM SoC drivers
 obj-$(CONFIG_UX500_SOC_DB8500)         += db8500-cpufreq.o
+obj-$(CONFIG_ARM_S3C2416_CPUFREQ)      += s3c2416-cpufreq.o
 obj-$(CONFIG_ARM_S3C64XX_CPUFREQ)      += s3c64xx-cpufreq.o
 obj-$(CONFIG_ARM_S5PV210_CPUFREQ)      += s5pv210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS_CPUFREQ)       += exynos-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)   += exynos4210-cpufreq.o
-obj-$(CONFIG_ARCH_OMAP2PLUS)            += omap-cpufreq.o
+obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)   += exynos4x12-cpufreq.o
+obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)   += exynos5250-cpufreq.o
+obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
index 622013f..7f2f149 100644 (file)
@@ -126,6 +126,15 @@ static int __init init_cpufreq_transition_notifier_list(void)
 }
 pure_initcall(init_cpufreq_transition_notifier_list);
 
+static int off __read_mostly;
+int cpufreq_disabled(void)
+{
+       return off;
+}
+void disable_cpufreq(void)
+{
+       off = 1;
+}
 static LIST_HEAD(cpufreq_governor_list);
 static DEFINE_MUTEX(cpufreq_governor_mutex);
 
@@ -1441,6 +1450,9 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
 {
        int retval = -EINVAL;
 
+       if (cpufreq_disabled())
+               return -ENODEV;
+
        pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
                target_freq, relation);
        if (cpu_online(policy->cpu) && cpufreq_driver->target)
@@ -1549,6 +1561,9 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
        if (!governor)
                return -EINVAL;
 
+       if (cpufreq_disabled())
+               return -ENODEV;
+
        mutex_lock(&cpufreq_governor_mutex);
 
        err = -EBUSY;
@@ -1572,6 +1587,9 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
        if (!governor)
                return;
 
+       if (cpufreq_disabled())
+               return;
+
 #ifdef CONFIG_HOTPLUG_CPU
        for_each_present_cpu(cpu) {
                if (cpu_online(cpu))
@@ -1814,6 +1832,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
        unsigned long flags;
        int ret;
 
+       if (cpufreq_disabled())
+               return -ENODEV;
+
        if (!driver_data || !driver_data->verify || !driver_data->init ||
            ((!driver_data->setpolicy) && (!driver_data->target)))
                return -EINVAL;
@@ -1901,6 +1922,9 @@ static int __init cpufreq_core_init(void)
 {
        int cpu;
 
+       if (cpufreq_disabled())
+               return -ENODEV;
+
        for_each_possible_cpu(cpu) {
                per_cpu(cpufreq_policy_cpu, cpu) = -1;
                init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
index c3e0652..836e9b0 100644 (file)
@@ -257,6 +257,62 @@ show_one(sampling_down_factor, sampling_down_factor);
 show_one(ignore_nice_load, ignore_nice);
 show_one(powersave_bias, powersave_bias);
 
+/**
+ * update_sampling_rate - update sampling rate effective immediately if needed.
+ * @new_rate: new sampling rate
+ *
+ * If new rate is smaller than the old, simply updaing
+ * dbs_tuners_int.sampling_rate might not be appropriate. For example,
+ * if the original sampling_rate was 1 second and the requested new sampling
+ * rate is 10 ms because the user needs immediate reaction from ondemand
+ * governor, but not sure if higher frequency will be required or not,
+ * then, the governor may change the sampling rate too late; up to 1 second
+ * later. Thus, if we are reducing the sampling rate, we need to make the
+ * new value effective immediately.
+ */
+static void update_sampling_rate(unsigned int new_rate)
+{
+       int cpu;
+
+       dbs_tuners_ins.sampling_rate = new_rate
+                                    = max(new_rate, min_sampling_rate);
+
+       for_each_online_cpu(cpu) {
+               struct cpufreq_policy *policy;
+               struct cpu_dbs_info_s *dbs_info;
+               unsigned long next_sampling, appointed_at;
+
+               policy = cpufreq_cpu_get(cpu);
+               if (!policy)
+                       continue;
+               dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu);
+               cpufreq_cpu_put(policy);
+
+               mutex_lock(&dbs_info->timer_mutex);
+
+               if (!delayed_work_pending(&dbs_info->work)) {
+                       mutex_unlock(&dbs_info->timer_mutex);
+                       continue;
+               }
+
+               next_sampling  = jiffies + usecs_to_jiffies(new_rate);
+               appointed_at = dbs_info->work.timer.expires;
+
+
+               if (time_before(next_sampling, appointed_at)) {
+
+                       mutex_unlock(&dbs_info->timer_mutex);
+                       cancel_delayed_work_sync(&dbs_info->work);
+                       mutex_lock(&dbs_info->timer_mutex);
+
+                       schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work,
+                                                usecs_to_jiffies(new_rate));
+
+               }
+               mutex_unlock(&dbs_info->timer_mutex);
+       }
+}
+
 static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
                                   const char *buf, size_t count)
 {
@@ -265,7 +321,7 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
        ret = sscanf(buf, "%u", &input);
        if (ret != 1)
                return -EINVAL;
-       dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate);
+       update_sampling_rate(input);
        return count;
 }
 
index f500201..a22ffa5 100644 (file)
@@ -22,11 +22,11 @@ static struct cpufreq_frequency_table freq_table[] = {
        },
        [1] = {
                .index = 1,
-               .frequency = 300000,
+               .frequency = 400000,
        },
        [2] = {
                .index = 2,
-               .frequency = 600000,
+               .frequency = 800000,
        },
        [3] = {
                /* Used for MAX_OPP, if available */
@@ -113,12 +113,9 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
 
        BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
 
-       if (!prcmu_is_u8400()) {
-               freq_table[1].frequency = 400000;
-               freq_table[2].frequency = 800000;
-               if (prcmu_has_arm_maxopp())
-                       freq_table[3].frequency = 1000000;
-       }
+       if (prcmu_has_arm_maxopp())
+               freq_table[3].frequency = 1000000;
+
        pr_info("db8500-cpufreq : Available frequencies:\n");
        for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
                pr_info("  %d Mhz\n", freq_table[i].frequency/1000);
index 5467879..b243a7e 100644 (file)
@@ -210,6 +210,8 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu);
 
+       locking_frequency = exynos_getspeed(0);
+
        /* set the transition latency value */
        policy->cpuinfo.transition_latency = 100000;
 
@@ -252,6 +254,10 @@ static int __init exynos_cpufreq_init(void)
 
        if (soc_is_exynos4210())
                ret = exynos4210_cpufreq_init(exynos_info);
+       else if (soc_is_exynos4212() || soc_is_exynos4412())
+               ret = exynos4x12_cpufreq_init(exynos_info);
+       else if (soc_is_exynos5250())
+               ret = exynos5250_cpufreq_init(exynos_info);
        else
                pr_err("%s: CPU type not found\n", __func__);
 
index 065da5b..fb148fa 100644 (file)
@@ -121,25 +121,25 @@ static void exynos4210_set_clkdiv(unsigned int div_index)
 
        tmp = exynos4210_clkdiv_table[div_index].clkdiv;
 
-       __raw_writel(tmp, S5P_CLKDIV_CPU);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STATCPU);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU);
        } while (tmp & 0x1111111);
 
        /* Change Divider - CPU1 */
 
-       tmp = __raw_readl(S5P_CLKDIV_CPU1);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_CPU1);
 
        tmp &= ~((0x7 << 4) | 0x7);
 
        tmp |= ((clkdiv_cpu1[div_index][0] << 4) |
                (clkdiv_cpu1[div_index][1] << 0));
 
-       __raw_writel(tmp, S5P_CLKDIV_CPU1);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STATCPU1);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STATCPU1);
        } while (tmp & 0x11);
 }
 
@@ -151,32 +151,32 @@ static void exynos4210_set_apll(unsigned int index)
        clk_set_parent(moutcore, mout_mpll);
 
        do {
-               tmp = (__raw_readl(S5P_CLKMUX_STATCPU)
-                       >> S5P_CLKSRC_CPU_MUXCORE_SHIFT);
+               tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
+                       >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
                tmp &= 0x7;
        } while (tmp != 0x2);
 
        /* 2. Set APLL Lock time */
-       __raw_writel(S5P_APLL_LOCKTIME, S5P_APLL_LOCK);
+       __raw_writel(EXYNOS4_APLL_LOCKTIME, EXYNOS4_APLL_LOCK);
 
        /* 3. Change PLL PMS values */
-       tmp = __raw_readl(S5P_APLL_CON0);
+       tmp = __raw_readl(EXYNOS4_APLL_CON0);
        tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
        tmp |= exynos4210_apll_pms_table[index];
-       __raw_writel(tmp, S5P_APLL_CON0);
+       __raw_writel(tmp, EXYNOS4_APLL_CON0);
 
        /* 4. wait_lock_time */
        do {
-               tmp = __raw_readl(S5P_APLL_CON0);
-       } while (!(tmp & (0x1 << S5P_APLLCON0_LOCKED_SHIFT)));
+               tmp = __raw_readl(EXYNOS4_APLL_CON0);
+       } while (!(tmp & (0x1 << EXYNOS4_APLLCON0_LOCKED_SHIFT)));
 
        /* 5. MUX_CORE_SEL = APLL */
        clk_set_parent(moutcore, mout_apll);
 
        do {
-               tmp = __raw_readl(S5P_CLKMUX_STATCPU);
-               tmp &= S5P_CLKMUX_STATCPU_MUXCORE_MASK;
-       } while (tmp != (0x1 << S5P_CLKSRC_CPU_MUXCORE_SHIFT));
+               tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
+               tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
+       } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
 }
 
 bool exynos4210_pms_change(unsigned int old_index, unsigned int new_index)
@@ -198,10 +198,10 @@ static void exynos4210_set_frequency(unsigned int old_index,
                        exynos4210_set_clkdiv(new_index);
 
                        /* 2. Change just s value in apll m,p,s value */
-                       tmp = __raw_readl(S5P_APLL_CON0);
+                       tmp = __raw_readl(EXYNOS4_APLL_CON0);
                        tmp &= ~(0x7 << 0);
                        tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
-                       __raw_writel(tmp, S5P_APLL_CON0);
+                       __raw_writel(tmp, EXYNOS4_APLL_CON0);
                } else {
                        /* Clock Configuration Procedure */
                        /* 1. Change the system clock divider values */
@@ -212,10 +212,10 @@ static void exynos4210_set_frequency(unsigned int old_index,
        } else if (old_index < new_index) {
                if (!exynos4210_pms_change(old_index, new_index)) {
                        /* 1. Change just s value in apll m,p,s value */
-                       tmp = __raw_readl(S5P_APLL_CON0);
+                       tmp = __raw_readl(EXYNOS4_APLL_CON0);
                        tmp &= ~(0x7 << 0);
                        tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
-                       __raw_writel(tmp, S5P_APLL_CON0);
+                       __raw_writel(tmp, EXYNOS4_APLL_CON0);
 
                        /* 2. Change the system clock divider values */
                        exynos4210_set_clkdiv(new_index);
@@ -253,24 +253,24 @@ int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
        if (IS_ERR(mout_apll))
                goto err_mout_apll;
 
-       tmp = __raw_readl(S5P_CLKDIV_CPU);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_CPU);
 
        for (i = L0; i <  CPUFREQ_LEVEL_END; i++) {
-               tmp &= ~(S5P_CLKDIV_CPU0_CORE_MASK |
-                       S5P_CLKDIV_CPU0_COREM0_MASK |
-                       S5P_CLKDIV_CPU0_COREM1_MASK |
-                       S5P_CLKDIV_CPU0_PERIPH_MASK |
-                       S5P_CLKDIV_CPU0_ATB_MASK |
-                       S5P_CLKDIV_CPU0_PCLKDBG_MASK |
-                       S5P_CLKDIV_CPU0_APLL_MASK);
-
-               tmp |= ((clkdiv_cpu0[i][0] << S5P_CLKDIV_CPU0_CORE_SHIFT) |
-                       (clkdiv_cpu0[i][1] << S5P_CLKDIV_CPU0_COREM0_SHIFT) |
-                       (clkdiv_cpu0[i][2] << S5P_CLKDIV_CPU0_COREM1_SHIFT) |
-                       (clkdiv_cpu0[i][3] << S5P_CLKDIV_CPU0_PERIPH_SHIFT) |
-                       (clkdiv_cpu0[i][4] << S5P_CLKDIV_CPU0_ATB_SHIFT) |
-                       (clkdiv_cpu0[i][5] << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) |
-                       (clkdiv_cpu0[i][6] << S5P_CLKDIV_CPU0_APLL_SHIFT));
+               tmp &= ~(EXYNOS4_CLKDIV_CPU0_CORE_MASK |
+                       EXYNOS4_CLKDIV_CPU0_COREM0_MASK |
+                       EXYNOS4_CLKDIV_CPU0_COREM1_MASK |
+                       EXYNOS4_CLKDIV_CPU0_PERIPH_MASK |
+                       EXYNOS4_CLKDIV_CPU0_ATB_MASK |
+                       EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK |
+                       EXYNOS4_CLKDIV_CPU0_APLL_MASK);
+
+               tmp |= ((clkdiv_cpu0[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
+                       (clkdiv_cpu0[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
+                       (clkdiv_cpu0[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
+                       (clkdiv_cpu0[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
+                       (clkdiv_cpu0[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
+                       (clkdiv_cpu0[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
+                       (clkdiv_cpu0[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT));
 
                exynos4210_clkdiv_table[i].clkdiv = tmp;
        }
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
new file mode 100644 (file)
index 0000000..8c5a7af
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * EXYNOS4X12 - CPU frequency scaling support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+
+#include <mach/regs-clock.h>
+#include <mach/cpufreq.h>
+
+#define CPUFREQ_LEVEL_END      (L13 + 1)
+
+static int max_support_idx;
+static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
+
+static struct clk *cpu_clk;
+static struct clk *moutcore;
+static struct clk *mout_mpll;
+static struct clk *mout_apll;
+
+struct cpufreq_clkdiv {
+       unsigned int    index;
+       unsigned int    clkdiv;
+       unsigned int    clkdiv1;
+};
+
+static unsigned int exynos4x12_volt_table[CPUFREQ_LEVEL_END];
+
+static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
+       {L0, 1500 * 1000},
+       {L1, 1400 * 1000},
+       {L2, 1300 * 1000},
+       {L3, 1200 * 1000},
+       {L4, 1100 * 1000},
+       {L5, 1000 * 1000},
+       {L6,  900 * 1000},
+       {L7,  800 * 1000},
+       {L8,  700 * 1000},
+       {L9,  600 * 1000},
+       {L10, 500 * 1000},
+       {L11, 400 * 1000},
+       {L12, 300 * 1000},
+       {L13, 200 * 1000},
+       {0, CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_clkdiv exynos4x12_clkdiv_table[CPUFREQ_LEVEL_END];
+
+static unsigned int clkdiv_cpu0_4212[CPUFREQ_LEVEL_END][8] = {
+       /*
+        * Clock divider value for following
+        * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
+        *              DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
+        */
+       /* ARM L0: 1500 MHz */
+       { 0, 3, 7, 0, 6, 1, 2, 0 },
+
+       /* ARM L1: 1400 MHz */
+       { 0, 3, 7, 0, 6, 1, 2, 0 },
+
+       /* ARM L2: 1300 MHz */
+       { 0, 3, 7, 0, 5, 1, 2, 0 },
+
+       /* ARM L3: 1200 MHz */
+       { 0, 3, 7, 0, 5, 1, 2, 0 },
+
+       /* ARM L4: 1100 MHz */
+       { 0, 3, 6, 0, 4, 1, 2, 0 },
+
+       /* ARM L5: 1000 MHz */
+       { 0, 2, 5, 0, 4, 1, 1, 0 },
+
+       /* ARM L6: 900 MHz */
+       { 0, 2, 5, 0, 3, 1, 1, 0 },
+
+       /* ARM L7: 800 MHz */
+       { 0, 2, 5, 0, 3, 1, 1, 0 },
+
+       /* ARM L8: 700 MHz */
+       { 0, 2, 4, 0, 3, 1, 1, 0 },
+
+       /* ARM L9: 600 MHz */
+       { 0, 2, 4, 0, 3, 1, 1, 0 },
+
+       /* ARM L10: 500 MHz */
+       { 0, 2, 4, 0, 3, 1, 1, 0 },
+
+       /* ARM L11: 400 MHz */
+       { 0, 2, 4, 0, 3, 1, 1, 0 },
+
+       /* ARM L12: 300 MHz */
+       { 0, 2, 4, 0, 2, 1, 1, 0 },
+
+       /* ARM L13: 200 MHz */
+       { 0, 1, 3, 0, 1, 1, 1, 0 },
+};
+
+static unsigned int clkdiv_cpu0_4412[CPUFREQ_LEVEL_END][8] = {
+       /*
+        * Clock divider value for following
+        * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
+        *              DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
+        */
+       /* ARM L0: 1500 MHz */
+       { 0, 3, 7, 0, 6, 1, 2, 0 },
+
+       /* ARM L1: 1400 MHz */
+       { 0, 3, 7, 0, 6, 1, 2, 0 },
+
+       /* ARM L2: 1300 MHz */
+       { 0, 3, 7, 0, 5, 1, 2, 0 },
+
+       /* ARM L3: 1200 MHz */
+       { 0, 3, 7, 0, 5, 1, 2, 0 },
+
+       /* ARM L4: 1100 MHz */
+       { 0, 3, 6, 0, 4, 1, 2, 0 },
+
+       /* ARM L5: 1000 MHz */
+       { 0, 2, 5, 0, 4, 1, 1, 0 },
+
+       /* ARM L6: 900 MHz */
+       { 0, 2, 5, 0, 3, 1, 1, 0 },
+
+       /* ARM L7: 800 MHz */
+       { 0, 2, 5, 0, 3, 1, 1, 0 },
+
+       /* ARM L8: 700 MHz */
+       { 0, 2, 4, 0, 3, 1, 1, 0 },
+
+       /* ARM L9: 600 MHz */
+       { 0, 2, 4, 0, 3, 1, 1, 0 },
+
+       /* ARM L10: 500 MHz */
+       { 0, 2, 4, 0, 3, 1, 1, 0 },
+
+       /* ARM L11: 400 MHz */
+       { 0, 2, 4, 0, 3, 1, 1, 0 },
+
+       /* ARM L12: 300 MHz */
+       { 0, 2, 4, 0, 2, 1, 1, 0 },
+
+       /* ARM L13: 200 MHz */
+       { 0, 1, 3, 0, 1, 1, 1, 0 },
+};
+
+static unsigned int clkdiv_cpu1_4212[CPUFREQ_LEVEL_END][2] = {
+       /* Clock divider value for following
+        * { DIVCOPY, DIVHPM }
+        */
+       /* ARM L0: 1500 MHz */
+       { 6, 0 },
+
+       /* ARM L1: 1400 MHz */
+       { 6, 0 },
+
+       /* ARM L2: 1300 MHz */
+       { 5, 0 },
+
+       /* ARM L3: 1200 MHz */
+       { 5, 0 },
+
+       /* ARM L4: 1100 MHz */
+       { 4, 0 },
+
+       /* ARM L5: 1000 MHz */
+       { 4, 0 },
+
+       /* ARM L6: 900 MHz */
+       { 3, 0 },
+
+       /* ARM L7: 800 MHz */
+       { 3, 0 },
+
+       /* ARM L8: 700 MHz */
+       { 3, 0 },
+
+       /* ARM L9: 600 MHz */
+       { 3, 0 },
+
+       /* ARM L10: 500 MHz */
+       { 3, 0 },
+
+       /* ARM L11: 400 MHz */
+       { 3, 0 },
+
+       /* ARM L12: 300 MHz */
+       { 3, 0 },
+
+       /* ARM L13: 200 MHz */
+       { 3, 0 },
+};
+
+static unsigned int clkdiv_cpu1_4412[CPUFREQ_LEVEL_END][3] = {
+       /* Clock divider value for following
+        * { DIVCOPY, DIVHPM, DIVCORES }
+        */
+       /* ARM L0: 1500 MHz */
+       { 6, 0, 7 },
+
+       /* ARM L1: 1400 MHz */
+       { 6, 0, 6 },
+
+       /* ARM L2: 1300 MHz */
+       { 5, 0, 6 },
+
+       /* ARM L3: 1200 MHz */
+       { 5, 0, 5 },
+
+       /* ARM L4: 1100 MHz */
+       { 4, 0, 5 },
+
+       /* ARM L5: 1000 MHz */
+       { 4, 0, 4 },
+
+       /* ARM L6: 900 MHz */
+       { 3, 0, 4 },
+
+       /* ARM L7: 800 MHz */
+       { 3, 0, 3 },
+
+       /* ARM L8: 700 MHz */
+       { 3, 0, 3 },
+
+       /* ARM L9: 600 MHz */
+       { 3, 0, 2 },
+
+       /* ARM L10: 500 MHz */
+       { 3, 0, 2 },
+
+       /* ARM L11: 400 MHz */
+       { 3, 0, 1 },
+
+       /* ARM L12: 300 MHz */
+       { 3, 0, 1 },
+
+       /* ARM L13: 200 MHz */
+       { 3, 0, 0 },
+};
+
+static unsigned int exynos4x12_apll_pms_table[CPUFREQ_LEVEL_END] = {
+       /* APLL FOUT L0: 1500 MHz */
+       ((250 << 16) | (4 << 8) | (0x0)),
+
+       /* APLL FOUT L1: 1400 MHz */
+       ((175 << 16) | (3 << 8) | (0x0)),
+
+       /* APLL FOUT L2: 1300 MHz */
+       ((325 << 16) | (6 << 8) | (0x0)),
+
+       /* APLL FOUT L3: 1200 MHz */
+       ((200 << 16) | (4 << 8) | (0x0)),
+
+       /* APLL FOUT L4: 1100 MHz */
+       ((275 << 16) | (6 << 8) | (0x0)),
+
+       /* APLL FOUT L5: 1000 MHz */
+       ((125 << 16) | (3 << 8) | (0x0)),
+
+       /* APLL FOUT L6: 900 MHz */
+       ((150 << 16) | (4 << 8) | (0x0)),
+
+       /* APLL FOUT L7: 800 MHz */
+       ((100 << 16) | (3 << 8) | (0x0)),
+
+       /* APLL FOUT L8: 700 MHz */
+       ((175 << 16) | (3 << 8) | (0x1)),
+
+       /* APLL FOUT L9: 600 MHz */
+       ((200 << 16) | (4 << 8) | (0x1)),
+
+       /* APLL FOUT L10: 500 MHz */
+       ((125 << 16) | (3 << 8) | (0x1)),
+
+       /* APLL FOUT L11 400 MHz */
+       ((100 << 16) | (3 << 8) | (0x1)),
+
+       /* APLL FOUT L12: 300 MHz */
+       ((200 << 16) | (4 << 8) | (0x2)),
+
+       /* APLL FOUT L13: 200 MHz */
+       ((100 << 16) | (3 << 8) | (0x2)),
+};
+
+static const unsigned int asv_voltage_4x12[CPUFREQ_LEVEL_END] = {
+       1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
+       1000000,  987500,  975000,  950000,  925000,  900000,  900000
+};
+
+static void exynos4x12_set_clkdiv(unsigned int div_index)
+{
+       unsigned int tmp;
+       unsigned int stat_cpu1;
+
+       /* Change Divider - CPU0 */
+
+       tmp = exynos4x12_clkdiv_table[div_index].clkdiv;
+
+       __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
+
+       while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
+               cpu_relax();
+
+       /* Change Divider - CPU1 */
+       tmp = exynos4x12_clkdiv_table[div_index].clkdiv1;
+
+       __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
+       if (soc_is_exynos4212())
+               stat_cpu1 = 0x11;
+       else
+               stat_cpu1 = 0x111;
+
+       while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
+               cpu_relax();
+}
+
+static void exynos4x12_set_apll(unsigned int index)
+{
+       unsigned int tmp, pdiv;
+
+       /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
+       clk_set_parent(moutcore, mout_mpll);
+
+       do {
+               cpu_relax();
+               tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
+                       >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
+               tmp &= 0x7;
+       } while (tmp != 0x2);
+
+       /* 2. Set APLL Lock time */
+       pdiv = ((exynos4x12_apll_pms_table[index] >> 8) & 0x3f);
+
+       __raw_writel((pdiv * 250), EXYNOS4_APLL_LOCK);
+
+       /* 3. Change PLL PMS values */
+       tmp = __raw_readl(EXYNOS4_APLL_CON0);
+       tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
+       tmp |= exynos4x12_apll_pms_table[index];
+       __raw_writel(tmp, EXYNOS4_APLL_CON0);
+
+       /* 4. wait_lock_time */
+       do {
+               cpu_relax();
+               tmp = __raw_readl(EXYNOS4_APLL_CON0);
+       } while (!(tmp & (0x1 << EXYNOS4_APLLCON0_LOCKED_SHIFT)));
+
+       /* 5. MUX_CORE_SEL = APLL */
+       clk_set_parent(moutcore, mout_apll);
+
+       do {
+               cpu_relax();
+               tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
+               tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
+       } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
+}
+
+bool exynos4x12_pms_change(unsigned int old_index, unsigned int new_index)
+{
+       unsigned int old_pm = exynos4x12_apll_pms_table[old_index] >> 8;
+       unsigned int new_pm = exynos4x12_apll_pms_table[new_index] >> 8;
+
+       return (old_pm == new_pm) ? 0 : 1;
+}
+
+static void exynos4x12_set_frequency(unsigned int old_index,
+                                 unsigned int new_index)
+{
+       unsigned int tmp;
+
+       if (old_index > new_index) {
+               if (!exynos4x12_pms_change(old_index, new_index)) {
+                       /* 1. Change the system clock divider values */
+                       exynos4x12_set_clkdiv(new_index);
+                       /* 2. Change just s value in apll m,p,s value */
+                       tmp = __raw_readl(EXYNOS4_APLL_CON0);
+                       tmp &= ~(0x7 << 0);
+                       tmp |= (exynos4x12_apll_pms_table[new_index] & 0x7);
+                       __raw_writel(tmp, EXYNOS4_APLL_CON0);
+
+               } else {
+                       /* Clock Configuration Procedure */
+                       /* 1. Change the system clock divider values */
+                       exynos4x12_set_clkdiv(new_index);
+                       /* 2. Change the apll m,p,s value */
+                       exynos4x12_set_apll(new_index);
+               }
+       } else if (old_index < new_index) {
+               if (!exynos4x12_pms_change(old_index, new_index)) {
+                       /* 1. Change just s value in apll m,p,s value */
+                       tmp = __raw_readl(EXYNOS4_APLL_CON0);
+                       tmp &= ~(0x7 << 0);
+                       tmp |= (exynos4x12_apll_pms_table[new_index] & 0x7);
+                       __raw_writel(tmp, EXYNOS4_APLL_CON0);
+                       /* 2. Change the system clock divider values */
+                       exynos4x12_set_clkdiv(new_index);
+               } else {
+                       /* Clock Configuration Procedure */
+                       /* 1. Change the apll m,p,s value */
+                       exynos4x12_set_apll(new_index);
+                       /* 2. Change the system clock divider values */
+                       exynos4x12_set_clkdiv(new_index);
+               }
+       }
+}
+
+static void __init set_volt_table(void)
+{
+       unsigned int i;
+
+       max_support_idx = L1;
+
+       /* Not supported */
+       exynos4x12_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
+
+       for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
+               exynos4x12_volt_table[i] = asv_voltage_4x12[i];
+}
+
+int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
+{
+       int i;
+       unsigned int tmp;
+       unsigned long rate;
+
+       set_volt_table();
+
+       cpu_clk = clk_get(NULL, "armclk");
+       if (IS_ERR(cpu_clk))
+               return PTR_ERR(cpu_clk);
+
+       moutcore = clk_get(NULL, "moutcore");
+       if (IS_ERR(moutcore))
+               goto err_moutcore;
+
+       mout_mpll = clk_get(NULL, "mout_mpll");
+       if (IS_ERR(mout_mpll))
+               goto err_mout_mpll;
+
+       rate = clk_get_rate(mout_mpll) / 1000;
+
+       mout_apll = clk_get(NULL, "mout_apll");
+       if (IS_ERR(mout_apll))
+               goto err_mout_apll;
+
+       for (i = L0; i <  CPUFREQ_LEVEL_END; i++) {
+
+               exynos4x12_clkdiv_table[i].index = i;
+
+               tmp = __raw_readl(EXYNOS4_CLKDIV_CPU);
+
+               tmp &= ~(EXYNOS4_CLKDIV_CPU0_CORE_MASK |
+                       EXYNOS4_CLKDIV_CPU0_COREM0_MASK |
+                       EXYNOS4_CLKDIV_CPU0_COREM1_MASK |
+                       EXYNOS4_CLKDIV_CPU0_PERIPH_MASK |
+                       EXYNOS4_CLKDIV_CPU0_ATB_MASK |
+                       EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK |
+                       EXYNOS4_CLKDIV_CPU0_APLL_MASK);
+
+               if (soc_is_exynos4212()) {
+                       tmp |= ((clkdiv_cpu0_4212[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
+                               (clkdiv_cpu0_4212[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
+                               (clkdiv_cpu0_4212[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
+                               (clkdiv_cpu0_4212[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
+                               (clkdiv_cpu0_4212[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
+                               (clkdiv_cpu0_4212[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
+                               (clkdiv_cpu0_4212[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT));
+               } else {
+                       tmp &= ~EXYNOS4_CLKDIV_CPU0_CORE2_MASK;
+
+                       tmp |= ((clkdiv_cpu0_4412[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
+                               (clkdiv_cpu0_4412[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
+                               (clkdiv_cpu0_4412[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
+                               (clkdiv_cpu0_4412[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
+                               (clkdiv_cpu0_4412[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
+                               (clkdiv_cpu0_4412[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
+                               (clkdiv_cpu0_4412[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT) |
+                               (clkdiv_cpu0_4412[i][7] << EXYNOS4_CLKDIV_CPU0_CORE2_SHIFT));
+               }
+
+               exynos4x12_clkdiv_table[i].clkdiv = tmp;
+
+               tmp = __raw_readl(EXYNOS4_CLKDIV_CPU1);
+
+               if (soc_is_exynos4212()) {
+                       tmp &= ~(EXYNOS4_CLKDIV_CPU1_COPY_MASK |
+                               EXYNOS4_CLKDIV_CPU1_HPM_MASK);
+                       tmp |= ((clkdiv_cpu1_4212[i][0] << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT) |
+                               (clkdiv_cpu1_4212[i][1] << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT));
+               } else {
+                       tmp &= ~(EXYNOS4_CLKDIV_CPU1_COPY_MASK |
+                               EXYNOS4_CLKDIV_CPU1_HPM_MASK |
+                               EXYNOS4_CLKDIV_CPU1_CORES_MASK);
+                       tmp |= ((clkdiv_cpu1_4412[i][0] << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT) |
+                               (clkdiv_cpu1_4412[i][1] << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT) |
+                               (clkdiv_cpu1_4412[i][2] << EXYNOS4_CLKDIV_CPU1_CORES_SHIFT));
+               }
+               exynos4x12_clkdiv_table[i].clkdiv1 = tmp;
+       }
+
+       info->mpll_freq_khz = rate;
+       info->pm_lock_idx = L5;
+       info->pll_safe_idx = L7;
+       info->max_support_idx = max_support_idx;
+       info->min_support_idx = min_support_idx;
+       info->cpu_clk = cpu_clk;
+       info->volt_table = exynos4x12_volt_table;
+       info->freq_table = exynos4x12_freq_table;
+       info->set_freq = exynos4x12_set_frequency;
+       info->need_apll_change = exynos4x12_pms_change;
+
+       return 0;
+
+err_mout_apll:
+       clk_put(mout_mpll);
+err_mout_mpll:
+       clk_put(moutcore);
+err_moutcore:
+       clk_put(cpu_clk);
+
+       pr_debug("%s: failed initialization\n", __func__);
+       return -EINVAL;
+}
+EXPORT_SYMBOL(exynos4x12_cpufreq_init);
diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c
new file mode 100644 (file)
index 0000000..a883316
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * EXYNOS5250 - CPU frequency scaling support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/cpufreq.h>
+
+#define CPUFREQ_LEVEL_END      (L15 + 1)
+
+static int max_support_idx;
+static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
+static struct clk *cpu_clk;
+static struct clk *moutcore;
+static struct clk *mout_mpll;
+static struct clk *mout_apll;
+
+struct cpufreq_clkdiv {
+       unsigned int    index;
+       unsigned int    clkdiv;
+       unsigned int    clkdiv1;
+};
+
+static unsigned int exynos5250_volt_table[CPUFREQ_LEVEL_END];
+
+static struct cpufreq_frequency_table exynos5250_freq_table[] = {
+       {L0, 1700 * 1000},
+       {L1, 1600 * 1000},
+       {L2, 1500 * 1000},
+       {L3, 1400 * 1000},
+       {L4, 1300 * 1000},
+       {L5, 1200 * 1000},
+       {L6, 1100 * 1000},
+       {L7, 1000 * 1000},
+       {L8, 900 * 1000},
+       {L9, 800 * 1000},
+       {L10, 700 * 1000},
+       {L11, 600 * 1000},
+       {L12, 500 * 1000},
+       {L13, 400 * 1000},
+       {L14, 300 * 1000},
+       {L15, 200 * 1000},
+       {0, CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_clkdiv exynos5250_clkdiv_table[CPUFREQ_LEVEL_END];
+
+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, 1, 7, 7, 3, 1, 1, 0 },     /* 700 MHz */
+       { 0, 1, 7, 7, 2, 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, 1, 1, 1, 0 },     /* 300 MHz */
+       { 0, 1, 7, 7, 1, 1, 1, 0 },     /* 200 MHz */
+};
+
+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 },       /* 1400 MHz */
+       { 0, 2 },       /* 1300 MHz */
+       { 0, 2 },       /* 1200 MHz */
+       { 0, 2 },       /* 1100 MHz */
+       { 0, 2 },       /* 1000 MHz */
+       { 0, 2 },       /* 900 MHz */
+       { 0, 2 },       /* 800 MHz */
+       { 0, 2 },       /* 700 MHz */
+       { 0, 2 },       /* 600 MHz */
+       { 0, 2 },       /* 500 MHz */
+       { 0, 2 },       /* 400 MHz */
+       { 0, 2 },       /* 300 MHz */
+       { 0, 2 },       /* 200 MHz */
+};
+
+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 */
+       ((325 << 16) | (6 << 8) | 0),   /* 1300 MHz */
+       ((200 << 16) | (4 << 8) | 0),   /* 1200 MHz */
+       ((275 << 16) | (6 << 8) | 0),   /* 1100 MHz */
+       ((125 << 16) | (3 << 8) | 0),   /* 1000 MHz */
+       ((150 << 16) | (4 << 8) | 0),   /* 900 MHz */
+       ((100 << 16) | (3 << 8) | 0),   /* 800 MHz */
+       ((175 << 16) | (3 << 8) | 1),   /* 700 MHz */
+       ((200 << 16) | (4 << 8) | 1),   /* 600 MHz */
+       ((125 << 16) | (3 << 8) | 1),   /* 500 MHz */
+       ((100 << 16) | (3 << 8) | 1),   /* 400 MHz */
+       ((200 << 16) | (4 << 8) | 2),   /* 300 MHz */
+       ((100 << 16) | (3 << 8) | 2),   /* 200 MHz */
+};
+
+/* 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
+};
+
+static void set_clkdiv(unsigned int div_index)
+{
+       unsigned int tmp;
+
+       /* Change Divider - CPU0 */
+
+       tmp = exynos5250_clkdiv_table[div_index].clkdiv;
+
+       __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
+
+       while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
+               cpu_relax();
+
+       /* Change Divider - CPU1 */
+       tmp = exynos5250_clkdiv_table[div_index].clkdiv1;
+
+       __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
+
+       while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
+               cpu_relax();
+}
+
+static void set_apll(unsigned int new_index,
+                            unsigned int old_index)
+{
+       unsigned int tmp, pdiv;
+
+       /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
+       clk_set_parent(moutcore, mout_mpll);
+
+       do {
+               cpu_relax();
+               tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
+               tmp &= 0x7;
+       } while (tmp != 0x2);
+
+       /* 2. Set APLL Lock time */
+       pdiv = ((exynos5_apll_pms_table[new_index] >> 8) & 0x3f);
+
+       __raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
+
+       /* 3. Change PLL PMS values */
+       tmp = __raw_readl(EXYNOS5_APLL_CON0);
+       tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
+       tmp |= exynos5_apll_pms_table[new_index];
+       __raw_writel(tmp, EXYNOS5_APLL_CON0);
+
+       /* 4. wait_lock_time */
+       do {
+               cpu_relax();
+               tmp = __raw_readl(EXYNOS5_APLL_CON0);
+       } while (!(tmp & (0x1 << 29)));
+
+       /* 5. MUX_CORE_SEL = APLL */
+       clk_set_parent(moutcore, mout_apll);
+
+       do {
+               cpu_relax();
+               tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
+               tmp &= (0x7 << 16);
+       } while (tmp != (0x1 << 16));
+
+}
+
+bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
+{
+       unsigned int old_pm = (exynos5_apll_pms_table[old_index] >> 8);
+       unsigned int new_pm = (exynos5_apll_pms_table[new_index] >> 8);
+
+       return (old_pm == new_pm) ? 0 : 1;
+}
+
+static void exynos5250_set_frequency(unsigned int old_index,
+                                 unsigned int new_index)
+{
+       unsigned int tmp;
+
+       if (old_index > new_index) {
+               if (!exynos5250_pms_change(old_index, new_index)) {
+                       /* 1. Change the system clock divider values */
+                       set_clkdiv(new_index);
+                       /* 2. Change just s value in apll m,p,s value */
+                       tmp = __raw_readl(EXYNOS5_APLL_CON0);
+                       tmp &= ~(0x7 << 0);
+                       tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
+                       __raw_writel(tmp, EXYNOS5_APLL_CON0);
+
+               } else {
+                       /* Clock Configuration Procedure */
+                       /* 1. Change the system clock divider values */
+                       set_clkdiv(new_index);
+                       /* 2. Change the apll m,p,s value */
+                       set_apll(new_index, old_index);
+               }
+       } else if (old_index < new_index) {
+               if (!exynos5250_pms_change(old_index, new_index)) {
+                       /* 1. Change just s value in apll m,p,s value */
+                       tmp = __raw_readl(EXYNOS5_APLL_CON0);
+                       tmp &= ~(0x7 << 0);
+                       tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
+                       __raw_writel(tmp, EXYNOS5_APLL_CON0);
+                       /* 2. Change the system clock divider values */
+                       set_clkdiv(new_index);
+               } else {
+                       /* Clock Configuration Procedure */
+                       /* 1. Change the apll m,p,s value */
+                       set_apll(new_index, old_index);
+                       /* 2. Change the system clock divider values */
+                       set_clkdiv(new_index);
+               }
+       }
+}
+
+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;
+
+       for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
+               exynos5250_volt_table[i] = asv_voltage_5250[i];
+}
+
+int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
+{
+       int i;
+       unsigned int tmp;
+       unsigned long rate;
+
+       set_volt_table();
+
+       cpu_clk = clk_get(NULL, "armclk");
+       if (IS_ERR(cpu_clk))
+               return PTR_ERR(cpu_clk);
+
+       moutcore = clk_get(NULL, "mout_cpu");
+       if (IS_ERR(moutcore))
+               goto err_moutcore;
+
+       mout_mpll = clk_get(NULL, "mout_mpll");
+       if (IS_ERR(mout_mpll))
+               goto err_mout_mpll;
+
+       rate = clk_get_rate(mout_mpll) / 1000;
+
+       mout_apll = clk_get(NULL, "mout_apll");
+       if (IS_ERR(mout_apll))
+               goto err_mout_apll;
+
+       for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
+
+               exynos5250_clkdiv_table[i].index = i;
+
+               tmp = __raw_readl(EXYNOS5_CLKDIV_CPU0);
+
+               tmp &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) |
+                       (0x7 << 12) | (0x7 << 16) | (0x7 << 20) |
+                       (0x7 << 24) | (0x7 << 28));
+
+               tmp |= ((clkdiv_cpu0_5250[i][0] << 0) |
+                       (clkdiv_cpu0_5250[i][1] << 4) |
+                       (clkdiv_cpu0_5250[i][2] << 8) |
+                       (clkdiv_cpu0_5250[i][3] << 12) |
+                       (clkdiv_cpu0_5250[i][4] << 16) |
+                       (clkdiv_cpu0_5250[i][5] << 20) |
+                       (clkdiv_cpu0_5250[i][6] << 24) |
+                       (clkdiv_cpu0_5250[i][7] << 28));
+
+               exynos5250_clkdiv_table[i].clkdiv = tmp;
+
+               tmp = __raw_readl(EXYNOS5_CLKDIV_CPU1);
+
+               tmp &= ~((0x7 << 0) | (0x7 << 4));
+
+               tmp |= ((clkdiv_cpu1_5250[i][0] << 0) |
+                       (clkdiv_cpu1_5250[i][1] << 4));
+
+               exynos5250_clkdiv_table[i].clkdiv1 = tmp;
+       }
+
+       info->mpll_freq_khz = rate;
+       /* 1000Mhz */
+       info->pm_lock_idx = L7;
+       /* 800Mhz */
+       info->pll_safe_idx = L9;
+       info->max_support_idx = max_support_idx;
+       info->min_support_idx = min_support_idx;
+       info->cpu_clk = cpu_clk;
+       info->volt_table = exynos5250_volt_table;
+       info->freq_table = exynos5250_freq_table;
+       info->set_freq = exynos5250_set_frequency;
+       info->need_apll_change = exynos5250_pms_change;
+
+       return 0;
+
+err_mout_apll:
+       clk_put(mout_mpll);
+err_mout_mpll:
+       clk_put(moutcore);
+err_moutcore:
+       clk_put(cpu_clk);
+
+       pr_err("%s: failed initialization\n", __func__);
+       return -EINVAL;
+}
+EXPORT_SYMBOL(exynos5250_cpufreq_init);
index 3093ca6..17fa04d 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/opp.h>
 #include <linux/cpu.h>
 #include <linux/module.h>
+#include <linux/regulator/consumer.h>
 
 #include <asm/smp_plat.h>
 #include <asm/cpu.h>
@@ -36,6 +37,9 @@
 
 #include <mach/hardware.h>
 
+/* OPP tolerance in percentage */
+#define        OPP_TOLERANCE   4
+
 #ifdef CONFIG_SMP
 struct lpj_info {
        unsigned long   ref;
@@ -51,6 +55,7 @@ static atomic_t freq_table_users = ATOMIC_INIT(0);
 static struct clk *mpu_clk;
 static char *mpu_clk_name;
 static struct device *mpu_dev;
+static struct regulator *mpu_reg;
 
 static int omap_verify_speed(struct cpufreq_policy *policy)
 {
@@ -75,8 +80,10 @@ static int omap_target(struct cpufreq_policy *policy,
                       unsigned int relation)
 {
        unsigned int i;
-       int ret = 0;
+       int r, ret = 0;
        struct cpufreq_freqs freqs;
+       struct opp *opp;
+       unsigned long freq, volt = 0, volt_old = 0, tol = 0;
 
        if (!freq_table) {
                dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
@@ -110,13 +117,50 @@ static int omap_target(struct cpufreq_policy *policy,
                cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
        }
 
-#ifdef CONFIG_CPU_FREQ_DEBUG
-       pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new);
-#endif
+       freq = freqs.new * 1000;
+
+       if (mpu_reg) {
+               opp = opp_find_freq_ceil(mpu_dev, &freq);
+               if (IS_ERR(opp)) {
+                       dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
+                               __func__, freqs.new);
+                       return -EINVAL;
+               }
+               volt = opp_get_voltage(opp);
+               tol = volt * OPP_TOLERANCE / 100;
+               volt_old = regulator_get_voltage(mpu_reg);
+       }
+
+       dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", 
+               freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
+               freqs.new / 1000, volt ? volt / 1000 : -1);
+
+       /* scaling up?  scale voltage before frequency */
+       if (mpu_reg && (freqs.new > freqs.old)) {
+               r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
+               if (r < 0) {
+                       dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
+                                __func__);
+                       freqs.new = freqs.old;
+                       goto done;
+               }
+       }
 
        ret = clk_set_rate(mpu_clk, freqs.new * 1000);
-       freqs.new = omap_getspeed(policy->cpu);
 
+       /* scaling down?  scale voltage after frequency */
+       if (mpu_reg && (freqs.new < freqs.old)) {
+               r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
+               if (r < 0) {
+                       dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
+                                __func__);
+                       ret = clk_set_rate(mpu_clk, freqs.old * 1000);
+                       freqs.new = freqs.old;
+                       goto done;
+               }
+       }
+
+       freqs.new = omap_getspeed(policy->cpu);
 #ifdef CONFIG_SMP
        /*
         * Note that loops_per_jiffy is not updated on SMP systems in
@@ -143,6 +187,7 @@ static int omap_target(struct cpufreq_policy *policy,
                                        freqs.new);
 #endif
 
+done:
        /* notifiers */
        for_each_cpu(i, policy->cpus) {
                freqs.cpu = i;
@@ -259,6 +304,23 @@ static int __init omap_cpufreq_init(void)
                return -EINVAL;
        }
 
+       mpu_reg = regulator_get(mpu_dev, "vcc");
+       if (IS_ERR(mpu_reg)) {
+               pr_warning("%s: unable to get MPU regulator\n", __func__);
+               mpu_reg = NULL;
+       } else {
+               /* 
+                * Ensure physical regulator is present.
+                * (e.g. could be dummy regulator.)
+                */
+               if (regulator_get_voltage(mpu_reg) < 0) {
+                       pr_warn("%s: physical regulator not present for MPU\n",
+                               __func__);
+                       regulator_put(mpu_reg);
+                       mpu_reg = NULL;
+               }
+       }
+
        return cpufreq_register_driver(&omap_driver);
 }
 
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c
new file mode 100644 (file)
index 0000000..50d2f15
--- /dev/null
@@ -0,0 +1,542 @@
+/*
+ * S3C2416/2450 CPUfreq Support
+ *
+ * Copyright 2011 Heiko Stuebner <heiko@sntech.de>
+ *
+ * based on s3c64xx_cpufreq.c
+ *
+ * Copyright 2009 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+
+static DEFINE_MUTEX(cpufreq_lock);
+
+struct s3c2416_data {
+       struct clk *armdiv;
+       struct clk *armclk;
+       struct clk *hclk;
+
+       unsigned long regulator_latency;
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+       struct regulator *vddarm;
+#endif
+
+       struct cpufreq_frequency_table *freq_table;
+
+       bool is_dvs;
+       bool disable_dvs;
+};
+
+static struct s3c2416_data s3c2416_cpufreq;
+
+struct s3c2416_dvfs {
+       unsigned int vddarm_min;
+       unsigned int vddarm_max;
+};
+
+/* pseudo-frequency for dvs mode */
+#define FREQ_DVS       132333
+
+/* frequency to sleep and reboot in
+ * it's essential to leave dvs, as some boards do not reconfigure the
+ * regulator on reboot
+ */
+#define FREQ_SLEEP     133333
+
+/* Sources for the ARMCLK */
+#define SOURCE_HCLK    0
+#define SOURCE_ARMDIV  1
+
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+/* S3C2416 only supports changing the voltage in the dvs-mode.
+ * Voltages down to 1.0V seem to work, so we take what the regulator
+ * can get us.
+ */
+static struct s3c2416_dvfs s3c2416_dvfs_table[] = {
+       [SOURCE_HCLK] = {  950000, 1250000 },
+       [SOURCE_ARMDIV] = { 1250000, 1350000 },
+};
+#endif
+
+static struct cpufreq_frequency_table s3c2416_freq_table[] = {
+       { SOURCE_HCLK, FREQ_DVS },
+       { SOURCE_ARMDIV, 133333 },
+       { SOURCE_ARMDIV, 266666 },
+       { SOURCE_ARMDIV, 400000 },
+       { 0, CPUFREQ_TABLE_END },
+};
+
+static struct cpufreq_frequency_table s3c2450_freq_table[] = {
+       { SOURCE_HCLK, FREQ_DVS },
+       { SOURCE_ARMDIV, 133500 },
+       { SOURCE_ARMDIV, 267000 },
+       { SOURCE_ARMDIV, 534000 },
+       { 0, CPUFREQ_TABLE_END },
+};
+
+static int s3c2416_cpufreq_verify_speed(struct cpufreq_policy *policy)
+{
+       struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
+
+       if (policy->cpu != 0)
+               return -EINVAL;
+
+       return cpufreq_frequency_table_verify(policy, s3c_freq->freq_table);
+}
+
+static unsigned int s3c2416_cpufreq_get_speed(unsigned int cpu)
+{
+       struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
+
+       if (cpu != 0)
+               return 0;
+
+       /* return our pseudo-frequency when in dvs mode */
+       if (s3c_freq->is_dvs)
+               return FREQ_DVS;
+
+       return clk_get_rate(s3c_freq->armclk) / 1000;
+}
+
+static int s3c2416_cpufreq_set_armdiv(struct s3c2416_data *s3c_freq,
+                                     unsigned int freq)
+{
+       int ret;
+
+       if (clk_get_rate(s3c_freq->armdiv) / 1000 != freq) {
+               ret = clk_set_rate(s3c_freq->armdiv, freq * 1000);
+               if (ret < 0) {
+                       pr_err("cpufreq: Failed to set armdiv rate %dkHz: %d\n",
+                              freq, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int s3c2416_cpufreq_enter_dvs(struct s3c2416_data *s3c_freq, int idx)
+{
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+       struct s3c2416_dvfs *dvfs;
+#endif
+       int ret;
+
+       if (s3c_freq->is_dvs) {
+               pr_debug("cpufreq: already in dvs mode, nothing to do\n");
+               return 0;
+       }
+
+       pr_debug("cpufreq: switching armclk to hclk (%lukHz)\n",
+                clk_get_rate(s3c_freq->hclk) / 1000);
+       ret = clk_set_parent(s3c_freq->armclk, s3c_freq->hclk);
+       if (ret < 0) {
+               pr_err("cpufreq: Failed to switch armclk to hclk: %d\n", ret);
+               return ret;
+       }
+
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+       /* changing the core voltage is only allowed when in dvs mode */
+       if (s3c_freq->vddarm) {
+               dvfs = &s3c2416_dvfs_table[idx];
+
+               pr_debug("cpufreq: setting regultor to %d-%d\n",
+                        dvfs->vddarm_min, dvfs->vddarm_max);
+               ret = regulator_set_voltage(s3c_freq->vddarm,
+                                           dvfs->vddarm_min,
+                                           dvfs->vddarm_max);
+
+               /* when lowering the voltage failed, there is nothing to do */
+               if (ret != 0)
+                       pr_err("cpufreq: Failed to set VDDARM: %d\n", ret);
+       }
+#endif
+
+       s3c_freq->is_dvs = 1;
+
+       return 0;
+}
+
+static int s3c2416_cpufreq_leave_dvs(struct s3c2416_data *s3c_freq, int idx)
+{
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+       struct s3c2416_dvfs *dvfs;
+#endif
+       int ret;
+
+       if (!s3c_freq->is_dvs) {
+               pr_debug("cpufreq: not in dvs mode, so can't leave\n");
+               return 0;
+       }
+
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+       if (s3c_freq->vddarm) {
+               dvfs = &s3c2416_dvfs_table[idx];
+
+               pr_debug("cpufreq: setting regultor to %d-%d\n",
+                        dvfs->vddarm_min, dvfs->vddarm_max);
+               ret = regulator_set_voltage(s3c_freq->vddarm,
+                                           dvfs->vddarm_min,
+                                           dvfs->vddarm_max);
+               if (ret != 0) {
+                       pr_err("cpufreq: Failed to set VDDARM: %d\n", ret);
+                       return ret;
+               }
+       }
+#endif
+
+       /* force armdiv to hclk frequency for transition from dvs*/
+       if (clk_get_rate(s3c_freq->armdiv) > clk_get_rate(s3c_freq->hclk)) {
+               pr_debug("cpufreq: force armdiv to hclk frequency (%lukHz)\n",
+                        clk_get_rate(s3c_freq->hclk) / 1000);
+               ret = s3c2416_cpufreq_set_armdiv(s3c_freq,
+                                       clk_get_rate(s3c_freq->hclk) / 1000);
+               if (ret < 0) {
+                       pr_err("cpufreq: Failed to to set the armdiv to %lukHz: %d\n",
+                              clk_get_rate(s3c_freq->hclk) / 1000, ret);
+                       return ret;
+               }
+       }
+
+       pr_debug("cpufreq: switching armclk parent to armdiv (%lukHz)\n",
+                       clk_get_rate(s3c_freq->armdiv) / 1000);
+
+       ret = clk_set_parent(s3c_freq->armclk, s3c_freq->armdiv);
+       if (ret < 0) {
+               pr_err("cpufreq: Failed to switch armclk clock parent to armdiv: %d\n",
+                      ret);
+               return ret;
+       }
+
+       s3c_freq->is_dvs = 0;
+
+       return 0;
+}
+
+static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
+                                     unsigned int target_freq,
+                                     unsigned int relation)
+{
+       struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
+       struct cpufreq_freqs freqs;
+       int idx, ret, to_dvs = 0;
+       unsigned int i;
+
+       mutex_lock(&cpufreq_lock);
+
+       pr_debug("cpufreq: to %dKHz, relation %d\n", target_freq, relation);
+
+       ret = cpufreq_frequency_table_target(policy, s3c_freq->freq_table,
+                                            target_freq, relation, &i);
+       if (ret != 0)
+               goto out;
+
+       idx = s3c_freq->freq_table[i].index;
+
+       if (idx == SOURCE_HCLK)
+               to_dvs = 1;
+
+       /* switching to dvs when it's not allowed */
+       if (to_dvs && s3c_freq->disable_dvs) {
+               pr_debug("cpufreq: entering dvs mode not allowed\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       freqs.cpu = 0;
+       freqs.flags = 0;
+       freqs.old = s3c_freq->is_dvs ? FREQ_DVS
+                                    : clk_get_rate(s3c_freq->armclk) / 1000;
+
+       /* When leavin dvs mode, always switch the armdiv to the hclk rate
+        * The S3C2416 has stability issues when switching directly to
+        * higher frequencies.
+        */
+       freqs.new = (s3c_freq->is_dvs && !to_dvs)
+                               ? clk_get_rate(s3c_freq->hclk) / 1000
+                               : s3c_freq->freq_table[i].frequency;
+
+       pr_debug("cpufreq: Transition %d-%dkHz\n", freqs.old, freqs.new);
+
+       if (!to_dvs && freqs.old == freqs.new)
+               goto out;
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+       if (to_dvs) {
+               pr_debug("cpufreq: enter dvs\n");
+               ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx);
+       } else if (s3c_freq->is_dvs) {
+               pr_debug("cpufreq: leave dvs\n");
+               ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx);
+       } else {
+               pr_debug("cpufreq: change armdiv to %dkHz\n", freqs.new);
+               ret = s3c2416_cpufreq_set_armdiv(s3c_freq, freqs.new);
+       }
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+out:
+       mutex_unlock(&cpufreq_lock);
+
+       return ret;
+}
+
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
+{
+       int count, v, i, found;
+       struct cpufreq_frequency_table *freq;
+       struct s3c2416_dvfs *dvfs;
+
+       count = regulator_count_voltages(s3c_freq->vddarm);
+       if (count < 0) {
+               pr_err("cpufreq: Unable to check supported voltages\n");
+               return;
+       }
+
+       freq = s3c_freq->freq_table;
+       while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
+               if (freq->frequency == CPUFREQ_ENTRY_INVALID)
+                       continue;
+
+               dvfs = &s3c2416_dvfs_table[freq->index];
+               found = 0;
+
+               /* Check only the min-voltage, more is always ok on S3C2416 */
+               for (i = 0; i < count; i++) {
+                       v = regulator_list_voltage(s3c_freq->vddarm, i);
+                       if (v >= dvfs->vddarm_min)
+                               found = 1;
+               }
+
+               if (!found) {
+                       pr_debug("cpufreq: %dkHz unsupported by regulator\n",
+                                freq->frequency);
+                       freq->frequency = CPUFREQ_ENTRY_INVALID;
+               }
+
+               freq++;
+       }
+
+       /* Guessed */
+       s3c_freq->regulator_latency = 1 * 1000 * 1000;
+}
+#endif
+
+static int s3c2416_cpufreq_reboot_notifier_evt(struct notifier_block *this,
+                                              unsigned long event, void *ptr)
+{
+       struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
+       int ret;
+
+       mutex_lock(&cpufreq_lock);
+
+       /* disable further changes */
+       s3c_freq->disable_dvs = 1;
+
+       mutex_unlock(&cpufreq_lock);
+
+       /* some boards don't reconfigure the regulator on reboot, which
+        * could lead to undervolting the cpu when the clock is reset.
+        * Therefore we always leave the DVS mode on reboot.
+        */
+       if (s3c_freq->is_dvs) {
+               pr_debug("cpufreq: leave dvs on reboot\n");
+               ret = cpufreq_driver_target(cpufreq_cpu_get(0), FREQ_SLEEP, 0);
+               if (ret < 0)
+                       return NOTIFY_BAD;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block s3c2416_cpufreq_reboot_notifier = {
+       .notifier_call = s3c2416_cpufreq_reboot_notifier_evt,
+};
+
+static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+       struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
+       struct cpufreq_frequency_table *freq;
+       struct clk *msysclk;
+       unsigned long rate;
+       int ret;
+
+       if (policy->cpu != 0)
+               return -EINVAL;
+
+       msysclk = clk_get(NULL, "msysclk");
+       if (IS_ERR(msysclk)) {
+               ret = PTR_ERR(msysclk);
+               pr_err("cpufreq: Unable to obtain msysclk: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * S3C2416 and S3C2450 share the same processor-ID and also provide no
+        * other means to distinguish them other than through the rate of
+        * msysclk. On S3C2416 msysclk runs at 800MHz and on S3C2450 at 533MHz.
+        */
+       rate = clk_get_rate(msysclk);
+       if (rate == 800 * 1000 * 1000) {
+               pr_info("cpufreq: msysclk running at %lukHz, using S3C2416 frequency table\n",
+                       rate / 1000);
+               s3c_freq->freq_table = s3c2416_freq_table;
+               policy->cpuinfo.max_freq = 400000;
+       } else if (rate / 1000 == 534000) {
+               pr_info("cpufreq: msysclk running at %lukHz, using S3C2450 frequency table\n",
+                       rate / 1000);
+               s3c_freq->freq_table = s3c2450_freq_table;
+               policy->cpuinfo.max_freq = 534000;
+       }
+
+       /* not needed anymore */
+       clk_put(msysclk);
+
+       if (s3c_freq->freq_table == NULL) {
+               pr_err("cpufreq: No frequency information for this CPU, msysclk at %lukHz\n",
+                      rate / 1000);
+               return -ENODEV;
+       }
+
+       s3c_freq->is_dvs = 0;
+
+       s3c_freq->armdiv = clk_get(NULL, "armdiv");
+       if (IS_ERR(s3c_freq->armdiv)) {
+               ret = PTR_ERR(s3c_freq->armdiv);
+               pr_err("cpufreq: Unable to obtain ARMDIV: %d\n", ret);
+               return ret;
+       }
+
+       s3c_freq->hclk = clk_get(NULL, "hclk");
+       if (IS_ERR(s3c_freq->hclk)) {
+               ret = PTR_ERR(s3c_freq->hclk);
+               pr_err("cpufreq: Unable to obtain HCLK: %d\n", ret);
+               goto err_hclk;
+       }
+
+       /* chech hclk rate, we only support the common 133MHz for now
+        * hclk could also run at 66MHz, but this not often used
+        */
+       rate = clk_get_rate(s3c_freq->hclk);
+       if (rate < 133 * 1000 * 1000) {
+               pr_err("cpufreq: HCLK not at 133MHz\n");
+               clk_put(s3c_freq->hclk);
+               ret = -EINVAL;
+               goto err_armclk;
+       }
+
+       s3c_freq->armclk = clk_get(NULL, "armclk");
+       if (IS_ERR(s3c_freq->armclk)) {
+               ret = PTR_ERR(s3c_freq->armclk);
+               pr_err("cpufreq: Unable to obtain ARMCLK: %d\n", ret);
+               goto err_armclk;
+       }
+
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+       s3c_freq->vddarm = regulator_get(NULL, "vddarm");
+       if (IS_ERR(s3c_freq->vddarm)) {
+               ret = PTR_ERR(s3c_freq->vddarm);
+               pr_err("cpufreq: Failed to obtain VDDARM: %d\n", ret);
+               goto err_vddarm;
+       }
+
+       s3c2416_cpufreq_cfg_regulator(s3c_freq);
+#else
+       s3c_freq->regulator_latency = 0;
+#endif
+
+       freq = s3c_freq->freq_table;
+       while (freq->frequency != CPUFREQ_TABLE_END) {
+               /* special handling for dvs mode */
+               if (freq->index == 0) {
+                       if (!s3c_freq->hclk) {
+                               pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
+                                        freq->frequency);
+                               freq->frequency = CPUFREQ_ENTRY_INVALID;
+                       } else {
+                               freq++;
+                               continue;
+                       }
+               }
+
+               /* Check for frequencies we can generate */
+               rate = clk_round_rate(s3c_freq->armdiv,
+                                     freq->frequency * 1000);
+               rate /= 1000;
+               if (rate != freq->frequency) {
+                       pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
+                                freq->frequency, rate);
+                       freq->frequency = CPUFREQ_ENTRY_INVALID;
+               }
+
+               freq++;
+       }
+
+       policy->cur = clk_get_rate(s3c_freq->armclk) / 1000;
+
+       /* Datasheet says PLL stabalisation time must be at least 300us,
+        * so but add some fudge. (reference in LOCKCON0 register description)
+        */
+       policy->cpuinfo.transition_latency = (500 * 1000) +
+                                            s3c_freq->regulator_latency;
+
+       ret = cpufreq_frequency_table_cpuinfo(policy, s3c_freq->freq_table);
+       if (ret)
+               goto err_freq_table;
+
+       cpufreq_frequency_table_get_attr(s3c_freq->freq_table, 0);
+
+       register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier);
+
+       return 0;
+
+err_freq_table:
+#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
+       regulator_put(s3c_freq->vddarm);
+err_vddarm:
+#endif
+       clk_put(s3c_freq->armclk);
+err_armclk:
+       clk_put(s3c_freq->hclk);
+err_hclk:
+       clk_put(s3c_freq->armdiv);
+
+       return ret;
+}
+
+static struct freq_attr *s3c2416_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+static struct cpufreq_driver s3c2416_cpufreq_driver = {
+       .owner          = THIS_MODULE,
+       .flags          = 0,
+       .verify         = s3c2416_cpufreq_verify_speed,
+       .target         = s3c2416_cpufreq_set_target,
+       .get            = s3c2416_cpufreq_get_speed,
+       .init           = s3c2416_cpufreq_driver_init,
+       .name           = "s3c2416",
+       .attr           = s3c2416_cpufreq_attr,
+};
+
+static int __init s3c2416_cpufreq_init(void)
+{
+       return cpufreq_register_driver(&s3c2416_cpufreq_driver);
+}
+module_init(s3c2416_cpufreq_init);
index a5e72cb..6f9490b 100644 (file)
@@ -217,13 +217,6 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
        } else {
                s3c64xx_cpufreq_config_regulator();
        }
-
-       vddint = regulator_get(NULL, "vddint");
-       if (IS_ERR(vddint)) {
-               ret = PTR_ERR(vddint);
-               pr_err("Failed to obtain VDDINT: %d\n", ret);
-               vddint = NULL;
-       }
 #endif
 
        freq = s3c64xx_freq_table;
index 1a361e9..88ddc77 100644 (file)
@@ -311,51 +311,51 @@ static int exynos4210_set_busclk(struct busfreq_data *data, struct opp *opp)
        /* Change Divider - DMC0 */
        tmp = data->dmc_divtable[index];
 
-       __raw_writel(tmp, S5P_CLKDIV_DMC0);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_DMC0);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC0);
        } while (tmp & 0x11111111);
 
        /* Change Divider - TOP */
        tmp = data->top_divtable[index];
 
-       __raw_writel(tmp, S5P_CLKDIV_TOP);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_TOP);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_TOP);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_TOP);
        } while (tmp & 0x11111);
 
        /* Change Divider - LEFTBUS */
-       tmp = __raw_readl(S5P_CLKDIV_LEFTBUS);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_LEFTBUS);
 
-       tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
+       tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
 
        tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
-                               S5P_CLKDIV_BUS_GDLR_SHIFT) |
+                               EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
                (exynos4210_clkdiv_lr_bus[index][1] <<
-                               S5P_CLKDIV_BUS_GPLR_SHIFT));
+                               EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
 
-       __raw_writel(tmp, S5P_CLKDIV_LEFTBUS);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_LEFTBUS);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_LEFTBUS);
        } while (tmp & 0x11);
 
        /* Change Divider - RIGHTBUS */
-       tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_RIGHTBUS);
 
-       tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
+       tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
 
        tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
-                               S5P_CLKDIV_BUS_GDLR_SHIFT) |
+                               EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
                (exynos4210_clkdiv_lr_bus[index][1] <<
-                               S5P_CLKDIV_BUS_GPLR_SHIFT));
+                               EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
 
-       __raw_writel(tmp, S5P_CLKDIV_RIGHTBUS);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_RIGHTBUS);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_RIGHTBUS);
        } while (tmp & 0x11);
 
        return 0;
@@ -376,137 +376,137 @@ static int exynos4x12_set_busclk(struct busfreq_data *data, struct opp *opp)
        /* Change Divider - DMC0 */
        tmp = data->dmc_divtable[index];
 
-       __raw_writel(tmp, S5P_CLKDIV_DMC0);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_DMC0);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC0);
        } while (tmp & 0x11111111);
 
        /* Change Divider - DMC1 */
-       tmp = __raw_readl(S5P_CLKDIV_DMC1);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_DMC1);
 
-       tmp &= ~(S5P_CLKDIV_DMC1_G2D_ACP_MASK |
-               S5P_CLKDIV_DMC1_C2C_MASK |
-               S5P_CLKDIV_DMC1_C2CACLK_MASK);
+       tmp &= ~(EXYNOS4_CLKDIV_DMC1_G2D_ACP_MASK |
+               EXYNOS4_CLKDIV_DMC1_C2C_MASK |
+               EXYNOS4_CLKDIV_DMC1_C2CACLK_MASK);
 
        tmp |= ((exynos4x12_clkdiv_dmc1[index][0] <<
-                               S5P_CLKDIV_DMC1_G2D_ACP_SHIFT) |
+                               EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT) |
                (exynos4x12_clkdiv_dmc1[index][1] <<
-                               S5P_CLKDIV_DMC1_C2C_SHIFT) |
+                               EXYNOS4_CLKDIV_DMC1_C2C_SHIFT) |
                (exynos4x12_clkdiv_dmc1[index][2] <<
-                               S5P_CLKDIV_DMC1_C2CACLK_SHIFT));
+                               EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT));
 
-       __raw_writel(tmp, S5P_CLKDIV_DMC1);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_DMC1);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_DMC1);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC1);
        } while (tmp & 0x111111);
 
        /* Change Divider - TOP */
-       tmp = __raw_readl(S5P_CLKDIV_TOP);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
 
-       tmp &= ~(S5P_CLKDIV_TOP_ACLK266_GPS_MASK |
-               S5P_CLKDIV_TOP_ACLK100_MASK |
-               S5P_CLKDIV_TOP_ACLK160_MASK |
-               S5P_CLKDIV_TOP_ACLK133_MASK |
-               S5P_CLKDIV_TOP_ONENAND_MASK);
+       tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK266_GPS_MASK |
+               EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
+               EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
+               EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
+               EXYNOS4_CLKDIV_TOP_ONENAND_MASK);
 
        tmp |= ((exynos4x12_clkdiv_top[index][0] <<
-                               S5P_CLKDIV_TOP_ACLK266_GPS_SHIFT) |
+                               EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT) |
                (exynos4x12_clkdiv_top[index][1] <<
-                               S5P_CLKDIV_TOP_ACLK100_SHIFT) |
+                               EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
                (exynos4x12_clkdiv_top[index][2] <<
-                               S5P_CLKDIV_TOP_ACLK160_SHIFT) |
+                               EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
                (exynos4x12_clkdiv_top[index][3] <<
-                               S5P_CLKDIV_TOP_ACLK133_SHIFT) |
+                               EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
                (exynos4x12_clkdiv_top[index][4] <<
-                               S5P_CLKDIV_TOP_ONENAND_SHIFT));
+                               EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));
 
-       __raw_writel(tmp, S5P_CLKDIV_TOP);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_TOP);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_TOP);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_TOP);
        } while (tmp & 0x11111);
 
        /* Change Divider - LEFTBUS */
-       tmp = __raw_readl(S5P_CLKDIV_LEFTBUS);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_LEFTBUS);
 
-       tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
+       tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
 
        tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
-                               S5P_CLKDIV_BUS_GDLR_SHIFT) |
+                               EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
                (exynos4x12_clkdiv_lr_bus[index][1] <<
-                               S5P_CLKDIV_BUS_GPLR_SHIFT));
+                               EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
 
-       __raw_writel(tmp, S5P_CLKDIV_LEFTBUS);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_LEFTBUS);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_LEFTBUS);
        } while (tmp & 0x11);
 
        /* Change Divider - RIGHTBUS */
-       tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_RIGHTBUS);
 
-       tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
+       tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
 
        tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
-                               S5P_CLKDIV_BUS_GDLR_SHIFT) |
+                               EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
                (exynos4x12_clkdiv_lr_bus[index][1] <<
-                               S5P_CLKDIV_BUS_GPLR_SHIFT));
+                               EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
 
-       __raw_writel(tmp, S5P_CLKDIV_RIGHTBUS);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_RIGHTBUS);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_RIGHTBUS);
        } while (tmp & 0x11);
 
        /* Change Divider - MFC */
-       tmp = __raw_readl(S5P_CLKDIV_MFC);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_MFC);
 
-       tmp &= ~(S5P_CLKDIV_MFC_MASK);
+       tmp &= ~(EXYNOS4_CLKDIV_MFC_MASK);
 
        tmp |= ((exynos4x12_clkdiv_sclkip[index][0] <<
-                               S5P_CLKDIV_MFC_SHIFT));
+                               EXYNOS4_CLKDIV_MFC_SHIFT));
 
-       __raw_writel(tmp, S5P_CLKDIV_MFC);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_MFC);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_MFC);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_MFC);
        } while (tmp & 0x1);
 
        /* Change Divider - JPEG */
-       tmp = __raw_readl(S5P_CLKDIV_CAM1);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_CAM1);
 
-       tmp &= ~(S5P_CLKDIV_CAM1_JPEG_MASK);
+       tmp &= ~(EXYNOS4_CLKDIV_CAM1_JPEG_MASK);
 
        tmp |= ((exynos4x12_clkdiv_sclkip[index][1] <<
-                               S5P_CLKDIV_CAM1_JPEG_SHIFT));
+                               EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT));
 
-       __raw_writel(tmp, S5P_CLKDIV_CAM1);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_CAM1);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_CAM1);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_CAM1);
        } while (tmp & 0x1);
 
        /* Change Divider - FIMC0~3 */
-       tmp = __raw_readl(S5P_CLKDIV_CAM);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_CAM);
 
-       tmp &= ~(S5P_CLKDIV_CAM_FIMC0_MASK | S5P_CLKDIV_CAM_FIMC1_MASK |
-               S5P_CLKDIV_CAM_FIMC2_MASK | S5P_CLKDIV_CAM_FIMC3_MASK);
+       tmp &= ~(EXYNOS4_CLKDIV_CAM_FIMC0_MASK | EXYNOS4_CLKDIV_CAM_FIMC1_MASK |
+               EXYNOS4_CLKDIV_CAM_FIMC2_MASK | EXYNOS4_CLKDIV_CAM_FIMC3_MASK);
 
        tmp |= ((exynos4x12_clkdiv_sclkip[index][2] <<
-                               S5P_CLKDIV_CAM_FIMC0_SHIFT) |
+                               EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT) |
                (exynos4x12_clkdiv_sclkip[index][2] <<
-                               S5P_CLKDIV_CAM_FIMC1_SHIFT) |
+                               EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT) |
                (exynos4x12_clkdiv_sclkip[index][2] <<
-                               S5P_CLKDIV_CAM_FIMC2_SHIFT) |
+                               EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT) |
                (exynos4x12_clkdiv_sclkip[index][2] <<
-                               S5P_CLKDIV_CAM_FIMC3_SHIFT));
+                               EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT));
 
-       __raw_writel(tmp, S5P_CLKDIV_CAM);
+       __raw_writel(tmp, EXYNOS4_CLKDIV_CAM);
 
        do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_CAM1);
+               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_CAM1);
        } while (tmp & 0x1111);
 
        return 0;
@@ -760,55 +760,55 @@ static int exynos4210_init_tables(struct busfreq_data *data)
        int mgrp;
        int i, err = 0;
 
-       tmp = __raw_readl(S5P_CLKDIV_DMC0);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
        for (i = LV_0; i < EX4210_LV_NUM; i++) {
-               tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK |
-                       S5P_CLKDIV_DMC0_ACPPCLK_MASK |
-                       S5P_CLKDIV_DMC0_DPHY_MASK |
-                       S5P_CLKDIV_DMC0_DMC_MASK |
-                       S5P_CLKDIV_DMC0_DMCD_MASK |
-                       S5P_CLKDIV_DMC0_DMCP_MASK |
-                       S5P_CLKDIV_DMC0_COPY2_MASK |
-                       S5P_CLKDIV_DMC0_CORETI_MASK);
+               tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
+                       EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
+                       EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
+                       EXYNOS4_CLKDIV_DMC0_DMC_MASK |
+                       EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
+                       EXYNOS4_CLKDIV_DMC0_DMCP_MASK |
+                       EXYNOS4_CLKDIV_DMC0_COPY2_MASK |
+                       EXYNOS4_CLKDIV_DMC0_CORETI_MASK);
 
                tmp |= ((exynos4210_clkdiv_dmc0[i][0] <<
-                                       S5P_CLKDIV_DMC0_ACP_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
                        (exynos4210_clkdiv_dmc0[i][1] <<
-                                       S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
                        (exynos4210_clkdiv_dmc0[i][2] <<
-                                       S5P_CLKDIV_DMC0_DPHY_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
                        (exynos4210_clkdiv_dmc0[i][3] <<
-                                       S5P_CLKDIV_DMC0_DMC_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
                        (exynos4210_clkdiv_dmc0[i][4] <<
-                                       S5P_CLKDIV_DMC0_DMCD_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
                        (exynos4210_clkdiv_dmc0[i][5] <<
-                                       S5P_CLKDIV_DMC0_DMCP_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT) |
                        (exynos4210_clkdiv_dmc0[i][6] <<
-                                       S5P_CLKDIV_DMC0_COPY2_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT) |
                        (exynos4210_clkdiv_dmc0[i][7] <<
-                                       S5P_CLKDIV_DMC0_CORETI_SHIFT));
+                                       EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT));
 
                data->dmc_divtable[i] = tmp;
        }
 
-       tmp = __raw_readl(S5P_CLKDIV_TOP);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
        for (i = LV_0; i <  EX4210_LV_NUM; i++) {
-               tmp &= ~(S5P_CLKDIV_TOP_ACLK200_MASK |
-                       S5P_CLKDIV_TOP_ACLK100_MASK |
-                       S5P_CLKDIV_TOP_ACLK160_MASK |
-                       S5P_CLKDIV_TOP_ACLK133_MASK |
-                       S5P_CLKDIV_TOP_ONENAND_MASK);
+               tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK200_MASK |
+                       EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
+                       EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
+                       EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
+                       EXYNOS4_CLKDIV_TOP_ONENAND_MASK);
 
                tmp |= ((exynos4210_clkdiv_top[i][0] <<
-                                       S5P_CLKDIV_TOP_ACLK200_SHIFT) |
+                                       EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT) |
                        (exynos4210_clkdiv_top[i][1] <<
-                                       S5P_CLKDIV_TOP_ACLK100_SHIFT) |
+                                       EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
                        (exynos4210_clkdiv_top[i][2] <<
-                                       S5P_CLKDIV_TOP_ACLK160_SHIFT) |
+                                       EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
                        (exynos4210_clkdiv_top[i][3] <<
-                                       S5P_CLKDIV_TOP_ACLK133_SHIFT) |
+                                       EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
                        (exynos4210_clkdiv_top[i][4] <<
-                                       S5P_CLKDIV_TOP_ONENAND_SHIFT));
+                                       EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));
 
                data->top_divtable[i] = tmp;
        }
@@ -868,32 +868,32 @@ static int exynos4x12_init_tables(struct busfreq_data *data)
        int ret;
 
        /* Enable pause function for DREX2 DVFS */
-       tmp = __raw_readl(S5P_DMC_PAUSE_CTRL);
-       tmp |= DMC_PAUSE_ENABLE;
-       __raw_writel(tmp, S5P_DMC_PAUSE_CTRL);
+       tmp = __raw_readl(EXYNOS4_DMC_PAUSE_CTRL);
+       tmp |= EXYNOS4_DMC_PAUSE_ENABLE;
+       __raw_writel(tmp, EXYNOS4_DMC_PAUSE_CTRL);
 
-       tmp = __raw_readl(S5P_CLKDIV_DMC0);
+       tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
 
        for (i = 0; i <  EX4x12_LV_NUM; i++) {
-               tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK |
-                       S5P_CLKDIV_DMC0_ACPPCLK_MASK |
-                       S5P_CLKDIV_DMC0_DPHY_MASK |
-                       S5P_CLKDIV_DMC0_DMC_MASK |
-                       S5P_CLKDIV_DMC0_DMCD_MASK |
-                       S5P_CLKDIV_DMC0_DMCP_MASK);
+               tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
+                       EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
+                       EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
+                       EXYNOS4_CLKDIV_DMC0_DMC_MASK |
+                       EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
+                       EXYNOS4_CLKDIV_DMC0_DMCP_MASK);
 
                tmp |= ((exynos4x12_clkdiv_dmc0[i][0] <<
-                                       S5P_CLKDIV_DMC0_ACP_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
                        (exynos4x12_clkdiv_dmc0[i][1] <<
-                                       S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
                        (exynos4x12_clkdiv_dmc0[i][2] <<
-                                       S5P_CLKDIV_DMC0_DPHY_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
                        (exynos4x12_clkdiv_dmc0[i][3] <<
-                                       S5P_CLKDIV_DMC0_DMC_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
                        (exynos4x12_clkdiv_dmc0[i][4] <<
-                                       S5P_CLKDIV_DMC0_DMCD_SHIFT) |
+                                       EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
                        (exynos4x12_clkdiv_dmc0[i][5] <<
-                                       S5P_CLKDIV_DMC0_DMCP_SHIFT));
+                                       EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT));
 
                data->dmc_divtable[i] = tmp;
        }
index f1a2749..4a6c46d 100644 (file)
@@ -252,6 +252,15 @@ config EP93XX_DMA
        help
          Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller.
 
+config DMA_SA11X0
+       tristate "SA-11x0 DMA support"
+       depends on ARCH_SA1100
+       select DMA_ENGINE
+       help
+         Support the DMA engine found on Intel StrongARM SA-1100 and
+         SA-1110 SoCs.  This DMA engine can only be used with on-chip
+         devices.
+
 config DMA_ENGINE
        bool
 
index 009a222..86b795b 100644 (file)
@@ -27,3 +27,4 @@ obj-$(CONFIG_PL330_DMA) += pl330.o
 obj-$(CONFIG_PCH_DMA) += pch_dma.o
 obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
 obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
+obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
index e4383ee..38586ba 100644 (file)
@@ -14,7 +14,6 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
index 8bc5acf..63540d3 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/dmaengine.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/module.h>
 
 #include <asm/irq.h>
 #include <mach/sdma.h>
index b8ec03e..16b66c8 100644 (file)
@@ -1035,18 +1035,7 @@ static struct amba_driver pl330_driver = {
        .remove = pl330_remove,
 };
 
-static int __init pl330_init(void)
-{
-       return amba_driver_register(&pl330_driver);
-}
-module_init(pl330_init);
-
-static void __exit pl330_exit(void)
-{
-       amba_driver_unregister(&pl330_driver);
-       return;
-}
-module_exit(pl330_exit);
+module_amba_driver(pl330_driver);
 
 MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
 MODULE_DESCRIPTION("API Driver for PL330 DMAC");
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
new file mode 100644 (file)
index 0000000..16a6b48
--- /dev/null
@@ -0,0 +1,1109 @@
+/*
+ * SA11x0 DMAengine support
+ *
+ * Copyright (C) 2012 Russell King
+ *   Derived in part from arch/arm/mach-sa1100/dma.c,
+ *   Copyright (C) 2000, 2001 by Nicolas Pitre
+ *
+ * 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/sched.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sa11x0-dma.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define NR_PHY_CHAN    6
+#define DMA_ALIGN      3
+#define DMA_MAX_SIZE   0x1fff
+#define DMA_CHUNK_SIZE 0x1000
+
+#define DMA_DDAR       0x00
+#define DMA_DCSR_S     0x04
+#define DMA_DCSR_C     0x08
+#define DMA_DCSR_R     0x0c
+#define DMA_DBSA       0x10
+#define DMA_DBTA       0x14
+#define DMA_DBSB       0x18
+#define DMA_DBTB       0x1c
+#define DMA_SIZE       0x20
+
+#define DCSR_RUN       (1 << 0)
+#define DCSR_IE                (1 << 1)
+#define DCSR_ERROR     (1 << 2)
+#define DCSR_DONEA     (1 << 3)
+#define DCSR_STRTA     (1 << 4)
+#define DCSR_DONEB     (1 << 5)
+#define DCSR_STRTB     (1 << 6)
+#define DCSR_BIU       (1 << 7)
+
+#define DDAR_RW                (1 << 0)        /* 0 = W, 1 = R */
+#define DDAR_E         (1 << 1)        /* 0 = LE, 1 = BE */
+#define DDAR_BS                (1 << 2)        /* 0 = BS4, 1 = BS8 */
+#define DDAR_DW                (1 << 3)        /* 0 = 8b, 1 = 16b */
+#define DDAR_Ser0UDCTr (0x0 << 4)
+#define DDAR_Ser0UDCRc (0x1 << 4)
+#define DDAR_Ser1SDLCTr        (0x2 << 4)
+#define DDAR_Ser1SDLCRc        (0x3 << 4)
+#define DDAR_Ser1UARTTr        (0x4 << 4)
+#define DDAR_Ser1UARTRc        (0x5 << 4)
+#define DDAR_Ser2ICPTr (0x6 << 4)
+#define DDAR_Ser2ICPRc (0x7 << 4)
+#define DDAR_Ser3UARTTr        (0x8 << 4)
+#define DDAR_Ser3UARTRc        (0x9 << 4)
+#define DDAR_Ser4MCP0Tr        (0xa << 4)
+#define DDAR_Ser4MCP0Rc        (0xb << 4)
+#define DDAR_Ser4MCP1Tr        (0xc << 4)
+#define DDAR_Ser4MCP1Rc        (0xd << 4)
+#define DDAR_Ser4SSPTr (0xe << 4)
+#define DDAR_Ser4SSPRc (0xf << 4)
+
+struct sa11x0_dma_sg {
+       u32                     addr;
+       u32                     len;
+};
+
+struct sa11x0_dma_desc {
+       struct dma_async_tx_descriptor tx;
+       u32                     ddar;
+       size_t                  size;
+
+       /* maybe protected by c->lock */
+       struct list_head        node;
+       unsigned                sglen;
+       struct sa11x0_dma_sg    sg[0];
+};
+
+struct sa11x0_dma_phy;
+
+struct sa11x0_dma_chan {
+       struct dma_chan         chan;
+       spinlock_t              lock;
+       dma_cookie_t            lc;
+
+       /* protected by c->lock */
+       struct sa11x0_dma_phy   *phy;
+       enum dma_status         status;
+       struct list_head        desc_submitted;
+       struct list_head        desc_issued;
+
+       /* protected by d->lock */
+       struct list_head        node;
+
+       u32                     ddar;
+       const char              *name;
+};
+
+struct sa11x0_dma_phy {
+       void __iomem            *base;
+       struct sa11x0_dma_dev   *dev;
+       unsigned                num;
+
+       struct sa11x0_dma_chan  *vchan;
+
+       /* Protected by c->lock */
+       unsigned                sg_load;
+       struct sa11x0_dma_desc  *txd_load;
+       unsigned                sg_done;
+       struct sa11x0_dma_desc  *txd_done;
+#ifdef CONFIG_PM_SLEEP
+       u32                     dbs[2];
+       u32                     dbt[2];
+       u32                     dcsr;
+#endif
+};
+
+struct sa11x0_dma_dev {
+       struct dma_device       slave;
+       void __iomem            *base;
+       spinlock_t              lock;
+       struct tasklet_struct   task;
+       struct list_head        chan_pending;
+       struct list_head        desc_complete;
+       struct sa11x0_dma_phy   phy[NR_PHY_CHAN];
+};
+
+static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan)
+{
+       return container_of(chan, struct sa11x0_dma_chan, chan);
+}
+
+static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev)
+{
+       return container_of(dmadev, struct sa11x0_dma_dev, slave);
+}
+
+static struct sa11x0_dma_desc *to_sa11x0_dma_tx(struct dma_async_tx_descriptor *tx)
+{
+       return container_of(tx, struct sa11x0_dma_desc, tx);
+}
+
+static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c)
+{
+       if (list_empty(&c->desc_issued))
+               return NULL;
+
+       return list_first_entry(&c->desc_issued, struct sa11x0_dma_desc, node);
+}
+
+static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd)
+{
+       list_del(&txd->node);
+       p->txd_load = txd;
+       p->sg_load = 0;
+
+       dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n",
+               p->num, txd, txd->tx.cookie, txd->ddar);
+}
+
+static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p,
+       struct sa11x0_dma_chan *c)
+{
+       struct sa11x0_dma_desc *txd = p->txd_load;
+       struct sa11x0_dma_sg *sg;
+       void __iomem *base = p->base;
+       unsigned dbsx, dbtx;
+       u32 dcsr;
+
+       if (!txd)
+               return;
+
+       dcsr = readl_relaxed(base + DMA_DCSR_R);
+
+       /* Don't try to load the next transfer if both buffers are started */
+       if ((dcsr & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB))
+               return;
+
+       if (p->sg_load == txd->sglen) {
+               struct sa11x0_dma_desc *txn = sa11x0_dma_next_desc(c);
+
+               /*
+                * We have reached the end of the current descriptor.
+                * Peek at the next descriptor, and if compatible with
+                * the current, start processing it.
+                */
+               if (txn && txn->ddar == txd->ddar) {
+                       txd = txn;
+                       sa11x0_dma_start_desc(p, txn);
+               } else {
+                       p->txd_load = NULL;
+                       return;
+               }
+       }
+
+       sg = &txd->sg[p->sg_load++];
+
+       /* Select buffer to load according to channel status */
+       if (((dcsr & (DCSR_BIU | DCSR_STRTB)) == (DCSR_BIU | DCSR_STRTB)) ||
+           ((dcsr & (DCSR_BIU | DCSR_STRTA)) == 0)) {
+               dbsx = DMA_DBSA;
+               dbtx = DMA_DBTA;
+               dcsr = DCSR_STRTA | DCSR_IE | DCSR_RUN;
+       } else {
+               dbsx = DMA_DBSB;
+               dbtx = DMA_DBTB;
+               dcsr = DCSR_STRTB | DCSR_IE | DCSR_RUN;
+       }
+
+       writel_relaxed(sg->addr, base + dbsx);
+       writel_relaxed(sg->len, base + dbtx);
+       writel(dcsr, base + DMA_DCSR_S);
+
+       dev_dbg(p->dev->slave.dev, "pchan %u: load: DCSR:%02x DBS%c:%08x DBT%c:%08x\n",
+               p->num, dcsr,
+               'A' + (dbsx == DMA_DBSB), sg->addr,
+               'A' + (dbtx == DMA_DBTB), sg->len);
+}
+
+static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p,
+       struct sa11x0_dma_chan *c)
+{
+       struct sa11x0_dma_desc *txd = p->txd_done;
+
+       if (++p->sg_done == txd->sglen) {
+               struct sa11x0_dma_dev *d = p->dev;
+
+               dev_vdbg(d->slave.dev, "pchan %u: txd %p[%x]: completed\n",
+                       p->num, p->txd_done, p->txd_done->tx.cookie);
+
+               c->lc = txd->tx.cookie;
+
+               spin_lock(&d->lock);
+               list_add_tail(&txd->node, &d->desc_complete);
+               spin_unlock(&d->lock);
+
+               p->sg_done = 0;
+               p->txd_done = p->txd_load;
+
+               tasklet_schedule(&d->task);
+       }
+
+       sa11x0_dma_start_sg(p, c);
+}
+
+static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id)
+{
+       struct sa11x0_dma_phy *p = dev_id;
+       struct sa11x0_dma_dev *d = p->dev;
+       struct sa11x0_dma_chan *c;
+       u32 dcsr;
+
+       dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+       if (!(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB)))
+               return IRQ_NONE;
+
+       /* Clear reported status bits */
+       writel_relaxed(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB),
+               p->base + DMA_DCSR_C);
+
+       dev_dbg(d->slave.dev, "pchan %u: irq: DCSR:%02x\n", p->num, dcsr);
+
+       if (dcsr & DCSR_ERROR) {
+               dev_err(d->slave.dev, "pchan %u: error. DCSR:%02x DDAR:%08x DBSA:%08x DBTA:%08x DBSB:%08x DBTB:%08x\n",
+                       p->num, dcsr,
+                       readl_relaxed(p->base + DMA_DDAR),
+                       readl_relaxed(p->base + DMA_DBSA),
+                       readl_relaxed(p->base + DMA_DBTA),
+                       readl_relaxed(p->base + DMA_DBSB),
+                       readl_relaxed(p->base + DMA_DBTB));
+       }
+
+       c = p->vchan;
+       if (c) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&c->lock, flags);
+               /*
+                * Now that we're holding the lock, check that the vchan
+                * really is associated with this pchan before touching the
+                * hardware.  This should always succeed, because we won't
+                * change p->vchan or c->phy while the channel is actively
+                * transferring.
+                */
+               if (c->phy == p) {
+                       if (dcsr & DCSR_DONEA)
+                               sa11x0_dma_complete(p, c);
+                       if (dcsr & DCSR_DONEB)
+                               sa11x0_dma_complete(p, c);
+               }
+               spin_unlock_irqrestore(&c->lock, flags);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void sa11x0_dma_start_txd(struct sa11x0_dma_chan *c)
+{
+       struct sa11x0_dma_desc *txd = sa11x0_dma_next_desc(c);
+
+       /* If the issued list is empty, we have no further txds to process */
+       if (txd) {
+               struct sa11x0_dma_phy *p = c->phy;
+
+               sa11x0_dma_start_desc(p, txd);
+               p->txd_done = txd;
+               p->sg_done = 0;
+
+               /* The channel should not have any transfers started */
+               WARN_ON(readl_relaxed(p->base + DMA_DCSR_R) &
+                                     (DCSR_STRTA | DCSR_STRTB));
+
+               /* Clear the run and start bits before changing DDAR */
+               writel_relaxed(DCSR_RUN | DCSR_STRTA | DCSR_STRTB,
+                              p->base + DMA_DCSR_C);
+               writel_relaxed(txd->ddar, p->base + DMA_DDAR);
+
+               /* Try to start both buffers */
+               sa11x0_dma_start_sg(p, c);
+               sa11x0_dma_start_sg(p, c);
+       }
+}
+
+static void sa11x0_dma_tasklet(unsigned long arg)
+{
+       struct sa11x0_dma_dev *d = (struct sa11x0_dma_dev *)arg;
+       struct sa11x0_dma_phy *p;
+       struct sa11x0_dma_chan *c;
+       struct sa11x0_dma_desc *txd, *txn;
+       LIST_HEAD(head);
+       unsigned pch, pch_alloc = 0;
+
+       dev_dbg(d->slave.dev, "tasklet enter\n");
+
+       /* Get the completed tx descriptors */
+       spin_lock_irq(&d->lock);
+       list_splice_init(&d->desc_complete, &head);
+       spin_unlock_irq(&d->lock);
+
+       list_for_each_entry(txd, &head, node) {
+               c = to_sa11x0_dma_chan(txd->tx.chan);
+
+               dev_dbg(d->slave.dev, "vchan %p: txd %p[%x] completed\n",
+                       c, txd, txd->tx.cookie);
+
+               spin_lock_irq(&c->lock);
+               p = c->phy;
+               if (p) {
+                       if (!p->txd_done)
+                               sa11x0_dma_start_txd(c);
+                       if (!p->txd_done) {
+                               /* No current txd associated with this channel */
+                               dev_dbg(d->slave.dev, "pchan %u: free\n", p->num);
+
+                               /* Mark this channel free */
+                               c->phy = NULL;
+                               p->vchan = NULL;
+                       }
+               }
+               spin_unlock_irq(&c->lock);
+       }
+
+       spin_lock_irq(&d->lock);
+       for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+               p = &d->phy[pch];
+
+               if (p->vchan == NULL && !list_empty(&d->chan_pending)) {
+                       c = list_first_entry(&d->chan_pending,
+                               struct sa11x0_dma_chan, node);
+                       list_del_init(&c->node);
+
+                       pch_alloc |= 1 << pch;
+
+                       /* Mark this channel allocated */
+                       p->vchan = c;
+
+                       dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, c);
+               }
+       }
+       spin_unlock_irq(&d->lock);
+
+       for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+               if (pch_alloc & (1 << pch)) {
+                       p = &d->phy[pch];
+                       c = p->vchan;
+
+                       spin_lock_irq(&c->lock);
+                       c->phy = p;
+
+                       sa11x0_dma_start_txd(c);
+                       spin_unlock_irq(&c->lock);
+               }
+       }
+
+       /* Now free the completed tx descriptor, and call their callbacks */
+       list_for_each_entry_safe(txd, txn, &head, node) {
+               dma_async_tx_callback callback = txd->tx.callback;
+               void *callback_param = txd->tx.callback_param;
+
+               dev_dbg(d->slave.dev, "txd %p[%x]: callback and free\n",
+                       txd, txd->tx.cookie);
+
+               kfree(txd);
+
+               if (callback)
+                       callback(callback_param);
+       }
+
+       dev_dbg(d->slave.dev, "tasklet exit\n");
+}
+
+
+static void sa11x0_dma_desc_free(struct sa11x0_dma_dev *d, struct list_head *head)
+{
+       struct sa11x0_dma_desc *txd, *txn;
+
+       list_for_each_entry_safe(txd, txn, head, node) {
+               dev_dbg(d->slave.dev, "txd %p: freeing\n", txd);
+               kfree(txd);
+       }
+}
+
+static int sa11x0_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+       return 0;
+}
+
+static void sa11x0_dma_free_chan_resources(struct dma_chan *chan)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+       struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+       unsigned long flags;
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&c->lock, flags);
+       spin_lock(&d->lock);
+       list_del_init(&c->node);
+       spin_unlock(&d->lock);
+
+       list_splice_tail_init(&c->desc_submitted, &head);
+       list_splice_tail_init(&c->desc_issued, &head);
+       spin_unlock_irqrestore(&c->lock, flags);
+
+       sa11x0_dma_desc_free(d, &head);
+}
+
+static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p)
+{
+       unsigned reg;
+       u32 dcsr;
+
+       dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+
+       if ((dcsr & (DCSR_BIU | DCSR_STRTA)) == DCSR_STRTA ||
+           (dcsr & (DCSR_BIU | DCSR_STRTB)) == DCSR_BIU)
+               reg = DMA_DBSA;
+       else
+               reg = DMA_DBSB;
+
+       return readl_relaxed(p->base + reg);
+}
+
+static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
+       dma_cookie_t cookie, struct dma_tx_state *state)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+       struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+       struct sa11x0_dma_phy *p;
+       struct sa11x0_dma_desc *txd;
+       dma_cookie_t last_used, last_complete;
+       unsigned long flags;
+       enum dma_status ret;
+       size_t bytes = 0;
+
+       last_used = c->chan.cookie;
+       last_complete = c->lc;
+
+       ret = dma_async_is_complete(cookie, last_complete, last_used);
+       if (ret == DMA_SUCCESS) {
+               dma_set_tx_state(state, last_complete, last_used, 0);
+               return ret;
+       }
+
+       spin_lock_irqsave(&c->lock, flags);
+       p = c->phy;
+       ret = c->status;
+       if (p) {
+               dma_addr_t addr = sa11x0_dma_pos(p);
+
+               dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
+
+               txd = p->txd_done;
+               if (txd) {
+                       unsigned i;
+
+                       for (i = 0; i < txd->sglen; i++) {
+                               dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
+                                       i, txd->sg[i].addr, txd->sg[i].len);
+                               if (addr >= txd->sg[i].addr &&
+                                   addr < txd->sg[i].addr + txd->sg[i].len) {
+                                       unsigned len;
+
+                                       len = txd->sg[i].len -
+                                               (addr - txd->sg[i].addr);
+                                       dev_vdbg(d->slave.dev, "tx_status: [%u] +%x\n",
+                                               i, len);
+                                       bytes += len;
+                                       i++;
+                                       break;
+                               }
+                       }
+                       for (; i < txd->sglen; i++) {
+                               dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x ++\n",
+                                       i, txd->sg[i].addr, txd->sg[i].len);
+                               bytes += txd->sg[i].len;
+                       }
+               }
+               if (txd != p->txd_load && p->txd_load)
+                       bytes += p->txd_load->size;
+       }
+       list_for_each_entry(txd, &c->desc_issued, node) {
+               bytes += txd->size;
+       }
+       spin_unlock_irqrestore(&c->lock, flags);
+
+       dma_set_tx_state(state, last_complete, last_used, bytes);
+
+       dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes);
+
+       return ret;
+}
+
+/*
+ * Move pending txds to the issued list, and re-init pending list.
+ * If not already pending, add this channel to the list of pending
+ * channels and trigger the tasklet to run.
+ */
+static void sa11x0_dma_issue_pending(struct dma_chan *chan)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+       struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->lock, flags);
+       list_splice_tail_init(&c->desc_submitted, &c->desc_issued);
+       if (!list_empty(&c->desc_issued)) {
+               spin_lock(&d->lock);
+               if (!c->phy && list_empty(&c->node)) {
+                       list_add_tail(&c->node, &d->chan_pending);
+                       tasklet_schedule(&d->task);
+                       dev_dbg(d->slave.dev, "vchan %p: issued\n", c);
+               }
+               spin_unlock(&d->lock);
+       } else
+               dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", c);
+       spin_unlock_irqrestore(&c->lock, flags);
+}
+
+static dma_cookie_t sa11x0_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(tx->chan);
+       struct sa11x0_dma_desc *txd = to_sa11x0_dma_tx(tx);
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->lock, flags);
+       c->chan.cookie += 1;
+       if (c->chan.cookie < 0)
+               c->chan.cookie = 1;
+       txd->tx.cookie = c->chan.cookie;
+
+       list_add_tail(&txd->node, &c->desc_submitted);
+       spin_unlock_irqrestore(&c->lock, flags);
+
+       dev_dbg(tx->chan->device->dev, "vchan %p: txd %p[%x]: submitted\n",
+               c, txd, txd->tx.cookie);
+
+       return txd->tx.cookie;
+}
+
+static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
+       struct dma_chan *chan, struct scatterlist *sg, unsigned int sglen,
+       enum dma_transfer_direction dir, unsigned long flags)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+       struct sa11x0_dma_desc *txd;
+       struct scatterlist *sgent;
+       unsigned i, j = sglen;
+       size_t size = 0;
+
+       /* SA11x0 channels can only operate in their native direction */
+       if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
+               dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
+                       c, c->ddar, dir);
+               return NULL;
+       }
+
+       /* Do not allow zero-sized txds */
+       if (sglen == 0)
+               return NULL;
+
+       for_each_sg(sg, sgent, sglen, i) {
+               dma_addr_t addr = sg_dma_address(sgent);
+               unsigned int len = sg_dma_len(sgent);
+
+               if (len > DMA_MAX_SIZE)
+                       j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1;
+               if (addr & DMA_ALIGN) {
+                       dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n",
+                               c, addr);
+                       return NULL;
+               }
+       }
+
+       txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC);
+       if (!txd) {
+               dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", c);
+               return NULL;
+       }
+
+       j = 0;
+       for_each_sg(sg, sgent, sglen, i) {
+               dma_addr_t addr = sg_dma_address(sgent);
+               unsigned len = sg_dma_len(sgent);
+
+               size += len;
+
+               do {
+                       unsigned tlen = len;
+
+                       /*
+                        * Check whether the transfer will fit.  If not, try
+                        * to split the transfer up such that we end up with
+                        * equal chunks - but make sure that we preserve the
+                        * alignment.  This avoids small segments.
+                        */
+                       if (tlen > DMA_MAX_SIZE) {
+                               unsigned mult = DIV_ROUND_UP(tlen,
+                                       DMA_MAX_SIZE & ~DMA_ALIGN);
+
+                               tlen = (tlen / mult) & ~DMA_ALIGN;
+                       }
+
+                       txd->sg[j].addr = addr;
+                       txd->sg[j].len = tlen;
+
+                       addr += tlen;
+                       len -= tlen;
+                       j++;
+               } while (len);
+       }
+
+       dma_async_tx_descriptor_init(&txd->tx, &c->chan);
+       txd->tx.flags = flags;
+       txd->tx.tx_submit = sa11x0_dma_tx_submit;
+       txd->ddar = c->ddar;
+       txd->size = size;
+       txd->sglen = j;
+
+       dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n",
+               c, txd, txd->size, txd->sglen);
+
+       return &txd->tx;
+}
+
+static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_config *cfg)
+{
+       u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW);
+       dma_addr_t addr;
+       enum dma_slave_buswidth width;
+       u32 maxburst;
+
+       if (ddar & DDAR_RW) {
+               addr = cfg->src_addr;
+               width = cfg->src_addr_width;
+               maxburst = cfg->src_maxburst;
+       } else {
+               addr = cfg->dst_addr;
+               width = cfg->dst_addr_width;
+               maxburst = cfg->dst_maxburst;
+       }
+
+       if ((width != DMA_SLAVE_BUSWIDTH_1_BYTE &&
+            width != DMA_SLAVE_BUSWIDTH_2_BYTES) ||
+           (maxburst != 4 && maxburst != 8))
+               return -EINVAL;
+
+       if (width == DMA_SLAVE_BUSWIDTH_2_BYTES)
+               ddar |= DDAR_DW;
+       if (maxburst == 8)
+               ddar |= DDAR_BS;
+
+       dev_dbg(c->chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n",
+               c, addr, width, maxburst);
+
+       c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6;
+
+       return 0;
+}
+
+static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+       unsigned long arg)
+{
+       struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+       struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+       struct sa11x0_dma_phy *p;
+       LIST_HEAD(head);
+       unsigned long flags;
+       int ret;
+
+       switch (cmd) {
+       case DMA_SLAVE_CONFIG:
+               return sa11x0_dma_slave_config(c, (struct dma_slave_config *)arg);
+
+       case DMA_TERMINATE_ALL:
+               dev_dbg(d->slave.dev, "vchan %p: terminate all\n", c);
+               /* Clear the tx descriptor lists */
+               spin_lock_irqsave(&c->lock, flags);
+               list_splice_tail_init(&c->desc_submitted, &head);
+               list_splice_tail_init(&c->desc_issued, &head);
+
+               p = c->phy;
+               if (p) {
+                       struct sa11x0_dma_desc *txd, *txn;
+
+                       dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
+                       /* vchan is assigned to a pchan - stop the channel */
+                       writel(DCSR_RUN | DCSR_IE |
+                               DCSR_STRTA | DCSR_DONEA |
+                               DCSR_STRTB | DCSR_DONEB,
+                               p->base + DMA_DCSR_C);
+
+                       list_for_each_entry_safe(txd, txn, &d->desc_complete, node)
+                               if (txd->tx.chan == &c->chan)
+                                       list_move(&txd->node, &head);
+
+                       if (p->txd_load) {
+                               if (p->txd_load != p->txd_done)
+                                       list_add_tail(&p->txd_load->node, &head);
+                               p->txd_load = NULL;
+                       }
+                       if (p->txd_done) {
+                               list_add_tail(&p->txd_done->node, &head);
+                               p->txd_done = NULL;
+                       }
+                       c->phy = NULL;
+                       spin_lock(&d->lock);
+                       p->vchan = NULL;
+                       spin_unlock(&d->lock);
+                       tasklet_schedule(&d->task);
+               }
+               spin_unlock_irqrestore(&c->lock, flags);
+               sa11x0_dma_desc_free(d, &head);
+               ret = 0;
+               break;
+
+       case DMA_PAUSE:
+               dev_dbg(d->slave.dev, "vchan %p: pause\n", c);
+               spin_lock_irqsave(&c->lock, flags);
+               if (c->status == DMA_IN_PROGRESS) {
+                       c->status = DMA_PAUSED;
+
+                       p = c->phy;
+                       if (p) {
+                               writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
+                       } else {
+                               spin_lock(&d->lock);
+                               list_del_init(&c->node);
+                               spin_unlock(&d->lock);
+                       }
+               }
+               spin_unlock_irqrestore(&c->lock, flags);
+               ret = 0;
+               break;
+
+       case DMA_RESUME:
+               dev_dbg(d->slave.dev, "vchan %p: resume\n", c);
+               spin_lock_irqsave(&c->lock, flags);
+               if (c->status == DMA_PAUSED) {
+                       c->status = DMA_IN_PROGRESS;
+
+                       p = c->phy;
+                       if (p) {
+                               writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
+                       } else if (!list_empty(&c->desc_issued)) {
+                               spin_lock(&d->lock);
+                               list_add_tail(&c->node, &d->chan_pending);
+                               spin_unlock(&d->lock);
+                       }
+               }
+               spin_unlock_irqrestore(&c->lock, flags);
+               ret = 0;
+               break;
+
+       default:
+               ret = -ENXIO;
+               break;
+       }
+
+       return ret;
+}
+
+struct sa11x0_dma_channel_desc {
+       u32 ddar;
+       const char *name;
+};
+
+#define CD(d1, d2) { .ddar = DDAR_##d1 | d2, .name = #d1 }
+static const struct sa11x0_dma_channel_desc chan_desc[] = {
+       CD(Ser0UDCTr, 0),
+       CD(Ser0UDCRc, DDAR_RW),
+       CD(Ser1SDLCTr, 0),
+       CD(Ser1SDLCRc, DDAR_RW),
+       CD(Ser1UARTTr, 0),
+       CD(Ser1UARTRc, DDAR_RW),
+       CD(Ser2ICPTr, 0),
+       CD(Ser2ICPRc, DDAR_RW),
+       CD(Ser3UARTTr, 0),
+       CD(Ser3UARTRc, DDAR_RW),
+       CD(Ser4MCP0Tr, 0),
+       CD(Ser4MCP0Rc, DDAR_RW),
+       CD(Ser4MCP1Tr, 0),
+       CD(Ser4MCP1Rc, DDAR_RW),
+       CD(Ser4SSPTr, 0),
+       CD(Ser4SSPRc, DDAR_RW),
+};
+
+static int __devinit sa11x0_dma_init_dmadev(struct dma_device *dmadev,
+       struct device *dev)
+{
+       unsigned i;
+
+       dmadev->chancnt = ARRAY_SIZE(chan_desc);
+       INIT_LIST_HEAD(&dmadev->channels);
+       dmadev->dev = dev;
+       dmadev->device_alloc_chan_resources = sa11x0_dma_alloc_chan_resources;
+       dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources;
+       dmadev->device_control = sa11x0_dma_control;
+       dmadev->device_tx_status = sa11x0_dma_tx_status;
+       dmadev->device_issue_pending = sa11x0_dma_issue_pending;
+
+       for (i = 0; i < dmadev->chancnt; i++) {
+               struct sa11x0_dma_chan *c;
+
+               c = kzalloc(sizeof(*c), GFP_KERNEL);
+               if (!c) {
+                       dev_err(dev, "no memory for channel %u\n", i);
+                       return -ENOMEM;
+               }
+
+               c->chan.device = dmadev;
+               c->status = DMA_IN_PROGRESS;
+               c->ddar = chan_desc[i].ddar;
+               c->name = chan_desc[i].name;
+               spin_lock_init(&c->lock);
+               INIT_LIST_HEAD(&c->desc_submitted);
+               INIT_LIST_HEAD(&c->desc_issued);
+               INIT_LIST_HEAD(&c->node);
+               list_add_tail(&c->chan.device_node, &dmadev->channels);
+       }
+
+       return dma_async_device_register(dmadev);
+}
+
+static int sa11x0_dma_request_irq(struct platform_device *pdev, int nr,
+       void *data)
+{
+       int irq = platform_get_irq(pdev, nr);
+
+       if (irq <= 0)
+               return -ENXIO;
+
+       return request_irq(irq, sa11x0_dma_irq, 0, dev_name(&pdev->dev), data);
+}
+
+static void sa11x0_dma_free_irq(struct platform_device *pdev, int nr,
+       void *data)
+{
+       int irq = platform_get_irq(pdev, nr);
+       if (irq > 0)
+               free_irq(irq, data);
+}
+
+static void sa11x0_dma_free_channels(struct dma_device *dmadev)
+{
+       struct sa11x0_dma_chan *c, *cn;
+
+       list_for_each_entry_safe(c, cn, &dmadev->channels, chan.device_node) {
+               list_del(&c->chan.device_node);
+               kfree(c);
+       }
+}
+
+static int __devinit sa11x0_dma_probe(struct platform_device *pdev)
+{
+       struct sa11x0_dma_dev *d;
+       struct resource *res;
+       unsigned i;
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
+
+       d = kzalloc(sizeof(*d), GFP_KERNEL);
+       if (!d) {
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
+
+       spin_lock_init(&d->lock);
+       INIT_LIST_HEAD(&d->chan_pending);
+       INIT_LIST_HEAD(&d->desc_complete);
+
+       d->base = ioremap(res->start, resource_size(res));
+       if (!d->base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       tasklet_init(&d->task, sa11x0_dma_tasklet, (unsigned long)d);
+
+       for (i = 0; i < NR_PHY_CHAN; i++) {
+               struct sa11x0_dma_phy *p = &d->phy[i];
+
+               p->dev = d;
+               p->num = i;
+               p->base = d->base + i * DMA_SIZE;
+               writel_relaxed(DCSR_RUN | DCSR_IE | DCSR_ERROR |
+                       DCSR_DONEA | DCSR_STRTA | DCSR_DONEB | DCSR_STRTB,
+                       p->base + DMA_DCSR_C);
+               writel_relaxed(0, p->base + DMA_DDAR);
+
+               ret = sa11x0_dma_request_irq(pdev, i, p);
+               if (ret) {
+                       while (i) {
+                               i--;
+                               sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
+                       }
+                       goto err_irq;
+               }
+       }
+
+       dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
+       d->slave.device_prep_slave_sg = sa11x0_dma_prep_slave_sg;
+       ret = sa11x0_dma_init_dmadev(&d->slave, &pdev->dev);
+       if (ret) {
+               dev_warn(d->slave.dev, "failed to register slave async device: %d\n",
+                       ret);
+               goto err_slave_reg;
+       }
+
+       platform_set_drvdata(pdev, d);
+       return 0;
+
+ err_slave_reg:
+       sa11x0_dma_free_channels(&d->slave);
+       for (i = 0; i < NR_PHY_CHAN; i++)
+               sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
+ err_irq:
+       tasklet_kill(&d->task);
+       iounmap(d->base);
+ err_ioremap:
+       kfree(d);
+ err_alloc:
+       return ret;
+}
+
+static int __devexit sa11x0_dma_remove(struct platform_device *pdev)
+{
+       struct sa11x0_dma_dev *d = platform_get_drvdata(pdev);
+       unsigned pch;
+
+       dma_async_device_unregister(&d->slave);
+
+       sa11x0_dma_free_channels(&d->slave);
+       for (pch = 0; pch < NR_PHY_CHAN; pch++)
+               sa11x0_dma_free_irq(pdev, pch, &d->phy[pch]);
+       tasklet_kill(&d->task);
+       iounmap(d->base);
+       kfree(d);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sa11x0_dma_suspend(struct device *dev)
+{
+       struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
+       unsigned pch;
+
+       for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+               struct sa11x0_dma_phy *p = &d->phy[pch];
+               u32 dcsr, saved_dcsr;
+
+               dcsr = saved_dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+               if (dcsr & DCSR_RUN) {
+                       writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
+                       dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+               }
+
+               saved_dcsr &= DCSR_RUN | DCSR_IE;
+               if (dcsr & DCSR_BIU) {
+                       p->dbs[0] = readl_relaxed(p->base + DMA_DBSB);
+                       p->dbt[0] = readl_relaxed(p->base + DMA_DBTB);
+                       p->dbs[1] = readl_relaxed(p->base + DMA_DBSA);
+                       p->dbt[1] = readl_relaxed(p->base + DMA_DBTA);
+                       saved_dcsr |= (dcsr & DCSR_STRTA ? DCSR_STRTB : 0) |
+                                     (dcsr & DCSR_STRTB ? DCSR_STRTA : 0);
+               } else {
+                       p->dbs[0] = readl_relaxed(p->base + DMA_DBSA);
+                       p->dbt[0] = readl_relaxed(p->base + DMA_DBTA);
+                       p->dbs[1] = readl_relaxed(p->base + DMA_DBSB);
+                       p->dbt[1] = readl_relaxed(p->base + DMA_DBTB);
+                       saved_dcsr |= dcsr & (DCSR_STRTA | DCSR_STRTB);
+               }
+               p->dcsr = saved_dcsr;
+
+               writel(DCSR_STRTA | DCSR_STRTB, p->base + DMA_DCSR_C);
+       }
+
+       return 0;
+}
+
+static int sa11x0_dma_resume(struct device *dev)
+{
+       struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
+       unsigned pch;
+
+       for (pch = 0; pch < NR_PHY_CHAN; pch++) {
+               struct sa11x0_dma_phy *p = &d->phy[pch];
+               struct sa11x0_dma_desc *txd = NULL;
+               u32 dcsr = readl_relaxed(p->base + DMA_DCSR_R);
+
+               WARN_ON(dcsr & (DCSR_BIU | DCSR_STRTA | DCSR_STRTB | DCSR_RUN));
+
+               if (p->txd_done)
+                       txd = p->txd_done;
+               else if (p->txd_load)
+                       txd = p->txd_load;
+
+               if (!txd)
+                       continue;
+
+               writel_relaxed(txd->ddar, p->base + DMA_DDAR);
+
+               writel_relaxed(p->dbs[0], p->base + DMA_DBSA);
+               writel_relaxed(p->dbt[0], p->base + DMA_DBTA);
+               writel_relaxed(p->dbs[1], p->base + DMA_DBSB);
+               writel_relaxed(p->dbt[1], p->base + DMA_DBTB);
+               writel_relaxed(p->dcsr, p->base + DMA_DCSR_S);
+       }
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops sa11x0_dma_pm_ops = {
+       .suspend_noirq = sa11x0_dma_suspend,
+       .resume_noirq = sa11x0_dma_resume,
+       .freeze_noirq = sa11x0_dma_suspend,
+       .thaw_noirq = sa11x0_dma_resume,
+       .poweroff_noirq = sa11x0_dma_suspend,
+       .restore_noirq = sa11x0_dma_resume,
+};
+
+static struct platform_driver sa11x0_dma_driver = {
+       .driver = {
+               .name   = "sa11x0-dma",
+               .owner  = THIS_MODULE,
+               .pm     = &sa11x0_dma_pm_ops,
+       },
+       .probe          = sa11x0_dma_probe,
+       .remove         = __devexit_p(sa11x0_dma_remove),
+};
+
+bool sa11x0_dma_filter_fn(struct dma_chan *chan, void *param)
+{
+       if (chan->device->dev->driver == &sa11x0_dma_driver.driver) {
+               struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+               const char *p = param;
+
+               return !strcmp(c->name, p);
+       }
+       return false;
+}
+EXPORT_SYMBOL(sa11x0_dma_filter_fn);
+
+static int __init sa11x0_dma_init(void)
+{
+       return platform_driver_register(&sa11x0_dma_driver);
+}
+subsys_initcall(sa11x0_dma_init);
+
+static void __exit sa11x0_dma_exit(void)
+{
+       platform_driver_unregister(&sa11x0_dma_driver);
+}
+module_exit(sa11x0_dma_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("SA-11x0 DMA driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sa11x0-dma");
index 5948a21..fdffa1b 100644 (file)
@@ -215,7 +215,7 @@ config EDAC_I7300
 config EDAC_SBRIDGE
        tristate "Intel Sandy-Bridge Integrated MC"
        depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL
-       depends on EXPERIMENTAL
+       depends on PCI_MMCONFIG && EXPERIMENTAL
        help
          Support for error detection and correction the Intel
          Sandy Bridge Integrated Memory Controller.
index c9eee6d..7ef73c9 100644 (file)
@@ -1132,12 +1132,36 @@ static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
                return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
        }
        else if (pvt->ext_model >= K8_REV_D) {
+               unsigned diff;
                WARN_ON(cs_mode > 10);
 
-               if (cs_mode == 3 || cs_mode == 8)
-                       return 32 << (cs_mode - 1);
-               else
-                       return 32 << cs_mode;
+               /*
+                * the below calculation, besides trying to win an obfuscated C
+                * contest, maps cs_mode values to DIMM chip select sizes. The
+                * mappings are:
+                *
+                * cs_mode      CS size (mb)
+                * =======      ============
+                * 0            32
+                * 1            64
+                * 2            128
+                * 3            128
+                * 4            256
+                * 5            512
+                * 6            256
+                * 7            512
+                * 8            1024
+                * 9            1024
+                * 10           2048
+                *
+                * Basically, it calculates a value with which to shift the
+                * smallest CS size of 32MB.
+                *
+                * ddr[23]_cs_size have a similar purpose.
+                */
+               diff = cs_mode/3 + (unsigned)(cs_mode > 5);
+
+               return 32 << (cs_mode - diff);
        }
        else {
                WARN_ON(cs_mode > 6);
@@ -2133,6 +2157,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)
 static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
 {
        u32 cs_mode, nr_pages;
+       u32 dbam = dct ? pvt->dbam1 : pvt->dbam0;
 
        /*
         * The math on this doesn't look right on the surface because x/2*4 can
@@ -2141,16 +2166,10 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
         * number of bits to shift the DBAM register to extract the proper CSROW
         * field.
         */
-       cs_mode = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF;
+       cs_mode =  (dbam >> ((csrow_nr / 2) * 4)) & 0xF;
 
        nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
 
-       /*
-        * If dual channel then double the memory size of single channel.
-        * Channel count is 1 or 2
-        */
-       nr_pages <<= (pvt->channel_count - 1);
-
        debugf0("  (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
        debugf0("    nr_pages= %u  channel-count = %d\n",
                nr_pages, pvt->channel_count);
@@ -2181,7 +2200,7 @@ static int init_csrows(struct mem_ctl_info *mci)
        for_each_chip_select(i, 0, pvt) {
                csrow = &mci->csrows[i];
 
-               if (!csrow_enabled(i, 0, pvt)) {
+               if (!csrow_enabled(i, 0, pvt) && !csrow_enabled(i, 1, pvt)) {
                        debugf1("----CSROW %d EMPTY for node %d\n", i,
                                pvt->mc_node_id);
                        continue;
@@ -2191,7 +2210,10 @@ static int init_csrows(struct mem_ctl_info *mci)
                        i, pvt->mc_node_id);
 
                empty = 0;
-               csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
+               if (csrow_enabled(i, 0, pvt))
+                       csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
+               if (csrow_enabled(i, 1, pvt))
+                       csrow->nr_pages += amd64_csrow_nr_pages(pvt, 1, i);
                find_csrow_limits(mci, i, &input_addr_min, &input_addr_max);
                sys_addr = input_addr_to_sys_addr(mci, input_addr_min);
                csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT);
@@ -2685,7 +2707,7 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
  * PCI core identifies what devices are on a system during boot, and then
  * inquiry this table to see if this driver is for a given device found.
  */
-static const struct pci_device_id amd64_pci_table[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(amd64_pci_table) = {
        {
                .vendor         = PCI_VENDOR_ID_AMD,
                .device         = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
index e47e73b..f8fd3c8 100644 (file)
@@ -321,7 +321,7 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(amd76x_pci_tbl) = {
        {
         PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
         AMD762},
index 1af531a..4122326 100644 (file)
@@ -1380,7 +1380,7 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(e752x_pci_tbl) = {
        {
         PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
         E7520},
index 6ffb6d2..68dea87 100644 (file)
@@ -525,7 +525,7 @@ static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(e7xxx_pci_tbl) = {
        {
         PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
         E7205},
index da09cd7..feef773 100644 (file)
@@ -39,7 +39,7 @@ static LIST_HEAD(mc_devices);
 
 #ifdef CONFIG_EDAC_DEBUG
 
-static void edac_mc_dump_channel(struct channel_info *chan)
+static void edac_mc_dump_channel(struct rank_info *chan)
 {
        debugf4("\tchannel = %p\n", chan);
        debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
@@ -156,7 +156,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
 {
        struct mem_ctl_info *mci;
        struct csrow_info *csi, *csrow;
-       struct channel_info *chi, *chp, *chan;
+       struct rank_info *chi, *chp, *chan;
        void *pvt;
        unsigned size;
        int row, chn;
@@ -181,7 +181,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
         * rather than an imaginary chunk of memory located at address 0.
         */
        csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
-       chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi));
+       chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi));
        pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
 
        /* setup index and various internal pointers */
index d56e634..e9a28f5 100644 (file)
@@ -452,7 +452,7 @@ static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
        int new_bw = 0;
 
        if (!mci->set_sdram_scrub_rate)
-               return -EINVAL;
+               return -ENODEV;
 
        if (strict_strtoul(data, 10, &bandwidth) < 0)
                return -EINVAL;
@@ -475,7 +475,7 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
        int bandwidth = 0;
 
        if (!mci->get_sdram_scrub_rate)
-               return -EINVAL;
+               return -ENODEV;
 
        bandwidth = mci->get_sdram_scrub_rate(mci);
        if (bandwidth < 0) {
index 670c448..6c86f6e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/edac.h>
 #include <linux/atomic.h>
+#include <linux/device.h>
 #include <asm/edac.h>
 
 int edac_op_state = EDAC_OPSTATE_INVAL;
index c0510b3..277689a 100644 (file)
@@ -470,7 +470,7 @@ static void __devexit i3000_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id i3000_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i3000_pci_tbl) = {
        {
         PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
         I3000},
index 73f55e2..046808c 100644 (file)
@@ -445,7 +445,7 @@ static void __devexit i3200_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id i3200_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i3200_pci_tbl) = {
        {
                PCI_VEND_DEV(INTEL, 3200_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                I3200},
index 4dc3ac2..a2680d8 100644 (file)
@@ -1516,7 +1516,7 @@ static void __devexit i5000_remove_one(struct pci_dev *pdev)
  *
  *     The "E500P" device is the first device supported.
  */
-static const struct pci_device_id i5000_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i5000_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I5000_DEV16),
         .driver_data = I5000P},
 
index bcbdeec..d500749 100644 (file)
@@ -49,7 +49,7 @@
 #define                I5100_FERR_NF_MEM_M6ERR_MASK    (1 << 6)
 #define                I5100_FERR_NF_MEM_M5ERR_MASK    (1 << 5)
 #define                I5100_FERR_NF_MEM_M4ERR_MASK    (1 << 4)
-#define                I5100_FERR_NF_MEM_M1ERR_MASK    1
+#define                I5100_FERR_NF_MEM_M1ERR_MASK    (1 << 1)
 #define                I5100_FERR_NF_MEM_ANY_MASK      \
                        (I5100_FERR_NF_MEM_M16ERR_MASK | \
                        I5100_FERR_NF_MEM_M15ERR_MASK | \
@@ -535,23 +535,20 @@ static void i5100_read_log(struct mem_ctl_info *mci, int chan,
 static void i5100_check_error(struct mem_ctl_info *mci)
 {
        struct i5100_priv *priv = mci->pvt_info;
-       u32 dw;
-
+       u32 dw, dw2;
 
        pci_read_config_dword(priv->mc, I5100_FERR_NF_MEM, &dw);
        if (i5100_ferr_nf_mem_any(dw)) {
-               u32 dw2;
 
                pci_read_config_dword(priv->mc, I5100_NERR_NF_MEM, &dw2);
-               if (dw2)
-                       pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM,
-                                              dw2);
-               pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw);
 
                i5100_read_log(mci, i5100_ferr_nf_mem_chan_indx(dw),
                               i5100_ferr_nf_mem_any(dw),
                               i5100_nerr_nf_mem_any(dw2));
+
+               pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM, dw2);
        }
+       pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw);
 }
 
 /* The i5100 chipset will scrub the entire memory once, then
@@ -1051,7 +1048,7 @@ static void __devexit i5100_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id i5100_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i5100_pci_tbl) = {
        /* Device 16, Function 0, Channel 0 Memory Map, Error Flag/Mask, ... */
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5100_16) },
        { 0, }
index 74d6ec3..1869a10 100644 (file)
@@ -735,7 +735,7 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
 
        /* Attempt to 'get' the MCH register we want */
        pdev = NULL;
-       while (!pvt->branchmap_werrors || !pvt->fsb_error_regs) {
+       while (1) {
                pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                      PCI_DEVICE_ID_INTEL_5400_ERR, pdev);
                if (!pdev) {
@@ -743,23 +743,42 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
                        i5400_printk(KERN_ERR,
                                "'system address,Process Bus' "
                                "device not found:"
-                               "vendor 0x%x device 0x%x ERR funcs "
+                               "vendor 0x%x device 0x%x ERR func 1 "
                                "(broken BIOS?)\n",
                                PCI_VENDOR_ID_INTEL,
                                PCI_DEVICE_ID_INTEL_5400_ERR);
-                       goto error;
+                       return -ENODEV;
                }
 
-               /* Store device 16 funcs 1 and 2 */
-               switch (PCI_FUNC(pdev->devfn)) {
-               case 1:
-                       pvt->branchmap_werrors = pdev;
-                       break;
-               case 2:
-                       pvt->fsb_error_regs = pdev;
+               /* Store device 16 func 1 */
+               if (PCI_FUNC(pdev->devfn) == 1)
                        break;
+       }
+       pvt->branchmap_werrors = pdev;
+
+       pdev = NULL;
+       while (1) {
+               pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                     PCI_DEVICE_ID_INTEL_5400_ERR, pdev);
+               if (!pdev) {
+                       /* End of list, leave */
+                       i5400_printk(KERN_ERR,
+                               "'system address,Process Bus' "
+                               "device not found:"
+                               "vendor 0x%x device 0x%x ERR func 2 "
+                               "(broken BIOS?)\n",
+                               PCI_VENDOR_ID_INTEL,
+                               PCI_DEVICE_ID_INTEL_5400_ERR);
+
+                       pci_dev_put(pvt->branchmap_werrors);
+                       return -ENODEV;
                }
+
+               /* Store device 16 func 2 */
+               if (PCI_FUNC(pdev->devfn) == 2)
+                       break;
        }
+       pvt->fsb_error_regs = pdev;
 
        debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
                pci_name(pvt->system_address),
@@ -778,7 +797,10 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
                        "MC: 'BRANCH 0' device not found:"
                        "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
                        PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_FBD0);
-               goto error;
+
+               pci_dev_put(pvt->fsb_error_regs);
+               pci_dev_put(pvt->branchmap_werrors);
+               return -ENODEV;
        }
 
        /* If this device claims to have more than 2 channels then
@@ -796,14 +818,14 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
                        "(broken BIOS?)\n",
                        PCI_VENDOR_ID_INTEL,
                        PCI_DEVICE_ID_INTEL_5400_FBD1);
-               goto error;
+
+               pci_dev_put(pvt->branch_0);
+               pci_dev_put(pvt->fsb_error_regs);
+               pci_dev_put(pvt->branchmap_werrors);
+               return -ENODEV;
        }
 
        return 0;
-
-error:
-       i5400_put_devices(mci);
-       return -ENODEV;
 }
 
 /*
@@ -1383,7 +1405,7 @@ static void __devexit i5400_remove_one(struct pci_dev *pdev)
  *
  *     The "E500P" device is the first device supported.
  */
-static const struct pci_device_id i5400_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i5400_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR)},
        {0,}                    /* 0 terminated list. */
 };
index 6104dba..3bafa3b 100644 (file)
@@ -1192,7 +1192,7 @@ static void __devexit i7300_remove_one(struct pci_dev *pdev)
  *
  * Has only 8086:360c PCI ID
  */
-static const struct pci_device_id i7300_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i7300_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)},
        {0,}                    /* 0 terminated list. */
 };
index 8568d9b..85226cc 100644 (file)
@@ -391,7 +391,7 @@ static const struct pci_id_table pci_dev_table[] = {
 /*
  *     pci_device_id   table for which devices we are looking for
  */
-static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i7core_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0)},
        {0,}                    /* 0 terminated list. */
index 4329d39..3bf2b2f 100644 (file)
@@ -380,7 +380,7 @@ static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
 
 EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
 
-static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i82443bxgx_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)},
index 931a057..c779092 100644 (file)
@@ -270,7 +270,7 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i82860_pci_tbl) = {
        {
         PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
         I82860},
index 33864c6..10f15d8 100644 (file)
@@ -511,7 +511,7 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i82875p_pci_tbl) = {
        {
         PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
         I82875P},
index 4184e01..0cd8368 100644 (file)
@@ -612,7 +612,7 @@ static void __devexit i82975x_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id i82975x_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(i82975x_pci_tbl) = {
        {
                PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                I82975X
index bd926ea..36e1486 100644 (file)
@@ -39,42 +39,31 @@ EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder);
  */
 
 /* transaction type */
-const char *tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
+const char * const tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
 EXPORT_SYMBOL_GPL(tt_msgs);
 
 /* cache level */
-const char *ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
+const char * const ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
 EXPORT_SYMBOL_GPL(ll_msgs);
 
 /* memory transaction type */
-const char *rrrr_msgs[] = {
+const char * const rrrr_msgs[] = {
        "GEN", "RD", "WR", "DRD", "DWR", "IRD", "PRF", "EV", "SNP"
 };
 EXPORT_SYMBOL_GPL(rrrr_msgs);
 
 /* participating processor */
-const char *pp_msgs[] = { "SRC", "RES", "OBS", "GEN" };
+const char * const pp_msgs[] = { "SRC", "RES", "OBS", "GEN" };
 EXPORT_SYMBOL_GPL(pp_msgs);
 
 /* request timeout */
-const char *to_msgs[] = { "no timeout",        "timed out" };
+const char * const to_msgs[] = { "no timeout", "timed out" };
 EXPORT_SYMBOL_GPL(to_msgs);
 
 /* memory or i/o */
-const char *ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
+const char * const ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
 EXPORT_SYMBOL_GPL(ii_msgs);
 
-static const char *f10h_nb_mce_desc[] = {
-       "HT link data error",
-       "Protocol error (link, L3, probe filter, etc.)",
-       "Parity error in NB-internal arrays",
-       "Link Retry due to IO link transmission error",
-       "L3 ECC data cache error",
-       "ECC error in L3 cache tag",
-       "L3 LRU parity bits error",
-       "ECC Error in the Probe Filter directory"
-};
-
 static const char * const f15h_ic_mce_desc[] = {
        "UC during a demand linefill from L2",
        "Parity error during data load from IC",
@@ -88,7 +77,7 @@ static const char * const f15h_ic_mce_desc[] = {
        "Parity error for IC probe tag valid bit",
        "PFB non-cacheable bit parity error",
        "PFB valid bit parity error",                   /* xec = 0xd */
-       "patch RAM",                                    /* xec = 010 */
+       "Microcode Patch Buffer",                       /* xec = 010 */
        "uop queue",
        "insn buffer",
        "predecode buffer",
@@ -104,7 +93,7 @@ static const char * const f15h_cu_mce_desc[] = {
        "WCC Tag ECC error",
        "WCC Data ECC error",
        "WCB Data parity error",
-       "VB Data/ECC error",
+       "VB Data ECC or parity error",
        "L2 Tag ECC error",                             /* xec = 0x10 */
        "Hard L2 Tag ECC error",
        "Multiple hits on L2 tag",
@@ -112,6 +101,28 @@ static const char * const f15h_cu_mce_desc[] = {
        "PRB address parity error"
 };
 
+static const char * const nb_mce_desc[] = {
+       "DRAM ECC error detected on the NB",
+       "CRC error detected on HT link",
+       "Link-defined sync error packets detected on HT link",
+       "HT Master abort",
+       "HT Target abort",
+       "Invalid GART PTE entry during GART table walk",
+       "Unsupported atomic RMW received from an IO link",
+       "Watchdog timeout due to lack of progress",
+       "DRAM ECC error detected on the NB",
+       "SVM DMA Exclusion Vector error",
+       "HT data error detected on link",
+       "Protocol error (link, L3, probe filter)",
+       "NB internal arrays parity error",
+       "DRAM addr/ctl signals parity error",
+       "IO link transmission error",
+       "L3 data cache ECC error",                      /* xec = 0x1c */
+       "L3 cache tag error",
+       "L3 LRU parity bits error",
+       "ECC Error in the Probe Filter directory"
+};
+
 static const char * const fr_ex_mce_desc[] = {
        "CPU Watchdog timer expire",
        "Wakeup array dest tag",
@@ -125,7 +136,7 @@ static const char * const fr_ex_mce_desc[] = {
        "Physical register file AG0 port",
        "Physical register file AG1 port",
        "Flag register file",
-       "DE correctable error could not be corrected"
+       "DE error occurred"
 };
 
 static bool f12h_dc_mce(u16 ec, u8 xec)
@@ -255,10 +266,9 @@ static bool f15h_dc_mce(u16 ec, u8 xec)
        } else if (BUS_ERROR(ec)) {
 
                if (!xec)
-                       pr_cont("during system linefill.\n");
+                       pr_cont("System Read Data Error.\n");
                else
-                       pr_cont(" Internal %s condition.\n",
-                               ((xec == 1) ? "livelock" : "deadlock"));
+                       pr_cont(" Internal error condition type %d.\n", xec);
        } else
                ret = false;
 
@@ -355,7 +365,11 @@ static bool f15h_ic_mce(u16 ec, u8 xec)
                pr_cont("%s.\n", f15h_ic_mce_desc[xec-2]);
                break;
 
-       case 0x10 ... 0x14:
+       case 0x10:
+               pr_cont("%s.\n", f15h_ic_mce_desc[xec-4]);
+               break;
+
+       case 0x11 ... 0x14:
                pr_cont("Decoder %s parity error.\n", f15h_ic_mce_desc[xec-4]);
                break;
 
@@ -496,58 +510,31 @@ wrong_ls_mce:
        pr_emerg(HW_ERR "Corrupted LS MCE info?\n");
 }
 
-static bool k8_nb_mce(u16 ec, u8 xec)
+void amd_decode_nb_mce(struct mce *m)
 {
-       bool ret = true;
-
-       switch (xec) {
-       case 0x1:
-               pr_cont("CRC error detected on HT link.\n");
-               break;
-
-       case 0x5:
-               pr_cont("Invalid GART PTE entry during GART table walk.\n");
-               break;
-
-       case 0x6:
-               pr_cont("Unsupported atomic RMW received from an IO link.\n");
-               break;
-
-       case 0x0:
-       case 0x8:
-               if (boot_cpu_data.x86 == 0x11)
-                       return false;
-
-               pr_cont("DRAM ECC error detected on the NB.\n");
-               break;
-
-       case 0xd:
-               pr_cont("Parity error on the DRAM addr/ctl signals.\n");
-               break;
-
-       default:
-               ret = false;
-               break;
-       }
+       struct cpuinfo_x86 *c = &boot_cpu_data;
+       int node_id = amd_get_nb_id(m->extcpu);
+       u16 ec = EC(m->status);
+       u8 xec = XEC(m->status, 0x1f);
+       u8 offset = 0;
 
-       return ret;
-}
+       pr_emerg(HW_ERR "Northbridge Error (node %d): ", node_id);
 
-static bool f10h_nb_mce(u16 ec, u8 xec)
-{
-       bool ret = true;
-       u8 offset = 0;
+       switch (xec) {
+       case 0x0 ... 0xe:
 
-       if (k8_nb_mce(ec, xec))
-               return true;
+               /* special handling for DRAM ECCs */
+               if (xec == 0x0 || xec == 0x8) {
+                       /* no ECCs on F11h */
+                       if (c->x86 == 0x11)
+                               goto wrong_nb_mce;
 
-       switch(xec) {
-       case 0xa ... 0xc:
-               offset = 10;
-               break;
+                       pr_cont("%s.\n", nb_mce_desc[xec]);
 
-       case 0xe:
-               offset = 11;
+                       if (nb_bus_decoder)
+                               nb_bus_decoder(node_id, m);
+                       return;
+               }
                break;
 
        case 0xf:
@@ -556,83 +543,25 @@ static bool f10h_nb_mce(u16 ec, u8 xec)
                else if (BUS_ERROR(ec))
                        pr_cont("DMA Exclusion Vector Table Walk error.\n");
                else
-                       ret = false;
-
-               goto out;
-               break;
+                       goto wrong_nb_mce;
+               return;
 
        case 0x19:
                if (boot_cpu_data.x86 == 0x15)
                        pr_cont("Compute Unit Data Error.\n");
                else
-                       ret = false;
-
-               goto out;
-               break;
+                       goto wrong_nb_mce;
+               return;
 
        case 0x1c ... 0x1f:
-               offset = 24;
+               offset = 13;
                break;
 
        default:
-               ret = false;
-
-               goto out;
-               break;
-       }
-
-       pr_cont("%s.\n", f10h_nb_mce_desc[xec - offset]);
-
-out:
-       return ret;
-}
-
-static bool nb_noop_mce(u16 ec, u8 xec)
-{
-       return false;
-}
-
-void amd_decode_nb_mce(struct mce *m)
-{
-       struct cpuinfo_x86 *c = &boot_cpu_data;
-       int node_id = amd_get_nb_id(m->extcpu);
-       u16 ec = EC(m->status);
-       u8 xec = XEC(m->status, 0x1f);
-
-       pr_emerg(HW_ERR "Northbridge Error (node %d): ", node_id);
-
-       switch (xec) {
-       case 0x2:
-               pr_cont("Sync error (sync packets on HT link detected).\n");
-               return;
-
-       case 0x3:
-               pr_cont("HT Master abort.\n");
-               return;
-
-       case 0x4:
-               pr_cont("HT Target abort.\n");
-               return;
-
-       case 0x7:
-               pr_cont("NB Watchdog timeout.\n");
-               return;
-
-       case 0x9:
-               pr_cont("SVM DMA Exclusion Vector error.\n");
-               return;
-
-       default:
-               break;
-       }
-
-       if (!fam_ops->nb_mce(ec, xec))
                goto wrong_nb_mce;
+       }
 
-       if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x15)
-               if ((xec == 0x8 || xec == 0x0) && nb_bus_decoder)
-                       nb_bus_decoder(node_id, m);
-
+       pr_cont("%s.\n", nb_mce_desc[xec - offset]);
        return;
 
 wrong_nb_mce:
@@ -648,9 +577,6 @@ static void amd_decode_fr_mce(struct mce *m)
        if (c->x86 == 0xf || c->x86 == 0x11)
                goto wrong_fr_mce;
 
-       if (c->x86 != 0x15 && xec != 0x0)
-               goto wrong_fr_mce;
-
        pr_emerg(HW_ERR "%s Error: ",
                 (c->x86 == 0x15 ? "Execution Unit" : "FIROB"));
 
@@ -841,39 +767,33 @@ static int __init mce_amd_init(void)
        case 0xf:
                fam_ops->dc_mce = k8_dc_mce;
                fam_ops->ic_mce = k8_ic_mce;
-               fam_ops->nb_mce = k8_nb_mce;
                break;
 
        case 0x10:
                fam_ops->dc_mce = f10h_dc_mce;
                fam_ops->ic_mce = k8_ic_mce;
-               fam_ops->nb_mce = f10h_nb_mce;
                break;
 
        case 0x11:
                fam_ops->dc_mce = k8_dc_mce;
                fam_ops->ic_mce = k8_ic_mce;
-               fam_ops->nb_mce = f10h_nb_mce;
                break;
 
        case 0x12:
                fam_ops->dc_mce = f12h_dc_mce;
                fam_ops->ic_mce = k8_ic_mce;
-               fam_ops->nb_mce = nb_noop_mce;
                break;
 
        case 0x14:
                nb_err_cpumask  = 0x3;
                fam_ops->dc_mce = f14h_dc_mce;
                fam_ops->ic_mce = f14h_ic_mce;
-               fam_ops->nb_mce = nb_noop_mce;
                break;
 
        case 0x15:
                xec_mask = 0x1f;
                fam_ops->dc_mce = f15h_dc_mce;
                fam_ops->ic_mce = f15h_ic_mce;
-               fam_ops->nb_mce = f10h_nb_mce;
                break;
 
        default:
index 0106747..c6074c5 100644 (file)
@@ -69,12 +69,12 @@ enum rrrr_ids {
        R4_SNOOP,
 };
 
-extern const char *tt_msgs[];
-extern const char *ll_msgs[];
-extern const char *rrrr_msgs[];
-extern const char *pp_msgs[];
-extern const char *to_msgs[];
-extern const char *ii_msgs[];
+extern const char * const tt_msgs[];
+extern const char * const ll_msgs[];
+extern const char * const rrrr_msgs[];
+extern const char * const pp_msgs[];
+extern const char * const to_msgs[];
+extern const char * const ii_msgs[];
 
 /*
  * per-family decoder ops
@@ -82,7 +82,6 @@ extern const char *ii_msgs[];
 struct amd_decoder_ops {
        bool (*dc_mce)(u16, u8);
        bool (*ic_mce)(u16, u8);
-       bool (*nb_mce)(u16, u8);
 };
 
 void amd_report_gart_errors(bool);
index 885e8ad..66b5151 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/kobject.h>
+#include <linux/device.h>
 #include <linux/edac.h>
 #include <linux/module.h>
 #include <asm/mce.h>
index fc75706..d427c69 100644 (file)
@@ -184,7 +184,7 @@ struct ppc4xx_ecc_status {
 
 /* Function Prototypes */
 
-static int ppc4xx_edac_probe(struct platform_device *device)
+static int ppc4xx_edac_probe(struct platform_device *device);
 static int ppc4xx_edac_remove(struct platform_device *device);
 
 /* Global Variables */
@@ -1068,7 +1068,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
 
        mci->mod_name           = PPC4XX_EDAC_MODULE_NAME;
        mci->mod_ver            = PPC4XX_EDAC_MODULE_REVISION;
-       mci->ctl_name           = match->compatible,
+       mci->ctl_name           = ppc4xx_edac_match->compatible,
        mci->dev_name           = np->full_name;
 
        /* Initialize callbacks */
index e294e1b..6d908ad 100644 (file)
@@ -373,7 +373,7 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id r82600_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(r82600_pci_tbl) = {
        {
         PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
         },
index 1dc118d..a203536 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mmzone.h>
 #include <linux/smp.h>
 #include <linux/bitmap.h>
+#include <linux/math64.h>
 #include <asm/processor.h>
 #include <asm/mce.h>
 
@@ -367,7 +368,7 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = {
 /*
  *     pci_device_id   table for which devices we are looking for
  */
-static const struct pci_device_id sbridge_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)},
        {0,}                    /* 0 terminated list. */
 };
@@ -670,6 +671,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
        u32 reg;
        u64 limit, prv = 0;
        u64 tmp_mb;
+       u32 mb, kb;
        u32 rir_way;
 
        /*
@@ -682,8 +684,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
        pvt->tolm = GET_TOLM(reg);
        tmp_mb = (1 + pvt->tolm) >> 20;
 
-       debugf0("TOLM: %Lu.%03Lu GB (0x%016Lx)\n",
-               tmp_mb / 1000, tmp_mb % 1000, (u64)pvt->tolm);
+       mb = div_u64_rem(tmp_mb, 1000, &kb);
+       debugf0("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,
@@ -691,8 +694,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
        pvt->tohm = GET_TOHM(reg);
        tmp_mb = (1 + pvt->tohm) >> 20;
 
-       debugf0("TOHM: %Lu.%03Lu GB (0x%016Lx)",
-               tmp_mb / 1000, tmp_mb % 1000, (u64)pvt->tohm);
+       mb = div_u64_rem(tmp_mb, 1000, &kb);
+       debugf0("TOHM: %u.%03u GB (0x%016Lx)",
+               mb, kb, (u64)pvt->tohm);
 
        /*
         * Step 2) Get SAD range and SAD Interleave list
@@ -714,10 +718,11 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                        break;
 
                tmp_mb = (limit + 1) >> 20;
-               debugf0("SAD#%d %s up to %Lu.%03Lu GB (0x%016Lx) %s reg=0x%08x\n",
+               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),
-                       tmp_mb / 1000, tmp_mb % 1000,
+                       mb, kb,
                        ((u64)tmp_mb) << 20L,
                        INTERLEAVE_MODE(reg) ? "Interleave: 8:6" : "Interleave: [8:6]XOR[18:16]",
                        reg);
@@ -747,8 +752,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                        break;
                tmp_mb = (limit + 1) >> 20;
 
-               debugf0("TAD#%d: up to %Lu.%03Lu GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
-                       n_tads, tmp_mb / 1000, tmp_mb % 1000,
+               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),
@@ -757,7 +763,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                        (u32)TAD_TGT2(reg),
                        (u32)TAD_TGT3(reg),
                        reg);
-               prv = tmp_mb;
+               prv = limit;
        }
 
        /*
@@ -771,9 +777,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                                              tad_ch_nilv_offset[j],
                                              &reg);
                        tmp_mb = TAD_OFFSET(reg) >> 20;
-                       debugf0("TAD CH#%d, offset #%d: %Lu.%03Lu GB (0x%016Lx), reg=0x%08x\n",
+                       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,
-                               tmp_mb / 1000, tmp_mb % 1000,
+                               mb, kb,
                                ((u64)tmp_mb) << 20L,
                                reg);
                }
@@ -795,9 +802,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
 
                        tmp_mb = RIR_LIMIT(reg) >> 20;
                        rir_way = 1 << RIR_WAY(reg);
-                       debugf0("CH#%d RIR#%d, limit: %Lu.%03Lu GB (0x%016Lx), way: %d, reg=0x%08x\n",
+                       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,
-                               tmp_mb / 1000, tmp_mb % 1000,
+                               mb, kb,
                                ((u64)tmp_mb) << 20L,
                                rir_way,
                                reg);
@@ -808,9 +816,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                                                      &reg);
                                tmp_mb = RIR_OFFSET(reg) << 6;
 
-                               debugf0("CH#%d RIR#%d INTL#%d, offset %Lu.%03Lu GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
+                               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,
-                                       tmp_mb / 1000, tmp_mb % 1000,
+                                       mb, kb,
                                        ((u64)tmp_mb) << 20L,
                                        (u32)RIR_RNK_TGT(reg),
                                        reg);
@@ -848,6 +857,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
        u8                      ch_way,sck_way;
        u32                     tad_offset;
        u32                     rir_way;
+       u32                     mb, kb;
        u64                     ch_addr, offset, limit, prv = 0;
 
 
@@ -858,7 +868,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
         * range (e. g. VGA addresses). It is unlikely, however, that the
         * memory controller would generate an error on that range.
         */
-       if ((addr > (u64) pvt->tolm) && (addr < (1L << 32))) {
+       if ((addr > (u64) pvt->tolm) && (addr < (1LL << 32))) {
                sprintf(msg, "Error at TOLM area, on addr 0x%08Lx", addr);
                edac_mc_handle_ce_no_info(mci, msg);
                return -EINVAL;
@@ -913,7 +923,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                addr,
                limit,
                sad_way + 7,
-               INTERLEAVE_MODE(reg) ? "" : "XOR[18:16]");
+               interleave_mode ? "" : "XOR[18:16]");
        if (interleave_mode)
                idx = ((addr >> 6) ^ (addr >> 16)) & 7;
        else
@@ -1053,7 +1063,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
        ch_addr = addr & 0x7f;
        /* Remove socket wayness and remove 6 bits */
        addr >>= 6;
-       addr /= sck_xch;
+       addr = div_u64(addr, sck_xch);
 #if 0
        /* Divide by channel way */
        addr = addr / ch_way;
@@ -1073,10 +1083,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                        continue;
 
                limit = RIR_LIMIT(reg);
-
-               debugf0("RIR#%d, limit: %Lu.%03Lu GB (0x%016Lx), way: %d\n",
+               mb = div_u64_rem(limit >> 20, 1000, &kb);
+               debugf0("RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
                        n_rir,
-                       (limit >> 20) / 1000, (limit >> 20) % 1000,
+                       mb, kb,
                        limit,
                        1 << RIR_WAY(reg));
                if  (ch_addr <= limit)
index b6f47de..a438297 100644 (file)
@@ -440,7 +440,7 @@ static void __devexit x38_remove_one(struct pci_dev *pdev)
        edac_mc_free(mci);
 }
 
-static const struct pci_device_id x38_pci_tbl[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(x38_pci_tbl) = {
        {
         PCI_VEND_DEV(INTEL, X38_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
         X38},
index 0409cf3..edadbda 100644 (file)
@@ -236,6 +236,12 @@ config GPIO_MAX732X_IRQ
          Say yes here to enable the max732x to be used as an interrupt
          controller. It requires the driver to be built in the kernel.
 
+config GPIO_MC9S08DZ60
+       bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions"
+       depends on I2C && MACH_MX35_3DS
+       help
+         Select this to enable the MC9S08DZ60 GPIO driver
+
 config GPIO_PCA953X
        tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports"
        depends on I2C
@@ -422,6 +428,14 @@ config GPIO_ML_IOH
          Hub) which is for IVI(In-Vehicle Infotainment) use.
          This driver can access the IOH's GPIO device.
 
+config GPIO_SODAVILLE
+       bool "Intel Sodaville GPIO support"
+       depends on X86 && PCI && OF && BROKEN
+       select GPIO_GENERIC
+       select GENERIC_IRQ_CHIP
+       help
+         Say Y here to support Intel Sodaville GPIO.
+
 config GPIO_TIMBERDALE
        bool "Support for timberdale GPIO IP"
        depends on MFD_TIMBERDALE && HAS_IOMEM
index 9a8fb54..007f54b 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_GPIO_MAX7300)    += gpio-max7300.o
 obj-$(CONFIG_GPIO_MAX7301)     += gpio-max7301.o
 obj-$(CONFIG_GPIO_MAX732X)     += gpio-max732x.o
 obj-$(CONFIG_GPIO_MC33880)     += gpio-mc33880.o
+obj-$(CONFIG_GPIO_MC9S08DZ60)  += gpio-mc9s08dz60.o
 obj-$(CONFIG_GPIO_MCP23S08)    += gpio-mcp23s08.o
 obj-$(CONFIG_GPIO_ML_IOH)      += gpio-ml-ioh.o
 obj-$(CONFIG_GPIO_MPC5200)     += gpio-mpc5200.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_GPIO_RDC321X)    += gpio-rdc321x.o
 obj-$(CONFIG_PLAT_SAMSUNG)     += gpio-samsung.o
 obj-$(CONFIG_ARCH_SA1100)      += gpio-sa1100.o
 obj-$(CONFIG_GPIO_SCH)         += gpio-sch.o
+obj-$(CONFIG_GPIO_SODAVILLE)   += gpio-sodaville.o
 obj-$(CONFIG_GPIO_STMPE)       += gpio-stmpe.o
 obj-$(CONFIG_GPIO_SX150X)      += gpio-sx150x.o
 obj-$(CONFIG_GPIO_TC3589X)     += gpio-tc3589x.o
index df0d595..3d00016 100644 (file)
@@ -313,10 +313,16 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
                return -ENODEV;
 }
 
-static int gpio_irq_type_unbanked(struct irq_data *d, unsigned trigger)
+static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
 {
-       struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
-       u32 mask = (u32) irq_data_get_irq_handler_data(d);
+       struct davinci_gpio_controller *d;
+       struct davinci_gpio_regs __iomem *g;
+       struct davinci_soc_info *soc_info = &davinci_soc_info;
+       u32 mask;
+
+       d = (struct davinci_gpio_controller *)data->handler_data;
+       g = (struct davinci_gpio_regs __iomem *)d->regs;
+       mask = __gpio_mask(data->irq - soc_info->gpio_irq);
 
        if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
                return -EINVAL;
@@ -380,7 +386,7 @@ static int __init davinci_gpio_irq_setup(void)
         * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
         */
        if (soc_info->gpio_unbanked) {
-               static struct irq_chip gpio_irqchip_unbanked;
+               static struct irq_chip_type gpio_unbanked;
 
                /* pass "bank 0" GPIO IRQs to AINTC */
                chips[0].chip.to_irq = gpio_to_irq_unbanked;
@@ -388,9 +394,10 @@ static int __init davinci_gpio_irq_setup(void)
 
                /* AINTC handles mask/unmask; GPIO handles triggering */
                irq = bank_irq;
-               gpio_irqchip_unbanked = *irq_get_chip(irq);
-               gpio_irqchip_unbanked.name = "GPIO-AINTC";
-               gpio_irqchip_unbanked.irq_set_type = gpio_irq_type_unbanked;
+               gpio_unbanked = *container_of(irq_get_chip(irq),
+                                             struct irq_chip_type, chip);
+               gpio_unbanked.chip.name = "GPIO-AINTC";
+               gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked;
 
                /* default trigger: both edges */
                g = gpio2regs(0);
@@ -399,9 +406,8 @@ static int __init davinci_gpio_irq_setup(void)
 
                /* set the direct IRQs up to use that irqchip */
                for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) {
-                       irq_set_chip(irq, &gpio_irqchip_unbanked);
-                       irq_set_handler_data(irq, (void *)__gpio_mask(gpio));
-                       irq_set_chip_data(irq, (__force void *)g);
+                       irq_set_chip(irq, &gpio_unbanked.chip);
+                       irq_set_handler_data(irq, &chips[gpio / 32]);
                        irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
                }
 
index 1c0fc37..776b772 100644 (file)
@@ -12,8 +12,6 @@
  *  published by the Free Software Foundation.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -65,11 +63,6 @@ static void ep93xx_gpio_update_int_params(unsigned port)
                EP93XX_GPIO_REG(int_en_register_offset[port]));
 }
 
-static inline void ep93xx_gpio_int_mask(unsigned line)
-{
-       gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
-}
-
 static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
 {
        int line = irq_to_gpio(irq);
@@ -212,7 +205,6 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
                handler = handle_edge_irq;
                break;
        default:
-               pr_err("failed to set irq type %d for gpio %d\n", type, gpio);
                return -EINVAL;
        }
 
@@ -378,13 +370,6 @@ static int __devinit ep93xx_gpio_probe(struct platform_device *pdev)
        }
        ep93xx_gpio->mmio_base = mmio;
 
-       /* Default all ports to GPIO */
-       ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS |
-                              EP93XX_SYSCON_DEVCFG_GONK |
-                              EP93XX_SYSCON_DEVCFG_EONIDE |
-                              EP93XX_SYSCON_DEVCFG_GONIDE |
-                              EP93XX_SYSCON_DEVCFG_HONIDE);
-
        for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
                struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i];
                struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
index ddfacc5..61c2d08 100644 (file)
 #define GPO3_PIN_TO_BIT(x)                     (1 << (x))
 #define GPIO012_PIN_IN_SEL(x, y)               (((x) >> (y)) & 1)
 #define GPIO3_PIN_IN_SHIFT(x)                  ((x) == 5 ? 24 : 10 + (x))
-#define GPIO3_PIN_IN_SEL(x, y)                 ((x) >> GPIO3_PIN_IN_SHIFT(y))
+#define GPIO3_PIN_IN_SEL(x, y)                 (((x) >> GPIO3_PIN_IN_SHIFT(y)) & 1)
 #define GPIO3_PIN5_IN_SEL(x)                   (((x) >> 24) & 1)
 #define GPI3_PIN_IN_SEL(x, y)                  (((x) >> (y)) & 1)
+#define GPO3_PIN_IN_SEL(x, y)                  (((x) >> (y)) & 1)
 
 struct gpio_regs {
        void __iomem *inp_state;
+       void __iomem *outp_state;
        void __iomem *outp_set;
        void __iomem *outp_clr;
        void __iomem *dir_set;
@@ -145,6 +147,7 @@ static struct gpio_regs gpio_grp_regs_p2 = {
 
 static struct gpio_regs gpio_grp_regs_p3 = {
        .inp_state      = LPC32XX_GPIO_P3_INP_STATE,
+       .outp_state     = LPC32XX_GPIO_P3_OUTP_STATE,
        .outp_set       = LPC32XX_GPIO_P3_OUTP_SET,
        .outp_clr       = LPC32XX_GPIO_P3_OUTP_CLR,
        .dir_set        = LPC32XX_GPIO_P2_DIR_SET,
@@ -240,6 +243,12 @@ static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group,
        return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin);
 }
 
+static int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group,
+       unsigned pin)
+{
+       return GPO3_PIN_IN_SEL(__raw_readl(group->gpio_grp->outp_state), pin);
+}
+
 /*
  * GENERIC_GPIO primitives.
  */
@@ -340,6 +349,13 @@ static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin,
        __set_gpo_level_p3(group, pin, value);
 }
 
+static int lpc32xx_gpo_get_value(struct gpio_chip *chip, unsigned pin)
+{
+       struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+       return __get_gpo_state_p3(group, pin);
+}
+
 static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
 {
        if (pin < chip->ngpio)
@@ -427,6 +443,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
                        .label                  = "gpo_p3",
                        .direction_output       = lpc32xx_gpio_dir_out_always,
                        .set                    = lpc32xx_gpo_set_value,
+                       .get                    = lpc32xx_gpo_get_value,
                        .request                = lpc32xx_gpio_request,
                        .base                   = LPC32XX_GPO_P3_GRP,
                        .ngpio                  = LPC32XX_GPO_P3_MAX,
diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c
new file mode 100644 (file)
index 0000000..2738cc4
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2009-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Author: Wu Guoxing <b39297@freescale.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+
+#define GPIO_GROUP_NUM 2
+#define GPIO_NUM_PER_GROUP 8
+#define GPIO_NUM (GPIO_GROUP_NUM*GPIO_NUM_PER_GROUP)
+
+struct mc9s08dz60 {
+       struct i2c_client *client;
+       struct gpio_chip chip;
+};
+
+static inline struct mc9s08dz60 *to_mc9s08dz60(struct gpio_chip *gc)
+{
+       return container_of(gc, struct mc9s08dz60, chip);
+}
+
+
+static void mc9s_gpio_to_reg_and_bit(int offset, u8 *reg, u8 *bit)
+{
+       *reg = 0x20 + offset / GPIO_NUM_PER_GROUP;
+       *bit = offset % GPIO_NUM_PER_GROUP;
+}
+
+static int mc9s08dz60_get_value(struct gpio_chip *gc, unsigned offset)
+{
+       u8 reg, bit;
+       s32 value;
+       struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+       mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
+       value = i2c_smbus_read_byte_data(mc9s->client, reg);
+
+       return (value >= 0) ? (value >> bit) & 0x1 : 0;
+}
+
+static int mc9s08dz60_set(struct mc9s08dz60 *mc9s, unsigned offset, int val)
+{
+       u8 reg, bit;
+       s32 value;
+
+       mc9s_gpio_to_reg_and_bit(offset, &reg, &bit);
+       value = i2c_smbus_read_byte_data(mc9s->client, reg);
+       if (value >= 0) {
+               if (val)
+                       value |= 1 << bit;
+               else
+                       value &= ~(1 << bit);
+
+               return i2c_smbus_write_byte_data(mc9s->client, reg, value);
+       } else
+               return value;
+
+}
+
+
+static void mc9s08dz60_set_value(struct gpio_chip *gc, unsigned offset, int val)
+{
+       struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+       mc9s08dz60_set(mc9s, offset, val);
+}
+
+static int mc9s08dz60_direction_output(struct gpio_chip *gc,
+                                      unsigned offset, int val)
+{
+       struct mc9s08dz60 *mc9s = to_mc9s08dz60(gc);
+
+       return mc9s08dz60_set(mc9s, offset, val);
+}
+
+static int mc9s08dz60_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       int ret = 0;
+       struct mc9s08dz60 *mc9s;
+
+       mc9s = kzalloc(sizeof(*mc9s), GFP_KERNEL);
+       if (!mc9s)
+               return -ENOMEM;
+
+       mc9s->chip.label = client->name;
+       mc9s->chip.base = -1;
+       mc9s->chip.dev = &client->dev;
+       mc9s->chip.owner = THIS_MODULE;
+       mc9s->chip.ngpio = GPIO_NUM;
+       mc9s->chip.can_sleep = 1;
+       mc9s->chip.get = mc9s08dz60_get_value;
+       mc9s->chip.set = mc9s08dz60_set_value;
+       mc9s->chip.direction_output = mc9s08dz60_direction_output;
+       mc9s->client = client;
+       i2c_set_clientdata(client, mc9s);
+
+       ret = gpiochip_add(&mc9s->chip);
+       if (ret)
+               goto error;
+
+       return 0;
+
+ error:
+       kfree(mc9s);
+       return ret;
+}
+
+static int mc9s08dz60_remove(struct i2c_client *client)
+{
+       struct mc9s08dz60 *mc9s;
+       int ret;
+
+       mc9s = i2c_get_clientdata(client);
+
+       ret = gpiochip_remove(&mc9s->chip);
+       if (!ret)
+               kfree(mc9s);
+
+       return ret;
+
+}
+
+static const struct i2c_device_id mc9s08dz60_id[] = {
+       {"mc9s08dz60", 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, mc9s08dz60_id);
+
+static struct i2c_driver mc9s08dz60_i2c_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "mc9s08dz60",
+       },
+       .probe = mc9s08dz60_probe,
+       .remove = mc9s08dz60_remove,
+       .id_table = mc9s08dz60_id,
+};
+
+module_i2c_driver(mc9s08dz60_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc. "
+               "Wu Guoxing <b39297@freescale.com>");
+MODULE_DESCRIPTION("mc9s08dz60 gpio function on mx35 3ds board");
+MODULE_LICENSE("GPL v2");
index 0b05629..1adc2ec 100644 (file)
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/slab.h>
+#include <linux/device.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/irqdomain.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/gpio.h>
 #include <asm/mach/irq.h>
 
+#define OFF_MODE       1
+
+static LIST_HEAD(omap_gpio_list);
+
+struct gpio_regs {
+       u32 irqenable1;
+       u32 irqenable2;
+       u32 wake_en;
+       u32 ctrl;
+       u32 oe;
+       u32 leveldetect0;
+       u32 leveldetect1;
+       u32 risingdetect;
+       u32 fallingdetect;
+       u32 dataout;
+       u32 debounce;
+       u32 debounce_en;
+};
+
 struct gpio_bank {
-       unsigned long pbase;
+       struct list_head node;
        void __iomem *base;
        u16 irq;
-       u16 virtual_irq_start;
-       int method;
+       int irq_base;
+       struct irq_domain *domain;
        u32 suspend_wakeup;
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
        u32 saved_wakeup;
-#endif
        u32 non_wakeup_gpios;
        u32 enabled_non_wakeup_gpios;
-
+       struct gpio_regs context;
        u32 saved_datain;
        u32 saved_fallingdetect;
        u32 saved_risingdetect;
@@ -51,44 +72,31 @@ struct gpio_bank {
        struct clk *dbck;
        u32 mod_usage;
        u32 dbck_enable_mask;
+       bool dbck_enabled;
        struct device *dev;
+       bool is_mpuio;
        bool dbck_flag;
+       bool loses_context;
        int stride;
        u32 width;
+       int context_loss_count;
+       int power_mode;
+       bool workaround_enabled;
 
        void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable);
+       int (*get_context_loss_count)(struct device *dev);
 
        struct omap_gpio_reg_offs *regs;
 };
 
-#ifdef CONFIG_ARCH_OMAP3
-struct omap3_gpio_regs {
-       u32 irqenable1;
-       u32 irqenable2;
-       u32 wake_en;
-       u32 ctrl;
-       u32 oe;
-       u32 leveldetect0;
-       u32 leveldetect1;
-       u32 risingdetect;
-       u32 fallingdetect;
-       u32 dataout;
-};
-
-static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS];
-#endif
-
-/*
- * TODO: Cleanup gpio_bank usage as it is having information
- * related to all instances of the device
- */
-static struct gpio_bank *gpio_bank;
-
-/* TODO: Analyze removing gpio_bank_count usage from driver code */
-int gpio_bank_count;
-
 #define GPIO_INDEX(bank, gpio) (gpio % bank->width)
 #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
+#define GPIO_MOD_CTRL_BIT      BIT(0)
+
+static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
+{
+       return gpio_irq - bank->irq_base + bank->chip.base;
+}
 
 static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
 {
@@ -102,6 +110,7 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
        else
                l &= ~(1 << gpio);
        __raw_writel(l, reg);
+       bank->context.oe = l;
 }
 
 
@@ -111,10 +120,13 @@ static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable)
        void __iomem *reg = bank->base;
        u32 l = GPIO_BIT(bank, gpio);
 
-       if (enable)
+       if (enable) {
                reg += bank->regs->set_dataout;
-       else
+               bank->context.dataout |= l;
+       } else {
                reg += bank->regs->clr_dataout;
+               bank->context.dataout &= ~l;
+       }
 
        __raw_writel(l, reg);
 }
@@ -132,27 +144,28 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable)
        else
                l &= ~gpio_bit;
        __raw_writel(l, reg);
+       bank->context.dataout = l;
 }
 
-static int _get_gpio_datain(struct gpio_bank *bank, int gpio)
+static int _get_gpio_datain(struct gpio_bank *bank, int offset)
 {
        void __iomem *reg = bank->base + bank->regs->datain;
 
-       return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0;
+       return (__raw_readl(reg) & (1 << offset)) != 0;
 }
 
-static int _get_gpio_dataout(struct gpio_bank *bank, int gpio)
+static int _get_gpio_dataout(struct gpio_bank *bank, int offset)
 {
        void __iomem *reg = bank->base + bank->regs->dataout;
 
-       return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0;
+       return (__raw_readl(reg) & (1 << offset)) != 0;
 }
 
 static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
 {
        int l = __raw_readl(base + reg);
 
-       if (set) 
+       if (set)
                l |= mask;
        else
                l &= ~mask;
@@ -160,6 +173,22 @@ static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
        __raw_writel(l, base + reg);
 }
 
+static inline void _gpio_dbck_enable(struct gpio_bank *bank)
+{
+       if (bank->dbck_enable_mask && !bank->dbck_enabled) {
+               clk_enable(bank->dbck);
+               bank->dbck_enabled = true;
+       }
+}
+
+static inline void _gpio_dbck_disable(struct gpio_bank *bank)
+{
+       if (bank->dbck_enable_mask && bank->dbck_enabled) {
+               clk_disable(bank->dbck);
+               bank->dbck_enabled = false;
+       }
+}
+
 /**
  * _set_gpio_debounce - low level gpio debounce time
  * @bank: the gpio bank we're acting upon
@@ -188,70 +217,74 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
 
        l = GPIO_BIT(bank, gpio);
 
+       clk_enable(bank->dbck);
        reg = bank->base + bank->regs->debounce;
        __raw_writel(debounce, reg);
 
        reg = bank->base + bank->regs->debounce_en;
        val = __raw_readl(reg);
 
-       if (debounce) {
+       if (debounce)
                val |= l;
-               clk_enable(bank->dbck);
-       } else {
+       else
                val &= ~l;
-               clk_disable(bank->dbck);
-       }
        bank->dbck_enable_mask = val;
 
        __raw_writel(val, reg);
+       clk_disable(bank->dbck);
+       /*
+        * Enable debounce clock per module.
+        * This call is mandatory because in omap_gpio_request() when
+        * *_runtime_get_sync() is called,  _gpio_dbck_enable() within
+        * runtime callbck fails to turn on dbck because dbck_enable_mask
+        * used within _gpio_dbck_enable() is still not initialized at
+        * that point. Therefore we have to enable dbck here.
+        */
+       _gpio_dbck_enable(bank);
+       if (bank->dbck_enable_mask) {
+               bank->context.debounce = debounce;
+               bank->context.debounce_en = val;
+       }
 }
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
-                                               int trigger)
+static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
+                                               unsigned trigger)
 {
        void __iomem *base = bank->base;
        u32 gpio_bit = 1 << gpio;
 
-       if (cpu_is_omap44xx()) {
-               _gpio_rmw(base, OMAP4_GPIO_LEVELDETECT0, gpio_bit,
-                         trigger & IRQ_TYPE_LEVEL_LOW);
-               _gpio_rmw(base, OMAP4_GPIO_LEVELDETECT1, gpio_bit,
-                         trigger & IRQ_TYPE_LEVEL_HIGH);
-               _gpio_rmw(base, OMAP4_GPIO_RISINGDETECT, gpio_bit,
-                         trigger & IRQ_TYPE_EDGE_RISING);
-               _gpio_rmw(base, OMAP4_GPIO_FALLINGDETECT, gpio_bit,
-                         trigger & IRQ_TYPE_EDGE_FALLING);
-       } else {
-               _gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
-                         trigger & IRQ_TYPE_LEVEL_LOW);
-               _gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT1, gpio_bit,
-                         trigger & IRQ_TYPE_LEVEL_HIGH);
-               _gpio_rmw(base, OMAP24XX_GPIO_RISINGDETECT, gpio_bit,
-                         trigger & IRQ_TYPE_EDGE_RISING);
-               _gpio_rmw(base, OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
-                         trigger & IRQ_TYPE_EDGE_FALLING);
-       }
+       _gpio_rmw(base, bank->regs->leveldetect0, gpio_bit,
+                 trigger & IRQ_TYPE_LEVEL_LOW);
+       _gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
+                 trigger & IRQ_TYPE_LEVEL_HIGH);
+       _gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
+                 trigger & IRQ_TYPE_EDGE_RISING);
+       _gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
+                 trigger & IRQ_TYPE_EDGE_FALLING);
+
+       bank->context.leveldetect0 =
+                       __raw_readl(bank->base + bank->regs->leveldetect0);
+       bank->context.leveldetect1 =
+                       __raw_readl(bank->base + bank->regs->leveldetect1);
+       bank->context.risingdetect =
+                       __raw_readl(bank->base + bank->regs->risingdetect);
+       bank->context.fallingdetect =
+                       __raw_readl(bank->base + bank->regs->fallingdetect);
+
        if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
-               if (cpu_is_omap44xx()) {
-                       _gpio_rmw(base, OMAP4_GPIO_IRQWAKEN0, gpio_bit,
-                                 trigger != 0);
-               } else {
-                       /*
-                        * GPIO wakeup request can only be generated on edge
-                        * transitions
-                        */
-                       if (trigger & IRQ_TYPE_EDGE_BOTH)
-                               __raw_writel(1 << gpio, bank->base
-                                       + OMAP24XX_GPIO_SETWKUENA);
-                       else
-                               __raw_writel(1 << gpio, bank->base
-                                       + OMAP24XX_GPIO_CLEARWKUENA);
-               }
+               _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
+               bank->context.wake_en =
+                       __raw_readl(bank->base + bank->regs->wkup_en);
        }
+
        /* This part needs to be executed always for OMAP{34xx, 44xx} */
-       if (cpu_is_omap34xx() || cpu_is_omap44xx() ||
-                       (bank->non_wakeup_gpios & gpio_bit)) {
+       if (!bank->regs->irqctrl) {
+               /* On omap24xx proceed only when valid GPIO bit is set */
+               if (bank->non_wakeup_gpios) {
+                       if (!(bank->non_wakeup_gpios & gpio_bit))
+                               goto exit;
+               }
+
                /*
                 * Log the edge gpio and manually trigger the IRQ
                 * after resume if the input level changes
@@ -264,17 +297,11 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
                        bank->enabled_non_wakeup_gpios &= ~gpio_bit;
        }
 
-       if (cpu_is_omap44xx()) {
-               bank->level_mask =
-                       __raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT0) |
-                       __raw_readl(bank->base + OMAP4_GPIO_LEVELDETECT1);
-       } else {
-               bank->level_mask =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0) |
-                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-       }
+exit:
+       bank->level_mask =
+               __raw_readl(bank->base + bank->regs->leveldetect0) |
+               __raw_readl(bank->base + bank->regs->leveldetect1);
 }
-#endif
 
 #ifdef CONFIG_ARCH_OMAP1
 /*
@@ -286,23 +313,10 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
        void __iomem *reg = bank->base;
        u32 l = 0;
 
-       switch (bank->method) {
-       case METHOD_MPUIO:
-               reg += OMAP_MPUIO_GPIO_INT_EDGE / bank->stride;
-               break;
-#ifdef CONFIG_ARCH_OMAP15XX
-       case METHOD_GPIO_1510:
-               reg += OMAP1510_GPIO_INT_CONTROL;
-               break;
-#endif
-#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
-       case METHOD_GPIO_7XX:
-               reg += OMAP7XX_GPIO_INT_CONTROL;
-               break;
-#endif
-       default:
+       if (!bank->regs->irqctrl)
                return;
-       }
+
+       reg += bank->regs->irqctrl;
 
        l = __raw_readl(reg);
        if ((l >> gpio) & 1)
@@ -312,31 +326,22 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
 
        __raw_writel(l, reg);
 }
+#else
+static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
 #endif
 
-static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
+static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
+                                                       unsigned trigger)
 {
        void __iomem *reg = bank->base;
+       void __iomem *base = bank->base;
        u32 l = 0;
 
-       switch (bank->method) {
-#ifdef CONFIG_ARCH_OMAP1
-       case METHOD_MPUIO:
-               reg += OMAP_MPUIO_GPIO_INT_EDGE / bank->stride;
-               l = __raw_readl(reg);
-               if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
-                       bank->toggle_mask |= 1 << gpio;
-               if (trigger & IRQ_TYPE_EDGE_RISING)
-                       l |= 1 << gpio;
-               else if (trigger & IRQ_TYPE_EDGE_FALLING)
-                       l &= ~(1 << gpio);
-               else
-                       goto bad;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP15XX
-       case METHOD_GPIO_1510:
-               reg += OMAP1510_GPIO_INT_CONTROL;
+       if (bank->regs->leveldetect0 && bank->regs->wkup_en) {
+               set_gpio_trigger(bank, gpio, trigger);
+       } else if (bank->regs->irqctrl) {
+               reg += bank->regs->irqctrl;
+
                l = __raw_readl(reg);
                if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
                        bank->toggle_mask |= 1 << gpio;
@@ -345,15 +350,15 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
                else if (trigger & IRQ_TYPE_EDGE_FALLING)
                        l &= ~(1 << gpio);
                else
-                       goto bad;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP16XX
-       case METHOD_GPIO_1610:
+                       return -EINVAL;
+
+               __raw_writel(l, reg);
+       } else if (bank->regs->edgectrl1) {
                if (gpio & 0x08)
-                       reg += OMAP1610_GPIO_EDGE_CTRL2;
+                       reg += bank->regs->edgectrl2;
                else
-                       reg += OMAP1610_GPIO_EDGE_CTRL1;
+                       reg += bank->regs->edgectrl1;
+
                gpio &= 0x07;
                l = __raw_readl(reg);
                l &= ~(3 << (gpio << 1));
@@ -361,45 +366,19 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
                        l |= 2 << (gpio << 1);
                if (trigger & IRQ_TYPE_EDGE_FALLING)
                        l |= 1 << (gpio << 1);
-               if (trigger)
-                       /* Enable wake-up during idle for dynamic tick */
-                       __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA);
-               else
-                       __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA);
-               break;
-#endif
-#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
-       case METHOD_GPIO_7XX:
-               reg += OMAP7XX_GPIO_INT_CONTROL;
-               l = __raw_readl(reg);
-               if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
-                       bank->toggle_mask |= 1 << gpio;
-               if (trigger & IRQ_TYPE_EDGE_RISING)
-                       l |= 1 << gpio;
-               else if (trigger & IRQ_TYPE_EDGE_FALLING)
-                       l &= ~(1 << gpio);
-               else
-                       goto bad;
-               break;
-#endif
-#ifdef CONFIG_ARCH_OMAP2PLUS
-       case METHOD_GPIO_24XX:
-       case METHOD_GPIO_44XX:
-               set_24xx_gpio_triggering(bank, gpio, trigger);
-               return 0;
-#endif
-       default:
-               goto bad;
+
+               /* Enable wake-up during idle for dynamic tick */
+               _gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger);
+               bank->context.wake_en =
+                       __raw_readl(bank->base + bank->regs->wkup_en);
+               __raw_writel(l, reg);
        }
-       __raw_writel(l, reg);
        return 0;
-bad:
-       return -EINVAL;
 }
 
 static int gpio_irq_type(struct irq_data *d, unsigned type)
 {
-       struct gpio_bank *bank;
+       struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
        unsigned gpio;
        int retval;
        unsigned long flags;
@@ -407,17 +386,15 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
        if (!cpu_class_is_omap2() && d->irq > IH_MPUIO_BASE)
                gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE);
        else
-               gpio = d->irq - IH_GPIO_BASE;
+               gpio = irq_to_gpio(bank, d->irq);
 
        if (type & ~IRQ_TYPE_SENSE_MASK)
                return -EINVAL;
 
-       /* OMAP1 allows only only edge triggering */
-       if (!cpu_class_is_omap2()
-                       && (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
+       if (!bank->regs->leveldetect0 &&
+               (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
                return -EINVAL;
 
-       bank = irq_data_get_irq_chip_data(d);
        spin_lock_irqsave(&bank->lock, flags);
        retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type);
        spin_unlock_irqrestore(&bank->lock, flags);
@@ -474,6 +451,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
        if (bank->regs->set_irqenable) {
                reg += bank->regs->set_irqenable;
                l = gpio_mask;
+               bank->context.irqenable1 |= gpio_mask;
        } else {
                reg += bank->regs->irqenable;
                l = __raw_readl(reg);
@@ -481,6 +459,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
                        l &= ~gpio_mask;
                else
                        l |= gpio_mask;
+               bank->context.irqenable1 = l;
        }
 
        __raw_writel(l, reg);
@@ -494,6 +473,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
        if (bank->regs->clr_irqenable) {
                reg += bank->regs->clr_irqenable;
                l = gpio_mask;
+               bank->context.irqenable1 &= ~gpio_mask;
        } else {
                reg += bank->regs->irqenable;
                l = __raw_readl(reg);
@@ -501,6 +481,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
                        l |= gpio_mask;
                else
                        l &= ~gpio_mask;
+               bank->context.irqenable1 = l;
        }
 
        __raw_writel(l, reg);
@@ -508,7 +489,10 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 
 static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
 {
-       _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+       if (enable)
+               _enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+       else
+               _disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
 }
 
 /*
@@ -525,7 +509,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
        unsigned long flags;
 
        if (bank->non_wakeup_gpios & gpio_bit) {
-               dev_err(bank->dev, 
+               dev_err(bank->dev,
                        "Unable to modify wakeup on non-wakeup GPIO%d\n", gpio);
                return -EINVAL;
        }
@@ -536,6 +520,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
        else
                bank->suspend_wakeup &= ~gpio_bit;
 
+       __raw_writel(bank->suspend_wakeup, bank->base + bank->regs->wkup_en);
        spin_unlock_irqrestore(&bank->lock, flags);
 
        return 0;
@@ -552,14 +537,10 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio)
 /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
 static int gpio_wake_enable(struct irq_data *d, unsigned int enable)
 {
-       unsigned int gpio = d->irq - IH_GPIO_BASE;
-       struct gpio_bank *bank;
-       int retval;
-
-       bank = irq_data_get_irq_chip_data(d);
-       retval = _set_gpio_wakeup(bank, gpio, enable);
+       struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned int gpio = irq_to_gpio(bank, d->irq);
 
-       return retval;
+       return _set_gpio_wakeup(bank, gpio, enable);
 }
 
 static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -567,38 +548,39 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
        struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
        unsigned long flags;
 
-       spin_lock_irqsave(&bank->lock, flags);
+       /*
+        * If this is the first gpio_request for the bank,
+        * enable the bank module.
+        */
+       if (!bank->mod_usage)
+               pm_runtime_get_sync(bank->dev);
 
+       spin_lock_irqsave(&bank->lock, flags);
        /* Set trigger to none. You need to enable the desired trigger with
         * request_irq() or set_irq_type().
         */
        _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
 
-#ifdef CONFIG_ARCH_OMAP15XX
-       if (bank->method == METHOD_GPIO_1510) {
-               void __iomem *reg;
+       if (bank->regs->pinctrl) {
+               void __iomem *reg = bank->base + bank->regs->pinctrl;
 
                /* Claim the pin for MPU */
-               reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
                __raw_writel(__raw_readl(reg) | (1 << offset), reg);
        }
-#endif
-       if (!cpu_class_is_omap1()) {
-               if (!bank->mod_usage) {
-                       void __iomem *reg = bank->base;
-                       u32 ctrl;
-
-                       if (cpu_is_omap24xx() || cpu_is_omap34xx())
-                               reg += OMAP24XX_GPIO_CTRL;
-                       else if (cpu_is_omap44xx())
-                               reg += OMAP4_GPIO_CTRL;
-                       ctrl = __raw_readl(reg);
-                       /* Module is enabled, clocks are not gated */
-                       ctrl &= 0xFFFFFFFE;
-                       __raw_writel(ctrl, reg);
-               }
-               bank->mod_usage |= 1 << offset;
+
+       if (bank->regs->ctrl && !bank->mod_usage) {
+               void __iomem *reg = bank->base + bank->regs->ctrl;
+               u32 ctrl;
+
+               ctrl = __raw_readl(reg);
+               /* Module is enabled, clocks are not gated */
+               ctrl &= ~GPIO_MOD_CTRL_BIT;
+               __raw_writel(ctrl, reg);
+               bank->context.ctrl = ctrl;
        }
+
+       bank->mod_usage |= 1 << offset;
+
        spin_unlock_irqrestore(&bank->lock, flags);
 
        return 0;
@@ -607,48 +589,40 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
        struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+       void __iomem *base = bank->base;
        unsigned long flags;
 
        spin_lock_irqsave(&bank->lock, flags);
-#ifdef CONFIG_ARCH_OMAP16XX
-       if (bank->method == METHOD_GPIO_1610) {
-               /* Disable wake-up during idle for dynamic tick */
-               void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-               __raw_writel(1 << offset, reg);
-       }
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-       if (bank->method == METHOD_GPIO_24XX) {
-               /* Disable wake-up during idle for dynamic tick */
-               void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-               __raw_writel(1 << offset, reg);
-       }
-#endif
-#ifdef CONFIG_ARCH_OMAP4
-       if (bank->method == METHOD_GPIO_44XX) {
+
+       if (bank->regs->wkup_en) {
                /* Disable wake-up during idle for dynamic tick */
-               void __iomem *reg = bank->base + OMAP4_GPIO_IRQWAKEN0;
-               __raw_writel(1 << offset, reg);
+               _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0);
+               bank->context.wake_en =
+                       __raw_readl(bank->base + bank->regs->wkup_en);
        }
-#endif
-       if (!cpu_class_is_omap1()) {
-               bank->mod_usage &= ~(1 << offset);
-               if (!bank->mod_usage) {
-                       void __iomem *reg = bank->base;
-                       u32 ctrl;
-
-                       if (cpu_is_omap24xx() || cpu_is_omap34xx())
-                               reg += OMAP24XX_GPIO_CTRL;
-                       else if (cpu_is_omap44xx())
-                               reg += OMAP4_GPIO_CTRL;
-                       ctrl = __raw_readl(reg);
-                       /* Module is disabled, clocks are gated */
-                       ctrl |= 1;
-                       __raw_writel(ctrl, reg);
-               }
+
+       bank->mod_usage &= ~(1 << offset);
+
+       if (bank->regs->ctrl && !bank->mod_usage) {
+               void __iomem *reg = bank->base + bank->regs->ctrl;
+               u32 ctrl;
+
+               ctrl = __raw_readl(reg);
+               /* Module is disabled, clocks are gated */
+               ctrl |= GPIO_MOD_CTRL_BIT;
+               __raw_writel(ctrl, reg);
+               bank->context.ctrl = ctrl;
        }
+
        _reset_gpio(bank, bank->chip.base + offset);
        spin_unlock_irqrestore(&bank->lock, flags);
+
+       /*
+        * If this is the last gpio to be freed in the bank,
+        * disable the bank module.
+        */
+       if (!bank->mod_usage)
+               pm_runtime_put(bank->dev);
 }
 
 /*
@@ -674,6 +648,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 
        bank = irq_get_handler_data(irq);
        isr_reg = bank->base + bank->regs->irqstatus;
+       pm_runtime_get_sync(bank->dev);
 
        if (WARN_ON(!isr_reg))
                goto exit;
@@ -685,12 +660,8 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
                enabled = _get_gpio_irqbank_mask(bank);
                isr_saved = isr = __raw_readl(isr_reg) & enabled;
 
-               if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO))
-                       isr &= 0x0000ffff;
-
-               if (cpu_class_is_omap2()) {
+               if (bank->level_mask)
                        level_mask = bank->level_mask & enabled;
-               }
 
                /* clear edge sensitive interrupts before handler(s) are
                called so that we don't miss any interrupt occurred while
@@ -711,14 +682,15 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
                if (!isr)
                        break;
 
-               gpio_irq = bank->virtual_irq_start;
+               gpio_irq = bank->irq_base;
                for (; isr != 0; isr >>= 1, gpio_irq++) {
-                       gpio_index = GPIO_INDEX(bank, irq_to_gpio(gpio_irq));
+                       int gpio = irq_to_gpio(bank, gpio_irq);
 
                        if (!(isr & 1))
                                continue;
 
-#ifdef CONFIG_ARCH_OMAP1
+                       gpio_index = GPIO_INDEX(bank, gpio);
+
                        /*
                         * Some chips can't respond to both rising and falling
                         * at the same time.  If this irq was requested with
@@ -728,7 +700,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
                         */
                        if (bank->toggle_mask & (1 << gpio_index))
                                _toggle_gpio_edge_triggering(bank, gpio_index);
-#endif
 
                        generic_handle_irq(gpio_irq);
                }
@@ -740,12 +711,13 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 exit:
        if (!unmasked)
                chained_irq_exit(chip, desc);
+       pm_runtime_put(bank->dev);
 }
 
 static void gpio_irq_shutdown(struct irq_data *d)
 {
-       unsigned int gpio = d->irq - IH_GPIO_BASE;
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned int gpio = irq_to_gpio(bank, d->irq);
        unsigned long flags;
 
        spin_lock_irqsave(&bank->lock, flags);
@@ -755,16 +727,16 @@ static void gpio_irq_shutdown(struct irq_data *d)
 
 static void gpio_ack_irq(struct irq_data *d)
 {
-       unsigned int gpio = d->irq - IH_GPIO_BASE;
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned int gpio = irq_to_gpio(bank, d->irq);
 
        _clear_gpio_irqstatus(bank, gpio);
 }
 
 static void gpio_mask_irq(struct irq_data *d)
 {
-       unsigned int gpio = d->irq - IH_GPIO_BASE;
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned int gpio = irq_to_gpio(bank, d->irq);
        unsigned long flags;
 
        spin_lock_irqsave(&bank->lock, flags);
@@ -775,8 +747,8 @@ static void gpio_mask_irq(struct irq_data *d)
 
 static void gpio_unmask_irq(struct irq_data *d)
 {
-       unsigned int gpio = d->irq - IH_GPIO_BASE;
        struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       unsigned int gpio = irq_to_gpio(bank, d->irq);
        unsigned int irq_mask = GPIO_BIT(bank, gpio);
        u32 trigger = irqd_get_trigger_type(d);
        unsigned long flags;
@@ -808,14 +780,6 @@ static struct irq_chip gpio_irq_chip = {
 
 /*---------------------------------------------------------------------*/
 
-#ifdef CONFIG_ARCH_OMAP1
-
-#define bank_is_mpuio(bank)    ((bank)->method == METHOD_MPUIO)
-
-#ifdef CONFIG_ARCH_OMAP16XX
-
-#include <linux/platform_device.h>
-
 static int omap_mpuio_suspend_noirq(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -869,32 +833,16 @@ static struct platform_device omap_mpuio_device = {
        /* could list the /proc/iomem resources */
 };
 
-static inline void mpuio_init(void)
+static inline void mpuio_init(struct gpio_bank *bank)
 {
-       struct gpio_bank *bank = &gpio_bank[0];
        platform_set_drvdata(&omap_mpuio_device, bank);
 
        if (platform_driver_register(&omap_mpuio_driver) == 0)
                (void) platform_device_register(&omap_mpuio_device);
 }
 
-#else
-static inline void mpuio_init(void) {}
-#endif /* 16xx */
-
-#else
-
-#define bank_is_mpuio(bank)    0
-static inline void mpuio_init(void) {}
-
-#endif
-
 /*---------------------------------------------------------------------*/
 
-/* REVISIT these are stupid implementations!  replace by ones that
- * don't switch on METHOD_* and which mostly avoid spinlocks
- */
-
 static int gpio_input(struct gpio_chip *chip, unsigned offset)
 {
        struct gpio_bank *bank;
@@ -917,19 +865,15 @@ static int gpio_is_input(struct gpio_bank *bank, int mask)
 static int gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct gpio_bank *bank;
-       void __iomem *reg;
-       int gpio;
        u32 mask;
 
-       gpio = chip->base + offset;
        bank = container_of(chip, struct gpio_bank, chip);
-       reg = bank->base;
-       mask = GPIO_BIT(bank, gpio);
+       mask = (1 << offset);
 
        if (gpio_is_input(bank, mask))
-               return _get_gpio_datain(bank, gpio);
+               return _get_gpio_datain(bank, offset);
        else
-               return _get_gpio_dataout(bank, gpio);
+               return _get_gpio_dataout(bank, offset);
 }
 
 static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
@@ -982,7 +926,7 @@ static int gpio_2irq(struct gpio_chip *chip, unsigned offset)
        struct gpio_bank *bank;
 
        bank = container_of(chip, struct gpio_bank, chip);
-       return bank->virtual_irq_start + offset;
+       return bank->irq_base + offset;
 }
 
 /*---------------------------------------------------------------------*/
@@ -1007,81 +951,35 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank)
  */
 static struct lock_class_key gpio_lock_class;
 
-static inline int init_gpio_info(struct platform_device *pdev)
+static void omap_gpio_mod_init(struct gpio_bank *bank)
 {
-       /* TODO: Analyze removing gpio_bank_count usage from driver code */
-       gpio_bank = kzalloc(gpio_bank_count * sizeof(struct gpio_bank),
-                               GFP_KERNEL);
-       if (!gpio_bank) {
-               dev_err(&pdev->dev, "Memory alloc failed for gpio_bank\n");
-               return -ENOMEM;
-       }
-       return 0;
-}
+       void __iomem *base = bank->base;
+       u32 l = 0xffffffff;
 
-/* TODO: Cleanup cpu_is_* checks */
-static void omap_gpio_mod_init(struct gpio_bank *bank, int id)
-{
-       if (cpu_class_is_omap2()) {
-               if (cpu_is_omap44xx()) {
-                       __raw_writel(0xffffffff, bank->base +
-                                       OMAP4_GPIO_IRQSTATUSCLR0);
-                       __raw_writel(0x00000000, bank->base +
-                                        OMAP4_GPIO_DEBOUNCENABLE);
-                       /* Initialize interface clk ungated, module enabled */
-                       __raw_writel(0, bank->base + OMAP4_GPIO_CTRL);
-               } else if (cpu_is_omap34xx()) {
-                       __raw_writel(0x00000000, bank->base +
-                                       OMAP24XX_GPIO_IRQENABLE1);
-                       __raw_writel(0xffffffff, bank->base +
-                                       OMAP24XX_GPIO_IRQSTATUS1);
-                       __raw_writel(0x00000000, bank->base +
-                                       OMAP24XX_GPIO_DEBOUNCE_EN);
-
-                       /* Initialize interface clk ungated, module enabled */
-                       __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
-               } else if (cpu_is_omap24xx()) {
-                       static const u32 non_wakeup_gpios[] = {
-                               0xe203ffc0, 0x08700040
-                       };
-                       if (id < ARRAY_SIZE(non_wakeup_gpios))
-                               bank->non_wakeup_gpios = non_wakeup_gpios[id];
-               }
-       } else if (cpu_class_is_omap1()) {
-               if (bank_is_mpuio(bank))
-                       __raw_writew(0xffff, bank->base +
-                               OMAP_MPUIO_GPIO_MASKIT / bank->stride);
-               if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) {
-                       __raw_writew(0xffff, bank->base
-                                               + OMAP1510_GPIO_INT_MASK);
-                       __raw_writew(0x0000, bank->base
-                                               + OMAP1510_GPIO_INT_STATUS);
-               }
-               if (cpu_is_omap16xx() && bank->method == METHOD_GPIO_1610) {
-                       __raw_writew(0x0000, bank->base
-                                               + OMAP1610_GPIO_IRQENABLE1);
-                       __raw_writew(0xffff, bank->base
-                                               + OMAP1610_GPIO_IRQSTATUS1);
-                       __raw_writew(0x0014, bank->base
-                                               + OMAP1610_GPIO_SYSCONFIG);
+       if (bank->width == 16)
+               l = 0xffff;
 
-                       /*
-                        * Enable system clock for GPIO module.
-                        * The CAM_CLK_CTRL *is* really the right place.
-                        */
-                       omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04,
-                                               ULPD_CAM_CLK_CTRL);
-               }
-               if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_7XX) {
-                       __raw_writel(0xffffffff, bank->base
-                                               + OMAP7XX_GPIO_INT_MASK);
-                       __raw_writel(0x00000000, bank->base
-                                               + OMAP7XX_GPIO_INT_STATUS);
-               }
+       if (bank->is_mpuio) {
+               __raw_writel(l, bank->base + bank->regs->irqenable);
+               return;
        }
+
+       _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv);
+       _gpio_rmw(base, bank->regs->irqstatus, l,
+                                       bank->regs->irqenable_inv == false);
+       _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->debounce_en != 0);
+       _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->ctrl != 0);
+       if (bank->regs->debounce_en)
+               _gpio_rmw(base, bank->regs->debounce_en, 0, 1);
+
+       /* Save OE default value (0xffffffff) in the context */
+       bank->context.oe = __raw_readl(bank->base + bank->regs->direction);
+        /* Initialize interface clk ungated, module enabled */
+       if (bank->regs->ctrl)
+               _gpio_rmw(base, bank->regs->ctrl, 0, 1);
 }
 
-static __init void
+static __devinit void
 omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
                    unsigned int num)
 {
@@ -1101,8 +999,8 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
        ct->chip.irq_mask = irq_gc_mask_set_bit;
        ct->chip.irq_unmask = irq_gc_mask_clr_bit;
        ct->chip.irq_set_type = gpio_irq_type;
-       /* REVISIT: assuming only 16xx supports MPUIO wake events */
-       if (cpu_is_omap16xx())
+
+       if (bank->regs->wkup_en)
                ct->chip.irq_set_wake = gpio_wake_enable,
 
        ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride;
@@ -1115,7 +1013,6 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
        int j;
        static int gpio;
 
-       bank->mod_usage = 0;
        /*
         * REVISIT eventually switch from OMAP-specific gpio structs
         * over to the generic ones
@@ -1128,11 +1025,10 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
        bank->chip.set_debounce = gpio_debounce;
        bank->chip.set = gpio_set;
        bank->chip.to_irq = gpio_2irq;
-       if (bank_is_mpuio(bank)) {
+       if (bank->is_mpuio) {
                bank->chip.label = "mpuio";
-#ifdef CONFIG_ARCH_OMAP16XX
-               bank->chip.dev = &omap_mpuio_device.dev;
-#endif
+               if (bank->regs->wkup_en)
+                       bank->chip.dev = &omap_mpuio_device.dev;
                bank->chip.base = OMAP_MPUIO(0);
        } else {
                bank->chip.label = "gpio";
@@ -1143,11 +1039,10 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
 
        gpiochip_add(&bank->chip);
 
-       for (j = bank->virtual_irq_start;
-                    j < bank->virtual_irq_start + bank->width; j++) {
+       for (j = bank->irq_base; j < bank->irq_base + bank->width; j++) {
                irq_set_lockdep_class(j, &gpio_lock_class);
                irq_set_chip_data(j, bank);
-               if (bank_is_mpuio(bank)) {
+               if (bank->is_mpuio) {
                        omap_mpuio_alloc_gc(bank, j, bank->width);
                } else {
                        irq_set_chip(j, &gpio_irq_chip);
@@ -1159,45 +1054,58 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
        irq_set_handler_data(bank->irq, bank);
 }
 
+static const struct of_device_id omap_gpio_match[];
+
 static int __devinit omap_gpio_probe(struct platform_device *pdev)
 {
-       static int gpio_init_done;
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+       const struct of_device_id *match;
        struct omap_gpio_platform_data *pdata;
        struct resource *res;
-       int id;
        struct gpio_bank *bank;
+       int ret = 0;
 
-       if (!pdev->dev.platform_data)
-               return -EINVAL;
-
-       pdata = pdev->dev.platform_data;
+       match = of_match_device(of_match_ptr(omap_gpio_match), dev);
 
-       if (!gpio_init_done) {
-               int ret;
+       pdata = match ? match->data : dev->platform_data;
+       if (!pdata)
+               return -EINVAL;
 
-               ret = init_gpio_info(pdev);
-               if (ret)
-                       return ret;
+       bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL);
+       if (!bank) {
+               dev_err(dev, "Memory alloc failed\n");
+               return -ENOMEM;
        }
 
-       id = pdev->id;
-       bank = &gpio_bank[id];
-
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (unlikely(!res)) {
-               dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n", id);
+               dev_err(dev, "Invalid IRQ resource\n");
                return -ENODEV;
        }
 
        bank->irq = res->start;
-       bank->virtual_irq_start = pdata->virtual_irq_start;
-       bank->method = pdata->bank_type;
-       bank->dev = &pdev->dev;
+       bank->dev = dev;
        bank->dbck_flag = pdata->dbck_flag;
        bank->stride = pdata->bank_stride;
        bank->width = pdata->bank_width;
-
+       bank->is_mpuio = pdata->is_mpuio;
+       bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
+       bank->loses_context = pdata->loses_context;
+       bank->get_context_loss_count = pdata->get_context_loss_count;
        bank->regs = pdata->regs;
+#ifdef CONFIG_OF_GPIO
+       bank->chip.of_node = of_node_get(node);
+#endif
+
+       bank->irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
+       if (bank->irq_base < 0) {
+               dev_err(dev, "Couldn't allocate IRQ numbers\n");
+               return -ENODEV;
+       }
+
+       bank->domain = irq_domain_add_legacy(node, bank->width, bank->irq_base,
+                                            0, &irq_domain_simple_ops, NULL);
 
        if (bank->regs->set_dataout && bank->regs->clr_dataout)
                bank->set_dataout = _set_gpio_dataout_reg;
@@ -1209,369 +1117,422 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
        /* Static mapping, never released */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (unlikely(!res)) {
-               dev_err(&pdev->dev, "GPIO Bank %i Invalid mem resource\n", id);
+               dev_err(dev, "Invalid mem resource\n");
                return -ENODEV;
        }
 
-       bank->base = ioremap(res->start, resource_size(res));
+       if (!devm_request_mem_region(dev, res->start, resource_size(res),
+                                    pdev->name)) {
+               dev_err(dev, "Region already claimed\n");
+               return -EBUSY;
+       }
+
+       bank->base = devm_ioremap(dev, res->start, resource_size(res));
        if (!bank->base) {
-               dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n", id);
+               dev_err(dev, "Could not ioremap\n");
                return -ENOMEM;
        }
 
+       platform_set_drvdata(pdev, bank);
+
        pm_runtime_enable(bank->dev);
+       pm_runtime_irq_safe(bank->dev);
        pm_runtime_get_sync(bank->dev);
 
-       omap_gpio_mod_init(bank, id);
+       if (bank->is_mpuio)
+               mpuio_init(bank);
+
+       omap_gpio_mod_init(bank);
        omap_gpio_chip_init(bank);
        omap_gpio_show_rev(bank);
 
-       if (!gpio_init_done)
-               gpio_init_done = 1;
+       pm_runtime_put(bank->dev);
 
-       return 0;
+       list_add_tail(&bank->node, &omap_gpio_list);
+
+       return ret;
 }
 
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-static int omap_gpio_suspend(void)
+#ifdef CONFIG_ARCH_OMAP2PLUS
+
+#if defined(CONFIG_PM_SLEEP)
+static int omap_gpio_suspend(struct device *dev)
 {
-       int i;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       void __iomem *base = bank->base;
+       void __iomem *wakeup_enable;
+       unsigned long flags;
 
-       if (!cpu_class_is_omap2() && !cpu_is_omap16xx())
+       if (!bank->mod_usage || !bank->loses_context)
                return 0;
 
-       for (i = 0; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               void __iomem *wake_status;
-               void __iomem *wake_clear;
-               void __iomem *wake_set;
-               unsigned long flags;
-
-               switch (bank->method) {
-#ifdef CONFIG_ARCH_OMAP16XX
-               case METHOD_GPIO_1610:
-                       wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE;
-                       wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-                       wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
-                       break;
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-               case METHOD_GPIO_24XX:
-                       wake_status = bank->base + OMAP24XX_GPIO_WAKE_EN;
-                       wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-                       wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
-                       break;
-#endif
-#ifdef CONFIG_ARCH_OMAP4
-               case METHOD_GPIO_44XX:
-                       wake_status = bank->base + OMAP4_GPIO_IRQWAKEN0;
-                       wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0;
-                       wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0;
-                       break;
-#endif
-               default:
-                       continue;
-               }
+       if (!bank->regs->wkup_en || !bank->suspend_wakeup)
+               return 0;
 
-               spin_lock_irqsave(&bank->lock, flags);
-               bank->saved_wakeup = __raw_readl(wake_status);
-               __raw_writel(0xffffffff, wake_clear);
-               __raw_writel(bank->suspend_wakeup, wake_set);
-               spin_unlock_irqrestore(&bank->lock, flags);
-       }
+       wakeup_enable = bank->base + bank->regs->wkup_en;
+
+       spin_lock_irqsave(&bank->lock, flags);
+       bank->saved_wakeup = __raw_readl(wakeup_enable);
+       _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0);
+       _gpio_rmw(base, bank->regs->wkup_en, bank->suspend_wakeup, 1);
+       spin_unlock_irqrestore(&bank->lock, flags);
 
        return 0;
 }
 
-static void omap_gpio_resume(void)
+static int omap_gpio_resume(struct device *dev)
 {
-       int i;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       void __iomem *base = bank->base;
+       unsigned long flags;
 
-       if (!cpu_class_is_omap2() && !cpu_is_omap16xx())
-               return;
+       if (!bank->mod_usage || !bank->loses_context)
+               return 0;
 
-       for (i = 0; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               void __iomem *wake_clear;
-               void __iomem *wake_set;
-               unsigned long flags;
-
-               switch (bank->method) {
-#ifdef CONFIG_ARCH_OMAP16XX
-               case METHOD_GPIO_1610:
-                       wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-                       wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
-                       break;
-#endif
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-               case METHOD_GPIO_24XX:
-                       wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-                       wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
-                       break;
-#endif
-#ifdef CONFIG_ARCH_OMAP4
-               case METHOD_GPIO_44XX:
-                       wake_clear = bank->base + OMAP4_GPIO_IRQWAKEN0;
-                       wake_set = bank->base + OMAP4_GPIO_IRQWAKEN0;
-                       break;
-#endif
-               default:
-                       continue;
-               }
+       if (!bank->regs->wkup_en || !bank->saved_wakeup)
+               return 0;
 
-               spin_lock_irqsave(&bank->lock, flags);
-               __raw_writel(0xffffffff, wake_clear);
-               __raw_writel(bank->saved_wakeup, wake_set);
-               spin_unlock_irqrestore(&bank->lock, flags);
-       }
+       spin_lock_irqsave(&bank->lock, flags);
+       _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0);
+       _gpio_rmw(base, bank->regs->wkup_en, bank->saved_wakeup, 1);
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
-static struct syscore_ops omap_gpio_syscore_ops = {
-       .suspend        = omap_gpio_suspend,
-       .resume         = omap_gpio_resume,
-};
+#if defined(CONFIG_PM_RUNTIME)
+static void omap_gpio_restore_context(struct gpio_bank *bank);
 
-#endif
+static int omap_gpio_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       u32 l1 = 0, l2 = 0;
+       unsigned long flags;
+       u32 wake_low, wake_hi;
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
+       spin_lock_irqsave(&bank->lock, flags);
 
-static int workaround_enabled;
+       /*
+        * Only edges can generate a wakeup event to the PRCM.
+        *
+        * Therefore, ensure any wake-up capable GPIOs have
+        * edge-detection enabled before going idle to ensure a wakeup
+        * to the PRCM is generated on a GPIO transition. (c.f. 34xx
+        * NDA TRM 25.5.3.1)
+        *
+        * The normal values will be restored upon ->runtime_resume()
+        * by writing back the values saved in bank->context.
+        */
+       wake_low = bank->context.leveldetect0 & bank->context.wake_en;
+       if (wake_low)
+               __raw_writel(wake_low | bank->context.fallingdetect,
+                            bank->base + bank->regs->fallingdetect);
+       wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
+       if (wake_hi)
+               __raw_writel(wake_hi | bank->context.risingdetect,
+                            bank->base + bank->regs->risingdetect);
+
+       if (bank->power_mode != OFF_MODE) {
+               bank->power_mode = 0;
+               goto update_gpio_context_count;
+       }
+       /*
+        * If going to OFF, remove triggering for all
+        * non-wakeup GPIOs.  Otherwise spurious IRQs will be
+        * generated.  See OMAP2420 Errata item 1.101.
+        */
+       bank->saved_datain = __raw_readl(bank->base +
+                                               bank->regs->datain);
+       l1 = __raw_readl(bank->base + bank->regs->fallingdetect);
+       l2 = __raw_readl(bank->base + bank->regs->risingdetect);
 
-void omap2_gpio_prepare_for_idle(int off_mode)
-{
-       int i, c = 0;
-       int min = 0;
+       bank->saved_fallingdetect = l1;
+       bank->saved_risingdetect = l2;
+       l1 &= ~bank->enabled_non_wakeup_gpios;
+       l2 &= ~bank->enabled_non_wakeup_gpios;
 
-       if (cpu_is_omap34xx())
-               min = 1;
+       __raw_writel(l1, bank->base + bank->regs->fallingdetect);
+       __raw_writel(l2, bank->base + bank->regs->risingdetect);
 
-       for (i = min; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               u32 l1 = 0, l2 = 0;
-               int j;
+       bank->workaround_enabled = true;
 
-               for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
-                       clk_disable(bank->dbck);
+update_gpio_context_count:
+       if (bank->get_context_loss_count)
+               bank->context_loss_count =
+                               bank->get_context_loss_count(bank->dev);
 
-               if (!off_mode)
-                       continue;
+       _gpio_dbck_disable(bank);
+       spin_unlock_irqrestore(&bank->lock, flags);
 
-               /* If going to OFF, remove triggering for all
-                * non-wakeup GPIOs.  Otherwise spurious IRQs will be
-                * generated.  See OMAP2420 Errata item 1.101. */
-               if (!(bank->enabled_non_wakeup_gpios))
-                       continue;
+       return 0;
+}
 
-               if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-                       bank->saved_datain = __raw_readl(bank->base +
-                                       OMAP24XX_GPIO_DATAIN);
-                       l1 = __raw_readl(bank->base +
-                                       OMAP24XX_GPIO_FALLINGDETECT);
-                       l2 = __raw_readl(bank->base +
-                                       OMAP24XX_GPIO_RISINGDETECT);
-               }
+static int omap_gpio_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       int context_lost_cnt_after;
+       u32 l = 0, gen, gen0, gen1;
+       unsigned long flags;
 
-               if (cpu_is_omap44xx()) {
-                       bank->saved_datain = __raw_readl(bank->base +
-                                               OMAP4_GPIO_DATAIN);
-                       l1 = __raw_readl(bank->base +
-                                               OMAP4_GPIO_FALLINGDETECT);
-                       l2 = __raw_readl(bank->base +
-                                               OMAP4_GPIO_RISINGDETECT);
-               }
+       spin_lock_irqsave(&bank->lock, flags);
+       _gpio_dbck_enable(bank);
 
-               bank->saved_fallingdetect = l1;
-               bank->saved_risingdetect = l2;
-               l1 &= ~bank->enabled_non_wakeup_gpios;
-               l2 &= ~bank->enabled_non_wakeup_gpios;
+       /*
+        * In ->runtime_suspend(), level-triggered, wakeup-enabled
+        * GPIOs were set to edge trigger also in order to be able to
+        * generate a PRCM wakeup.  Here we restore the
+        * pre-runtime_suspend() values for edge triggering.
+        */
+       __raw_writel(bank->context.fallingdetect,
+                    bank->base + bank->regs->fallingdetect);
+       __raw_writel(bank->context.risingdetect,
+                    bank->base + bank->regs->risingdetect);
 
-               if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-                       __raw_writel(l1, bank->base +
-                                       OMAP24XX_GPIO_FALLINGDETECT);
-                       __raw_writel(l2, bank->base +
-                                       OMAP24XX_GPIO_RISINGDETECT);
-               }
+       if (!bank->workaround_enabled) {
+               spin_unlock_irqrestore(&bank->lock, flags);
+               return 0;
+       }
 
-               if (cpu_is_omap44xx()) {
-                       __raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT);
-                       __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT);
+       if (bank->get_context_loss_count) {
+               context_lost_cnt_after =
+                       bank->get_context_loss_count(bank->dev);
+               if (context_lost_cnt_after != bank->context_loss_count ||
+                                               !context_lost_cnt_after) {
+                       omap_gpio_restore_context(bank);
+               } else {
+                       spin_unlock_irqrestore(&bank->lock, flags);
+                       return 0;
                }
-
-               c++;
-       }
-       if (!c) {
-               workaround_enabled = 0;
-               return;
        }
-       workaround_enabled = 1;
-}
 
-void omap2_gpio_resume_after_idle(void)
-{
-       int i;
-       int min = 0;
+       __raw_writel(bank->saved_fallingdetect,
+                       bank->base + bank->regs->fallingdetect);
+       __raw_writel(bank->saved_risingdetect,
+                       bank->base + bank->regs->risingdetect);
+       l = __raw_readl(bank->base + bank->regs->datain);
 
-       if (cpu_is_omap34xx())
-               min = 1;
-       for (i = min; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               u32 l = 0, gen, gen0, gen1;
-               int j;
+       /*
+        * Check if any of the non-wakeup interrupt GPIOs have changed
+        * state.  If so, generate an IRQ by software.  This is
+        * horribly racy, but it's the best we can do to work around
+        * this silicon bug.
+        */
+       l ^= bank->saved_datain;
+       l &= bank->enabled_non_wakeup_gpios;
 
-               for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
-                       clk_enable(bank->dbck);
+       /*
+        * No need to generate IRQs for the rising edge for gpio IRQs
+        * configured with falling edge only; and vice versa.
+        */
+       gen0 = l & bank->saved_fallingdetect;
+       gen0 &= bank->saved_datain;
 
-               if (!workaround_enabled)
-                       continue;
+       gen1 = l & bank->saved_risingdetect;
+       gen1 &= ~(bank->saved_datain);
 
-               if (!(bank->enabled_non_wakeup_gpios))
-                       continue;
+       /* FIXME: Consider GPIO IRQs with level detections properly! */
+       gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect));
+       /* Consider all GPIO IRQs needed to be updated */
+       gen |= gen0 | gen1;
+
+       if (gen) {
+               u32 old0, old1;
+
+               old0 = __raw_readl(bank->base + bank->regs->leveldetect0);
+               old1 = __raw_readl(bank->base + bank->regs->leveldetect1);
 
                if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-                       __raw_writel(bank->saved_fallingdetect,
-                                bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-                       __raw_writel(bank->saved_risingdetect,
-                                bank->base + OMAP24XX_GPIO_RISINGDETECT);
-                       l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
+                       __raw_writel(old0 | gen, bank->base +
+                                               bank->regs->leveldetect0);
+                       __raw_writel(old1 | gen, bank->base +
+                                               bank->regs->leveldetect1);
                }
 
                if (cpu_is_omap44xx()) {
-                       __raw_writel(bank->saved_fallingdetect,
-                                bank->base + OMAP4_GPIO_FALLINGDETECT);
-                       __raw_writel(bank->saved_risingdetect,
-                                bank->base + OMAP4_GPIO_RISINGDETECT);
-                       l = __raw_readl(bank->base + OMAP4_GPIO_DATAIN);
-               }
-
-               /* Check if any of the non-wakeup interrupt GPIOs have changed
-                * state.  If so, generate an IRQ by software.  This is
-                * horribly racy, but it's the best we can do to work around
-                * this silicon bug. */
-               l ^= bank->saved_datain;
-               l &= bank->enabled_non_wakeup_gpios;
-
-               /*
-                * No need to generate IRQs for the rising edge for gpio IRQs
-                * configured with falling edge only; and vice versa.
-                */
-               gen0 = l & bank->saved_fallingdetect;
-               gen0 &= bank->saved_datain;
-
-               gen1 = l & bank->saved_risingdetect;
-               gen1 &= ~(bank->saved_datain);
-
-               /* FIXME: Consider GPIO IRQs with level detections properly! */
-               gen = l & (~(bank->saved_fallingdetect) &
-                               ~(bank->saved_risingdetect));
-               /* Consider all GPIO IRQs needed to be updated */
-               gen |= gen0 | gen1;
-
-               if (gen) {
-                       u32 old0, old1;
-
-                       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-                               old0 = __raw_readl(bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT0);
-                               old1 = __raw_readl(bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT1);
-                               __raw_writel(old0 | gen, bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT0);
-                               __raw_writel(old1 | gen, bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT1);
-                               __raw_writel(old0, bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT0);
-                               __raw_writel(old1, bank->base +
-                                       OMAP24XX_GPIO_LEVELDETECT1);
-                       }
-
-                       if (cpu_is_omap44xx()) {
-                               old0 = __raw_readl(bank->base +
-                                               OMAP4_GPIO_LEVELDETECT0);
-                               old1 = __raw_readl(bank->base +
-                                               OMAP4_GPIO_LEVELDETECT1);
-                               __raw_writel(old0 | l, bank->base +
-                                               OMAP4_GPIO_LEVELDETECT0);
-                               __raw_writel(old1 | l, bank->base +
-                                               OMAP4_GPIO_LEVELDETECT1);
-                               __raw_writel(old0, bank->base +
-                                               OMAP4_GPIO_LEVELDETECT0);
-                               __raw_writel(old1, bank->base +
-                                               OMAP4_GPIO_LEVELDETECT1);
-                       }
+                       __raw_writel(old0 | l, bank->base +
+                                               bank->regs->leveldetect0);
+                       __raw_writel(old1 | l, bank->base +
+                                               bank->regs->leveldetect1);
                }
+               __raw_writel(old0, bank->base + bank->regs->leveldetect0);
+               __raw_writel(old1, bank->base + bank->regs->leveldetect1);
        }
 
+       bank->workaround_enabled = false;
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       return 0;
 }
+#endif /* CONFIG_PM_RUNTIME */
 
-#endif
+void omap2_gpio_prepare_for_idle(int pwr_mode)
+{
+       struct gpio_bank *bank;
+
+       list_for_each_entry(bank, &omap_gpio_list, node) {
+               if (!bank->mod_usage || !bank->loses_context)
+                       continue;
 
-#ifdef CONFIG_ARCH_OMAP3
-/* save the registers of bank 2-6 */
-void omap_gpio_save_context(void)
+               bank->power_mode = pwr_mode;
+
+               pm_runtime_put_sync_suspend(bank->dev);
+       }
+}
+
+void omap2_gpio_resume_after_idle(void)
 {
-       int i;
-
-       /* saving banks from 2-6 only since GPIO1 is in WKUP */
-       for (i = 1; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               gpio_context[i].irqenable1 =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1);
-               gpio_context[i].irqenable2 =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2);
-               gpio_context[i].wake_en =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN);
-               gpio_context[i].ctrl =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_CTRL);
-               gpio_context[i].oe =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_OE);
-               gpio_context[i].leveldetect0 =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
-               gpio_context[i].leveldetect1 =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-               gpio_context[i].risingdetect =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
-               gpio_context[i].fallingdetect =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-               gpio_context[i].dataout =
-                       __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT);
+       struct gpio_bank *bank;
+
+       list_for_each_entry(bank, &omap_gpio_list, node) {
+               if (!bank->mod_usage || !bank->loses_context)
+                       continue;
+
+               pm_runtime_get_sync(bank->dev);
        }
 }
 
-/* restore the required registers of bank 2-6 */
-void omap_gpio_restore_context(void)
+#if defined(CONFIG_PM_RUNTIME)
+static void omap_gpio_restore_context(struct gpio_bank *bank)
 {
-       int i;
-
-       for (i = 1; i < gpio_bank_count; i++) {
-               struct gpio_bank *bank = &gpio_bank[i];
-               __raw_writel(gpio_context[i].irqenable1,
-                               bank->base + OMAP24XX_GPIO_IRQENABLE1);
-               __raw_writel(gpio_context[i].irqenable2,
-                               bank->base + OMAP24XX_GPIO_IRQENABLE2);
-               __raw_writel(gpio_context[i].wake_en,
-                               bank->base + OMAP24XX_GPIO_WAKE_EN);
-               __raw_writel(gpio_context[i].ctrl,
-                               bank->base + OMAP24XX_GPIO_CTRL);
-               __raw_writel(gpio_context[i].oe,
-                               bank->base + OMAP24XX_GPIO_OE);
-               __raw_writel(gpio_context[i].leveldetect0,
-                               bank->base + OMAP24XX_GPIO_LEVELDETECT0);
-               __raw_writel(gpio_context[i].leveldetect1,
-                               bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-               __raw_writel(gpio_context[i].risingdetect,
-                               bank->base + OMAP24XX_GPIO_RISINGDETECT);
-               __raw_writel(gpio_context[i].fallingdetect,
-                               bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-               __raw_writel(gpio_context[i].dataout,
-                               bank->base + OMAP24XX_GPIO_DATAOUT);
+       __raw_writel(bank->context.wake_en,
+                               bank->base + bank->regs->wkup_en);
+       __raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl);
+       __raw_writel(bank->context.leveldetect0,
+                               bank->base + bank->regs->leveldetect0);
+       __raw_writel(bank->context.leveldetect1,
+                               bank->base + bank->regs->leveldetect1);
+       __raw_writel(bank->context.risingdetect,
+                               bank->base + bank->regs->risingdetect);
+       __raw_writel(bank->context.fallingdetect,
+                               bank->base + bank->regs->fallingdetect);
+       if (bank->regs->set_dataout && bank->regs->clr_dataout)
+               __raw_writel(bank->context.dataout,
+                               bank->base + bank->regs->set_dataout);
+       else
+               __raw_writel(bank->context.dataout,
+                               bank->base + bank->regs->dataout);
+       __raw_writel(bank->context.oe, bank->base + bank->regs->direction);
+
+       if (bank->dbck_enable_mask) {
+               __raw_writel(bank->context.debounce, bank->base +
+                                       bank->regs->debounce);
+               __raw_writel(bank->context.debounce_en,
+                                       bank->base + bank->regs->debounce_en);
        }
+
+       __raw_writel(bank->context.irqenable1,
+                               bank->base + bank->regs->irqenable);
+       __raw_writel(bank->context.irqenable2,
+                               bank->base + bank->regs->irqenable2);
 }
+#endif /* CONFIG_PM_RUNTIME */
+#else
+#define omap_gpio_suspend NULL
+#define omap_gpio_resume NULL
+#define omap_gpio_runtime_suspend NULL
+#define omap_gpio_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops gpio_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume)
+       SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
+                                                                       NULL)
+};
+
+#if defined(CONFIG_OF)
+static struct omap_gpio_reg_offs omap2_gpio_regs = {
+       .revision =             OMAP24XX_GPIO_REVISION,
+       .direction =            OMAP24XX_GPIO_OE,
+       .datain =               OMAP24XX_GPIO_DATAIN,
+       .dataout =              OMAP24XX_GPIO_DATAOUT,
+       .set_dataout =          OMAP24XX_GPIO_SETDATAOUT,
+       .clr_dataout =          OMAP24XX_GPIO_CLEARDATAOUT,
+       .irqstatus =            OMAP24XX_GPIO_IRQSTATUS1,
+       .irqstatus2 =           OMAP24XX_GPIO_IRQSTATUS2,
+       .irqenable =            OMAP24XX_GPIO_IRQENABLE1,
+       .irqenable2 =           OMAP24XX_GPIO_IRQENABLE2,
+       .set_irqenable =        OMAP24XX_GPIO_SETIRQENABLE1,
+       .clr_irqenable =        OMAP24XX_GPIO_CLEARIRQENABLE1,
+       .debounce =             OMAP24XX_GPIO_DEBOUNCE_VAL,
+       .debounce_en =          OMAP24XX_GPIO_DEBOUNCE_EN,
+       .ctrl =                 OMAP24XX_GPIO_CTRL,
+       .wkup_en =              OMAP24XX_GPIO_WAKE_EN,
+       .leveldetect0 =         OMAP24XX_GPIO_LEVELDETECT0,
+       .leveldetect1 =         OMAP24XX_GPIO_LEVELDETECT1,
+       .risingdetect =         OMAP24XX_GPIO_RISINGDETECT,
+       .fallingdetect =        OMAP24XX_GPIO_FALLINGDETECT,
+};
+
+static struct omap_gpio_reg_offs omap4_gpio_regs = {
+       .revision =             OMAP4_GPIO_REVISION,
+       .direction =            OMAP4_GPIO_OE,
+       .datain =               OMAP4_GPIO_DATAIN,
+       .dataout =              OMAP4_GPIO_DATAOUT,
+       .set_dataout =          OMAP4_GPIO_SETDATAOUT,
+       .clr_dataout =          OMAP4_GPIO_CLEARDATAOUT,
+       .irqstatus =            OMAP4_GPIO_IRQSTATUS0,
+       .irqstatus2 =           OMAP4_GPIO_IRQSTATUS1,
+       .irqenable =            OMAP4_GPIO_IRQSTATUSSET0,
+       .irqenable2 =           OMAP4_GPIO_IRQSTATUSSET1,
+       .set_irqenable =        OMAP4_GPIO_IRQSTATUSSET0,
+       .clr_irqenable =        OMAP4_GPIO_IRQSTATUSCLR0,
+       .debounce =             OMAP4_GPIO_DEBOUNCINGTIME,
+       .debounce_en =          OMAP4_GPIO_DEBOUNCENABLE,
+       .ctrl =                 OMAP4_GPIO_CTRL,
+       .wkup_en =              OMAP4_GPIO_IRQWAKEN0,
+       .leveldetect0 =         OMAP4_GPIO_LEVELDETECT0,
+       .leveldetect1 =         OMAP4_GPIO_LEVELDETECT1,
+       .risingdetect =         OMAP4_GPIO_RISINGDETECT,
+       .fallingdetect =        OMAP4_GPIO_FALLINGDETECT,
+};
+
+static struct omap_gpio_platform_data omap2_pdata = {
+       .regs = &omap2_gpio_regs,
+       .bank_width = 32,
+       .dbck_flag = false,
+};
+
+static struct omap_gpio_platform_data omap3_pdata = {
+       .regs = &omap2_gpio_regs,
+       .bank_width = 32,
+       .dbck_flag = true,
+};
+
+static struct omap_gpio_platform_data omap4_pdata = {
+       .regs = &omap4_gpio_regs,
+       .bank_width = 32,
+       .dbck_flag = true,
+};
+
+static const struct of_device_id omap_gpio_match[] = {
+       {
+               .compatible = "ti,omap4-gpio",
+               .data = &omap4_pdata,
+       },
+       {
+               .compatible = "ti,omap3-gpio",
+               .data = &omap3_pdata,
+       },
+       {
+               .compatible = "ti,omap2-gpio",
+               .data = &omap2_pdata,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_gpio_match);
 #endif
 
 static struct platform_driver omap_gpio_driver = {
        .probe          = omap_gpio_probe,
        .driver         = {
                .name   = "omap_gpio",
+               .pm     = &gpio_pm_ops,
+               .of_match_table = of_match_ptr(omap_gpio_match),
        },
 };
 
@@ -1585,17 +1546,3 @@ static int __init omap_gpio_drv_reg(void)
        return platform_driver_register(&omap_gpio_driver);
 }
 postcore_initcall(omap_gpio_drv_reg);
-
-static int __init omap_gpio_sysinit(void)
-{
-       mpuio_init();
-
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-       if (cpu_is_omap16xx() || cpu_class_is_omap2())
-               register_syscore_ops(&omap_gpio_syscore_ops);
-#endif
-
-       return 0;
-}
-
-arch_initcall(omap_gpio_sysinit);
index 77c9cc7..b4b5da4 100644 (file)
@@ -352,7 +352,12 @@ static int pl061_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume);
+static const struct dev_pm_ops pl061_dev_pm_ops = {
+       .suspend = pl061_suspend,
+       .resume = pl061_resume,
+       .freeze = pl061_suspend,
+       .restore = pl061_resume,
+};
 #endif
 
 static struct amba_id pl061_ids[] = {
index 7eecf69..8ea3b33 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
index 0a79a11..4627787 100644 (file)
@@ -169,7 +169,7 @@ int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip,
        return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN);
 }
 
-static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip,
+static int exynos_gpio_setpull(struct samsung_gpio_chip *chip,
                                unsigned int off, samsung_gpio_pull_t pull)
 {
        if (pull == S3C_GPIO_PULL_UP)
@@ -178,7 +178,7 @@ static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip,
        return samsung_gpio_setpull_updown(chip, off, pull);
 }
 
-static samsung_gpio_pull_t exynos4_gpio_getpull(struct samsung_gpio_chip *chip,
+static samsung_gpio_pull_t exynos_gpio_getpull(struct samsung_gpio_chip *chip,
                                                unsigned int off)
 {
        samsung_gpio_pull_t pull;
@@ -452,9 +452,9 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = {
 };
 #endif
 
-static struct samsung_gpio_cfg exynos4_gpio_cfg = {
-       .set_pull       = exynos4_gpio_setpull,
-       .get_pull       = exynos4_gpio_getpull,
+static struct samsung_gpio_cfg exynos_gpio_cfg = {
+       .set_pull       = exynos_gpio_setpull,
+       .get_pull       = exynos_gpio_getpull,
        .set_config     = samsung_gpio_setcfg_4bit,
        .get_config     = samsung_gpio_getcfg_4bit,
 };
@@ -502,13 +502,13 @@ static struct samsung_gpio_cfg samsung_gpio_cfgs[] = {
                .get_config     = samsung_gpio_getcfg_2bit,
        },
        [8] = {
-               .set_pull       = exynos4_gpio_setpull,
-               .get_pull       = exynos4_gpio_getpull,
+               .set_pull       = exynos_gpio_setpull,
+               .get_pull       = exynos_gpio_getpull,
        },
        [9] = {
                .cfg_eint       = 0x3,
-               .set_pull       = exynos4_gpio_setpull,
-               .get_pull       = exynos4_gpio_getpull,
+               .set_pull       = exynos_gpio_setpull,
+               .get_pull       = exynos_gpio_getpull,
        }
 };
 
@@ -2113,10 +2113,10 @@ static struct samsung_gpio_chip s5pv210_gpios_4bit[] = {
 };
 
 /*
- * Followings are the gpio banks in EXYNOS4210
+ * Followings are the gpio banks in EXYNOS SoCs
  *
  * The 'config' member when left to NULL, is initialized to the default
- * structure samsung_gpio_cfgs[3] in the init function below.
+ * structure exynos_gpio_cfg in the init function below.
  *
  * The 'base' member is also initialized in the init function below.
  * Note: The initialization of 'base' member of samsung_gpio_chip structure
@@ -2331,7 +2331,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = {
                        .label  = "GPY6",
                },
        }, {
-               .base   = (S5P_VA_GPIO2 + 0xC00),
                .config = &samsung_gpio_cfgs[9],
                .irq_base = IRQ_EINT(0),
                .chip   = {
@@ -2341,7 +2340,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = {
                        .to_irq = samsung_gpiolib_to_irq,
                },
        }, {
-               .base   = (S5P_VA_GPIO2 + 0xC20),
                .config = &samsung_gpio_cfgs[9],
                .irq_base = IRQ_EINT(8),
                .chip   = {
@@ -2351,7 +2349,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = {
                        .to_irq = samsung_gpiolib_to_irq,
                },
        }, {
-               .base   = (S5P_VA_GPIO2 + 0xC40),
                .config = &samsung_gpio_cfgs[9],
                .irq_base = IRQ_EINT(16),
                .chip   = {
@@ -2361,7 +2358,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = {
                        .to_irq = samsung_gpiolib_to_irq,
                },
        }, {
-               .base   = (S5P_VA_GPIO2 + 0xC60),
                .config = &samsung_gpio_cfgs[9],
                .irq_base = IRQ_EINT(24),
                .chip   = {
@@ -2386,8 +2382,280 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = {
 #endif
 };
 
-#if defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF)
-static int exynos4_gpio_xlate(struct gpio_chip *gc,
+static struct samsung_gpio_chip exynos5_gpios_1[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+       {
+               .chip   = {
+                       .base   = EXYNOS5_GPA0(0),
+                       .ngpio  = EXYNOS5_GPIO_A0_NR,
+                       .label  = "GPA0",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPA1(0),
+                       .ngpio  = EXYNOS5_GPIO_A1_NR,
+                       .label  = "GPA1",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPA2(0),
+                       .ngpio  = EXYNOS5_GPIO_A2_NR,
+                       .label  = "GPA2",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPB0(0),
+                       .ngpio  = EXYNOS5_GPIO_B0_NR,
+                       .label  = "GPB0",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPB1(0),
+                       .ngpio  = EXYNOS5_GPIO_B1_NR,
+                       .label  = "GPB1",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPB2(0),
+                       .ngpio  = EXYNOS5_GPIO_B2_NR,
+                       .label  = "GPB2",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPB3(0),
+                       .ngpio  = EXYNOS5_GPIO_B3_NR,
+                       .label  = "GPB3",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPC0(0),
+                       .ngpio  = EXYNOS5_GPIO_C0_NR,
+                       .label  = "GPC0",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPC1(0),
+                       .ngpio  = EXYNOS5_GPIO_C1_NR,
+                       .label  = "GPC1",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPC2(0),
+                       .ngpio  = EXYNOS5_GPIO_C2_NR,
+                       .label  = "GPC2",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPC3(0),
+                       .ngpio  = EXYNOS5_GPIO_C3_NR,
+                       .label  = "GPC3",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPD0(0),
+                       .ngpio  = EXYNOS5_GPIO_D0_NR,
+                       .label  = "GPD0",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPD1(0),
+                       .ngpio  = EXYNOS5_GPIO_D1_NR,
+                       .label  = "GPD1",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPY0(0),
+                       .ngpio  = EXYNOS5_GPIO_Y0_NR,
+                       .label  = "GPY0",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPY1(0),
+                       .ngpio  = EXYNOS5_GPIO_Y1_NR,
+                       .label  = "GPY1",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPY2(0),
+                       .ngpio  = EXYNOS5_GPIO_Y2_NR,
+                       .label  = "GPY2",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPY3(0),
+                       .ngpio  = EXYNOS5_GPIO_Y3_NR,
+                       .label  = "GPY3",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPY4(0),
+                       .ngpio  = EXYNOS5_GPIO_Y4_NR,
+                       .label  = "GPY4",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPY5(0),
+                       .ngpio  = EXYNOS5_GPIO_Y5_NR,
+                       .label  = "GPY5",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPY6(0),
+                       .ngpio  = EXYNOS5_GPIO_Y6_NR,
+                       .label  = "GPY6",
+               },
+       }, {
+               .config = &samsung_gpio_cfgs[9],
+               .irq_base = IRQ_EINT(0),
+               .chip   = {
+                       .base   = EXYNOS5_GPX0(0),
+                       .ngpio  = EXYNOS5_GPIO_X0_NR,
+                       .label  = "GPX0",
+                       .to_irq = samsung_gpiolib_to_irq,
+               },
+       }, {
+               .config = &samsung_gpio_cfgs[9],
+               .irq_base = IRQ_EINT(8),
+               .chip   = {
+                       .base   = EXYNOS5_GPX1(0),
+                       .ngpio  = EXYNOS5_GPIO_X1_NR,
+                       .label  = "GPX1",
+                       .to_irq = samsung_gpiolib_to_irq,
+               },
+       }, {
+               .config = &samsung_gpio_cfgs[9],
+               .irq_base = IRQ_EINT(16),
+               .chip   = {
+                       .base   = EXYNOS5_GPX2(0),
+                       .ngpio  = EXYNOS5_GPIO_X2_NR,
+                       .label  = "GPX2",
+                       .to_irq = samsung_gpiolib_to_irq,
+               },
+       }, {
+               .config = &samsung_gpio_cfgs[9],
+               .irq_base = IRQ_EINT(24),
+               .chip   = {
+                       .base   = EXYNOS5_GPX3(0),
+                       .ngpio  = EXYNOS5_GPIO_X3_NR,
+                       .label  = "GPX3",
+                       .to_irq = samsung_gpiolib_to_irq,
+               },
+       },
+#endif
+};
+
+static struct samsung_gpio_chip exynos5_gpios_2[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+       {
+               .chip   = {
+                       .base   = EXYNOS5_GPE0(0),
+                       .ngpio  = EXYNOS5_GPIO_E0_NR,
+                       .label  = "GPE0",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPE1(0),
+                       .ngpio  = EXYNOS5_GPIO_E1_NR,
+                       .label  = "GPE1",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPF0(0),
+                       .ngpio  = EXYNOS5_GPIO_F0_NR,
+                       .label  = "GPF0",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPF1(0),
+                       .ngpio  = EXYNOS5_GPIO_F1_NR,
+                       .label  = "GPF1",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPG0(0),
+                       .ngpio  = EXYNOS5_GPIO_G0_NR,
+                       .label  = "GPG0",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPG1(0),
+                       .ngpio  = EXYNOS5_GPIO_G1_NR,
+                       .label  = "GPG1",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPG2(0),
+                       .ngpio  = EXYNOS5_GPIO_G2_NR,
+                       .label  = "GPG2",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPH0(0),
+                       .ngpio  = EXYNOS5_GPIO_H0_NR,
+                       .label  = "GPH0",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPH1(0),
+                       .ngpio  = EXYNOS5_GPIO_H1_NR,
+                       .label  = "GPH1",
+
+               },
+       },
+#endif
+};
+
+static struct samsung_gpio_chip exynos5_gpios_3[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+       {
+               .chip   = {
+                       .base   = EXYNOS5_GPV0(0),
+                       .ngpio  = EXYNOS5_GPIO_V0_NR,
+                       .label  = "GPV0",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPV1(0),
+                       .ngpio  = EXYNOS5_GPIO_V1_NR,
+                       .label  = "GPV1",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPV2(0),
+                       .ngpio  = EXYNOS5_GPIO_V2_NR,
+                       .label  = "GPV2",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPV3(0),
+                       .ngpio  = EXYNOS5_GPIO_V3_NR,
+                       .label  = "GPV3",
+               },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPV4(0),
+                       .ngpio  = EXYNOS5_GPIO_V4_NR,
+                       .label  = "GPV4",
+               },
+       },
+#endif
+};
+
+static struct samsung_gpio_chip exynos5_gpios_4[] = {
+#ifdef CONFIG_ARCH_EXYNOS5
+       {
+               .chip   = {
+                       .base   = EXYNOS5_GPZ(0),
+                       .ngpio  = EXYNOS5_GPIO_Z_NR,
+                       .label  = "GPZ",
+               },
+       },
+#endif
+};
+
+
+#if defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF)
+static int exynos_gpio_xlate(struct gpio_chip *gc,
                        const struct of_phandle_args *gpiospec, u32 *flags)
 {
        unsigned int pin;
@@ -2413,13 +2681,13 @@ static int exynos4_gpio_xlate(struct gpio_chip *gc,
        return gpiospec->args[0];
 }
 
-static const struct of_device_id exynos4_gpio_dt_match[] __initdata = {
+static const struct of_device_id exynos_gpio_dt_match[] __initdata = {
        { .compatible = "samsung,exynos4-gpio", },
        {}
 };
 
-static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
-                                                u64 base, u64 offset)
+static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
+                                               u64 base, u64 offset)
 {
        struct gpio_chip *gc =  &chip->chip;
        u64 address;
@@ -2429,28 +2697,29 @@ static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
 
        address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset;
        gc->of_node = of_find_matching_node_by_address(NULL,
-                       exynos4_gpio_dt_match, address);
+                       exynos_gpio_dt_match, address);
        if (!gc->of_node) {
                pr_info("gpio: device tree node not found for gpio controller"
                        " with base address %08llx\n", address);
                return;
        }
        gc->of_gpio_n_cells = 4;
-       gc->of_xlate = exynos4_gpio_xlate;
+       gc->of_xlate = exynos_gpio_xlate;
 }
-#elif defined(CONFIG_ARCH_EXYNOS4)
-static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
-                                                u64 base, u64 offset)
+#elif defined(CONFIG_ARCH_EXYNOS)
+static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
+                                               u64 base, u64 offset)
 {
        return;
 }
-#endif /* defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) */
+#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */
 
 /* TODO: cleanup soc_is_* */
 static __init int samsung_gpiolib_init(void)
 {
        struct samsung_gpio_chip *chip;
        int i, nr_chips;
+       void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4;
        int group = 0;
 
        samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs));
@@ -2516,66 +2785,200 @@ static __init int samsung_gpiolib_init(void)
                s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
 #endif
        } else if (soc_is_exynos4210()) {
-               group = 0;
+#ifdef CONFIG_CPU_EXYNOS4210
+               void __iomem *gpx_base;
 
                /* gpio part1 */
+               gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
+               if (gpio_base1 == NULL) {
+                       pr_err("unable to ioremap for gpio_base1\n");
+                       goto err_ioremap1;
+               }
+
                chip = exynos4_gpios_1;
                nr_chips = ARRAY_SIZE(exynos4_gpios_1);
 
                for (i = 0; i < nr_chips; i++, chip++) {
                        if (!chip->config) {
-                               chip->config = &exynos4_gpio_cfg;
+                               chip->config = &exynos_gpio_cfg;
                                chip->group = group++;
                        }
-#ifdef CONFIG_CPU_EXYNOS4210
-                       exynos4_gpiolib_attach_ofnode(chip,
+                       exynos_gpiolib_attach_ofnode(chip,
                                        EXYNOS4_PA_GPIO1, i * 0x20);
-#endif
                }
-               samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, nr_chips, S5P_VA_GPIO1);
+               samsung_gpiolib_add_4bit_chips(exynos4_gpios_1,
+                                              nr_chips, gpio_base1);
 
                /* gpio part2 */
+               gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
+               if (gpio_base2 == NULL) {
+                       pr_err("unable to ioremap for gpio_base2\n");
+                       goto err_ioremap2;
+               }
+
+               /* need to set base address for gpx */
+               chip = &exynos4_gpios_2[16];
+               gpx_base = gpio_base2 + 0xC00;
+               for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
+                       chip->base = gpx_base;
+
                chip = exynos4_gpios_2;
                nr_chips = ARRAY_SIZE(exynos4_gpios_2);
 
                for (i = 0; i < nr_chips; i++, chip++) {
                        if (!chip->config) {
-                               chip->config = &exynos4_gpio_cfg;
+                               chip->config = &exynos_gpio_cfg;
                                chip->group = group++;
                        }
-#ifdef CONFIG_CPU_EXYNOS4210
-                       exynos4_gpiolib_attach_ofnode(chip,
+                       exynos_gpiolib_attach_ofnode(chip,
                                        EXYNOS4_PA_GPIO2, i * 0x20);
-#endif
                }
-               samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, nr_chips, S5P_VA_GPIO2);
+               samsung_gpiolib_add_4bit_chips(exynos4_gpios_2,
+                                              nr_chips, gpio_base2);
 
                /* gpio part3 */
+               gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256);
+               if (gpio_base3 == NULL) {
+                       pr_err("unable to ioremap for gpio_base3\n");
+                       goto err_ioremap3;
+               }
+
                chip = exynos4_gpios_3;
                nr_chips = ARRAY_SIZE(exynos4_gpios_3);
 
                for (i = 0; i < nr_chips; i++, chip++) {
                        if (!chip->config) {
-                               chip->config = &exynos4_gpio_cfg;
+                               chip->config = &exynos_gpio_cfg;
                                chip->group = group++;
                        }
-#ifdef CONFIG_CPU_EXYNOS4210
-                       exynos4_gpiolib_attach_ofnode(chip,
+                       exynos_gpiolib_attach_ofnode(chip,
                                        EXYNOS4_PA_GPIO3, i * 0x20);
-#endif
                }
-               samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, nr_chips, S5P_VA_GPIO3);
+               samsung_gpiolib_add_4bit_chips(exynos4_gpios_3,
+                                              nr_chips, gpio_base3);
 
 #if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT)
                s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
                s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
 #endif
+
+#endif /* CONFIG_CPU_EXYNOS4210 */
+       } else if (soc_is_exynos5250()) {
+#ifdef CONFIG_SOC_EXYNOS5250
+               void __iomem *gpx_base;
+
+               /* gpio part1 */
+               gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
+               if (gpio_base1 == NULL) {
+                       pr_err("unable to ioremap for gpio_base1\n");
+                       goto err_ioremap1;
+               }
+
+               /* need to set base address for gpx */
+               chip = &exynos5_gpios_1[20];
+               gpx_base = gpio_base1 + 0xC00;
+               for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
+                       chip->base = gpx_base;
+
+               chip = exynos5_gpios_1;
+               nr_chips = ARRAY_SIZE(exynos5_gpios_1);
+
+               for (i = 0; i < nr_chips; i++, chip++) {
+                       if (!chip->config) {
+                               chip->config = &exynos_gpio_cfg;
+                               chip->group = group++;
+                       }
+                       exynos_gpiolib_attach_ofnode(chip,
+                                       EXYNOS5_PA_GPIO1, i * 0x20);
+               }
+               samsung_gpiolib_add_4bit_chips(exynos5_gpios_1,
+                                              nr_chips, gpio_base1);
+
+               /* gpio part2 */
+               gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K);
+               if (gpio_base2 == NULL) {
+                       pr_err("unable to ioremap for gpio_base2\n");
+                       goto err_ioremap2;
+               }
+
+               chip = exynos5_gpios_2;
+               nr_chips = ARRAY_SIZE(exynos5_gpios_2);
+
+               for (i = 0; i < nr_chips; i++, chip++) {
+                       if (!chip->config) {
+                               chip->config = &exynos_gpio_cfg;
+                               chip->group = group++;
+                       }
+                       exynos_gpiolib_attach_ofnode(chip,
+                                       EXYNOS5_PA_GPIO2, i * 0x20);
+               }
+               samsung_gpiolib_add_4bit_chips(exynos5_gpios_2,
+                                              nr_chips, gpio_base2);
+
+               /* gpio part3 */
+               gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K);
+               if (gpio_base3 == NULL) {
+                       pr_err("unable to ioremap for gpio_base3\n");
+                       goto err_ioremap3;
+               }
+
+               /* need to set base address for gpv */
+               exynos5_gpios_3[0].base = gpio_base3;
+               exynos5_gpios_3[1].base = gpio_base3 + 0x20;
+               exynos5_gpios_3[2].base = gpio_base3 + 0x60;
+               exynos5_gpios_3[3].base = gpio_base3 + 0x80;
+               exynos5_gpios_3[4].base = gpio_base3 + 0xC0;
+
+               chip = exynos5_gpios_3;
+               nr_chips = ARRAY_SIZE(exynos5_gpios_3);
+
+               for (i = 0; i < nr_chips; i++, chip++) {
+                       if (!chip->config) {
+                               chip->config = &exynos_gpio_cfg;
+                               chip->group = group++;
+                       }
+                       exynos_gpiolib_attach_ofnode(chip,
+                                       EXYNOS5_PA_GPIO3, i * 0x20);
+               }
+               samsung_gpiolib_add_4bit_chips(exynos5_gpios_3,
+                                              nr_chips, gpio_base3);
+
+               /* gpio part4 */
+               gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K);
+               if (gpio_base4 == NULL) {
+                       pr_err("unable to ioremap for gpio_base4\n");
+                       goto err_ioremap4;
+               }
+
+               chip = exynos5_gpios_4;
+               nr_chips = ARRAY_SIZE(exynos5_gpios_4);
+
+               for (i = 0; i < nr_chips; i++, chip++) {
+                       if (!chip->config) {
+                               chip->config = &exynos_gpio_cfg;
+                               chip->group = group++;
+                       }
+                       exynos_gpiolib_attach_ofnode(chip,
+                                       EXYNOS5_PA_GPIO4, i * 0x20);
+               }
+               samsung_gpiolib_add_4bit_chips(exynos5_gpios_4,
+                                              nr_chips, gpio_base4);
+#endif /* CONFIG_SOC_EXYNOS5250 */
        } else {
                WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n");
                return -ENODEV;
        }
 
        return 0;
+
+err_ioremap4:
+       iounmap(gpio_base3);
+err_ioremap3:
+       iounmap(gpio_base2);
+err_ioremap2:
+       iounmap(gpio_base1);
+err_ioremap1:
+       return -ENOMEM;
 }
 core_initcall(samsung_gpiolib_init);
 
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
new file mode 100644 (file)
index 0000000..9ba15d3
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ *  GPIO interface for Intel Sodaville SoCs.
+ *
+ *  Copyright (c) 2010, 2011 Intel Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/basic_mmio_gpio.h>
+
+#define DRV_NAME               "sdv_gpio"
+#define SDV_NUM_PUB_GPIOS      12
+#define PCI_DEVICE_ID_SDV_GPIO 0x2e67
+#define GPIO_BAR               0
+
+#define GPOUTR         0x00
+#define GPOER          0x04
+#define GPINR          0x08
+
+#define GPSTR          0x0c
+#define GPIT1R0                0x10
+#define GPIO_INT       0x14
+#define GPIT1R1                0x18
+
+#define GPMUXCTL       0x1c
+
+struct sdv_gpio_chip_data {
+       int irq_base;
+       void __iomem *gpio_pub_base;
+       struct irq_domain id;
+       struct irq_chip_generic *gc;
+       struct bgpio_chip bgpio;
+};
+
+static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct sdv_gpio_chip_data *sd = gc->private;
+       void __iomem *type_reg;
+       u32 irq_offs = d->irq - sd->irq_base;
+       u32 reg;
+
+       if (irq_offs < 8)
+               type_reg = sd->gpio_pub_base + GPIT1R0;
+       else
+               type_reg = sd->gpio_pub_base + GPIT1R1;
+
+       reg = readl(type_reg);
+
+       switch (type) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               reg &= ~BIT(4 * (irq_offs % 8));
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               reg |= BIT(4 * (irq_offs % 8));
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       writel(reg, type_reg);
+       return 0;
+}
+
+static irqreturn_t sdv_gpio_pub_irq_handler(int irq, void *data)
+{
+       struct sdv_gpio_chip_data *sd = data;
+       u32 irq_stat = readl(sd->gpio_pub_base + GPSTR);
+
+       irq_stat &= readl(sd->gpio_pub_base + GPIO_INT);
+       if (!irq_stat)
+               return IRQ_NONE;
+
+       while (irq_stat) {
+               u32 irq_bit = __fls(irq_stat);
+
+               irq_stat &= ~BIT(irq_bit);
+               generic_handle_irq(sd->irq_base + irq_bit);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int sdv_xlate(struct irq_domain *h, struct device_node *node,
+               const u32 *intspec, u32 intsize, irq_hw_number_t *out_hwirq,
+               u32 *out_type)
+{
+       u32 line, type;
+
+       if (node != h->of_node)
+               return -EINVAL;
+
+       if (intsize < 2)
+               return -EINVAL;
+
+       line = *intspec;
+       *out_hwirq = line;
+
+       intspec++;
+       type = *intspec;
+
+       switch (type) {
+       case IRQ_TYPE_LEVEL_LOW:
+       case IRQ_TYPE_LEVEL_HIGH:
+               *out_type = type;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static struct irq_domain_ops irq_domain_sdv_ops = {
+       .dt_translate   = sdv_xlate,
+};
+
+static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
+               struct pci_dev *pdev)
+{
+       struct irq_chip_type *ct;
+       int ret;
+
+       sd->irq_base = irq_alloc_descs(-1, 0, SDV_NUM_PUB_GPIOS, -1);
+       if (sd->irq_base < 0)
+               return sd->irq_base;
+
+       /* mask + ACK all interrupt sources */
+       writel(0, sd->gpio_pub_base + GPIO_INT);
+       writel((1 << 11) - 1, sd->gpio_pub_base + GPSTR);
+
+       ret = request_irq(pdev->irq, sdv_gpio_pub_irq_handler, IRQF_SHARED,
+                       "sdv_gpio", sd);
+       if (ret)
+               goto out_free_desc;
+
+       sd->id.irq_base = sd->irq_base;
+       sd->id.of_node = of_node_get(pdev->dev.of_node);
+       sd->id.ops = &irq_domain_sdv_ops;
+
+       /*
+        * This gpio irq controller latches level irqs. Testing shows that if
+        * we unmask & ACK the IRQ before the source of the interrupt is gone
+        * then the interrupt is active again.
+        */
+       sd->gc = irq_alloc_generic_chip("sdv-gpio", 1, sd->irq_base,
+                       sd->gpio_pub_base, handle_fasteoi_irq);
+       if (!sd->gc) {
+               ret = -ENOMEM;
+               goto out_free_irq;
+       }
+
+       sd->gc->private = sd;
+       ct = sd->gc->chip_types;
+       ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
+       ct->regs.eoi = GPSTR;
+       ct->regs.mask = GPIO_INT;
+       ct->chip.irq_mask = irq_gc_mask_clr_bit;
+       ct->chip.irq_unmask = irq_gc_mask_set_bit;
+       ct->chip.irq_eoi = irq_gc_eoi;
+       ct->chip.irq_set_type = sdv_gpio_pub_set_type;
+
+       irq_setup_generic_chip(sd->gc, IRQ_MSK(SDV_NUM_PUB_GPIOS),
+                       IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST,
+                       IRQ_LEVEL | IRQ_NOPROBE);
+
+       irq_domain_add(&sd->id);
+       return 0;
+out_free_irq:
+       free_irq(pdev->irq, sd);
+out_free_desc:
+       irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
+       return ret;
+}
+
+static int __devinit sdv_gpio_probe(struct pci_dev *pdev,
+                                       const struct pci_device_id *pci_id)
+{
+       struct sdv_gpio_chip_data *sd;
+       unsigned long addr;
+       const void *prop;
+       int len;
+       int ret;
+       u32 mux_val;
+
+       sd = kzalloc(sizeof(struct sdv_gpio_chip_data), GFP_KERNEL);
+       if (!sd)
+               return -ENOMEM;
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "can't enable device.\n");
+               goto done;
+       }
+
+       ret = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
+       if (ret) {
+               dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
+               goto disable_pci;
+       }
+
+       addr = pci_resource_start(pdev, GPIO_BAR);
+       if (!addr)
+               goto release_reg;
+       sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR));
+
+       prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len);
+       if (prop && len == 4) {
+               mux_val = of_read_number(prop, 1);
+               writel(mux_val, sd->gpio_pub_base + GPMUXCTL);
+       }
+
+       ret = bgpio_init(&sd->bgpio, &pdev->dev, 4,
+                       sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR,
+                       NULL, sd->gpio_pub_base + GPOER, NULL, false);
+       if (ret)
+               goto unmap;
+       sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS;
+
+       ret = gpiochip_add(&sd->bgpio.gc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "gpiochip_add() failed.\n");
+               goto unmap;
+       }
+
+       ret = sdv_register_irqsupport(sd, pdev);
+       if (ret)
+               goto unmap;
+
+       pci_set_drvdata(pdev, sd);
+       dev_info(&pdev->dev, "Sodaville GPIO driver registered.\n");
+       return 0;
+
+unmap:
+       iounmap(sd->gpio_pub_base);
+release_reg:
+       pci_release_region(pdev, GPIO_BAR);
+disable_pci:
+       pci_disable_device(pdev);
+done:
+       kfree(sd);
+       return ret;
+}
+
+static void sdv_gpio_remove(struct pci_dev *pdev)
+{
+       struct sdv_gpio_chip_data *sd = pci_get_drvdata(pdev);
+
+       irq_domain_del(&sd->id);
+       free_irq(pdev->irq, sd);
+       irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
+
+       if (gpiochip_remove(&sd->bgpio.gc))
+               dev_err(&pdev->dev, "gpiochip_remove() failed.\n");
+
+       pci_release_region(pdev, GPIO_BAR);
+       iounmap(sd->gpio_pub_base);
+       pci_disable_device(pdev);
+       kfree(sd);
+}
+
+static struct pci_device_id sdv_gpio_pci_ids[] __devinitdata = {
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) },
+       { 0, },
+};
+
+static struct pci_driver sdv_gpio_driver = {
+       .name = DRV_NAME,
+       .id_table = sdv_gpio_pci_ids,
+       .probe = sdv_gpio_probe,
+       .remove = sdv_gpio_remove,
+};
+
+static int __init sdv_gpio_init(void)
+{
+       return pci_register_driver(&sdv_gpio_driver);
+}
+module_init(sdv_gpio_init);
+
+static void __exit sdv_gpio_exit(void)
+{
+       pci_unregister_driver(&sdv_gpio_driver);
+}
+module_exit(sdv_gpio_exit);
+
+MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>");
+MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs");
+MODULE_LICENSE("GPL v2");
index 87a68a8..dce3472 100644 (file)
@@ -54,7 +54,7 @@ static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
        if (ret < 0)
                return ret;
 
-       return ret & mask;
+       return !!(ret & mask);
 }
 
 static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
@@ -307,13 +307,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
        struct stmpe_gpio_platform_data *pdata;
        struct stmpe_gpio *stmpe_gpio;
        int ret;
-       int irq;
+       int irq = 0;
 
        pdata = stmpe->pdata->gpio;
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
 
        stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
        if (!stmpe_gpio)
@@ -330,21 +328,28 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
        stmpe_gpio->chip.dev = &pdev->dev;
        stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
 
-       stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+       if (irq >= 0)
+               stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+       else
+               dev_info(&pdev->dev,
+                       "device configured in no-irq mode; "
+                       "irqs are not available\n");
 
        ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
        if (ret)
                goto out_free;
 
-       ret = stmpe_gpio_irq_init(stmpe_gpio);
-       if (ret)
-               goto out_disable;
+       if (irq >= 0) {
+               ret = stmpe_gpio_irq_init(stmpe_gpio);
+               if (ret)
+                       goto out_disable;
 
-       ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
-                                  "stmpe-gpio", stmpe_gpio);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
-               goto out_removeirq;
+               ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq,
+                               IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio);
+               if (ret) {
+                       dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
+                       goto out_removeirq;
+               }
        }
 
        ret = gpiochip_add(&stmpe_gpio->chip);
@@ -361,9 +366,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
        return 0;
 
 out_freeirq:
-       free_irq(irq, stmpe_gpio);
+       if (irq >= 0)
+               free_irq(irq, stmpe_gpio);
 out_removeirq:
-       stmpe_gpio_irq_remove(stmpe_gpio);
+       if (irq >= 0)
+               stmpe_gpio_irq_remove(stmpe_gpio);
 out_disable:
        stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 out_free:
@@ -391,8 +398,10 @@ static int __devexit stmpe_gpio_remove(struct platform_device *pdev)
 
        stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 
-       free_irq(irq, stmpe_gpio);
-       stmpe_gpio_irq_remove(stmpe_gpio);
+       if (irq >= 0) {
+               free_irq(irq, stmpe_gpio);
+               stmpe_gpio_irq_remove(stmpe_gpio);
+       }
        platform_set_drvdata(pdev, NULL);
        kfree(stmpe_gpio);
 
index bdc2937..32de670 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/irqdomain.h>
 
 #include <asm/mach/irq.h>
 
@@ -74,9 +75,10 @@ struct tegra_gpio_bank {
 #endif
 };
 
-
+static struct irq_domain *irq_domain;
 static void __iomem *regs;
-static struct tegra_gpio_bank tegra_gpio_banks[7];
+static u32 tegra_gpio_bank_count;
+static struct tegra_gpio_bank *tegra_gpio_banks;
 
 static inline void tegra_gpio_writel(u32 val, u32 reg)
 {
@@ -107,11 +109,13 @@ void tegra_gpio_enable(int gpio)
 {
        tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
 }
+EXPORT_SYMBOL_GPL(tegra_gpio_enable);
 
 void tegra_gpio_disable(int gpio)
 {
        tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
 }
+EXPORT_SYMBOL_GPL(tegra_gpio_disable);
 
 static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
@@ -139,7 +143,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 
 static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-       return TEGRA_GPIO_TO_IRQ(offset);
+       return irq_find_mapping(irq_domain, offset);
 }
 
 static struct gpio_chip tegra_gpio_chip = {
@@ -155,28 +159,28 @@ static struct gpio_chip tegra_gpio_chip = {
 
 static void tegra_gpio_irq_ack(struct irq_data *d)
 {
-       int gpio = d->irq - INT_GPIO_BASE;
+       int gpio = d->hwirq;
 
        tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
 }
 
 static void tegra_gpio_irq_mask(struct irq_data *d)
 {
-       int gpio = d->irq - INT_GPIO_BASE;
+       int gpio = d->hwirq;
 
        tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0);
 }
 
 static void tegra_gpio_irq_unmask(struct irq_data *d)
 {
-       int gpio = d->irq - INT_GPIO_BASE;
+       int gpio = d->hwirq;
 
        tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1);
 }
 
 static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
-       int gpio = d->irq - INT_GPIO_BASE;
+       int gpio = d->hwirq;
        struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
        int port = GPIO_PORT(gpio);
        int lvl_type;
@@ -273,7 +277,7 @@ void tegra_gpio_resume(void)
 
        local_irq_save(flags);
 
-       for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
+       for (b = 0; b < tegra_gpio_bank_count; b++) {
                struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
 
                for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
@@ -296,7 +300,7 @@ void tegra_gpio_suspend(void)
        int p;
 
        local_irq_save(flags);
-       for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
+       for (b = 0; b < tegra_gpio_bank_count; b++) {
                struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
 
                for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
@@ -337,13 +341,44 @@ static struct lock_class_key gpio_lock_class;
 
 static int __devinit tegra_gpio_probe(struct platform_device *pdev)
 {
+       int irq_base;
        struct resource *res;
        struct tegra_gpio_bank *bank;
        int gpio;
        int i;
        int j;
 
-       for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
+       for (;;) {
+               res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count);
+               if (!res)
+                       break;
+               tegra_gpio_bank_count++;
+       }
+       if (!tegra_gpio_bank_count) {
+               dev_err(&pdev->dev, "Missing IRQ resource\n");
+               return -ENODEV;
+       }
+
+       tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32;
+
+       tegra_gpio_banks = devm_kzalloc(&pdev->dev,
+                       tegra_gpio_bank_count * sizeof(*tegra_gpio_banks),
+                       GFP_KERNEL);
+       if (!tegra_gpio_banks) {
+               dev_err(&pdev->dev, "Couldn't allocate bank structure\n");
+               return -ENODEV;
+       }
+
+       irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0);
+       if (irq_base < 0) {
+               dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n");
+               return -ENODEV;
+       }
+       irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
+                                          tegra_gpio_chip.ngpio, irq_base, 0,
+                                          &irq_domain_simple_ops, NULL);
+
+       for (i = 0; i < tegra_gpio_bank_count; i++) {
                res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
                if (!res) {
                        dev_err(&pdev->dev, "Missing IRQ resource\n");
@@ -380,8 +415,8 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
 
        gpiochip_add(&tegra_gpio_chip);
 
-       for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) {
-               int irq = TEGRA_GPIO_TO_IRQ(gpio);
+       for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) {
+               int irq = irq_find_mapping(irq_domain, gpio);
                /* No validity check; all Tegra GPIOs are valid IRQs */
 
                bank = &tegra_gpio_banks[GPIO_BANK(gpio)];
@@ -393,7 +428,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
                set_irq_flags(irq, IRQF_VALID);
        }
 
-       for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
+       for (i = 0; i < tegra_gpio_bank_count; i++) {
                bank = &tegra_gpio_banks[i];
 
                irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler);
@@ -426,7 +461,7 @@ static int __init tegra_gpio_init(void)
 }
 postcore_initcall(tegra_gpio_init);
 
-void __init tegra_gpio_config(struct tegra_gpio_table *table, int num)
+void tegra_gpio_config(struct tegra_gpio_table *table, int num)
 {
        int i;
 
index 91f45b9..7eef648 100644 (file)
@@ -69,6 +69,7 @@ static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
 void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
 {
        int ret;
+       struct tps65910_board *board_data;
 
        if (!gpio_base)
                return;
@@ -80,10 +81,10 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
 
        switch(tps65910_chip_id(tps65910)) {
        case TPS65910:
-               tps65910->gpio.ngpio    = 6;
+               tps65910->gpio.ngpio    = TPS65910_NUM_GPIO;
                break;
        case TPS65911:
-               tps65910->gpio.ngpio    = 9;
+               tps65910->gpio.ngpio    = TPS65911_NUM_GPIO;
                break;
        default:
                return;
@@ -95,6 +96,21 @@ void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
        tps65910->gpio.set              = tps65910_gpio_set;
        tps65910->gpio.get              = tps65910_gpio_get;
 
+       /* Configure sleep control for gpios */
+       board_data = dev_get_platdata(tps65910->dev);
+       if (board_data) {
+               int i;
+               for (i = 0; i < tps65910->gpio.ngpio; ++i) {
+                       if (board_data->en_gpio_sleep[i]) {
+                               ret = tps65910_set_bits(tps65910,
+                                       TPS65910_GPIO0 + i, GPIO_SLEEP_MASK);
+                               if (ret < 0)
+                                       dev_warn(tps65910->dev,
+                                               "GPIO Sleep setting failed\n");
+                       }
+               }
+       }
+
        ret = gpiochip_add(&tps65910->gpio);
 
        if (ret)
index b8b4f22..94256fe 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/irq.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 
 #include <linux/i2c/twl.h>
 
@@ -256,7 +258,8 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
                 * and vMMC2 power supplies based on card presence.
                 */
                pdata = chip->dev->platform_data;
-               value |= pdata->mmc_cd & 0x03;
+               if (pdata)
+                       value |= pdata->mmc_cd & 0x03;
 
                status = gpio_twl4030_write(REG_GPIO_CTRL, value);
        }
@@ -395,59 +398,70 @@ static int gpio_twl4030_remove(struct platform_device *pdev);
 static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
 {
        struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
-       int ret;
+       struct device_node *node = pdev->dev.of_node;
+       int ret, irq_base;
 
        /* maybe setup IRQs */
-       if (pdata->irq_base) {
-               if (is_module()) {
-                       dev_err(&pdev->dev,
-                               "can't dispatch IRQs from modules\n");
-                       goto no_irqs;
-               }
-               ret = twl4030_sih_setup(TWL4030_MODULE_GPIO);
-               if (ret < 0)
-                       return ret;
-               WARN_ON(ret != pdata->irq_base);
-               twl4030_gpio_irq_base = ret;
+       if (is_module()) {
+               dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
+               goto no_irqs;
+       }
+
+       irq_base = irq_alloc_descs(-1, 0, TWL4030_GPIO_MAX, 0);
+       if (irq_base < 0) {
+               dev_err(&pdev->dev, "Failed to alloc irq_descs\n");
+               return irq_base;
        }
 
+       irq_domain_add_legacy(node, TWL4030_GPIO_MAX, irq_base, 0,
+                             &irq_domain_simple_ops, NULL);
+
+       ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, irq_base);
+       if (ret < 0)
+               return ret;
+
+       twl4030_gpio_irq_base = irq_base;
+
 no_irqs:
-       /*
-        * NOTE:  boards may waste power if they don't set pullups
-        * and pulldowns correctly ... default for non-ULPI pins is
-        * pulldown, and some other pins may have external pullups
-        * or pulldowns.  Careful!
-        */
-       ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
-       if (ret)
-               dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
-                               pdata->pullups, pdata->pulldowns,
-                               ret);
-
-       ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
-       if (ret)
-               dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
-                               pdata->debounce, pdata->mmc_cd,
-                               ret);
-
-       twl_gpiochip.base = pdata->gpio_base;
+       twl_gpiochip.base = -1;
        twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
        twl_gpiochip.dev = &pdev->dev;
 
-       /* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
-        * is (still) clear if use_leds is set.
-        */
-       if (pdata->use_leds)
-               twl_gpiochip.ngpio += 2;
+       if (pdata) {
+               twl_gpiochip.base = pdata->gpio_base;
+
+               /*
+                * NOTE:  boards may waste power if they don't set pullups
+                * and pulldowns correctly ... default for non-ULPI pins is
+                * pulldown, and some other pins may have external pullups
+                * or pulldowns.  Careful!
+                */
+               ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
+               if (ret)
+                       dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
+                                       pdata->pullups, pdata->pulldowns,
+                                       ret);
+
+               ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
+               if (ret)
+                       dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
+                                       pdata->debounce, pdata->mmc_cd,
+                                       ret);
+
+               /*
+                * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
+                * is (still) clear if use_leds is set.
+                */
+               if (pdata->use_leds)
+                       twl_gpiochip.ngpio += 2;
+       }
 
        ret = gpiochip_add(&twl_gpiochip);
        if (ret < 0) {
-               dev_err(&pdev->dev,
-                               "could not register gpiochip, %d\n",
-                               ret);
+               dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
                twl_gpiochip.ngpio = 0;
                gpio_twl4030_remove(pdev);
-       } else if (pdata->setup) {
+       } else if (pdata && pdata->setup) {
                int status;
 
                status = pdata->setup(&pdev->dev,
@@ -465,7 +479,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
        struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
        int status;
 
-       if (pdata->teardown) {
+       if (pdata && pdata->teardown) {
                status = pdata->teardown(&pdev->dev,
                                pdata->gpio_base, TWL4030_GPIO_MAX);
                if (status) {
@@ -486,12 +500,21 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
        return -EIO;
 }
 
+static const struct of_device_id twl_gpio_match[] = {
+       { .compatible = "ti,twl4030-gpio", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, twl_gpio_match);
+
 /* Note:  this hardware lives inside an I2C-based multi-function device. */
 MODULE_ALIAS("platform:twl4030_gpio");
 
 static struct platform_driver gpio_twl4030_driver = {
-       .driver.name    = "twl4030_gpio",
-       .driver.owner   = THIS_MODULE,
+       .driver = {
+               .name   = "twl4030_gpio",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(twl_gpio_match),
+       },
        .probe          = gpio_twl4030_probe,
        .remove         = gpio_twl4030_remove,
 };
index 17fdf4b..5a75510 100644 (file)
@@ -58,6 +58,8 @@ struct gpio_desc {
 #define FLAG_TRIG_FALL 5       /* trigger on falling edge */
 #define FLAG_TRIG_RISE 6       /* trigger on rising edge */
 #define FLAG_ACTIVE_LOW        7       /* sysfs value has active low */
+#define FLAG_OPEN_DRAIN        8       /* Gpio is open drain type */
+#define FLAG_OPEN_SOURCE 9     /* Gpio is open source type */
 
 #define ID_SHIFT       16      /* add new flags before this one */
 
@@ -873,6 +875,7 @@ void gpio_unexport(unsigned gpio)
 {
        struct gpio_desc        *desc;
        int                     status = 0;
+       struct device           *dev = NULL;
 
        if (!gpio_is_valid(gpio)) {
                status = -EINVAL;
@@ -884,19 +887,20 @@ void gpio_unexport(unsigned gpio)
        desc = &gpio_desc[gpio];
 
        if (test_bit(FLAG_EXPORT, &desc->flags)) {
-               struct device   *dev = NULL;
 
                dev = class_find_device(&gpio_class, NULL, desc, match_export);
                if (dev) {
                        gpio_setup_irq(desc, dev, 0);
                        clear_bit(FLAG_EXPORT, &desc->flags);
-                       put_device(dev);
-                       device_unregister(dev);
                } else
                        status = -ENODEV;
        }
 
        mutex_unlock(&sysfs_lock);
+       if (dev) {
+               device_unregister(dev);
+               put_device(dev);
+       }
 done:
        if (status)
                pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
@@ -1150,8 +1154,9 @@ EXPORT_SYMBOL_GPL(gpiochip_remove);
  * non-zero, this function will return to the caller and not iterate over any
  * more gpio_chips.
  */
-struct gpio_chip *gpiochip_find(void *data,
-                               int (*match)(struct gpio_chip *chip, void *data))
+struct gpio_chip *gpiochip_find(const void *data,
+                               int (*match)(struct gpio_chip *chip,
+                                            const void *data))
 {
        struct gpio_chip *chip = NULL;
        unsigned long flags;
@@ -1261,6 +1266,8 @@ void gpio_free(unsigned gpio)
                module_put(desc->chip->owner);
                clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
                clear_bit(FLAG_REQUESTED, &desc->flags);
+               clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
+               clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
        } else
                WARN_ON(extra_checks);
 
@@ -1282,6 +1289,12 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
        if (err)
                return err;
 
+       if (flags & GPIOF_OPEN_DRAIN)
+               set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags);
+
+       if (flags & GPIOF_OPEN_SOURCE)
+               set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags);
+
        if (flags & GPIOF_DIR_IN)
                err = gpio_direction_input(gpio);
        else
@@ -1431,6 +1444,14 @@ int gpio_direction_output(unsigned gpio, int value)
        struct gpio_desc        *desc = &gpio_desc[gpio];
        int                     status = -EINVAL;
 
+       /* Open drain pin should not be driven to 1 */
+       if (value && test_bit(FLAG_OPEN_DRAIN,  &desc->flags))
+               return gpio_direction_input(gpio);
+
+       /* Open source pin should not be driven to 0 */
+       if (!value && test_bit(FLAG_OPEN_SOURCE,  &desc->flags))
+               return gpio_direction_input(gpio);
+
        spin_lock_irqsave(&gpio_lock, flags);
 
        if (!gpio_is_valid(gpio))
@@ -1560,6 +1581,7 @@ int __gpio_get_value(unsigned gpio)
        int value;
 
        chip = gpio_to_chip(gpio);
+       /* Should be using gpio_get_value_cansleep() */
        WARN_ON(chip->can_sleep);
        value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
        trace_gpio_value(gpio, 1, value);
@@ -1567,6 +1589,57 @@ int __gpio_get_value(unsigned gpio)
 }
 EXPORT_SYMBOL_GPL(__gpio_get_value);
 
+/*
+ *  _gpio_set_open_drain_value() - Set the open drain gpio's value.
+ * @gpio: Gpio whose state need to be set.
+ * @chip: Gpio chip.
+ * @value: Non-zero for setting it HIGH otherise it will set to LOW.
+ */
+static void _gpio_set_open_drain_value(unsigned gpio,
+                       struct gpio_chip *chip, int value)
+{
+       int err = 0;
+       if (value) {
+               err = chip->direction_input(chip, gpio - chip->base);
+               if (!err)
+                       clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+       } else {
+               err = chip->direction_output(chip, gpio - chip->base, 0);
+               if (!err)
+                       set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+       }
+       trace_gpio_direction(gpio, value, err);
+       if (err < 0)
+               pr_err("%s: Error in set_value for open drain gpio%d err %d\n",
+                                       __func__, gpio, err);
+}
+
+/*
+ *  _gpio_set_open_source() - Set the open source gpio's value.
+ * @gpio: Gpio whose state need to be set.
+ * @chip: Gpio chip.
+ * @value: Non-zero for setting it HIGH otherise it will set to LOW.
+ */
+static void _gpio_set_open_source_value(unsigned gpio,
+                       struct gpio_chip *chip, int value)
+{
+       int err = 0;
+       if (value) {
+               err = chip->direction_output(chip, gpio - chip->base, 1);
+               if (!err)
+                       set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+       } else {
+               err = chip->direction_input(chip, gpio - chip->base);
+               if (!err)
+                       clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+       }
+       trace_gpio_direction(gpio, !value, err);
+       if (err < 0)
+               pr_err("%s: Error in set_value for open source gpio%d err %d\n",
+                                       __func__, gpio, err);
+}
+
+
 /**
  * __gpio_set_value() - assign a gpio's value
  * @gpio: gpio whose value will be assigned
@@ -1581,9 +1654,15 @@ void __gpio_set_value(unsigned gpio, int value)
        struct gpio_chip        *chip;
 
        chip = gpio_to_chip(gpio);
+       /* Should be using gpio_set_value_cansleep() */
        WARN_ON(chip->can_sleep);
        trace_gpio_value(gpio, 0, value);
-       chip->set(chip, gpio - chip->base, value);
+       if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
+               _gpio_set_open_drain_value(gpio, chip, value);
+       else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
+               _gpio_set_open_source_value(gpio, chip, value);
+       else
+               chip->set(chip, gpio - chip->base, value);
 }
 EXPORT_SYMBOL_GPL(__gpio_set_value);
 
@@ -1650,7 +1729,12 @@ void gpio_set_value_cansleep(unsigned gpio, int value)
        might_sleep_if(extra_checks);
        chip = gpio_to_chip(gpio);
        trace_gpio_value(gpio, 0, value);
-       chip->set(chip, gpio - chip->base, value);
+       if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
+               _gpio_set_open_drain_value(gpio, chip, value);
+       else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
+               _gpio_set_open_source_value(gpio, chip, value);
+       else
+               chip->set(chip, gpio - chip->base, value);
 }
 EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
 
index 4c2cb4a..5675d93 100644 (file)
@@ -244,7 +244,6 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
                                uint64_t value)
 {
        struct drm_encoder *encoder = connector->encoder;
-       struct backlight_device *psb_bd;
 
        if (!strcmp(property->name, "scaling mode") && encoder) {
                struct psb_intel_crtc *psb_crtc =
@@ -301,11 +300,15 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
                                                                        value))
                        goto set_prop_error;
                else {
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+                       struct backlight_device *psb_bd;
+
                        psb_bd = mdfld_get_backlight_device();
                        if (psb_bd) {
                                psb_bd->props.brightness = value;
                                mdfld_set_brightness(psb_bd);
                        }
+#endif
                }
        }
 set_prop_done:
index 8f510fd..fa86035 100644 (file)
@@ -654,10 +654,13 @@ nouveau_connector_detect_depth(struct drm_connector *connector)
        if (nv_connector->edid && connector->display_info.bpc)
                return;
 
-       /* if not, we're out of options unless we're LVDS, default to 6bpc */
-       connector->display_info.bpc = 6;
-       if (nv_encoder->dcb->type != OUTPUT_LVDS)
+       /* if not, we're out of options unless we're LVDS, default to 8bpc */
+       if (nv_encoder->dcb->type != OUTPUT_LVDS) {
+               connector->display_info.bpc = 8;
                return;
+       }
+
+       connector->display_info.bpc = 6;
 
        /* LVDS: panel straps */
        if (bios->fp_no_ddc) {
index 8f4f914..e2be95a 100644 (file)
@@ -315,8 +315,8 @@ nouveau_i2c_init(struct drm_device *dev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nvbios *bios = &dev_priv->vbios;
        struct nouveau_i2c_chan *port;
+       u8 version = 0x00, entries, recordlen;
        u8 *i2c, *entry, legacy[2][4] = {};
-       u8 version, entries, recordlen;
        int ret, i;
 
        INIT_LIST_HEAD(&dev_priv->i2c_ports);
@@ -346,12 +346,12 @@ nouveau_i2c_init(struct drm_device *dev)
                if (i2c[7]) legacy[1][1] = i2c[7];
        }
 
-       if (i2c && version >= 0x30) {
+       if (version >= 0x30) {
                entry     = i2c[1] + i2c;
                entries   = i2c[2];
                recordlen = i2c[3];
        } else
-       if (i2c) {
+       if (version) {
                entry     = i2c;
                entries   = 16;
                recordlen = 4;
index a3ae91f..a4886b3 100644 (file)
@@ -852,7 +852,7 @@ nouveau_card_init(struct drm_device *dev)
        if (ret)
                goto out_pm;
 
-       if (!dev_priv->noaccel) {
+       if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
                ret = nouveau_card_channel_init(dev);
                if (ret)
                        goto out_fence;
index 083b3ea..b5ff1f7 100644 (file)
@@ -588,8 +588,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                if (encoder->crtc == crtc) {
                        radeon_encoder = to_radeon_encoder(encoder);
                        connector = radeon_get_connector_for_encoder(encoder);
-                       if (connector && connector->display_info.bpc)
-                               bpc = connector->display_info.bpc;
+                       /* if (connector && connector->display_info.bpc)
+                               bpc = connector->display_info.bpc; */
                        encoder_mode = atombios_get_encoder_mode(encoder);
                        is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
                        if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
@@ -965,7 +965,9 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                struct radeon_connector_atom_dig *dig_connector =
                        radeon_connector->con_priv;
                int dp_clock;
-               bpc = connector->display_info.bpc;
+
+               /* if (connector->display_info.bpc)
+                       bpc = connector->display_info.bpc; */
 
                switch (encoder_mode) {
                case ATOM_ENCODER_MODE_DP_MST:
index 6c62be2..c57d856 100644 (file)
@@ -405,10 +405,13 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
 /* get bpc from the EDID */
 static int convert_bpc_to_bpp(int bpc)
 {
+#if 0
        if (bpc == 0)
                return 24;
        else
                return bpc * 3;
+#endif
+       return 24;
 }
 
 /* get the max pix clock supported by the link rate and lane num */
index 468b874..e607c4d 100644 (file)
@@ -541,7 +541,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
                dp_clock = dig_connector->dp_clock;
                dp_lane_count = dig_connector->dp_lane_count;
                hpd_id = radeon_connector->hpd.hpd;
-               bpc = connector->display_info.bpc;
+               /* bpc = connector->display_info.bpc; */
        }
 
        /* no dig encoder assigned */
@@ -1159,7 +1159,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
                dp_lane_count = dig_connector->dp_lane_count;
                connector_object_id =
                        (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
-               bpc = connector->display_info.bpc;
+               /* bpc = connector->display_info.bpc; */
        }
 
        memset(&args, 0, sizeof(args));
index 7b4eeb7..19a0114 100644 (file)
@@ -24,6 +24,7 @@
  *     Alex Deucher <alexander.deucher@amd.com>
  */
 
+#include <linux/bug.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 
index 3a10399..f85c0af 100644 (file)
@@ -24,6 +24,7 @@
  *     Alex Deucher <alexander.deucher@amd.com>
  */
 
+#include <linux/bug.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 
index a58b37a..70089d3 100644 (file)
@@ -80,6 +80,9 @@ struct evergreen_cs_track {
        bool                    cb_dirty;
        bool                    db_dirty;
        bool                    streamout_dirty;
+       u32                     htile_offset;
+       u32                     htile_surface;
+       struct radeon_bo        *htile_bo;
 };
 
 static u32 evergreen_cs_get_aray_mode(u32 tiling_flags)
@@ -144,6 +147,9 @@ static void evergreen_cs_track_init(struct evergreen_cs_track *track)
        track->db_s_read_bo = NULL;
        track->db_s_write_bo = NULL;
        track->db_dirty = true;
+       track->htile_bo = NULL;
+       track->htile_offset = 0xFFFFFFFF;
+       track->htile_surface = 0;
 
        for (i = 0; i < 4; i++) {
                track->vgt_strmout_size[i] = 0;
@@ -444,6 +450,62 @@ static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned i
        return 0;
 }
 
+static int evergreen_cs_track_validate_htile(struct radeon_cs_parser *p,
+                                               unsigned nbx, unsigned nby)
+{
+       struct evergreen_cs_track *track = p->track;
+       unsigned long size;
+
+       if (track->htile_bo == NULL) {
+               dev_warn(p->dev, "%s:%d htile enabled without htile surface 0x%08x\n",
+                               __func__, __LINE__, track->db_z_info);
+               return -EINVAL;
+       }
+
+       if (G_028ABC_LINEAR(track->htile_surface)) {
+               /* pitch must be 16 htiles aligned == 16 * 8 pixel aligned */
+               nbx = round_up(nbx, 16 * 8);
+               /* height is npipes htiles aligned == npipes * 8 pixel aligned */
+               nby = round_up(nby, track->npipes * 8);
+       } else {
+               switch (track->npipes) {
+               case 8:
+                       nbx = round_up(nbx, 64 * 8);
+                       nby = round_up(nby, 64 * 8);
+                       break;
+               case 4:
+                       nbx = round_up(nbx, 64 * 8);
+                       nby = round_up(nby, 32 * 8);
+                       break;
+               case 2:
+                       nbx = round_up(nbx, 32 * 8);
+                       nby = round_up(nby, 32 * 8);
+                       break;
+               case 1:
+                       nbx = round_up(nbx, 32 * 8);
+                       nby = round_up(nby, 16 * 8);
+                       break;
+               default:
+                       dev_warn(p->dev, "%s:%d invalid num pipes %d\n",
+                                       __func__, __LINE__, track->npipes);
+                       return -EINVAL;
+               }
+       }
+       /* compute number of htile */
+       nbx = nbx / 8;
+       nby = nby / 8;
+       size = nbx * nby * 4;
+       size += track->htile_offset;
+
+       if (size > radeon_bo_size(track->htile_bo)) {
+               dev_warn(p->dev, "%s:%d htile surface too small %ld for %ld (%d %d)\n",
+                               __func__, __LINE__, radeon_bo_size(track->htile_bo),
+                               size, nbx, nby);
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p)
 {
        struct evergreen_cs_track *track = p->track;
@@ -530,6 +592,14 @@ static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p)
                return -EINVAL;
        }
 
+       /* hyperz */
+       if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) {
+               r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby);
+               if (r) {
+                       return r;
+               }
+       }
+
        return 0;
 }
 
@@ -617,6 +687,14 @@ static int evergreen_cs_track_validate_depth(struct radeon_cs_parser *p)
                return -EINVAL;
        }
 
+       /* hyperz */
+       if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) {
+               r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby);
+               if (r) {
+                       return r;
+               }
+       }
+
        return 0;
 }
 
@@ -850,7 +928,7 @@ static int evergreen_cs_track_check(struct radeon_cs_parser *p)
                                return r;
                }
                /* Check depth buffer */
-               if (G_028800_Z_WRITE_ENABLE(track->db_depth_control)) {
+               if (G_028800_Z_ENABLE(track->db_depth_control)) {
                        r = evergreen_cs_track_validate_depth(p);
                        if (r)
                                return r;
@@ -1616,6 +1694,23 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                track->cb_color_bo[tmp] = reloc->robj;
                track->cb_dirty = true;
                break;
+       case DB_HTILE_DATA_BASE:
+               r = evergreen_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       dev_warn(p->dev, "bad SET_CONTEXT_REG "
+                                       "0x%04X\n", reg);
+                       return -EINVAL;
+               }
+               track->htile_offset = radeon_get_ib_value(p, idx);
+               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               track->htile_bo = reloc->robj;
+               track->db_dirty = true;
+               break;
+       case DB_HTILE_SURFACE:
+               /* 8x8 only */
+               track->htile_surface = radeon_get_ib_value(p, idx);
+               track->db_dirty = true;
+               break;
        case CB_IMMED0_BASE:
        case CB_IMMED1_BASE:
        case CB_IMMED2_BASE:
@@ -1628,7 +1723,6 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
        case CB_IMMED9_BASE:
        case CB_IMMED10_BASE:
        case CB_IMMED11_BASE:
-       case DB_HTILE_DATA_BASE:
        case SQ_PGM_START_FS:
        case SQ_PGM_START_ES:
        case SQ_PGM_START_VS:
index eb5708c..b4eefc3 100644 (file)
 #define   G_028008_SLICE_MAX(x)                        (((x) >> 13) & 0x7FF)
 #define   C_028008_SLICE_MAX                           0xFF001FFF
 #define DB_HTILE_DATA_BASE                             0x28014
+#define DB_HTILE_SURFACE                               0x28abc
+#define   S_028ABC_HTILE_WIDTH(x)                      (((x) & 0x1) << 0)
+#define   G_028ABC_HTILE_WIDTH(x)                      (((x) >> 0) & 0x1)
+#define   C_028ABC_HTILE_WIDTH                         0xFFFFFFFE
+#define   S_028ABC_HTILE_HEIGHT(x)                      (((x) & 0x1) << 1)
+#define   G_028ABC_HTILE_HEIGHT(x)                      (((x) >> 1) & 0x1)
+#define   C_028ABC_HTILE_HEIGHT                         0xFFFFFFFD
+#define   G_028ABC_LINEAR(x)                           (((x) >> 2) & 0x1)
 #define DB_Z_INFO                                      0x28040
 #       define Z_ARRAY_MODE(x)                          ((x) << 4)
 #       define DB_TILE_SPLIT(x)                         (((x) & 0x7) << 8)
index 73e2c7c..34c8b23 100644 (file)
@@ -24,6 +24,7 @@
  *     Alex Deucher <alexander.deucher@amd.com>
  */
 
+#include <linux/bug.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 
index 0ec3f20..b8e12af 100644 (file)
@@ -78,6 +78,9 @@ struct r600_cs_track {
        bool                    cb_dirty;
        bool                    db_dirty;
        bool                    streamout_dirty;
+       struct radeon_bo        *htile_bo;
+       u64                     htile_offset;
+       u32                     htile_surface;
 };
 
 #define FMT_8_BIT(fmt, vc)   [fmt] = { 1, 1, 1, vc, CHIP_R600 }
@@ -321,6 +324,9 @@ static void r600_cs_track_init(struct r600_cs_track *track)
        track->db_depth_size_idx = 0;
        track->db_depth_control = 0xFFFFFFFF;
        track->db_dirty = true;
+       track->htile_bo = NULL;
+       track->htile_offset = 0xFFFFFFFF;
+       track->htile_surface = 0;
 
        for (i = 0; i < 4; i++) {
                track->vgt_strmout_size[i] = 0;
@@ -455,12 +461,256 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
        return 0;
 }
 
+static int r600_cs_track_validate_db(struct radeon_cs_parser *p)
+{
+       struct r600_cs_track *track = p->track;
+       u32 nviews, bpe, ntiles, size, slice_tile_max, tmp;
+       u32 height_align, pitch_align, depth_align;
+       u32 pitch = 8192;
+       u32 height = 8192;
+       u64 base_offset, base_align;
+       struct array_mode_checker array_check;
+       int array_mode;
+       volatile u32 *ib = p->ib->ptr;
+
+
+       if (track->db_bo == NULL) {
+               dev_warn(p->dev, "z/stencil with no depth buffer\n");
+               return -EINVAL;
+       }
+       switch (G_028010_FORMAT(track->db_depth_info)) {
+       case V_028010_DEPTH_16:
+               bpe = 2;
+               break;
+       case V_028010_DEPTH_X8_24:
+       case V_028010_DEPTH_8_24:
+       case V_028010_DEPTH_X8_24_FLOAT:
+       case V_028010_DEPTH_8_24_FLOAT:
+       case V_028010_DEPTH_32_FLOAT:
+               bpe = 4;
+               break;
+       case V_028010_DEPTH_X24_8_32_FLOAT:
+               bpe = 8;
+               break;
+       default:
+               dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info));
+               return -EINVAL;
+       }
+       if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
+               if (!track->db_depth_size_idx) {
+                       dev_warn(p->dev, "z/stencil buffer size not set\n");
+                       return -EINVAL;
+               }
+               tmp = radeon_bo_size(track->db_bo) - track->db_offset;
+               tmp = (tmp / bpe) >> 6;
+               if (!tmp) {
+                       dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n",
+                                       track->db_depth_size, bpe, track->db_offset,
+                                       radeon_bo_size(track->db_bo));
+                       return -EINVAL;
+               }
+               ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
+       } else {
+               size = radeon_bo_size(track->db_bo);
+               /* pitch in pixels */
+               pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
+               slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
+               slice_tile_max *= 64;
+               height = slice_tile_max / pitch;
+               if (height > 8192)
+                       height = 8192;
+               base_offset = track->db_bo_mc + track->db_offset;
+               array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
+               array_check.array_mode = array_mode;
+               array_check.group_size = track->group_size;
+               array_check.nbanks = track->nbanks;
+               array_check.npipes = track->npipes;
+               array_check.nsamples = track->nsamples;
+               array_check.blocksize = bpe;
+               if (r600_get_array_mode_alignment(&array_check,
+                                       &pitch_align, &height_align, &depth_align, &base_align)) {
+                       dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+                                       G_028010_ARRAY_MODE(track->db_depth_info),
+                                       track->db_depth_info);
+                       return -EINVAL;
+               }
+               switch (array_mode) {
+               case V_028010_ARRAY_1D_TILED_THIN1:
+                       /* don't break userspace */
+                       height &= ~0x7;
+                       break;
+               case V_028010_ARRAY_2D_TILED_THIN1:
+                       break;
+               default:
+                       dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+                                       G_028010_ARRAY_MODE(track->db_depth_info),
+                                       track->db_depth_info);
+                       return -EINVAL;
+               }
+
+               if (!IS_ALIGNED(pitch, pitch_align)) {
+                       dev_warn(p->dev, "%s:%d db pitch (%d, 0x%x, %d) invalid\n",
+                                       __func__, __LINE__, pitch, pitch_align, array_mode);
+                       return -EINVAL;
+               }
+               if (!IS_ALIGNED(height, height_align)) {
+                       dev_warn(p->dev, "%s:%d db height (%d, 0x%x, %d) invalid\n",
+                                       __func__, __LINE__, height, height_align, array_mode);
+                       return -EINVAL;
+               }
+               if (!IS_ALIGNED(base_offset, base_align)) {
+                       dev_warn(p->dev, "%s offset 0x%llx, 0x%llx, %d not aligned\n", __func__,
+                                       base_offset, base_align, array_mode);
+                       return -EINVAL;
+               }
+
+               ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
+               nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
+               tmp = ntiles * bpe * 64 * nviews;
+               if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
+                       dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",
+                                       array_mode,
+                                       track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
+                                       radeon_bo_size(track->db_bo));
+                       return -EINVAL;
+               }
+       }
+
+       /* hyperz */
+       if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) {
+               unsigned long size;
+               unsigned nbx, nby;
+
+               if (track->htile_bo == NULL) {
+                       dev_warn(p->dev, "%s:%d htile enabled without htile surface 0x%08x\n",
+                                __func__, __LINE__, track->db_depth_info);
+                       return -EINVAL;
+               }
+               if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
+                       dev_warn(p->dev, "%s:%d htile can't be enabled with bogus db_depth_size 0x%08x\n",
+                                __func__, __LINE__, track->db_depth_size);
+                       return -EINVAL;
+               }
+
+               nbx = pitch;
+               nby = height;
+               if (G_028D24_LINEAR(track->htile_surface)) {
+                       /* nbx must be 16 htiles aligned == 16 * 8 pixel aligned */
+                       nbx = round_up(nbx, 16 * 8);
+                       /* nby is npipes htiles aligned == npipes * 8 pixel aligned */
+                       nby = round_up(nby, track->npipes * 8);
+               } else {
+                       /* htile widht & nby (8 or 4) make 2 bits number */
+                       tmp = track->htile_surface & 3;
+                       /* align is htile align * 8, htile align vary according to
+                        * number of pipe and tile width and nby
+                        */
+                       switch (track->npipes) {
+                       case 8:
+                               switch (tmp) {
+                               case 3: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+                                       nbx = round_up(nbx, 64 * 8);
+                                       nby = round_up(nby, 64 * 8);
+                                       break;
+                               case 2: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+                               case 1: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+                                       nbx = round_up(nbx, 64 * 8);
+                                       nby = round_up(nby, 32 * 8);
+                                       break;
+                               case 0: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+                                       nbx = round_up(nbx, 32 * 8);
+                                       nby = round_up(nby, 32 * 8);
+                                       break;
+                               default:
+                                       return -EINVAL;
+                               }
+                               break;
+                       case 4:
+                               switch (tmp) {
+                               case 3: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+                                       nbx = round_up(nbx, 64 * 8);
+                                       nby = round_up(nby, 32 * 8);
+                                       break;
+                               case 2: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+                               case 1: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+                                       nbx = round_up(nbx, 32 * 8);
+                                       nby = round_up(nby, 32 * 8);
+                                       break;
+                               case 0: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+                                       nbx = round_up(nbx, 32 * 8);
+                                       nby = round_up(nby, 16 * 8);
+                                       break;
+                               default:
+                                       return -EINVAL;
+                               }
+                               break;
+                       case 2:
+                               switch (tmp) {
+                               case 3: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+                                       nbx = round_up(nbx, 32 * 8);
+                                       nby = round_up(nby, 32 * 8);
+                                       break;
+                               case 2: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+                               case 1: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+                                       nbx = round_up(nbx, 32 * 8);
+                                       nby = round_up(nby, 16 * 8);
+                                       break;
+                               case 0: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+                                       nbx = round_up(nbx, 16 * 8);
+                                       nby = round_up(nby, 16 * 8);
+                                       break;
+                               default:
+                                       return -EINVAL;
+                               }
+                               break;
+                       case 1:
+                               switch (tmp) {
+                               case 3: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
+                                       nbx = round_up(nbx, 32 * 8);
+                                       nby = round_up(nby, 16 * 8);
+                                       break;
+                               case 2: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 8*/
+                               case 1: /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 4*/
+                                       nbx = round_up(nbx, 16 * 8);
+                                       nby = round_up(nby, 16 * 8);
+                                       break;
+                               case 0: /* HTILE_WIDTH = 4 & HTILE_HEIGHT = 4*/
+                                       nbx = round_up(nbx, 16 * 8);
+                                       nby = round_up(nby, 8 * 8);
+                                       break;
+                               default:
+                                       return -EINVAL;
+                               }
+                               break;
+                       default:
+                               dev_warn(p->dev, "%s:%d invalid num pipes %d\n",
+                                        __func__, __LINE__, track->npipes);
+                               return -EINVAL;
+                       }
+               }
+               /* compute number of htile */
+               nbx = G_028D24_HTILE_WIDTH(track->htile_surface) ? nbx / 8 : nbx / 4;
+               nby = G_028D24_HTILE_HEIGHT(track->htile_surface) ? nby / 8 : nby / 4;
+               size = nbx * nby * 4;
+               size += track->htile_offset;
+
+               if (size > radeon_bo_size(track->htile_bo)) {
+                       dev_warn(p->dev, "%s:%d htile surface too small %ld for %ld (%d %d)\n",
+                                __func__, __LINE__, radeon_bo_size(track->htile_bo),
+                                size, nbx, nby);
+                       return -EINVAL;
+               }
+       }
+
+       track->db_dirty = false;
+       return 0;
+}
+
 static int r600_cs_track_check(struct radeon_cs_parser *p)
 {
        struct r600_cs_track *track = p->track;
        u32 tmp;
        int r, i;
-       volatile u32 *ib = p->ib->ptr;
 
        /* on legacy kernel we don't perform advanced check */
        if (p->rdev == NULL)
@@ -513,124 +763,14 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
                track->cb_dirty = false;
        }
 
-       if (track->db_dirty) {
-               /* Check depth buffer */
-               if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
-                       G_028800_Z_ENABLE(track->db_depth_control)) {
-                       u32 nviews, bpe, ntiles, size, slice_tile_max;
-                       u32 height, height_align, pitch, pitch_align, depth_align;
-                       u64 base_offset, base_align;
-                       struct array_mode_checker array_check;
-                       int array_mode;
-
-                       if (track->db_bo == NULL) {
-                               dev_warn(p->dev, "z/stencil with no depth buffer\n");
-                               return -EINVAL;
-                       }
-                       if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) {
-                               dev_warn(p->dev, "this kernel doesn't support z/stencil htile\n");
-                               return -EINVAL;
-                       }
-                       switch (G_028010_FORMAT(track->db_depth_info)) {
-                       case V_028010_DEPTH_16:
-                               bpe = 2;
-                               break;
-                       case V_028010_DEPTH_X8_24:
-                       case V_028010_DEPTH_8_24:
-                       case V_028010_DEPTH_X8_24_FLOAT:
-                       case V_028010_DEPTH_8_24_FLOAT:
-                       case V_028010_DEPTH_32_FLOAT:
-                               bpe = 4;
-                               break;
-                       case V_028010_DEPTH_X24_8_32_FLOAT:
-                               bpe = 8;
-                               break;
-                       default:
-                               dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info));
-                               return -EINVAL;
-                       }
-                       if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
-                               if (!track->db_depth_size_idx) {
-                                       dev_warn(p->dev, "z/stencil buffer size not set\n");
-                                       return -EINVAL;
-                               }
-                               tmp = radeon_bo_size(track->db_bo) - track->db_offset;
-                               tmp = (tmp / bpe) >> 6;
-                               if (!tmp) {
-                                       dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n",
-                                                       track->db_depth_size, bpe, track->db_offset,
-                                                       radeon_bo_size(track->db_bo));
-                                       return -EINVAL;
-                               }
-                               ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
-                       } else {
-                               size = radeon_bo_size(track->db_bo);
-                               /* pitch in pixels */
-                               pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
-                               slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
-                               slice_tile_max *= 64;
-                               height = slice_tile_max / pitch;
-                               if (height > 8192)
-                                       height = 8192;
-                               base_offset = track->db_bo_mc + track->db_offset;
-                               array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
-                               array_check.array_mode = array_mode;
-                               array_check.group_size = track->group_size;
-                               array_check.nbanks = track->nbanks;
-                               array_check.npipes = track->npipes;
-                               array_check.nsamples = track->nsamples;
-                               array_check.blocksize = bpe;
-                               if (r600_get_array_mode_alignment(&array_check,
-                                                                 &pitch_align, &height_align, &depth_align, &base_align)) {
-                                       dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
-                                                G_028010_ARRAY_MODE(track->db_depth_info),
-                                                track->db_depth_info);
-                                       return -EINVAL;
-                               }
-                               switch (array_mode) {
-                               case V_028010_ARRAY_1D_TILED_THIN1:
-                                       /* don't break userspace */
-                                       height &= ~0x7;
-                                       break;
-                               case V_028010_ARRAY_2D_TILED_THIN1:
-                                       break;
-                               default:
-                                       dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
-                                                G_028010_ARRAY_MODE(track->db_depth_info),
-                                                track->db_depth_info);
-                                       return -EINVAL;
-                               }
-
-                               if (!IS_ALIGNED(pitch, pitch_align)) {
-                                       dev_warn(p->dev, "%s:%d db pitch (%d, 0x%x, %d) invalid\n",
-                                                __func__, __LINE__, pitch, pitch_align, array_mode);
-                                       return -EINVAL;
-                               }
-                               if (!IS_ALIGNED(height, height_align)) {
-                                       dev_warn(p->dev, "%s:%d db height (%d, 0x%x, %d) invalid\n",
-                                                __func__, __LINE__, height, height_align, array_mode);
-                                       return -EINVAL;
-                               }
-                               if (!IS_ALIGNED(base_offset, base_align)) {
-                                       dev_warn(p->dev, "%s offset[%d] 0x%llx, 0x%llx, %d not aligned\n", __func__, i,
-                                                base_offset, base_align, array_mode);
-                                       return -EINVAL;
-                               }
-
-                               ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
-                               nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
-                               tmp = ntiles * bpe * 64 * nviews;
-                               if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
-                                       dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",
-                                                array_mode,
-                                                track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
-                                                radeon_bo_size(track->db_bo));
-                                       return -EINVAL;
-                               }
-                       }
-               }
-               track->db_dirty = false;
+       /* Check depth buffer */
+       if (track->db_dirty && (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
+               G_028800_Z_ENABLE(track->db_depth_control))) {
+               r = r600_cs_track_validate_db(p);
+               if (r)
+                       return r;
        }
+
        return 0;
 }
 
@@ -1244,6 +1384,21 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                track->db_dirty = true;
                break;
        case DB_HTILE_DATA_BASE:
+               r = r600_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       dev_warn(p->dev, "bad SET_CONTEXT_REG "
+                                       "0x%04X\n", reg);
+                       return -EINVAL;
+               }
+               track->htile_offset = radeon_get_ib_value(p, idx) << 8;
+               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               track->htile_bo = reloc->robj;
+               track->db_dirty = true;
+               break;
+       case DB_HTILE_SURFACE:
+               track->htile_surface = radeon_get_ib_value(p, idx);
+               track->db_dirty = true;
+               break;
        case SQ_PGM_START_FS:
        case SQ_PGM_START_ES:
        case SQ_PGM_START_VS:
index 3568a2e..59f9c99 100644 (file)
 #define                PREZ_MUST_WAIT_FOR_POSTZ_DONE                   (1 << 31)
 #define        DB_DEPTH_BASE                                   0x2800C
 #define        DB_HTILE_DATA_BASE                              0x28014
+#define        DB_HTILE_SURFACE                                0x28D24
+#define   S_028D24_HTILE_WIDTH(x)                      (((x) & 0x1) << 0)
+#define   G_028D24_HTILE_WIDTH(x)                      (((x) >> 0) & 0x1)
+#define   C_028D24_HTILE_WIDTH                         0xFFFFFFFE
+#define   S_028D24_HTILE_HEIGHT(x)                      (((x) & 0x1) << 1)
+#define   G_028D24_HTILE_HEIGHT(x)                      (((x) >> 1) & 0x1)
+#define   C_028D24_HTILE_HEIGHT                         0xFFFFFFFD
+#define   G_028D24_LINEAR(x)                           (((x) >> 2) & 0x1)
 #define        DB_WATERMARKS                                   0x9838
 #define                DEPTH_FREE(x)                                   ((x) << 0)
 #define                DEPTH_FLUSH(x)                                  ((x) << 5)
index 91541e6..6f70158 100644 (file)
@@ -233,7 +233,17 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
                bo->pin_count++;
                if (gpu_addr)
                        *gpu_addr = radeon_bo_gpu_offset(bo);
-               WARN_ON_ONCE(max_offset != 0);
+
+               if (max_offset != 0) {
+                       u64 domain_start;
+
+                       if (domain == RADEON_GEM_DOMAIN_VRAM)
+                               domain_start = bo->rdev->mc.vram_start;
+                       else
+                               domain_start = bo->rdev->mc.gtt_start;
+                       WARN_ON_ONCE((*gpu_addr - domain_start) > max_offset);
+               }
+
                return 0;
        }
        radeon_ttm_placement_from_domain(bo, domain);
index aea63c4..0f656b1 100644 (file)
@@ -509,7 +509,6 @@ cayman 0x9400
 0x00028AA8 IA_MULTI_VGT_PARAM
 0x00028AB4 VGT_REUSE_OFF
 0x00028AB8 VGT_VTX_CNT_EN
-0x00028ABC DB_HTILE_SURFACE
 0x00028AC0 DB_SRESULTS_COMPARE_STATE0
 0x00028AC4 DB_SRESULTS_COMPARE_STATE1
 0x00028AC8 DB_PRELOAD_CONTROL
index 77c3720..b912a37 100644 (file)
@@ -519,7 +519,6 @@ evergreen 0x9400
 0x00028AA4 VGT_INSTANCE_STEP_RATE_1
 0x00028AB4 VGT_REUSE_OFF
 0x00028AB8 VGT_VTX_CNT_EN
-0x00028ABC DB_HTILE_SURFACE
 0x00028AC0 DB_SRESULTS_COMPARE_STATE0
 0x00028AC4 DB_SRESULTS_COMPARE_STATE1
 0x00028AC8 DB_PRELOAD_CONTROL
index 626c24e..5e659b0 100644 (file)
@@ -713,7 +713,6 @@ r600 0x9400
 0x0000A710 TD_VS_SAMPLER17_BORDER_RED
 0x00009508 TA_CNTL_AUX
 0x0002802C DB_DEPTH_CLEAR
-0x00028D24 DB_HTILE_SURFACE
 0x00028D34 DB_PREFETCH_LIMIT
 0x00028D30 DB_PRELOAD_CONTROL
 0x00028D0C DB_RENDER_CONTROL
index a7124b4..ec415e7 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/bug.h>
 #include <linux/kernel.h>
 
 const u32 si_default_state[] =
index 70ca07f..4da66b4 100644 (file)
@@ -2026,6 +2026,16 @@ static bool hid_ignore(struct hid_device *hdev)
                if (hdev->product >= USB_DEVICE_ID_LOGITECH_HARMONY_FIRST &&
                                hdev->product <= USB_DEVICE_ID_LOGITECH_HARMONY_LAST)
                        return true;
+               /*
+                * The Keene FM transmitter USB device has the same USB ID as
+                * the Logitech AudioHub Speaker, but it should ignore the hid.
+                * Check if the name is that of the Keene device.
+                * For reference: the name of the AudioHub is
+                * "HOLTEK  AudioHub Speaker".
+                */
+               if (hdev->product == USB_DEVICE_ID_LOGITECH_AUDIOHUB &&
+                       !strcmp(hdev->name, "HOLTEK  B-LINK USB Audio  "))
+                               return true;
                break;
        case USB_VENDOR_ID_SOUNDGRAPH:
                if (hdev->product >= USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST &&
index 2a5cef2..e39aecb 100644 (file)
 #define USB_DEVICE_ID_LG_MULTITOUCH    0x0064
 
 #define USB_VENDOR_ID_LOGITECH         0x046d
+#define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
 #define USB_DEVICE_ID_LOGITECH_RECEIVER        0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
index 811e6c4..5b32d56 100644 (file)
@@ -648,7 +648,8 @@ config SENSORS_LM90
          LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
          Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
          MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008,
-         Winbond/Nuvoton W83L771W/G/AWG/ASG and Philips SA56004 sensor chips.
+         Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, and GMT G781
+         sensor chips.
 
          This driver can also be built as a module.  If so, the module
          will be called lm90.
@@ -812,6 +813,16 @@ config SENSORS_MAX6650
          This driver can also be built as a module.  If so, the module
          will be called max6650.
 
+config SENSORS_MCP3021
+       tristate "Microchip MCP3021"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for the MCP3021 chip
+         that is a A/D converter (ADC) with 10-bit resolution.
+
+         This driver can also be built as a module.  If so, the module
+         will be called mcp3021.
+
 config SENSORS_NTC_THERMISTOR
        tristate "NTC thermistor support"
        depends on EXPERIMENTAL
@@ -1229,18 +1240,19 @@ config SENSORS_W83795
        depends on I2C && EXPERIMENTAL
        help
          If you say yes here you get support for the Winbond W83795G and
-         W83795ADG hardware monitoring chip.
+         W83795ADG hardware monitoring chip, including manual fan speed
+         control.
 
          This driver can also be built as a module.  If so, the module
          will be called w83795.
 
 config SENSORS_W83795_FANCTRL
-       boolean "Include fan control support (DANGEROUS)"
+       boolean "Include automatic fan control support (DANGEROUS)"
        depends on SENSORS_W83795 && EXPERIMENTAL
        default n
        help
-         If you say yes here, support for the both manual and automatic
-         fan control features will be included in the driver.
+         If you say yes here, support for automatic fan speed control
+         will be included in the driver.
 
          This part of the code wasn't carefully reviewed and tested yet,
          so enabling this option is strongly discouraged on production
@@ -1358,10 +1370,10 @@ config SENSORS_APPLESMC
          the awesome power of applesmc.
 
 config SENSORS_MC13783_ADC
-        tristate "Freescale MC13783 ADC"
-        depends on MFD_MC13783
+        tristate "Freescale MC13783/MC13892 ADC"
+        depends on MFD_MC13XXX
         help
-          Support for the A/D converter on MC13783 PMIC.
+          Support for the A/D converter on MC13783 and MC13892 PMIC.
 
 if ACPI
 
index 8251ce8..6d3f11f 100644 (file)
@@ -95,6 +95,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
 obj-$(CONFIG_SENSORS_MAX6642)  += max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)  += max6650.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
+obj-$(CONFIG_SENSORS_MCP3021)  += mcp3021.o
 obj-$(CONFIG_SENSORS_NTC_THERMISTOR)   += ntc_thermistor.o
 obj-$(CONFIG_SENSORS_PC87360)  += pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)  += pc87427.o
index 523f8fb..b7494af 100644 (file)
@@ -60,15 +60,15 @@ static ssize_t show_power(struct device *dev,
        pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
                                  REG_TDP_RUNNING_AVERAGE, &val);
        running_avg_capture = (val >> 4) & 0x3fffff;
-       running_avg_capture = sign_extend32(running_avg_capture, 22);
-       running_avg_range = val & 0xf;
+       running_avg_capture = sign_extend32(running_avg_capture, 21);
+       running_avg_range = (val & 0xf) + 1;
 
        pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
                                  REG_TDP_LIMIT3, &val);
 
        tdp_limit = val >> 16;
-       curr_pwr_watts = tdp_limit + data->base_tdp -
-               (s32)(running_avg_capture >> (running_avg_range + 1));
+       curr_pwr_watts = (tdp_limit + data->base_tdp) << running_avg_range;
+       curr_pwr_watts -= running_avg_capture;
        curr_pwr_watts *= data->tdp_to_watts;
 
        /*
@@ -78,7 +78,7 @@ static ssize_t show_power(struct device *dev,
         * scaling factor 1/(2^16).  For conversion we use
         * (10^6)/(2^16) = 15625/(2^10)
         */
-       curr_pwr_watts = (curr_pwr_watts * 15625) >> 10;
+       curr_pwr_watts = (curr_pwr_watts * 15625) >> (10 + running_avg_range);
        return sprintf(buf, "%u\n", (unsigned int) curr_pwr_watts);
 }
 static DEVICE_ATTR(power1_input, S_IRUGO, show_power, NULL);
index 8305d29..519ce8b 100644 (file)
@@ -53,8 +53,8 @@
 static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
 
 /* Insmod parameters */
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
index 15c05cc..602a0f0 100644 (file)
@@ -148,46 +148,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
 #define UPDATE_INTERVAL(max, rate) \
                        ((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
 
-/*
- * Functions declaration
- */
-
-static int lm63_probe(struct i2c_client *client,
-                     const struct i2c_device_id *id);
-static int lm63_remove(struct i2c_client *client);
-
-static struct lm63_data *lm63_update_device(struct device *dev);
-
-static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
-static void lm63_init_client(struct i2c_client *client);
-
 enum chips { lm63, lm64, lm96163 };
 
 /*
- * Driver data (common to all clients)
- */
-
-static const struct i2c_device_id lm63_id[] = {
-       { "lm63", lm63 },
-       { "lm64", lm64 },
-       { "lm96163", lm96163 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, lm63_id);
-
-static struct i2c_driver lm63_driver = {
-       .class          = I2C_CLASS_HWMON,
-       .driver = {
-               .name   = "lm63",
-       },
-       .probe          = lm63_probe,
-       .remove         = lm63_remove,
-       .id_table       = lm63_id,
-       .detect         = lm63_detect,
-       .address_list   = normal_i2c,
-};
-
-/*
  * Client data (each client gets its own)
  */
 
@@ -242,6 +205,145 @@ static inline int lut_temp_from_reg(struct lm63_data *data, int nr)
        return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
 }
 
+static inline int lut_temp_to_reg(struct lm63_data *data, long val)
+{
+       val -= data->temp2_offset;
+       if (data->lut_temp_highres)
+               return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127500), 500);
+       else
+               return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127000), 1000);
+}
+
+/*
+ * Update the lookup table register cache.
+ * client->update_lock must be held when calling this function.
+ */
+static void lm63_update_lut(struct i2c_client *client)
+{
+       struct lm63_data *data = i2c_get_clientdata(client);
+       int i;
+
+       if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
+           !data->lut_valid) {
+               for (i = 0; i < data->lut_size; i++) {
+                       data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
+                                           LM63_REG_LUT_PWM(i));
+                       data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
+                                            LM63_REG_LUT_TEMP(i));
+               }
+               data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
+                                     LM63_REG_LUT_TEMP_HYST);
+
+               data->lut_last_updated = jiffies;
+               data->lut_valid = 1;
+       }
+}
+
+static struct lm63_data *lm63_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm63_data *data = i2c_get_clientdata(client);
+       unsigned long next_update;
+
+       mutex_lock(&data->update_lock);
+
+       next_update = data->last_updated
+         + msecs_to_jiffies(data->update_interval) + 1;
+
+       if (time_after(jiffies, next_update) || !data->valid) {
+               if (data->config & 0x04) { /* tachometer enabled  */
+                       /* order matters for fan1_input */
+                       data->fan[0] = i2c_smbus_read_byte_data(client,
+                                      LM63_REG_TACH_COUNT_LSB) & 0xFC;
+                       data->fan[0] |= i2c_smbus_read_byte_data(client,
+                                       LM63_REG_TACH_COUNT_MSB) << 8;
+                       data->fan[1] = (i2c_smbus_read_byte_data(client,
+                                       LM63_REG_TACH_LIMIT_LSB) & 0xFC)
+                                    | (i2c_smbus_read_byte_data(client,
+                                       LM63_REG_TACH_LIMIT_MSB) << 8);
+               }
+
+               data->pwm1_freq = i2c_smbus_read_byte_data(client,
+                                 LM63_REG_PWM_FREQ);
+               if (data->pwm1_freq == 0)
+                       data->pwm1_freq = 1;
+               data->pwm1[0] = i2c_smbus_read_byte_data(client,
+                               LM63_REG_PWM_VALUE);
+
+               data->temp8[0] = i2c_smbus_read_byte_data(client,
+                                LM63_REG_LOCAL_TEMP);
+               data->temp8[1] = i2c_smbus_read_byte_data(client,
+                                LM63_REG_LOCAL_HIGH);
+
+               /* order matters for temp2_input */
+               data->temp11[0] = i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_TEMP_MSB) << 8;
+               data->temp11[0] |= i2c_smbus_read_byte_data(client,
+                                  LM63_REG_REMOTE_TEMP_LSB);
+               data->temp11[1] = (i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_LOW_MSB) << 8)
+                               | i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_LOW_LSB);
+               data->temp11[2] = (i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_HIGH_MSB) << 8)
+                               | i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_HIGH_LSB);
+               data->temp11[3] = (i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_OFFSET_MSB) << 8)
+                               | i2c_smbus_read_byte_data(client,
+                                 LM63_REG_REMOTE_OFFSET_LSB);
+
+               if (data->kind == lm96163)
+                       data->temp11u = (i2c_smbus_read_byte_data(client,
+                                       LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
+                                     | i2c_smbus_read_byte_data(client,
+                                       LM96163_REG_REMOTE_TEMP_U_LSB);
+
+               data->temp8[2] = i2c_smbus_read_byte_data(client,
+                                LM63_REG_REMOTE_TCRIT);
+               data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
+                                       LM63_REG_REMOTE_TCRIT_HYST);
+
+               data->alarms = i2c_smbus_read_byte_data(client,
+                              LM63_REG_ALERT_STATUS) & 0x7F;
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       lm63_update_lut(client);
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+/*
+ * Trip points in the lookup table should be in ascending order for both
+ * temperatures and PWM output values.
+ */
+static int lm63_lut_looks_bad(struct i2c_client *client)
+{
+       struct lm63_data *data = i2c_get_clientdata(client);
+       int i;
+
+       mutex_lock(&data->update_lock);
+       lm63_update_lut(client);
+
+       for (i = 1; i < data->lut_size; i++) {
+               if (data->pwm1[1 + i - 1] > data->pwm1[1 + i]
+                || data->temp8[3 + i - 1] > data->temp8[3 + i]) {
+                       dev_warn(&client->dev,
+                                "Lookup table doesn't look sane (check entries %d and %d)\n",
+                                i, i + 1);
+                       break;
+               }
+       }
+       mutex_unlock(&data->update_lock);
+
+       return i == data->lut_size ? 0 : 1;
+}
+
 /*
  * Sysfs callback functions and files
  */
@@ -294,13 +396,16 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
        return sprintf(buf, "%d\n", pwm);
 }
 
-static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
+static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr,
                        const char *buf, size_t count)
 {
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
+       int nr = attr->index;
        unsigned long val;
        int err;
+       u8 reg;
 
        if (!(data->config_fan & 0x20)) /* register is read-only */
                return -EPERM;
@@ -309,11 +414,13 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
        if (err)
                return err;
 
+       reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE;
        val = SENSORS_LIMIT(val, 0, 255);
+
        mutex_lock(&data->update_lock);
-       data->pwm1[0] = data->pwm_highres ? val :
+       data->pwm1[nr] = data->pwm_highres ? val :
                        (val * data->pwm1_freq * 2 + 127) / 255;
-       i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]);
+       i2c_smbus_write_byte_data(client, reg, data->pwm1[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
@@ -325,6 +432,41 @@ static ssize_t show_pwm1_enable(struct device *dev,
        return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
 }
 
+static ssize_t set_pwm1_enable(struct device *dev,
+                              struct device_attribute *dummy,
+                              const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm63_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 10, &val);
+       if (err)
+               return err;
+       if (val < 1 || val > 2)
+               return -EINVAL;
+
+       /*
+        * Only let the user switch to automatic mode if the lookup table
+        * looks sane.
+        */
+       if (val == 2 && lm63_lut_looks_bad(client))
+               return -EPERM;
+
+       mutex_lock(&data->update_lock);
+       data->config_fan = i2c_smbus_read_byte_data(client,
+                                                   LM63_REG_CONFIG_FAN);
+       if (val == 1)
+               data->config_fan |= 0x20;
+       else
+               data->config_fan &= ~0x20;
+       i2c_smbus_write_byte_data(client, LM63_REG_CONFIG_FAN,
+       data->config_fan);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
 /*
  * There are 8bit registers for both local(temp1) and remote(temp2) sensor.
  * For remote sensor registers temp2_offset has to be considered,
@@ -367,23 +509,31 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
        int nr = attr->index;
-       int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH;
        long val;
        int err;
        int temp;
+       u8 reg;
 
        err = kstrtol(buf, 10, &val);
        if (err)
                return err;
 
        mutex_lock(&data->update_lock);
-       if (nr == 2) {
+       switch (nr) {
+       case 2:
+               reg = LM63_REG_REMOTE_TCRIT;
                if (data->remote_unsigned)
                        temp = TEMP8U_TO_REG(val - data->temp2_offset);
                else
                        temp = TEMP8_TO_REG(val - data->temp2_offset);
-       } else {
+               break;
+       case 1:
+               reg = LM63_REG_LOCAL_HIGH;
                temp = TEMP8_TO_REG(val);
+               break;
+       default:        /* lookup table */
+               reg = LM63_REG_LUT_TEMP(nr - 3);
+               temp = lut_temp_to_reg(data, val);
        }
        data->temp8[nr] = temp;
        i2c_smbus_write_byte_data(client, reg, temp);
@@ -613,65 +763,78 @@ static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
        set_fan, 1);
 
 static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
-static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO,
-       show_lut_temp, NULL, 3);
+static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+       show_pwm1_enable, set_pwm1_enable);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 1);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 3);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 3);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO,
-       show_lut_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 2);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 4);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 4);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO,
-       show_lut_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 5);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 5);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO,
-       show_lut_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 6);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 6);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO,
-       show_lut_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 7);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 7);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO,
-       show_lut_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 8);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 8);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO,
-       show_lut_temp, NULL, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 9);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 9);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO,
-       show_lut_temp, NULL, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 10);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 10);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IRUGO, show_pwm1, NULL, 9);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IRUGO,
-       show_lut_temp, NULL, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 11);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 11);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IRUGO, show_pwm1, NULL, 10);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IRUGO,
-       show_lut_temp, NULL, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 12);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 12);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IRUGO, show_pwm1, NULL, 11);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IRUGO,
-       show_lut_temp, NULL, 13);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 13);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 13);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IRUGO, show_pwm1, NULL, 12);
-static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IRUGO,
-       show_lut_temp, NULL, 14);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IWUSR | S_IRUGO,
+       show_pwm1, set_pwm1, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IWUSR | S_IRUGO,
+       show_lut_temp, set_temp8, 14);
 static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO,
        show_lut_temp_hyst, NULL, 14);
 
@@ -817,28 +980,25 @@ static const struct attribute_group lm63_group_fan1 = {
  */
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
-static int lm63_detect(struct i2c_client *new_client,
+static int lm63_detect(struct i2c_client *client,
                       struct i2c_board_info *info)
 {
-       struct i2c_adapter *adapter = new_client->adapter;
+       struct i2c_adapter *adapter = client->adapter;
        u8 man_id, chip_id, reg_config1, reg_config2;
        u8 reg_alert_status, reg_alert_mask;
-       int address = new_client->addr;
+       int address = client->addr;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       man_id = i2c_smbus_read_byte_data(new_client, LM63_REG_MAN_ID);
-       chip_id = i2c_smbus_read_byte_data(new_client, LM63_REG_CHIP_ID);
+       man_id = i2c_smbus_read_byte_data(client, LM63_REG_MAN_ID);
+       chip_id = i2c_smbus_read_byte_data(client, LM63_REG_CHIP_ID);
 
-       reg_config1 = i2c_smbus_read_byte_data(new_client,
-                     LM63_REG_CONFIG1);
-       reg_config2 = i2c_smbus_read_byte_data(new_client,
-                     LM63_REG_CONFIG2);
-       reg_alert_status = i2c_smbus_read_byte_data(new_client,
+       reg_config1 = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
+       reg_config2 = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG2);
+       reg_alert_status = i2c_smbus_read_byte_data(client,
                           LM63_REG_ALERT_STATUS);
-       reg_alert_mask = i2c_smbus_read_byte_data(new_client,
-                        LM63_REG_ALERT_MASK);
+       reg_alert_mask = i2c_smbus_read_byte_data(client, LM63_REG_ALERT_MASK);
 
        if (man_id != 0x01 /* National Semiconductor */
         || (reg_config1 & 0x18) != 0x00
@@ -863,74 +1023,6 @@ static int lm63_detect(struct i2c_client *new_client,
        return 0;
 }
 
-static int lm63_probe(struct i2c_client *new_client,
-                     const struct i2c_device_id *id)
-{
-       struct lm63_data *data;
-       int err;
-
-       data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
-
-       i2c_set_clientdata(new_client, data);
-       data->valid = 0;
-       mutex_init(&data->update_lock);
-
-       /* Set the device type */
-       data->kind = id->driver_data;
-       if (data->kind == lm64)
-               data->temp2_offset = 16000;
-
-       /* Initialize chip */
-       lm63_init_client(new_client);
-
-       /* Register sysfs hooks */
-       err = sysfs_create_group(&new_client->dev.kobj, &lm63_group);
-       if (err)
-               goto exit_free;
-       if (data->config & 0x04) { /* tachometer enabled */
-               err = sysfs_create_group(&new_client->dev.kobj,
-                                        &lm63_group_fan1);
-               if (err)
-                       goto exit_remove_files;
-       }
-       if (data->kind == lm96163) {
-               err = device_create_file(&new_client->dev,
-                                        &dev_attr_temp2_type);
-               if (err)
-                       goto exit_remove_files;
-
-               err = sysfs_create_group(&new_client->dev.kobj,
-                                        &lm63_group_extra_lut);
-               if (err)
-                       goto exit_remove_files;
-       }
-
-       data->hwmon_dev = hwmon_device_register(&new_client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               goto exit_remove_files;
-       }
-
-       return 0;
-
-exit_remove_files:
-       sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
-       sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
-       if (data->kind == lm96163) {
-               device_remove_file(&new_client->dev, &dev_attr_temp2_type);
-               sysfs_remove_group(&new_client->dev.kobj,
-                                  &lm63_group_extra_lut);
-       }
-exit_free:
-       kfree(data);
-exit:
-       return err;
-}
-
 /*
  * Ideally we shouldn't have to initialize anything, since the BIOS
  * should have taken care of everything
@@ -1010,114 +1102,110 @@ static void lm63_init_client(struct i2c_client *client)
                (data->config_fan & 0x20) ? "manual" : "auto");
 }
 
-static int lm63_remove(struct i2c_client *client)
+static int lm63_probe(struct i2c_client *client,
+                     const struct i2c_device_id *id)
 {
-       struct lm63_data *data = i2c_get_clientdata(client);
+       struct lm63_data *data;
+       int err;
 
-       hwmon_device_unregister(data->hwmon_dev);
+       data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(client, data);
+       data->valid = 0;
+       mutex_init(&data->update_lock);
+
+       /* Set the device type */
+       data->kind = id->driver_data;
+       if (data->kind == lm64)
+               data->temp2_offset = 16000;
+
+       /* Initialize chip */
+       lm63_init_client(client);
+
+       /* Register sysfs hooks */
+       err = sysfs_create_group(&client->dev.kobj, &lm63_group);
+       if (err)
+               goto exit_free;
+       if (data->config & 0x04) { /* tachometer enabled */
+               err = sysfs_create_group(&client->dev.kobj, &lm63_group_fan1);
+               if (err)
+                       goto exit_remove_files;
+       }
+       if (data->kind == lm96163) {
+               err = device_create_file(&client->dev, &dev_attr_temp2_type);
+               if (err)
+                       goto exit_remove_files;
+
+               err = sysfs_create_group(&client->dev.kobj,
+                                        &lm63_group_extra_lut);
+               if (err)
+                       goto exit_remove_files;
+       }
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_files;
+       }
+
+       return 0;
+
+exit_remove_files:
        sysfs_remove_group(&client->dev.kobj, &lm63_group);
        sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
        if (data->kind == lm96163) {
                device_remove_file(&client->dev, &dev_attr_temp2_type);
                sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut);
        }
-
+exit_free:
        kfree(data);
-       return 0;
+exit:
+       return err;
 }
 
-static struct lm63_data *lm63_update_device(struct device *dev)
+static int lm63_remove(struct i2c_client *client)
 {
-       struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
-       unsigned long next_update;
-       int i;
-
-       mutex_lock(&data->update_lock);
-
-       next_update = data->last_updated
-         + msecs_to_jiffies(data->update_interval) + 1;
-
-       if (time_after(jiffies, next_update) || !data->valid) {
-               if (data->config & 0x04) { /* tachometer enabled  */
-                       /* order matters for fan1_input */
-                       data->fan[0] = i2c_smbus_read_byte_data(client,
-                                      LM63_REG_TACH_COUNT_LSB) & 0xFC;
-                       data->fan[0] |= i2c_smbus_read_byte_data(client,
-                                       LM63_REG_TACH_COUNT_MSB) << 8;
-                       data->fan[1] = (i2c_smbus_read_byte_data(client,
-                                       LM63_REG_TACH_LIMIT_LSB) & 0xFC)
-                                    | (i2c_smbus_read_byte_data(client,
-                                       LM63_REG_TACH_LIMIT_MSB) << 8);
-               }
-
-               data->pwm1_freq = i2c_smbus_read_byte_data(client,
-                                 LM63_REG_PWM_FREQ);
-               if (data->pwm1_freq == 0)
-                       data->pwm1_freq = 1;
-               data->pwm1[0] = i2c_smbus_read_byte_data(client,
-                               LM63_REG_PWM_VALUE);
-
-               data->temp8[0] = i2c_smbus_read_byte_data(client,
-                                LM63_REG_LOCAL_TEMP);
-               data->temp8[1] = i2c_smbus_read_byte_data(client,
-                                LM63_REG_LOCAL_HIGH);
-
-               /* order matters for temp2_input */
-               data->temp11[0] = i2c_smbus_read_byte_data(client,
-                                 LM63_REG_REMOTE_TEMP_MSB) << 8;
-               data->temp11[0] |= i2c_smbus_read_byte_data(client,
-                                  LM63_REG_REMOTE_TEMP_LSB);
-               data->temp11[1] = (i2c_smbus_read_byte_data(client,
-                                 LM63_REG_REMOTE_LOW_MSB) << 8)
-                               | i2c_smbus_read_byte_data(client,
-                                 LM63_REG_REMOTE_LOW_LSB);
-               data->temp11[2] = (i2c_smbus_read_byte_data(client,
-                                 LM63_REG_REMOTE_HIGH_MSB) << 8)
-                               | i2c_smbus_read_byte_data(client,
-                                 LM63_REG_REMOTE_HIGH_LSB);
-               data->temp11[3] = (i2c_smbus_read_byte_data(client,
-                                 LM63_REG_REMOTE_OFFSET_MSB) << 8)
-                               | i2c_smbus_read_byte_data(client,
-                                 LM63_REG_REMOTE_OFFSET_LSB);
-
-               if (data->kind == lm96163)
-                       data->temp11u = (i2c_smbus_read_byte_data(client,
-                                       LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
-                                     | i2c_smbus_read_byte_data(client,
-                                       LM96163_REG_REMOTE_TEMP_U_LSB);
-
-               data->temp8[2] = i2c_smbus_read_byte_data(client,
-                                LM63_REG_REMOTE_TCRIT);
-               data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
-                                       LM63_REG_REMOTE_TCRIT_HYST);
-
-               data->alarms = i2c_smbus_read_byte_data(client,
-                              LM63_REG_ALERT_STATUS) & 0x7F;
 
-               data->last_updated = jiffies;
-               data->valid = 1;
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &lm63_group);
+       sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
+       if (data->kind == lm96163) {
+               device_remove_file(&client->dev, &dev_attr_temp2_type);
+               sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut);
        }
 
-       if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
-           !data->lut_valid) {
-               for (i = 0; i < data->lut_size; i++) {
-                       data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
-                                           LM63_REG_LUT_PWM(i));
-                       data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
-                                            LM63_REG_LUT_TEMP(i));
-               }
-               data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
-                                     LM63_REG_LUT_TEMP_HYST);
+       kfree(data);
+       return 0;
+}
 
-               data->lut_last_updated = jiffies;
-               data->lut_valid = 1;
-       }
+/*
+ * Driver data (common to all clients)
+ */
 
-       mutex_unlock(&data->update_lock);
+static const struct i2c_device_id lm63_id[] = {
+       { "lm63", lm63 },
+       { "lm64", lm64 },
+       { "lm96163", lm96163 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lm63_id);
 
-       return data;
-}
+static struct i2c_driver lm63_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "lm63",
+       },
+       .probe          = lm63_probe,
+       .remove         = lm63_remove,
+       .id_table       = lm63_id,
+       .detect         = lm63_detect,
+       .address_list   = normal_i2c,
+};
 
 module_i2c_driver(lm63_driver);
 
index 248f2b4..22b14a6 100644 (file)
@@ -57,6 +57,9 @@
  * This driver also supports the SA56004 from Philips. This device is
  * pin-compatible with the LM86, the ED/EDP parts are also address-compatible.
  *
+ * This driver also supports the G781 from GMT. This device is compatible
+ * with the ADM1032.
+ *
  * Since the LM90 was the first chipset supported by this driver, most
  * comments will refer to this chipset, but are actually general and
  * concern all supported chipsets, unless mentioned otherwise.
@@ -107,7 +110,7 @@ static const unsigned short normal_i2c[] = {
        0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 
 enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
-       max6646, w83l771, max6696, sa56004 };
+       max6646, w83l771, max6696, sa56004, g781 };
 
 /*
  * The LM90 registers
@@ -184,6 +187,7 @@ static const struct i2c_device_id lm90_id[] = {
        { "adm1032", adm1032 },
        { "adt7461", adt7461 },
        { "adt7461a", adt7461 },
+       { "g781", g781 },
        { "lm90", lm90 },
        { "lm86", lm86 },
        { "lm89", lm86 },
@@ -229,6 +233,12 @@ static const struct lm90_params lm90_params[] = {
                .alert_alarms = 0x7c,
                .max_convrate = 10,
        },
+       [g781] = {
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+                 | LM90_HAVE_BROKEN_ALERT,
+               .alert_alarms = 0x7c,
+               .max_convrate = 8,
+       },
        [lm86] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
                .alert_alarms = 0x7b,
@@ -308,22 +318,24 @@ struct lm90_data {
 
        /* registers values */
        s8 temp8[8];    /* 0: local low limit
-                          1: local high limit
-                          2: local critical limit
-                          3: remote critical limit
-                          4: local emergency limit (max6659 and max6695/96)
-                          5: remote emergency limit (max6659 and max6695/96)
-                          6: remote 2 critical limit (max6695/96 only)
-                          7: remote 2 emergency limit (max6695/96 only) */
+                        * 1: local high limit
+                        * 2: local critical limit
+                        * 3: remote critical limit
+                        * 4: local emergency limit (max6659 and max6695/96)
+                        * 5: remote emergency limit (max6659 and max6695/96)
+                        * 6: remote 2 critical limit (max6695/96 only)
+                        * 7: remote 2 emergency limit (max6695/96 only)
+                        */
        s16 temp11[8];  /* 0: remote input
-                          1: remote low limit
-                          2: remote high limit
-                          3: remote offset (except max6646, max6657/58/59,
-                                            and max6695/96)
-                          4: local input
-                          5: remote 2 input (max6695/96 only)
-                          6: remote 2 low limit (max6695/96 only)
-                          7: remote 2 high limit (ma6695/96 only) */
+                        * 1: remote low limit
+                        * 2: remote high limit
+                        * 3: remote offset (except max6646, max6657/58/59,
+                        *                   and max6695/96)
+                        * 4: local input
+                        * 5: remote 2 input (max6695/96 only)
+                        * 6: remote 2 low limit (max6695/96 only)
+                        * 7: remote 2 high limit (max6695/96 only)
+                        */
        u8 temp_hyst;
        u16 alarms; /* bitvector (upper 8 bits for max6695/96) */
 };
@@ -533,8 +545,10 @@ static struct lm90_data *lm90_update_device(struct device *dev)
                                data->alarms |= alarms << 8;
                }
 
-               /* Re-enable ALERT# output if it was originally enabled and
-                * relevant alarms are all clear */
+               /*
+                * Re-enable ALERT# output if it was originally enabled and
+                * relevant alarms are all clear
+                */
                if ((data->config_orig & 0x80) == 0
                 && (data->alarms & data->alert_alarms) == 0) {
                        u8 config;
@@ -1162,8 +1176,10 @@ static int lm90_detect(struct i2c_client *client,
                 && (config1 & 0x3F) == 0x00
                 && convrate <= 0x0A) {
                        name = "adm1032";
-                       /* The ADM1032 supports PEC, but only if combined
-                          transactions are not used. */
+                       /*
+                        * The ADM1032 supports PEC, but only if combined
+                        * transactions are not used.
+                        */
                        if (i2c_check_functionality(adapter,
                                                    I2C_FUNC_SMBUS_BYTE))
                                info->flags |= I2C_CLIENT_PEC;
@@ -1283,6 +1299,13 @@ static int lm90_detect(struct i2c_client *client,
                 && convrate <= 0x09) {
                        name = "sa56004";
                }
+       } else
+       if ((address == 0x4C || address == 0x4D)
+        && man_id == 0x47) { /* GMT */
+               if (chip_id == 0x01 /* G781 */
+                && (config1 & 0x3F) == 0x00
+                && convrate <= 0x08)
+                       name = "g781";
        }
 
        if (!name) { /* identification failed */
@@ -1313,6 +1336,15 @@ static void lm90_remove_files(struct i2c_client *client, struct lm90_data *data)
        sysfs_remove_group(&dev->kobj, &lm90_group);
 }
 
+static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data)
+{
+       /* Restore initial configuration */
+       i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
+                                 data->convrate_orig);
+       i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
+                                 data->config_orig);
+}
+
 static void lm90_init_client(struct i2c_client *client)
 {
        u8 config, convrate;
@@ -1382,8 +1414,10 @@ static int lm90_probe(struct i2c_client *client,
                        client->flags &= ~I2C_CLIENT_PEC;
        }
 
-       /* Different devices have different alarm bits triggering the
-        * ALERT# output */
+       /*
+        * Different devices have different alarm bits triggering the
+        * ALERT# output
+        */
        data->alert_alarms = lm90_params[data->kind].alert_alarms;
 
        /* Set chip capabilities */
@@ -1399,7 +1433,7 @@ static int lm90_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&dev->kobj, &lm90_group);
        if (err)
-               goto exit_free;
+               goto exit_restore;
        if (client->flags & I2C_CLIENT_PEC) {
                err = device_create_file(dev, &dev_attr_pec);
                if (err)
@@ -1438,7 +1472,8 @@ static int lm90_probe(struct i2c_client *client,
 
 exit_remove_files:
        lm90_remove_files(client, data);
-exit_free:
+exit_restore:
+       lm90_restore_conf(client, data);
        kfree(data);
 exit:
        return err;
@@ -1450,12 +1485,7 @@ static int lm90_remove(struct i2c_client *client)
 
        hwmon_device_unregister(data->hwmon_dev);
        lm90_remove_files(client, data);
-
-       /* Restore initial configuration */
-       i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
-                                 data->convrate_orig);
-       i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
-                                 data->config_orig);
+       lm90_restore_conf(client, data);
 
        kfree(data);
        return 0;
@@ -1488,9 +1518,11 @@ static void lm90_alert(struct i2c_client *client, unsigned int flag)
                        dev_warn(&client->dev,
                                 "temp%d out of range, please check!\n", 3);
 
-               /* Disable ALERT# output, because these chips don't implement
-                 SMBus alert correctly; they should only hold the alert line
-                 low briefly. */
+               /*
+                * Disable ALERT# output, because these chips don't implement
+                * SMBus alert correctly; they should only hold the alert line
+                * low briefly.
+                */
                if ((data->flags & LM90_HAVE_BROKEN_ALERT)
                 && (alarms & data->alert_alarms)) {
                        dev_dbg(&client->dev, "Disabling ALERT#\n");
index ef65ab5..ce86c5e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Driver for the Freescale Semiconductor MC13783 adc.
+ * Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
  *
  * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
  * Copyright (C) 2009 Sascha Hauer, Pengutronix
@@ -18,7 +18,7 @@
  * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include <linux/mfd/mc13783.h>
+#include <linux/mfd/mc13xxx.h>
 #include <linux/platform_device.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/err.h>
 
-#define MC13783_ADC_NAME       "mc13783-adc"
+#define DRIVER_NAME    "mc13783-adc"
+
+/* platform device id driver data */
+#define MC13783_ADC_16CHANS    1
+#define MC13783_ADC_BPDIV2     2
 
 struct mc13783_adc_priv {
        struct mc13xxx *mc13xxx;
        struct device *hwmon_dev;
+       char name[10];
 };
 
 static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute
                              *devattr, char *buf)
 {
-       return sprintf(buf, "mc13783_adc\n");
+       struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", priv->name);
 }
 
 static int mc13783_adc_read(struct device *dev,
                struct device_attribute *devattr, unsigned int *val)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
+       struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        unsigned int channel = attr->index;
        unsigned int sample[4];
@@ -53,7 +59,7 @@ static int mc13783_adc_read(struct device *dev,
 
        ret = mc13xxx_adc_do_conversion(priv->mc13xxx,
                        MC13XXX_ADC_MODE_MULT_CHAN,
-                       channel, sample);
+                       channel, 0, 0, sample);
        if (ret)
                return ret;
 
@@ -68,16 +74,21 @@ static ssize_t mc13783_adc_read_bp(struct device *dev,
                struct device_attribute *devattr, char *buf)
 {
        unsigned val;
+       struct platform_device *pdev = to_platform_device(dev);
+       kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
        int ret = mc13783_adc_read(dev, devattr, &val);
 
        if (ret)
                return ret;
 
-       /*
-        * BP (channel 2) reports with offset 2.4V to the actual value to fit
-        * the input range of the ADC.  unit = 2.25mV = 9/4 mV.
-        */
-       val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
+       if (driver_data & MC13783_ADC_BPDIV2)
+               val = DIV_ROUND_CLOSEST(val * 9, 2);
+       else
+               /*
+                * BP (channel 2) reports with offset 2.4V to the actual value
+                * to fit the input range of the ADC.  unit = 2.25mV = 9/4 mV.
+                */
+               val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
 
        return sprintf(buf, "%u\n", val);
 }
@@ -114,12 +125,21 @@ static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13);
 static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14);
 static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15);
 
-static struct attribute *mc13783_attr[] = {
+static struct attribute *mc13783_attr_base[] = {
        &dev_attr_name.attr,
        &sensor_dev_attr_in2_input.dev_attr.attr,
        &sensor_dev_attr_in5_input.dev_attr.attr,
        &sensor_dev_attr_in6_input.dev_attr.attr,
        &sensor_dev_attr_in7_input.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group mc13783_group_base = {
+       .attrs = mc13783_attr_base,
+};
+
+/* these are only used if MC13783_ADC_16CHANS is provided in driver data */
+static struct attribute *mc13783_attr_16chans[] = {
        &sensor_dev_attr_in8_input.dev_attr.attr,
        &sensor_dev_attr_in9_input.dev_attr.attr,
        &sensor_dev_attr_in10_input.dev_attr.attr,
@@ -127,8 +147,8 @@ static struct attribute *mc13783_attr[] = {
        NULL
 };
 
-static const struct attribute_group mc13783_group = {
-       .attrs = mc13783_attr,
+static const struct attribute_group mc13783_group_16chans = {
+       .attrs = mc13783_attr_16chans,
 };
 
 /* last four channels may be occupied by the touchscreen */
@@ -156,24 +176,37 @@ static int __init mc13783_adc_probe(struct platform_device *pdev)
 {
        struct mc13783_adc_priv *priv;
        int ret;
+       const struct platform_device_id *id = platform_get_device_id(pdev);
+       char *dash;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
        priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
+       snprintf(priv->name, ARRAY_SIZE(priv->name), "%s", id->name);
+       dash = strchr(priv->name, '-');
+       if (dash)
+               *dash = '\0';
 
        platform_set_drvdata(pdev, priv);
 
        /* Register sysfs hooks */
-       ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group);
+       ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base);
        if (ret)
-               goto out_err_create1;
+               goto out_err_create_base;
+
+       if (id->driver_data & MC13783_ADC_16CHANS) {
+               ret = sysfs_create_group(&pdev->dev.kobj,
+                               &mc13783_group_16chans);
+               if (ret)
+                       goto out_err_create_16chans;
+       }
 
        if (!mc13783_adc_use_touchscreen(pdev)) {
                ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
                if (ret)
-                       goto out_err_create2;
+                       goto out_err_create_ts;
        }
 
        priv->hwmon_dev = hwmon_device_register(&pdev->dev);
@@ -184,17 +217,20 @@ static int __init mc13783_adc_probe(struct platform_device *pdev)
                goto out_err_register;
        }
 
-
        return 0;
 
 out_err_register:
 
        if (!mc13783_adc_use_touchscreen(pdev))
                sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
-out_err_create2:
+out_err_create_ts:
 
-       sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
-out_err_create1:
+       if (id->driver_data & MC13783_ADC_16CHANS)
+               sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
+out_err_create_16chans:
+
+       sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
+out_err_create_base:
 
        platform_set_drvdata(pdev, NULL);
        kfree(priv);
@@ -205,13 +241,17 @@ out_err_create1:
 static int __devexit mc13783_adc_remove(struct platform_device *pdev)
 {
        struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
+       kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
 
        hwmon_device_unregister(priv->hwmon_dev);
 
        if (!mc13783_adc_use_touchscreen(pdev))
                sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
 
-       sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
+       if (driver_data & MC13783_ADC_16CHANS)
+               sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
+
+       sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
 
        platform_set_drvdata(pdev, NULL);
        kfree(priv);
@@ -219,12 +259,26 @@ static int __devexit mc13783_adc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id mc13783_adc_idtable[] = {
+       {
+               .name = "mc13783-adc",
+               .driver_data = MC13783_ADC_16CHANS,
+       }, {
+               .name = "mc13892-adc",
+               .driver_data = MC13783_ADC_BPDIV2,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable);
+
 static struct platform_driver mc13783_adc_driver = {
-       .remove         = __devexit_p(mc13783_adc_remove),
+       .remove         = __devexit_p(mc13783_adc_remove),
        .driver         = {
                .owner  = THIS_MODULE,
-               .name   = MC13783_ADC_NAME,
+               .name   = DRIVER_NAME,
        },
+       .id_table       = mc13783_adc_idtable,
 };
 
 static int __init mc13783_adc_init(void)
@@ -243,4 +297,3 @@ module_exit(mc13783_adc_exit);
 MODULE_DESCRIPTION("MC13783 ADC driver");
 MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" MC13783_ADC_NAME);
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c
new file mode 100644 (file)
index 0000000..d0afc0c
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * mcp3021.c - driver for the Microchip MCP3021 chip
+ *
+ * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc.
+ * Author: Mingkai Hu <Mingkai.hu@freescale.com>
+ *
+ * This driver export the value of analog input voltage to sysfs, the
+ * voltage unit is mV. Through the sysfs interface, lm-sensors tool
+ * can also display the input voltage.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+/* Vdd info */
+#define MCP3021_VDD_MAX                5500
+#define MCP3021_VDD_MIN                2700
+#define MCP3021_VDD_REF                3300
+
+/* output format */
+#define MCP3021_SAR_SHIFT      2
+#define MCP3021_SAR_MASK       0x3ff
+
+#define MCP3021_OUTPUT_RES     10      /* 10-bit resolution */
+#define MCP3021_OUTPUT_SCALE   4
+
+/*
+ * Client data (each client gets its own)
+ */
+struct mcp3021_data {
+       struct device *hwmon_dev;
+       u32 vdd;        /* device power supply */
+};
+
+static int mcp3021_read16(struct i2c_client *client)
+{
+       int ret;
+       u16 reg;
+       __be16 buf;
+
+       ret = i2c_master_recv(client, (char *)&buf, 2);
+       if (ret < 0)
+               return ret;
+       if (ret != 2)
+               return -EIO;
+
+       /* The output code of the MCP3021 is transmitted with MSB first. */
+       reg = be16_to_cpu(buf);
+
+       /*
+        * The ten-bit output code is composed of the lower 4-bit of the
+        * first byte and the upper 6-bit of the second byte.
+        */
+       reg = (reg >> MCP3021_SAR_SHIFT) & MCP3021_SAR_MASK;
+
+       return reg;
+}
+
+static inline u16 volts_from_reg(u16 vdd, u16 val)
+{
+       if (val == 0)
+               return 0;
+
+       val = val * MCP3021_OUTPUT_SCALE - MCP3021_OUTPUT_SCALE / 2;
+
+       return val * DIV_ROUND_CLOSEST(vdd,
+                       (1 << MCP3021_OUTPUT_RES) * MCP3021_OUTPUT_SCALE);
+}
+
+static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct mcp3021_data *data = i2c_get_clientdata(client);
+       int reg, in_input;
+
+       reg = mcp3021_read16(client);
+       if (reg < 0)
+               return reg;
+
+       in_input = volts_from_reg(data->vdd, reg);
+       return sprintf(buf, "%d\n", in_input);
+}
+
+static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL);
+
+static int mcp3021_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       int err;
+       struct mcp3021_data *data = NULL;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       data = kzalloc(sizeof(struct mcp3021_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+
+       if (client->dev.platform_data) {
+               data->vdd = *(u32 *)client->dev.platform_data;
+               if (data->vdd > MCP3021_VDD_MAX ||
+                               data->vdd < MCP3021_VDD_MIN) {
+                       err = -EINVAL;
+                       goto exit_free;
+               }
+       } else
+               data->vdd = MCP3021_VDD_REF;
+
+       err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
+       if (err)
+               goto exit_free;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove;
+       }
+
+       return 0;
+
+exit_remove:
+       sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
+exit_free:
+       kfree(data);
+       return err;
+}
+
+static int mcp3021_remove(struct i2c_client *client)
+{
+       struct mcp3021_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
+       kfree(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id mcp3021_id[] = {
+       { "mcp3021", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mcp3021_id);
+
+static struct i2c_driver mcp3021_driver = {
+       .driver = {
+               .name = "mcp3021",
+       },
+       .probe = mcp3021_probe,
+       .remove = mcp3021_remove,
+       .id_table = mcp3021_id,
+};
+
+module_i2c_driver(mcp3021_driver);
+
+MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>");
+MODULE_DESCRIPTION("Microchip MCP3021 driver");
+MODULE_LICENSE("GPL");
index 834e49d..d6b0bdd 100644 (file)
@@ -71,8 +71,8 @@ MODULE_PARM_DESC(timeout,
        "Watchdog timeout in minutes. 2<= timeout <=255 (default="
                                __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
index deb12c9..d887cb3 100644 (file)
@@ -72,8 +72,10 @@ MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
 #define TEMP_CRIT_HYST                 2
 #define TEMP_WARN                      3
 #define TEMP_WARN_HYST                 4
-/* only crit and crit_hyst affect real-time alarm status
- * current crit crit_hyst warn warn_hyst */
+/*
+ * only crit and crit_hyst affect real-time alarm status
+ * current crit crit_hyst warn warn_hyst
+ */
 static const u16 W83795_REG_TEMP[][5] = {
        {0x21, 0x96, 0x97, 0x98, 0x99}, /* TD1/TR1 */
        {0x22, 0x9a, 0x9b, 0x9c, 0x9d}, /* TD2/TR2 */
@@ -354,26 +356,34 @@ struct w83795_data {
        u8 temp_mode;           /* Bit vector, 0 = TR, 1 = TD */
        u8 temp_src[3];         /* Register value */
 
-       u8 enable_dts;          /* Enable PECI and SB-TSI,
+       u8 enable_dts;          /*
+                                * Enable PECI and SB-TSI,
                                 * bit 0: =1 enable, =0 disable,
-                                * bit 1: =1 AMD SB-TSI, =0 Intel PECI */
+                                * bit 1: =1 AMD SB-TSI, =0 Intel PECI
+                                */
        u8 has_dts;             /* Enable monitor DTS temp */
        s8 dts[8];              /* Register value */
        u8 dts_read_vrlsb[8];   /* Register value */
        s8 dts_ext[4];          /* Register value */
 
-       u8 has_pwm;             /* 795g supports 8 pwm, 795adg only supports 2,
+       u8 has_pwm;             /*
+                                * 795g supports 8 pwm, 795adg only supports 2,
                                 * no config register, only affected by chip
-                                * type */
-       u8 pwm[8][5];           /* Register value, output, freq, start,
-                                *  non stop, stop time */
+                                * type
+                                */
+       u8 pwm[8][5];           /*
+                                * Register value, output, freq, start,
+                                *  non stop, stop time
+                                */
        u16 clkin;              /* CLKIN frequency in kHz */
        u8 pwm_fcms[2];         /* Register value */
        u8 pwm_tfmr[6];         /* Register value */
        u8 pwm_fomc;            /* Register value */
 
-       u16 target_speed[8];    /* Register value, target speed for speed
-                                * cruise */
+       u16 target_speed[8];    /*
+                                * Register value, target speed for speed
+                                * cruise
+                                */
        u8 tol_speed;           /* tolerance of target speed */
        u8 pwm_temp[6][4];      /* TTTI, CTFS, HCT, HOT */
        u8 sf4_reg[6][2][7];    /* 6 temp, temp/dcpwm, 7 registers */
@@ -482,8 +492,10 @@ static void w83795_update_limits(struct i2c_client *client)
        /* Read the fan limits */
        lsb = 0; /* Silent false gcc warning */
        for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
-               /* Each register contains LSB for 2 fans, but we want to
-                * read it only once to save time */
+               /*
+                * Each register contains LSB for 2 fans, but we want to
+                * read it only once to save time
+                */
                if ((i & 1) == 0 && (data->has_fan & (3 << i)))
                        lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i));
 
@@ -665,9 +677,11 @@ static struct w83795_data *w83795_update_device(struct device *dev)
                    w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT));
        }
 
-       /* Update intrusion and alarms
+       /*
+        * Update intrusion and alarms
         * It is important to read intrusion first, because reading from
-        * register SMI STS6 clears the interrupt status temporarily. */
+        * register SMI STS6 clears the interrupt status temporarily.
+        */
        tmp = w83795_read(client, W83795_REG_ALARM_CTRL);
        /* Switch to interrupt status for intrusion if needed */
        if (tmp & ALARM_CTRL_RTSACS)
@@ -929,6 +943,14 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
        if (val < 1 || val > 2)
                return -EINVAL;
 
+#ifndef CONFIG_SENSORS_W83795_FANCTRL
+       if (val > 1) {
+               dev_warn(dev, "Automatic fan speed control support disabled\n");
+               dev_warn(dev, "Build with CONFIG_SENSORS_W83795_FANCTRL=y if you want it\n");
+               return -EOPNOTSUPP;
+       }
+#endif
+
        mutex_lock(&data->update_lock);
        switch (val) {
        case 1:
@@ -1595,8 +1617,10 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
 
 #define NOT_USED                       -1
 
-/* Don't change the attribute order, _max, _min and _beep are accessed by index
- * somewhere else in the code */
+/*
+ * Don't change the attribute order, _max, _min and _beep are accessed by index
+ * somewhere else in the code
+ */
 #define SENSOR_ATTR_IN(index) {                                                \
        SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL,        \
                IN_READ, index), \
@@ -1610,8 +1634,10 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
                show_alarm_beep, store_beep, BEEP_ENABLE,               \
                index + ((index > 14) ? 1 : 0)) }
 
-/* Don't change the attribute order, _beep is accessed by index
- * somewhere else in the code */
+/*
+ * Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code
+ */
 #define SENSOR_ATTR_FAN(index) {                                       \
        SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan,            \
                NULL, FAN_INPUT, index - 1), \
@@ -1625,23 +1651,25 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
 #define SENSOR_ATTR_PWM(index) {                                       \
        SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm,          \
                store_pwm, PWM_OUTPUT, index - 1),                      \
+       SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO,           \
+               show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
+       SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO,                       \
+               show_pwm_mode, NULL, NOT_USED, index - 1),              \
+       SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO,             \
+               show_pwm, store_pwm, PWM_FREQ, index - 1),              \
        SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO,          \
                show_pwm, store_pwm, PWM_NONSTOP, index - 1),           \
        SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO,            \
                show_pwm, store_pwm, PWM_START, index - 1),             \
        SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO,        \
                show_pwm, store_pwm, PWM_STOP_TIME, index - 1),  \
-       SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO,     \
-               show_pwm, store_pwm, PWM_FREQ, index - 1),       \
-       SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO,           \
-               show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
-       SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO,                       \
-               show_pwm_mode, NULL, NOT_USED, index - 1),              \
        SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \
                show_fanin, store_fanin, FANIN_TARGET, index - 1) }
 
-/* Don't change the attribute order, _beep is accessed by index
- * somewhere else in the code */
+/*
+ * Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code
+ */
 #define SENSOR_ATTR_DTS(index) {                                       \
        SENSOR_ATTR_2(temp##index##_type, S_IRUGO ,             \
                show_dts_mode, NULL, NOT_USED, index - 7),      \
@@ -1660,8 +1688,10 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
        SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,            \
                show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) }
 
-/* Don't change the attribute order, _beep is accessed by index
- * somewhere else in the code */
+/*
+ * Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code
+ */
 #define SENSOR_ATTR_TEMP(index) {                                      \
        SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \
                show_temp_mode, store_temp_mode, NOT_USED, index - 1),  \
@@ -1867,8 +1897,10 @@ static int w83795_get_device_id(struct i2c_client *client)
 
        device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID);
 
-       /* Special case for rev. A chips; can't be checked first because later
-          revisions emulate this for compatibility */
+       /*
+        * Special case for rev. A chips; can't be checked first because later
+        * revisions emulate this for compatibility
+        */
        if (device_id < 0 || (device_id & 0xf0) != 0x50) {
                int alt_id;
 
@@ -1920,8 +1952,10 @@ static int w83795_detect(struct i2c_client *client,
                return -ENODEV;
        }
 
-       /* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR
-          should match */
+       /*
+        * If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR
+        * should match
+        */
        if ((bank & 0x07) == 0) {
                i2c_addr = i2c_smbus_read_byte_data(client,
                                                    W83795_REG_I2C_ADDR);
@@ -1933,10 +1967,12 @@ static int w83795_detect(struct i2c_client *client,
                }
        }
 
-       /* Check 795 chip type: 795G or 795ADG
-          Usually we don't write to chips during detection, but here we don't
-          quite have the choice; hopefully it's OK, we are about to return
-          success anyway */
+       /*
+        * Check 795 chip type: 795G or 795ADG
+        * Usually we don't write to chips during detection, but here we don't
+        * quite have the choice; hopefully it's OK, we are about to return
+        * success anyway
+        */
        if ((bank & 0x07) != 0)
                i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL,
                                          bank & ~0x07);
@@ -1953,6 +1989,14 @@ static int w83795_detect(struct i2c_client *client,
        return 0;
 }
 
+#ifdef CONFIG_SENSORS_W83795_FANCTRL
+#define NUM_PWM_ATTRIBUTES     ARRAY_SIZE(w83795_pwm[0])
+#define NUM_TEMP_ATTRIBUTES    ARRAY_SIZE(w83795_temp[0])
+#else
+#define NUM_PWM_ATTRIBUTES     4
+#define NUM_TEMP_ATTRIBUTES    8
+#endif
+
 static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
                               const struct device_attribute *))
 {
@@ -2006,24 +2050,18 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
                }
        }
 
-#ifdef CONFIG_SENSORS_W83795_FANCTRL
        for (i = 0; i < data->has_pwm; i++) {
-               for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) {
+               for (j = 0; j < NUM_PWM_ATTRIBUTES; j++) {
                        err = fn(dev, &w83795_pwm[i][j].dev_attr);
                        if (err)
                                return err;
                }
        }
-#endif
 
        for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) {
                if (!(data->has_temp & (1 << i)))
                        continue;
-#ifdef CONFIG_SENSORS_W83795_FANCTRL
-               for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) {
-#else
-               for (j = 0; j < 8; j++) {
-#endif
+               for (j = 0; j < NUM_TEMP_ATTRIBUTES; j++) {
                        if (j == 7 && !data->enable_beep)
                                continue;
                        err = fn(dev, &w83795_temp[i][j].dev_attr);
@@ -2183,8 +2221,10 @@ static int w83795_probe(struct i2c_client *client,
                /* The W83795G has a dedicated BEEP pin */
                data->enable_beep = 1;
        } else {
-               /* The W83795ADG has a shared pin for OVT# and BEEP, so you
-                * can't have both */
+               /*
+                * The W83795ADG has a shared pin for OVT# and BEEP, so you
+                * can't have both
+                */
                tmp = w83795_read(client, W83795_REG_OVT_CFG);
                if ((tmp & OVT_CFG_SEL) == 0)
                        data->enable_beep = 1;
index acba1c6..7f0b832 100644 (file)
@@ -15,7 +15,8 @@
 
     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.
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.
  * ------------------------------------------------------------------------- */
 
 /* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
@@ -111,7 +112,7 @@ static int sclhi(struct i2c_algo_bit_data *adap)
                                break;
                        return -ETIMEDOUT;
                }
-               cond_resched();
+               cpu_relax();
        }
 #ifdef DEBUG
        if (jiffies != start && i2c_debug >= 3)
index beb9ffe..73133b1 100644 (file)
@@ -15,7 +15,8 @@
  *
  *  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.
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301 USA.
  */
 
 #include <linux/kernel.h>
index 5eebf56..5c23795 100644 (file)
@@ -16,7 +16,8 @@
  *
  *  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.
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301 USA.
  *
  * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
  * Frodo Looijaard <frodol@dds.nl>, and also from Martin Bailey
index 5263a9e..1ec703e 100644 (file)
@@ -16,7 +16,8 @@
 
     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.          */
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.                                                 */
 /* --------------------------------------------------------------------        */
 
 /* With some changes from Frodo Looijaard <frodol@dds.nl> */
index 3101dd5..d2c5095 100644 (file)
@@ -103,6 +103,7 @@ config I2C_I801
            Patsburg (PCH)
            DH89xxCC (PCH)
            Panther Point (PCH)
+           Lynx Point (PCH)
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-i801.
@@ -369,6 +370,21 @@ config I2C_DESIGNWARE_PCI
          This driver can also be built as a module.  If so, the module
          will be called i2c-designware-pci.
 
+config I2C_EG20T
+       tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
+       depends on PCI
+       help
+         This driver is for PCH(Platform controller Hub) I2C of EG20T which
+         is an IOH(Input/Output Hub) for x86 embedded processor.
+         This driver can access PCH I2C bus device.
+
+         This driver also can be used for LAPIS Semiconductor IOH(Input/
+         Output Hub), ML7213, ML7223 and ML7831.
+         ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
+         for MP(Media Phone) use and ML7831 IOH is for general purpose use.
+         ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+         ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
+
 config I2C_GPIO
        tristate "GPIO-based bitbanging I2C"
        depends on GENERIC_GPIO
@@ -630,6 +646,16 @@ config I2C_SIMTEC
          This driver can also be built as a module. If so, the module
          will be called i2c-simtec.
 
+config I2C_SIRF
+       tristate "CSR SiRFprimaII I2C interface"
+       depends on ARCH_PRIMA2
+       help
+         If you say yes to this option, support will be included for the
+         CSR SiRFprimaII I2C interface.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-sirf.
+
 config I2C_STU300
        tristate "ST Microelectronics DDC I2C interface"
        depends on MACH_U300
@@ -681,20 +707,15 @@ config I2C_XILINX
          This driver can also be built as a module.  If so, the module
          will be called xilinx_i2c.
 
-config I2C_EG20T
-       tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
-       depends on PCI
+config I2C_XLR
+       tristate "XLR I2C support"
+       depends on CPU_XLR
        help
-         This driver is for PCH(Platform controller Hub) I2C of EG20T which
-         is an IOH(Input/Output Hub) for x86 embedded processor.
-         This driver can access PCH I2C bus device.
+         This driver enables support for the on-chip I2C interface of
+         the Netlogic XLR/XLS MIPS processors.
 
-         This driver also can be used for LAPIS Semiconductor IOH(Input/
-         Output Hub), ML7213, ML7223 and ML7831.
-         ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
-         for MP(Media Phone) use and ML7831 IOH is for general purpose use.
-         ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
-         ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-xlr.
 
 comment "External I2C/SMBus adapter drivers"
 
index fba6da6..569567b 100644 (file)
@@ -37,6 +37,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
 i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o
 obj-$(CONFIG_I2C_DESIGNWARE_PCI)       += i2c-designware-pci.o
 i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o
+obj-$(CONFIG_I2C_EG20T)                += i2c-eg20t.o
 obj-$(CONFIG_I2C_GPIO)         += i2c-gpio.o
 obj-$(CONFIG_I2C_HIGHLANDER)   += i2c-highlander.o
 obj-$(CONFIG_I2C_IBM_IIC)      += i2c-ibm_iic.o
@@ -63,12 +64,13 @@ obj-$(CONFIG_I2C_S6000)             += i2c-s6000.o
 obj-$(CONFIG_I2C_SH7760)       += i2c-sh7760.o
 obj-$(CONFIG_I2C_SH_MOBILE)    += i2c-sh_mobile.o
 obj-$(CONFIG_I2C_SIMTEC)       += i2c-simtec.o
+obj-$(CONFIG_I2C_SIRF)         += i2c-sirf.o
 obj-$(CONFIG_I2C_STU300)       += i2c-stu300.o
 obj-$(CONFIG_I2C_TEGRA)                += i2c-tegra.o
 obj-$(CONFIG_I2C_VERSATILE)    += i2c-versatile.o
 obj-$(CONFIG_I2C_OCTEON)       += i2c-octeon.o
 obj-$(CONFIG_I2C_XILINX)       += i2c-xiic.o
-obj-$(CONFIG_I2C_EG20T)         += i2c-eg20t.o
+obj-$(CONFIG_I2C_XLR)          += i2c-xlr.o
 
 # External I2C/SMBus adapter drivers
 obj-$(CONFIG_I2C_DIOLAN_U2C)   += i2c-diolan-u2c.o
index 5244c47..4ba589a 100644 (file)
@@ -214,7 +214,7 @@ static int __init dw_i2c_init_driver(void)
 {
        return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
 }
-module_init(dw_i2c_init_driver);
+subsys_initcall(dw_i2c_init_driver);
 
 static void __exit dw_i2c_exit_driver(void)
 {
index ca88776..f086131 100644 (file)
@@ -271,30 +271,36 @@ static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
 /**
  * pch_i2c_wait_for_bus_idle() - check the status of bus.
  * @adap:      Pointer to struct i2c_algo_pch_data.
- * @timeout:   waiting time counter (us).
+ * @timeout:   waiting time counter (ms).
  */
 static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
                                     s32 timeout)
 {
        void __iomem *p = adap->pch_base_address;
-       ktime_t ns_val;
+       int schedule = 0;
+       unsigned long end = jiffies + msecs_to_jiffies(timeout);
+
+       while (ioread32(p + PCH_I2CSR) & I2CMBB_BIT) {
+               if (time_after(jiffies, end)) {
+                       pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+                       pch_err(adap, "%s: Timeout Error.return%d\n",
+                                       __func__, -ETIME);
+                       pch_i2c_init(adap);
 
-       if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
-               return 0;
+                       return -ETIME;
+               }
 
-       /* MAX timeout value is timeout*1000*1000nsec */
-       ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000);
-       do {
-               msleep(20);
-               if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0)
-                       return 0;
-       } while (ktime_lt(ktime_get(), ns_val));
+               if (!schedule)
+                       /* Retry after some usecs */
+                       udelay(5);
+               else
+                       /* Wait a bit more without consuming CPU */
+                       usleep_range(20, 1000);
 
-       pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
-       pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME);
-       pch_i2c_init(adap);
+               schedule = 1;
+       }
 
-       return -ETIME;
+       return 0;
 }
 
 /**
@@ -778,8 +784,6 @@ static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
        struct i2c_msg *pmsg;
        u32 i = 0;
        u32 status;
-       u32 msglen;
-       u32 subaddrlen;
        s32 ret;
 
        struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
@@ -804,12 +808,6 @@ static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
                status = pmsg->flags;
                pch_dbg(adap,
                        "After invoking I2C_MODE_SEL :flag= 0x%x\n", status);
-               /* calculate sub address length and message length */
-               /* these are applicable only for buffer mode */
-               subaddrlen = pmsg->buf[0];
-               /* calculate actual message length excluding
-                * the sub address fields */
-               msglen = (pmsg->len) - (subaddrlen + 1);
 
                if ((status & (I2C_M_RD)) != false) {
                        ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num),
index a651779..c0330a4 100644 (file)
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
-
-#include <asm/gpio.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_i2c.h>
+
+struct i2c_gpio_private_data {
+       struct i2c_adapter adap;
+       struct i2c_algo_bit_data bit_data;
+       struct i2c_gpio_platform_data pdata;
+};
 
 /* Toggle SDA by changing the direction of the pin */
 static void i2c_gpio_setsda_dir(void *data, int state)
@@ -78,24 +85,62 @@ static int i2c_gpio_getscl(void *data)
        return gpio_get_value(pdata->scl_pin);
 }
 
+static int __devinit of_i2c_gpio_probe(struct device_node *np,
+                            struct i2c_gpio_platform_data *pdata)
+{
+       u32 reg;
+
+       if (of_gpio_count(np) < 2)
+               return -ENODEV;
+
+       pdata->sda_pin = of_get_gpio(np, 0);
+       pdata->scl_pin = of_get_gpio(np, 1);
+
+       if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) {
+               pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n",
+                      np->full_name, pdata->sda_pin, pdata->scl_pin);
+               return -ENODEV;
+       }
+
+       of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay);
+
+       if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", &reg))
+               pdata->timeout = msecs_to_jiffies(reg);
+
+       pdata->sda_is_open_drain =
+               of_property_read_bool(np, "i2c-gpio,sda-open-drain");
+       pdata->scl_is_open_drain =
+               of_property_read_bool(np, "i2c-gpio,scl-open-drain");
+       pdata->scl_is_output_only =
+               of_property_read_bool(np, "i2c-gpio,scl-output-only");
+
+       return 0;
+}
+
 static int __devinit i2c_gpio_probe(struct platform_device *pdev)
 {
+       struct i2c_gpio_private_data *priv;
        struct i2c_gpio_platform_data *pdata;
        struct i2c_algo_bit_data *bit_data;
        struct i2c_adapter *adap;
        int ret;
 
-       pdata = pdev->dev.platform_data;
-       if (!pdata)
-               return -ENXIO;
-
-       ret = -ENOMEM;
-       adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
-       if (!adap)
-               goto err_alloc_adap;
-       bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);
-       if (!bit_data)
-               goto err_alloc_bit_data;
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       adap = &priv->adap;
+       bit_data = &priv->bit_data;
+       pdata = &priv->pdata;
+
+       if (pdev->dev.of_node) {
+               ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata);
+               if (ret)
+                       return ret;
+       } else {
+               if (!pdev->dev.platform_data)
+                       return -ENXIO;
+               memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
+       }
 
        ret = gpio_request(pdata->sda_pin, "sda");
        if (ret)
@@ -143,6 +188,7 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev)
        adap->algo_data = bit_data;
        adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        adap->dev.parent = &pdev->dev;
+       adap->dev.of_node = pdev->dev.of_node;
 
        /*
         * If "dev->id" is negative we consider it as zero.
@@ -154,7 +200,9 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev)
        if (ret)
                goto err_add_bus;
 
-       platform_set_drvdata(pdev, adap);
+       of_i2c_register_devices(adap);
+
+       platform_set_drvdata(pdev, priv);
 
        dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
                 pdata->sda_pin, pdata->scl_pin,
@@ -168,34 +216,40 @@ err_add_bus:
 err_request_scl:
        gpio_free(pdata->sda_pin);
 err_request_sda:
-       kfree(bit_data);
-err_alloc_bit_data:
-       kfree(adap);
-err_alloc_adap:
        return ret;
 }
 
 static int __devexit i2c_gpio_remove(struct platform_device *pdev)
 {
+       struct i2c_gpio_private_data *priv;
        struct i2c_gpio_platform_data *pdata;
        struct i2c_adapter *adap;
 
-       adap = platform_get_drvdata(pdev);
-       pdata = pdev->dev.platform_data;
+       priv = platform_get_drvdata(pdev);
+       adap = &priv->adap;
+       pdata = &priv->pdata;
 
        i2c_del_adapter(adap);
        gpio_free(pdata->scl_pin);
        gpio_free(pdata->sda_pin);
-       kfree(adap->algo_data);
-       kfree(adap);
 
        return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id i2c_gpio_dt_ids[] = {
+       { .compatible = "i2c-gpio", },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids);
+#endif
+
 static struct platform_driver i2c_gpio_driver = {
        .driver         = {
                .name   = "i2c-gpio",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(i2c_gpio_dt_ids),
        },
        .probe          = i2c_gpio_probe,
        .remove         = __devexit_p(i2c_gpio_remove),
index 5d2e281..ae2945a 100644 (file)
@@ -2,7 +2,7 @@
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
     <mdsxyz123@yahoo.com>
-    Copyright (C) 2007, 2008   Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2007 - 2012  Jean Delvare <khali@linux-fr.org>
     Copyright (C) 2010         Intel Corporation,
                                David Woodhouse <dwmw2@infradead.org>
 
@@ -51,6 +51,7 @@
   Patsburg (PCH) IDF    0x1d72     32     hard     yes     yes     yes
   DH89xxCC (PCH)        0x2330     32     hard     yes     yes     yes
   Panther Point (PCH)   0x1e22     32     hard     yes     yes     yes
+  Lynx Point (PCH)      0x8c22     32     hard     yes     yes     yes
 
   Features supported by this driver:
   Software PEC                     no
 #define SMBHSTCNT_KILL         2
 
 /* Other settings */
-#define MAX_TIMEOUT            100
+#define MAX_RETRIES            400
 #define ENABLE_INT9            0       /* set to 0x01 to enable - untested */
 
 /* I801 command constants */
 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
 #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS     0x2330
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS        0x3b30
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS    0x8c22
 
 struct i801_priv {
        struct i2c_adapter adapter;
@@ -215,7 +217,7 @@ static int i801_check_post(struct i801_priv *priv, int status, int timeout)
                dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
                outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL,
                       SMBHSTCNT(priv));
-               msleep(1);
+               usleep_range(1000, 2000);
                outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL),
                       SMBHSTCNT(priv));
 
@@ -272,11 +274,11 @@ static int i801_transaction(struct i801_priv *priv, int xact)
 
        /* We will always wait for a fraction of a second! */
        do {
-               msleep(1);
+               usleep_range(250, 500);
                status = inb_p(SMBHSTSTS(priv));
-       } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
+       } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES));
 
-       result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
+       result = i801_check_post(priv, status, timeout > MAX_RETRIES);
        if (result < 0)
                return result;
 
@@ -291,12 +293,12 @@ static void i801_wait_hwpec(struct i801_priv *priv)
        int status;
 
        do {
-               msleep(1);
+               usleep_range(250, 500);
                status = inb_p(SMBHSTSTS(priv));
        } while ((!(status & SMBHSTSTS_INTR))
-                && (timeout++ < MAX_TIMEOUT));
+                && (timeout++ < MAX_RETRIES));
 
-       if (timeout > MAX_TIMEOUT)
+       if (timeout > MAX_RETRIES)
                dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n");
 
        outb_p(status, SMBHSTSTS(priv));
@@ -380,12 +382,12 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
                /* We will always wait for a fraction of a second! */
                timeout = 0;
                do {
-                       msleep(1);
+                       usleep_range(250, 500);
                        status = inb_p(SMBHSTSTS(priv));
                } while ((!(status & SMBHSTSTS_BYTE_DONE))
-                        && (timeout++ < MAX_TIMEOUT));
+                        && (timeout++ < MAX_RETRIES));
 
-               result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
+               result = i801_check_post(priv, status, timeout > MAX_RETRIES);
                if (result < 0)
                        return result;
 
@@ -633,6 +635,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) },
        { 0, }
 };
 
index 58832e5..dfb84b7 100644 (file)
@@ -149,11 +149,6 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
                        break;
                if (!for_busy && !(temp & I2SR_IBB))
                        break;
-               if (signal_pending(current)) {
-                       dev_dbg(&i2c_imx->adapter.dev,
-                               "<%s> I2C Interrupted\n", __func__);
-                       return -EINTR;
-               }
                if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
                        dev_dbg(&i2c_imx->adapter.dev,
                                "<%s> I2C bus is busy\n", __func__);
@@ -196,7 +191,7 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
 
        dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
 
-       clk_enable(i2c_imx->clk);
+       clk_prepare_enable(i2c_imx->clk);
        writeb(i2c_imx->ifdr, i2c_imx->base + IMX_I2C_IFDR);
        /* Enable I2C controller */
        writeb(0, i2c_imx->base + IMX_I2C_I2SR);
@@ -245,7 +240,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
 
        /* Disable I2C controller */
        writeb(0, i2c_imx->base + IMX_I2C_I2CR);
-       clk_disable(i2c_imx->clk);
+       clk_disable_unprepare(i2c_imx->clk);
 }
 
 static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
index 6561d27..f90a605 100644 (file)
@@ -47,7 +47,7 @@
 #define SMBBLKDAT      (0x20 + sch_smba)
 
 /* Other settings */
-#define MAX_TIMEOUT    500
+#define MAX_RETRIES    5000
 
 /* I2C constants */
 #define SCH_QUICK              0x00
@@ -68,7 +68,7 @@ static int sch_transaction(void)
 {
        int temp;
        int result = 0;
-       int timeout = 0;
+       int retries = 0;
 
        dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
                "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
@@ -100,12 +100,12 @@ static int sch_transaction(void)
        outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT);
 
        do {
-               msleep(1);
+               usleep_range(100, 200);
                temp = inb(SMBHSTSTS) & 0x0f;
-       } while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT));
+       } while ((temp & 0x08) && (retries++ < MAX_RETRIES));
 
        /* If the SMBus is still busy, we give up */
-       if (timeout > MAX_TIMEOUT) {
+       if (retries > MAX_RETRIES) {
                dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
                result = -ETIMEDOUT;
        }
index a8ebb84..206caac 100644 (file)
@@ -454,7 +454,7 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
 }
 
 static int mpc_read(struct mpc_i2c *i2c, int target,
-                   u8 *data, int length, int restart)
+                   u8 *data, int length, int restart, bool recv_len)
 {
        unsigned timeout = i2c->adap.timeout;
        int i, result;
@@ -470,7 +470,7 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
                return result;
 
        if (length) {
-               if (length == 1)
+               if (length == 1 && !recv_len)
                        writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
                else
                        writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
@@ -479,17 +479,46 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
        }
 
        for (i = 0; i < length; i++) {
+               u8 byte;
+
                result = i2c_wait(i2c, timeout, 0);
                if (result < 0)
                        return result;
 
-               /* Generate txack on next to last byte */
-               if (i == length - 2)
-                       writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
-               /* Do not generate stop on last byte */
-               if (i == length - 1)
-                       writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX);
-               data[i] = readb(i2c->base + MPC_I2C_DR);
+               /*
+                * For block reads, we have to know the total length (1st byte)
+                * before we can determine if we are done.
+                */
+               if (i || !recv_len) {
+                       /* Generate txack on next to last byte */
+                       if (i == length - 2)
+                               writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+                                        | CCR_TXAK);
+                       /* Do not generate stop on last byte */
+                       if (i == length - 1)
+                               writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+                                        | CCR_MTX);
+               }
+
+               byte = readb(i2c->base + MPC_I2C_DR);
+
+               /*
+                * Adjust length if first received byte is length.
+                * The length is 1 length byte plus actually data length
+                */
+               if (i == 0 && recv_len) {
+                       if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX)
+                               return -EPROTO;
+                       length += byte;
+                       /*
+                        * For block reads, generate txack here if data length
+                        * is 1 byte (total length is 2 bytes).
+                        */
+                       if (length == 2)
+                               writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+                                        | CCR_TXAK);
+               }
+               data[i] = byte;
        }
 
        return length;
@@ -532,12 +561,17 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        "Doing %s %d bytes to 0x%02x - %d of %d messages\n",
                        pmsg->flags & I2C_M_RD ? "read" : "write",
                        pmsg->len, pmsg->addr, i + 1, num);
-               if (pmsg->flags & I2C_M_RD)
-                       ret =
-                           mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
-               else
+               if (pmsg->flags & I2C_M_RD) {
+                       bool recv_len = pmsg->flags & I2C_M_RECV_LEN;
+
+                       ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i,
+                                      recv_len);
+                       if (recv_len && ret > 0)
+                               pmsg->len = ret;
+               } else {
                        ret =
                            mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+               }
        }
        mpc_i2c_stop(i2c);
        return (ret < 0) ? ret : num;
@@ -545,7 +579,8 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 
 static u32 mpc_functionality(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+         | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
 }
 
 static const struct i2c_algorithm mpc_algo = {
index d603646..f673326 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/i2c-pxa.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_i2c.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
@@ -1044,23 +1046,60 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
        .functionality  = i2c_pxa_functionality,
 };
 
-static int i2c_pxa_probe(struct platform_device *dev)
+static struct of_device_id i2c_pxa_dt_ids[] = {
+       { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX },
+       { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX },
+       { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX },
+       {}
+};
+MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
+
+static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
+                           enum pxa_i2c_types *i2c_types)
 {
-       struct pxa_i2c *i2c;
-       struct resource *res;
-       struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
-       const struct platform_device_id *id = platform_get_device_id(dev);
-       enum pxa_i2c_types i2c_type = id->driver_data;
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *of_id =
+                       of_match_device(i2c_pxa_dt_ids, &pdev->dev);
        int ret;
-       int irq;
 
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       irq = platform_get_irq(dev, 0);
-       if (res == NULL || irq < 0)
-               return -ENODEV;
+       if (!of_id)
+               return 1;
+       ret = of_alias_get_id(np, "i2c");
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+               return ret;
+       }
+       pdev->id = ret;
+       if (of_get_property(np, "mrvl,i2c-polling", NULL))
+               i2c->use_pio = 1;
+       if (of_get_property(np, "mrvl,i2c-fast-mode", NULL))
+               i2c->fast_mode = 1;
+       *i2c_types = (u32)(of_id->data);
+       return 0;
+}
 
-       if (!request_mem_region(res->start, resource_size(res), res->name))
-               return -ENOMEM;
+static int i2c_pxa_probe_pdata(struct platform_device *pdev,
+                              struct pxa_i2c *i2c,
+                              enum pxa_i2c_types *i2c_types)
+{
+       struct i2c_pxa_platform_data *plat = pdev->dev.platform_data;
+       const struct platform_device_id *id = platform_get_device_id(pdev);
+
+       *i2c_types = id->driver_data;
+       if (plat) {
+               i2c->use_pio = plat->use_pio;
+               i2c->fast_mode = plat->fast_mode;
+       }
+       return 0;
+}
+
+static int i2c_pxa_probe(struct platform_device *dev)
+{
+       struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
+       enum pxa_i2c_types i2c_type;
+       struct pxa_i2c *i2c;
+       struct resource *res = NULL;
+       int ret, irq;
 
        i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
        if (!i2c) {
@@ -1068,6 +1107,24 @@ static int i2c_pxa_probe(struct platform_device *dev)
                goto emalloc;
        }
 
+       ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type);
+       if (ret > 0)
+               ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type);
+       if (ret < 0)
+               goto eclk;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(dev, 0);
+       if (res == NULL || irq < 0) {
+               ret = -ENODEV;
+               goto eclk;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res), res->name)) {
+               ret = -ENOMEM;
+               goto eclk;
+       }
+
        i2c->adap.owner   = THIS_MODULE;
        i2c->adap.retries = 5;
 
@@ -1109,21 +1166,16 @@ static int i2c_pxa_probe(struct platform_device *dev)
 
        i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
 
-#ifdef CONFIG_I2C_PXA_SLAVE
        if (plat) {
+#ifdef CONFIG_I2C_PXA_SLAVE
                i2c->slave_addr = plat->slave_addr;
                i2c->slave = plat->slave;
-       }
 #endif
-
-       clk_enable(i2c->clk);
-
-       if (plat) {
                i2c->adap.class = plat->class;
-               i2c->use_pio = plat->use_pio;
-               i2c->fast_mode = plat->fast_mode;
        }
 
+       clk_enable(i2c->clk);
+
        if (i2c->use_pio) {
                i2c->adap.algo = &i2c_pxa_pio_algorithm;
        } else {
@@ -1234,6 +1286,7 @@ static struct platform_driver i2c_pxa_driver = {
                .name   = "pxa2xx-i2c",
                .owner  = THIS_MODULE,
                .pm     = I2C_PXA_DEV_PM_OPS,
+               .of_match_table = i2c_pxa_dt_ids,
        },
        .id_table       = i2c_pxa_id_table,
 };
index 4c17180..737f721 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
@@ -564,6 +565,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
        int retry;
        int ret;
 
+       pm_runtime_get_sync(&adap->dev);
        clk_enable(i2c->clk);
 
        for (retry = 0; retry < adap->retries; retry++) {
@@ -572,6 +574,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
 
                if (ret != -EAGAIN) {
                        clk_disable(i2c->clk);
+                       pm_runtime_put_sync(&adap->dev);
                        return ret;
                }
 
@@ -581,6 +584,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
        }
 
        clk_disable(i2c->clk);
+       pm_runtime_put_sync(&adap->dev);
        return -EREMOTEIO;
 }
 
@@ -890,7 +894,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
                }
        }
 
-       i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
+       i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL);
        if (!i2c) {
                dev_err(&pdev->dev, "no memory for state\n");
                return -ENOMEM;
@@ -1013,6 +1017,9 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
        of_i2c_register_devices(&i2c->adap);
        platform_set_drvdata(pdev, i2c);
 
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_enable(&i2c->adap.dev);
+
        dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
        clk_disable(i2c->clk);
        return 0;
@@ -1035,7 +1042,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
        clk_put(i2c->clk);
 
  err_noclk:
-       kfree(i2c);
        return ret;
 }
 
@@ -1048,6 +1054,9 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
 {
        struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
 
+       pm_runtime_disable(&i2c->adap.dev);
+       pm_runtime_disable(&pdev->dev);
+
        s3c24xx_i2c_deregister_cpufreq(i2c);
 
        i2c_del_adapter(&i2c->adap);
@@ -1061,7 +1070,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
        release_resource(i2c->ioarea);
        s3c24xx_i2c_dt_gpio_free(i2c);
        kfree(i2c->ioarea);
-       kfree(i2c);
 
        return 0;
 }
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
new file mode 100644 (file)
index 0000000..5574a47
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * I2C bus driver for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#define SIRFSOC_I2C_CLK_CTRL           0x00
+#define SIRFSOC_I2C_STATUS             0x0C
+#define SIRFSOC_I2C_CTRL               0x10
+#define SIRFSOC_I2C_IO_CTRL            0x14
+#define SIRFSOC_I2C_SDA_DELAY          0x18
+#define SIRFSOC_I2C_CMD_START          0x1C
+#define SIRFSOC_I2C_CMD_BUF            0x30
+#define SIRFSOC_I2C_DATA_BUF           0x80
+
+#define SIRFSOC_I2C_CMD_BUF_MAX                16
+#define SIRFSOC_I2C_DATA_BUF_MAX       16
+
+#define SIRFSOC_I2C_CMD(x)             (SIRFSOC_I2C_CMD_BUF + (x)*0x04)
+#define SIRFSOC_I2C_DATA_MASK(x)        (0xFF<<(((x)&3)*8))
+#define SIRFSOC_I2C_DATA_SHIFT(x)       (((x)&3)*8)
+
+#define SIRFSOC_I2C_DIV_MASK           (0xFFFF)
+
+/* I2C status flags */
+#define SIRFSOC_I2C_STAT_BUSY          BIT(0)
+#define SIRFSOC_I2C_STAT_TIP           BIT(1)
+#define SIRFSOC_I2C_STAT_NACK          BIT(2)
+#define SIRFSOC_I2C_STAT_TR_INT                BIT(4)
+#define SIRFSOC_I2C_STAT_STOP          BIT(6)
+#define SIRFSOC_I2C_STAT_CMD_DONE      BIT(8)
+#define SIRFSOC_I2C_STAT_ERR           BIT(9)
+#define SIRFSOC_I2C_CMD_INDEX          (0x1F<<16)
+
+/* I2C control flags */
+#define SIRFSOC_I2C_RESET              BIT(0)
+#define SIRFSOC_I2C_CORE_EN            BIT(1)
+#define SIRFSOC_I2C_MASTER_MODE                BIT(2)
+#define SIRFSOC_I2C_CMD_DONE_EN                BIT(11)
+#define SIRFSOC_I2C_ERR_INT_EN         BIT(12)
+
+#define SIRFSOC_I2C_SDA_DELAY_MASK     (0xFF)
+#define SIRFSOC_I2C_SCLF_FILTER                (3<<8)
+
+#define SIRFSOC_I2C_START_CMD          BIT(0)
+
+#define SIRFSOC_I2C_CMD_RP(x)          ((x)&0x7)
+#define SIRFSOC_I2C_NACK               BIT(3)
+#define SIRFSOC_I2C_WRITE              BIT(4)
+#define SIRFSOC_I2C_READ               BIT(5)
+#define SIRFSOC_I2C_STOP               BIT(6)
+#define SIRFSOC_I2C_START              BIT(7)
+
+#define SIRFSOC_I2C_DEFAULT_SPEED 100000
+
+struct sirfsoc_i2c {
+       void __iomem *base;
+       struct clk *clk;
+       u32 cmd_ptr;            /* Current position in CMD buffer */
+       u8 *buf;                /* Buffer passed by user */
+       u32 msg_len;            /* Message length */
+       u32 finished_len;       /* number of bytes read/written */
+       u32 read_cmd_len;       /* number of read cmd sent */
+       int msg_read;           /* 1 indicates a read message */
+       int err_status;         /* 1 indicates an error on bus */
+
+       u32 sda_delay;          /* For suspend/resume */
+       u32 clk_div;
+       int last;               /* Last message in transfer, STOP cmd can be sent */
+
+       struct completion done; /* indicates completion of message transfer */
+       struct i2c_adapter adapter;
+};
+
+static void i2c_sirfsoc_read_data(struct sirfsoc_i2c *siic)
+{
+       u32 data = 0;
+       int i;
+
+       for (i = 0; i < siic->read_cmd_len; i++) {
+               if (!(i & 0x3))
+                       data = readl(siic->base + SIRFSOC_I2C_DATA_BUF + i);
+               siic->buf[siic->finished_len++] =
+                       (u8)((data & SIRFSOC_I2C_DATA_MASK(i)) >>
+                               SIRFSOC_I2C_DATA_SHIFT(i));
+       }
+}
+
+static void i2c_sirfsoc_queue_cmd(struct sirfsoc_i2c *siic)
+{
+       u32 regval;
+       int i = 0;
+
+       if (siic->msg_read) {
+               while (((siic->finished_len + i) < siic->msg_len)
+                               && (siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX)) {
+                       regval = SIRFSOC_I2C_READ | SIRFSOC_I2C_CMD_RP(0);
+                       if (((siic->finished_len + i) ==
+                                       (siic->msg_len - 1)) && siic->last)
+                               regval |= SIRFSOC_I2C_STOP | SIRFSOC_I2C_NACK;
+                       writel(regval,
+                               siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+                       i++;
+               }
+
+               siic->read_cmd_len = i;
+       } else {
+               while ((siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX - 1)
+                               && (siic->finished_len < siic->msg_len)) {
+                       regval = SIRFSOC_I2C_WRITE | SIRFSOC_I2C_CMD_RP(0);
+                       if ((siic->finished_len == (siic->msg_len - 1))
+                               && siic->last)
+                               regval |= SIRFSOC_I2C_STOP;
+                       writel(regval,
+                               siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+                       writel(siic->buf[siic->finished_len++],
+                               siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+               }
+       }
+       siic->cmd_ptr = 0;
+
+       /* Trigger the transfer */
+       writel(SIRFSOC_I2C_START_CMD, siic->base + SIRFSOC_I2C_CMD_START);
+}
+
+static irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id)
+{
+       struct sirfsoc_i2c *siic = (struct sirfsoc_i2c *)dev_id;
+       u32 i2c_stat = readl(siic->base + SIRFSOC_I2C_STATUS);
+
+       if (i2c_stat & SIRFSOC_I2C_STAT_ERR) {
+               /* Error conditions */
+               siic->err_status = 1;
+               writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS);
+
+               if (i2c_stat & SIRFSOC_I2C_STAT_NACK)
+                       dev_err(&siic->adapter.dev, "ACK not received\n");
+               else
+                       dev_err(&siic->adapter.dev, "I2C error\n");
+
+               complete(&siic->done);
+       } else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) {
+               /* CMD buffer execution complete */
+               if (siic->msg_read)
+                       i2c_sirfsoc_read_data(siic);
+               if (siic->finished_len == siic->msg_len)
+                       complete(&siic->done);
+               else /* Fill a new CMD buffer for left data */
+                       i2c_sirfsoc_queue_cmd(siic);
+
+               writel(SIRFSOC_I2C_STAT_CMD_DONE, siic->base + SIRFSOC_I2C_STATUS);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
+       struct i2c_msg *msg)
+{
+       unsigned char addr;
+       u32 regval = SIRFSOC_I2C_START | SIRFSOC_I2C_CMD_RP(0) | SIRFSOC_I2C_WRITE;
+
+       /* no data and last message -> add STOP */
+       if (siic->last && (msg->len == 0))
+               regval |= SIRFSOC_I2C_STOP;
+
+       writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+
+       addr = msg->addr << 1;  /* Generate address */
+       if (msg->flags & I2C_M_RD)
+               addr |= 1;
+
+       writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+}
+
+static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
+{
+       u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL);
+       /* timeout waiting for the xfer to finish or fail */
+       int timeout = msecs_to_jiffies((msg->len + 1) * 50);
+       int ret = 0;
+
+       i2c_sirfsoc_set_address(siic, msg);
+
+       writel(regval | SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN,
+               siic->base + SIRFSOC_I2C_CTRL);
+       i2c_sirfsoc_queue_cmd(siic);
+
+       if (wait_for_completion_timeout(&siic->done, timeout) == 0) {
+               siic->err_status = 1;
+               dev_err(&siic->adapter.dev, "Transfer timeout\n");
+       }
+
+       writel(regval & ~(SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN),
+               siic->base + SIRFSOC_I2C_CTRL);
+       writel(0, siic->base + SIRFSOC_I2C_CMD_START);
+
+       if (siic->err_status) {
+               writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
+                       siic->base + SIRFSOC_I2C_CTRL);
+               while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+                       cpu_relax();
+
+               ret = -EIO;
+       }
+
+       return ret;
+}
+
+static u32 i2c_sirfsoc_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static int i2c_sirfsoc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+       int num)
+{
+       struct sirfsoc_i2c *siic = adap->algo_data;
+       int i, ret;
+
+       clk_enable(siic->clk);
+
+       for (i = 0; i < num; i++) {
+               siic->buf = msgs[i].buf;
+               siic->msg_len = msgs[i].len;
+               siic->msg_read = !!(msgs[i].flags & I2C_M_RD);
+               siic->err_status = 0;
+               siic->cmd_ptr = 0;
+               siic->finished_len = 0;
+               siic->last = (i == (num - 1));
+
+               ret = i2c_sirfsoc_xfer_msg(siic, &msgs[i]);
+               if (ret) {
+                       clk_disable(siic->clk);
+                       return ret;
+               }
+       }
+
+       clk_disable(siic->clk);
+       return num;
+}
+
+/* I2C algorithms associated with this master controller driver */
+static const struct i2c_algorithm i2c_sirfsoc_algo = {
+       .master_xfer = i2c_sirfsoc_xfer,
+       .functionality = i2c_sirfsoc_func,
+};
+
+static int __devinit i2c_sirfsoc_probe(struct platform_device *pdev)
+{
+       struct sirfsoc_i2c *siic;
+       struct i2c_adapter *adap;
+       struct resource *mem_res;
+       struct clk *clk;
+       int bitrate;
+       int ctrl_speed;
+       int irq;
+
+       int err;
+       u32 regval;
+
+       clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
+               err = PTR_ERR(clk);
+               dev_err(&pdev->dev, "Clock get failed\n");
+               goto err_get_clk;
+       }
+
+       err = clk_prepare(clk);
+       if (err) {
+               dev_err(&pdev->dev, "Clock prepare failed\n");
+               goto err_clk_prep;
+       }
+
+       err = clk_enable(clk);
+       if (err) {
+               dev_err(&pdev->dev, "Clock enable failed\n");
+               goto err_clk_en;
+       }
+
+       ctrl_speed = clk_get_rate(clk);
+
+       siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL);
+       if (!siic) {
+               dev_err(&pdev->dev, "Can't allocate driver data\n");
+               err = -ENOMEM;
+               goto out;
+       }
+       adap = &siic->adapter;
+       adap->class = I2C_CLASS_HWMON;
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (mem_res == NULL) {
+               dev_err(&pdev->dev, "Unable to get MEM resource\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       siic->base = devm_request_and_ioremap(&pdev->dev, mem_res);
+       if (siic->base == NULL) {
+               dev_err(&pdev->dev, "IO remap failed!\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               err = irq;
+               goto out;
+       }
+       err = devm_request_irq(&pdev->dev, irq, i2c_sirfsoc_irq, 0,
+               dev_name(&pdev->dev), siic);
+       if (err)
+               goto out;
+
+       adap->algo = &i2c_sirfsoc_algo;
+       adap->algo_data = siic;
+
+       adap->dev.parent = &pdev->dev;
+       adap->nr = pdev->id;
+
+       strlcpy(adap->name, "sirfsoc-i2c", sizeof(adap->name));
+
+       platform_set_drvdata(pdev, adap);
+       init_completion(&siic->done);
+
+       /* Controller Initalisation */
+
+       writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+       while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+               cpu_relax();
+       writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
+               siic->base + SIRFSOC_I2C_CTRL);
+
+       siic->clk = clk;
+
+       err = of_property_read_u32(pdev->dev.of_node,
+               "clock-frequency", &bitrate);
+       if (err < 0)
+               bitrate = SIRFSOC_I2C_DEFAULT_SPEED;
+
+       if (bitrate < 100000)
+               regval =
+                       (2 * ctrl_speed) / (2 * bitrate * 11);
+       else
+               regval = ctrl_speed / (bitrate * 5);
+
+       writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL);
+       if (regval > 0xFF)
+               writel(0xFF, siic->base + SIRFSOC_I2C_SDA_DELAY);
+       else
+               writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY);
+
+       err = i2c_add_numbered_adapter(adap);
+       if (err < 0) {
+               dev_err(&pdev->dev, "Can't add new i2c adapter\n");
+               goto out;
+       }
+
+       clk_disable(clk);
+
+       dev_info(&pdev->dev, " I2C adapter ready to operate\n");
+
+       return 0;
+
+out:
+       clk_disable(clk);
+err_clk_en:
+       clk_unprepare(clk);
+err_clk_prep:
+       clk_put(clk);
+err_get_clk:
+       return err;
+}
+
+static int __devexit i2c_sirfsoc_remove(struct platform_device *pdev)
+{
+       struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+       struct sirfsoc_i2c *siic = adapter->algo_data;
+
+       writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+       i2c_del_adapter(adapter);
+       clk_unprepare(siic->clk);
+       clk_put(siic->clk);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_sirfsoc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+       struct sirfsoc_i2c *siic = adapter->algo_data;
+
+       clk_enable(siic->clk);
+       siic->sda_delay = readl(siic->base + SIRFSOC_I2C_SDA_DELAY);
+       siic->clk_div = readl(siic->base + SIRFSOC_I2C_CLK_CTRL);
+       clk_disable(siic->clk);
+       return 0;
+}
+
+static int i2c_sirfsoc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+       struct sirfsoc_i2c *siic = adapter->algo_data;
+
+       clk_enable(siic->clk);
+       writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+       writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
+               siic->base + SIRFSOC_I2C_CTRL);
+       writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL);
+       writel(siic->sda_delay, siic->base + SIRFSOC_I2C_SDA_DELAY);
+       clk_disable(siic->clk);
+       return 0;
+}
+
+static const struct dev_pm_ops i2c_sirfsoc_pm_ops = {
+       .suspend = i2c_sirfsoc_suspend,
+       .resume = i2c_sirfsoc_resume,
+};
+#endif
+
+static const struct of_device_id sirfsoc_i2c_of_match[] __devinitconst = {
+       { .compatible = "sirf,prima2-i2c", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sirfsoc_i2c_of_match);
+
+static struct platform_driver i2c_sirfsoc_driver = {
+       .driver = {
+               .name = "sirfsoc_i2c",
+               .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm = &i2c_sirfsoc_pm_ops,
+#endif
+               .of_match_table = sirfsoc_i2c_of_match,
+       },
+       .probe = i2c_sirfsoc_probe,
+       .remove = __devexit_p(i2c_sirfsoc_remove),
+};
+module_platform_driver(i2c_sirfsoc_driver);
+
+MODULE_DESCRIPTION("SiRF SoC I2C master controller driver");
+MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>, "
+       "Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
+MODULE_LICENSE("GPL v2");
index 0ab4a95..e978635 100644 (file)
@@ -457,7 +457,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
        int ret;
 
        tegra_i2c_flush_fifos(i2c_dev);
-       i2c_writel(i2c_dev, 0xFF, I2C_INT_STATUS);
 
        if (msg->len == 0)
                return -EINVAL;
index 6055601..f585aea 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/of_i2c.h>
 
 #define I2C_CONTROL    0x00
 #define I2C_CONTROLS   0x00
@@ -99,6 +100,7 @@ static int i2c_versatile_probe(struct platform_device *dev)
        strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name));
        i2c->adap.algo_data = &i2c->algo;
        i2c->adap.dev.parent = &dev->dev;
+       i2c->adap.dev.of_node = dev->dev.of_node;
        i2c->algo = i2c_versatile_algo;
        i2c->algo.data = i2c;
 
@@ -111,6 +113,7 @@ static int i2c_versatile_probe(struct platform_device *dev)
                ret = i2c_bit_add_bus(&i2c->adap);
        if (ret >= 0) {
                platform_set_drvdata(dev, i2c);
+               of_i2c_register_devices(&i2c->adap);
                return 0;
        }
 
@@ -133,12 +136,19 @@ static int i2c_versatile_remove(struct platform_device *dev)
        return 0;
 }
 
+static const struct of_device_id i2c_versatile_match[] = {
+       { .compatible = "arm,versatile-i2c", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, i2c_versatile_match);
+
 static struct platform_driver i2c_versatile_driver = {
        .probe          = i2c_versatile_probe,
        .remove         = i2c_versatile_remove,
        .driver         = {
                .name   = "versatile-i2c",
                .owner  = THIS_MODULE,
+               .of_match_table = i2c_versatile_match,
        },
 };
 
diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c
new file mode 100644 (file)
index 0000000..96d3fab
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2011, Netlogic Microsystems Inc.
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+/* XLR I2C REGISTERS */
+#define XLR_I2C_CFG            0x00
+#define XLR_I2C_CLKDIV         0x01
+#define XLR_I2C_DEVADDR                0x02
+#define XLR_I2C_ADDR           0x03
+#define XLR_I2C_DATAOUT                0x04
+#define XLR_I2C_DATAIN         0x05
+#define XLR_I2C_STATUS         0x06
+#define XLR_I2C_STARTXFR       0x07
+#define XLR_I2C_BYTECNT                0x08
+#define XLR_I2C_HDSTATIM       0x09
+
+/* XLR I2C REGISTERS FLAGS */
+#define XLR_I2C_BUS_BUSY       0x01
+#define XLR_I2C_SDOEMPTY       0x02
+#define XLR_I2C_RXRDY          0x04
+#define XLR_I2C_ACK_ERR                0x08
+#define XLR_I2C_ARB_STARTERR   0x30
+
+/* Register Values */
+#define XLR_I2C_CFG_ADDR       0xF8
+#define XLR_I2C_CFG_NOADDR     0xFA
+#define XLR_I2C_STARTXFR_ND    0x02    /* No Data */
+#define XLR_I2C_STARTXFR_RD    0x01    /* Read */
+#define XLR_I2C_STARTXFR_WR    0x00    /* Write */
+
+#define XLR_I2C_TIMEOUT                10      /* timeout per byte in msec */
+
+/*
+ * On XLR/XLS, we need to use __raw_ IO to read the I2C registers
+ * because they are in the big-endian MMIO area on the SoC.
+ *
+ * The readl/writel implementation on XLR/XLS byteswaps, because
+ * those are for its little-endian PCI space (see arch/mips/Kconfig).
+ */
+static inline void xlr_i2c_wreg(u32 __iomem *base, unsigned int reg, u32 val)
+{
+       __raw_writel(val, base + reg);
+}
+
+static inline u32 xlr_i2c_rdreg(u32 __iomem *base, unsigned int reg)
+{
+       return __raw_readl(base + reg);
+}
+
+struct xlr_i2c_private {
+       struct i2c_adapter adap;
+       u32 __iomem *iobase;
+};
+
+static int xlr_i2c_tx(struct xlr_i2c_private *priv,  u16 len,
+       u8 *buf, u16 addr)
+{
+       struct i2c_adapter *adap = &priv->adap;
+       unsigned long timeout, stoptime, checktime;
+       u32 i2c_status;
+       int pos, timedout;
+       u8 offset, byte;
+
+       offset = buf[0];
+       xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset);
+       xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
+       xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_ADDR);
+       xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
+
+       timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
+       stoptime = jiffies + timeout;
+       timedout = 0;
+       pos = 1;
+retry:
+       if (len == 1) {
+               xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR,
+                               XLR_I2C_STARTXFR_ND);
+       } else {
+               xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos]);
+               xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR,
+                               XLR_I2C_STARTXFR_WR);
+       }
+
+       while (!timedout) {
+               checktime = jiffies;
+               i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+
+               if (i2c_status & XLR_I2C_SDOEMPTY) {
+                       pos++;
+                       /* need to do a empty dataout after the last byte */
+                       byte = (pos < len) ? buf[pos] : 0;
+                       xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, byte);
+
+                       /* reset timeout on successful xmit */
+                       stoptime = jiffies + timeout;
+               }
+               timedout = time_after(checktime, stoptime);
+
+               if (i2c_status & XLR_I2C_ARB_STARTERR) {
+                       if (timedout)
+                               break;
+                       goto retry;
+               }
+
+               if (i2c_status & XLR_I2C_ACK_ERR)
+                       return -EIO;
+
+               if ((i2c_status & XLR_I2C_BUS_BUSY) == 0 && pos >= len)
+                       return 0;
+       }
+       dev_err(&adap->dev, "I2C transmit timeout\n");
+       return -ETIMEDOUT;
+}
+
+static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)
+{
+       struct i2c_adapter *adap = &priv->adap;
+       u32 i2c_status;
+       unsigned long timeout, stoptime, checktime;
+       int nbytes, timedout;
+       u8 byte;
+
+       xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR);
+       xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len);
+       xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
+
+       timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
+       stoptime = jiffies + timeout;
+       timedout = 0;
+       nbytes = 0;
+retry:
+       xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD);
+
+       while (!timedout) {
+               checktime = jiffies;
+               i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+               if (i2c_status & XLR_I2C_RXRDY) {
+                       if (nbytes > len)
+                               return -EIO;    /* should not happen */
+
+                       /* we need to do a dummy datain when nbytes == len */
+                       byte = xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
+                       if (nbytes < len)
+                               buf[nbytes] = byte;
+                       nbytes++;
+
+                       /* reset timeout on successful read */
+                       stoptime = jiffies + timeout;
+               }
+
+               timedout = time_after(checktime, stoptime);
+               if (i2c_status & XLR_I2C_ARB_STARTERR) {
+                       if (timedout)
+                               break;
+                       goto retry;
+               }
+
+               if (i2c_status & XLR_I2C_ACK_ERR)
+                       return -EIO;
+
+               if ((i2c_status & XLR_I2C_BUS_BUSY) == 0)
+                       return 0;
+       }
+
+       dev_err(&adap->dev, "I2C receive timeout\n");
+       return -ETIMEDOUT;
+}
+
+static int xlr_i2c_xfer(struct i2c_adapter *adap,
+       struct i2c_msg *msgs, int num)
+{
+       struct i2c_msg *msg;
+       int i;
+       int ret = 0;
+       struct xlr_i2c_private *priv = i2c_get_adapdata(adap);
+
+       for (i = 0; ret == 0 && i < num; i++) {
+               msg = &msgs[i];
+               if (msg->flags & I2C_M_RD)
+                       ret = xlr_i2c_rx(priv, msg->len, &msg->buf[0],
+                                       msg->addr);
+               else
+                       ret = xlr_i2c_tx(priv, msg->len, &msg->buf[0],
+                                       msg->addr);
+       }
+
+       return (ret != 0) ? ret : num;
+}
+
+static u32 xlr_func(struct i2c_adapter *adap)
+{
+       /* Emulate SMBUS over I2C */
+       return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm xlr_i2c_algo = {
+       .master_xfer    = xlr_i2c_xfer,
+       .functionality  = xlr_func,
+};
+
+static int __devinit xlr_i2c_probe(struct platform_device *pdev)
+{
+       struct xlr_i2c_private  *priv;
+       struct resource *res;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->iobase = devm_request_and_ioremap(&pdev->dev, res);
+       if (!priv->iobase) {
+               dev_err(&pdev->dev, "devm_request_and_ioremap failed\n");
+               return -EBUSY;
+       }
+
+       priv->adap.dev.parent = &pdev->dev;
+       priv->adap.owner        = THIS_MODULE;
+       priv->adap.algo_data    = priv;
+       priv->adap.algo         = &xlr_i2c_algo;
+       priv->adap.nr           = pdev->id;
+       priv->adap.class        = I2C_CLASS_HWMON;
+       snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c");
+
+       i2c_set_adapdata(&priv->adap, priv);
+       ret = i2c_add_numbered_adapter(&priv->adap);
+       if (ret < 0) {
+               dev_err(&priv->adap.dev, "Failed to add i2c bus.\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, priv);
+       dev_info(&priv->adap.dev, "Added I2C Bus.\n");
+       return 0;
+}
+
+static int __devexit xlr_i2c_remove(struct platform_device *pdev)
+{
+       struct xlr_i2c_private *priv;
+
+       priv = platform_get_drvdata(pdev);
+       i2c_del_adapter(&priv->adap);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver xlr_i2c_driver = {
+       .probe  = xlr_i2c_probe,
+       .remove = __devexit_p(xlr_i2c_remove),
+       .driver = {
+               .name   = "xlr-i2cbus",
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(xlr_i2c_driver);
+
+MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@netlogicmicro.com>");
+MODULE_DESCRIPTION("XLR/XLS SoC I2C Controller driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:xlr-i2cbus");
index 10274ff..f24cc64 100644 (file)
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
  */
 
 #include <linux/kernel.h>
index e9c1893..feb7dc3 100644 (file)
@@ -14,7 +14,8 @@
 
     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.               */
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.                                                      */
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
index 9f9c57f..18a8fd2 100644 (file)
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
  */
 
 #include <linux/rwsem.h>
index 10e7f1e..4504832 100644 (file)
@@ -17,7 +17,8 @@
 
     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.
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.
 */
 
 /* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
index f61ccc1..9836d08 100644 (file)
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
  */
 
 #include <linux/kernel.h>
index ed699c5..e0df9b6 100644 (file)
@@ -393,18 +393,7 @@ static struct i2c_driver pca9541_driver = {
        .id_table = pca9541_id,
 };
 
-static int __init pca9541_init(void)
-{
-       return i2c_add_driver(&pca9541_driver);
-}
-
-static void __exit pca9541_exit(void)
-{
-       i2c_del_driver(&pca9541_driver);
-}
-
-module_init(pca9541_init);
-module_exit(pca9541_exit);
+module_i2c_driver(pca9541_driver);
 
 MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
 MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
index 6f89536..0e37ef2 100644 (file)
@@ -284,18 +284,7 @@ static struct i2c_driver pca954x_driver = {
        .id_table       = pca954x_id,
 };
 
-static int __init pca954x_init(void)
-{
-       return i2c_add_driver(&pca954x_driver);
-}
-
-static void __exit pca954x_exit(void)
-{
-       i2c_del_driver(&pca954x_driver);
-}
-
-module_init(pca954x_init);
-module_exit(pca954x_exit);
+module_i2c_driver(pca954x_driver);
 
 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
 MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
index eeafc30..9d639fa 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <mach/jornada720.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>");
 MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver");
index f2e0cbc..f9ce183 100644 (file)
@@ -105,6 +105,8 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, info);
+       device_init_wakeup(&pdev->dev, 1);
+
        return 0;
 
 out_irq:
@@ -129,10 +131,34 @@ static int __devexit pm860x_onkey_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_onkey_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag |= 1 << PM8607_IRQ_ONKEY;
+       return 0;
+}
+static int pm860x_onkey_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag &= ~(1 << PM8607_IRQ_ONKEY);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops, pm860x_onkey_suspend, pm860x_onkey_resume);
+
 static struct platform_driver pm860x_onkey_driver = {
        .driver         = {
                .name   = "88pm860x-onkey",
                .owner  = THIS_MODULE,
+               .pm     = &pm860x_onkey_pm_ops,
        },
        .probe          = pm860x_onkey_probe,
        .remove         = __devexit_p(pm860x_onkey_remove),
index 8407d5b..2ffd110 100644 (file)
@@ -208,18 +208,7 @@ static struct amba_driver ambakmi_driver = {
        .resume         = amba_kmi_resume,
 };
 
-static int __init amba_kmi_init(void)
-{
-       return amba_driver_register(&ambakmi_driver);
-}
-
-static void __exit amba_kmi_exit(void)
-{
-       amba_driver_unregister(&ambakmi_driver);
-}
-
-module_init(amba_kmi_init);
-module_exit(amba_kmi_exit);
+module_amba_driver(ambakmi_driver);
 
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("AMBA KMI controller driver");
index d4d08bd..bd5b10e 100644 (file)
@@ -92,8 +92,7 @@ static irqreturn_t ams_delta_serio_interrupt(int irq, void *dev_id)
 static int ams_delta_serio_open(struct serio *serio)
 {
        /* enable keyboard */
-       ams_delta_latch2_write(AMD_DELTA_LATCH2_KEYBRD_PWR,
-                       AMD_DELTA_LATCH2_KEYBRD_PWR);
+       gpio_set_value(AMS_DELTA_GPIO_PIN_KEYBRD_PWR, 1);
 
        return 0;
 }
@@ -101,9 +100,32 @@ static int ams_delta_serio_open(struct serio *serio)
 static void ams_delta_serio_close(struct serio *serio)
 {
        /* disable keyboard */
-       ams_delta_latch2_write(AMD_DELTA_LATCH2_KEYBRD_PWR, 0);
+       gpio_set_value(AMS_DELTA_GPIO_PIN_KEYBRD_PWR, 0);
 }
 
+static const struct gpio ams_delta_gpios[] __initconst_or_module = {
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_KEYBRD_DATA,
+               .flags  = GPIOF_DIR_IN,
+               .label  = "serio-data",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_KEYBRD_CLK,
+               .flags  = GPIOF_DIR_IN,
+               .label  = "serio-clock",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_KEYBRD_PWR,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "serio-power",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_KEYBRD_DATAOUT,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "serio-dataout",
+       },
+};
+
 static int __init ams_delta_serio_init(void)
 {
        int err;
@@ -123,19 +145,12 @@ static int __init ams_delta_serio_init(void)
        strlcpy(ams_delta_serio->phys, "GPIO/serio0",
                        sizeof(ams_delta_serio->phys));
 
-       err = gpio_request(AMS_DELTA_GPIO_PIN_KEYBRD_DATA, "serio-data");
+       err = gpio_request_array(ams_delta_gpios,
+                               ARRAY_SIZE(ams_delta_gpios));
        if (err) {
-               pr_err("ams_delta_serio: Couldn't request gpio pin for data\n");
+               pr_err("ams_delta_serio: Couldn't request gpio pins\n");
                goto serio;
        }
-       gpio_direction_input(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
-
-       err = gpio_request(AMS_DELTA_GPIO_PIN_KEYBRD_CLK, "serio-clock");
-       if (err) {
-               pr_err("ams_delta_serio: couldn't request gpio pin for clock\n");
-               goto gpio_data;
-       }
-       gpio_direction_input(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
 
        err = request_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK),
                        ams_delta_serio_interrupt, IRQ_TYPE_EDGE_RISING,
@@ -143,7 +158,7 @@ static int __init ams_delta_serio_init(void)
        if (err < 0) {
                pr_err("ams_delta_serio: couldn't request gpio interrupt %d\n",
                                gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
-               goto gpio_clk;
+               goto gpio;
        }
        /*
         * Since GPIO register handling for keyboard clock pin is performed
@@ -157,10 +172,9 @@ static int __init ams_delta_serio_init(void)
        dev_info(&ams_delta_serio->dev, "%s\n", ams_delta_serio->name);
 
        return 0;
-gpio_clk:
-       gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
-gpio_data:
-       gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
+gpio:
+       gpio_free_array(ams_delta_gpios,
+                       ARRAY_SIZE(ams_delta_gpios));
 serio:
        kfree(ams_delta_serio);
        return err;
@@ -171,7 +185,7 @@ static void __exit ams_delta_serio_exit(void)
 {
        serio_unregister_port(ams_delta_serio);
        free_irq(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
-       gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
-       gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
+       gpio_free_array(ams_delta_gpios,
+                       ARRAY_SIZE(ams_delta_gpios));
 }
 module_exit(ams_delta_serio_exit);
index d8aac17..2af5df6 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 
-#include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/hardware/iomd.h>
 
@@ -45,6 +44,11 @@ MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:kart");
 
+struct rpckbd_data {
+       int tx_irq;
+       int rx_irq;
+};
+
 static int rpckbd_write(struct serio *port, unsigned char val)
 {
        while (!(iomd_readb(IOMD_KCTRL) & (1 << 7)))
@@ -77,19 +81,21 @@ static irqreturn_t rpckbd_tx(int irq, void *dev_id)
 
 static int rpckbd_open(struct serio *port)
 {
+       struct rpckbd_data *rpckbd = port->port_data;
+
        /* Reset the keyboard state machine. */
        iomd_writeb(0, IOMD_KCTRL);
        iomd_writeb(8, IOMD_KCTRL);
        iomd_readb(IOMD_KARTRX);
 
-       if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", port) != 0) {
+       if (request_irq(rpckbd->rx_irq, rpckbd_rx, 0, "rpckbd", port) != 0) {
                printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ\n");
                return -EBUSY;
        }
 
-       if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", port) != 0) {
+       if (request_irq(rpckbd->tx_irq, rpckbd_tx, 0, "rpckbd", port) != 0) {
                printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n");
-               free_irq(IRQ_KEYBOARDRX, port);
+               free_irq(rpckbd->rx_irq, port);
                return -EBUSY;
        }
 
@@ -98,8 +104,10 @@ static int rpckbd_open(struct serio *port)
 
 static void rpckbd_close(struct serio *port)
 {
-       free_irq(IRQ_KEYBOARDRX, port);
-       free_irq(IRQ_KEYBOARDTX, port);
+       struct rpckbd_data *rpckbd = port->port_data;
+
+       free_irq(rpckbd->rx_irq, port);
+       free_irq(rpckbd->tx_irq, port);
 }
 
 /*
@@ -108,17 +116,35 @@ static void rpckbd_close(struct serio *port)
  */
 static int __devinit rpckbd_probe(struct platform_device *dev)
 {
+       struct rpckbd_data *rpckbd;
        struct serio *serio;
+       int tx_irq, rx_irq;
+
+       rx_irq = platform_get_irq(dev, 0);
+       if (rx_irq <= 0)
+               return rx_irq < 0 ? rx_irq : -ENXIO;
+
+       tx_irq = platform_get_irq(dev, 1);
+       if (tx_irq <= 0)
+               return tx_irq < 0 ? tx_irq : -ENXIO;
 
        serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
-       if (!serio)
+       rpckbd = kzalloc(sizeof(*rpckbd), GFP_KERNEL);
+       if (!serio || !rpckbd) {
+               kfree(rpckbd);
+               kfree(serio);
                return -ENOMEM;
+       }
+
+       rpckbd->rx_irq = rx_irq;
+       rpckbd->tx_irq = tx_irq;
 
        serio->id.type          = SERIO_8042;
        serio->write            = rpckbd_write;
        serio->open             = rpckbd_open;
        serio->close            = rpckbd_close;
        serio->dev.parent       = &dev->dev;
+       serio->port_data        = rpckbd;
        strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name));
        strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys));
 
@@ -130,7 +156,11 @@ static int __devinit rpckbd_probe(struct platform_device *dev)
 static int __devexit rpckbd_remove(struct platform_device *dev)
 {
        struct serio *serio = platform_get_drvdata(dev);
+       struct rpckbd_data *rpckbd = serio->port_data;
+
        serio_unregister_port(serio);
+       kfree(rpckbd);
+
        return 0;
 }
 
index e3c85fa..3897667 100644 (file)
 
 #include <asm/hardware/sa1111.h>
 
+#define PS2CR          0x0000
+#define PS2STAT                0x0004
+#define PS2DATA                0x0008
+#define PS2CLKDIV      0x000c
+#define PS2PRECNT      0x0010
+
+#define PS2CR_ENA      0x08
+#define PS2CR_FKD      0x02
+#define PS2CR_FKC      0x01
+
+#define PS2STAT_STP    0x0100
+#define PS2STAT_TXE    0x0080
+#define PS2STAT_TXB    0x0040
+#define PS2STAT_RXF    0x0020
+#define PS2STAT_RXB    0x0010
+#define PS2STAT_ENA    0x0008
+#define PS2STAT_RXP    0x0004
+#define PS2STAT_KBD    0x0002
+#define PS2STAT_KBC    0x0001
+
 struct ps2if {
        struct serio            *io;
        struct sa1111_dev       *dev;
@@ -44,22 +64,22 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id)
        struct ps2if *ps2if = dev_id;
        unsigned int scancode, flag, status;
 
-       status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+       status = sa1111_readl(ps2if->base + PS2STAT);
        while (status & PS2STAT_RXF) {
                if (status & PS2STAT_STP)
-                       sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT);
+                       sa1111_writel(PS2STAT_STP, ps2if->base + PS2STAT);
 
                flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
                       (status & PS2STAT_RXP ? 0 : SERIO_PARITY);
 
-               scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff;
+               scancode = sa1111_readl(ps2if->base + PS2DATA) & 0xff;
 
                if (hweight8(scancode) & 1)
                        flag ^= SERIO_PARITY;
 
                serio_interrupt(ps2if->io, scancode, flag);
 
-               status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+               status = sa1111_readl(ps2if->base + PS2STAT);
         }
 
         return IRQ_HANDLED;
@@ -74,12 +94,12 @@ static irqreturn_t ps2_txint(int irq, void *dev_id)
        unsigned int status;
 
        spin_lock(&ps2if->lock);
-       status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+       status = sa1111_readl(ps2if->base + PS2STAT);
        if (ps2if->head == ps2if->tail) {
                disable_irq_nosync(irq);
                /* done */
        } else if (status & PS2STAT_TXE) {
-               sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA);
+               sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA);
                ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
        }
        spin_unlock(&ps2if->lock);
@@ -102,8 +122,8 @@ static int ps2_write(struct serio *io, unsigned char val)
        /*
         * If the TX register is empty, we can go straight out.
         */
-       if (sa1111_readl(ps2if->base + SA1111_PS2STAT) & PS2STAT_TXE) {
-               sa1111_writel(val, ps2if->base + SA1111_PS2DATA);
+       if (sa1111_readl(ps2if->base + PS2STAT) & PS2STAT_TXE) {
+               sa1111_writel(val, ps2if->base + PS2DATA);
        } else {
                if (ps2if->head == ps2if->tail)
                        enable_irq(ps2if->dev->irq[1]);
@@ -123,13 +143,16 @@ static int ps2_open(struct serio *io)
        struct ps2if *ps2if = io->port_data;
        int ret;
 
-       sa1111_enable_device(ps2if->dev);
+       ret = sa1111_enable_device(ps2if->dev);
+       if (ret)
+               return ret;
 
        ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0,
                          SA1111_DRIVER_NAME(ps2if->dev), ps2if);
        if (ret) {
                printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
                        ps2if->dev->irq[0], ret);
+               sa1111_disable_device(ps2if->dev);
                return ret;
        }
 
@@ -139,6 +162,7 @@ static int ps2_open(struct serio *io)
                printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
                        ps2if->dev->irq[1], ret);
                free_irq(ps2if->dev->irq[0], ps2if);
+               sa1111_disable_device(ps2if->dev);
                return ret;
        }
 
@@ -146,7 +170,7 @@ static int ps2_open(struct serio *io)
 
        enable_irq_wake(ps2if->dev->irq[0]);
 
-       sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR);
+       sa1111_writel(PS2CR_ENA, ps2if->base + PS2CR);
        return 0;
 }
 
@@ -154,7 +178,7 @@ static void ps2_close(struct serio *io)
 {
        struct ps2if *ps2if = io->port_data;
 
-       sa1111_writel(0, ps2if->base + SA1111_PS2CR);
+       sa1111_writel(0, ps2if->base + PS2CR);
 
        disable_irq_wake(ps2if->dev->irq[0]);
 
@@ -174,7 +198,7 @@ static void __devinit ps2_clear_input(struct ps2if *ps2if)
        int maxread = 100;
 
        while (maxread--) {
-               if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff)
+               if ((sa1111_readl(ps2if->base + PS2DATA) & 0xff) == 0xff)
                        break;
        }
 }
@@ -184,11 +208,11 @@ static unsigned int __devinit ps2_test_one(struct ps2if *ps2if,
 {
        unsigned int val;
 
-       sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR);
+       sa1111_writel(PS2CR_ENA | mask, ps2if->base + PS2CR);
 
        udelay(2);
 
-       val = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+       val = sa1111_readl(ps2if->base + PS2STAT);
        return val & (PS2STAT_KBC | PS2STAT_KBD);
 }
 
@@ -219,7 +243,7 @@ static int __devinit ps2_test(struct ps2if *ps2if)
                ret = -ENODEV;
        }
 
-       sa1111_writel(0, ps2if->base + SA1111_PS2CR);
+       sa1111_writel(0, ps2if->base + PS2CR);
 
        return ret;
 }
@@ -273,8 +297,8 @@ static int __devinit ps2_probe(struct sa1111_dev *dev)
        sa1111_enable_device(ps2if->dev);
 
        /* Incoming clock is 8MHz */
-       sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV);
-       sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT);
+       sa1111_writel(0, ps2if->base + PS2CLKDIV);
+       sa1111_writel(127, ps2if->base + PS2PRECNT);
 
        /*
         * Flush any pending input.
@@ -329,6 +353,7 @@ static int __devexit ps2_remove(struct sa1111_dev *dev)
 static struct sa1111_driver ps2_driver = {
        .drv = {
                .name   = "sa1111-ps2",
+               .owner  = THIS_MODULE,
        },
        .devid          = SA1111_DEVID_PS2,
        .probe          = ps2_probe,
index 97b31a0..2a21419 100644 (file)
@@ -260,7 +260,7 @@ config TOUCHSCREEN_ILI210X
 
 config TOUCHSCREEN_S3C2410
        tristate "Samsung S3C2410/generic touchscreen input driver"
-       depends on ARCH_S3C2410 || SAMSUNG_DEV_TS
+       depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
        select S3C_ADC
        help
          Say Y here if you have the s3c2410 touchscreen.
index c3848ad..d9be6ea 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <mach/hardware.h>
 #include <mach/jornada720.h>
+#include <mach/irqs.h>
 
 MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
 MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
index ede0274..48dc5b0 100644 (file)
@@ -39,6 +39,7 @@ struct mc13783_ts_priv {
        struct delayed_work work;
        struct workqueue_struct *workq;
        unsigned int sample[4];
+       struct mc13xxx_ts_platform_data *touch;
 };
 
 static irqreturn_t mc13783_ts_handler(int irq, void *data)
@@ -125,7 +126,9 @@ static void mc13783_ts_work(struct work_struct *work)
        unsigned int channel = 12;
 
        if (mc13xxx_adc_do_conversion(priv->mc13xxx,
-                               mode, channel, priv->sample) == 0)
+                               mode, channel,
+                               priv->touch->ato, priv->touch->atox,
+                               priv->sample) == 0)
                mc13783_ts_report_sample(priv);
 }
 
@@ -179,6 +182,12 @@ static int __init mc13783_ts_probe(struct platform_device *pdev)
        INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
        priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
        priv->idev = idev;
+       priv->touch = dev_get_platdata(&pdev->dev);
+       if (!priv->touch) {
+               dev_err(&pdev->dev, "missing platform data\n");
+               ret = -ENODEV;
+               goto err_free_mem;
+       }
 
        /*
         * We need separate workqueue because mc13783_adc_do_conversion
index 6bea696..3bd9fff 100644 (file)
@@ -142,4 +142,24 @@ config OMAP_IOMMU_DEBUG
 
          Say N unless you know you need this.
 
+config TEGRA_IOMMU_GART
+       bool "Tegra GART IOMMU Support"
+       depends on ARCH_TEGRA_2x_SOC
+       select IOMMU_API
+       help
+         Enables support for remapping discontiguous physical memory
+         shared with the operating system into contiguous I/O virtual
+         space through the GART (Graphics Address Relocation Table)
+         hardware included on Tegra SoCs.
+
+config TEGRA_IOMMU_SMMU
+       bool "Tegra SMMU IOMMU Support"
+       depends on ARCH_TEGRA_3x_SOC
+       select IOMMU_API
+       help
+         Enables support for remapping discontiguous physical memory
+         shared with the operating system into contiguous I/O virtual
+         space through the SMMU (System Memory Management Unit)
+         hardware included on Tegra SoCs.
+
 endif # IOMMU_SUPPORT
index 0e36b49..7ad7a3b 100644 (file)
@@ -8,3 +8,5 @@ obj-$(CONFIG_IRQ_REMAP) += intr_remapping.o
 obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
 obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
 obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
+obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
+obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
index a35e98a..c567903 100644 (file)
@@ -196,6 +196,8 @@ static u32 rlookup_table_size;      /* size if the rlookup table */
  */
 extern void iommu_flush_all_caches(struct amd_iommu *iommu);
 
+static int amd_iommu_enable_interrupts(void);
+
 static inline void update_last_devid(u16 devid)
 {
        if (devid > amd_iommu_last_bdf)
@@ -358,8 +360,6 @@ static void iommu_disable(struct amd_iommu *iommu)
  */
 static u8 * __init iommu_map_mmio_space(u64 address)
 {
-       u8 *ret;
-
        if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu")) {
                pr_err("AMD-Vi: Can not reserve memory region %llx for mmio\n",
                        address);
@@ -367,13 +367,7 @@ static u8 * __init iommu_map_mmio_space(u64 address)
                return NULL;
        }
 
-       ret = ioremap_nocache(address, MMIO_REGION_LENGTH);
-       if (ret != NULL)
-               return ret;
-
-       release_mem_region(address, MMIO_REGION_LENGTH);
-
-       return NULL;
+       return ioremap_nocache(address, MMIO_REGION_LENGTH);
 }
 
 static void __init iommu_unmap_mmio_space(struct amd_iommu *iommu)
@@ -1131,8 +1125,9 @@ static int iommu_setup_msi(struct amd_iommu *iommu)
 {
        int r;
 
-       if (pci_enable_msi(iommu->dev))
-               return 1;
+       r = pci_enable_msi(iommu->dev);
+       if (r)
+               return r;
 
        r = request_threaded_irq(iommu->dev->irq,
                                 amd_iommu_int_handler,
@@ -1142,27 +1137,36 @@ static int iommu_setup_msi(struct amd_iommu *iommu)
 
        if (r) {
                pci_disable_msi(iommu->dev);
-               return 1;
+               return r;
        }
 
        iommu->int_enabled = true;
-       iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
-
-       if (iommu->ppr_log != NULL)
-               iommu_feature_enable(iommu, CONTROL_PPFINT_EN);
 
        return 0;
 }
 
 static int iommu_init_msi(struct amd_iommu *iommu)
 {
+       int ret;
+
        if (iommu->int_enabled)
-               return 0;
+               goto enable_faults;
 
        if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSI))
-               return iommu_setup_msi(iommu);
+               ret = iommu_setup_msi(iommu);
+       else
+               ret = -ENODEV;
 
-       return 1;
+       if (ret)
+               return ret;
+
+enable_faults:
+       iommu_feature_enable(iommu, CONTROL_EVT_INT_EN);
+
+       if (iommu->ppr_log != NULL)
+               iommu_feature_enable(iommu, CONTROL_PPFINT_EN);
+
+       return 0;
 }
 
 /****************************************************************************
@@ -1381,7 +1385,6 @@ static void enable_iommus(void)
                iommu_enable_ppr_log(iommu);
                iommu_enable_gt(iommu);
                iommu_set_exclusion_range(iommu);
-               iommu_init_msi(iommu);
                iommu_enable(iommu);
                iommu_flush_all_caches(iommu);
        }
@@ -1409,6 +1412,8 @@ static void amd_iommu_resume(void)
 
        /* re-load the hardware */
        enable_iommus();
+
+       amd_iommu_enable_interrupts();
 }
 
 static int amd_iommu_suspend(void)
@@ -1424,10 +1429,40 @@ static struct syscore_ops amd_iommu_syscore_ops = {
        .resume = amd_iommu_resume,
 };
 
+static void __init free_on_init_error(void)
+{
+       amd_iommu_uninit_devices();
+
+       free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
+                  get_order(MAX_DOMAIN_ID/8));
+
+       free_pages((unsigned long)amd_iommu_rlookup_table,
+                  get_order(rlookup_table_size));
+
+       free_pages((unsigned long)amd_iommu_alias_table,
+                  get_order(alias_table_size));
+
+       free_pages((unsigned long)amd_iommu_dev_table,
+                  get_order(dev_table_size));
+
+       free_iommu_all();
+
+       free_unity_maps();
+
+#ifdef CONFIG_GART_IOMMU
+       /*
+        * We failed to initialize the AMD IOMMU - try fallback to GART
+        * if possible.
+        */
+       gart_iommu_init();
+
+#endif
+}
+
 /*
- * This is the core init function for AMD IOMMU hardware in the system.
- * This function is called from the generic x86 DMA layer initialization
- * code.
+ * This is the hardware init function for AMD IOMMU in the system.
+ * This function is called either from amd_iommu_init or from the interrupt
+ * remapping setup code.
  *
  * This function basically parses the ACPI table for AMD IOMMU (IVRS)
  * three times:
@@ -1446,16 +1481,21 @@ static struct syscore_ops amd_iommu_syscore_ops = {
  *             remapping requirements parsed out of the ACPI table in
  *             this last pass.
  *
- * After that the hardware is initialized and ready to go. In the last
- * step we do some Linux specific things like registering the driver in
- * the dma_ops interface and initializing the suspend/resume support
- * functions. Finally it prints some information about AMD IOMMUs and
- * the driver state and enables the hardware.
+ * After everything is set up the IOMMUs are enabled and the necessary
+ * hotplug and suspend notifiers are registered.
  */
-static int __init amd_iommu_init(void)
+int __init amd_iommu_init_hardware(void)
 {
        int i, ret = 0;
 
+       if (!amd_iommu_detected)
+               return -ENODEV;
+
+       if (amd_iommu_dev_table != NULL) {
+               /* Hardware already initialized */
+               return 0;
+       }
+
        /*
         * First parse ACPI tables to find the largest Bus/Dev/Func
         * we need to handle. Upon this information the shared data
@@ -1472,9 +1512,8 @@ static int __init amd_iommu_init(void)
        alias_table_size   = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
        rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE);
 
-       ret = -ENOMEM;
-
        /* Device table - directly used by all IOMMUs */
+       ret = -ENOMEM;
        amd_iommu_dev_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
                                      get_order(dev_table_size));
        if (amd_iommu_dev_table == NULL)
@@ -1546,20 +1585,65 @@ static int __init amd_iommu_init(void)
 
        enable_iommus();
 
+       amd_iommu_init_notifier();
+
+       register_syscore_ops(&amd_iommu_syscore_ops);
+
+out:
+       return ret;
+
+free:
+       free_on_init_error();
+
+       return ret;
+}
+
+static int amd_iommu_enable_interrupts(void)
+{
+       struct amd_iommu *iommu;
+       int ret = 0;
+
+       for_each_iommu(iommu) {
+               ret = iommu_init_msi(iommu);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       return ret;
+}
+
+/*
+ * This is the core init function for AMD IOMMU hardware in the system.
+ * This function is called from the generic x86 DMA layer initialization
+ * code.
+ *
+ * The function calls amd_iommu_init_hardware() to setup and enable the
+ * IOMMU hardware if this has not happened yet. After that the driver
+ * registers for the DMA-API and for the IOMMU-API as necessary.
+ */
+static int __init amd_iommu_init(void)
+{
+       int ret = 0;
+
+       ret = amd_iommu_init_hardware();
+       if (ret)
+               goto out;
+
+       ret = amd_iommu_enable_interrupts();
+       if (ret)
+               goto free;
+
        if (iommu_pass_through)
                ret = amd_iommu_init_passthrough();
        else
                ret = amd_iommu_init_dma_ops();
 
        if (ret)
-               goto free_disable;
+               goto free;
 
        amd_iommu_init_api();
 
-       amd_iommu_init_notifier();
-
-       register_syscore_ops(&amd_iommu_syscore_ops);
-
        if (iommu_pass_through)
                goto out;
 
@@ -1569,39 +1653,14 @@ static int __init amd_iommu_init(void)
                printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n");
 
        x86_platform.iommu_shutdown = disable_iommus;
+
 out:
        return ret;
 
-free_disable:
-       disable_iommus();
-
 free:
-       amd_iommu_uninit_devices();
-
-       free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
-                  get_order(MAX_DOMAIN_ID/8));
-
-       free_pages((unsigned long)amd_iommu_rlookup_table,
-                  get_order(rlookup_table_size));
-
-       free_pages((unsigned long)amd_iommu_alias_table,
-                  get_order(alias_table_size));
-
-       free_pages((unsigned long)amd_iommu_dev_table,
-                  get_order(dev_table_size));
-
-       free_iommu_all();
-
-       free_unity_maps();
-
-#ifdef CONFIG_GART_IOMMU
-       /*
-        * We failed to initialize the AMD IOMMU - try fallback to GART
-        * if possible.
-        */
-       gart_iommu_init();
+       disable_iommus();
 
-#endif
+       free_on_init_error();
 
        goto out;
 }
index 8add9f1..036fe9b 100644 (file)
@@ -921,7 +921,16 @@ static int __init amd_iommu_v2_init(void)
        size_t state_table_size;
        int ret;
 
-       pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>");
+       pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>\n");
+
+       if (!amd_iommu_v2_supported()) {
+               pr_info("AMD IOMMUv2 functionality not available on this sytem\n");
+               /*
+                * Load anyway to provide the symbols to other modules
+                * which may use AMD IOMMUv2 optionally.
+                */
+               return 0;
+       }
 
        spin_lock_init(&state_lock);
 
@@ -961,6 +970,9 @@ static void __exit amd_iommu_v2_exit(void)
        size_t state_table_size;
        int i;
 
+       if (!amd_iommu_v2_supported())
+               return;
+
        profile_event_unregister(PROFILE_TASK_EXIT, &profile_nb);
        amd_iommu_unregister_ppr_notifier(&ppr_nb);
 
diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c
new file mode 100644 (file)
index 0000000..779306e
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+ * IOMMU API for GART in Tegra20
+ *
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define pr_fmt(fmt)    "%s(): " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+
+#include <asm/cacheflush.h>
+
+/* bitmap of the page sizes currently supported */
+#define GART_IOMMU_PGSIZES     (SZ_4K)
+
+#define GART_CONFIG            0x24
+#define GART_ENTRY_ADDR                0x28
+#define GART_ENTRY_DATA                0x2c
+#define GART_ENTRY_PHYS_ADDR_VALID     (1 << 31)
+
+#define GART_PAGE_SHIFT                12
+#define GART_PAGE_SIZE         (1 << GART_PAGE_SHIFT)
+#define GART_PAGE_MASK                                         \
+       (~(GART_PAGE_SIZE - 1) & ~GART_ENTRY_PHYS_ADDR_VALID)
+
+struct gart_client {
+       struct device           *dev;
+       struct list_head        list;
+};
+
+struct gart_device {
+       void __iomem            *regs;
+       u32                     *savedata;
+       u32                     page_count;     /* total remappable size */
+       dma_addr_t              iovmm_base;     /* offset to vmm_area */
+       spinlock_t              pte_lock;       /* for pagetable */
+       struct list_head        client;
+       spinlock_t              client_lock;    /* for client list */
+       struct device           *dev;
+};
+
+static struct gart_device *gart_handle; /* unique for a system */
+
+#define GART_PTE(_pfn)                                         \
+       (GART_ENTRY_PHYS_ADDR_VALID | ((_pfn) << PAGE_SHIFT))
+
+/*
+ * Any interaction between any block on PPSB and a block on APB or AHB
+ * must have these read-back to ensure the APB/AHB bus transaction is
+ * complete before initiating activity on the PPSB block.
+ */
+#define FLUSH_GART_REGS(gart)  ((void)readl((gart)->regs + GART_CONFIG))
+
+#define for_each_gart_pte(gart, iova)                                  \
+       for (iova = gart->iovmm_base;                                   \
+            iova < gart->iovmm_base + GART_PAGE_SIZE * gart->page_count; \
+            iova += GART_PAGE_SIZE)
+
+static inline void gart_set_pte(struct gart_device *gart,
+                               unsigned long offs, u32 pte)
+{
+       writel(offs, gart->regs + GART_ENTRY_ADDR);
+       writel(pte, gart->regs + GART_ENTRY_DATA);
+
+       dev_dbg(gart->dev, "%s %08lx:%08x\n",
+                pte ? "map" : "unmap", offs, pte & GART_PAGE_MASK);
+}
+
+static inline unsigned long gart_read_pte(struct gart_device *gart,
+                                         unsigned long offs)
+{
+       unsigned long pte;
+
+       writel(offs, gart->regs + GART_ENTRY_ADDR);
+       pte = readl(gart->regs + GART_ENTRY_DATA);
+
+       return pte;
+}
+
+static void do_gart_setup(struct gart_device *gart, const u32 *data)
+{
+       unsigned long iova;
+
+       for_each_gart_pte(gart, iova)
+               gart_set_pte(gart, iova, data ? *(data++) : 0);
+
+       writel(1, gart->regs + GART_CONFIG);
+       FLUSH_GART_REGS(gart);
+}
+
+#ifdef DEBUG
+static void gart_dump_table(struct gart_device *gart)
+{
+       unsigned long iova;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gart->pte_lock, flags);
+       for_each_gart_pte(gart, iova) {
+               unsigned long pte;
+
+               pte = gart_read_pte(gart, iova);
+
+               dev_dbg(gart->dev, "%s %08lx:%08lx\n",
+                       (GART_ENTRY_PHYS_ADDR_VALID & pte) ? "v" : " ",
+                       iova, pte & GART_PAGE_MASK);
+       }
+       spin_unlock_irqrestore(&gart->pte_lock, flags);
+}
+#else
+static inline void gart_dump_table(struct gart_device *gart)
+{
+}
+#endif
+
+static inline bool gart_iova_range_valid(struct gart_device *gart,
+                                        unsigned long iova, size_t bytes)
+{
+       unsigned long iova_start, iova_end, gart_start, gart_end;
+
+       iova_start = iova;
+       iova_end = iova_start + bytes - 1;
+       gart_start = gart->iovmm_base;
+       gart_end = gart_start + gart->page_count * GART_PAGE_SIZE - 1;
+
+       if (iova_start < gart_start)
+               return false;
+       if (iova_end > gart_end)
+               return false;
+       return true;
+}
+
+static int gart_iommu_attach_dev(struct iommu_domain *domain,
+                                struct device *dev)
+{
+       struct gart_device *gart;
+       struct gart_client *client, *c;
+       int err = 0;
+
+       gart = dev_get_drvdata(dev->parent);
+       if (!gart)
+               return -EINVAL;
+       domain->priv = gart;
+
+       client = devm_kzalloc(gart->dev, sizeof(*c), GFP_KERNEL);
+       if (!client)
+               return -ENOMEM;
+       client->dev = dev;
+
+       spin_lock(&gart->client_lock);
+       list_for_each_entry(c, &gart->client, list) {
+               if (c->dev == dev) {
+                       dev_err(gart->dev,
+                               "%s is already attached\n", dev_name(dev));
+                       err = -EINVAL;
+                       goto fail;
+               }
+       }
+       list_add(&client->list, &gart->client);
+       spin_unlock(&gart->client_lock);
+       dev_dbg(gart->dev, "Attached %s\n", dev_name(dev));
+       return 0;
+
+fail:
+       devm_kfree(gart->dev, client);
+       spin_unlock(&gart->client_lock);
+       return err;
+}
+
+static void gart_iommu_detach_dev(struct iommu_domain *domain,
+                                 struct device *dev)
+{
+       struct gart_device *gart = domain->priv;
+       struct gart_client *c;
+
+       spin_lock(&gart->client_lock);
+
+       list_for_each_entry(c, &gart->client, list) {
+               if (c->dev == dev) {
+                       list_del(&c->list);
+                       devm_kfree(gart->dev, c);
+                       dev_dbg(gart->dev, "Detached %s\n", dev_name(dev));
+                       goto out;
+               }
+       }
+       dev_err(gart->dev, "Couldn't find\n");
+out:
+       spin_unlock(&gart->client_lock);
+}
+
+static int gart_iommu_domain_init(struct iommu_domain *domain)
+{
+       return 0;
+}
+
+static void gart_iommu_domain_destroy(struct iommu_domain *domain)
+{
+       struct gart_device *gart = domain->priv;
+
+       if (!gart)
+               return;
+
+       spin_lock(&gart->client_lock);
+       if (!list_empty(&gart->client)) {
+               struct gart_client *c;
+
+               list_for_each_entry(c, &gart->client, list)
+                       gart_iommu_detach_dev(domain, c->dev);
+       }
+       spin_unlock(&gart->client_lock);
+       domain->priv = NULL;
+}
+
+static int gart_iommu_map(struct iommu_domain *domain, unsigned long iova,
+                         phys_addr_t pa, size_t bytes, int prot)
+{
+       struct gart_device *gart = domain->priv;
+       unsigned long flags;
+       unsigned long pfn;
+
+       if (!gart_iova_range_valid(gart, iova, bytes))
+               return -EINVAL;
+
+       spin_lock_irqsave(&gart->pte_lock, flags);
+       pfn = __phys_to_pfn(pa);
+       if (!pfn_valid(pfn)) {
+               dev_err(gart->dev, "Invalid page: %08x\n", pa);
+               spin_unlock_irqrestore(&gart->pte_lock, flags);
+               return -EINVAL;
+       }
+       gart_set_pte(gart, iova, GART_PTE(pfn));
+       FLUSH_GART_REGS(gart);
+       spin_unlock_irqrestore(&gart->pte_lock, flags);
+       return 0;
+}
+
+static size_t gart_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
+                              size_t bytes)
+{
+       struct gart_device *gart = domain->priv;
+       unsigned long flags;
+
+       if (!gart_iova_range_valid(gart, iova, bytes))
+               return 0;
+
+       spin_lock_irqsave(&gart->pte_lock, flags);
+       gart_set_pte(gart, iova, 0);
+       FLUSH_GART_REGS(gart);
+       spin_unlock_irqrestore(&gart->pte_lock, flags);
+       return 0;
+}
+
+static phys_addr_t gart_iommu_iova_to_phys(struct iommu_domain *domain,
+                                          unsigned long iova)
+{
+       struct gart_device *gart = domain->priv;
+       unsigned long pte;
+       phys_addr_t pa;
+       unsigned long flags;
+
+       if (!gart_iova_range_valid(gart, iova, 0))
+               return -EINVAL;
+
+       spin_lock_irqsave(&gart->pte_lock, flags);
+       pte = gart_read_pte(gart, iova);
+       spin_unlock_irqrestore(&gart->pte_lock, flags);
+
+       pa = (pte & GART_PAGE_MASK);
+       if (!pfn_valid(__phys_to_pfn(pa))) {
+               dev_err(gart->dev, "No entry for %08lx:%08x\n", iova, pa);
+               gart_dump_table(gart);
+               return -EINVAL;
+       }
+       return pa;
+}
+
+static int gart_iommu_domain_has_cap(struct iommu_domain *domain,
+                                    unsigned long cap)
+{
+       return 0;
+}
+
+static struct iommu_ops gart_iommu_ops = {
+       .domain_init    = gart_iommu_domain_init,
+       .domain_destroy = gart_iommu_domain_destroy,
+       .attach_dev     = gart_iommu_attach_dev,
+       .detach_dev     = gart_iommu_detach_dev,
+       .map            = gart_iommu_map,
+       .unmap          = gart_iommu_unmap,
+       .iova_to_phys   = gart_iommu_iova_to_phys,
+       .domain_has_cap = gart_iommu_domain_has_cap,
+       .pgsize_bitmap  = GART_IOMMU_PGSIZES,
+};
+
+static int tegra_gart_suspend(struct device *dev)
+{
+       struct gart_device *gart = dev_get_drvdata(dev);
+       unsigned long iova;
+       u32 *data = gart->savedata;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gart->pte_lock, flags);
+       for_each_gart_pte(gart, iova)
+               *(data++) = gart_read_pte(gart, iova);
+       spin_unlock_irqrestore(&gart->pte_lock, flags);
+       return 0;
+}
+
+static int tegra_gart_resume(struct device *dev)
+{
+       struct gart_device *gart = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gart->pte_lock, flags);
+       do_gart_setup(gart, gart->savedata);
+       spin_unlock_irqrestore(&gart->pte_lock, flags);
+       return 0;
+}
+
+static int tegra_gart_probe(struct platform_device *pdev)
+{
+       struct gart_device *gart;
+       struct resource *res, *res_remap;
+       void __iomem *gart_regs;
+       int err;
+       struct device *dev = &pdev->dev;
+
+       if (gart_handle)
+               return -EIO;
+
+       BUILD_BUG_ON(PAGE_SHIFT != GART_PAGE_SHIFT);
+
+       /* the GART memory aperture is required */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       res_remap = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res || !res_remap) {
+               dev_err(dev, "GART memory aperture expected\n");
+               return -ENXIO;
+       }
+
+       gart = devm_kzalloc(dev, sizeof(*gart), GFP_KERNEL);
+       if (!gart) {
+               dev_err(dev, "failed to allocate gart_device\n");
+               return -ENOMEM;
+       }
+
+       gart_regs = devm_ioremap(dev, res->start, resource_size(res));
+       if (!gart_regs) {
+               dev_err(dev, "failed to remap GART registers\n");
+               err = -ENXIO;
+               goto fail;
+       }
+
+       gart->dev = &pdev->dev;
+       spin_lock_init(&gart->pte_lock);
+       spin_lock_init(&gart->client_lock);
+       INIT_LIST_HEAD(&gart->client);
+       gart->regs = gart_regs;
+       gart->iovmm_base = (dma_addr_t)res_remap->start;
+       gart->page_count = (resource_size(res_remap) >> GART_PAGE_SHIFT);
+
+       gart->savedata = vmalloc(sizeof(u32) * gart->page_count);
+       if (!gart->savedata) {
+               dev_err(dev, "failed to allocate context save area\n");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       platform_set_drvdata(pdev, gart);
+       do_gart_setup(gart, NULL);
+
+       gart_handle = gart;
+       return 0;
+
+fail:
+       if (gart_regs)
+               devm_iounmap(dev, gart_regs);
+       if (gart && gart->savedata)
+               vfree(gart->savedata);
+       devm_kfree(dev, gart);
+       return err;
+}
+
+static int tegra_gart_remove(struct platform_device *pdev)
+{
+       struct gart_device *gart = platform_get_drvdata(pdev);
+       struct device *dev = gart->dev;
+
+       writel(0, gart->regs + GART_CONFIG);
+       if (gart->savedata)
+               vfree(gart->savedata);
+       if (gart->regs)
+               devm_iounmap(dev, gart->regs);
+       devm_kfree(dev, gart);
+       gart_handle = NULL;
+       return 0;
+}
+
+const struct dev_pm_ops tegra_gart_pm_ops = {
+       .suspend        = tegra_gart_suspend,
+       .resume         = tegra_gart_resume,
+};
+
+static struct platform_driver tegra_gart_driver = {
+       .probe          = tegra_gart_probe,
+       .remove         = tegra_gart_remove,
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tegra-gart",
+               .pm     = &tegra_gart_pm_ops,
+       },
+};
+
+static int __devinit tegra_gart_init(void)
+{
+       bus_set_iommu(&platform_bus_type, &gart_iommu_ops);
+       return platform_driver_register(&tegra_gart_driver);
+}
+
+static void __exit tegra_gart_exit(void)
+{
+       platform_driver_unregister(&tegra_gart_driver);
+}
+
+subsys_initcall(tegra_gart_init);
+module_exit(tegra_gart_exit);
+
+MODULE_DESCRIPTION("IOMMU API for GART in Tegra20");
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
new file mode 100644 (file)
index 0000000..eb93c82
--- /dev/null
@@ -0,0 +1,1034 @@
+/*
+ * IOMMU API for SMMU in Tegra30
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define pr_fmt(fmt)    "%s(): " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/iommu.h>
+#include <linux/io.h>
+
+#include <asm/page.h>
+#include <asm/cacheflush.h>
+
+#include <mach/iomap.h>
+#include <mach/smmu.h>
+
+/* bitmap of the page sizes currently supported */
+#define SMMU_IOMMU_PGSIZES     (SZ_4K)
+
+#define SMMU_CONFIG                            0x10
+#define SMMU_CONFIG_DISABLE                    0
+#define SMMU_CONFIG_ENABLE                     1
+
+#define SMMU_TLB_CONFIG                                0x14
+#define SMMU_TLB_CONFIG_STATS__MASK            (1 << 31)
+#define SMMU_TLB_CONFIG_STATS__ENABLE          (1 << 31)
+#define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE (1 << 29)
+#define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE    0x10
+#define SMMU_TLB_CONFIG_RESET_VAL              0x20000010
+
+#define SMMU_PTC_CONFIG                                0x18
+#define SMMU_PTC_CONFIG_STATS__MASK            (1 << 31)
+#define SMMU_PTC_CONFIG_STATS__ENABLE          (1 << 31)
+#define SMMU_PTC_CONFIG_CACHE__ENABLE          (1 << 29)
+#define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN     0x3f
+#define SMMU_PTC_CONFIG_RESET_VAL              0x2000003f
+
+#define SMMU_PTB_ASID                          0x1c
+#define SMMU_PTB_ASID_CURRENT_SHIFT            0
+
+#define SMMU_PTB_DATA                          0x20
+#define SMMU_PTB_DATA_RESET_VAL                        0
+#define SMMU_PTB_DATA_ASID_NONSECURE_SHIFT     29
+#define SMMU_PTB_DATA_ASID_WRITABLE_SHIFT      30
+#define SMMU_PTB_DATA_ASID_READABLE_SHIFT      31
+
+#define SMMU_TLB_FLUSH                         0x30
+#define SMMU_TLB_FLUSH_VA_MATCH_ALL            0
+#define SMMU_TLB_FLUSH_VA_MATCH_SECTION                2
+#define SMMU_TLB_FLUSH_VA_MATCH_GROUP          3
+#define SMMU_TLB_FLUSH_ASID_SHIFT              29
+#define SMMU_TLB_FLUSH_ASID_MATCH_DISABLE      0
+#define SMMU_TLB_FLUSH_ASID_MATCH_ENABLE       1
+#define SMMU_TLB_FLUSH_ASID_MATCH_SHIFT                31
+
+#define SMMU_PTC_FLUSH                         0x34
+#define SMMU_PTC_FLUSH_TYPE_ALL                        0
+#define SMMU_PTC_FLUSH_TYPE_ADR                        1
+#define SMMU_PTC_FLUSH_ADR_SHIFT               4
+
+#define SMMU_ASID_SECURITY                     0x38
+
+#define SMMU_STATS_TLB_HIT_COUNT               0x1f0
+#define SMMU_STATS_TLB_MISS_COUNT              0x1f4
+#define SMMU_STATS_PTC_HIT_COUNT               0x1f8
+#define SMMU_STATS_PTC_MISS_COUNT              0x1fc
+
+#define SMMU_TRANSLATION_ENABLE_0              0x228
+#define SMMU_TRANSLATION_ENABLE_1              0x22c
+#define SMMU_TRANSLATION_ENABLE_2              0x230
+
+#define SMMU_AFI_ASID  0x238   /* PCIE */
+#define SMMU_AVPC_ASID 0x23c   /* AVP */
+#define SMMU_DC_ASID   0x240   /* Display controller */
+#define SMMU_DCB_ASID  0x244   /* Display controller B */
+#define SMMU_EPP_ASID  0x248   /* Encoder pre-processor */
+#define SMMU_G2_ASID   0x24c   /* 2D engine */
+#define SMMU_HC_ASID   0x250   /* Host1x */
+#define SMMU_HDA_ASID  0x254   /* High-def audio */
+#define SMMU_ISP_ASID  0x258   /* Image signal processor */
+#define SMMU_MPE_ASID  0x264   /* MPEG encoder */
+#define SMMU_NV_ASID   0x268   /* (3D) */
+#define SMMU_NV2_ASID  0x26c   /* (3D) */
+#define SMMU_PPCS_ASID 0x270   /* AHB */
+#define SMMU_SATA_ASID 0x278   /* SATA */
+#define SMMU_VDE_ASID  0x27c   /* Video decoder */
+#define SMMU_VI_ASID   0x280   /* Video input */
+
+#define SMMU_PDE_NEXT_SHIFT            28
+
+/* AHB Arbiter Registers */
+#define AHB_XBAR_CTRL                          0xe0
+#define AHB_XBAR_CTRL_SMMU_INIT_DONE_DONE      1
+#define AHB_XBAR_CTRL_SMMU_INIT_DONE_SHIFT     17
+
+#define SMMU_NUM_ASIDS                         4
+#define SMMU_TLB_FLUSH_VA_SECTION__MASK                0xffc00000
+#define SMMU_TLB_FLUSH_VA_SECTION__SHIFT       12 /* right shift */
+#define SMMU_TLB_FLUSH_VA_GROUP__MASK          0xffffc000
+#define SMMU_TLB_FLUSH_VA_GROUP__SHIFT         12 /* right shift */
+#define SMMU_TLB_FLUSH_VA(iova, which) \
+       ((((iova) & SMMU_TLB_FLUSH_VA_##which##__MASK) >> \
+               SMMU_TLB_FLUSH_VA_##which##__SHIFT) |   \
+       SMMU_TLB_FLUSH_VA_MATCH_##which)
+#define SMMU_PTB_ASID_CUR(n)   \
+               ((n) << SMMU_PTB_ASID_CURRENT_SHIFT)
+#define SMMU_TLB_FLUSH_ASID_MATCH_disable              \
+               (SMMU_TLB_FLUSH_ASID_MATCH_DISABLE <<   \
+                       SMMU_TLB_FLUSH_ASID_MATCH_SHIFT)
+#define SMMU_TLB_FLUSH_ASID_MATCH__ENABLE              \
+               (SMMU_TLB_FLUSH_ASID_MATCH_ENABLE <<    \
+                       SMMU_TLB_FLUSH_ASID_MATCH_SHIFT)
+
+#define SMMU_PAGE_SHIFT 12
+#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT)
+
+#define SMMU_PDIR_COUNT        1024
+#define SMMU_PDIR_SIZE (sizeof(unsigned long) * SMMU_PDIR_COUNT)
+#define SMMU_PTBL_COUNT        1024
+#define SMMU_PTBL_SIZE (sizeof(unsigned long) * SMMU_PTBL_COUNT)
+#define SMMU_PDIR_SHIFT        12
+#define SMMU_PDE_SHIFT 12
+#define SMMU_PTE_SHIFT 12
+#define SMMU_PFN_MASK  0x000fffff
+
+#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12)
+#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22)
+#define SMMU_PDN_TO_ADDR(addr) ((pdn) << 22)
+
+#define _READABLE      (1 << SMMU_PTB_DATA_ASID_READABLE_SHIFT)
+#define _WRITABLE      (1 << SMMU_PTB_DATA_ASID_WRITABLE_SHIFT)
+#define _NONSECURE     (1 << SMMU_PTB_DATA_ASID_NONSECURE_SHIFT)
+#define _PDE_NEXT      (1 << SMMU_PDE_NEXT_SHIFT)
+#define _MASK_ATTR     (_READABLE | _WRITABLE | _NONSECURE)
+
+#define _PDIR_ATTR     (_READABLE | _WRITABLE | _NONSECURE)
+
+#define _PDE_ATTR      (_READABLE | _WRITABLE | _NONSECURE)
+#define _PDE_ATTR_N    (_PDE_ATTR | _PDE_NEXT)
+#define _PDE_VACANT(pdn)       (((pdn) << 10) | _PDE_ATTR)
+
+#define _PTE_ATTR      (_READABLE | _WRITABLE | _NONSECURE)
+#define _PTE_VACANT(addr)      (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR)
+
+#define SMMU_MK_PDIR(page, attr)       \
+               ((page_to_phys(page) >> SMMU_PDIR_SHIFT) | (attr))
+#define SMMU_MK_PDE(page, attr)                \
+               (unsigned long)((page_to_phys(page) >> SMMU_PDE_SHIFT) | (attr))
+#define SMMU_EX_PTBL_PAGE(pde)         \
+               pfn_to_page((unsigned long)(pde) & SMMU_PFN_MASK)
+#define SMMU_PFN_TO_PTE(pfn, attr)     (unsigned long)((pfn) | (attr))
+
+#define SMMU_ASID_ENABLE(asid) ((asid) | (1 << 31))
+#define SMMU_ASID_DISABLE      0
+#define SMMU_ASID_ASID(n)      ((n) & ~SMMU_ASID_ENABLE(0))
+
+#define smmu_client_enable_hwgrp(c, m) smmu_client_set_hwgrp(c, m, 1)
+#define smmu_client_disable_hwgrp(c)   smmu_client_set_hwgrp(c, 0, 0)
+#define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1)
+#define __smmu_client_disable_hwgrp(c) __smmu_client_set_hwgrp(c, 0, 0)
+
+#define HWGRP_INIT(client) [HWGRP_##client] = SMMU_##client##_ASID
+
+static const u32 smmu_hwgrp_asid_reg[] = {
+       HWGRP_INIT(AFI),
+       HWGRP_INIT(AVPC),
+       HWGRP_INIT(DC),
+       HWGRP_INIT(DCB),
+       HWGRP_INIT(EPP),
+       HWGRP_INIT(G2),
+       HWGRP_INIT(HC),
+       HWGRP_INIT(HDA),
+       HWGRP_INIT(ISP),
+       HWGRP_INIT(MPE),
+       HWGRP_INIT(NV),
+       HWGRP_INIT(NV2),
+       HWGRP_INIT(PPCS),
+       HWGRP_INIT(SATA),
+       HWGRP_INIT(VDE),
+       HWGRP_INIT(VI),
+};
+#define HWGRP_ASID_REG(x) (smmu_hwgrp_asid_reg[x])
+
+/*
+ * Per client for address space
+ */
+struct smmu_client {
+       struct device           *dev;
+       struct list_head        list;
+       struct smmu_as          *as;
+       u32                     hwgrp;
+};
+
+/*
+ * Per address space
+ */
+struct smmu_as {
+       struct smmu_device      *smmu;  /* back pointer to container */
+       unsigned int            asid;
+       spinlock_t              lock;   /* for pagetable */
+       struct page             *pdir_page;
+       unsigned long           pdir_attr;
+       unsigned long           pde_attr;
+       unsigned long           pte_attr;
+       unsigned int            *pte_count;
+
+       struct list_head        client;
+       spinlock_t              client_lock; /* for client list */
+};
+
+/*
+ * Per SMMU device - IOMMU device
+ */
+struct smmu_device {
+       void __iomem    *regs, *regs_ahbarb;
+       unsigned long   iovmm_base;     /* remappable base address */
+       unsigned long   page_count;     /* total remappable size */
+       spinlock_t      lock;
+       char            *name;
+       struct device   *dev;
+       int             num_as;
+       struct smmu_as  *as;            /* Run-time allocated array */
+       struct page *avp_vector_page;   /* dummy page shared by all AS's */
+
+       /*
+        * Register image savers for suspend/resume
+        */
+       unsigned long translation_enable_0;
+       unsigned long translation_enable_1;
+       unsigned long translation_enable_2;
+       unsigned long asid_security;
+};
+
+static struct smmu_device *smmu_handle; /* unique for a system */
+
+/*
+ *     SMMU/AHB register accessors
+ */
+static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
+{
+       return readl(smmu->regs + offs);
+}
+static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
+{
+       writel(val, smmu->regs + offs);
+}
+
+static inline u32 ahb_read(struct smmu_device *smmu, size_t offs)
+{
+       return readl(smmu->regs_ahbarb + offs);
+}
+static inline void ahb_write(struct smmu_device *smmu, u32 val, size_t offs)
+{
+       writel(val, smmu->regs_ahbarb + offs);
+}
+
+#define VA_PAGE_TO_PA(va, page)        \
+       (page_to_phys(page) + ((unsigned long)(va) & ~PAGE_MASK))
+
+#define FLUSH_CPU_DCACHE(va, page, size)       \
+       do {    \
+               unsigned long _pa_ = VA_PAGE_TO_PA(va, page);           \
+               __cpuc_flush_dcache_area((void *)(va), (size_t)(size)); \
+               outer_flush_range(_pa_, _pa_+(size_t)(size));           \
+       } while (0)
+
+/*
+ * Any interaction between any block on PPSB and a block on APB or AHB
+ * must have these read-back barriers to ensure the APB/AHB bus
+ * transaction is complete before initiating activity on the PPSB
+ * block.
+ */
+#define FLUSH_SMMU_REGS(smmu)  smmu_read(smmu, SMMU_CONFIG)
+
+#define smmu_client_hwgrp(c) (u32)((c)->dev->platform_data)
+
+static int __smmu_client_set_hwgrp(struct smmu_client *c,
+                                  unsigned long map, int on)
+{
+       int i;
+       struct smmu_as *as = c->as;
+       u32 val, offs, mask = SMMU_ASID_ENABLE(as->asid);
+       struct smmu_device *smmu = as->smmu;
+
+       WARN_ON(!on && map);
+       if (on && !map)
+               return -EINVAL;
+       if (!on)
+               map = smmu_client_hwgrp(c);
+
+       for_each_set_bit(i, &map, HWGRP_COUNT) {
+               offs = HWGRP_ASID_REG(i);
+               val = smmu_read(smmu, offs);
+               if (on) {
+                       if (WARN_ON(val & mask))
+                               goto err_hw_busy;
+                       val |= mask;
+               } else {
+                       WARN_ON((val & mask) == mask);
+                       val &= ~mask;
+               }
+               smmu_write(smmu, val, offs);
+       }
+       FLUSH_SMMU_REGS(smmu);
+       c->hwgrp = map;
+       return 0;
+
+err_hw_busy:
+       for_each_set_bit(i, &map, HWGRP_COUNT) {
+               offs = HWGRP_ASID_REG(i);
+               val = smmu_read(smmu, offs);
+               val &= ~mask;
+               smmu_write(smmu, val, offs);
+       }
+       return -EBUSY;
+}
+
+static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on)
+{
+       u32 val;
+       unsigned long flags;
+       struct smmu_as *as = c->as;
+       struct smmu_device *smmu = as->smmu;
+
+       spin_lock_irqsave(&smmu->lock, flags);
+       val = __smmu_client_set_hwgrp(c, map, on);
+       spin_unlock_irqrestore(&smmu->lock, flags);
+       return val;
+}
+
+/*
+ * Flush all TLB entries and all PTC entries
+ * Caller must lock smmu
+ */
+static void smmu_flush_regs(struct smmu_device *smmu, int enable)
+{
+       u32 val;
+
+       smmu_write(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH);
+       FLUSH_SMMU_REGS(smmu);
+       val = SMMU_TLB_FLUSH_VA_MATCH_ALL |
+               SMMU_TLB_FLUSH_ASID_MATCH_disable;
+       smmu_write(smmu, val, SMMU_TLB_FLUSH);
+
+       if (enable)
+               smmu_write(smmu, SMMU_CONFIG_ENABLE, SMMU_CONFIG);
+       FLUSH_SMMU_REGS(smmu);
+}
+
+static void smmu_setup_regs(struct smmu_device *smmu)
+{
+       int i;
+       u32 val;
+
+       for (i = 0; i < smmu->num_as; i++) {
+               struct smmu_as *as = &smmu->as[i];
+               struct smmu_client *c;
+
+               smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
+               val = as->pdir_page ?
+                       SMMU_MK_PDIR(as->pdir_page, as->pdir_attr) :
+                       SMMU_PTB_DATA_RESET_VAL;
+               smmu_write(smmu, val, SMMU_PTB_DATA);
+
+               list_for_each_entry(c, &as->client, list)
+                       __smmu_client_set_hwgrp(c, c->hwgrp, 1);
+       }
+
+       smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
+       smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1);
+       smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2);
+       smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY);
+       smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_TLB_CONFIG);
+       smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_PTC_CONFIG);
+
+       smmu_flush_regs(smmu, 1);
+
+       val = ahb_read(smmu, AHB_XBAR_CTRL);
+       val |= AHB_XBAR_CTRL_SMMU_INIT_DONE_DONE <<
+               AHB_XBAR_CTRL_SMMU_INIT_DONE_SHIFT;
+       ahb_write(smmu, val, AHB_XBAR_CTRL);
+}
+
+static void flush_ptc_and_tlb(struct smmu_device *smmu,
+                     struct smmu_as *as, dma_addr_t iova,
+                     unsigned long *pte, struct page *page, int is_pde)
+{
+       u32 val;
+       unsigned long tlb_flush_va = is_pde
+               ?  SMMU_TLB_FLUSH_VA(iova, SECTION)
+               :  SMMU_TLB_FLUSH_VA(iova, GROUP);
+
+       val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page);
+       smmu_write(smmu, val, SMMU_PTC_FLUSH);
+       FLUSH_SMMU_REGS(smmu);
+       val = tlb_flush_va |
+               SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
+               (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
+       smmu_write(smmu, val, SMMU_TLB_FLUSH);
+       FLUSH_SMMU_REGS(smmu);
+}
+
+static void free_ptbl(struct smmu_as *as, dma_addr_t iova)
+{
+       unsigned long pdn = SMMU_ADDR_TO_PDN(iova);
+       unsigned long *pdir = (unsigned long *)page_address(as->pdir_page);
+
+       if (pdir[pdn] != _PDE_VACANT(pdn)) {
+               dev_dbg(as->smmu->dev, "pdn: %lx\n", pdn);
+
+               ClearPageReserved(SMMU_EX_PTBL_PAGE(pdir[pdn]));
+               __free_page(SMMU_EX_PTBL_PAGE(pdir[pdn]));
+               pdir[pdn] = _PDE_VACANT(pdn);
+               FLUSH_CPU_DCACHE(&pdir[pdn], as->pdir_page, sizeof pdir[pdn]);
+               flush_ptc_and_tlb(as->smmu, as, iova, &pdir[pdn],
+                                 as->pdir_page, 1);
+       }
+}
+
+static void free_pdir(struct smmu_as *as)
+{
+       unsigned addr;
+       int count;
+       struct device *dev = as->smmu->dev;
+
+       if (!as->pdir_page)
+               return;
+
+       addr = as->smmu->iovmm_base;
+       count = as->smmu->page_count;
+       while (count-- > 0) {
+               free_ptbl(as, addr);
+               addr += SMMU_PAGE_SIZE * SMMU_PTBL_COUNT;
+       }
+       ClearPageReserved(as->pdir_page);
+       __free_page(as->pdir_page);
+       as->pdir_page = NULL;
+       devm_kfree(dev, as->pte_count);
+       as->pte_count = NULL;
+}
+
+/*
+ * Maps PTBL for given iova and returns the PTE address
+ * Caller must unmap the mapped PTBL returned in *ptbl_page_p
+ */
+static unsigned long *locate_pte(struct smmu_as *as,
+                                dma_addr_t iova, bool allocate,
+                                struct page **ptbl_page_p,
+                                unsigned int **count)
+{
+       unsigned long ptn = SMMU_ADDR_TO_PFN(iova);
+       unsigned long pdn = SMMU_ADDR_TO_PDN(iova);
+       unsigned long *pdir = page_address(as->pdir_page);
+       unsigned long *ptbl;
+
+       if (pdir[pdn] != _PDE_VACANT(pdn)) {
+               /* Mapped entry table already exists */
+               *ptbl_page_p = SMMU_EX_PTBL_PAGE(pdir[pdn]);
+               ptbl = page_address(*ptbl_page_p);
+       } else if (!allocate) {
+               return NULL;
+       } else {
+               int pn;
+               unsigned long addr = SMMU_PDN_TO_ADDR(pdn);
+
+               /* Vacant - allocate a new page table */
+               dev_dbg(as->smmu->dev, "New PTBL pdn: %lx\n", pdn);
+
+               *ptbl_page_p = alloc_page(GFP_ATOMIC);
+               if (!*ptbl_page_p) {
+                       dev_err(as->smmu->dev,
+                               "failed to allocate smmu_device page table\n");
+                       return NULL;
+               }
+               SetPageReserved(*ptbl_page_p);
+               ptbl = (unsigned long *)page_address(*ptbl_page_p);
+               for (pn = 0; pn < SMMU_PTBL_COUNT;
+                    pn++, addr += SMMU_PAGE_SIZE) {
+                       ptbl[pn] = _PTE_VACANT(addr);
+               }
+               FLUSH_CPU_DCACHE(ptbl, *ptbl_page_p, SMMU_PTBL_SIZE);
+               pdir[pdn] = SMMU_MK_PDE(*ptbl_page_p,
+                                       as->pde_attr | _PDE_NEXT);
+               FLUSH_CPU_DCACHE(&pdir[pdn], as->pdir_page, sizeof pdir[pdn]);
+               flush_ptc_and_tlb(as->smmu, as, iova, &pdir[pdn],
+                                 as->pdir_page, 1);
+       }
+       *count = &as->pte_count[pdn];
+
+       return &ptbl[ptn % SMMU_PTBL_COUNT];
+}
+
+#ifdef CONFIG_SMMU_SIG_DEBUG
+static void put_signature(struct smmu_as *as,
+                         dma_addr_t iova, unsigned long pfn)
+{
+       struct page *page;
+       unsigned long *vaddr;
+
+       page = pfn_to_page(pfn);
+       vaddr = page_address(page);
+       if (!vaddr)
+               return;
+
+       vaddr[0] = iova;
+       vaddr[1] = pfn << PAGE_SHIFT;
+       FLUSH_CPU_DCACHE(vaddr, page, sizeof(vaddr[0]) * 2);
+}
+#else
+static inline void put_signature(struct smmu_as *as,
+                                unsigned long addr, unsigned long pfn)
+{
+}
+#endif
+
+/*
+ * Caller must lock/unlock as
+ */
+static int alloc_pdir(struct smmu_as *as)
+{
+       unsigned long *pdir;
+       int pdn;
+       u32 val;
+       struct smmu_device *smmu = as->smmu;
+
+       if (as->pdir_page)
+               return 0;
+
+       as->pte_count = devm_kzalloc(smmu->dev,
+                    sizeof(as->pte_count[0]) * SMMU_PDIR_COUNT, GFP_KERNEL);
+       if (!as->pte_count) {
+               dev_err(smmu->dev,
+                       "failed to allocate smmu_device PTE cunters\n");
+               return -ENOMEM;
+       }
+       as->pdir_page = alloc_page(GFP_KERNEL | __GFP_DMA);
+       if (!as->pdir_page) {
+               dev_err(smmu->dev,
+                       "failed to allocate smmu_device page directory\n");
+               devm_kfree(smmu->dev, as->pte_count);
+               as->pte_count = NULL;
+               return -ENOMEM;
+       }
+       SetPageReserved(as->pdir_page);
+       pdir = page_address(as->pdir_page);
+
+       for (pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++)
+               pdir[pdn] = _PDE_VACANT(pdn);
+       FLUSH_CPU_DCACHE(pdir, as->pdir_page, SMMU_PDIR_SIZE);
+       val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pdir, as->pdir_page);
+       smmu_write(smmu, val, SMMU_PTC_FLUSH);
+       FLUSH_SMMU_REGS(as->smmu);
+       val = SMMU_TLB_FLUSH_VA_MATCH_ALL |
+               SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
+               (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
+       smmu_write(smmu, val, SMMU_TLB_FLUSH);
+       FLUSH_SMMU_REGS(as->smmu);
+
+       return 0;
+}
+
+static void __smmu_iommu_unmap(struct smmu_as *as, dma_addr_t iova)
+{
+       unsigned long *pte;
+       struct page *page;
+       unsigned int *count;
+
+       pte = locate_pte(as, iova, false, &page, &count);
+       if (WARN_ON(!pte))
+               return;
+
+       if (WARN_ON(*pte == _PTE_VACANT(iova)))
+               return;
+
+       *pte = _PTE_VACANT(iova);
+       FLUSH_CPU_DCACHE(pte, page, sizeof(*pte));
+       flush_ptc_and_tlb(as->smmu, as, iova, pte, page, 0);
+       if (!--(*count)) {
+               free_ptbl(as, iova);
+               smmu_flush_regs(as->smmu, 0);
+       }
+}
+
+static void __smmu_iommu_map_pfn(struct smmu_as *as, dma_addr_t iova,
+                                unsigned long pfn)
+{
+       struct smmu_device *smmu = as->smmu;
+       unsigned long *pte;
+       unsigned int *count;
+       struct page *page;
+
+       pte = locate_pte(as, iova, true, &page, &count);
+       if (WARN_ON(!pte))
+               return;
+
+       if (*pte == _PTE_VACANT(iova))
+               (*count)++;
+       *pte = SMMU_PFN_TO_PTE(pfn, as->pte_attr);
+       if (unlikely((*pte == _PTE_VACANT(iova))))
+               (*count)--;
+       FLUSH_CPU_DCACHE(pte, page, sizeof(*pte));
+       flush_ptc_and_tlb(smmu, as, iova, pte, page, 0);
+       put_signature(as, iova, pfn);
+}
+
+static int smmu_iommu_map(struct iommu_domain *domain, unsigned long iova,
+                         phys_addr_t pa, size_t bytes, int prot)
+{
+       struct smmu_as *as = domain->priv;
+       unsigned long pfn = __phys_to_pfn(pa);
+       unsigned long flags;
+
+       dev_dbg(as->smmu->dev, "[%d] %08lx:%08x\n", as->asid, iova, pa);
+
+       if (!pfn_valid(pfn))
+               return -ENOMEM;
+
+       spin_lock_irqsave(&as->lock, flags);
+       __smmu_iommu_map_pfn(as, iova, pfn);
+       spin_unlock_irqrestore(&as->lock, flags);
+       return 0;
+}
+
+static size_t smmu_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
+                              size_t bytes)
+{
+       struct smmu_as *as = domain->priv;
+       unsigned long flags;
+
+       dev_dbg(as->smmu->dev, "[%d] %08lx\n", as->asid, iova);
+
+       spin_lock_irqsave(&as->lock, flags);
+       __smmu_iommu_unmap(as, iova);
+       spin_unlock_irqrestore(&as->lock, flags);
+       return SMMU_PAGE_SIZE;
+}
+
+static phys_addr_t smmu_iommu_iova_to_phys(struct iommu_domain *domain,
+                                          unsigned long iova)
+{
+       struct smmu_as *as = domain->priv;
+       unsigned long *pte;
+       unsigned int *count;
+       struct page *page;
+       unsigned long pfn;
+       unsigned long flags;
+
+       spin_lock_irqsave(&as->lock, flags);
+
+       pte = locate_pte(as, iova, true, &page, &count);
+       pfn = *pte & SMMU_PFN_MASK;
+       WARN_ON(!pfn_valid(pfn));
+       dev_dbg(as->smmu->dev,
+               "iova:%08lx pfn:%08lx asid:%d\n", iova, pfn, as->asid);
+
+       spin_unlock_irqrestore(&as->lock, flags);
+       return PFN_PHYS(pfn);
+}
+
+static int smmu_iommu_domain_has_cap(struct iommu_domain *domain,
+                                    unsigned long cap)
+{
+       return 0;
+}
+
+static int smmu_iommu_attach_dev(struct iommu_domain *domain,
+                                struct device *dev)
+{
+       struct smmu_as *as = domain->priv;
+       struct smmu_device *smmu = as->smmu;
+       struct smmu_client *client, *c;
+       u32 map;
+       int err;
+
+       client = devm_kzalloc(smmu->dev, sizeof(*c), GFP_KERNEL);
+       if (!client)
+               return -ENOMEM;
+       client->dev = dev;
+       client->as = as;
+       map = (unsigned long)dev->platform_data;
+       if (!map)
+               return -EINVAL;
+
+       err = smmu_client_enable_hwgrp(client, map);
+       if (err)
+               goto err_hwgrp;
+
+       spin_lock(&as->client_lock);
+       list_for_each_entry(c, &as->client, list) {
+               if (c->dev == dev) {
+                       dev_err(smmu->dev,
+                               "%s is already attached\n", dev_name(c->dev));
+                       err = -EINVAL;
+                       goto err_client;
+               }
+       }
+       list_add(&client->list, &as->client);
+       spin_unlock(&as->client_lock);
+
+       /*
+        * Reserve "page zero" for AVP vectors using a common dummy
+        * page.
+        */
+       if (map & HWG_AVPC) {
+               struct page *page;
+
+               page = as->smmu->avp_vector_page;
+               __smmu_iommu_map_pfn(as, 0, page_to_pfn(page));
+
+               pr_info("Reserve \"page zero\" for AVP vectors using a common dummy\n");
+       }
+
+       dev_dbg(smmu->dev, "%s is attached\n", dev_name(c->dev));
+       return 0;
+
+err_client:
+       smmu_client_disable_hwgrp(client);
+       spin_unlock(&as->client_lock);
+err_hwgrp:
+       devm_kfree(smmu->dev, client);
+       return err;
+}
+
+static void smmu_iommu_detach_dev(struct iommu_domain *domain,
+                                 struct device *dev)
+{
+       struct smmu_as *as = domain->priv;
+       struct smmu_device *smmu = as->smmu;
+       struct smmu_client *c;
+
+       spin_lock(&as->client_lock);
+
+       list_for_each_entry(c, &as->client, list) {
+               if (c->dev == dev) {
+                       smmu_client_disable_hwgrp(c);
+                       list_del(&c->list);
+                       devm_kfree(smmu->dev, c);
+                       c->as = NULL;
+                       dev_dbg(smmu->dev,
+                               "%s is detached\n", dev_name(c->dev));
+                       goto out;
+               }
+       }
+       dev_err(smmu->dev, "Couldn't find %s\n", dev_name(c->dev));
+out:
+       spin_unlock(&as->client_lock);
+}
+
+static int smmu_iommu_domain_init(struct iommu_domain *domain)
+{
+       int i;
+       unsigned long flags;
+       struct smmu_as *as;
+       struct smmu_device *smmu = smmu_handle;
+
+       /* Look for a free AS with lock held */
+       for  (i = 0; i < smmu->num_as; i++) {
+               struct smmu_as *tmp = &smmu->as[i];
+
+               spin_lock_irqsave(&tmp->lock, flags);
+               if (!tmp->pdir_page) {
+                       as = tmp;
+                       goto found;
+               }
+               spin_unlock_irqrestore(&tmp->lock, flags);
+       }
+       dev_err(smmu->dev, "no free AS\n");
+       return -ENODEV;
+
+found:
+       if (alloc_pdir(as) < 0)
+               goto err_alloc_pdir;
+
+       spin_lock(&smmu->lock);
+
+       /* Update PDIR register */
+       smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
+       smmu_write(smmu,
+                  SMMU_MK_PDIR(as->pdir_page, as->pdir_attr), SMMU_PTB_DATA);
+       FLUSH_SMMU_REGS(smmu);
+
+       spin_unlock(&smmu->lock);
+
+       spin_unlock_irqrestore(&as->lock, flags);
+       domain->priv = as;
+
+       dev_dbg(smmu->dev, "smmu_as@%p\n", as);
+       return 0;
+
+err_alloc_pdir:
+       spin_unlock_irqrestore(&as->lock, flags);
+       return -ENODEV;
+}
+
+static void smmu_iommu_domain_destroy(struct iommu_domain *domain)
+{
+       struct smmu_as *as = domain->priv;
+       struct smmu_device *smmu = as->smmu;
+       unsigned long flags;
+
+       spin_lock_irqsave(&as->lock, flags);
+
+       if (as->pdir_page) {
+               spin_lock(&smmu->lock);
+               smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
+               smmu_write(smmu, SMMU_PTB_DATA_RESET_VAL, SMMU_PTB_DATA);
+               FLUSH_SMMU_REGS(smmu);
+               spin_unlock(&smmu->lock);
+
+               free_pdir(as);
+       }
+
+       if (!list_empty(&as->client)) {
+               struct smmu_client *c;
+
+               list_for_each_entry(c, &as->client, list)
+                       smmu_iommu_detach_dev(domain, c->dev);
+       }
+
+       spin_unlock_irqrestore(&as->lock, flags);
+
+       domain->priv = NULL;
+       dev_dbg(smmu->dev, "smmu_as@%p\n", as);
+}
+
+static struct iommu_ops smmu_iommu_ops = {
+       .domain_init    = smmu_iommu_domain_init,
+       .domain_destroy = smmu_iommu_domain_destroy,
+       .attach_dev     = smmu_iommu_attach_dev,
+       .detach_dev     = smmu_iommu_detach_dev,
+       .map            = smmu_iommu_map,
+       .unmap          = smmu_iommu_unmap,
+       .iova_to_phys   = smmu_iommu_iova_to_phys,
+       .domain_has_cap = smmu_iommu_domain_has_cap,
+       .pgsize_bitmap  = SMMU_IOMMU_PGSIZES,
+};
+
+static int tegra_smmu_suspend(struct device *dev)
+{
+       struct smmu_device *smmu = dev_get_drvdata(dev);
+
+       smmu->translation_enable_0 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_0);
+       smmu->translation_enable_1 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_1);
+       smmu->translation_enable_2 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_2);
+       smmu->asid_security = smmu_read(smmu, SMMU_ASID_SECURITY);
+       return 0;
+}
+
+static int tegra_smmu_resume(struct device *dev)
+{
+       struct smmu_device *smmu = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&smmu->lock, flags);
+       smmu_setup_regs(smmu);
+       spin_unlock_irqrestore(&smmu->lock, flags);
+       return 0;
+}
+
+static int tegra_smmu_probe(struct platform_device *pdev)
+{
+       struct smmu_device *smmu;
+       struct resource *regs, *regs2, *window;
+       struct device *dev = &pdev->dev;
+       int i, err = 0;
+
+       if (smmu_handle)
+               return -EIO;
+
+       BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       window = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       if (!regs || !regs2 || !window) {
+               dev_err(dev, "No SMMU resources\n");
+               return -ENODEV;
+       }
+
+       smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
+       if (!smmu) {
+               dev_err(dev, "failed to allocate smmu_device\n");
+               return -ENOMEM;
+       }
+
+       smmu->dev = dev;
+       smmu->num_as = SMMU_NUM_ASIDS;
+       smmu->iovmm_base = (unsigned long)window->start;
+       smmu->page_count = resource_size(window) >> SMMU_PAGE_SHIFT;
+       smmu->regs = devm_ioremap(dev, regs->start, resource_size(regs));
+       smmu->regs_ahbarb = devm_ioremap(dev, regs2->start,
+                                        resource_size(regs2));
+       if (!smmu->regs || !smmu->regs_ahbarb) {
+               dev_err(dev, "failed to remap SMMU registers\n");
+               err = -ENXIO;
+               goto fail;
+       }
+
+       smmu->translation_enable_0 = ~0;
+       smmu->translation_enable_1 = ~0;
+       smmu->translation_enable_2 = ~0;
+       smmu->asid_security = 0;
+
+       smmu->as = devm_kzalloc(dev,
+                       sizeof(smmu->as[0]) * smmu->num_as, GFP_KERNEL);
+       if (!smmu->as) {
+               dev_err(dev, "failed to allocate smmu_as\n");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       for (i = 0; i < smmu->num_as; i++) {
+               struct smmu_as *as = &smmu->as[i];
+
+               as->smmu = smmu;
+               as->asid = i;
+               as->pdir_attr = _PDIR_ATTR;
+               as->pde_attr = _PDE_ATTR;
+               as->pte_attr = _PTE_ATTR;
+
+               spin_lock_init(&as->lock);
+               INIT_LIST_HEAD(&as->client);
+       }
+       spin_lock_init(&smmu->lock);
+       smmu_setup_regs(smmu);
+       platform_set_drvdata(pdev, smmu);
+
+       smmu->avp_vector_page = alloc_page(GFP_KERNEL);
+       if (!smmu->avp_vector_page)
+               goto fail;
+
+       smmu_handle = smmu;
+       return 0;
+
+fail:
+       if (smmu->avp_vector_page)
+               __free_page(smmu->avp_vector_page);
+       if (smmu->regs)
+               devm_iounmap(dev, smmu->regs);
+       if (smmu->regs_ahbarb)
+               devm_iounmap(dev, smmu->regs_ahbarb);
+       if (smmu && smmu->as) {
+               for (i = 0; i < smmu->num_as; i++) {
+                       if (smmu->as[i].pdir_page) {
+                               ClearPageReserved(smmu->as[i].pdir_page);
+                               __free_page(smmu->as[i].pdir_page);
+                       }
+               }
+               devm_kfree(dev, smmu->as);
+       }
+       devm_kfree(dev, smmu);
+       return err;
+}
+
+static int tegra_smmu_remove(struct platform_device *pdev)
+{
+       struct smmu_device *smmu = platform_get_drvdata(pdev);
+       struct device *dev = smmu->dev;
+
+       smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG);
+       platform_set_drvdata(pdev, NULL);
+       if (smmu->as) {
+               int i;
+
+               for (i = 0; i < smmu->num_as; i++)
+                       free_pdir(&smmu->as[i]);
+               devm_kfree(dev, smmu->as);
+       }
+       if (smmu->avp_vector_page)
+               __free_page(smmu->avp_vector_page);
+       if (smmu->regs)
+               devm_iounmap(dev, smmu->regs);
+       if (smmu->regs_ahbarb)
+               devm_iounmap(dev, smmu->regs_ahbarb);
+       devm_kfree(dev, smmu);
+       smmu_handle = NULL;
+       return 0;
+}
+
+const struct dev_pm_ops tegra_smmu_pm_ops = {
+       .suspend        = tegra_smmu_suspend,
+       .resume         = tegra_smmu_resume,
+};
+
+static struct platform_driver tegra_smmu_driver = {
+       .probe          = tegra_smmu_probe,
+       .remove         = tegra_smmu_remove,
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "tegra-smmu",
+               .pm     = &tegra_smmu_pm_ops,
+       },
+};
+
+static int __devinit tegra_smmu_init(void)
+{
+       bus_set_iommu(&platform_bus_type, &smmu_iommu_ops);
+       return platform_driver_register(&tegra_smmu_driver);
+}
+
+static void __exit tegra_smmu_exit(void)
+{
+       platform_driver_unregister(&tegra_smmu_driver);
+}
+
+subsys_initcall(tegra_smmu_init);
+module_exit(tegra_smmu_exit);
+
+MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30");
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
index 8c7a75d..ff4b8cf 100644 (file)
@@ -17,7 +17,7 @@ menuconfig NEW_LEDS
 if NEW_LEDS
 
 config LEDS_CLASS
-       bool "LED Class Support"
+       tristate "LED Class Support"
        help
          This option enables the led sysfs class in /sys/class/leds.  You'll
          need this to do anything useful with LEDs.  If unsure, say N.
@@ -69,18 +69,11 @@ config LEDS_MIKROTIK_RB532
 config LEDS_S3C24XX
        tristate "LED Support for Samsung S3C24XX GPIO LEDs"
        depends on LEDS_CLASS
-       depends on ARCH_S3C2410
+       depends on ARCH_S3C24XX
        help
          This option enables support for LEDs connected to GPIO lines
          on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440.
 
-config LEDS_AMS_DELTA
-       tristate "LED Support for the Amstrad Delta (E3)"
-       depends on LEDS_CLASS
-       depends on MACH_AMS_DELTA
-       help
-         This option enables support for the LEDs on Amstrad Delta (E3).
-
 config LEDS_NET48XX
        tristate "LED Support for Soekris net48xx series Error LED"
        depends on LEDS_CLASS
@@ -234,6 +227,14 @@ config LEDS_PCA955X
          LED driver chips accessed via the I2C bus.  Supported
          devices include PCA9550, PCA9551, PCA9552, and PCA9553.
 
+config LEDS_PCA9633
+       tristate "LED support for PCA9633 I2C chip"
+       depends on LEDS_CLASS
+       depends on I2C
+       help
+         This option enables support for LEDs connected to the PCA9633
+         LED driver chip accessed via the I2C bus.
+
 config LEDS_WM831X_STATUS
        tristate "LED support for status LEDs on WM831x PMICs"
        depends on LEDS_CLASS
index 6bcf4f6..890481c 100644 (file)
@@ -12,7 +12,6 @@ obj-$(CONFIG_LEDS_LOCOMO)             += leds-locomo.o
 obj-$(CONFIG_LEDS_LM3530)              += leds-lm3530.o
 obj-$(CONFIG_LEDS_MIKROTIK_RB532)      += leds-rb532.o
 obj-$(CONFIG_LEDS_S3C24XX)             += leds-s3c24xx.o
-obj-$(CONFIG_LEDS_AMS_DELTA)           += leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
 obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
 obj-$(CONFIG_LEDS_COBALT_QUBE)         += leds-cobalt-qube.o
@@ -30,6 +29,7 @@ obj-$(CONFIG_LEDS_HP6XX)              += leds-hp6xx.o
 obj-$(CONFIG_LEDS_OT200)               += leds-ot200.o
 obj-$(CONFIG_LEDS_FSG)                 += leds-fsg.o
 obj-$(CONFIG_LEDS_PCA955X)             += leds-pca955x.o
+obj-$(CONFIG_LEDS_PCA9633)             += leds-pca9633.o
 obj-$(CONFIG_LEDS_DA903X)              += leds-da903x.o
 obj-$(CONFIG_LEDS_WM831X_STATUS)       += leds-wm831x-status.o
 obj-$(CONFIG_LEDS_WM8350)              += leds-wm8350.o
index 0c8739c..5bff843 100644 (file)
@@ -110,50 +110,6 @@ static void led_timer_function(unsigned long data)
        mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
 }
 
-static void led_stop_software_blink(struct led_classdev *led_cdev)
-{
-       /* deactivate previous settings */
-       del_timer_sync(&led_cdev->blink_timer);
-       led_cdev->blink_delay_on = 0;
-       led_cdev->blink_delay_off = 0;
-}
-
-static void led_set_software_blink(struct led_classdev *led_cdev,
-                                  unsigned long delay_on,
-                                  unsigned long delay_off)
-{
-       int current_brightness;
-
-       current_brightness = led_get_brightness(led_cdev);
-       if (current_brightness)
-               led_cdev->blink_brightness = current_brightness;
-       if (!led_cdev->blink_brightness)
-               led_cdev->blink_brightness = led_cdev->max_brightness;
-
-       if (led_get_trigger_data(led_cdev) &&
-           delay_on == led_cdev->blink_delay_on &&
-           delay_off == led_cdev->blink_delay_off)
-               return;
-
-       led_stop_software_blink(led_cdev);
-
-       led_cdev->blink_delay_on = delay_on;
-       led_cdev->blink_delay_off = delay_off;
-
-       /* never on - don't blink */
-       if (!delay_on)
-               return;
-
-       /* never off - just set to brightness */
-       if (!delay_off) {
-               led_set_brightness(led_cdev, led_cdev->blink_brightness);
-               return;
-       }
-
-       mod_timer(&led_cdev->blink_timer, jiffies + 1);
-}
-
-
 /**
  * led_classdev_suspend - suspend an led_classdev.
  * @led_cdev: the led_classdev to suspend.
@@ -262,32 +218,6 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
 }
 EXPORT_SYMBOL_GPL(led_classdev_unregister);
 
-void led_blink_set(struct led_classdev *led_cdev,
-                  unsigned long *delay_on,
-                  unsigned long *delay_off)
-{
-       del_timer_sync(&led_cdev->blink_timer);
-
-       if (led_cdev->blink_set &&
-           !led_cdev->blink_set(led_cdev, delay_on, delay_off))
-               return;
-
-       /* blink with 1 Hz as default if nothing specified */
-       if (!*delay_on && !*delay_off)
-               *delay_on = *delay_off = 500;
-
-       led_set_software_blink(led_cdev, *delay_on, *delay_off);
-}
-EXPORT_SYMBOL(led_blink_set);
-
-void led_brightness_set(struct led_classdev *led_cdev,
-                       enum led_brightness brightness)
-{
-       led_stop_software_blink(led_cdev);
-       led_cdev->brightness_set(led_cdev, brightness);
-}
-EXPORT_SYMBOL(led_brightness_set);
-
 static int __init leds_init(void)
 {
        leds_class = class_create(THIS_MODULE, "leds");
index 016d19f..d686004 100644 (file)
@@ -23,3 +23,73 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
 
 LIST_HEAD(leds_list);
 EXPORT_SYMBOL_GPL(leds_list);
+
+static void led_stop_software_blink(struct led_classdev *led_cdev)
+{
+       /* deactivate previous settings */
+       del_timer_sync(&led_cdev->blink_timer);
+       led_cdev->blink_delay_on = 0;
+       led_cdev->blink_delay_off = 0;
+}
+
+static void led_set_software_blink(struct led_classdev *led_cdev,
+                                  unsigned long delay_on,
+                                  unsigned long delay_off)
+{
+       int current_brightness;
+
+       current_brightness = led_get_brightness(led_cdev);
+       if (current_brightness)
+               led_cdev->blink_brightness = current_brightness;
+       if (!led_cdev->blink_brightness)
+               led_cdev->blink_brightness = led_cdev->max_brightness;
+
+       if (led_get_trigger_data(led_cdev) &&
+           delay_on == led_cdev->blink_delay_on &&
+           delay_off == led_cdev->blink_delay_off)
+               return;
+
+       led_stop_software_blink(led_cdev);
+
+       led_cdev->blink_delay_on = delay_on;
+       led_cdev->blink_delay_off = delay_off;
+
+       /* never on - don't blink */
+       if (!delay_on)
+               return;
+
+       /* never off - just set to brightness */
+       if (!delay_off) {
+               led_set_brightness(led_cdev, led_cdev->blink_brightness);
+               return;
+       }
+
+       mod_timer(&led_cdev->blink_timer, jiffies + 1);
+}
+
+
+void led_blink_set(struct led_classdev *led_cdev,
+                  unsigned long *delay_on,
+                  unsigned long *delay_off)
+{
+       del_timer_sync(&led_cdev->blink_timer);
+
+       if (led_cdev->blink_set &&
+           !led_cdev->blink_set(led_cdev, delay_on, delay_off))
+               return;
+
+       /* blink with 1 Hz as default if nothing specified */
+       if (!*delay_on && !*delay_off)
+               *delay_on = *delay_off = 500;
+
+       led_set_software_blink(led_cdev, *delay_on, *delay_off);
+}
+EXPORT_SYMBOL(led_blink_set);
+
+void led_brightness_set(struct led_classdev *led_cdev,
+                       enum led_brightness brightness)
+{
+       led_stop_software_blink(led_cdev);
+       led_cdev->brightness_set(led_cdev, brightness);
+}
+EXPORT_SYMBOL(led_brightness_set);
index 4ca0062..5b61aaf 100644 (file)
@@ -114,6 +114,27 @@ static inline int __blink_ctl_mask(int port)
        return ret;
 }
 
+static int led_power_set(struct pm860x_chip *chip, int port, int on)
+{
+       int ret = -EINVAL;
+
+       switch (port) {
+       case PM8606_LED1_RED:
+       case PM8606_LED1_GREEN:
+       case PM8606_LED1_BLUE:
+               ret = on ? pm8606_osc_enable(chip, RGB1_ENABLE) :
+                       pm8606_osc_disable(chip, RGB1_ENABLE);
+               break;
+       case PM8606_LED2_RED:
+       case PM8606_LED2_GREEN:
+       case PM8606_LED2_BLUE:
+               ret = on ? pm8606_osc_enable(chip, RGB2_ENABLE) :
+                       pm8606_osc_disable(chip, RGB2_ENABLE);
+               break;
+       }
+       return ret;
+}
+
 static void pm860x_led_work(struct work_struct *work)
 {
 
@@ -126,6 +147,7 @@ static void pm860x_led_work(struct work_struct *work)
        chip = led->chip;
        mutex_lock(&led->lock);
        if ((led->current_brightness == 0) && led->brightness) {
+               led_power_set(chip, led->port, 1);
                if (led->iset) {
                        pm860x_set_bits(led->i2c, __led_off(led->port),
                                        LED_CURRENT_MASK, led->iset);
@@ -149,6 +171,7 @@ static void pm860x_led_work(struct work_struct *work)
                                        LED_CURRENT_MASK, 0);
                        mask = __blink_ctl_mask(led->port);
                        pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
+                       led_power_set(chip, led->port, 0);
                }
        }
        led->current_brightness = led->brightness;
diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
deleted file mode 100644 (file)
index 0742835..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * LEDs driver for Amstrad Delta (E3)
- *
- * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/leds.h>
-#include <plat/board-ams-delta.h>
-
-/*
- * Our context
- */
-struct ams_delta_led {
-       struct led_classdev     cdev;
-       u8                      bitmask;
-};
-
-static void ams_delta_led_set(struct led_classdev *led_cdev,
-               enum led_brightness value)
-{
-       struct ams_delta_led *led_dev =
-               container_of(led_cdev, struct ams_delta_led, cdev);
-
-       if (value)
-               ams_delta_latch1_write(led_dev->bitmask, led_dev->bitmask);
-       else
-               ams_delta_latch1_write(led_dev->bitmask, 0);
-}
-
-static struct ams_delta_led ams_delta_leds[] = {
-       {
-               .cdev           = {
-                       .name           = "ams-delta::camera",
-                       .brightness_set = ams_delta_led_set,
-               },
-               .bitmask        = AMS_DELTA_LATCH1_LED_CAMERA,
-       },
-       {
-               .cdev           = {
-                       .name           = "ams-delta::advert",
-                       .brightness_set = ams_delta_led_set,
-               },
-               .bitmask        = AMS_DELTA_LATCH1_LED_ADVERT,
-       },
-       {
-               .cdev           = {
-                       .name           = "ams-delta::email",
-                       .brightness_set = ams_delta_led_set,
-               },
-               .bitmask        = AMS_DELTA_LATCH1_LED_EMAIL,
-       },
-       {
-               .cdev           = {
-                       .name           = "ams-delta::handsfree",
-                       .brightness_set = ams_delta_led_set,
-               },
-               .bitmask        = AMS_DELTA_LATCH1_LED_HANDSFREE,
-       },
-       {
-               .cdev           = {
-                       .name           = "ams-delta::voicemail",
-                       .brightness_set = ams_delta_led_set,
-               },
-               .bitmask        = AMS_DELTA_LATCH1_LED_VOICEMAIL,
-       },
-       {
-               .cdev           = {
-                       .name           = "ams-delta::voice",
-                       .brightness_set = ams_delta_led_set,
-               },
-               .bitmask        = AMS_DELTA_LATCH1_LED_VOICE,
-       },
-};
-
-static int ams_delta_led_probe(struct platform_device *pdev)
-{
-       int i, ret;
-
-       for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++) {
-               ams_delta_leds[i].cdev.flags |= LED_CORE_SUSPENDRESUME;
-               ret = led_classdev_register(&pdev->dev,
-                               &ams_delta_leds[i].cdev);
-               if (ret < 0)
-                       goto fail;
-       }
-
-       return 0;
-fail:
-       while (--i >= 0)
-               led_classdev_unregister(&ams_delta_leds[i].cdev);
-       return ret;     
-}
-
-static int ams_delta_led_remove(struct platform_device *pdev)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++)
-               led_classdev_unregister(&ams_delta_leds[i].cdev);
-
-       return 0;
-}
-
-static struct platform_driver ams_delta_led_driver = {
-       .probe          = ams_delta_led_probe,
-       .remove         = ams_delta_led_remove,
-       .driver         = {
-               .name = "ams-delta-led",
-               .owner = THIS_MODULE,
-       },
-};
-
-module_platform_driver(ams_delta_led_driver);
-
-MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
-MODULE_DESCRIPTION("Amstrad Delta LED driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ams-delta-led");
index 7df74cb..f4c470a 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
 #include <linux/leds.h>
 #include <linux/of_platform.h>
 #include <linux/of_gpio.h>
@@ -20,8 +21,6 @@
 #include <linux/workqueue.h>
 #include <linux/module.h>
 
-#include <asm/gpio.h>
-
 struct gpio_led_data {
        struct led_classdev cdev;
        unsigned gpio;
index e59c166..968fd5f 100644 (file)
@@ -26,7 +26,6 @@
 #define LM3530_GEN_CONFIG              0x10
 #define LM3530_ALS_CONFIG              0x20
 #define LM3530_BRT_RAMP_RATE           0x30
-#define LM3530_ALS_ZONE_REG            0x40
 #define LM3530_ALS_IMP_SELECT          0x41
 #define LM3530_BRT_CTRL_REG            0xA0
 #define LM3530_ALS_ZB0_REG             0x60
@@ -38,7 +37,7 @@
 #define LM3530_ALS_Z2T_REG             0x72
 #define LM3530_ALS_Z3T_REG             0x73
 #define LM3530_ALS_Z4T_REG             0x74
-#define LM3530_REG_MAX                 15
+#define LM3530_REG_MAX                 14
 
 /* General Control Register */
 #define LM3530_EN_I2C_SHIFT            (0)
@@ -80,6 +79,9 @@
 #define LM3530_DEF_ZT_3                        (0x33)
 #define LM3530_DEF_ZT_4                        (0x19)
 
+/* 7 bits are used for the brightness : LM3530_BRT_CTRL_REG */
+#define MAX_BRIGHTNESS                 (127)
+
 struct lm3530_mode_map {
        const char *mode;
        enum lm3530_mode mode_val;
@@ -115,7 +117,6 @@ static const u8 lm3530_reg[LM3530_REG_MAX] = {
        LM3530_GEN_CONFIG,
        LM3530_ALS_CONFIG,
        LM3530_BRT_RAMP_RATE,
-       LM3530_ALS_ZONE_REG,
        LM3530_ALS_IMP_SELECT,
        LM3530_BRT_CTRL_REG,
        LM3530_ALS_ZB0_REG,
@@ -152,27 +153,35 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
        u8 reg_val[LM3530_REG_MAX];
        u8 zones[LM3530_ALS_ZB_MAX];
        u32 als_vmin, als_vmax, als_vstep;
-       struct lm3530_platform_data *pltfm = drvdata->pdata;
+       struct lm3530_platform_data *pdata = drvdata->pdata;
        struct i2c_client *client = drvdata->client;
+       struct lm3530_pwm_data *pwm = &pdata->pwm_data;
 
-       gen_config = (pltfm->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) |
-                       ((pltfm->max_current & 7) << LM3530_MAX_CURR_SHIFT);
+       gen_config = (pdata->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) |
+                       ((pdata->max_current & 7) << LM3530_MAX_CURR_SHIFT);
 
-       if (drvdata->mode == LM3530_BL_MODE_MANUAL ||
-           drvdata->mode == LM3530_BL_MODE_ALS)
-               gen_config |= (LM3530_ENABLE_I2C);
+       switch (drvdata->mode) {
+       case LM3530_BL_MODE_MANUAL:
+       case LM3530_BL_MODE_ALS:
+               gen_config |= LM3530_ENABLE_I2C;
+               break;
+       case LM3530_BL_MODE_PWM:
+               gen_config |= LM3530_ENABLE_PWM | LM3530_ENABLE_PWM_SIMPLE |
+                             (pdata->pwm_pol_hi << LM3530_PWM_POL_SHIFT);
+               break;
+       }
 
        if (drvdata->mode == LM3530_BL_MODE_ALS) {
-               if (pltfm->als_vmax == 0) {
-                       pltfm->als_vmin = 0;
-                       pltfm->als_vmax = LM3530_ALS_WINDOW_mV;
+               if (pdata->als_vmax == 0) {
+                       pdata->als_vmin = 0;
+                       pdata->als_vmax = LM3530_ALS_WINDOW_mV;
                }
 
-               als_vmin = pltfm->als_vmin;
-               als_vmax = pltfm->als_vmax;
+               als_vmin = pdata->als_vmin;
+               als_vmax = pdata->als_vmax;
 
                if ((als_vmax - als_vmin) > LM3530_ALS_WINDOW_mV)
-                       pltfm->als_vmax = als_vmax =
+                       pdata->als_vmax = als_vmax =
                                als_vmin + LM3530_ALS_WINDOW_mV;
 
                /* n zone boundary makes n+1 zones */
@@ -184,44 +193,41 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
                                        / 1000;
 
                als_config =
-                       (pltfm->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) |
+                       (pdata->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) |
                        (LM3530_ENABLE_ALS) |
-                       (pltfm->als_input_mode << LM3530_ALS_SEL_SHIFT);
+                       (pdata->als_input_mode << LM3530_ALS_SEL_SHIFT);
 
                als_imp_sel =
-                       (pltfm->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) |
-                       (pltfm->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
+                       (pdata->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) |
+                       (pdata->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT);
 
        }
 
-       if (drvdata->mode == LM3530_BL_MODE_PWM)
-               gen_config |= (LM3530_ENABLE_PWM) |
-                               (pltfm->pwm_pol_hi << LM3530_PWM_POL_SHIFT) |
-                               (LM3530_ENABLE_PWM_SIMPLE);
-
-       brt_ramp = (pltfm->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
-                       (pltfm->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
+       brt_ramp = (pdata->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
+                       (pdata->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
 
        if (drvdata->brightness)
                brightness = drvdata->brightness;
        else
-               brightness = drvdata->brightness = pltfm->brt_val;
+               brightness = drvdata->brightness = pdata->brt_val;
+
+       if (brightness > drvdata->led_dev.max_brightness)
+               brightness = drvdata->led_dev.max_brightness;
 
        reg_val[0] = gen_config;        /* LM3530_GEN_CONFIG */
        reg_val[1] = als_config;        /* LM3530_ALS_CONFIG */
        reg_val[2] = brt_ramp;          /* LM3530_BRT_RAMP_RATE */
-       reg_val[3] = 0x00;              /* LM3530_ALS_ZONE_REG */
-       reg_val[4] = als_imp_sel;       /* LM3530_ALS_IMP_SELECT */
-       reg_val[5] = brightness;        /* LM3530_BRT_CTRL_REG */
-       reg_val[6] = zones[0];          /* LM3530_ALS_ZB0_REG */
-       reg_val[7] = zones[1];          /* LM3530_ALS_ZB1_REG */
-       reg_val[8] = zones[2];          /* LM3530_ALS_ZB2_REG */
-       reg_val[9] = zones[3];          /* LM3530_ALS_ZB3_REG */
-       reg_val[10] = LM3530_DEF_ZT_0;  /* LM3530_ALS_Z0T_REG */
-       reg_val[11] = LM3530_DEF_ZT_1;  /* LM3530_ALS_Z1T_REG */
-       reg_val[12] = LM3530_DEF_ZT_2;  /* LM3530_ALS_Z2T_REG */
-       reg_val[13] = LM3530_DEF_ZT_3;  /* LM3530_ALS_Z3T_REG */
-       reg_val[14] = LM3530_DEF_ZT_4;  /* LM3530_ALS_Z4T_REG */
+       reg_val[3] = als_imp_sel;       /* LM3530_ALS_IMP_SELECT */
+       reg_val[4] = brightness;        /* LM3530_BRT_CTRL_REG */
+       reg_val[5] = zones[0];          /* LM3530_ALS_ZB0_REG */
+       reg_val[6] = zones[1];          /* LM3530_ALS_ZB1_REG */
+       reg_val[7] = zones[2];          /* LM3530_ALS_ZB2_REG */
+       reg_val[8] = zones[3];          /* LM3530_ALS_ZB3_REG */
+       reg_val[9] = LM3530_DEF_ZT_0;   /* LM3530_ALS_Z0T_REG */
+       reg_val[10] = LM3530_DEF_ZT_1;  /* LM3530_ALS_Z1T_REG */
+       reg_val[11] = LM3530_DEF_ZT_2;  /* LM3530_ALS_Z2T_REG */
+       reg_val[12] = LM3530_DEF_ZT_3;  /* LM3530_ALS_Z3T_REG */
+       reg_val[13] = LM3530_DEF_ZT_4;  /* LM3530_ALS_Z4T_REG */
 
        if (!drvdata->enable) {
                ret = regulator_enable(drvdata->regulator);
@@ -234,6 +240,15 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
        }
 
        for (i = 0; i < LM3530_REG_MAX; i++) {
+               /* do not update brightness register when pwm mode */
+               if (lm3530_reg[i] == LM3530_BRT_CTRL_REG &&
+                   drvdata->mode == LM3530_BL_MODE_PWM) {
+                       if (pwm->pwm_set_intensity)
+                               pwm->pwm_set_intensity(reg_val[i],
+                                       drvdata->led_dev.max_brightness);
+                       continue;
+               }
+
                ret = i2c_smbus_write_byte_data(client,
                                lm3530_reg[i], reg_val[i]);
                if (ret)
@@ -249,6 +264,9 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev,
        int err;
        struct lm3530_data *drvdata =
            container_of(led_cdev, struct lm3530_data, led_dev);
+       struct lm3530_platform_data *pdata = drvdata->pdata;
+       struct lm3530_pwm_data *pwm = &pdata->pwm_data;
+       u8 max_brightness = led_cdev->max_brightness;
 
        switch (drvdata->mode) {
        case LM3530_BL_MODE_MANUAL:
@@ -264,12 +282,12 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev,
 
                /* set the brightness in brightness control register*/
                err = i2c_smbus_write_byte_data(drvdata->client,
-                               LM3530_BRT_CTRL_REG, brt_val / 2);
+                               LM3530_BRT_CTRL_REG, brt_val);
                if (err)
                        dev_err(&drvdata->client->dev,
                                "Unable to set brightness: %d\n", err);
                else
-                       drvdata->brightness = brt_val / 2;
+                       drvdata->brightness = brt_val;
 
                if (brt_val == 0) {
                        err = regulator_disable(drvdata->regulator);
@@ -282,6 +300,8 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev,
        case LM3530_BL_MODE_ALS:
                break;
        case LM3530_BL_MODE_PWM:
+               if (pwm->pwm_set_intensity)
+                       pwm->pwm_set_intensity(brt_val, max_brightness);
                break;
        default:
                break;
@@ -291,11 +311,11 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev,
 static ssize_t lm3530_mode_get(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct i2c_client *client = container_of(
-                                       dev->parent, struct i2c_client, dev);
-       struct lm3530_data *drvdata = i2c_get_clientdata(client);
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lm3530_data *drvdata;
        int i, len = 0;
 
+       drvdata = container_of(led_cdev, struct lm3530_data, led_dev);
        for (i = 0; i < ARRAY_SIZE(mode_map); i++)
                if (drvdata->mode == mode_map[i].mode_val)
                        len += sprintf(buf + len, "[%s] ", mode_map[i].mode);
@@ -310,26 +330,26 @@ static ssize_t lm3530_mode_get(struct device *dev,
 static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute
                                   *attr, const char *buf, size_t size)
 {
-       int err;
-       struct i2c_client *client = container_of(
-                                       dev->parent, struct i2c_client, dev);
-       struct lm3530_data *drvdata = i2c_get_clientdata(client);
-       int mode;
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lm3530_data *drvdata;
+       struct lm3530_pwm_data *pwm;
+       u8 max_brightness;
+       int mode, err;
 
+       drvdata = container_of(led_cdev, struct lm3530_data, led_dev);
+       pwm = &drvdata->pdata->pwm_data;
+       max_brightness = led_cdev->max_brightness;
        mode = lm3530_get_mode_from_str(buf);
        if (mode < 0) {
                dev_err(dev, "Invalid mode\n");
                return -EINVAL;
        }
 
-       if (mode == LM3530_BL_MODE_MANUAL)
-               drvdata->mode = LM3530_BL_MODE_MANUAL;
-       else if (mode == LM3530_BL_MODE_ALS)
-               drvdata->mode = LM3530_BL_MODE_ALS;
-       else if (mode == LM3530_BL_MODE_PWM) {
-               dev_err(dev, "PWM mode not supported\n");
-               return -EINVAL;
-       }
+       drvdata->mode = mode;
+
+       /* set pwm to low if unnecessary */
+       if (mode != LM3530_BL_MODE_PWM && pwm->pwm_set_intensity)
+               pwm->pwm_set_intensity(0, max_brightness);
 
        err = lm3530_init_registers(drvdata);
        if (err) {
@@ -380,6 +400,7 @@ static int __devinit lm3530_probe(struct i2c_client *client,
        drvdata->enable = false;
        drvdata->led_dev.name = LM3530_LED_DEV;
        drvdata->led_dev.brightness_set = lm3530_brightness_set;
+       drvdata->led_dev.max_brightness = MAX_BRIGHTNESS;
 
        i2c_set_clientdata(client, drvdata);
 
index d62a798..410a723 100644 (file)
 #define LP5521_MASTER_ENABLE           0x40    /* Chip master enable */
 #define LP5521_LOGARITHMIC_PWM         0x80    /* Logarithmic PWM adjustment */
 #define LP5521_EXEC_RUN                        0x2A
-
-/* Bits in CONFIG register */
-#define LP5521_PWM_HF                  0x40    /* PWM: 0 = 256Hz, 1 = 558Hz */
-#define LP5521_PWRSAVE_EN              0x20    /* 1 = Power save mode */
-#define LP5521_CP_MODE_OFF             0       /* Charge pump (CP) off */
-#define LP5521_CP_MODE_BYPASS          8       /* CP forced to bypass mode */
-#define LP5521_CP_MODE_1X5             0x10    /* CP forced to 1.5x mode */
-#define LP5521_CP_MODE_AUTO            0x18    /* Automatic mode selection */
-#define LP5521_R_TO_BATT               4       /* R out: 0 = CP, 1 = Vbat */
-#define LP5521_CLK_SRC_EXT             0       /* Ext-clk source (CLK_32K) */
-#define LP5521_CLK_INT                 1       /* Internal clock */
-#define LP5521_CLK_AUTO                        2       /* Automatic clock selection */
+#define LP5521_ENABLE_DEFAULT  \
+       (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM)
+#define LP5521_ENABLE_RUN_PROGRAM      \
+       (LP5521_ENABLE_DEFAULT | LP5521_EXEC_RUN)
 
 /* Status */
 #define LP5521_EXT_CLK_USED            0x08
 /* default R channel current register value */
 #define LP5521_REG_R_CURR_DEFAULT      0xAF
 
+/* Pattern Mode */
+#define PATTERN_OFF    0
+
 struct lp5521_engine {
        int             id;
        u8              mode;
@@ -241,15 +236,16 @@ static int lp5521_configure(struct i2c_client *client)
 {
        struct lp5521_chip *chip = i2c_get_clientdata(client);
        int ret;
+       u8 cfg;
 
        lp5521_init_engine(chip);
 
        /* Set all PWMs to direct control mode */
-       ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F);
+       ret = lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
 
-       /* Enable auto-powersave, set charge pump to auto, red to battery */
-       ret |= lp5521_write(client, LP5521_REG_CONFIG,
-               LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT);
+       cfg = chip->pdata->update_config ?
+               : (LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT);
+       ret |= lp5521_write(client, LP5521_REG_CONFIG, cfg);
 
        /* Initialize all channels PWM to zero -> leds off */
        ret |= lp5521_write(client, LP5521_REG_R_PWM, 0);
@@ -258,8 +254,7 @@ static int lp5521_configure(struct i2c_client *client)
 
        /* Set engines are set to run state when OP_MODE enables engines */
        ret |= lp5521_write(client, LP5521_REG_ENABLE,
-                       LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM |
-                       LP5521_EXEC_RUN);
+                       LP5521_ENABLE_RUN_PROGRAM);
        /* enable takes 500us. 1 - 2 ms leaves some margin */
        usleep_range(1000, 2000);
 
@@ -310,8 +305,7 @@ static int lp5521_detect(struct i2c_client *client)
        int ret;
        u8 buf;
 
-       ret = lp5521_write(client, LP5521_REG_ENABLE,
-                       LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM);
+       ret = lp5521_write(client, LP5521_REG_ENABLE, LP5521_ENABLE_DEFAULT);
        if (ret)
                return ret;
        /* enable takes 500us. 1 - 2 ms leaves some margin */
@@ -319,7 +313,7 @@ static int lp5521_detect(struct i2c_client *client)
        ret = lp5521_read(client, LP5521_REG_ENABLE, &buf);
        if (ret)
                return ret;
-       if (buf != (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM))
+       if (buf != LP5521_ENABLE_DEFAULT)
                return -ENODEV;
 
        return 0;
@@ -504,7 +498,7 @@ static ssize_t store_current(struct device *dev,
        ssize_t ret;
        unsigned long curr;
 
-       if (strict_strtoul(buf, 0, &curr))
+       if (kstrtoul(buf, 0, &curr))
                return -EINVAL;
 
        if (curr > led->max_current)
@@ -536,6 +530,97 @@ static ssize_t lp5521_selftest(struct device *dev,
        return sprintf(buf, "%s\n", ret ? "FAIL" : "OK");
 }
 
+static void lp5521_clear_program_memory(struct i2c_client *cl)
+{
+       int i;
+       u8 rgb_mem[] = {
+               LP5521_REG_R_PROG_MEM,
+               LP5521_REG_G_PROG_MEM,
+               LP5521_REG_B_PROG_MEM,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(rgb_mem); i++) {
+               lp5521_write(cl, rgb_mem[i], 0);
+               lp5521_write(cl, rgb_mem[i] + 1, 0);
+       }
+}
+
+static void lp5521_write_program_memory(struct i2c_client *cl,
+                               u8 base, u8 *rgb, int size)
+{
+       int i;
+
+       if (!rgb || size <= 0)
+               return;
+
+       for (i = 0; i < size; i++)
+               lp5521_write(cl, base + i, *(rgb + i));
+
+       lp5521_write(cl, base + i, 0);
+       lp5521_write(cl, base + i + 1, 0);
+}
+
+static inline struct lp5521_led_pattern *lp5521_get_pattern
+                                       (struct lp5521_chip *chip, u8 offset)
+{
+       struct lp5521_led_pattern *ptn;
+       ptn = chip->pdata->patterns + (offset - 1);
+       return ptn;
+}
+
+static void lp5521_run_led_pattern(int mode, struct lp5521_chip *chip)
+{
+       struct lp5521_led_pattern *ptn;
+       struct i2c_client *cl = chip->client;
+       int num_patterns = chip->pdata->num_patterns;
+
+       if (mode > num_patterns || !(chip->pdata->patterns))
+               return;
+
+       if (mode == PATTERN_OFF) {
+               lp5521_write(cl, LP5521_REG_ENABLE, LP5521_ENABLE_DEFAULT);
+               usleep_range(1000, 2000);
+               lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
+       } else {
+               ptn = lp5521_get_pattern(chip, mode);
+               if (!ptn)
+                       return;
+
+               lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
+               usleep_range(1000, 2000);
+
+               lp5521_clear_program_memory(cl);
+
+               lp5521_write_program_memory(cl, LP5521_REG_R_PROG_MEM,
+                                       ptn->r, ptn->size_r);
+               lp5521_write_program_memory(cl, LP5521_REG_G_PROG_MEM,
+                                       ptn->g, ptn->size_g);
+               lp5521_write_program_memory(cl, LP5521_REG_B_PROG_MEM,
+                                       ptn->b, ptn->size_b);
+
+               lp5521_write(cl, LP5521_REG_OP_MODE, LP5521_CMD_RUN);
+               usleep_range(1000, 2000);
+               lp5521_write(cl, LP5521_REG_ENABLE, LP5521_ENABLE_RUN_PROGRAM);
+       }
+}
+
+static ssize_t store_led_pattern(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t len)
+{
+       struct lp5521_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
+       unsigned long val;
+       int ret;
+
+       ret = strict_strtoul(buf, 16, &val);
+       if (ret)
+               return ret;
+
+       lp5521_run_led_pattern(val, chip);
+
+       return len;
+}
+
 /* led class device attributes */
 static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current);
 static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
@@ -561,6 +646,7 @@ static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load);
 static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load);
 static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load);
 static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
+static DEVICE_ATTR(led_pattern, S_IWUSR, NULL, store_led_pattern);
 
 static struct attribute *lp5521_attributes[] = {
        &dev_attr_engine1_mode.attr,
@@ -570,6 +656,7 @@ static struct attribute *lp5521_attributes[] = {
        &dev_attr_engine1_load.attr,
        &dev_attr_engine2_load.attr,
        &dev_attr_engine3_load.attr,
+       &dev_attr_led_pattern.attr,
        NULL
 };
 
@@ -620,10 +707,15 @@ static int __devinit lp5521_init_led(struct lp5521_led *led,
                return -EINVAL;
        }
 
-       snprintf(name, sizeof(name), "%s:channel%d",
-                       pdata->label ?: client->name, chan);
        led->cdev.brightness_set = lp5521_set_brightness;
-       led->cdev.name = name;
+       if (pdata->led_config[chan].name) {
+               led->cdev.name = pdata->led_config[chan].name;
+       } else {
+               snprintf(name, sizeof(name), "%s:channel%d",
+                       pdata->label ?: client->name, chan);
+               led->cdev.name = name;
+       }
+
        res = led_classdev_register(dev, &led->cdev);
        if (res < 0) {
                dev_err(dev, "couldn't register led on channel %d\n", chan);
@@ -692,9 +784,9 @@ static int __devinit lp5521_probe(struct i2c_client *client,
         * otherwise further access to the R G B channels in the
         * LP5521_REG_ENABLE register will not have any effect - strange!
         */
-       lp5521_read(client, LP5521_REG_R_CURRENT, &buf);
+       ret = lp5521_read(client, LP5521_REG_R_CURRENT, &buf);
        if (buf != LP5521_REG_R_CURR_DEFAULT) {
-               dev_err(&client->dev, "error in reseting chip\n");
+               dev_err(&client->dev, "error in resetting chip\n");
                goto fail2;
        }
        usleep_range(10000, 20000);
@@ -767,6 +859,7 @@ static int __devexit lp5521_remove(struct i2c_client *client)
        struct lp5521_chip *chip = i2c_get_clientdata(client);
        int i;
 
+       lp5521_run_led_pattern(PATTERN_OFF, chip);
        lp5521_unregister_sysfs(client);
 
        for (i = 0; i < chip->num_leds; i++) {
index 73e791a..857a3e1 100644 (file)
@@ -152,7 +152,7 @@ static inline struct lp5523_chip *led_to_lp5523(struct lp5523_led *led)
 
 static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode);
 static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode);
-static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern);
+static int lp5523_load_program(struct lp5523_engine *engine, const u8 *pattern);
 
 static void lp5523_led_brightness_work(struct work_struct *work);
 
@@ -196,7 +196,7 @@ static int lp5523_configure(struct i2c_client *client)
        u8 status;
 
        /* one pattern per engine setting led mux start and stop addresses */
-       u8 pattern[][LP5523_PROGRAM_LENGTH] =  {
+       static const u8 pattern[][LP5523_PROGRAM_LENGTH] =  {
                { 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0},
                { 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0},
                { 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0},
@@ -301,7 +301,7 @@ static int lp5523_load_mux(struct lp5523_engine *engine, u16 mux)
        return ret;
 }
 
-static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern)
+static int lp5523_load_program(struct lp5523_engine *engine, const u8 *pattern)
 {
        struct lp5523_chip *chip = engine_to_lp5523(engine);
        struct i2c_client *client = chip->client;
diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c
new file mode 100644 (file)
index 0000000..d8926fd
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2011 bct electronic GmbH
+ *
+ * Author: Peter Meerwald <p.meerwald@bct-electronic.com>
+ *
+ * Based on leds-pca955x.c
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+/* LED select registers determine the source that drives LED outputs */
+#define PCA9633_LED_OFF                0x0     /* LED driver off */
+#define PCA9633_LED_ON         0x1     /* LED driver on */
+#define PCA9633_LED_PWM                0x2     /* Controlled through PWM */
+#define PCA9633_LED_GRP_PWM    0x3     /* Controlled through PWM/GRPPWM */
+
+#define PCA9633_MODE1          0x00
+#define PCA9633_MODE2          0x01
+#define PCA9633_PWM_BASE       0x02
+#define PCA9633_LEDOUT         0x08
+
+static const struct i2c_device_id pca9633_id[] = {
+       { "pca9633", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, pca9633_id);
+
+struct pca9633_led {
+       struct i2c_client *client;
+       struct work_struct work;
+       enum led_brightness brightness;
+       struct led_classdev led_cdev;
+       int led_num; /* 0 .. 3 potentially */
+       char name[32];
+};
+
+static void pca9633_led_work(struct work_struct *work)
+{
+       struct pca9633_led *pca9633 = container_of(work,
+               struct pca9633_led, work);
+       u8 ledout = i2c_smbus_read_byte_data(pca9633->client, PCA9633_LEDOUT);
+       int shift = 2 * pca9633->led_num;
+       u8 mask = 0x3 << shift;
+
+       switch (pca9633->brightness) {
+       case LED_FULL:
+               i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
+                       (ledout & ~mask) | (PCA9633_LED_ON << shift));
+               break;
+       case LED_OFF:
+               i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
+                       ledout & ~mask);
+               break;
+       default:
+               i2c_smbus_write_byte_data(pca9633->client,
+                       PCA9633_PWM_BASE + pca9633->led_num,
+                       pca9633->brightness);
+               i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
+                       (ledout & ~mask) | (PCA9633_LED_PWM << shift));
+               break;
+       }
+}
+
+static void pca9633_led_set(struct led_classdev *led_cdev,
+       enum led_brightness value)
+{
+       struct pca9633_led *pca9633;
+
+       pca9633 = container_of(led_cdev, struct pca9633_led, led_cdev);
+
+       pca9633->brightness = value;
+
+       /*
+        * Must use workqueue for the actual I/O since I2C operations
+        * can sleep.
+        */
+       schedule_work(&pca9633->work);
+}
+
+static int __devinit pca9633_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct pca9633_led *pca9633;
+       struct led_platform_data *pdata;
+       int i, err;
+
+       pdata = client->dev.platform_data;
+
+       if (pdata) {
+               if (pdata->num_leds <= 0 || pdata->num_leds > 4) {
+                       dev_err(&client->dev, "board info must claim at most 4 LEDs");
+                       return -EINVAL;
+               }
+       }
+
+       pca9633 = kcalloc(4, sizeof(*pca9633), GFP_KERNEL);
+       if (!pca9633)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, pca9633);
+
+       for (i = 0; i < 4; i++) {
+               pca9633[i].client = client;
+               pca9633[i].led_num = i;
+
+               /* Platform data can specify LED names and default triggers */
+               if (pdata && i < pdata->num_leds) {
+                       if (pdata->leds[i].name)
+                               snprintf(pca9633[i].name,
+                                        sizeof(pca9633[i].name), "pca9633:%s",
+                                        pdata->leds[i].name);
+                       if (pdata->leds[i].default_trigger)
+                               pca9633[i].led_cdev.default_trigger =
+                                       pdata->leds[i].default_trigger;
+               } else {
+                       snprintf(pca9633[i].name, sizeof(pca9633[i].name),
+                                "pca9633:%d", i);
+               }
+
+               pca9633[i].led_cdev.name = pca9633[i].name;
+               pca9633[i].led_cdev.brightness_set = pca9633_led_set;
+
+               INIT_WORK(&pca9633[i].work, pca9633_led_work);
+
+               err = led_classdev_register(&client->dev, &pca9633[i].led_cdev);
+               if (err < 0)
+                       goto exit;
+       }
+
+       /* Disable LED all-call address and set normal mode */
+       i2c_smbus_write_byte_data(client, PCA9633_MODE1, 0x00);
+
+       /* Turn off LEDs */
+       i2c_smbus_write_byte_data(client, PCA9633_LEDOUT, 0x00);
+
+       return 0;
+
+exit:
+       while (i--) {
+               led_classdev_unregister(&pca9633[i].led_cdev);
+               cancel_work_sync(&pca9633[i].work);
+       }
+
+       kfree(pca9633);
+
+       return err;
+}
+
+static int __devexit pca9633_remove(struct i2c_client *client)
+{
+       struct pca9633_led *pca9633 = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               led_classdev_unregister(&pca9633[i].led_cdev);
+               cancel_work_sync(&pca9633[i].work);
+       }
+
+       kfree(pca9633);
+
+       return 0;
+}
+
+static struct i2c_driver pca9633_driver = {
+       .driver = {
+               .name   = "leds-pca9633",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = pca9633_probe,
+       .remove = __devexit_p(pca9633_remove),
+       .id_table = pca9633_id,
+};
+
+module_i2c_driver(pca9633_driver);
+
+MODULE_AUTHOR("Peter Meerwald <p.meerwald@bct-electronic.com>");
+MODULE_DESCRIPTION("PCA9633 LED driver");
+MODULE_LICENSE("GPL v2");
index 133f89f..6c1c14f 100644 (file)
@@ -687,10 +687,9 @@ static int __devinit tca6507_probe(struct i2c_client *client,
                        NUM_LEDS);
                return -ENODEV;
        }
-       err = -ENOMEM;
        tca = kzalloc(sizeof(*tca), GFP_KERNEL);
        if (!tca)
-               goto exit;
+               return -ENOMEM;
 
        tca->client = client;
        INIT_WORK(&tca->work, tca6507_work);
@@ -724,11 +723,10 @@ static int __devinit tca6507_probe(struct i2c_client *client,
 
        return 0;
 exit:
-       while (i--)
+       while (i--) {
                if (tca->leds[i].led_cdev.name)
                        led_classdev_unregister(&tca->leds[i].led_cdev);
-       cancel_work_sync(&tca->work);
-       i2c_set_clientdata(client, NULL);
+       }
        kfree(tca);
        return err;
 }
@@ -745,7 +743,6 @@ static int __devexit tca6507_remove(struct i2c_client *client)
        }
        tca6507_remove_gpio(tca);
        cancel_work_sync(&tca->work);
-       i2c_set_clientdata(client, NULL);
        kfree(tca);
 
        return 0;
index faa4741..10f122a 100644 (file)
@@ -277,8 +277,8 @@ config DM_MIRROR
          needed for live data migration tools such as 'pvmove'.
 
 config DM_RAID
-       tristate "RAID 1/4/5/6 target (EXPERIMENTAL)"
-       depends on BLK_DEV_DM && EXPERIMENTAL
+       tristate "RAID 1/4/5/6 target"
+       depends on BLK_DEV_DM
        select MD_RAID1
        select MD_RAID456
        select BLK_DEV_MD
@@ -359,8 +359,8 @@ config DM_DELAY
        If unsure, say N.
 
 config DM_UEVENT
-       bool "DM uevents (EXPERIMENTAL)"
-       depends on BLK_DEV_DM && EXPERIMENTAL
+       bool "DM uevents"
+       depends on BLK_DEV_DM
        ---help---
        Generate udev events for DM events.
 
@@ -370,4 +370,24 @@ config DM_FLAKEY
        ---help---
          A target that intermittently fails I/O for debugging purposes.
 
+config DM_VERITY
+       tristate "Verity target support (EXPERIMENTAL)"
+       depends on BLK_DEV_DM && EXPERIMENTAL
+       select CRYPTO
+       select CRYPTO_HASH
+       select DM_BUFIO
+       ---help---
+         This device-mapper target creates a read-only device that
+         transparently validates the data on one underlying device against
+         a pre-generated tree of cryptographic checksums stored on a second
+         device.
+
+         You'll need to activate the digests you're going to use in the
+         cryptoapi configuration.
+
+         To compile this code as a module, choose M here: the module will
+         be called dm-verity.
+
+         If unsure, say N.
+
 endif # MD
index 046860c..8b2e0df 100644 (file)
@@ -42,6 +42,7 @@ obj-$(CONFIG_DM_LOG_USERSPACE)        += dm-log-userspace.o
 obj-$(CONFIG_DM_ZERO)          += dm-zero.o
 obj-$(CONFIG_DM_RAID)  += dm-raid.o
 obj-$(CONFIG_DM_THIN_PROVISIONING)     += dm-thin-pool.o
+obj-$(CONFIG_DM_VERITY)                += dm-verity.o
 
 ifeq ($(CONFIG_DM_UEVENT),y)
 dm-mod-objs                    += dm-uevent.o
index b6e58c7..cc06a1e 100644 (file)
@@ -578,7 +578,7 @@ static void write_endio(struct bio *bio, int error)
        struct dm_buffer *b = container_of(bio, struct dm_buffer, bio);
 
        b->write_error = error;
-       if (error) {
+       if (unlikely(error)) {
                struct dm_bufio_client *c = b->c;
                (void)cmpxchg(&c->async_write_error, 0, error);
        }
@@ -697,13 +697,20 @@ static void __wait_for_free_buffer(struct dm_bufio_client *c)
        dm_bufio_lock(c);
 }
 
+enum new_flag {
+       NF_FRESH = 0,
+       NF_READ = 1,
+       NF_GET = 2,
+       NF_PREFETCH = 3
+};
+
 /*
  * Allocate a new buffer. If the allocation is not possible, wait until
  * some other thread frees a buffer.
  *
  * May drop the lock and regain it.
  */
-static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c)
+static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf)
 {
        struct dm_buffer *b;
 
@@ -726,6 +733,9 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client
                                return b;
                }
 
+               if (nf == NF_PREFETCH)
+                       return NULL;
+
                if (!list_empty(&c->reserved_buffers)) {
                        b = list_entry(c->reserved_buffers.next,
                                       struct dm_buffer, lru_list);
@@ -743,9 +753,12 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client
        }
 }
 
-static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c)
+static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c, enum new_flag nf)
 {
-       struct dm_buffer *b = __alloc_buffer_wait_no_callback(c);
+       struct dm_buffer *b = __alloc_buffer_wait_no_callback(c, nf);
+
+       if (!b)
+               return NULL;
 
        if (c->alloc_callback)
                c->alloc_callback(b);
@@ -865,32 +878,23 @@ static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
  * Getting a buffer
  *--------------------------------------------------------------*/
 
-enum new_flag {
-       NF_FRESH = 0,
-       NF_READ = 1,
-       NF_GET = 2
-};
-
 static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
-                                    enum new_flag nf, struct dm_buffer **bp,
-                                    int *need_submit)
+                                    enum new_flag nf, int *need_submit)
 {
        struct dm_buffer *b, *new_b = NULL;
 
        *need_submit = 0;
 
        b = __find(c, block);
-       if (b) {
-               b->hold_count++;
-               __relink_lru(b, test_bit(B_DIRTY, &b->state) ||
-                            test_bit(B_WRITING, &b->state));
-               return b;
-       }
+       if (b)
+               goto found_buffer;
 
        if (nf == NF_GET)
                return NULL;
 
-       new_b = __alloc_buffer_wait(c);
+       new_b = __alloc_buffer_wait(c, nf);
+       if (!new_b)
+               return NULL;
 
        /*
         * We've had a period where the mutex was unlocked, so need to
@@ -899,10 +903,7 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
        b = __find(c, block);
        if (b) {
                __free_buffer_wake(new_b);
-               b->hold_count++;
-               __relink_lru(b, test_bit(B_DIRTY, &b->state) ||
-                            test_bit(B_WRITING, &b->state));
-               return b;
+               goto found_buffer;
        }
 
        __check_watermark(c);
@@ -922,6 +923,24 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
        *need_submit = 1;
 
        return b;
+
+found_buffer:
+       if (nf == NF_PREFETCH)
+               return NULL;
+       /*
+        * Note: it is essential that we don't wait for the buffer to be
+        * read if dm_bufio_get function is used. Both dm_bufio_get and
+        * dm_bufio_prefetch can be used in the driver request routine.
+        * If the user called both dm_bufio_prefetch and dm_bufio_get on
+        * the same buffer, it would deadlock if we waited.
+        */
+       if (nf == NF_GET && unlikely(test_bit(B_READING, &b->state)))
+               return NULL;
+
+       b->hold_count++;
+       __relink_lru(b, test_bit(B_DIRTY, &b->state) ||
+                    test_bit(B_WRITING, &b->state));
+       return b;
 }
 
 /*
@@ -956,10 +975,10 @@ static void *new_read(struct dm_bufio_client *c, sector_t block,
        struct dm_buffer *b;
 
        dm_bufio_lock(c);
-       b = __bufio_new(c, block, nf, bp, &need_submit);
+       b = __bufio_new(c, block, nf, &need_submit);
        dm_bufio_unlock(c);
 
-       if (!b || IS_ERR(b))
+       if (!b)
                return b;
 
        if (need_submit)
@@ -1005,13 +1024,47 @@ void *dm_bufio_new(struct dm_bufio_client *c, sector_t block,
 }
 EXPORT_SYMBOL_GPL(dm_bufio_new);
 
+void dm_bufio_prefetch(struct dm_bufio_client *c,
+                      sector_t block, unsigned n_blocks)
+{
+       struct blk_plug plug;
+
+       blk_start_plug(&plug);
+       dm_bufio_lock(c);
+
+       for (; n_blocks--; block++) {
+               int need_submit;
+               struct dm_buffer *b;
+               b = __bufio_new(c, block, NF_PREFETCH, &need_submit);
+               if (unlikely(b != NULL)) {
+                       dm_bufio_unlock(c);
+
+                       if (need_submit)
+                               submit_io(b, READ, b->block, read_endio);
+                       dm_bufio_release(b);
+
+                       dm_bufio_cond_resched();
+
+                       if (!n_blocks)
+                               goto flush_plug;
+                       dm_bufio_lock(c);
+               }
+
+       }
+
+       dm_bufio_unlock(c);
+
+flush_plug:
+       blk_finish_plug(&plug);
+}
+EXPORT_SYMBOL_GPL(dm_bufio_prefetch);
+
 void dm_bufio_release(struct dm_buffer *b)
 {
        struct dm_bufio_client *c = b->c;
 
        dm_bufio_lock(c);
 
-       BUG_ON(test_bit(B_READING, &b->state));
        BUG_ON(!b->hold_count);
 
        b->hold_count--;
@@ -1024,6 +1077,7 @@ void dm_bufio_release(struct dm_buffer *b)
                 * invalid buffer.
                 */
                if ((b->read_error || b->write_error) &&
+                   !test_bit(B_READING, &b->state) &&
                    !test_bit(B_WRITING, &b->state) &&
                    !test_bit(B_DIRTY, &b->state)) {
                        __unlink_buffer(b);
@@ -1041,6 +1095,8 @@ void dm_bufio_mark_buffer_dirty(struct dm_buffer *b)
 
        dm_bufio_lock(c);
 
+       BUG_ON(test_bit(B_READING, &b->state));
+
        if (!test_and_set_bit(B_DIRTY, &b->state))
                __relink_lru(b, LIST_DIRTY);
 
index 5c4c3a0..b142946 100644 (file)
@@ -63,6 +63,14 @@ void *dm_bufio_new(struct dm_bufio_client *c, sector_t block,
                   struct dm_buffer **bp);
 
 /*
+ * Prefetch the specified blocks to the cache.
+ * The function starts to read the blocks and returns without waiting for
+ * I/O to finish.
+ */
+void dm_bufio_prefetch(struct dm_bufio_client *c,
+                      sector_t block, unsigned n_blocks);
+
+/*
  * Release a reference obtained with dm_bufio_{read,get,new}. The data
  * pointer and dm_buffer pointer is no longer valid after this call.
  */
index db6b516..3f06df5 100644 (file)
@@ -176,7 +176,6 @@ struct crypt_config {
 
 #define MIN_IOS        16
 #define MIN_POOL_PAGES 32
-#define MIN_BIO_PAGES  8
 
 static struct kmem_cache *_crypt_io_pool;
 
@@ -848,12 +847,11 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size,
                }
 
                /*
-                * if additional pages cannot be allocated without waiting,
-                * return a partially allocated bio, the caller will then try
-                * to allocate additional bios while submitting this partial bio
+                * If additional pages cannot be allocated without waiting,
+                * return a partially-allocated bio.  The caller will then try
+                * to allocate more bios while submitting this partial bio.
                 */
-               if (i == (MIN_BIO_PAGES - 1))
-                       gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
+               gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
 
                len = (size > PAGE_SIZE) ? PAGE_SIZE : size;
 
@@ -1046,16 +1044,14 @@ static void kcryptd_queue_io(struct dm_crypt_io *io)
        queue_work(cc->io_queue, &io->work);
 }
 
-static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io,
-                                         int error, int async)
+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;
 
-       if (unlikely(error < 0)) {
+       if (unlikely(io->error < 0)) {
                crypt_free_buffer_pages(cc, clone);
                bio_put(clone);
-               io->error = -EIO;
                crypt_dec_pending(io);
                return;
        }
@@ -1106,12 +1102,16 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
                sector += bio_sectors(clone);
 
                crypt_inc_pending(io);
+
                r = crypt_convert(cc, &io->ctx);
+               if (r < 0)
+                       io->error = -EIO;
+
                crypt_finished = atomic_dec_and_test(&io->ctx.pending);
 
                /* Encryption was already finished, submit io now */
                if (crypt_finished) {
-                       kcryptd_crypt_write_io_submit(io, r, 0);
+                       kcryptd_crypt_write_io_submit(io, 0);
 
                        /*
                         * If there was an error, do not try next fragments.
@@ -1162,11 +1162,8 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
        crypt_dec_pending(io);
 }
 
-static void kcryptd_crypt_read_done(struct dm_crypt_io *io, int error)
+static void kcryptd_crypt_read_done(struct dm_crypt_io *io)
 {
-       if (unlikely(error < 0))
-               io->error = -EIO;
-
        crypt_dec_pending(io);
 }
 
@@ -1181,9 +1178,11 @@ static void kcryptd_crypt_read_convert(struct dm_crypt_io *io)
                           io->sector);
 
        r = crypt_convert(cc, &io->ctx);
+       if (r < 0)
+               io->error = -EIO;
 
        if (atomic_dec_and_test(&io->ctx.pending))
-               kcryptd_crypt_read_done(io, r);
+               kcryptd_crypt_read_done(io);
 
        crypt_dec_pending(io);
 }
@@ -1204,15 +1203,18 @@ static void kcryptd_async_done(struct crypto_async_request *async_req,
        if (!error && cc->iv_gen_ops && cc->iv_gen_ops->post)
                error = cc->iv_gen_ops->post(cc, iv_of_dmreq(cc, dmreq), dmreq);
 
+       if (error < 0)
+               io->error = -EIO;
+
        mempool_free(req_of_dmreq(cc, dmreq), cc->req_pool);
 
        if (!atomic_dec_and_test(&ctx->pending))
                return;
 
        if (bio_data_dir(io->base_bio) == READ)
-               kcryptd_crypt_read_done(io, error);
+               kcryptd_crypt_read_done(io);
        else
-               kcryptd_crypt_write_io_submit(io, error, 1);
+               kcryptd_crypt_write_io_submit(io, 1);
 }
 
 static void kcryptd_crypt(struct work_struct *work)
@@ -1413,6 +1415,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,
        char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount;
        char *cipher_api = NULL;
        int cpu, ret = -EINVAL;
+       char dummy;
 
        /* Convert to crypto api definition? */
        if (strchr(cipher_in, '(')) {
@@ -1434,7 +1437,7 @@ static int crypt_ctr_cipher(struct dm_target *ti,
 
        if (!keycount)
                cc->tfms_count = 1;
-       else if (sscanf(keycount, "%u", &cc->tfms_count) != 1 ||
+       else if (sscanf(keycount, "%u%c", &cc->tfms_count, &dummy) != 1 ||
                 !is_power_of_2(cc->tfms_count)) {
                ti->error = "Bad cipher key count specification";
                return -EINVAL;
@@ -1579,6 +1582,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        int ret;
        struct dm_arg_set as;
        const char *opt_string;
+       char dummy;
 
        static struct dm_arg _args[] = {
                {0, 1, "Invalid number of feature args"},
@@ -1636,7 +1640,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
 
        ret = -EINVAL;
-       if (sscanf(argv[2], "%llu", &tmpll) != 1) {
+       if (sscanf(argv[2], "%llu%c", &tmpll, &dummy) != 1) {
                ti->error = "Invalid iv_offset sector";
                goto bad;
        }
@@ -1647,7 +1651,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad;
        }
 
-       if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+       if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
                ti->error = "Invalid device sector";
                goto bad;
        }
index f18375d..2dc22dd 100644 (file)
@@ -131,6 +131,7 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
        struct delay_c *dc;
        unsigned long long tmpll;
+       char dummy;
 
        if (argc != 3 && argc != 6) {
                ti->error = "requires exactly 3 or 6 arguments";
@@ -145,13 +146,13 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        dc->reads = dc->writes = 0;
 
-       if (sscanf(argv[1], "%llu", &tmpll) != 1) {
+       if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1) {
                ti->error = "Invalid device sector";
                goto bad;
        }
        dc->start_read = tmpll;
 
-       if (sscanf(argv[2], "%u", &dc->read_delay) != 1) {
+       if (sscanf(argv[2], "%u%c", &dc->read_delay, &dummy) != 1) {
                ti->error = "Invalid delay";
                goto bad;
        }
@@ -166,13 +167,13 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        if (argc == 3)
                goto out;
 
-       if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+       if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
                ti->error = "Invalid write device sector";
                goto bad_dev_read;
        }
        dc->start_write = tmpll;
 
-       if (sscanf(argv[5], "%u", &dc->write_delay) != 1) {
+       if (sscanf(argv[5], "%u%c", &dc->write_delay, &dummy) != 1) {
                ti->error = "Invalid write delay";
                goto bad_dev_read;
        }
index 042e719..aa70f7d 100644 (file)
@@ -283,7 +283,7 @@ int dm_exception_store_init(void)
        return 0;
 
 persistent_fail:
-       dm_persistent_snapshot_exit();
+       dm_transient_snapshot_exit();
 transient_fail:
        return r;
 }
index b280c43..ac49c01 100644 (file)
@@ -160,6 +160,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        unsigned long long tmpll;
        struct dm_arg_set as;
        const char *devname;
+       char dummy;
 
        as.argc = argc;
        as.argv = argv;
@@ -178,7 +179,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        devname = dm_shift_arg(&as);
 
-       if (sscanf(dm_shift_arg(&as), "%llu", &tmpll) != 1) {
+       if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1) {
                ti->error = "Invalid device sector";
                goto bad;
        }
index 1ce84ed..a1a3e6d 100644 (file)
@@ -880,6 +880,7 @@ static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
        struct hd_geometry geometry;
        unsigned long indata[4];
        char *geostr = (char *) param + param->data_start;
+       char dummy;
 
        md = find_device(param);
        if (!md)
@@ -891,8 +892,8 @@ static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
                goto out;
        }
 
-       x = sscanf(geostr, "%lu %lu %lu %lu", indata,
-                  indata + 1, indata + 2, indata + 3);
+       x = sscanf(geostr, "%lu %lu %lu %lu%c", indata,
+                  indata + 1, indata + 2, indata + 3, &dummy);
 
        if (x != 4) {
                DMWARN("Unable to interpret geometry settings.");
index 9728839..3639eea 100644 (file)
@@ -29,6 +29,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
        struct linear_c *lc;
        unsigned long long tmp;
+       char dummy;
 
        if (argc != 2) {
                ti->error = "Invalid argument count";
@@ -41,7 +42,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                return -ENOMEM;
        }
 
-       if (sscanf(argv[1], "%llu", &tmp) != 1) {
+       if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1) {
                ti->error = "dm-linear: Invalid device sector";
                goto bad;
        }
index 3b52bb7..65ebaeb 100644 (file)
@@ -369,6 +369,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
        unsigned int region_count;
        size_t bitset_size, buf_size;
        int r;
+       char dummy;
 
        if (argc < 1 || argc > 2) {
                DMWARN("wrong number of arguments to dirty region log");
@@ -387,7 +388,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
                }
        }
 
-       if (sscanf(argv[0], "%u", &region_size) != 1 ||
+       if (sscanf(argv[0], "%u%c", &region_size, &dummy) != 1 ||
            !_check_region_size(ti, region_size)) {
                DMWARN("invalid region size %s", argv[0]);
                return -EINVAL;
index 801d92d..922a338 100644 (file)
@@ -226,6 +226,27 @@ static void free_multipath(struct multipath *m)
        kfree(m);
 }
 
+static int set_mapinfo(struct multipath *m, union map_info *info)
+{
+       struct dm_mpath_io *mpio;
+
+       mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
+       if (!mpio)
+               return -ENOMEM;
+
+       memset(mpio, 0, sizeof(*mpio));
+       info->ptr = mpio;
+
+       return 0;
+}
+
+static void clear_mapinfo(struct multipath *m, union map_info *info)
+{
+       struct dm_mpath_io *mpio = info->ptr;
+
+       info->ptr = NULL;
+       mempool_free(mpio, m->mpio_pool);
+}
 
 /*-----------------------------------------------
  * Path selection
@@ -341,13 +362,14 @@ static int __must_push_back(struct multipath *m)
 }
 
 static int map_io(struct multipath *m, struct request *clone,
-                 struct dm_mpath_io *mpio, unsigned was_queued)
+                 union map_info *map_context, unsigned was_queued)
 {
        int r = DM_MAPIO_REMAPPED;
        size_t nr_bytes = blk_rq_bytes(clone);
        unsigned long flags;
        struct pgpath *pgpath;
        struct block_device *bdev;
+       struct dm_mpath_io *mpio = map_context->ptr;
 
        spin_lock_irqsave(&m->lock, flags);
 
@@ -423,7 +445,6 @@ static void dispatch_queued_ios(struct multipath *m)
 {
        int r;
        unsigned long flags;
-       struct dm_mpath_io *mpio;
        union map_info *info;
        struct request *clone, *n;
        LIST_HEAD(cl);
@@ -436,16 +457,15 @@ static void dispatch_queued_ios(struct multipath *m)
                list_del_init(&clone->queuelist);
 
                info = dm_get_rq_mapinfo(clone);
-               mpio = info->ptr;
 
-               r = map_io(m, clone, mpio, 1);
+               r = map_io(m, clone, info, 1);
                if (r < 0) {
-                       mempool_free(mpio, m->mpio_pool);
+                       clear_mapinfo(m, info);
                        dm_kill_unmapped_request(clone, r);
                } else if (r == DM_MAPIO_REMAPPED)
                        dm_dispatch_request(clone);
                else if (r == DM_MAPIO_REQUEUE) {
-                       mempool_free(mpio, m->mpio_pool);
+                       clear_mapinfo(m, info);
                        dm_requeue_unmapped_request(clone);
                }
        }
@@ -908,20 +928,16 @@ static int multipath_map(struct dm_target *ti, struct request *clone,
                         union map_info *map_context)
 {
        int r;
-       struct dm_mpath_io *mpio;
        struct multipath *m = (struct multipath *) ti->private;
 
-       mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
-       if (!mpio)
+       if (set_mapinfo(m, map_context) < 0)
                /* ENOMEM, requeue */
                return DM_MAPIO_REQUEUE;
-       memset(mpio, 0, sizeof(*mpio));
 
-       map_context->ptr = mpio;
        clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
-       r = map_io(m, clone, mpio, 0);
+       r = map_io(m, clone, map_context, 0);
        if (r < 0 || r == DM_MAPIO_REQUEUE)
-               mempool_free(mpio, m->mpio_pool);
+               clear_mapinfo(m, map_context);
 
        return r;
 }
@@ -1054,8 +1070,9 @@ static int switch_pg_num(struct multipath *m, const char *pgstr)
        struct priority_group *pg;
        unsigned pgnum;
        unsigned long flags;
+       char dummy;
 
-       if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
+       if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||
            (pgnum > m->nr_priority_groups)) {
                DMWARN("invalid PG number supplied to switch_pg_num");
                return -EINVAL;
@@ -1085,8 +1102,9 @@ static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed)
 {
        struct priority_group *pg;
        unsigned pgnum;
+       char dummy;
 
-       if (!pgstr || (sscanf(pgstr, "%u", &pgnum) != 1) || !pgnum ||
+       if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||
            (pgnum > m->nr_priority_groups)) {
                DMWARN("invalid PG number supplied to bypass_pg");
                return -EINVAL;
@@ -1261,13 +1279,15 @@ static int multipath_end_io(struct dm_target *ti, struct request *clone,
        struct path_selector *ps;
        int r;
 
+       BUG_ON(!mpio);
+
        r  = do_end_io(m, clone, error, mpio);
        if (pgpath) {
                ps = &pgpath->pg->ps;
                if (ps->type->end_io)
                        ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes);
        }
-       mempool_free(mpio, m->mpio_pool);
+       clear_mapinfo(m, map_context);
 
        return r;
 }
index 03a837a..3941fae 100644 (file)
@@ -112,6 +112,7 @@ static int ql_add_path(struct path_selector *ps, struct dm_path *path,
        struct selector *s = ps->context;
        struct path_info *pi;
        unsigned repeat_count = QL_MIN_IO;
+       char dummy;
 
        /*
         * Arguments: [<repeat_count>]
@@ -123,7 +124,7 @@ static int ql_add_path(struct path_selector *ps, struct dm_path *path,
                return -EINVAL;
        }
 
-       if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+       if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
                *error = "queue-length ps: invalid repeat count";
                return -EINVAL;
        }
index c5a875d..b0ba524 100644 (file)
@@ -604,7 +604,9 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
                return 0;
 
        if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, 1)) {
-               DMERR("Failed to read device superblock");
+               DMERR("Failed to read superblock of device at position %d",
+                     rdev->raid_disk);
+               set_bit(Faulty, &rdev->flags);
                return -EINVAL;
        }
 
@@ -855,9 +857,25 @@ static int super_validate(struct mddev *mddev, struct md_rdev *rdev)
 static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
 {
        int ret;
+       unsigned redundancy = 0;
+       struct raid_dev *dev;
        struct md_rdev *rdev, *freshest;
        struct mddev *mddev = &rs->md;
 
+       switch (rs->raid_type->level) {
+       case 1:
+               redundancy = rs->md.raid_disks - 1;
+               break;
+       case 4:
+       case 5:
+       case 6:
+               redundancy = rs->raid_type->parity_devs;
+               break;
+       default:
+               ti->error = "Unknown RAID type";
+               return -EINVAL;
+       }
+
        freshest = NULL;
        rdev_for_each(rdev, mddev) {
                if (!rdev->meta_bdev)
@@ -872,6 +890,37 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
                case 0:
                        break;
                default:
+                       dev = container_of(rdev, struct raid_dev, rdev);
+                       if (redundancy--) {
+                               if (dev->meta_dev)
+                                       dm_put_device(ti, dev->meta_dev);
+
+                               dev->meta_dev = NULL;
+                               rdev->meta_bdev = NULL;
+
+                               if (rdev->sb_page)
+                                       put_page(rdev->sb_page);
+
+                               rdev->sb_page = NULL;
+
+                               rdev->sb_loaded = 0;
+
+                               /*
+                                * We might be able to salvage the data device
+                                * even though the meta device has failed.  For
+                                * now, we behave as though '- -' had been
+                                * set for this device in the table.
+                                */
+                               if (dev->data_dev)
+                                       dm_put_device(ti, dev->data_dev);
+
+                               dev->data_dev = NULL;
+                               rdev->bdev = NULL;
+
+                               list_del(&rdev->same_set);
+
+                               continue;
+                       }
                        ti->error = "Failed to load superblock";
                        return ret;
                }
@@ -1214,7 +1263,7 @@ static void raid_resume(struct dm_target *ti)
 
 static struct target_type raid_target = {
        .name = "raid",
-       .version = {1, 1, 0},
+       .version = {1, 2, 0},
        .module = THIS_MODULE,
        .ctr = raid_ctr,
        .dtr = raid_dtr,
index 9bfd057..d039de8 100644 (file)
@@ -924,8 +924,9 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
                      unsigned int mirror, char **argv)
 {
        unsigned long long offset;
+       char dummy;
 
-       if (sscanf(argv[1], "%llu", &offset) != 1) {
+       if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1) {
                ti->error = "Invalid offset";
                return -EINVAL;
        }
@@ -953,13 +954,14 @@ static struct dm_dirty_log *create_dirty_log(struct dm_target *ti,
 {
        unsigned param_count;
        struct dm_dirty_log *dl;
+       char dummy;
 
        if (argc < 2) {
                ti->error = "Insufficient mirror log arguments";
                return NULL;
        }
 
-       if (sscanf(argv[1], "%u", &param_count) != 1) {
+       if (sscanf(argv[1], "%u%c", &param_count, &dummy) != 1) {
                ti->error = "Invalid mirror log argument count";
                return NULL;
        }
@@ -986,13 +988,14 @@ static int parse_features(struct mirror_set *ms, unsigned argc, char **argv,
 {
        unsigned num_features;
        struct dm_target *ti = ms->ti;
+       char dummy;
 
        *args_used = 0;
 
        if (!argc)
                return 0;
 
-       if (sscanf(argv[0], "%u", &num_features) != 1) {
+       if (sscanf(argv[0], "%u%c", &num_features, &dummy) != 1) {
                ti->error = "Invalid number of features";
                return -EINVAL;
        }
@@ -1036,6 +1039,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        unsigned int nr_mirrors, m, args_used;
        struct mirror_set *ms;
        struct dm_dirty_log *dl;
+       char dummy;
 
        dl = create_dirty_log(ti, argc, argv, &args_used);
        if (!dl)
@@ -1044,7 +1048,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        argv += args_used;
        argc -= args_used;
 
-       if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 ||
+       if (!argc || sscanf(argv[0], "%u%c", &nr_mirrors, &dummy) != 1 ||
            nr_mirrors < 2 || nr_mirrors > DM_KCOPYD_MAX_REGIONS + 1) {
                ti->error = "Invalid number of mirrors";
                dm_dirty_log_destroy(dl);
index 27f1d42..6ab1192 100644 (file)
@@ -114,6 +114,7 @@ static int rr_add_path(struct path_selector *ps, struct dm_path *path,
        struct selector *s = (struct selector *) ps->context;
        struct path_info *pi;
        unsigned repeat_count = RR_MIN_IO;
+       char dummy;
 
        if (argc > 1) {
                *error = "round-robin ps: incorrect number of arguments";
@@ -121,7 +122,7 @@ static int rr_add_path(struct path_selector *ps, struct dm_path *path,
        }
 
        /* First path argument is number of I/Os before switching path */
-       if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+       if ((argc == 1) && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
                *error = "round-robin ps: invalid repeat count";
                return -EINVAL;
        }
index 59883bd..9df8f6b 100644 (file)
@@ -110,6 +110,7 @@ static int st_add_path(struct path_selector *ps, struct dm_path *path,
        struct path_info *pi;
        unsigned repeat_count = ST_MIN_IO;
        unsigned relative_throughput = 1;
+       char dummy;
 
        /*
         * Arguments: [<repeat_count> [<relative_throughput>]]
@@ -128,13 +129,13 @@ static int st_add_path(struct path_selector *ps, struct dm_path *path,
                return -EINVAL;
        }
 
-       if (argc && (sscanf(argv[0], "%u", &repeat_count) != 1)) {
+       if (argc && (sscanf(argv[0], "%u%c", &repeat_count, &dummy) != 1)) {
                *error = "service-time ps: invalid repeat count";
                return -EINVAL;
        }
 
        if ((argc == 2) &&
-           (sscanf(argv[1], "%u", &relative_throughput) != 1 ||
+           (sscanf(argv[1], "%u%c", &relative_throughput, &dummy) != 1 ||
             relative_throughput > ST_MAX_RELATIVE_THROUGHPUT)) {
                *error = "service-time ps: invalid relative_throughput value";
                return -EINVAL;
index 3d80cf0..35c94ff 100644 (file)
@@ -75,8 +75,9 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
                      unsigned int stripe, char **argv)
 {
        unsigned long long start;
+       char dummy;
 
-       if (sscanf(argv[1], "%llu", &start) != 1)
+       if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1)
                return -EINVAL;
 
        if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
index 63cc542..2e227fb 100644 (file)
@@ -268,8 +268,7 @@ void dm_table_destroy(struct dm_table *t)
        vfree(t->highs);
 
        /* free the device list */
-       if (t->devices.next != &t->devices)
-               free_devices(&t->devices);
+       free_devices(&t->devices);
 
        dm_free_md_mempools(t->mempools);
 
@@ -464,10 +463,11 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
        struct dm_dev_internal *dd;
        unsigned int major, minor;
        struct dm_table *t = ti->table;
+       char dummy;
 
        BUG_ON(!t);
 
-       if (sscanf(path, "%u:%u", &major, &minor) == 2) {
+       if (sscanf(path, "%u:%u%c", &major, &minor, &dummy) == 2) {
                /* Extract the major/minor numbers */
                dev = MKDEV(major, minor);
                if (MAJOR(dev) != major || MINOR(dev) != minor)
@@ -842,9 +842,10 @@ static int validate_next_arg(struct dm_arg *arg, struct dm_arg_set *arg_set,
                             unsigned *value, char **error, unsigned grouped)
 {
        const char *arg_str = dm_shift_arg(arg_set);
+       char dummy;
 
        if (!arg_str ||
-           (sscanf(arg_str, "%u", value) != 1) ||
+           (sscanf(arg_str, "%u%c", value, &dummy) != 1) ||
            (*value < arg->min) ||
            (*value > arg->max) ||
            (grouped && arg_set->argc < *value)) {
index 237571a..737d388 100644 (file)
@@ -614,7 +614,7 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
        if (r < 0)
                goto out;
 
-       r = dm_sm_root_size(pmd->metadata_sm, &data_len);
+       r = dm_sm_root_size(pmd->data_sm, &data_len);
        if (r < 0)
                goto out;
 
@@ -713,6 +713,9 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
        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);
index 859c168..ed4725e 100644 (file)
 
 #define THIN_METADATA_BLOCK_SIZE 4096
 
+/*
+ * The metadata device is currently limited in size.
+ *
+ * We have one block of index, which can hold 255 index entries.  Each
+ * index entry contains allocation info about 16k metadata blocks.
+ */
+#define THIN_METADATA_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT)))
+
+/*
+ * A metadata device larger than 16GB triggers a warning.
+ */
+#define THIN_METADATA_MAX_SECTORS_WARNING (16 * (1024 * 1024 * 1024 >> SECTOR_SHIFT))
+
 /*----------------------------------------------------------------*/
 
 struct dm_pool_metadata;
index c308757..213ae32 100644 (file)
@@ -23,6 +23,7 @@
 #define DEFERRED_SET_SIZE 64
 #define MAPPING_POOL_SIZE 1024
 #define PRISON_CELLS 1024
+#define COMMIT_PERIOD HZ
 
 /*
  * The block size of the device holding pool data must be
 #define DATA_DEV_BLOCK_SIZE_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT)
 
 /*
- * The metadata device is currently limited in size.  The limitation is
- * checked lower down in dm-space-map-metadata, but we also check it here
- * so we can fail early.
- *
- * We have one block of index, which can hold 255 index entries.  Each
- * index entry contains allocation info about 16k metadata blocks.
- */
-#define METADATA_DEV_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT)))
-
-/*
  * Device id is restricted to 24 bits.
  */
 #define MAX_DEV_ID ((1 << 24) - 1)
@@ -72,7 +63,7 @@
  * missed out if the io covers the block. (schedule_copy).
  *
  * iv) insert the new mapping into the origin's btree
- * (process_prepared_mappings).  This act of inserting breaks some
+ * (process_prepared_mapping).  This act of inserting breaks some
  * sharing of btree nodes between the two devices.  Breaking sharing only
  * effects the btree of that specific device.  Btrees for the other
  * devices that share the block never change.  The btree for the origin
@@ -124,7 +115,7 @@ struct cell {
        struct hlist_node list;
        struct bio_prison *prison;
        struct cell_key key;
-       unsigned count;
+       struct bio *holder;
        struct bio_list bios;
 };
 
@@ -220,54 +211,59 @@ static struct cell *__search_bucket(struct hlist_head *bucket,
  * This may block if a new cell needs allocating.  You must ensure that
  * cells will be unlocked even if the calling thread is blocked.
  *
- * Returns the number of entries in the cell prior to the new addition
- * or < 0 on failure.
+ * Returns 1 if the cell was already held, 0 if @inmate is the new holder.
  */
 static int bio_detain(struct bio_prison *prison, struct cell_key *key,
                      struct bio *inmate, struct cell **ref)
 {
-       int r;
+       int r = 1;
        unsigned long flags;
        uint32_t hash = hash_key(prison, key);
-       struct cell *uninitialized_var(cell), *cell2 = NULL;
+       struct cell *cell, *cell2;
 
        BUG_ON(hash > prison->nr_buckets);
 
        spin_lock_irqsave(&prison->lock, flags);
+
        cell = __search_bucket(prison->cells + hash, key);
+       if (cell) {
+               bio_list_add(&cell->bios, inmate);
+               goto out;
+       }
 
-       if (!cell) {
-               /*
-                * Allocate a new cell
-                */
-               spin_unlock_irqrestore(&prison->lock, flags);
-               cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
-               spin_lock_irqsave(&prison->lock, flags);
+       /*
+        * Allocate a new cell
+        */
+       spin_unlock_irqrestore(&prison->lock, flags);
+       cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
+       spin_lock_irqsave(&prison->lock, flags);
 
-               /*
-                * We've been unlocked, so we have to double check that
-                * nobody else has inserted this cell in the meantime.
-                */
-               cell = __search_bucket(prison->cells + hash, key);
+       /*
+        * We've been unlocked, so we have to double check that
+        * nobody else has inserted this cell in the meantime.
+        */
+       cell = __search_bucket(prison->cells + hash, key);
+       if (cell) {
+               mempool_free(cell2, prison->cell_pool);
+               bio_list_add(&cell->bios, inmate);
+               goto out;
+       }
 
-               if (!cell) {
-                       cell = cell2;
-                       cell2 = NULL;
+       /*
+        * Use new cell.
+        */
+       cell = cell2;
 
-                       cell->prison = prison;
-                       memcpy(&cell->key, key, sizeof(cell->key));
-                       cell->count = 0;
-                       bio_list_init(&cell->bios);
-                       hlist_add_head(&cell->list, prison->cells + hash);
-               }
-       }
+       cell->prison = prison;
+       memcpy(&cell->key, key, sizeof(cell->key));
+       cell->holder = inmate;
+       bio_list_init(&cell->bios);
+       hlist_add_head(&cell->list, prison->cells + hash);
 
-       r = cell->count++;
-       bio_list_add(&cell->bios, inmate);
-       spin_unlock_irqrestore(&prison->lock, flags);
+       r = 0;
 
-       if (cell2)
-               mempool_free(cell2, prison->cell_pool);
+out:
+       spin_unlock_irqrestore(&prison->lock, flags);
 
        *ref = cell;
 
@@ -283,8 +279,8 @@ static void __cell_release(struct cell *cell, struct bio_list *inmates)
 
        hlist_del(&cell->list);
 
-       if (inmates)
-               bio_list_merge(inmates, &cell->bios);
+       bio_list_add(inmates, cell->holder);
+       bio_list_merge(inmates, &cell->bios);
 
        mempool_free(cell, prison->cell_pool);
 }
@@ -305,22 +301,44 @@ static void cell_release(struct cell *cell, struct bio_list *bios)
  * bio may be in the cell.  This function releases the cell, and also does
  * a sanity check.
  */
+static void __cell_release_singleton(struct cell *cell, struct bio *bio)
+{
+       hlist_del(&cell->list);
+       BUG_ON(cell->holder != bio);
+       BUG_ON(!bio_list_empty(&cell->bios));
+}
+
 static void cell_release_singleton(struct cell *cell, struct bio *bio)
 {
-       struct bio_prison *prison = cell->prison;
-       struct bio_list bios;
-       struct bio *b;
        unsigned long flags;
-
-       bio_list_init(&bios);
+       struct bio_prison *prison = cell->prison;
 
        spin_lock_irqsave(&prison->lock, flags);
-       __cell_release(cell, &bios);
+       __cell_release_singleton(cell, bio);
        spin_unlock_irqrestore(&prison->lock, flags);
+}
+
+/*
+ * Sometimes we don't want the holder, just the additional bios.
+ */
+static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
+{
+       struct bio_prison *prison = cell->prison;
+
+       hlist_del(&cell->list);
+       bio_list_merge(inmates, &cell->bios);
 
-       b = bio_list_pop(&bios);
-       BUG_ON(b != bio);
-       BUG_ON(!bio_list_empty(&bios));
+       mempool_free(cell, prison->cell_pool);
+}
+
+static void cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
+{
+       unsigned long flags;
+       struct bio_prison *prison = cell->prison;
+
+       spin_lock_irqsave(&prison->lock, flags);
+       __cell_release_no_holder(cell, inmates);
+       spin_unlock_irqrestore(&prison->lock, flags);
 }
 
 static void cell_error(struct cell *cell)
@@ -471,6 +489,13 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
  * devices.
  */
 struct new_mapping;
+
+struct pool_features {
+       unsigned zero_new_blocks:1;
+       unsigned discard_enabled:1;
+       unsigned discard_passdown:1;
+};
+
 struct pool {
        struct list_head list;
        struct dm_target *ti;   /* Only set if a pool target is bound */
@@ -484,7 +509,7 @@ struct pool {
        dm_block_t offset_mask;
        dm_block_t low_water_blocks;
 
-       unsigned zero_new_blocks:1;
+       struct pool_features pf;
        unsigned low_water_triggered:1; /* A dm event has been sent */
        unsigned no_free_space:1;       /* A -ENOSPC warning has been issued */
 
@@ -493,17 +518,21 @@ struct pool {
 
        struct workqueue_struct *wq;
        struct work_struct worker;
+       struct delayed_work waker;
 
        unsigned ref_count;
+       unsigned long last_commit_jiffies;
 
        spinlock_t lock;
        struct bio_list deferred_bios;
        struct bio_list deferred_flush_bios;
        struct list_head prepared_mappings;
+       struct list_head prepared_discards;
 
        struct bio_list retry_on_resume_list;
 
-       struct deferred_set ds; /* FIXME: move to thin_c */
+       struct deferred_set shared_read_ds;
+       struct deferred_set all_io_ds;
 
        struct new_mapping *next_mapping;
        mempool_t *mapping_pool;
@@ -521,7 +550,7 @@ struct pool_c {
        struct dm_target_callbacks callbacks;
 
        dm_block_t low_water_blocks;
-       unsigned zero_new_blocks:1;
+       struct pool_features pf;
 };
 
 /*
@@ -529,6 +558,7 @@ struct pool_c {
  */
 struct thin_c {
        struct dm_dev *pool_dev;
+       struct dm_dev *origin_dev;
        dm_thin_id dev_id;
 
        struct pool *pool;
@@ -597,6 +627,13 @@ static struct pool *__pool_table_lookup_metadata_dev(struct block_device *md_dev
 
 /*----------------------------------------------------------------*/
 
+struct endio_hook {
+       struct thin_c *tc;
+       struct deferred_entry *shared_read_entry;
+       struct deferred_entry *all_io_entry;
+       struct new_mapping *overwrite_mapping;
+};
+
 static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
 {
        struct bio *bio;
@@ -607,7 +644,8 @@ static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
        bio_list_init(master);
 
        while ((bio = bio_list_pop(&bios))) {
-               if (dm_get_mapinfo(bio)->ptr == tc)
+               struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+               if (h->tc == tc)
                        bio_endio(bio, DM_ENDIO_REQUEUE);
                else
                        bio_list_add(master, bio);
@@ -646,14 +684,16 @@ static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block)
                (bio->bi_sector & pool->offset_mask);
 }
 
-static void remap_and_issue(struct thin_c *tc, struct bio *bio,
-                           dm_block_t block)
+static void remap_to_origin(struct thin_c *tc, struct bio *bio)
+{
+       bio->bi_bdev = tc->origin_dev->bdev;
+}
+
+static void issue(struct thin_c *tc, struct bio *bio)
 {
        struct pool *pool = tc->pool;
        unsigned long flags;
 
-       remap(tc, bio, block);
-
        /*
         * Batch together any FUA/FLUSH bios we find and then issue
         * a single commit for them in process_deferred_bios().
@@ -666,6 +706,19 @@ static void remap_and_issue(struct thin_c *tc, struct bio *bio,
                generic_make_request(bio);
 }
 
+static void remap_to_origin_and_issue(struct thin_c *tc, struct bio *bio)
+{
+       remap_to_origin(tc, bio);
+       issue(tc, bio);
+}
+
+static void remap_and_issue(struct thin_c *tc, struct bio *bio,
+                           dm_block_t block)
+{
+       remap(tc, bio, block);
+       issue(tc, bio);
+}
+
 /*
  * wake_worker() is used when new work is queued and when pool_resume is
  * ready to continue deferred IO processing.
@@ -680,21 +733,17 @@ static void wake_worker(struct pool *pool)
 /*
  * Bio endio functions.
  */
-struct endio_hook {
-       struct thin_c *tc;
-       bio_end_io_t *saved_bi_end_io;
-       struct deferred_entry *entry;
-};
-
 struct new_mapping {
        struct list_head list;
 
-       int prepared;
+       unsigned quiesced:1;
+       unsigned prepared:1;
+       unsigned pass_discard:1;
 
        struct thin_c *tc;
        dm_block_t virt_block;
        dm_block_t data_block;
-       struct cell *cell;
+       struct cell *cell, *cell2;
        int err;
 
        /*
@@ -711,7 +760,7 @@ static void __maybe_add_mapping(struct new_mapping *m)
 {
        struct pool *pool = m->tc->pool;
 
-       if (list_empty(&m->list) && m->prepared) {
+       if (m->quiesced && m->prepared) {
                list_add(&m->list, &pool->prepared_mappings);
                wake_worker(pool);
        }
@@ -734,7 +783,8 @@ static void copy_complete(int read_err, unsigned long write_err, void *context)
 static void overwrite_endio(struct bio *bio, int err)
 {
        unsigned long flags;
-       struct new_mapping *m = dm_get_mapinfo(bio)->ptr;
+       struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+       struct new_mapping *m = h->overwrite_mapping;
        struct pool *pool = m->tc->pool;
 
        m->err = err;
@@ -745,31 +795,6 @@ static void overwrite_endio(struct bio *bio, int err)
        spin_unlock_irqrestore(&pool->lock, flags);
 }
 
-static void shared_read_endio(struct bio *bio, int err)
-{
-       struct list_head mappings;
-       struct new_mapping *m, *tmp;
-       struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
-       unsigned long flags;
-       struct pool *pool = h->tc->pool;
-
-       bio->bi_end_io = h->saved_bi_end_io;
-       bio_endio(bio, err);
-
-       INIT_LIST_HEAD(&mappings);
-       ds_dec(h->entry, &mappings);
-
-       spin_lock_irqsave(&pool->lock, flags);
-       list_for_each_entry_safe(m, tmp, &mappings, list) {
-               list_del(&m->list);
-               INIT_LIST_HEAD(&m->list);
-               __maybe_add_mapping(m);
-       }
-       spin_unlock_irqrestore(&pool->lock, flags);
-
-       mempool_free(h, pool->endio_hook_pool);
-}
-
 /*----------------------------------------------------------------*/
 
 /*
@@ -800,21 +825,16 @@ static void cell_defer(struct thin_c *tc, struct cell *cell,
  * Same as cell_defer above, except it omits one particular detainee,
  * a write bio that covers the block and has already been processed.
  */
-static void cell_defer_except(struct thin_c *tc, struct cell *cell,
-                             struct bio *exception)
+static void cell_defer_except(struct thin_c *tc, struct cell *cell)
 {
        struct bio_list bios;
-       struct bio *bio;
        struct pool *pool = tc->pool;
        unsigned long flags;
 
        bio_list_init(&bios);
-       cell_release(cell, &bios);
 
        spin_lock_irqsave(&pool->lock, flags);
-       while ((bio = bio_list_pop(&bios)))
-               if (bio != exception)
-                       bio_list_add(&pool->deferred_bios, bio);
+       cell_release_no_holder(cell, &pool->deferred_bios);
        spin_unlock_irqrestore(&pool->lock, flags);
 
        wake_worker(pool);
@@ -854,7 +874,7 @@ static void process_prepared_mapping(struct new_mapping *m)
         * the bios in the cell.
         */
        if (bio) {
-               cell_defer_except(tc, m->cell, bio);
+               cell_defer_except(tc, m->cell);
                bio_endio(bio, 0);
        } else
                cell_defer(tc, m->cell, m->data_block);
@@ -863,7 +883,30 @@ static void process_prepared_mapping(struct new_mapping *m)
        mempool_free(m, tc->pool->mapping_pool);
 }
 
-static void process_prepared_mappings(struct pool *pool)
+static void process_prepared_discard(struct 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");
+
+       /*
+        * Pass the discard down to the underlying device?
+        */
+       if (m->pass_discard)
+               remap_and_issue(tc, m->bio, m->data_block);
+       else
+               bio_endio(m->bio, 0);
+
+       cell_defer_except(tc, m->cell);
+       cell_defer_except(tc, m->cell2);
+       mempool_free(m, tc->pool->mapping_pool);
+}
+
+static void process_prepared(struct pool *pool, struct list_head *head,
+                            void (*fn)(struct new_mapping *))
 {
        unsigned long flags;
        struct list_head maps;
@@ -871,21 +914,27 @@ static void process_prepared_mappings(struct pool *pool)
 
        INIT_LIST_HEAD(&maps);
        spin_lock_irqsave(&pool->lock, flags);
-       list_splice_init(&pool->prepared_mappings, &maps);
+       list_splice_init(head, &maps);
        spin_unlock_irqrestore(&pool->lock, flags);
 
        list_for_each_entry_safe(m, tmp, &maps, list)
-               process_prepared_mapping(m);
+               fn(m);
 }
 
 /*
  * Deferred bio jobs.
  */
-static int io_overwrites_block(struct pool *pool, struct bio *bio)
+static int io_overlaps_block(struct pool *pool, struct bio *bio)
 {
-       return ((bio_data_dir(bio) == WRITE) &&
-               !(bio->bi_sector & pool->offset_mask)) &&
+       return !(bio->bi_sector & pool->offset_mask) &&
                (bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT));
+
+}
+
+static int io_overwrites_block(struct pool *pool, struct bio *bio)
+{
+       return (bio_data_dir(bio) == WRITE) &&
+               io_overlaps_block(pool, bio);
 }
 
 static void save_and_set_endio(struct bio *bio, bio_end_io_t **save,
@@ -917,7 +966,8 @@ static struct new_mapping *get_next_mapping(struct pool *pool)
 }
 
 static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
-                         dm_block_t data_origin, dm_block_t data_dest,
+                         struct dm_dev *origin, dm_block_t data_origin,
+                         dm_block_t data_dest,
                          struct cell *cell, struct bio *bio)
 {
        int r;
@@ -925,6 +975,7 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
        struct new_mapping *m = get_next_mapping(pool);
 
        INIT_LIST_HEAD(&m->list);
+       m->quiesced = 0;
        m->prepared = 0;
        m->tc = tc;
        m->virt_block = virt_block;
@@ -933,7 +984,8 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
        m->err = 0;
        m->bio = NULL;
 
-       ds_add_work(&pool->ds, &m->list);
+       if (!ds_add_work(&pool->shared_read_ds, &m->list))
+               m->quiesced = 1;
 
        /*
         * IO to pool_dev remaps to the pool target's data_dev.
@@ -942,14 +994,15 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
         * bio immediately. Otherwise we use kcopyd to clone the data first.
         */
        if (io_overwrites_block(pool, bio)) {
+               struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+               h->overwrite_mapping = m;
                m->bio = bio;
                save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
-               dm_get_mapinfo(bio)->ptr = m;
                remap_and_issue(tc, bio, data_dest);
        } else {
                struct dm_io_region from, to;
 
-               from.bdev = tc->pool_dev->bdev;
+               from.bdev = origin->bdev;
                from.sector = data_origin * pool->sectors_per_block;
                from.count = pool->sectors_per_block;
 
@@ -967,6 +1020,22 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
        }
 }
 
+static void schedule_internal_copy(struct thin_c *tc, dm_block_t virt_block,
+                                  dm_block_t data_origin, dm_block_t data_dest,
+                                  struct cell *cell, struct bio *bio)
+{
+       schedule_copy(tc, virt_block, tc->pool_dev,
+                     data_origin, data_dest, cell, bio);
+}
+
+static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block,
+                                  dm_block_t data_dest,
+                                  struct cell *cell, struct bio *bio)
+{
+       schedule_copy(tc, virt_block, tc->origin_dev,
+                     virt_block, data_dest, cell, bio);
+}
+
 static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
                          dm_block_t data_block, struct cell *cell,
                          struct bio *bio)
@@ -975,6 +1044,7 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
        struct new_mapping *m = get_next_mapping(pool);
 
        INIT_LIST_HEAD(&m->list);
+       m->quiesced = 1;
        m->prepared = 0;
        m->tc = tc;
        m->virt_block = virt_block;
@@ -988,13 +1058,14 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
         * zeroing pre-existing data, we can issue the bio immediately.
         * Otherwise we use kcopyd to zero the data first.
         */
-       if (!pool->zero_new_blocks)
+       if (!pool->pf.zero_new_blocks)
                process_prepared_mapping(m);
 
        else if (io_overwrites_block(pool, bio)) {
+               struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+               h->overwrite_mapping = m;
                m->bio = bio;
                save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
-               dm_get_mapinfo(bio)->ptr = m;
                remap_and_issue(tc, bio, data_block);
 
        } else {
@@ -1081,7 +1152,8 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
  */
 static void retry_on_resume(struct bio *bio)
 {
-       struct thin_c *tc = dm_get_mapinfo(bio)->ptr;
+       struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+       struct thin_c *tc = h->tc;
        struct pool *pool = tc->pool;
        unsigned long flags;
 
@@ -1102,6 +1174,86 @@ static void no_space(struct cell *cell)
                retry_on_resume(bio);
 }
 
+static void process_discard(struct thin_c *tc, struct bio *bio)
+{
+       int r;
+       struct pool *pool = tc->pool;
+       struct cell *cell, *cell2;
+       struct cell_key key, key2;
+       dm_block_t block = get_bio_block(tc, bio);
+       struct dm_thin_lookup_result lookup_result;
+       struct new_mapping *m;
+
+       build_virtual_key(tc->td, block, &key);
+       if (bio_detain(tc->pool->prison, &key, bio, &cell))
+               return;
+
+       r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
+       switch (r) {
+       case 0:
+               /*
+                * Check nobody is fiddling with this pool block.  This can
+                * happen if someone's in the process of breaking sharing
+                * on this block.
+                */
+               build_data_key(tc->td, lookup_result.block, &key2);
+               if (bio_detain(tc->pool->prison, &key2, bio, &cell2)) {
+                       cell_release_singleton(cell, bio);
+                       break;
+               }
+
+               if (io_overlaps_block(pool, bio)) {
+                       /*
+                        * IO may still be going to the destination block.  We must
+                        * quiesce before we can do the removal.
+                        */
+                       m = get_next_mapping(pool);
+                       m->tc = tc;
+                       m->pass_discard = (!lookup_result.shared) & pool->pf.discard_passdown;
+                       m->virt_block = block;
+                       m->data_block = lookup_result.block;
+                       m->cell = cell;
+                       m->cell2 = cell2;
+                       m->err = 0;
+                       m->bio = bio;
+
+                       if (!ds_add_work(&pool->all_io_ds, &m->list)) {
+                               list_add(&m->list, &pool->prepared_discards);
+                               wake_worker(pool);
+                       }
+               } 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.
+                        */
+                       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);
+                       remap_and_issue(tc, bio, lookup_result.block);
+               }
+               break;
+
+       case -ENODATA:
+               /*
+                * It isn't provisioned, just forget it.
+                */
+               cell_release_singleton(cell, bio);
+               bio_endio(bio, 0);
+               break;
+
+       default:
+               DMERR("discard: find block unexpectedly returned %d", r);
+               cell_release_singleton(cell, bio);
+               bio_io_error(bio);
+               break;
+       }
+}
+
 static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
                          struct cell_key *key,
                          struct dm_thin_lookup_result *lookup_result,
@@ -1113,8 +1265,8 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
        r = alloc_data_block(tc, &data_block);
        switch (r) {
        case 0:
-               schedule_copy(tc, block, lookup_result->block,
-                             data_block, cell, bio);
+               schedule_internal_copy(tc, block, lookup_result->block,
+                                      data_block, cell, bio);
                break;
 
        case -ENOSPC:
@@ -1147,13 +1299,9 @@ static void process_shared_bio(struct thin_c *tc, struct bio *bio,
        if (bio_data_dir(bio) == WRITE)
                break_sharing(tc, bio, block, &key, lookup_result, cell);
        else {
-               struct endio_hook *h;
-               h = mempool_alloc(pool->endio_hook_pool, GFP_NOIO);
+               struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
 
-               h->tc = tc;
-               h->entry = ds_inc(&pool->ds);
-               save_and_set_endio(bio, &h->saved_bi_end_io, shared_read_endio);
-               dm_get_mapinfo(bio)->ptr = h;
+               h->shared_read_entry = ds_inc(&pool->shared_read_ds);
 
                cell_release_singleton(cell, bio);
                remap_and_issue(tc, bio, lookup_result->block);
@@ -1188,7 +1336,10 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
        r = alloc_data_block(tc, &data_block);
        switch (r) {
        case 0:
-               schedule_zero(tc, block, data_block, cell, bio);
+               if (tc->origin_dev)
+                       schedule_external_copy(tc, block, data_block, cell, bio);
+               else
+                       schedule_zero(tc, block, data_block, cell, bio);
                break;
 
        case -ENOSPC:
@@ -1239,16 +1390,27 @@ static void process_bio(struct thin_c *tc, struct bio *bio)
                break;
 
        case -ENODATA:
-               provision_block(tc, bio, block, cell);
+               if (bio_data_dir(bio) == READ && tc->origin_dev) {
+                       cell_release_singleton(cell, bio);
+                       remap_to_origin_and_issue(tc, bio);
+               } else
+                       provision_block(tc, bio, block, cell);
                break;
 
        default:
                DMERR("dm_thin_find_block() failed, error = %d", r);
+               cell_release_singleton(cell, bio);
                bio_io_error(bio);
                break;
        }
 }
 
+static int need_commit_due_to_time(struct pool *pool)
+{
+       return jiffies < pool->last_commit_jiffies ||
+              jiffies > pool->last_commit_jiffies + COMMIT_PERIOD;
+}
+
 static void process_deferred_bios(struct pool *pool)
 {
        unsigned long flags;
@@ -1264,7 +1426,9 @@ static void process_deferred_bios(struct pool *pool)
        spin_unlock_irqrestore(&pool->lock, flags);
 
        while ((bio = bio_list_pop(&bios))) {
-               struct thin_c *tc = dm_get_mapinfo(bio)->ptr;
+               struct endio_hook *h = dm_get_mapinfo(bio)->ptr;
+               struct thin_c *tc = h->tc;
+
                /*
                 * If we've got no free new_mapping structs, and processing
                 * this bio might require one, we pause until there are some
@@ -1277,7 +1441,11 @@ static void process_deferred_bios(struct pool *pool)
 
                        break;
                }
-               process_bio(tc, bio);
+
+               if (bio->bi_rw & REQ_DISCARD)
+                       process_discard(tc, bio);
+               else
+                       process_bio(tc, bio);
        }
 
        /*
@@ -1290,7 +1458,7 @@ static void process_deferred_bios(struct pool *pool)
        bio_list_init(&pool->deferred_flush_bios);
        spin_unlock_irqrestore(&pool->lock, flags);
 
-       if (bio_list_empty(&bios))
+       if (bio_list_empty(&bios) && !need_commit_due_to_time(pool))
                return;
 
        r = dm_pool_commit_metadata(pool->pmd);
@@ -1301,6 +1469,7 @@ static void process_deferred_bios(struct pool *pool)
                        bio_io_error(bio);
                return;
        }
+       pool->last_commit_jiffies = jiffies;
 
        while ((bio = bio_list_pop(&bios)))
                generic_make_request(bio);
@@ -1310,10 +1479,22 @@ static void do_worker(struct work_struct *ws)
 {
        struct pool *pool = container_of(ws, struct pool, worker);
 
-       process_prepared_mappings(pool);
+       process_prepared(pool, &pool->prepared_mappings, process_prepared_mapping);
+       process_prepared(pool, &pool->prepared_discards, process_prepared_discard);
        process_deferred_bios(pool);
 }
 
+/*
+ * We want to commit periodically so that not too much
+ * unwritten data builds up.
+ */
+static void do_waker(struct work_struct *ws)
+{
+       struct pool *pool = container_of(to_delayed_work(ws), struct pool, waker);
+       wake_worker(pool);
+       queue_delayed_work(pool->wq, &pool->waker, COMMIT_PERIOD);
+}
+
 /*----------------------------------------------------------------*/
 
 /*
@@ -1335,6 +1516,19 @@ static void thin_defer_bio(struct thin_c *tc, struct bio *bio)
        wake_worker(pool);
 }
 
+static struct endio_hook *thin_hook_bio(struct thin_c *tc, struct bio *bio)
+{
+       struct pool *pool = tc->pool;
+       struct endio_hook *h = mempool_alloc(pool->endio_hook_pool, GFP_NOIO);
+
+       h->tc = tc;
+       h->shared_read_entry = NULL;
+       h->all_io_entry = bio->bi_rw & REQ_DISCARD ? NULL : ds_inc(&pool->all_io_ds);
+       h->overwrite_mapping = NULL;
+
+       return h;
+}
+
 /*
  * Non-blocking function called from the thin target's map function.
  */
@@ -1347,12 +1541,8 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio,
        struct dm_thin_device *td = tc->td;
        struct dm_thin_lookup_result result;
 
-       /*
-        * Save the thin context for easy access from the deferred bio later.
-        */
-       map_context->ptr = tc;
-
-       if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {
+       map_context->ptr = thin_hook_bio(tc, bio);
+       if (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA)) {
                thin_defer_bio(tc, bio);
                return DM_MAPIO_SUBMITTED;
        }
@@ -1434,7 +1624,7 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
 
        pool->ti = ti;
        pool->low_water_blocks = pt->low_water_blocks;
-       pool->zero_new_blocks = pt->zero_new_blocks;
+       pool->pf = pt->pf;
 
        return 0;
 }
@@ -1448,6 +1638,14 @@ static void unbind_control_target(struct pool *pool, struct dm_target *ti)
 /*----------------------------------------------------------------
  * Pool creation
  *--------------------------------------------------------------*/
+/* Initialize pool features. */
+static void pool_features_init(struct pool_features *pf)
+{
+       pf->zero_new_blocks = 1;
+       pf->discard_enabled = 1;
+       pf->discard_passdown = 1;
+}
+
 static void __pool_destroy(struct pool *pool)
 {
        __pool_table_remove(pool);
@@ -1495,7 +1693,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
        pool->block_shift = ffs(block_size) - 1;
        pool->offset_mask = block_size - 1;
        pool->low_water_blocks = 0;
-       pool->zero_new_blocks = 1;
+       pool_features_init(&pool->pf);
        pool->prison = prison_create(PRISON_CELLS);
        if (!pool->prison) {
                *error = "Error creating pool's bio prison";
@@ -1523,14 +1721,17 @@ static struct pool *pool_create(struct mapped_device *pool_md,
        }
 
        INIT_WORK(&pool->worker, do_worker);
+       INIT_DELAYED_WORK(&pool->waker, do_waker);
        spin_lock_init(&pool->lock);
        bio_list_init(&pool->deferred_bios);
        bio_list_init(&pool->deferred_flush_bios);
        INIT_LIST_HEAD(&pool->prepared_mappings);
+       INIT_LIST_HEAD(&pool->prepared_discards);
        pool->low_water_triggered = 0;
        pool->no_free_space = 0;
        bio_list_init(&pool->retry_on_resume_list);
-       ds_init(&pool->ds);
+       ds_init(&pool->shared_read_ds);
+       ds_init(&pool->all_io_ds);
 
        pool->next_mapping = NULL;
        pool->mapping_pool =
@@ -1549,6 +1750,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
                goto bad_endio_hook_pool;
        }
        pool->ref_count = 1;
+       pool->last_commit_jiffies = jiffies;
        pool->pool_md = pool_md;
        pool->md_dev = metadata_dev;
        __pool_table_insert(pool);
@@ -1588,7 +1790,8 @@ 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)
+                               unsigned long block_size, char **error,
+                               int *created)
 {
        struct pool *pool = __pool_table_lookup_metadata_dev(metadata_dev);
 
@@ -1604,8 +1807,10 @@ static struct pool *__pool_find(struct mapped_device *pool_md,
                                return ERR_PTR(-EINVAL);
                        __pool_inc(pool);
 
-               } else
+               } else {
                        pool = pool_create(pool_md, metadata_dev, block_size, error);
+                       *created = 1;
+               }
        }
 
        return pool;
@@ -1629,10 +1834,6 @@ static void pool_dtr(struct dm_target *ti)
        mutex_unlock(&dm_thin_pool_table.mutex);
 }
 
-struct pool_features {
-       unsigned zero_new_blocks:1;
-};
-
 static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
                               struct dm_target *ti)
 {
@@ -1641,7 +1842,7 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
        const char *arg_name;
 
        static struct dm_arg _args[] = {
-               {0, 1, "Invalid number of pool feature arguments"},
+               {0, 3, "Invalid number of pool feature arguments"},
        };
 
        /*
@@ -1661,6 +1862,12 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
                if (!strcasecmp(arg_name, "skip_block_zeroing")) {
                        pf->zero_new_blocks = 0;
                        continue;
+               } else if (!strcasecmp(arg_name, "ignore_discard")) {
+                       pf->discard_enabled = 0;
+                       continue;
+               } else if (!strcasecmp(arg_name, "no_discard_passdown")) {
+                       pf->discard_passdown = 0;
+                       continue;
                }
 
                ti->error = "Unrecognised pool feature requested";
@@ -1678,10 +1885,12 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
  *
  * Optional feature arguments are:
  *          skip_block_zeroing: skips the zeroing of newly-provisioned blocks.
+ *          ignore_discard: disable discard
+ *          no_discard_passdown: don't pass discards down to the data device
  */
 static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
 {
-       int r;
+       int r, pool_created = 0;
        struct pool_c *pt;
        struct pool *pool;
        struct pool_features pf;
@@ -1691,6 +1900,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
        dm_block_t low_water_blocks;
        struct dm_dev *metadata_dev;
        sector_t metadata_dev_size;
+       char b[BDEVNAME_SIZE];
 
        /*
         * FIXME Remove validation from scope of lock.
@@ -1712,11 +1922,9 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
 
        metadata_dev_size = i_size_read(metadata_dev->bdev->bd_inode) >> SECTOR_SHIFT;
-       if (metadata_dev_size > METADATA_DEV_MAX_SECTORS) {
-               ti->error = "Metadata device is too large";
-               r = -EINVAL;
-               goto out_metadata;
-       }
+       if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING)
+               DMWARN("Metadata device %s is larger than %u sectors: excess space will not be used.",
+                      bdevname(metadata_dev->bdev, b), THIN_METADATA_MAX_SECTORS);
 
        r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev);
        if (r) {
@@ -1742,8 +1950,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
        /*
         * Set default pool features.
         */
-       memset(&pf, 0, sizeof(pf));
-       pf.zero_new_blocks = 1;
+       pool_features_init(&pf);
 
        dm_consume_args(&as, 4);
        r = parse_pool_features(&as, &pf, ti);
@@ -1757,20 +1964,58 @@ 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);
+                          block_size, &ti->error, &pool_created);
        if (IS_ERR(pool)) {
                r = PTR_ERR(pool);
                goto out_free_pt;
        }
 
+       /*
+        * 'pool_created' reflects whether this is the first table load.
+        * Top level discard support is not allowed to be changed after
+        * initial load.  This would require a pool reload to trigger thin
+        * device changes.
+        */
+       if (!pool_created && pf.discard_enabled != pool->pf.discard_enabled) {
+               ti->error = "Discard support cannot be disabled once enabled";
+               r = -EINVAL;
+               goto out_flags_changed;
+       }
+
+       /*
+        * If discard_passdown was enabled verify that the data device
+        * supports discards.  Disable discard_passdown if not; otherwise
+        * -EOPNOTSUPP will be returned.
+        */
+       if (pf.discard_passdown) {
+               struct request_queue *q = bdev_get_queue(data_dev->bdev);
+               if (!q || !blk_queue_discard(q)) {
+                       DMWARN("Discard unsupported by data device: Disabling discard passdown.");
+                       pf.discard_passdown = 0;
+               }
+       }
+
        pt->pool = pool;
        pt->ti = ti;
        pt->metadata_dev = metadata_dev;
        pt->data_dev = data_dev;
        pt->low_water_blocks = low_water_blocks;
-       pt->zero_new_blocks = pf.zero_new_blocks;
+       pt->pf = pf;
        ti->num_flush_requests = 1;
-       ti->num_discard_requests = 0;
+       /*
+        * Only need to enable discards if the pool should pass
+        * them down to the data device.  The thin device's discard
+        * processing will cause mappings to be removed from the btree.
+        */
+       if (pf.discard_enabled && pf.discard_passdown) {
+               ti->num_discard_requests = 1;
+               /*
+                * Setting 'discards_supported' circumvents the normal
+                * stacking of discard limits (this keeps the pool and
+                * thin devices' discard limits consistent).
+                */
+               ti->discards_supported = 1;
+       }
        ti->private = pt;
 
        pt->callbacks.congested_fn = pool_is_congested;
@@ -1780,6 +2025,8 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        return 0;
 
+out_flags_changed:
+       __pool_dec(pool);
 out_free_pt:
        kfree(pt);
 out:
@@ -1878,7 +2125,7 @@ static void pool_resume(struct dm_target *ti)
        __requeue_bios(pool);
        spin_unlock_irqrestore(&pool->lock, flags);
 
-       wake_worker(pool);
+       do_waker(&pool->waker.work);
 }
 
 static void pool_postsuspend(struct dm_target *ti)
@@ -1887,6 +2134,7 @@ static void pool_postsuspend(struct dm_target *ti)
        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);
@@ -2067,7 +2315,7 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv)
 static int pool_status(struct dm_target *ti, status_type_t type,
                       char *result, unsigned maxlen)
 {
-       int r;
+       int r, count;
        unsigned sz = 0;
        uint64_t transaction_id;
        dm_block_t nr_free_blocks_data;
@@ -2130,10 +2378,19 @@ static int pool_status(struct dm_target *ti, status_type_t type,
                       (unsigned long)pool->sectors_per_block,
                       (unsigned long long)pt->low_water_blocks);
 
-               DMEMIT("%u ", !pool->zero_new_blocks);
+               count = !pool->pf.zero_new_blocks + !pool->pf.discard_enabled +
+                       !pool->pf.discard_passdown;
+               DMEMIT("%u ", count);
 
-               if (!pool->zero_new_blocks)
+               if (!pool->pf.zero_new_blocks)
                        DMEMIT("skip_block_zeroing ");
+
+               if (!pool->pf.discard_enabled)
+                       DMEMIT("ignore_discard ");
+
+               if (!pool->pf.discard_passdown)
+                       DMEMIT("no_discard_passdown ");
+
                break;
        }
 
@@ -2162,6 +2419,21 @@ static int pool_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
        return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
 }
 
+static void set_discard_limits(struct pool *pool, struct queue_limits *limits)
+{
+       /*
+        * FIXME: these limits may be incompatible with the pool's data device
+        */
+       limits->max_discard_sectors = pool->sectors_per_block;
+
+       /*
+        * This is just a hint, and not enforced.  We have to cope with
+        * bios that overlap 2 blocks.
+        */
+       limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT;
+       limits->discard_zeroes_data = pool->pf.zero_new_blocks;
+}
+
 static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
 {
        struct pool_c *pt = ti->private;
@@ -2169,13 +2441,15 @@ static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
        blk_limits_io_min(limits, 0);
        blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
+       if (pool->pf.discard_enabled)
+               set_discard_limits(pool, limits);
 }
 
 static struct target_type pool_target = {
        .name = "thin-pool",
        .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
                    DM_TARGET_IMMUTABLE,
-       .version = {1, 0, 0},
+       .version = {1, 1, 0},
        .module = THIS_MODULE,
        .ctr = pool_ctr,
        .dtr = pool_dtr,
@@ -2202,6 +2476,8 @@ static void thin_dtr(struct dm_target *ti)
        __pool_dec(tc->pool);
        dm_pool_close_thin_device(tc->td);
        dm_put_device(ti, tc->pool_dev);
+       if (tc->origin_dev)
+               dm_put_device(ti, tc->origin_dev);
        kfree(tc);
 
        mutex_unlock(&dm_thin_pool_table.mutex);
@@ -2210,21 +2486,25 @@ static void thin_dtr(struct dm_target *ti)
 /*
  * Thin target parameters:
  *
- * <pool_dev> <dev_id>
+ * <pool_dev> <dev_id> [origin_dev]
  *
  * pool_dev: the path to the pool (eg, /dev/mapper/my_pool)
  * dev_id: the internal device identifier
+ * origin_dev: a device external to the pool that should act as the origin
+ *
+ * If the pool device has discards disabled, they get disabled for the thin
+ * device as well.
  */
 static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 {
        int r;
        struct thin_c *tc;
-       struct dm_dev *pool_dev;
+       struct dm_dev *pool_dev, *origin_dev;
        struct mapped_device *pool_md;
 
        mutex_lock(&dm_thin_pool_table.mutex);
 
-       if (argc != 2) {
+       if (argc != 2 && argc != 3) {
                ti->error = "Invalid argument count";
                r = -EINVAL;
                goto out_unlock;
@@ -2237,6 +2517,15 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
                goto out_unlock;
        }
 
+       if (argc == 3) {
+               r = dm_get_device(ti, argv[2], FMODE_READ, &origin_dev);
+               if (r) {
+                       ti->error = "Error opening origin device";
+                       goto bad_origin_dev;
+               }
+               tc->origin_dev = origin_dev;
+       }
+
        r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &pool_dev);
        if (r) {
                ti->error = "Error opening pool device";
@@ -2273,8 +2562,12 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        ti->split_io = tc->pool->sectors_per_block;
        ti->num_flush_requests = 1;
-       ti->num_discard_requests = 0;
-       ti->discards_supported = 0;
+
+       /* In case the pool supports discards, pass them on. */
+       if (tc->pool->pf.discard_enabled) {
+               ti->discards_supported = 1;
+               ti->num_discard_requests = 1;
+       }
 
        dm_put(pool_md);
 
@@ -2289,6 +2582,9 @@ bad_pool_lookup:
 bad_common:
        dm_put_device(ti, tc->pool_dev);
 bad_pool_dev:
+       if (tc->origin_dev)
+               dm_put_device(ti, tc->origin_dev);
+bad_origin_dev:
        kfree(tc);
 out_unlock:
        mutex_unlock(&dm_thin_pool_table.mutex);
@@ -2299,11 +2595,46 @@ out_unlock:
 static int thin_map(struct dm_target *ti, struct bio *bio,
                    union map_info *map_context)
 {
-       bio->bi_sector -= ti->begin;
+       bio->bi_sector = dm_target_offset(ti, bio->bi_sector);
 
        return thin_bio_map(ti, bio, map_context);
 }
 
+static int thin_endio(struct dm_target *ti,
+                     struct bio *bio, int err,
+                     union map_info *map_context)
+{
+       unsigned long flags;
+       struct endio_hook *h = map_context->ptr;
+       struct list_head work;
+       struct new_mapping *m, *tmp;
+       struct pool *pool = h->tc->pool;
+
+       if (h->shared_read_entry) {
+               INIT_LIST_HEAD(&work);
+               ds_dec(h->shared_read_entry, &work);
+
+               spin_lock_irqsave(&pool->lock, flags);
+               list_for_each_entry_safe(m, tmp, &work, list) {
+                       list_del(&m->list);
+                       m->quiesced = 1;
+                       __maybe_add_mapping(m);
+               }
+               spin_unlock_irqrestore(&pool->lock, flags);
+       }
+
+       if (h->all_io_entry) {
+               INIT_LIST_HEAD(&work);
+               ds_dec(h->all_io_entry, &work);
+               list_for_each_entry_safe(m, tmp, &work, list)
+                       list_add(&m->list, &pool->prepared_discards);
+       }
+
+       mempool_free(h, pool->endio_hook_pool);
+
+       return 0;
+}
+
 static void thin_postsuspend(struct dm_target *ti)
 {
        if (dm_noflush_suspending(ti))
@@ -2347,6 +2678,8 @@ static int thin_status(struct dm_target *ti, status_type_t type,
                        DMEMIT("%s %lu",
                               format_dev_t(buf, tc->pool_dev->bdev->bd_dev),
                               (unsigned long) tc->dev_id);
+                       if (tc->origin_dev)
+                               DMEMIT(" %s", format_dev_t(buf, tc->origin_dev->bdev->bd_dev));
                        break;
                }
        }
@@ -2377,18 +2710,21 @@ static int thin_iterate_devices(struct dm_target *ti,
 static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
 {
        struct thin_c *tc = ti->private;
+       struct pool *pool = tc->pool;
 
        blk_limits_io_min(limits, 0);
-       blk_limits_io_opt(limits, tc->pool->sectors_per_block << SECTOR_SHIFT);
+       blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
+       set_discard_limits(pool, limits);
 }
 
 static struct target_type thin_target = {
        .name = "thin",
-       .version = {1, 0, 0},
+       .version = {1, 1, 0},
        .module = THIS_MODULE,
        .ctr = thin_ctr,
        .dtr = thin_dtr,
        .map = thin_map,
+       .end_io = thin_endio,
        .postsuspend = thin_postsuspend,
        .status = thin_status,
        .iterate_devices = thin_iterate_devices,
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c
new file mode 100644 (file)
index 0000000..fa365d3
--- /dev/null
@@ -0,0 +1,913 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Author: Mikulas Patocka <mpatocka@redhat.com>
+ *
+ * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
+ *
+ * This file is released under the GPLv2.
+ *
+ * In the file "/sys/module/dm_verity/parameters/prefetch_cluster" you can set
+ * default prefetch value. Data are read in "prefetch_cluster" chunks from the
+ * hash device. Setting this greatly improves performance when data and hash
+ * are on the same disk on different partitions on devices with poor random
+ * access behavior.
+ */
+
+#include "dm-bufio.h"
+
+#include <linux/module.h>
+#include <linux/device-mapper.h>
+#include <crypto/hash.h>
+
+#define DM_MSG_PREFIX                  "verity"
+
+#define DM_VERITY_IO_VEC_INLINE                16
+#define DM_VERITY_MEMPOOL_SIZE         4
+#define DM_VERITY_DEFAULT_PREFETCH_SIZE        262144
+
+#define DM_VERITY_MAX_LEVELS           63
+
+static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
+
+module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);
+
+struct dm_verity {
+       struct dm_dev *data_dev;
+       struct dm_dev *hash_dev;
+       struct dm_target *ti;
+       struct dm_bufio_client *bufio;
+       char *alg_name;
+       struct crypto_shash *tfm;
+       u8 *root_digest;        /* digest of the root block */
+       u8 *salt;               /* salt: its size is salt_size */
+       unsigned salt_size;
+       sector_t data_start;    /* data offset in 512-byte sectors */
+       sector_t hash_start;    /* hash start in blocks */
+       sector_t data_blocks;   /* the number of data blocks */
+       sector_t hash_blocks;   /* the number of hash blocks */
+       unsigned char data_dev_block_bits;      /* log2(data blocksize) */
+       unsigned char hash_dev_block_bits;      /* log2(hash blocksize) */
+       unsigned char hash_per_block_bits;      /* log2(hashes in hash block) */
+       unsigned char levels;   /* the number of tree levels */
+       unsigned char version;
+       unsigned digest_size;   /* digest size for the current hash algorithm */
+       unsigned shash_descsize;/* the size of temporary space for crypto */
+       int hash_failed;        /* set to 1 if hash of any block failed */
+
+       mempool_t *io_mempool;  /* mempool of struct dm_verity_io */
+       mempool_t *vec_mempool; /* mempool of bio vector */
+
+       struct workqueue_struct *verify_wq;
+
+       /* starting blocks for each tree level. 0 is the lowest level. */
+       sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
+};
+
+struct dm_verity_io {
+       struct dm_verity *v;
+       struct bio *bio;
+
+       /* original values of bio->bi_end_io and bio->bi_private */
+       bio_end_io_t *orig_bi_end_io;
+       void *orig_bi_private;
+
+       sector_t block;
+       unsigned n_blocks;
+
+       /* saved bio vector */
+       struct bio_vec *io_vec;
+       unsigned io_vec_size;
+
+       struct work_struct work;
+
+       /* A space for short vectors; longer vectors are allocated separately. */
+       struct bio_vec io_vec_inline[DM_VERITY_IO_VEC_INLINE];
+
+       /*
+        * Three variably-size fields follow this struct:
+        *
+        * u8 hash_desc[v->shash_descsize];
+        * u8 real_digest[v->digest_size];
+        * u8 want_digest[v->digest_size];
+        *
+        * To access them use: io_hash_desc(), io_real_digest() and io_want_digest().
+        */
+};
+
+static struct shash_desc *io_hash_desc(struct dm_verity *v, struct dm_verity_io *io)
+{
+       return (struct shash_desc *)(io + 1);
+}
+
+static u8 *io_real_digest(struct dm_verity *v, struct dm_verity_io *io)
+{
+       return (u8 *)(io + 1) + v->shash_descsize;
+}
+
+static u8 *io_want_digest(struct dm_verity *v, struct dm_verity_io *io)
+{
+       return (u8 *)(io + 1) + v->shash_descsize + v->digest_size;
+}
+
+/*
+ * Auxiliary structure appended to each dm-bufio buffer. If the value
+ * hash_verified is nonzero, hash of the block has been verified.
+ *
+ * The variable hash_verified is set to 0 when allocating the buffer, then
+ * it can be changed to 1 and it is never reset to 0 again.
+ *
+ * There is no lock around this value, a race condition can at worst cause
+ * that multiple processes verify the hash of the same buffer simultaneously
+ * and write 1 to hash_verified simultaneously.
+ * This condition is harmless, so we don't need locking.
+ */
+struct buffer_aux {
+       int hash_verified;
+};
+
+/*
+ * Initialize struct buffer_aux for a freshly created buffer.
+ */
+static void dm_bufio_alloc_callback(struct dm_buffer *buf)
+{
+       struct buffer_aux *aux = dm_bufio_get_aux_data(buf);
+
+       aux->hash_verified = 0;
+}
+
+/*
+ * Translate input sector number to the sector number on the target device.
+ */
+static sector_t verity_map_sector(struct dm_verity *v, sector_t bi_sector)
+{
+       return v->data_start + dm_target_offset(v->ti, bi_sector);
+}
+
+/*
+ * Return hash position of a specified block at a specified tree level
+ * (0 is the lowest level).
+ * The lowest "hash_per_block_bits"-bits of the result denote hash position
+ * inside a hash block. The remaining bits denote location of the hash block.
+ */
+static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
+                                        int level)
+{
+       return block >> (level * v->hash_per_block_bits);
+}
+
+static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
+                                sector_t *hash_block, unsigned *offset)
+{
+       sector_t position = verity_position_at_level(v, block, level);
+       unsigned idx;
+
+       *hash_block = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
+
+       if (!offset)
+               return;
+
+       idx = position & ((1 << v->hash_per_block_bits) - 1);
+       if (!v->version)
+               *offset = idx * v->digest_size;
+       else
+               *offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits);
+}
+
+/*
+ * Verify hash of a metadata block pertaining to the specified data block
+ * ("block" argument) at a specified level ("level" argument).
+ *
+ * On successful return, io_want_digest(v, io) contains the hash value for
+ * a lower tree level or for the data block (if we're at the lowest leve).
+ *
+ * If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
+ * If "skip_unverified" is false, unverified buffer is hashed and verified
+ * against current value of io_want_digest(v, io).
+ */
+static int verity_verify_level(struct dm_verity_io *io, sector_t block,
+                              int level, bool skip_unverified)
+{
+       struct dm_verity *v = io->v;
+       struct dm_buffer *buf;
+       struct buffer_aux *aux;
+       u8 *data;
+       int r;
+       sector_t hash_block;
+       unsigned offset;
+
+       verity_hash_at_level(v, block, level, &hash_block, &offset);
+
+       data = dm_bufio_read(v->bufio, hash_block, &buf);
+       if (unlikely(IS_ERR(data)))
+               return PTR_ERR(data);
+
+       aux = dm_bufio_get_aux_data(buf);
+
+       if (!aux->hash_verified) {
+               struct shash_desc *desc;
+               u8 *result;
+
+               if (skip_unverified) {
+                       r = 1;
+                       goto release_ret_r;
+               }
+
+               desc = io_hash_desc(v, io);
+               desc->tfm = v->tfm;
+               desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+               r = crypto_shash_init(desc);
+               if (r < 0) {
+                       DMERR("crypto_shash_init failed: %d", r);
+                       goto release_ret_r;
+               }
+
+               if (likely(v->version >= 1)) {
+                       r = crypto_shash_update(desc, v->salt, v->salt_size);
+                       if (r < 0) {
+                               DMERR("crypto_shash_update failed: %d", r);
+                               goto release_ret_r;
+                       }
+               }
+
+               r = crypto_shash_update(desc, data, 1 << v->hash_dev_block_bits);
+               if (r < 0) {
+                       DMERR("crypto_shash_update failed: %d", r);
+                       goto release_ret_r;
+               }
+
+               if (!v->version) {
+                       r = crypto_shash_update(desc, v->salt, v->salt_size);
+                       if (r < 0) {
+                               DMERR("crypto_shash_update failed: %d", r);
+                               goto release_ret_r;
+                       }
+               }
+
+               result = io_real_digest(v, io);
+               r = crypto_shash_final(desc, result);
+               if (r < 0) {
+                       DMERR("crypto_shash_final failed: %d", r);
+                       goto release_ret_r;
+               }
+               if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
+                       DMERR_LIMIT("metadata block %llu is corrupted",
+                               (unsigned long long)hash_block);
+                       v->hash_failed = 1;
+                       r = -EIO;
+                       goto release_ret_r;
+               } else
+                       aux->hash_verified = 1;
+       }
+
+       data += offset;
+
+       memcpy(io_want_digest(v, io), data, v->digest_size);
+
+       dm_bufio_release(buf);
+       return 0;
+
+release_ret_r:
+       dm_bufio_release(buf);
+
+       return r;
+}
+
+/*
+ * Verify one "dm_verity_io" structure.
+ */
+static int verity_verify_io(struct dm_verity_io *io)
+{
+       struct dm_verity *v = io->v;
+       unsigned b;
+       int i;
+       unsigned vector = 0, offset = 0;
+
+       for (b = 0; b < io->n_blocks; b++) {
+               struct shash_desc *desc;
+               u8 *result;
+               int r;
+               unsigned todo;
+
+               if (likely(v->levels)) {
+                       /*
+                        * First, we try to get the requested hash for
+                        * the current block. If the hash block itself is
+                        * verified, zero is returned. If it isn't, this
+                        * function returns 0 and we fall back to whole
+                        * chain verification.
+                        */
+                       int r = verity_verify_level(io, io->block + b, 0, true);
+                       if (likely(!r))
+                               goto test_block_hash;
+                       if (r < 0)
+                               return r;
+               }
+
+               memcpy(io_want_digest(v, io), v->root_digest, v->digest_size);
+
+               for (i = v->levels - 1; i >= 0; i--) {
+                       int r = verity_verify_level(io, io->block + b, i, false);
+                       if (unlikely(r))
+                               return r;
+               }
+
+test_block_hash:
+               desc = io_hash_desc(v, io);
+               desc->tfm = v->tfm;
+               desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+               r = crypto_shash_init(desc);
+               if (r < 0) {
+                       DMERR("crypto_shash_init failed: %d", r);
+                       return r;
+               }
+
+               if (likely(v->version >= 1)) {
+                       r = crypto_shash_update(desc, v->salt, v->salt_size);
+                       if (r < 0) {
+                               DMERR("crypto_shash_update failed: %d", r);
+                               return r;
+                       }
+               }
+
+               todo = 1 << v->data_dev_block_bits;
+               do {
+                       struct bio_vec *bv;
+                       u8 *page;
+                       unsigned len;
+
+                       BUG_ON(vector >= io->io_vec_size);
+                       bv = &io->io_vec[vector];
+                       page = kmap_atomic(bv->bv_page);
+                       len = bv->bv_len - offset;
+                       if (likely(len >= todo))
+                               len = todo;
+                       r = crypto_shash_update(desc,
+                                       page + bv->bv_offset + offset, len);
+                       kunmap_atomic(page);
+                       if (r < 0) {
+                               DMERR("crypto_shash_update failed: %d", r);
+                               return r;
+                       }
+                       offset += len;
+                       if (likely(offset == bv->bv_len)) {
+                               offset = 0;
+                               vector++;
+                       }
+                       todo -= len;
+               } while (todo);
+
+               if (!v->version) {
+                       r = crypto_shash_update(desc, v->salt, v->salt_size);
+                       if (r < 0) {
+                               DMERR("crypto_shash_update failed: %d", r);
+                               return r;
+                       }
+               }
+
+               result = io_real_digest(v, io);
+               r = crypto_shash_final(desc, result);
+               if (r < 0) {
+                       DMERR("crypto_shash_final failed: %d", r);
+                       return r;
+               }
+               if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
+                       DMERR_LIMIT("data block %llu is corrupted",
+                               (unsigned long long)(io->block + b));
+                       v->hash_failed = 1;
+                       return -EIO;
+               }
+       }
+       BUG_ON(vector != io->io_vec_size);
+       BUG_ON(offset);
+
+       return 0;
+}
+
+/*
+ * End one "io" structure with a given error.
+ */
+static void verity_finish_io(struct dm_verity_io *io, int error)
+{
+       struct bio *bio = io->bio;
+       struct dm_verity *v = io->v;
+
+       bio->bi_end_io = io->orig_bi_end_io;
+       bio->bi_private = io->orig_bi_private;
+
+       if (io->io_vec != io->io_vec_inline)
+               mempool_free(io->io_vec, v->vec_mempool);
+
+       mempool_free(io, v->io_mempool);
+
+       bio_endio(bio, error);
+}
+
+static void verity_work(struct work_struct *w)
+{
+       struct dm_verity_io *io = container_of(w, struct dm_verity_io, work);
+
+       verity_finish_io(io, verity_verify_io(io));
+}
+
+static void verity_end_io(struct bio *bio, int error)
+{
+       struct dm_verity_io *io = bio->bi_private;
+
+       if (error) {
+               verity_finish_io(io, error);
+               return;
+       }
+
+       INIT_WORK(&io->work, verity_work);
+       queue_work(io->v->verify_wq, &io->work);
+}
+
+/*
+ * Prefetch buffers for the specified io.
+ * The root buffer is not prefetched, it is assumed that it will be cached
+ * all the time.
+ */
+static void verity_prefetch_io(struct dm_verity *v, struct dm_verity_io *io)
+{
+       int i;
+
+       for (i = v->levels - 2; i >= 0; i--) {
+               sector_t hash_block_start;
+               sector_t hash_block_end;
+               verity_hash_at_level(v, io->block, i, &hash_block_start, NULL);
+               verity_hash_at_level(v, io->block + io->n_blocks - 1, i, &hash_block_end, NULL);
+               if (!i) {
+                       unsigned cluster = *(volatile unsigned *)&dm_verity_prefetch_cluster;
+
+                       cluster >>= v->data_dev_block_bits;
+                       if (unlikely(!cluster))
+                               goto no_prefetch_cluster;
+
+                       if (unlikely(cluster & (cluster - 1)))
+                               cluster = 1 << (fls(cluster) - 1);
+
+                       hash_block_start &= ~(sector_t)(cluster - 1);
+                       hash_block_end |= cluster - 1;
+                       if (unlikely(hash_block_end >= v->hash_blocks))
+                               hash_block_end = v->hash_blocks - 1;
+               }
+no_prefetch_cluster:
+               dm_bufio_prefetch(v->bufio, hash_block_start,
+                                 hash_block_end - hash_block_start + 1);
+       }
+}
+
+/*
+ * Bio map function. It allocates dm_verity_io structure and bio vector and
+ * fills them. Then it issues prefetches and the I/O.
+ */
+static int verity_map(struct dm_target *ti, struct bio *bio,
+                     union map_info *map_context)
+{
+       struct dm_verity *v = ti->private;
+       struct dm_verity_io *io;
+
+       bio->bi_bdev = v->data_dev->bdev;
+       bio->bi_sector = verity_map_sector(v, bio->bi_sector);
+
+       if (((unsigned)bio->bi_sector | bio_sectors(bio)) &
+           ((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) {
+               DMERR_LIMIT("unaligned io");
+               return -EIO;
+       }
+
+       if ((bio->bi_sector + bio_sectors(bio)) >>
+           (v->data_dev_block_bits - SECTOR_SHIFT) > v->data_blocks) {
+               DMERR_LIMIT("io out of range");
+               return -EIO;
+       }
+
+       if (bio_data_dir(bio) == WRITE)
+               return -EIO;
+
+       io = mempool_alloc(v->io_mempool, GFP_NOIO);
+       io->v = v;
+       io->bio = bio;
+       io->orig_bi_end_io = bio->bi_end_io;
+       io->orig_bi_private = bio->bi_private;
+       io->block = bio->bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
+       io->n_blocks = bio->bi_size >> v->data_dev_block_bits;
+
+       bio->bi_end_io = verity_end_io;
+       bio->bi_private = io;
+       io->io_vec_size = bio->bi_vcnt - bio->bi_idx;
+       if (io->io_vec_size < DM_VERITY_IO_VEC_INLINE)
+               io->io_vec = io->io_vec_inline;
+       else
+               io->io_vec = mempool_alloc(v->vec_mempool, GFP_NOIO);
+       memcpy(io->io_vec, bio_iovec(bio),
+              io->io_vec_size * sizeof(struct bio_vec));
+
+       verity_prefetch_io(v, io);
+
+       generic_make_request(bio);
+
+       return DM_MAPIO_SUBMITTED;
+}
+
+/*
+ * Status: V (valid) or C (corruption found)
+ */
+static int verity_status(struct dm_target *ti, status_type_t type,
+                        char *result, unsigned maxlen)
+{
+       struct dm_verity *v = ti->private;
+       unsigned sz = 0;
+       unsigned x;
+
+       switch (type) {
+       case STATUSTYPE_INFO:
+               DMEMIT("%c", v->hash_failed ? 'C' : 'V');
+               break;
+       case STATUSTYPE_TABLE:
+               DMEMIT("%u %s %s %u %u %llu %llu %s ",
+                       v->version,
+                       v->data_dev->name,
+                       v->hash_dev->name,
+                       1 << v->data_dev_block_bits,
+                       1 << v->hash_dev_block_bits,
+                       (unsigned long long)v->data_blocks,
+                       (unsigned long long)v->hash_start,
+                       v->alg_name
+                       );
+               for (x = 0; x < v->digest_size; x++)
+                       DMEMIT("%02x", v->root_digest[x]);
+               DMEMIT(" ");
+               if (!v->salt_size)
+                       DMEMIT("-");
+               else
+                       for (x = 0; x < v->salt_size; x++)
+                               DMEMIT("%02x", v->salt[x]);
+               break;
+       }
+
+       return 0;
+}
+
+static int verity_ioctl(struct dm_target *ti, unsigned cmd,
+                       unsigned long arg)
+{
+       struct dm_verity *v = ti->private;
+       int r = 0;
+
+       if (v->data_start ||
+           ti->len != i_size_read(v->data_dev->bdev->bd_inode) >> SECTOR_SHIFT)
+               r = scsi_verify_blk_ioctl(NULL, cmd);
+
+       return r ? : __blkdev_driver_ioctl(v->data_dev->bdev, v->data_dev->mode,
+                                    cmd, arg);
+}
+
+static int verity_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
+                       struct bio_vec *biovec, int max_size)
+{
+       struct dm_verity *v = ti->private;
+       struct request_queue *q = bdev_get_queue(v->data_dev->bdev);
+
+       if (!q->merge_bvec_fn)
+               return max_size;
+
+       bvm->bi_bdev = v->data_dev->bdev;
+       bvm->bi_sector = verity_map_sector(v, bvm->bi_sector);
+
+       return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
+}
+
+static int verity_iterate_devices(struct dm_target *ti,
+                                 iterate_devices_callout_fn fn, void *data)
+{
+       struct dm_verity *v = ti->private;
+
+       return fn(ti, v->data_dev, v->data_start, ti->len, data);
+}
+
+static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
+{
+       struct dm_verity *v = ti->private;
+
+       if (limits->logical_block_size < 1 << v->data_dev_block_bits)
+               limits->logical_block_size = 1 << v->data_dev_block_bits;
+
+       if (limits->physical_block_size < 1 << v->data_dev_block_bits)
+               limits->physical_block_size = 1 << v->data_dev_block_bits;
+
+       blk_limits_io_min(limits, limits->logical_block_size);
+}
+
+static void verity_dtr(struct dm_target *ti)
+{
+       struct dm_verity *v = ti->private;
+
+       if (v->verify_wq)
+               destroy_workqueue(v->verify_wq);
+
+       if (v->vec_mempool)
+               mempool_destroy(v->vec_mempool);
+
+       if (v->io_mempool)
+               mempool_destroy(v->io_mempool);
+
+       if (v->bufio)
+               dm_bufio_client_destroy(v->bufio);
+
+       kfree(v->salt);
+       kfree(v->root_digest);
+
+       if (v->tfm)
+               crypto_free_shash(v->tfm);
+
+       kfree(v->alg_name);
+
+       if (v->hash_dev)
+               dm_put_device(ti, v->hash_dev);
+
+       if (v->data_dev)
+               dm_put_device(ti, v->data_dev);
+
+       kfree(v);
+}
+
+/*
+ * Target parameters:
+ *     <version>       The current format is version 1.
+ *                     Vsn 0 is compatible with original Chromium OS releases.
+ *     <data device>
+ *     <hash device>
+ *     <data block size>
+ *     <hash block size>
+ *     <the number of data blocks>
+ *     <hash start block>
+ *     <algorithm>
+ *     <digest>
+ *     <salt>          Hex string or "-" if no salt.
+ */
+static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
+{
+       struct dm_verity *v;
+       unsigned num;
+       unsigned long long num_ll;
+       int r;
+       int i;
+       sector_t hash_position;
+       char dummy;
+
+       v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
+       if (!v) {
+               ti->error = "Cannot allocate verity structure";
+               return -ENOMEM;
+       }
+       ti->private = v;
+       v->ti = ti;
+
+       if ((dm_table_get_mode(ti->table) & ~FMODE_READ)) {
+               ti->error = "Device must be readonly";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (argc != 10) {
+               ti->error = "Invalid argument count: exactly 10 arguments required";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (sscanf(argv[0], "%d%c", &num, &dummy) != 1 ||
+           num < 0 || num > 1) {
+               ti->error = "Invalid version";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->version = num;
+
+       r = dm_get_device(ti, argv[1], FMODE_READ, &v->data_dev);
+       if (r) {
+               ti->error = "Data device lookup failed";
+               goto bad;
+       }
+
+       r = dm_get_device(ti, argv[2], FMODE_READ, &v->hash_dev);
+       if (r) {
+               ti->error = "Data device lookup failed";
+               goto bad;
+       }
+
+       if (sscanf(argv[3], "%u%c", &num, &dummy) != 1 ||
+           !num || (num & (num - 1)) ||
+           num < bdev_logical_block_size(v->data_dev->bdev) ||
+           num > PAGE_SIZE) {
+               ti->error = "Invalid data device block size";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->data_dev_block_bits = ffs(num) - 1;
+
+       if (sscanf(argv[4], "%u%c", &num, &dummy) != 1 ||
+           !num || (num & (num - 1)) ||
+           num < bdev_logical_block_size(v->hash_dev->bdev) ||
+           num > INT_MAX) {
+               ti->error = "Invalid hash device block size";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->hash_dev_block_bits = ffs(num) - 1;
+
+       if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
+           num_ll << (v->data_dev_block_bits - SECTOR_SHIFT) !=
+           (sector_t)num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) {
+               ti->error = "Invalid data blocks";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->data_blocks = num_ll;
+
+       if (ti->len > (v->data_blocks << (v->data_dev_block_bits - SECTOR_SHIFT))) {
+               ti->error = "Data device is too small";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (sscanf(argv[6], "%llu%c", &num_ll, &dummy) != 1 ||
+           num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT) !=
+           (sector_t)num_ll << (v->hash_dev_block_bits - SECTOR_SHIFT)) {
+               ti->error = "Invalid hash start";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->hash_start = num_ll;
+
+       v->alg_name = kstrdup(argv[7], GFP_KERNEL);
+       if (!v->alg_name) {
+               ti->error = "Cannot allocate algorithm name";
+               r = -ENOMEM;
+               goto bad;
+       }
+
+       v->tfm = crypto_alloc_shash(v->alg_name, 0, 0);
+       if (IS_ERR(v->tfm)) {
+               ti->error = "Cannot initialize hash function";
+               r = PTR_ERR(v->tfm);
+               v->tfm = NULL;
+               goto bad;
+       }
+       v->digest_size = crypto_shash_digestsize(v->tfm);
+       if ((1 << v->hash_dev_block_bits) < v->digest_size * 2) {
+               ti->error = "Digest size too big";
+               r = -EINVAL;
+               goto bad;
+       }
+       v->shash_descsize =
+               sizeof(struct shash_desc) + crypto_shash_descsize(v->tfm);
+
+       v->root_digest = kmalloc(v->digest_size, GFP_KERNEL);
+       if (!v->root_digest) {
+               ti->error = "Cannot allocate root digest";
+               r = -ENOMEM;
+               goto bad;
+       }
+       if (strlen(argv[8]) != v->digest_size * 2 ||
+           hex2bin(v->root_digest, argv[8], v->digest_size)) {
+               ti->error = "Invalid root digest";
+               r = -EINVAL;
+               goto bad;
+       }
+
+       if (strcmp(argv[9], "-")) {
+               v->salt_size = strlen(argv[9]) / 2;
+               v->salt = kmalloc(v->salt_size, GFP_KERNEL);
+               if (!v->salt) {
+                       ti->error = "Cannot allocate salt";
+                       r = -ENOMEM;
+                       goto bad;
+               }
+               if (strlen(argv[9]) != v->salt_size * 2 ||
+                   hex2bin(v->salt, argv[9], v->salt_size)) {
+                       ti->error = "Invalid salt";
+                       r = -EINVAL;
+                       goto bad;
+               }
+       }
+
+       v->hash_per_block_bits =
+               fls((1 << v->hash_dev_block_bits) / v->digest_size) - 1;
+
+       v->levels = 0;
+       if (v->data_blocks)
+               while (v->hash_per_block_bits * v->levels < 64 &&
+                      (unsigned long long)(v->data_blocks - 1) >>
+                      (v->hash_per_block_bits * v->levels))
+                       v->levels++;
+
+       if (v->levels > DM_VERITY_MAX_LEVELS) {
+               ti->error = "Too many tree levels";
+               r = -E2BIG;
+               goto bad;
+       }
+
+       hash_position = v->hash_start;
+       for (i = v->levels - 1; i >= 0; i--) {
+               sector_t s;
+               v->hash_level_block[i] = hash_position;
+               s = verity_position_at_level(v, v->data_blocks, i);
+               s = (s >> v->hash_per_block_bits) +
+                   !!(s & ((1 << v->hash_per_block_bits) - 1));
+               if (hash_position + s < hash_position) {
+                       ti->error = "Hash device offset overflow";
+                       r = -E2BIG;
+                       goto bad;
+               }
+               hash_position += s;
+       }
+       v->hash_blocks = hash_position;
+
+       v->bufio = dm_bufio_client_create(v->hash_dev->bdev,
+               1 << v->hash_dev_block_bits, 1, sizeof(struct buffer_aux),
+               dm_bufio_alloc_callback, NULL);
+       if (IS_ERR(v->bufio)) {
+               ti->error = "Cannot initialize dm-bufio";
+               r = PTR_ERR(v->bufio);
+               v->bufio = NULL;
+               goto bad;
+       }
+
+       if (dm_bufio_get_device_size(v->bufio) < v->hash_blocks) {
+               ti->error = "Hash device is too small";
+               r = -E2BIG;
+               goto bad;
+       }
+
+       v->io_mempool = mempool_create_kmalloc_pool(DM_VERITY_MEMPOOL_SIZE,
+         sizeof(struct dm_verity_io) + v->shash_descsize + v->digest_size * 2);
+       if (!v->io_mempool) {
+               ti->error = "Cannot allocate io mempool";
+               r = -ENOMEM;
+               goto bad;
+       }
+
+       v->vec_mempool = mempool_create_kmalloc_pool(DM_VERITY_MEMPOOL_SIZE,
+                                       BIO_MAX_PAGES * sizeof(struct bio_vec));
+       if (!v->vec_mempool) {
+               ti->error = "Cannot allocate vector mempool";
+               r = -ENOMEM;
+               goto bad;
+       }
+
+       /* WQ_UNBOUND greatly improves performance when running on ramdisk */
+       v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus());
+       if (!v->verify_wq) {
+               ti->error = "Cannot allocate workqueue";
+               r = -ENOMEM;
+               goto bad;
+       }
+
+       return 0;
+
+bad:
+       verity_dtr(ti);
+
+       return r;
+}
+
+static struct target_type verity_target = {
+       .name           = "verity",
+       .version        = {1, 0, 0},
+       .module         = THIS_MODULE,
+       .ctr            = verity_ctr,
+       .dtr            = verity_dtr,
+       .map            = verity_map,
+       .status         = verity_status,
+       .ioctl          = verity_ioctl,
+       .merge          = verity_merge,
+       .iterate_devices = verity_iterate_devices,
+       .io_hints       = verity_io_hints,
+};
+
+static int __init dm_verity_init(void)
+{
+       int r;
+
+       r = dm_register_target(&verity_target);
+       if (r < 0)
+               DMERR("register failed %d", r);
+
+       return r;
+}
+
+static void __exit dm_verity_exit(void)
+{
+       dm_unregister_target(&verity_target);
+}
+
+module_init(dm_verity_init);
+module_exit(dm_verity_exit);
+
+MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
+MODULE_AUTHOR("Mandeep Baines <msb@chromium.org>");
+MODULE_AUTHOR("Will Drewry <wad@chromium.org>");
+MODULE_DESCRIPTION(DM_NAME " target for transparent disk integrity checking");
+MODULE_LICENSE("GPL");
index b89c548..e24143c 100644 (file)
@@ -1016,6 +1016,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
                /*
                 * Store bio_set for cleanup.
                 */
+               clone->bi_end_io = NULL;
                clone->bi_private = md->bs;
                bio_put(clone);
                free_tio(md, tio);
index d279c76..5709bfe 100644 (file)
@@ -108,12 +108,9 @@ static inline void *value_base(struct node *n)
        return &n->keys[le32_to_cpu(n->header.max_entries)];
 }
 
-/*
- * FIXME: Now that value size is stored in node we don't need the third parm.
- */
-static inline void *value_ptr(struct node *n, uint32_t index, size_t value_size)
+static inline void *value_ptr(struct node *n, uint32_t index)
 {
-       BUG_ON(value_size != le32_to_cpu(n->header.value_size));
+       uint32_t value_size = le32_to_cpu(n->header.value_size);
        return value_base(n) + (value_size * index);
 }
 
index 023fbc2..aa71e23 100644 (file)
@@ -61,20 +61,20 @@ static void node_shift(struct node *n, int shift)
        if (shift < 0) {
                shift = -shift;
                BUG_ON(shift > nr_entries);
-               BUG_ON((void *) key_ptr(n, shift) >= value_ptr(n, shift, value_size));
+               BUG_ON((void *) key_ptr(n, shift) >= value_ptr(n, shift));
                memmove(key_ptr(n, 0),
                        key_ptr(n, shift),
                        (nr_entries - shift) * sizeof(__le64));
-               memmove(value_ptr(n, 0, value_size),
-                       value_ptr(n, shift, value_size),
+               memmove(value_ptr(n, 0),
+                       value_ptr(n, shift),
                        (nr_entries - shift) * value_size);
        } else {
                BUG_ON(nr_entries + shift > le32_to_cpu(n->header.max_entries));
                memmove(key_ptr(n, shift),
                        key_ptr(n, 0),
                        nr_entries * sizeof(__le64));
-               memmove(value_ptr(n, shift, value_size),
-                       value_ptr(n, 0, value_size),
+               memmove(value_ptr(n, shift),
+                       value_ptr(n, 0),
                        nr_entries * value_size);
        }
 }
@@ -91,16 +91,16 @@ static void node_copy(struct node *left, struct node *right, int shift)
                memcpy(key_ptr(left, nr_left),
                       key_ptr(right, 0),
                       shift * sizeof(__le64));
-               memcpy(value_ptr(left, nr_left, value_size),
-                      value_ptr(right, 0, value_size),
+               memcpy(value_ptr(left, nr_left),
+                      value_ptr(right, 0),
                       shift * value_size);
        } else {
                BUG_ON(shift > le32_to_cpu(right->header.max_entries));
                memcpy(key_ptr(right, 0),
                       key_ptr(left, nr_left - shift),
                       shift * sizeof(__le64));
-               memcpy(value_ptr(right, 0, value_size),
-                      value_ptr(left, nr_left - shift, value_size),
+               memcpy(value_ptr(right, 0),
+                      value_ptr(left, nr_left - shift),
                       shift * value_size);
        }
 }
@@ -120,26 +120,17 @@ static void delete_at(struct node *n, unsigned index)
                        key_ptr(n, index + 1),
                        nr_to_copy * sizeof(__le64));
 
-               memmove(value_ptr(n, index, value_size),
-                       value_ptr(n, index + 1, value_size),
+               memmove(value_ptr(n, index),
+                       value_ptr(n, index + 1),
                        nr_to_copy * value_size);
        }
 
        n->header.nr_entries = cpu_to_le32(nr_entries - 1);
 }
 
-static unsigned del_threshold(struct node *n)
-{
-       return le32_to_cpu(n->header.max_entries) / 3;
-}
-
 static unsigned merge_threshold(struct node *n)
 {
-       /*
-        * The extra one is because we know we're potentially going to
-        * delete an entry.
-        */
-       return 2 * (le32_to_cpu(n->header.max_entries) / 3) + 1;
+       return le32_to_cpu(n->header.max_entries) / 3;
 }
 
 struct child {
@@ -175,7 +166,7 @@ static int init_child(struct dm_btree_info *info, struct node *parent,
        if (inc)
                inc_children(info->tm, result->n, &le64_type);
 
-       *((__le64 *) value_ptr(parent, index, sizeof(__le64))) =
+       *((__le64 *) value_ptr(parent, index)) =
                cpu_to_le64(dm_block_location(result->block));
 
        return 0;
@@ -188,6 +179,15 @@ static int exit_child(struct dm_btree_info *info, struct child *c)
 
 static void shift(struct node *left, struct node *right, int count)
 {
+       uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
+       uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
+       uint32_t max_entries = le32_to_cpu(left->header.max_entries);
+       uint32_t r_max_entries = le32_to_cpu(right->header.max_entries);
+
+       BUG_ON(max_entries != r_max_entries);
+       BUG_ON(nr_left - count > max_entries);
+       BUG_ON(nr_right + count > max_entries);
+
        if (!count)
                return;
 
@@ -199,13 +199,8 @@ static void shift(struct node *left, struct node *right, int count)
                node_shift(right, count);
        }
 
-       left->header.nr_entries =
-               cpu_to_le32(le32_to_cpu(left->header.nr_entries) - count);
-       BUG_ON(le32_to_cpu(left->header.nr_entries) > le32_to_cpu(left->header.max_entries));
-
-       right->header.nr_entries =
-               cpu_to_le32(le32_to_cpu(right->header.nr_entries) + count);
-       BUG_ON(le32_to_cpu(right->header.nr_entries) > le32_to_cpu(right->header.max_entries));
+       left->header.nr_entries = cpu_to_le32(nr_left - count);
+       right->header.nr_entries = cpu_to_le32(nr_right + count);
 }
 
 static void __rebalance2(struct dm_btree_info *info, struct node *parent,
@@ -215,8 +210,9 @@ static void __rebalance2(struct dm_btree_info *info, struct node *parent,
        struct node *right = r->n;
        uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
        uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
+       unsigned threshold = 2 * merge_threshold(left) + 1;
 
-       if (nr_left + nr_right <= merge_threshold(left)) {
+       if (nr_left + nr_right < threshold) {
                /*
                 * Merge
                 */
@@ -234,9 +230,6 @@ static void __rebalance2(struct dm_btree_info *info, struct node *parent,
                 * Rebalance.
                 */
                unsigned target_left = (nr_left + nr_right) / 2;
-               unsigned shift_ = nr_left - target_left;
-               BUG_ON(le32_to_cpu(left->header.max_entries) <= nr_left - shift_);
-               BUG_ON(le32_to_cpu(right->header.max_entries) <= nr_right + shift_);
                shift(left, right, nr_left - target_left);
                *key_ptr(parent, r->index) = right->keys[0];
        }
@@ -272,6 +265,84 @@ static int rebalance2(struct shadow_spine *s, struct dm_btree_info *info,
        return exit_child(info, &right);
 }
 
+/*
+ * We dump as many entries from center as possible into left, then the rest
+ * in right, then rebalance2.  This wastes some cpu, but I want something
+ * simple atm.
+ */
+static void delete_center_node(struct dm_btree_info *info, struct node *parent,
+                              struct child *l, struct child *c, struct child *r,
+                              struct node *left, struct node *center, struct node *right,
+                              uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
+{
+       uint32_t max_entries = le32_to_cpu(left->header.max_entries);
+       unsigned shift = min(max_entries - nr_left, nr_center);
+
+       BUG_ON(nr_left + shift > max_entries);
+       node_copy(left, center, -shift);
+       left->header.nr_entries = cpu_to_le32(nr_left + shift);
+
+       if (shift != nr_center) {
+               shift = nr_center - shift;
+               BUG_ON((nr_right + shift) > max_entries);
+               node_shift(right, shift);
+               node_copy(center, right, shift);
+               right->header.nr_entries = cpu_to_le32(nr_right + shift);
+       }
+       *key_ptr(parent, r->index) = right->keys[0];
+
+       delete_at(parent, c->index);
+       r->index--;
+
+       dm_tm_dec(info->tm, dm_block_location(c->block));
+       __rebalance2(info, parent, l, r);
+}
+
+/*
+ * Redistributes entries among 3 sibling nodes.
+ */
+static void redistribute3(struct dm_btree_info *info, struct node *parent,
+                         struct child *l, struct child *c, struct child *r,
+                         struct node *left, struct node *center, struct node *right,
+                         uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
+{
+       int s;
+       uint32_t max_entries = le32_to_cpu(left->header.max_entries);
+       unsigned target = (nr_left + nr_center + nr_right) / 3;
+       BUG_ON(target > max_entries);
+
+       if (nr_left < nr_right) {
+               s = nr_left - target;
+
+               if (s < 0 && nr_center < -s) {
+                       /* not enough in central node */
+                       shift(left, center, nr_center);
+                       s = nr_center - target;
+                       shift(left, right, s);
+                       nr_right += s;
+               } else
+                       shift(left, center, s);
+
+               shift(center, right, target - nr_right);
+
+       } else {
+               s = target - nr_right;
+               if (s > 0 && nr_center < s) {
+                       /* not enough in central node */
+                       shift(center, right, nr_center);
+                       s = target - nr_center;
+                       shift(left, right, s);
+                       nr_left -= s;
+               } else
+                       shift(center, right, s);
+
+               shift(left, center, nr_left - target);
+       }
+
+       *key_ptr(parent, c->index) = center->keys[0];
+       *key_ptr(parent, r->index) = right->keys[0];
+}
+
 static void __rebalance3(struct dm_btree_info *info, struct node *parent,
                         struct child *l, struct child *c, struct child *r)
 {
@@ -282,62 +353,18 @@ static void __rebalance3(struct dm_btree_info *info, struct node *parent,
        uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
        uint32_t nr_center = le32_to_cpu(center->header.nr_entries);
        uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
-       uint32_t max_entries = le32_to_cpu(left->header.max_entries);
 
-       unsigned target;
+       unsigned threshold = merge_threshold(left) * 4 + 1;
 
        BUG_ON(left->header.max_entries != center->header.max_entries);
        BUG_ON(center->header.max_entries != right->header.max_entries);
 
-       if (((nr_left + nr_center + nr_right) / 2) < merge_threshold(center)) {
-               /*
-                * Delete center node:
-                *
-                * We dump as many entries from center as possible into
-                * left, then the rest in right, then rebalance2.  This
-                * wastes some cpu, but I want something simple atm.
-                */
-               unsigned shift = min(max_entries - nr_left, nr_center);
-
-               BUG_ON(nr_left + shift > max_entries);
-               node_copy(left, center, -shift);
-               left->header.nr_entries = cpu_to_le32(nr_left + shift);
-
-               if (shift != nr_center) {
-                       shift = nr_center - shift;
-                       BUG_ON((nr_right + shift) >= max_entries);
-                       node_shift(right, shift);
-                       node_copy(center, right, shift);
-                       right->header.nr_entries = cpu_to_le32(nr_right + shift);
-               }
-               *key_ptr(parent, r->index) = right->keys[0];
-
-               delete_at(parent, c->index);
-               r->index--;
-
-               dm_tm_dec(info->tm, dm_block_location(c->block));
-               __rebalance2(info, parent, l, r);
-
-               return;
-       }
-
-       /*
-        * Rebalance
-        */
-       target = (nr_left + nr_center + nr_right) / 3;
-       BUG_ON(target > max_entries);
-
-       /*
-        * Adjust the left node
-        */
-       shift(left, center, nr_left - target);
-
-       /*
-        * Adjust the right node
-        */
-       shift(center, right, target - nr_right);
-       *key_ptr(parent, c->index) = center->keys[0];
-       *key_ptr(parent, r->index) = right->keys[0];
+       if ((nr_left + nr_center + nr_right) < threshold)
+               delete_center_node(info, parent, l, c, r, left, center, right,
+                                  nr_left, nr_center, nr_right);
+       else
+               redistribute3(info, parent, l, c, r, left, center, right,
+                             nr_left, nr_center, nr_right);
 }
 
 static int rebalance3(struct shadow_spine *s, struct dm_btree_info *info,
@@ -441,9 +468,6 @@ static int rebalance_children(struct shadow_spine *s,
        if (r)
                return r;
 
-       if (child_entries > del_threshold(n))
-               return 0;
-
        has_left_sibling = i > 0;
        has_right_sibling = i < (le32_to_cpu(n->header.nr_entries) - 1);
 
@@ -496,7 +520,7 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
                 */
                if (shadow_has_parent(s)) {
                        __le64 location = cpu_to_le64(dm_block_location(shadow_current(s)));
-                       memcpy(value_ptr(dm_block_data(shadow_parent(s)), i, sizeof(__le64)),
+                       memcpy(value_ptr(dm_block_data(shadow_parent(s)), i),
                               &location, sizeof(__le64));
                }
 
@@ -553,7 +577,7 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
 
                if (info->value_type.dec)
                        info->value_type.dec(info->value_type.context,
-                                            value_ptr(n, index, info->value_type.size));
+                                            value_ptr(n, index));
 
                delete_at(n, index);
        }
index bd1e7ff..d12b2cc 100644 (file)
@@ -74,8 +74,7 @@ void inc_children(struct dm_transaction_manager *tm, struct node *n,
                        dm_tm_inc(tm, value64(n, i));
        else if (vt->inc)
                for (i = 0; i < nr_entries; i++)
-                       vt->inc(vt->context,
-                               value_ptr(n, i, vt->size));
+                       vt->inc(vt->context, value_ptr(n, i));
 }
 
 static int insert_at(size_t value_size, struct node *node, unsigned index,
@@ -281,7 +280,7 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
 
                                for (i = 0; i < f->nr_children; i++)
                                        info->value_type.dec(info->value_type.context,
-                                                            value_ptr(f->n, i, info->value_type.size));
+                                                            value_ptr(f->n, i));
                        }
                        f->current_child = f->nr_children;
                }
@@ -320,7 +319,7 @@ static int btree_lookup_raw(struct ro_spine *s, dm_block_t block, uint64_t key,
        } while (!(flags & LEAF_NODE));
 
        *result_key = le64_to_cpu(ro_node(s)->keys[i]);
-       memcpy(v, value_ptr(ro_node(s), i, value_size), value_size);
+       memcpy(v, value_ptr(ro_node(s), i), value_size);
 
        return 0;
 }
@@ -432,7 +431,7 @@ static int btree_split_sibling(struct shadow_spine *s, dm_block_t root,
 
        size = le32_to_cpu(ln->header.flags) & INTERNAL_NODE ?
                sizeof(uint64_t) : s->info->value_type.size;
-       memcpy(value_ptr(rn, 0, size), value_ptr(ln, nr_left, size),
+       memcpy(value_ptr(rn, 0), value_ptr(ln, nr_left),
               size * nr_right);
 
        /*
@@ -443,7 +442,7 @@ static int btree_split_sibling(struct shadow_spine *s, dm_block_t root,
        pn = dm_block_data(parent);
        location = cpu_to_le64(dm_block_location(left));
        __dm_bless_for_disk(&location);
-       memcpy_disk(value_ptr(pn, parent_index, sizeof(__le64)),
+       memcpy_disk(value_ptr(pn, parent_index),
                    &location, sizeof(__le64));
 
        location = cpu_to_le64(dm_block_location(right));
@@ -529,8 +528,8 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
 
        size = le32_to_cpu(pn->header.flags) & INTERNAL_NODE ?
                sizeof(__le64) : s->info->value_type.size;
-       memcpy(value_ptr(ln, 0, size), value_ptr(pn, 0, size), nr_left * size);
-       memcpy(value_ptr(rn, 0, size), value_ptr(pn, nr_left, size),
+       memcpy(value_ptr(ln, 0), value_ptr(pn, 0), nr_left * size);
+       memcpy(value_ptr(rn, 0), value_ptr(pn, nr_left),
               nr_right * size);
 
        /* new_parent should just point to l and r now */
@@ -545,12 +544,12 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
        val = cpu_to_le64(dm_block_location(left));
        __dm_bless_for_disk(&val);
        pn->keys[0] = ln->keys[0];
-       memcpy_disk(value_ptr(pn, 0, sizeof(__le64)), &val, sizeof(__le64));
+       memcpy_disk(value_ptr(pn, 0), &val, sizeof(__le64));
 
        val = cpu_to_le64(dm_block_location(right));
        __dm_bless_for_disk(&val);
        pn->keys[1] = rn->keys[0];
-       memcpy_disk(value_ptr(pn, 1, sizeof(__le64)), &val, sizeof(__le64));
+       memcpy_disk(value_ptr(pn, 1), &val, sizeof(__le64));
 
        /*
         * rejig the spine.  This is ugly, since it knows too
@@ -595,7 +594,7 @@ static int btree_insert_raw(struct shadow_spine *s, dm_block_t root,
                        __le64 location = cpu_to_le64(dm_block_location(shadow_current(s)));
 
                        __dm_bless_for_disk(&location);
-                       memcpy_disk(value_ptr(dm_block_data(shadow_parent(s)), i, sizeof(uint64_t)),
+                       memcpy_disk(value_ptr(dm_block_data(shadow_parent(s)), i),
                                    &location, sizeof(__le64));
                }
 
@@ -710,12 +709,12 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
                    (!info->value_type.equal ||
                     !info->value_type.equal(
                             info->value_type.context,
-                            value_ptr(n, index, info->value_type.size),
+                            value_ptr(n, index),
                             value))) {
                        info->value_type.dec(info->value_type.context,
-                                            value_ptr(n, index, info->value_type.size));
+                                            value_ptr(n, index));
                }
-               memcpy_disk(value_ptr(n, index, info->value_type.size),
+               memcpy_disk(value_ptr(n, index),
                            value, info->value_type.size);
        }
 
index df2494c..ff3beed 100644 (file)
@@ -405,8 +405,6 @@ int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
                if (r < 0)
                        return r;
 
-#if 0
-               /* FIXME: dm_btree_remove doesn't handle this yet */
                if (old > 2) {
                        r = dm_btree_remove(&ll->ref_count_info,
                                            ll->ref_count_root,
@@ -414,7 +412,6 @@ int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
                        if (r)
                                return r;
                }
-#endif
 
        } else {
                __le32 le_rc = cpu_to_le32(ref_count);
index 8295854..f80407e 100644 (file)
@@ -29,5 +29,5 @@ obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
index cb2c98f..ba84936 100644 (file)
@@ -168,7 +168,7 @@ int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction)
        int i;
 
        if (0 == divisor)
-               return -1;
+               return -EINVAL;
 
        q = dividend / divisor;
        remainder = dividend - q * divisor;
@@ -194,10 +194,13 @@ static int max2165_set_rf(struct max2165_priv *priv, u32 freq)
        u8 tf_ntch;
        u32 t;
        u32 quotient, fraction;
+       int ret;
 
        /* Set PLL divider according to RF frequency */
-       fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
-               &quotient, &fraction);
+       ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
+                        &quotient, &fraction);
+       if (ret != 0)
+               return ret;
 
        /* 20-bit fraction */
        fraction >>= 12;
index c89af3c..0ed9091 100644 (file)
@@ -350,7 +350,7 @@ static int MT2063_Sleep(struct dvb_frontend *fe)
        /*
         *  ToDo:  Add code here to implement a OS blocking
         */
-       msleep(10);
+       msleep(100);
 
        return 0;
 }
@@ -2226,7 +2226,7 @@ static struct dvb_tuner_ops mt2063_ops = {
        .info = {
                 .name = "MT2063 Silicon Tuner",
                 .frequency_min = 45000000,
-                .frequency_max = 850000000,
+                .frequency_max = 865000000,
                 .frequency_step = 0,
                 },
 
index 62d0e8e..3f5cfd9 100644 (file)
@@ -23,10 +23,6 @@ static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe,
        return NULL;
 }
 
-int mt2063_setTune(struct dvb_frontend *fe, u32 f_in,
-                                  u32 bw_in,
-                                  enum MTTune_atv_standard tv_type);
-
 /* FIXME: Should use the standard DVB attachment interfaces */
 unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe);
 unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe);
index e13683b..2da4440 100644 (file)
@@ -1868,6 +1868,10 @@ struct tunertype tuners[] = {
                .params = tuner_tena_tnf_5337_params,
                .count  = ARRAY_SIZE(tuner_tena_tnf_5337_params),
        },
+       [TUNER_XC5000C] = { /* Xceive 5000C */
+               .name   = "Xceive 5000C tuner",
+               /* see xc5000.c for details */
+       },
 };
 EXPORT_SYMBOL(tuners);
 
index 296df05..7f98984 100644 (file)
@@ -49,9 +49,6 @@ static LIST_HEAD(hybrid_tuner_instance_list);
 #define dprintk(level, fmt, arg...) if (debug >= level) \
        printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
-#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
-#define XC5000_DEFAULT_FIRMWARE_SIZE 12401
-
 struct xc5000_priv {
        struct tuner_i2c_props i2c_props;
        struct list_head hybrid_tuner_instance_list;
@@ -62,6 +59,8 @@ struct xc5000_priv {
        u8  video_standard;
        u8  rf_mode;
        u8  radio_input;
+
+       int chip_id;
 };
 
 /* Misc Defines */
@@ -204,6 +203,33 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
        {"FM Radio-INPUT1_MONO", 0x0278, 0x9002}
 };
 
+
+struct xc5000_fw_cfg {
+       char *name;
+       u16 size;
+};
+
+static const struct xc5000_fw_cfg xc5000a_1_6_114 = {
+       .name = "dvb-fe-xc5000-1.6.114.fw",
+       .size = 12401,
+};
+
+static const struct xc5000_fw_cfg xc5000c_41_024_5_31875 = {
+       .name = "dvb-fe-xc5000c-41.024.5-31875.fw",
+       .size = 16503,
+};
+
+static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id)
+{
+       switch (chip_id) {
+       default:
+       case XC5000A:
+               return &xc5000a_1_6_114;
+       case XC5000C:
+               return &xc5000c_41_024_5_31875;
+       }
+}
+
 static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
 static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
 static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
@@ -552,12 +578,14 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
        struct xc5000_priv *priv = fe->tuner_priv;
        const struct firmware *fw;
        int ret;
+       const struct xc5000_fw_cfg *desired_fw =
+               xc5000_assign_firmware(priv->chip_id);
 
        /* request the firmware, this will block and timeout */
        printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
-               XC5000_DEFAULT_FIRMWARE);
+               desired_fw->name);
 
-       ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
+       ret = request_firmware(&fw, desired_fw->name,
                priv->i2c_props.adap->dev.parent);
        if (ret) {
                printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
@@ -569,7 +597,7 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
                ret = XC_RESULT_SUCCESS;
        }
 
-       if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) {
+       if (fw->size != desired_fw->size) {
                printk(KERN_ERR "xc5000: firmware incorrect size\n");
                ret = XC_RESULT_RESET_FAILURE;
        } else {
@@ -1139,6 +1167,13 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
        if (priv->radio_input == 0)
                priv->radio_input = cfg->radio_input;
 
+       /* don't override chip id if it's already been set
+          unless explicitly specified */
+       if ((priv->chip_id == 0) || (cfg->chip_id))
+               /* use default chip id if none specified, set to 0 so
+                  it can be overridden if this is a hybrid driver */
+               priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0;
+
        /* Check if firmware has been loaded. It is possible that another
           instance of the driver has loaded the firmware.
         */
index e295745..3396f8e 100644 (file)
 struct dvb_frontend;
 struct i2c_adapter;
 
+#define XC5000A 1
+#define XC5000C 2
+
 struct xc5000_config {
        u8   i2c_address;
        u32  if_khz;
        u8   radio_input;
+
+       int chip_id;
 };
 
 /* xc5000 callback command */
index ce4f858..d88c4aa 100644 (file)
@@ -578,6 +578,7 @@ static int demod_attach_drxk(struct ddb_input *input)
        struct drxk_config config;
 
        memset(&config, 0, sizeof(config));
+       config.microcode_name = "drxk_a3.mc";
        config.adr = 0x29 + (input->nr & 1);
 
        fe = input->fe = dvb_attach(drxk_attach, &config, i2c);
index 6d14893..8b1b41d 100644 (file)
@@ -32,8 +32,6 @@
 #include <asm/dma.h>
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/ca.h>
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
 #include <linux/socket.h>
 
 #include "dmxdev.h"
index fbbe545..4555baa 100644 (file)
@@ -655,6 +655,8 @@ restart:
                                        dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
                                        re_tune = true;
                                        fepriv->state = FESTATE_TUNED;
+                               } else {
+                                       re_tune = false;
                                }
 
                                if (fe->ops.tune)
index 9f203c6..63bf456 100644 (file)
@@ -361,6 +361,14 @@ config DVB_USB_EC168
        help
          Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
 
+config DVB_USB_AZ6007
+       tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
+       depends on DVB_USB
+       select DVB_DRXK if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support theAfatech AF9005 based DVB-T/DVB-C receivers.
+
 config DVB_USB_AZ6027
        tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
        depends on DVB_USB
@@ -378,6 +386,7 @@ config DVB_USB_LME2510
        select DVB_IX2505V if !DVB_FE_CUSTOMISE
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_PLL if !DVB_FE_CUSTOMISE
+       select DVB_M88RS2000 if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
 
@@ -403,3 +412,13 @@ config DVB_USB_MXL111SF
        select VIDEO_TVEEPROM
        help
          Say Y here to support the MxL111SF USB2.0 DTV receiver.
+
+config DVB_USB_RTL28XXU
+       tristate "Realtek RTL28xxU DVB USB support"
+       depends on DVB_USB && EXPERIMENTAL
+       select DVB_RTL2830
+       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+       help
+         Say Y here to support the Realtek RTL28xxU DVB USB receiver.
index 26c8b9e..b76acb5 100644 (file)
@@ -54,7 +54,6 @@ obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
 dvb-usb-opera-objs = opera1.o
 obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
 
-
 dvb-usb-af9005-objs = af9005.o af9005-fe.o
 obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
 
@@ -88,6 +87,9 @@ obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
 dvb-usb-ec168-objs = ec168.o
 obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
 
+dvb-usb-az6007-objs = az6007.o
+obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o
+
 dvb-usb-az6027-objs = az6027.o
 obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
 
@@ -105,8 +107,12 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o
 obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o
 obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+dvb-usb-rtl28xxu-objs = rtl28xxu.o
+obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
 # due to tuner-xc3028
-ccflags-y += -Idrivers/media/common/tuners
-EXTRA_CFLAGS += -Idrivers/media/dvb/ttpci
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci
 
index 282a43d..7e70ea5 100644 (file)
@@ -1164,6 +1164,41 @@ static int af9015_af9013_sleep(struct dvb_frontend *fe)
        return ret;
 }
 
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_init(struct dvb_frontend *fe)
+{
+       int ret;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct af9015_state *priv = adap->dev->priv;
+
+       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+               return -EAGAIN;
+
+       ret = priv->tuner_init[adap->id](fe);
+
+       mutex_unlock(&adap->dev->usb_mutex);
+
+       return ret;
+}
+
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_sleep(struct dvb_frontend *fe)
+{
+       int ret;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct af9015_state *priv = adap->dev->priv;
+
+       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+               return -EAGAIN;
+
+       ret = priv->tuner_sleep[adap->id](fe);
+
+       mutex_unlock(&adap->dev->usb_mutex);
+
+       return ret;
+}
+
+
 static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
@@ -1283,6 +1318,7 @@ static struct mxl5007t_config af9015_mxl5007t_config = {
 static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
+       struct af9015_state *state = adap->dev->priv;
        deb_info("%s:\n", __func__);
 
        switch (af9015_af9013_config[adap->id].tuner) {
@@ -1340,6 +1376,19 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
                err("Unknown tuner id:%d",
                        af9015_af9013_config[adap->id].tuner);
        }
+
+       if (adap->fe_adap[0].fe->ops.tuner_ops.init) {
+               state->tuner_init[adap->id] =
+                       adap->fe_adap[0].fe->ops.tuner_ops.init;
+               adap->fe_adap[0].fe->ops.tuner_ops.init = af9015_tuner_init;
+       }
+
+       if (adap->fe_adap[0].fe->ops.tuner_ops.sleep) {
+               state->tuner_sleep[adap->id] =
+                       adap->fe_adap[0].fe->ops.tuner_ops.sleep;
+               adap->fe_adap[0].fe->ops.tuner_ops.sleep = af9015_tuner_sleep;
+       }
+
        return ret;
 }
 
index f619063..2f68419 100644 (file)
@@ -108,6 +108,8 @@ struct af9015_state {
        int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status);
        int (*init[2]) (struct dvb_frontend *fe);
        int (*sleep[2]) (struct dvb_frontend *fe);
+       int (*tuner_init[2]) (struct dvb_frontend *fe);
+       int (*tuner_sleep[2]) (struct dvb_frontend *fe);
 };
 
 struct af9015_config {
index cf0c318..03c2865 100644 (file)
@@ -58,7 +58,7 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
        u8 *rbuf, u8 rlen)
 {
        struct anysee_state *state = d->priv;
-       int act_len, ret;
+       int act_len, ret, i;
        u8 buf[64];
 
        memcpy(&buf[0], sbuf, slen);
@@ -73,26 +73,52 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
        /* We need receive one message more after dvb_usb_generic_rw due
           to weird transaction flow, which is 1 x send + 2 x receive. */
        ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
-       if (!ret) {
+       if (ret)
+               goto error_unlock;
+
+       /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32
+        * (EPIPE, Broken pipe). Function supports currently msleep() as a
+        * parameter but I would not like to use it, since according to
+        * Documentation/timers/timers-howto.txt it should not be used such
+        * short, under < 20ms, sleeps. Repeating failed message would be
+        * better choice as not to add unwanted delays...
+        * Fixing that correctly is one of those or both;
+        * 1) use repeat if possible
+        * 2) add suitable delay
+        */
+
+       /* get answer, retry few times if error returned */
+       for (i = 0; i < 3; i++) {
                /* receive 2nd answer */
                ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
                        d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf),
                        &act_len, 2000);
-               if (ret)
-                       err("%s: recv bulk message failed: %d", __func__, ret);
-               else {
+
+               if (ret) {
+                       deb_info("%s: recv bulk message failed: %d",
+                                       __func__, ret);
+               } else {
                        deb_xfer("<<< ");
                        debug_dump(buf, rlen, deb_xfer);
 
                        if (buf[63] != 0x4f)
                                deb_info("%s: cmd failed\n", __func__);
+
+                       break;
                }
        }
 
+       if (ret) {
+               /* all retries failed, it is fatal */
+               err("%s: recv bulk message failed: %d", __func__, ret);
+               goto error_unlock;
+       }
+
        /* read request, copy returned data to return buf */
-       if (!ret && rbuf && rlen)
+       if (rbuf && rlen)
                memcpy(rbuf, buf, rlen);
 
+error_unlock:
        mutex_unlock(&anysee_usb_mutex);
 
        return ret;
diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c
new file mode 100644 (file)
index 0000000..4008b9c
--- /dev/null
@@ -0,0 +1,957 @@
+/*
+ * Driver for AzureWave 6007 DVB-C/T USB2.0 and clones
+ *
+ * Copyright (c) Henry Wang <Henry.wang@AzureWave.com>
+ *
+ * This driver was made publicly available by Terratec, at:
+ *     http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
+ * The original driver's license is GPL, as declared with MODULE_LICENSE()
+ *
+ * Copyright (c) 2010-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *     Driver modified by in order to work with upstream drxk driver, and
+ *     tons of bugs got fixed.
+ *
+ * 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 under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "drxk.h"
+#include "mt2063.h"
+#include "dvb_ca_en50221.h"
+
+#define DVB_USB_LOG_PREFIX "az6007"
+#include "dvb-usb.h"
+
+/* debug */
+int dvb_usb_az6007_debug;
+module_param_named(debug, dvb_usb_az6007_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))."
+                DVB_USB_DEBUG_STATUS);
+
+#define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_az6007_debug, 0x04, args)
+#define deb_fe(args...)   dprintk(dvb_usb_az6007_debug, 0x08, args)
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* Known requests (Cypress FX2 firmware + az6007 "private" ones*/
+
+#define FX2_OED                        0xb5
+#define AZ6007_READ_DATA       0xb7
+#define AZ6007_I2C_RD          0xb9
+#define AZ6007_POWER           0xbc
+#define AZ6007_I2C_WR          0xbd
+#define FX2_SCON1              0xc0
+#define AZ6007_TS_THROUGH      0xc7
+#define AZ6007_READ_IR         0xb4
+
+struct az6007_device_state {
+       struct mutex            mutex;
+       struct mutex            ca_mutex;
+       struct dvb_ca_en50221   ca;
+       unsigned                warm:1;
+       int                     (*gate_ctrl) (struct dvb_frontend *, int);
+       unsigned char           data[4096];
+};
+
+static struct drxk_config terratec_h7_drxk = {
+       .adr = 0x29,
+       .parallel_ts = true,
+       .dynamic_clk = true,
+       .single_master = true,
+       .enable_merr_cfg = true,
+       .no_i2c_bridge = false,
+       .chunk_size = 64,
+       .mpeg_out_clk_strength = 0x02,
+       .microcode_name = "dvb-usb-terratec-h7-drxk.fw",
+};
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct dvb_usb_adapter *adap = fe->sec_priv;
+       struct az6007_device_state *st;
+       int status = 0;
+
+       deb_info("%s: %s\n", __func__, enable ? "enable" : "disable");
+
+       if (!adap)
+               return -EINVAL;
+
+       st = adap->dev->priv;
+
+       if (!st)
+               return -EINVAL;
+
+       if (enable)
+               status = st->gate_ctrl(fe, 1);
+       else
+               status = st->gate_ctrl(fe, 0);
+
+       return status;
+}
+
+static struct mt2063_config az6007_mt2063_config = {
+       .tuner_address = 0x60,
+       .refclock = 36125000,
+};
+
+static int __az6007_read(struct usb_device *udev, u8 req, u16 value,
+                           u16 index, u8 *b, int blen)
+{
+       int ret;
+
+       ret = usb_control_msg(udev,
+                             usb_rcvctrlpipe(udev, 0),
+                             req,
+                             USB_TYPE_VENDOR | USB_DIR_IN,
+                             value, index, b, blen, 5000);
+       if (ret < 0) {
+               warn("usb read operation failed. (%d)", ret);
+               return -EIO;
+       }
+
+       deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
+                index);
+       debug_dump(b, blen, deb_xfer);
+
+       return ret;
+}
+
+static int az6007_read(struct dvb_usb_device *d, u8 req, u16 value,
+                           u16 index, u8 *b, int blen)
+{
+       struct az6007_device_state *st = d->priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&st->mutex) < 0)
+               return -EAGAIN;
+
+       ret = __az6007_read(d->udev, req, value, index, b, blen);
+
+       mutex_unlock(&st->mutex);
+
+       return ret;
+}
+
+static int __az6007_write(struct usb_device *udev, u8 req, u16 value,
+                            u16 index, u8 *b, int blen)
+{
+       int ret;
+
+       deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
+                index);
+       debug_dump(b, blen, deb_xfer);
+
+       if (blen > 64) {
+               err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n",
+                   blen);
+               return -EOPNOTSUPP;
+       }
+
+       ret = usb_control_msg(udev,
+                             usb_sndctrlpipe(udev, 0),
+                             req,
+                             USB_TYPE_VENDOR | USB_DIR_OUT,
+                             value, index, b, blen, 5000);
+       if (ret != blen) {
+               err("usb write operation failed. (%d)", ret);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value,
+                           u16 index, u8 *b, int blen)
+{
+       struct az6007_device_state *st = d->priv;
+       int ret;
+
+       if (mutex_lock_interruptible(&st->mutex) < 0)
+               return -EAGAIN;
+
+       ret = __az6007_write(d->udev, req, value, index, b, blen);
+
+       mutex_unlock(&st->mutex);
+
+       return ret;
+}
+
+static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       struct dvb_usb_device *d = adap->dev;
+
+       deb_info("%s: %s", __func__, onoff ? "enable" : "disable");
+
+       return az6007_write(d, 0xbc, onoff, 0, NULL, 0);
+}
+
+/* remote control stuff (does not work with my box) */
+static int az6007_rc_query(struct dvb_usb_device *d)
+{
+       struct az6007_device_state *st = d->priv;
+       unsigned code = 0;
+
+       az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
+
+       if (st->data[1] == 0x44)
+               return 0;
+
+       if ((st->data[1] ^ st->data[2]) == 0xff)
+               code = st->data[1];
+       else
+               code = st->data[1] << 8 | st->data[2];
+
+       if ((st->data[3] ^ st->data[4]) == 0xff)
+               code = code << 8 | st->data[3];
+       else
+               code = code << 16 | st->data[3] << 8 | st->data[4];
+
+       rc_keydown(d->rc_dev, code, st->data[5]);
+
+       return 0;
+}
+
+static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+                                       int slot,
+                                       int address)
+{
+       struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+       int ret;
+       u8 req;
+       u16 value;
+       u16 index;
+       int blen;
+       u8 *b;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       b = kmalloc(12, GFP_KERNEL);
+       if (!b)
+               return -ENOMEM;
+
+       mutex_lock(&state->ca_mutex);
+
+       req = 0xC1;
+       value = address;
+       index = 0;
+       blen = 1;
+
+       ret = az6007_read(d, req, value, index, b, blen);
+       if (ret < 0) {
+               warn("usb in operation failed. (%d)", ret);
+               ret = -EINVAL;
+       } else {
+               ret = b[0];
+       }
+
+       mutex_unlock(&state->ca_mutex);
+       kfree(b);
+       return ret;
+}
+
+static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+                                        int slot,
+                                        int address,
+                                        u8 value)
+{
+       struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+       int ret;
+       u8 req;
+       u16 value1;
+       u16 index;
+       int blen;
+
+       deb_info("%s %d", __func__, slot);
+       if (slot != 0)
+               return -EINVAL;
+
+       mutex_lock(&state->ca_mutex);
+       req = 0xC2;
+       value1 = address;
+       index = value;
+       blen = 0;
+
+       ret = az6007_write(d, req, value1, index, NULL, blen);
+       if (ret != 0)
+               warn("usb out operation failed. (%d)", ret);
+
+       mutex_unlock(&state->ca_mutex);
+       return ret;
+}
+
+static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+                                     int slot,
+                                     u8 address)
+{
+       struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+       int ret;
+       u8 req;
+       u16 value;
+       u16 index;
+       int blen;
+       u8 *b;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       b = kmalloc(12, GFP_KERNEL);
+       if (!b)
+               return -ENOMEM;
+
+       mutex_lock(&state->ca_mutex);
+
+       req = 0xC3;
+       value = address;
+       index = 0;
+       blen = 2;
+
+       ret = az6007_read(d, req, value, index, b, blen);
+       if (ret < 0) {
+               warn("usb in operation failed. (%d)", ret);
+               ret = -EINVAL;
+       } else {
+               if (b[0] == 0)
+                       warn("Read CI IO error");
+
+               ret = b[1];
+               deb_info("read cam data = %x from 0x%x", b[1], value);
+       }
+
+       mutex_unlock(&state->ca_mutex);
+       kfree(b);
+       return ret;
+}
+
+static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+                                      int slot,
+                                      u8 address,
+                                      u8 value)
+{
+       struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+       int ret;
+       u8 req;
+       u16 value1;
+       u16 index;
+       int blen;
+
+       if (slot != 0)
+               return -EINVAL;
+
+       mutex_lock(&state->ca_mutex);
+       req = 0xC4;
+       value1 = address;
+       index = value;
+       blen = 0;
+
+       ret = az6007_write(d, req, value1, index, NULL, blen);
+       if (ret != 0) {
+               warn("usb out operation failed. (%d)", ret);
+               goto failed;
+       }
+
+failed:
+       mutex_unlock(&state->ca_mutex);
+       return ret;
+}
+
+static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+
+       int ret;
+       u8 req;
+       u16 value;
+       u16 index;
+       int blen;
+       u8 *b;
+
+       b = kmalloc(12, GFP_KERNEL);
+       if (!b)
+               return -ENOMEM;
+
+       req = 0xC8;
+       value = 0;
+       index = 0;
+       blen = 1;
+
+       ret = az6007_read(d, req, value, index, b, blen);
+       if (ret < 0) {
+               warn("usb in operation failed. (%d)", ret);
+               ret = -EIO;
+       } else{
+               ret = b[0];
+       }
+       kfree(b);
+       return ret;
+}
+
+static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+       int ret, i;
+       u8 req;
+       u16 value;
+       u16 index;
+       int blen;
+
+       mutex_lock(&state->ca_mutex);
+
+       req = 0xC6;
+       value = 1;
+       index = 0;
+       blen = 0;
+
+       ret = az6007_write(d, req, value, index, NULL, blen);
+       if (ret != 0) {
+               warn("usb out operation failed. (%d)", ret);
+               goto failed;
+       }
+
+       msleep(500);
+       req = 0xC6;
+       value = 0;
+       index = 0;
+       blen = 0;
+
+       ret = az6007_write(d, req, value, index, NULL, blen);
+       if (ret != 0) {
+               warn("usb out operation failed. (%d)", ret);
+               goto failed;
+       }
+
+       for (i = 0; i < 15; i++) {
+               msleep(100);
+
+               if (CI_CamReady(ca, slot)) {
+                       deb_info("CAM Ready");
+                       break;
+               }
+       }
+       msleep(5000);
+
+failed:
+       mutex_unlock(&state->ca_mutex);
+       return ret;
+}
+
+static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+       return 0;
+}
+
+static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+
+       int ret;
+       u8 req;
+       u16 value;
+       u16 index;
+       int blen;
+
+       deb_info("%s", __func__);
+       mutex_lock(&state->ca_mutex);
+       req = 0xC7;
+       value = 1;
+       index = 0;
+       blen = 0;
+
+       ret = az6007_write(d, req, value, index, NULL, blen);
+       if (ret != 0) {
+               warn("usb out operation failed. (%d)", ret);
+               goto failed;
+       }
+
+failed:
+       mutex_unlock(&state->ca_mutex);
+       return ret;
+}
+
+static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+       struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+       int ret;
+       u8 req;
+       u16 value;
+       u16 index;
+       int blen;
+       u8 *b;
+
+       b = kmalloc(12, GFP_KERNEL);
+       if (!b)
+               return -ENOMEM;
+       mutex_lock(&state->ca_mutex);
+
+       req = 0xC5;
+       value = 0;
+       index = 0;
+       blen = 1;
+
+       ret = az6007_read(d, req, value, index, b, blen);
+       if (ret < 0) {
+               warn("usb in operation failed. (%d)", ret);
+               ret = -EIO;
+       } else
+               ret = 0;
+
+       if (!ret && b[0] == 1) {
+               ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
+                     DVB_CA_EN50221_POLL_CAM_READY;
+       }
+
+       mutex_unlock(&state->ca_mutex);
+       kfree(b);
+       return ret;
+}
+
+
+static void az6007_ci_uninit(struct dvb_usb_device *d)
+{
+       struct az6007_device_state *state;
+
+       deb_info("%s", __func__);
+
+       if (NULL == d)
+               return;
+
+       state = (struct az6007_device_state *)d->priv;
+       if (NULL == state)
+               return;
+
+       if (NULL == state->ca.data)
+               return;
+
+       dvb_ca_en50221_release(&state->ca);
+
+       memset(&state->ca, 0, sizeof(state->ca));
+}
+
+
+static int az6007_ci_init(struct dvb_usb_adapter *a)
+{
+       struct dvb_usb_device *d = a->dev;
+       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+       int ret;
+
+       deb_info("%s", __func__);
+
+       mutex_init(&state->ca_mutex);
+
+       state->ca.owner                 = THIS_MODULE;
+       state->ca.read_attribute_mem    = az6007_ci_read_attribute_mem;
+       state->ca.write_attribute_mem   = az6007_ci_write_attribute_mem;
+       state->ca.read_cam_control      = az6007_ci_read_cam_control;
+       state->ca.write_cam_control     = az6007_ci_write_cam_control;
+       state->ca.slot_reset            = az6007_ci_slot_reset;
+       state->ca.slot_shutdown         = az6007_ci_slot_shutdown;
+       state->ca.slot_ts_enable        = az6007_ci_slot_ts_enable;
+       state->ca.poll_slot_status      = az6007_ci_poll_slot_status;
+       state->ca.data                  = d;
+
+       ret = dvb_ca_en50221_init(&a->dvb_adap,
+                                 &state->ca,
+                                 0, /* flags */
+                                 1);/* n_slots */
+       if (ret != 0) {
+               err("Cannot initialize CI: Error %d.", ret);
+               memset(&state->ca, 0, sizeof(state->ca));
+               return ret;
+       }
+
+       deb_info("CI initialized.");
+
+       return 0;
+}
+
+static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
+{
+       struct az6007_device_state *st = d->priv;
+       int ret;
+
+       ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 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]);
+
+       return ret;
+}
+
+static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct az6007_device_state *st = adap->dev->priv;
+
+       deb_info("attaching demod drxk");
+
+       adap->fe_adap[0].fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
+                                        &adap->dev->i2c_adap);
+       if (!adap->fe_adap[0].fe)
+               return -EINVAL;
+
+       adap->fe_adap[0].fe->sec_priv = adap;
+       st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl;
+       adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+       az6007_ci_init(adap);
+
+       return 0;
+}
+
+static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       deb_info("attaching tuner mt2063");
+
+       /* Attach mt2063 to DVB-C frontend */
+       if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
+               adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
+       if (!dvb_attach(mt2063_attach, adap->fe_adap[0].fe,
+                       &az6007_mt2063_config,
+                       &adap->dev->i2c_adap))
+               return -EINVAL;
+
+       if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
+               adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
+
+       return 0;
+}
+
+int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       struct az6007_device_state *st = d->priv;
+       int ret;
+
+       deb_info("%s()\n", __func__);
+
+       if (!st->warm) {
+               mutex_init(&st->mutex);
+
+               ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0);
+               if (ret < 0)
+                       return ret;
+               msleep(60);
+               ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
+               if (ret < 0)
+                       return ret;
+               msleep(100);
+               ret = az6007_write(d, AZ6007_POWER, 1, 3, NULL, 0);
+               if (ret < 0)
+                       return ret;
+               msleep(20);
+               ret = az6007_write(d, AZ6007_POWER, 1, 4, NULL, 0);
+               if (ret < 0)
+                       return ret;
+
+               msleep(400);
+               ret = az6007_write(d, FX2_SCON1, 0, 3, NULL, 0);
+               if (ret < 0)
+                       return ret;
+               msleep(150);
+               ret = az6007_write(d, FX2_SCON1, 1, 3, NULL, 0);
+               if (ret < 0)
+                       return ret;
+               msleep(430);
+               ret = az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
+               if (ret < 0)
+                       return ret;
+
+               st->warm = true;
+
+               return 0;
+       }
+
+       if (!onoff)
+               return 0;
+
+       az6007_write(d, AZ6007_POWER, 0, 0, NULL, 0);
+       az6007_write(d, AZ6007_TS_THROUGH, 0, 0, NULL, 0);
+
+       return 0;
+}
+
+/* I2C */
+static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+                          int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct az6007_device_state *st = d->priv;
+       int i, j, len;
+       int ret = 0;
+       u16 index;
+       u16 value;
+       int length;
+       u8 req, addr;
+
+       if (mutex_lock_interruptible(&st->mutex) < 0)
+               return -EAGAIN;
+
+       for (i = 0; i < num; i++) {
+               addr = msgs[i].addr << 1;
+               if (((i + 1) < num)
+                   && (msgs[i].len == 1)
+                   && (!msgs[i].flags & I2C_M_RD)
+                   && (msgs[i + 1].flags & I2C_M_RD)
+                   && (msgs[i].addr == msgs[i + 1].addr)) {
+                       /*
+                        * A write + read xfer for the same address, where
+                        * the first xfer has just 1 byte length.
+                        * Need to join both into one operation
+                        */
+                       if (dvb_usb_az6007_debug & 2)
+                               printk(KERN_DEBUG
+                                      "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ",
+                                      addr, msgs[i].len, msgs[i + 1].len);
+                       req = AZ6007_I2C_RD;
+                       index = msgs[i].buf[0];
+                       value = addr | (1 << 8);
+                       length = 6 + msgs[i + 1].len;
+                       len = msgs[i + 1].len;
+                       ret = __az6007_read(d->udev, req, value, index,
+                                           st->data, length);
+                       if (ret >= len) {
+                               for (j = 0; j < len; j++) {
+                                       msgs[i + 1].buf[j] = st->data[j + 5];
+                                       if (dvb_usb_az6007_debug & 2)
+                                               printk(KERN_CONT
+                                                      "0x%02x ",
+                                                      msgs[i + 1].buf[j]);
+                               }
+                       } else
+                               ret = -EIO;
+                       i++;
+               } else if (!(msgs[i].flags & I2C_M_RD)) {
+                       /* write bytes */
+                       if (dvb_usb_az6007_debug & 2)
+                               printk(KERN_DEBUG
+                                      "az6007 I2C xfer write addr=0x%x len=%d: ",
+                                      addr, msgs[i].len);
+                       req = AZ6007_I2C_WR;
+                       index = msgs[i].buf[0];
+                       value = addr | (1 << 8);
+                       length = msgs[i].len - 1;
+                       len = msgs[i].len - 1;
+                       if (dvb_usb_az6007_debug & 2)
+                               printk(KERN_CONT "(0x%02x) ", msgs[i].buf[0]);
+                       for (j = 0; j < len; j++) {
+                               st->data[j] = msgs[i].buf[j + 1];
+                               if (dvb_usb_az6007_debug & 2)
+                                       printk(KERN_CONT "0x%02x ",
+                                              st->data[j]);
+                       }
+                       ret =  __az6007_write(d->udev, req, value, index,
+                                             st->data, length);
+               } else {
+                       /* read bytes */
+                       if (dvb_usb_az6007_debug & 2)
+                               printk(KERN_DEBUG
+                                      "az6007 I2C xfer read addr=0x%x len=%d: ",
+                                      addr, msgs[i].len);
+                       req = AZ6007_I2C_RD;
+                       index = msgs[i].buf[0];
+                       value = addr;
+                       length = msgs[i].len + 6;
+                       len = msgs[i].len;
+                       ret = __az6007_read(d->udev, req, value, index,
+                                           st->data, length);
+                       for (j = 0; j < len; j++) {
+                               msgs[i].buf[j] = st->data[j + 5];
+                               if (dvb_usb_az6007_debug & 2)
+                                       printk(KERN_CONT
+                                              "0x%02x ", st->data[j + 5]);
+                       }
+               }
+               if (dvb_usb_az6007_debug & 2)
+                       printk(KERN_CONT "\n");
+               if (ret < 0)
+                       goto err;
+       }
+err:
+       mutex_unlock(&st->mutex);
+
+       if (ret < 0) {
+               info("%s ERROR: %i", __func__, ret);
+               return ret;
+       }
+       return num;
+}
+
+static u32 az6007_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm az6007_i2c_algo = {
+       .master_xfer = az6007_i2c_xfer,
+       .functionality = az6007_i2c_func,
+};
+
+int az6007_identify_state(struct usb_device *udev,
+                         struct dvb_usb_device_properties *props,
+                         struct dvb_usb_device_description **desc, int *cold)
+{
+       int ret;
+       u8 *mac;
+
+       mac = kmalloc(6, GFP_ATOMIC);
+       if (!mac)
+               return -ENOMEM;
+
+       /* Try to read the mac address */
+       ret = __az6007_read(udev, AZ6007_READ_DATA, 6, 0, mac, 6);
+       if (ret == 6)
+               *cold = 0;
+       else
+               *cold = 1;
+
+       kfree(mac);
+
+       if (*cold) {
+               __az6007_write(udev, 0x09, 1, 0, NULL, 0);
+               __az6007_write(udev, 0x00, 0, 0, NULL, 0);
+               __az6007_write(udev, 0x00, 0, 0, NULL, 0);
+       }
+
+       deb_info("Device is on %s state\n", *cold ? "warm" : "cold");
+       return 0;
+}
+
+static struct dvb_usb_device_properties az6007_properties;
+
+static void az6007_usb_disconnect(struct usb_interface *intf)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+       az6007_ci_uninit(d);
+       dvb_usb_device_exit(intf);
+}
+
+static int az6007_usb_probe(struct usb_interface *intf,
+                           const struct usb_device_id *id)
+{
+       return dvb_usb_device_init(intf, &az6007_properties,
+                                  THIS_MODULE, NULL, adapter_nr);
+}
+
+static struct usb_device_id az6007_usb_table[] = {
+       {USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007)},
+       {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7)},
+       {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2)},
+       {0},
+};
+
+MODULE_DEVICE_TABLE(usb, az6007_usb_table);
+
+static struct dvb_usb_device_properties az6007_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = CYPRESS_FX2,
+       .firmware            = "dvb-usb-terratec-h7-az6007.fw",
+       .no_reconnect        = 1,
+       .size_of_priv        = sizeof(struct az6007_device_state),
+       .identify_state      = az6007_identify_state,
+       .num_adapters = 1,
+       .adapter = {
+               {
+               .num_frontends = 1,
+               .fe = {{
+                       .streaming_ctrl   = az6007_streaming_ctrl,
+                       .tuner_attach     = az6007_tuner_attach,
+                       .frontend_attach  = az6007_frontend_attach,
+
+                       /* parameter for the MPEG2-data transfer */
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 10,
+                               .endpoint = 0x02,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
+               } }
+       } },
+       .power_ctrl       = az6007_power_ctrl,
+       .read_mac_address = az6007_read_mac_addr,
+
+       .rc.core = {
+               .rc_interval      = 400,
+               .rc_codes         = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+               .module_name      = "az6007",
+               .rc_query         = az6007_rc_query,
+               .allowed_protos   = RC_TYPE_NEC,
+       },
+       .i2c_algo         = &az6007_i2c_algo,
+
+       .num_device_descs = 2,
+       .devices = {
+               { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)",
+                 .cold_ids = { &az6007_usb_table[0], NULL },
+                 .warm_ids = { NULL },
+               },
+               { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)",
+                 .cold_ids = { &az6007_usb_table[1], &az6007_usb_table[2], NULL },
+                 .warm_ids = { NULL },
+               },
+               { NULL },
+       }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver az6007_usb_driver = {
+       .name           = "dvb_usb_az6007",
+       .probe          = az6007_usb_probe,
+       .disconnect     = az6007_usb_disconnect,
+       .id_table       = az6007_usb_table,
+};
+
+/* module stuff */
+static int __init az6007_usb_module_init(void)
+{
+       int result;
+       deb_info("az6007 usb module init\n");
+
+       result = usb_register(&az6007_usb_driver);
+       if (result) {
+               err("usb_register failed. (%d)", result);
+               return result;
+       }
+
+       return 0;
+}
+
+static void __exit az6007_usb_module_exit(void)
+{
+       /* deregister this driver from the USB subsystem */
+       deb_info("az6007 usb module exit\n");
+       usb_deregister(&az6007_usb_driver);
+}
+
+module_init(az6007_usb_module_init);
+module_exit(az6007_usb_module_exit);
+
+MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
+MODULE_VERSION("1.1");
+MODULE_LICENSE("GPL");
index 070e82a..02290c6 100644 (file)
@@ -677,11 +677,9 @@ static void dib0700_rc_urb_completion(struct urb *purb)
        u8 toggle;
 
        deb_info("%s()\n", __func__);
-       if (d == NULL)
-               return;
-
        if (d->rc_dev == NULL) {
                /* This will occur if disable_rc_polling=1 */
+               kfree(purb->transfer_buffer);
                usb_free_urb(purb);
                return;
        }
@@ -690,6 +688,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
 
        if (purb->status < 0) {
                deb_info("discontinuing polling\n");
+               kfree(purb->transfer_buffer);
                usb_free_urb(purb);
                return;
        }
@@ -784,8 +783,11 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
                          dib0700_rc_urb_completion, d);
 
        ret = usb_submit_urb(purb, GFP_ATOMIC);
-       if (ret)
+       if (ret) {
                err("rc submit urb failed\n");
+               kfree(purb->transfer_buffer);
+               usb_free_urb(purb);
+       }
 
        return ret;
 }
index d390dda..397d8f2 100644 (file)
@@ -51,6 +51,7 @@
 #define USB_VID_PINNACLE                       0x2304
 #define USB_VID_PCTV                           0x2013
 #define USB_VID_PIXELVIEW                      0x1554
+#define USB_VID_REALTEK                                0x0bda
 #define USB_VID_TECHNOTREND                    0x0b48
 #define USB_VID_TERRATEC                       0x0ccd
 #define USB_VID_TELESTAR                       0x10b9
@@ -80,6 +81,7 @@
 #define USB_PID_ANSONIC_DVBT_USB                       0x6000
 #define USB_PID_ANYSEE                                 0x861f
 #define USB_PID_AZUREWAVE_AD_TU700                     0x3237
+#define USB_PID_AZUREWAVE_6007                         0x0ccd
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD                        0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM                        0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD               0xa800
 #define USB_PID_E3C_EC168_3                            0xfffb
 #define USB_PID_E3C_EC168_4                            0x1001
 #define USB_PID_E3C_EC168_5                            0x1002
+#define USB_PID_FREECOM_DVBT                           0x0160
+#define USB_PID_FREECOM_DVBT_2                         0x0161
 #define USB_PID_UNIWILL_STK7700P                       0x6003
 #define USB_PID_GENIUS_TVGO_DVB_T03                    0x4012
 #define USB_PID_GRANDTEC_DVBT_USB_COLD                 0x0fa0
 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS             0x0062
 #define USB_PID_TERRATEC_CINERGY_T_XXS                 0x0078
 #define USB_PID_TERRATEC_CINERGY_T_XXS_2               0x00ab
+#define USB_PID_TERRATEC_H7                            0x10b4
+#define USB_PID_TERRATEC_H7_2                          0x10a3
 #define USB_PID_TERRATEC_T3                            0x10a0
 #define USB_PID_TERRATEC_T5                            0x10a1
 #define USB_PID_PINNACLE_EXPRESSCARD_320CX             0x022e
 #define USB_PID_PCTV_400E                              0x020f
 #define USB_PID_PCTV_450E                              0x0222
 #define USB_PID_PCTV_452E                              0x021f
+#define USB_PID_REALTEK_RTL2831U                       0x2831
+#define USB_PID_REALTEK_RTL2832U                       0x2832
 #define USB_PID_TECHNOTREND_CONNECT_S2_3600            0x3007
 #define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI         0x300a
 #define USB_PID_NEBULA_DIGITV                          0x0201
index 9f01cd7..3b7b102 100644 (file)
@@ -64,6 +64,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 struct it913x_state {
        u8 id;
        struct ite_config it913x_config;
+       u8 pid_filter_onoff;
 };
 
 struct ite_config it913x_config;
@@ -259,15 +260,16 @@ static u32 it913x_query(struct usb_device *udev, u8 pro)
 
 static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
+       struct it913x_state *st = adap->dev->priv;
        struct usb_device *udev = adap->dev->udev;
        int ret;
        u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
 
-       if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
-                       return -EAGAIN;
+       mutex_lock(&adap->dev->i2c_mutex);
+
        deb_info(1, "PID_C  (%02x)", onoff);
 
-       ret = it913x_wr_reg(udev, pro, PID_EN, onoff);
+       ret = it913x_wr_reg(udev, pro, PID_EN, st->pid_filter_onoff);
 
        mutex_unlock(&adap->dev->i2c_mutex);
        return ret;
@@ -276,12 +278,13 @@ static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 static int it913x_pid_filter(struct dvb_usb_adapter *adap,
                int index, u16 pid, int onoff)
 {
+       struct it913x_state *st = adap->dev->priv;
        struct usb_device *udev = adap->dev->udev;
        int ret;
        u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
 
-       if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
-                       return -EAGAIN;
+       mutex_lock(&adap->dev->i2c_mutex);
+
        deb_info(1, "PID_F  (%02x)", onoff);
 
        ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff));
@@ -292,6 +295,13 @@ static int it913x_pid_filter(struct dvb_usb_adapter *adap,
 
        ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f));
 
+       if (udev->speed == USB_SPEED_HIGH && pid == 0x2000) {
+                       ret |= it913x_wr_reg(udev, pro, PID_EN, !onoff);
+                       st->pid_filter_onoff = !onoff;
+       } else
+               st->pid_filter_onoff =
+                       adap->fe_adap[adap->active_fe].pid_filtering;
+
        mutex_unlock(&adap->dev->i2c_mutex);
        return 0;
 }
@@ -316,8 +326,8 @@ static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        int ret;
        u32 reg;
        u8 pro;
-       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-                       return -EAGAIN;
+
+       mutex_lock(&d->i2c_mutex);
 
        debug_data_snipet(1, "Message out", msg[0].buf);
        deb_info(2, "num of messages %d address %02x", num, msg[0].addr);
@@ -358,8 +368,7 @@ static int it913x_rc_query(struct dvb_usb_device *d)
        int ret;
        u32 key;
        /* Avoid conflict with frontends*/
-       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-                       return -EAGAIN;
+       mutex_lock(&d->i2c_mutex);
 
        ret = it913x_io(d->udev, READ_LONG, PRO_LINK, CMD_IR_GET,
                0, 0, &ibuf[0], sizeof(ibuf));
@@ -388,19 +397,12 @@ static int ite_firmware_select(struct usb_device *udev,
 {
        int sw;
        /* auto switch */
-       if (le16_to_cpu(udev->descriptor.idProduct) ==
-                       USB_PID_ITETECH_IT9135)
-               sw = IT9135_V1_FW;
-       else if (le16_to_cpu(udev->descriptor.idProduct) ==
-                       USB_PID_ITETECH_IT9135_9005)
+       if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_KWORLD_2)
+               sw = IT9137_FW;
+       else if (it913x_config.chip_ver == 1)
                sw = IT9135_V1_FW;
-       else if (le16_to_cpu(udev->descriptor.idProduct) ==
-                       USB_PID_ITETECH_IT9135_9006) {
+       else
                sw = IT9135_V2_FW;
-               if (it913x_config.tuner_id_0 == 0)
-                       it913x_config.tuner_id_0 = IT9135_60;
-       } else
-               sw = IT9137_FW;
 
        /* force switch */
        if (dvb_usb_it913x_firmware != IT9135_AUTO)
@@ -410,41 +412,103 @@ static int ite_firmware_select(struct usb_device *udev,
        case IT9135_V1_FW:
                it913x_config.firmware_ver = 1;
                it913x_config.adc_x2 = 1;
+               it913x_config.read_slevel = false;
                props->firmware = fw_it9135_v1;
                break;
        case IT9135_V2_FW:
                it913x_config.firmware_ver = 1;
                it913x_config.adc_x2 = 1;
+               it913x_config.read_slevel = false;
                props->firmware = fw_it9135_v2;
+               switch (it913x_config.tuner_id_0) {
+               case IT9135_61:
+               case IT9135_62:
+                       break;
+               default:
+                       info("Unknown tuner ID applying default 0x60");
+               case IT9135_60:
+                       it913x_config.tuner_id_0 = IT9135_60;
+               }
                break;
        case IT9137_FW:
        default:
                it913x_config.firmware_ver = 0;
                it913x_config.adc_x2 = 0;
+               it913x_config.read_slevel = true;
                props->firmware = fw_it9137;
        }
 
        return 0;
 }
 
+static void it913x_select_remote(struct usb_device *udev,
+       struct dvb_usb_device_properties *props)
+{
+       switch (le16_to_cpu(udev->descriptor.idProduct)) {
+       case USB_PID_ITETECH_IT9135_9005:
+               props->rc.core.rc_codes = RC_MAP_IT913X_V2;
+               return;
+       default:
+               props->rc.core.rc_codes = RC_MAP_IT913X_V1;
+       }
+       return;
+}
+
 #define TS_MPEG_PKT_SIZE       188
 #define EP_LOW                 21
 #define TS_BUFFER_SIZE_PID     (EP_LOW*TS_MPEG_PKT_SIZE)
 #define EP_HIGH                        348
 #define TS_BUFFER_SIZE_MAX     (EP_HIGH*TS_MPEG_PKT_SIZE)
 
-static int it913x_identify_state(struct usb_device *udev,
-               struct dvb_usb_device_properties *props,
-               struct dvb_usb_device_description **desc,
-               int *cold)
+static int it913x_select_config(struct usb_device *udev,
+       struct dvb_usb_device_properties *props)
 {
-       int ret = 0, firm_no;
-       u8 reg, remote;
+       int ret = 0, reg;
+       bool proprietary_ir = false;
 
-       firm_no = it913x_return_status(udev);
+       if (it913x_config.chip_ver == 0x02
+                       && it913x_config.chip_type == 0x9135)
+               reg = it913x_read_reg(udev, 0x461d);
+       else
+               reg = it913x_read_reg(udev, 0x461b);
 
-       /* checnk for dual mode */
-       it913x_config.dual_mode =  it913x_read_reg(udev, 0x49c5);
+       if (reg < 0)
+               return reg;
+
+       if (reg == 0) {
+               it913x_config.dual_mode = 0;
+               it913x_config.tuner_id_0 = IT9135_38;
+               proprietary_ir = true;
+       } else {
+               /* TS mode */
+               reg =  it913x_read_reg(udev, 0x49c5);
+               if (reg < 0)
+                       return reg;
+               it913x_config.dual_mode = reg;
+
+               /* IR mode type */
+               reg = it913x_read_reg(udev, 0x49ac);
+               if (reg < 0)
+                       return reg;
+               if (reg == 5) {
+                       info("Remote propriety (raw) mode");
+                       proprietary_ir = true;
+               } else if (reg == 1) {
+                       info("Remote HID mode NOT SUPPORTED");
+                       proprietary_ir = false;
+                       props->rc.core.rc_codes = NULL;
+               } else
+                       props->rc.core.rc_codes = NULL;
+
+               /* Tuner_id */
+               reg = it913x_read_reg(udev, 0x49d0);
+               if (reg < 0)
+                       return reg;
+               it913x_config.tuner_id_0 = reg;
+       }
+
+       if (proprietary_ir)
+               it913x_select_remote(udev, props);
 
        if (udev->speed != USB_SPEED_HIGH) {
                props->adapter[0].fe[0].pid_filter_count = 5;
@@ -459,17 +523,6 @@ static int it913x_identify_state(struct usb_device *udev,
                if(props->adapter[0].fe[0].pid_filter_count == 5)
                        props->adapter[0].fe[0].pid_filter_count = 31;
 
-       /* TODO different remotes */
-       remote = it913x_read_reg(udev, 0x49ac); /* Remote */
-       if (remote == 0)
-               props->rc.core.rc_codes = NULL;
-
-       /* TODO at the moment tuner_id is always assigned to 0x38 */
-       it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0);
-
-       info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode
-               , remote, it913x_config.tuner_id_0);
-
        /* Select Stream Buffer Size and pid filter option*/
        if (pid_filter) {
                props->adapter[0].fe[0].stream.u.bulk.buffersize =
@@ -490,8 +543,29 @@ static int it913x_identify_state(struct usb_device *udev,
        } else
                props->num_adapters = 1;
 
+       info("Dual mode=%x Tuner Type=%x", it913x_config.dual_mode,
+               it913x_config.tuner_id_0);
+
        ret = ite_firmware_select(udev, props);
 
+       return ret;
+}
+
+static int it913x_identify_state(struct usb_device *udev,
+               struct dvb_usb_device_properties *props,
+               struct dvb_usb_device_description **desc,
+               int *cold)
+{
+       int ret = 0, firm_no;
+       u8 reg;
+
+       firm_no = it913x_return_status(udev);
+
+       /* Read and select config */
+       ret = it913x_select_config(udev, props);
+       if (ret < 0)
+               return ret;
+
        if (firm_no > 0) {
                *cold = 0;
                return 0;
@@ -538,18 +612,22 @@ static int it913x_identify_state(struct usb_device *udev,
 
 static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
+       struct it913x_state *st = adap->dev->priv;
        int ret = 0;
        u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD;
 
-       if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
-                       return -EAGAIN;
        deb_info(1, "STM  (%02x)", onoff);
 
-       if (!onoff)
+       if (!onoff) {
+               mutex_lock(&adap->dev->i2c_mutex);
+
                ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1);
 
+               mutex_unlock(&adap->dev->i2c_mutex);
+               st->pid_filter_onoff =
+                       adap->fe_adap[adap->active_fe].pid_filtering;
 
-       mutex_unlock(&adap->dev->i2c_mutex);
+       }
 
        return ret;
 }
@@ -789,7 +867,7 @@ static struct dvb_usb_device_properties it913x_properties = {
                .rc_query       = it913x_rc_query,
                .rc_interval    = IT913X_POLL,
                .allowed_protos = RC_TYPE_NEC,
-               .rc_codes       = RC_MAP_MSI_DIGIVOX_III,
+               .rc_codes       = RC_MAP_IT913X_V1,
        },
        .i2c_algo         = &it913x_i2c_algo,
        .num_device_descs = 5,
@@ -823,5 +901,5 @@ module_usb_driver(it913x_driver);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("it913x USB 2 Driver");
-MODULE_VERSION("1.22");
+MODULE_VERSION("1.27");
 MODULE_LICENSE("GPL");
index 291f6b1..5dde06d 100644 (file)
@@ -77,6 +77,7 @@
 #include "stv0299.h"
 #include "dvb-pll.h"
 #include "z0194a.h"
+#include "m88rs2000.h"
 
 
 
@@ -104,7 +105,7 @@ MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
 
 static int pid_filter;
 module_param_named(pid, pid_filter, int, 0644);
-MODULE_PARM_DESC(pid, "set default 0=on 1=off");
+MODULE_PARM_DESC(pid, "set default 0=default 1=off 2=on");
 
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -113,6 +114,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 #define TUNER_LG       0x1
 #define TUNER_S7395    0x2
 #define TUNER_S0194    0x3
+#define TUNER_RS2000   0x4
 
 struct lme2510_state {
        u8 id;
@@ -121,6 +123,8 @@ struct lme2510_state {
        u8 signal_level;
        u8 signal_sn;
        u8 time_key;
+       u8 last_key;
+       u8 key_timeout;
        u8 i2c_talk_onoff;
        u8 i2c_gate;
        u8 i2c_tuner_gate_w;
@@ -128,6 +132,7 @@ struct lme2510_state {
        u8 i2c_tuner_addr;
        u8 stream_on;
        u8 pid_size;
+       u8 pid_off;
        void *buffer;
        struct urb *lme_urb;
        void *usb_buffer;
@@ -178,14 +183,8 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
        /* the read/write capped at 64 */
        memcpy(buff, wbuf, (wlen < 64) ? wlen : 64);
 
-       ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
-
        ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
 
-       msleep(10);
-
-       ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01));
-
        ret |= lme2510_bulk_read(d->udev, buff, (rlen < 64) ?
                        rlen : 64 , 0x01);
 
@@ -199,9 +198,14 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
 
 static int lme2510_stream_restart(struct dvb_usb_device *d)
 {
-       static u8 stream_on[] = LME_ST_ON_W;
+       struct lme2510_state *st = d->priv;
+       u8 all_pids[] = LME_ALL_PIDS;
+       u8 stream_on[] = LME_ST_ON_W;
        int ret;
-       u8 rbuff[10];
+       u8 rbuff[1];
+       if (st->pid_off)
+               ret = lme2510_usb_talk(d, all_pids, sizeof(all_pids),
+                       rbuff, sizeof(rbuff));
        /*Restart Stream Command*/
        ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on),
                        rbuff, sizeof(rbuff));
@@ -308,6 +312,14 @@ static void lme2510_int_response(struct urb *lme_urb)
                                                ((ibuf[2] & 0x01) << 0x03);
                                }
                                break;
+                       case TUNER_RS2000:
+                               if (ibuf[2] > 0)
+                                       st->signal_lock = 0xff;
+                               else
+                                       st->signal_lock = 0xf0;
+                               st->signal_level = ibuf[4];
+                               st->signal_sn = ibuf[5];
+                               st->time_key = ibuf[7];
                        default:
                                break;
                        }
@@ -359,19 +371,20 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
 static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
        struct lme2510_state *st = adap->dev->priv;
-       static u8 clear_pid_reg[] = LME_CLEAR_PID;
+       static u8 clear_pid_reg[] = LME_ALL_PIDS;
        static u8 rbuf[1];
        int ret;
 
        deb_info(1, "PID Clearing Filter");
 
-       ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
-       if (ret < 0)
-               return -EAGAIN;
+       mutex_lock(&adap->dev->i2c_mutex);
 
-       if (!onoff)
+       if (!onoff) {
                ret |= lme2510_usb_talk(adap->dev, clear_pid_reg,
                        sizeof(clear_pid_reg), rbuf, sizeof(rbuf));
+               st->pid_off = true;
+       } else
+               st->pid_off = false;
 
        st->pid_size = 0;
 
@@ -389,11 +402,9 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
                pid, index, onoff);
 
        if (onoff) {
-                       ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
-                       if (ret < 0)
-                               return -EAGAIN;
-                       ret |= lme2510_enable_pid(adap->dev, index, pid);
-                       mutex_unlock(&adap->dev->i2c_mutex);
+               mutex_lock(&adap->dev->i2c_mutex);
+               ret |= lme2510_enable_pid(adap->dev, index, pid);
+               mutex_unlock(&adap->dev->i2c_mutex);
        }
 
 
@@ -425,9 +436,6 @@ static int lme2510_msg(struct dvb_usb_device *d,
        int ret = 0;
        struct lme2510_state *st = d->priv;
 
-       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-                       return -EAGAIN;
-
        if (st->i2c_talk_onoff == 1) {
 
                ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
@@ -456,8 +464,6 @@ static int lme2510_msg(struct dvb_usb_device *d,
                                                st->i2c_talk_onoff = 0;
                                        }
                                }
-                               if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5))
-                                       msleep(5);
                        }
                        break;
                case TUNER_S0194:
@@ -472,10 +478,12 @@ static int lme2510_msg(struct dvb_usb_device *d,
                                }
                        }
                        break;
+               case TUNER_RS2000:
                default:
                        break;
                }
        } else {
+               /* TODO rewrite this section */
                switch (st->tuner_config) {
                case TUNER_LG:
                        switch (wbuf[3]) {
@@ -559,6 +567,24 @@ static int lme2510_msg(struct dvb_usb_device *d,
                                break;
                        }
                        break;
+               case TUNER_RS2000:
+                       switch (wbuf[3]) {
+                       case 0x8c:
+                               rbuf[0] = 0x55;
+                               rbuf[1] = 0xff;
+                               if (st->last_key == st->time_key) {
+                                       st->key_timeout++;
+                                       if (st->key_timeout > 5)
+                                               rbuf[1] = 0;
+                               } else
+                                       st->key_timeout = 0;
+                               st->last_key = st->time_key;
+                               break;
+                       default:
+                               lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+                               st->i2c_talk_onoff = 1;
+                               break;
+                       }
                default:
                        break;
                }
@@ -568,8 +594,6 @@ static int lme2510_msg(struct dvb_usb_device *d,
 
        }
 
-       mutex_unlock(&d->i2c_mutex);
-
        return ret;
 }
 
@@ -584,6 +608,8 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        u16 len;
        u8 gate = st->i2c_gate;
 
+       mutex_lock(&d->i2c_mutex);
+
        if (gate == 0)
                gate = 5;
 
@@ -622,6 +648,7 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 
                if (lme2510_msg(d, obuf, len, ibuf, 64) < 0) {
                        deb_info(1, "i2c transfer failed.");
+                       mutex_unlock(&d->i2c_mutex);
                        return -EAGAIN;
                }
 
@@ -634,6 +661,8 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        }
                }
        }
+
+       mutex_unlock(&d->i2c_mutex);
        return i;
 }
 
@@ -653,7 +682,7 @@ static int lme2510_identify_state(struct usb_device *udev,
                struct dvb_usb_device_description **desc,
                int *cold)
 {
-       if (pid_filter > 0)
+       if (pid_filter != 2)
                props->adapter[0].fe[0].caps &=
                        ~DVB_USB_ADAP_NEED_PID_FILTERING;
        *cold = 0;
@@ -663,7 +692,7 @@ static int lme2510_identify_state(struct usb_device *udev,
 static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
        struct lme2510_state *st = adap->dev->priv;
-       static u8 clear_reg_3[] = LME_CLEAR_PID;
+       static u8 clear_reg_3[] = LME_ALL_PIDS;
        static u8 rbuf[1];
        int ret = 0, rlen = sizeof(rbuf);
 
@@ -675,8 +704,7 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        else {
                deb_info(1, "STM Steam Off");
                /* mutex is here only to avoid collision with I2C */
-               if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
-                       return -EAGAIN;
+               mutex_lock(&adap->dev->i2c_mutex);
 
                ret = lme2510_usb_talk(adap->dev, clear_reg_3,
                                sizeof(clear_reg_3), rbuf, rlen);
@@ -781,16 +809,18 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
        const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
        const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw";
        const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw";
+       const char fw_c_rs2000[] = "dvb-usb-lme2510c-rs2000.fw";
        const char fw_lg[] = "dvb-usb-lme2510-lg.fw";
        const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw";
        const char *fw_lme;
-       int ret, cold_fw;
+       int ret = 0, cold_fw;
 
        cold = (cold > 0) ? (cold & 1) : 0;
 
        cold_fw = !cold;
 
-       if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) {
+       switch (le16_to_cpu(udev->descriptor.idProduct)) {
+       case 0x1122:
                switch (dvb_usb_lme2510_firmware) {
                default:
                        dvb_usb_lme2510_firmware = TUNER_S0194;
@@ -813,7 +843,8 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
                        cold_fw = 0;
                        break;
                }
-       } else {
+               break;
+       case 0x1120:
                switch (dvb_usb_lme2510_firmware) {
                default:
                        dvb_usb_lme2510_firmware = TUNER_S7395;
@@ -842,8 +873,17 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
                        cold_fw = 0;
                        break;
                }
+               break;
+       case 0x22f0:
+               fw_lme = fw_c_rs2000;
+               ret = request_firmware(&fw, fw_lme, &udev->dev);
+               dvb_usb_lme2510_firmware = TUNER_RS2000;
+               break;
+       default:
+               fw_lme = fw_c_s7395;
        }
 
+
        if (cold_fw) {
                info("FRM Loading %s file", fw_lme);
                ret = lme2510_download_firmware(udev, fw);
@@ -906,6 +946,29 @@ static struct stv0299_config sharp_z0194_config = {
        .set_symbol_rate = sharp_z0194a_set_symbol_rate,
 };
 
+static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe,
+       int caller)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dvb_usb_device *d = adap->dev;
+       struct lme2510_state *st = d->priv;
+
+       mutex_lock(&d->i2c_mutex);
+       if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) {
+               st->i2c_talk_onoff = 0;
+               lme2510_stream_restart(d);
+       }
+       mutex_unlock(&d->i2c_mutex);
+
+       return 0;
+}
+
+static struct m88rs2000_config m88rs2000_config = {
+       .demod_addr = 0xd0,
+       .tuner_addr = 0xc0,
+       .set_ts_params = dm04_rs2000_set_ts_param,
+};
+
 static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
                                        fe_sec_voltage_t voltage)
 {
@@ -915,8 +978,7 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
        static u8 rbuf[1];
        int ret = 0, len = 3, rlen = 1;
 
-       if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
-                       return -EAGAIN;
+       mutex_lock(&adap->dev->i2c_mutex);
 
        switch (voltage) {
        case SEC_VOLTAGE_18:
@@ -937,12 +999,31 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
        return (ret < 0) ? -ENODEV : 0;
 }
 
+static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe,
+       u16 *strength)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct lme2510_state *st = adap->dev->priv;
+
+       *strength = (u16)((u32)st->signal_level * 0xffff / 0x7f);
+       return 0;
+}
+
+static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct lme2510_state *st = adap->dev->priv;
+
+       *snr = (u16)((u32)st->signal_sn * 0xffff / 0xff);
+       return 0;
+}
+
 static int lme_name(struct dvb_usb_adapter *adap)
 {
        struct lme2510_state *st = adap->dev->priv;
        const char *desc = adap->dev->desc->name;
        char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
-                               " SHARP:BS2F7HZ0194"};
+                               " SHARP:BS2F7HZ0194", " RS2000"};
        char *name = adap->fe_adap[0].fe->ops.info.name;
 
        strlcpy(name, desc, 128);
@@ -958,60 +1039,82 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
        int ret = 0;
 
        st->i2c_talk_onoff = 1;
+       switch (le16_to_cpu(adap->dev->udev->descriptor.idProduct)) {
+       case 0x1122:
+       case 0x1120:
+               st->i2c_gate = 4;
+               adap->fe_adap[0].fe = dvb_attach(tda10086_attach,
+                       &tda10086_config, &adap->dev->i2c_adap);
+               if (adap->fe_adap[0].fe) {
+                       info("TUN Found Frontend TDA10086");
+                       st->i2c_tuner_gate_w = 4;
+                       st->i2c_tuner_gate_r = 4;
+                       st->i2c_tuner_addr = 0xc0;
+                       st->tuner_config = TUNER_LG;
+                       if (dvb_usb_lme2510_firmware != TUNER_LG) {
+                               dvb_usb_lme2510_firmware = TUNER_LG;
+                               ret = lme_firmware_switch(adap->dev->udev, 1);
+                       }
+                       break;
+               }
 
-       st->i2c_gate = 4;
-       adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config,
-               &adap->dev->i2c_adap);
-
-       if (adap->fe_adap[0].fe) {
-               info("TUN Found Frontend TDA10086");
-               st->i2c_tuner_gate_w = 4;
-               st->i2c_tuner_gate_r = 4;
-               st->i2c_tuner_addr = 0xc0;
-               st->tuner_config = TUNER_LG;
-               if (dvb_usb_lme2510_firmware != TUNER_LG) {
-                       dvb_usb_lme2510_firmware = TUNER_LG;
-                       ret = lme_firmware_switch(adap->dev->udev, 1);
+               st->i2c_gate = 4;
+               adap->fe_adap[0].fe = dvb_attach(stv0299_attach,
+                               &sharp_z0194_config, &adap->dev->i2c_adap);
+               if (adap->fe_adap[0].fe) {
+                       info("FE Found Stv0299");
+                       st->i2c_tuner_gate_w = 4;
+                       st->i2c_tuner_gate_r = 5;
+                       st->i2c_tuner_addr = 0xc0;
+                       st->tuner_config = TUNER_S0194;
+                       if (dvb_usb_lme2510_firmware != TUNER_S0194) {
+                               dvb_usb_lme2510_firmware = TUNER_S0194;
+                               ret = lme_firmware_switch(adap->dev->udev, 1);
+                       }
+                       break;
                }
-               goto end;
-       }
 
-       st->i2c_gate = 4;
-       adap->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194_config,
+               st->i2c_gate = 5;
+               adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config,
                        &adap->dev->i2c_adap);
-       if (adap->fe_adap[0].fe) {
-               info("FE Found Stv0299");
-               st->i2c_tuner_gate_w = 4;
-               st->i2c_tuner_gate_r = 5;
-               st->i2c_tuner_addr = 0xc0;
-               st->tuner_config = TUNER_S0194;
-               if (dvb_usb_lme2510_firmware != TUNER_S0194) {
-                       dvb_usb_lme2510_firmware = TUNER_S0194;
-                       ret = lme_firmware_switch(adap->dev->udev, 1);
+
+               if (adap->fe_adap[0].fe) {
+                       info("FE Found Stv0288");
+                       st->i2c_tuner_gate_w = 4;
+                       st->i2c_tuner_gate_r = 5;
+                       st->i2c_tuner_addr = 0xc0;
+                       st->tuner_config = TUNER_S7395;
+                       if (dvb_usb_lme2510_firmware != TUNER_S7395) {
+                               dvb_usb_lme2510_firmware = TUNER_S7395;
+                               ret = lme_firmware_switch(adap->dev->udev, 1);
+                       }
+                       break;
                }
-               goto end;
-       }
+       case 0x22f0:
+               st->i2c_gate = 5;
+               adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach,
+                       &m88rs2000_config, &adap->dev->i2c_adap);
 
-       st->i2c_gate = 5;
-       adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config,
-                       &adap->dev->i2c_adap);
-       if (adap->fe_adap[0].fe) {
-               info("FE Found Stv0288");
-               st->i2c_tuner_gate_w = 4;
-               st->i2c_tuner_gate_r = 5;
-               st->i2c_tuner_addr = 0xc0;
-               st->tuner_config = TUNER_S7395;
-               if (dvb_usb_lme2510_firmware != TUNER_S7395) {
-                       dvb_usb_lme2510_firmware = TUNER_S7395;
-                       ret = lme_firmware_switch(adap->dev->udev, 1);
+               if (adap->fe_adap[0].fe) {
+                       info("FE Found M88RS2000");
+                       st->i2c_tuner_gate_w = 5;
+                       st->i2c_tuner_gate_r = 5;
+                       st->i2c_tuner_addr = 0xc0;
+                       st->tuner_config = TUNER_RS2000;
+                       adap->fe_adap[0].fe->ops.read_signal_strength =
+                               dm04_rs2000_read_signal_strength;
+                       adap->fe_adap[0].fe->ops.read_snr =
+                               dm04_rs2000_read_snr;
                }
-       } else {
-               info("DM04 Not Supported");
-               return -ENODEV;
+               break;
        }
 
+       if (adap->fe_adap[0].fe == NULL) {
+                       info("DM04/QQBOX Not Powered up or not Supported");
+                       return -ENODEV;
+       }
 
-end:   if (ret) {
+       if (ret) {
                if (adap->fe_adap[0].fe) {
                        dvb_frontend_detach(adap->fe_adap[0].fe);
                        adap->fe_adap[0].fe = NULL;
@@ -1028,7 +1131,7 @@ end:      if (ret) {
 static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
 {
        struct lme2510_state *st = adap->dev->priv;
-       char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA"};
+       char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"};
        int ret = 0;
 
        switch (st->tuner_config) {
@@ -1047,6 +1150,9 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
                        &adap->dev->i2c_adap, DVB_PLL_OPERA1))
                        ret = st->tuner_config;
                break;
+       case TUNER_RS2000:
+               ret = st->tuner_config;
+               break;
        default:
                break;
        }
@@ -1075,10 +1181,9 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
        static u8 lnb_on[] = LNB_ON;
        static u8 lnb_off[] = LNB_OFF;
        static u8 rbuf[1];
-       int ret, len = 3, rlen = 1;
+       int ret = 0, len = 3, rlen = 1;
 
-       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-               return -EAGAIN;
+       mutex_lock(&d->i2c_mutex);
 
        if (onoff)
                ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
@@ -1136,6 +1241,7 @@ static int lme2510_probe(struct usb_interface *intf,
 static struct usb_device_id lme2510_table[] = {
        { USB_DEVICE(0x3344, 0x1122) },  /* LME2510 */
        { USB_DEVICE(0x3344, 0x1120) },  /* LME2510C */
+       { USB_DEVICE(0x3344, 0x22f0) },  /* LME2510C RS2000 */
        {}              /* Terminating entry */
 };
 
@@ -1153,7 +1259,7 @@ static struct dvb_usb_device_properties lme2510_properties = {
                                DVB_USB_ADAP_NEED_PID_FILTERING|
                                DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .streaming_ctrl   = lme2510_streaming_ctrl,
-                       .pid_filter_count = 15,
+                       .pid_filter_count = 32,
                        .pid_filter = lme2510_pid_filter,
                        .pid_filter_ctrl  = lme2510_pid_filter_ctrl,
                        .frontend_attach  = dm04_lme2510_frontend_attach,
@@ -1204,7 +1310,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
                                DVB_USB_ADAP_NEED_PID_FILTERING|
                                DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                        .streaming_ctrl   = lme2510_streaming_ctrl,
-                       .pid_filter_count = 15,
+                       .pid_filter_count = 32,
                        .pid_filter = lme2510_pid_filter,
                        .pid_filter_ctrl  = lme2510_pid_filter_ctrl,
                        .frontend_attach  = dm04_lme2510_frontend_attach,
@@ -1234,11 +1340,14 @@ static struct dvb_usb_device_properties lme2510c_properties = {
        .identify_state   = lme2510_identify_state,
        .i2c_algo         = &lme2510_i2c_algo,
        .generic_bulk_ctrl_endpoint = 0,
-       .num_device_descs = 1,
+       .num_device_descs = 2,
        .devices = {
                {   "DM04_LME2510C_DVB-S",
                        { &lme2510_table[1], NULL },
                        },
+               {   "DM04_LME2510C_DVB-S RS2000",
+                       { &lme2510_table[2], NULL },
+                       },
        }
 };
 
@@ -1295,5 +1404,5 @@ module_usb_driver(lme2510_driver);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.91");
+MODULE_VERSION("1.99");
 MODULE_LICENSE("GPL");
index ab21e2e..e9c2072 100644 (file)
@@ -41,6 +41,7 @@
 #define LME_ST_ON_W    {0x06, 0x00}
 #define LME_CLEAR_PID   {0x03, 0x02, 0x20, 0xa0}
 #define LME_ZERO_PID   {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c}
+#define LME_ALL_PIDS   {0x03, 0x06, 0x00, 0xff, 0x01, 0x1f, 0x20, 0x81}
 
 /*  LNB Voltage
  *  07 XX XX
index 38ef025..81305de 100644 (file)
@@ -351,15 +351,13 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
                                              adap_state->ep6_clockphase,
                                              0, 0);
                mxl_fail(ret);
+#if 0
        } else {
                ret = mxl111sf_disable_656_port(state);
                mxl_fail(ret);
+#endif
        }
 
-       mxl111sf_read_reg(state, 0x12, &tmp);
-       tmp &= ~0x04;
-       mxl111sf_write_reg(state, 0x12, tmp);
-
        return ret;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
new file mode 100644 (file)
index 0000000..8f4736a
--- /dev/null
@@ -0,0 +1,982 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 "rtl28xxu.h"
+
+#include "rtl2830.h"
+
+#include "qt1010.h"
+#include "mt2060.h"
+#include "mxl5005s.h"
+
+/* debug */
+static int dvb_usb_rtl28xxu_debug;
+module_param_named(debug, dvb_usb_rtl28xxu_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
+{
+       int ret;
+       unsigned int pipe;
+       u8 requesttype;
+       u8 *buf;
+
+       buf = kmalloc(req->size, GFP_KERNEL);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       if (req->index & CMD_WR_FLAG) {
+               /* write */
+               memcpy(buf, req->data, req->size);
+               requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+               pipe = usb_sndctrlpipe(d->udev, 0);
+       } else {
+               /* read */
+               requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+               pipe = usb_rcvctrlpipe(d->udev, 0);
+       }
+
+       ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value,
+                       req->index, buf, req->size, 1000);
+       if (ret > 0)
+               ret = 0;
+
+       deb_dump(0, requesttype, req->value, req->index, buf, req->size,
+                       deb_xfer);
+
+       /* read request, copy returned data to return buf */
+       if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
+               memcpy(req->data, buf, req->size);
+
+       kfree(buf);
+
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       deb_info("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int rtl2831_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+{
+       struct rtl28xxu_req req;
+
+       if (reg < 0x3000)
+               req.index = CMD_USB_WR;
+       else if (reg < 0x4000)
+               req.index = CMD_SYS_WR;
+       else
+               req.index = CMD_IR_WR;
+
+       req.value = reg;
+       req.size = len;
+       req.data = val;
+
+       return rtl28xxu_ctrl_msg(d, &req);
+}
+
+static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+{
+       struct rtl28xxu_req req;
+
+       if (reg < 0x3000)
+               req.index = CMD_USB_RD;
+       else if (reg < 0x4000)
+               req.index = CMD_SYS_RD;
+       else
+               req.index = CMD_IR_RD;
+
+       req.value = reg;
+       req.size = len;
+       req.data = val;
+
+       return rtl28xxu_ctrl_msg(d, &req);
+}
+
+static int rtl2831_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+{
+       return rtl2831_wr_regs(d, reg, &val, 1);
+}
+
+static int rtl2831_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+{
+       return rtl2831_rd_regs(d, reg, val, 1);
+}
+
+/* I2C */
+static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+       int num)
+{
+       int ret;
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct rtl28xxu_priv *priv = d->priv;
+       struct rtl28xxu_req req;
+
+       /*
+        * It is not known which are real I2C bus xfer limits, but testing
+        * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes.
+        * TODO: find out RTL2832U lens
+        */
+
+       /*
+        * I2C adapter logic looks rather complicated due to fact it handles
+        * three different access methods. Those methods are;
+        * 1) integrated demod access
+        * 2) old I2C access
+        * 3) new I2C access
+        *
+        * Used method is selected in order 1, 2, 3. Method 3 can handle all
+        * requests but there is two reasons why not use it always;
+        * 1) It is most expensive, usually two USB messages are needed
+        * 2) At least RTL2831U does not support it
+        *
+        * Method 3 is needed in case of I2C write+read (typical register read)
+        * where write is more than one byte.
+        */
+
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
+               (msg[1].flags & I2C_M_RD)) {
+               if (msg[0].len > 24 || msg[1].len > 24) {
+                       /* TODO: check msg[0].len max */
+                       ret = -EOPNOTSUPP;
+                       goto err_mutex_unlock;
+               } else if (msg[0].addr == 0x10) {
+                       /* method 1 - integrated demod */
+                       req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+                       req.index = CMD_DEMOD_RD | priv->page;
+                       req.size = msg[1].len;
+                       req.data = &msg[1].buf[0];
+                       ret = rtl28xxu_ctrl_msg(d, &req);
+               } else if (msg[0].len < 2) {
+                       /* method 2 - old I2C */
+                       req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+                       req.index = CMD_I2C_RD;
+                       req.size = msg[1].len;
+                       req.data = &msg[1].buf[0];
+                       ret = rtl28xxu_ctrl_msg(d, &req);
+               } else {
+                       /* method 3 - new I2C */
+                       req.value = (msg[0].addr << 1);
+                       req.index = CMD_I2C_DA_WR;
+                       req.size = msg[0].len;
+                       req.data = msg[0].buf;
+                       ret = rtl28xxu_ctrl_msg(d, &req);
+                       if (ret)
+                               goto err_mutex_unlock;
+
+                       req.value = (msg[0].addr << 1);
+                       req.index = CMD_I2C_DA_RD;
+                       req.size = msg[1].len;
+                       req.data = msg[1].buf;
+                       ret = rtl28xxu_ctrl_msg(d, &req);
+               }
+       } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+               if (msg[0].len > 22) {
+                       /* TODO: check msg[0].len max */
+                       ret = -EOPNOTSUPP;
+                       goto err_mutex_unlock;
+               } else if (msg[0].addr == 0x10) {
+                       /* method 1 - integrated demod */
+                       if (msg[0].buf[0] == 0x00) {
+                               /* save demod page for later demod access */
+                               priv->page = msg[0].buf[1];
+                               ret = 0;
+                       } else {
+                               req.value = (msg[0].buf[0] << 8) |
+                                       (msg[0].addr << 1);
+                               req.index = CMD_DEMOD_WR | priv->page;
+                               req.size = msg[0].len-1;
+                               req.data = &msg[0].buf[1];
+                               ret = rtl28xxu_ctrl_msg(d, &req);
+                       }
+               } else if (msg[0].len < 23) {
+                       /* method 2 - old I2C */
+                       req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+                       req.index = CMD_I2C_WR;
+                       req.size = msg[0].len-1;
+                       req.data = &msg[0].buf[1];
+                       ret = rtl28xxu_ctrl_msg(d, &req);
+               } else {
+                       /* method 3 - new I2C */
+                       req.value = (msg[0].addr << 1);
+                       req.index = CMD_I2C_DA_WR;
+                       req.size = msg[0].len;
+                       req.data = msg[0].buf;
+                       ret = rtl28xxu_ctrl_msg(d, &req);
+               }
+       } else {
+               ret = -EINVAL;
+       }
+
+err_mutex_unlock:
+       mutex_unlock(&d->i2c_mutex);
+
+       return ret ? ret : num;
+}
+
+static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm rtl28xxu_i2c_algo = {
+       .master_xfer   = rtl28xxu_i2c_xfer,
+       .functionality = rtl28xxu_i2c_func,
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
+       .i2c_addr = 0x10, /* 0x20 */
+       .xtal = 28800000,
+       .ts_mode = 0,
+       .spec_inv = 1,
+       .if_dvbt = 36150000,
+       .vtop = 0x20,
+       .krf = 0x04,
+       .agc_targ_val = 0x2d,
+
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
+       .i2c_addr = 0x10, /* 0x20 */
+       .xtal = 28800000,
+       .ts_mode = 0,
+       .spec_inv = 1,
+       .if_dvbt = 36125000,
+       .vtop = 0x20,
+       .krf = 0x04,
+       .agc_targ_val = 0x2d,
+};
+
+static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
+       .i2c_addr = 0x10, /* 0x20 */
+       .xtal = 28800000,
+       .ts_mode = 0,
+       .spec_inv = 0,
+       .if_dvbt = 4570000,
+       .vtop = 0x3f,
+       .krf = 0x04,
+       .agc_targ_val = 0x3e,
+};
+
+static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       struct rtl28xxu_priv *priv = adap->dev->priv;
+       u8 buf[1];
+       struct rtl2830_config *rtl2830_config;
+       /* open RTL2831U/RTL2830 I2C gate */
+       struct rtl28xxu_req req_gate = { 0x0120, 0x0011, 0x0001, "\x08" };
+       /* for MT2060 tuner probe */
+       struct rtl28xxu_req req_mt2060 = { 0x00c0, CMD_I2C_RD, 1, buf };
+       /* for QT1010 tuner probe */
+       struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };
+
+       deb_info("%s:\n", __func__);
+
+       /*
+        * RTL2831U GPIOs
+        * =========================================================
+        * GPIO0 | tuner#0 | 0 off | 1 on  | MXL5005S (?)
+        * GPIO2 | LED     | 0 off | 1 on  |
+        * GPIO4 | tuner#1 | 0 on  | 1 off | MT2060
+        */
+
+       /* GPIO direction */
+       ret = rtl2831_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);
+       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.
+        */
+
+       /* open demod I2C gate */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
+       if (ret)
+               goto err;
+
+       /* check QT1010 ID(?) register; reg=0f val=2c */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_qt1010);
+       if (ret == 0 && buf[0] == 0x2c) {
+               priv->tuner = TUNER_RTL2830_QT1010;
+               rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
+               deb_info("%s: QT1010\n", __func__);
+               goto found;
+       } else {
+               deb_info("%s: QT1010 probe failed=%d - %02x\n",
+                       __func__, ret, buf[0]);
+       }
+
+       /* open demod I2C gate */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
+       if (ret)
+               goto err;
+
+       /* check MT2060 ID register; reg=00 val=63 */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2060);
+       if (ret == 0 && buf[0] == 0x63) {
+               priv->tuner = TUNER_RTL2830_MT2060;
+               rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
+               deb_info("%s: MT2060\n", __func__);
+               goto found;
+       } else {
+               deb_info("%s: MT2060 probe failed=%d - %02x\n",
+                       __func__, ret, buf[0]);
+       }
+
+       /* assume MXL5005S */
+       ret = 0;
+       priv->tuner = TUNER_RTL2830_MXL5005S;
+       rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
+       deb_info("%s: MXL5005S\n", __func__);
+       goto found;
+
+found:
+       /* attach demodulator */
+       adap->fe_adap[0].fe = dvb_attach(rtl2830_attach, rtl2830_config,
+               &adap->dev->i2c_adap);
+       if (adap->fe_adap[0].fe == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       return ret;
+err:
+       deb_info("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       struct rtl28xxu_priv *priv = adap->dev->priv;
+       u8 buf[1];
+       /* 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 FC2580 tuner probe */
+       struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
+
+       deb_info("%s:\n", __func__);
+
+       /* GPIO direction */
+       ret = rtl2831_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);
+       if (ret)
+               goto err;
+
+       ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8);
+       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.
+        */
+
+       /* open demod I2C gate */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_open);
+       if (ret)
+               goto err;
+
+       /* 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]);
+       }
+
+       /* close demod I2C gate */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
+       if (ret)
+               goto err;
+
+       /* tuner not found */
+       ret = -ENODEV;
+       goto err;
+
+found:
+       /* close demod I2C gate */
+       ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
+       if (ret)
+               goto err;
+
+       /* attach demodulator */
+       /* TODO: */
+
+       return ret;
+err:
+       deb_info("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static struct qt1010_config rtl28xxu_qt1010_config = {
+       .i2c_address = 0x62, /* 0xc4 */
+};
+
+static struct mt2060_config rtl28xxu_mt2060_config = {
+       .i2c_address = 0x60, /* 0xc0 */
+       .clock_out = 0,
+};
+
+static struct mxl5005s_config rtl28xxu_mxl5005s_config = {
+       .i2c_address     = 0x63, /* 0xc6 */
+       .if_freq         = IF_FREQ_4570000HZ,
+       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+       .agc_mode        = MXL_SINGLE_AGC,
+       .tracking_filter = MXL_TF_C_H,
+       .rssi_enable     = MXL_RSSI_ENABLE,
+       .cap_select      = MXL_CAP_SEL_ENABLE,
+       .div_out         = MXL_DIV_OUT_4,
+       .clock_out       = MXL_CLOCK_OUT_DISABLE,
+       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+       .top             = MXL5005S_TOP_25P2,
+       .mod_mode        = MXL_DIGITAL_MODE,
+       .if_mode         = MXL_ZERO_IF,
+       .AgcMasterByte   = 0x00,
+};
+
+static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       struct rtl28xxu_priv *priv = adap->dev->priv;
+       struct i2c_adapter *rtl2830_tuner_i2c;
+       struct dvb_frontend *fe;
+
+       deb_info("%s:\n", __func__);
+
+       /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
+       rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe);
+
+       switch (priv->tuner) {
+       case TUNER_RTL2830_QT1010:
+               fe = dvb_attach(qt1010_attach, adap->fe_adap[0].fe,
+                               rtl2830_tuner_i2c, &rtl28xxu_qt1010_config);
+               break;
+       case TUNER_RTL2830_MT2060:
+               fe = dvb_attach(mt2060_attach, adap->fe_adap[0].fe,
+                               rtl2830_tuner_i2c, &rtl28xxu_mt2060_config,
+                               1220);
+               break;
+       case TUNER_RTL2830_MXL5005S:
+               fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
+                               rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config);
+               break;
+       default:
+               fe = NULL;
+               err("unknown tuner=%d", priv->tuner);
+       }
+
+       if (fe == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       return 0;
+err:
+       deb_info("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       struct rtl28xxu_priv *priv = adap->dev->priv;
+       struct dvb_frontend *fe;
+
+       deb_info("%s:\n", __func__);
+
+       switch (priv->tuner) {
+       case TUNER_RTL2832_FC2580:
+               /* TODO: */
+               fe = NULL;
+               break;
+       default:
+               fe = NULL;
+               err("unknown tuner=%d", priv->tuner);
+       }
+
+       if (fe == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       return 0;
+err:
+       deb_info("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int rtl28xxu_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);
+       if (ret)
+               goto err;
+
+       if (onoff) {
+               buf[0] = 0x00;
+               buf[1] = 0x00;
+               gpio |= 0x04; /* LED on */
+       } else {
+               buf[0] = 0x10; /* stall EPA */
+               buf[1] = 0x02; /* reset EPA */
+               gpio &= (~0x04); /* LED off */
+       }
+
+       ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio);
+       if (ret)
+               goto err;
+
+       ret = rtl2831_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 rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       int ret;
+       u8 gpio, sys0;
+
+       deb_info("%s: onoff=%d\n", __func__, onoff);
+
+       /* demod adc */
+       ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0);
+       if (ret)
+               goto err;
+
+       /* tuner power, read GPIOs */
+       ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
+       if (ret)
+               goto err;
+
+       deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
+
+       if (onoff) {
+               gpio |= 0x01; /* GPIO0 = 1 */
+               gpio &= (~0x10); /* GPIO4 = 0 */
+               sys0 = sys0 & 0x0f;
+               sys0 |= 0xe0;
+       } else {
+               gpio &= (~0x01); /* GPIO0 = 0 */
+               gpio |= 0x10; /* GPIO4 = 1 */
+               sys0 = sys0 & (~0xc0);
+       }
+
+       deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
+
+       /* demod adc */
+       ret = rtl2831_wr_reg(d, SYS_SYS0, sys0);
+       if (ret)
+               goto err;
+
+       /* tuner power, write GPIOs */
+       ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
+       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;
+       struct rtl28xxu_priv *priv = d->priv;
+       u8 buf[5];
+       u32 rc_code;
+       struct rtl28xxu_reg_val rc_nec_tab[] = {
+               { 0x3033, 0x80 },
+               { 0x3020, 0x43 },
+               { 0x3021, 0x16 },
+               { 0x3022, 0x16 },
+               { 0x3023, 0x5a },
+               { 0x3024, 0x2d },
+               { 0x3025, 0x16 },
+               { 0x3026, 0x01 },
+               { 0x3028, 0xb0 },
+               { 0x3029, 0x04 },
+               { 0x302c, 0x88 },
+               { 0x302e, 0x13 },
+               { 0x3030, 0xdf },
+               { 0x3031, 0x05 },
+       };
+
+       /* 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,
+                                       rc_nec_tab[i].val);
+                       if (ret)
+                               goto err;
+               }
+               priv->rc_active = true;
+       }
+
+       ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5);
+       if (ret)
+               goto err;
+
+       if (buf[4] & 0x01) {
+               if (buf[2] == (u8) ~buf[3]) {
+                       if (buf[0] == (u8) ~buf[1]) {
+                               /* NEC standard (16 bit) */
+                               rc_code = buf[0] << 8 | buf[2];
+                       } else {
+                               /* NEC extended (24 bit) */
+                               rc_code = buf[0] << 16 |
+                                               buf[1] << 8 | buf[2];
+                       }
+               } else {
+                       /* NEC full (32 bit) */
+                       rc_code = buf[0] << 24 | buf[1] << 16 |
+                                       buf[2] << 8 | buf[3];
+               }
+
+               rc_keydown(d->rc_dev, rc_code, 0);
+
+               ret = rtl2831_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);
+               if (ret)
+                       goto err;
+       }
+
+       return ret;
+err:
+       deb_info("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int rtl2832u_rc_query(struct dvb_usb_device *d)
+{
+       int ret, i;
+       struct rtl28xxu_priv *priv = d->priv;
+       u8 buf[128];
+       int len;
+       struct rtl28xxu_reg_val rc_nec_tab[] = {
+               { IR_RX_CTRL,             0x20 },
+               { IR_RX_BUF_CTRL,         0x80 },
+               { IR_RX_IF,               0xff },
+               { IR_RX_IE,               0xff },
+               { IR_MAX_DURATION0,       0xd0 },
+               { IR_MAX_DURATION1,       0x07 },
+               { IR_IDLE_LEN0,           0xc0 },
+               { IR_IDLE_LEN1,           0x00 },
+               { IR_GLITCH_LEN,          0x03 },
+               { IR_RX_CLK,              0x09 },
+               { IR_RX_CFG,              0x1c },
+               { IR_MAX_H_TOL_LEN,       0x1e },
+               { IR_MAX_L_TOL_LEN,       0x1e },
+               { IR_RX_CTRL,             0x80 },
+       };
+
+       /* 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,
+                                       rc_nec_tab[i].val);
+                       if (ret)
+                               goto err;
+               }
+               priv->rc_active = true;
+       }
+
+       ret = rtl2831_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]);
+       if (ret)
+               goto err;
+
+       len = buf[0];
+       ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
+
+       /* 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);
+
+exit:
+       return ret;
+err:
+       deb_info("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+enum rtl28xxu_usb_table_entry {
+       RTL2831U_0BDA_2831,
+       RTL2831U_14AA_0160,
+       RTL2831U_14AA_0161,
+};
+
+static struct usb_device_id rtl28xxu_table[] = {
+       /* RTL2831U */
+       [RTL2831U_0BDA_2831] = {
+               USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U)},
+       [RTL2831U_14AA_0160] = {
+               USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT)},
+       [RTL2831U_14AA_0161] = {
+               USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)},
+
+       /* RTL2832U */
+       {} /* terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, rtl28xxu_table);
+
+static struct dvb_usb_device_properties rtl28xxu_properties[] = {
+       {
+               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+               .usb_ctrl = DEVICE_SPECIFIC,
+               .no_reconnect = 1,
+
+               .size_of_priv = sizeof(struct rtl28xxu_priv),
+
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .num_frontends = 1,
+                               .fe = {
+                                       {
+                                               .frontend_attach = rtl2831u_frontend_attach,
+                                               .tuner_attach    = rtl2831u_tuner_attach,
+                                               .streaming_ctrl  = rtl28xxu_streaming_ctrl,
+                                               .stream = {
+                                                       .type = USB_BULK,
+                                                       .count = 6,
+                                                       .endpoint = 0x81,
+                                                       .u = {
+                                                               .bulk = {
+                                                                       .buffersize = 8*512,
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               },
+
+               .power_ctrl = rtl28xxu_power_ctrl,
+
+               .rc.core = {
+                       .protocol       = RC_TYPE_NEC,
+                       .module_name    = "rtl28xxu",
+                       .rc_query       = rtl2831u_rc_query,
+                       .rc_interval    = 400,
+                       .allowed_protos = RC_TYPE_NEC,
+                       .rc_codes       = RC_MAP_EMPTY,
+               },
+
+               .i2c_algo = &rtl28xxu_i2c_algo,
+
+               .num_device_descs = 2,
+               .devices = {
+                       {
+                               .name = "Realtek RTL2831U reference design",
+                               .warm_ids = {
+                                       &rtl28xxu_table[RTL2831U_0BDA_2831],
+                               },
+                       },
+                       {
+                               .name = "Freecom USB2.0 DVB-T",
+                               .warm_ids = {
+                                       &rtl28xxu_table[RTL2831U_14AA_0160],
+                                       &rtl28xxu_table[RTL2831U_14AA_0161],
+                               },
+                       },
+               }
+       },
+       {
+               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+               .usb_ctrl = DEVICE_SPECIFIC,
+               .no_reconnect = 1,
+
+               .size_of_priv = sizeof(struct rtl28xxu_priv),
+
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .num_frontends = 1,
+                               .fe = {
+                                       {
+                                               .frontend_attach = rtl2832u_frontend_attach,
+                                               .tuner_attach    = rtl2832u_tuner_attach,
+                                               .streaming_ctrl  = rtl28xxu_streaming_ctrl,
+                                               .stream = {
+                                                       .type = USB_BULK,
+                                                       .count = 6,
+                                                       .endpoint = 0x81,
+                                                       .u = {
+                                                               .bulk = {
+                                                                       .buffersize = 8*512,
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               },
+
+               .power_ctrl = rtl28xxu_power_ctrl,
+
+               .rc.core = {
+                       .protocol       = RC_TYPE_NEC,
+                       .module_name    = "rtl28xxu",
+                       .rc_query       = rtl2832u_rc_query,
+                       .rc_interval    = 400,
+                       .allowed_protos = RC_TYPE_NEC,
+                       .rc_codes       = RC_MAP_EMPTY,
+               },
+
+               .i2c_algo = &rtl28xxu_i2c_algo,
+
+               .num_device_descs = 0, /* disabled as no support for RTL2832 */
+               .devices = {
+                       {
+                               .name = "Realtek RTL2832U reference design",
+                       },
+               }
+       },
+
+};
+
+static int rtl28xxu_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       int ret, i;
+       int properties_count = ARRAY_SIZE(rtl28xxu_properties);
+       struct dvb_usb_device *d;
+
+       deb_info("%s: interface=%d\n", __func__,
+               intf->cur_altsetting->desc.bInterfaceNumber);
+
+       if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+               return 0;
+
+       for (i = 0; i < properties_count; i++) {
+               ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i],
+                               THIS_MODULE, &d, adapter_nr);
+               if (ret == 0 || ret != -ENODEV)
+                       break;
+       }
+
+       if (ret)
+               goto err;
+
+       /* init USB endpoints */
+       ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09);
+       if (ret)
+               goto err;
+
+       ret = rtl2831_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);
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       deb_info("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static struct usb_driver rtl28xxu_driver = {
+       .name       = "dvb_usb_rtl28xxu",
+       .probe      = rtl28xxu_probe,
+       .disconnect = dvb_usb_device_exit,
+       .id_table   = rtl28xxu_table,
+};
+
+/* module stuff */
+static int __init rtl28xxu_module_init(void)
+{
+       int ret;
+
+       deb_info("%s:\n", __func__);
+
+       ret = usb_register(&rtl28xxu_driver);
+       if (ret)
+               err("usb_register failed=%d", ret);
+
+       return ret;
+}
+
+static void __exit rtl28xxu_module_exit(void)
+{
+       deb_info("%s:\n", __func__);
+
+       /* deregister this driver from the USB subsystem */
+       usb_deregister(&rtl28xxu_driver);
+}
+
+module_init(rtl28xxu_module_init);
+module_exit(rtl28xxu_module_exit);
+
+MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.h b/drivers/media/dvb/dvb-usb/rtl28xxu.h
new file mode 100644 (file)
index 0000000..90f3bb4
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 RTL28XXU_H
+#define RTL28XXU_H
+
+#define DVB_USB_LOG_PREFIX "rtl28xxu"
+#include "dvb-usb.h"
+
+#define deb_info(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x01, args)
+#define deb_rc(args...)   dprintk(dvb_usb_rtl28xxu_debug, 0x02, args)
+#define deb_xfer(args...) dprintk(dvb_usb_rtl28xxu_debug, 0x04, args)
+#define deb_reg(args...)  dprintk(dvb_usb_rtl28xxu_debug, 0x08, args)
+#define deb_i2c(args...)  dprintk(dvb_usb_rtl28xxu_debug, 0x10, args)
+#define deb_fw(args...)   dprintk(dvb_usb_rtl28xxu_debug, 0x20, args)
+
+#define deb_dump(r, t, v, i, b, l, func) { \
+       int loop_; \
+       func("%02x %02x %02x %02x %02x %02x %02x %02x", \
+               t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
+       if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
+               func(" >>> "); \
+       else \
+               func(" <<< "); \
+       for (loop_ = 0; loop_ < l; loop_++) \
+               func("%02x ", b[loop_]); \
+       func("\n");\
+}
+
+/*
+ * USB commands
+ * (usb_control_msg() index parameter)
+ */
+
+#define DEMOD            0x0000
+#define USB              0x0100
+#define SYS              0x0200
+#define I2C              0x0300
+#define I2C_DA           0x0600
+
+#define CMD_WR_FLAG      0x0010
+#define CMD_DEMOD_RD     0x0000
+#define CMD_DEMOD_WR     0x0010
+#define CMD_USB_RD       0x0100
+#define CMD_USB_WR       0x0110
+#define CMD_SYS_RD       0x0200
+#define CMD_IR_RD        0x0201
+#define CMD_IR_WR        0x0211
+#define CMD_SYS_WR       0x0210
+#define CMD_I2C_RD       0x0300
+#define CMD_I2C_WR       0x0310
+#define CMD_I2C_DA_RD    0x0600
+#define CMD_I2C_DA_WR    0x0610
+
+
+struct rtl28xxu_priv {
+       u8 chip_id;
+       u8 tuner;
+       u8 page; /* integrated demod active register page */
+       bool rc_active;
+};
+
+enum rtl28xxu_chip_id {
+       CHIP_ID_NONE,
+       CHIP_ID_RTL2831U,
+       CHIP_ID_RTL2832U,
+};
+
+enum rtl28xxu_tuner {
+       TUNER_NONE,
+
+       TUNER_RTL2830_QT1010,
+       TUNER_RTL2830_MT2060,
+       TUNER_RTL2830_MXL5005S,
+
+       TUNER_RTL2832_MT2266,
+       TUNER_RTL2832_FC2580,
+       TUNER_RTL2832_MT2063,
+       TUNER_RTL2832_MAX3543,
+       TUNER_RTL2832_TUA9001,
+       TUNER_RTL2832_MXL5007T,
+       TUNER_RTL2832_FC0012,
+       TUNER_RTL2832_E4000,
+       TUNER_RTL2832_TDA18272,
+       TUNER_RTL2832_FC0013,
+};
+
+struct rtl28xxu_req {
+       u16 value;
+       u16 index;
+       u16 size;
+       u8 *data;
+};
+
+struct rtl28xxu_reg_val {
+       u16 reg;
+       u8 val;
+};
+
+/*
+ * memory map
+ *
+ * 0x0000 DEMOD : demodulator
+ * 0x2000 USB   : SIE, USB endpoint, debug, DMA
+ * 0x3000 SYS   : system
+ * 0xfc00 RC    : remote controller (not RTL2831U)
+ */
+
+/*
+ * USB registers
+ */
+/* SIE Control Registers */
+#define USB_SYSCTL         0x2000 /* USB system control */
+#define USB_SYSCTL_0       0x2000 /* USB system control */
+#define USB_SYSCTL_1       0x2001 /* USB system control */
+#define USB_SYSCTL_2       0x2002 /* USB system control */
+#define USB_SYSCTL_3       0x2003 /* USB system control */
+#define USB_IRQSTAT        0x2008 /* SIE interrupt status */
+#define USB_IRQEN          0x200C /* SIE interrupt enable */
+#define USB_CTRL           0x2010 /* USB control */
+#define USB_STAT           0x2014 /* USB status */
+#define USB_DEVADDR        0x2018 /* USB device address */
+#define USB_TEST           0x201C /* USB test mode */
+#define USB_FRAME_NUMBER   0x2020 /* frame number */
+#define USB_FIFO_ADDR      0x2028 /* address of SIE FIFO RAM */
+#define USB_FIFO_CMD       0x202A /* SIE FIFO RAM access command */
+#define USB_FIFO_DATA      0x2030 /* SIE FIFO RAM data */
+/* Endpoint Registers */
+#define EP0_SETUPA         0x20F8 /* EP 0 setup packet lower byte */
+#define EP0_SETUPB         0x20FC /* EP 0 setup packet higher byte */
+#define USB_EP0_CFG        0x2104 /* EP 0 configure */
+#define USB_EP0_CTL        0x2108 /* EP 0 control */
+#define USB_EP0_STAT       0x210C /* EP 0 status */
+#define USB_EP0_IRQSTAT    0x2110 /* EP 0 interrupt status */
+#define USB_EP0_IRQEN      0x2114 /* EP 0 interrupt enable */
+#define USB_EP0_MAXPKT     0x2118 /* EP 0 max packet size */
+#define USB_EP0_BC         0x2120 /* EP 0 FIFO byte counter */
+#define USB_EPA_CFG        0x2144 /* EP A configure */
+#define USB_EPA_CFG_0      0x2144 /* EP A configure */
+#define USB_EPA_CFG_1      0x2145 /* EP A configure */
+#define USB_EPA_CFG_2      0x2146 /* EP A configure */
+#define USB_EPA_CFG_3      0x2147 /* EP A configure */
+#define USB_EPA_CTL        0x2148 /* EP A control */
+#define USB_EPA_CTL_0      0x2148 /* EP A control */
+#define USB_EPA_CTL_1      0x2149 /* EP A control */
+#define USB_EPA_CTL_2      0x214A /* EP A control */
+#define USB_EPA_CTL_3      0x214B /* EP A control */
+#define USB_EPA_STAT       0x214C /* EP A status */
+#define USB_EPA_IRQSTAT    0x2150 /* EP A interrupt status */
+#define USB_EPA_IRQEN      0x2154 /* EP A interrupt enable */
+#define USB_EPA_MAXPKT     0x2158 /* EP A max packet size */
+#define USB_EPA_MAXPKT_0   0x2158 /* EP A max packet size */
+#define USB_EPA_MAXPKT_1   0x2159 /* EP A max packet size */
+#define USB_EPA_MAXPKT_2   0x215A /* EP A max packet size */
+#define USB_EPA_MAXPKT_3   0x215B /* EP A max packet size */
+#define USB_EPA_FIFO_CFG   0x2160 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_0 0x2160 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_1 0x2161 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_2 0x2162 /* EP A FIFO configure */
+#define USB_EPA_FIFO_CFG_3 0x2163 /* EP A FIFO configure */
+/* Debug Registers */
+#define USB_PHYTSTDIS      0x2F04 /* PHY test disable */
+#define USB_TOUT_VAL       0x2F08 /* USB time-out time */
+#define USB_VDRCTRL        0x2F10 /* UTMI vendor signal control */
+#define USB_VSTAIN         0x2F14 /* UTMI vendor signal status in */
+#define USB_VLOADM         0x2F18 /* UTMI load vendor signal status in */
+#define USB_VSTAOUT        0x2F1C /* UTMI vendor signal status out */
+#define USB_UTMI_TST       0x2F80 /* UTMI test */
+#define USB_UTMI_STATUS    0x2F84 /* UTMI status */
+#define USB_TSTCTL         0x2F88 /* test control */
+#define USB_TSTCTL2        0x2F8C /* test control 2 */
+#define USB_PID_FORCE      0x2F90 /* force PID */
+#define USB_PKTERR_CNT     0x2F94 /* packet error counter */
+#define USB_RXERR_CNT      0x2F98 /* RX error counter */
+#define USB_MEM_BIST       0x2F9C /* MEM BIST test */
+#define USB_SLBBIST        0x2FA0 /* self-loop-back BIST */
+#define USB_CNTTEST        0x2FA4 /* counter test */
+#define USB_PHYTST         0x2FC0 /* USB PHY test */
+#define USB_DBGIDX         0x2FF0 /* select individual block debug signal */
+#define USB_DBGMUX         0x2FF4 /* debug signal module mux */
+
+/*
+ * SYS registers
+ */
+/* demod control registers */
+#define SYS_SYS0           0x3000 /* include DEMOD_CTL, GPO, GPI, GPOE */
+#define SYS_DEMOD_CTL      0x3000 /* control register for DVB-T demodulator */
+/* GPIO registers */
+#define SYS_GPIO_OUT_VAL   0x3001 /* output value of GPIO */
+#define SYS_GPIO_IN_VAL    0x3002 /* input value of GPIO */
+#define SYS_GPIO_OUT_EN    0x3003 /* output enable of GPIO */
+#define SYS_SYS1           0x3004 /* include GPD, SYSINTE, SYSINTS, GP_CFG0 */
+#define SYS_GPIO_DIR       0x3004 /* direction control for GPIO */
+#define SYS_SYSINTE        0x3005 /* system interrupt enable */
+#define SYS_SYSINTS        0x3006 /* system interrupt status */
+#define SYS_GPIO_CFG0      0x3007 /* PAD configuration for GPIO0-GPIO3 */
+#define SYS_SYS2           0x3008 /* include GP_CFG1 and 3 reserved bytes */
+#define SYS_GPIO_CFG1      0x3008 /* PAD configuration for GPIO4 */
+#define SYS_DEMOD_CTL1     0x300B
+
+/* IrDA registers */
+#define SYS_IRRC_PSR       0x3020 /* IR protocol selection */
+#define SYS_IRRC_PER       0x3024 /* IR protocol extension */
+#define SYS_IRRC_SF        0x3028 /* IR sampling frequency */
+#define SYS_IRRC_DPIR      0x302C /* IR data package interval */
+#define SYS_IRRC_CR        0x3030 /* IR control */
+#define SYS_IRRC_RP        0x3034 /* IR read port */
+#define SYS_IRRC_SR        0x3038 /* IR status */
+/* I2C master registers */
+#define SYS_I2CCR          0x3040 /* I2C clock */
+#define SYS_I2CMCR         0x3044 /* I2C master control */
+#define SYS_I2CMSTR        0x3048 /* I2C master SCL timing */
+#define SYS_I2CMSR         0x304C /* I2C master status */
+#define SYS_I2CMFR         0x3050 /* I2C master FIFO */
+
+/*
+ * IR registers
+ */
+#define IR_RX_BUF          0xFC00
+#define IR_RX_IE           0xFD00
+#define IR_RX_IF           0xFD01
+#define IR_RX_CTRL         0xFD02
+#define IR_RX_CFG          0xFD03
+#define IR_MAX_DURATION0   0xFD04
+#define IR_MAX_DURATION1   0xFD05
+#define IR_IDLE_LEN0       0xFD06
+#define IR_IDLE_LEN1       0xFD07
+#define IR_GLITCH_LEN      0xFD08
+#define IR_RX_BUF_CTRL     0xFD09
+#define IR_RX_BUF_DATA     0xFD0A
+#define IR_RX_BC           0xFD0B
+#define IR_RX_CLK          0xFD0C
+#define IR_RX_C_COUNT_L    0xFD0D
+#define IR_RX_C_COUNT_H    0xFD0E
+#define IR_SUSPEND_CTRL    0xFD10
+#define IR_ERR_TOL_CTRL    0xFD11
+#define IR_UNIT_LEN        0xFD12
+#define IR_ERR_TOL_LEN     0xFD13
+#define IR_MAX_H_TOL_LEN   0xFD14
+#define IR_MAX_L_TOL_LEN   0xFD15
+#define IR_MASK_CTRL       0xFD16
+#define IR_MASK_DATA       0xFD17
+#define IR_RES_MASK_ADDR   0xFD18
+#define IR_RES_MASK_T_LEN  0xFD19
+
+#endif
index ebb5ed7..2124670 100644 (file)
@@ -425,6 +425,13 @@ config DVB_CXD2820R
        help
          Say Y when you want to support this frontend.
 
+config DVB_RTL2830
+       tristate "Realtek RTL2830 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
 
@@ -698,6 +705,14 @@ config DVB_IT913X_FE
          A DVB-T tuner module.
          Say Y when you want to support this frontend.
 
+config DVB_M88RS2000
+       tristate "M88RS2000 DVB-S demodulator and tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S tuner module.
+         Say Y when you want to support this frontend.
+
 comment "Tools to develop new frontends"
 
 config DVB_DUMMY_FE
index 00a2063..86fa808 100644 (file)
@@ -2,8 +2,8 @@
 # Makefile for the kernel DVB frontend device drivers.
 #
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/
-ccflags-y += -Idrivers/media/common/tuners/
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core/
+ccflags-y += -I$(srctree)/drivers/media/common/tuners/
 
 stb0899-objs = stb0899_drv.o stb0899_algo.o
 stv0900-objs = stv0900_core.o stv0900_sw.o
@@ -96,4 +96,6 @@ obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
 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_M88RS2000) += m88rs2000.o
 
index 2b248c1..55b6390 100644 (file)
@@ -839,15 +839,4 @@ static struct i2c_driver au8522_driver = {
        .id_table       = au8522_id,
 };
 
-static __init int init_au8522(void)
-{
-       return i2c_add_driver(&au8522_driver);
-}
-
-static __exit void exit_au8522(void)
-{
-       i2c_del_driver(&au8522_driver);
-}
-
-module_init(init_au8522);
-module_exit(exit_au8522);
+module_i2c_driver(au8522_driver);
index c688b95..25f6509 100644 (file)
@@ -588,11 +588,6 @@ static int au8522_set_frontend(struct dvb_frontend *fe)
            (state->current_modulation == c->modulation))
                return 0;
 
-       au8522_enable_modulation(fe, c->modulation);
-
-       /* Allow the demod to settle */
-       msleep(100);
-
        if (fe->ops.tuner_ops.set_params) {
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
@@ -604,6 +599,11 @@ static int au8522_set_frontend(struct dvb_frontend *fe)
        if (ret < 0)
                return ret;
 
+       /* Allow the tuner to settle */
+       msleep(100);
+
+       au8522_enable_modulation(fe, c->modulation);
+
        state->current_frequency = c->frequency;
 
        return 0;
index faba824..edc8eaf 100644 (file)
@@ -502,10 +502,26 @@ static int cx22702_read_signal_strength(struct dvb_frontend *fe,
        u16 *signal_strength)
 {
        struct cx22702_state *state = fe->demodulator_priv;
+       u8 reg23;
 
-       u16 rs_ber;
-       rs_ber = cx22702_readreg(state, 0x23);
-       *signal_strength = (rs_ber << 8) | rs_ber;
+       /*
+        * Experience suggests that the strength signal register works as
+        * follows:
+        * - In the absence of signal, value is 0xff.
+        * - In the presence of a weak signal, bit 7 is set, not sure what
+        *   the lower 7 bits mean.
+        * - In the presence of a strong signal, the register holds a 7-bit
+        *   value (bit 7 is cleared), with greater values standing for
+        *   weaker signals.
+        */
+       reg23 = cx22702_readreg(state, 0x23);
+       if (reg23 & 0x80) {
+               *signal_strength = 0;
+       } else {
+               reg23 = ~reg23 & 0x7f;
+               /* Scale to 16 bit */
+               *signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5);
+       }
 
        return 0;
 }
index 224d81e..d9fe60b 100644 (file)
@@ -519,7 +519,7 @@ static int dib0090_fw_identify(struct dvb_frontend *fe)
        return 0;
 
 identification_error:
-       return -EIO;;
+       return -EIO;
 }
 
 static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
index 863ef3c..80848b4 100644 (file)
@@ -33,7 +33,7 @@ struct i2c_device {
 
 /* lock */
 #define DIB_LOCK struct mutex
-#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock) < 0) dprintk("could not get the lock"); } while (0)
+#define DibAcquireLock(lock) mutex_lock_interruptible(lock)
 #define DibReleaseLock(lock) mutex_unlock(lock)
 #define DibInitLock(lock) mutex_init(lock)
 #define DibFreeLock(lock)
@@ -446,7 +446,10 @@ static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u1
        if (!state->platform.risc.fw_is_running)
                return -EIO;
 
-       DibAcquireLock(&state->platform.risc.mem_lock);
+       if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
        dib9000_risc_mem_setup(state, cmd | 0x80);
        dib9000_risc_mem_read_chunks(state, b, len);
        DibReleaseLock(&state->platform.risc.mem_lock);
@@ -459,7 +462,10 @@ static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8
        if (!state->platform.risc.fw_is_running)
                return -EIO;
 
-       DibAcquireLock(&state->platform.risc.mem_lock);
+       if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
        dib9000_risc_mem_setup(state, cmd);
        dib9000_risc_mem_write_chunks(state, b, m->size);
        DibReleaseLock(&state->platform.risc.mem_lock);
@@ -531,7 +537,10 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data,
        if (!state->platform.risc.fw_is_running)
                return -EINVAL;
 
-       DibAcquireLock(&state->platform.risc.mbx_if_lock);
+       if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
        tmp = MAX_MAILBOX_TRY;
        do {
                size = dib9000_read_word_attr(state, 1043, attr) & 0xff;
@@ -593,7 +602,10 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id,
        if (!state->platform.risc.fw_is_running)
                return 0;
 
-       DibAcquireLock(&state->platform.risc.mbx_if_lock);
+       if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) {
+               dprintk("could not get the lock");
+               return 0;
+       }
        if (risc_id == 1)
                mc_base = 16;
        else
@@ -701,7 +713,10 @@ static int dib9000_mbx_process(struct dib9000_state *state, u16 attr)
        if (!state->platform.risc.fw_is_running)
                return -1;
 
-       DibAcquireLock(&state->platform.risc.mbx_lock);
+       if (DibAcquireLock(&state->platform.risc.mbx_lock) < 0) {
+               dprintk("could not get the lock");
+               return -1;
+       }
 
        if (dib9000_mbx_count(state, 1, attr))  /* 1=RiscB */
                ret = dib9000_mbx_fetch_to_cache(state, attr);
@@ -1178,7 +1193,10 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe)
        struct dibDVBTChannel *ch;
        int ret = 0;
 
-       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
        if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
                ret = -EIO;
                goto error;
@@ -1660,7 +1678,10 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2
                p[12] = 0;
        }
 
-       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+               dprintk("could not get the lock");
+               return 0;
+       }
 
        dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p);
 
@@ -1768,7 +1789,10 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
                return 0;
        }
 
-       DibAcquireLock(&state->demod_lock);
+       if (DibAcquireLock(&state->demod_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
 
        val = dib9000_read_word(state, 294 + 1) & 0xffef;
        val |= (onoff & 0x1) << 4;
@@ -1800,7 +1824,10 @@ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
                return 0;
        }
 
-       DibAcquireLock(&state->demod_lock);
+       if (DibAcquireLock(&state->demod_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
        dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
        ret = dib9000_write_word(state, 300 + 1 + id,
                        onoff ? (1 << 13) | pid : 0);
@@ -1848,7 +1875,10 @@ static int dib9000_sleep(struct dvb_frontend *fe)
        u8 index_frontend;
        int ret = 0;
 
-       DibAcquireLock(&state->demod_lock);
+       if (DibAcquireLock(&state->demod_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
                ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
                if (ret < 0)
@@ -1874,8 +1904,12 @@ static int dib9000_get_frontend(struct dvb_frontend *fe)
        fe_status_t stat;
        int ret = 0;
 
-       if (state->get_frontend_internal == 0)
-               DibAcquireLock(&state->demod_lock);
+       if (state->get_frontend_internal == 0) {
+               if (DibAcquireLock(&state->demod_lock) < 0) {
+                       dprintk("could not get the lock");
+                       return -EINTR;
+               }
+       }
 
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
                state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
@@ -1978,7 +2012,10 @@ static int dib9000_set_frontend(struct dvb_frontend *fe)
        }
 
        state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
-       DibAcquireLock(&state->demod_lock);
+       if (DibAcquireLock(&state->demod_lock) < 0) {
+               dprintk("could not get the lock");
+               return 0;
+       }
 
        fe->dtv_property_cache.delivery_system = SYS_DVBT;
 
@@ -2138,7 +2175,10 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
        u8 index_frontend;
        u16 lock = 0, lock_slave = 0;
 
-       DibAcquireLock(&state->demod_lock);
+       if (DibAcquireLock(&state->demod_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
                lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
 
@@ -2168,8 +2208,15 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
        u16 *c;
        int ret = 0;
 
-       DibAcquireLock(&state->demod_lock);
-       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (DibAcquireLock(&state->demod_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
+       if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+               dprintk("could not get the lock");
+               ret = -EINTR;
+               goto error;
+       }
        if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
                DibReleaseLock(&state->platform.risc.mem_mbx_lock);
                ret = -EIO;
@@ -2196,7 +2243,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
        u16 val;
        int ret = 0;
 
-       DibAcquireLock(&state->demod_lock);
+       if (DibAcquireLock(&state->demod_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
        *strength = 0;
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
                state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
@@ -2206,8 +2256,13 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
                        *strength += val;
        }
 
-       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+               dprintk("could not get the lock");
+               ret = -EINTR;
+               goto error;
+       }
        if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+               DibReleaseLock(&state->platform.risc.mem_mbx_lock);
                ret = -EIO;
                goto error;
        }
@@ -2232,9 +2287,14 @@ static u32 dib9000_get_snr(struct dvb_frontend *fe)
        u32 n, s, exp;
        u16 val;
 
-       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
-       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
-               return -EIO;
+       if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+               dprintk("could not get the lock");
+               return 0;
+       }
+       if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+               DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+               return 0;
+       }
        dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
        DibReleaseLock(&state->platform.risc.mem_mbx_lock);
 
@@ -2266,7 +2326,10 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
        u8 index_frontend;
        u32 snr_master;
 
-       DibAcquireLock(&state->demod_lock);
+       if (DibAcquireLock(&state->demod_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
        snr_master = dib9000_get_snr(fe);
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
                snr_master += dib9000_get_snr(state->fe[index_frontend]);
@@ -2288,9 +2351,17 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
        u16 *c = (u16 *)state->i2c_read_buffer;
        int ret = 0;
 
-       DibAcquireLock(&state->demod_lock);
-       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+       if (DibAcquireLock(&state->demod_lock) < 0) {
+               dprintk("could not get the lock");
+               return -EINTR;
+       }
+       if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+               dprintk("could not get the lock");
+               ret = -EINTR;
+               goto error;
+       }
        if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
+               DibReleaseLock(&state->platform.risc.mem_mbx_lock);
                ret = -EIO;
                goto error;
        }
index 7bf39cd..f380eb4 100644 (file)
@@ -101,9 +101,9 @@ struct SCfgAgc {
 
 struct SNoiseCal {
        int cpOpt;
-       u16 cpNexpOfs;
-       u16 tdCal2k;
-       u16 tdCal8k;
+       short cpNexpOfs;
+       short tdCal2k;
+       short tdCal8k;
 };
 
 enum app_env {
index 0209818..9d64e4f 100644 (file)
@@ -7,15 +7,19 @@
 /**
  * struct drxk_config - Configure the initial parameters for DRX-K
  *
- * adr:                        I2C Address of the DRX-K
- * parallel_ts:                true means that the device uses parallel TS,
+ * @adr:               I2C Address of the DRX-K
+ * @parallel_ts:       True means that the device uses parallel TS,
  *                     Serial otherwise.
- * single_master:      Device is on the single master mode
- * no_i2c_bridge:      Don't switch the I2C bridge to talk with tuner
- * antenna_gpio:       GPIO bit used to control the antenna
- * antenna_dvbt:       GPIO bit for changing antenna to DVB-C. A value of 1
+ * @dynamic_clk:       True means that the clock will be dynamically
+ *                     adjusted. Static clock otherwise.
+ * @enable_merr_cfg:   Enable SIO_PDR_PERR_CFG/SIO_PDR_MVAL_CFG.
+ * @single_master:     Device is on the single master mode
+ * @no_i2c_bridge:     Don't switch the I2C bridge to talk with tuner
+ * @antenna_gpio:      GPIO bit used to control the antenna
+ * @antenna_dvbt:      GPIO bit for changing antenna to DVB-C. A value of 1
  *                     means that 1=DVBC, 0 = DVBT. Zero means the opposite.
- * microcode_name:     Name of the firmware file with the microcode
+ * @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength.
+ * @microcode_name:    Name of the firmware file with the microcode
  *
  * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
  * UIO-3.
@@ -25,11 +29,14 @@ struct drxk_config {
        bool    single_master;
        bool    no_i2c_bridge;
        bool    parallel_ts;
+       bool    dynamic_clk;
+       bool    enable_merr_cfg;
 
        bool    antenna_dvbt;
        u16     antenna_gpio;
 
-       int    chunk_size;
+       u8      mpeg_out_clk_strength;
+       int     chunk_size;
 
        const char *microcode_name;
 };
index 5ab5379..36d1175 100644 (file)
@@ -90,10 +90,6 @@ bool IsA1WithRomCode(struct drxk_state *state)
 #define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03)
 #endif
 
-#ifndef DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH
-#define DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH (0x06)
-#endif
-
 #define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700
 #define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500
 
@@ -649,9 +645,6 @@ static int init_state(struct drxk_state *state)
        u32 ulQual83 = DEFAULT_MER_83;
        u32 ulQual93 = DEFAULT_MER_93;
 
-       u32 ulDVBTStaticTSClock = 1;
-       u32 ulDVBCStaticTSClock = 1;
-
        u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
        u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
 
@@ -661,7 +654,6 @@ static int init_state(struct drxk_state *state)
        u32 ulGPIOCfg = 0x0113;
        u32 ulInvertTSClock = 0;
        u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
-       u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH;
        u32 ulDVBTBitrate = 50000000;
        u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
 
@@ -814,8 +806,7 @@ static int init_state(struct drxk_state *state)
        state->m_invertSTR = false;     /* If TRUE; invert STR signals */
        state->m_invertVAL = false;     /* If TRUE; invert VAL signals */
        state->m_invertCLK = (ulInvertTSClock != 0);    /* If TRUE; invert CLK signals */
-       state->m_DVBTStaticCLK = (ulDVBTStaticTSClock != 0);
-       state->m_DVBCStaticCLK = (ulDVBCStaticTSClock != 0);
+
        /* If TRUE; static MPEG clockrate will be used;
           otherwise clockrate will adapt to the bitrate of the TS */
 
@@ -823,7 +814,6 @@ static int init_state(struct drxk_state *state)
        state->m_DVBCBitrate = ulDVBCBitrate;
 
        state->m_TSDataStrength = (ulTSDataStrength & 0x07);
-       state->m_TSClockkStrength = (ulTSClockkStrength & 0x07);
 
        /* Maximum bitrate in b/s in case static clockrate is selected */
        state->m_mpegTsStaticBitrate = 19392658;
@@ -1188,6 +1178,7 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
        int status = -1;
        u16 sioPdrMclkCfg = 0;
        u16 sioPdrMdxCfg = 0;
+       u16 err_cfg = 0;
 
        dprintk(1, ": mpeg %s, %s mode\n",
                mpegEnable ? "enable" : "disable",
@@ -1253,12 +1244,17 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
                status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg);
                if (status < 0)
                        goto error;
-               status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000);   /* Disable */
+
+               if (state->enable_merr_cfg)
+                       err_cfg = sioPdrMdxCfg;
+
+               status = write16(state, SIO_PDR_MERR_CFG__A, err_cfg);
                if (status < 0)
                        goto error;
-               status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000);   /* Disable */
+               status = write16(state, SIO_PDR_MVAL_CFG__A, err_cfg);
                if (status < 0)
                        goto error;
+
                if (state->m_enableParallel == true) {
                        /* paralel -> enable MD1 to MD7 */
                        status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg);
@@ -6069,9 +6065,7 @@ static int init_drxk(struct drxk_state *state)
                if (status < 0)
                        goto error;
 
-               if (!state->microcode_name)
-                       load_microcode(state, "drxk_a3.mc");
-               else
+               if (state->microcode_name)
                        load_microcode(state, state->microcode_name);
 
                /* disable token-ring bus through OFDM block for possible ucode upload */
@@ -6322,15 +6316,12 @@ static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_t
        switch (p->delivery_system) {
        case SYS_DVBC_ANNEX_A:
        case SYS_DVBC_ANNEX_C:
+       case SYS_DVBT:
                sets->min_delay_ms = 3000;
                sets->max_drift = 0;
                sets->step_size = 0;
                return 0;
        default:
-               /*
-                * For DVB-T, let it use the default DVB core way, that is:
-                *      fepriv->step_size = fe->ops.info.frequency_stepsize * 2
-                */
                return -EINVAL;
        }
 }
@@ -6390,6 +6381,21 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
        state->antenna_gpio = config->antenna_gpio;
        state->antenna_dvbt = config->antenna_dvbt;
        state->m_ChunkSize = config->chunk_size;
+       state->enable_merr_cfg = config->enable_merr_cfg;
+
+       if (config->dynamic_clk) {
+               state->m_DVBTStaticCLK = 0;
+               state->m_DVBCStaticCLK = 0;
+       } else {
+               state->m_DVBTStaticCLK = 1;
+               state->m_DVBCStaticCLK = 1;
+       }
+
+
+       if (config->mpeg_out_clk_strength)
+               state->m_TSClockkStrength = config->mpeg_out_clk_strength & 0x07;
+       else
+               state->m_TSClockkStrength = 0x06;
 
        if (config->parallel_ts)
                state->m_enableParallel = true;
index 3a58b73..4bbf841 100644 (file)
@@ -332,6 +332,7 @@ struct drxk_state {
 
        u16     UIO_mask;       /* Bits used by UIO */
 
+       bool    enable_merr_cfg;
        bool    single_master;
        bool    no_i2c_bridge;
        bool    antenna_dvbt;
index 93b086e..eb6fd8a 100644 (file)
@@ -201,6 +201,11 @@ fe_modulation_t fe_con[] = {
        QAM_64,
 };
 
+enum {
+       PRIORITY_HIGH = 0,      /* High-priority stream */
+       PRIORITY_LOW,   /* Low-priority stream */
+};
+
 /* Standard demodulator functions */
 static struct it913xset set_solo_fe[] = {
        {PRO_LINK, GPIOH5_EN, {0x01}, 0x01},
index ccc36bf..84df03c 100644 (file)
@@ -57,6 +57,7 @@ struct it913x_fe_state {
        u32 frequency;
        fe_modulation_t constellation;
        fe_transmit_mode_t transmission_mode;
+       u8 priority;
        u32 crystalFrequency;
        u32 adcFrequency;
        u8 tuner_type;
@@ -500,19 +501,87 @@ static int it913x_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
        return 0;
 }
 
+/* FEC values based on fe_code_rate_t non supported values 0*/
+int it913x_qpsk_pval[] = {0, -93, -91, -90, 0, -89, -88};
+int it913x_16qam_pval[] = {0, -87, -85, -84, 0, -83, -82};
+int it913x_64qam_pval[] = {0, -82, -80, -78, 0, -77, -76};
+
+static int it913x_get_signal_strength(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+       struct it913x_fe_state *state = fe->demodulator_priv;
+       u8 code_rate;
+       int ret, temp;
+       u8 lna_gain_os;
+
+       ret = it913x_read_reg_u8(state, VAR_P_INBAND);
+       if (ret < 0)
+               return ret;
+
+       /* VHF/UHF gain offset */
+       if (state->frequency < 300000000)
+               lna_gain_os = 7;
+       else
+               lna_gain_os = 14;
+
+       temp = (ret - 100) - lna_gain_os;
+
+       if (state->priority == PRIORITY_HIGH)
+               code_rate = p->code_rate_HP;
+       else
+               code_rate = p->code_rate_LP;
+
+       if (code_rate >= ARRAY_SIZE(it913x_qpsk_pval))
+               return -EINVAL;
+
+       deb_info("Reg VAR_P_INBAND:%d Calc Offset Value:%d", ret, temp);
+
+       /* Apply FEC offset values*/
+       switch (p->modulation) {
+       case QPSK:
+               temp -= it913x_qpsk_pval[code_rate];
+               break;
+       case QAM_16:
+               temp -= it913x_16qam_pval[code_rate];
+               break;
+       case QAM_64:
+               temp -= it913x_64qam_pval[code_rate];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (temp < -15)
+               ret = 0;
+       else if ((-15 <= temp) && (temp < 0))
+               ret = (2 * (temp + 15)) / 3;
+       else if ((0 <= temp) && (temp < 20))
+               ret = 4 * temp + 10;
+       else if ((20 <= temp) && (temp < 35))
+               ret = (2 * (temp - 20)) / 3 + 90;
+       else if (temp >= 35)
+               ret = 100;
+
+       deb_info("Signal Strength :%d", ret);
+
+       return ret;
+}
+
 static int it913x_fe_read_signal_strength(struct dvb_frontend *fe,
                u16 *strength)
 {
        struct it913x_fe_state *state = fe->demodulator_priv;
-       int ret = it913x_read_reg_u8(state, SIGNAL_LEVEL);
-       /*SIGNAL_LEVEL always returns 100%! so using FE_HAS_SIGNAL as switch*/
-       if (state->it913x_status & FE_HAS_SIGNAL)
-               ret = (ret * 0xff) / 0x64;
-       else
-               ret = 0x0;
-       ret |= ret << 0x8;
-       *strength = ret;
-       return 0;
+       int ret = 0;
+       if (state->config->read_slevel) {
+               if (state->it913x_status & FE_HAS_SIGNAL)
+                       ret = it913x_read_reg_u8(state, SIGNAL_LEVEL);
+       } else
+               ret = it913x_get_signal_strength(fe);
+
+       if (ret >= 0)
+               *strength = (u16)((u32)ret * 0xffff / 0x64);
+
+       return (ret < 0) ? -ENODEV : 0;
 }
 
 static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
@@ -606,6 +675,8 @@ static int it913x_fe_get_frontend(struct dvb_frontend *fe)
        if (reg[2] < 4)
                p->hierarchy = fe_hi[reg[2]];
 
+       state->priority = reg[5];
+
        p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE;
        p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE;
 
@@ -972,5 +1043,5 @@ static struct dvb_frontend_ops it913x_fe_ofdm_ops = {
 
 MODULE_DESCRIPTION("it913x Frontend and it9137 tuner");
 MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
-MODULE_VERSION("1.13");
+MODULE_VERSION("1.15");
 MODULE_LICENSE("GPL");
index c4a908e..07fa459 100644 (file)
@@ -34,6 +34,8 @@ struct ite_config {
        u8 tuner_id_1;
        u8 dual_mode;
        u8 adf;
+       /* option to read SIGNAL_LEVEL */
+       u8 read_slevel;
 };
 
 #if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \
@@ -168,6 +170,8 @@ static inline struct dvb_frontend *it913x_fe_attach(
 #define EST_SIGNAL_LEVEL       0x004a
 #define FREE_BAND              0x004b
 #define SUSPEND_FLAG           0x004c
+#define VAR_P_INBAND           0x00f7
+
 /* Build in tuner types */
 #define IT9137 0x38
 #define IT9135_38 0x38
index c990d35..e046622 100644 (file)
@@ -104,8 +104,8 @@ static int i2c_write_demod_bytes (struct lgdt330x_state* state,
  * then reads the data returned for (len) bytes.
  */
 
-static u8 i2c_read_demod_bytes (struct lgdt330x_state* state,
-                              enum I2C_REG reg, u8* buf, int len)
+static int i2c_read_demod_bytes(struct lgdt330x_state *state,
+                               enum I2C_REG reg, u8 *buf, int len)
 {
        u8 wr [] = { reg };
        struct i2c_msg msg [] = {
@@ -118,6 +118,8 @@ static u8 i2c_read_demod_bytes (struct lgdt330x_state* state,
        ret = i2c_transfer(state->i2c, msg, 2);
        if (ret != 2) {
                printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __func__, state->config->demod_address, reg, ret);
+               if (ret >= 0)
+                       ret = -EIO;
        } else {
                ret = 0;
        }
diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c
new file mode 100644 (file)
index 0000000..045ee5a
--- /dev/null
@@ -0,0 +1,904 @@
+/*
+       Driver for M88RS2000 demodulator and tuner
+
+       Copyright (C) 2012 Malcolm Priestley (tvboxspy@gmail.com)
+       Beta Driver
+
+       Include various calculation code from DS3000 driver.
+       Copyright (C) 2009 Konstantin Dimitrov.
+
+       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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+
+#include "dvb_frontend.h"
+#include "m88rs2000.h"
+
+struct m88rs2000_state {
+       struct i2c_adapter *i2c;
+       const struct m88rs2000_config *config;
+       struct dvb_frontend frontend;
+       u8 no_lock_count;
+       u32 tuner_frequency;
+       u32 symbol_rate;
+       fe_code_rate_t fec_inner;
+       u8 tuner_level;
+       int errmode;
+};
+
+static int m88rs2000_debug;
+
+module_param_named(debug, m88rs2000_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
+
+#define dprintk(level, args...) do { \
+       if (level & m88rs2000_debug) \
+               printk(KERN_DEBUG "m88rs2000-fe: " args); \
+} while (0)
+
+#define deb_info(args...)  dprintk(0x01, args)
+#define info(format, arg...) \
+       printk(KERN_INFO "m88rs2000-fe: " format "\n" , ## arg)
+
+static int m88rs2000_writereg(struct m88rs2000_state *state, u8 tuner,
+       u8 reg, u8 data)
+{
+       int ret;
+       u8 addr = (tuner == 0) ? state->config->tuner_addr :
+               state->config->demod_addr;
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = {
+               .addr = addr,
+               .flags = 0,
+               .buf = buf,
+               .len = 2
+       };
+
+       ret = i2c_transfer(state->i2c, &msg, 1);
+
+       if (ret != 1)
+               deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, "
+                       "ret == %i)\n", __func__, reg, data, ret);
+
+       return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int m88rs2000_demod_write(struct m88rs2000_state *state, u8 reg, u8 data)
+{
+       return m88rs2000_writereg(state, 1, reg, data);
+}
+
+static int m88rs2000_tuner_write(struct m88rs2000_state *state, u8 reg, u8 data)
+{
+       m88rs2000_demod_write(state, 0x81, 0x84);
+       udelay(10);
+       return m88rs2000_writereg(state, 0, reg, data);
+
+}
+
+static int m88rs2000_write(struct dvb_frontend *fe, const u8 buf[], int len)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+
+       if (len != 2)
+               return -EINVAL;
+
+       return m88rs2000_writereg(state, 1, buf[0], buf[1]);
+}
+
+static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 tuner, u8 reg)
+{
+       int ret;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+       u8 addr = (tuner == 0) ? state->config->tuner_addr :
+               state->config->demod_addr;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = addr,
+                       .flags = 0,
+                       .buf = b0,
+                       .len = 1
+               }, {
+                       .addr = addr,
+                       .flags = I2C_M_RD,
+                       .buf = b1,
+                       .len = 1
+               }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2)
+               deb_info("%s: readreg error (reg == 0x%02x, ret == %i)\n",
+                               __func__, reg, ret);
+
+       return b1[0];
+}
+
+static u8 m88rs2000_demod_read(struct m88rs2000_state *state, u8 reg)
+{
+       return m88rs2000_readreg(state, 1, reg);
+}
+
+static u8 m88rs2000_tuner_read(struct m88rs2000_state *state, u8 reg)
+{
+       m88rs2000_demod_write(state, 0x81, 0x85);
+       udelay(10);
+       return m88rs2000_readreg(state, 0, reg);
+}
+
+static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       int ret;
+       u32 temp;
+       u8 b[3];
+
+       if ((srate < 1000000) || (srate > 45000000))
+               return -EINVAL;
+
+       temp = srate / 1000;
+       temp *= 11831;
+       temp /= 68;
+       temp -= 3;
+
+       b[0] = (u8) (temp >> 16) & 0xff;
+       b[1] = (u8) (temp >> 8) & 0xff;
+       b[2] = (u8) temp & 0xff;
+       ret = m88rs2000_demod_write(state, 0x93, b[2]);
+       ret |= m88rs2000_demod_write(state, 0x94, b[1]);
+       ret |= m88rs2000_demod_write(state, 0x95, b[0]);
+
+       deb_info("m88rs2000: m88rs2000_set_symbolrate\n");
+       return ret;
+}
+
+static int m88rs2000_send_diseqc_msg(struct dvb_frontend *fe,
+                                   struct dvb_diseqc_master_cmd *m)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+
+       int i;
+       u8 reg;
+       deb_info("%s\n", __func__);
+       m88rs2000_demod_write(state, 0x9a, 0x30);
+       reg = m88rs2000_demod_read(state, 0xb2);
+       reg &= 0x3f;
+       m88rs2000_demod_write(state, 0xb2, reg);
+       for (i = 0; i <  m->msg_len; i++)
+               m88rs2000_demod_write(state, 0xb3 + i, m->msg[i]);
+
+       reg = m88rs2000_demod_read(state, 0xb1);
+       reg &= 0x87;
+       reg |= ((m->msg_len - 1) << 3) | 0x07;
+       reg &= 0x7f;
+       m88rs2000_demod_write(state, 0xb1, reg);
+
+       for (i = 0; i < 15; i++) {
+               if ((m88rs2000_demod_read(state, 0xb1) & 0x40) == 0x0)
+                       break;
+               msleep(20);
+       }
+
+       reg = m88rs2000_demod_read(state, 0xb1);
+       if ((reg & 0x40) > 0x0) {
+               reg &= 0x7f;
+               reg |= 0x40;
+               m88rs2000_demod_write(state, 0xb1, reg);
+       }
+
+       reg = m88rs2000_demod_read(state, 0xb2);
+       reg &= 0x3f;
+       reg |= 0x80;
+       m88rs2000_demod_write(state, 0xb2, reg);
+       m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+
+       return 0;
+}
+
+static int m88rs2000_send_diseqc_burst(struct dvb_frontend *fe,
+                                               fe_sec_mini_cmd_t burst)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       u8 reg0, reg1;
+       deb_info("%s\n", __func__);
+       m88rs2000_demod_write(state, 0x9a, 0x30);
+       msleep(50);
+       reg0 = m88rs2000_demod_read(state, 0xb1);
+       reg1 = m88rs2000_demod_read(state, 0xb2);
+       /* TODO complete this section */
+       m88rs2000_demod_write(state, 0xb2, reg1);
+       m88rs2000_demod_write(state, 0xb1, reg0);
+       m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+       return 0;
+}
+
+static int m88rs2000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       u8 reg0, reg1;
+       m88rs2000_demod_write(state, 0x9a, 0x30);
+       reg0 = m88rs2000_demod_read(state, 0xb1);
+       reg1 = m88rs2000_demod_read(state, 0xb2);
+
+       reg1 &= 0x3f;
+
+       switch (tone) {
+       case SEC_TONE_ON:
+               reg0 |= 0x4;
+               reg0 &= 0xbc;
+               break;
+       case SEC_TONE_OFF:
+               reg1 |= 0x80;
+               break;
+       default:
+               break;
+       }
+       m88rs2000_demod_write(state, 0xb2, reg1);
+       m88rs2000_demod_write(state, 0xb1, reg0);
+       m88rs2000_demod_write(state, 0x9a, 0xb0);
+       return 0;
+}
+
+struct inittab {
+       u8 cmd;
+       u8 reg;
+       u8 val;
+};
+
+struct inittab m88rs2000_setup[] = {
+       {DEMOD_WRITE, 0x9a, 0x30},
+       {DEMOD_WRITE, 0x00, 0x01},
+       {WRITE_DELAY, 0x19, 0x00},
+       {DEMOD_WRITE, 0x00, 0x00},
+       {DEMOD_WRITE, 0x9a, 0xb0},
+       {DEMOD_WRITE, 0x81, 0xc1},
+       {TUNER_WRITE, 0x42, 0x73},
+       {TUNER_WRITE, 0x05, 0x07},
+       {TUNER_WRITE, 0x20, 0x27},
+       {TUNER_WRITE, 0x07, 0x02},
+       {TUNER_WRITE, 0x11, 0xff},
+       {TUNER_WRITE, 0x60, 0xf9},
+       {TUNER_WRITE, 0x08, 0x01},
+       {TUNER_WRITE, 0x00, 0x41},
+       {DEMOD_WRITE, 0x81, 0x81},
+       {DEMOD_WRITE, 0x86, 0xc6},
+       {DEMOD_WRITE, 0x9a, 0x30},
+       {DEMOD_WRITE, 0xf0, 0x22},
+       {DEMOD_WRITE, 0xf1, 0xbf},
+       {DEMOD_WRITE, 0xb0, 0x45},
+       {DEMOD_WRITE, 0xb2, 0x01}, /* set voltage pin always set 1*/
+       {DEMOD_WRITE, 0x9a, 0xb0},
+       {0xff, 0xaa, 0xff}
+};
+
+struct inittab m88rs2000_shutdown[] = {
+       {DEMOD_WRITE, 0x9a, 0x30},
+       {DEMOD_WRITE, 0xb0, 0x00},
+       {DEMOD_WRITE, 0xf1, 0x89},
+       {DEMOD_WRITE, 0x00, 0x01},
+       {DEMOD_WRITE, 0x9a, 0xb0},
+       {TUNER_WRITE, 0x00, 0x40},
+       {DEMOD_WRITE, 0x81, 0x81},
+       {0xff, 0xaa, 0xff}
+};
+
+struct inittab tuner_reset[] = {
+       {TUNER_WRITE, 0x42, 0x73},
+       {TUNER_WRITE, 0x05, 0x07},
+       {TUNER_WRITE, 0x20, 0x27},
+       {TUNER_WRITE, 0x07, 0x02},
+       {TUNER_WRITE, 0x11, 0xff},
+       {TUNER_WRITE, 0x60, 0xf9},
+       {TUNER_WRITE, 0x08, 0x01},
+       {TUNER_WRITE, 0x00, 0x41},
+       {0xff, 0xaa, 0xff}
+};
+
+struct inittab fe_reset[] = {
+       {DEMOD_WRITE, 0x00, 0x01},
+       {DEMOD_WRITE, 0xf1, 0xbf},
+       {DEMOD_WRITE, 0x00, 0x01},
+       {DEMOD_WRITE, 0x20, 0x81},
+       {DEMOD_WRITE, 0x21, 0x80},
+       {DEMOD_WRITE, 0x10, 0x33},
+       {DEMOD_WRITE, 0x11, 0x44},
+       {DEMOD_WRITE, 0x12, 0x07},
+       {DEMOD_WRITE, 0x18, 0x20},
+       {DEMOD_WRITE, 0x28, 0x04},
+       {DEMOD_WRITE, 0x29, 0x8e},
+       {DEMOD_WRITE, 0x3b, 0xff},
+       {DEMOD_WRITE, 0x32, 0x10},
+       {DEMOD_WRITE, 0x33, 0x02},
+       {DEMOD_WRITE, 0x34, 0x30},
+       {DEMOD_WRITE, 0x35, 0xff},
+       {DEMOD_WRITE, 0x38, 0x50},
+       {DEMOD_WRITE, 0x39, 0x68},
+       {DEMOD_WRITE, 0x3c, 0x7f},
+       {DEMOD_WRITE, 0x3d, 0x0f},
+       {DEMOD_WRITE, 0x45, 0x20},
+       {DEMOD_WRITE, 0x46, 0x24},
+       {DEMOD_WRITE, 0x47, 0x7c},
+       {DEMOD_WRITE, 0x48, 0x16},
+       {DEMOD_WRITE, 0x49, 0x04},
+       {DEMOD_WRITE, 0x4a, 0x01},
+       {DEMOD_WRITE, 0x4b, 0x78},
+       {DEMOD_WRITE, 0X4d, 0xd2},
+       {DEMOD_WRITE, 0x4e, 0x6d},
+       {DEMOD_WRITE, 0x50, 0x30},
+       {DEMOD_WRITE, 0x51, 0x30},
+       {DEMOD_WRITE, 0x54, 0x7b},
+       {DEMOD_WRITE, 0x56, 0x09},
+       {DEMOD_WRITE, 0x58, 0x59},
+       {DEMOD_WRITE, 0x59, 0x37},
+       {DEMOD_WRITE, 0x63, 0xfa},
+       {0xff, 0xaa, 0xff}
+};
+
+struct inittab fe_trigger[] = {
+       {DEMOD_WRITE, 0x97, 0x04},
+       {DEMOD_WRITE, 0x99, 0x77},
+       {DEMOD_WRITE, 0x9b, 0x64},
+       {DEMOD_WRITE, 0x9e, 0x00},
+       {DEMOD_WRITE, 0x9f, 0xf8},
+       {DEMOD_WRITE, 0xa0, 0x20},
+       {DEMOD_WRITE, 0xa1, 0xe0},
+       {DEMOD_WRITE, 0xa3, 0x38},
+       {DEMOD_WRITE, 0x98, 0xff},
+       {DEMOD_WRITE, 0xc0, 0x0f},
+       {DEMOD_WRITE, 0x89, 0x01},
+       {DEMOD_WRITE, 0x00, 0x00},
+       {WRITE_DELAY, 0x0a, 0x00},
+       {DEMOD_WRITE, 0x00, 0x01},
+       {DEMOD_WRITE, 0x00, 0x00},
+       {DEMOD_WRITE, 0x9a, 0xb0},
+       {0xff, 0xaa, 0xff}
+};
+
+static int m88rs2000_tab_set(struct m88rs2000_state *state,
+               struct inittab *tab)
+{
+       int ret = 0;
+       u8 i;
+       if (tab == NULL)
+               return -EINVAL;
+
+       for (i = 0; i < 255; i++) {
+               switch (tab[i].cmd) {
+               case 0x01:
+                       ret = m88rs2000_demod_write(state, tab[i].reg,
+                               tab[i].val);
+                       break;
+               case 0x02:
+                       ret = m88rs2000_tuner_write(state, tab[i].reg,
+                               tab[i].val);
+                       break;
+               case 0x10:
+                       if (tab[i].reg > 0)
+                               mdelay(tab[i].reg);
+                       break;
+               case 0xff:
+                       if (tab[i].reg == 0xaa && tab[i].val == 0xff)
+                               return 0;
+               case 0x00:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               if (ret < 0)
+                       return -ENODEV;
+       }
+       return 0;
+}
+
+static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+       deb_info("%s: %s\n", __func__,
+               volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+               volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+
+       return 0;
+}
+
+static int m88rs2000_startup(struct m88rs2000_state *state)
+{
+       int ret = 0;
+       u8 reg;
+
+       reg = m88rs2000_tuner_read(state, 0x00);
+       if ((reg & 0x40) == 0)
+               ret = -ENODEV;
+
+       return ret;
+}
+
+static int m88rs2000_init(struct dvb_frontend *fe)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       int ret;
+
+       deb_info("m88rs2000: init chip\n");
+       /* Setup frontend from shutdown/cold */
+       ret = m88rs2000_tab_set(state, m88rs2000_setup);
+
+       return ret;
+}
+
+static int m88rs2000_sleep(struct dvb_frontend *fe)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       int ret;
+       /* Shutdown the frondend */
+       ret = m88rs2000_tab_set(state, m88rs2000_shutdown);
+       return ret;
+}
+
+static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       u8 reg = m88rs2000_demod_read(state, 0x8c);
+
+       *status = 0;
+
+       if ((reg & 0x7) == 0x7) {
+               *status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI
+                       | FE_HAS_LOCK;
+               if (state->config->set_ts_params)
+                       state->config->set_ts_params(fe, CALL_IS_READ);
+       }
+       return 0;
+}
+
+/* Extact code for these unknown but lmedm04 driver uses interupt callbacks */
+
+static int m88rs2000_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       deb_info("m88rs2000_read_ber %d\n", *ber);
+       *ber = 0;
+       return 0;
+}
+
+static int m88rs2000_read_signal_strength(struct dvb_frontend *fe,
+       u16 *strength)
+{
+       *strength = 0;
+       return 0;
+}
+
+static int m88rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       deb_info("m88rs2000_read_snr %d\n", *snr);
+       *snr = 0;
+       return 0;
+}
+
+static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       deb_info("m88rs2000_read_ber %d\n", *ucblocks);
+       *ucblocks = 0;
+       return 0;
+}
+
+static int m88rs2000_tuner_gate_ctrl(struct m88rs2000_state *state, u8 offset)
+{
+       int ret;
+       ret = m88rs2000_tuner_write(state, 0x51, 0x1f - offset);
+       ret |= m88rs2000_tuner_write(state, 0x51, 0x1f);
+       ret |= m88rs2000_tuner_write(state, 0x50, offset);
+       ret |= m88rs2000_tuner_write(state, 0x50, 0x00);
+       msleep(20);
+       return ret;
+}
+
+static int m88rs2000_set_tuner_rf(struct dvb_frontend *fe)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       int reg;
+       reg = m88rs2000_tuner_read(state, 0x3d);
+       reg &= 0x7f;
+       if (reg < 0x16)
+               reg = 0xa1;
+       else if (reg == 0x16)
+               reg = 0x99;
+       else
+               reg = 0xf9;
+
+       m88rs2000_tuner_write(state, 0x60, reg);
+       reg = m88rs2000_tuner_gate_ctrl(state, 0x08);
+
+       if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       return reg;
+}
+
+static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       int ret;
+       u32 frequency = c->frequency;
+       s32 offset_khz;
+       s32 tmp;
+       u32 symbol_rate = (c->symbol_rate / 1000);
+       u32 f3db, gdiv28;
+       u16 value, ndiv, lpf_coeff;
+       u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
+       u8 lo = 0x01, div4 = 0x0;
+
+       /* Reset Tuner */
+       ret = m88rs2000_tab_set(state, tuner_reset);
+
+       /* Calculate frequency divider */
+       if (frequency < 1060000) {
+               lo |= 0x10;
+               div4 = 0x1;
+               ndiv = (frequency * 14 * 4) / FE_CRYSTAL_KHZ;
+       } else
+               ndiv = (frequency * 14 * 2) / FE_CRYSTAL_KHZ;
+       ndiv = ndiv + ndiv % 2;
+       ndiv = ndiv - 1024;
+
+       ret = m88rs2000_tuner_write(state, 0x10, 0x80 | lo);
+
+       /* Set frequency divider */
+       ret |= m88rs2000_tuner_write(state, 0x01, (ndiv >> 8) & 0xf);
+       ret |= m88rs2000_tuner_write(state, 0x02, ndiv & 0xff);
+
+       ret |= m88rs2000_tuner_write(state, 0x03, 0x06);
+       ret |= m88rs2000_tuner_gate_ctrl(state, 0x10);
+       if (ret < 0)
+               return -ENODEV;
+
+       /* Tuner Frequency Range */
+       ret = m88rs2000_tuner_write(state, 0x10, lo);
+
+       ret |= m88rs2000_tuner_gate_ctrl(state, 0x08);
+
+       /* Tuner RF */
+       ret |= m88rs2000_set_tuner_rf(fe);
+
+       gdiv28 = (FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000;
+       ret |= m88rs2000_tuner_write(state, 0x04, gdiv28 & 0xff);
+       ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
+       if (ret < 0)
+               return -ENODEV;
+
+       value = m88rs2000_tuner_read(state, 0x26);
+
+       f3db = (symbol_rate * 135) / 200 + 2000;
+       f3db += FREQ_OFFSET_LOW_SYM_RATE;
+       if (f3db < 7000)
+               f3db = 7000;
+       if (f3db > 40000)
+               f3db = 40000;
+
+       gdiv28 = gdiv28 * 207 / (value * 2 + 151);
+       mlpf_max = gdiv28 * 135 / 100;
+       mlpf_min = gdiv28 * 78 / 100;
+       if (mlpf_max > 63)
+               mlpf_max = 63;
+
+       lpf_coeff = 2766;
+
+       nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
+               (FE_CRYSTAL_KHZ / 1000)  + 1) / 2;
+       if (nlpf > 23)
+               nlpf = 23;
+       if (nlpf < 1)
+               nlpf = 1;
+
+       lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
+               * lpf_coeff * 2  / f3db + 1) / 2;
+
+       if (lpf_mxdiv < mlpf_min) {
+               nlpf++;
+               lpf_mxdiv = (nlpf * (FE_CRYSTAL_KHZ / 1000)
+                       * lpf_coeff * 2  / f3db + 1) / 2;
+       }
+
+       if (lpf_mxdiv > mlpf_max)
+               lpf_mxdiv = mlpf_max;
+
+       ret = m88rs2000_tuner_write(state, 0x04, lpf_mxdiv);
+       ret |= m88rs2000_tuner_write(state, 0x06, nlpf);
+
+       ret |= m88rs2000_tuner_gate_ctrl(state, 0x04);
+
+       ret |= m88rs2000_tuner_gate_ctrl(state, 0x01);
+
+       msleep(80);
+       /* calculate offset assuming 96000kHz*/
+       offset_khz = (ndiv - ndiv % 2 + 1024) * FE_CRYSTAL_KHZ
+               / 14 / (div4 + 1) / 2;
+
+       offset_khz -= frequency;
+
+       tmp = offset_khz;
+       tmp *= 65536;
+
+       tmp = (2 * tmp + 96000) / (2 * 96000);
+       if (tmp < 0)
+               tmp += 65536;
+
+       *offset = tmp & 0xffff;
+
+       if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+
+       return (ret < 0) ? -EINVAL : 0;
+}
+
+static int m88rs2000_set_fec(struct m88rs2000_state *state,
+               fe_code_rate_t fec)
+{
+       int ret;
+       u16 fec_set;
+       switch (fec) {
+       /* This is not confirmed kept for reference */
+/*     case FEC_1_2:
+               fec_set = 0x88;
+               break;
+       case FEC_2_3:
+               fec_set = 0x68;
+               break;
+       case FEC_3_4:
+               fec_set = 0x48;
+               break;
+       case FEC_5_6:
+               fec_set = 0x28;
+               break;
+       case FEC_7_8:
+               fec_set = 0x18;
+               break; */
+       case FEC_AUTO:
+       default:
+               fec_set = 0x08;
+       }
+       ret = m88rs2000_demod_write(state, 0x76, fec_set);
+
+       return 0;
+}
+
+
+static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
+{
+       u8 reg;
+       m88rs2000_demod_write(state, 0x9a, 0x30);
+       reg = m88rs2000_demod_read(state, 0x76);
+       m88rs2000_demod_write(state, 0x9a, 0xb0);
+
+       switch (reg) {
+       case 0x88:
+               return FEC_1_2;
+       case 0x68:
+               return FEC_2_3;
+       case 0x48:
+               return FEC_3_4;
+       case 0x28:
+               return FEC_5_6;
+       case 0x18:
+               return FEC_7_8;
+       case 0x08:
+       default:
+               break;
+       }
+
+       return FEC_AUTO;
+}
+
+static int m88rs2000_set_frontend(struct dvb_frontend *fe)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       fe_status_t status;
+       int i, ret;
+       u16 offset = 0;
+       u8 reg;
+
+       state->no_lock_count = 0;
+
+       if (c->delivery_system != SYS_DVBS) {
+                       deb_info("%s: unsupported delivery "
+                               "system selected (%d)\n",
+                               __func__, c->delivery_system);
+                       return -EOPNOTSUPP;
+       }
+
+       /* Set Tuner */
+       ret = m88rs2000_set_tuner(fe, &offset);
+       if (ret < 0)
+               return -ENODEV;
+
+       ret = m88rs2000_demod_write(state, 0x9a, 0x30);
+       /* Unknown usually 0xc6 sometimes 0xc1 */
+       reg = m88rs2000_demod_read(state, 0x86);
+       ret |= m88rs2000_demod_write(state, 0x86, reg);
+       /* Offset lower nibble always 0 */
+       ret |= m88rs2000_demod_write(state, 0x9c, (offset >> 8));
+       ret |= m88rs2000_demod_write(state, 0x9d, offset & 0xf0);
+
+
+       /* Reset Demod */
+       ret = m88rs2000_tab_set(state, fe_reset);
+       if (ret < 0)
+               return -ENODEV;
+
+       /* Unknown */
+       reg = m88rs2000_demod_read(state, 0x70);
+       ret = m88rs2000_demod_write(state, 0x70, reg);
+
+       /* Set FEC */
+       ret |= m88rs2000_set_fec(state, c->fec_inner);
+       ret |= m88rs2000_demod_write(state, 0x85, 0x1);
+       ret |= m88rs2000_demod_write(state, 0x8a, 0xbf);
+       ret |= m88rs2000_demod_write(state, 0x8d, 0x1e);
+       ret |= m88rs2000_demod_write(state, 0x90, 0xf1);
+       ret |= m88rs2000_demod_write(state, 0x91, 0x08);
+
+       if (ret < 0)
+               return -ENODEV;
+
+       /* Set Symbol Rate */
+       ret = m88rs2000_set_symbolrate(fe, c->symbol_rate);
+       if (ret < 0)
+               return -ENODEV;
+
+       /* Set up Demod */
+       ret = m88rs2000_tab_set(state, fe_trigger);
+       if (ret < 0)
+               return -ENODEV;
+
+       for (i = 0; i < 25; i++) {
+               u8 reg = m88rs2000_demod_read(state, 0x8c);
+               if ((reg & 0x7) == 0x7) {
+                       status = FE_HAS_LOCK;
+                       break;
+               }
+               state->no_lock_count++;
+               if (state->no_lock_count > 15) {
+                       reg = m88rs2000_demod_read(state, 0x70);
+                       reg ^= 0x4;
+                       m88rs2000_demod_write(state, 0x70, reg);
+                       state->no_lock_count = 0;
+               }
+               if (state->no_lock_count == 20)
+                       m88rs2000_set_tuner_rf(fe);
+               msleep(20);
+       }
+
+       if (status & FE_HAS_LOCK) {
+               state->fec_inner = m88rs2000_get_fec(state);
+               /* Uknown suspect SNR level */
+               reg = m88rs2000_demod_read(state, 0x65);
+       }
+
+       state->tuner_frequency = c->frequency;
+       state->symbol_rate = c->symbol_rate;
+       return 0;
+}
+
+static int m88rs2000_get_frontend(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       c->fec_inner = state->fec_inner;
+       c->frequency = state->tuner_frequency;
+       c->symbol_rate = state->symbol_rate;
+       return 0;
+}
+
+static int m88rs2000_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+
+       if (enable)
+               m88rs2000_demod_write(state, 0x81, 0x84);
+       else
+               m88rs2000_demod_write(state, 0x81, 0x81);
+       udelay(10);
+       return 0;
+}
+
+static void m88rs2000_release(struct dvb_frontend *fe)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops m88rs2000_ops = {
+       .delsys = { SYS_DVBS },
+       .info = {
+               .name                   = "M88RS2000 DVB-S",
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 1000,  /* kHz for QPSK frontends */
+               .frequency_tolerance    = 5000,
+               .symbol_rate_min        = 1000000,
+               .symbol_rate_max        = 45000000,
+               .symbol_rate_tolerance  = 500,  /* ppm */
+               .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_QPSK |
+                     FE_CAN_FEC_AUTO
+       },
+
+       .release = m88rs2000_release,
+       .init = m88rs2000_init,
+       .sleep = m88rs2000_sleep,
+       .write = m88rs2000_write,
+       .i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl,
+       .read_status = m88rs2000_read_status,
+       .read_ber = m88rs2000_read_ber,
+       .read_signal_strength = m88rs2000_read_signal_strength,
+       .read_snr = m88rs2000_read_snr,
+       .read_ucblocks = m88rs2000_read_ucblocks,
+       .diseqc_send_master_cmd = m88rs2000_send_diseqc_msg,
+       .diseqc_send_burst = m88rs2000_send_diseqc_burst,
+       .set_tone = m88rs2000_set_tone,
+       .set_voltage = m88rs2000_set_voltage,
+
+       .set_frontend = m88rs2000_set_frontend,
+       .get_frontend = m88rs2000_get_frontend,
+};
+
+struct dvb_frontend *m88rs2000_attach(const struct m88rs2000_config *config,
+                                   struct i2c_adapter *i2c)
+{
+       struct m88rs2000_state *state = NULL;
+
+       /* allocate memory for the internal state */
+       state = kzalloc(sizeof(struct m88rs2000_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       state->tuner_frequency = 0;
+       state->symbol_rate = 0;
+       state->fec_inner = 0;
+
+       if (m88rs2000_startup(state) < 0)
+               goto error;
+
+       /* create dvb_frontend */
+       memcpy(&state->frontend.ops, &m88rs2000_ops,
+                       sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       kfree(state);
+
+       return NULL;
+}
+EXPORT_SYMBOL(m88rs2000_attach);
+
+MODULE_DESCRIPTION("M88RS2000 DVB-S Demodulator driver");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.13");
+
diff --git a/drivers/media/dvb/frontends/m88rs2000.h b/drivers/media/dvb/frontends/m88rs2000.h
new file mode 100644 (file)
index 0000000..59acdb6
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+       Driver for M88RS2000 demodulator
+
+       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 M88RS2000_H
+#define M88RS2000_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+struct m88rs2000_config {
+       /* Demodulator i2c address */
+       u8 demod_addr;
+       /* Tuner address */
+       u8 tuner_addr;
+
+       u8 *inittab;
+
+       /* minimum delay before retuning */
+       int min_delay_ms;
+
+       int (*set_ts_params)(struct dvb_frontend *, int);
+};
+
+enum {
+       CALL_IS_SET_FRONTEND = 0x0,
+       CALL_IS_READ,
+};
+
+#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \
+                                                       defined(MODULE))
+extern struct dvb_frontend *m88rs2000_attach(
+       const struct m88rs2000_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *m88rs2000_attach(
+       const struct m88rs2000_config *config, struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_M88RS2000 */
+
+#define FE_CRYSTAL_KHZ 27000
+#define FREQ_OFFSET_LOW_SYM_RATE 3000
+
+enum {
+       DEMOD_WRITE = 0x1,
+       TUNER_WRITE,
+       WRITE_DELAY = 0x10,
+};
+#endif /* M88RS2000_H */
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c
new file mode 100644 (file)
index 0000000..45196c5
--- /dev/null
@@ -0,0 +1,562 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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.
+ */
+
+
+/*
+ * Driver implements own I2C-adapter for tuner I2C access. That's since chip
+ * have unusual I2C-gate control which closes gate automatically after each
+ * I2C transfer. Using own I2C adapter we can workaround that.
+ */
+
+#include "rtl2830_priv.h"
+
+int rtl2830_debug;
+module_param_named(debug, rtl2830_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+/* write multiple hardware registers */
+static int rtl2830_wr(struct rtl2830_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 rtl2830_rd(struct rtl2830_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 rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
+{
+       int ret;
+       u8 reg2 = (reg >> 0) & 0xff;
+       u8 page = (reg >> 8) & 0xff;
+
+       /* switch bank if needed */
+       if (page != priv->page) {
+               ret = rtl2830_wr(priv, 0x00, &page, 1);
+               if (ret)
+                       return ret;
+
+               priv->page = page;
+       }
+
+       return rtl2830_wr(priv, reg2, val, len);
+}
+
+/* read multiple registers */
+static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
+{
+       int ret;
+       u8 reg2 = (reg >> 0) & 0xff;
+       u8 page = (reg >> 8) & 0xff;
+
+       /* switch bank if needed */
+       if (page != priv->page) {
+               ret = rtl2830_wr(priv, 0x00, &page, 1);
+               if (ret)
+                       return ret;
+
+               priv->page = page;
+       }
+
+       return rtl2830_rd(priv, reg2, val, len);
+}
+
+#if 0 /* currently not used */
+/* write single register */
+static int rtl2830_wr_reg(struct rtl2830_priv *priv, u16 reg, u8 val)
+{
+       return rtl2830_wr_regs(priv, reg, &val, 1);
+}
+#endif
+
+/* read single register */
+static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val)
+{
+       return rtl2830_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask)
+{
+       int ret;
+       u8 tmp;
+
+       /* no need for read if whole reg is written */
+       if (mask != 0xff) {
+               ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
+               if (ret)
+                       return ret;
+
+               val &= mask;
+               tmp &= ~mask;
+               val |= tmp;
+       }
+
+       return rtl2830_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register with mask */
+int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask)
+{
+       int ret, i;
+       u8 tmp;
+
+       ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
+       if (ret)
+               return ret;
+
+       tmp &= mask;
+
+       /* find position of the first bit */
+       for (i = 0; i < 8; i++) {
+               if ((mask >> i) & 0x01)
+                       break;
+       }
+       *val = tmp >> i;
+
+       return 0;
+}
+
+static int rtl2830_init(struct dvb_frontend *fe)
+{
+       struct rtl2830_priv *priv = fe->demodulator_priv;
+       int ret, i;
+       u64 num;
+       u8 buf[3], tmp;
+       u32 if_ctl;
+       struct rtl2830_reg_val_mask tab[] = {
+               { 0x00d, 0x01, 0x03 },
+               { 0x00d, 0x10, 0x10 },
+               { 0x104, 0x00, 0x1e },
+               { 0x105, 0x80, 0x80 },
+               { 0x110, 0x02, 0x03 },
+               { 0x110, 0x08, 0x0c },
+               { 0x17b, 0x00, 0x40 },
+               { 0x17d, 0x05, 0x0f },
+               { 0x17d, 0x50, 0xf0 },
+               { 0x18c, 0x08, 0x0f },
+               { 0x18d, 0x00, 0xc0 },
+               { 0x188, 0x05, 0x0f },
+               { 0x189, 0x00, 0xfc },
+               { 0x2d5, 0x02, 0x02 },
+               { 0x2f1, 0x02, 0x06 },
+               { 0x2f1, 0x20, 0xf8 },
+               { 0x16d, 0x00, 0x01 },
+               { 0x1a6, 0x00, 0x80 },
+               { 0x106, priv->cfg.vtop, 0x3f },
+               { 0x107, priv->cfg.krf, 0x3f },
+               { 0x112, 0x28, 0xff },
+               { 0x103, priv->cfg.agc_targ_val, 0xff },
+               { 0x00a, 0x02, 0x07 },
+               { 0x140, 0x0c, 0x3c },
+               { 0x140, 0x40, 0xc0 },
+               { 0x15b, 0x05, 0x07 },
+               { 0x15b, 0x28, 0x38 },
+               { 0x15c, 0x05, 0x07 },
+               { 0x15c, 0x28, 0x38 },
+               { 0x115, priv->cfg.spec_inv, 0x01 },
+               { 0x16f, 0x01, 0x07 },
+               { 0x170, 0x18, 0x38 },
+               { 0x172, 0x0f, 0x0f },
+               { 0x173, 0x08, 0x38 },
+               { 0x175, 0x01, 0x07 },
+               { 0x176, 0x00, 0xc0 },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(tab); i++) {
+               ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+                       tab[i].mask);
+               if (ret)
+                       goto err;
+       }
+
+       ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2);
+       if (ret)
+               goto err;
+
+       ret = rtl2830_wr_regs(priv, 0x195,
+               "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
+       if (ret)
+               goto err;
+
+       num = priv->cfg.if_dvbt % priv->cfg.xtal;
+       num *= 0x400000;
+       num = div_u64(num, priv->cfg.xtal);
+       num = -num;
+       if_ctl = num & 0x3fffff;
+       dbg("%s: if_ctl=%08x", __func__, if_ctl);
+
+       ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */
+       if (ret)
+               goto err;
+
+       buf[0] = tmp << 6;
+       buf[0] = (if_ctl >> 16) & 0x3f;
+       buf[1] = (if_ctl >>  8) & 0xff;
+       buf[2] = (if_ctl >>  0) & 0xff;
+
+       ret = rtl2830_wr_regs(priv, 0x119, buf, 3);
+       if (ret)
+               goto err;
+
+       /* TODO: spec init */
+
+       /* soft reset */
+       ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04);
+       if (ret)
+               goto err;
+
+       ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04);
+       if (ret)
+               goto err;
+
+       priv->sleeping = false;
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int rtl2830_sleep(struct dvb_frontend *fe)
+{
+       struct rtl2830_priv *priv = fe->demodulator_priv;
+       priv->sleeping = true;
+       return 0;
+}
+
+int rtl2830_get_tune_settings(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s)
+{
+       s->min_delay_ms = 500;
+       s->step_size = fe->ops.info.frequency_stepsize * 2;
+       s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+
+       return 0;
+}
+
+static int rtl2830_set_frontend(struct dvb_frontend *fe)
+{
+       struct rtl2830_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i;
+       static u8 bw_params1[3][34] = {
+               {
+               0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xfa, 0x00, 0x17, 0x00, 0x41,
+               0x00, 0x64, 0x00, 0x67, 0x00, 0x38, 0x1f, 0xde, 0x1f, 0x7a,
+               0x1f, 0x47, 0x1f, 0x7c, 0x00, 0x30, 0x01, 0x4b, 0x02, 0x82,
+               0x03, 0x73, 0x03, 0xcf, /* 6 MHz */
+               }, {
+               0x1f, 0xfa, 0x1f, 0xda, 0x1f, 0xc1, 0x1f, 0xb3, 0x1f, 0xca,
+               0x00, 0x07, 0x00, 0x4d, 0x00, 0x6d, 0x00, 0x40, 0x1f, 0xca,
+               0x1f, 0x4d, 0x1f, 0x2a, 0x1f, 0xb2, 0x00, 0xec, 0x02, 0x7e,
+               0x03, 0xd0, 0x04, 0x53, /* 7 MHz */
+               }, {
+               0x00, 0x10, 0x00, 0x0e, 0x1f, 0xf7, 0x1f, 0xc9, 0x1f, 0xa0,
+               0x1f, 0xa6, 0x1f, 0xec, 0x00, 0x4e, 0x00, 0x7d, 0x00, 0x3a,
+               0x1f, 0x98, 0x1f, 0x10, 0x1f, 0x40, 0x00, 0x75, 0x02, 0x5f,
+               0x04, 0x24, 0x04, 0xdb, /* 8 MHz */
+               },
+       };
+       static u8 bw_params2[3][6] = {
+               {0xc3, 0x0c, 0x44, 0x33, 0x33, 0x30,}, /* 6 MHz */
+               {0xb8, 0xe3, 0x93, 0x99, 0x99, 0x98,}, /* 7 MHz */
+               {0xae, 0xba, 0xf3, 0x26, 0x66, 0x64,}, /* 8 MHz */
+       };
+
+
+       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;
+               break;
+       case 7000000:
+               i = 1;
+               break;
+       case 8000000:
+               i = 2;
+               break;
+       default:
+               dbg("invalid bandwidth");
+               return -EINVAL;
+       }
+
+       ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06);
+       if (ret)
+               goto err;
+
+       /* 1/2 split I2C write */
+       ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17);
+       if (ret)
+               goto err;
+
+       /* 2/2 split I2C write */
+       ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17);
+       if (ret)
+               goto err;
+
+       ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6);
+       if (ret)
+               goto err;
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct rtl2830_priv *priv = fe->demodulator_priv;
+       int ret;
+       u8 tmp;
+       *status = 0;
+
+       if (priv->sleeping)
+               return 0;
+
+       ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */
+       if (ret)
+               goto err;
+
+       if (tmp == 11) {
+               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                       FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+       } else if (tmp == 10) {
+               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                       FE_HAS_VITERBI;
+       }
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       *snr = 0;
+       return 0;
+}
+
+static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       *ber = 0;
+       return 0;
+}
+
+static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       *ucblocks = 0;
+       return 0;
+}
+
+static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       *strength = 0;
+       return 0;
+}
+
+static struct dvb_frontend_ops rtl2830_ops;
+
+static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
+       struct i2c_msg msg[], int num)
+{
+       struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap);
+       int ret;
+
+       /* open i2c-gate */
+       ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08);
+       if (ret)
+               goto err;
+
+       ret = i2c_transfer(priv->i2c, msg, num);
+       if (ret < 0)
+               warn("tuner i2c failed=%d", ret);
+
+       return ret;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       return ret;
+}
+
+static struct i2c_algorithm rtl2830_tuner_i2c_algo = {
+       .master_xfer   = rtl2830_tuner_i2c_xfer,
+       .functionality = rtl2830_tuner_i2c_func,
+};
+
+struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+       struct rtl2830_priv *priv = fe->demodulator_priv;
+       return &priv->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter);
+
+static void rtl2830_release(struct dvb_frontend *fe)
+{
+       struct rtl2830_priv *priv = fe->demodulator_priv;
+
+       i2c_del_adapter(&priv->tuner_i2c_adapter);
+       kfree(priv);
+}
+
+struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg,
+       struct i2c_adapter *i2c)
+{
+       struct rtl2830_priv *priv = NULL;
+       int ret = 0;
+       u8 tmp;
+
+       /* allocate memory for the internal state */
+       priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL);
+       if (priv == NULL)
+               goto err;
+
+       /* setup the priv */
+       priv->i2c = i2c;
+       memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config));
+
+       /* check if the demod is there */
+       ret = rtl2830_rd_reg(priv, 0x000, &tmp);
+       if (ret)
+               goto err;
+
+       /* create dvb_frontend */
+       memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops));
+       priv->fe.demodulator_priv = priv;
+
+       /* create tuner i2c adapter */
+       strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter",
+               sizeof(priv->tuner_i2c_adapter.name));
+       priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo;
+       priv->tuner_i2c_adapter.algo_data = NULL;
+       i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
+       if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
+               err("tuner I2C bus could not be initialized");
+               goto err;
+       }
+
+       priv->sleeping = true;
+
+       return &priv->fe;
+err:
+       dbg("%s: failed=%d", __func__, ret);
+       kfree(priv);
+       return NULL;
+}
+EXPORT_SYMBOL(rtl2830_attach);
+
+static struct dvb_frontend_ops rtl2830_ops = {
+       .delsys = { SYS_DVBT },
+       .info = {
+               .name = "Realtek RTL2830 (DVB-T)",
+               .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 = rtl2830_release,
+
+       .init = rtl2830_init,
+       .sleep = rtl2830_sleep,
+
+       .get_tune_settings = rtl2830_get_tune_settings,
+
+       .set_frontend = rtl2830_set_frontend,
+
+       .read_status = rtl2830_read_status,
+       .read_snr = rtl2830_read_snr,
+       .read_ber = rtl2830_read_ber,
+       .read_ucblocks = rtl2830_read_ucblocks,
+       .read_signal_strength = rtl2830_read_signal_strength,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/rtl2830.h b/drivers/media/dvb/frontends/rtl2830.h
new file mode 100644 (file)
index 0000000..1c6ee91
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 RTL2830_H
+#define RTL2830_H
+
+#include <linux/dvb/frontend.h>
+
+struct rtl2830_config {
+       /*
+        * Demodulator I2C address.
+        */
+       u8 i2c_addr;
+
+       /*
+        * Xtal frequency.
+        * Hz
+        * 4000000, 16000000, 25000000, 28800000
+        */
+       u32 xtal;
+
+       /*
+        * TS output mode.
+        */
+       u8 ts_mode;
+
+       /*
+        * Spectrum inversion.
+        */
+       bool spec_inv;
+
+       /*
+        * IFs for all used modes.
+        * Hz
+        * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
+        */
+       u32 if_dvbt;
+
+       /*
+        */
+       u8 vtop;
+
+       /*
+        */
+       u8 krf;
+
+       /*
+        */
+       u8 agc_targ_val;
+};
+
+#if defined(CONFIG_DVB_RTL2830) || \
+       (defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE))
+extern struct dvb_frontend *rtl2830_attach(
+       const struct rtl2830_config *config,
+       struct i2c_adapter *i2c
+);
+
+extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
+       struct dvb_frontend *fe
+);
+#else
+static inline struct dvb_frontend *rtl2830_attach(
+       const struct rtl2830_config *config,
+       struct i2c_adapter *i2c
+)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
+       struct dvb_frontend *fe
+)
+{
+       return NULL;
+}
+#endif
+
+#endif /* RTL2830_H */
diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h
new file mode 100644 (file)
index 0000000..4a46476
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Realtek RTL2830 DVB-T demodulator driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 RTL2830_PRIV_H
+#define RTL2830_PRIV_H
+
+#include "dvb_frontend.h"
+#include "rtl2830.h"
+
+#define LOG_PREFIX "rtl2830"
+
+#undef dbg
+#define dbg(f, arg...) \
+       if (rtl2830_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 rtl2830_priv {
+       struct i2c_adapter *i2c;
+       struct dvb_frontend fe;
+       struct rtl2830_config cfg;
+       struct i2c_adapter tuner_i2c_adapter;
+
+       bool sleeping;
+
+       u8 page; /* active register page */
+};
+
+struct rtl2830_reg_val_mask {
+       u16 reg;
+       u8  val;
+       u8  mask;
+};
+
+#endif /* RTL2830_PRIV_H */
index 38565be..dd08f4a 100644 (file)
@@ -67,7 +67,7 @@ static const struct stb0899_tab stb0899_cn_tab[] = {
  * Crude linear extrapolation below -84.8dBm and above -8.0dBm.
  */
 static const struct stb0899_tab stb0899_dvbsrf_tab[] = {
-       { -950, -128 },
+       { -750, -128 },
        { -748,  -94 },
        { -745,  -92 },
        { -735,  -90 },
@@ -131,7 +131,7 @@ static const struct stb0899_tab stb0899_dvbs2rf_tab[] = {
        { -730, 13645 },
        { -750, 13909 },
        { -766, 14153 },
-       { -999, 16383 }
+       { -950, 16383 }
 };
 
 /* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/
@@ -964,6 +964,7 @@ static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 
        int val;
        u32 reg;
+       *strength = 0;
        switch (state->delsys) {
        case SYS_DVBS:
        case SYS_DSS:
@@ -983,11 +984,11 @@ static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
                break;
        case SYS_DVBS2:
                if (internal->lock) {
-                       reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN);
+                       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_GAIN);
                        val = STB0899_GETFIELD(IF_AGC_GAIN, reg);
 
                        *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val);
-                       *strength += 750;
+                       *strength += 950;
                        dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm",
                                val & 0x3fff, *strength);
                }
@@ -1009,6 +1010,7 @@ static int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr)
        u8 buf[2];
        u32 reg;
 
+       *snr = 0;
        reg  = stb0899_read_reg(state, STB0899_VSTATUS);
        switch (state->delsys) {
        case SYS_DVBS:
@@ -1071,7 +1073,7 @@ static int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status)
                        reg  = stb0899_read_reg(state, STB0899_VSTATUS);
                        if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
                                dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK");
-                               *status |= FE_HAS_CARRIER | FE_HAS_LOCK;
+                               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
 
                                reg = stb0899_read_reg(state, STB0899_PLPARM);
                                if (STB0899_GETFIELD(VITCURPUN, reg)) {
index fb5548a..632b251 100644 (file)
@@ -506,7 +506,7 @@ static int stv0288_set_frontend(struct dvb_frontend *fe)
                tda[1] = (unsigned char)tm;
                stv0288_writeregI(state, 0x2b, tda[1]);
                stv0288_writeregI(state, 0x2c, tda[2]);
-               udelay(30);
+               msleep(30);
        }
        state->tuner_frequency = c->frequency;
        state->fec_inner = FEC_AUTO;
index a992050..c21bc92 100644 (file)
@@ -1215,7 +1215,7 @@ error:
 EXPORT_SYMBOL(tda10071_attach);
 
 static struct dvb_frontend_ops tda10071_ops = {
-       .delsys = { SYS_DVBT, SYS_DVBT2 },
+       .delsys = { SYS_DVBS, SYS_DVBS2 },
        .info = {
                .name = "NXP TDA10071",
                .frequency_min = 950000,
index 8418c02..7539a5d 100644 (file)
@@ -216,6 +216,7 @@ static int demod_attach_drxk(struct ngene_channel *chan,
        struct drxk_config config;
 
        memset(&config, 0, sizeof(config));
+       config.microcode_name = "drxk_a3.mc";
        config.adr = 0x29 + (chan->number ^ 2);
 
        chan->fe = dvb_attach(drxk_attach, &config, i2c);
index b81df5f..15b35c4 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/pci.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
+#include <linux/ratelimit.h>
 
 #include "dvbdev.h"
 #include "dvb_demux.h"
@@ -77,6 +78,8 @@ struct pt1 {
        struct pt1_adapter *adaps[PT1_NR_ADAPS];
        struct pt1_table *tables;
        struct task_struct *kthread;
+       int table_index;
+       int buf_index;
 
        struct mutex lock;
        int power;
@@ -90,12 +93,12 @@ struct pt1_adapter {
        u8 *buf;
        int upacket_count;
        int packet_count;
+       int st_count;
 
        struct dvb_adapter adap;
        struct dvb_demux demux;
        int users;
        struct dmxdev dmxdev;
-       struct dvb_net net;
        struct dvb_frontend *fe;
        int (*orig_set_voltage)(struct dvb_frontend *fe,
                                fe_sec_voltage_t voltage);
@@ -119,7 +122,7 @@ static u32 pt1_read_reg(struct pt1 *pt1, int reg)
        return readl(pt1->regs + reg * 4);
 }
 
-static int pt1_nr_tables = 64;
+static int pt1_nr_tables = 8;
 module_param_named(nr_tables, pt1_nr_tables, int, 0);
 
 static void pt1_increment_table_count(struct pt1 *pt1)
@@ -264,6 +267,7 @@ static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
        struct pt1_adapter *adap;
        int offset;
        u8 *buf;
+       int sc;
 
        if (!page->upackets[PT1_NR_UPACKETS - 1])
                return 0;
@@ -280,6 +284,16 @@ static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
                else if (!adap->upacket_count)
                        continue;
 
+               if (upacket >> 24 & 1)
+                       printk_ratelimited(KERN_INFO "earth-pt1: device "
+                               "buffer overflowing. table[%d] buf[%d]\n",
+                               pt1->table_index, pt1->buf_index);
+               sc = upacket >> 26 & 0x7;
+               if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7))
+                       printk_ratelimited(KERN_INFO "earth-pt1: data loss"
+                               " in streamID(adapter)[%d]\n", index);
+               adap->st_count = sc;
+
                buf = adap->buf;
                offset = adap->packet_count * 188 + adap->upacket_count * 3;
                buf[offset] = upacket >> 16;
@@ -303,30 +317,25 @@ static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
 static int pt1_thread(void *data)
 {
        struct pt1 *pt1;
-       int table_index;
-       int buf_index;
        struct pt1_buffer_page *page;
 
        pt1 = data;
        set_freezable();
 
-       table_index = 0;
-       buf_index = 0;
-
        while (!kthread_should_stop()) {
                try_to_freeze();
 
-               page = pt1->tables[table_index].bufs[buf_index].page;
+               page = pt1->tables[pt1->table_index].bufs[pt1->buf_index].page;
                if (!pt1_filter(pt1, page)) {
                        schedule_timeout_interruptible((HZ + 999) / 1000);
                        continue;
                }
 
-               if (++buf_index >= PT1_NR_BUFS) {
+               if (++pt1->buf_index >= PT1_NR_BUFS) {
                        pt1_increment_table_count(pt1);
-                       buf_index = 0;
-                       if (++table_index >= pt1_nr_tables)
-                               table_index = 0;
+                       pt1->buf_index = 0;
+                       if (++pt1->table_index >= pt1_nr_tables)
+                               pt1->table_index = 0;
                }
        }
 
@@ -477,21 +486,60 @@ err:
        return ret;
 }
 
+static int pt1_start_polling(struct pt1 *pt1)
+{
+       int ret = 0;
+
+       mutex_lock(&pt1->lock);
+       if (!pt1->kthread) {
+               pt1->kthread = kthread_run(pt1_thread, pt1, "earth-pt1");
+               if (IS_ERR(pt1->kthread)) {
+                       ret = PTR_ERR(pt1->kthread);
+                       pt1->kthread = NULL;
+               }
+       }
+       mutex_unlock(&pt1->lock);
+       return ret;
+}
+
 static int pt1_start_feed(struct dvb_demux_feed *feed)
 {
        struct pt1_adapter *adap;
        adap = container_of(feed->demux, struct pt1_adapter, demux);
-       if (!adap->users++)
+       if (!adap->users++) {
+               int ret;
+
+               ret = pt1_start_polling(adap->pt1);
+               if (ret)
+                       return ret;
                pt1_set_stream(adap->pt1, adap->index, 1);
+       }
        return 0;
 }
 
+static void pt1_stop_polling(struct pt1 *pt1)
+{
+       int i, count;
+
+       mutex_lock(&pt1->lock);
+       for (i = 0, count = 0; i < PT1_NR_ADAPS; i++)
+               count += pt1->adaps[i]->users;
+
+       if (count == 0 && pt1->kthread) {
+               kthread_stop(pt1->kthread);
+               pt1->kthread = NULL;
+       }
+       mutex_unlock(&pt1->lock);
+}
+
 static int pt1_stop_feed(struct dvb_demux_feed *feed)
 {
        struct pt1_adapter *adap;
        adap = container_of(feed->demux, struct pt1_adapter, demux);
-       if (!--adap->users)
+       if (!--adap->users) {
                pt1_set_stream(adap->pt1, adap->index, 0);
+               pt1_stop_polling(adap->pt1);
+       }
        return 0;
 }
 
@@ -575,7 +623,6 @@ static int pt1_wakeup(struct dvb_frontend *fe)
 
 static void pt1_free_adapter(struct pt1_adapter *adap)
 {
-       dvb_net_release(&adap->net);
        adap->demux.dmx.close(&adap->demux.dmx);
        dvb_dmxdev_release(&adap->dmxdev);
        dvb_dmx_release(&adap->demux);
@@ -616,6 +663,7 @@ pt1_alloc_adapter(struct pt1 *pt1)
        adap->buf = buf;
        adap->upacket_count = 0;
        adap->packet_count = 0;
+       adap->st_count = -1;
 
        dvb_adap = &adap->adap;
        dvb_adap->priv = adap;
@@ -644,8 +692,6 @@ pt1_alloc_adapter(struct pt1 *pt1)
        if (ret < 0)
                goto err_dmx_release;
 
-       dvb_net_init(dvb_adap, &adap->net, &demux->dmx);
-
        return adap;
 
 err_dmx_release:
@@ -1020,7 +1066,8 @@ static void __devexit pt1_remove(struct pci_dev *pdev)
        pt1 = pci_get_drvdata(pdev);
        regs = pt1->regs;
 
-       kthread_stop(pt1->kthread);
+       if (pt1->kthread)
+               kthread_stop(pt1->kthread);
        pt1_cleanup_tables(pt1);
        pt1_cleanup_frontends(pt1);
        pt1_disable_ram(pt1);
@@ -1043,7 +1090,6 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        void __iomem *regs;
        struct pt1 *pt1;
        struct i2c_adapter *i2c_adap;
-       struct task_struct *kthread;
 
        ret = pci_enable_device(pdev);
        if (ret < 0)
@@ -1139,17 +1185,8 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ret < 0)
                goto err_pt1_cleanup_frontends;
 
-       kthread = kthread_run(pt1_thread, pt1, "pt1");
-       if (IS_ERR(kthread)) {
-               ret = PTR_ERR(kthread);
-               goto err_pt1_cleanup_tables;
-       }
-
-       pt1->kthread = kthread;
        return 0;
 
-err_pt1_cleanup_tables:
-       pt1_cleanup_tables(pt1);
 err_pt1_cleanup_frontends:
        pt1_cleanup_frontends(pt1);
 err_pt1_disable_ram:
index 04d6d54..f6b52d5 100644 (file)
@@ -311,7 +311,7 @@ static void __exit media_devnode_exit(void)
        unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
 }
 
-module_init(media_devnode_init)
+subsys_initcall(media_devnode_init);
 module_exit(media_devnode_exit)
 
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
index e954781..8db2d7f 100644 (file)
@@ -43,7 +43,7 @@ config USB_DSBR
 
 config RADIO_MAXIRADIO
        tristate "Guillemot MAXI Radio FM 2000 radio"
-       depends on VIDEO_V4L2 && PCI
+       depends on VIDEO_V4L2 && PCI && SND
        ---help---
          Choose Y here if you have this radio card.  This card may also be
          found as Gemtek PCI FM.
@@ -80,6 +80,16 @@ config RADIO_SI4713
          To compile this driver as a module, choose M here: the
          module will be called radio-si4713.
 
+config USB_KEENE
+       tristate "Keene FM Transmitter USB support"
+       depends on USB && VIDEO_V4L2
+       ---help---
+         Say Y here if you want to connect this type of FM transmitter
+         to your computer's USB port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-keene.
+
 config RADIO_TEA5764
        tristate "TEA5764 I2C FM radio support"
        depends on I2C && VIDEO_V4L2
@@ -167,6 +177,10 @@ menuconfig V4L_RADIO_ISA_DRIVERS
 
 if V4L_RADIO_ISA_DRIVERS
 
+config RADIO_ISA
+       depends on ISA
+       tristate
+
 config RADIO_CADET
        tristate "ADS Cadet AM/FM Tuner"
        depends on ISA && VIDEO_V4L2
@@ -174,20 +188,13 @@ config RADIO_CADET
          Choose Y here if you have one of these AM/FM radio cards, and then
          fill in the port address below.
 
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         Further documentation on this driver can be found on the WWW at
-         <http://linux.blackhawke.net/cadet/>.
-
          To compile this driver as a module, choose M here: the
          module will be called radio-cadet.
 
 config RADIO_RTRACK
        tristate "AIMSlab RadioTrack (aka RadioReveal) support"
        depends on ISA && VIDEO_V4L2
+       select RADIO_ISA
        ---help---
          Choose Y here if you have one of these FM radio cards, and then fill
          in the port address below.
@@ -201,11 +208,7 @@ config RADIO_RTRACK
          You must also pass the module a suitable io parameter, 0x248 has
          been reported to be used by these cards.
 
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>. More information is
-         contained in the file
+         More information is contained in the file
          <file:Documentation/video4linux/radiotrack.txt>.
 
          To compile this driver as a module, choose M here: the
@@ -214,7 +217,7 @@ config RADIO_RTRACK
 config RADIO_RTRACK_PORT
        hex "RadioTrack i/o port (0x20f or 0x30f)"
        depends on RADIO_RTRACK=y
-       default "20f"
+       default "30f"
        help
          Enter either 0x30f or 0x20f here.  The card default is 0x30f, if you
          haven't changed the jumper setting on the card.
@@ -222,14 +225,14 @@ config RADIO_RTRACK_PORT
 config RADIO_RTRACK2
        tristate "AIMSlab RadioTrack II support"
        depends on ISA && VIDEO_V4L2
+       select RADIO_ISA
        ---help---
          Choose Y here if you have this FM radio card, and then fill in the
          port address below.
 
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
+         Note: this driver hasn't been tested since a long time due to lack
+         of hardware. If you have this hardware, then please contact the
+         linux-media mailinglist.
 
          To compile this driver as a module, choose M here: the
          module will be called radio-rtrack2.
@@ -245,15 +248,11 @@ config RADIO_RTRACK2_PORT
 config RADIO_AZTECH
        tristate "Aztech/Packard Bell Radio"
        depends on ISA && VIDEO_V4L2
+       select RADIO_ISA
        ---help---
          Choose Y here if you have one of these FM radio cards, and then fill
          in the port address below.
 
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
          To compile this driver as a module, choose M here: the
          module will be called radio-aztech.
 
@@ -269,6 +268,7 @@ config RADIO_AZTECH_PORT
 config RADIO_GEMTEK
        tristate "GemTek Radio card (or compatible) support"
        depends on ISA && VIDEO_V4L2
+       select RADIO_ISA
        ---help---
          Choose Y here if you have this FM radio card, and then fill in the
          I/O port address and settings below. The following cards either have
@@ -278,23 +278,21 @@ config RADIO_GEMTEK
          - Typhoon Radio card (some models)
          - Hama Radio card
 
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
          To compile this driver as a module, choose M here: the
          module will be called radio-gemtek.
 
 config RADIO_GEMTEK_PORT
-       hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)"
+       hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c)"
        depends on RADIO_GEMTEK=y
        default "34c"
        help
-         Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
-         0x34c, if you haven't changed the jumper setting on the card. On
-         Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
+         Enter either 0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c here. The
+         card default is 0x34c, if you haven't changed the jumper setting
+         on the card.
+
+         On Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
          port is 0x20c, 0x248 or 0x28c.
+
          If automatic I/O port probing is enabled this port will be used only
          in case of automatic probing failure, ie. as a fallback.
 
@@ -318,11 +316,6 @@ config RADIO_MIROPCM20
          sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this
          is required for the radio-miropcm20.
 
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
          To compile this driver as a module, choose M here: the
          module will be called radio-miropcm20.
 
@@ -332,11 +325,6 @@ config RADIO_SF16FMI
        ---help---
          Choose Y here if you have one of these FM radio cards.
 
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
          To compile this driver as a module, choose M here: the
          module will be called radio-sf16fmi.
 
@@ -346,50 +334,35 @@ config RADIO_SF16FMR2
        ---help---
          Choose Y here if you have one of these FM radio cards.
 
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found on the WWW at
-         <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
          To compile this driver as a module, choose M here: the
          module will be called radio-sf16fmr2.
 
 config RADIO_TERRATEC
        tristate "TerraTec ActiveRadio ISA Standalone"
        depends on ISA && VIDEO_V4L2
+       select RADIO_ISA
        ---help---
-         Choose Y here if you have this FM radio card, and then fill in the
-         port address below. (TODO)
+         Choose Y here if you have this FM radio card.
 
-         Note: This driver is in its early stages.  Right now volume and
-         frequency control and muting works at least for me, but
-         unfortunately I have not found anybody who wants to use this card
-         with Linux.  So if it is this what YOU are trying to do right now,
-         PLEASE DROP ME A NOTE!!  Rolf Offermanns <rolf@offermanns.de>.
-
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
+         Note: this driver hasn't been tested since a long time due to lack
+         of hardware. If you have this hardware, then please contact the
+         linux-media mailinglist.
 
          To compile this driver as a module, choose M here: the
          module will be called radio-terratec.
 
-config RADIO_TERRATEC_PORT
-       hex "Terratec i/o port (normally 0x590)"
-       depends on RADIO_TERRATEC=y
-       default "590"
-       help
-         Fill in the I/O port of your TerraTec FM radio card. If unsure, go
-         with the default.
-
 config RADIO_TRUST
        tristate "Trust FM radio card"
        depends on ISA && VIDEO_V4L2
+       select RADIO_ISA
        help
          This is a driver for the Trust FM radio cards. Say Y if you have
          such a card and want to use it under Linux.
 
+         Note: this driver hasn't been tested since a long time due to lack
+         of hardware. If you have this hardware, then please contact the
+         linux-media mailinglist.
+
          To compile this driver as a module, choose M here: the
          module will be called radio-trust.
 
@@ -404,14 +377,14 @@ config RADIO_TRUST_PORT
 config RADIO_TYPHOON
        tristate "Typhoon Radio (a.k.a. EcoRadio)"
        depends on ISA && VIDEO_V4L2
+       select RADIO_ISA
        ---help---
          Choose Y here if you have one of these FM radio cards, and then fill
          in the port address and the frequency used for muting below.
 
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
+         Note: this driver hasn't been tested since a long time due to lack
+         of hardware. If you have this hardware, then please contact the
+         linux-media mailinglist.
 
          To compile this driver as a module, choose M here: the
          module will be called radio-typhoon.
@@ -438,14 +411,14 @@ config RADIO_TYPHOON_MUTEFREQ
 config RADIO_ZOLTRIX
        tristate "Zoltrix Radio"
        depends on ISA && VIDEO_V4L2
+       select RADIO_ISA
        ---help---
          Choose Y here if you have one of these FM radio cards, and then fill
          in the port address below.
 
-         In order to control your radio card, you will need to use programs
-         that are compatible with the Video For Linux API.  Information on
-         this API and pointers to "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
+         Note: this driver hasn't been tested since a long time due to lack
+         of hardware. If you have this hardware, then please contact the
+         linux-media mailinglist.
 
          To compile this driver as a module, choose M here: the
          module will be called radio-zoltrix.
index 390daf9..ca8c7d1 100644 (file)
@@ -2,6 +2,7 @@
 # Makefile for the kernel character device drivers.
 #
 
+obj-$(CONFIG_RADIO_ISA) += radio-isa.o
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
 obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
@@ -20,6 +21,7 @@ obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_RADIO_SI470X) += si470x/
 obj-$(CONFIG_USB_MR800) += radio-mr800.o
+obj-$(CONFIG_USB_KEENE) += radio-keene.o
 obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
 obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
 obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
index 1c3f844..98e0c8c 100644 (file)
@@ -1,16 +1,13 @@
-/* radiotrack (radioreveal) driver for Linux radio support
- * (c) 1997 M. Kirkwood
+/*
+ * AimsLab RadioTrack (aka RadioVeveal) driver
+ *
+ * Copyright 1997 M. Kirkwood
+ *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
- * History:
- * 1999-02-24  Russell Kroll <rkroll@exploits.org>
- *             Fine tuning/VIDEO_TUNER_LOW
- *             Frequency range expanded to start at 87 MHz
- *
- * TODO: Allow for more than one of these foolish entities :-)
- *
  * Notes on the hardware (reverse engineered from other peoples'
  * reverse engineering of AIMS' code :-)
  *
@@ -26,6 +23,7 @@
  *   wait(a_wee_while);
  *   out(port, stop_changing_the_volume);
  *
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
  */
 
 #include <linux/module.h>      /* Modules                      */
 #include <linux/delay.h>       /* msleep                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
 #include <linux/io.h>          /* outb, outb_p                 */
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include "radio-isa.h"
 
-MODULE_AUTHOR("M.Kirkwood");
+MODULE_AUTHOR("M. Kirkwood");
 MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("1.0.0");
 
 #ifndef CONFIG_RADIO_RTRACK_PORT
 #define CONFIG_RADIO_RTRACK_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_RTRACK_PORT;
-static int radio_nr = -1;
+#define RTRACK_MAX 2
 
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
-module_param(radio_nr, int, 0);
+static int io[RTRACK_MAX] = { [0] = CONFIG_RADIO_RTRACK_PORT,
+                             [1 ... (RTRACK_MAX - 1)] = -1 };
+static int radio_nr[RTRACK_MAX]        = { [0 ... (RTRACK_MAX - 1)] = -1 };
 
-struct rtrack
-{
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       int port;
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
+struct rtrack {
+       struct radio_isa_card isa;
        int curvol;
-       unsigned long curfreq;
-       int muted;
-       int io;
-       struct mutex lock;
 };
 
-static struct rtrack rtrack_card;
-
-/* local things */
-
-static void rt_decvol(struct rtrack *rt)
-{
-       outb(0x58, rt->io);             /* volume down + sigstr + on    */
-       msleep(100);
-       outb(0xd8, rt->io);             /* volume steady + sigstr + on  */
-}
-
-static void rt_incvol(struct rtrack *rt)
-{
-       outb(0x98, rt->io);             /* volume up + sigstr + on      */
-       msleep(100);
-       outb(0xd8, rt->io);             /* volume steady + sigstr + on  */
-}
-
-static void rt_mute(struct rtrack *rt)
-{
-       rt->muted = 1;
-       mutex_lock(&rt->lock);
-       outb(0xd0, rt->io);             /* volume steady, off           */
-       mutex_unlock(&rt->lock);
-}
-
-static int rt_setvol(struct rtrack *rt, int vol)
+static struct radio_isa_card *rtrack_alloc(void)
 {
-       int i;
-
-       mutex_lock(&rt->lock);
-
-       if (vol == rt->curvol) {        /* requested volume = current */
-               if (rt->muted) {        /* user is unmuting the card  */
-                       rt->muted = 0;
-                       outb(0xd8, rt->io);     /* enable card */
-               }
-               mutex_unlock(&rt->lock);
-               return 0;
-       }
-
-       if (vol == 0) {                 /* volume = 0 means mute the card */
-               outb(0x48, rt->io);     /* volume down but still "on"   */
-               msleep(2000);   /* make sure it's totally down  */
-               outb(0xd0, rt->io);     /* volume steady, off           */
-               rt->curvol = 0;         /* track the volume state!      */
-               mutex_unlock(&rt->lock);
-               return 0;
-       }
+       struct rtrack *rt = kzalloc(sizeof(struct rtrack), GFP_KERNEL);
 
-       rt->muted = 0;
-       if (vol > rt->curvol)
-               for (i = rt->curvol; i < vol; i++)
-                       rt_incvol(rt);
-       else
-               for (i = rt->curvol; i > vol; i--)
-                       rt_decvol(rt);
-
-       rt->curvol = vol;
-       mutex_unlock(&rt->lock);
-       return 0;
+       if (rt)
+               rt->curvol = 0xff;
+       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
+/* 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.
  */
 
-static void send_0_byte(struct rtrack *rt)
+static void send_0_byte(struct radio_isa_card *isa, int on)
 {
-       if (rt->curvol == 0 || rt->muted) {
-               outb_p(128+64+16+  1, rt->io);   /* wr-enable + data low */
-               outb_p(128+64+16+2+1, rt->io);   /* clock */
-       }
-       else {
-               outb_p(128+64+16+8+  1, rt->io);  /* on + wr-enable + data low */
-               outb_p(128+64+16+8+2+1, rt->io);  /* clock */
-       }
+       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);
 }
 
-static void send_1_byte(struct rtrack *rt)
+static void send_1_byte(struct radio_isa_card *isa, int on)
 {
-       if (rt->curvol == 0 || rt->muted) {
-               outb_p(128+64+16+4  +1, rt->io);   /* wr-enable+data high */
-               outb_p(128+64+16+4+2+1, rt->io);   /* clock */
-       }
-       else {
-               outb_p(128+64+16+8+4  +1, rt->io); /* on+wr-enable+data high */
-               outb_p(128+64+16+8+4+2+1, rt->io); /* clock */
-       }
-
+       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);
 }
 
-static int rt_setfreq(struct rtrack *rt, unsigned long freq)
+static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
+       int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8;
        int i;
 
-       mutex_lock(&rt->lock);                  /* Stop other ops interfering */
-
-       rt->curfreq = freq;
-
-       /* now uses VIDEO_TUNER_LOW for fine tuning */
-
        freq += 171200;                 /* Add 10.7 MHz IF              */
        freq /= 800;                    /* Convert to 50 kHz units      */
 
-       send_0_byte(rt);                /*  0: LSB of frequency         */
+       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(rt);
+                       send_1_byte(isa, on);
                else
-                       send_0_byte(rt);
-
-       send_0_byte(rt);                /* 14: test bit - always 0    */
-       send_0_byte(rt);                /* 15: test bit - always 0    */
-
-       send_0_byte(rt);                /* 16: band data 0 - always 0 */
-       send_0_byte(rt);                /* 17: band data 1 - always 0 */
-       send_0_byte(rt);                /* 18: band data 2 - always 0 */
-       send_0_byte(rt);                /* 19: time base - always 0   */
-
-       send_0_byte(rt);                /* 20: spacing (0 = 25 kHz)   */
-       send_1_byte(rt);                /* 21: spacing (1 = 25 kHz)   */
-       send_0_byte(rt);                /* 22: spacing (0 = 25 kHz)   */
-       send_1_byte(rt);                /* 23: AM/FM (FM = 1, always) */
-
-       if (rt->curvol == 0 || rt->muted)
-               outb(0xd0, rt->io);     /* volume steady + sigstr */
-       else
-               outb(0xd8, rt->io);     /* volume steady + sigstr + on */
-
-       mutex_unlock(&rt->lock);
-
-       return 0;
-}
-
-static int rt_getsigstr(struct rtrack *rt)
-{
-       int sig = 1;
-
-       mutex_lock(&rt->lock);
-       if (inb(rt->io) & 2)    /* bit set = no signal present  */
-               sig = 0;
-       mutex_unlock(&rt->lock);
-       return sig;
-}
-
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *v)
-{
-       strlcpy(v->driver, "radio-aimslab", sizeof(v->driver));
-       strlcpy(v->card, "RadioTrack", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       struct rtrack *rt = video_drvdata(file);
+                       send_0_byte(isa, on);
 
-       if (v->index > 0)
-               return -EINVAL;
+       send_0_byte(isa, on);           /* 14: test bit - always 0    */
+       send_0_byte(isa, on);           /* 15: test bit - always 0    */
 
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-       v->rangelow = 87 * 16000;
-       v->rangehigh = 108 * 16000;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xffff * rt_getsigstr(rt);
-       return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct rtrack *rt = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       rt_setfreq(rt, f->frequency);
-       return 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   */
 
-static int vidioc_g_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct rtrack *rt = video_drvdata(file);
+       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) */
 
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = rt->curfreq;
+       outb(0xd0 + on, isa->io);       /* volume steady + sigstr */
        return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
+static u32 rtrack_g_signal(struct radio_isa_card *isa)
 {
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
-       }
-       return -EINVAL;
+       /* bit set = no signal present */
+       return 0xffff * !(inb(isa->io) & 2);
 }
 
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
+static int rtrack_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
-       struct rtrack *rt = video_drvdata(file);
+       struct rtrack *rt = container_of(isa, struct rtrack, isa);
+       int curvol = rt->curvol;
 
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = rt->muted;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = rt->curvol;
+       if (mute) {
+               outb(0xd0, isa->io);    /* volume steady + sigstr + off */
                return 0;
        }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct rtrack *rt = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value)
-                       rt_mute(rt);
-               else
-                       rt_setvol(rt, rt->curvol);
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               rt_setvol(rt, ctrl->value);
-               return 0;
+       if (vol == 0) {                 /* volume = 0 means mute the card */
+               outb(0x48, isa->io);    /* volume down but still "on"   */
+               msleep(curvol * 3);     /* make sure it's totally down  */
+       } else if (curvol < vol) {
+               outb(0x98, isa->io);    /* volume up + sigstr + on      */
+               for (; curvol < vol; curvol++)
+                       udelay(3000);
+       } else if (curvol > vol) {
+               outb(0x58, isa->io);    /* volume down + sigstr + on    */
+               for (; curvol > vol; curvol--)
+                       udelay(3000);
        }
-       return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
+       outb(0xd8, isa->io);            /* volume steady + sigstr + on  */
+       rt->curvol = vol;
        return 0;
 }
 
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+/* Mute card - prevents noisy bootups */
+static int rtrack_initialize(struct radio_isa_card *isa)
 {
-       return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
+       /* this ensures that the volume is all the way up  */
+       outb(0x90, isa->io);    /* volume up but still "on"     */
+       msleep(3000);           /* make sure it's totally up    */
+       outb(0xc0, isa->io);    /* steady volume, mute card     */
        return 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations rtrack_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops rtrack_ops = {
+       .alloc = rtrack_alloc,
+       .init = rtrack_initialize,
+       .s_mute_volume = rtrack_s_mute_volume,
+       .s_frequency = rtrack_s_frequency,
+       .g_signal = rtrack_g_signal,
 };
 
-static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .vidioc_g_tuner     = vidioc_g_tuner,
-       .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
-       .vidioc_g_frequency = vidioc_g_frequency,
-       .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
+static const int rtrack_ioports[] = { 0x20f, 0x30f };
+
+static struct radio_isa_driver rtrack_driver = {
+       .driver = {
+               .match          = radio_isa_match,
+               .probe          = radio_isa_probe,
+               .remove         = radio_isa_remove,
+               .driver         = {
+                       .name   = "radio-aimslab",
+               },
+       },
+       .io_params = io,
+       .radio_nr_params = radio_nr,
+       .io_ports = rtrack_ioports,
+       .num_of_io_ports = ARRAY_SIZE(rtrack_ioports),
+       .region_size = 2,
+       .card = "AIMSlab RadioTrack/RadioReveal",
+       .ops = &rtrack_ops,
+       .has_stereo = true,
+       .max_volume = 0xff,
 };
 
 static int __init rtrack_init(void)
 {
-       struct rtrack *rt = &rtrack_card;
-       struct v4l2_device *v4l2_dev = &rt->v4l2_dev;
-       int res;
-
-       strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name));
-       rt->io = io;
-
-       if (rt->io == -1) {
-               v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n");
-               return -EINVAL;
-       }
-
-       if (!request_region(rt->io, 2, "rtrack")) {
-               v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io);
-               return -EBUSY;
-       }
-
-       res = v4l2_device_register(NULL, v4l2_dev);
-       if (res < 0) {
-               release_region(rt->io, 2);
-               v4l2_err(v4l2_dev, "could not register v4l2_device\n");
-               return res;
-       }
-
-       strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name));
-       rt->vdev.v4l2_dev = v4l2_dev;
-       rt->vdev.fops = &rtrack_fops;
-       rt->vdev.ioctl_ops = &rtrack_ioctl_ops;
-       rt->vdev.release = video_device_release_empty;
-       video_set_drvdata(&rt->vdev, rt);
-
-       /* Set up the I/O locking */
-
-       mutex_init(&rt->lock);
-
-       /* mute card - prevents noisy bootups */
-
-       /* this ensures that the volume is all the way down  */
-       outb(0x48, rt->io);             /* volume down but still "on"   */
-       msleep(2000);   /* make sure it's totally down  */
-       outb(0xc0, rt->io);             /* steady volume, mute card     */
-
-       if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_device_unregister(&rt->v4l2_dev);
-               release_region(rt->io, 2);
-               return -EINVAL;
-       }
-       v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
-
-       return 0;
+       return isa_register_driver(&rtrack_driver.driver, RTRACK_MAX);
 }
 
 static void __exit rtrack_exit(void)
 {
-       struct rtrack *rt = &rtrack_card;
-
-       video_unregister_device(&rt->vdev);
-       v4l2_device_unregister(&rt->v4l2_dev);
-       release_region(rt->io, 2);
+       isa_unregister_driver(&rtrack_driver.driver);
 }
 
 module_init(rtrack_init);
 module_exit(rtrack_exit);
-
index eed7b08..177bcbd 100644 (file)
@@ -1,5 +1,7 @@
-/* radio-aztech.c - Aztech radio card driver for Linux 2.2
+/*
+ * radio-aztech.c - Aztech radio card driver
  *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@xs4all.nl>
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  * Adapted to support the Video for Linux API by
  * Russell Kroll <rkroll@exploits.org>.  Based on original tuner code by:
  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  *
- * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
- * along with more information on the card itself.
- *
- * History:
- * 1999-02-24  Russell Kroll <rkroll@exploits.org>
- *             Fine tuning/VIDEO_TUNER_LOW
- *             Range expanded to 87-108 MHz (from 87.9-107.8)
- *
- * Notable changes from the original source:
- * - includes stripped down to the essentials
- * - for loops used as delays replaced with udelay()
- * - #defines removed, changed to static values
- * - tuning structure changed - no more character arrays, other changes
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
 */
 
 #include <linux/module.h>      /* Modules                      */
 #include <linux/delay.h>       /* udelay                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
 #include <linux/io.h>          /* outb, outb_p                 */
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include "radio-isa.h"
 
 MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the Aztech radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("1.0.0");
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
-
 #ifndef CONFIG_RADIO_AZTECH_PORT
 #define CONFIG_RADIO_AZTECH_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_AZTECH_PORT;
-static int radio_nr = -1;
-static int radio_wait_time = 1000;
+#define AZTECH_MAX 2
 
-module_param(io, int, 0);
-module_param(radio_nr, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
+static int io[AZTECH_MAX] = { [0] = CONFIG_RADIO_AZTECH_PORT,
+                             [1 ... (AZTECH_MAX - 1)] = -1 };
+static int radio_nr[AZTECH_MAX]        = { [0 ... (AZTECH_MAX - 1)] = -1 };
+static const int radio_wait_time = 1000;
 
-struct aztech
-{
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       int io;
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Aztech card (0x350 or 0x358)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
+struct aztech {
+       struct radio_isa_card isa;
        int curvol;
-       unsigned long curfreq;
-       int stereo;
-       struct mutex lock;
 };
 
-static struct aztech aztech_card;
-
-static int volconvert(int level)
-{
-       level >>= 14;           /* Map 16bits down to 2 bit */
-       level &= 3;
-
-       /* convert to card-friendly values */
-       switch (level) {
-       case 0:
-               return 0;
-       case 1:
-               return 1;
-       case 2:
-               return 4;
-       case 3:
-               return 5;
-       }
-       return 0;       /* Quieten gcc */
-}
-
 static void send_0_byte(struct aztech *az)
 {
        udelay(radio_wait_time);
-       outb_p(2 + volconvert(az->curvol), az->io);
-       outb_p(64 + 2 + volconvert(az->curvol), az->io);
+       outb_p(2 + az->curvol, az->isa.io);
+       outb_p(64 + 2 + az->curvol, az->isa.io);
 }
 
 static void send_1_byte(struct aztech *az)
 {
-       udelay (radio_wait_time);
-       outb_p(128 + 2 + volconvert(az->curvol), az->io);
-       outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io);
-}
-
-static int az_setvol(struct aztech *az, int vol)
-{
-       mutex_lock(&az->lock);
-       outb(volconvert(vol), az->io);
-       mutex_unlock(&az->lock);
-       return 0;
-}
-
-/* thanks to Michael Dwyer for giving me a dose of clues in
- * the signal strength department..
- *
- * This card has a stereo bit - bit 0 set = mono, not set = stereo
- * It also has a "signal" bit - bit 1 set = bad signal, not set = good
- *
- */
-
-static int az_getsigstr(struct aztech *az)
-{
-       int sig = 1;
-
-       mutex_lock(&az->lock);
-       if (inb(az->io) & 2)    /* bit set = no signal present */
-               sig = 0;
-       mutex_unlock(&az->lock);
-       return sig;
+       udelay(radio_wait_time);
+       outb_p(128 + 2 + az->curvol, az->isa.io);
+       outb_p(128 + 64 + 2 + az->curvol, az->isa.io);
 }
 
-static int az_getstereo(struct aztech *az)
+static struct radio_isa_card *aztech_alloc(void)
 {
-       int stereo = 1;
+       struct aztech *az = kzalloc(sizeof(*az), GFP_KERNEL);
 
-       mutex_lock(&az->lock);
-       if (inb(az->io) & 1)    /* bit set = mono */
-               stereo = 0;
-       mutex_unlock(&az->lock);
-       return stereo;
+       return az ? &az->isa : NULL;
 }
 
-static int az_setfreq(struct aztech *az, unsigned long frequency)
+static int aztech_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
+       struct aztech *az = container_of(isa, struct aztech, isa);
        int  i;
 
-       mutex_lock(&az->lock);
-
-       az->curfreq = frequency;
-       frequency += 171200;            /* Add 10.7 MHz IF              */
-       frequency /= 800;               /* Convert to 50 kHz units      */
+       freq += 171200;                 /* Add 10.7 MHz IF              */
+       freq /= 800;                    /* Convert to 50 kHz units      */
 
        send_0_byte(az);                /*  0: LSB of frequency       */
 
        for (i = 0; i < 13; i++)        /*   : frequency bits (1-13)  */
-               if (frequency & (1 << i))
+               if (freq & (1 << i))
                        send_1_byte(az);
                else
                        send_0_byte(az);
@@ -158,7 +94,7 @@ static int az_setfreq(struct aztech *az, unsigned long frequency)
        send_0_byte(az);                /* 14: test bit - always 0    */
        send_0_byte(az);                /* 15: test bit - always 0    */
        send_0_byte(az);                /* 16: band data 0 - always 0 */
-       if (az->stereo)         /* 17: stereo (1 to enable)   */
+       if (isa->stereo)                /* 17: stereo (1 to enable)   */
                send_1_byte(az);
        else
                send_0_byte(az);
@@ -173,225 +109,77 @@ static int az_setfreq(struct aztech *az, unsigned long frequency)
        /* latch frequency */
 
        udelay(radio_wait_time);
-       outb_p(128 + 64 + volconvert(az->curvol), az->io);
-
-       mutex_unlock(&az->lock);
-
-       return 0;
-}
-
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *v)
-{
-       strlcpy(v->driver, "radio-aztech", sizeof(v->driver));
-       strlcpy(v->card, "Aztech Radio", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *v)
-{
-       struct aztech *az = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
-
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-
-       v->rangelow = 87 * 16000;
-       v->rangehigh = 108 * 16000;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       if (az_getstereo(az))
-               v->audmode = V4L2_TUNER_MODE_STEREO;
-       else
-               v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xFFFF * az_getsigstr(az);
-
-       return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *v)
-{
-       return v->index ? -EINVAL : 0;
-}
+       outb_p(128 + 64 + az->curvol, az->isa.io);
 
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
        return 0;
 }
 
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                          struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-                          struct v4l2_audio *a)
+/* thanks to Michael Dwyer for giving me a dose of clues in
+ * the signal strength department..
+ *
+ * This card has a stereo bit - bit 0 set = mono, not set = stereo
+ */
+static u32 aztech_g_rxsubchans(struct radio_isa_card *isa)
 {
-       return a->index ? -EINVAL : 0;
+       if (inb(isa->io) & 1)
+               return V4L2_TUNER_SUB_MONO;
+       return V4L2_TUNER_SUB_STEREO;
 }
 
-static int vidioc_s_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
+static int aztech_s_stereo(struct radio_isa_card *isa, bool stereo)
 {
-       struct aztech *az = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       az_setfreq(az, f->frequency);
-       return 0;
+       return aztech_s_frequency(isa, isa->freq);
 }
 
-static int vidioc_g_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
+static int aztech_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
-       struct aztech *az = video_drvdata(file);
+       struct aztech *az = container_of(isa, struct aztech, isa);
 
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = az->curfreq;
+       if (mute)
+               vol = 0;
+       az->curvol = (vol & 1) + ((vol & 2) << 1);
+       outb(az->curvol, isa->io);
        return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                           struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                           struct v4l2_control *ctrl)
-{
-       struct aztech *az = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (az->curvol == 0)
-                       ctrl->value = 1;
-               else
-                       ctrl->value = 0;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = az->curvol * 6554;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                           struct v4l2_control *ctrl)
-{
-       struct aztech *az = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value)
-                       az_setvol(az, 0);
-               else
-                       az_setvol(az, az->curvol);
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               az_setvol(az, ctrl->value);
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static const struct v4l2_file_operations aztech_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops aztech_ops = {
+       .alloc = aztech_alloc,
+       .s_mute_volume = aztech_s_mute_volume,
+       .s_frequency = aztech_s_frequency,
+       .s_stereo = aztech_s_stereo,
+       .g_rxsubchans = aztech_g_rxsubchans,
 };
 
-static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .vidioc_g_tuner     = vidioc_g_tuner,
-       .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
-       .vidioc_g_frequency = vidioc_g_frequency,
-       .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
+static const int aztech_ioports[] = { 0x350, 0x358 };
+
+static struct radio_isa_driver aztech_driver = {
+       .driver = {
+               .match          = radio_isa_match,
+               .probe          = radio_isa_probe,
+               .remove         = radio_isa_remove,
+               .driver         = {
+                       .name   = "radio-aztech",
+               },
+       },
+       .io_params = io,
+       .radio_nr_params = radio_nr,
+       .io_ports = aztech_ioports,
+       .num_of_io_ports = ARRAY_SIZE(aztech_ioports),
+       .region_size = 2,
+       .card = "Aztech Radio",
+       .ops = &aztech_ops,
+       .has_stereo = true,
+       .max_volume = 3,
 };
 
 static int __init aztech_init(void)
 {
-       struct aztech *az = &aztech_card;
-       struct v4l2_device *v4l2_dev = &az->v4l2_dev;
-       int res;
-
-       strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name));
-       az->io = io;
-
-       if (az->io == -1) {
-               v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n");
-               return -EINVAL;
-       }
-
-       if (!request_region(az->io, 2, "aztech")) {
-               v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io);
-               return -EBUSY;
-       }
-
-       res = v4l2_device_register(NULL, v4l2_dev);
-       if (res < 0) {
-               release_region(az->io, 2);
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               return res;
-       }
-
-       mutex_init(&az->lock);
-       strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name));
-       az->vdev.v4l2_dev = v4l2_dev;
-       az->vdev.fops = &aztech_fops;
-       az->vdev.ioctl_ops = &aztech_ioctl_ops;
-       az->vdev.release = video_device_release_empty;
-       video_set_drvdata(&az->vdev, az);
-       /* mute card - prevents noisy bootups */
-       outb(0, az->io);
-
-       if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_device_unregister(v4l2_dev);
-               release_region(az->io, 2);
-               return -EINVAL;
-       }
-
-       v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
-       return 0;
+       return isa_register_driver(&aztech_driver.driver, AZTECH_MAX);
 }
 
 static void __exit aztech_exit(void)
 {
-       struct aztech *az = &aztech_card;
-
-       video_unregister_device(&az->vdev);
-       v4l2_device_unregister(&az->v4l2_dev);
-       release_region(az->io, 2);
+       isa_unregister_driver(&aztech_driver.driver);
 }
 
 module_init(aztech_init);
index 36ce061..2e639ce 100644 (file)
@@ -1,4 +1,7 @@
-/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin <jmunsin@iki.fi>
+/*
+ * GemTek radio card driver
+ *
+ * Copyright 1998 Jonas Munsin <jmunsin@iki.fi>
  *
  * GemTek hasn't released any specs on the card, so the protocol had to
  * be reverse engineered with dosemu.
  *    Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
  *    Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
- * TODO: Allow for more than one of these foolish entities :-)
- *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Note: this card seems to swap the left and right audio channels!
+ *
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
  */
 
 #include <linux/module.h>      /* Modules                      */
 #include <linux/videodev2.h>   /* kernel radio structs         */
 #include <linux/mutex.h>
 #include <linux/io.h>          /* outb, outb_p                 */
+#include <linux/slab.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
+#include "radio-isa.h"
 
 /*
  * Module info.
@@ -33,7 +41,7 @@
 MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
 MODULE_DESCRIPTION("A driver for the GemTek Radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.4");
+MODULE_VERSION("1.0.0");
 
 /*
  * Module params.
@@ -46,45 +54,29 @@ MODULE_VERSION("0.0.4");
 #define CONFIG_RADIO_GEMTEK_PROBE 1
 #endif
 
-static int io          = CONFIG_RADIO_GEMTEK_PORT;
-static bool probe      = CONFIG_RADIO_GEMTEK_PROBE;
-static bool hardmute;
-static bool shutdown   = 1;
-static bool keepmuted  = 1;
-static bool initmute   = 1;
-static int radio_nr    = -1;
+#define GEMTEK_MAX 4
 
-module_param(io, int, 0444);
-MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
-        "probing is disabled or fails. The most common I/O ports are: 0x20c "
-        "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
-        "work for the combined sound/radiocard).");
+static bool probe = CONFIG_RADIO_GEMTEK_PROBE;
+static bool hardmute;
+static int io[GEMTEK_MAX] = { [0] = CONFIG_RADIO_GEMTEK_PORT,
+                             [1 ... (GEMTEK_MAX - 1)] = -1 };
+static int radio_nr[GEMTEK_MAX]        = { [0 ... (GEMTEK_MAX - 1)] = -1 };
 
 module_param(probe, bool, 0444);
-MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
-       "common I/O ports used by the card are probed.");
+MODULE_PARM_DESC(probe, "Enable automatic device probing.");
 
 module_param(hardmute, bool, 0644);
-MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may "
+MODULE_PARM_DESC(hardmute, "Enable 'hard muting' by shutting down PLL, may "
         "reduce static noise.");
 
-module_param(shutdown, bool, 0644);
-MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when "
-        "module is unloaded.");
-
-module_param(keepmuted, bool, 0644);
-MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed.");
-
-module_param(initmute, bool, 0444);
-MODULE_PARM_DESC(initmute, "Mute card when module is loaded.");
-
-module_param(radio_nr, int, 0444);
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "Force I/O ports for the GemTek Radio card if automatic "
+        "probing is disabled or fails. The most common I/O ports are: 0x20c "
+        "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
+        "work for the combined sound/radiocard).");
 
-/*
- * Functions for controlling the card.
- */
-#define GEMTEK_LOWFREQ (87*16000)
-#define GEMTEK_HIGHFREQ        (108*16000)
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 
 /*
  * Frequency calculation constants.  Intermediate frequency 10.52 MHz (nominal
@@ -108,18 +100,11 @@ module_param(radio_nr, int, 0444);
 #define LONG_DELAY 75          /* usec */
 
 struct gemtek {
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       struct mutex lock;
-       unsigned long lastfreq;
-       int muted;
-       int verified;
-       int io;
+       struct radio_isa_card isa;
+       bool muted;
        u32 bu2614data;
 };
 
-static struct gemtek gemtek_card;
-
 #define BU2614_FREQ_BITS       16 /* D0..D15, Frequency data           */
 #define BU2614_PORT_BITS       3 /* P0..P2, Output port control data   */
 #define BU2614_VOID_BITS       4 /* unused                             */
@@ -166,31 +151,24 @@ static struct gemtek gemtek_card;
  */
 static void gemtek_bu2614_transmit(struct gemtek *gt)
 {
+       struct radio_isa_card *isa = &gt->isa;
        int i, bit, q, mute;
 
-       mutex_lock(&gt->lock);
-
        mute = gt->muted ? GEMTEK_MT : 0x00;
 
-       outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io);
-       udelay(SHORT_DELAY);
-       outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io);
+       outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, isa->io);
        udelay(LONG_DELAY);
 
        for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) {
                bit = (q & 1) ? GEMTEK_DA : 0;
-               outb_p(mute | GEMTEK_CE | bit, gt->io);
+               outb_p(mute | GEMTEK_CE | bit, isa->io);
                udelay(SHORT_DELAY);
-               outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io);
+               outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, isa->io);
                udelay(SHORT_DELAY);
        }
 
-       outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io);
+       outb_p(mute | GEMTEK_DA | GEMTEK_CK, isa->io);
        udelay(SHORT_DELAY);
-       outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io);
-       udelay(LONG_DELAY);
-
-       mutex_unlock(&gt->lock);
 }
 
 /*
@@ -198,21 +176,27 @@ static void gemtek_bu2614_transmit(struct gemtek *gt)
  */
 static unsigned long gemtek_convfreq(unsigned long freq)
 {
-       return ((freq<<FSCALE) + IF_OFFSET + REF_FREQ/2) / REF_FREQ;
+       return ((freq << FSCALE) + IF_OFFSET + REF_FREQ / 2) / REF_FREQ;
+}
+
+static struct radio_isa_card *gemtek_alloc(void)
+{
+       struct gemtek *gt = kzalloc(sizeof(*gt), GFP_KERNEL);
+
+       if (gt)
+               gt->muted = true;
+       return gt ? &gt->isa : NULL;
 }
 
 /*
  * Set FM-frequency.
  */
-static void gemtek_setfreq(struct gemtek *gt, unsigned long freq)
+static int gemtek_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-       if (keepmuted && hardmute && gt->muted)
-               return;
+       struct gemtek *gt = container_of(isa, struct gemtek, isa);
 
-       freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ);
-
-       gt->lastfreq = freq;
-       gt->muted = 0;
+       if (hardmute && gt->muted)
+               return 0;
 
        gemtek_bu2614_set(gt, BU2614_PORT, 0);
        gemtek_bu2614_set(gt, BU2614_FMES, 0);
@@ -220,23 +204,25 @@ static void gemtek_setfreq(struct gemtek *gt, unsigned long freq)
        gemtek_bu2614_set(gt, BU2614_SWAL, 0);
        gemtek_bu2614_set(gt, BU2614_FMUN, 1);  /* GT bit set   */
        gemtek_bu2614_set(gt, BU2614_TEST, 0);
-
        gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
        gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq));
-
        gemtek_bu2614_transmit(gt);
+       return 0;
 }
 
 /*
  * Set mute flag.
  */
-static void gemtek_mute(struct gemtek *gt)
+static int gemtek_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
+       struct gemtek *gt = container_of(isa, struct gemtek, isa);
        int i;
 
-       gt->muted = 1;
-
+       gt->muted = mute;
        if (hardmute) {
+               if (!mute)
+                       return gemtek_s_frequency(isa, isa->freq);
+
                /* Turn off PLL, disable data output */
                gemtek_bu2614_set(gt, BU2614_PORT, 0);
                gemtek_bu2614_set(gt, BU2614_FMES, 0);  /* CT bit off   */
@@ -247,367 +233,85 @@ static void gemtek_mute(struct gemtek *gt)
                gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF);
                gemtek_bu2614_set(gt, BU2614_FREQ, 0);
                gemtek_bu2614_transmit(gt);
-               return;
+               return 0;
        }
 
-       mutex_lock(&gt->lock);
-
        /* Read bus contents (CE, CK and DA). */
-       i = inb_p(gt->io);
+       i = inb_p(isa->io);
        /* Write it back with mute flag set. */
-       outb_p((i >> 5) | GEMTEK_MT, gt->io);
+       outb_p((i >> 5) | (mute ? GEMTEK_MT : 0), isa->io);
        udelay(SHORT_DELAY);
-
-       mutex_unlock(&gt->lock);
-}
-
-/*
- * Unset mute flag.
- */
-static void gemtek_unmute(struct gemtek *gt)
-{
-       int i;
-
-       gt->muted = 0;
-       if (hardmute) {
-               /* Turn PLL back on. */
-               gemtek_setfreq(gt, gt->lastfreq);
-               return;
-       }
-       mutex_lock(&gt->lock);
-
-       i = inb_p(gt->io);
-       outb_p(i >> 5, gt->io);
-       udelay(SHORT_DELAY);
-
-       mutex_unlock(&gt->lock);
+       return 0;
 }
 
-/*
- * Get signal strength (= stereo status).
- */
-static inline int gemtek_getsigstr(struct gemtek *gt)
+static u32 gemtek_g_rxsubchans(struct radio_isa_card *isa)
 {
-       int sig;
-
-       mutex_lock(&gt->lock);
-       sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1;
-       mutex_unlock(&gt->lock);
-       return sig;
+       if (inb_p(isa->io) & GEMTEK_NS)
+               return V4L2_TUNER_SUB_MONO;
+       return V4L2_TUNER_SUB_STEREO;
 }
 
 /*
  * Check if requested card acts like GemTek Radio card.
  */
-static int gemtek_verify(struct gemtek *gt, int port)
+static bool gemtek_probe(struct radio_isa_card *isa, int io)
 {
        int i, q;
 
-       if (gt->verified == port)
-               return 1;
-
-       mutex_lock(&gt->lock);
-
-       q = inb_p(port);        /* Read bus contents before probing. */
+       q = inb_p(io);  /* Read bus contents before probing. */
        /* Try to turn on CE, CK and DA respectively and check if card responds
           properly. */
        for (i = 0; i < 3; ++i) {
-               outb_p(1 << i, port);
+               outb_p(1 << i, io);
                udelay(SHORT_DELAY);
 
-               if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) {
-                       mutex_unlock(&gt->lock);
-                       return 0;
-               }
+               if ((inb_p(io) & ~GEMTEK_NS) != (0x17 | (1 << (i + 5))))
+                       return false;
        }
-       outb_p(q >> 5, port);   /* Write bus contents back. */
+       outb_p(q >> 5, io);     /* Write bus contents back. */
        udelay(SHORT_DELAY);
-
-       mutex_unlock(&gt->lock);
-       gt->verified = port;
-
-       return 1;
-}
-
-/*
- * Automatic probing for card.
- */
-static int gemtek_probe(struct gemtek *gt)
-{
-       struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
-       int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
-       int i;
-
-       if (!probe) {
-               v4l2_info(v4l2_dev, "Automatic device probing disabled.\n");
-               return -1;
-       }
-
-       v4l2_info(v4l2_dev, "Automatic device probing enabled.\n");
-
-       for (i = 0; i < ARRAY_SIZE(ioports); ++i) {
-               v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]);
-
-               if (!request_region(ioports[i], 1, "gemtek-probe")) {
-                       v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n",
-                              ioports[i]);
-                       continue;
-               }
-
-               if (gemtek_verify(gt, ioports[i])) {
-                       v4l2_info(v4l2_dev, "Card found from I/O port "
-                              "0x%x!\n", ioports[i]);
-
-                       release_region(ioports[i], 1);
-                       gt->io = ioports[i];
-                       return gt->io;
-               }
-
-               release_region(ioports[i], 1);
-       }
-
-       v4l2_err(v4l2_dev, "Automatic probing failed!\n");
-       return -1;
+       return true;
 }
 
-/*
- * Video 4 Linux stuff.
- */
-
-static const struct v4l2_file_operations gemtek_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops gemtek_ops = {
+       .alloc = gemtek_alloc,
+       .probe = gemtek_probe,
+       .s_mute_volume = gemtek_s_mute_volume,
+       .s_frequency = gemtek_s_frequency,
+       .g_rxsubchans = gemtek_g_rxsubchans,
 };
 
-static int vidioc_querycap(struct file *file, void *priv,
-                          struct v4l2_capability *v)
-{
-       strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
-       strlcpy(v->card, "GemTek", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
-{
-       struct gemtek *gt = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
-
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-       v->rangelow = GEMTEK_LOWFREQ;
-       v->rangehigh = GEMTEK_HIGHFREQ;
-       v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-       v->signal = 0xffff * gemtek_getsigstr(gt);
-       if (v->signal) {
-               v->audmode = V4L2_TUNER_MODE_STEREO;
-               v->rxsubchans = V4L2_TUNER_SUB_STEREO;
-       } else {
-               v->audmode = V4L2_TUNER_MODE_MONO;
-               v->rxsubchans = V4L2_TUNER_SUB_MONO;
-       }
-       return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
-{
-       return (v->index != 0) ? -EINVAL : 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                             struct v4l2_frequency *f)
-{
-       struct gemtek *gt = video_drvdata(file);
-
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = gt->lastfreq;
-       return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                             struct v4l2_frequency *f)
-{
-       struct gemtek *gt = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       gemtek_setfreq(gt, f->frequency);
-       return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-                           struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-       default:
-               return -EINVAL;
-       }
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctrl)
-{
-       struct gemtek *gt = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = gt->muted;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                        struct v4l2_control *ctrl)
-{
-       struct gemtek *gt = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value)
-                       gemtek_mute(gt);
-               else
-                       gemtek_unmute(gt);
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return (i != 0) ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
-       return (a->index != 0) ? -EINVAL : 0;
-}
-
-static const struct v4l2_ioctl_ops gemtek_ioctl_ops = {
-       .vidioc_querycap        = vidioc_querycap,
-       .vidioc_g_tuner         = vidioc_g_tuner,
-       .vidioc_s_tuner         = vidioc_s_tuner,
-       .vidioc_g_audio         = vidioc_g_audio,
-       .vidioc_s_audio         = vidioc_s_audio,
-       .vidioc_g_input         = vidioc_g_input,
-       .vidioc_s_input         = vidioc_s_input,
-       .vidioc_g_frequency     = vidioc_g_frequency,
-       .vidioc_s_frequency     = vidioc_s_frequency,
-       .vidioc_queryctrl       = vidioc_queryctrl,
-       .vidioc_g_ctrl          = vidioc_g_ctrl,
-       .vidioc_s_ctrl          = vidioc_s_ctrl
+static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
+
+static struct radio_isa_driver gemtek_driver = {
+       .driver = {
+               .match          = radio_isa_match,
+               .probe          = radio_isa_probe,
+               .remove         = radio_isa_remove,
+               .driver         = {
+                       .name   = "radio-gemtek",
+               },
+       },
+       .io_params = io,
+       .radio_nr_params = radio_nr,
+       .io_ports = gemtek_ioports,
+       .num_of_io_ports = ARRAY_SIZE(gemtek_ioports),
+       .region_size = 1,
+       .card = "GemTek Radio",
+       .ops = &gemtek_ops,
+       .has_stereo = true,
 };
 
-/*
- * Initialization / cleanup related stuff.
- */
-
 static int __init gemtek_init(void)
 {
-       struct gemtek *gt = &gemtek_card;
-       struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
-       int res;
-
-       strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name));
-
-       v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n");
-
-       mutex_init(&gt->lock);
-
-       gt->verified = -1;
-       gt->io = io;
-       gemtek_probe(gt);
-       if (gt->io) {
-               if (!request_region(gt->io, 1, "gemtek")) {
-                       v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io);
-                       return -EBUSY;
-               }
-
-               if (!gemtek_verify(gt, gt->io))
-                       v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not "
-                              "respond properly, check your "
-                              "configuration.\n", gt->io);
-               else
-                       v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io);
-       } else if (probe) {
-               v4l2_err(v4l2_dev, "Automatic probing failed and no "
-                      "fixed I/O port defined.\n");
-               return -ENODEV;
-       } else {
-               v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed "
-                      "I/O port defined.");
-               return -EINVAL;
-       }
-
-       res = v4l2_device_register(NULL, v4l2_dev);
-       if (res < 0) {
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               release_region(gt->io, 1);
-               return res;
-       }
-
-       strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name));
-       gt->vdev.v4l2_dev = v4l2_dev;
-       gt->vdev.fops = &gemtek_fops;
-       gt->vdev.ioctl_ops = &gemtek_ioctl_ops;
-       gt->vdev.release = video_device_release_empty;
-       video_set_drvdata(&gt->vdev, gt);
-
-       /* Set defaults */
-       gt->lastfreq = GEMTEK_LOWFREQ;
-       gt->bu2614data = 0;
-
-       if (initmute)
-               gemtek_mute(gt);
-
-       if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_device_unregister(v4l2_dev);
-               release_region(gt->io, 1);
-               return -EBUSY;
-       }
-
-       return 0;
+       gemtek_driver.probe = probe;
+       return isa_register_driver(&gemtek_driver.driver, GEMTEK_MAX);
 }
 
-/*
- * Module cleanup
- */
 static void __exit gemtek_exit(void)
 {
-       struct gemtek *gt = &gemtek_card;
-       struct v4l2_device *v4l2_dev = &gt->v4l2_dev;
-
-       if (shutdown) {
-               hardmute = 1;   /* Turn off PLL */
-               gemtek_mute(gt);
-       } else {
-               v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n");
-       }
-
-       video_unregister_device(&gt->vdev);
-       v4l2_device_unregister(&gt->v4l2_dev);
-       release_region(gt->io, 1);
+       hardmute = 1;   /* Turn off PLL */
+       isa_unregister_driver(&gemtek_driver.driver);
 }
 
 module_init(gemtek_init);
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
new file mode 100644 (file)
index 0000000..06f9063
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Framework for ISA radio drivers.
+ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers
+ * to concentrate on the actual hardware operation.
+ *
+ * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+
+#include "radio-isa.h"
+
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_DESCRIPTION("A framework for ISA radio drivers.");
+MODULE_LICENSE("GPL");
+
+#define FREQ_LOW  (87U * 16000U)
+#define FREQ_HIGH (108U * 16000U)
+
+static int radio_isa_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *v)
+{
+       struct radio_isa_card *isa = video_drvdata(file);
+
+       strlcpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver));
+       strlcpy(v->card, isa->drv->card, sizeof(v->card));
+       snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name);
+
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       v->device_caps = v->capabilities | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int radio_isa_g_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *v)
+{
+       struct radio_isa_card *isa = video_drvdata(file);
+       const struct radio_isa_ops *ops = isa->drv->ops;
+
+       if (v->index > 0)
+               return -EINVAL;
+
+       strlcpy(v->name, "FM", sizeof(v->name));
+       v->type = V4L2_TUNER_RADIO;
+       v->rangelow = FREQ_LOW;
+       v->rangehigh = FREQ_HIGH;
+       v->capability = V4L2_TUNER_CAP_LOW;
+       if (isa->drv->has_stereo)
+               v->capability |= V4L2_TUNER_CAP_STEREO;
+
+       if (ops->g_rxsubchans)
+               v->rxsubchans = ops->g_rxsubchans(isa);
+       else
+               v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+       v->audmode = isa->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+       if (ops->g_signal)
+               v->signal = ops->g_signal(isa);
+       else
+               v->signal = (v->rxsubchans & V4L2_TUNER_SUB_STEREO) ?
+                                                               0xffff : 0;
+       return 0;
+}
+
+static int radio_isa_s_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *v)
+{
+       struct radio_isa_card *isa = video_drvdata(file);
+       const struct radio_isa_ops *ops = isa->drv->ops;
+
+       if (v->index)
+               return -EINVAL;
+       if (ops->s_stereo) {
+               isa->stereo = (v->audmode == V4L2_TUNER_MODE_STEREO);
+               return ops->s_stereo(isa, isa->stereo);
+       }
+       return 0;
+}
+
+static int radio_isa_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct radio_isa_card *isa = video_drvdata(file);
+       int res;
+
+       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+               return -EINVAL;
+       f->frequency = clamp(f->frequency, FREQ_LOW, FREQ_HIGH);
+       res = isa->drv->ops->s_frequency(isa, f->frequency);
+       if (res == 0)
+               isa->freq = f->frequency;
+       return res;
+}
+
+static int radio_isa_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct radio_isa_card *isa = video_drvdata(file);
+
+       if (f->tuner != 0)
+               return -EINVAL;
+       f->type = V4L2_TUNER_RADIO;
+       f->frequency = isa->freq;
+       return 0;
+}
+
+static int radio_isa_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct radio_isa_card *isa =
+               container_of(ctrl->handler, struct radio_isa_card, hdl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               return isa->drv->ops->s_mute_volume(isa, ctrl->val,
+                               isa->volume ? isa->volume->val : 0);
+       }
+       return -EINVAL;
+}
+
+static int radio_isa_log_status(struct file *file, void *priv)
+{
+       struct radio_isa_card *isa = video_drvdata(file);
+
+       v4l2_info(&isa->v4l2_dev, "I/O Port = 0x%03x\n", isa->io);
+       v4l2_ctrl_handler_log_status(&isa->hdl, isa->v4l2_dev.name);
+       return 0;
+}
+
+static int radio_isa_subscribe_event(struct v4l2_fh *fh,
+                               struct v4l2_event_subscription *sub)
+{
+       if (sub->type == V4L2_EVENT_CTRL)
+               return v4l2_event_subscribe(fh, sub, 0);
+       return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops radio_isa_ctrl_ops = {
+       .s_ctrl = radio_isa_s_ctrl,
+};
+
+static const struct v4l2_file_operations radio_isa_fops = {
+       .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = v4l2_fh_release,
+       .poll           = v4l2_ctrl_poll,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops radio_isa_ioctl_ops = {
+       .vidioc_querycap    = radio_isa_querycap,
+       .vidioc_g_tuner     = radio_isa_g_tuner,
+       .vidioc_s_tuner     = radio_isa_s_tuner,
+       .vidioc_g_frequency = radio_isa_g_frequency,
+       .vidioc_s_frequency = radio_isa_s_frequency,
+       .vidioc_log_status  = radio_isa_log_status,
+       .vidioc_subscribe_event   = radio_isa_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+int radio_isa_match(struct device *pdev, unsigned int dev)
+{
+       struct radio_isa_driver *drv = pdev->platform_data;
+
+       return drv->probe || drv->io_params[dev] >= 0;
+}
+EXPORT_SYMBOL_GPL(radio_isa_match);
+
+static bool radio_isa_valid_io(const struct radio_isa_driver *drv, int io)
+{
+       int i;
+
+       for (i = 0; i < drv->num_of_io_ports; i++)
+               if (drv->io_ports[i] == io)
+                       return true;
+       return false;
+}
+
+int radio_isa_probe(struct device *pdev, unsigned int dev)
+{
+       struct radio_isa_driver *drv = pdev->platform_data;
+       const struct radio_isa_ops *ops = drv->ops;
+       struct v4l2_device *v4l2_dev;
+       struct radio_isa_card *isa;
+       int res;
+
+       isa = drv->ops->alloc();
+       if (isa == NULL)
+               return -ENOMEM;
+       dev_set_drvdata(pdev, isa);
+       isa->drv = drv;
+       isa->io = drv->io_params[dev];
+       v4l2_dev = &isa->v4l2_dev;
+       strlcpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name));
+
+       if (drv->probe && ops->probe) {
+               int i;
+
+               for (i = 0; i < drv->num_of_io_ports; ++i) {
+                       int io = drv->io_ports[i];
+
+                       if (request_region(io, drv->region_size, v4l2_dev->name)) {
+                               bool found = ops->probe(isa, io);
+
+                               release_region(io, drv->region_size);
+                               if (found) {
+                                       isa->io = io;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       if (!radio_isa_valid_io(drv, isa->io)) {
+               int i;
+
+               if (isa->io < 0)
+                       return -ENODEV;
+               v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x",
+                               drv->io_ports[0]);
+               for (i = 1; i < drv->num_of_io_ports; i++)
+                       printk(KERN_CONT "/0x%03x", drv->io_ports[i]);
+               printk(KERN_CONT ".\n");
+               kfree(isa);
+               return -EINVAL;
+       }
+
+       if (!request_region(isa->io, drv->region_size, v4l2_dev->name)) {
+               v4l2_err(v4l2_dev, "port 0x%x already in use\n", isa->io);
+               kfree(isa);
+               return -EBUSY;
+       }
+
+       res = v4l2_device_register(pdev, v4l2_dev);
+       if (res < 0) {
+               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               goto err_dev_reg;
+       }
+
+       v4l2_ctrl_handler_init(&isa->hdl, 1);
+       isa->mute = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops,
+                               V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+       if (drv->max_volume)
+               isa->volume = v4l2_ctrl_new_std(&isa->hdl, &radio_isa_ctrl_ops,
+                       V4L2_CID_AUDIO_VOLUME, 0, drv->max_volume, 1,
+                       drv->max_volume);
+       v4l2_dev->ctrl_handler = &isa->hdl;
+       if (isa->hdl.error) {
+               res = isa->hdl.error;
+               v4l2_err(v4l2_dev, "Could not register controls\n");
+               goto err_hdl;
+       }
+       if (drv->max_volume)
+               v4l2_ctrl_cluster(2, &isa->mute);
+       v4l2_dev->ctrl_handler = &isa->hdl;
+
+       mutex_init(&isa->lock);
+       isa->vdev.lock = &isa->lock;
+       strlcpy(isa->vdev.name, v4l2_dev->name, sizeof(isa->vdev.name));
+       isa->vdev.v4l2_dev = v4l2_dev;
+       isa->vdev.fops = &radio_isa_fops;
+       isa->vdev.ioctl_ops = &radio_isa_ioctl_ops;
+       isa->vdev.release = video_device_release_empty;
+       set_bit(V4L2_FL_USE_FH_PRIO, &isa->vdev.flags);
+       video_set_drvdata(&isa->vdev, isa);
+       isa->freq = FREQ_LOW;
+       isa->stereo = drv->has_stereo;
+
+       if (ops->init)
+               res = ops->init(isa);
+       if (!res)
+               res = v4l2_ctrl_handler_setup(&isa->hdl);
+       if (!res)
+               res = ops->s_frequency(isa, isa->freq);
+       if (!res && ops->s_stereo)
+               res = ops->s_stereo(isa, isa->stereo);
+       if (res < 0) {
+               v4l2_err(v4l2_dev, "Could not setup card\n");
+               goto err_node_reg;
+       }
+       res = video_register_device(&isa->vdev, VFL_TYPE_RADIO,
+                                       drv->radio_nr_params[dev]);
+       if (res < 0) {
+               v4l2_err(v4l2_dev, "Could not register device node\n");
+               goto err_node_reg;
+       }
+
+       v4l2_info(v4l2_dev, "Initialized radio card %s on port 0x%03x\n",
+                       drv->card, isa->io);
+       return 0;
+
+err_node_reg:
+       v4l2_ctrl_handler_free(&isa->hdl);
+err_hdl:
+       v4l2_device_unregister(&isa->v4l2_dev);
+err_dev_reg:
+       release_region(isa->io, drv->region_size);
+       kfree(isa);
+       return res;
+}
+EXPORT_SYMBOL_GPL(radio_isa_probe);
+
+int radio_isa_remove(struct device *pdev, unsigned int dev)
+{
+       struct radio_isa_card *isa = dev_get_drvdata(pdev);
+       const struct radio_isa_ops *ops = isa->drv->ops;
+
+       ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0);
+       video_unregister_device(&isa->vdev);
+       v4l2_ctrl_handler_free(&isa->hdl);
+       v4l2_device_unregister(&isa->v4l2_dev);
+       release_region(isa->io, isa->drv->region_size);
+       v4l2_info(&isa->v4l2_dev, "Removed radio card %s\n", isa->drv->card);
+       kfree(isa);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(radio_isa_remove);
diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h
new file mode 100644 (file)
index 0000000..8a0ea84
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Framework for ISA radio drivers.
+ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers
+ * to concentrate on the actual hardware operation.
+ *
+ * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 _RADIO_ISA_H_
+#define _RADIO_ISA_H_
+
+#include <linux/isa.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+struct radio_isa_driver;
+struct radio_isa_ops;
+
+/* Core structure for radio ISA cards */
+struct radio_isa_card {
+       const struct radio_isa_driver *drv;
+       struct v4l2_device v4l2_dev;
+       struct v4l2_ctrl_handler hdl;
+       struct video_device vdev;
+       struct mutex lock;
+       const struct radio_isa_ops *ops;
+       struct {        /* mute/volume cluster */
+               struct v4l2_ctrl *mute;
+               struct v4l2_ctrl *volume;
+       };
+       /* I/O port */
+       int io;
+
+       /* Card is in stereo audio mode */
+       bool stereo;
+       /* Current frequency */
+       u32 freq;
+};
+
+struct radio_isa_ops {
+       /* Allocate and initialize a radio_isa_card struct */
+       struct radio_isa_card *(*alloc)(void);
+       /* Probe whether a card is present at the given port */
+       bool (*probe)(struct radio_isa_card *isa, int io);
+       /* Special card initialization can be done here, this is called after
+        * the standard controls are registered, but before they are setup,
+        * thus allowing drivers to add their own controls here. */
+       int (*init)(struct radio_isa_card *isa);
+       /* Set mute and volume. */
+       int (*s_mute_volume)(struct radio_isa_card *isa, bool mute, int volume);
+       /* Set frequency */
+       int (*s_frequency)(struct radio_isa_card *isa, u32 freq);
+       /* Set stereo/mono audio mode */
+       int (*s_stereo)(struct radio_isa_card *isa, bool stereo);
+       /* Get rxsubchans value for VIDIOC_G_TUNER */
+       u32 (*g_rxsubchans)(struct radio_isa_card *isa);
+       /* Get the signal strength for VIDIOC_G_TUNER */
+       u32 (*g_signal)(struct radio_isa_card *isa);
+};
+
+/* Top level structure needed to instantiate the cards */
+struct radio_isa_driver {
+       struct isa_driver driver;
+       const struct radio_isa_ops *ops;
+       /* The module_param_array with the specified I/O ports */
+       int *io_params;
+       /* The module_param_array with the radio_nr values */
+       int *radio_nr_params;
+       /* Whether we should probe for possible cards */
+       bool probe;
+       /* The list of possible I/O ports */
+       const int *io_ports;
+       /* The size of that list */
+       int num_of_io_ports;
+       /* The region size to request */
+       unsigned region_size;
+       /* The name of the card */
+       const char *card;
+       /* Card can capture stereo audio */
+       bool has_stereo;
+       /* The maximum volume for the volume control. If 0, then there
+          is no volume control possible. */
+       int max_volume;
+};
+
+int radio_isa_match(struct device *pdev, unsigned int dev);
+int radio_isa_probe(struct device *pdev, unsigned int dev);
+int radio_isa_remove(struct device *pdev, unsigned int dev);
+
+#endif
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
new file mode 100644 (file)
index 0000000..55bd1d2
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2012 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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
+ */
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+
+/* driver and module definitions */
+MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
+MODULE_DESCRIPTION("Keene FM Transmitter driver");
+MODULE_LICENSE("GPL");
+
+/* Actually, it advertises itself as a Logitech */
+#define USB_KEENE_VENDOR 0x046d
+#define USB_KEENE_PRODUCT 0x0a0e
+
+/* Probably USB_TIMEOUT should be modified in module parameter */
+#define BUFFER_LENGTH 8
+#define USB_TIMEOUT 500
+
+/* Frequency limits in MHz */
+#define FREQ_MIN  76U
+#define FREQ_MAX 108U
+#define FREQ_MUL 16000U
+
+/* USB Device ID List */
+static struct usb_device_id usb_keene_device_table[] = {
+       {USB_DEVICE_AND_INTERFACE_INFO(USB_KEENE_VENDOR, USB_KEENE_PRODUCT,
+                                                       USB_CLASS_HID, 0, 0) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_keene_device_table);
+
+struct keene_device {
+       struct usb_device *usbdev;
+       struct usb_interface *intf;
+       struct video_device vdev;
+       struct v4l2_device v4l2_dev;
+       struct v4l2_ctrl_handler hdl;
+       struct mutex lock;
+
+       u8 *buffer;
+       unsigned curfreq;
+       u8 tx;
+       u8 pa;
+       bool stereo;
+       bool muted;
+       bool preemph_75_us;
+};
+
+static inline struct keene_device *to_keene_dev(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct keene_device, v4l2_dev);
+}
+
+/* Set frequency (if non-0), PA, mute and turn on/off the FM transmitter. */
+static int keene_cmd_main(struct keene_device *radio, unsigned freq, bool play)
+{
+       unsigned short freq_send = freq ? (freq - 76 * 16000) / 800 : 0;
+       int ret;
+
+       radio->buffer[0] = 0x00;
+       radio->buffer[1] = 0x50;
+       radio->buffer[2] = (freq_send >> 8) & 0xff;
+       radio->buffer[3] = freq_send & 0xff;
+       radio->buffer[4] = radio->pa;
+       /* If bit 4 is set, then tune to the frequency.
+          If bit 3 is set, then unmute; if bit 2 is set, then mute.
+          If bit 1 is set, then enter idle mode; if bit 0 is set,
+          then enter transit mode.
+        */
+       radio->buffer[5] = (radio->muted ? 4 : 8) | (play ? 1 : 2) |
+                                                       (freq ? 0x10 : 0);
+       radio->buffer[6] = 0x00;
+       radio->buffer[7] = 0x00;
+
+       ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+               9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
+
+       if (ret < 0) {
+               dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret);
+               return ret;
+       }
+       if (freq)
+               radio->curfreq = freq;
+       return 0;
+}
+
+/* Set TX, stereo and preemphasis mode (50 us vs 75 us). */
+static int keene_cmd_set(struct keene_device *radio)
+{
+       int ret;
+
+       radio->buffer[0] = 0x00;
+       radio->buffer[1] = 0x51;
+       radio->buffer[2] = radio->tx;
+       /* If bit 0 is set, then transmit mono, otherwise stereo.
+          If bit 2 is set, then enable 75 us preemphasis, otherwise
+          it is 50 us. */
+       radio->buffer[3] = (!radio->stereo) | (radio->preemph_75_us ? 4 : 0);
+       radio->buffer[4] = 0x00;
+       radio->buffer[5] = 0x00;
+       radio->buffer[6] = 0x00;
+       radio->buffer[7] = 0x00;
+
+       ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+               9, 0x21, 0x200, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
+
+       if (ret < 0) {
+               dev_warn(&radio->vdev.dev, "%s failed (%d)\n", __func__, ret);
+               return ret;
+       }
+       return 0;
+}
+
+/* Handle unplugging the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_keene_device_release.
+ */
+static void usb_keene_disconnect(struct usb_interface *intf)
+{
+       struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf));
+
+       v4l2_device_get(&radio->v4l2_dev);
+       mutex_lock(&radio->lock);
+       usb_set_intfdata(intf, NULL);
+       video_unregister_device(&radio->vdev);
+       v4l2_device_disconnect(&radio->v4l2_dev);
+       mutex_unlock(&radio->lock);
+       v4l2_device_put(&radio->v4l2_dev);
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+                                       struct v4l2_capability *v)
+{
+       struct keene_device *radio = video_drvdata(file);
+
+       strlcpy(v->driver, "radio-keene", sizeof(v->driver));
+       strlcpy(v->card, "Keene FM Transmitter", sizeof(v->card));
+       usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
+       v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR;
+       v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int vidioc_g_modulator(struct file *file, void *priv,
+                               struct v4l2_modulator *v)
+{
+       struct keene_device *radio = video_drvdata(file);
+
+       if (v->index > 0)
+               return -EINVAL;
+
+       strlcpy(v->name, "FM", sizeof(v->name));
+       v->rangelow = FREQ_MIN * FREQ_MUL;
+       v->rangehigh = FREQ_MAX * FREQ_MUL;
+       v->txsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+       v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+       return 0;
+}
+
+static int vidioc_s_modulator(struct file *file, void *priv,
+                               struct v4l2_modulator *v)
+{
+       struct keene_device *radio = video_drvdata(file);
+
+       if (v->index > 0)
+               return -EINVAL;
+
+       radio->stereo = (v->txsubchans == V4L2_TUNER_SUB_STEREO);
+       return keene_cmd_set(radio);
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct keene_device *radio = video_drvdata(file);
+
+       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+               return -EINVAL;
+       f->frequency = clamp(f->frequency,
+                       FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
+       return keene_cmd_main(radio, f->frequency, true);
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct keene_device *radio = video_drvdata(file);
+
+       if (f->tuner != 0)
+               return -EINVAL;
+       f->type = V4L2_TUNER_RADIO;
+       f->frequency = radio->curfreq;
+       return 0;
+}
+
+static int keene_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       static const u8 db2tx[] = {
+            /*  -15,  -12,   -9,   -6,   -3,    0 dB */
+               0x03, 0x13, 0x02, 0x12, 0x22, 0x32,
+            /*    3,    6,    9,   12,   15,   18 dB */
+               0x21, 0x31, 0x20, 0x30, 0x40, 0x50
+       };
+       struct keene_device *radio =
+               container_of(ctrl->handler, struct keene_device, hdl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               radio->muted = ctrl->val;
+               return keene_cmd_main(radio, 0, true);
+
+       case V4L2_CID_TUNE_POWER_LEVEL:
+               /* To go from dBuV to the register value we apply the
+                  following formula: */
+               radio->pa = (ctrl->val - 71) * 100 / 62;
+               return keene_cmd_main(radio, 0, true);
+
+       case V4L2_CID_TUNE_PREEMPHASIS:
+               radio->preemph_75_us = ctrl->val == V4L2_PREEMPHASIS_75_uS;
+               return keene_cmd_set(radio);
+
+       case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+               radio->tx = db2tx[(ctrl->val - ctrl->minimum) / ctrl->step];
+               return keene_cmd_set(radio);
+       }
+       return -EINVAL;
+}
+
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+                               struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_CTRL:
+               return v4l2_event_subscribe(fh, sub, 0);
+       default:
+               return -EINVAL;
+       }
+}
+
+
+/* File system interface */
+static const struct v4l2_file_operations usb_keene_fops = {
+       .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = v4l2_fh_release,
+       .poll           = v4l2_ctrl_poll,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ctrl_ops keene_ctrl_ops = {
+       .s_ctrl = keene_s_ctrl,
+};
+
+static const struct v4l2_ioctl_ops usb_keene_ioctl_ops = {
+       .vidioc_querycap    = vidioc_querycap,
+       .vidioc_g_modulator = vidioc_g_modulator,
+       .vidioc_s_modulator = vidioc_s_modulator,
+       .vidioc_g_frequency = vidioc_g_frequency,
+       .vidioc_s_frequency = vidioc_s_frequency,
+       .vidioc_log_status = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event = vidioc_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static void usb_keene_video_device_release(struct v4l2_device *v4l2_dev)
+{
+       struct keene_device *radio = to_keene_dev(v4l2_dev);
+
+       /* free rest memory */
+       v4l2_ctrl_handler_free(&radio->hdl);
+       kfree(radio->buffer);
+       kfree(radio);
+}
+
+/* check if the device is present and register with v4l and usb if it is */
+static int usb_keene_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct keene_device *radio;
+       struct v4l2_ctrl_handler *hdl;
+       int retval = 0;
+
+       /*
+        * The Keene FM transmitter USB device has the same USB ID as
+        * the Logitech AudioHub Speaker, but it should ignore the hid.
+        * Check if the name is that of the Keene device.
+        * If not, then someone connected the AudioHub and we shouldn't
+        * attempt to handle this driver.
+        * For reference: the product name of the AudioHub is
+        * "AudioHub Speaker".
+        */
+       if (dev->product && strcmp(dev->product, "B-LINK USB Audio  "))
+               return -ENODEV;
+
+       radio = kzalloc(sizeof(struct keene_device), GFP_KERNEL);
+       if (radio)
+               radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+
+       if (!radio || !radio->buffer) {
+               dev_err(&intf->dev, "kmalloc for keene_device failed\n");
+               kfree(radio);
+               retval = -ENOMEM;
+               goto err;
+       }
+
+       hdl = &radio->hdl;
+       v4l2_ctrl_handler_init(hdl, 4);
+       v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_MUTE,
+                       0, 1, 1, 0);
+       v4l2_ctrl_new_std_menu(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS,
+                       V4L2_PREEMPHASIS_75_uS, 1, V4L2_PREEMPHASIS_50_uS);
+       v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_TUNE_POWER_LEVEL,
+                       84, 118, 1, 118);
+       v4l2_ctrl_new_std(hdl, &keene_ctrl_ops, V4L2_CID_AUDIO_COMPRESSION_GAIN,
+                       -15, 18, 3, 0);
+       radio->pa = 118;
+       radio->tx = 0x32;
+       radio->stereo = true;
+       radio->curfreq = 95.16 * FREQ_MUL;
+       if (hdl->error) {
+               retval = hdl->error;
+
+               v4l2_ctrl_handler_free(hdl);
+               goto err_v4l2;
+       }
+       retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
+       if (retval < 0) {
+               dev_err(&intf->dev, "couldn't register v4l2_device\n");
+               goto err_v4l2;
+       }
+
+       mutex_init(&radio->lock);
+
+       radio->v4l2_dev.ctrl_handler = hdl;
+       radio->v4l2_dev.release = usb_keene_video_device_release;
+       strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+               sizeof(radio->vdev.name));
+       radio->vdev.v4l2_dev = &radio->v4l2_dev;
+       radio->vdev.fops = &usb_keene_fops;
+       radio->vdev.ioctl_ops = &usb_keene_ioctl_ops;
+       radio->vdev.lock = &radio->lock;
+       radio->vdev.release = video_device_release_empty;
+
+       radio->usbdev = interface_to_usbdev(intf);
+       radio->intf = intf;
+       usb_set_intfdata(intf, &radio->v4l2_dev);
+
+       video_set_drvdata(&radio->vdev, radio);
+       set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
+
+       retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
+       if (retval < 0) {
+               dev_err(&intf->dev, "could not register video device\n");
+               goto err_vdev;
+       }
+       v4l2_ctrl_handler_setup(hdl);
+       dev_info(&intf->dev, "V4L2 device registered as %s\n",
+                       video_device_node_name(&radio->vdev));
+       return 0;
+
+err_vdev:
+       v4l2_device_unregister(&radio->v4l2_dev);
+err_v4l2:
+       kfree(radio->buffer);
+       kfree(radio);
+err:
+       return retval;
+}
+
+/* USB subsystem interface */
+static struct usb_driver usb_keene_driver = {
+       .name                   = "radio-keene",
+       .probe                  = usb_keene_probe,
+       .disconnect             = usb_keene_disconnect,
+       .id_table               = usb_keene_device_table,
+};
+
+static int __init keene_init(void)
+{
+       int retval = usb_register(&usb_keene_driver);
+
+       if (retval)
+               pr_err(KBUILD_MODNAME
+                       ": usb_register failed. Error number %d\n", retval);
+
+       return retval;
+}
+
+static void __exit keene_exit(void)
+{
+       usb_deregister(&usb_keene_driver);
+}
+
+module_init(keene_init);
+module_exit(keene_exit);
+
index f872a54..740a3d5 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <sound/tea575x-tuner.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
-
-#define DRIVER_VERSION "0.7.8"
-
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 
 MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
-MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
+MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
+MODULE_VERSION("1.0.0");
 
 static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-#define dprintk(dev, num, fmt, arg...) \
-       v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg)
-
-#ifndef PCI_VENDOR_ID_GUILLEMOT
-#define PCI_VENDOR_ID_GUILLEMOT 0x5046
-#endif
-
-#ifndef PCI_DEVICE_ID_GUILLEMOT
-#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001
-#endif
-
+module_param(radio_nr, int, 0644);
+MODULE_PARM_DESC(radio_nr, "Radio device number");
 
 /* TEA5757 pin mappings */
 static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16;
 
-#define FREQ_LO                (87 * 16000)
-#define FREQ_HI                (108 * 16000)
-
-#define FREQ_IF         171200 /* 10.7*16000   */
-#define FREQ_STEP       200    /* 12.5*16      */
-
-/* (x==fmhz*16*1000) -> bits */
-#define FREQ2BITS(x) \
-  ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2)
-
-#define BITS2FREQ(x)   ((x) * FREQ_STEP - FREQ_IF)
+static atomic_t maxiradio_instance = ATOMIC_INIT(0);
 
+#define PCI_VENDOR_ID_GUILLEMOT 0x5046
+#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001
 
 struct maxiradio
 {
+       struct snd_tea575x tea;
        struct v4l2_device v4l2_dev;
-       struct video_device vdev;
        struct pci_dev *pdev;
 
        u16     io;     /* base of radio io */
-       u16     muted;  /* VIDEO_AUDIO_MUTE */
-       u16     stereo; /* VIDEO_TUNER_STEREO_ON */
-       u16     tuned;  /* signal strength (0 or 0xffff) */
-
-       unsigned long freq;
-
-       struct mutex lock;
 };
 
 static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev)
@@ -110,259 +80,41 @@ static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev)
        return container_of(v4l2_dev, struct maxiradio, v4l2_dev);
 }
 
-static void outbit(unsigned long bit, u16 io)
-{
-       int val = power | wren | (bit ? data : 0);
-
-       outb(val, io);
-       udelay(4);
-       outb(val | clk, io);
-       udelay(4);
-       outb(val, io);
-       udelay(4);
-}
-
-static void turn_power(struct maxiradio *dev, int p)
-{
-       if (p != 0) {
-               dprintk(dev, 1, "Radio powered on\n");
-               outb(power, dev->io);
-       } else {
-               dprintk(dev, 1, "Radio powered off\n");
-               outb(0, dev->io);
-       }
-}
-
-static void set_freq(struct maxiradio *dev, u32 freq)
-{
-       unsigned long int si;
-       int bl;
-       int io = dev->io;
-       int val = FREQ2BITS(freq);
-
-       /* TEA5757 shift register bits (see pdf) */
-
-       outbit(0, io); /* 24  search */
-       outbit(1, io); /* 23  search up/down */
-
-       outbit(0, io); /* 22  stereo/mono */
-
-       outbit(0, io); /* 21  band */
-       outbit(0, io); /* 20  band (only 00=FM works I think) */
-
-       outbit(0, io); /* 19  port ? */
-       outbit(0, io); /* 18  port ? */
-
-       outbit(0, io); /* 17  search level */
-       outbit(0, io); /* 16  search level */
-
-       si = 0x8000;
-       for (bl = 1; bl <= 16; bl++) {
-               outbit(val & si, io);
-               si >>= 1;
-       }
-
-       dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n",
-                               freq / 16000,
-                               freq % 16000 * 100 / 16000);
-
-       turn_power(dev, 1);
-}
-
-static int get_stereo(u16 io)
+static void maxiradio_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
 {
-       outb(power,io);
-       udelay(4);
+       struct maxiradio *dev = tea->private_data;
+       u8 bits = 0;
 
-       return !(inb(io) & mo_st);
-}
+       bits |= (pins & TEA575X_DATA) ? data : 0;
+       bits |= (pins & TEA575X_CLK)  ? clk  : 0;
+       bits |= (pins & TEA575X_WREN) ? wren : 0;
+       bits |= power;
 
-static int get_tune(u16 io)
-{
-       outb(power+clk,io);
-       udelay(4);
-
-       return !(inb(io) & mo_st);
-}
-
-
-static int vidioc_querycap(struct file *file, void  *priv,
-                           struct v4l2_capability *v)
-{
-       struct maxiradio *dev = video_drvdata(file);
-
-       strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver));
-       strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card));
-       snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
+       outb(bits, dev->io);
 }
 
-static int vidioc_g_tuner(struct file *file, void *priv,
-                          struct v4l2_tuner *v)
+/* Note: this card cannot read out the data of the shift registers,
+   only the mono/stereo pin works. */
+static u8 maxiradio_tea575x_get_pins(struct snd_tea575x *tea)
 {
-       struct maxiradio *dev = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
-
-       mutex_lock(&dev->lock);
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-       v->rangelow = FREQ_LO;
-       v->rangehigh = FREQ_HI;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       if (get_stereo(dev->io))
-               v->audmode = V4L2_TUNER_MODE_STEREO;
-       else
-               v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xffff * get_tune(dev->io);
-       mutex_unlock(&dev->lock);
+       struct maxiradio *dev = tea->private_data;
+       u8 bits = inb(dev->io);
 
-       return 0;
+       return  ((bits & data) ? TEA575X_DATA : 0) |
+               ((bits & mo_st) ? TEA575X_MOST : 0);
 }
 
-static int vidioc_s_tuner(struct file *file, void *priv,
-                          struct v4l2_tuner *v)
+static void maxiradio_tea575x_set_direction(struct snd_tea575x *tea, bool output)
 {
-       return v->index ? -EINVAL : 0;
 }
 
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                          struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-
-static int vidioc_s_audio(struct file *file, void *priv,
-                          struct v4l2_audio *a)
-{
-       return a->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                              struct v4l2_frequency *f)
-{
-       struct maxiradio *dev = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
-               dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
-                                       f->frequency / 16000,
-                                       f->frequency % 16000 * 100 / 16000,
-                                       FREQ_LO / 16000, FREQ_HI / 16000);
-
-               return -EINVAL;
-       }
-
-       mutex_lock(&dev->lock);
-       dev->freq = f->frequency;
-       set_freq(dev, dev->freq);
-       msleep(125);
-       mutex_unlock(&dev->lock);
-
-       return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                              struct v4l2_frequency *f)
-{
-       struct maxiradio *dev = video_drvdata(file);
-
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = dev->freq;
-
-       dprintk(dev, 4, "radio freq is %d.%02d MHz",
-                               f->frequency / 16000,
-                               f->frequency % 16000 * 100 / 16000);
-
-       return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-                            struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-               struct v4l2_control *ctrl)
-{
-       struct maxiradio *dev = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = dev->muted;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-               struct v4l2_control *ctrl)
-{
-       struct maxiradio *dev = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               mutex_lock(&dev->lock);
-               dev->muted = ctrl->value;
-               if (dev->muted)
-                       turn_power(dev, 0);
-               else
-                       set_freq(dev, dev->freq);
-               mutex_unlock(&dev->lock);
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static const struct v4l2_file_operations maxiradio_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
+static struct snd_tea575x_ops maxiradio_tea_ops = {
+       .set_pins = maxiradio_tea575x_set_pins,
+       .get_pins = maxiradio_tea575x_get_pins,
+       .set_direction = maxiradio_tea575x_set_direction,
 };
 
-static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .vidioc_g_tuner     = vidioc_g_tuner,
-       .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
-       .vidioc_g_frequency = vidioc_g_frequency,
-       .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
-};
-
-static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit maxiradio_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct maxiradio *dev;
        struct v4l2_device *v4l2_dev;
@@ -375,63 +127,60 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
        }
 
        v4l2_dev = &dev->v4l2_dev;
-       mutex_init(&dev->lock);
-       dev->pdev = pdev;
-       dev->muted = 1;
-       dev->freq = FREQ_LO;
-
-       strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name));
+       v4l2_device_set_name(v4l2_dev, "maxiradio", &maxiradio_instance);
 
        retval = v4l2_device_register(&pdev->dev, v4l2_dev);
        if (retval < 0) {
                v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
                goto errfr;
        }
+       dev->tea.private_data = dev;
+       dev->tea.ops = &maxiradio_tea_ops;
+       /* The data pin cannot be read. This may be a hardware limitation, or
+          we just don't know how to read it. */
+       dev->tea.cannot_read_data = true;
+       dev->tea.v4l2_dev = v4l2_dev;
+       dev->tea.radio_nr = radio_nr;
+       strlcpy(dev->tea.card, "Maxi Radio FM2000", sizeof(dev->tea.card));
+       snprintf(dev->tea.bus_info, sizeof(dev->tea.bus_info),
+                       "PCI:%s", pci_name(pdev));
+
+       retval = -ENODEV;
 
        if (!request_region(pci_resource_start(pdev, 0),
-                          pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
-               v4l2_err(v4l2_dev, "can't reserve I/O ports\n");
-               goto err_out;
+                          pci_resource_len(pdev, 0), v4l2_dev->name)) {
+               dev_err(&pdev->dev, "can't reserve I/O ports\n");
+               goto err_hdl;
        }
 
        if (pci_enable_device(pdev))
                goto err_out_free_region;
 
        dev->io = pci_resource_start(pdev, 0);
-       strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
-       dev->vdev.v4l2_dev = v4l2_dev;
-       dev->vdev.fops = &maxiradio_fops;
-       dev->vdev.ioctl_ops = &maxiradio_ioctl_ops;
-       dev->vdev.release = video_device_release_empty;
-       video_set_drvdata(&dev->vdev, dev);
-
-       if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_err(v4l2_dev, "can't register device!");
+       if (snd_tea575x_init(&dev->tea)) {
+               printk(KERN_ERR "radio-maxiradio: Unable to detect TEA575x tuner\n");
                goto err_out_free_region;
        }
-
-       v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
-
-       v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n",
-              dev->io);
        return 0;
 
 err_out_free_region:
        release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
-err_out:
+err_hdl:
        v4l2_device_unregister(v4l2_dev);
 errfr:
        kfree(dev);
-       return -ENODEV;
+       return retval;
 }
 
-static void __devexit maxiradio_remove_one(struct pci_dev *pdev)
+static void __devexit maxiradio_remove(struct pci_dev *pdev)
 {
        struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
        struct maxiradio *dev = to_maxiradio(v4l2_dev);
 
-       video_unregister_device(&dev->vdev);
-       v4l2_device_unregister(&dev->v4l2_dev);
+       snd_tea575x_exit(&dev->tea);
+       /* Turn off power */
+       outb(0, dev->io);
+       v4l2_device_unregister(v4l2_dev);
        release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
 }
 
@@ -446,19 +195,19 @@ MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl);
 static struct pci_driver maxiradio_driver = {
        .name           = "radio-maxiradio",
        .id_table       = maxiradio_pci_tbl,
-       .probe          = maxiradio_init_one,
-       .remove         = __devexit_p(maxiradio_remove_one),
+       .probe          = maxiradio_probe,
+       .remove         = __devexit_p(maxiradio_remove),
 };
 
-static int __init maxiradio_radio_init(void)
+static int __init maxiradio_init(void)
 {
        return pci_register_driver(&maxiradio_driver);
 }
 
-static void __exit maxiradio_radio_exit(void)
+static void __exit maxiradio_exit(void)
 {
        pci_unregister_driver(&maxiradio_driver);
 }
 
-module_init(maxiradio_radio_init);
-module_exit(maxiradio_radio_exit);
+module_init(maxiradio_init);
+module_exit(maxiradio_exit);
index 3628be6..b275c5d 100644 (file)
@@ -1,11 +1,12 @@
-/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
+/*
+ * RadioTrack II driver
+ * Copyright 1998 Ben Pfaff
  *
  * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
  * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
- * TODO: Allow for more than one of these foolish entities :-)
- *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
 
 MODULE_AUTHOR("Ben Pfaff");
 MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("0.1.99");
 
 #ifndef CONFIG_RADIO_RTRACK2_PORT
 #define CONFIG_RADIO_RTRACK2_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_RTRACK2_PORT;
-static int radio_nr = -1;
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
-module_param(radio_nr, int, 0);
-
-struct rtrack2
-{
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       int io;
-       unsigned long curfreq;
-       int muted;
-       struct mutex lock;
-};
+#define RTRACK2_MAX 2
 
-static struct rtrack2 rtrack2_card;
+static int io[RTRACK2_MAX] = { [0] = CONFIG_RADIO_RTRACK2_PORT,
+                             [1 ... (RTRACK2_MAX - 1)] = -1 };
+static int radio_nr[RTRACK2_MAX] = { [0 ... (RTRACK2_MAX - 1)] = -1 };
 
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 
-/* local things */
-
-static void rt_mute(struct rtrack2 *dev)
-{
-       if (dev->muted)
-               return;
-       mutex_lock(&dev->lock);
-       outb(1, dev->io);
-       mutex_unlock(&dev->lock);
-       dev->muted = 1;
-}
-
-static void rt_unmute(struct rtrack2 *dev)
+static struct radio_isa_card *rtrack2_alloc(void)
 {
-       if(dev->muted == 0)
-               return;
-       mutex_lock(&dev->lock);
-       outb(0, dev->io);
-       mutex_unlock(&dev->lock);
-       dev->muted = 0;
+       return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL);
 }
 
-static void zero(struct rtrack2 *dev)
+static void zero(struct radio_isa_card *isa)
 {
-       outb_p(1, dev->io);
-       outb_p(3, dev->io);
-       outb_p(1, dev->io);
+       outb_p(1, isa->io);
+       outb_p(3, isa->io);
+       outb_p(1, isa->io);
 }
 
-static void one(struct rtrack2 *dev)
+static void one(struct radio_isa_card *isa)
 {
-       outb_p(5, dev->io);
-       outb_p(7, dev->io);
-       outb_p(5, dev->io);
+       outb_p(5, isa->io);
+       outb_p(7, isa->io);
+       outb_p(5, isa->io);
 }
 
-static int rt_setfreq(struct rtrack2 *dev, unsigned long freq)
+static int rtrack2_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
        int i;
 
-       mutex_lock(&dev->lock);
-       dev->curfreq = freq;
        freq = freq / 200 + 856;
 
-       outb_p(0xc8, dev->io);
-       outb_p(0xc9, dev->io);
-       outb_p(0xc9, dev->io);
+       outb_p(0xc8, isa->io);
+       outb_p(0xc9, isa->io);
+       outb_p(0xc9, isa->io);
 
        for (i = 0; i < 10; i++)
-               zero(dev);
+               zero(isa);
 
        for (i = 14; i >= 0; i--)
                if (freq & (1 << i))
-                       one(dev);
+                       one(isa);
                else
-                       zero(dev);
-
-       outb_p(0xc8, dev->io);
-       if (!dev->muted)
-               outb_p(0, dev->io);
-
-       mutex_unlock(&dev->lock);
-       return 0;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
-                               struct v4l2_capability *v)
-{
-       strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver));
-       strlcpy(v->card, "RadioTrack II", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
+                       zero(isa);
 
-static int vidioc_s_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *v)
-{
-       return v->index ? -EINVAL : 0;
-}
-
-static int rt_getsigstr(struct rtrack2 *dev)
-{
-       int sig = 1;
-
-       mutex_lock(&dev->lock);
-       if (inb(dev->io) & 2)   /* bit set = no signal present  */
-               sig = 0;
-       mutex_unlock(&dev->lock);
-       return sig;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *v)
-{
-       struct rtrack2 *rt = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
-
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-       v->rangelow = 88 * 16000;
-       v->rangehigh = 108 * 16000;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xFFFF * rt_getsigstr(rt);
+       outb_p(0xc8, isa->io);
+       if (!v4l2_ctrl_g_ctrl(isa->mute))
+               outb_p(0, isa->io);
        return 0;
 }
 
-static int vidioc_s_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
+static u32 rtrack2_g_signal(struct radio_isa_card *isa)
 {
-       struct rtrack2 *rt = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       rt_setfreq(rt, f->frequency);
-       return 0;
+       /* bit set = no signal present  */
+       return (inb(isa->io) & 2) ? 0 : 0xffff;
 }
 
-static int vidioc_g_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
+static int rtrack2_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
-       struct rtrack2 *rt = video_drvdata(file);
-
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = rt->curfreq;
+       outb(mute, isa->io);
        return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                               struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
-{
-       struct rtrack2 *rt = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = rt->muted;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               if (rt->muted)
-                       ctrl->value = 0;
-               else
-                       ctrl->value = 65535;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
-{
-       struct rtrack2 *rt = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value)
-                       rt_mute(rt);
-               else
-                       rt_unmute(rt);
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               if (ctrl->value)
-                       rt_unmute(rt);
-               else
-                       rt_mute(rt);
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                               struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-                               struct v4l2_audio *a)
-{
-       return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations rtrack2_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops rtrack2_ops = {
+       .alloc = rtrack2_alloc,
+       .s_mute_volume = rtrack2_s_mute_volume,
+       .s_frequency = rtrack2_s_frequency,
+       .g_signal = rtrack2_g_signal,
 };
 
-static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .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_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
+static const int rtrack2_ioports[] = { 0x20f, 0x30f };
+
+static struct radio_isa_driver rtrack2_driver = {
+       .driver = {
+               .match          = radio_isa_match,
+               .probe          = radio_isa_probe,
+               .remove         = radio_isa_remove,
+               .driver         = {
+                       .name   = "radio-rtrack2",
+               },
+       },
+       .io_params = io,
+       .radio_nr_params = radio_nr,
+       .io_ports = rtrack2_ioports,
+       .num_of_io_ports = ARRAY_SIZE(rtrack2_ioports),
+       .region_size = 4,
+       .card = "AIMSlab RadioTrack II",
+       .ops = &rtrack2_ops,
+       .has_stereo = true,
 };
 
 static int __init rtrack2_init(void)
 {
-       struct rtrack2 *dev = &rtrack2_card;
-       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
-       int res;
-
-       strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name));
-       dev->io = io;
-       if (dev->io == -1) {
-               v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n");
-               return -EINVAL;
-       }
-       if (!request_region(dev->io, 4, "rtrack2")) {
-               v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io);
-               return -EBUSY;
-       }
-
-       res = v4l2_device_register(NULL, v4l2_dev);
-       if (res < 0) {
-               release_region(dev->io, 4);
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               return res;
-       }
-
-       strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
-       dev->vdev.v4l2_dev = v4l2_dev;
-       dev->vdev.fops = &rtrack2_fops;
-       dev->vdev.ioctl_ops = &rtrack2_ioctl_ops;
-       dev->vdev.release = video_device_release_empty;
-       video_set_drvdata(&dev->vdev, dev);
-
-       /* mute card - prevents noisy bootups */
-       outb(1, dev->io);
-       dev->muted = 1;
-
-       mutex_init(&dev->lock);
-       if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_device_unregister(v4l2_dev);
-               release_region(dev->io, 4);
-               return -EINVAL;
-       }
-
-       v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
-
-       return 0;
+       return isa_register_driver(&rtrack2_driver.driver, RTRACK2_MAX);
 }
 
 static void __exit rtrack2_exit(void)
 {
-       struct rtrack2 *dev = &rtrack2_card;
-
-       video_unregister_device(&dev->vdev);
-       v4l2_device_unregister(&dev->v4l2_dev);
-       release_region(dev->io, 4);
+       isa_unregister_driver(&rtrack2_driver.driver);
 }
 
 module_init(rtrack2_init);
index 7ab9afa..7c69214 100644 (file)
@@ -9,16 +9,23 @@
 #include <linux/delay.h>
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
+#include <linux/slab.h>
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/io.h>          /* outb, outb_p                 */
+#include <linux/isa.h>
 #include <sound/tea575x-tuner.h>
 
 MODULE_AUTHOR("Ondrej Zary");
 MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver");
 MODULE_LICENSE("GPL");
 
+static int radio_nr = -1;
+module_param(radio_nr, int, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device number");
+
 struct fmr2 {
        int io;
+       struct v4l2_device v4l2_dev;
        struct snd_tea575x tea;
        struct v4l2_ctrl *volume;
        struct v4l2_ctrl *balance;
@@ -26,7 +33,6 @@ struct fmr2 {
 
 /* the port is hardwired so no need to support multiple cards */
 #define FMR2_PORT      0x384
-static struct fmr2 fmr2_card;
 
 /* TEA575x tuner pins */
 #define STR_DATA       (1 << 0)
@@ -180,26 +186,46 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea)
        return 0;
 }
 
-static int __init fmr2_init(void)
+static int __devinit fmr2_probe(struct device *pdev, unsigned int dev)
 {
-       struct fmr2 *fmr2 = &fmr2_card;
+       struct fmr2 *fmr2;
+       int err;
+
+       fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
+       if (fmr2 == NULL)
+               return -ENOMEM;
 
+       strlcpy(fmr2->v4l2_dev.name, dev_name(pdev),
+                       sizeof(fmr2->v4l2_dev.name));
        fmr2->io = FMR2_PORT;
 
-       if (!request_region(fmr2->io, 2, "SF16-FMR2")) {
+       if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) {
                printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io);
+               kfree(fmr2);
                return -EBUSY;
        }
 
+       dev_set_drvdata(pdev, fmr2);
+       err = v4l2_device_register(pdev, &fmr2->v4l2_dev);
+       if (err < 0) {
+               v4l2_err(&fmr2->v4l2_dev, "Could not register v4l2_device\n");
+               release_region(fmr2->io, 2);
+               kfree(fmr2);
+               return err;
+       }
+       fmr2->tea.v4l2_dev = &fmr2->v4l2_dev;
        fmr2->tea.private_data = fmr2;
+       fmr2->tea.radio_nr = radio_nr;
        fmr2->tea.ops = &fmr2_tea_ops;
        fmr2->tea.ext_init = fmr2_tea_ext_init;
        strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card));
-       strcpy(fmr2->tea.bus_info, "ISA");
+       snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "ISA:%s",
+                       fmr2->v4l2_dev.name);
 
        if (snd_tea575x_init(&fmr2->tea)) {
                printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n");
                release_region(fmr2->io, 2);
+               kfree(fmr2);
                return -ENODEV;
        }
 
@@ -207,12 +233,33 @@ static int __init fmr2_init(void)
        return 0;
 }
 
-static void __exit fmr2_exit(void)
+static int __exit fmr2_remove(struct device *pdev, unsigned int dev)
 {
-       struct fmr2 *fmr2 = &fmr2_card;
+       struct fmr2 *fmr2 = dev_get_drvdata(pdev);
 
        snd_tea575x_exit(&fmr2->tea);
        release_region(fmr2->io, 2);
+       v4l2_device_unregister(&fmr2->v4l2_dev);
+       kfree(fmr2);
+       return 0;
+}
+
+struct isa_driver fmr2_driver = {
+       .probe          = fmr2_probe,
+       .remove         = fmr2_remove,
+       .driver         = {
+               .name   = "radio-sf16fmr2",
+       },
+};
+
+static int __init fmr2_init(void)
+{
+       return isa_register_driver(&fmr2_driver, 1);
+}
+
+static void __exit fmr2_exit(void)
+{
+       isa_unregister_driver(&fmr2_driver);
 }
 
 module_init(fmr2_init);
index db20904..6b1fae3 100644 (file)
@@ -575,21 +575,7 @@ static struct i2c_driver tea5764_i2c_driver = {
        .id_table = tea5764_id,
 };
 
-/* init the driver */
-static int __init tea5764_init(void)
-{
-       int ret = i2c_add_driver(&tea5764_i2c_driver);
-
-       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": "
-               DRIVER_DESC "\n");
-       return ret;
-}
-
-/* cleanup the driver */
-static void __exit tea5764_exit(void)
-{
-       i2c_del_driver(&tea5764_i2c_driver);
-}
+module_i2c_driver(tea5764_i2c_driver);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -600,6 +586,3 @@ module_param(use_xtal, int, 0);
 MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board");
 module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(radio_nr, "video4linux device number to use");
-
-module_init(tea5764_init);
-module_exit(tea5764_exit);
index f2ed9cc..be10a80 100644 (file)
  *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
  *  Volume Control is done digitally
  *
- *  there is a I2C controlled RDS decoder (SAA6588)  onboard, which i would like to support someday
- *  (as soon i have understand how to get started :)
- *  If you can help me out with that, please contact me!!
- *
- *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
 #include <linux/videodev2.h>   /* kernel radio structs         */
 #include <linux/mutex.h>
 #include <linux/io.h>          /* outb, outb_p                 */
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
 
-MODULE_AUTHOR("R.OFFERMANNS & others");
+MODULE_AUTHOR("R. Offermans & others");
 MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
-
-#ifndef CONFIG_RADIO_TERRATEC_PORT
-#define CONFIG_RADIO_TERRATEC_PORT 0x590
-#endif
+MODULE_VERSION("0.1.99");
 
-static int io = CONFIG_RADIO_TERRATEC_PORT;
+/* Note: there seems to be only one possible port (0x590), but without
+   hardware this is hard to verify. For now, this is the only one we will
+   support. */
+static int io = 0x590;
 static int radio_nr = -1;
 
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
-module_param(radio_nr, int, 0);
-
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = 0,
-               .maximum       = 0xff,
-               .step          = 1,
-               .default_value = 0xff,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       }
-};
+module_param(radio_nr, int, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device number");
 
 #define WRT_DIS        0x00
 #define CLK_OFF                0x00
@@ -76,63 +53,24 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 #define CLK_ON                 0x08
 #define WRT_EN         0x10
 
-struct terratec
+static struct radio_isa_card *terratec_alloc(void)
 {
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       int io;
-       int curvol;
-       unsigned long curfreq;
-       int muted;
-       struct mutex lock;
-};
-
-static struct terratec terratec_card;
-
-/* local things */
+       return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL);
+}
 
-static void tt_write_vol(struct terratec *tt, int volume)
+static int terratec_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
        int i;
 
-       volume = volume + (volume * 32); /* change both channels */
-       mutex_lock(&tt->lock);
+       if (mute)
+               vol = 0;
+       vol = vol + (vol * 32); /* change both channels */
        for (i = 0; i < 8; i++) {
-               if (volume & (0x80 >> i))
-                       outb(0x80, tt->io + 1);
+               if (vol & (0x80 >> i))
+                       outb(0x80, isa->io + 1);
                else
-                       outb(0x00, tt->io + 1);
-       }
-       mutex_unlock(&tt->lock);
-}
-
-
-
-static void tt_mute(struct terratec *tt)
-{
-       tt->muted = 1;
-       tt_write_vol(tt, 0);
-}
-
-static int tt_setvol(struct terratec *tt, int vol)
-{
-       if (vol == tt->curvol) {        /* requested volume = current */
-               if (tt->muted) {        /* user is unmuting the card  */
-                       tt->muted = 0;
-                       tt_write_vol(tt, vol);  /* enable card */
-               }
-               return 0;
-       }
-
-       if (vol == 0) {                 /* volume = 0 means mute the card */
-               tt_write_vol(tt, 0);    /* "turn off card" by setting vol to 0 */
-               tt->curvol = vol;       /* track the volume state!      */
-               return 0;
+                       outb(0x00, isa->io + 1);
        }
-
-       tt->muted = 0;
-       tt_write_vol(tt, vol);
-       tt->curvol = vol;
        return 0;
 }
 
@@ -140,20 +78,15 @@ static int tt_setvol(struct terratec *tt, int vol)
 /* this is the worst part in this driver */
 /* many more or less strange things are going on here, but hey, it works :) */
 
-static int tt_setfreq(struct terratec *tt, unsigned long freq1)
+static int terratec_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-       int freq;
        int i;
        int p;
-       int  temp;
+       int temp;
        long rest;
        unsigned char buffer[25];               /* we have to bit shift 25 registers */
 
-       mutex_lock(&tt->lock);
-
-       tt->curfreq = freq1;
-
-       freq = freq1 / 160;                     /* convert the freq. to a nice to handle value */
+       freq = freq / 160;                      /* convert the freq. to a nice to handle value */
        memset(buffer, 0, sizeof(buffer));
 
        rest = freq * 10 + 10700;       /* I once had understood what is going on here */
@@ -175,239 +108,61 @@ static int tt_setfreq(struct terratec *tt, unsigned long freq1)
 
        for (i = 24; i > -1; i--) {     /* bit shift the values to the radiocard */
                if (buffer[i] == 1) {
-                       outb(WRT_EN | DATA, tt->io);
-                       outb(WRT_EN | DATA | CLK_ON, tt->io);
-                       outb(WRT_EN | DATA, tt->io);
+                       outb(WRT_EN | DATA, isa->io);
+                       outb(WRT_EN | DATA | CLK_ON, isa->io);
+                       outb(WRT_EN | DATA, isa->io);
                } else {
-                       outb(WRT_EN | 0x00, tt->io);
-                       outb(WRT_EN | 0x00 | CLK_ON, tt->io);
-               }
-       }
-       outb(0x00, tt->io);
-
-       mutex_unlock(&tt->lock);
-
-       return 0;
-}
-
-static int tt_getsigstr(struct terratec *tt)
-{
-       if (inb(tt->io) & 2)    /* bit set = no signal present  */
-               return 0;
-       return 1;               /* signal present               */
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
-                                       struct v4l2_capability *v)
-{
-       strlcpy(v->driver, "radio-terratec", sizeof(v->driver));
-       strlcpy(v->card, "ActiveRadio", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       struct terratec *tt = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
-
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-       v->rangelow = 87 * 16000;
-       v->rangehigh = 108 * 16000;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xFFFF * tt_getsigstr(tt);
-       return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct terratec *tt = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       tt_setfreq(tt, f->frequency);
-       return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct terratec *tt = video_drvdata(file);
-
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = tt->curfreq;
-       return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
-                       return 0;
+                       outb(WRT_EN | 0x00, isa->io);
+                       outb(WRT_EN | 0x00 | CLK_ON, isa->io);
                }
        }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct terratec *tt = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (tt->muted)
-                       ctrl->value = 1;
-               else
-                       ctrl->value = 0;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = tt->curvol * 6554;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct terratec *tt = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value)
-                       tt_mute(tt);
-               else
-                       tt_setvol(tt,tt->curvol);
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               tt_setvol(tt,ctrl->value);
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
+       outb(0x00, isa->io);
        return 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
+static u32 terratec_g_signal(struct radio_isa_card *isa)
 {
-       return a->index ? -EINVAL : 0;
+       /* bit set = no signal present  */
+       return (inb(isa->io) & 2) ? 0 : 0xffff;
 }
 
-static const struct v4l2_file_operations terratec_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops terratec_ops = {
+       .alloc = terratec_alloc,
+       .s_mute_volume = terratec_s_mute_volume,
+       .s_frequency = terratec_s_frequency,
+       .g_signal = terratec_g_signal,
 };
 
-static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .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_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
+static const int terratec_ioports[] = { 0x590 };
+
+static struct radio_isa_driver terratec_driver = {
+       .driver = {
+               .match          = radio_isa_match,
+               .probe          = radio_isa_probe,
+               .remove         = radio_isa_remove,
+               .driver         = {
+                       .name   = "radio-terratec",
+               },
+       },
+       .io_params = &io,
+       .radio_nr_params = &radio_nr,
+       .io_ports = terratec_ioports,
+       .num_of_io_ports = ARRAY_SIZE(terratec_ioports),
+       .region_size = 2,
+       .card = "TerraTec ActiveRadio",
+       .ops = &terratec_ops,
+       .has_stereo = true,
+       .max_volume = 10,
 };
 
 static int __init terratec_init(void)
 {
-       struct terratec *tt = &terratec_card;
-       struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
-       int res;
-
-       strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name));
-       tt->io = io;
-       if (tt->io == -1) {
-               v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n");
-               return -EINVAL;
-       }
-       if (!request_region(tt->io, 2, "terratec")) {
-               v4l2_err(v4l2_dev, "port 0x%x already in use\n", io);
-               return -EBUSY;
-       }
-
-       res = v4l2_device_register(NULL, v4l2_dev);
-       if (res < 0) {
-               release_region(tt->io, 2);
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               return res;
-       }
-
-       strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name));
-       tt->vdev.v4l2_dev = v4l2_dev;
-       tt->vdev.fops = &terratec_fops;
-       tt->vdev.ioctl_ops = &terratec_ioctl_ops;
-       tt->vdev.release = video_device_release_empty;
-       video_set_drvdata(&tt->vdev, tt);
-
-       mutex_init(&tt->lock);
-
-       /* mute card - prevents noisy bootups */
-       tt_write_vol(tt, 0);
-
-       if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_device_unregister(&tt->v4l2_dev);
-               release_region(tt->io, 2);
-               return -EINVAL;
-       }
-
-       v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
-       return 0;
+       return isa_register_driver(&terratec_driver.driver, 1);
 }
 
 static void __exit terratec_exit(void)
 {
-       struct terratec *tt = &terratec_card;
-       struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
-
-       video_unregister_device(&tt->vdev);
-       v4l2_device_unregister(&tt->v4l2_dev);
-       release_region(tt->io, 2);
-       v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n");
+       isa_unregister_driver(&terratec_driver.driver);
 }
 
 module_init(terratec_init);
index b3f45a0..26a8c60 100644 (file)
 #include <linux/ioport.h>
 #include <linux/videodev2.h>
 #include <linux/io.h>
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
 
 MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("0.1.99");
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
 
@@ -35,39 +37,38 @@ MODULE_VERSION("0.0.3");
 #define CONFIG_RADIO_TRUST_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_TRUST_PORT;
-static int radio_nr = -1;
+#define TRUST_MAX 2
 
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
-module_param(radio_nr, int, 0);
+static int io[TRUST_MAX] = { [0] = CONFIG_RADIO_TRUST_PORT,
+                             [1 ... (TRUST_MAX - 1)] = -1 };
+static int radio_nr[TRUST_MAX] = { [0 ... (TRUST_MAX - 1)] = -1 };
+
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Trust FM Radio card (0x350 or 0x358)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 
 struct trust {
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       int io;
+       struct radio_isa_card isa;
        int ioval;
-       __u16 curvol;
-       __u16 curbass;
-       __u16 curtreble;
-       int muted;
-       unsigned long curfreq;
-       int curstereo;
-       int curmute;
-       struct mutex lock;
 };
 
-static struct trust trust_card;
+static struct radio_isa_card *trust_alloc(void)
+{
+       struct trust *tr = kzalloc(sizeof(*tr), GFP_KERNEL);
+
+       return tr ? &tr->isa : NULL;
+}
 
 /* i2c addresses */
 #define TDA7318_ADDR 0x88
 #define TSA6060T_ADDR 0xc4
 
-#define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0)
-#define TR_SET_SCL outb(tr->ioval |= 2, tr->io)
-#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io)
-#define TR_SET_SDA outb(tr->ioval |= 1, tr->io)
-#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io)
+#define TR_DELAY do { inb(tr->isa.io); inb(tr->isa.io); inb(tr->isa.io); } while (0)
+#define TR_SET_SCL outb(tr->ioval |= 2, tr->isa.io)
+#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->isa.io)
+#define TR_SET_SDA outb(tr->ioval |= 1, tr->isa.io)
+#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->isa.io)
 
 static void write_i2c(struct trust *tr, int n, ...)
 {
@@ -84,10 +85,10 @@ static void write_i2c(struct trust *tr, int n, ...)
        TR_CLR_SCL;
        TR_DELAY;
 
-       for(; n; n--) {
+       for (; n; n--) {
                val = va_arg(args, unsigned);
-               for(mask = 0x80; mask; mask >>= 1) {
-                       if(val & mask)
+               for (mask = 0x80; mask; mask >>= 1) {
+                       if (val & mask)
                                TR_SET_SDA;
                        else
                                TR_CLR_SDA;
@@ -115,317 +116,128 @@ static void write_i2c(struct trust *tr, int n, ...)
        va_end(args);
 }
 
-static void tr_setvol(struct trust *tr, __u16 vol)
+static int trust_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
-       mutex_lock(&tr->lock);
-       tr->curvol = vol / 2048;
-       write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f);
-       mutex_unlock(&tr->lock);
-}
+       struct trust *tr = container_of(isa, struct trust, isa);
 
-static int basstreble2chip[15] = {
-       0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8
-};
-
-static void tr_setbass(struct trust *tr, __u16 bass)
-{
-       mutex_lock(&tr->lock);
-       tr->curbass = bass / 4370;
-       write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]);
-       mutex_unlock(&tr->lock);
-}
-
-static void tr_settreble(struct trust *tr, __u16 treble)
-{
-       mutex_lock(&tr->lock);
-       tr->curtreble = treble / 4370;
-       write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]);
-       mutex_unlock(&tr->lock);
+       tr->ioval = (tr->ioval & 0xf7) | (mute << 3);
+       outb(tr->ioval, isa->io);
+       write_i2c(tr, 2, TDA7318_ADDR, vol ^ 0x1f);
+       return 0;
 }
 
-static void tr_setstereo(struct trust *tr, int stereo)
+static int trust_s_stereo(struct radio_isa_card *isa, bool stereo)
 {
-       mutex_lock(&tr->lock);
-       tr->curstereo = !!stereo;
-       tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2);
-       outb(tr->ioval, tr->io);
-       mutex_unlock(&tr->lock);
-}
+       struct trust *tr = container_of(isa, struct trust, isa);
 
-static void tr_setmute(struct trust *tr, int mute)
-{
-       mutex_lock(&tr->lock);
-       tr->curmute = !!mute;
-       tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3);
-       outb(tr->ioval, tr->io);
-       mutex_unlock(&tr->lock);
+       tr->ioval = (tr->ioval & 0xfb) | (!stereo << 2);
+       outb(tr->ioval, isa->io);
+       return 0;
 }
 
-static int tr_getsigstr(struct trust *tr)
+static u32 trust_g_signal(struct radio_isa_card *isa)
 {
        int i, v;
 
-       mutex_lock(&tr->lock);
        for (i = 0, v = 0; i < 100; i++)
-               v |= inb(tr->io);
-       mutex_unlock(&tr->lock);
+               v |= inb(isa->io);
        return (v & 1) ? 0 : 0xffff;
 }
 
-static int tr_getstereo(struct trust *tr)
-{
-       /* don't know how to determine it, just return the setting */
-       return tr->curstereo;
-}
-
-static void tr_setfreq(struct trust *tr, unsigned long f)
+static int trust_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-       mutex_lock(&tr->lock);
-       tr->curfreq = f;
-       f /= 160;       /* Convert to 10 kHz units      */
-       f += 1070;      /* Add 10.7 MHz IF              */
-       write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
-       mutex_unlock(&tr->lock);
-}
+       struct trust *tr = container_of(isa, struct trust, isa);
 
-static int vidioc_querycap(struct file *file, void *priv,
-                               struct v4l2_capability *v)
-{
-       strlcpy(v->driver, "radio-trust", sizeof(v->driver));
-       strlcpy(v->card, "Trust FM Radio", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       freq /= 160;    /* Convert to 10 kHz units      */
+       freq += 1070;   /* Add 10.7 MHz IF              */
+       write_i2c(tr, 5, TSA6060T_ADDR, (freq << 1) | 1,
+                       freq >> 7, 0x60 | ((freq >> 15) & 1), 0);
        return 0;
 }
 
-static int vidioc_g_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *v)
-{
-       struct trust *tr = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
-
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-       v->rangelow = 87.5 * 16000;
-       v->rangehigh = 108 * 16000;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       if (tr_getstereo(tr))
-               v->audmode = V4L2_TUNER_MODE_STEREO;
-       else
-               v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = tr_getsigstr(tr);
-       return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *v)
-{
-       struct trust *tr = video_drvdata(file);
-
-       if (v->index)
-               return -EINVAL;
-       tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO);
-       return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
-{
-       struct trust *tr = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       tr_setfreq(tr, f->frequency);
-       return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
-{
-       struct trust *tr = video_drvdata(file);
-
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = tr->curfreq;
-       return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-                               struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535);
-       case V4L2_CID_AUDIO_BASS:
-       case V4L2_CID_AUDIO_TREBLE:
-               return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768);
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
-{
-       struct trust *tr = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = tr->curmute;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = tr->curvol * 2048;
-               return 0;
-       case V4L2_CID_AUDIO_BASS:
-               ctrl->value = tr->curbass * 4370;
-               return 0;
-       case V4L2_CID_AUDIO_TREBLE:
-               ctrl->value = tr->curtreble * 4370;
-               return 0;
-       }
-       return -EINVAL;
-}
+static int basstreble2chip[15] = {
+       0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8
+};
 
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
+static int trust_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct trust *tr = video_drvdata(file);
+       struct radio_isa_card *isa =
+               container_of(ctrl->handler, struct radio_isa_card, hdl);
+       struct trust *tr = container_of(isa, struct trust, isa);
 
        switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               tr_setmute(tr, ctrl->value);
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               tr_setvol(tr, ctrl->value);
-               return 0;
        case V4L2_CID_AUDIO_BASS:
-               tr_setbass(tr, ctrl->value);
+               write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[ctrl->val]);
                return 0;
        case V4L2_CID_AUDIO_TREBLE:
-               tr_settreble(tr, ctrl->value);
+               write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[ctrl->val]);
                return 0;
        }
        return -EINVAL;
 }
 
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                               struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-                               struct v4l2_audio *a)
-{
-       return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations trust_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops trust_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .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_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
+static const struct v4l2_ctrl_ops trust_ctrl_ops = {
+       .s_ctrl = trust_s_ctrl,
 };
 
-static int __init trust_init(void)
+static int trust_initialize(struct radio_isa_card *isa)
 {
-       struct trust *tr = &trust_card;
-       struct v4l2_device *v4l2_dev = &tr->v4l2_dev;
-       int res;
+       struct trust *tr = container_of(isa, struct trust, isa);
 
-       strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name));
-       tr->io = io;
        tr->ioval = 0xf;
-       mutex_init(&tr->lock);
-
-       if (tr->io == -1) {
-               v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n");
-               return -EINVAL;
-       }
-       if (!request_region(tr->io, 2, "Trust FM Radio")) {
-               v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io);
-               return -EBUSY;
-       }
-
-       res = v4l2_device_register(NULL, v4l2_dev);
-       if (res < 0) {
-               release_region(tr->io, 2);
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               return res;
-       }
-
-       strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name));
-       tr->vdev.v4l2_dev = v4l2_dev;
-       tr->vdev.fops = &trust_fops;
-       tr->vdev.ioctl_ops = &trust_ioctl_ops;
-       tr->vdev.release = video_device_release_empty;
-       video_set_drvdata(&tr->vdev, tr);
-
        write_i2c(tr, 2, TDA7318_ADDR, 0x80);   /* speaker att. LF = 0 dB */
        write_i2c(tr, 2, TDA7318_ADDR, 0xa0);   /* speaker att. RF = 0 dB */
        write_i2c(tr, 2, TDA7318_ADDR, 0xc0);   /* speaker att. LR = 0 dB */
        write_i2c(tr, 2, TDA7318_ADDR, 0xe0);   /* speaker att. RR = 0 dB */
        write_i2c(tr, 2, TDA7318_ADDR, 0x40);   /* stereo 1 input, gain = 18.75 dB */
 
-       tr_setvol(tr, 0xffff);
-       tr_setbass(tr, 0x8000);
-       tr_settreble(tr, 0x8000);
-       tr_setstereo(tr, 1);
-
-       /* mute card - prevents noisy bootups */
-       tr_setmute(tr, 1);
+       v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops,
+                               V4L2_CID_AUDIO_BASS, 0, 15, 1, 8);
+       v4l2_ctrl_new_std(&isa->hdl, &trust_ctrl_ops,
+                               V4L2_CID_AUDIO_TREBLE, 0, 15, 1, 8);
+       return isa->hdl.error;
+}
 
-       if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_device_unregister(v4l2_dev);
-               release_region(tr->io, 2);
-               return -EINVAL;
-       }
+static const struct radio_isa_ops trust_ops = {
+       .init = trust_initialize,
+       .alloc = trust_alloc,
+       .s_mute_volume = trust_s_mute_volume,
+       .s_frequency = trust_s_frequency,
+       .s_stereo = trust_s_stereo,
+       .g_signal = trust_g_signal,
+};
 
-       v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
+static const int trust_ioports[] = { 0x350, 0x358 };
+
+static struct radio_isa_driver trust_driver = {
+       .driver = {
+               .match          = radio_isa_match,
+               .probe          = radio_isa_probe,
+               .remove         = radio_isa_remove,
+               .driver         = {
+                       .name   = "radio-trust",
+               },
+       },
+       .io_params = io,
+       .radio_nr_params = radio_nr,
+       .io_ports = trust_ioports,
+       .num_of_io_ports = ARRAY_SIZE(trust_ioports),
+       .region_size = 2,
+       .card = "Trust FM Radio",
+       .ops = &trust_ops,
+       .has_stereo = true,
+       .max_volume = 31,
+};
 
-       return 0;
+static int __init trust_init(void)
+{
+       return isa_register_driver(&trust_driver.driver, TRUST_MAX);
 }
 
-static void __exit cleanup_trust_module(void)
+static void __exit trust_exit(void)
 {
-       struct trust *tr = &trust_card;
-
-       video_unregister_device(&tr->vdev);
-       v4l2_device_unregister(&tr->v4l2_dev);
-       release_region(tr->io, 2);
+       isa_unregister_driver(&trust_driver.driver);
 }
 
 module_init(trust_init);
-module_exit(cleanup_trust_module);
+module_exit(trust_exit);
index 398726a..eb72a4d 100644 (file)
 #include <linux/ioport.h>      /* request_region                 */
 #include <linux/videodev2.h>   /* kernel radio structs           */
 #include <linux/io.h>          /* outb, outb_p                   */
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
 
 #define DRIVER_VERSION "0.1.2"
 
 MODULE_AUTHOR("Dr. Henrik Seidel");
 MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
+MODULE_VERSION("0.1.99");
 
 #ifndef CONFIG_RADIO_TYPHOON_PORT
 #define CONFIG_RADIO_TYPHOON_PORT -1
 #endif
 
 #ifndef CONFIG_RADIO_TYPHOON_MUTEFREQ
-#define CONFIG_RADIO_TYPHOON_MUTEFREQ 0
+#define CONFIG_RADIO_TYPHOON_MUTEFREQ 87000
 #endif
 
-static int io = CONFIG_RADIO_TYPHOON_PORT;
-static int radio_nr = -1;
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)");
-
-module_param(radio_nr, int, 0);
+#define TYPHOON_MAX 2
 
+static int io[TYPHOON_MAX] = { [0] = CONFIG_RADIO_TYPHOON_PORT,
+                             [1 ... (TYPHOON_MAX - 1)] = -1 };
+static int radio_nr[TYPHOON_MAX]       = { [0 ... (TYPHOON_MAX - 1)] = -1 };
 static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ;
+
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Typhoon card (0x316 or 0x336)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 module_param(mutefreq, ulong, 0);
 MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
 
-#define BANNER "Typhoon Radio Card driver v" DRIVER_VERSION "\n"
-
 struct typhoon {
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       int io;
-       int curvol;
+       struct radio_isa_card isa;
        int muted;
-       unsigned long curfreq;
-       unsigned long mutefreq;
-       struct mutex lock;
 };
 
-static struct typhoon typhoon_card;
-
-static void typhoon_setvol_generic(struct typhoon *dev, int vol)
+static struct radio_isa_card *typhoon_alloc(void)
 {
-       mutex_lock(&dev->lock);
-       vol >>= 14;                             /* Map 16 bit to 2 bit */
-       vol &= 3;
-       outb_p(vol / 2, dev->io);               /* Set the volume, high bit. */
-       outb_p(vol % 2, dev->io + 2);   /* Set the volume, low bit. */
-       mutex_unlock(&dev->lock);
+       struct typhoon *ty = kzalloc(sizeof(*ty), GFP_KERNEL);
+
+       return ty ? &ty->isa : NULL;
 }
 
-static int typhoon_setfreq_generic(struct typhoon *dev,
-                                  unsigned long frequency)
+static int typhoon_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
        unsigned long outval;
        unsigned long x;
@@ -105,302 +95,86 @@ static int typhoon_setfreq_generic(struct typhoon *dev,
         *
         */
 
-       mutex_lock(&dev->lock);
-       x = frequency / 160;
+       x = freq / 160;
        outval = (x * x + 2500) / 5000;
        outval = (outval * x + 5000) / 10000;
        outval -= (10 * x * x + 10433) / 20866;
        outval += 4 * x - 11505;
 
-       outb_p((outval >> 8) & 0x01, dev->io + 4);
-       outb_p(outval >> 9, dev->io + 6);
-       outb_p(outval & 0xff, dev->io + 8);
-       mutex_unlock(&dev->lock);
-
-       return 0;
-}
-
-static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency)
-{
-       typhoon_setfreq_generic(dev, frequency);
-       dev->curfreq = frequency;
-       return 0;
-}
-
-static void typhoon_mute(struct typhoon *dev)
-{
-       if (dev->muted == 1)
-               return;
-       typhoon_setvol_generic(dev, 0);
-       typhoon_setfreq_generic(dev, dev->mutefreq);
-       dev->muted = 1;
-}
-
-static void typhoon_unmute(struct typhoon *dev)
-{
-       if (dev->muted == 0)
-               return;
-       typhoon_setfreq_generic(dev, dev->curfreq);
-       typhoon_setvol_generic(dev, dev->curvol);
-       dev->muted = 0;
-}
-
-static int typhoon_setvol(struct typhoon *dev, int vol)
-{
-       if (dev->muted && vol != 0) {   /* user is unmuting the card */
-               dev->curvol = vol;
-               typhoon_unmute(dev);
-               return 0;
-       }
-       if (vol == dev->curvol)         /* requested volume == current */
-               return 0;
-
-       if (vol == 0) {                 /* volume == 0 means mute the card */
-               typhoon_mute(dev);
-               dev->curvol = vol;
-               return 0;
-       }
-       typhoon_setvol_generic(dev, vol);
-       dev->curvol = vol;
-       return 0;
-}
-
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *v)
-{
-       strlcpy(v->driver, "radio-typhoon", sizeof(v->driver));
-       strlcpy(v->card, "Typhoon Radio", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       if (v->index > 0)
-               return -EINVAL;
-
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-       v->rangelow = 87.5 * 16000;
-       v->rangehigh = 108 * 16000;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xFFFF;     /* We can't get the signal strength */
-       return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct typhoon *dev = video_drvdata(file);
-
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = dev->curfreq;
-       return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct typhoon *dev = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       dev->curfreq = f->frequency;
-       typhoon_setfreq(dev, dev->curfreq);
+       outb_p((outval >> 8) & 0x01, isa->io + 4);
+       outb_p(outval >> 9, isa->io + 6);
+       outb_p(outval & 0xff, isa->io + 8);
        return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
+static int typhoon_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535);
-       }
-       return -EINVAL;
-}
+       struct typhoon *ty = container_of(isa, struct typhoon, isa);
 
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct typhoon *dev = video_drvdata(file);
+       if (mute)
+               vol = 0;
+       vol >>= 14;                     /* Map 16 bit to 2 bit */
+       vol &= 3;
+       outb_p(vol / 2, isa->io);       /* Set the volume, high bit. */
+       outb_p(vol % 2, isa->io + 2);   /* Set the volume, low bit. */
 
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = dev->muted;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = dev->curvol;
-               return 0;
+       if (vol == 0 && !ty->muted) {
+               ty->muted = true;
+               return typhoon_s_frequency(isa, mutefreq << 4);
        }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl (struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct typhoon *dev = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value)
-                       typhoon_mute(dev);
-               else
-                       typhoon_unmute(dev);
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               typhoon_setvol(dev, ctrl->value);
-               return 0;
+       if (vol && ty->muted) {
+               ty->muted = false;
+               return typhoon_s_frequency(isa, isa->freq);
        }
-       return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
        return 0;
 }
 
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       return a->index ? -EINVAL : 0;
-}
-
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct typhoon *dev = video_drvdata(file);
-       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
-
-       v4l2_info(v4l2_dev, BANNER);
-#ifdef MODULE
-       v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n");
-#else
-       v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n");
-#endif
-       v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4);
-       v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol);
-       v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ?  "on" : "off");
-       v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io);
-       v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4);
-       return 0;
-}
-
-static const struct v4l2_file_operations typhoon_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops typhoon_ops = {
+       .alloc = typhoon_alloc,
+       .s_mute_volume = typhoon_s_mute_volume,
+       .s_frequency = typhoon_s_frequency,
 };
 
-static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
-       .vidioc_log_status  = vidioc_log_status,
-       .vidioc_querycap    = vidioc_querycap,
-       .vidioc_g_tuner     = vidioc_g_tuner,
-       .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
-       .vidioc_g_frequency = vidioc_g_frequency,
-       .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
+static const int typhoon_ioports[] = { 0x316, 0x336 };
+
+static struct radio_isa_driver typhoon_driver = {
+       .driver = {
+               .match          = radio_isa_match,
+               .probe          = radio_isa_probe,
+               .remove         = radio_isa_remove,
+               .driver         = {
+                       .name   = "radio-typhoon",
+               },
+       },
+       .io_params = io,
+       .radio_nr_params = radio_nr,
+       .io_ports = typhoon_ioports,
+       .num_of_io_ports = ARRAY_SIZE(typhoon_ioports),
+       .region_size = 8,
+       .card = "Typhoon Radio",
+       .ops = &typhoon_ops,
+       .has_stereo = true,
+       .max_volume = 3,
 };
 
 static int __init typhoon_init(void)
 {
-       struct typhoon *dev = &typhoon_card;
-       struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
-       int res;
-
-       strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name));
-       dev->io = io;
-
-       if (dev->io == -1) {
-               v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n");
-               return -EINVAL;
-       }
-
-       if (mutefreq < 87000 || mutefreq > 108500) {
-               v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n");
-               v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
-               return -EINVAL;
-       }
-       dev->curfreq = dev->mutefreq = mutefreq << 4;
-
-       mutex_init(&dev->lock);
-       if (!request_region(dev->io, 8, "typhoon")) {
-               v4l2_err(v4l2_dev, "port 0x%x already in use\n",
-                      dev->io);
-               return -EBUSY;
-       }
-
-       res = v4l2_device_register(NULL, v4l2_dev);
-       if (res < 0) {
-               release_region(dev->io, 8);
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               return res;
+       if (mutefreq < 87000 || mutefreq > 108000) {
+               printk(KERN_ERR "%s: You must set a frequency (in kHz) used when muting the card,\n",
+                               typhoon_driver.driver.driver.name);
+               printk(KERN_ERR "%s: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108000)\n",
+                               typhoon_driver.driver.driver.name);
+               return -ENODEV;
        }
-       v4l2_info(v4l2_dev, BANNER);
-
-       strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
-       dev->vdev.v4l2_dev = v4l2_dev;
-       dev->vdev.fops = &typhoon_fops;
-       dev->vdev.ioctl_ops = &typhoon_ioctl_ops;
-       dev->vdev.release = video_device_release_empty;
-       video_set_drvdata(&dev->vdev, dev);
-
-       /* mute card - prevents noisy bootups */
-       typhoon_mute(dev);
-
-       if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_device_unregister(&dev->v4l2_dev);
-               release_region(dev->io, 8);
-               return -EINVAL;
-       }
-       v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io);
-       v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq);
-
-       return 0;
+       return isa_register_driver(&typhoon_driver.driver, TYPHOON_MAX);
 }
 
 static void __exit typhoon_exit(void)
 {
-       struct typhoon *dev = &typhoon_card;
-
-       video_unregister_device(&dev->vdev);
-       v4l2_device_unregister(&dev->v4l2_dev);
-       release_region(dev->io, 8);
+       isa_unregister_driver(&typhoon_driver.driver);
 }
 
+
 module_init(typhoon_init);
 module_exit(typhoon_exit);
 
index f5613b9..026e88e 100644 (file)
@@ -1,5 +1,6 @@
-/* zoltrix radio plus driver for Linux radio support
- * (c) 1998 C. van Schaik <carl@leg.uct.ac.za>
+/*
+ * Zoltrix Radio Plus driver
+ * Copyright 1998 C. van Schaik <carl@leg.uct.ac.za>
  *
  * BUGS
  *  Due to the inconsistency in reading from the signal flags
  *
  * 2006-07-24 - Converted to V4L2 API
  *             by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
+ *
+ * Note that this is the driver for the Zoltrix Radio Plus.
+ * This driver does not work for the Zoltrix Radio Plus 108 or the
+ * Zoltrix Radio Plus for Windows.
+ *
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
  */
 
 #include <linux/module.h>      /* Modules                        */
 #include <linux/videodev2.h>   /* kernel radio structs           */
 #include <linux/mutex.h>
 #include <linux/io.h>          /* outb, outb_p                   */
+#include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include "radio-isa.h"
 
-MODULE_AUTHOR("C.van Schaik");
+MODULE_AUTHOR("C. van Schaik");
 MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
+MODULE_VERSION("0.1.99");
 
 #ifndef CONFIG_RADIO_ZOLTRIX_PORT
 #define CONFIG_RADIO_ZOLTRIX_PORT -1
 #endif
 
-static int io = CONFIG_RADIO_ZOLTRIX_PORT;
-static int radio_nr = -1;
+#define ZOLTRIX_MAX 2
+
+static int io[ZOLTRIX_MAX] = { [0] = CONFIG_RADIO_ZOLTRIX_PORT,
+                              [1 ... (ZOLTRIX_MAX - 1)] = -1 };
+static int radio_nr[ZOLTRIX_MAX] = { [0 ... (ZOLTRIX_MAX - 1)] = -1 };
 
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
-module_param(radio_nr, int, 0);
+module_param_array(io, int, NULL, 0444);
+MODULE_PARM_DESC(io, "I/O addresses of the Zoltrix Radio Plus card (0x20c or 0x30c)");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
 
 struct zoltrix {
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       int io;
+       struct radio_isa_card isa;
        int curvol;
-       unsigned long curfreq;
-       int muted;
-       unsigned int stereo;
-       struct mutex lock;
+       bool muted;
 };
 
-static struct zoltrix zoltrix_card;
+static struct radio_isa_card *zoltrix_alloc(void)
+{
+       struct zoltrix *zol = kzalloc(sizeof(*zol), GFP_KERNEL);
+
+       return zol ? &zol->isa : NULL;
+}
 
-static int zol_setvol(struct zoltrix *zol, int vol)
+static int zoltrix_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
 {
-       zol->curvol = vol;
-       if (zol->muted)
-               return 0;
+       struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
 
-       mutex_lock(&zol->lock);
-       if (vol == 0) {
-               outb(0, zol->io);
-               outb(0, zol->io);
-               inb(zol->io + 3);    /* Zoltrix needs to be read to confirm */
-               mutex_unlock(&zol->lock);
+       zol->curvol = vol;
+       zol->muted = mute;
+       if (mute || vol == 0) {
+               outb(0, isa->io);
+               outb(0, isa->io);
+               inb(isa->io + 3);            /* Zoltrix needs to be read to confirm */
                return 0;
        }
 
-       outb(zol->curvol-1, zol->io);
+       outb(vol - 1, isa->io);
        msleep(10);
-       inb(zol->io + 2);
-       mutex_unlock(&zol->lock);
+       inb(isa->io + 2);
        return 0;
 }
 
-static void zol_mute(struct zoltrix *zol)
-{
-       zol->muted = 1;
-       mutex_lock(&zol->lock);
-       outb(0, zol->io);
-       outb(0, zol->io);
-       inb(zol->io + 3);            /* Zoltrix needs to be read to confirm */
-       mutex_unlock(&zol->lock);
-}
-
-static void zol_unmute(struct zoltrix *zol)
-{
-       zol->muted = 0;
-       zol_setvol(zol, zol->curvol);
-}
-
-static int zol_setfreq(struct zoltrix *zol, unsigned long freq)
+/* tunes the radio to the desired frequency */
+static int zoltrix_s_frequency(struct radio_isa_card *isa, u32 freq)
 {
-       /* tunes the radio to the desired frequency */
-       struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
+       struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
+       struct v4l2_device *v4l2_dev = &isa->v4l2_dev;
        unsigned long long bitmask, f, m;
-       unsigned int stereo = zol->stereo;
+       bool stereo = isa->stereo;
        int i;
 
        if (freq == 0) {
@@ -125,340 +122,125 @@ static int zol_setfreq(struct zoltrix *zol, unsigned long freq)
        bitmask = 0xc480402c10080000ull;
        i = 45;
 
-       mutex_lock(&zol->lock);
-
-       zol->curfreq = freq;
-
-       outb(0, zol->io);
-       outb(0, zol->io);
-       inb(zol->io + 3);            /* Zoltrix needs to be read to confirm */
+       outb(0, isa->io);
+       outb(0, isa->io);
+       inb(isa->io + 3);            /* Zoltrix needs to be read to confirm */
 
-       outb(0x40, zol->io);
-       outb(0xc0, zol->io);
+       outb(0x40, isa->io);
+       outb(0xc0, isa->io);
 
        bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31));
        while (i--) {
                if ((bitmask & 0x8000000000000000ull) != 0) {
-                       outb(0x80, zol->io);
+                       outb(0x80, isa->io);
                        udelay(50);
-                       outb(0x00, zol->io);
+                       outb(0x00, isa->io);
                        udelay(50);
-                       outb(0x80, zol->io);
+                       outb(0x80, isa->io);
                        udelay(50);
                } else {
-                       outb(0xc0, zol->io);
+                       outb(0xc0, isa->io);
                        udelay(50);
-                       outb(0x40, zol->io);
+                       outb(0x40, isa->io);
                        udelay(50);
-                       outb(0xc0, zol->io);
+                       outb(0xc0, isa->io);
                        udelay(50);
                }
                bitmask *= 2;
        }
        /* termination sequence */
-       outb(0x80, zol->io);
-       outb(0xc0, zol->io);
-       outb(0x40, zol->io);
+       outb(0x80, isa->io);
+       outb(0xc0, isa->io);
+       outb(0x40, isa->io);
        udelay(1000);
-       inb(zol->io + 2);
-
+       inb(isa->io + 2);
        udelay(1000);
 
-       if (zol->muted) {
-               outb(0, zol->io);
-               outb(0, zol->io);
-               inb(zol->io + 3);
-               udelay(1000);
-       }
-
-       mutex_unlock(&zol->lock);
-
-       if (!zol->muted)
-               zol_setvol(zol, zol->curvol);
-       return 0;
+       return zoltrix_s_mute_volume(isa, zol->muted, zol->curvol);
 }
 
 /* Get signal strength */
-static int zol_getsigstr(struct zoltrix *zol)
+static u32 zoltrix_g_rxsubchans(struct radio_isa_card *isa)
 {
+       struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
        int a, b;
 
-       mutex_lock(&zol->lock);
-       outb(0x00, zol->io);         /* This stuff I found to do nothing */
-       outb(zol->curvol, zol->io);
+       outb(0x00, isa->io);         /* This stuff I found to do nothing */
+       outb(zol->curvol, isa->io);
        msleep(20);
 
-       a = inb(zol->io);
+       a = inb(isa->io);
        msleep(10);
-       b = inb(zol->io);
+       b = inb(isa->io);
 
-       mutex_unlock(&zol->lock);
-
-       if (a != b)
-               return 0;
-
-       /* I found this out by playing with a binary scanner on the card io */
-       return a == 0xcf || a == 0xdf || a == 0xef;
+       return (a == b && a == 0xcf) ?
+               V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
 }
 
-static int zol_is_stereo(struct zoltrix *zol)
+static u32 zoltrix_g_signal(struct radio_isa_card *isa)
 {
-       int x1, x2;
-
-       mutex_lock(&zol->lock);
+       struct zoltrix *zol = container_of(isa, struct zoltrix, isa);
+       int a, b;
 
-       outb(0x00, zol->io);
-       outb(zol->curvol, zol->io);
+       outb(0x00, isa->io);         /* This stuff I found to do nothing */
+       outb(zol->curvol, isa->io);
        msleep(20);
 
-       x1 = inb(zol->io);
+       a = inb(isa->io);
        msleep(10);
-       x2 = inb(zol->io);
-
-       mutex_unlock(&zol->lock);
-
-       return x1 == x2 && x1 == 0xcf;
-}
-
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *v)
-{
-       strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver));
-       strlcpy(v->card, "Zoltrix Radio", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       struct zoltrix *zol = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
-
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-       v->rangelow = 88 * 16000;
-       v->rangehigh = 108 * 16000;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       v->capability = V4L2_TUNER_CAP_LOW;
-       if (zol_is_stereo(zol))
-               v->audmode = V4L2_TUNER_MODE_STEREO;
-       else
-               v->audmode = V4L2_TUNER_MODE_MONO;
-       v->signal = 0xFFFF * zol_getsigstr(zol);
-       return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct zoltrix *zol = video_drvdata(file);
-
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       if (zol_setfreq(zol, f->frequency) != 0)
-               return -EINVAL;
-       return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct zoltrix *zol = video_drvdata(file);
+       b = inb(isa->io);
 
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = zol->curfreq;
-       return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
-{
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       case V4L2_CID_AUDIO_VOLUME:
-               return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535);
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
-{
-       struct zoltrix *zol = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = zol->muted;
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = zol->curvol * 4096;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
-{
-       struct zoltrix *zol = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value)
-                       zol_mute(zol);
-               else {
-                       zol_unmute(zol);
-                       zol_setvol(zol, zol->curvol);
-               }
-               return 0;
-       case V4L2_CID_AUDIO_VOLUME:
-               zol_setvol(zol, ctrl->value / 4096);
+       if (a != b)
                return 0;
-       }
-       zol->stereo = 1;
-       if (zol_setfreq(zol, zol->curfreq) != 0)
-               return -EINVAL;
-#if 0
-/* FIXME: Implement stereo/mono switch on V4L2 */
-       if (v->mode & VIDEO_SOUND_STEREO) {
-               zol->stereo = 1;
-               zol_setfreq(zol, zol->curfreq);
-       }
-       if (v->mode & VIDEO_SOUND_MONO) {
-               zol->stereo = 0;
-               zol_setfreq(zol, zol->curfreq);
-       }
-#endif
-       return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
+       /* I found this out by playing with a binary scanner on the card io */
+       return (a == 0xcf || a == 0xdf || a == 0xef) ? 0xffff : 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
+static int zoltrix_s_stereo(struct radio_isa_card *isa, bool stereo)
 {
-       return a->index ? -EINVAL : 0;
+       return zoltrix_s_frequency(isa, isa->freq);
 }
 
-static const struct v4l2_file_operations zoltrix_fops =
-{
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
+static const struct radio_isa_ops zoltrix_ops = {
+       .alloc = zoltrix_alloc,
+       .s_mute_volume = zoltrix_s_mute_volume,
+       .s_frequency = zoltrix_s_frequency,
+       .s_stereo = zoltrix_s_stereo,
+       .g_rxsubchans = zoltrix_g_rxsubchans,
+       .g_signal = zoltrix_g_signal,
 };
 
-static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .vidioc_g_tuner     = vidioc_g_tuner,
-       .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
-       .vidioc_g_frequency = vidioc_g_frequency,
-       .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
+static const int zoltrix_ioports[] = { 0x20c, 0x30c };
+
+static struct radio_isa_driver zoltrix_driver = {
+       .driver = {
+               .match          = radio_isa_match,
+               .probe          = radio_isa_probe,
+               .remove         = radio_isa_remove,
+               .driver         = {
+                       .name   = "radio-zoltrix",
+               },
+       },
+       .io_params = io,
+       .radio_nr_params = radio_nr,
+       .io_ports = zoltrix_ioports,
+       .num_of_io_ports = ARRAY_SIZE(zoltrix_ioports),
+       .region_size = 2,
+       .card = "Zoltrix Radio Plus",
+       .ops = &zoltrix_ops,
+       .has_stereo = true,
+       .max_volume = 15,
 };
 
 static int __init zoltrix_init(void)
 {
-       struct zoltrix *zol = &zoltrix_card;
-       struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
-       int res;
-
-       strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name));
-       zol->io = io;
-       if (zol->io == -1) {
-               v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n");
-               return -EINVAL;
-       }
-       if (zol->io != 0x20c && zol->io != 0x30c) {
-               v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n");
-               return -ENXIO;
-       }
-
-       if (!request_region(zol->io, 2, "zoltrix")) {
-               v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io);
-               return -EBUSY;
-       }
-
-       res = v4l2_device_register(NULL, v4l2_dev);
-       if (res < 0) {
-               release_region(zol->io, 2);
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               return res;
-       }
-
-       mutex_init(&zol->lock);
-
-       /* mute card - prevents noisy bootups */
-
-       /* this ensures that the volume is all the way down  */
-
-       outb(0, zol->io);
-       outb(0, zol->io);
-       msleep(20);
-       inb(zol->io + 3);
-
-       zol->curvol = 0;
-       zol->stereo = 1;
-
-       strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
-       zol->vdev.v4l2_dev = v4l2_dev;
-       zol->vdev.fops = &zoltrix_fops;
-       zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
-       zol->vdev.release = video_device_release_empty;
-       video_set_drvdata(&zol->vdev, zol);
-
-       if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_device_unregister(v4l2_dev);
-               release_region(zol->io, 2);
-               return -EINVAL;
-       }
-       v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
-
-       return 0;
+       return isa_register_driver(&zoltrix_driver.driver, ZOLTRIX_MAX);
 }
 
 static void __exit zoltrix_exit(void)
 {
-       struct zoltrix *zol = &zoltrix_card;
-
-       video_unregister_device(&zol->vdev);
-       v4l2_device_unregister(&zol->v4l2_dev);
-       release_region(zol->io, 2);
+       isa_unregister_driver(&zoltrix_driver.driver);
 }
 
 module_init(zoltrix_init);
index b1193df..9474706 100644 (file)
@@ -434,18 +434,7 @@ static struct i2c_driver saa7706h_driver = {
        .id_table       = saa7706h_id,
 };
 
-static __init int saa7706h_init(void)
-{
-       return i2c_add_driver(&saa7706h_driver);
-}
-
-static __exit void saa7706h_exit(void)
-{
-       i2c_del_driver(&saa7706h_driver);
-}
-
-module_init(saa7706h_init);
-module_exit(saa7706h_exit);
+module_i2c_driver(saa7706h_driver);
 
 MODULE_DESCRIPTION("SAA7706H Car Radio DSP driver");
 MODULE_AUTHOR("Mocean Laboratories");
index fd3541b..9b546a5 100644 (file)
@@ -539,33 +539,7 @@ static struct i2c_driver si470x_i2c_driver = {
        .id_table               = si470x_i2c_id,
 };
 
-
-
-/**************************************************************************
- * Module Interface
- **************************************************************************/
-
-/*
- * si470x_i2c_init - module init
- */
-static int __init si470x_i2c_init(void)
-{
-       printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
-       return i2c_add_driver(&si470x_i2c_driver);
-}
-
-
-/*
- * si470x_i2c_exit - module exit
- */
-static void __exit si470x_i2c_exit(void)
-{
-       i2c_del_driver(&si470x_i2c_driver);
-}
-
-
-module_init(si470x_i2c_init);
-module_exit(si470x_i2c_exit);
+module_i2c_driver(si470x_i2c_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR(DRIVER_AUTHOR);
index 27aba93..b898c89 100644 (file)
@@ -2106,17 +2106,4 @@ static struct i2c_driver si4713_i2c_driver = {
        .id_table       = si4713_id,
 };
 
-/* Module Interface */
-static int __init si4713_module_init(void)
-{
-       return i2c_add_driver(&si4713_i2c_driver);
-}
-
-static void __exit si4713_module_exit(void)
-{
-       i2c_del_driver(&si4713_i2c_driver);
-}
-
-module_init(si4713_module_init);
-module_exit(si4713_module_exit);
-
+module_i2c_driver(si4713_i2c_driver);
index 3408685..6418c4c 100644 (file)
@@ -215,20 +215,8 @@ static struct i2c_driver tef6862_driver = {
        .id_table       = tef6862_id,
 };
 
-static __init int tef6862_init(void)
-{
-       return i2c_add_driver(&tef6862_driver);
-}
-
-static __exit void tef6862_exit(void)
-{
-       i2c_del_driver(&tef6862_driver);
-}
-
-module_init(tef6862_init);
-module_exit(tef6862_exit);
+module_i2c_driver(tef6862_driver);
 
 MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner");
 MODULE_AUTHOR("Mocean Laboratories");
 MODULE_LICENSE("GPL v2");
-
index 4df4aff..a3fbb21 100644 (file)
@@ -266,4 +266,13 @@ config RC_LOOPBACK
           To compile this driver as a module, choose M here: the module will
           be called rc_loopback.
 
+config IR_GPIO_CIR
+       tristate "GPIO IR remote control"
+       depends on RC_CORE
+       ---help---
+          Say Y if you want to use GPIO based IR Receiver.
+
+          To compile this driver as a module, choose M here: the module will
+          be called gpio-ir-recv.
+
 endif #RC_CORE
index fb3dee2..29f364f 100644 (file)
@@ -26,3 +26,4 @@ obj-$(CONFIG_IR_REDRAT3) += redrat3.o
 obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
 obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
 obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
+obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o
index 7f7079b..392d4be 100644 (file)
@@ -117,7 +117,7 @@ static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset)
 static void cir_dump_regs(struct fintek_dev *fintek)
 {
        fintek_config_mode_enable(fintek);
-       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       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",
@@ -143,7 +143,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
        u8 chip_major, chip_minor;
        u8 vendor_major, vendor_minor;
        u8 portsel, ir_class;
-       u16 vendor;
+       u16 vendor, chip;
        int ret = 0;
 
        fintek_config_mode_enable(fintek);
@@ -176,6 +176,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
 
        chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI);
        chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO);
+       chip  = chip_major << 8 | chip_minor;
 
        vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI);
        vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO);
@@ -192,6 +193,15 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
        fintek->chip_major  = chip_major;
        fintek->chip_minor  = chip_minor;
        fintek->chip_vendor = vendor;
+
+       /*
+        * Newer reviews of this chipset uses port 8 instead of 5
+        */
+       if ((chip != 0x0408) || (chip != 0x0804))
+               fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV2;
+       else
+               fintek->logical_dev_cir = LOGICAL_DEV_CIR_REV1;
+
        spin_unlock_irqrestore(&fintek->fintek_lock, flags);
 
        return ret;
@@ -200,7 +210,7 @@ static int fintek_hw_detect(struct fintek_dev *fintek)
 static void fintek_cir_ldev_init(struct fintek_dev *fintek)
 {
        /* Select CIR logical device and enable */
-       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
        fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
 
        /* Write allocated CIR address and IRQ information to hardware */
@@ -381,7 +391,7 @@ static irqreturn_t fintek_cir_isr(int irq, void *data)
        fit_dbg_verbose("%s firing", __func__);
 
        fintek_config_mode_enable(fintek);
-       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
        fintek_config_mode_disable(fintek);
 
        /*
@@ -422,7 +432,7 @@ static void fintek_enable_cir(struct fintek_dev *fintek)
        fintek_config_mode_enable(fintek);
 
        /* enable the CIR logical device */
-       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
        fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
 
        fintek_config_mode_disable(fintek);
@@ -439,7 +449,7 @@ static void fintek_disable_cir(struct fintek_dev *fintek)
        fintek_config_mode_enable(fintek);
 
        /* disable the CIR logical device */
-       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
        fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
 
        fintek_config_mode_disable(fintek);
@@ -611,7 +621,7 @@ static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state)
        fintek_config_mode_enable(fintek);
 
        /* disable cir logical dev */
-       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
        fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
 
        fintek_config_mode_disable(fintek);
@@ -634,7 +644,7 @@ static int fintek_resume(struct pnp_dev *pdev)
 
        /* Enable CIR logical device */
        fintek_config_mode_enable(fintek);
-       fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+       fintek_select_logical_dev(fintek, fintek->logical_dev_cir);
        fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
 
        fintek_config_mode_disable(fintek);
index 1b10b20..82516a1 100644 (file)
@@ -88,6 +88,7 @@ struct fintek_dev {
        u8 chip_major;
        u8 chip_minor;
        u16 chip_vendor;
+       u8 logical_dev_cir;
 
        /* hardware features */
        bool hw_learning_capable;
@@ -172,7 +173,8 @@ struct fintek_dev {
 #define LOGICAL_DEV_ENABLE     0x01
 
 /* Logical device number of the CIR function */
-#define LOGICAL_DEV_CIR                0x05
+#define LOGICAL_DEV_CIR_REV1   0x05
+#define LOGICAL_DEV_CIR_REV2   0x08
 
 /* CIR Logical Device (LDN 0x08) config registers */
 #define CIR_CR_COMMAND_INDEX   0x04
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
new file mode 100644 (file)
index 0000000..0d87545
--- /dev/null
@@ -0,0 +1,205 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <media/rc-core.h>
+#include <media/gpio-ir-recv.h>
+
+#define GPIO_IR_DRIVER_NAME    "gpio-rc-recv"
+#define GPIO_IR_DEVICE_NAME    "gpio_ir_recv"
+
+struct gpio_rc_dev {
+       struct rc_dev *rcdev;
+       int gpio_nr;
+       bool active_low;
+};
+
+static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
+{
+       struct gpio_rc_dev *gpio_dev = dev_id;
+       int gval;
+       int rc = 0;
+       enum raw_event_type type = IR_SPACE;
+
+       gval = gpio_get_value_cansleep(gpio_dev->gpio_nr);
+
+       if (gval < 0)
+               goto err_get_value;
+
+       if (gpio_dev->active_low)
+               gval = !gval;
+
+       if (gval == 1)
+               type = IR_PULSE;
+
+       rc = ir_raw_event_store_edge(gpio_dev->rcdev, type);
+       if (rc < 0)
+               goto err_get_value;
+
+       ir_raw_event_handle(gpio_dev->rcdev);
+
+err_get_value:
+       return IRQ_HANDLED;
+}
+
+static int __devinit gpio_ir_recv_probe(struct platform_device *pdev)
+{
+       struct gpio_rc_dev *gpio_dev;
+       struct rc_dev *rcdev;
+       const struct gpio_ir_recv_platform_data *pdata =
+                                       pdev->dev.platform_data;
+       int rc;
+
+       if (!pdata)
+               return -EINVAL;
+
+       if (pdata->gpio_nr < 0)
+               return -EINVAL;
+
+       gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL);
+       if (!gpio_dev)
+               return -ENOMEM;
+
+       rcdev = rc_allocate_device();
+       if (!rcdev) {
+               rc = -ENOMEM;
+               goto err_allocate_device;
+       }
+
+       rcdev->driver_type = RC_DRIVER_IR_RAW;
+       rcdev->allowed_protos = RC_TYPE_ALL;
+       rcdev->input_name = GPIO_IR_DEVICE_NAME;
+       rcdev->input_id.bustype = BUS_HOST;
+       rcdev->driver_name = GPIO_IR_DRIVER_NAME;
+       rcdev->map_name = RC_MAP_EMPTY;
+
+       gpio_dev->rcdev = rcdev;
+       gpio_dev->gpio_nr = pdata->gpio_nr;
+       gpio_dev->active_low = pdata->active_low;
+
+       rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
+       if (rc < 0)
+               goto err_gpio_request;
+       rc  = gpio_direction_input(pdata->gpio_nr);
+       if (rc < 0)
+               goto err_gpio_direction_input;
+
+       rc = rc_register_device(rcdev);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "failed to register rc device\n");
+               goto err_register_rc_device;
+       }
+
+       platform_set_drvdata(pdev, gpio_dev);
+
+       rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr),
+                               gpio_ir_recv_irq,
+                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                                       "gpio-ir-recv-irq", gpio_dev);
+       if (rc < 0)
+               goto err_request_irq;
+
+       return 0;
+
+err_request_irq:
+       platform_set_drvdata(pdev, NULL);
+       rc_unregister_device(rcdev);
+err_register_rc_device:
+err_gpio_direction_input:
+       gpio_free(pdata->gpio_nr);
+err_gpio_request:
+       rc_free_device(rcdev);
+       rcdev = NULL;
+err_allocate_device:
+       kfree(gpio_dev);
+       return rc;
+}
+
+static int __devexit gpio_ir_recv_remove(struct platform_device *pdev)
+{
+       struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+       free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
+       platform_set_drvdata(pdev, NULL);
+       rc_unregister_device(gpio_dev->rcdev);
+       gpio_free(gpio_dev->gpio_nr);
+       rc_free_device(gpio_dev->rcdev);
+       kfree(gpio_dev);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_ir_recv_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
+       else
+               disable_irq(gpio_to_irq(gpio_dev->gpio_nr));
+
+       return 0;
+}
+
+static int gpio_ir_recv_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
+       else
+               enable_irq(gpio_to_irq(gpio_dev->gpio_nr));
+
+       return 0;
+}
+
+static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
+       .suspend        = gpio_ir_recv_suspend,
+       .resume         = gpio_ir_recv_resume,
+};
+#endif
+
+static struct platform_driver gpio_ir_recv_driver = {
+       .probe  = gpio_ir_recv_probe,
+       .remove = __devexit_p(gpio_ir_recv_remove),
+       .driver = {
+               .name   = GPIO_IR_DRIVER_NAME,
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &gpio_ir_recv_pm_ops,
+#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_DESCRIPTION("GPIO IR Receiver driver");
+MODULE_LICENSE("GPL v2");
index d5e2b50..dab98b3 100644 (file)
@@ -130,7 +130,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
                case 15:
                        device    = bitrev8((data->bits >>  0) & 0xFF);
                        subdevice = 0;
-                       function  = bitrev8((data->bits >>  7) & 0xFD);
+                       function  = bitrev8((data->bits >>  7) & 0xFE);
                        break;
                case 20:
                        device    = bitrev8((data->bits >>  5) & 0xF8);
index 36e4d5e..49ce266 100644 (file)
@@ -41,8 +41,11 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-imon-mce.o \
                        rc-imon-pad.o \
                        rc-iodata-bctv7e.o \
+                       rc-it913x-v1.o \
+                       rc-it913x-v2.o \
                        rc-kaiomy.o \
                        rc-kworld-315u.o \
+                       rc-kworld-pc150u.o \
                        rc-kworld-plus-tv-analog.o \
                        rc-leadtek-y04g0051.o \
                        rc-lirc.o \
diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c
new file mode 100644 (file)
index 0000000..0ac775f
--- /dev/null
@@ -0,0 +1,95 @@
+/* ITE Generic remotes Version 1
+ *
+ * Copyright (C) 2012 Malcolm Priestley (tvboxspy@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 <media/rc-map.h>
+#include <linux/module.h>
+
+
+static struct rc_map_table it913x_v1_rc[] = {
+       /* Type 1 */
+       { 0x61d601, KEY_VIDEO },           /* Source */
+       { 0x61d602, KEY_3 },
+       { 0x61d603, KEY_POWER },           /* ShutDown */
+       { 0x61d604, KEY_1 },
+       { 0x61d605, KEY_5 },
+       { 0x61d606, KEY_6 },
+       { 0x61d607, KEY_CHANNELDOWN },     /* CH- */
+       { 0x61d608, KEY_2 },
+       { 0x61d609, KEY_CHANNELUP },       /* CH+ */
+       { 0x61d60a, KEY_9 },
+       { 0x61d60b, KEY_ZOOM },            /* Zoom */
+       { 0x61d60c, KEY_7 },
+       { 0x61d60d, KEY_8 },
+       { 0x61d60e, KEY_VOLUMEUP },        /* Vol+ */
+       { 0x61d60f, KEY_4 },
+       { 0x61d610, KEY_ESC },             /* [back up arrow] */
+       { 0x61d611, KEY_0 },
+       { 0x61d612, KEY_OK },              /* [enter arrow] */
+       { 0x61d613, KEY_VOLUMEDOWN },      /* Vol- */
+       { 0x61d614, KEY_RECORD },          /* Rec */
+       { 0x61d615, KEY_STOP },            /* Stop */
+       { 0x61d616, KEY_PLAY },            /* Play */
+       { 0x61d617, KEY_MUTE },            /* Mute */
+       { 0x61d618, KEY_UP },
+       { 0x61d619, KEY_DOWN },
+       { 0x61d61a, KEY_LEFT },
+       { 0x61d61b, KEY_RIGHT },
+       { 0x61d61c, KEY_RED },
+       { 0x61d61d, KEY_GREEN },
+       { 0x61d61e, KEY_YELLOW },
+       { 0x61d61f, KEY_BLUE },
+       { 0x61d643, KEY_POWER2 },          /* [red power button] */
+       /* Type 2 - 20 buttons */
+       { 0x807f0d, KEY_0 },
+       { 0x807f04, KEY_1 },
+       { 0x807f05, KEY_2 },
+       { 0x807f06, KEY_3 },
+       { 0x807f07, KEY_4 },
+       { 0x807f08, KEY_5 },
+       { 0x807f09, KEY_6 },
+       { 0x807f0a, KEY_7 },
+       { 0x807f1b, KEY_8 },
+       { 0x807f1f, KEY_9 },
+       { 0x807f12, KEY_POWER },
+       { 0x807f01, KEY_MEDIA_REPEAT}, /* Recall */
+       { 0x807f19, KEY_PAUSE }, /* Timeshift */
+       { 0x807f1e, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+       { 0x807f03, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
+       { 0x807f1a, KEY_CHANNELUP },
+       { 0x807f02, KEY_CHANNELDOWN },
+       { 0x807f0c, KEY_ZOOM },
+       { 0x807f00, KEY_RECORD },
+       { 0x807f0e, KEY_STOP },
+};
+
+static struct rc_map_list it913x_v1_map = {
+       .map = {
+               .scan    = it913x_v1_rc,
+               .size    = ARRAY_SIZE(it913x_v1_rc),
+               .rc_type = RC_TYPE_NEC,
+               .name    = RC_MAP_IT913X_V1,
+       }
+};
+
+static int __init init_rc_it913x_v1_map(void)
+{
+       return rc_map_register(&it913x_v1_map);
+}
+
+static void __exit exit_rc_it913x_v1_map(void)
+{
+       rc_map_unregister(&it913x_v1_map);
+}
+
+module_init(init_rc_it913x_v1_map)
+module_exit(exit_rc_it913x_v1_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c
new file mode 100644 (file)
index 0000000..28e376e
--- /dev/null
@@ -0,0 +1,94 @@
+/* ITE Generic remotes Version 2
+ *
+ * Copyright (C) 2012 Malcolm Priestley (tvboxspy@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 <media/rc-map.h>
+#include <linux/module.h>
+
+
+static struct rc_map_table it913x_v2_rc[] = {
+       /* Type 1 */
+       /* 9005 remote */
+       { 0x807f12, KEY_POWER2 },       /* Power (RED POWER BUTTON)*/
+       { 0x807f1a, KEY_VIDEO },        /* Source */
+       { 0x807f1e, KEY_MUTE },         /* Mute */
+       { 0x807f01, KEY_RECORD },       /* Record */
+       { 0x807f02, KEY_CHANNELUP },    /* Channel+ */
+       { 0x807f03, KEY_TIME },         /* TimeShift */
+       { 0x807f04, KEY_VOLUMEUP },     /* Volume- */
+       { 0x807f05, KEY_SCREEN },       /* FullScreen */
+       { 0x807f06, KEY_VOLUMEDOWN },   /* Volume- */
+       { 0x807f07, KEY_0 },            /* 0 */
+       { 0x807f08, KEY_CHANNELDOWN },  /* Channel- */
+       { 0x807f09, KEY_PREVIOUS },     /* Recall */
+       { 0x807f0a, KEY_1 },            /* 1 */
+       { 0x807f1b, KEY_2 },            /* 2 */
+       { 0x807f1f, KEY_3 },            /* 3 */
+       { 0x807f0c, KEY_4 },            /* 4 */
+       { 0x807f0d, KEY_5 },            /* 5 */
+       { 0x807f0e, KEY_6 },            /* 6 */
+       { 0x807f00, KEY_7 },            /* 7 */
+       { 0x807f0f, KEY_8 },            /* 8 */
+       { 0x807f19, KEY_9 },            /* 9 */
+
+       /* Type 2 */
+       /* keys stereo, snapshot unassigned */
+       { 0x866b00, KEY_0 },
+       { 0x866b1b, KEY_1 },
+       { 0x866b02, KEY_2 },
+       { 0x866b03, KEY_3 },
+       { 0x866b04, KEY_4 },
+       { 0x866b05, KEY_5 },
+       { 0x866b06, KEY_6 },
+       { 0x866b07, KEY_7 },
+       { 0x866b08, KEY_8 },
+       { 0x866b09, KEY_9 },
+       { 0x866b12, KEY_POWER },
+       { 0x866b13, KEY_MUTE },
+       { 0x866b0a, KEY_PREVIOUS }, /* Recall */
+       { 0x866b1e, KEY_PAUSE },
+       { 0x866b0c, KEY_VOLUMEUP },
+       { 0x866b18, KEY_VOLUMEDOWN },
+       { 0x866b0b, KEY_CHANNELUP },
+       { 0x866b18, KEY_CHANNELDOWN },
+       { 0x866b10, KEY_ZOOM },
+       { 0x866b1d, KEY_RECORD },
+       { 0x866b0e, KEY_STOP },
+       { 0x866b11, KEY_EPG},
+       { 0x866b1a, KEY_FASTFORWARD },
+       { 0x866b0f, KEY_REWIND },
+       { 0x866b1c, KEY_TV },
+       { 0x866b1b, KEY_TEXT },
+
+};
+
+static struct rc_map_list it913x_v2_map = {
+       .map = {
+               .scan    = it913x_v2_rc,
+               .size    = ARRAY_SIZE(it913x_v2_rc),
+               .rc_type = RC_TYPE_NEC,
+               .name    = RC_MAP_IT913X_V2,
+       }
+};
+
+static int __init init_rc_it913x_v2_map(void)
+{
+       return rc_map_register(&it913x_v2_map);
+}
+
+static void __exit exit_rc_it913x_v2_map(void)
+{
+       rc_map_unregister(&it913x_v2_map);
+}
+
+module_init(init_rc_it913x_v2_map)
+module_exit(exit_rc_it913x_v2_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c
new file mode 100644 (file)
index 0000000..233bb5e
--- /dev/null
@@ -0,0 +1,102 @@
+/* kworld-pc150u.c - Keytable for kworld_pc150u Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Kyle Strickland
+ *   (based on kworld-plus-tv-analog.c by
+ *    Mauro Carvalho Chehab <mchehab@redhat.com>)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+/* Kworld PC150-U
+   Kyle Strickland <kyle@kyle.strickland.name>
+ */
+
+static struct rc_map_table kworld_pc150u[] = {
+       { 0x0c, KEY_MEDIA },            /* Kworld key */
+       { 0x16, KEY_EJECTCLOSECD },     /* -> ) */
+       { 0x1d, KEY_POWER2 },
+
+       { 0x00, KEY_1 },
+       { 0x01, KEY_2 },
+       { 0x02, KEY_3 },
+       { 0x03, KEY_4 },
+       { 0x04, KEY_5 },
+       { 0x05, KEY_6 },
+       { 0x06, KEY_7 },
+       { 0x07, KEY_8 },
+       { 0x08, KEY_9 },
+       { 0x0a, KEY_0 },
+
+       { 0x09, KEY_AGAIN },
+       { 0x14, KEY_MUTE },
+
+       { 0x1e, KEY_LAST },
+       { 0x17, KEY_ZOOM },
+       { 0x1f, KEY_HOMEPAGE },
+       { 0x0e, KEY_ESC },
+
+       { 0x20, KEY_UP },
+       { 0x21, KEY_DOWN },
+       { 0x42, KEY_LEFT },
+       { 0x43, KEY_RIGHT },
+       { 0x0b, KEY_ENTER },
+
+       { 0x10, KEY_CHANNELUP },
+       { 0x11, KEY_CHANNELDOWN },
+
+       { 0x13, KEY_VOLUMEUP },
+       { 0x12, KEY_VOLUMEDOWN },
+
+       { 0x19, KEY_TIME},              /* Timeshift */
+       { 0x1a, KEY_STOP},
+       { 0x1b, KEY_RECORD},
+       { 0x4b, KEY_EMAIL},
+
+       { 0x40, KEY_REWIND},
+       { 0x44, KEY_PLAYPAUSE},
+       { 0x41, KEY_FORWARD},
+       { 0x22, KEY_TEXT},
+
+       { 0x15, KEY_AUDIO},             /* ((*)) */
+       { 0x0f, KEY_MODE},              /* display ratio */
+       { 0x1c, KEY_SYSRQ},             /* snapshot */
+       { 0x4a, KEY_SLEEP},             /* sleep timer */
+
+       { 0x48, KEY_SOUND},             /* switch theater mode */
+       { 0x49, KEY_BLUE},              /* A */
+       { 0x18, KEY_RED},               /* B */
+       { 0x23, KEY_GREEN},             /* C */
+};
+
+static struct rc_map_list kworld_pc150u_map = {
+       .map = {
+               .scan    = kworld_pc150u,
+               .size    = ARRAY_SIZE(kworld_pc150u),
+               .rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
+               .name    = RC_MAP_KWORLD_PC150U,
+       }
+};
+
+static int __init init_rc_map_kworld_pc150u(void)
+{
+       return rc_map_register(&kworld_pc150u_map);
+}
+
+static void __exit exit_rc_map_kworld_pc150u(void)
+{
+       rc_map_unregister(&kworld_pc150u_map);
+}
+
+module_init(init_rc_map_kworld_pc150u)
+module_exit(exit_rc_map_kworld_pc150u)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kyle Strickland <kyle@kyle.strickland.name>");
index f3b86c8..8d4dae2 100644 (file)
@@ -18,6 +18,8 @@
  */
 
 static struct rc_map_table nec_terratec_cinergy_xs[] = {
+
+       /* Terratec Grey IR, with most keys in orange */
        { 0x1441, KEY_HOME},
        { 0x1401, KEY_POWER2},
 
@@ -78,6 +80,56 @@ static struct rc_map_table nec_terratec_cinergy_xs[] = {
        { 0x144e, KEY_REWIND},
        { 0x144f, KEY_FASTFORWARD},
        { 0x145c, KEY_NEXT},
+
+       /* Terratec Black IR, with most keys in black */
+       { 0x04eb01, KEY_POWER2},
+
+       { 0x04eb02, KEY_1},
+       { 0x04eb03, KEY_2},
+       { 0x04eb04, KEY_3},
+       { 0x04eb05, KEY_4},
+       { 0x04eb06, KEY_5},
+       { 0x04eb07, KEY_6},
+       { 0x04eb08, KEY_7},
+       { 0x04eb09, KEY_8},
+       { 0x04eb0a, KEY_9},
+       { 0x04eb0c, KEY_0},
+
+       { 0x04eb0b, KEY_TEXT},          /* TXT */
+       { 0x04eb0d, KEY_REFRESH},       /* Refresh */
+
+       { 0x04eb0e, KEY_HOME},
+       { 0x04eb0f, KEY_EPG},
+
+       { 0x04eb10, KEY_UP},
+       { 0x04eb11, KEY_LEFT},
+       { 0x04eb12, KEY_OK},
+       { 0x04eb13, KEY_RIGHT},
+       { 0x04eb14, KEY_DOWN},
+
+       { 0x04eb15, KEY_BACKSPACE},
+       { 0x04eb16, KEY_INFO},
+
+       { 0x04eb17, KEY_RED},
+       { 0x04eb18, KEY_GREEN},
+       { 0x04eb19, KEY_YELLOW},
+       { 0x04eb1a, KEY_BLUE},
+
+       { 0x04eb1c, KEY_VOLUMEUP},
+       { 0x04eb1e, KEY_VOLUMEDOWN},
+
+       { 0x04eb1d, KEY_MUTE},
+
+       { 0x04eb1b, KEY_CHANNELUP},
+       { 0x04eb1f, KEY_CHANNELDOWN},
+
+       { 0x04eb40, KEY_RECORD},
+       { 0x04eb4c, KEY_PLAY},
+       { 0x04eb58, KEY_PAUSE},
+
+       { 0x04eb54, KEY_REWIND},
+       { 0x04eb48, KEY_STOP},
+       { 0x04eb5c, KEY_NEXT},
 };
 
 static struct rc_map_list nec_terratec_cinergy_xs_map = {
index 21105bf..e150a2e 100644 (file)
@@ -361,6 +361,8 @@ static struct usb_device_id mceusb_dev_table[] = {
        { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) },
        /* Formosa Industrial Computing */
        { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) },
+       /* Formosa Industrial Computing */
+       { USB_DEVICE(VENDOR_FORMOSA, 0xe042) },
        /* Fintek eHome Infrared Transceiver (HP branded) */
        { USB_DEVICE(VENDOR_FINTEK, 0x5168) },
        /* Fintek eHome Infrared Transceiver */
index b72f858..96f0a8b 100644 (file)
@@ -35,7 +35,7 @@ struct ir_raw_event_ctrl {
        struct list_head                list;           /* to keep track of raw clients */
        struct task_struct              *thread;
        spinlock_t                      lock;
-       struct kfifo                    kfifo;          /* fifo for the pulse/space durations */
+       struct kfifo_rec_ptr_1          kfifo;          /* fifo for the pulse/space durations */
        ktime_t                         last_event;     /* when last event occurred */
        enum raw_event_type             last_type;      /* last event type */
        struct rc_dev                   *dev;           /* pointer to the parent rc_dev */
index f6a930b..6e16b09 100644 (file)
@@ -1029,6 +1029,7 @@ EXPORT_SYMBOL_GPL(rc_free_device);
 
 int rc_register_device(struct rc_dev *dev)
 {
+       static bool raw_init = false; /* raw decoders loaded? */
        static atomic_t devno = ATOMIC_INIT(0);
        struct rc_map *rc_map;
        const char *path;
@@ -1103,6 +1104,12 @@ int rc_register_device(struct rc_dev *dev)
        kfree(path);
 
        if (dev->driver_type == RC_DRIVER_IR_RAW) {
+               /* Load raw decoders, if they aren't already */
+               if (!raw_init) {
+                       IR_dprintk(1, "Loading raw decoders\n");
+                       ir_raw_init();
+                       raw_init = true;
+               }
                rc = ir_raw_event_register(dev);
                if (rc < 0)
                        goto out_input;
@@ -1176,8 +1183,6 @@ static int __init rc_core_init(void)
                return rc;
        }
 
-       /* Initialize/load the decoders/keymap code that will be used */
-       ir_raw_init();
        rc_map_register(&empty_map);
 
        return 0;
index 9adada0..f2479c5 100644 (file)
@@ -273,6 +273,16 @@ config VIDEO_ADV7180
          To compile this driver as a module, choose M here: the
          module will be called adv7180.
 
+config VIDEO_ADV7183
+       tristate "Analog Devices ADV7183 decoder"
+       depends on VIDEO_V4L2 && I2C
+       ---help---
+         V4l2 subdevice driver for the Analog Devices
+         ADV7183 video decoder.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adv7183.
+
 config VIDEO_BT819
        tristate "BT819A VideoStream decoder"
        depends on VIDEO_V4L2 && I2C
@@ -459,6 +469,9 @@ config VIDEO_AK881X
 
 comment "Camera sensor devices"
 
+config VIDEO_APTINA_PLL
+       tristate
+
 config VIDEO_OV7670
        tristate "OmniVision OV7670 sensor support"
        depends on I2C && VIDEO_V4L2
@@ -467,9 +480,28 @@ config VIDEO_OV7670
          OV7670 VGA camera.  It currently only works with the M88ALP01
          controller.
 
+config VIDEO_VS6624
+       tristate "ST VS6624 sensor support"
+       depends on VIDEO_V4L2 && I2C
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the ST VS6624
+         camera.
+
+         To compile this driver as a module, choose M here: the
+         module will be called vs6624.
+
+config VIDEO_MT9M032
+       tristate "MT9M032 camera sensor support"
+       depends on I2C && VIDEO_V4L2
+       select VIDEO_APTINA_PLL
+       ---help---
+         This driver supports MT9M032 camera sensors from Aptina, monochrome
+         models only.
+
 config VIDEO_MT9P031
        tristate "Aptina MT9P031 support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       select VIDEO_APTINA_PLL
        ---help---
          This is a Video4Linux2 sensor-level driver for the Aptina
          (Micron) mt9p031 5 Mpixel camera.
@@ -851,6 +883,8 @@ source "drivers/media/video/davinci/Kconfig"
 
 source "drivers/media/video/omap/Kconfig"
 
+source "drivers/media/video/blackfin/Kconfig"
+
 config VIDEO_SH_VOU
        tristate "SuperH VOU video output driver"
        depends on VIDEO_DEV && ARCH_SHMOBILE
@@ -1087,7 +1121,7 @@ config VIDEO_MX2_HOSTSUPPORT
 config VIDEO_MX2
        tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
        depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25)
-       select VIDEOBUF_DMA_CONTIG
+       select VIDEOBUF2_DMA_CONTIG
        select VIDEO_MX2_HOSTSUPPORT
        ---help---
          This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
@@ -1116,7 +1150,8 @@ config VIDEO_ATMEL_ISI
 
 config VIDEO_S5P_MIPI_CSIS
        tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
-       depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API
+       depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P
+       depends on VIDEO_V4L2_SUBDEV_API && REGULATOR
        ---help---
          This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
 
@@ -1176,4 +1211,14 @@ config VIDEO_SAMSUNG_S5P_MFC
        help
            MFC 5.1 driver for V4L2.
 
+config VIDEO_MX2_EMMAPRP
+       tristate "MX2 eMMa-PrP support"
+       depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       help
+           MX2X chips have a PrP that can be used to process buffers from
+           memory to memory. Operations include resizing and format
+           conversion.
+
 endif # V4L_MEM2MEM_DRIVERS
index 3541388..a6282a3 100644 (file)
@@ -12,16 +12,19 @@ omap2cam-objs       :=      omap24xxcam.o omap24xxcam-dma.o
 
 videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
                        v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
+ifeq ($(CONFIG_COMPAT),y)
+  videodev-objs += v4l2-compat-ioctl32.o
+endif
 
 # V4L2 core modules
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
-ifeq ($(CONFIG_COMPAT),y)
-  obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
-endif
-
 obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
 
+# Helper modules
+
+obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o
+
 # All i2c modules must come first:
 
 obj-$(CONFIG_VIDEO_TUNER) += tuner.o
@@ -40,8 +43,10 @@ obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
 obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
 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_VPX3220) += vpx3220.o
+obj-$(CONFIG_VIDEO_VS6624)  += vs6624.o
 obj-$(CONFIG_VIDEO_BT819) += bt819.o
 obj-$(CONFIG_VIDEO_BT856) += bt856.o
 obj-$(CONFIG_VIDEO_BT866) += bt866.o
@@ -65,6 +70,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
 obj-$(CONFIG_VIDEO_OV7670)     += ov7670.o
 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
+obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
 obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
 obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
 obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
@@ -177,6 +183,8 @@ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)   += sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_OMAP1)              += omap1_camera.o
 obj-$(CONFIG_VIDEO_ATMEL_ISI)          += atmel-isi.o
 
+obj-$(CONFIG_VIDEO_MX2_EMMAPRP)                += mx2_emmaprp.o
+
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC)   += s5p-fimc/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG)   += s5p-jpeg/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC)    += s5p-mfc/
@@ -184,6 +192,8 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV)  += s5p-tv/
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D)    += s5p-g2d/
 
+obj-$(CONFIG_BLACKFIN)                  += blackfin/
+
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci/
 
 obj-$(CONFIG_VIDEO_SH_VOU)             += sh_vou.o
@@ -199,6 +209,6 @@ obj-y       += davinci/
 
 obj-$(CONFIG_ARCH_OMAP)        += omap/
 
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
-ccflags-y += -Idrivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
index 12eedf4..5b045b4 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/version.h>
 #include <media/adp1653.h>
@@ -482,24 +481,7 @@ static struct i2c_driver adp1653_i2c_driver = {
        .id_table       = adp1653_id_table,
 };
 
-static int __init adp1653_init(void)
-{
-       int rval;
-
-       rval = i2c_add_driver(&adp1653_i2c_driver);
-       if (rval)
-               printk(KERN_ALERT "%s: failed at i2c_add_driver\n", __func__);
-
-       return rval;
-}
-
-static void __exit adp1653_exit(void)
-{
-       i2c_del_driver(&adp1653_i2c_driver);
-}
-
-module_init(adp1653_init);
-module_exit(adp1653_exit);
+module_i2c_driver(adp1653_i2c_driver);
 
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
 MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver");
index 879f1d8..6bc01fb 100644 (file)
@@ -407,15 +407,4 @@ static struct i2c_driver adv7170_driver = {
        .id_table       = adv7170_id,
 };
 
-static __init int init_adv7170(void)
-{
-       return i2c_add_driver(&adv7170_driver);
-}
-
-static __exit void exit_adv7170(void)
-{
-       i2c_del_driver(&adv7170_driver);
-}
-
-module_init(init_adv7170);
-module_exit(exit_adv7170);
+module_i2c_driver(adv7170_driver);
index 206078e..c7640fa 100644 (file)
@@ -457,15 +457,4 @@ static struct i2c_driver adv7175_driver = {
        .id_table       = adv7175_id,
 };
 
-static __init int init_adv7175(void)
-{
-       return i2c_add_driver(&adv7175_driver);
-}
-
-static __exit void exit_adv7175(void)
-{
-       i2c_del_driver(&adv7175_driver);
-}
-
-module_init(init_adv7175);
-module_exit(exit_adv7175);
+module_i2c_driver(adv7175_driver);
index d2138d0..b8b6c4b 100644 (file)
@@ -444,20 +444,8 @@ static struct i2c_driver adv7180_driver = {
        .id_table       = adv7180_id,
 };
 
-static __init int adv7180_init(void)
-{
-       return i2c_add_driver(&adv7180_driver);
-}
-
-static __exit void adv7180_exit(void)
-{
-       i2c_del_driver(&adv7180_driver);
-}
-
-module_init(adv7180_init);
-module_exit(adv7180_exit);
+module_i2c_driver(adv7180_driver);
 
 MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
 MODULE_AUTHOR("Mocean Laboratories");
 MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/media/video/adv7183.c b/drivers/media/video/adv7183.c
new file mode 100644 (file)
index 0000000..e1d4c89
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+ * adv7183.c Analog Devices ADV7183 video decoder driver
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/adv7183.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#include "adv7183_regs.h"
+
+struct adv7183 {
+       struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
+
+       v4l2_std_id std; /* Current set standard */
+       u32 input;
+       u32 output;
+       unsigned reset_pin;
+       unsigned oe_pin;
+       struct v4l2_mbus_framefmt fmt;
+};
+
+/* EXAMPLES USING 27 MHz CLOCK
+ * Mode 1 CVBS Input (Composite Video on AIN5)
+ * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8.
+ */
+static const unsigned char adv7183_init_regs[] = {
+       ADV7183_IN_CTRL, 0x04,           /* CVBS input on AIN5 */
+       ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */
+       ADV7183_SHAP_FILT_CTRL, 0x41,    /* Set CSFM to SH1 */
+       ADV7183_ADC_CTRL, 0x16,          /* Power down ADC 1 and ADC 2 */
+       ADV7183_CTI_DNR_CTRL_4, 0x04,    /* Set DNR threshold to 4 for flat response */
+       /* ADI recommended programming sequence */
+       ADV7183_ADI_CTRL, 0x80,
+       ADV7183_CTI_DNR_CTRL_4, 0x20,
+       0x52, 0x18,
+       0x58, 0xED,
+       0x77, 0xC5,
+       0x7C, 0x93,
+       0x7D, 0x00,
+       0xD0, 0x48,
+       0xD5, 0xA0,
+       0xD7, 0xEA,
+       ADV7183_SD_SATURATION_CR, 0x3E,
+       ADV7183_PAL_V_END, 0x3E,
+       ADV7183_PAL_F_TOGGLE, 0x0F,
+       ADV7183_ADI_CTRL, 0x00,
+};
+
+static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct adv7183, sd);
+}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct adv7183, hdl)->sd;
+}
+
+static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg,
+                               unsigned char value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int adv7183_writeregs(struct v4l2_subdev *sd,
+               const unsigned char *regs, unsigned int num)
+{
+       unsigned char reg, data;
+       unsigned int cnt = 0;
+
+       if (num & 0x1) {
+               v4l2_err(sd, "invalid regs array\n");
+               return -1;
+       }
+
+       while (cnt < num) {
+               reg = *regs++;
+               data = *regs++;
+               cnt += 2;
+
+               adv7183_write(sd, reg, data);
+       }
+       return 0;
+}
+
+static int adv7183_log_status(struct v4l2_subdev *sd)
+{
+       struct adv7183 *decoder = to_adv7183(sd);
+
+       v4l2_info(sd, "adv7183: Input control = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_IN_CTRL));
+       v4l2_info(sd, "adv7183: Video selection = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_VD_SEL));
+       v4l2_info(sd, "adv7183: Output control = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_OUT_CTRL));
+       v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_EXT_OUT_CTRL));
+       v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_AUTO_DET_EN));
+       v4l2_info(sd, "adv7183: Contrast = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_CONTRAST));
+       v4l2_info(sd, "adv7183: Brightness = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_BRIGHTNESS));
+       v4l2_info(sd, "adv7183: Hue = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_HUE));
+       v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_DEF_Y));
+       v4l2_info(sd, "adv7183: Default value C = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_DEF_C));
+       v4l2_info(sd, "adv7183: ADI control = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_ADI_CTRL));
+       v4l2_info(sd, "adv7183: Power Management = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_POW_MANAGE));
+       v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+                       adv7183_read(sd, ADV7183_STATUS_1),
+                       adv7183_read(sd, ADV7183_STATUS_2),
+                       adv7183_read(sd, ADV7183_STATUS_3));
+       v4l2_info(sd, "adv7183: Ident = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_IDENT));
+       v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL));
+       v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1));
+       v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n",
+                       adv7183_read(sd, ADV7183_SHAP_FILT_CTRL),
+                       adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2));
+       v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_COMB_FILT_CTRL));
+       v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_ADI_CTRL_2));
+       v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_PIX_DELAY_CTRL));
+       v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_MISC_GAIN_CTRL));
+       v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_AGC_MODE_CTRL));
+       v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n",
+                       adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1),
+                       adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2));
+       v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n",
+                       adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1),
+                       adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2));
+       v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+                       adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1),
+                       adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2),
+                       adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3));
+       v4l2_info(sd, "adv7183: Hsync positon control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
+                       adv7183_read(sd, ADV7183_HS_POS_CTRL_1),
+                       adv7183_read(sd, ADV7183_HS_POS_CTRL_2),
+                       adv7183_read(sd, ADV7183_HS_POS_CTRL_3));
+       v4l2_info(sd, "adv7183: Polarity = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_POLARITY));
+       v4l2_info(sd, "adv7183: ADC control = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_ADC_CTRL));
+       v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n",
+                       adv7183_read(sd, ADV7183_SD_OFFSET_CB),
+                       adv7183_read(sd, ADV7183_SD_OFFSET_CR));
+       v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n",
+                       adv7183_read(sd, ADV7183_SD_SATURATION_CB),
+                       adv7183_read(sd, ADV7183_SD_SATURATION_CR));
+       v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n",
+                       adv7183_read(sd, ADV7183_DRIVE_STR));
+       v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name);
+       return 0;
+}
+
+static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       struct adv7183 *decoder = to_adv7183(sd);
+
+       *std = decoder->std;
+       return 0;
+}
+
+static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct adv7183 *decoder = to_adv7183(sd);
+       int reg;
+
+       reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
+       if (std == V4L2_STD_PAL_60)
+               reg |= 0x60;
+       else if (std == V4L2_STD_NTSC_443)
+               reg |= 0x70;
+       else if (std == V4L2_STD_PAL_N)
+               reg |= 0x90;
+       else if (std == V4L2_STD_PAL_M)
+               reg |= 0xA0;
+       else if (std == V4L2_STD_PAL_Nc)
+               reg |= 0xC0;
+       else if (std & V4L2_STD_PAL)
+               reg |= 0x80;
+       else if (std & V4L2_STD_NTSC)
+               reg |= 0x50;
+       else if (std & V4L2_STD_SECAM)
+               reg |= 0xE0;
+       else
+               return -EINVAL;
+       adv7183_write(sd, ADV7183_IN_CTRL, reg);
+
+       decoder->std = std;
+
+       return 0;
+}
+
+static int adv7183_reset(struct v4l2_subdev *sd, u32 val)
+{
+       int reg;
+
+       reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80;
+       adv7183_write(sd, ADV7183_POW_MANAGE, reg);
+       /* wait 5ms before any further i2c writes are performed */
+       usleep_range(5000, 10000);
+       return 0;
+}
+
+static int adv7183_s_routing(struct v4l2_subdev *sd,
+                               u32 input, u32 output, u32 config)
+{
+       struct adv7183 *decoder = to_adv7183(sd);
+       int reg;
+
+       if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT))
+               return -EINVAL;
+
+       if (input != decoder->input) {
+               decoder->input = input;
+               reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0;
+               switch (input) {
+               case ADV7183_COMPOSITE1:
+                       reg |= 0x1;
+                       break;
+               case ADV7183_COMPOSITE2:
+                       reg |= 0x2;
+                       break;
+               case ADV7183_COMPOSITE3:
+                       reg |= 0x3;
+                       break;
+               case ADV7183_COMPOSITE4:
+                       reg |= 0x4;
+                       break;
+               case ADV7183_COMPOSITE5:
+                       reg |= 0x5;
+                       break;
+               case ADV7183_COMPOSITE6:
+                       reg |= 0xB;
+                       break;
+               case ADV7183_COMPOSITE7:
+                       reg |= 0xC;
+                       break;
+               case ADV7183_COMPOSITE8:
+                       reg |= 0xD;
+                       break;
+               case ADV7183_COMPOSITE9:
+                       reg |= 0xE;
+                       break;
+               case ADV7183_COMPOSITE10:
+                       reg |= 0xF;
+                       break;
+               case ADV7183_SVIDEO0:
+                       reg |= 0x6;
+                       break;
+               case ADV7183_SVIDEO1:
+                       reg |= 0x7;
+                       break;
+               case ADV7183_SVIDEO2:
+                       reg |= 0x8;
+                       break;
+               case ADV7183_COMPONENT0:
+                       reg |= 0x9;
+                       break;
+               case ADV7183_COMPONENT1:
+                       reg |= 0xA;
+                       break;
+               default:
+                       break;
+               }
+               adv7183_write(sd, ADV7183_IN_CTRL, reg);
+       }
+
+       if (output != decoder->output) {
+               decoder->output = output;
+               reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0;
+               switch (output) {
+               case ADV7183_16BIT_OUT:
+                       reg |= 0x9;
+                       break;
+               default:
+                       reg |= 0xC;
+                       break;
+               }
+               adv7183_write(sd, ADV7183_OUT_CTRL, reg);
+       }
+
+       return 0;
+}
+
+static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_subdev *sd = to_sd(ctrl);
+       int val = ctrl->val;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if (val < 0)
+                       val = 127 - val;
+               adv7183_write(sd, ADV7183_BRIGHTNESS, val);
+               break;
+       case V4L2_CID_CONTRAST:
+               adv7183_write(sd, ADV7183_CONTRAST, val);
+               break;
+       case V4L2_CID_SATURATION:
+               adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8);
+               adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF));
+               break;
+       case V4L2_CID_HUE:
+               adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8);
+               adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       struct adv7183 *decoder = to_adv7183(sd);
+       int reg;
+
+       /* enable autodetection block */
+       reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
+       adv7183_write(sd, ADV7183_IN_CTRL, reg);
+
+       /* wait autodetection switch */
+       mdelay(10);
+
+       /* get autodetection result */
+       reg = adv7183_read(sd, ADV7183_STATUS_1);
+       switch ((reg >> 0x4) & 0x7) {
+       case 0:
+               *std = V4L2_STD_NTSC;
+               break;
+       case 1:
+               *std = V4L2_STD_NTSC_443;
+               break;
+       case 2:
+               *std = V4L2_STD_PAL_M;
+               break;
+       case 3:
+               *std = V4L2_STD_PAL_60;
+               break;
+       case 4:
+               *std = V4L2_STD_PAL;
+               break;
+       case 5:
+               *std = V4L2_STD_SECAM;
+               break;
+       case 6:
+               *std = V4L2_STD_PAL_Nc;
+               break;
+       case 7:
+               *std = V4L2_STD_SECAM;
+               break;
+       default:
+               *std = V4L2_STD_UNKNOWN;
+               break;
+       }
+
+       /* after std detection, write back user set std */
+       adv7183_s_std(sd, decoder->std);
+       return 0;
+}
+
+static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+       int reg;
+
+       *status = V4L2_IN_ST_NO_SIGNAL;
+       reg = adv7183_read(sd, ADV7183_STATUS_1);
+       if (reg < 0)
+               return reg;
+       if (reg & 0x1)
+               *status = 0;
+       return 0;
+}
+
+static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+                               enum v4l2_mbus_pixelcode *code)
+{
+       if (index > 0)
+               return -EINVAL;
+
+       *code = V4L2_MBUS_FMT_UYVY8_2X8;
+       return 0;
+}
+
+static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_framefmt *fmt)
+{
+       struct adv7183 *decoder = to_adv7183(sd);
+
+       fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+       fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       if (decoder->std & V4L2_STD_525_60) {
+               fmt->field = V4L2_FIELD_SEQ_TB;
+               fmt->width = 720;
+               fmt->height = 480;
+       } else {
+               fmt->field = V4L2_FIELD_SEQ_BT;
+               fmt->width = 720;
+               fmt->height = 576;
+       }
+       return 0;
+}
+
+static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_framefmt *fmt)
+{
+       struct adv7183 *decoder = to_adv7183(sd);
+
+       adv7183_try_mbus_fmt(sd, fmt);
+       decoder->fmt = *fmt;
+       return 0;
+}
+
+static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_framefmt *fmt)
+{
+       struct adv7183 *decoder = to_adv7183(sd);
+
+       *fmt = decoder->fmt;
+       return 0;
+}
+
+static int adv7183_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct adv7183 *decoder = to_adv7183(sd);
+
+       if (enable)
+               gpio_direction_output(decoder->oe_pin, 0);
+       else
+               gpio_direction_output(decoder->oe_pin, 1);
+       udelay(1);
+       return 0;
+}
+
+static int adv7183_g_chip_ident(struct v4l2_subdev *sd,
+               struct v4l2_dbg_chip_ident *chip)
+{
+       int rev;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       /* 0x11 for adv7183, 0x13 for adv7183b */
+       rev = adv7183_read(sd, ADV7183_IDENT);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7183, rev);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       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 = adv7183_read(sd, reg->reg & 0xff);
+       reg->size = 1;
+       return 0;
+}
+
+static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       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;
+       adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff);
+       return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops adv7183_ctrl_ops = {
+       .s_ctrl = adv7183_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops adv7183_core_ops = {
+       .log_status = adv7183_log_status,
+       .g_std = adv7183_g_std,
+       .s_std = adv7183_s_std,
+       .reset = adv7183_reset,
+       .g_chip_ident = adv7183_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = adv7183_g_register,
+       .s_register = adv7183_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops adv7183_video_ops = {
+       .s_routing = adv7183_s_routing,
+       .querystd = adv7183_querystd,
+       .g_input_status = adv7183_g_input_status,
+       .enum_mbus_fmt = adv7183_enum_mbus_fmt,
+       .try_mbus_fmt = adv7183_try_mbus_fmt,
+       .s_mbus_fmt = adv7183_s_mbus_fmt,
+       .g_mbus_fmt = adv7183_g_mbus_fmt,
+       .s_stream = adv7183_s_stream,
+};
+
+static const struct v4l2_subdev_ops adv7183_ops = {
+       .core = &adv7183_core_ops,
+       .video = &adv7183_video_ops,
+};
+
+static int adv7183_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct adv7183 *decoder;
+       struct v4l2_subdev *sd;
+       struct v4l2_ctrl_handler *hdl;
+       int ret;
+       struct v4l2_mbus_framefmt fmt;
+       const unsigned *pin_array;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
+
+       v4l_info(client, "chip found @ 0x%02x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       pin_array = client->dev.platform_data;
+       if (pin_array == NULL)
+               return -EINVAL;
+
+       decoder = kzalloc(sizeof(struct adv7183), GFP_KERNEL);
+       if (decoder == NULL)
+               return -ENOMEM;
+
+       decoder->reset_pin = pin_array[0];
+       decoder->oe_pin = pin_array[1];
+
+       if (gpio_request(decoder->reset_pin, "ADV7183 Reset")) {
+               v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin);
+               ret = -EBUSY;
+               goto err_free_decoder;
+       }
+
+       if (gpio_request(decoder->oe_pin, "ADV7183 Output Enable")) {
+               v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin);
+               ret = -EBUSY;
+               goto err_free_reset;
+       }
+
+       sd = &decoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &adv7183_ops);
+
+       hdl = &decoder->hdl;
+       v4l2_ctrl_handler_init(hdl, 4);
+       v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+       v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80);
+       v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080);
+       v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
+                       V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080);
+       /* hook the control handler into the driver */
+       sd->ctrl_handler = hdl;
+       if (hdl->error) {
+               ret = hdl->error;
+
+               v4l2_ctrl_handler_free(hdl);
+               goto err_free_oe;
+       }
+
+       /* v4l2 doesn't support an autodetect standard, pick PAL as default */
+       decoder->std = V4L2_STD_PAL;
+       decoder->input = ADV7183_COMPOSITE4;
+       decoder->output = ADV7183_8BIT_OUT;
+
+       gpio_direction_output(decoder->oe_pin, 1);
+       /* reset chip */
+       gpio_direction_output(decoder->reset_pin, 0);
+       /* reset pulse width at least 5ms */
+       mdelay(10);
+       gpio_direction_output(decoder->reset_pin, 1);
+       /* wait 5ms before any further i2c writes are performed */
+       mdelay(5);
+
+       adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs));
+       adv7183_s_std(sd, decoder->std);
+       fmt.width = 720;
+       fmt.height = 576;
+       adv7183_s_mbus_fmt(sd, &fmt);
+
+       /* initialize the hardware to the default control values */
+       ret = v4l2_ctrl_handler_setup(hdl);
+       if (ret) {
+               v4l2_ctrl_handler_free(hdl);
+               goto err_free_oe;
+       }
+
+       return 0;
+err_free_oe:
+       gpio_free(decoder->oe_pin);
+err_free_reset:
+       gpio_free(decoder->reset_pin);
+err_free_decoder:
+       kfree(decoder);
+       return ret;
+}
+
+static int adv7183_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct adv7183 *decoder = to_adv7183(sd);
+
+       v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(sd->ctrl_handler);
+       gpio_free(decoder->oe_pin);
+       gpio_free(decoder->reset_pin);
+       kfree(decoder);
+       return 0;
+}
+
+static const struct i2c_device_id adv7183_id[] = {
+       {"adv7183", 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7183_id);
+
+static struct i2c_driver adv7183_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "adv7183",
+       },
+       .probe          = adv7183_probe,
+       .remove         = __devexit_p(adv7183_remove),
+       .id_table       = adv7183_id,
+};
+
+static __init int adv7183_init(void)
+{
+       return i2c_add_driver(&adv7183_driver);
+}
+
+static __exit void adv7183_exit(void)
+{
+       i2c_del_driver(&adv7183_driver);
+}
+
+module_init(adv7183_init);
+module_exit(adv7183_exit);
+
+MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/adv7183_regs.h b/drivers/media/video/adv7183_regs.h
new file mode 100644 (file)
index 0000000..4a5b7d2
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * adv7183 - Analog Devices ADV7183 video decoder registers
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ADV7183_REGS_H_
+#define _ADV7183_REGS_H_
+
+#define ADV7183_IN_CTRL            0x00 /* Input control */
+#define ADV7183_VD_SEL             0x01 /* Video selection */
+#define ADV7183_OUT_CTRL           0x03 /* Output control */
+#define ADV7183_EXT_OUT_CTRL       0x04 /* Extended output control */
+#define ADV7183_AUTO_DET_EN        0x07 /* Autodetect enable */
+#define ADV7183_CONTRAST           0x08 /* Contrast */
+#define ADV7183_BRIGHTNESS         0x0A /* Brightness */
+#define ADV7183_HUE                0x0B /* Hue */
+#define ADV7183_DEF_Y              0x0C /* Default value Y */
+#define ADV7183_DEF_C              0x0D /* Default value C */
+#define ADV7183_ADI_CTRL           0x0E /* ADI control */
+#define ADV7183_POW_MANAGE         0x0F /* Power Management */
+#define ADV7183_STATUS_1           0x10 /* Status 1 */
+#define ADV7183_IDENT              0x11 /* Ident */
+#define ADV7183_STATUS_2           0x12 /* Status 2 */
+#define ADV7183_STATUS_3           0x13 /* Status 3 */
+#define ADV7183_ANAL_CLAMP_CTRL    0x14 /* Analog clamp control */
+#define ADV7183_DIGI_CLAMP_CTRL_1  0x15 /* Digital clamp control 1 */
+#define ADV7183_SHAP_FILT_CTRL     0x17 /* Shaping filter control */
+#define ADV7183_SHAP_FILT_CTRL_2   0x18 /* Shaping filter control 2 */
+#define ADV7183_COMB_FILT_CTRL     0x19 /* Comb filter control */
+#define ADV7183_ADI_CTRL_2         0x1D /* ADI control 2 */
+#define ADV7183_PIX_DELAY_CTRL     0x27 /* Pixel delay control */
+#define ADV7183_MISC_GAIN_CTRL     0x2B /* Misc gain control */
+#define ADV7183_AGC_MODE_CTRL      0x2C /* AGC mode control */
+#define ADV7183_CHRO_GAIN_CTRL_1   0x2D /* Chroma gain control 1 */
+#define ADV7183_CHRO_GAIN_CTRL_2   0x2E /* Chroma gain control 2 */
+#define ADV7183_LUMA_GAIN_CTRL_1   0x2F /* Luma gain control 1 */
+#define ADV7183_LUMA_GAIN_CTRL_2   0x30 /* Luma gain control 2 */
+#define ADV7183_VS_FIELD_CTRL_1    0x31 /* Vsync field control 1 */
+#define ADV7183_VS_FIELD_CTRL_2    0x32 /* Vsync field control 2 */
+#define ADV7183_VS_FIELD_CTRL_3    0x33 /* Vsync field control 3 */
+#define ADV7183_HS_POS_CTRL_1      0x34 /* Hsync positon control 1 */
+#define ADV7183_HS_POS_CTRL_2      0x35 /* Hsync positon control 2 */
+#define ADV7183_HS_POS_CTRL_3      0x36 /* Hsync positon control 3 */
+#define ADV7183_POLARITY           0x37 /* Polarity */
+#define ADV7183_NTSC_COMB_CTRL     0x38 /* NTSC comb control */
+#define ADV7183_PAL_COMB_CTRL      0x39 /* PAL comb control */
+#define ADV7183_ADC_CTRL           0x3A /* ADC control */
+#define ADV7183_MAN_WIN_CTRL       0x3D /* Manual window control */
+#define ADV7183_RESAMPLE_CTRL      0x41 /* Resample control */
+#define ADV7183_GEMSTAR_CTRL_1     0x48 /* Gemstar ctrl 1 */
+#define ADV7183_GEMSTAR_CTRL_2     0x49 /* Gemstar ctrl 2 */
+#define ADV7183_GEMSTAR_CTRL_3     0x4A /* Gemstar ctrl 3 */
+#define ADV7183_GEMSTAR_CTRL_4     0x4B /* Gemstar ctrl 4 */
+#define ADV7183_GEMSTAR_CTRL_5     0x4C /* Gemstar ctrl 5 */
+#define ADV7183_CTI_DNR_CTRL_1     0x4D /* CTI DNR ctrl 1 */
+#define ADV7183_CTI_DNR_CTRL_2     0x4E /* CTI DNR ctrl 2 */
+#define ADV7183_CTI_DNR_CTRL_4     0x50 /* CTI DNR ctrl 4 */
+#define ADV7183_LOCK_CNT           0x51 /* Lock count */
+#define ADV7183_FREE_LINE_LEN      0x8F /* Free-Run line length 1 */
+#define ADV7183_VBI_INFO           0x90 /* VBI info */
+#define ADV7183_WSS_1              0x91 /* WSS 1 */
+#define ADV7183_WSS_2              0x92 /* WSS 2 */
+#define ADV7183_EDTV_1             0x93 /* EDTV 1 */
+#define ADV7183_EDTV_2             0x94 /* EDTV 2 */
+#define ADV7183_EDTV_3             0x95 /* EDTV 3 */
+#define ADV7183_CGMS_1             0x96 /* CGMS 1 */
+#define ADV7183_CGMS_2             0x97 /* CGMS 2 */
+#define ADV7183_CGMS_3             0x98 /* CGMS 3 */
+#define ADV7183_CCAP_1             0x99 /* CCAP 1 */
+#define ADV7183_CCAP_2             0x9A /* CCAP 2 */
+#define ADV7183_LETTERBOX_1        0x9B /* Letterbox 1 */
+#define ADV7183_LETTERBOX_2        0x9C /* Letterbox 2 */
+#define ADV7183_LETTERBOX_3        0x9D /* Letterbox 3 */
+#define ADV7183_CRC_EN             0xB2 /* CRC enable */
+#define ADV7183_ADC_SWITCH_1       0xC3 /* ADC switch 1 */
+#define ADV7183_ADC_SWITCH_2       0xC4 /* ADC swithc 2 */
+#define ADV7183_LETTERBOX_CTRL_1   0xDC /* Letterbox control 1 */
+#define ADV7183_LETTERBOX_CTRL_2   0xDD /* Letterbox control 2 */
+#define ADV7183_SD_OFFSET_CB       0xE1 /* SD offset Cb */
+#define ADV7183_SD_OFFSET_CR       0xE2 /* SD offset Cr */
+#define ADV7183_SD_SATURATION_CB   0xE3 /* SD saturation Cb */
+#define ADV7183_SD_SATURATION_CR   0xE4 /* SD saturation Cr */
+#define ADV7183_NTSC_V_BEGIN       0xE5 /* NTSC V bit begin */
+#define ADV7183_NTSC_V_END         0xE6 /* NTSC V bit end */
+#define ADV7183_NTSC_F_TOGGLE      0xE7 /* NTSC F bit toggle */
+#define ADV7183_PAL_V_BEGIN        0xE8 /* PAL V bit begin */
+#define ADV7183_PAL_V_END          0xE9 /* PAL V bit end */
+#define ADV7183_PAL_F_TOGGLE       0xEA /* PAL F bit toggle */
+#define ADV7183_DRIVE_STR          0xF4 /* Drive strength */
+#define ADV7183_IF_COMP_CTRL       0xF8 /* IF comp control */
+#define ADV7183_VS_MODE_CTRL       0xF9 /* VS mode control */
+
+#endif
index 021fab2..119b604 100644 (file)
@@ -475,15 +475,4 @@ static struct i2c_driver adv7343_driver = {
        .id_table       = adv7343_id,
 };
 
-static __init int init_adv7343(void)
-{
-       return i2c_add_driver(&adv7343_driver);
-}
-
-static __exit void exit_adv7343(void)
-{
-       i2c_del_driver(&adv7343_driver);
-}
-
-module_init(init_adv7343);
-module_exit(exit_adv7343);
+module_i2c_driver(adv7343_driver);
index 53c496c..ba67465 100644 (file)
@@ -352,18 +352,7 @@ static struct i2c_driver ak881x_i2c_driver = {
        .id_table       = ak881x_id,
 };
 
-static int __init ak881x_module_init(void)
-{
-       return i2c_add_driver(&ak881x_i2c_driver);
-}
-
-static void __exit ak881x_module_exit(void)
-{
-       i2c_del_driver(&ak881x_i2c_driver);
-}
-
-module_init(ak881x_module_init);
-module_exit(ak881x_module_exit);
+module_i2c_driver(ak881x_i2c_driver);
 
 MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/media/video/aptina-pll.c b/drivers/media/video/aptina-pll.c
new file mode 100644 (file)
index 0000000..0bd3813
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Aptina Sensor PLL Configuration
+ *
+ * Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/gcd.h>
+#include <linux/kernel.h>
+#include <linux/lcm.h>
+#include <linux/module.h>
+
+#include "aptina-pll.h"
+
+int aptina_pll_calculate(struct device *dev,
+                        const struct aptina_pll_limits *limits,
+                        struct aptina_pll *pll)
+{
+       unsigned int mf_min;
+       unsigned int mf_max;
+       unsigned int p1_min;
+       unsigned int p1_max;
+       unsigned int p1;
+       unsigned int div;
+
+       dev_dbg(dev, "PLL: ext clock %u pix clock %u\n",
+               pll->ext_clock, pll->pix_clock);
+
+       if (pll->ext_clock < limits->ext_clock_min ||
+           pll->ext_clock > limits->ext_clock_max) {
+               dev_err(dev, "pll: invalid external clock frequency.\n");
+               return -EINVAL;
+       }
+
+       if (pll->pix_clock == 0 || pll->pix_clock > limits->pix_clock_max) {
+               dev_err(dev, "pll: invalid pixel clock frequency.\n");
+               return -EINVAL;
+       }
+
+       /* Compute the multiplier M and combined N*P1 divisor. */
+       div = gcd(pll->pix_clock, pll->ext_clock);
+       pll->m = pll->pix_clock / div;
+       div = pll->ext_clock / div;
+
+       /* We now have the smallest M and N*P1 values that will result in the
+        * desired pixel clock frequency, but they might be out of the valid
+        * range. Compute the factor by which we should multiply them given the
+        * following constraints:
+        *
+        * - minimum/maximum multiplier
+        * - minimum/maximum multiplier output clock frequency assuming the
+        *   minimum/maximum N value
+        * - minimum/maximum combined N*P1 divisor
+        */
+       mf_min = DIV_ROUND_UP(limits->m_min, pll->m);
+       mf_min = max(mf_min, limits->out_clock_min /
+                    (pll->ext_clock / limits->n_min * pll->m));
+       mf_min = max(mf_min, limits->n_min * limits->p1_min / div);
+       mf_max = limits->m_max / pll->m;
+       mf_max = min(mf_max, limits->out_clock_max /
+                   (pll->ext_clock / limits->n_max * pll->m));
+       mf_max = min(mf_max, DIV_ROUND_UP(limits->n_max * limits->p1_max, div));
+
+       dev_dbg(dev, "pll: mf min %u max %u\n", mf_min, mf_max);
+       if (mf_min > mf_max) {
+               dev_err(dev, "pll: no valid combined N*P1 divisor.\n");
+               return -EINVAL;
+       }
+
+       /*
+        * We're looking for the highest acceptable P1 value for which a
+        * multiplier factor MF exists that fulfills the following conditions:
+        *
+        * 1. p1 is in the [p1_min, p1_max] range given by the limits and is
+        *    even
+        * 2. mf is in the [mf_min, mf_max] range computed above
+        * 3. div * mf is a multiple of p1, in order to compute
+        *      n = div * mf / p1
+        *      m = pll->m * mf
+        * 4. the internal clock frequency, given by ext_clock / n, is in the
+        *    [int_clock_min, int_clock_max] range given by the limits
+        * 5. the output clock frequency, given by ext_clock / n * m, is in the
+        *    [out_clock_min, out_clock_max] range given by the limits
+        *
+        * The first naive approach is to iterate over all p1 values acceptable
+        * according to (1) and all mf values acceptable according to (2), and
+        * stop at the first combination that fulfills (3), (4) and (5). This
+        * has a O(n^2) complexity.
+        *
+        * Instead of iterating over all mf values in the [mf_min, mf_max] range
+        * we can compute the mf increment between two acceptable values
+        * according to (3) with
+        *
+        *      mf_inc = p1 / gcd(div, p1)                      (6)
+        *
+        * and round the minimum up to the nearest multiple of mf_inc. This will
+        * restrict the number of mf values to be checked.
+        *
+        * Furthermore, conditions (4) and (5) only restrict the range of
+        * acceptable p1 and mf values by modifying the minimum and maximum
+        * limits. (5) can be expressed as
+        *
+        *      ext_clock / (div * mf / p1) * m * mf >= out_clock_min
+        *      ext_clock / (div * mf / p1) * m * mf <= out_clock_max
+        *
+        * or
+        *
+        *      p1 >= out_clock_min * div / (ext_clock * m)     (7)
+        *      p1 <= out_clock_max * div / (ext_clock * m)
+        *
+        * Similarly, (4) can be expressed as
+        *
+        *      mf >= ext_clock * p1 / (int_clock_max * div)    (8)
+        *      mf <= ext_clock * p1 / (int_clock_min * div)
+        *
+        * We can thus iterate over the restricted p1 range defined by the
+        * combination of (1) and (7), and then compute the restricted mf range
+        * defined by the combination of (2), (6) and (8). If the resulting mf
+        * range is not empty, any value in the mf range is acceptable. We thus
+        * select the mf lwoer bound and the corresponding p1 value.
+        */
+       if (limits->p1_min == 0) {
+               dev_err(dev, "pll: P1 minimum value must be >0.\n");
+               return -EINVAL;
+       }
+
+       p1_min = max(limits->p1_min, DIV_ROUND_UP(limits->out_clock_min * div,
+                    pll->ext_clock * pll->m));
+       p1_max = min(limits->p1_max, limits->out_clock_max * div /
+                    (pll->ext_clock * pll->m));
+
+       for (p1 = p1_max & ~1; p1 >= p1_min; p1 -= 2) {
+               unsigned int mf_inc = p1 / gcd(div, p1);
+               unsigned int mf_high;
+               unsigned int mf_low;
+
+               mf_low = max(roundup(mf_min, mf_inc),
+                            DIV_ROUND_UP(pll->ext_clock * p1,
+                              limits->int_clock_max * div));
+               mf_high = min(mf_max, pll->ext_clock * p1 /
+                             (limits->int_clock_min * div));
+
+               if (mf_low > mf_high)
+                       continue;
+
+               pll->n = div * mf_low / p1;
+               pll->m *= mf_low;
+               pll->p1 = p1;
+               dev_dbg(dev, "PLL: N %u M %u P1 %u\n", pll->n, pll->m, pll->p1);
+               return 0;
+       }
+
+       dev_err(dev, "pll: no valid N and P1 divisors found.\n");
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(aptina_pll_calculate);
+
+MODULE_DESCRIPTION("Aptina PLL Helpers");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/aptina-pll.h b/drivers/media/video/aptina-pll.h
new file mode 100644 (file)
index 0000000..b370e34
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Aptina Sensor PLL Configuration
+ *
+ * Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __APTINA_PLL_H
+#define __APTINA_PLL_H
+
+struct aptina_pll {
+       unsigned int ext_clock;
+       unsigned int pix_clock;
+
+       unsigned int n;
+       unsigned int m;
+       unsigned int p1;
+};
+
+struct aptina_pll_limits {
+       unsigned int ext_clock_min;
+       unsigned int ext_clock_max;
+       unsigned int int_clock_min;
+       unsigned int int_clock_max;
+       unsigned int out_clock_min;
+       unsigned int out_clock_max;
+       unsigned int pix_clock_max;
+
+       unsigned int n_min;
+       unsigned int n_max;
+       unsigned int m_min;
+       unsigned int m_max;
+       unsigned int p1_min;
+       unsigned int p1_max;
+};
+
+struct device;
+
+int aptina_pll_calculate(struct device *dev,
+                        const struct aptina_pll_limits *limits,
+                        struct aptina_pll *pll);
+
+#endif /* __APTINA_PLL_H */
index f241702..7a3371f 100644 (file)
@@ -881,24 +881,7 @@ static struct i2c_driver as3645a_i2c_driver = {
        .id_table = as3645a_id_table,
 };
 
-static int __init as3645a_init(void)
-{
-       int rval;
-
-       rval = i2c_add_driver(&as3645a_i2c_driver);
-       if (rval)
-               pr_err("%s: Failed to register the driver\n", AS3645A_NAME);
-
-       return rval;
-}
-
-static void __exit as3645a_exit(void)
-{
-       i2c_del_driver(&as3645a_i2c_driver);
-}
-
-module_init(as3645a_init);
-module_exit(as3645a_exit);
+module_i2c_driver(as3645a_i2c_driver);
 
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
 MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones");
diff --git a/drivers/media/video/blackfin/Kconfig b/drivers/media/video/blackfin/Kconfig
new file mode 100644 (file)
index 0000000..ecd5323
--- /dev/null
@@ -0,0 +1,10 @@
+config VIDEO_BLACKFIN_CAPTURE
+       tristate "Blackfin Video Capture Driver"
+       depends on VIDEO_V4L2 && BLACKFIN && I2C
+       select VIDEOBUF2_DMA_CONTIG
+       help
+         V4L2 bridge driver for Blackfin video capture device.
+         Choose PPI or EPPI as its interface.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bfin_video_capture.
diff --git a/drivers/media/video/blackfin/Makefile b/drivers/media/video/blackfin/Makefile
new file mode 100644 (file)
index 0000000..aa3a0a2
--- /dev/null
@@ -0,0 +1,2 @@
+bfin_video_capture-objs := bfin_capture.o ppi.o
+obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_video_capture.o
diff --git a/drivers/media/video/blackfin/bfin_capture.c b/drivers/media/video/blackfin/bfin_capture.c
new file mode 100644 (file)
index 0000000..514fcf7
--- /dev/null
@@ -0,0 +1,1059 @@
+/*
+ * Analog Devices video capture driver
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <asm/dma.h>
+
+#include <media/blackfin/bfin_capture.h>
+#include <media/blackfin/ppi.h>
+
+#define CAPTURE_DRV_NAME        "bfin_capture"
+#define BCAP_MIN_NUM_BUF        2
+
+struct bcap_format {
+       char *desc;
+       u32 pixelformat;
+       enum v4l2_mbus_pixelcode mbus_code;
+       int bpp; /* bits per pixel */
+};
+
+struct bcap_buffer {
+       struct vb2_buffer vb;
+       struct list_head list;
+};
+
+struct bcap_device {
+       /* capture device instance */
+       struct v4l2_device v4l2_dev;
+       /* v4l2 control handler */
+       struct v4l2_ctrl_handler ctrl_handler;
+       /* device node data */
+       struct video_device *video_dev;
+       /* sub device instance */
+       struct v4l2_subdev *sd;
+       /* capture config */
+       struct bfin_capture_config *cfg;
+       /* ppi interface */
+       struct ppi_if *ppi;
+       /* current input */
+       unsigned int cur_input;
+       /* current selected standard */
+       v4l2_std_id std;
+       /* used to store pixel format */
+       struct v4l2_pix_format fmt;
+       /* bits per pixel*/
+       int bpp;
+       /* used to store sensor supported format */
+       struct bcap_format *sensor_formats;
+       /* number of sensor formats array */
+       int num_sensor_formats;
+       /* pointing to current video buffer */
+       struct bcap_buffer *cur_frm;
+       /* pointing to next video buffer */
+       struct bcap_buffer *next_frm;
+       /* buffer queue used in videobuf2 */
+       struct vb2_queue buffer_queue;
+       /* allocator-specific contexts for each plane */
+       struct vb2_alloc_ctx *alloc_ctx;
+       /* queue of filled frames */
+       struct list_head dma_queue;
+       /* used in videobuf2 callback */
+       spinlock_t lock;
+       /* used to access capture device */
+       struct mutex mutex;
+       /* used to wait ppi to complete one transfer */
+       struct completion comp;
+       /* prepare to stop */
+       bool stop;
+};
+
+struct bcap_fh {
+       struct v4l2_fh fh;
+       /* indicates whether this file handle is doing IO */
+       bool io_allowed;
+};
+
+static const struct bcap_format bcap_formats[] = {
+       {
+               .desc        = "YCbCr 4:2:2 Interleaved UYVY",
+               .pixelformat = V4L2_PIX_FMT_UYVY,
+               .mbus_code   = V4L2_MBUS_FMT_UYVY8_2X8,
+               .bpp         = 16,
+       },
+       {
+               .desc        = "YCbCr 4:2:2 Interleaved YUYV",
+               .pixelformat = V4L2_PIX_FMT_YUYV,
+               .mbus_code   = V4L2_MBUS_FMT_YUYV8_2X8,
+               .bpp         = 16,
+       },
+       {
+               .desc        = "RGB 565",
+               .pixelformat = V4L2_PIX_FMT_RGB565,
+               .mbus_code   = V4L2_MBUS_FMT_RGB565_2X8_LE,
+               .bpp         = 16,
+       },
+       {
+               .desc        = "RGB 444",
+               .pixelformat = V4L2_PIX_FMT_RGB444,
+               .mbus_code   = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+               .bpp         = 16,
+       },
+
+};
+#define BCAP_MAX_FMTS ARRAY_SIZE(bcap_formats)
+
+static irqreturn_t bcap_isr(int irq, void *dev_id);
+
+static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb)
+{
+       return container_of(vb, struct bcap_buffer, vb);
+}
+
+static int bcap_init_sensor_formats(struct bcap_device *bcap_dev)
+{
+       enum v4l2_mbus_pixelcode code;
+       struct bcap_format *sf;
+       unsigned int num_formats = 0;
+       int i, j;
+
+       while (!v4l2_subdev_call(bcap_dev->sd, video,
+                               enum_mbus_fmt, num_formats, &code))
+               num_formats++;
+       if (!num_formats)
+               return -ENXIO;
+
+       sf = kzalloc(num_formats * sizeof(*sf), GFP_KERNEL);
+       if (!sf)
+               return -ENOMEM;
+
+       for (i = 0; i < num_formats; i++) {
+               v4l2_subdev_call(bcap_dev->sd, video,
+                               enum_mbus_fmt, i, &code);
+               for (j = 0; j < BCAP_MAX_FMTS; j++)
+                       if (code == bcap_formats[j].mbus_code)
+                               break;
+               if (j == BCAP_MAX_FMTS) {
+                       /* we don't allow this sensor working with our bridge */
+                       kfree(sf);
+                       return -EINVAL;
+               }
+               sf[i] = bcap_formats[j];
+       }
+       bcap_dev->sensor_formats = sf;
+       bcap_dev->num_sensor_formats = num_formats;
+       return 0;
+}
+
+static void bcap_free_sensor_formats(struct bcap_device *bcap_dev)
+{
+       bcap_dev->num_sensor_formats = 0;
+       kfree(bcap_dev->sensor_formats);
+       bcap_dev->sensor_formats = NULL;
+}
+
+static int bcap_open(struct file *file)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct video_device *vfd = bcap_dev->video_dev;
+       struct bcap_fh *bcap_fh;
+
+       if (!bcap_dev->sd) {
+               v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n");
+               return -ENODEV;
+       }
+
+       bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL);
+       if (!bcap_fh) {
+               v4l2_err(&bcap_dev->v4l2_dev,
+                        "unable to allocate memory for file handle object\n");
+               return -ENOMEM;
+       }
+
+       v4l2_fh_init(&bcap_fh->fh, vfd);
+
+       /* store pointer to v4l2_fh in private_data member of file */
+       file->private_data = &bcap_fh->fh;
+       v4l2_fh_add(&bcap_fh->fh);
+       bcap_fh->io_allowed = false;
+       return 0;
+}
+
+static int bcap_release(struct file *file)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct v4l2_fh *fh = file->private_data;
+       struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+       /* if this instance is doing IO */
+       if (bcap_fh->io_allowed)
+               vb2_queue_release(&bcap_dev->buffer_queue);
+
+       file->private_data = NULL;
+       v4l2_fh_del(&bcap_fh->fh);
+       v4l2_fh_exit(&bcap_fh->fh);
+       kfree(bcap_fh);
+       return 0;
+}
+
+static int bcap_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       return vb2_mmap(&bcap_dev->buffer_queue, vma);
+}
+
+#ifndef CONFIG_MMU
+static unsigned long bcap_get_unmapped_area(struct file *file,
+                                           unsigned long addr,
+                                           unsigned long len,
+                                           unsigned long pgoff,
+                                           unsigned long flags)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       return vb2_get_unmapped_area(&bcap_dev->buffer_queue,
+                                    addr,
+                                    len,
+                                    pgoff,
+                                    flags);
+}
+#endif
+
+static unsigned int bcap_poll(struct file *file, poll_table *wait)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       return vb2_poll(&bcap_dev->buffer_queue, file, wait);
+}
+
+static int bcap_queue_setup(struct vb2_queue *vq,
+                               const struct v4l2_format *fmt,
+                               unsigned int *nbuffers, unsigned int *nplanes,
+                               unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+
+       if (*nbuffers < BCAP_MIN_NUM_BUF)
+               *nbuffers = BCAP_MIN_NUM_BUF;
+
+       *nplanes = 1;
+       sizes[0] = bcap_dev->fmt.sizeimage;
+       alloc_ctxs[0] = bcap_dev->alloc_ctx;
+
+       return 0;
+}
+
+static int bcap_buffer_init(struct vb2_buffer *vb)
+{
+       struct bcap_buffer *buf = to_bcap_vb(vb);
+
+       INIT_LIST_HEAD(&buf->list);
+       return 0;
+}
+
+static int bcap_buffer_prepare(struct vb2_buffer *vb)
+{
+       struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct bcap_buffer *buf = to_bcap_vb(vb);
+       unsigned long size;
+
+       size = bcap_dev->fmt.sizeimage;
+       if (vb2_plane_size(vb, 0) < size) {
+               v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n",
+                               vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+       vb2_set_plane_payload(&buf->vb, 0, size);
+
+       return 0;
+}
+
+static void bcap_buffer_queue(struct vb2_buffer *vb)
+{
+       struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct bcap_buffer *buf = to_bcap_vb(vb);
+       unsigned long flags;
+
+       spin_lock_irqsave(&bcap_dev->lock, flags);
+       list_add_tail(&buf->list, &bcap_dev->dma_queue);
+       spin_unlock_irqrestore(&bcap_dev->lock, flags);
+}
+
+static void bcap_buffer_cleanup(struct vb2_buffer *vb)
+{
+       struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct bcap_buffer *buf = to_bcap_vb(vb);
+       unsigned long flags;
+
+       spin_lock_irqsave(&bcap_dev->lock, flags);
+       list_del_init(&buf->list);
+       spin_unlock_irqrestore(&bcap_dev->lock, flags);
+}
+
+static void bcap_lock(struct vb2_queue *vq)
+{
+       struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+       mutex_lock(&bcap_dev->mutex);
+}
+
+static void bcap_unlock(struct vb2_queue *vq)
+{
+       struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+       mutex_unlock(&bcap_dev->mutex);
+}
+
+static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+       struct ppi_if *ppi = bcap_dev->ppi;
+       struct ppi_params params;
+       int ret;
+
+       /* enable streamon on the sub device */
+       ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1);
+       if (ret && (ret != -ENOIOCTLCMD)) {
+               v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n");
+               return ret;
+       }
+
+       /* set ppi params */
+       params.width = bcap_dev->fmt.width;
+       params.height = bcap_dev->fmt.height;
+       params.bpp = bcap_dev->bpp;
+       params.ppi_control = bcap_dev->cfg->ppi_control;
+       params.int_mask = bcap_dev->cfg->int_mask;
+       params.blank_clocks = bcap_dev->cfg->blank_clocks;
+       ret = ppi->ops->set_params(ppi, &params);
+       if (ret < 0) {
+               v4l2_err(&bcap_dev->v4l2_dev,
+                               "Error in setting ppi params\n");
+               return ret;
+       }
+
+       /* attach ppi DMA irq handler */
+       ret = ppi->ops->attach_irq(ppi, bcap_isr);
+       if (ret < 0) {
+               v4l2_err(&bcap_dev->v4l2_dev,
+                               "Error in attaching interrupt handler\n");
+               return ret;
+       }
+
+       INIT_COMPLETION(bcap_dev->comp);
+       bcap_dev->stop = false;
+       return 0;
+}
+
+static int bcap_stop_streaming(struct vb2_queue *vq)
+{
+       struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
+       struct ppi_if *ppi = bcap_dev->ppi;
+       int ret;
+
+       if (!vb2_is_streaming(vq))
+               return 0;
+
+       bcap_dev->stop = true;
+       wait_for_completion(&bcap_dev->comp);
+       ppi->ops->stop(ppi);
+       ppi->ops->detach_irq(ppi);
+       ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 0);
+       if (ret && (ret != -ENOIOCTLCMD))
+               v4l2_err(&bcap_dev->v4l2_dev,
+                               "stream off failed in subdev\n");
+
+       /* release all active buffers */
+       while (!list_empty(&bcap_dev->dma_queue)) {
+               bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+                                               struct bcap_buffer, list);
+               list_del(&bcap_dev->next_frm->list);
+               vb2_buffer_done(&bcap_dev->next_frm->vb, VB2_BUF_STATE_ERROR);
+       }
+       return 0;
+}
+
+static struct vb2_ops bcap_video_qops = {
+       .queue_setup            = bcap_queue_setup,
+       .buf_init               = bcap_buffer_init,
+       .buf_prepare            = bcap_buffer_prepare,
+       .buf_cleanup            = bcap_buffer_cleanup,
+       .buf_queue              = bcap_buffer_queue,
+       .wait_prepare           = bcap_unlock,
+       .wait_finish            = bcap_lock,
+       .start_streaming        = bcap_start_streaming,
+       .stop_streaming         = bcap_stop_streaming,
+};
+
+static int bcap_reqbufs(struct file *file, void *priv,
+                       struct v4l2_requestbuffers *req_buf)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct vb2_queue *vq = &bcap_dev->buffer_queue;
+       struct v4l2_fh *fh = file->private_data;
+       struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+       if (vb2_is_busy(vq))
+               return -EBUSY;
+
+       bcap_fh->io_allowed = true;
+
+       return vb2_reqbufs(vq, req_buf);
+}
+
+static int bcap_querybuf(struct file *file, void *priv,
+                               struct v4l2_buffer *buf)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       return vb2_querybuf(&bcap_dev->buffer_queue, buf);
+}
+
+static int bcap_qbuf(struct file *file, void *priv,
+                       struct v4l2_buffer *buf)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct v4l2_fh *fh = file->private_data;
+       struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+       if (!bcap_fh->io_allowed)
+               return -EBUSY;
+
+       return vb2_qbuf(&bcap_dev->buffer_queue, buf);
+}
+
+static int bcap_dqbuf(struct file *file, void *priv,
+                       struct v4l2_buffer *buf)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct v4l2_fh *fh = file->private_data;
+       struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh);
+
+       if (!bcap_fh->io_allowed)
+               return -EBUSY;
+
+       return vb2_dqbuf(&bcap_dev->buffer_queue,
+                               buf, file->f_flags & O_NONBLOCK);
+}
+
+static irqreturn_t bcap_isr(int irq, void *dev_id)
+{
+       struct ppi_if *ppi = dev_id;
+       struct bcap_device *bcap_dev = ppi->priv;
+       struct timeval timevalue;
+       struct vb2_buffer *vb = &bcap_dev->cur_frm->vb;
+       dma_addr_t addr;
+
+       spin_lock(&bcap_dev->lock);
+
+       if (bcap_dev->cur_frm != bcap_dev->next_frm) {
+               do_gettimeofday(&timevalue);
+               vb->v4l2_buf.timestamp = timevalue;
+               vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+               bcap_dev->cur_frm = bcap_dev->next_frm;
+       }
+
+       ppi->ops->stop(ppi);
+
+       if (bcap_dev->stop) {
+               complete(&bcap_dev->comp);
+       } else {
+               if (!list_empty(&bcap_dev->dma_queue)) {
+                       bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+                                               struct bcap_buffer, list);
+                       list_del(&bcap_dev->next_frm->list);
+                       addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->next_frm->vb, 0);
+                       ppi->ops->update_addr(ppi, (unsigned long)addr);
+               }
+               ppi->ops->start(ppi);
+       }
+
+       spin_unlock(&bcap_dev->lock);
+
+       return IRQ_HANDLED;
+}
+
+static int bcap_streamon(struct file *file, void *priv,
+                               enum v4l2_buf_type buf_type)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct bcap_fh *fh = file->private_data;
+       struct ppi_if *ppi = bcap_dev->ppi;
+       dma_addr_t addr;
+       int ret;
+
+       if (!fh->io_allowed)
+               return -EBUSY;
+
+       /* call streamon to start streaming in videobuf */
+       ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type);
+       if (ret)
+               return ret;
+
+       /* if dma queue is empty, return error */
+       if (list_empty(&bcap_dev->dma_queue)) {
+               v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* get the next frame from the dma queue */
+       bcap_dev->next_frm = list_entry(bcap_dev->dma_queue.next,
+                                       struct bcap_buffer, list);
+       bcap_dev->cur_frm = bcap_dev->next_frm;
+       /* remove buffer from the dma queue */
+       list_del(&bcap_dev->cur_frm->list);
+       addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0);
+       /* update DMA address */
+       ppi->ops->update_addr(ppi, (unsigned long)addr);
+       /* enable ppi */
+       ppi->ops->start(ppi);
+
+       return 0;
+err:
+       vb2_streamoff(&bcap_dev->buffer_queue, buf_type);
+       return ret;
+}
+
+static int bcap_streamoff(struct file *file, void *priv,
+                               enum v4l2_buf_type buf_type)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct bcap_fh *fh = file->private_data;
+
+       if (!fh->io_allowed)
+               return -EBUSY;
+
+       return vb2_streamoff(&bcap_dev->buffer_queue, buf_type);
+}
+
+static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       return v4l2_subdev_call(bcap_dev->sd, video, querystd, std);
+}
+
+static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       *std = bcap_dev->std;
+       return 0;
+}
+
+static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       int ret;
+
+       if (vb2_is_busy(&bcap_dev->buffer_queue))
+               return -EBUSY;
+
+       ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std);
+       if (ret < 0)
+               return ret;
+
+       bcap_dev->std = *std;
+       return 0;
+}
+
+static int bcap_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *input)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct bfin_capture_config *config = bcap_dev->cfg;
+       int ret;
+       u32 status;
+
+       if (input->index >= config->num_inputs)
+               return -EINVAL;
+
+       *input = config->inputs[input->index];
+       /* get input status */
+       ret = v4l2_subdev_call(bcap_dev->sd, video, g_input_status, &status);
+       if (!ret)
+               input->status = status;
+       return 0;
+}
+
+static int bcap_g_input(struct file *file, void *priv, unsigned int *index)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       *index = bcap_dev->cur_input;
+       return 0;
+}
+
+static int bcap_s_input(struct file *file, void *priv, unsigned int index)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct bfin_capture_config *config = bcap_dev->cfg;
+       struct bcap_route *route;
+       int ret;
+
+       if (vb2_is_busy(&bcap_dev->buffer_queue))
+               return -EBUSY;
+
+       if (index >= config->num_inputs)
+               return -EINVAL;
+
+       route = &config->routes[index];
+       ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing,
+                               route->input, route->output, 0);
+       if ((ret < 0) && (ret != -ENOIOCTLCMD)) {
+               v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n");
+               return ret;
+       }
+       bcap_dev->cur_input = index;
+       return 0;
+}
+
+static int bcap_try_format(struct bcap_device *bcap,
+                               struct v4l2_pix_format *pixfmt,
+                               enum v4l2_mbus_pixelcode *mbus_code,
+                               int *bpp)
+{
+       struct bcap_format *sf = bcap->sensor_formats;
+       struct bcap_format *fmt = NULL;
+       struct v4l2_mbus_framefmt mbus_fmt;
+       int ret, i;
+
+       for (i = 0; i < bcap->num_sensor_formats; i++) {
+               fmt = &sf[i];
+               if (pixfmt->pixelformat == fmt->pixelformat)
+                       break;
+       }
+       if (i == bcap->num_sensor_formats)
+               fmt = &sf[0];
+
+       if (mbus_code)
+               *mbus_code = fmt->mbus_code;
+       if (bpp)
+               *bpp = fmt->bpp;
+       v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code);
+       ret = v4l2_subdev_call(bcap->sd, video,
+                               try_mbus_fmt, &mbus_fmt);
+       if (ret < 0)
+               return ret;
+       v4l2_fill_pix_format(pixfmt, &mbus_fmt);
+       pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8;
+       pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+       return 0;
+}
+
+static int bcap_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *fmt)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct bcap_format *sf = bcap_dev->sensor_formats;
+
+       if (fmt->index >= bcap_dev->num_sensor_formats)
+               return -EINVAL;
+
+       fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       strlcpy(fmt->description,
+               sf[fmt->index].desc,
+               sizeof(fmt->description));
+       fmt->pixelformat = sf[fmt->index].pixelformat;
+       return 0;
+}
+
+static int bcap_try_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *fmt)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+       return bcap_try_format(bcap_dev, pixfmt, NULL, NULL);
+}
+
+static int bcap_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *fmt)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       fmt->fmt.pix = bcap_dev->fmt;
+       return 0;
+}
+
+static int bcap_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *fmt)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       struct v4l2_mbus_framefmt mbus_fmt;
+       enum v4l2_mbus_pixelcode mbus_code;
+       struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+       int ret, bpp;
+
+       if (vb2_is_busy(&bcap_dev->buffer_queue))
+               return -EBUSY;
+
+       /* see if format works */
+       ret = bcap_try_format(bcap_dev, pixfmt, &mbus_code, &bpp);
+       if (ret < 0)
+               return ret;
+
+       v4l2_fill_mbus_format(&mbus_fmt, pixfmt, mbus_code);
+       ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt);
+       if (ret < 0)
+               return ret;
+       bcap_dev->fmt = *pixfmt;
+       bcap_dev->bpp = bpp;
+       return 0;
+}
+
+static int bcap_querycap(struct file *file, void  *priv,
+                               struct v4l2_capability *cap)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
+       strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info));
+       strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card));
+       return 0;
+}
+
+static int bcap_g_parm(struct file *file, void *fh,
+                               struct v4l2_streamparm *a)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a);
+}
+
+static int bcap_s_parm(struct file *file, void *fh,
+                               struct v4l2_streamparm *a)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a);
+}
+
+static int bcap_g_chip_ident(struct file *file, void *priv,
+               struct v4l2_dbg_chip_ident *chip)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+       if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+                       chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+               return -EINVAL;
+
+       return v4l2_subdev_call(bcap_dev->sd, core,
+                       g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int bcap_dbg_g_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       return v4l2_subdev_call(bcap_dev->sd, core,
+                       g_register, reg);
+}
+
+static int bcap_dbg_s_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+
+       return v4l2_subdev_call(bcap_dev->sd, core,
+                       s_register, reg);
+}
+#endif
+
+static int bcap_log_status(struct file *file, void *priv)
+{
+       struct bcap_device *bcap_dev = video_drvdata(file);
+       /* status for sub devices */
+       v4l2_device_call_all(&bcap_dev->v4l2_dev, 0, core, log_status);
+       return 0;
+}
+
+static const struct v4l2_ioctl_ops bcap_ioctl_ops = {
+       .vidioc_querycap         = bcap_querycap,
+       .vidioc_g_fmt_vid_cap    = bcap_g_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_cap = bcap_enum_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap    = bcap_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap  = bcap_try_fmt_vid_cap,
+       .vidioc_enum_input       = bcap_enum_input,
+       .vidioc_g_input          = bcap_g_input,
+       .vidioc_s_input          = bcap_s_input,
+       .vidioc_querystd         = bcap_querystd,
+       .vidioc_s_std            = bcap_s_std,
+       .vidioc_g_std            = bcap_g_std,
+       .vidioc_reqbufs          = bcap_reqbufs,
+       .vidioc_querybuf         = bcap_querybuf,
+       .vidioc_qbuf             = bcap_qbuf,
+       .vidioc_dqbuf            = bcap_dqbuf,
+       .vidioc_streamon         = bcap_streamon,
+       .vidioc_streamoff        = bcap_streamoff,
+       .vidioc_g_parm           = bcap_g_parm,
+       .vidioc_s_parm           = bcap_s_parm,
+       .vidioc_g_chip_ident     = bcap_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register       = bcap_dbg_g_register,
+       .vidioc_s_register       = bcap_dbg_s_register,
+#endif
+       .vidioc_log_status       = bcap_log_status,
+};
+
+static struct v4l2_file_operations bcap_fops = {
+       .owner = THIS_MODULE,
+       .open = bcap_open,
+       .release = bcap_release,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap = bcap_mmap,
+#ifndef CONFIG_MMU
+       .get_unmapped_area = bcap_get_unmapped_area,
+#endif
+       .poll = bcap_poll
+};
+
+static int __devinit bcap_probe(struct platform_device *pdev)
+{
+       struct bcap_device *bcap_dev;
+       struct video_device *vfd;
+       struct i2c_adapter *i2c_adap;
+       struct bfin_capture_config *config;
+       struct vb2_queue *q;
+       int ret;
+
+       config = pdev->dev.platform_data;
+       if (!config) {
+               v4l2_err(pdev->dev.driver, "Unable to get board config\n");
+               return -ENODEV;
+       }
+
+       bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL);
+       if (!bcap_dev) {
+               v4l2_err(pdev->dev.driver, "Unable to alloc bcap_dev\n");
+               return -ENOMEM;
+       }
+
+       bcap_dev->cfg = config;
+
+       bcap_dev->ppi = ppi_create_instance(config->ppi_info);
+       if (!bcap_dev->ppi) {
+               v4l2_err(pdev->dev.driver, "Unable to create ppi\n");
+               ret = -ENODEV;
+               goto err_free_dev;
+       }
+       bcap_dev->ppi->priv = bcap_dev;
+
+       bcap_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(bcap_dev->alloc_ctx)) {
+               ret = PTR_ERR(bcap_dev->alloc_ctx);
+               goto err_free_ppi;
+       }
+
+       vfd = video_device_alloc();
+       if (!vfd) {
+               ret = -ENOMEM;
+               v4l2_err(pdev->dev.driver, "Unable to alloc video device\n");
+               goto err_cleanup_ctx;
+       }
+
+       /* initialize field of video device */
+       vfd->release            = video_device_release;
+       vfd->fops               = &bcap_fops;
+       vfd->ioctl_ops          = &bcap_ioctl_ops;
+       vfd->tvnorms            = 0;
+       vfd->v4l2_dev           = &bcap_dev->v4l2_dev;
+       set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+       strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name));
+       bcap_dev->video_dev     = vfd;
+
+       ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev);
+       if (ret) {
+               v4l2_err(pdev->dev.driver,
+                               "Unable to register v4l2 device\n");
+               goto err_release_vdev;
+       }
+       v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n");
+
+       bcap_dev->v4l2_dev.ctrl_handler = &bcap_dev->ctrl_handler;
+       ret = v4l2_ctrl_handler_init(&bcap_dev->ctrl_handler, 0);
+       if (ret) {
+               v4l2_err(&bcap_dev->v4l2_dev,
+                               "Unable to init control handler\n");
+               goto err_unreg_v4l2;
+       }
+
+       spin_lock_init(&bcap_dev->lock);
+       /* initialize queue */
+       q = &bcap_dev->buffer_queue;
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP;
+       q->drv_priv = bcap_dev;
+       q->buf_struct_size = sizeof(struct bcap_buffer);
+       q->ops = &bcap_video_qops;
+       q->mem_ops = &vb2_dma_contig_memops;
+
+       vb2_queue_init(q);
+
+       mutex_init(&bcap_dev->mutex);
+       init_completion(&bcap_dev->comp);
+
+       /* init video dma queues */
+       INIT_LIST_HEAD(&bcap_dev->dma_queue);
+
+       vfd->lock = &bcap_dev->mutex;
+
+       /* register video device */
+       ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1);
+       if (ret) {
+               v4l2_err(&bcap_dev->v4l2_dev,
+                               "Unable to register video device\n");
+               goto err_free_handler;
+       }
+       video_set_drvdata(bcap_dev->video_dev, bcap_dev);
+       v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n",
+                       video_device_node_name(vfd));
+
+       /* load up the subdevice */
+       i2c_adap = i2c_get_adapter(config->i2c_adapter_id);
+       if (!i2c_adap) {
+               v4l2_err(&bcap_dev->v4l2_dev,
+                               "Unable to find i2c adapter\n");
+               goto err_unreg_vdev;
+
+       }
+       bcap_dev->sd = v4l2_i2c_new_subdev_board(&bcap_dev->v4l2_dev,
+                                                i2c_adap,
+                                                &config->board_info,
+                                                NULL);
+       if (bcap_dev->sd) {
+               int i;
+               /* update tvnorms from the sub devices */
+               for (i = 0; i < config->num_inputs; i++)
+                       vfd->tvnorms |= config->inputs[i].std;
+       } else {
+               v4l2_err(&bcap_dev->v4l2_dev,
+                               "Unable to register sub device\n");
+               goto err_unreg_vdev;
+       }
+
+       v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n");
+
+       /* now we can probe the default state */
+       if (vfd->tvnorms) {
+               v4l2_std_id std;
+               ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std);
+               if (ret) {
+                       v4l2_err(&bcap_dev->v4l2_dev,
+                                       "Unable to get std\n");
+                       goto err_unreg_vdev;
+               }
+               bcap_dev->std = std;
+       }
+       ret = bcap_init_sensor_formats(bcap_dev);
+       if (ret) {
+               v4l2_err(&bcap_dev->v4l2_dev,
+                               "Unable to create sensor formats table\n");
+               goto err_unreg_vdev;
+       }
+       return 0;
+err_unreg_vdev:
+       video_unregister_device(bcap_dev->video_dev);
+       bcap_dev->video_dev = NULL;
+err_free_handler:
+       v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler);
+err_unreg_v4l2:
+       v4l2_device_unregister(&bcap_dev->v4l2_dev);
+err_release_vdev:
+       if (bcap_dev->video_dev)
+               video_device_release(bcap_dev->video_dev);
+err_cleanup_ctx:
+       vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx);
+err_free_ppi:
+       ppi_delete_instance(bcap_dev->ppi);
+err_free_dev:
+       kfree(bcap_dev);
+       return ret;
+}
+
+static int __devexit bcap_remove(struct platform_device *pdev)
+{
+       struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+       struct bcap_device *bcap_dev = container_of(v4l2_dev,
+                                               struct bcap_device, v4l2_dev);
+
+       bcap_free_sensor_formats(bcap_dev);
+       video_unregister_device(bcap_dev->video_dev);
+       v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler);
+       v4l2_device_unregister(v4l2_dev);
+       vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx);
+       ppi_delete_instance(bcap_dev->ppi);
+       kfree(bcap_dev);
+       return 0;
+}
+
+static struct platform_driver bcap_driver = {
+       .driver = {
+               .name  = CAPTURE_DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = bcap_probe,
+       .remove = __devexit_p(bcap_remove),
+};
+
+static __init int bcap_init(void)
+{
+       return platform_driver_register(&bcap_driver);
+}
+
+static __exit void bcap_exit(void)
+{
+       platform_driver_unregister(&bcap_driver);
+}
+
+module_init(bcap_init);
+module_exit(bcap_exit);
+
+MODULE_DESCRIPTION("Analog Devices blackfin video capture driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/blackfin/ppi.c b/drivers/media/video/blackfin/ppi.c
new file mode 100644 (file)
index 0000000..d295921
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * ppi.c Analog Devices Parallel Peripheral Interface driver
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+
+#include <asm/bfin_ppi.h>
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#include <media/blackfin/ppi.h>
+
+static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler);
+static void ppi_detach_irq(struct ppi_if *ppi);
+static int ppi_start(struct ppi_if *ppi);
+static int ppi_stop(struct ppi_if *ppi);
+static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params);
+static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr);
+
+static const struct ppi_ops ppi_ops = {
+       .attach_irq = ppi_attach_irq,
+       .detach_irq = ppi_detach_irq,
+       .start = ppi_start,
+       .stop = ppi_stop,
+       .set_params = ppi_set_params,
+       .update_addr = ppi_update_addr,
+};
+
+static irqreturn_t ppi_irq_err(int irq, void *dev_id)
+{
+       struct ppi_if *ppi = dev_id;
+       const struct ppi_info *info = ppi->info;
+
+       switch (info->type) {
+       case PPI_TYPE_PPI:
+       {
+               struct bfin_ppi_regs *reg = info->base;
+               unsigned short status;
+
+               /* register on bf561 is cleared when read 
+                * others are W1C
+                */
+               status = bfin_read16(&reg->status);
+               bfin_write16(&reg->status, 0xff00);
+               break;
+       }
+       case PPI_TYPE_EPPI:
+       {
+               struct bfin_eppi_regs *reg = info->base;
+               bfin_write16(&reg->status, 0xffff);
+               break;
+       }
+       default:
+               break;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler)
+{
+       const struct ppi_info *info = ppi->info;
+       int ret;
+
+       ret = request_dma(info->dma_ch, "PPI_DMA");
+
+       if (ret) {
+               pr_err("Unable to allocate DMA channel for PPI\n");
+               return ret;
+       }
+       set_dma_callback(info->dma_ch, handler, ppi);
+
+       if (ppi->err_int) {
+               ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi);
+               if (ret) {
+                       pr_err("Unable to allocate IRQ for PPI\n");
+                       free_dma(info->dma_ch);
+               }
+       }
+       return ret;
+}
+
+static void ppi_detach_irq(struct ppi_if *ppi)
+{
+       const struct ppi_info *info = ppi->info;
+
+       if (ppi->err_int)
+               free_irq(info->irq_err, ppi);
+       free_dma(info->dma_ch);
+}
+
+static int ppi_start(struct ppi_if *ppi)
+{
+       const struct ppi_info *info = ppi->info;
+
+       /* enable DMA */
+       enable_dma(info->dma_ch);
+
+       /* enable PPI */
+       ppi->ppi_control |= PORT_EN;
+       switch (info->type) {
+       case PPI_TYPE_PPI:
+       {
+               struct bfin_ppi_regs *reg = info->base;
+               bfin_write16(&reg->control, ppi->ppi_control);
+               break;
+       }
+       case PPI_TYPE_EPPI:
+       {
+               struct bfin_eppi_regs *reg = info->base;
+               bfin_write32(&reg->control, ppi->ppi_control);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       SSYNC();
+       return 0;
+}
+
+static int ppi_stop(struct ppi_if *ppi)
+{
+       const struct ppi_info *info = ppi->info;
+
+       /* disable PPI */
+       ppi->ppi_control &= ~PORT_EN;
+       switch (info->type) {
+       case PPI_TYPE_PPI:
+       {
+               struct bfin_ppi_regs *reg = info->base;
+               bfin_write16(&reg->control, ppi->ppi_control);
+               break;
+       }
+       case PPI_TYPE_EPPI:
+       {
+               struct bfin_eppi_regs *reg = info->base;
+               bfin_write32(&reg->control, ppi->ppi_control);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       /* disable DMA */
+       clear_dma_irqstat(info->dma_ch);
+       disable_dma(info->dma_ch);
+
+       SSYNC();
+       return 0;
+}
+
+static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
+{
+       const struct ppi_info *info = ppi->info;
+       int dma32 = 0;
+       int dma_config, bytes_per_line, lines_per_frame;
+
+       bytes_per_line = params->width * params->bpp / 8;
+       lines_per_frame = params->height;
+       if (params->int_mask == 0xFFFFFFFF)
+               ppi->err_int = false;
+       else
+               ppi->err_int = true;
+
+       dma_config = (DMA_FLOW_STOP | WNR | RESTART | DMA2D | DI_EN);
+       ppi->ppi_control = params->ppi_control & ~PORT_EN;
+       switch (info->type) {
+       case PPI_TYPE_PPI:
+       {
+               struct bfin_ppi_regs *reg = info->base;
+
+               if (params->ppi_control & DMA32)
+                       dma32 = 1;
+
+               bfin_write16(&reg->control, ppi->ppi_control);
+               bfin_write16(&reg->count, bytes_per_line - 1);
+               bfin_write16(&reg->frame, lines_per_frame);
+               break;
+       }
+       case PPI_TYPE_EPPI:
+       {
+               struct bfin_eppi_regs *reg = info->base;
+
+               if ((params->ppi_control & PACK_EN)
+                       || (params->ppi_control & 0x38000) > DLEN_16)
+                       dma32 = 1;
+
+               bfin_write32(&reg->control, ppi->ppi_control);
+               bfin_write16(&reg->line, bytes_per_line + params->blank_clocks);
+               bfin_write16(&reg->frame, lines_per_frame);
+               bfin_write16(&reg->hdelay, 0);
+               bfin_write16(&reg->vdelay, 0);
+               bfin_write16(&reg->hcount, bytes_per_line);
+               bfin_write16(&reg->vcount, lines_per_frame);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       if (dma32) {
+               dma_config |= WDSIZE_32;
+               set_dma_x_count(info->dma_ch, bytes_per_line >> 2);
+               set_dma_x_modify(info->dma_ch, 4);
+               set_dma_y_modify(info->dma_ch, 4);
+       } else {
+               dma_config |= WDSIZE_16;
+               set_dma_x_count(info->dma_ch, bytes_per_line >> 1);
+               set_dma_x_modify(info->dma_ch, 2);
+               set_dma_y_modify(info->dma_ch, 2);
+       }
+       set_dma_y_count(info->dma_ch, lines_per_frame);
+       set_dma_config(info->dma_ch, dma_config);
+
+       SSYNC();
+       return 0;
+}
+
+static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr)
+{
+       set_dma_start_addr(ppi->info->dma_ch, addr);
+}
+
+struct ppi_if *ppi_create_instance(const struct ppi_info *info)
+{
+       struct ppi_if *ppi;
+
+       if (!info || !info->pin_req)
+               return NULL;
+
+       if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) {
+               pr_err("request peripheral failed\n");
+               return NULL;
+       }
+
+       ppi = kzalloc(sizeof(*ppi), GFP_KERNEL);
+       if (!ppi) {
+               peripheral_free_list(info->pin_req);
+               pr_err("unable to allocate memory for ppi handle\n");
+               return NULL;
+       }
+       ppi->ops = &ppi_ops;
+       ppi->info = info;
+
+       pr_info("ppi probe success\n");
+       return ppi;
+}
+
+void ppi_delete_instance(struct ppi_if *ppi)
+{
+       peripheral_free_list(ppi->info->pin_req);
+       kfree(ppi);
+}
index 859eabf..377bf05 100644 (file)
@@ -514,15 +514,4 @@ static struct i2c_driver bt819_driver = {
        .id_table       = bt819_id,
 };
 
-static __init int init_bt819(void)
-{
-       return i2c_add_driver(&bt819_driver);
-}
-
-static __exit void exit_bt819(void)
-{
-       i2c_del_driver(&bt819_driver);
-}
-
-module_init(init_bt819);
-module_exit(exit_bt819);
+module_i2c_driver(bt819_driver);
index a43059d..7e5bd36 100644 (file)
@@ -270,15 +270,4 @@ static struct i2c_driver bt856_driver = {
        .id_table       = bt856_id,
 };
 
-static __init int init_bt856(void)
-{
-       return i2c_add_driver(&bt856_driver);
-}
-
-static __exit void exit_bt856(void)
-{
-       i2c_del_driver(&bt856_driver);
-}
-
-module_init(init_bt856);
-module_exit(exit_bt856);
+module_i2c_driver(bt856_driver);
index 4e5dcea..905320b 100644 (file)
@@ -240,15 +240,4 @@ static struct i2c_driver bt866_driver = {
        .id_table       = bt866_id,
 };
 
-static __init int init_bt866(void)
-{
-       return i2c_add_driver(&bt866_driver);
-}
-
-static __exit void exit_bt866(void)
-{
-       i2c_del_driver(&bt866_driver);
-}
-
-module_init(init_bt866);
-module_exit(exit_bt866);
+module_i2c_driver(bt866_driver);
index 76c301f..e581b37 100644 (file)
@@ -2035,11 +2035,7 @@ static int bttv_log_status(struct file *file, void *f)
        struct bttv_fh *fh  = f;
        struct bttv *btv = fh->btv;
 
-       pr_info("%d: ========  START STATUS CARD #%d  ========\n",
-               btv->c.nr, btv->c.nr);
        bttv_call_all(btv, core, log_status);
-       pr_info("%d: ========  END STATUS CARD   #%d  ========\n",
-               btv->c.nr, btv->c.nr);
        return 0;
 }
 
index 1d64af9..c8581e2 100644 (file)
@@ -249,15 +249,4 @@ static struct i2c_driver cs5345_driver = {
        .id_table       = cs5345_id,
 };
 
-static __init int init_cs5345(void)
-{
-       return i2c_add_driver(&cs5345_driver);
-}
-
-static __exit void exit_cs5345(void)
-{
-       i2c_del_driver(&cs5345_driver);
-}
-
-module_init(init_cs5345);
-module_exit(exit_cs5345);
+module_i2c_driver(cs5345_driver);
index 51c5b9a..b293912 100644 (file)
@@ -248,15 +248,4 @@ static struct i2c_driver cs53l32a_driver = {
        .id_table       = cs53l32a_id,
 };
 
-static __init int init_cs53l32a(void)
-{
-       return i2c_add_driver(&cs53l32a_driver);
-}
-
-static __exit void exit_cs53l32a(void)
-{
-       i2c_del_driver(&cs53l32a_driver);
-}
-
-module_init(init_cs53l32a);
-module_exit(exit_cs53l32a);
+module_i2c_driver(cs53l32a_driver);
index 349bd9c..b55d57c 100644 (file)
@@ -38,7 +38,7 @@
 #include "cx18-ioctl.h"
 #include "cx18-controls.h"
 #include "tuner-xc2028.h"
-
+#include <linux/dma-mapping.h>
 #include <media/tveeprom.h>
 
 /* If you have already X v4l cards, then set this to X. This way
@@ -75,7 +75,7 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1 };
 static unsigned cardtype_c = 1;
 static unsigned tuner_c = 1;
-static bool radio_c = 1;
+static unsigned radio_c = 1;
 static char pal[] = "--";
 static char secam[] = "--";
 static char ntsc[] = "-";
@@ -110,7 +110,7 @@ static int retry_mmio = 1;
 int cx18_debug;
 
 module_param_array(tuner, int, &tuner_c, 0644);
-module_param_array(radio, bool, &radio_c, 0644);
+module_param_array(radio, int, &radio_c, 0644);
 module_param_array(cardtype, int, &cardtype_c, 0644);
 module_param_string(pal, pal, sizeof(pal), 0644);
 module_param_string(secam, secam, sizeof(secam), 0644);
@@ -812,7 +812,7 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
                CX18_ERR("Can't enable device %d!\n", cx->instance);
                return -EIO;
        }
-       if (pci_set_dma_mask(pci_dev, 0xffffffff)) {
+       if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) {
                CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
                return -EIO;
        }
index b9a94fc..7a37e0e 100644 (file)
@@ -44,8 +44,6 @@
 #include <linux/slab.h>
 #include <asm/byteorder.h>
 
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
index 66b1c15..be49f68 100644 (file)
@@ -1085,8 +1085,6 @@ static int cx18_log_status(struct file *file, void *fh)
        struct v4l2_audio audin;
        int i;
 
-       CX18_INFO("=================  START STATUS CARD #%d  "
-                 "=================\n", cx->instance);
        CX18_INFO("Version: %s  Card: %s\n", CX18_VERSION, cx->card_name);
        if (cx->hw_flags & CX18_HW_TVEEPROM) {
                struct tveeprom tv;
@@ -1120,8 +1118,6 @@ static int cx18_log_status(struct file *file, void *fh)
        CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
                        (long long)cx->mpg_data_received,
                        (long long)cx->vbi_data_inserted);
-       CX18_INFO("==================  END STATUS CARD #%d  "
-                 "==================\n", cx->instance);
        return 0;
 }
 
index f8f0e59..d4327da 100644 (file)
@@ -1686,7 +1686,6 @@ static struct v4l2_capability pvr_capability = {
        .capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
                           V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
                         V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
-       .reserved       = {0, 0, 0, 0}
 };
 static int vidioc_querycap(struct file *file, void  *priv,
                                struct v4l2_capability *cap)
index 875a7ce..8ed460d 100644 (file)
@@ -861,7 +861,6 @@ void cx231xx_release_resources(struct cx231xx *dev)
        kfree(dev->sliced_cc_mode.alt_max_pkt_size);
        kfree(dev->ts1_mode.alt_max_pkt_size);
        kfree(dev);
-       dev = NULL;
 }
 
 /*
index 829a41b..7f916f0 100644 (file)
@@ -2319,8 +2319,7 @@ static int cx231xx_v4l2_close(struct file *filp)
                        if (dev->state & DEV_DISCONNECTED) {
                                if (atomic_read(&dev->devlist_count) > 0) {
                                        cx231xx_release_resources(dev);
-                                       kfree(dev);
-                                       dev = NULL;
+                                       fh->dev = NULL;
                                        return 0;
                                }
                                return 0;
@@ -2350,8 +2349,7 @@ static int cx231xx_v4l2_close(struct file *filp)
                   free the remaining resources */
                if (dev->state & DEV_DISCONNECTED) {
                        cx231xx_release_resources(dev);
-                       kfree(dev);
-                       dev = NULL;
+                       fh->dev = NULL;
                        return 0;
                }
 
index f617474..7930ca5 100644 (file)
@@ -1474,8 +1474,13 @@ static DEFINE_PCI_DEVICE_TABLE(cx25821_pci_tbl) = {
                .device = 0x8210,
                .subvendor = 0x14f1,
                .subdevice = 0x0920,
-       },
-       {
+       }, {
+               /* CX25821 No Brand */
+               .vendor = 0x14f1,
+               .device = 0x8210,
+               .subvendor = 0x0000,
+               .subdevice = 0x0000,
+       }, {
                /* --- end of list --- */
        }
 };
index 05247d4..fc1ff69 100644 (file)
@@ -5301,15 +5301,4 @@ static struct i2c_driver cx25840_driver = {
        .id_table       = cx25840_id,
 };
 
-static __init int init_cx25840(void)
-{
-       return i2c_add_driver(&cx25840_driver);
-}
-
-static __exit void exit_cx25840(void)
-{
-       i2c_del_driver(&cx25840_driver);
-}
-
-module_init(init_cx25840);
-module_exit(exit_cx25840);
+module_i2c_driver(cx25840_driver);
index 25036cb..8bcac65 100644 (file)
@@ -18,8 +18,6 @@
 
 #include <linux/io.h>
 #include <linux/videodev2.h>
-#include <mach/hardware.h>
-#include <mach/dm646x.h>
 #include <media/davinci/vpif_types.h>
 
 /* Maximum channel allowed */
index 286f029..7fa34b4 100644 (file)
@@ -39,8 +39,6 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-chip-ident.h>
 
-#include <mach/dm646x.h>
-
 #include "vpif_display.h"
 #include "vpif.h"
 
index 4561cd8..9fd8cc7 100644 (file)
@@ -353,6 +353,44 @@ static struct em28xx_reg_seq hauppauge_930c_digital[] = {
 };
 #endif
 
+/* 1b80:e425 MaxMedia UB425-TC
+ * GPIO_6 - demod reset, 0=active
+ * GPIO_7 - LED, 0=active
+ */
+static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
+       {EM2874_R80_GPIO,  0x83,  0xff,  100},
+       {EM2874_R80_GPIO,  0xc3,  0xff,  100}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO,  0x43,  0xff,  000}, /* GPIO_7 = 0 */
+       {-1,                 -1,    -1,   -1},
+};
+
+/* 2304:0242 PCTV QuatroStick (510e)
+ * GPIO_2: decoder reset, 0=active
+ * GPIO_4: decoder suspend, 0=active
+ * GPIO_6: demod reset, 0=active
+ * GPIO_7: LED, 1=active
+ */
+static struct em28xx_reg_seq pctv_510e[] = {
+       {EM2874_R80_GPIO, 0x10, 0xff, 100},
+       {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+       {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+       {             -1,   -1,   -1,  -1},
+};
+
+/* 2013:0251 PCTV QuatroStick nano (520e)
+ * GPIO_2: decoder reset, 0=active
+ * GPIO_4: decoder suspend, 0=active
+ * GPIO_6: demod reset, 0=active
+ * GPIO_7: LED, 1=active
+ */
+static struct em28xx_reg_seq pctv_520e[] = {
+       {EM2874_R80_GPIO, 0x10, 0xff, 100},
+       {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+       {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
+       {             -1,   -1,   -1,  -1},
+};
+
 /*
  *  Board definitions
  */
@@ -1908,6 +1946,41 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
+       /* 1b80:e425 MaxMedia UB425-TC
+        * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */
+       [EM2874_BOARD_MAXMEDIA_UB425_TC] = {
+               .name          = "MaxMedia UB425-TC",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = maxmedia_ub425_tc,
+               .has_dvb       = 1,
+               .i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
+       /* 2304:0242 PCTV QuatroStick (510e)
+        * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+       [EM2884_BOARD_PCTV_510E] = {
+               .name          = "PCTV QuatroStick (510e)",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = pctv_510e,
+               .has_dvb       = 1,
+               .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+               .i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
+       /* 2013:0251 PCTV QuatroStick nano (520e)
+        * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+       [EM2884_BOARD_PCTV_520E] = {
+               .name          = "PCTV QuatroStick nano (520e)",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = pctv_520e,
+               .has_dvb       = 1,
+               .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+               .i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -2059,6 +2132,12 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 },
        { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */
                        .driver_info = EM2860_BOARD_EASYCAP },
+       { USB_DEVICE(0x1b80, 0xe425),
+                       .driver_info = EM2874_BOARD_MAXMEDIA_UB425_TC },
+       { USB_DEVICE(0x2304, 0x0242),
+                       .driver_info = EM2884_BOARD_PCTV_510E },
+       { USB_DEVICE(0x2013, 0x0251),
+                       .driver_info = EM2884_BOARD_PCTV_520E },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -3122,7 +3201,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        int i, nr;
        const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
        char *speed;
-       char descr[255] = "";
 
        udev = usb_get_dev(interface_to_usbdev(interface));
 
@@ -3227,21 +3305,11 @@ static int em28xx_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));
-
        printk(KERN_INFO DRIVER_NAME
-               ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n",
-               descr,
+               ": New device %s %s @ %s Mbps "
+               "(%04x:%04x, interface %d, class %d)\n",
+               udev->manufacturer ? udev->manufacturer : "",
+               udev->product ? udev->product : "",
                speed,
                le16_to_cpu(udev->descriptor.idVendor),
                le16_to_cpu(udev->descriptor.idProduct),
@@ -3307,6 +3375,17 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                goto unlock_and_free;
        }
 
+       if (has_dvb) {
+               /* pre-allocate DVB isoc transfer buffers */
+               retval = em28xx_alloc_isoc(dev, EM28XX_DIGITAL_MODE,
+                                          EM28XX_DVB_MAX_PACKETS,
+                                          EM28XX_DVB_NUM_BUFS,
+                                          dev->dvb_max_pkt_size);
+               if (retval) {
+                       goto unlock_and_free;
+               }
+       }
+
        request_modules(dev);
 
        /* Should be the last thing to do, to avoid newer udev's to
@@ -3379,7 +3458,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
                     video_device_node_name(dev->vdev));
 
                dev->state |= DEV_MISCONFIGURED;
-               em28xx_uninit_isoc(dev);
+               em28xx_uninit_isoc(dev, dev->mode);
                dev->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&dev->wait_frame);
                wake_up_interruptible(&dev->wait_stream);
@@ -3388,6 +3467,9 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
                em28xx_release_resources(dev);
        }
 
+       /* free DVB isoc buffers */
+       em28xx_uninit_isoc(dev, EM28XX_DIGITAL_MODE);
+
        mutex_unlock(&dev->lock);
 
        em28xx_close_extension(dev);
index 0aacc96..53a9fb9 100644 (file)
@@ -666,6 +666,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(em28xx_capture_start);
 
 int em28xx_vbi_supported(struct em28xx *dev)
 {
@@ -961,146 +962,192 @@ static void em28xx_irq_callback(struct urb *urb)
 /*
  * Stop and Deallocate URBs
  */
-void em28xx_uninit_isoc(struct em28xx *dev)
+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode)
 {
        struct urb *urb;
+       struct em28xx_usb_isoc_bufs *isoc_bufs;
        int i;
 
-       em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
+       em28xx_isocdbg("em28xx: called em28xx_uninit_isoc in mode %d\n", mode);
+
+       if (mode == EM28XX_DIGITAL_MODE)
+               isoc_bufs = &dev->isoc_ctl.digital_bufs;
+       else
+               isoc_bufs = &dev->isoc_ctl.analog_bufs;
 
        dev->isoc_ctl.nfields = -1;
-       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               urb = dev->isoc_ctl.urb[i];
+       for (i = 0; i < isoc_bufs->num_bufs; i++) {
+               urb = isoc_bufs->urb[i];
                if (urb) {
                        if (!irqs_disabled())
                                usb_kill_urb(urb);
                        else
                                usb_unlink_urb(urb);
 
-                       if (dev->isoc_ctl.transfer_buffer[i]) {
+                       if (isoc_bufs->transfer_buffer[i]) {
                                usb_free_coherent(dev->udev,
                                        urb->transfer_buffer_length,
-                                       dev->isoc_ctl.transfer_buffer[i],
+                                       isoc_bufs->transfer_buffer[i],
                                        urb->transfer_dma);
                        }
                        usb_free_urb(urb);
-                       dev->isoc_ctl.urb[i] = NULL;
+                       isoc_bufs->urb[i] = NULL;
                }
-               dev->isoc_ctl.transfer_buffer[i] = NULL;
+               isoc_bufs->transfer_buffer[i] = NULL;
        }
 
-       kfree(dev->isoc_ctl.urb);
-       kfree(dev->isoc_ctl.transfer_buffer);
+       kfree(isoc_bufs->urb);
+       kfree(isoc_bufs->transfer_buffer);
 
-       dev->isoc_ctl.urb = NULL;
-       dev->isoc_ctl.transfer_buffer = NULL;
-       dev->isoc_ctl.num_bufs = 0;
+       isoc_bufs->urb = NULL;
+       isoc_bufs->transfer_buffer = NULL;
+       isoc_bufs->num_bufs = 0;
 
        em28xx_capture_start(dev, 0);
 }
 EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
 
 /*
- * Allocate URBs and start IRQ
+ * Allocate URBs
  */
-int em28xx_init_isoc(struct em28xx *dev, int max_packets,
-                    int num_bufs, int max_pkt_size,
-                    int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
+                     int max_packets, int num_bufs, int max_pkt_size)
 {
-       struct em28xx_dmaqueue *dma_q = &dev->vidq;
-       struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+       struct em28xx_usb_isoc_bufs *isoc_bufs;
        int i;
        int sb_size, pipe;
        struct urb *urb;
        int j, k;
-       int rc;
 
-       em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
+       em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode);
+
+       if (mode == EM28XX_DIGITAL_MODE)
+               isoc_bufs = &dev->isoc_ctl.digital_bufs;
+       else
+               isoc_bufs = &dev->isoc_ctl.analog_bufs;
 
        /* De-allocates all pending stuff */
-       em28xx_uninit_isoc(dev);
+       em28xx_uninit_isoc(dev, mode);
 
-       dev->isoc_ctl.isoc_copy = isoc_copy;
-       dev->isoc_ctl.num_bufs = num_bufs;
+       isoc_bufs->num_bufs = num_bufs;
 
-       dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
-       if (!dev->isoc_ctl.urb) {
+       isoc_bufs->urb = kzalloc(sizeof(void *)*num_bufs,  GFP_KERNEL);
+       if (!isoc_bufs->urb) {
                em28xx_errdev("cannot alloc memory for usb buffers\n");
                return -ENOMEM;
        }
 
-       dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
-                                             GFP_KERNEL);
-       if (!dev->isoc_ctl.transfer_buffer) {
+       isoc_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+                                            GFP_KERNEL);
+       if (!isoc_bufs->transfer_buffer) {
                em28xx_errdev("cannot allocate memory for usb transfer\n");
-               kfree(dev->isoc_ctl.urb);
+               kfree(isoc_bufs->urb);
                return -ENOMEM;
        }
 
-       dev->isoc_ctl.max_pkt_size = max_pkt_size;
+       isoc_bufs->max_pkt_size = max_pkt_size;
+       isoc_bufs->num_packets = max_packets;
        dev->isoc_ctl.vid_buf = NULL;
        dev->isoc_ctl.vbi_buf = NULL;
 
-       sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+       sb_size = isoc_bufs->num_packets * isoc_bufs->max_pkt_size;
 
        /* allocate urbs and transfer buffers */
-       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+       for (i = 0; i < isoc_bufs->num_bufs; i++) {
+               urb = usb_alloc_urb(isoc_bufs->num_packets, GFP_KERNEL);
                if (!urb) {
                        em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
-                       em28xx_uninit_isoc(dev);
+                       em28xx_uninit_isoc(dev, mode);
                        return -ENOMEM;
                }
-               dev->isoc_ctl.urb[i] = urb;
+               isoc_bufs->urb[i] = urb;
 
-               dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+               isoc_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev,
                        sb_size, GFP_KERNEL, &urb->transfer_dma);
-               if (!dev->isoc_ctl.transfer_buffer[i]) {
+               if (!isoc_bufs->transfer_buffer[i]) {
                        em28xx_err("unable to allocate %i bytes for transfer"
                                        " buffer %i%s\n",
                                        sb_size, i,
                                        in_interrupt() ? " while in int" : "");
-                       em28xx_uninit_isoc(dev);
+                       em28xx_uninit_isoc(dev, mode);
                        return -ENOMEM;
                }
-               memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+               memset(isoc_bufs->transfer_buffer[i], 0, sb_size);
 
                /* FIXME: this is a hack - should be
                        'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
                        should also be using 'desc.bInterval'
                 */
                pipe = usb_rcvisocpipe(dev->udev,
-                                      dev->mode == EM28XX_ANALOG_MODE ?
+                                      mode == EM28XX_ANALOG_MODE ?
                                       EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL);
 
                usb_fill_int_urb(urb, dev->udev, pipe,
-                                dev->isoc_ctl.transfer_buffer[i], sb_size,
+                                isoc_bufs->transfer_buffer[i], sb_size,
                                 em28xx_irq_callback, dev, 1);
 
-               urb->number_of_packets = max_packets;
+               urb->number_of_packets = isoc_bufs->num_packets;
                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
 
                k = 0;
-               for (j = 0; j < max_packets; j++) {
+               for (j = 0; j < isoc_bufs->num_packets; j++) {
                        urb->iso_frame_desc[j].offset = k;
                        urb->iso_frame_desc[j].length =
-                                               dev->isoc_ctl.max_pkt_size;
-                       k += dev->isoc_ctl.max_pkt_size;
+                                               isoc_bufs->max_pkt_size;
+                       k += isoc_bufs->max_pkt_size;
                }
        }
 
+       return 0;
+}
+EXPORT_SYMBOL_GPL(em28xx_alloc_isoc);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
+                    int max_packets, int num_bufs, int max_pkt_size,
+                    int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
+{
+       struct em28xx_dmaqueue *dma_q = &dev->vidq;
+       struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
+       struct em28xx_usb_isoc_bufs *isoc_bufs;
+       int i;
+       int rc;
+       int alloc;
+
+       em28xx_isocdbg("em28xx: called em28xx_init_isoc in mode %d\n", mode);
+
+       dev->isoc_ctl.isoc_copy = isoc_copy;
+
+       if (mode == EM28XX_DIGITAL_MODE) {
+               isoc_bufs = &dev->isoc_ctl.digital_bufs;
+               /* no need to free/alloc isoc buffers in digital mode */
+               alloc = 0;
+       } else {
+               isoc_bufs = &dev->isoc_ctl.analog_bufs;
+               alloc = 1;
+       }
+
+       if (alloc) {
+               rc = em28xx_alloc_isoc(dev, mode, max_packets,
+                                      num_bufs, max_pkt_size);
+               if (rc)
+                       return rc;
+       }
+
        init_waitqueue_head(&dma_q->wq);
        init_waitqueue_head(&vbi_dma_q->wq);
 
        em28xx_capture_start(dev, 1);
 
        /* submit urbs and enables IRQ */
-       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
-               rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+       for (i = 0; i < isoc_bufs->num_bufs; i++) {
+               rc = usb_submit_urb(isoc_bufs->urb[i], GFP_ATOMIC);
                if (rc) {
                        em28xx_err("submit of urb %i failed (error=%i)\n", i,
                                   rc);
-                       em28xx_uninit_isoc(dev);
+                       em28xx_uninit_isoc(dev, mode);
                        return rc;
                }
        }
index aabbf48..503a8d5 100644 (file)
@@ -61,9 +61,6 @@ if (debug >= level)                                           \
        printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
 } while (0)
 
-#define EM28XX_DVB_NUM_BUFS 5
-#define EM28XX_DVB_MAX_PACKETS 64
-
 struct em28xx_dvb {
        struct dvb_frontend        *fe[2];
 
@@ -172,20 +169,21 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
        max_dvb_packet_size = dev->dvb_max_pkt_size;
        if (max_dvb_packet_size < 0)
                return max_dvb_packet_size;
-       dprintk(1, "Using %d buffers each with %d bytes\n",
+       dprintk(1, "Using %d buffers each with %d x %d bytes\n",
                EM28XX_DVB_NUM_BUFS,
+               EM28XX_DVB_MAX_PACKETS,
                max_dvb_packet_size);
 
-       return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
-                               EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
-                               em28xx_dvb_isoc_copy);
+       return em28xx_init_isoc(dev, EM28XX_DIGITAL_MODE,
+                               EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS,
+                               max_dvb_packet_size, em28xx_dvb_isoc_copy);
 }
 
 static int em28xx_stop_streaming(struct em28xx_dvb *dvb)
 {
        struct em28xx *dev = dvb->adapter.priv;
 
-       em28xx_uninit_isoc(dev);
+       em28xx_capture_start(dev, 0);
 
        em28xx_set_mode(dev, EM28XX_SUSPEND);
 
@@ -327,6 +325,19 @@ struct drxk_config hauppauge_930c_drxk = {
        .chunk_size = 56,
 };
 
+struct drxk_config maxmedia_ub425_tc_drxk = {
+       .adr = 0x29,
+       .single_master = 1,
+       .no_i2c_bridge = 1,
+};
+
+struct drxk_config pctv_520e_drxk = {
+       .adr = 0x29,
+       .single_master = 1,
+       .microcode_name = "dvb-demod-drxk-pctv.fw",
+       .chunk_size = 58,
+};
+
 static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        struct em28xx_dvb *dvb = fe->sec_priv;
@@ -460,6 +471,33 @@ static void terratec_h5_init(struct em28xx *dev)
        em28xx_gpio_set(dev, terratec_h5_end);
 };
 
+static void pctv_520e_init(struct em28xx *dev)
+{
+       /*
+        * Init TDA8295(?) analog demodulator. Looks like I2C traffic to
+        * digital demodulator and tuner are routed via TDA8295.
+        */
+       int i;
+       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},
+               {{ 0x01, 0x00, 0x03, 0xa0 }, 4},
+               {{ 0x01, 0x00 }, 2},
+               {{ 0x01, 0x00, 0x73, 0xaf }, 4},
+       };
+
+       dev->i2c_client.addr = 0x82 >> 1; /* 0x41 */
+
+       for (i = 0; i < ARRAY_SIZE(regs); i++)
+               i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+};
+
 static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
 {
        /* Values extracted from a USB trace of the Terratec Windows driver */
@@ -938,6 +976,48 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap,
                                &em28xx_a8293_config);
                break;
+       case EM2874_BOARD_MAXMEDIA_UB425_TC:
+               /* attach demodulator */
+               dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
+                               &dev->i2c_adap);
+
+               if (dvb->fe[0]) {
+                       /* disable I2C-gate */
+                       dvb->fe[0]->ops.i2c_gate_ctrl = NULL;
+
+                       /* attach tuner */
+                       if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
+                                       &dev->i2c_adap, 0x60)) {
+                               dvb_frontend_detach(dvb->fe[0]);
+                               result = -EINVAL;
+                               goto out_free;
+                       }
+               }
+
+               /* TODO: we need drx-3913k firmware in order to support DVB-T */
+               em28xx_info("MaxMedia UB425-TC: only DVB-C supported by that " \
+                               "driver version\n");
+
+               break;
+       case EM2884_BOARD_PCTV_510E:
+       case EM2884_BOARD_PCTV_520E:
+               pctv_520e_init(dev);
+
+               /* attach demodulator */
+               dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk,
+                               &dev->i2c_adap);
+
+               if (dvb->fe[0]) {
+                       /* attach tuner */
+                       if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+                                       &dev->i2c_adap,
+                                       &em28xx_cxd2820r_tda18271_config)) {
+                               dvb_frontend_detach(dvb->fe[0]);
+                               result = -EINVAL;
+                               goto out_free;
+                       }
+               }
+               break;
        default:
                em28xx_errdev("/2: The frontend of your DVB/ATSC card"
                                " isn't supported yet\n");
index 36f5a9b..a88e169 100644 (file)
@@ -41,14 +41,6 @@ static unsigned int i2c_debug;
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
-
-#define dprintk1(lvl, fmt, args...)                    \
-do {                                                   \
-       if (i2c_debug >= lvl) {                         \
-       printk(fmt, ##args);                            \
-      }                                                        \
-} while (0)
-
 #define dprintk2(lvl, fmt, args...)                    \
 do {                                                   \
        if (i2c_debug >= lvl) {                         \
index 613300b..324b695 100644 (file)
@@ -760,17 +760,19 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
                        goto fail;
        }
 
-       if (!dev->isoc_ctl.num_bufs)
+       if (!dev->isoc_ctl.analog_bufs.num_bufs)
                urb_init = 1;
 
        if (urb_init) {
                if (em28xx_vbi_supported(dev) == 1)
-                       rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+                       rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
+                                             EM28XX_NUM_PACKETS,
                                              EM28XX_NUM_BUFS,
                                              dev->max_pkt_size,
                                              em28xx_isoc_copy_vbi);
                else
-                       rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+                       rc = em28xx_init_isoc(dev, EM28XX_ANALOG_MODE,
+                                             EM28XX_NUM_PACKETS,
                                              EM28XX_NUM_BUFS,
                                              dev->max_pkt_size,
                                              em28xx_isoc_copy);
@@ -2267,7 +2269,7 @@ static int em28xx_v4l2_close(struct file *filp)
                v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
 
                /* do this before setting alternate! */
-               em28xx_uninit_isoc(dev);
+               em28xx_uninit_isoc(dev, EM28XX_ANALOG_MODE);
                em28xx_set_mode(dev, EM28XX_SUSPEND);
 
                /* set alternate 0 */
index 22e252b..2868b19 100644 (file)
 #define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C    81
 #define EM2884_BOARD_CINERGY_HTC_STICK           82
 #define EM2860_BOARD_HT_VIDBOX_NW03              83
+#define EM2874_BOARD_MAXMEDIA_UB425_TC            84
+#define EM2884_BOARD_PCTV_510E                    85
+#define EM2884_BOARD_PCTV_520E                    86
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
 
 /* number of buffers for isoc transfers */
 #define EM28XX_NUM_BUFS 5
+#define EM28XX_DVB_NUM_BUFS 5
 
 /* number of packets for each buffer
    windows requests only 64 packets .. so we better do the same
    this is what I found out for all alternate numbers there!
  */
 #define EM28XX_NUM_PACKETS 64
+#define EM28XX_DVB_MAX_PACKETS 64
 
 #define EM28XX_INTERLACED_DEFAULT 1
 
@@ -197,10 +202,13 @@ enum em28xx_mode {
 
 struct em28xx;
 
-struct em28xx_usb_isoc_ctl {
+struct em28xx_usb_isoc_bufs {
                /* max packet size of isoc transaction */
        int                             max_pkt_size;
 
+               /* number of packets in each buffer */
+       int                             num_packets;
+
                /* number of allocated urbs */
        int                             num_bufs;
 
@@ -209,6 +217,14 @@ struct em28xx_usb_isoc_ctl {
 
                /* transfer buffers for isoc transfer */
        char                            **transfer_buffer;
+};
+
+struct em28xx_usb_isoc_ctl {
+               /* isoc transfer buffers for analog mode */
+       struct em28xx_usb_isoc_bufs     analog_bufs;
+
+               /* isoc transfer buffers for digital mode */
+       struct em28xx_usb_isoc_bufs     digital_bufs;
 
                /* Last buffer command and region */
        u8                              cmd;
@@ -600,9 +616,6 @@ struct em28xx {
        unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
        int dvb_alt;                            /* alternate for DVB */
        unsigned int dvb_max_pkt_size;          /* wMaxPacketSize for DVB */
-       struct urb *urb[EM28XX_NUM_BUFS];       /* urb for isoc transfers */
-       char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc
-                                                  transfer */
        char urb_buf[URB_MAX_CTRL_SIZE];        /* urb control msg buffer */
 
        /* helper funcs that call usb_control_msg */
@@ -676,10 +689,12 @@ int em28xx_vbi_supported(struct em28xx *dev);
 int em28xx_set_outfmt(struct em28xx *dev);
 int em28xx_resolution_set(struct em28xx *dev);
 int em28xx_set_alternate(struct em28xx *dev);
-int em28xx_init_isoc(struct em28xx *dev, int max_packets,
-                    int num_bufs, int max_pkt_size,
+int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
+                     int max_packets, int num_bufs, int max_pkt_size);
+int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
+                    int max_packets, int num_bufs, int max_pkt_size,
                     int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
-void em28xx_uninit_isoc(struct em28xx *dev);
+void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode);
 int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
index f511ecc..773ea34 100644 (file)
@@ -6,5 +6,5 @@ gspca_gl860-objs := gl860.o \
                    gl860-ov9655.o \
                    gl860-mi2020.o
 
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
 
index 7f52961..575b75b 100644 (file)
@@ -8,4 +8,4 @@ gspca_m5602-objs := m5602_core.o \
                    m5602_s5k83a.o \
                    m5602_s5k4aa.o
 
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
index fbfa02a..e6601b8 100644 (file)
@@ -1107,16 +1107,34 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 val;
+       s8 sval;
 
        if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS))
                return;
-       val = sd->ctrls[BRIGHTNESS].val;
-       if (val < 8)
-               val = 15 - val;         /* f .. 8 */
-       else
-               val = val - 8;          /* 0 .. 7 */
-       sccb_write(gspca_dev, 0x55,     /* brtn - brightness adjustment */
-                       0x0f | (val << 4));
+       if (sd->sensor == SENSOR_OV562x) {
+               sval = sd->ctrls[BRIGHTNESS].val;
+               val = 0x76;
+               val += sval;
+               sccb_write(gspca_dev, 0x24, val);
+               val = 0x6a;
+               val += sval;
+               sccb_write(gspca_dev, 0x25, val);
+               if (sval < -40)
+                       val = 0x71;
+               else if (sval < 20)
+                       val = 0x94;
+               else
+                       val = 0xe6;
+               sccb_write(gspca_dev, 0x26, val);
+       } else {
+               val = sd->ctrls[BRIGHTNESS].val;
+               if (val < 8)
+                       val = 15 - val;         /* f .. 8 */
+               else
+                       val = val - 8;          /* 0 .. 7 */
+               sccb_write(gspca_dev, 0x55,     /* brtn - brightness adjustment */
+                               0x0f | (val << 4));
+       }
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
@@ -1339,7 +1357,16 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        reg_w(gspca_dev, 0x56, 0x17);
        } else if ((sensor_id & 0xfff0) == 0x5620) {
                sd->sensor = SENSOR_OV562x;
-
+               gspca_dev->ctrl_dis = (1 << CONTRAST) |
+                                       (1 << AUTOGAIN) |
+                                       (1 << EXPOSURE) |
+                                       (1 << SHARPNESS) |
+                                       (1 << SATUR) |
+                                       (1 << LIGHTFREQ);
+
+               sd->ctrls[BRIGHTNESS].min = -90;
+               sd->ctrls[BRIGHTNESS].max = 90;
+               sd->ctrls[BRIGHTNESS].def = 0;
                gspca_dev->cam.cam_mode = ov562x_mode;
                gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode);
 
@@ -1360,8 +1387,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (sd->sensor == SENSOR_OV971x || sd->sensor == SENSOR_OV562x)
+       if (sd->sensor == SENSOR_OV971x)
                return gspca_dev->usb_err;
+       else if (sd->sensor == SENSOR_OV562x) {
+               setbrightness(gspca_dev);
+               return gspca_dev->usb_err;
+       }
        switch (gspca_dev->curr_mode) {
        case QVGA_MODE:                 /* 320x240 */
                sccb_w_array(gspca_dev, ov965x_start_1_vga,
index 9db2b34..30662fc 100644 (file)
@@ -1,8 +1,8 @@
 /*
- *             Pixart PAC7302 library
- *             Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ * Pixart PAC7302 driver
  *
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2008-2012 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
  *
  * Separated from Pixart PAC7311 library by Márton Németh
  * Camera button input handling by Márton Németh <nm127@freemail.hu>
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#define MODULE_NAME "pac7302"
-
 #include <linux/input.h>
 #include <media/v4l2-chip-ident.h>
 #include "gspca.h"
+/* Include pac common sof detection functions */
+#include "pac_common.h"
 
-MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
+               "Thomas Kaiser thomas@kaiser-linux.li");
 MODULE_DESCRIPTION("Pixart PAC7302");
 MODULE_LICENSE("GPL");
 
+enum e_ctrl {
+       BRIGHTNESS,
+       CONTRAST,
+       COLORS,
+       WHITE_BALANCE,
+       RED_BALANCE,
+       BLUE_BALANCE,
+       GAIN,
+       AUTOGAIN,
+       EXPOSURE,
+       VFLIP,
+       HFLIP,
+       NCTRLS          /* number of controls */
+};
+
 /* specific webcam descriptor for pac7302 */
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
-       unsigned char brightness;
-       unsigned char contrast;
-       unsigned char colors;
-       unsigned char white_balance;
-       unsigned char red_balance;
-       unsigned char blue_balance;
-       unsigned char gain;
-       unsigned char autogain;
-       unsigned short exposure;
-       __u8 hflip;
-       __u8 vflip;
+       struct gspca_ctrl ctrls[NCTRLS];
+
        u8 flags;
 #define FL_HFLIP 0x01          /* mirrored by default */
 #define FL_VFLIP 0x02          /* vertical flipped by default */
 
        u8 sof_read;
-       u8 autogain_ignore_frames;
+       s8 autogain_ignore_frames;
 
        atomic_t avg_lum;
 };
 
 /* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightcont(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setwhitebalance(struct gspca_dev *gspca_dev);
+static void setredbalance(struct gspca_dev *gspca_dev);
+static void setbluebalance(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static void setautogain(struct gspca_dev *gspca_dev);
+static void sethvflip(struct gspca_dev *gspca_dev);
 
 static const struct ctrl sd_ctrls[] = {
-       {
+[BRIGHTNESS] = {
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -132,13 +126,11 @@ static const struct ctrl sd_ctrls[] = {
 #define BRIGHTNESS_MAX 0x20
                .maximum = BRIGHTNESS_MAX,
                .step    = 1,
-#define BRIGHTNESS_DEF 0x10
-               .default_value = BRIGHTNESS_DEF,
+               .default_value = 0x10,
            },
-           .set = sd_setbrightness,
-           .get = sd_getbrightness,
+           .set_control = setbrightcont
        },
-       {
+[CONTRAST] = {
            {
                .id      = V4L2_CID_CONTRAST,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -147,13 +139,11 @@ static const struct ctrl sd_ctrls[] = {
 #define CONTRAST_MAX 255
                .maximum = CONTRAST_MAX,
                .step    = 1,
-#define CONTRAST_DEF 127
-               .default_value = CONTRAST_DEF,
+               .default_value = 127,
            },
-           .set = sd_setcontrast,
-           .get = sd_getcontrast,
+           .set_control = setbrightcont
        },
-       {
+[COLORS] = {
            {
                .id      = V4L2_CID_SATURATION,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -162,13 +152,11 @@ static const struct ctrl sd_ctrls[] = {
 #define COLOR_MAX 255
                .maximum = COLOR_MAX,
                .step    = 1,
-#define COLOR_DEF 127
-               .default_value = COLOR_DEF,
+               .default_value = 127
            },
-           .set = sd_setcolors,
-           .get = sd_getcolors,
+           .set_control = setcolors
        },
-       {
+[WHITE_BALANCE] = {
            {
                .id      = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -176,13 +164,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 255,
                .step    = 1,
-#define WHITEBALANCE_DEF 4
-               .default_value = WHITEBALANCE_DEF,
+               .default_value = 4,
            },
-           .set = sd_setwhitebalance,
-           .get = sd_getwhitebalance,
+           .set_control = setwhitebalance
        },
-       {
+[RED_BALANCE] = {
            {
                .id      = V4L2_CID_RED_BALANCE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -190,13 +176,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 3,
                .step    = 1,
-#define REDBALANCE_DEF 1
-               .default_value = REDBALANCE_DEF,
+               .default_value = 1,
            },
-           .set = sd_setredbalance,
-           .get = sd_getredbalance,
+           .set_control = setredbalance
        },
-       {
+[BLUE_BALANCE] = {
            {
                .id      = V4L2_CID_BLUE_BALANCE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -204,29 +188,25 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 3,
                .step    = 1,
-#define BLUEBALANCE_DEF 1
-               .default_value = BLUEBALANCE_DEF,
+               .default_value = 1,
            },
-           .set = sd_setbluebalance,
-           .get = sd_getbluebalance,
+           .set_control = setbluebalance
        },
-       {
+[GAIN] = {
            {
                .id      = V4L2_CID_GAIN,
                .type    = V4L2_CTRL_TYPE_INTEGER,
                .name    = "Gain",
                .minimum = 0,
-#define GAIN_MAX 255
-               .maximum = GAIN_MAX,
+               .maximum = 255,
                .step    = 1,
 #define GAIN_DEF 127
 #define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
                .default_value = GAIN_DEF,
            },
-           .set = sd_setgain,
-           .get = sd_getgain,
+           .set_control = setgain
        },
-       {
+[EXPOSURE] = {
            {
                .id      = V4L2_CID_EXPOSURE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -238,10 +218,9 @@ static const struct ctrl sd_ctrls[] = {
 #define EXPOSURE_KNEE 133 /*  66 ms / 15 fps */
                .default_value = EXPOSURE_DEF,
            },
-           .set = sd_setexposure,
-           .get = sd_getexposure,
+           .set_control = setexposure
        },
-       {
+[AUTOGAIN] = {
            {
                .id      = V4L2_CID_AUTOGAIN,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -252,10 +231,9 @@ static const struct ctrl sd_ctrls[] = {
 #define AUTOGAIN_DEF 1
                .default_value = AUTOGAIN_DEF,
            },
-           .set = sd_setautogain,
-           .get = sd_getautogain,
+           .set_control = setautogain,
        },
-       {
+[HFLIP] = {
            {
                .id      = V4L2_CID_HFLIP,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -263,13 +241,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define HFLIP_DEF 0
-               .default_value = HFLIP_DEF,
+               .default_value = 0,
            },
-           .set = sd_sethflip,
-           .get = sd_gethflip,
+           .set_control = sethvflip,
        },
-       {
+[VFLIP] = {
            {
                .id      = V4L2_CID_VFLIP,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -277,11 +253,9 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define VFLIP_DEF 0
-               .default_value = VFLIP_DEF,
+               .default_value = 0,
            },
-           .set = sd_setvflip,
-           .get = sd_getvflip,
+           .set_control = sethvflip
        },
 };
 
@@ -290,21 +264,21 @@ static const struct v4l2_pix_format vga_mode[] = {
                .bytesperline = 640,
                .sizeimage = 640 * 480 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
-               .priv = 0},
+       },
 };
 
 #define LOAD_PAGE3             255
 #define END_OF_SEQUENCE                0
 
 /* pac 7302 */
-static const __u8 init_7302[] = {
+static const u8 init_7302[] = {
 /*     index,value */
        0xff, 0x01,             /* page 1 */
        0x78, 0x00,             /* deactivate */
        0xff, 0x01,
        0x78, 0x40,             /* led off */
 };
-static const __u8 start_7302[] = {
+static const u8 start_7302[] = {
 /*     index, len, [value]* */
        0xff, 1,        0x00,           /* page 0 */
        0x00, 12,       0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
@@ -319,7 +293,7 @@ static const __u8 start_7302[] = {
        0x43, 11,       0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
                        0x00, 0x54, 0x11,
        0x55, 1,        0x00,
-       0x62, 4,        0x10, 0x1e, 0x1e, 0x18,
+       0x62, 4,        0x10, 0x1e, 0x1e, 0x18,
        0x6b, 1,        0x00,
        0x6e, 3,        0x08, 0x06, 0x00,
        0x72, 3,        0x00, 0xff, 0x00,
@@ -370,7 +344,7 @@ static const __u8 start_7302[] = {
 
 #define SKIP           0xaa
 /* page 3 - the value SKIP says skip the index - see reg_w_page() */
-static const __u8 page3_7302[] = {
+static const u8 page3_7302[] = {
        0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
        0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
        0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -394,7 +368,7 @@ static const __u8 page3_7302[] = {
 };
 
 static void reg_w_buf(struct gspca_dev *gspca_dev,
-                 __u8 index,
+               u8 index,
                  const u8 *buffer, int len)
 {
        int ret;
@@ -410,7 +384,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, len,
                        500);
        if (ret < 0) {
-               pr_err("reg_w_buf failed index 0x%02x, error %d\n",
+               pr_err("reg_w_buf failed i: %02x error %d\n",
                       index, ret);
                gspca_dev->usb_err = ret;
        }
@@ -418,8 +392,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
 
 
 static void reg_w(struct gspca_dev *gspca_dev,
-                 __u8 index,
-                 __u8 value)
+               u8 index,
+               u8 value)
 {
        int ret;
 
@@ -433,14 +407,14 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        0, index, gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
+               pr_err("reg_w() failed i: %02x v: %02x error %d\n",
                       index, value, ret);
                gspca_dev->usb_err = ret;
        }
 }
 
 static void reg_w_seq(struct gspca_dev *gspca_dev,
-               const __u8 *seq, int len)
+               const u8 *seq, int len)
 {
        while (--len >= 0) {
                reg_w(gspca_dev, seq[0], seq[1]);
@@ -450,7 +424,7 @@ static void reg_w_seq(struct gspca_dev *gspca_dev,
 
 /* load the beginning of a page */
 static void reg_w_page(struct gspca_dev *gspca_dev,
-                       const __u8 *page, int len)
+                       const u8 *page, int len)
 {
        int index;
        int ret = 0;
@@ -468,7 +442,7 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
                                0, index, gspca_dev->usb_buf, 1,
                                500);
                if (ret < 0) {
-                       pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
+                       pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
                               index, page[index], ret);
                        gspca_dev->usb_err = ret;
                        break;
@@ -478,8 +452,8 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
 
 /* output a variable sequence */
 static void reg_w_var(struct gspca_dev *gspca_dev,
-                       const __u8 *seq,
-                       const __u8 *page3, unsigned int page3_len)
+                       const u8 *seq,
+                       const u8 *page3, unsigned int page3_len)
 {
        int index, len;
 
@@ -493,11 +467,13 @@ static void reg_w_var(struct gspca_dev *gspca_dev,
                        reg_w_page(gspca_dev, page3, page3_len);
                        break;
                default:
+#ifdef GSPCA_DEBUG
                        if (len > USB_BUF_SZ) {
                                PDEBUG(D_ERR|D_STREAM,
                                        "Incorrect variable sequence");
                                return;
                        }
+#endif
                        while (len > 0) {
                                if (len < 8) {
                                        reg_w_buf(gspca_dev,
@@ -524,21 +500,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        cam = &gspca_dev->cam;
 
-       PDEBUG(D_CONF, "Find Sensor PAC7302");
        cam->cam_mode = vga_mode;       /* only 640x480 */
        cam->nmodes = ARRAY_SIZE(vga_mode);
 
-       sd->brightness = BRIGHTNESS_DEF;
-       sd->contrast = CONTRAST_DEF;
-       sd->colors = COLOR_DEF;
-       sd->white_balance = WHITEBALANCE_DEF;
-       sd->red_balance = REDBALANCE_DEF;
-       sd->blue_balance = BLUEBALANCE_DEF;
-       sd->gain = GAIN_DEF;
-       sd->exposure = EXPOSURE_DEF;
-       sd->autogain = AUTOGAIN_DEF;
-       sd->hflip = HFLIP_DEF;
-       sd->vflip = VFLIP_DEF;
+       gspca_dev->cam.ctrls = sd->ctrls;
+
        sd->flags = id->driver_info;
        return 0;
 }
@@ -548,19 +514,19 @@ static void setbrightcont(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i, v;
-       static const __u8 max[10] =
+       static const u8 max[10] =
                {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
                 0xd4, 0xec};
-       static const __u8 delta[10] =
+       static const u8 delta[10] =
                {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
                 0x11, 0x0b};
 
        reg_w(gspca_dev, 0xff, 0x00);           /* page 0 */
        for (i = 0; i < 10; i++) {
                v = max[i];
-               v += (sd->brightness - BRIGHTNESS_MAX)
+               v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX)
                        * 150 / BRIGHTNESS_MAX;         /* 200 ? */
-               v -= delta[i] * sd->contrast / CONTRAST_MAX;
+               v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX;
                if (v < 0)
                        v = 0;
                else if (v > 0xff)
@@ -584,12 +550,11 @@ static void setcolors(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0x11, 0x01);
        reg_w(gspca_dev, 0xff, 0x00);                   /* page 0 */
        for (i = 0; i < 9; i++) {
-               v = a[i] * sd->colors / COLOR_MAX + b[i];
+               v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i];
                reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
                reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
        }
        reg_w(gspca_dev, 0xdc, 0x01);
-       PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
 }
 
 static void setwhitebalance(struct gspca_dev *gspca_dev)
@@ -597,10 +562,9 @@ static void setwhitebalance(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        reg_w(gspca_dev, 0xff, 0x00);           /* page 0 */
-       reg_w(gspca_dev, 0xc6, sd->white_balance);
+       reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val);
 
        reg_w(gspca_dev, 0xdc, 0x01);
-       PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
 }
 
 static void setredbalance(struct gspca_dev *gspca_dev)
@@ -608,10 +572,9 @@ static void setredbalance(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        reg_w(gspca_dev, 0xff, 0x00);           /* page 0 */
-       reg_w(gspca_dev, 0xc5, sd->red_balance);
+       reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val);
 
        reg_w(gspca_dev, 0xdc, 0x01);
-       PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
 }
 
 static void setbluebalance(struct gspca_dev *gspca_dev)
@@ -619,10 +582,9 @@ static void setbluebalance(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        reg_w(gspca_dev, 0xff, 0x00);                   /* page 0 */
-       reg_w(gspca_dev, 0xc7, sd->blue_balance);
+       reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val);
 
        reg_w(gspca_dev, 0xdc, 0x01);
-       PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
 }
 
 static void setgain(struct gspca_dev *gspca_dev)
@@ -630,7 +592,7 @@ static void setgain(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        reg_w(gspca_dev, 0xff, 0x03);                   /* page 3 */
-       reg_w(gspca_dev, 0x10, sd->gain >> 3);
+       reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3);
 
        /* load registers to sensor (Bit 0, auto clear) */
        reg_w(gspca_dev, 0x11, 0x01);
@@ -639,13 +601,13 @@ static void setgain(struct gspca_dev *gspca_dev)
 static void setexposure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 clockdiv;
-       __u16 exposure;
+       u8 clockdiv;
+       u16 exposure;
 
        /* register 2 of frame 3 contains the clock divider configuring the
           no fps according to the formula: 90 / reg. sd->exposure is the
           desired exposure time in 0.5 ms. */
-       clockdiv = (90 * sd->exposure + 1999) / 2000;
+       clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000;
 
        /* Note clockdiv = 3 also works, but when running at 30 fps, depending
           on the scene being recorded, the camera switches to another
@@ -664,7 +626,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
 
        /* frame exposure time in ms = 1000 * clockdiv / 90    ->
        exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
-       exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv);
+       exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv);
        /* 0 = use full frametime, 448 = no exposure, reverse it */
        exposure = 448 - exposure;
 
@@ -677,15 +639,35 @@ static void setexposure(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0x11, 0x01);
 }
 
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* when switching to autogain set defaults to make sure
+          we are on a valid point of the autogain gain /
+          exposure knee graph, and give this change time to
+          take effect before doing autogain. */
+       if (sd->ctrls[AUTOGAIN].val) {
+               sd->ctrls[EXPOSURE].val = EXPOSURE_DEF;
+               sd->ctrls[GAIN].val = GAIN_DEF;
+               sd->autogain_ignore_frames =
+                               PAC_AUTOGAIN_IGNORE_FRAMES;
+       } else {
+               sd->autogain_ignore_frames = -1;
+       }
+       setexposure(gspca_dev);
+       setgain(gspca_dev);
+}
+
 static void sethvflip(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 data, hflip, vflip;
 
-       hflip = sd->hflip;
+       hflip = sd->ctrls[HFLIP].val;
        if (sd->flags & FL_HFLIP)
                hflip = !hflip;
-       vflip = sd->vflip;
+       vflip = sd->ctrls[VFLIP].val;
        if (sd->flags & FL_VFLIP)
                vflip = !vflip;
 
@@ -708,8 +690,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->sof_read = 0;
-
        reg_w_var(gspca_dev, start_7302,
                page3_7302, sizeof(page3_7302));
        setbrightcont(gspca_dev);
@@ -717,15 +697,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
        setwhitebalance(gspca_dev);
        setredbalance(gspca_dev);
        setbluebalance(gspca_dev);
-       setgain(gspca_dev);
-       setexposure(gspca_dev);
+       setautogain(gspca_dev);
        sethvflip(gspca_dev);
 
        /* only resolution 640x480 is supported for pac7302 */
 
        sd->sof_read = 0;
-       sd->autogain_ignore_frames = 0;
-       atomic_set(&sd->avg_lum, -1);
+       atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val);
 
        /* start stream */
        reg_w(gspca_dev, 0xff, 0x01);
@@ -751,8 +729,10 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0x78, 0x40);
 }
 
-/* Include pac common sof detection functions */
-#include "pac_common.h"
+/* !! coarse_grained_expo_autogain is not used !! */
+#define exp_too_low_cnt flags
+#define exp_too_high_cnt sof_read
+#include "autogain_functions.h"
 
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
@@ -761,65 +741,44 @@ static void do_autogain(struct gspca_dev *gspca_dev)
        int desired_lum;
        const int deadzone = 30;
 
-       if (avg_lum == -1)
+       if (sd->autogain_ignore_frames < 0)
                return;
 
-       desired_lum = 270 + sd->brightness;
-
-       if (sd->autogain_ignore_frames > 0)
+       if (sd->autogain_ignore_frames > 0) {
                sd->autogain_ignore_frames--;
-       else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
-                       deadzone, GAIN_KNEE, EXPOSURE_KNEE))
+       } else {
+               desired_lum = 270 + sd->ctrls[BRIGHTNESS].val;
+
+               auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+                               deadzone, GAIN_KNEE, EXPOSURE_KNEE);
                sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
+       }
 }
 
-/* JPEG header, part 1 */
-static const unsigned char pac_jpeg_header1[] = {
-  0xff, 0xd8,          /* SOI: Start of Image */
-
-  0xff, 0xc0,          /* SOF0: Start of Frame (Baseline DCT) */
-  0x00, 0x11,          /* length = 17 bytes (including this length field) */
-  0x08                 /* Precision: 8 */
-  /* 2 bytes is placed here: number of image lines */
-  /* 2 bytes is placed here: samples per line */
-};
-
-/* JPEG header, continued */
-static const unsigned char pac_jpeg_header2[] = {
-  0x03,                        /* Number of image components: 3 */
-  0x01, 0x21, 0x00,    /* ID=1, Subsampling 1x1, Quantization table: 0 */
-  0x02, 0x11, 0x01,    /* ID=2, Subsampling 2x1, Quantization table: 1 */
-  0x03, 0x11, 0x01,    /* ID=3, Subsampling 2x1, Quantization table: 1 */
-
-  0xff, 0xda,          /* SOS: Start Of Scan */
-  0x00, 0x0c,          /* length = 12 bytes (including this length field) */
-  0x03,                        /* number of components: 3 */
-  0x01, 0x00,          /* selector 1, table 0x00 */
-  0x02, 0x11,          /* selector 2, table 0x11 */
-  0x03, 0x11,          /* selector 3, table 0x11 */
-  0x00, 0x3f,          /* Spectral selection: 0 .. 63 */
-  0x00                 /* Successive approximation: 0 */
+/* JPEG header */
+static const u8 jpeg_header[] = {
+       0xff, 0xd8,     /* SOI: Start of Image */
+
+       0xff, 0xc0,     /* SOF0: Start of Frame (Baseline DCT) */
+       0x00, 0x11,     /* length = 17 bytes (including this length field) */
+       0x08,           /* Precision: 8 */
+       0x02, 0x80,     /* height = 640 (image rotated) */
+       0x01, 0xe0,     /* width = 480 */
+       0x03,           /* Number of image components: 3 */
+       0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
+       0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
+       0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
+
+       0xff, 0xda,     /* SOS: Start Of Scan */
+       0x00, 0x0c,     /* length = 12 bytes (including this length field) */
+       0x03,           /* number of components: 3 */
+       0x01, 0x00,     /* selector 1, table 0x00 */
+       0x02, 0x11,     /* selector 2, table 0x11 */
+       0x03, 0x11,     /* selector 3, table 0x11 */
+       0x00, 0x3f,     /* Spectral selection: 0 .. 63 */
+       0x00            /* Successive approximation: 0 */
 };
 
-static void pac_start_frame(struct gspca_dev *gspca_dev,
-               __u16 lines, __u16 samples_per_line)
-{
-       unsigned char tmpbuf[4];
-
-       gspca_frame_add(gspca_dev, FIRST_PACKET,
-               pac_jpeg_header1, sizeof(pac_jpeg_header1));
-
-       tmpbuf[0] = lines >> 8;
-       tmpbuf[1] = lines & 0xff;
-       tmpbuf[2] = samples_per_line >> 8;
-       tmpbuf[3] = samples_per_line & 0xff;
-
-       gspca_frame_add(gspca_dev, INTER_PACKET,
-               tmpbuf, sizeof(tmpbuf));
-       gspca_frame_add(gspca_dev, INTER_PACKET,
-               pac_jpeg_header2, sizeof(pac_jpeg_header2));
-}
-
 /* this function is run at interrupt level */
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,                       /* isoc packet */
@@ -827,7 +786,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 *image;
-       unsigned char *sof;
+       u8 *sof;
 
        sof = pac_find_sof(&sd->sof_read, data, len);
        if (sof) {
@@ -864,234 +823,21 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                n >= lum_offset)
                        atomic_set(&sd->avg_lum, data[-lum_offset] +
                                                data[-lum_offset + 1]);
-               else
-                       atomic_set(&sd->avg_lum, -1);
 
                /* Start the new frame with the jpeg header */
                /* The PAC7302 has the image rotated 90 degrees */
-               pac_start_frame(gspca_dev,
-                       gspca_dev->width, gspca_dev->height);
+               gspca_frame_add(gspca_dev, FIRST_PACKET,
+                               jpeg_header, sizeof jpeg_header);
        }
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 }
 
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->brightness = val;
-       if (gspca_dev->streaming)
-               setbrightcont(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->brightness;
-       return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->contrast = val;
-       if (gspca_dev->streaming)
-               setbrightcont(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->contrast;
-       return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->colors = val;
-       if (gspca_dev->streaming)
-               setcolors(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->colors;
-       return 0;
-}
-
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->white_balance = val;
-       if (gspca_dev->streaming)
-               setwhitebalance(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->white_balance;
-       return 0;
-}
-
-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->red_balance = val;
-       if (gspca_dev->streaming)
-               setredbalance(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->red_balance;
-       return 0;
-}
-
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->blue_balance = val;
-       if (gspca_dev->streaming)
-               setbluebalance(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->blue_balance;
-       return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->gain = val;
-       if (gspca_dev->streaming)
-               setgain(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->gain;
-       return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->exposure = val;
-       if (gspca_dev->streaming)
-               setexposure(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->exposure;
-       return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->autogain = val;
-       /* when switching to autogain set defaults to make sure
-          we are on a valid point of the autogain gain /
-          exposure knee graph, and give this change time to
-          take effect before doing autogain. */
-       if (sd->autogain) {
-               sd->exposure = EXPOSURE_DEF;
-               sd->gain = GAIN_DEF;
-               if (gspca_dev->streaming) {
-                       sd->autogain_ignore_frames =
-                               PAC_AUTOGAIN_IGNORE_FRAMES;
-                       setexposure(gspca_dev);
-                       setgain(gspca_dev);
-               }
-       }
-
-       return gspca_dev->usb_err;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->autogain;
-       return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->hflip = val;
-       if (gspca_dev->streaming)
-               sethvflip(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->hflip;
-       return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->vflip = val;
-       if (gspca_dev->streaming)
-               sethvflip(gspca_dev);
-       return gspca_dev->usb_err;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       *val = sd->vflip;
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
                        struct v4l2_dbg_register *reg)
 {
-       __u8 index;
-       __u8 value;
+       u8 index;
+       u8 value;
 
        /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
                               long on the USB bus)
@@ -1103,8 +849,8 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
        ) {
                /* Currently writing to page 0 is only supported. */
                /* reg_w() only supports 8bit index */
-               index = reg->reg & 0x000000ff;
-               value = reg->val & 0x000000ff;
+               index = reg->reg;
+               value = reg->val;
 
                /* Note that there shall be no access to other page
                   by any other function between the page swith and
@@ -1165,7 +911,7 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
 
 /* sub-driver description for pac7302 */
 static const struct sd_desc sd_desc = {
-       .name = MODULE_NAME,
+       .name = KBUILD_MODNAME,
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
@@ -1187,6 +933,7 @@ static const struct sd_desc sd_desc = {
 /* -- module initialisation -- */
 static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x06f8, 0x3009)},
+       {USB_DEVICE(0x06f8, 0x301b)},
        {USB_DEVICE(0x093a, 0x2620)},
        {USB_DEVICE(0x093a, 0x2621)},
        {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
@@ -1211,7 +958,7 @@ static int sd_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver sd_driver = {
-       .name = MODULE_NAME,
+       .name = KBUILD_MODNAME,
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
index 9e198b4..7e71aa2 100644 (file)
@@ -1,5 +1,7 @@
 /*
  *     Sonix sn9c201 sn9c202 library
+ *
+ * Copyright (C) 2012 Jean-Francois Moine <http://moinejf.free.fr>
  *     Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
  *     Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
  *
@@ -33,8 +35,6 @@ MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
 MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define MODULE_NAME "sn9c20x"
-
 /*
  * Pixel format private data
  */
@@ -66,10 +66,37 @@ MODULE_LICENSE("GPL");
 #define LED_REVERSE    0x2 /* some cameras unset gpio to turn on leds */
 #define FLIP_DETECT    0x4
 
+enum e_ctrl {
+       BRIGHTNESS,
+       CONTRAST,
+       SATURATION,
+       HUE,
+       GAMMA,
+       BLUE,
+       RED,
+       VFLIP,
+       HFLIP,
+       EXPOSURE,
+       GAIN,
+       AUTOGAIN,
+       QUALITY,
+       NCTRLS          /* number of controls */
+};
+
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;
 
+       struct gspca_ctrl ctrls[NCTRLS];
+
+       struct work_struct work;
+       struct workqueue_struct *work_thread;
+
+       u32 pktsz;                      /* (used by pkt_scan) */
+       u16 npkt;
+       s8 nchg;
+       u8 fmt;                         /* (used for JPEG QTAB update */
+
 #define MIN_AVG_LUM 80
 #define MAX_AVG_LUM 130
        atomic_t avg_lum;
@@ -77,31 +104,18 @@ struct sd {
        u8 older_step;
        u8 exposure_step;
 
-       u8 brightness;
-       u8 contrast;
-       u8 saturation;
-       s16 hue;
-       u8 gamma;
-       u8 red;
-       u8 blue;
-
-       u8 hflip;
-       u8 vflip;
-       u8 gain;
-       u16 exposure;
-       u8 auto_exposure;
-
        u8 i2c_addr;
        u8 sensor;
        u8 hstart;
        u8 vstart;
 
        u8 jpeg_hdr[JPEG_HDR_SZ];
-       u8 quality;
 
        u8 flags;
 };
 
+static void qual_upd(struct work_struct *work);
+
 struct i2c_reg_u8 {
        u8 reg;
        u8 val;
@@ -112,31 +126,6 @@ struct i2c_reg_u16 {
        u16 val;
 };
 
-static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_sethue(struct gspca_dev *gspca_dev, s32 val);
-static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
-
 static const struct dmi_system_id flip_dmi_table[] = {
        {
                .ident = "MSI MS-1034",
@@ -177,9 +166,16 @@ static const struct dmi_system_id flip_dmi_table[] = {
        {}
 };
 
-static const struct ctrl sd_ctrls[] = {
-       {
-#define BRIGHTNESS_IDX 0
+static void set_cmatrix(struct gspca_dev *gspca_dev);
+static void set_gamma(struct gspca_dev *gspca_dev);
+static void set_redblue(struct gspca_dev *gspca_dev);
+static void set_hvflip(struct gspca_dev *gspca_dev);
+static void set_exposure(struct gspca_dev *gspca_dev);
+static void set_gain(struct gspca_dev *gspca_dev);
+static void set_quality(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -187,14 +183,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 0xff,
                .step    = 1,
-#define BRIGHTNESS_DEFAULT 0x7f
-               .default_value = BRIGHTNESS_DEFAULT,
+               .default_value = 0x7f
            },
-           .set = sd_setbrightness,
-           .get = sd_getbrightness,
+           .set_control = set_cmatrix
        },
-       {
-#define CONTRAST_IDX 1
+[CONTRAST] = {
            {
                .id      = V4L2_CID_CONTRAST,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -202,14 +195,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 0xff,
                .step    = 1,
-#define CONTRAST_DEFAULT 0x7f
-               .default_value = CONTRAST_DEFAULT,
+               .default_value = 0x7f
            },
-           .set = sd_setcontrast,
-           .get = sd_getcontrast,
+           .set_control = set_cmatrix
        },
-       {
-#define SATURATION_IDX 2
+[SATURATION] = {
            {
                .id      = V4L2_CID_SATURATION,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -217,14 +207,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 0xff,
                .step    = 1,
-#define SATURATION_DEFAULT 0x7f
-               .default_value = SATURATION_DEFAULT,
+               .default_value = 0x7f
            },
-           .set = sd_setsaturation,
-           .get = sd_getsaturation,
+           .set_control = set_cmatrix
        },
-       {
-#define HUE_IDX 3
+[HUE] = {
            {
                .id      = V4L2_CID_HUE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -232,14 +219,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = -180,
                .maximum = 180,
                .step    = 1,
-#define HUE_DEFAULT 0
-               .default_value = HUE_DEFAULT,
+               .default_value = 0
            },
-           .set = sd_sethue,
-           .get = sd_gethue,
+           .set_control = set_cmatrix
        },
-       {
-#define GAMMA_IDX 4
+[GAMMA] = {
            {
                .id      = V4L2_CID_GAMMA,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -247,14 +231,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 0xff,
                .step    = 1,
-#define GAMMA_DEFAULT 0x10
-               .default_value = GAMMA_DEFAULT,
+               .default_value = 0x10
            },
-           .set = sd_setgamma,
-           .get = sd_getgamma,
+           .set_control = set_gamma
        },
-       {
-#define BLUE_IDX 5
+[BLUE] = {
            {
                .id      = V4L2_CID_BLUE_BALANCE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -262,14 +243,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 0x7f,
                .step    = 1,
-#define BLUE_DEFAULT 0x28
-               .default_value = BLUE_DEFAULT,
+               .default_value = 0x28
            },
-           .set = sd_setbluebalance,
-           .get = sd_getbluebalance,
+           .set_control = set_redblue
        },
-       {
-#define RED_IDX 6
+[RED] = {
            {
                .id      = V4L2_CID_RED_BALANCE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -277,14 +255,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 0x7f,
                .step    = 1,
-#define RED_DEFAULT 0x28
-               .default_value = RED_DEFAULT,
+               .default_value = 0x28
            },
-           .set = sd_setredbalance,
-           .get = sd_getredbalance,
+           .set_control = set_redblue
        },
-       {
-#define HFLIP_IDX 7
+[HFLIP] = {
            {
                .id      = V4L2_CID_HFLIP,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -292,14 +267,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define HFLIP_DEFAULT 0
-               .default_value = HFLIP_DEFAULT,
+               .default_value = 0,
            },
-           .set = sd_sethflip,
-           .get = sd_gethflip,
+           .set_control = set_hvflip
        },
-       {
-#define VFLIP_IDX 8
+[VFLIP] = {
            {
                .id      = V4L2_CID_VFLIP,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -307,14 +279,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define VFLIP_DEFAULT 0
-               .default_value = VFLIP_DEFAULT,
+               .default_value = 0,
            },
-           .set = sd_setvflip,
-           .get = sd_getvflip,
+           .set_control = set_hvflip
        },
-       {
-#define EXPOSURE_IDX 9
+[EXPOSURE] = {
            {
                .id      = V4L2_CID_EXPOSURE,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -322,14 +291,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 0x1780,
                .step    = 1,
-#define EXPOSURE_DEFAULT 0x33
-               .default_value = EXPOSURE_DEFAULT,
+               .default_value = 0x33,
            },
-           .set = sd_setexposure,
-           .get = sd_getexposure,
+           .set_control = set_exposure
        },
-       {
-#define GAIN_IDX 10
+[GAIN] = {
            {
                .id      = V4L2_CID_GAIN,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -337,14 +303,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 28,
                .step    = 1,
-#define GAIN_DEFAULT 0x00
-               .default_value = GAIN_DEFAULT,
+               .default_value = 0,
            },
-           .set = sd_setgain,
-           .get = sd_getgain,
+           .set_control = set_gain
        },
-       {
-#define AUTOGAIN_IDX 11
+[AUTOGAIN] = {
            {
                .id      = V4L2_CID_AUTOGAIN,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
@@ -352,11 +315,23 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define AUTO_EXPOSURE_DEFAULT 1
-               .default_value = AUTO_EXPOSURE_DEFAULT,
+               .default_value = 1,
+           },
+       },
+[QUALITY] = {
+           {
+               .id      = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Compression Quality",
+#define QUALITY_MIN 50
+#define QUALITY_MAX 90
+#define QUALITY_DEF 80
+               .minimum = QUALITY_MIN,
+               .maximum = QUALITY_MAX,
+               .step    = 1,
+               .default_value = QUALITY_DEF,
            },
-           .set = sd_setautoexposure,
-           .get = sd_getautoexposure,
+           .set_control = set_quality
        },
 };
 
@@ -876,7 +851,7 @@ static u8 hv7131r_gain[] = {
 };
 
 static struct i2c_reg_u8 soi968_init[] = {
-       {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
+       {0x0c, 0x00}, {0x0f, 0x1f},
        {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
        {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
        {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
@@ -902,7 +877,7 @@ static struct i2c_reg_u8 ov7660_init[] = {
 };
 
 static struct i2c_reg_u8 ov7670_init[] = {
-       {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
+       {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
        {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
        {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
        {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
@@ -959,7 +934,7 @@ static struct i2c_reg_u8 ov7670_init[] = {
 };
 
 static struct i2c_reg_u8 ov9650_init[] = {
-       {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
+       {0x00, 0x00}, {0x01, 0x78},
        {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
        {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
        {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
@@ -989,7 +964,7 @@ static struct i2c_reg_u8 ov9650_init[] = {
 };
 
 static struct i2c_reg_u8 ov9655_init[] = {
-       {0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
+       {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
        {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
        {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
        {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
@@ -1112,10 +1087,13 @@ static struct i2c_reg_u8 hv7131r_init[] = {
        {0x23, 0x09}, {0x01, 0x08},
 };
 
-static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
+static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
 {
        struct usb_device *dev = gspca_dev->dev;
        int result;
+
+       if (gspca_dev->usb_err < 0)
+               return;
        result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                        0x00,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1125,17 +1103,19 @@ static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
                        length,
                        500);
        if (unlikely(result < 0 || result != length)) {
-               pr_err("Read register failed 0x%02X\n", reg);
-               return -EIO;
+               pr_err("Read register %02x failed %d\n", reg, result);
+               gspca_dev->usb_err = result;
        }
-       return 0;
 }
 
-static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
+static void reg_w(struct gspca_dev *gspca_dev, u16 reg,
                 const u8 *buffer, int length)
 {
        struct usb_device *dev = gspca_dev->dev;
        int result;
+
+       if (gspca_dev->usb_err < 0)
+               return;
        memcpy(gspca_dev->usb_buf, buffer, length);
        result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                        0x08,
@@ -1146,38 +1126,41 @@ static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
                        length,
                        500);
        if (unlikely(result < 0 || result != length)) {
-               pr_err("Write register failed index 0x%02X\n", reg);
-               return -EIO;
+               pr_err("Write register %02x failed %d\n", reg, result);
+               gspca_dev->usb_err = result;
        }
-       return 0;
 }
 
-static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
+static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
 {
-       u8 data[1] = {value};
-       return reg_w(gspca_dev, reg, data, 1);
+       reg_w(gspca_dev, reg, &value, 1);
 }
 
-static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
+static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
 {
        int i;
+
        reg_w(gspca_dev, 0x10c0, buffer, 8);
        for (i = 0; i < 5; i++) {
                reg_r(gspca_dev, 0x10c0, 1);
+               if (gspca_dev->usb_err < 0)
+                       return;
                if (gspca_dev->usb_buf[0] & 0x04) {
-                       if (gspca_dev->usb_buf[0] & 0x08)
-                               return -EIO;
-                       return 0;
+                       if (gspca_dev->usb_buf[0] & 0x08) {
+                               pr_err("i2c_w error\n");
+                               gspca_dev->usb_err = -EIO;
+                       }
+                       return;
                }
-               msleep(1);
+               msleep(10);
        }
-       return -EIO;
+       pr_err("i2c_w reg %02x no response\n", buffer[2]);
+/*     gspca_dev->usb_err = -EIO;      fixme: may occur */
 }
 
-static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-
        u8 row[8];
 
        /*
@@ -1193,10 +1176,19 @@ static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
        row[6] = 0x00;
        row[7] = 0x10;
 
-       return i2c_w(gspca_dev, row);
+       i2c_w(gspca_dev, row);
+}
+
+static void i2c_w1_buf(struct gspca_dev *gspca_dev,
+                       struct i2c_reg_u8 *buf, int sz)
+{
+       while (--sz >= 0) {
+               i2c_w1(gspca_dev, buf->reg, buf->val);
+               buf++;
+       }
 }
 
-static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
+static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 row[8];
@@ -1208,16 +1200,25 @@ static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
        row[0] = 0x81 | (3 << 4);
        row[1] = sd->i2c_addr;
        row[2] = reg;
-       row[3] = (val >> 8) & 0xff;
-       row[4] = val & 0xff;
+       row[3] = val >> 8;
+       row[4] = val;
        row[5] = 0x00;
        row[6] = 0x00;
        row[7] = 0x10;
 
-       return i2c_w(gspca_dev, row);
+       i2c_w(gspca_dev, row);
+}
+
+static void i2c_w2_buf(struct gspca_dev *gspca_dev,
+                       struct i2c_reg_u16 *buf, int sz)
+{
+       while (--sz >= 0) {
+               i2c_w2(gspca_dev, buf->reg, buf->val);
+               buf++;
+       }
 }
 
-static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
+static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 row[8];
@@ -1230,19 +1231,15 @@ static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
        row[5] = 0;
        row[6] = 0;
        row[7] = 0x10;
-       if (i2c_w(gspca_dev, row) < 0)
-               return -EIO;
+       i2c_w(gspca_dev, row);
        row[0] = 0x81 | (1 << 4) | 0x02;
        row[2] = 0;
-       if (i2c_w(gspca_dev, row) < 0)
-               return -EIO;
-       if (reg_r(gspca_dev, 0x10c2, 5) < 0)
-               return -EIO;
+       i2c_w(gspca_dev, row);
+       reg_r(gspca_dev, 0x10c2, 5);
        *val = gspca_dev->usb_buf[4];
-       return 0;
 }
 
-static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
+static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 row[8];
@@ -1255,233 +1252,204 @@ static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
        row[5] = 0;
        row[6] = 0;
        row[7] = 0x10;
-       if (i2c_w(gspca_dev, row) < 0)
-               return -EIO;
+       i2c_w(gspca_dev, row);
        row[0] = 0x81 | (2 << 4) | 0x02;
        row[2] = 0;
-       if (i2c_w(gspca_dev, row) < 0)
-               return -EIO;
-       if (reg_r(gspca_dev, 0x10c2, 5) < 0)
-               return -EIO;
+       i2c_w(gspca_dev, row);
+       reg_r(gspca_dev, 0x10c2, 5);
        *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
-       return 0;
 }
 
-static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
+static void ov9650_init_sensor(struct gspca_dev *gspca_dev)
 {
-       int i;
        u16 id;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (i2c_r2(gspca_dev, 0x1c, &id) < 0)
-               return -EINVAL;
+       i2c_r2(gspca_dev, 0x1c, &id);
+       if (gspca_dev->usb_err < 0)
+               return;
 
        if (id != 0x7fa2) {
                pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
-               return -ENODEV;
+               gspca_dev->usb_err = -ENODEV;
+               return;
        }
 
-       for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
-               if (i2c_w1(gspca_dev, ov9650_init[i].reg,
-                               ov9650_init[i].val) < 0) {
-                       pr_err("OV9650 sensor initialization failed\n");
-                       return -ENODEV;
-               }
-       }
+       i2c_w1(gspca_dev, 0x12, 0x80);          /* sensor reset */
+       msleep(200);
+       i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init));
+       if (gspca_dev->usb_err < 0)
+               pr_err("OV9650 sensor initialization failed\n");
        sd->hstart = 1;
        sd->vstart = 7;
-       return 0;
 }
 
-static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
+static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
 {
-       int i;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
-               if (i2c_w1(gspca_dev, ov9655_init[i].reg,
-                               ov9655_init[i].val) < 0) {
-                       pr_err("OV9655 sensor initialization failed\n");
-                       return -ENODEV;
-               }
-       }
+       i2c_w1(gspca_dev, 0x12, 0x80);          /* sensor reset */
+       msleep(200);
+       i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init));
+       if (gspca_dev->usb_err < 0)
+               pr_err("OV9655 sensor initialization failed\n");
+
        /* disable hflip and vflip */
-       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+       gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
        sd->hstart = 1;
        sd->vstart = 2;
-       return 0;
 }
 
-static int soi968_init_sensor(struct gspca_dev *gspca_dev)
+static void soi968_init_sensor(struct gspca_dev *gspca_dev)
 {
-       int i;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
-               if (i2c_w1(gspca_dev, soi968_init[i].reg,
-                               soi968_init[i].val) < 0) {
-                       pr_err("SOI968 sensor initialization failed\n");
-                       return -ENODEV;
-               }
-       }
+       i2c_w1(gspca_dev, 0x12, 0x80);          /* sensor reset */
+       msleep(200);
+       i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init));
+       if (gspca_dev->usb_err < 0)
+               pr_err("SOI968 sensor initialization failed\n");
+
        /* disable hflip and vflip */
-       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX)
-                               | (1 << EXPOSURE_IDX);
+       gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP)
+                               | (1 << EXPOSURE);
        sd->hstart = 60;
        sd->vstart = 11;
-       return 0;
 }
 
-static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
+static void ov7660_init_sensor(struct gspca_dev *gspca_dev)
 {
-       int i;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
-               if (i2c_w1(gspca_dev, ov7660_init[i].reg,
-                               ov7660_init[i].val) < 0) {
-                       pr_err("OV7660 sensor initialization failed\n");
-                       return -ENODEV;
-               }
-       }
+       i2c_w1(gspca_dev, 0x12, 0x80);          /* sensor reset */
+       msleep(200);
+       i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init));
+       if (gspca_dev->usb_err < 0)
+               pr_err("OV7660 sensor initialization failed\n");
        sd->hstart = 3;
        sd->vstart = 3;
-       return 0;
 }
 
-static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
+static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
 {
-       int i;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
-               if (i2c_w1(gspca_dev, ov7670_init[i].reg,
-                               ov7670_init[i].val) < 0) {
-                       pr_err("OV7670 sensor initialization failed\n");
-                       return -ENODEV;
-               }
-       }
+       i2c_w1(gspca_dev, 0x12, 0x80);          /* sensor reset */
+       msleep(200);
+       i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init));
+       if (gspca_dev->usb_err < 0)
+               pr_err("OV7670 sensor initialization failed\n");
+
        /* disable hflip and vflip */
-       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+       gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
        sd->hstart = 0;
        sd->vstart = 1;
-       return 0;
 }
 
-static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int i;
        u16 value;
-       int ret;
 
        sd->i2c_addr = 0x5d;
-       ret = i2c_r2(gspca_dev, 0xff, &value);
-       if ((ret == 0) && (value == 0x8243)) {
-               for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
-                       if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
-                                       mt9v011_init[i].val) < 0) {
-                               pr_err("MT9V011 sensor initialization failed\n");
-                               return -ENODEV;
-                       }
+       i2c_r2(gspca_dev, 0xff, &value);
+       if (gspca_dev->usb_err >= 0
+        && value == 0x8243) {
+               i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init));
+               if (gspca_dev->usb_err < 0) {
+                       pr_err("MT9V011 sensor initialization failed\n");
+                       return;
                }
                sd->hstart = 2;
                sd->vstart = 2;
                sd->sensor = SENSOR_MT9V011;
                pr_info("MT9V011 sensor detected\n");
-               return 0;
+               return;
        }
 
+       gspca_dev->usb_err = 0;
        sd->i2c_addr = 0x5c;
        i2c_w2(gspca_dev, 0x01, 0x0004);
-       ret = i2c_r2(gspca_dev, 0xff, &value);
-       if ((ret == 0) && (value == 0x823a)) {
-               for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
-                       if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
-                                       mt9v111_init[i].val) < 0) {
-                               pr_err("MT9V111 sensor initialization failed\n");
-                               return -ENODEV;
-                       }
+       i2c_r2(gspca_dev, 0xff, &value);
+       if (gspca_dev->usb_err >= 0
+        && value == 0x823a) {
+               i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init));
+               if (gspca_dev->usb_err < 0) {
+                       pr_err("MT9V111 sensor initialization failed\n");
+                       return;
                }
-               gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX)
-                                       | (1 << AUTOGAIN_IDX)
-                                       | (1 << GAIN_IDX);
+               gspca_dev->ctrl_dis = (1 << EXPOSURE)
+                                       | (1 << AUTOGAIN)
+                                       | (1 << GAIN);
                sd->hstart = 2;
                sd->vstart = 2;
                sd->sensor = SENSOR_MT9V111;
                pr_info("MT9V111 sensor detected\n");
-               return 0;
+               return;
        }
 
+       gspca_dev->usb_err = 0;
        sd->i2c_addr = 0x5d;
-       ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
-       if (ret < 0) {
+       i2c_w2(gspca_dev, 0xf0, 0x0000);
+       if (gspca_dev->usb_err < 0) {
+               gspca_dev->usb_err = 0;
                sd->i2c_addr = 0x48;
                i2c_w2(gspca_dev, 0xf0, 0x0000);
        }
-       ret = i2c_r2(gspca_dev, 0x00, &value);
-       if ((ret == 0) && (value == 0x1229)) {
-               for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
-                       if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
-                                       mt9v112_init[i].val) < 0) {
-                               pr_err("MT9V112 sensor initialization failed\n");
-                               return -ENODEV;
-                       }
+       i2c_r2(gspca_dev, 0x00, &value);
+       if (gspca_dev->usb_err >= 0
+        && value == 0x1229) {
+               i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init));
+               if (gspca_dev->usb_err < 0) {
+                       pr_err("MT9V112 sensor initialization failed\n");
+                       return;
                }
                sd->hstart = 6;
                sd->vstart = 2;
                sd->sensor = SENSOR_MT9V112;
                pr_info("MT9V112 sensor detected\n");
-               return 0;
+               return;
        }
 
-       return -ENODEV;
+       gspca_dev->usb_err = -ENODEV;
 }
 
-static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int i;
-       for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
-               if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
-                               mt9m112_init[i].val) < 0) {
-                       pr_err("MT9M112 sensor initialization failed\n");
-                       return -ENODEV;
-               }
-       }
-       gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
-                               | (1 << GAIN_IDX);
+
+       i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init));
+       if (gspca_dev->usb_err < 0)
+               pr_err("MT9M112 sensor initialization failed\n");
+
+       gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
+                               | (1 << GAIN);
        sd->hstart = 0;
        sd->vstart = 2;
-       return 0;
 }
 
-static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int i;
-       for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
-               if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
-                               mt9m111_init[i].val) < 0) {
-                       pr_err("MT9M111 sensor initialization failed\n");
-                       return -ENODEV;
-               }
-       }
-       gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
-                               | (1 << GAIN_IDX);
+
+       i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init));
+       if (gspca_dev->usb_err < 0)
+               pr_err("MT9M111 sensor initialization failed\n");
+
+       gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
+                               | (1 << GAIN);
        sd->hstart = 0;
        sd->vstart = 2;
-       return 0;
 }
 
-static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int i;
        u16 id;
 
-       if (i2c_r2(gspca_dev, 0x00, &id) < 0)
-               return -EINVAL;
+       i2c_r2(gspca_dev, 0x00, &id);
+       if (gspca_dev->usb_err < 0)
+               return;
 
        /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
        switch (id) {
@@ -1494,85 +1462,78 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
                break;
        default:
                pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
-               return -ENODEV;
+               gspca_dev->usb_err = -ENODEV;
+               return;
        }
 
-       for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
-               if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
-                               mt9m001_init[i].val) < 0) {
-                       pr_err("MT9M001 sensor initialization failed\n");
-                       return -ENODEV;
-               }
-       }
+       i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init));
+       if (gspca_dev->usb_err < 0)
+               pr_err("MT9M001 sensor initialization failed\n");
+
        /* disable hflip and vflip */
-       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+       gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
        sd->hstart = 1;
        sd->vstart = 1;
-       return 0;
 }
 
-static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
+static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
 {
-       int i;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
-               if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
-                               hv7131r_init[i].val) < 0) {
-                       pr_err("HV7131R Sensor initialization failed\n");
-                       return -ENODEV;
-               }
-       }
+       i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init));
+       if (gspca_dev->usb_err < 0)
+               pr_err("HV7131R Sensor initialization failed\n");
+
        sd->hstart = 0;
        sd->vstart = 1;
-       return 0;
 }
 
-static int set_cmatrix(struct gspca_dev *gspca_dev)
+static void set_cmatrix(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 hue_coord, hue_index = 180 + sd->hue;
+       int satur;
+       s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val;
        u8 cmatrix[21];
 
        memset(cmatrix, 0, sizeof cmatrix);
-       cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
+       cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26;
        cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
        cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
-       cmatrix[18] = sd->brightness - 0x80;
+       cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80;
 
-       hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
+       satur = sd->ctrls[SATURATION].val;
+       hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
        cmatrix[6] = hue_coord;
        cmatrix[7] = (hue_coord >> 8) & 0x0f;
 
-       hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
+       hue_coord = (hsv_red_y[hue_index] * satur) >> 8;
        cmatrix[8] = hue_coord;
        cmatrix[9] = (hue_coord >> 8) & 0x0f;
 
-       hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
+       hue_coord = (hsv_green_x[hue_index] * satur) >> 8;
        cmatrix[10] = hue_coord;
        cmatrix[11] = (hue_coord >> 8) & 0x0f;
 
-       hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
+       hue_coord = (hsv_green_y[hue_index] * satur) >> 8;
        cmatrix[12] = hue_coord;
        cmatrix[13] = (hue_coord >> 8) & 0x0f;
 
-       hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
+       hue_coord = (hsv_blue_x[hue_index] * satur) >> 8;
        cmatrix[14] = hue_coord;
        cmatrix[15] = (hue_coord >> 8) & 0x0f;
 
-       hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
+       hue_coord = (hsv_blue_y[hue_index] * satur) >> 8;
        cmatrix[16] = hue_coord;
        cmatrix[17] = (hue_coord >> 8) & 0x0f;
 
-       return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
+       reg_w(gspca_dev, 0x10e1, cmatrix, 21);
 }
 
-static int set_gamma(struct gspca_dev *gspca_dev)
+static void set_gamma(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 gamma[17];
-       u8 gval = sd->gamma * 0xb8 / 0x100;
-
+       u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100;
 
        gamma[0] = 0x0a;
        gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
@@ -1592,29 +1553,29 @@ static int set_gamma(struct gspca_dev *gspca_dev)
        gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
        gamma[16] = 0xf5;
 
-       return reg_w(gspca_dev, 0x1190, gamma, 17);
+       reg_w(gspca_dev, 0x1190, gamma, 17);
 }
 
-static int set_redblue(struct gspca_dev *gspca_dev)
+static void set_redblue(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       reg_w1(gspca_dev, 0x118c, sd->red);
-       reg_w1(gspca_dev, 0x118f, sd->blue);
-       return 0;
+
+       reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val);
+       reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val);
 }
 
-static int set_hvflip(struct gspca_dev *gspca_dev)
+static void set_hvflip(struct gspca_dev *gspca_dev)
 {
        u8 value, tslb, hflip, vflip;
        u16 value2;
        struct sd *sd = (struct sd *) gspca_dev;
 
        if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
-               hflip = !sd->hflip;
-               vflip = !sd->vflip;
+               hflip = !sd->ctrls[HFLIP].val;
+               vflip = !sd->ctrls[VFLIP].val;
        } else {
-               hflip = sd->hflip;
-               vflip = sd->vflip;
+               hflip = sd->ctrls[HFLIP].val;
+               vflip = sd->ctrls[VFLIP].val;
        }
 
        switch (sd->sensor) {
@@ -1625,8 +1586,9 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
                if (vflip) {
                        value |= 0x10;
                        sd->vstart = 2;
-               } else
+               } else {
                        sd->vstart = 3;
+               }
                reg_w1(gspca_dev, 0x1182, sd->vstart);
                i2c_w1(gspca_dev, 0x1e, value);
                break;
@@ -1674,13 +1636,15 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
                i2c_w1(gspca_dev, 0x01, value);
                break;
        }
-       return 0;
 }
 
-static int set_exposure(struct gspca_dev *gspca_dev)
+static void set_exposure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
+       int expo;
+
+       expo = sd->ctrls[EXPOSURE].val;
        switch (sd->sensor) {
        case SENSOR_OV7660:
        case SENSOR_OV7670:
@@ -1688,35 +1652,37 @@ static int set_exposure(struct gspca_dev *gspca_dev)
        case SENSOR_OV9650:
                exp[0] |= (3 << 4);
                exp[2] = 0x2d;
-               exp[3] = sd->exposure & 0xff;
-               exp[4] = sd->exposure >> 8;
+               exp[3] = expo;
+               exp[4] = expo >> 8;
                break;
        case SENSOR_MT9M001:
        case SENSOR_MT9V112:
        case SENSOR_MT9V011:
                exp[0] |= (3 << 4);
                exp[2] = 0x09;
-               exp[3] = sd->exposure >> 8;
-               exp[4] = sd->exposure & 0xff;
+               exp[3] = expo >> 8;
+               exp[4] = expo;
                break;
        case SENSOR_HV7131R:
                exp[0] |= (4 << 4);
                exp[2] = 0x25;
-               exp[3] = (sd->exposure >> 5) & 0xff;
-               exp[4] = (sd->exposure << 3) & 0xff;
+               exp[3] = expo >> 5;
+               exp[4] = expo << 3;
                exp[5] = 0;
                break;
        default:
-               return 0;
+               return;
        }
        i2c_w(gspca_dev, exp);
-       return 0;
 }
 
-static int set_gain(struct gspca_dev *gspca_dev)
+static void set_gain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
+       int g;
+
+       g = sd->ctrls[GAIN].val;
        switch (sd->sensor) {
        case SENSOR_OV7660:
        case SENSOR_OV7670:
@@ -1724,238 +1690,50 @@ static int set_gain(struct gspca_dev *gspca_dev)
        case SENSOR_OV9655:
        case SENSOR_OV9650:
                gain[0] |= (2 << 4);
-               gain[3] = ov_gain[sd->gain];
+               gain[3] = ov_gain[g];
                break;
        case SENSOR_MT9V011:
                gain[0] |= (3 << 4);
                gain[2] = 0x35;
-               gain[3] = micron1_gain[sd->gain] >> 8;
-               gain[4] = micron1_gain[sd->gain] & 0xff;
+               gain[3] = micron1_gain[g] >> 8;
+               gain[4] = micron1_gain[g];
                break;
        case SENSOR_MT9V112:
                gain[0] |= (3 << 4);
                gain[2] = 0x2f;
-               gain[3] = micron1_gain[sd->gain] >> 8;
-               gain[4] = micron1_gain[sd->gain] & 0xff;
+               gain[3] = micron1_gain[g] >> 8;
+               gain[4] = micron1_gain[g];
                break;
        case SENSOR_MT9M001:
                gain[0] |= (3 << 4);
                gain[2] = 0x2f;
-               gain[3] = micron2_gain[sd->gain] >> 8;
-               gain[4] = micron2_gain[sd->gain] & 0xff;
+               gain[3] = micron2_gain[g] >> 8;
+               gain[4] = micron2_gain[g];
                break;
        case SENSOR_HV7131R:
                gain[0] |= (2 << 4);
                gain[2] = 0x30;
-               gain[3] = hv7131r_gain[sd->gain];
+               gain[3] = hv7131r_gain[g];
                break;
        default:
-               return 0;
+               return;
        }
        i2c_w(gspca_dev, gain);
-       return 0;
-}
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->brightness = val;
-       if (gspca_dev->streaming)
-               return set_cmatrix(gspca_dev);
-       return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->brightness;
-       return 0;
-}
-
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->contrast = val;
-       if (gspca_dev->streaming)
-               return set_cmatrix(gspca_dev);
-       return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->contrast;
-       return 0;
-}
-
-static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->saturation = val;
-       if (gspca_dev->streaming)
-               return set_cmatrix(gspca_dev);
-       return 0;
 }
 
-static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
+static void set_quality(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->saturation;
-       return 0;
-}
-
-static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->hue = val;
-       if (gspca_dev->streaming)
-               return set_cmatrix(gspca_dev);
-       return 0;
-}
-
-static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->hue;
-       return 0;
-}
-
-static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->gamma = val;
-       if (gspca_dev->streaming)
-               return set_gamma(gspca_dev);
-       return 0;
-}
-
-static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->gamma;
-       return 0;
-}
-
-static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->red = val;
-       if (gspca_dev->streaming)
-               return set_redblue(gspca_dev);
-       return 0;
-}
-
-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->red;
-       return 0;
-}
-
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->blue = val;
-       if (gspca_dev->streaming)
-               return set_redblue(gspca_dev);
-       return 0;
-}
-
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->blue;
-       return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->hflip = val;
-       if (gspca_dev->streaming)
-               return set_hvflip(gspca_dev);
-       return 0;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->hflip;
-       return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->vflip = val;
-       if (gspca_dev->streaming)
-               return set_hvflip(gspca_dev);
-       return 0;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->vflip;
-       return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->exposure = val;
-       if (gspca_dev->streaming)
-               return set_exposure(gspca_dev);
-       return 0;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->exposure;
-       return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-
-       sd->gain = val;
-       if (gspca_dev->streaming)
-               return set_gain(gspca_dev);
-       return 0;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->gain;
-       return 0;
-}
-
-static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       sd->auto_exposure = val;
-       return 0;
-}
 
-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       *val = sd->auto_exposure;
-       return 0;
+       jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+       reg_w1(gspca_dev, 0x1061, 0x01);        /* stop transfer */
+       reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
+       reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
+       reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
+       reg_w1(gspca_dev, 0x1061, 0x03);        /* restart transfer */
+       reg_w1(gspca_dev, 0x10e0, sd->fmt);
+       sd->fmt ^= 0x0c;                        /* invert QTAB use + write */
+       reg_w1(gspca_dev, 0x10e0, sd->fmt);
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1963,28 +1741,26 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
                        struct v4l2_dbg_register *reg)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+
        switch (reg->match.type) {
        case V4L2_CHIP_MATCH_HOST:
                if (reg->match.addr != 0)
                        return -EINVAL;
                if (reg->reg < 0x1000 || reg->reg > 0x11ff)
                        return -EINVAL;
-               if (reg_r(gspca_dev, reg->reg, 1) < 0)
-                       return -EINVAL;
+               reg_r(gspca_dev, reg->reg, 1);
                reg->val = gspca_dev->usb_buf[0];
-               return 0;
+               return gspca_dev->usb_err;
        case V4L2_CHIP_MATCH_I2C_ADDR:
                if (reg->match.addr != sd->i2c_addr)
                        return -EINVAL;
                if (sd->sensor >= SENSOR_MT9V011 &&
                    sd->sensor <= SENSOR_MT9M112) {
-                       if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
-                               return -EINVAL;
+                       i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
                } else {
-                       if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
-                               return -EINVAL;
+                       i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
                }
-               return 0;
+               return gspca_dev->usb_err;
        }
        return -EINVAL;
 }
@@ -1993,27 +1769,25 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
                        struct v4l2_dbg_register *reg)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+
        switch (reg->match.type) {
        case V4L2_CHIP_MATCH_HOST:
                if (reg->match.addr != 0)
                        return -EINVAL;
                if (reg->reg < 0x1000 || reg->reg > 0x11ff)
                        return -EINVAL;
-               if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
-                       return -EINVAL;
-               return 0;
+               reg_w1(gspca_dev, reg->reg, reg->val);
+               return gspca_dev->usb_err;
        case V4L2_CHIP_MATCH_I2C_ADDR:
                if (reg->match.addr != sd->i2c_addr)
                        return -EINVAL;
                if (sd->sensor >= SENSOR_MT9V011 &&
                    sd->sensor <= SENSOR_MT9M112) {
-                       if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
-                               return -EINVAL;
+                       i2c_w2(gspca_dev, reg->reg, reg->val);
                } else {
-                       if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
-                               return -EINVAL;
+                       i2c_w1(gspca_dev, reg->reg, reg->val);
                }
-               return 0;
+               return gspca_dev->usb_err;
        }
        return -EINVAL;
 }
@@ -2050,9 +1824,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
        cam = &gspca_dev->cam;
        cam->needs_full_bandwidth = 1;
 
-       sd->sensor = (id->driver_info >> 8) & 0xff;
-       sd->i2c_addr = id->driver_info & 0xff;
-       sd->flags = (id->driver_info >> 16) & 0xff;
+       sd->sensor = id->driver_info >> 8;
+       sd->i2c_addr = id->driver_info;
+       sd->flags = id->driver_info >> 16;
 
        switch (sd->sensor) {
        case SENSOR_MT9M112:
@@ -2076,21 +1850,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->older_step = 0;
        sd->exposure_step = 16;
 
-       sd->brightness = BRIGHTNESS_DEFAULT;
-       sd->contrast = CONTRAST_DEFAULT;
-       sd->saturation = SATURATION_DEFAULT;
-       sd->hue = HUE_DEFAULT;
-       sd->gamma = GAMMA_DEFAULT;
-       sd->red = RED_DEFAULT;
-       sd->blue = BLUE_DEFAULT;
+       gspca_dev->cam.ctrls = sd->ctrls;
 
-       sd->hflip = HFLIP_DEFAULT;
-       sd->vflip = VFLIP_DEFAULT;
-       sd->exposure = EXPOSURE_DEFAULT;
-       sd->gain = GAIN_DEFAULT;
-       sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
-
-       sd->quality = 95;
+       INIT_WORK(&sd->work, qual_upd);
 
        return 0;
 }
@@ -2105,9 +1867,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
 
        for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
                value = bridge_init[i][1];
-               if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
+               reg_w(gspca_dev, bridge_init[i][0], &value, 1);
+               if (gspca_dev->usb_err < 0) {
                        pr_err("Device initialization failed\n");
-                       return -ENODEV;
+                       return gspca_dev->usb_err;
                }
        }
 
@@ -2116,72 +1879,85 @@ static int sd_init(struct gspca_dev *gspca_dev)
        else
                reg_w1(gspca_dev, 0x1006, 0x20);
 
-       if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
+       reg_w(gspca_dev, 0x10c0, i2c_init, 9);
+       if (gspca_dev->usb_err < 0) {
                pr_err("Device initialization failed\n");
-               return -ENODEV;
+               return gspca_dev->usb_err;
        }
 
        switch (sd->sensor) {
        case SENSOR_OV9650:
-               if (ov9650_init_sensor(gspca_dev) < 0)
-                       return -ENODEV;
+               ov9650_init_sensor(gspca_dev);
+               if (gspca_dev->usb_err < 0)
+                       break;
                pr_info("OV9650 sensor detected\n");
                break;
        case SENSOR_OV9655:
-               if (ov9655_init_sensor(gspca_dev) < 0)
-                       return -ENODEV;
+               ov9655_init_sensor(gspca_dev);
+               if (gspca_dev->usb_err < 0)
+                       break;
                pr_info("OV9655 sensor detected\n");
                break;
        case SENSOR_SOI968:
-               if (soi968_init_sensor(gspca_dev) < 0)
-                       return -ENODEV;
+               soi968_init_sensor(gspca_dev);
+               if (gspca_dev->usb_err < 0)
+                       break;
                pr_info("SOI968 sensor detected\n");
                break;
        case SENSOR_OV7660:
-               if (ov7660_init_sensor(gspca_dev) < 0)
-                       return -ENODEV;
+               ov7660_init_sensor(gspca_dev);
+               if (gspca_dev->usb_err < 0)
+                       break;
                pr_info("OV7660 sensor detected\n");
                break;
        case SENSOR_OV7670:
-               if (ov7670_init_sensor(gspca_dev) < 0)
-                       return -ENODEV;
+               ov7670_init_sensor(gspca_dev);
+               if (gspca_dev->usb_err < 0)
+                       break;
                pr_info("OV7670 sensor detected\n");
                break;
        case SENSOR_MT9VPRB:
-               if (mt9v_init_sensor(gspca_dev) < 0)
-                       return -ENODEV;
+               mt9v_init_sensor(gspca_dev);
+               if (gspca_dev->usb_err < 0)
+                       break;
+               pr_info("MT9VPRB sensor detected\n");
                break;
        case SENSOR_MT9M111:
-               if (mt9m111_init_sensor(gspca_dev) < 0)
-                       return -ENODEV;
+               mt9m111_init_sensor(gspca_dev);
+               if (gspca_dev->usb_err < 0)
+                       break;
                pr_info("MT9M111 sensor detected\n");
                break;
        case SENSOR_MT9M112:
-               if (mt9m112_init_sensor(gspca_dev) < 0)
-                       return -ENODEV;
+               mt9m112_init_sensor(gspca_dev);
+               if (gspca_dev->usb_err < 0)
+                       break;
                pr_info("MT9M112 sensor detected\n");
                break;
        case SENSOR_MT9M001:
-               if (mt9m001_init_sensor(gspca_dev) < 0)
-                       return -ENODEV;
+               mt9m001_init_sensor(gspca_dev);
+               if (gspca_dev->usb_err < 0)
+                       break;
                break;
        case SENSOR_HV7131R:
-               if (hv7131r_init_sensor(gspca_dev) < 0)
-                       return -ENODEV;
+               hv7131r_init_sensor(gspca_dev);
+               if (gspca_dev->usb_err < 0)
+                       break;
                pr_info("HV7131R sensor detected\n");
                break;
        default:
-               pr_info("Unsupported Sensor\n");
-               return -ENODEV;
+               pr_err("Unsupported sensor\n");
+               gspca_dev->usb_err = -ENODEV;
        }
 
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 value;
+
        switch (sd->sensor) {
        case SENSOR_SOI968:
                if (mode & MODE_SXGA) {
@@ -2264,6 +2040,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
                        break;
                default:  /* >= 640x480 */
                        gspca_dev->alt = 9;
+                       break;
                }
        }
 
@@ -2290,14 +2067,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        jpeg_define(sd->jpeg_hdr, height, width,
                        0x21);
-       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+       jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
 
        if (mode & MODE_RAW)
                fmt = 0x2d;
        else if (mode & MODE_JPEG)
-               fmt = 0x2c;
+               fmt = 0x24;
        else
                fmt = 0x2f;     /* YUV 420 */
+       sd->fmt = fmt;
 
        switch (mode & SCALE_MASK) {
        case SCALE_1280x1024:
@@ -2334,18 +2112,37 @@ static int sd_start(struct gspca_dev *gspca_dev)
        set_hvflip(gspca_dev);
 
        reg_w1(gspca_dev, 0x1007, 0x20);
+       reg_w1(gspca_dev, 0x1061, 0x03);
+
+       /* if JPEG, prepare the compression quality update */
+       if (mode & MODE_JPEG) {
+               sd->pktsz = sd->npkt = 0;
+               sd->nchg = 0;
+               sd->work_thread =
+                       create_singlethread_workqueue(KBUILD_MODNAME);
+       }
 
-       reg_r(gspca_dev, 0x1061, 1);
-       reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
-       return 0;
+       return gspca_dev->usb_err;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
        reg_w1(gspca_dev, 0x1007, 0x00);
+       reg_w1(gspca_dev, 0x1061, 0x01);
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_r(gspca_dev, 0x1061, 1);
-       reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
+       if (sd->work_thread != NULL) {
+               mutex_unlock(&gspca_dev->usb_lock);
+               destroy_workqueue(sd->work_thread);
+               mutex_lock(&gspca_dev->usb_lock);
+               sd->work_thread = NULL;
+       }
 }
 
 static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
@@ -2359,15 +2156,15 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
         * and exposure steps
         */
        if (avg_lum < MIN_AVG_LUM) {
-               if (sd->exposure > 0x1770)
+               if (sd->ctrls[EXPOSURE].val > 0x1770)
                        return;
 
-               new_exp = sd->exposure + sd->exposure_step;
+               new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step;
                if (new_exp > 0x1770)
                        new_exp = 0x1770;
                if (new_exp < 0x10)
                        new_exp = 0x10;
-               sd->exposure = new_exp;
+               sd->ctrls[EXPOSURE].val = new_exp;
                set_exposure(gspca_dev);
 
                sd->older_step = sd->old_step;
@@ -2379,14 +2176,14 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
                        sd->exposure_step += 2;
        }
        if (avg_lum > MAX_AVG_LUM) {
-               if (sd->exposure < 0x10)
+               if (sd->ctrls[EXPOSURE].val < 0x10)
                        return;
-               new_exp = sd->exposure - sd->exposure_step;
+               new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step;
                if (new_exp > 0x1700)
                        new_exp = 0x1770;
                if (new_exp < 0x10)
                        new_exp = 0x10;
-               sd->exposure = new_exp;
+               sd->ctrls[EXPOSURE].val = new_exp;
                set_exposure(gspca_dev);
                sd->older_step = sd->old_step;
                sd->old_step = 0;
@@ -2403,14 +2200,14 @@ static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
        struct sd *sd = (struct sd *) gspca_dev;
 
        if (avg_lum < MIN_AVG_LUM) {
-               if (sd->gain + 1 <= 28) {
-                       sd->gain++;
+               if (sd->ctrls[GAIN].val + 1 <= 28) {
+                       sd->ctrls[GAIN].val++;
                        set_gain(gspca_dev);
                }
        }
        if (avg_lum > MAX_AVG_LUM) {
-               if (sd->gain > 0) {
-                       sd->gain--;
+               if (sd->ctrls[GAIN].val > 0) {
+                       sd->ctrls[GAIN].val--;
                        set_gain(gspca_dev);
                }
        }
@@ -2421,7 +2218,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int avg_lum;
 
-       if (!sd->auto_exposure)
+       if (!sd->ctrls[AUTOGAIN].val)
                return;
 
        avg_lum = atomic_read(&sd->avg_lum);
@@ -2431,33 +2228,92 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
                do_autoexposure(gspca_dev, avg_lum);
 }
 
+/* JPEG quality update */
+/* This function is executed from a work queue. */
+static void qual_upd(struct work_struct *work)
+{
+       struct sd *sd = container_of(work, struct sd, work);
+       struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+       mutex_lock(&gspca_dev->usb_lock);
+       PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val);
+       set_quality(gspca_dev);
+       mutex_unlock(&gspca_dev->usb_lock);
+}
+
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
 static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,               /* interrupt packet */
                        int len)                /* interrupt packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int ret = -EINVAL;
+
        if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
-                       input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
-                       input_sync(gspca_dev->input_dev);
-                       input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
-                       input_sync(gspca_dev->input_dev);
-                       ret = 0;
+               input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+               input_sync(gspca_dev->input_dev);
+               input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+               input_sync(gspca_dev->input_dev);
+               return 0;
        }
-       return ret;
+       return -EINVAL;
 }
 #endif
 
+/* check the JPEG compression */
+static void transfer_check(struct gspca_dev *gspca_dev,
+                       u8 *data)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int new_qual, r;
+
+       new_qual = 0;
+
+       /* if USB error, discard the frame and decrease the quality */
+       if (data[6] & 0x08) {                           /* USB FIFO full */
+               gspca_dev->last_packet_type = DISCARD_PACKET;
+               new_qual = -5;
+       } else {
+
+               /* else, compute the filling rate and a new JPEG quality */
+               r = (sd->pktsz * 100) /
+                       (sd->npkt *
+                               gspca_dev->urb[0]->iso_frame_desc[0].length);
+               if (r >= 85)
+                       new_qual = -3;
+               else if (r < 75)
+                       new_qual = 2;
+       }
+       if (new_qual != 0) {
+               sd->nchg += new_qual;
+               if (sd->nchg < -6 || sd->nchg >= 12) {
+                       sd->nchg = 0;
+                       new_qual += sd->ctrls[QUALITY].val;
+                       if (new_qual < QUALITY_MIN)
+                               new_qual = QUALITY_MIN;
+                       else if (new_qual > QUALITY_MAX)
+                               new_qual = QUALITY_MAX;
+                       if (new_qual != sd->ctrls[QUALITY].val) {
+                               sd->ctrls[QUALITY].val = new_qual;
+                               queue_work(sd->work_thread, &sd->work);
+                       }
+               }
+       } else {
+               sd->nchg = 0;
+       }
+       sd->pktsz = sd->npkt = 0;
+}
+
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int avg_lum;
+       int avg_lum, is_jpeg;
        static u8 frame_header[] =
                {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
-       if (len == 64 && memcmp(data, frame_header, 6) == 0) {
+
+       is_jpeg = (sd->fmt & 0x03) == 0;
+       if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
                avg_lum = ((data[35] >> 2) & 3) |
                           (data[20] << 2) |
                           (data[19] << 10);
@@ -2484,12 +2340,18 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                            (data[33] << 10);
                avg_lum >>= 9;
                atomic_set(&sd->avg_lum, avg_lum);
+
+               if (is_jpeg)
+                       transfer_check(gspca_dev, data);
+
                gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
-               return;
+               len -= 64;
+               if (len == 0)
+                       return;
+               data += 64;
        }
        if (gspca_dev->last_packet_type == LAST_PACKET) {
-               if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
-                               & MODE_JPEG) {
+               if (is_jpeg) {
                        gspca_frame_add(gspca_dev, FIRST_PACKET,
                                sd->jpeg_hdr, JPEG_HDR_SZ);
                        gspca_frame_add(gspca_dev, INTER_PACKET,
@@ -2499,13 +2361,18 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                data, len);
                }
        } else {
+               /* if JPEG, count the packets and their size */
+               if (is_jpeg) {
+                       sd->npkt++;
+                       sd->pktsz += len;
+               }
                gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
        }
 }
 
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
-       .name = MODULE_NAME,
+       .name = KBUILD_MODNAME,
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
@@ -2513,6 +2380,7 @@ static const struct sd_desc sd_desc = {
        .isoc_init = sd_isoc_init,
        .start = sd_start,
        .stopN = sd_stopN,
+       .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
@@ -2581,7 +2449,7 @@ static int sd_probe(struct usb_interface *intf,
 }
 
 static struct usb_driver sd_driver = {
-       .name = MODULE_NAME,
+       .name = KBUILD_MODNAME,
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
index 0c9e6dd..db8e508 100644 (file)
@@ -39,7 +39,9 @@ enum e_ctrl {
        BLUE,
        RED,
        GAMMA,
+       EXPOSURE,
        AUTOGAIN,
+       GAIN,
        HFLIP,
        VFLIP,
        SHARPNESS,
@@ -131,7 +133,9 @@ static void setcontrast(struct gspca_dev *gspca_dev);
 static void setcolors(struct gspca_dev *gspca_dev);
 static void setredblue(struct gspca_dev *gspca_dev);
 static void setgamma(struct gspca_dev *gspca_dev);
-static void setautogain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static void setgain(struct gspca_dev *gspca_dev);
 static void sethvflip(struct gspca_dev *gspca_dev);
 static void setsharpness(struct gspca_dev *gspca_dev);
 static void setillum(struct gspca_dev *gspca_dev);
@@ -213,6 +217,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
            },
            .set_control = setgamma
        },
+[EXPOSURE] = {
+           {
+               .id      = V4L2_CID_EXPOSURE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Exposure",
+               .minimum = 500,
+               .maximum = 1500,
+               .step    = 1,
+               .default_value = 1024
+           },
+           .set_control = setexposure
+       },
 [AUTOGAIN] = {
            {
                .id      = V4L2_CID_AUTOGAIN,
@@ -223,7 +239,19 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
                .step    = 1,
                .default_value = 1
            },
-           .set_control = setautogain
+           .set = sd_setautogain,
+       },
+[GAIN] = {
+           {
+               .id      = V4L2_CID_GAIN,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gain",
+               .minimum = 4,
+               .maximum = 49,
+               .step    = 1,
+               .default_value = 15
+           },
+           .set_control = setgain
        },
 [HFLIP] = {
            {
@@ -290,60 +318,87 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
 
 /* table of the disabled controls */
 static const __u32 ctrl_dis[] = {
-[SENSOR_ADCM1700] =    (1 << AUTOGAIN) |
+[SENSOR_ADCM1700] =    (1 << EXPOSURE) |
+                       (1 << AUTOGAIN) |
+                       (1 << GAIN) |
                        (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_GC0307] =      (1 << HFLIP) |
+[SENSOR_GC0307] =      (1 << EXPOSURE) |
+                       (1 << GAIN) |
+                       (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_HV7131R] =     (1 << HFLIP) |
+[SENSOR_HV7131R] =     (1 << EXPOSURE) |
+                       (1 << GAIN) |
+                       (1 << HFLIP) |
                        (1 << FREQ),
 
-[SENSOR_MI0360] =      (1 << HFLIP) |
+[SENSOR_MI0360] =      (1 << EXPOSURE) |
+                       (1 << GAIN) |
+                       (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_MI0360B] =     (1 << HFLIP) |
+[SENSOR_MI0360B] =     (1 << EXPOSURE) |
+                       (1 << GAIN) |
+                       (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_MO4000] =      (1 << HFLIP) |
+[SENSOR_MO4000] =      (1 << EXPOSURE) |
+                       (1 << GAIN) |
+                       (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_MT9V111] =     (1 << HFLIP) |
+[SENSOR_MT9V111] =     (1 << EXPOSURE) |
+                       (1 << GAIN) |
+                       (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_OM6802] =      (1 << HFLIP) |
+[SENSOR_OM6802] =      (1 << EXPOSURE) |
+                       (1 << GAIN) |
+                       (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_OV7630] =      (1 << HFLIP),
+[SENSOR_OV7630] =      (1 << EXPOSURE) |
+                       (1 << GAIN) |
+                       (1 << HFLIP),
 
-[SENSOR_OV7648] =      (1 << HFLIP),
+[SENSOR_OV7648] =      (1 << EXPOSURE) |
+                       (1 << GAIN) |
+                       (1 << HFLIP),
 
-[SENSOR_OV7660] =      (1 << AUTOGAIN) |
+[SENSOR_OV7660] =      (1 << EXPOSURE) |
+                       (1 << AUTOGAIN) |
+                       (1 << GAIN) |
                        (1 << HFLIP) |
                        (1 << VFLIP),
 
-[SENSOR_PO1030] =      (1 << AUTOGAIN) |
+[SENSOR_PO1030] =      (1 << EXPOSURE) |
+                       (1 << AUTOGAIN) |
+                       (1 << GAIN) |
                        (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_PO2030N] =     (1 << AUTOGAIN) |
-                       (1 << FREQ),
+[SENSOR_PO2030N] =     (1 << FREQ),
 
-[SENSOR_SOI768] =      (1 << AUTOGAIN) |
+[SENSOR_SOI768] =      (1 << EXPOSURE) |
+                       (1 << AUTOGAIN) |
+                       (1 << GAIN) |
                        (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
 
-[SENSOR_SP80708] =     (1 << AUTOGAIN) |
+[SENSOR_SP80708] =     (1 << EXPOSURE) |
+                       (1 << AUTOGAIN) |
+                       (1 << GAIN) |
                        (1 << HFLIP) |
                        (1 << VFLIP) |
                        (1 << FREQ),
@@ -1242,14 +1297,6 @@ static const u8 po2030n_sensor_param1[][8] = {
        {0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
        {0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10},
-       {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
-       {0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10},
-/*after start*/
-       {0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10},
-       {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
-       {0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10},
-       {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
-       {0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10},
        {}
 };
 
@@ -1858,7 +1905,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return gspca_dev->usb_err;
 }
 
-static u32 setexposure(struct gspca_dev *gspca_dev,
+static u32 expo_adjust(struct gspca_dev *gspca_dev,
                        u32 expo)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1982,28 +2029,28 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                        expo = 0x002dc6c0;
                else if (expo < 0x02a0)
                        expo = 0x02a0;
-               sd->exposure = setexposure(gspca_dev, expo);
+               sd->exposure = expo_adjust(gspca_dev, expo);
                break;
        case SENSOR_MI0360:
        case SENSOR_MO4000:
                expo = brightness << 4;
-               sd->exposure = setexposure(gspca_dev, expo);
+               sd->exposure = expo_adjust(gspca_dev, expo);
                break;
        case SENSOR_MI0360B:
                expo = brightness << 2;
-               sd->exposure = setexposure(gspca_dev, expo);
+               sd->exposure = expo_adjust(gspca_dev, expo);
                break;
        case SENSOR_GC0307:
                expo = brightness;
-               sd->exposure = setexposure(gspca_dev, expo);
+               sd->exposure = expo_adjust(gspca_dev, expo);
                return;                 /* don't set the Y offset */
        case SENSOR_MT9V111:
                expo = brightness << 2;
-               sd->exposure = setexposure(gspca_dev, expo);
+               sd->exposure = expo_adjust(gspca_dev, expo);
                return;                 /* don't set the Y offset */
        case SENSOR_OM6802:
                expo = brightness << 2;
-               sd->exposure = setexposure(gspca_dev, expo);
+               sd->exposure = expo_adjust(gspca_dev, expo);
                return;                 /* Y offset already set */
        }
 
@@ -2112,6 +2159,23 @@ static void setgamma(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0x20, gamma, sizeof gamma);
 }
 
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->sensor == SENSOR_PO2030N) {
+               u8 rexpo[] =            /* 1a: expo H, 1b: expo M */
+                       {0xa1, 0x6e, 0x1a, 0x00, 0x40, 0x00, 0x00, 0x10};
+
+               rexpo[3] = sd->ctrls[EXPOSURE].val >> 8;
+               i2c_w8(gspca_dev, rexpo);
+               msleep(6);
+               rexpo[2] = 0x1b;
+               rexpo[3] = sd->ctrls[EXPOSURE].val;
+               i2c_w8(gspca_dev, rexpo);
+       }
+}
+
 static void setautogain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -2139,6 +2203,19 @@ static void setautogain(struct gspca_dev *gspca_dev)
                sd->ag_cnt = -1;
 }
 
+static void setgain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (sd->sensor == SENSOR_PO2030N) {
+               u8 rgain[] =            /* 15: gain */
+                       {0xa1, 0x6e, 0x15, 0x00, 0x40, 0x00, 0x00, 0x15};
+
+               rgain[3] = sd->ctrls[GAIN].val;
+               i2c_w8(gspca_dev, rgain);
+       }
+}
+
 static void sethvflip(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -2623,6 +2700,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
        setcontrast(gspca_dev);
        setcolors(gspca_dev);
        setautogain(gspca_dev);
+       if (!(gspca_dev->ctrl_inac & ((1 << EXPOSURE) | (1 << GAIN)))) {
+               setexposure(gspca_dev);
+               setgain(gspca_dev);
+       }
        setfreq(gspca_dev);
 
        sd->pktsz = sd->npkt = 0;
@@ -2719,6 +2800,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
        }
 }
 
+/* !! coarse_grained_expo_autogain is not used !! */
+#define exp_too_low_cnt bridge
+#define exp_too_high_cnt sensor
+
+#include "autogain_functions.h"
+
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -2736,6 +2823,13 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 
        delta = atomic_read(&sd->avg_lum);
        PDEBUG(D_FRAM, "mean lum %d", delta);
+
+       if (sd->sensor == SENSOR_PO2030N) {
+               auto_gain_n_exposure(gspca_dev, delta, luma_mean, luma_delta,
+                                       15, 1024);
+               return;
+       }
+
        if (delta < luma_mean - luma_delta ||
            delta > luma_mean + luma_delta) {
                switch (sd->sensor) {
@@ -2744,7 +2838,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                        expotimes += (luma_mean - delta) >> 6;
                        if (expotimes < 0)
                                expotimes = 0;
-                       sd->exposure = setexposure(gspca_dev,
+                       sd->exposure = expo_adjust(gspca_dev,
                                                   (unsigned int) expotimes);
                        break;
                case SENSOR_HV7131R:
@@ -2752,7 +2846,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                        expotimes += (luma_mean - delta) >> 4;
                        if (expotimes < 0)
                                expotimes = 0;
-                       sd->exposure = setexposure(gspca_dev,
+                       sd->exposure = expo_adjust(gspca_dev,
                                        (unsigned int) (expotimes << 8));
                        break;
                case SENSOR_OM6802:
@@ -2761,7 +2855,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                        expotimes += (luma_mean - delta) >> 2;
                        if (expotimes < 0)
                                expotimes = 0;
-                       sd->exposure = setexposure(gspca_dev,
+                       sd->exposure = expo_adjust(gspca_dev,
                                                   (unsigned int) expotimes);
                        setredblue(gspca_dev);
                        break;
@@ -2773,7 +2867,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                        expotimes += (luma_mean - delta) >> 6;
                        if (expotimes < 0)
                                expotimes = 0;
-                       sd->exposure = setexposure(gspca_dev,
+                       sd->exposure = expo_adjust(gspca_dev,
                                                   (unsigned int) expotimes);
                        setredblue(gspca_dev);
                        break;
@@ -2948,16 +3042,18 @@ marker_found:
        }
 }
 
-static int sd_get_jcomp(struct gspca_dev *gspca_dev,
-                       struct v4l2_jpegcompression *jcomp)
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       memset(jcomp, 0, sizeof *jcomp);
-       jcomp->quality = sd->quality;
-       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
-                       | V4L2_JPEG_MARKER_DQT;
-       return 0;
+       sd->ctrls[AUTOGAIN].val = val;
+       if (val)
+               gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
+       else
+               gspca_dev->ctrl_inac &= ~(1 << EXPOSURE) & ~(1 << GAIN);
+       if (gspca_dev->streaming)
+               setautogain(gspca_dev);
+       return gspca_dev->usb_err;
 }
 
 static int sd_querymenu(struct gspca_dev *gspca_dev,
@@ -3012,7 +3108,6 @@ static const struct sd_desc sd_desc = {
        .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
        .dq_callback = do_autogain,
-       .get_jcomp = sd_get_jcomp,
        .querymenu = sd_querymenu,
 #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
        .int_pkt_scan = sd_int_pkt_scan,
index 5b318fa..38bc410 100644 (file)
@@ -6,5 +6,5 @@ gspca_stv06xx-objs := stv06xx.o \
                      stv06xx_pb0100.o \
                      stv06xx_st6422.o
 
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
 
index b9e15bb..7d9a4f1 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Z-Star/Vimicro zc301/zc302p/vc30x library
+ * Z-Star/Vimicro zc301/zc302p/vc30x driver
  *
- * Copyright (C) 2009-2011 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2012 Jean-Francois Moine <http://moinejf.free.fr>
  * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr
  *
  * This program is free software; you can redistribute it and/or modify
@@ -21,8 +21,6 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#define MODULE_NAME "zc3xx"
-
 #include <linux/input.h>
 #include "gspca.h"
 #include "jpeg.h"
@@ -34,7 +32,7 @@ MODULE_LICENSE("GPL");
 
 static int force_sensor = -1;
 
-#define QUANT_VAL 1            /* quantization table */
+#define REG08_DEF 3            /* default JPEG compression (70%) */
 #include "zc3xx-reg.h"
 
 /* controls */
@@ -46,6 +44,7 @@ enum e_ctrl {
        AUTOGAIN,
        LIGHTFREQ,
        SHARPNESS,
+       QUALITY,
        NCTRLS          /* number of controls */
 };
 
@@ -57,10 +56,10 @@ struct sd {
 
        struct gspca_ctrl ctrls[NCTRLS];
 
-       u8 quality;                     /* image quality */
-#define QUALITY_MIN 50
-#define QUALITY_MAX 80
-#define QUALITY_DEF 70
+       struct work_struct work;
+       struct workqueue_struct *work_thread;
+
+       u8 reg08;               /* webcam compression quality */
 
        u8 bridge;
        u8 sensor;              /* Type of image sensor chip */
@@ -101,6 +100,7 @@ static void setexposure(struct gspca_dev *gspca_dev);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static void setlightfreq(struct gspca_dev *gspca_dev);
 static void setsharpness(struct gspca_dev *gspca_dev);
+static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val);
 
 static const struct ctrl sd_ctrls[NCTRLS] = {
 [BRIGHTNESS] = {
@@ -188,6 +188,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
            },
            .set_control = setsharpness
        },
+[QUALITY] = {
+           {
+               .id      = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Compression Quality",
+               .minimum = 40,
+               .maximum = 70,
+               .step    = 1,
+               .default_value = 70     /* updated in sd_init() */
+           },
+           .set = sd_setquality
+       },
 };
 
 static const struct v4l2_pix_format vga_mode[] = {
@@ -229,6 +241,9 @@ static const struct v4l2_pix_format sif_mode[] = {
                .priv = 0},
 };
 
+/* bridge reg08 -> JPEG quality conversion table */
+static u8 jpeg_qual[] = {40, 50, 60, 70, /*80*/};
+
 /* usb exchanges */
 struct usb_action {
        u8      req;
@@ -3894,7 +3909,6 @@ static const struct usb_action pas106b_Initial[] = {      /* 352x288 */
 /* Gains */
        {0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF},
        {0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP},
-       {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN},
        {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
 /* Auto correction */
        {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
@@ -5640,7 +5654,7 @@ static const struct usb_action gc0303_NoFlikerScale[] = {
        {}
 };
 
-static u8 reg_r_i(struct gspca_dev *gspca_dev,
+static u8 reg_r(struct gspca_dev *gspca_dev,
                u16 index)
 {
        int ret;
@@ -5655,24 +5669,14 @@ static u8 reg_r_i(struct gspca_dev *gspca_dev,
                        index, gspca_dev->usb_buf, 1,
                        500);
        if (ret < 0) {
-               pr_err("reg_r_i err %d\n", ret);
+               pr_err("reg_r err %d\n", ret);
                gspca_dev->usb_err = ret;
                return 0;
        }
        return gspca_dev->usb_buf[0];
 }
 
-static u8 reg_r(struct gspca_dev *gspca_dev,
-               u16 index)
-{
-       u8 ret;
-
-       ret = reg_r_i(gspca_dev, index);
-       PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret);
-       return ret;
-}
-
-static void reg_w_i(struct gspca_dev *gspca_dev,
+static void reg_w(struct gspca_dev *gspca_dev,
                        u8 value,
                        u16 index)
 {
@@ -5692,14 +5696,6 @@ static void reg_w_i(struct gspca_dev *gspca_dev,
        }
 }
 
-static void reg_w(struct gspca_dev *gspca_dev,
-                       u8 value,
-                       u16 index)
-{
-       PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value);
-       reg_w_i(gspca_dev, value, index);
-}
-
 static u16 i2c_read(struct gspca_dev *gspca_dev,
                        u8 reg)
 {
@@ -5708,16 +5704,14 @@ static u16 i2c_read(struct gspca_dev *gspca_dev,
 
        if (gspca_dev->usb_err < 0)
                return 0;
-       reg_w_i(gspca_dev, reg, 0x0092);
-       reg_w_i(gspca_dev, 0x02, 0x0090);               /* <- read command */
+       reg_w(gspca_dev, reg, 0x0092);
+       reg_w(gspca_dev, 0x02, 0x0090);                 /* <- read command */
        msleep(20);
-       retbyte = reg_r_i(gspca_dev, 0x0091);           /* read status */
+       retbyte = reg_r(gspca_dev, 0x0091);             /* read status */
        if (retbyte != 0x00)
                pr_err("i2c_r status error %02x\n", retbyte);
-       retval = reg_r_i(gspca_dev, 0x0095);            /* read Lowbyte */
-       retval |= reg_r_i(gspca_dev, 0x0096) << 8;      /* read Hightbyte */
-       PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)",
-                       reg, retval, retbyte);
+       retval = reg_r(gspca_dev, 0x0095);              /* read Lowbyte */
+       retval |= reg_r(gspca_dev, 0x0096) << 8;        /* read Hightbyte */
        return retval;
 }
 
@@ -5730,16 +5724,14 @@ static u8 i2c_write(struct gspca_dev *gspca_dev,
 
        if (gspca_dev->usb_err < 0)
                return 0;
-       reg_w_i(gspca_dev, reg, 0x92);
-       reg_w_i(gspca_dev, valL, 0x93);
-       reg_w_i(gspca_dev, valH, 0x94);
-       reg_w_i(gspca_dev, 0x01, 0x90);         /* <- write command */
+       reg_w(gspca_dev, reg, 0x92);
+       reg_w(gspca_dev, valL, 0x93);
+       reg_w(gspca_dev, valH, 0x94);
+       reg_w(gspca_dev, 0x01, 0x90);           /* <- write command */
        msleep(1);
-       retbyte = reg_r_i(gspca_dev, 0x0091);           /* read status */
+       retbyte = reg_r(gspca_dev, 0x0091);             /* read status */
        if (retbyte != 0x00)
                pr_err("i2c_w status error %02x\n", retbyte);
-       PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)",
-                       reg, valH, valL, retbyte);
        return retbyte;
 }
 
@@ -5906,6 +5898,8 @@ static void getexposure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
+       if (sd->sensor != SENSOR_HV7131R)
+               return;
        sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9)
                | (i2c_read(gspca_dev, 0x26) << 1)
                | (i2c_read(gspca_dev, 0x27) >> 7);
@@ -5916,6 +5910,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int val;
 
+       if (sd->sensor != SENSOR_HV7131R)
+               return;
        val = sd->ctrls[EXPOSURE].val;
        i2c_write(gspca_dev, 0x25, val >> 9, 0x00);
        i2c_write(gspca_dev, 0x26, val >> 1, 0x00);
@@ -5925,32 +5921,20 @@ static void setexposure(struct gspca_dev *gspca_dev)
 static void setquality(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 frxt;
+       s8 reg07;
 
+       reg07 = 0;
        switch (sd->sensor) {
-       case SENSOR_ADCM2700:
-       case SENSOR_GC0305:
-       case SENSOR_HV7131B:
-       case SENSOR_HV7131R:
        case SENSOR_OV7620:
+               reg07 = 0x30;
+               break;
+       case SENSOR_HV7131R:
        case SENSOR_PAS202B:
-       case SENSOR_PO2030:
-               return;
+               return;                 /* done by work queue */
        }
-/*fixme: is it really 0008 0007 0018 for all other sensors? */
-       reg_w(gspca_dev, QUANT_VAL, 0x0008);
-       frxt = 0x30;
-       reg_w(gspca_dev, frxt, 0x0007);
-#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2
-       frxt = 0xff;
-#elif QUANT_VAL == 3
-       frxt = 0xf0;
-#elif QUANT_VAL == 4
-       frxt = 0xe0;
-#else
-       frxt = 0x20;
-#endif
-       reg_w(gspca_dev, frxt, 0x0018);
+       reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
+       if (reg07 != 0)
+               reg_w(gspca_dev, reg07, 0x0007);
 }
 
 /* Matches the sensor's internal frame rate to the lighting frequency.
@@ -6084,6 +6068,115 @@ static void setautogain(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, autoval, 0x0180);
 }
 
+/* update the transfer parameters */
+/* This function is executed from a work queue. */
+/* The exact use of the bridge registers 07 and 08 is not known.
+ * The following algorithm has been adapted from ms-win traces */
+static void transfer_update(struct work_struct *work)
+{
+       struct sd *sd = container_of(work, struct sd, work);
+       struct gspca_dev *gspca_dev = &sd->gspca_dev;
+       int change, good;
+       u8 reg07, reg11;
+
+       /* synchronize with the main driver and initialize the registers */
+       mutex_lock(&gspca_dev->usb_lock);
+       reg07 = 0;                                      /* max */
+       reg_w(gspca_dev, reg07, 0x0007);
+       reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
+       mutex_unlock(&gspca_dev->usb_lock);
+
+       good = 0;
+       for (;;) {
+               msleep(100);
+
+               /* get the transfer status */
+               /* the bit 0 of the bridge register 11 indicates overflow */
+               mutex_lock(&gspca_dev->usb_lock);
+               if (!gspca_dev->present || !gspca_dev->streaming)
+                       goto err;
+               reg11 = reg_r(gspca_dev, 0x0011);
+               if (gspca_dev->usb_err < 0
+                || !gspca_dev->present || !gspca_dev->streaming)
+                       goto err;
+
+               change = reg11 & 0x01;
+               if (change) {                           /* overflow */
+                       switch (reg07) {
+                       case 0:                         /* max */
+                               reg07 = sd->sensor == SENSOR_HV7131R
+                                               ? 0x30 : 0x32;
+                               if (sd->reg08 != 0) {
+                                       change = 3;
+                                       sd->reg08--;
+                               }
+                               break;
+                       case 0x32:
+                               reg07 -= 4;
+                               break;
+                       default:
+                               reg07 -= 2;
+                               break;
+                       case 2:
+                               change = 0;             /* already min */
+                               break;
+                       }
+                       good = 0;
+               } else {                                /* no overflow */
+                       if (reg07 != 0) {               /* if not max */
+                               good++;
+                               if (good >= 10) {
+                                       good = 0;
+                                       change = 1;
+                                       reg07 += 2;
+                                       switch (reg07) {
+                                       case 0x30:
+                                               if (sd->sensor == SENSOR_PAS202B)
+                                                       reg07 += 2;
+                                               break;
+                                       case 0x32:
+                                       case 0x34:
+                                               reg07 = 0;
+                                               break;
+                                       }
+                               }
+                       } else {                        /* reg07 max */
+                               if (sd->reg08 < sizeof jpeg_qual - 1) {
+                                       good++;
+                                       if (good > 10) {
+                                               sd->reg08++;
+                                               change = 2;
+                                       }
+                               }
+                       }
+               }
+               if (change) {
+                       if (change & 1) {
+                               reg_w(gspca_dev, reg07, 0x0007);
+                               if (gspca_dev->usb_err < 0
+                                || !gspca_dev->present
+                                || !gspca_dev->streaming)
+                                       goto err;
+                       }
+                       if (change & 2) {
+                               reg_w(gspca_dev, sd->reg08,
+                                               ZC3XX_R008_CLOCKSETTING);
+                               if (gspca_dev->usb_err < 0
+                                || !gspca_dev->present
+                                || !gspca_dev->streaming)
+                                       goto err;
+                               sd->ctrls[QUALITY].val = jpeg_qual[sd->reg08];
+                               jpeg_set_qual(sd->jpeg_hdr,
+                                               jpeg_qual[sd->reg08]);
+                       }
+               }
+               mutex_unlock(&gspca_dev->usb_lock);
+       }
+       return;
+err:
+       mutex_unlock(&gspca_dev->usb_lock);
+}
+
 static void send_unknown(struct gspca_dev *gspca_dev, int sensor)
 {
        reg_w(gspca_dev, 0x01, 0x0000);         /* bridge reset */
@@ -6411,7 +6504,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->sensor = id->driver_info;
 
        gspca_dev->cam.ctrls = sd->ctrls;
-       sd->quality = QUALITY_DEF;
+       sd->reg08 = REG08_DEF;
+
+       INIT_WORK(&sd->work, transfer_update);
 
        return 0;
 }
@@ -6464,6 +6559,27 @@ static int sd_init(struct gspca_dev *gspca_dev)
                [SENSOR_PO2030] =       1,
                [SENSOR_TAS5130C] =     1,
        };
+       static const u8 reg08_tb[SENSOR_MAX] = {
+               [SENSOR_ADCM2700] =     1,
+               [SENSOR_CS2102] =       3,
+               [SENSOR_CS2102K] =      3,
+               [SENSOR_GC0303] =       2,
+               [SENSOR_GC0305] =       3,
+               [SENSOR_HDCS2020] =     1,
+               [SENSOR_HV7131B] =      3,
+               [SENSOR_HV7131R] =      3,
+               [SENSOR_ICM105A] =      3,
+               [SENSOR_MC501CB] =      3,
+               [SENSOR_MT9V111_1] =    3,
+               [SENSOR_MT9V111_3] =    3,
+               [SENSOR_OV7620] =       1,
+               [SENSOR_OV7630C] =      3,
+               [SENSOR_PAS106] =       3,
+               [SENSOR_PAS202B] =      3,
+               [SENSOR_PB0330] =       3,
+               [SENSOR_PO2030] =       2,
+               [SENSOR_TAS5130C] =     3,
+       };
 
        sensor = zcxx_probeSensor(gspca_dev);
        if (sensor >= 0)
@@ -6528,7 +6644,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
                case 0x0e:
                        PDEBUG(D_PROBE, "Find Sensor PAS202B");
                        sd->sensor = SENSOR_PAS202B;
-/*                     sd->sharpness = 1; */
                        break;
                case 0x0f:
                        PDEBUG(D_PROBE, "Find Sensor PAS106");
@@ -6616,13 +6731,21 @@ static int sd_init(struct gspca_dev *gspca_dev)
        }
 
        sd->ctrls[GAMMA].def = gamma[sd->sensor];
+       sd->reg08 = reg08_tb[sd->sensor];
+       sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08];
+       sd->ctrls[QUALITY].min = jpeg_qual[0];
+       sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1];
 
        switch (sd->sensor) {
        case SENSOR_HV7131R:
+               gspca_dev->ctrl_dis = (1 << QUALITY);
                break;
        case SENSOR_OV7630C:
                gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
                break;
+       case SENSOR_PAS202B:
+               gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE);
+               break;
        default:
                gspca_dev->ctrl_dis = (1 << EXPOSURE);
                break;
@@ -6685,7 +6808,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        /* create the JPEG header */
        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
                        0x21);          /* JPEG 422 */
-       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
 
        mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
        switch (sd->sensor) {
@@ -6761,10 +6883,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_r(gspca_dev, 0x0180);       /* from win */
                reg_w(gspca_dev, 0x00, 0x0180);
                break;
-       default:
-               setquality(gspca_dev);
-               break;
        }
+       setquality(gspca_dev);
+       jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08]);
        setlightfreq(gspca_dev);
 
        switch (sd->sensor) {
@@ -6776,8 +6897,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev, 0x40, 0x0117);
                break;
        case SENSOR_HV7131R:
-               if (!sd->ctrls[AUTOGAIN].val)
-                       setexposure(gspca_dev);
+               setexposure(gspca_dev);
                reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
                break;
        case SENSOR_GC0305:
@@ -6802,13 +6922,19 @@ static int sd_start(struct gspca_dev *gspca_dev)
        }
 
        setautogain(gspca_dev);
-       switch (sd->sensor) {
-       case SENSOR_PO2030:
-               msleep(50);
-               reg_w(gspca_dev, 0x00, 0x0007); /* (from win traces) */
-               reg_w(gspca_dev, 0x02, ZC3XX_R008_CLOCKSETTING);
-               break;
+
+       /* start the transfer update thread if needed */
+       if (gspca_dev->usb_err >= 0) {
+               switch (sd->sensor) {
+               case SENSOR_HV7131R:
+               case SENSOR_PAS202B:
+                       sd->work_thread =
+                               create_singlethread_workqueue(KBUILD_MODNAME);
+                       queue_work(sd->work_thread, &sd->work);
+                       break;
+               }
        }
+
        return gspca_dev->usb_err;
 }
 
@@ -6817,6 +6943,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
+       if (sd->work_thread != NULL) {
+               mutex_unlock(&gspca_dev->usb_lock);
+               destroy_workqueue(sd->work_thread);
+               mutex_lock(&gspca_dev->usb_lock);
+               sd->work_thread = NULL;
+       }
        if (!gspca_dev->present)
                return;
        send_unknown(gspca_dev, sd->sensor);
@@ -6893,19 +7025,33 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
        return -EINVAL;
 }
 
+static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(jpeg_qual) - 1; i++) {
+               if (val <= jpeg_qual[i])
+                       break;
+       }
+       if (i > 0
+        && i == sd->reg08
+        && val < jpeg_qual[sd->reg08])
+               i--;
+       sd->reg08 = i;
+       sd->ctrls[QUALITY].val = jpeg_qual[i];
+       if (gspca_dev->streaming)
+               jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+       return gspca_dev->usb_err;
+}
+
 static int sd_set_jcomp(struct gspca_dev *gspca_dev,
                        struct v4l2_jpegcompression *jcomp)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (jcomp->quality < QUALITY_MIN)
-               sd->quality = QUALITY_MIN;
-       else if (jcomp->quality > QUALITY_MAX)
-               sd->quality = QUALITY_MAX;
-       else
-               sd->quality = jcomp->quality;
-       if (gspca_dev->streaming)
-               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+       sd_setquality(gspca_dev, jcomp->quality);
+       jcomp->quality = sd->ctrls[QUALITY].val;
        return gspca_dev->usb_err;
 }
 
@@ -6915,7 +7061,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
        struct sd *sd = (struct sd *) gspca_dev;
 
        memset(jcomp, 0, sizeof *jcomp);
-       jcomp->quality = sd->quality;
+       jcomp->quality = sd->ctrls[QUALITY].val;
        jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
                        | V4L2_JPEG_MARKER_DQT;
        return 0;
@@ -6938,7 +7084,7 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
 #endif
 
 static const struct sd_desc sd_desc = {
-       .name = MODULE_NAME,
+       .name = KBUILD_MODNAME,
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
@@ -7023,7 +7169,7 @@ static int sd_probe(struct usb_interface *intf,
 
 /* USB driver */
 static struct usb_driver sd_driver = {
-       .name = MODULE_NAME,
+       .name = KBUILD_MODNAME,
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
index eec75bb..351e9ba 100644 (file)
@@ -468,18 +468,7 @@ static struct i2c_driver imx074_i2c_driver = {
        .id_table       = imx074_id,
 };
 
-static int __init imx074_mod_init(void)
-{
-       return i2c_add_driver(&imx074_i2c_driver);
-}
-
-static void __exit imx074_mod_exit(void)
-{
-       i2c_del_driver(&imx074_i2c_driver);
-}
-
-module_init(imx074_mod_init);
-module_exit(imx074_mod_exit);
+module_i2c_driver(imx074_i2c_driver);
 
 MODULE_DESCRIPTION("Sony IMX074 Camera driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
index e5ed4db..5482363 100644 (file)
@@ -387,15 +387,4 @@ static struct i2c_driver indycam_driver = {
        .id_table       = indycam_id,
 };
 
-static __init int init_indycam(void)
-{
-       return i2c_add_driver(&indycam_driver);
-}
-
-static __exit void exit_indycam(void)
-{
-       i2c_del_driver(&indycam_driver);
-}
-
-module_init(init_indycam);
-module_exit(exit_indycam);
+module_i2c_driver(indycam_driver);
index a7c41d3..04f192a 100644 (file)
@@ -471,7 +471,7 @@ static const struct i2c_device_id ir_kbd_id[] = {
        { }
 };
 
-static struct i2c_driver driver = {
+static struct i2c_driver ir_kbd_driver = {
        .driver = {
                .name   = "ir-kbd-i2c",
        },
@@ -480,21 +480,10 @@ static struct i2c_driver driver = {
        .id_table       = ir_kbd_id,
 };
 
+module_i2c_driver(ir_kbd_driver);
+
 /* ----------------------------------------------------------------------- */
 
 MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller");
 MODULE_DESCRIPTION("input driver for i2c IR remote controls");
 MODULE_LICENSE("GPL");
-
-static int __init ir_init(void)
-{
-       return i2c_add_driver(&driver);
-}
-
-static void __exit ir_fini(void)
-{
-       i2c_del_driver(&driver);
-}
-
-module_init(ir_init);
-module_exit(ir_fini);
index 71ab76a..77de8a4 100644 (file)
@@ -7,8 +7,8 @@ ivtv-objs       := ivtv-routing.o ivtv-cards.o ivtv-controls.o \
 obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
 obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
 
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/video
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
 
index b31ee1b..c604246 100644 (file)
@@ -21,6 +21,7 @@
 #include "ivtv-driver.h"
 #include "ivtv-ioctl.h"
 #include "ivtv-controls.h"
+#include "ivtv-mailbox.h"
 
 static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
 {
@@ -99,3 +100,64 @@ struct cx2341x_handler_ops ivtv_cxhdl_ops = {
        .s_video_encoding = ivtv_s_video_encoding,
        .s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt,
 };
+
+int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame)
+{
+       u32 data[CX2341X_MBOX_MAX_DATA];
+
+       if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
+               *pts = (s64)((u64)itv->last_dec_timing[2] << 32) |
+                       (u64)itv->last_dec_timing[1];
+               *frame = itv->last_dec_timing[0];
+               return 0;
+       }
+       *pts = 0;
+       *frame = 0;
+       if (atomic_read(&itv->decoding)) {
+               if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
+                       IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
+                       return -EIO;
+               }
+               memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
+               set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
+               *pts = (s64)((u64) data[2] << 32) | (u64) data[1];
+               *frame = data[0];
+               /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/
+       }
+       return 0;
+}
+
+static int ivtv_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl);
+
+       switch (ctrl->id) {
+       /* V4L2_CID_MPEG_VIDEO_DEC_PTS and V4L2_CID_MPEG_VIDEO_DEC_FRAME
+          control cluster */
+       case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+               return ivtv_g_pts_frame(itv, &itv->ctrl_pts->val64,
+                                            &itv->ctrl_frame->val64);
+       }
+       return 0;
+}
+
+static int ivtv_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ivtv *itv = container_of(ctrl->handler, struct ivtv, cxhdl.hdl);
+
+       switch (ctrl->id) {
+       /* V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK and MULTILINGUAL_PLAYBACK
+          control cluster */
+       case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+               itv->audio_stereo_mode = itv->ctrl_audio_playback->val - 1;
+               itv->audio_bilingual_mode = itv->ctrl_audio_multilingual_playback->val - 1;
+               ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+               break;
+       }
+       return 0;
+}
+
+const struct v4l2_ctrl_ops ivtv_hdl_out_ops = {
+       .s_ctrl = ivtv_s_ctrl,
+       .g_volatile_ctrl = ivtv_g_volatile_ctrl,
+};
index d12893d..3999e63 100644 (file)
@@ -22,5 +22,7 @@
 #define IVTV_CONTROLS_H
 
 extern struct cx2341x_handler_ops ivtv_cxhdl_ops;
+extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops;
+int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame);
 
 #endif
index 3949b7d..679262e 100644 (file)
@@ -55,7 +55,7 @@
 #include "ivtv-routing.h"
 #include "ivtv-controls.h"
 #include "ivtv-gpio.h"
-
+#include <linux/dma-mapping.h>
 #include <media/tveeprom.h>
 #include <media/saa7115.h>
 #include <media/v4l2-chip-ident.h>
@@ -99,7 +99,7 @@ static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
 
 static unsigned int cardtype_c = 1;
 static unsigned int tuner_c = 1;
-static bool radio_c = 1;
+static int radio_c = 1;
 static unsigned int i2c_clock_period_c = 1;
 static char pal[] = "---";
 static char secam[] = "--";
@@ -139,7 +139,7 @@ static int tunertype = -1;
 static int newi2c = -1;
 
 module_param_array(tuner, int, &tuner_c, 0644);
-module_param_array(radio, bool, &radio_c, 0644);
+module_param_array(radio, int, &radio_c, 0644);
 module_param_array(cardtype, int, &cardtype_c, 0644);
 module_param_string(pal, pal, sizeof(pal), 0644);
 module_param_string(secam, secam, sizeof(secam), 0644);
@@ -744,8 +744,6 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
 
        itv->cur_dma_stream = -1;
        itv->cur_pio_stream = -1;
-       itv->audio_stereo_mode = AUDIO_STEREO;
-       itv->audio_bilingual_mode = AUDIO_MONO_LEFT;
 
        /* Ctrls */
        itv->speed = 1000;
@@ -815,7 +813,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
                IVTV_ERR("Can't enable device!\n");
                return -EIO;
        }
-       if (pci_set_dma_mask(pdev, 0xffffffff)) {
+       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
                IVTV_ERR("No suitable DMA available.\n");
                return -EIO;
        }
@@ -1200,6 +1198,32 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
        itv->tuner_std = itv->std;
 
        if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+               struct v4l2_ctrl_handler *hdl = itv->v4l2_dev.ctrl_handler;
+
+               itv->ctrl_pts = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
+                               V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 1, 0);
+               itv->ctrl_frame = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
+                               V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0x7fffffff, 1, 0);
+               /* Note: V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO is not supported,
+                  mask that menu item. */
+               itv->ctrl_audio_playback =
+                       v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops,
+                               V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK,
+                               V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO,
+                               1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO,
+                               V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO);
+               itv->ctrl_audio_multilingual_playback =
+                       v4l2_ctrl_new_std_menu(hdl, &ivtv_hdl_out_ops,
+                               V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK,
+                               V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO,
+                               1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO,
+                               V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT);
+               if (hdl->error) {
+                       retval = hdl->error;
+                       goto free_i2c;
+               }
+               v4l2_ctrl_cluster(2, &itv->ctrl_pts);
+               v4l2_ctrl_cluster(2, &itv->ctrl_audio_playback);
                ivtv_call_all(itv, video, s_std_output, itv->std);
                /* Turn off the output signal. The mpeg decoder is not yet
                   active so without this you would get a green image until the
@@ -1236,6 +1260,7 @@ free_streams:
 free_irq:
        free_irq(itv->pdev->irq, (void *)itv);
 free_i2c:
+       v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
        exit_ivtv_i2c(itv);
 free_io:
        ivtv_iounmap(itv);
@@ -1375,7 +1400,7 @@ static void ivtv_remove(struct pci_dev *pdev)
                        else
                                type = IVTV_DEC_STREAM_TYPE_MPG;
                        ivtv_stop_v4l2_decode_stream(&itv->streams[type],
-                               VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+                               V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0);
                }
                ivtv_halt_firmware(itv);
        }
@@ -1391,6 +1416,8 @@ static void ivtv_remove(struct pci_dev *pdev)
        ivtv_streams_cleanup(itv, 1);
        ivtv_udma_free(itv);
 
+       v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
+
        exit_ivtv_i2c(itv);
 
        free_irq(itv->pdev->irq, (void *)itv);
index 52d5dd7..2e22002 100644 (file)
@@ -330,6 +330,7 @@ struct ivtv_stream {
        struct ivtv *itv;               /* for ease of use */
        const char *name;               /* name of the stream */
        int type;                       /* stream type */
+       u32 caps;                       /* V4L2 capabilities */
 
        struct v4l2_fh *fh;             /* pointer to the streaming filehandle */
        spinlock_t qlock;               /* locks access to the queues */
@@ -629,6 +630,16 @@ struct ivtv {
 
        struct v4l2_device v4l2_dev;
        struct cx2341x_handler cxhdl;
+       struct {
+               /* PTS/Frame count control cluster */
+               struct v4l2_ctrl *ctrl_pts;
+               struct v4l2_ctrl *ctrl_frame;
+       };
+       struct {
+               /* Audio Playback control cluster */
+               struct v4l2_ctrl *ctrl_audio_playback;
+               struct v4l2_ctrl *ctrl_audio_multilingual_playback;
+       };
        struct v4l2_ctrl_handler hdl_gpio;
        struct v4l2_subdev sd_gpio;     /* GPIO sub-device */
        u16 instance;
@@ -648,7 +659,6 @@ struct ivtv {
        u8 audio_stereo_mode;           /* decoder setting how to handle stereo MPEG audio */
        u8 audio_bilingual_mode;        /* decoder setting how to handle bilingual MPEG audio */
 
-
        /* Locking */
        spinlock_t lock;                /* lock access to this struct */
        struct mutex serialize_lock;    /* mutex used to serialize open/close/start/stop/ioctl operations */
index 2cd6c89..c9663e8 100644 (file)
@@ -900,7 +900,7 @@ int ivtv_v4l2_close(struct file *filp)
        if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
                struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT];
 
-               ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+               ivtv_stop_decoding(id, V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0);
 
                /* If all output streams are closed, and if the user doesn't have
                   IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */
index c4bc481..5452bee 100644 (file)
@@ -246,34 +246,40 @@ static int ivtv_validate_speed(int cur_speed, int new_speed)
 }
 
 static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
-               struct video_command *vc, int try)
+               struct v4l2_decoder_cmd *dc, int try)
 {
        struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
 
        if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
                return -EINVAL;
 
-       switch (vc->cmd) {
-       case VIDEO_CMD_PLAY: {
-               vc->flags = 0;
-               vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed);
-               if (vc->play.speed < 0)
-                       vc->play.format = VIDEO_PLAY_FMT_GOP;
+       switch (dc->cmd) {
+       case V4L2_DEC_CMD_START: {
+               dc->flags &= V4L2_DEC_CMD_START_MUTE_AUDIO;
+               dc->start.speed = ivtv_validate_speed(itv->speed, dc->start.speed);
+               if (dc->start.speed < 0)
+                       dc->start.format = V4L2_DEC_START_FMT_GOP;
+               else
+                       dc->start.format = V4L2_DEC_START_FMT_NONE;
+               if (dc->start.speed != 500 && dc->start.speed != 1500)
+                       dc->flags = dc->start.speed == 1000 ? 0 :
+                                       V4L2_DEC_CMD_START_MUTE_AUDIO;
                if (try) break;
 
+               itv->speed_mute_audio = dc->flags & V4L2_DEC_CMD_START_MUTE_AUDIO;
                if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)
                        return -EBUSY;
                if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
                        /* forces ivtv_set_speed to be called */
                        itv->speed = 0;
                }
-               return ivtv_start_decoding(id, vc->play.speed);
+               return ivtv_start_decoding(id, dc->start.speed);
        }
 
-       case VIDEO_CMD_STOP:
-               vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK;
-               if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY)
-                       vc->stop.pts = 0;
+       case V4L2_DEC_CMD_STOP:
+               dc->flags &= V4L2_DEC_CMD_STOP_IMMEDIATELY | V4L2_DEC_CMD_STOP_TO_BLACK;
+               if (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY)
+                       dc->stop.pts = 0;
                if (try) break;
                if (atomic_read(&itv->decoding) == 0)
                        return 0;
@@ -281,22 +287,22 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
                        return -EBUSY;
 
                itv->output_mode = OUT_NONE;
-               return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts);
+               return ivtv_stop_v4l2_decode_stream(s, dc->flags, dc->stop.pts);
 
-       case VIDEO_CMD_FREEZE:
-               vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK;
+       case V4L2_DEC_CMD_PAUSE:
+               dc->flags &= V4L2_DEC_CMD_PAUSE_TO_BLACK;
                if (try) break;
                if (itv->output_mode != OUT_MPG)
                        return -EBUSY;
                if (atomic_read(&itv->decoding) > 0) {
                        ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,
-                               (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0);
+                               (dc->flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? 1 : 0);
                        set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
                }
                break;
 
-       case VIDEO_CMD_CONTINUE:
-               vc->flags = 0;
+       case V4L2_DEC_CMD_RESUME:
+               dc->flags = 0;
                if (try) break;
                if (itv->output_mode != OUT_MPG)
                        return -EBUSY;
@@ -754,12 +760,15 @@ static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register
 
 static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap)
 {
-       struct ivtv *itv = fh2id(fh)->itv;
+       struct ivtv_open_id *id = fh2id(file->private_data);
+       struct ivtv *itv = id->itv;
+       struct ivtv_stream *s = &itv->streams[id->type];
 
        strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
        strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
        snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
-       vcap->capabilities = itv->v4l2_cap;         /* capabilities */
+       vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
+       vcap->device_caps = s->caps;
        return 0;
 }
 
@@ -1476,8 +1485,6 @@ static int ivtv_log_status(struct file *file, void *fh)
        struct v4l2_audio audin;
        int i;
 
-       IVTV_INFO("=================  START STATUS CARD #%d  =================\n",
-                      itv->instance);
        IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
        if (itv->hw_flags & IVTV_HW_TVEEPROM) {
                struct tveeprom tv;
@@ -1501,13 +1508,6 @@ static int ivtv_log_status(struct file *file, void *fh)
                        "YUV Frames",
                        "Passthrough",
                };
-               static const char * const audio_modes[5] = {
-                       "Stereo",
-                       "Left",
-                       "Right",
-                       "Mono",
-                       "Swapped"
-               };
                static const char * const alpha_mode[4] = {
                        "None",
                        "Global",
@@ -1536,9 +1536,6 @@ static int ivtv_log_status(struct file *file, void *fh)
                ivtv_get_output(itv, itv->active_output, &vidout);
                ivtv_get_audio_output(itv, 0, &audout);
                IVTV_INFO("Video Output: %s\n", vidout.name);
-               IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
-                       audio_modes[itv->audio_stereo_mode],
-                       audio_modes[itv->audio_bilingual_mode]);
                if (mode < 0 || mode > OUT_PASSTHROUGH)
                        mode = OUT_NONE;
                IVTV_INFO("Output Mode:  %s\n", output_modes[mode]);
@@ -1566,12 +1563,27 @@ static int ivtv_log_status(struct file *file, void *fh)
        IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n",
                        (long long)itv->mpg_data_received,
                        (long long)itv->vbi_data_inserted);
-       IVTV_INFO("==================  END STATUS CARD #%d  ==================\n",
-                       itv->instance);
-
        return 0;
 }
 
+static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
+{
+       struct ivtv_open_id *id = fh2id(file->private_data);
+       struct ivtv *itv = id->itv;
+
+       IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd);
+       return ivtv_video_command(itv, id, dec, false);
+}
+
+static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec)
+{
+       struct ivtv_open_id *id = fh2id(file->private_data);
+       struct ivtv *itv = id->itv;
+
+       IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd);
+       return ivtv_video_command(itv, id, dec, true);
+}
+
 static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
 {
        struct ivtv_open_id *id = fh2id(filp->private_data);
@@ -1605,9 +1617,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                return ivtv_yuv_prep_frame(itv, args);
        }
 
+       case IVTV_IOC_PASSTHROUGH_MODE:
+               IVTV_DEBUG_IOCTL("IVTV_IOC_PASSTHROUGH_MODE\n");
+               if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+                       return -EINVAL;
+               return ivtv_passthrough_mode(itv, *(int *)arg != 0);
+
        case VIDEO_GET_PTS: {
-               u32 data[CX2341X_MBOX_MAX_DATA];
-               u64 *pts = arg;
+               s64 *pts = arg;
+               s64 frame;
 
                IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n");
                if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
@@ -1616,29 +1634,12 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                }
                if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
                        return -EINVAL;
-
-               if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
-                       *pts = (u64) ((u64)itv->last_dec_timing[2] << 32) |
-                                       (u64)itv->last_dec_timing[1];
-                       break;
-               }
-               *pts = 0;
-               if (atomic_read(&itv->decoding)) {
-                       if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
-                               IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
-                               return -EIO;
-                       }
-                       memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
-                       set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
-                       *pts = (u64) ((u64) data[2] << 32) | (u64) data[1];
-                       /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/
-               }
-               break;
+               return ivtv_g_pts_frame(itv, pts, &frame);
        }
 
        case VIDEO_GET_FRAME_COUNT: {
-               u32 data[CX2341X_MBOX_MAX_DATA];
-               u64 *frame = arg;
+               s64 *frame = arg;
+               s64 pts;
 
                IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n");
                if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
@@ -1647,71 +1648,58 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                }
                if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
                        return -EINVAL;
-
-               if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
-                       *frame = itv->last_dec_timing[0];
-                       break;
-               }
-               *frame = 0;
-               if (atomic_read(&itv->decoding)) {
-                       if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
-                               IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
-                               return -EIO;
-                       }
-                       memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
-                       set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
-                       *frame = data[0];
-               }
-               break;
+               return ivtv_g_pts_frame(itv, &pts, frame);
        }
 
        case VIDEO_PLAY: {
-               struct video_command vc;
+               struct v4l2_decoder_cmd dc;
 
                IVTV_DEBUG_IOCTL("VIDEO_PLAY\n");
-               memset(&vc, 0, sizeof(vc));
-               vc.cmd = VIDEO_CMD_PLAY;
-               return ivtv_video_command(itv, id, &vc, 0);
+               memset(&dc, 0, sizeof(dc));
+               dc.cmd = V4L2_DEC_CMD_START;
+               return ivtv_video_command(itv, id, &dc, 0);
        }
 
        case VIDEO_STOP: {
-               struct video_command vc;
+               struct v4l2_decoder_cmd dc;
 
                IVTV_DEBUG_IOCTL("VIDEO_STOP\n");
-               memset(&vc, 0, sizeof(vc));
-               vc.cmd = VIDEO_CMD_STOP;
-               vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY;
-               return ivtv_video_command(itv, id, &vc, 0);
+               memset(&dc, 0, sizeof(dc));
+               dc.cmd = V4L2_DEC_CMD_STOP;
+               dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY;
+               return ivtv_video_command(itv, id, &dc, 0);
        }
 
        case VIDEO_FREEZE: {
-               struct video_command vc;
+               struct v4l2_decoder_cmd dc;
 
                IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n");
-               memset(&vc, 0, sizeof(vc));
-               vc.cmd = VIDEO_CMD_FREEZE;
-               return ivtv_video_command(itv, id, &vc, 0);
+               memset(&dc, 0, sizeof(dc));
+               dc.cmd = V4L2_DEC_CMD_PAUSE;
+               return ivtv_video_command(itv, id, &dc, 0);
        }
 
        case VIDEO_CONTINUE: {
-               struct video_command vc;
+               struct v4l2_decoder_cmd dc;
 
                IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n");
-               memset(&vc, 0, sizeof(vc));
-               vc.cmd = VIDEO_CMD_CONTINUE;
-               return ivtv_video_command(itv, id, &vc, 0);
+               memset(&dc, 0, sizeof(dc));
+               dc.cmd = V4L2_DEC_CMD_RESUME;
+               return ivtv_video_command(itv, id, &dc, 0);
        }
 
        case VIDEO_COMMAND:
        case VIDEO_TRY_COMMAND: {
-               struct video_command *vc = arg;
+               /* Note: struct v4l2_decoder_cmd has the same layout as
+                  struct video_command */
+               struct v4l2_decoder_cmd *dc = arg;
                int try = (cmd == VIDEO_TRY_COMMAND);
 
                if (try)
-                       IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd);
+                       IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", dc->cmd);
                else
-                       IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd);
-               return ivtv_video_command(itv, id, vc, try);
+                       IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", dc->cmd);
+               return ivtv_video_command(itv, id, dc, try);
        }
 
        case VIDEO_GET_EVENT: {
@@ -1775,17 +1763,13 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n");
                if (iarg > AUDIO_STEREO_SWAPPED)
                        return -EINVAL;
-               itv->audio_stereo_mode = iarg;
-               ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
-               return 0;
+               return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg);
 
        case AUDIO_BILINGUAL_CHANNEL_SELECT:
                IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n");
                if (iarg > AUDIO_STEREO_SWAPPED)
                        return -EINVAL;
-               itv->audio_bilingual_mode = iarg;
-               ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
-               return 0;
+               return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg);
 
        default:
                return -EINVAL;
@@ -1800,6 +1784,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
 
        if (!valid_prio) {
                switch (cmd) {
+               case IVTV_IOC_PASSTHROUGH_MODE:
                case VIDEO_PLAY:
                case VIDEO_STOP:
                case VIDEO_FREEZE:
@@ -1825,6 +1810,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
        }
 
        case IVTV_IOC_DMA_FRAME:
+       case IVTV_IOC_PASSTHROUGH_MODE:
        case VIDEO_GET_PTS:
        case VIDEO_GET_FRAME_COUNT:
        case VIDEO_GET_EVENT:
@@ -1889,6 +1875,8 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
        .vidioc_enum_fmt_vid_cap            = ivtv_enum_fmt_vid_cap,
        .vidioc_encoder_cmd                 = ivtv_encoder_cmd,
        .vidioc_try_encoder_cmd             = ivtv_try_encoder_cmd,
+       .vidioc_decoder_cmd                 = ivtv_decoder_cmd,
+       .vidioc_try_decoder_cmd             = ivtv_try_decoder_cmd,
        .vidioc_enum_fmt_vid_out            = ivtv_enum_fmt_vid_out,
        .vidioc_g_fmt_vid_cap               = ivtv_g_fmt_vid_cap,
        .vidioc_g_fmt_vbi_cap               = ivtv_g_fmt_vbi_cap,
index c6e28b4..7ea5ca7 100644 (file)
@@ -78,60 +78,73 @@ static struct {
        int num_offset;
        int dma, pio;
        enum v4l2_buf_type buf_type;
+       u32 v4l2_caps;
        const struct v4l2_file_operations *fops;
 } ivtv_stream_info[] = {
        {       /* IVTV_ENC_STREAM_TYPE_MPG */
                "encoder MPG",
                VFL_TYPE_GRABBER, 0,
                PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+                       V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
                &ivtv_v4l2_enc_fops
        },
        {       /* IVTV_ENC_STREAM_TYPE_YUV */
                "encoder YUV",
                VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET,
                PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+                       V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
                &ivtv_v4l2_enc_fops
        },
        {       /* IVTV_ENC_STREAM_TYPE_VBI */
                "encoder VBI",
                VFL_TYPE_VBI, 0,
                PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE,
+               V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_TUNER |
+                       V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
                &ivtv_v4l2_enc_fops
        },
        {       /* IVTV_ENC_STREAM_TYPE_PCM */
                "encoder PCM",
                VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET,
                PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE,
+               V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
                &ivtv_v4l2_enc_fops
        },
        {       /* IVTV_ENC_STREAM_TYPE_RAD */
                "encoder radio",
                VFL_TYPE_RADIO, 0,
                PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE,
+               V4L2_CAP_RADIO | V4L2_CAP_TUNER,
                &ivtv_v4l2_enc_fops
        },
        {       /* IVTV_DEC_STREAM_TYPE_MPG */
                "decoder MPG",
                VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
                PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
                &ivtv_v4l2_dec_fops
        },
        {       /* IVTV_DEC_STREAM_TYPE_VBI */
                "decoder VBI",
                VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET,
                PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE,
+               V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_READWRITE,
                &ivtv_v4l2_enc_fops
        },
        {       /* IVTV_DEC_STREAM_TYPE_VOUT */
                "decoder VOUT",
                VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET,
                PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT,
+               V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
                &ivtv_v4l2_dec_fops
        },
        {       /* IVTV_DEC_STREAM_TYPE_YUV */
                "decoder YUV",
                VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET,
                PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
                &ivtv_v4l2_dec_fops
        }
 };
@@ -149,6 +162,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
        s->itv = itv;
        s->type = type;
        s->name = ivtv_stream_info[type].name;
+       s->caps = ivtv_stream_info[type].v4l2_caps;
 
        if (ivtv_stream_info[type].pio)
                s->dma = PCI_DMA_NONE;
@@ -209,8 +223,8 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
 
        s->vdev->num = num;
        s->vdev->v4l2_dev = &itv->v4l2_dev;
-       s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler;
        s->vdev->fops = ivtv_stream_info[type].fops;
+       s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler;
        s->vdev->release = video_device_release;
        s->vdev->tvnorms = V4L2_STD_ALL;
        s->vdev->lock = &itv->serialize_lock;
@@ -891,7 +905,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
        IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", (unsigned long long)pts, flags);
 
        /* Stop Decoder */
-       if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) {
+       if (!(flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) || pts) {
                u32 tmp = 0;
 
                /* Wait until the decoder is no longer running */
@@ -911,7 +925,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
                                break;
                }
        }
-       ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0);
+       ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & V4L2_DEC_CMD_STOP_TO_BLACK, 0, 0);
 
        /* turn off notification of dual/stereo mode change */
        ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
index afa9118..ee7ca2d 100644 (file)
@@ -721,15 +721,4 @@ static struct i2c_driver ks0127_driver = {
        .id_table       = ks0127_id,
 };
 
-static __init int init_ks0127(void)
-{
-       return i2c_add_driver(&ks0127_driver);
-}
-
-static __exit void exit_ks0127(void)
-{
-       i2c_del_driver(&ks0127_driver);
-}
-
-module_init(init_ks0127);
-module_exit(exit_ks0127);
+module_i2c_driver(ks0127_driver);
index 303ffa7..0991576 100644 (file)
@@ -213,15 +213,4 @@ static struct i2c_driver m52790_driver = {
        .id_table       = m52790_id,
 };
 
-static __init int init_m52790(void)
-{
-       return i2c_add_driver(&m52790_driver);
-}
-
-static __exit void exit_m52790(void)
-{
-       i2c_del_driver(&m52790_driver);
-}
-
-module_init(init_m52790);
-module_exit(exit_m52790);
+module_i2c_driver(m52790_driver);
index 93d768d..d718aee 100644 (file)
@@ -982,8 +982,8 @@ static int __devinit m5mols_probe(struct i2c_client *client,
        }
 
        sd = &info->sd;
-       strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
        v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
+       strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
        sd->internal_ops = &m5mols_subdev_internal_ops;
@@ -1057,18 +1057,7 @@ static struct i2c_driver m5mols_i2c_driver = {
        .id_table       = m5mols_id,
 };
 
-static int __init m5mols_mod_init(void)
-{
-       return i2c_add_driver(&m5mols_i2c_driver);
-}
-
-static void __exit m5mols_mod_exit(void)
-{
-       i2c_del_driver(&m5mols_i2c_driver);
-}
-
-module_init(m5mols_mod_init);
-module_exit(m5mols_mod_exit);
+module_i2c_driver(m5mols_i2c_driver);
 
 MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
 MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>");
index 37d20e7..996ac34 100644 (file)
@@ -509,11 +509,17 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam)
 
        buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
        list_del_init(&buf->queue);
+       /*
+        * Very Bad Not Good Things happen if you don't clear
+        * C1_DESC_ENA before making any descriptor changes.
+        */
+       mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
        mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa);
        mcam_reg_write(cam, REG_DESC_LEN_Y,
                        buf->dma_desc_nent*sizeof(struct mcam_dma_desc));
        mcam_reg_write(cam, REG_DESC_LEN_U, 0);
        mcam_reg_write(cam, REG_DESC_LEN_V, 0);
+       mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
        cam->vb_bufs[0] = buf;
 }
 
@@ -533,7 +539,6 @@ static void mcam_ctlr_dma_sg(struct mcam_camera *cam)
 
        mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD);
        mcam_sg_next_buffer(cam);
-       mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
        cam->nbufs = 3;
 }
 
@@ -556,17 +561,16 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
        struct mcam_vb_buffer *buf = cam->vb_bufs[0];
 
        /*
-        * Very Bad Not Good Things happen if you don't clear
-        * C1_DESC_ENA before making any descriptor changes.
+        * If we're no longer supposed to be streaming, don't do anything.
         */
-       mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
+       if (cam->state != S_STREAMING)
+               return;
        /*
         * If we have another buffer available, put it in and
         * restart the engine.
         */
        if (!list_empty(&cam->buffers)) {
                mcam_sg_next_buffer(cam);
-               mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
                mcam_ctlr_start(cam);
        /*
         * Otherwise set CF_SG_RESTART and the controller will
@@ -737,7 +741,14 @@ static void mcam_ctlr_stop_dma(struct mcam_camera *cam)
        mcam_ctlr_stop(cam);
        cam->state = S_IDLE;
        spin_unlock_irqrestore(&cam->dev_lock, flags);
-       msleep(40);
+       /*
+        * This is a brutally long sleep, but experience shows that
+        * it can take the controller a while to get the message that
+        * it needs to stop grabbing frames.  In particular, we can
+        * sometimes (on mmp) get a frame at the end WITHOUT the
+        * start-of-frame indication.
+        */
+       msleep(150);
        if (test_bit(CF_DMA_ACTIVE, &cam->flags))
                cam_err(cam, "Timeout waiting for DMA to end\n");
                /* This would be bad news - what now? */
@@ -880,6 +891,7 @@ static int mcam_read_setup(struct mcam_camera *cam)
         * Turn it loose.
         */
        spin_lock_irqsave(&cam->dev_lock, flags);
+       clear_bit(CF_DMA_ACTIVE, &cam->flags);
        mcam_reset_buffers(cam);
        mcam_ctlr_irq_enable(cam);
        cam->state = S_STREAMING;
@@ -922,7 +934,7 @@ static void mcam_vb_buf_queue(struct vb2_buffer *vb)
        spin_lock_irqsave(&cam->dev_lock, flags);
        start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers);
        list_add(&mvb->queue, &cam->buffers);
-       if (test_bit(CF_SG_RESTART, &cam->flags))
+       if (cam->state == S_STREAMING && test_bit(CF_SG_RESTART, &cam->flags))
                mcam_sg_restart(cam);
        spin_unlock_irqrestore(&cam->dev_lock, flags);
        if (start)
@@ -1555,15 +1567,12 @@ static int mcam_v4l_release(struct file *filp)
 {
        struct mcam_camera *cam = filp->private_data;
 
-       cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
+       cam_dbg(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
                        singles, delivered);
        mutex_lock(&cam->s_mutex);
        (cam->users)--;
-       if (filp == cam->owner) {
-               mcam_ctlr_stop_dma(cam);
-               cam->owner = NULL;
-       }
        if (cam->users == 0) {
+               mcam_ctlr_stop_dma(cam);
                mcam_cleanup_vb2(cam);
                mcam_ctlr_power_down(cam);
                if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
@@ -1688,6 +1697,8 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
                if (irqs & (IRQ_EOF0 << frame)) {
                        mcam_frame_complete(cam, frame);
                        handled = 1;
+                       if (cam->buffer_mode == B_DMA_sg)
+                               break;
                }
        /*
         * If a frame starts, note that we have DMA active.  This
index 917200e..bd6acba 100644 (file)
@@ -107,7 +107,6 @@ struct mcam_camera {
        enum mcam_state state;
        unsigned long flags;            /* Buffer status, mainly (dev_lock) */
        int users;                      /* How many open FDs */
-       struct file *owner;             /* Who has data access (v4l2) */
 
        /*
         * Subsystem structures.
index 0d64e2d..d235523 100644 (file)
@@ -106,6 +106,13 @@ static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
 /*
  * Power control.
  */
+static void mmpcam_power_up_ctlr(struct mmp_camera *cam)
+{
+       iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
+       iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
+       mdelay(1);
+}
+
 static void mmpcam_power_up(struct mcam_camera *mcam)
 {
        struct mmp_camera *cam = mcam_to_cam(mcam);
@@ -113,9 +120,7 @@ static void mmpcam_power_up(struct mcam_camera *mcam)
 /*
  * Turn on power and clocks to the controller.
  */
-       iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
-       iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
-       mdelay(1);
+       mmpcam_power_up_ctlr(cam);
 /*
  * Provide power to the sensor.
  */
@@ -335,7 +340,7 @@ static int mmpcam_resume(struct platform_device *pdev)
         * touch a register even if nothing was active before; trust
         * me, it's better this way.
         */
-       mmpcam_power_up(&cam->mcam);
+       mmpcam_power_up_ctlr(cam);
        return mccic_resume(&cam->mcam);
 }
 
index d7cd0f6..82ce507 100644 (file)
@@ -881,18 +881,7 @@ static struct i2c_driver msp_driver = {
        .id_table       = msp_id,
 };
 
-static __init int init_msp(void)
-{
-       return i2c_add_driver(&msp_driver);
-}
-
-static __exit void exit_msp(void)
-{
-       i2c_del_driver(&msp_driver);
-}
-
-module_init(init_msp);
-module_exit(exit_msp);
+module_i2c_driver(msp_driver);
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
index 097c9d3..7e64818 100644 (file)
@@ -730,18 +730,7 @@ static struct i2c_driver mt9m001_i2c_driver = {
        .id_table       = mt9m001_id,
 };
 
-static int __init mt9m001_mod_init(void)
-{
-       return i2c_add_driver(&mt9m001_i2c_driver);
-}
-
-static void __exit mt9m001_mod_exit(void)
-{
-       i2c_del_driver(&mt9m001_i2c_driver);
-}
-
-module_init(mt9m001_mod_init);
-module_exit(mt9m001_mod_exit);
+module_i2c_driver(mt9m001_i2c_driver);
 
 MODULE_DESCRIPTION("Micron MT9M001 Camera driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
diff --git a/drivers/media/video/mt9m032.c b/drivers/media/video/mt9m032.c
new file mode 100644 (file)
index 0000000..7636672
--- /dev/null
@@ -0,0 +1,868 @@
+/*
+ * Driver for MT9M032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010-2011 Lund Engineering
+ * Contact: Gil Lund <gwlund@lundeng.com>
+ * Author: Martin Hostettler <martin@neutronstar.dyndns.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/media-entity.h>
+#include <media/mt9m032.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "aptina-pll.h"
+
+/*
+ * width and height include active boundary and black parts
+ *
+ * column    0-  15 active boundary
+ * column   16-1455 image
+ * column 1456-1471 active boundary
+ * column 1472-1599 black
+ *
+ * row       0-  51 black
+ * row      53-  59 active boundary
+ * row      60-1139 image
+ * row    1140-1147 active boundary
+ * row    1148-1151 black
+ */
+
+#define MT9M032_PIXEL_ARRAY_WIDTH                      1600
+#define MT9M032_PIXEL_ARRAY_HEIGHT                     1152
+
+#define MT9M032_CHIP_VERSION                           0x00
+#define                MT9M032_CHIP_VERSION_VALUE              0x1402
+#define MT9M032_ROW_START                              0x01
+#define                MT9M032_ROW_START_MIN                   0
+#define                MT9M032_ROW_START_MAX                   1152
+#define                MT9M032_ROW_START_DEF                   60
+#define MT9M032_COLUMN_START                           0x02
+#define                MT9M032_COLUMN_START_MIN                0
+#define                MT9M032_COLUMN_START_MAX                1600
+#define                MT9M032_COLUMN_START_DEF                16
+#define MT9M032_ROW_SIZE                               0x03
+#define                MT9M032_ROW_SIZE_MIN                    32
+#define                MT9M032_ROW_SIZE_MAX                    1152
+#define                MT9M032_ROW_SIZE_DEF                    1080
+#define MT9M032_COLUMN_SIZE                            0x04
+#define                MT9M032_COLUMN_SIZE_MIN                 32
+#define                MT9M032_COLUMN_SIZE_MAX                 1600
+#define                MT9M032_COLUMN_SIZE_DEF                 1440
+#define MT9M032_HBLANK                                 0x05
+#define MT9M032_VBLANK                                 0x06
+#define                MT9M032_VBLANK_MAX                      0x7ff
+#define MT9M032_SHUTTER_WIDTH_HIGH                     0x08
+#define MT9M032_SHUTTER_WIDTH_LOW                      0x09
+#define                MT9M032_SHUTTER_WIDTH_MIN               1
+#define                MT9M032_SHUTTER_WIDTH_MAX               1048575
+#define                MT9M032_SHUTTER_WIDTH_DEF               1943
+#define MT9M032_PIX_CLK_CTRL                           0x0a
+#define                MT9M032_PIX_CLK_CTRL_INV_PIXCLK         0x8000
+#define MT9M032_RESTART                                        0x0b
+#define MT9M032_RESET                                  0x0d
+#define MT9M032_PLL_CONFIG1                            0x11
+#define                MT9M032_PLL_CONFIG1_OUTDIV_MASK         0x3f
+#define                MT9M032_PLL_CONFIG1_MUL_SHIFT           8
+#define MT9M032_READ_MODE1                             0x1e
+#define MT9M032_READ_MODE2                             0x20
+#define                MT9M032_READ_MODE2_VFLIP_SHIFT          15
+#define                MT9M032_READ_MODE2_HFLIP_SHIFT          14
+#define                MT9M032_READ_MODE2_ROW_BLC              0x40
+#define MT9M032_GAIN_GREEN1                            0x2b
+#define MT9M032_GAIN_BLUE                              0x2c
+#define MT9M032_GAIN_RED                               0x2d
+#define MT9M032_GAIN_GREEN2                            0x2e
+
+/* write only */
+#define MT9M032_GAIN_ALL                               0x35
+#define                MT9M032_GAIN_DIGITAL_MASK               0x7f
+#define                MT9M032_GAIN_DIGITAL_SHIFT              8
+#define                MT9M032_GAIN_AMUL_SHIFT                 6
+#define                MT9M032_GAIN_ANALOG_MASK                0x3f
+#define MT9M032_FORMATTER1                             0x9e
+#define MT9M032_FORMATTER2                             0x9f
+#define                MT9M032_FORMATTER2_DOUT_EN              0x1000
+#define                MT9M032_FORMATTER2_PIXCLK_EN            0x2000
+
+/*
+ * The available MT9M032 datasheet is missing documentation for register 0x10
+ * MT9P031 seems to be close enough, so use constants from that datasheet for
+ * now.
+ * But keep the name MT9P031 to remind us, that this isn't really confirmed
+ * for this sensor.
+ */
+#define MT9P031_PLL_CONTROL                            0x10
+#define                MT9P031_PLL_CONTROL_PWROFF              0x0050
+#define                MT9P031_PLL_CONTROL_PWRON               0x0051
+#define                MT9P031_PLL_CONTROL_USEPLL              0x0052
+#define MT9P031_PLL_CONFIG2                            0x11
+#define                MT9P031_PLL_CONFIG2_P1_DIV_MASK         0x1f
+
+struct mt9m032 {
+       struct v4l2_subdev subdev;
+       struct media_pad pad;
+       struct mt9m032_platform_data *pdata;
+
+       unsigned int pix_clock;
+
+       struct v4l2_ctrl_handler ctrls;
+       struct {
+               struct v4l2_ctrl *hflip;
+               struct v4l2_ctrl *vflip;
+       };
+
+       struct mutex lock; /* Protects streaming, format, interval and crop */
+
+       bool streaming;
+
+       struct v4l2_mbus_framefmt format;
+       struct v4l2_rect crop;
+       struct v4l2_fract frame_interval;
+};
+
+#define to_mt9m032(sd) container_of(sd, struct mt9m032, subdev)
+#define to_dev(sensor) \
+       (&((struct i2c_client *)v4l2_get_subdevdata(&(sensor)->subdev))->dev)
+
+static int mt9m032_read(struct i2c_client *client, u8 reg)
+{
+       return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int mt9m032_write(struct i2c_client *client, u8 reg, const u16 data)
+{
+       return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static u32 mt9m032_row_time(struct mt9m032 *sensor, unsigned int width)
+{
+       unsigned int effective_width;
+       u32 ns;
+
+       effective_width = width + 716; /* empirical value */
+       ns = div_u64(1000000000ULL * effective_width, sensor->pix_clock);
+       dev_dbg(to_dev(sensor), "MT9M032 line time: %u ns\n", ns);
+       return ns;
+}
+
+static int mt9m032_update_timing(struct mt9m032 *sensor,
+                                struct v4l2_fract *interval)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       struct v4l2_rect *crop = &sensor->crop;
+       unsigned int min_vblank;
+       unsigned int vblank;
+       u32 row_time;
+
+       if (!interval)
+               interval = &sensor->frame_interval;
+
+       row_time = mt9m032_row_time(sensor, crop->width);
+
+       vblank = div_u64(1000000000ULL * interval->numerator,
+                        (u64)row_time * interval->denominator)
+              - crop->height;
+
+       if (vblank > MT9M032_VBLANK_MAX) {
+               /* hardware limits to 11 bit values */
+               interval->denominator = 1000;
+               interval->numerator =
+                       div_u64((crop->height + MT9M032_VBLANK_MAX) *
+                               (u64)row_time * interval->denominator,
+                               1000000000ULL);
+               vblank = div_u64(1000000000ULL * interval->numerator,
+                                (u64)row_time * interval->denominator)
+                      - crop->height;
+       }
+       /* enforce minimal 1.6ms blanking time. */
+       min_vblank = 1600000 / row_time;
+       vblank = clamp_t(unsigned int, vblank, min_vblank, MT9M032_VBLANK_MAX);
+
+       return mt9m032_write(client, MT9M032_VBLANK, vblank);
+}
+
+static int mt9m032_update_geom_timing(struct mt9m032 *sensor)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       int ret;
+
+       ret = mt9m032_write(client, MT9M032_COLUMN_SIZE,
+                           sensor->crop.width - 1);
+       if (!ret)
+               ret = mt9m032_write(client, MT9M032_ROW_SIZE,
+                                   sensor->crop.height - 1);
+       if (!ret)
+               ret = mt9m032_write(client, MT9M032_COLUMN_START,
+                                   sensor->crop.left);
+       if (!ret)
+               ret = mt9m032_write(client, MT9M032_ROW_START,
+                                   sensor->crop.top);
+       if (!ret)
+               ret = mt9m032_update_timing(sensor, NULL);
+       return ret;
+}
+
+static int update_formatter2(struct mt9m032 *sensor, bool streaming)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       u16 reg_val =   MT9M032_FORMATTER2_DOUT_EN
+                     | 0x0070;  /* parts reserved! */
+                                /* possibly for changing to 14-bit mode */
+
+       if (streaming)
+               reg_val |= MT9M032_FORMATTER2_PIXCLK_EN;   /* pixclock enable */
+
+       return mt9m032_write(client, MT9M032_FORMATTER2, reg_val);
+}
+
+static int mt9m032_setup_pll(struct mt9m032 *sensor)
+{
+       static const struct aptina_pll_limits limits = {
+               .ext_clock_min = 8000000,
+               .ext_clock_max = 16500000,
+               .int_clock_min = 2000000,
+               .int_clock_max = 24000000,
+               .out_clock_min = 322000000,
+               .out_clock_max = 693000000,
+               .pix_clock_max = 99000000,
+               .n_min = 1,
+               .n_max = 64,
+               .m_min = 16,
+               .m_max = 255,
+               .p1_min = 1,
+               .p1_max = 128,
+       };
+
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       struct mt9m032_platform_data *pdata = sensor->pdata;
+       struct aptina_pll pll;
+       int ret;
+
+       pll.ext_clock = pdata->ext_clock;
+       pll.pix_clock = pdata->pix_clock;
+
+       ret = aptina_pll_calculate(&client->dev, &limits, &pll);
+       if (ret < 0)
+               return ret;
+
+       sensor->pix_clock = pdata->pix_clock;
+
+       ret = mt9m032_write(client, MT9M032_PLL_CONFIG1,
+                           (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT)
+                           | (pll.p1 - 1));
+       if (!ret)
+               ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1);
+       if (!ret)
+               ret = mt9m032_write(client, MT9P031_PLL_CONTROL,
+                                   MT9P031_PLL_CONTROL_PWRON |
+                                   MT9P031_PLL_CONTROL_USEPLL);
+       if (!ret)               /* more reserved, Continuous, Master Mode */
+               ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006);
+       if (!ret)               /* Set 14-bit mode, select 7 divider */
+               ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e);
+
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Subdev pad operations
+ */
+
+static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index != 0)
+               return -EINVAL;
+
+       code->code = V4L2_MBUS_FMT_Y8_1X8;
+       return 0;
+}
+
+static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
+                                  struct v4l2_subdev_fh *fh,
+                                  struct v4l2_subdev_frame_size_enum *fse)
+{
+       if (fse->index != 0 || fse->code != V4L2_MBUS_FMT_Y8_1X8)
+               return -EINVAL;
+
+       fse->min_width = MT9M032_COLUMN_SIZE_DEF;
+       fse->max_width = MT9M032_COLUMN_SIZE_DEF;
+       fse->min_height = MT9M032_ROW_SIZE_DEF;
+       fse->max_height = MT9M032_ROW_SIZE_DEF;
+
+       return 0;
+}
+
+/**
+ * __mt9m032_get_pad_crop() - get crop rect
+ * @sensor: pointer to the sensor struct
+ * @fh: file handle for getting the try crop rect from
+ * @which: select try or active crop rect
+ *
+ * Returns a pointer the current active or fh relative try crop rect
+ */
+static struct v4l2_rect *
+__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
+                      enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_crop(fh, 0);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &sensor->crop;
+       default:
+               return NULL;
+       }
+}
+
+/**
+ * __mt9m032_get_pad_format() - get format
+ * @sensor: pointer to the sensor struct
+ * @fh: file handle for getting the try format from
+ * @which: select try or active format
+ *
+ * Returns a pointer the current active or fh relative try format
+ */
+static struct v4l2_mbus_framefmt *
+__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh,
+                        enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_format(fh, 0);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &sensor->format;
+       default:
+               return NULL;
+       }
+}
+
+static int mt9m032_get_pad_format(struct v4l2_subdev *subdev,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_format *fmt)
+{
+       struct mt9m032 *sensor = to_mt9m032(subdev);
+
+       mutex_lock(&sensor->lock);
+       fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which);
+       mutex_unlock(&sensor->lock);
+
+       return 0;
+}
+
+static int mt9m032_set_pad_format(struct v4l2_subdev *subdev,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_format *fmt)
+{
+       struct mt9m032 *sensor = to_mt9m032(subdev);
+       int ret;
+
+       mutex_lock(&sensor->lock);
+
+       if (sensor->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+               ret = -EBUSY;
+               goto done;
+       }
+
+       /* Scaling is not supported, the format is thus fixed. */
+       ret = mt9m032_get_pad_format(subdev, fh, fmt);
+
+done:
+       mutex_lock(&sensor->lock);
+       return ret;
+}
+
+static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_crop *crop)
+{
+       struct mt9m032 *sensor = to_mt9m032(subdev);
+
+       mutex_lock(&sensor->lock);
+       crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which);
+       mutex_unlock(&sensor->lock);
+
+       return 0;
+}
+
+static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_crop *crop)
+{
+       struct mt9m032 *sensor = to_mt9m032(subdev);
+       struct v4l2_mbus_framefmt *format;
+       struct v4l2_rect *__crop;
+       struct v4l2_rect rect;
+       int ret = 0;
+
+       mutex_lock(&sensor->lock);
+
+       if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+               ret = -EBUSY;
+               goto done;
+       }
+
+       /* Clamp the crop rectangle boundaries and align them to a multiple of 2
+        * pixels to ensure a GRBG Bayer pattern.
+        */
+       rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN,
+                         MT9M032_COLUMN_START_MAX);
+       rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN,
+                        MT9M032_ROW_START_MAX);
+       rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN,
+                          MT9M032_COLUMN_SIZE_MAX);
+       rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN,
+                           MT9M032_ROW_SIZE_MAX);
+
+       rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left);
+       rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
+
+       __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which);
+
+       if (rect.width != __crop->width || rect.height != __crop->height) {
+               /* Reset the output image size if the crop rectangle size has
+                * been modified.
+                */
+               format = __mt9m032_get_pad_format(sensor, fh, crop->which);
+               format->width = rect.width;
+               format->height = rect.height;
+       }
+
+       *__crop = rect;
+       crop->rect = rect;
+
+       if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+               ret = mt9m032_update_geom_timing(sensor);
+
+done:
+       mutex_unlock(&sensor->lock);
+       return ret;
+}
+
+static int mt9m032_get_frame_interval(struct v4l2_subdev *subdev,
+                                     struct v4l2_subdev_frame_interval *fi)
+{
+       struct mt9m032 *sensor = to_mt9m032(subdev);
+
+       mutex_lock(&sensor->lock);
+       memset(fi, 0, sizeof(*fi));
+       fi->interval = sensor->frame_interval;
+       mutex_unlock(&sensor->lock);
+
+       return 0;
+}
+
+static int mt9m032_set_frame_interval(struct v4l2_subdev *subdev,
+                                     struct v4l2_subdev_frame_interval *fi)
+{
+       struct mt9m032 *sensor = to_mt9m032(subdev);
+       int ret;
+
+       mutex_lock(&sensor->lock);
+
+       if (sensor->streaming) {
+               ret = -EBUSY;
+               goto done;
+       }
+
+       /* Avoid divisions by 0. */
+       if (fi->interval.denominator == 0)
+               fi->interval.denominator = 1;
+
+       ret = mt9m032_update_timing(sensor, &fi->interval);
+       if (!ret)
+               sensor->frame_interval = fi->interval;
+
+done:
+       mutex_unlock(&sensor->lock);
+       return ret;
+}
+
+static int mt9m032_s_stream(struct v4l2_subdev *subdev, int streaming)
+{
+       struct mt9m032 *sensor = to_mt9m032(subdev);
+       int ret;
+
+       mutex_lock(&sensor->lock);
+       ret = update_formatter2(sensor, streaming);
+       if (!ret)
+               sensor->streaming = streaming;
+       mutex_unlock(&sensor->lock);
+
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m032_g_register(struct v4l2_subdev *sd,
+                             struct v4l2_dbg_register *reg)
+{
+       struct mt9m032 *sensor = to_mt9m032(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       int val;
+
+       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+               return -EINVAL;
+       if (reg->match.addr != client->addr)
+               return -ENODEV;
+
+       val = mt9m032_read(client, reg->reg);
+       if (val < 0)
+               return -EIO;
+
+       reg->size = 2;
+       reg->val = val;
+
+       return 0;
+}
+
+static int mt9m032_s_register(struct v4l2_subdev *sd,
+                             struct v4l2_dbg_register *reg)
+{
+       struct mt9m032 *sensor = to_mt9m032(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+
+       if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+               return -EINVAL;
+
+       if (reg->match.addr != client->addr)
+               return -ENODEV;
+
+       return mt9m032_write(client, reg->reg, reg->val);
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+static int update_read_mode2(struct mt9m032 *sensor, bool vflip, bool hflip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       int reg_val = (vflip << MT9M032_READ_MODE2_VFLIP_SHIFT)
+                   | (hflip << MT9M032_READ_MODE2_HFLIP_SHIFT)
+                   | MT9M032_READ_MODE2_ROW_BLC
+                   | 0x0007;
+
+       return mt9m032_write(client, MT9M032_READ_MODE2, reg_val);
+}
+
+static int mt9m032_set_gain(struct mt9m032 *sensor, s32 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       int digital_gain_val;   /* in 1/8th (0..127) */
+       int analog_mul;         /* 0 or 1 */
+       int analog_gain_val;    /* in 1/16th. (0..63) */
+       u16 reg_val;
+
+       digital_gain_val = 51; /* from setup example */
+
+       if (val < 63) {
+               analog_mul = 0;
+               analog_gain_val = val;
+       } else {
+               analog_mul = 1;
+               analog_gain_val = val / 2;
+       }
+
+       /* a_gain = (1 + analog_mul) + (analog_gain_val + 1) / 16 */
+       /* overall_gain = a_gain * (1 + digital_gain_val / 8) */
+
+       reg_val = ((digital_gain_val & MT9M032_GAIN_DIGITAL_MASK)
+                  << MT9M032_GAIN_DIGITAL_SHIFT)
+               | ((analog_mul & 1) << MT9M032_GAIN_AMUL_SHIFT)
+               | (analog_gain_val & MT9M032_GAIN_ANALOG_MASK);
+
+       return mt9m032_write(client, MT9M032_GAIN_ALL, reg_val);
+}
+
+static int mt9m032_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+       if (ctrl->id == V4L2_CID_GAIN && ctrl->val >= 63) {
+               /* round because of multiplier used for values >= 63 */
+               ctrl->val &= ~1;
+       }
+
+       return 0;
+}
+
+static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mt9m032 *sensor =
+               container_of(ctrl->handler, struct mt9m032, ctrls);
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       int ret;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               return mt9m032_set_gain(sensor, ctrl->val);
+
+       case V4L2_CID_HFLIP:
+       /* case V4L2_CID_VFLIP: -- In the same cluster */
+               return update_read_mode2(sensor, sensor->vflip->val,
+                                        sensor->hflip->val);
+
+       case V4L2_CID_EXPOSURE:
+               ret = mt9m032_write(client, MT9M032_SHUTTER_WIDTH_HIGH,
+                                   (ctrl->val >> 16) & 0xffff);
+               if (ret < 0)
+                       return ret;
+
+               return mt9m032_write(client, MT9M032_SHUTTER_WIDTH_LOW,
+                                    ctrl->val & 0xffff);
+       }
+
+       return 0;
+}
+
+static struct v4l2_ctrl_ops mt9m032_ctrl_ops = {
+       .s_ctrl = mt9m032_set_ctrl,
+       .try_ctrl = mt9m032_try_ctrl,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops mt9m032_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = mt9m032_g_register,
+       .s_register = mt9m032_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops mt9m032_video_ops = {
+       .s_stream = mt9m032_s_stream,
+       .g_frame_interval = mt9m032_get_frame_interval,
+       .s_frame_interval = mt9m032_set_frame_interval,
+};
+
+static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = {
+       .enum_mbus_code = mt9m032_enum_mbus_code,
+       .enum_frame_size = mt9m032_enum_frame_size,
+       .get_fmt = mt9m032_get_pad_format,
+       .set_fmt = mt9m032_set_pad_format,
+       .set_crop = mt9m032_set_pad_crop,
+       .get_crop = mt9m032_get_pad_crop,
+};
+
+static const struct v4l2_subdev_ops mt9m032_ops = {
+       .core = &mt9m032_core_ops,
+       .video = &mt9m032_video_ops,
+       .pad = &mt9m032_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9m032_probe(struct i2c_client *client,
+                        const struct i2c_device_id *devid)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct mt9m032 *sensor;
+       int chip_version;
+       int ret;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_warn(&client->dev,
+                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+               return -EIO;
+       }
+
+       if (!client->dev.platform_data)
+               return -ENODEV;
+
+       sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+       if (sensor == NULL)
+               return -ENOMEM;
+
+       mutex_init(&sensor->lock);
+
+       sensor->pdata = client->dev.platform_data;
+
+       v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops);
+       sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       chip_version = mt9m032_read(client, MT9M032_CHIP_VERSION);
+       if (chip_version != MT9M032_CHIP_VERSION_VALUE) {
+               dev_err(&client->dev, "MT9M032 not detected, wrong version "
+                       "0x%04x\n", chip_version);
+               ret = -ENODEV;
+               goto error_sensor;
+       }
+
+       dev_info(&client->dev, "MT9M032 detected at address 0x%02x\n",
+                client->addr);
+
+       sensor->frame_interval.numerator = 1;
+       sensor->frame_interval.denominator = 30;
+
+       sensor->crop.left = MT9M032_COLUMN_START_DEF;
+       sensor->crop.top = MT9M032_ROW_START_DEF;
+       sensor->crop.width = MT9M032_COLUMN_SIZE_DEF;
+       sensor->crop.height = MT9M032_ROW_SIZE_DEF;
+
+       sensor->format.width = sensor->crop.width;
+       sensor->format.height = sensor->crop.height;
+       sensor->format.code = V4L2_MBUS_FMT_Y8_1X8;
+       sensor->format.field = V4L2_FIELD_NONE;
+       sensor->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+       v4l2_ctrl_handler_init(&sensor->ctrls, 4);
+
+       v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+                         V4L2_CID_GAIN, 0, 127, 1, 64);
+
+       sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls,
+                                         &mt9m032_ctrl_ops,
+                                         V4L2_CID_HFLIP, 0, 1, 1, 0);
+       sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls,
+                                         &mt9m032_ctrl_ops,
+                                         V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+       v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops,
+                         V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN,
+                         MT9M032_SHUTTER_WIDTH_MAX, 1,
+                         MT9M032_SHUTTER_WIDTH_DEF);
+
+       if (sensor->ctrls.error) {
+               ret = sensor->ctrls.error;
+               dev_err(&client->dev, "control initialization error %d\n", ret);
+               goto error_ctrl;
+       }
+
+       v4l2_ctrl_cluster(2, &sensor->hflip);
+
+       sensor->subdev.ctrl_handler = &sensor->ctrls;
+       sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+       ret = media_entity_init(&sensor->subdev.entity, 1, &sensor->pad, 0);
+       if (ret < 0)
+               goto error_ctrl;
+
+       ret = mt9m032_write(client, MT9M032_RESET, 1);  /* reset on */
+       if (ret < 0)
+               goto error_entity;
+       mt9m032_write(client, MT9M032_RESET, 0);        /* reset off */
+       if (ret < 0)
+               goto error_entity;
+
+       ret = mt9m032_setup_pll(sensor);
+       if (ret < 0)
+               goto error_entity;
+       usleep_range(10000, 11000);
+
+       ret = v4l2_ctrl_handler_setup(&sensor->ctrls);
+       if (ret < 0)
+               goto error_entity;
+
+       /* SIZE */
+       ret = mt9m032_update_geom_timing(sensor);
+       if (ret < 0)
+               goto error_entity;
+
+       ret = mt9m032_write(client, 0x41, 0x0000);      /* reserved !!! */
+       if (ret < 0)
+               goto error_entity;
+       ret = mt9m032_write(client, 0x42, 0x0003);      /* reserved !!! */
+       if (ret < 0)
+               goto error_entity;
+       ret = mt9m032_write(client, 0x43, 0x0003);      /* reserved !!! */
+       if (ret < 0)
+               goto error_entity;
+       ret = mt9m032_write(client, 0x7f, 0x0000);      /* reserved !!! */
+       if (ret < 0)
+               goto error_entity;
+       if (sensor->pdata->invert_pixclock) {
+               ret = mt9m032_write(client, MT9M032_PIX_CLK_CTRL,
+                                   MT9M032_PIX_CLK_CTRL_INV_PIXCLK);
+               if (ret < 0)
+                       goto error_entity;
+       }
+
+       ret = mt9m032_write(client, MT9M032_RESTART, 1); /* Restart on */
+       if (ret < 0)
+               goto error_entity;
+       msleep(100);
+       ret = mt9m032_write(client, MT9M032_RESTART, 0); /* Restart off */
+       if (ret < 0)
+               goto error_entity;
+       msleep(100);
+       ret = update_formatter2(sensor, false);
+       if (ret < 0)
+               goto error_entity;
+
+       return ret;
+
+error_entity:
+       media_entity_cleanup(&sensor->subdev.entity);
+error_ctrl:
+       v4l2_ctrl_handler_free(&sensor->ctrls);
+error_sensor:
+       mutex_destroy(&sensor->lock);
+       kfree(sensor);
+       return ret;
+}
+
+static int mt9m032_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct mt9m032 *sensor = to_mt9m032(subdev);
+
+       v4l2_device_unregister_subdev(&sensor->subdev);
+       v4l2_ctrl_handler_free(&sensor->ctrls);
+       media_entity_cleanup(&sensor->subdev.entity);
+       mutex_destroy(&sensor->lock);
+       kfree(sensor);
+       return 0;
+}
+
+static const struct i2c_device_id mt9m032_id_table[] = {
+       { MT9M032_NAME, 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, mt9m032_id_table);
+
+static struct i2c_driver mt9m032_i2c_driver = {
+       .driver = {
+               .name = MT9M032_NAME,
+       },
+       .probe = mt9m032_probe,
+       .remove = mt9m032_remove,
+       .id_table = mt9m032_id_table,
+};
+
+module_i2c_driver(mt9m032_i2c_driver);
+
+MODULE_AUTHOR("Martin Hostettler <martin@neutronstar.dyndns.org>");
+MODULE_DESCRIPTION("MT9M032 camera sensor driver");
+MODULE_LICENSE("GPL v2");
index bee65bf..b0c5299 100644 (file)
@@ -1008,18 +1008,7 @@ static struct i2c_driver mt9m111_i2c_driver = {
        .id_table       = mt9m111_id,
 };
 
-static int __init mt9m111_mod_init(void)
-{
-       return i2c_add_driver(&mt9m111_i2c_driver);
-}
-
-static void __exit mt9m111_mod_exit(void)
-{
-       i2c_del_driver(&mt9m111_i2c_driver);
-}
-
-module_init(mt9m111_mod_init);
-module_exit(mt9m111_mod_exit);
+module_i2c_driver(mt9m111_i2c_driver);
 
 MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver");
 MODULE_AUTHOR("Robert Jarzmik");
index 93c3ec7..c81eaf4 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/log2.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
-#include <media/v4l2-subdev.h>
 #include <linux/videodev2.h>
 
 #include <media/mt9p031.h>
@@ -28,6 +27,8 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
 
+#include "aptina-pll.h"
+
 #define MT9P031_PIXEL_ARRAY_WIDTH                      2752
 #define MT9P031_PIXEL_ARRAY_HEIGHT                     2004
 
 #define MT9P031_TEST_PATTERN_RED                       0xa2
 #define MT9P031_TEST_PATTERN_BLUE                      0xa3
 
-struct mt9p031_pll_divs {
-       u32 ext_freq;
-       u32 target_freq;
-       u8 m;
-       u8 n;
-       u8 p1;
-};
-
 struct mt9p031 {
        struct v4l2_subdev subdev;
        struct media_pad pad;
@@ -115,10 +108,8 @@ struct mt9p031 {
        struct mt9p031_platform_data *pdata;
        struct mutex power_lock; /* lock to protect power_count */
        int power_count;
-       u16 xskip;
-       u16 yskip;
 
-       const struct mt9p031_pll_divs *pll;
+       struct aptina_pll pll;
 
        /* Registers cache */
        u16 output_control;
@@ -186,33 +177,31 @@ static int mt9p031_reset(struct mt9p031 *mt9p031)
                                          0);
 }
 
-/*
- * This static table uses ext_freq and vdd_io values to select suitable
- * PLL dividers m, n and p1 which have been calculated as specifiec in p36
- * of Aptina's mt9p031 datasheet. New values should be added here.
- */
-static const struct mt9p031_pll_divs mt9p031_divs[] = {
-       /* ext_freq     target_freq     m       n       p1 */
-       {21000000,      48000000,       26,     2,      6}
-};
-
-static int mt9p031_pll_get_divs(struct mt9p031 *mt9p031)
+static int mt9p031_pll_setup(struct mt9p031 *mt9p031)
 {
+       static const struct aptina_pll_limits limits = {
+               .ext_clock_min = 6000000,
+               .ext_clock_max = 27000000,
+               .int_clock_min = 2000000,
+               .int_clock_max = 13500000,
+               .out_clock_min = 180000000,
+               .out_clock_max = 360000000,
+               .pix_clock_max = 96000000,
+               .n_min = 1,
+               .n_max = 64,
+               .m_min = 16,
+               .m_max = 255,
+               .p1_min = 1,
+               .p1_max = 128,
+       };
+
        struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
-       int i;
+       struct mt9p031_platform_data *pdata = mt9p031->pdata;
 
-       for (i = 0; i < ARRAY_SIZE(mt9p031_divs); i++) {
-               if (mt9p031_divs[i].ext_freq == mt9p031->pdata->ext_freq &&
-                 mt9p031_divs[i].target_freq == mt9p031->pdata->target_freq) {
-                       mt9p031->pll = &mt9p031_divs[i];
-                       return 0;
-               }
-       }
+       mt9p031->pll.ext_clock = pdata->ext_freq;
+       mt9p031->pll.pix_clock = pdata->target_freq;
 
-       dev_err(&client->dev, "Couldn't find PLL dividers for ext_freq = %d, "
-               "target_freq = %d\n", mt9p031->pdata->ext_freq,
-               mt9p031->pdata->target_freq);
-       return -EINVAL;
+       return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
 }
 
 static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
@@ -226,11 +215,11 @@ static int mt9p031_pll_enable(struct mt9p031 *mt9p031)
                return ret;
 
        ret = mt9p031_write(client, MT9P031_PLL_CONFIG_1,
-                           (mt9p031->pll->m << 8) | (mt9p031->pll->n - 1));
+                           (mt9p031->pll.m << 8) | (mt9p031->pll.n - 1));
        if (ret < 0)
                return ret;
 
-       ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll->p1 - 1);
+       ret = mt9p031_write(client, MT9P031_PLL_CONFIG_2, mt9p031->pll.p1 - 1);
        if (ret < 0)
                return ret;
 
@@ -785,8 +774,6 @@ static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
        format->field = V4L2_FIELD_NONE;
        format->colorspace = V4L2_COLORSPACE_SRGB;
 
-       mt9p031->xskip = 1;
-       mt9p031->yskip = 1;
        return mt9p031_set_power(subdev, 1);
 }
 
@@ -905,7 +892,7 @@ static int mt9p031_probe(struct i2c_client *client,
        mt9p031->format.field = V4L2_FIELD_NONE;
        mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
 
-       ret = mt9p031_pll_get_divs(mt9p031);
+       ret = mt9p031_pll_setup(mt9p031);
 
 done:
        if (ret < 0) {
@@ -945,18 +932,7 @@ static struct i2c_driver mt9p031_i2c_driver = {
        .id_table       = mt9p031_id,
 };
 
-static int __init mt9p031_mod_init(void)
-{
-       return i2c_add_driver(&mt9p031_i2c_driver);
-}
-
-static void __exit mt9p031_mod_exit(void)
-{
-       i2c_del_driver(&mt9p031_i2c_driver);
-}
-
-module_init(mt9p031_mod_init);
-module_exit(mt9p031_mod_exit);
+module_i2c_driver(mt9p031_i2c_driver);
 
 MODULE_DESCRIPTION("Aptina MT9P031 Camera driver");
 MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
index cd81d04..49ca3cb 100644 (file)
@@ -817,18 +817,7 @@ static struct i2c_driver mt9t001_driver = {
        .id_table       = mt9t001_id,
 };
 
-static int __init mt9t001_init(void)
-{
-       return i2c_add_driver(&mt9t001_driver);
-}
-
-static void __exit mt9t001_exit(void)
-{
-       i2c_del_driver(&mt9t001_driver);
-}
-
-module_init(mt9t001_init);
-module_exit(mt9t001_exit);
+module_i2c_driver(mt9t001_driver);
 
 MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver");
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
index 84add1a..1415074 100644 (file)
@@ -850,18 +850,7 @@ static struct i2c_driver mt9t031_i2c_driver = {
        .id_table       = mt9t031_id,
 };
 
-static int __init mt9t031_mod_init(void)
-{
-       return i2c_add_driver(&mt9t031_i2c_driver);
-}
-
-static void __exit mt9t031_mod_exit(void)
-{
-       i2c_del_driver(&mt9t031_i2c_driver);
-}
-
-module_init(mt9t031_mod_init);
-module_exit(mt9t031_mod_exit);
+module_i2c_driver(mt9t031_i2c_driver);
 
 MODULE_DESCRIPTION("Micron MT9T031 Camera driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
index 7b34b11..8d1445f 100644 (file)
@@ -1117,21 +1117,7 @@ static struct i2c_driver mt9t112_i2c_driver = {
        .id_table = mt9t112_id,
 };
 
-/************************************************************************
-                       module function
-************************************************************************/
-static int __init mt9t112_module_init(void)
-{
-       return i2c_add_driver(&mt9t112_i2c_driver);
-}
-
-static void __exit mt9t112_module_exit(void)
-{
-       i2c_del_driver(&mt9t112_i2c_driver);
-}
-
-module_init(mt9t112_module_init);
-module_exit(mt9t112_module_exit);
+module_i2c_driver(mt9t112_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for mt9t112");
 MODULE_AUTHOR("Kuninori Morimoto");
index db74dd2..6bf01ad 100644 (file)
@@ -709,15 +709,4 @@ static struct i2c_driver mt9v011_driver = {
        .id_table       = mt9v011_id,
 };
 
-static __init int init_mt9v011(void)
-{
-       return i2c_add_driver(&mt9v011_driver);
-}
-
-static __exit void exit_mt9v011(void)
-{
-       i2c_del_driver(&mt9v011_driver);
-}
-
-module_init(init_mt9v011);
-module_exit(exit_mt9v011);
+module_i2c_driver(mt9v011_driver);
index 9449407..bf63417 100644 (file)
@@ -872,18 +872,7 @@ static struct i2c_driver mt9v022_i2c_driver = {
        .id_table       = mt9v022_id,
 };
 
-static int __init mt9v022_mod_init(void)
-{
-       return i2c_add_driver(&mt9v022_i2c_driver);
-}
-
-static void __exit mt9v022_mod_exit(void)
-{
-       i2c_del_driver(&mt9v022_i2c_driver);
-}
-
-module_init(mt9v022_mod_init);
-module_exit(mt9v022_mod_exit);
+module_i2c_driver(mt9v022_i2c_driver);
 
 MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
index d90b982..75e253a 100644 (file)
@@ -756,18 +756,7 @@ static struct i2c_driver mt9v032_driver = {
        .id_table       = mt9v032_id,
 };
 
-static int __init mt9v032_init(void)
-{
-       return i2c_add_driver(&mt9v032_driver);
-}
-
-static void __exit mt9v032_exit(void)
-{
-       i2c_del_driver(&mt9v032_driver);
-}
-
-module_init(mt9v032_init);
-module_exit(mt9v032_exit);
+module_i2c_driver(mt9v032_driver);
 
 MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
index 04aab0c..18afaee 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2008, Sascha Hauer, Pengutronix
  * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography
+ * Copyright (C) 2012, Javier Martin, Vista Silicon S.L.
  *
  * 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
@@ -18,6 +19,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/gcd.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
-#include <media/videobuf-core.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
 #include <media/soc_camera.h>
 #include <media/soc_mediabus.h>
 
 #include <linux/videodev2.h>
 
 #include <mach/mx2_cam.h>
-#ifdef CONFIG_MACH_MX27
-#include <mach/dma-mx1-mx2.h>
-#endif
 #include <mach/hardware.h>
 
 #include <asm/dma.h>
 #define PRP_INTR_LBOVF         (1 << 7)
 #define PRP_INTR_CH2OVF                (1 << 8)
 
-#define mx27_camera_emma(pcdev)        (cpu_is_mx27() && pcdev->use_emma)
+/* Resizing registers */
+#define PRP_RZ_VALID_TBL_LEN(x)        ((x) << 24)
+#define PRP_RZ_VALID_BILINEAR  (1 << 31)
 
 #define MAX_VIDEO_MEM  16
 
+#define RESIZE_NUM_MIN 1
+#define RESIZE_NUM_MAX 20
+#define BC_COEF                3
+#define SZ_COEF                (1 << BC_COEF)
+
+#define RESIZE_DIR_H   0
+#define RESIZE_DIR_V   1
+
+#define RESIZE_ALGO_BILINEAR 0
+#define RESIZE_ALGO_AVERAGING 1
+
 struct mx2_prp_cfg {
        int channel;
        u32 in_fmt;
@@ -219,6 +231,13 @@ struct mx2_prp_cfg {
        u32 irq_flags;
 };
 
+/* prp resizing parameters */
+struct emma_prp_resize {
+       int             algo; /* type of algorithm used */
+       int             len; /* number of coefficients */
+       unsigned char   s[RESIZE_NUM_MAX]; /* table of coefficients */
+};
+
 /* prp configuration for a client-host fmt pair */
 struct mx2_fmt_cfg {
        enum v4l2_mbus_pixelcode        in_fmt;
@@ -226,6 +245,26 @@ struct mx2_fmt_cfg {
        struct mx2_prp_cfg              cfg;
 };
 
+enum mx2_buffer_state {
+       MX2_STATE_QUEUED,
+       MX2_STATE_ACTIVE,
+       MX2_STATE_DONE,
+};
+
+struct mx2_buf_internal {
+       struct list_head        queue;
+       int                     bufnum;
+       bool                    discard;
+};
+
+/* buffer for one video frame */
+struct mx2_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct vb2_buffer               vb;
+       enum mx2_buffer_state           state;
+       struct mx2_buf_internal         internal;
+};
+
 struct mx2_camera_dev {
        struct device           *dev;
        struct soc_camera_host  soc_host;
@@ -242,6 +281,7 @@ struct mx2_camera_dev {
 
        struct list_head        capture;
        struct list_head        active_bufs;
+       struct list_head        discard;
 
        spinlock_t              lock;
 
@@ -250,26 +290,23 @@ struct mx2_camera_dev {
        struct mx2_buffer       *fb1_active;
        struct mx2_buffer       *fb2_active;
 
-       int                     use_emma;
-
        u32                     csicr1;
 
+       struct mx2_buf_internal buf_discard[2];
        void                    *discard_buffer;
        dma_addr_t              discard_buffer_dma;
        size_t                  discard_size;
        struct mx2_fmt_cfg      *emma_prp;
+       struct emma_prp_resize  resizing[2];
+       unsigned int            s_width, s_height;
        u32                     frame_count;
+       struct vb2_alloc_ctx    *alloc_ctx;
 };
 
-/* buffer for one video frame */
-struct mx2_buffer {
-       /* common v4l buffer stuff -- must be first */
-       struct videobuf_buffer          vb;
-
-       enum v4l2_mbus_pixelcode        code;
-
-       int bufnum;
-};
+static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf)
+{
+       return container_of(int_buf, struct mx2_buffer, internal);
+}
 
 static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
        /*
@@ -324,13 +361,36 @@ static struct mx2_fmt_cfg *mx27_emma_prp_get_format(
        return &mx27_emma_prp_table[0];
 };
 
+static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev,
+                                unsigned long phys, int bufnum)
+{
+       struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+
+       if (prp->cfg.channel == 1) {
+               writel(phys, pcdev->base_emma +
+                               PRP_DEST_RGB1_PTR + 4 * bufnum);
+       } else {
+               writel(phys, pcdev->base_emma +
+                       PRP_DEST_Y_PTR - 0x14 * bufnum);
+               if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
+                       u32 imgsize = pcdev->icd->user_height *
+                                       pcdev->icd->user_width;
+
+                       writel(phys + imgsize, pcdev->base_emma +
+                               PRP_DEST_CB_PTR - 0x14 * bufnum);
+                       writel(phys + ((5 * imgsize) / 4), pcdev->base_emma +
+                               PRP_DEST_CR_PTR - 0x14 * bufnum);
+               }
+       }
+}
+
 static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
 {
        unsigned long flags;
 
        clk_disable(pcdev->clk_csi);
        writel(0, pcdev->base_csi + CSICR1);
-       if (mx27_camera_emma(pcdev)) {
+       if (cpu_is_mx27()) {
                writel(0, pcdev->base_emma + PRP_CNTL);
        } else if (cpu_is_mx25()) {
                spin_lock_irqsave(&pcdev->lock, flags);
@@ -362,7 +422,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
 
        csicr1 = CSICR1_MCLKEN;
 
-       if (mx27_camera_emma(pcdev)) {
+       if (cpu_is_mx27()) {
                csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
                        CSICR1_RXFF_LEVEL(0);
        } else if (cpu_is_mx27())
@@ -392,56 +452,13 @@ static void mx2_camera_remove_device(struct soc_camera_device *icd)
 
        mx2_camera_deactivate(pcdev);
 
-       if (pcdev->discard_buffer) {
-               dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size,
-                               pcdev->discard_buffer,
-                               pcdev->discard_buffer_dma);
-               pcdev->discard_buffer = NULL;
-       }
-
        pcdev->icd = NULL;
 }
 
-#ifdef CONFIG_MACH_MX27
-static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev)
-{
-       u32 tmp;
-
-       imx_dma_enable(pcdev->dma);
-
-       tmp = readl(pcdev->base_csi + CSICR1);
-       tmp |= CSICR1_RF_OR_INTEN;
-       writel(tmp, pcdev->base_csi + CSICR1);
-}
-
-static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
-{
-       struct mx2_camera_dev *pcdev = data;
-       u32 status = readl(pcdev->base_csi + CSISR);
-
-       if (status & CSISR_SOF_INT && pcdev->active) {
-               u32 tmp;
-
-               tmp = readl(pcdev->base_csi + CSICR1);
-               writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1);
-               mx27_camera_dma_enable(pcdev);
-       }
-
-       writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR);
-
-       return IRQ_HANDLED;
-}
-#else
-static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
-{
-       return IRQ_NONE;
-}
-#endif /* CONFIG_MACH_MX27 */
-
 static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
                int state)
 {
-       struct videobuf_buffer *vb;
+       struct vb2_buffer *vb;
        struct mx2_buffer *buf;
        struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
                &pcdev->fb2_active;
@@ -454,25 +471,24 @@ static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
                goto out;
 
        vb = &(*fb_active)->vb;
-       dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-               vb, vb->baddr, vb->bsize);
+       dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+               vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
-       vb->state = state;
-       do_gettimeofday(&vb->ts);
-       vb->field_count++;
-
-       wake_up(&vb->done);
+       do_gettimeofday(&vb->v4l2_buf.timestamp);
+       vb->v4l2_buf.sequence++;
+       vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
 
        if (list_empty(&pcdev->capture)) {
                buf = NULL;
                writel(0, pcdev->base_csi + fb_reg);
        } else {
-               buf = list_entry(pcdev->capture.next, struct mx2_buffer,
-                               vb.queue);
+               buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+                               internal.queue);
                vb = &buf->vb;
-               list_del(&vb->queue);
-               vb->state = VIDEOBUF_ACTIVE;
-               writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg);
+               list_del(&buf->internal.queue);
+               buf->state = MX2_STATE_ACTIVE;
+               writel(vb2_dma_contig_plane_dma_addr(vb, 0),
+                      pcdev->base_csi + fb_reg);
        }
 
        *fb_active = buf;
@@ -487,9 +503,9 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
        u32 status = readl(pcdev->base_csi + CSISR);
 
        if (status & CSISR_DMA_TSF_FB1_INT)
-               mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE);
+               mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE);
        else if (status & CSISR_DMA_TSF_FB2_INT)
-               mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE);
+               mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE);
 
        /* FIXME: handle CSISR_RFF_OR_INT */
 
@@ -501,59 +517,50 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
 /*
  *  Videobuf operations
  */
-static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
-                             unsigned int *size)
+static int mx2_videobuf_setup(struct vb2_queue *vq,
+                       const struct v4l2_format *fmt,
+                       unsigned int *count, unsigned int *num_planes,
+                       unsigned int sizes[], void *alloc_ctxs[])
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                        icd->current_fmt->host_fmt);
 
-       dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
+       dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]);
+
+       /* TODO: support for VIDIOC_CREATE_BUFS not ready */
+       if (fmt != NULL)
+               return -ENOTTY;
 
        if (bytes_per_line < 0)
                return bytes_per_line;
 
-       *size = bytes_per_line * icd->user_height;
+       alloc_ctxs[0] = pcdev->alloc_ctx;
+
+       sizes[0] = bytes_per_line * icd->user_height;
 
        if (0 == *count)
                *count = 32;
-       if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
-               *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
+       if (!*num_planes &&
+           sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
+               *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0];
 
-       return 0;
-}
+       *num_planes = 1;
 
-static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
-{
-       struct soc_camera_device *icd = vq->priv_data;
-       struct videobuf_buffer *vb = &buf->vb;
-
-       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-               vb, vb->baddr, vb->bsize);
-
-       /*
-        * This waits until this buffer is out of danger, i.e., until it is no
-        * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE
-        */
-       videobuf_waiton(vq, vb, 0, 0);
-
-       videobuf_dma_contig_free(vq, vb);
-       dev_dbg(icd->parent, "%s freed\n", __func__);
-
-       vb->state = VIDEOBUF_NEEDS_INIT;
+       return 0;
 }
 
-static int mx2_videobuf_prepare(struct videobuf_queue *vq,
-               struct videobuf_buffer *vb, enum v4l2_field field)
+static int mx2_videobuf_prepare(struct vb2_buffer *vb)
 {
-       struct soc_camera_device *icd = vq->priv_data;
-       struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                        icd->current_fmt->host_fmt);
        int ret = 0;
 
-       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-               vb, vb->baddr, vb->bsize);
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+               vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
        if (bytes_per_line < 0)
                return bytes_per_line;
@@ -563,99 +570,58 @@ static int mx2_videobuf_prepare(struct videobuf_queue *vq,
         * This can be useful if you want to see if we actually fill
         * the buffer with something
         */
-       memset((void *)vb->baddr, 0xaa, vb->bsize);
+       memset((void *)vb2_plane_vaddr(vb, 0),
+              0xaa, vb2_get_plane_payload(vb, 0));
 #endif
 
-       if (buf->code   != icd->current_fmt->code ||
-           vb->width   != icd->user_width ||
-           vb->height  != icd->user_height ||
-           vb->field   != field) {
-               buf->code       = icd->current_fmt->code;
-               vb->width       = icd->user_width;
-               vb->height      = icd->user_height;
-               vb->field       = field;
-               vb->state       = VIDEOBUF_NEEDS_INIT;
-       }
-
-       vb->size = bytes_per_line * vb->height;
-       if (vb->baddr && vb->bsize < vb->size) {
+       vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height);
+       if (vb2_plane_vaddr(vb, 0) &&
+           vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
                ret = -EINVAL;
                goto out;
        }
 
-       if (vb->state == VIDEOBUF_NEEDS_INIT) {
-               ret = videobuf_iolock(vq, vb, NULL);
-               if (ret)
-                       goto fail;
-
-               vb->state = VIDEOBUF_PREPARED;
-       }
-
        return 0;
 
-fail:
-       free_buffer(vq, buf);
 out:
        return ret;
 }
 
-static void mx2_videobuf_queue(struct videobuf_queue *vq,
-                              struct videobuf_buffer *vb)
+static void mx2_videobuf_queue(struct vb2_buffer *vb)
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
        struct soc_camera_host *ici =
                to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
        unsigned long flags;
 
-       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-               vb, vb->baddr, vb->bsize);
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+               vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
        spin_lock_irqsave(&pcdev->lock, flags);
 
-       vb->state = VIDEOBUF_QUEUED;
-       list_add_tail(&vb->queue, &pcdev->capture);
+       buf->state = MX2_STATE_QUEUED;
+       list_add_tail(&buf->internal.queue, &pcdev->capture);
 
-       if (mx27_camera_emma(pcdev)) {
-               goto out;
-#ifdef CONFIG_MACH_MX27
-       } else if (cpu_is_mx27()) {
-               int ret;
-
-               if (pcdev->active == NULL) {
-                       ret = imx_dma_setup_single(pcdev->dma,
-                                       videobuf_to_dma_contig(vb), vb->size,
-                                       (u32)pcdev->base_dma + 0x10,
-                                       DMA_MODE_READ);
-                       if (ret) {
-                               vb->state = VIDEOBUF_ERROR;
-                               wake_up(&vb->done);
-                               goto out;
-                       }
-
-                       vb->state = VIDEOBUF_ACTIVE;
-                       pcdev->active = buf;
-               }
-#endif
-       } else { /* cpu_is_mx25() */
+       if (cpu_is_mx25()) {
                u32 csicr3, dma_inten = 0;
 
                if (pcdev->fb1_active == NULL) {
-                       writel(videobuf_to_dma_contig(vb),
+                       writel(vb2_dma_contig_plane_dma_addr(vb, 0),
                                        pcdev->base_csi + CSIDMASA_FB1);
                        pcdev->fb1_active = buf;
                        dma_inten = CSICR1_FB1_DMA_INTEN;
                } else if (pcdev->fb2_active == NULL) {
-                       writel(videobuf_to_dma_contig(vb),
+                       writel(vb2_dma_contig_plane_dma_addr(vb, 0),
                                        pcdev->base_csi + CSIDMASA_FB2);
                        pcdev->fb2_active = buf;
                        dma_inten = CSICR1_FB2_DMA_INTEN;
                }
 
                if (dma_inten) {
-                       list_del(&vb->queue);
-                       vb->state = VIDEOBUF_ACTIVE;
+                       list_del(&buf->internal.queue);
+                       buf->state = MX2_STATE_ACTIVE;
 
                        csicr3 = readl(pcdev->base_csi + CSICR3);
 
@@ -674,36 +640,31 @@ static void mx2_videobuf_queue(struct videobuf_queue *vq,
                }
        }
 
-out:
        spin_unlock_irqrestore(&pcdev->lock, flags);
 }
 
-static void mx2_videobuf_release(struct videobuf_queue *vq,
-                                struct videobuf_buffer *vb)
+static void mx2_videobuf_release(struct vb2_buffer *vb)
 {
-       struct soc_camera_device *icd = vq->priv_data;
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
        unsigned long flags;
 
 #ifdef DEBUG
-       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-               vb, vb->baddr, vb->bsize);
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+               vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
-       switch (vb->state) {
-       case VIDEOBUF_ACTIVE:
+       switch (buf->state) {
+       case MX2_STATE_ACTIVE:
                dev_info(icd->parent, "%s (active)\n", __func__);
                break;
-       case VIDEOBUF_QUEUED:
+       case MX2_STATE_QUEUED:
                dev_info(icd->parent, "%s (queued)\n", __func__);
                break;
-       case VIDEOBUF_PREPARED:
-               dev_info(icd->parent, "%s (prepared)\n", __func__);
-               break;
        default:
                dev_info(icd->parent, "%s (unknown) %d\n", __func__,
-                               vb->state);
+                               buf->state);
                break;
        }
 #endif
@@ -717,11 +678,9 @@ static void mx2_videobuf_release(struct videobuf_queue *vq,
         * state. This requires a specific handling for each of the these DMA
         * types.
         */
+
        spin_lock_irqsave(&pcdev->lock, flags);
-       if (vb->state == VIDEOBUF_QUEUED) {
-               list_del(&vb->queue);
-               vb->state = VIDEOBUF_ERROR;
-       } else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) {
+       if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) {
                if (pcdev->fb1_active == buf) {
                        pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
                        writel(0, pcdev->base_csi + CSIDMASA_FB1);
@@ -732,75 +691,178 @@ static void mx2_videobuf_release(struct videobuf_queue *vq,
                        pcdev->fb2_active = NULL;
                }
                writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
-               vb->state = VIDEOBUF_ERROR;
        }
        spin_unlock_irqrestore(&pcdev->lock, flags);
-
-       free_buffer(vq, buf);
 }
 
-static struct videobuf_queue_ops mx2_videobuf_ops = {
-       .buf_setup      = mx2_videobuf_setup,
-       .buf_prepare    = mx2_videobuf_prepare,
-       .buf_queue      = mx2_videobuf_queue,
-       .buf_release    = mx2_videobuf_release,
-};
-
-static void mx2_camera_init_videobuf(struct videobuf_queue *q,
-                             struct soc_camera_device *icd)
+static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
+               int bytesperline)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct soc_camera_host *ici =
+               to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
+       struct mx2_fmt_cfg *prp = pcdev->emma_prp;
 
-       videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev,
-                       &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                       V4L2_FIELD_NONE, sizeof(struct mx2_buffer),
-                       icd, &icd->video_lock);
-}
+       writel((pcdev->s_width << 16) | pcdev->s_height,
+              pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+       writel(prp->cfg.src_pixel,
+              pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
+       if (prp->cfg.channel == 1) {
+               writel((icd->user_width << 16) | icd->user_height,
+                       pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
+               writel(bytesperline,
+                       pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
+               writel(prp->cfg.ch1_pixel,
+                       pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
+       } else { /* channel 2 */
+               writel((icd->user_width << 16) | icd->user_height,
+                       pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
+       }
 
-#define MX2_BUS_FLAGS  (V4L2_MBUS_MASTER | \
-                       V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
-                       V4L2_MBUS_VSYNC_ACTIVE_LOW | \
-                       V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
-                       V4L2_MBUS_HSYNC_ACTIVE_LOW | \
-                       V4L2_MBUS_PCLK_SAMPLE_RISING | \
-                       V4L2_MBUS_PCLK_SAMPLE_FALLING | \
-                       V4L2_MBUS_DATA_ACTIVE_HIGH | \
-                       V4L2_MBUS_DATA_ACTIVE_LOW)
+       /* Enable interrupts */
+       writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
+}
 
-static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
+static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev)
 {
-       u32 cntl;
-       int count = 0;
+       int dir;
 
-       cntl = readl(pcdev->base_emma + PRP_CNTL);
-       writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
-       while (count++ < 100) {
-               if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
-                       return 0;
-               barrier();
-               udelay(1);
-       }
+       for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
+               unsigned char *s = pcdev->resizing[dir].s;
+               int len = pcdev->resizing[dir].len;
+               unsigned int coeff[2] = {0, 0};
+               unsigned int valid  = 0;
+               int i;
 
-       return -ETIMEDOUT;
+               if (len == 0)
+                       continue;
+
+               for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) {
+                       int j;
+
+                       j = i > 9 ? 1 : 0;
+                       coeff[j] = (coeff[j] << BC_COEF) |
+                                       (s[i] & (SZ_COEF - 1));
+
+                       if (i == 5 || i == 15)
+                               coeff[j] <<= 1;
+
+                       valid = (valid << 1) | (s[i] >> BC_COEF);
+               }
+
+               valid |= PRP_RZ_VALID_TBL_LEN(len);
+
+               if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR)
+                       valid |= PRP_RZ_VALID_BILINEAR;
+
+               if (pcdev->emma_prp->cfg.channel == 1) {
+                       if (dir == RESIZE_DIR_H) {
+                               writel(coeff[0], pcdev->base_emma +
+                                                       PRP_CH1_RZ_HORI_COEF1);
+                               writel(coeff[1], pcdev->base_emma +
+                                                       PRP_CH1_RZ_HORI_COEF2);
+                               writel(valid, pcdev->base_emma +
+                                                       PRP_CH1_RZ_HORI_VALID);
+                       } else {
+                               writel(coeff[0], pcdev->base_emma +
+                                                       PRP_CH1_RZ_VERT_COEF1);
+                               writel(coeff[1], pcdev->base_emma +
+                                                       PRP_CH1_RZ_VERT_COEF2);
+                               writel(valid, pcdev->base_emma +
+                                                       PRP_CH1_RZ_VERT_VALID);
+                       }
+               } else {
+                       if (dir == RESIZE_DIR_H) {
+                               writel(coeff[0], pcdev->base_emma +
+                                                       PRP_CH2_RZ_HORI_COEF1);
+                               writel(coeff[1], pcdev->base_emma +
+                                                       PRP_CH2_RZ_HORI_COEF2);
+                               writel(valid, pcdev->base_emma +
+                                                       PRP_CH2_RZ_HORI_VALID);
+                       } else {
+                               writel(coeff[0], pcdev->base_emma +
+                                                       PRP_CH2_RZ_VERT_COEF1);
+                               writel(coeff[1], pcdev->base_emma +
+                                                       PRP_CH2_RZ_VERT_COEF2);
+                               writel(valid, pcdev->base_emma +
+                                                       PRP_CH2_RZ_VERT_VALID);
+                       }
+               }
+       }
 }
 
-static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
-               int bytesperline)
+static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
 {
+       struct soc_camera_device *icd = soc_camera_from_vb2q(q);
        struct soc_camera_host *ici =
                to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        struct mx2_fmt_cfg *prp = pcdev->emma_prp;
-       u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
+       struct vb2_buffer *vb;
+       struct mx2_buffer *buf;
+       unsigned long phys;
+       int bytesperline;
 
-       if (prp->cfg.channel == 1) {
-               writel(pcdev->discard_buffer_dma,
-                               pcdev->base_emma + PRP_DEST_RGB1_PTR);
-               writel(pcdev->discard_buffer_dma,
-                               pcdev->base_emma + PRP_DEST_RGB2_PTR);
+       if (cpu_is_mx27()) {
+               unsigned long flags;
+               if (count < 2)
+                       return -EINVAL;
+
+               spin_lock_irqsave(&pcdev->lock, flags);
+
+               buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+                                      internal.queue);
+               buf->internal.bufnum = 0;
+               vb = &buf->vb;
+               buf->state = MX2_STATE_ACTIVE;
+
+               phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+               mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
+               list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+               buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+                                      internal.queue);
+               buf->internal.bufnum = 1;
+               vb = &buf->vb;
+               buf->state = MX2_STATE_ACTIVE;
 
-               writel(PRP_CNTL_CH1EN |
+               phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+               mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum);
+               list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+               bytesperline = soc_mbus_bytes_per_line(icd->user_width,
+                               icd->current_fmt->host_fmt);
+               if (bytesperline < 0)
+                       return bytesperline;
+
+               /*
+                * I didn't manage to properly enable/disable the prp
+                * on a per frame basis during running transfers,
+                * thus we allocate a buffer here and use it to
+                * discard frames when no buffer is available.
+                * Feel free to work on this ;)
+                */
+               pcdev->discard_size = icd->user_height * bytesperline;
+               pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
+                               pcdev->discard_size, &pcdev->discard_buffer_dma,
+                               GFP_KERNEL);
+               if (!pcdev->discard_buffer)
+                       return -ENOMEM;
+
+               pcdev->buf_discard[0].discard = true;
+               list_add_tail(&pcdev->buf_discard[0].queue,
+                                     &pcdev->discard);
+
+               pcdev->buf_discard[1].discard = true;
+               list_add_tail(&pcdev->buf_discard[1].queue,
+                                     &pcdev->discard);
+
+               mx2_prp_resize_commit(pcdev);
+
+               mx27_camera_emma_buf_init(icd, bytesperline);
+
+               if (prp->cfg.channel == 1) {
+                       writel(PRP_CNTL_CH1EN |
                                PRP_CNTL_CSIEN |
                                prp->cfg.in_fmt |
                                prp->cfg.out_fmt |
@@ -809,56 +871,107 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
                                PRP_CNTL_CH1_TSKIP(0) |
                                PRP_CNTL_IN_TSKIP(0),
                                pcdev->base_emma + PRP_CNTL);
+               } else {
+                       writel(PRP_CNTL_CH2EN |
+                               PRP_CNTL_CSIEN |
+                               prp->cfg.in_fmt |
+                               prp->cfg.out_fmt |
+                               PRP_CNTL_CH2_LEN |
+                               PRP_CNTL_CH2_TSKIP(0) |
+                               PRP_CNTL_IN_TSKIP(0),
+                               pcdev->base_emma + PRP_CNTL);
+               }
+               spin_unlock_irqrestore(&pcdev->lock, flags);
+       }
 
-               writel((icd->user_width << 16) | icd->user_height,
-                       pcdev->base_emma + PRP_SRC_FRAME_SIZE);
-               writel((icd->user_width << 16) | icd->user_height,
-                       pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
-               writel(bytesperline,
-                       pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
-               writel(prp->cfg.src_pixel,
-                       pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
-               writel(prp->cfg.ch1_pixel,
-                       pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
-       } else { /* channel 2 */
-               writel(pcdev->discard_buffer_dma,
-                       pcdev->base_emma + PRP_DEST_Y_PTR);
-               writel(pcdev->discard_buffer_dma,
-                       pcdev->base_emma + PRP_SOURCE_Y_PTR);
-
-               if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) {
-                       writel(pcdev->discard_buffer_dma + imgsize,
-                               pcdev->base_emma + PRP_DEST_CB_PTR);
-                       writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4),
-                               pcdev->base_emma + PRP_DEST_CR_PTR);
-                       writel(pcdev->discard_buffer_dma + imgsize,
-                               pcdev->base_emma + PRP_SOURCE_CB_PTR);
-                       writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4),
-                               pcdev->base_emma + PRP_SOURCE_CR_PTR);
+       return 0;
+}
+
+static int mx2_stop_streaming(struct vb2_queue *q)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+       struct soc_camera_host *ici =
+               to_soc_camera_host(icd->parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
+       struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+       unsigned long flags;
+       void *b;
+       u32 cntl;
+
+       if (cpu_is_mx27()) {
+               spin_lock_irqsave(&pcdev->lock, flags);
+
+               cntl = readl(pcdev->base_emma + PRP_CNTL);
+               if (prp->cfg.channel == 1) {
+                       writel(cntl & ~PRP_CNTL_CH1EN,
+                              pcdev->base_emma + PRP_CNTL);
+               } else {
+                       writel(cntl & ~PRP_CNTL_CH2EN,
+                              pcdev->base_emma + PRP_CNTL);
                }
+               INIT_LIST_HEAD(&pcdev->capture);
+               INIT_LIST_HEAD(&pcdev->active_bufs);
+               INIT_LIST_HEAD(&pcdev->discard);
 
-               writel(PRP_CNTL_CH2EN |
-                       PRP_CNTL_CSIEN |
-                       prp->cfg.in_fmt |
-                       prp->cfg.out_fmt |
-                       PRP_CNTL_CH2_LEN |
-                       PRP_CNTL_CH2_TSKIP(0) |
-                       PRP_CNTL_IN_TSKIP(0),
-                       pcdev->base_emma + PRP_CNTL);
+               b = pcdev->discard_buffer;
+               pcdev->discard_buffer = NULL;
 
-               writel((icd->user_width << 16) | icd->user_height,
-                       pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+               spin_unlock_irqrestore(&pcdev->lock, flags);
 
-               writel((icd->user_width << 16) | icd->user_height,
-                       pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
+               dma_free_coherent(ici->v4l2_dev.dev,
+                       pcdev->discard_size, b, pcdev->discard_buffer_dma);
+       }
 
-               writel(prp->cfg.src_pixel,
-                       pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
+       return 0;
+}
+
+static struct vb2_ops mx2_videobuf_ops = {
+       .queue_setup     = mx2_videobuf_setup,
+       .buf_prepare     = mx2_videobuf_prepare,
+       .buf_queue       = mx2_videobuf_queue,
+       .buf_cleanup     = mx2_videobuf_release,
+       .start_streaming = mx2_start_streaming,
+       .stop_streaming  = mx2_stop_streaming,
+};
+
+static int mx2_camera_init_videobuf(struct vb2_queue *q,
+                             struct soc_camera_device *icd)
+{
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR;
+       q->drv_priv = icd;
+       q->ops = &mx2_videobuf_ops;
+       q->mem_ops = &vb2_dma_contig_memops;
+       q->buf_struct_size = sizeof(struct mx2_buffer);
+
+       return vb2_queue_init(q);
+}
 
+#define MX2_BUS_FLAGS  (V4L2_MBUS_MASTER | \
+                       V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
+                       V4L2_MBUS_VSYNC_ACTIVE_LOW | \
+                       V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
+                       V4L2_MBUS_HSYNC_ACTIVE_LOW | \
+                       V4L2_MBUS_PCLK_SAMPLE_RISING | \
+                       V4L2_MBUS_PCLK_SAMPLE_FALLING | \
+                       V4L2_MBUS_DATA_ACTIVE_HIGH | \
+                       V4L2_MBUS_DATA_ACTIVE_LOW)
+
+static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
+{
+       u32 cntl;
+       int count = 0;
+
+       cntl = readl(pcdev->base_emma + PRP_CNTL);
+       writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
+       while (count++ < 100) {
+               if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
+                       return 0;
+               barrier();
+               udelay(1);
        }
 
-       /* Enable interrupts */
-       writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
+       return -ETIMEDOUT;
 }
 
 static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
@@ -939,31 +1052,10 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
        if (bytesperline < 0)
                return bytesperline;
 
-       if (mx27_camera_emma(pcdev)) {
+       if (cpu_is_mx27()) {
                ret = mx27_camera_emma_prp_reset(pcdev);
                if (ret)
                        return ret;
-
-               if (pcdev->discard_buffer)
-                       dma_free_coherent(ici->v4l2_dev.dev,
-                               pcdev->discard_size, pcdev->discard_buffer,
-                               pcdev->discard_buffer_dma);
-
-               /*
-                * I didn't manage to properly enable/disable the prp
-                * on a per frame basis during running transfers,
-                * thus we allocate a buffer here and use it to
-                * discard frames when no buffer is available.
-                * Feel free to work on this ;)
-                */
-               pcdev->discard_size = icd->user_height * bytesperline;
-               pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
-                               pcdev->discard_size, &pcdev->discard_buffer_dma,
-                               GFP_KERNEL);
-               if (!pcdev->discard_buffer)
-                       return -ENOMEM;
-
-               mx27_camera_emma_buf_init(icd, bytesperline);
        } else if (cpu_is_mx25()) {
                writel((bytesperline * icd->user_height) >> 2,
                                pcdev->base_csi + CSIRXCNT);
@@ -1052,6 +1144,123 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
        return formats;
 }
 
+static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev,
+                             struct v4l2_mbus_framefmt *mf_in,
+                             struct v4l2_pix_format *pix_out, bool apply)
+{
+       int num, den;
+       unsigned long m;
+       int i, dir;
+
+       for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
+               struct emma_prp_resize tmprsz;
+               unsigned char *s = tmprsz.s;
+               int len = 0;
+               int in, out;
+
+               if (dir == RESIZE_DIR_H) {
+                       in = mf_in->width;
+                       out = pix_out->width;
+               } else {
+                       in = mf_in->height;
+                       out = pix_out->height;
+               }
+
+               if (in < out)
+                       return -EINVAL;
+               else if (in == out)
+                       continue;
+
+               /* Calculate ratio */
+               m = gcd(in, out);
+               num = in / m;
+               den = out / m;
+               if (num > RESIZE_NUM_MAX)
+                       return -EINVAL;
+
+               if ((num >= 2 * den) && (den == 1) &&
+                   (num < 9) && (!(num & 0x01))) {
+                       int sum = 0;
+                       int j;
+
+                       /* Average scaling for >= 2:1 ratios */
+                       /* Support can be added for num >=9 and odd values */
+
+                       tmprsz.algo = RESIZE_ALGO_AVERAGING;
+                       len = num;
+
+                       for (i = 0; i < (len / 2); i++)
+                               s[i] = 8;
+
+                       do {
+                               for (i = 0; i < (len / 2); i++) {
+                                       s[i] = s[i] >> 1;
+                                       sum = 0;
+                                       for (j = 0; j < (len / 2); j++)
+                                               sum += s[j];
+                                       if (sum == 4)
+                                               break;
+                               }
+                       } while (sum != 4);
+
+                       for (i = (len / 2); i < len; i++)
+                               s[i] = s[len - i - 1];
+
+                       s[len - 1] |= SZ_COEF;
+               } else {
+                       /* bilinear scaling for < 2:1 ratios */
+                       int v; /* overflow counter */
+                       int coeff, nxt; /* table output */
+                       int in_pos_inc = 2 * den;
+                       int out_pos = num;
+                       int out_pos_inc = 2 * num;
+                       int init_carry = num - den;
+                       int carry = init_carry;
+
+                       tmprsz.algo = RESIZE_ALGO_BILINEAR;
+                       v = den + in_pos_inc;
+                       do {
+                               coeff = v - out_pos;
+                               out_pos += out_pos_inc;
+                               carry += out_pos_inc;
+                               for (nxt = 0; v < out_pos; nxt++) {
+                                       v += in_pos_inc;
+                                       carry -= in_pos_inc;
+                               }
+
+                               if (len > RESIZE_NUM_MAX)
+                                       return -EINVAL;
+
+                               coeff = ((coeff << BC_COEF) +
+                                       (in_pos_inc >> 1)) / in_pos_inc;
+
+                               if (coeff >= (SZ_COEF - 1))
+                                       coeff--;
+
+                               coeff |= SZ_COEF;
+                               s[len] = (unsigned char)coeff;
+                               len++;
+
+                               for (i = 1; i < nxt; i++) {
+                                       if (len >= RESIZE_NUM_MAX)
+                                               return -EINVAL;
+                                       s[len] = 0;
+                                       len++;
+                               }
+                       } while (carry != init_carry);
+               }
+               tmprsz.len = len;
+               if (dir == RESIZE_DIR_H)
+                       mf_in->width = pix_out->width;
+               else
+                       mf_in->height = pix_out->height;
+
+               if (apply)
+                       memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz));
+       }
+       return 0;
+}
+
 static int mx2_camera_set_fmt(struct soc_camera_device *icd,
                               struct v4l2_format *f)
 {
@@ -1063,6 +1272,9 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
        struct v4l2_mbus_framefmt mf;
        int ret;
 
+       dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
+               __func__, pix->width, pix->height);
+
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
                dev_warn(icd->parent, "Format %x not found\n",
@@ -1080,6 +1292,22 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
        if (ret < 0 && ret != -ENOIOCTLCMD)
                return ret;
 
+       /* Store width and height returned by the sensor for resizing */
+       pcdev->s_width = mf.width;
+       pcdev->s_height = mf.height;
+       dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
+               __func__, pcdev->s_width, pcdev->s_height);
+
+       pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
+                                                  xlate->host_fmt->fourcc);
+
+       memset(pcdev->resizing, 0, sizeof(pcdev->resizing));
+       if ((mf.width != pix->width || mf.height != pix->height) &&
+               pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
+               if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0)
+                       dev_dbg(icd->parent, "%s: can't resize\n", __func__);
+       }
+
        if (mf.code != xlate->code)
                return -EINVAL;
 
@@ -1089,9 +1317,8 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
        pix->colorspace         = mf.colorspace;
        icd->current_fmt        = xlate;
 
-       if (mx27_camera_emma(pcdev))
-               pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
-                                               xlate->host_fmt->fourcc);
+       dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
+               __func__, pix->width, pix->height);
 
        return 0;
 }
@@ -1104,9 +1331,14 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
        struct v4l2_pix_format *pix = &f->fmt.pix;
        struct v4l2_mbus_framefmt mf;
        __u32 pixfmt = pix->pixelformat;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct mx2_camera_dev *pcdev = ici->priv;
        unsigned int width_limit;
        int ret;
 
+       dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
+               __func__, pix->width, pix->height);
+
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (pixfmt && !xlate) {
                dev_warn(icd->parent, "Format %x not found\n", pixfmt);
@@ -1156,6 +1388,20 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
        if (ret < 0)
                return ret;
 
+       dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
+               __func__, pcdev->s_width, pcdev->s_height);
+
+       /* If the sensor does not support image size try PrP resizing */
+       pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
+                                                  xlate->host_fmt->fourcc);
+
+       memset(pcdev->resizing, 0, sizeof(pcdev->resizing));
+       if ((mf.width != pix->width || mf.height != pix->height) &&
+               pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
+               if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0)
+                       dev_dbg(icd->parent, "%s: can't resize\n", __func__);
+       }
+
        if (mf.field == V4L2_FIELD_ANY)
                mf.field = V4L2_FIELD_NONE;
        /*
@@ -1174,6 +1420,9 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
        pix->field      = mf.field;
        pix->colorspace = mf.colorspace;
 
+       dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
+               __func__, pix->width, pix->height);
+
        return 0;
 }
 
@@ -1187,136 +1436,11 @@ static int mx2_camera_querycap(struct soc_camera_host *ici,
        return 0;
 }
 
-static int mx2_camera_reqbufs(struct soc_camera_device *icd,
-                             struct v4l2_requestbuffers *p)
-{
-       int i;
-
-       for (i = 0; i < p->count; i++) {
-               struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i],
-                                                     struct mx2_buffer, vb);
-               INIT_LIST_HEAD(&buf->vb.queue);
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_MACH_MX27
-static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state)
-{
-       struct videobuf_buffer *vb;
-       struct mx2_buffer *buf;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&pcdev->lock, flags);
-
-       if (!pcdev->active) {
-               dev_err(pcdev->dev, "%s called with no active buffer!\n",
-                               __func__);
-               goto out;
-       }
-
-       vb = &pcdev->active->vb;
-       buf = container_of(vb, struct mx2_buffer, vb);
-       WARN_ON(list_empty(&vb->queue));
-       dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
-               vb, vb->baddr, vb->bsize);
-
-       /* _init is used to debug races, see comment in pxa_camera_reqbufs() */
-       list_del_init(&vb->queue);
-       vb->state = state;
-       do_gettimeofday(&vb->ts);
-       vb->field_count++;
-
-       wake_up(&vb->done);
-
-       if (list_empty(&pcdev->capture)) {
-               pcdev->active = NULL;
-               goto out;
-       }
-
-       pcdev->active = list_entry(pcdev->capture.next,
-                       struct mx2_buffer, vb.queue);
-
-       vb = &pcdev->active->vb;
-       vb->state = VIDEOBUF_ACTIVE;
-
-       ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb),
-                       vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ);
-
-       if (ret) {
-               vb->state = VIDEOBUF_ERROR;
-               pcdev->active = NULL;
-               wake_up(&vb->done);
-       }
-
-out:
-       spin_unlock_irqrestore(&pcdev->lock, flags);
-}
-
-static void mx27_camera_dma_err_callback(int channel, void *data, int err)
-{
-       struct mx2_camera_dev *pcdev = data;
-
-       mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR);
-}
-
-static void mx27_camera_dma_callback(int channel, void *data)
-{
-       struct mx2_camera_dev *pcdev = data;
-
-       mx27_camera_frame_done(pcdev, VIDEOBUF_DONE);
-}
-
-#define DMA_REQ_CSI_RX          31 /* FIXME: Add this to a resource */
-
-static int __devinit mx27_camera_dma_init(struct platform_device *pdev,
-               struct mx2_camera_dev *pcdev)
-{
-       int err;
-
-       pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH);
-       if (pcdev->dma < 0) {
-               dev_err(&pdev->dev, "%s failed to request DMA channel\n",
-                               __func__);
-               return pcdev->dma;
-       }
-
-       err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback,
-                                       mx27_camera_dma_err_callback, pcdev);
-       if (err) {
-               dev_err(&pdev->dev, "%s failed to set DMA callback\n",
-                               __func__);
-               goto err_out;
-       }
-
-       err = imx_dma_config_channel(pcdev->dma,
-                       IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO,
-                       IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-                       DMA_REQ_CSI_RX, 1);
-       if (err) {
-               dev_err(&pdev->dev, "%s failed to config DMA channel\n",
-                               __func__);
-               goto err_out;
-       }
-
-       imx_dma_config_burstlen(pcdev->dma, 64);
-
-       return 0;
-
-err_out:
-       imx_dma_free(pcdev->dma);
-
-       return err;
-}
-#endif /* CONFIG_MACH_MX27 */
-
 static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
 {
        struct soc_camera_device *icd = file->private_data;
 
-       return videobuf_poll_stream(file, &icd->vb_vidq, pt);
+       return vb2_poll(&icd->vb2_vidq, file, pt);
 }
 
 static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
@@ -1327,144 +1451,148 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
        .set_crop       = mx2_camera_set_crop,
        .get_formats    = mx2_camera_get_formats,
        .try_fmt        = mx2_camera_try_fmt,
-       .init_videobuf  = mx2_camera_init_videobuf,
-       .reqbufs        = mx2_camera_reqbufs,
+       .init_videobuf2 = mx2_camera_init_videobuf,
        .poll           = mx2_camera_poll,
        .querycap       = mx2_camera_querycap,
        .set_bus_param  = mx2_camera_set_bus_param,
 };
 
 static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
-               int bufnum, int state)
+               int bufnum, bool err)
 {
-       u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
+#ifdef DEBUG
        struct mx2_fmt_cfg *prp = pcdev->emma_prp;
+#endif
+       struct mx2_buf_internal *ibuf;
        struct mx2_buffer *buf;
-       struct videobuf_buffer *vb;
+       struct vb2_buffer *vb;
        unsigned long phys;
 
-       if (!list_empty(&pcdev->active_bufs)) {
-               buf = list_entry(pcdev->active_bufs.next,
-                       struct mx2_buffer, vb.queue);
+       ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal,
+                              queue);
+
+       BUG_ON(ibuf->bufnum != bufnum);
 
-               BUG_ON(buf->bufnum != bufnum);
+       if (ibuf->discard) {
+               /*
+                * Discard buffer must not be returned to user space.
+                * Just return it to the discard queue.
+                */
+               list_move_tail(pcdev->active_bufs.next, &pcdev->discard);
+       } else {
+               buf = mx2_ibuf_to_buf(ibuf);
 
                vb = &buf->vb;
 #ifdef DEBUG
-               phys = videobuf_to_dma_contig(vb);
+               phys = vb2_dma_contig_plane_dma_addr(vb, 0);
                if (prp->cfg.channel == 1) {
                        if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR +
                                4 * bufnum) != phys) {
-                               dev_err(pcdev->dev, "%p != %p\n", phys,
-                                               readl(pcdev->base_emma +
-                                                       PRP_DEST_RGB1_PTR +
-                                                       4 * bufnum));
+                               dev_err(pcdev->dev, "%lx != %x\n", phys,
+                                       readl(pcdev->base_emma +
+                                       PRP_DEST_RGB1_PTR + 4 * bufnum));
                        }
                } else {
                        if (readl(pcdev->base_emma + PRP_DEST_Y_PTR -
                                0x14 * bufnum) != phys) {
-                               dev_err(pcdev->dev, "%p != %p\n", phys,
-                                               readl(pcdev->base_emma +
-                                                       PRP_DEST_Y_PTR -
-                                                       0x14 * bufnum));
+                               dev_err(pcdev->dev, "%lx != %x\n", phys,
+                                       readl(pcdev->base_emma +
+                                       PRP_DEST_Y_PTR - 0x14 * bufnum));
                        }
                }
 #endif
-               dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb,
-                               vb->baddr, vb->bsize);
+               dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb,
+                               vb2_plane_vaddr(vb, 0),
+                               vb2_get_plane_payload(vb, 0));
 
-               list_del(&vb->queue);
-               vb->state = state;
-               do_gettimeofday(&vb->ts);
-               vb->field_count = pcdev->frame_count * 2;
-               pcdev->frame_count++;
-
-               wake_up(&vb->done);
+               list_del_init(&buf->internal.queue);
+               do_gettimeofday(&vb->v4l2_buf.timestamp);
+               vb->v4l2_buf.sequence = pcdev->frame_count;
+               if (err)
+                       vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+               else
+                       vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
        }
 
+       pcdev->frame_count++;
+
        if (list_empty(&pcdev->capture)) {
-               if (prp->cfg.channel == 1) {
-                       writel(pcdev->discard_buffer_dma, pcdev->base_emma +
-                                       PRP_DEST_RGB1_PTR + 4 * bufnum);
-               } else {
-                       writel(pcdev->discard_buffer_dma, pcdev->base_emma +
-                                               PRP_DEST_Y_PTR -
-                                               0x14 * bufnum);
-                       if (prp->out_fmt == V4L2_PIX_FMT_YUV420) {
-                               writel(pcdev->discard_buffer_dma + imgsize,
-                                      pcdev->base_emma + PRP_DEST_CB_PTR -
-                                      0x14 * bufnum);
-                               writel(pcdev->discard_buffer_dma +
-                                      ((5 * imgsize) / 4), pcdev->base_emma +
-                                      PRP_DEST_CR_PTR - 0x14 * bufnum);
-                       }
+               if (list_empty(&pcdev->discard)) {
+                       dev_warn(pcdev->dev, "%s: trying to access empty discard list\n",
+                                __func__);
+                       return;
                }
+
+               ibuf = list_first_entry(&pcdev->discard,
+                                       struct mx2_buf_internal, queue);
+               ibuf->bufnum = bufnum;
+
+               list_move_tail(pcdev->discard.next, &pcdev->active_bufs);
+               mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum);
                return;
        }
 
-       buf = list_entry(pcdev->capture.next,
-                       struct mx2_buffer, vb.queue);
+       buf = list_first_entry(&pcdev->capture, struct mx2_buffer,
+                              internal.queue);
 
-       buf->bufnum = !bufnum;
+       buf->internal.bufnum = bufnum;
 
        list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
 
        vb = &buf->vb;
-       vb->state = VIDEOBUF_ACTIVE;
+       buf->state = MX2_STATE_ACTIVE;
 
-       phys = videobuf_to_dma_contig(vb);
-       if (prp->cfg.channel == 1) {
-               writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
-       } else {
-               writel(phys, pcdev->base_emma +
-                               PRP_DEST_Y_PTR - 0x14 * bufnum);
-               if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) {
-                       writel(phys + imgsize, pcdev->base_emma +
-                                       PRP_DEST_CB_PTR - 0x14 * bufnum);
-                       writel(phys + ((5 * imgsize) / 4), pcdev->base_emma +
-                                       PRP_DEST_CR_PTR - 0x14 * bufnum);
-               }
-       }
+       phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+       mx27_update_emma_buf(pcdev, phys, bufnum);
 }
 
 static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
 {
        struct mx2_camera_dev *pcdev = data;
        unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS);
-       struct mx2_buffer *buf;
+       struct mx2_buf_internal *ibuf;
+
+       spin_lock(&pcdev->lock);
+
+       if (list_empty(&pcdev->active_bufs)) {
+               dev_warn(pcdev->dev, "%s: called while active list is empty\n",
+                       __func__);
+
+               if (!status) {
+                       spin_unlock(&pcdev->lock);
+                       return IRQ_NONE;
+               }
+       }
 
        if (status & (1 << 7)) { /* overflow */
-               u32 cntl;
-               /*
-                * We only disable channel 1 here since this is the only
-                * enabled channel
-                *
-                * FIXME: the correct DMA overflow handling should be resetting
-                * the buffer, returning an error frame, and continuing with
-                * the next one.
-                */
-               cntl = readl(pcdev->base_emma + PRP_CNTL);
+               u32 cntl = readl(pcdev->base_emma + PRP_CNTL);
                writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN),
                       pcdev->base_emma + PRP_CNTL);
                writel(cntl, pcdev->base_emma + PRP_CNTL);
-       }
-       if ((((status & (3 << 5)) == (3 << 5)) ||
-               ((status & (3 << 3)) == (3 << 3)))
-                       && !list_empty(&pcdev->active_bufs)) {
+
+               ibuf = list_first_entry(&pcdev->active_bufs,
+                                       struct mx2_buf_internal, queue);
+               mx27_camera_frame_done_emma(pcdev,
+                                       ibuf->bufnum, true);
+
+               status &= ~(1 << 7);
+       } else if (((status & (3 << 5)) == (3 << 5)) ||
+               ((status & (3 << 3)) == (3 << 3))) {
                /*
                 * Both buffers have triggered, process the one we're expecting
                 * to first
                 */
-               buf = list_entry(pcdev->active_bufs.next,
-                       struct mx2_buffer, vb.queue);
-               mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE);
-               status &= ~(1 << (6 - buf->bufnum)); /* mark processed */
+               ibuf = list_first_entry(&pcdev->active_bufs,
+                                       struct mx2_buf_internal, queue);
+               mx27_camera_frame_done_emma(pcdev, ibuf->bufnum, false);
+               status &= ~(1 << (6 - ibuf->bufnum)); /* mark processed */
+       } else if ((status & (1 << 6)) || (status & (1 << 4))) {
+               mx27_camera_frame_done_emma(pcdev, 0, false);
+       } else if ((status & (1 << 5)) || (status & (1 << 3))) {
+               mx27_camera_frame_done_emma(pcdev, 1, false);
        }
-       if ((status & (1 << 6)) || (status & (1 << 4)))
-               mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE);
-       if ((status & (1 << 5)) || (status & (1 << 3)))
-               mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE);
 
+       spin_unlock(&pcdev->lock);
        writel(status, pcdev->base_emma + PRP_INTRSTATUS);
 
        return IRQ_HANDLED;
@@ -1527,8 +1655,6 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
        struct resource *res_csi, *res_emma;
        void __iomem *base_csi;
        int irq_csi, irq_emma;
-       irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq
-               : mx27_camera_irq;
        int err = 0;
 
        dev_dbg(&pdev->dev, "initialising\n");
@@ -1550,22 +1676,11 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
 
        pcdev->clk_csi = clk_get(&pdev->dev, NULL);
        if (IS_ERR(pcdev->clk_csi)) {
+               dev_err(&pdev->dev, "Could not get csi clock\n");
                err = PTR_ERR(pcdev->clk_csi);
                goto exit_kfree;
        }
 
-       dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n",
-                       clk_get_rate(pcdev->clk_csi));
-
-       /* Initialize DMA */
-#ifdef CONFIG_MACH_MX27
-       if (cpu_is_mx27()) {
-               err = mx27_camera_dma_init(pdev, pcdev);
-               if (err)
-                       goto exit_clk_put;
-       }
-#endif /* CONFIG_MACH_MX27 */
-
        pcdev->res_csi = res_csi;
        pcdev->pdata = pdev->dev.platform_data;
        if (pcdev->pdata) {
@@ -1585,6 +1700,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
 
        INIT_LIST_HEAD(&pcdev->capture);
        INIT_LIST_HEAD(&pcdev->active_bufs);
+       INIT_LIST_HEAD(&pcdev->discard);
        spin_lock_init(&pcdev->lock);
 
        /*
@@ -1606,11 +1722,13 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
        pcdev->base_dma = res_csi->start;
        pcdev->dev = &pdev->dev;
 
-       err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0,
-                       MX2_CAM_DRV_NAME, pcdev);
-       if (err) {
-               dev_err(pcdev->dev, "Camera interrupt register failed \n");
-               goto exit_iounmap;
+       if (cpu_is_mx25()) {
+               err = request_irq(pcdev->irq_csi, mx25_camera_irq, 0,
+                               MX2_CAM_DRV_NAME, pcdev);
+               if (err) {
+                       dev_err(pcdev->dev, "Camera interrupt register failed \n");
+                       goto exit_iounmap;
+               }
        }
 
        if (cpu_is_mx27()) {
@@ -1618,14 +1736,15 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
                res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1);
                irq_emma = platform_get_irq(pdev, 1);
 
-               if (res_emma && irq_emma >= 0) {
-                       dev_info(&pdev->dev, "Using EMMA\n");
-                       pcdev->use_emma = 1;
-                       pcdev->res_emma = res_emma;
-                       pcdev->irq_emma = irq_emma;
-                       if (mx27_camera_emma_init(pcdev))
-                               goto exit_free_irq;
+               if (!res_emma || !irq_emma) {
+                       dev_err(&pdev->dev, "no EMMA resources\n");
+                       goto exit_free_irq;
                }
+
+               pcdev->res_emma = res_emma;
+               pcdev->irq_emma = irq_emma;
+               if (mx27_camera_emma_init(pcdev))
+                       goto exit_free_irq;
        }
 
        pcdev->soc_host.drv_name        = MX2_CAM_DRV_NAME,
@@ -1633,6 +1752,12 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
        pcdev->soc_host.priv            = pcdev;
        pcdev->soc_host.v4l2_dev.dev    = &pdev->dev;
        pcdev->soc_host.nr              = pdev->id;
+
+       pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(pcdev->alloc_ctx)) {
+               err = PTR_ERR(pcdev->alloc_ctx);
+               goto eallocctx;
+       }
        err = soc_camera_host_register(&pcdev->soc_host);
        if (err)
                goto exit_free_emma;
@@ -1643,26 +1768,24 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
        return 0;
 
 exit_free_emma:
-       if (mx27_camera_emma(pcdev)) {
+       vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+eallocctx:
+       if (cpu_is_mx27()) {
                free_irq(pcdev->irq_emma, pcdev);
                clk_disable(pcdev->clk_emma);
                clk_put(pcdev->clk_emma);
                iounmap(pcdev->base_emma);
-               release_mem_region(res_emma->start, resource_size(res_emma));
+               release_mem_region(pcdev->res_emma->start, resource_size(pcdev->res_emma));
        }
 exit_free_irq:
-       free_irq(pcdev->irq_csi, pcdev);
+       if (cpu_is_mx25())
+               free_irq(pcdev->irq_csi, pcdev);
 exit_iounmap:
        iounmap(base_csi);
 exit_release:
        release_mem_region(res_csi->start, resource_size(res_csi));
 exit_dma_free:
-#ifdef CONFIG_MACH_MX27
-       if (cpu_is_mx27())
-               imx_dma_free(pcdev->dma);
-exit_clk_put:
        clk_put(pcdev->clk_csi);
-#endif /* CONFIG_MACH_MX27 */
 exit_kfree:
        kfree(pcdev);
 exit:
@@ -1677,19 +1800,18 @@ static int __devexit mx2_camera_remove(struct platform_device *pdev)
        struct resource *res;
 
        clk_put(pcdev->clk_csi);
-#ifdef CONFIG_MACH_MX27
+       if (cpu_is_mx25())
+               free_irq(pcdev->irq_csi, pcdev);
        if (cpu_is_mx27())
-               imx_dma_free(pcdev->dma);
-#endif /* CONFIG_MACH_MX27 */
-       free_irq(pcdev->irq_csi, pcdev);
-       if (mx27_camera_emma(pcdev))
                free_irq(pcdev->irq_emma, pcdev);
 
        soc_camera_host_unregister(&pcdev->soc_host);
 
+       vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+
        iounmap(pcdev->base_csi);
 
-       if (mx27_camera_emma(pcdev)) {
+       if (cpu_is_mx27()) {
                clk_disable(pcdev->clk_emma);
                clk_put(pcdev->clk_emma);
                iounmap(pcdev->base_emma);
diff --git a/drivers/media/video/mx2_emmaprp.c b/drivers/media/video/mx2_emmaprp.c
new file mode 100644 (file)
index 0000000..ba89a74
--- /dev/null
@@ -0,0 +1,1008 @@
+/*
+ * Support eMMa-PrP through mem2mem framework.
+ *
+ * eMMa-PrP is a piece of HW that allows fetching buffers
+ * from one memory location and do several operations on
+ * them such as scaling or format conversion giving, as a result
+ * a new processed buffer in another memory location.
+ *
+ * Based on mem2mem_testdev.c by Pawel Osciak.
+ *
+ * Copyright (c) 2011 Vista Silicon S.L.
+ * Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+#include <asm/sizes.h>
+
+#define EMMAPRP_MODULE_NAME "mem2mem-emmaprp"
+
+MODULE_DESCRIPTION("Mem-to-mem device which supports eMMa-PrP present in mx2 SoCs");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.1");
+
+static bool debug;
+module_param(debug, bool, 0644);
+
+#define MIN_W 32
+#define MIN_H 32
+#define MAX_W 2040
+#define MAX_H 2046
+
+#define S_ALIGN                1 /* multiple of 2 */
+#define W_ALIGN_YUV420 3 /* multiple of 8 */
+#define W_ALIGN_OTHERS 2 /* multiple of 4 */
+#define H_ALIGN                1 /* multiple of 2 */
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE        (1 << 0)
+#define MEM2MEM_OUTPUT (1 << 1)
+
+#define MEM2MEM_NAME           "m2m-emmaprp"
+
+/* In bytes, per queue */
+#define MEM2MEM_VID_MEM_LIMIT  SZ_16M
+
+#define dprintk(dev, fmt, arg...) \
+       v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+/* EMMA PrP */
+#define PRP_CNTL                        0x00
+#define PRP_INTR_CNTL                   0x04
+#define PRP_INTRSTATUS                  0x08
+#define PRP_SOURCE_Y_PTR                0x0c
+#define PRP_SOURCE_CB_PTR               0x10
+#define PRP_SOURCE_CR_PTR               0x14
+#define PRP_DEST_RGB1_PTR               0x18
+#define PRP_DEST_RGB2_PTR               0x1c
+#define PRP_DEST_Y_PTR                  0x20
+#define PRP_DEST_CB_PTR                 0x24
+#define PRP_DEST_CR_PTR                 0x28
+#define PRP_SRC_FRAME_SIZE              0x2c
+#define PRP_DEST_CH1_LINE_STRIDE        0x30
+#define PRP_SRC_PIXEL_FORMAT_CNTL       0x34
+#define PRP_CH1_PIXEL_FORMAT_CNTL       0x38
+#define PRP_CH1_OUT_IMAGE_SIZE          0x3c
+#define PRP_CH2_OUT_IMAGE_SIZE          0x40
+#define PRP_SRC_LINE_STRIDE             0x44
+#define PRP_CSC_COEF_012                0x48
+#define PRP_CSC_COEF_345                0x4c
+#define PRP_CSC_COEF_678                0x50
+#define PRP_CH1_RZ_HORI_COEF1           0x54
+#define PRP_CH1_RZ_HORI_COEF2           0x58
+#define PRP_CH1_RZ_HORI_VALID           0x5c
+#define PRP_CH1_RZ_VERT_COEF1           0x60
+#define PRP_CH1_RZ_VERT_COEF2           0x64
+#define PRP_CH1_RZ_VERT_VALID           0x68
+#define PRP_CH2_RZ_HORI_COEF1           0x6c
+#define PRP_CH2_RZ_HORI_COEF2           0x70
+#define PRP_CH2_RZ_HORI_VALID           0x74
+#define PRP_CH2_RZ_VERT_COEF1           0x78
+#define PRP_CH2_RZ_VERT_COEF2           0x7c
+#define PRP_CH2_RZ_VERT_VALID           0x80
+
+#define PRP_CNTL_CH1EN          (1 << 0)
+#define PRP_CNTL_CH2EN          (1 << 1)
+#define PRP_CNTL_CSIEN          (1 << 2)
+#define PRP_CNTL_DATA_IN_YUV420 (0 << 3)
+#define PRP_CNTL_DATA_IN_YUV422 (1 << 3)
+#define PRP_CNTL_DATA_IN_RGB16  (2 << 3)
+#define PRP_CNTL_DATA_IN_RGB32  (3 << 3)
+#define PRP_CNTL_CH1_OUT_RGB8   (0 << 5)
+#define PRP_CNTL_CH1_OUT_RGB16  (1 << 5)
+#define PRP_CNTL_CH1_OUT_RGB32  (2 << 5)
+#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5)
+#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7)
+#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
+#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7)
+#define PRP_CNTL_CH1_LEN        (1 << 9)
+#define PRP_CNTL_CH2_LEN        (1 << 10)
+#define PRP_CNTL_SKIP_FRAME     (1 << 11)
+#define PRP_CNTL_SWRST          (1 << 12)
+#define PRP_CNTL_CLKEN          (1 << 13)
+#define PRP_CNTL_WEN            (1 << 14)
+#define PRP_CNTL_CH1BYP         (1 << 15)
+#define PRP_CNTL_IN_TSKIP(x)    ((x) << 16)
+#define PRP_CNTL_CH1_TSKIP(x)   ((x) << 19)
+#define PRP_CNTL_CH2_TSKIP(x)   ((x) << 22)
+#define PRP_CNTL_INPUT_FIFO_LEVEL(x)    ((x) << 25)
+#define PRP_CNTL_RZ_FIFO_LEVEL(x)       ((x) << 27)
+#define PRP_CNTL_CH2B1EN        (1 << 29)
+#define PRP_CNTL_CH2B2EN        (1 << 30)
+#define PRP_CNTL_CH2FEN         (1 << 31)
+
+#define PRP_SIZE_HEIGHT(x)     (x)
+#define PRP_SIZE_WIDTH(x)      ((x) << 16)
+
+/* IRQ Enable and status register */
+#define PRP_INTR_RDERR          (1 << 0)
+#define PRP_INTR_CH1WERR        (1 << 1)
+#define PRP_INTR_CH2WERR        (1 << 2)
+#define PRP_INTR_CH1FC          (1 << 3)
+#define PRP_INTR_CH2FC          (1 << 5)
+#define PRP_INTR_LBOVF          (1 << 7)
+#define PRP_INTR_CH2OVF         (1 << 8)
+
+#define PRP_INTR_ST_RDERR      (1 << 0)
+#define PRP_INTR_ST_CH1WERR    (1 << 1)
+#define PRP_INTR_ST_CH2WERR    (1 << 2)
+#define PRP_INTR_ST_CH2B2CI    (1 << 3)
+#define PRP_INTR_ST_CH2B1CI    (1 << 4)
+#define PRP_INTR_ST_CH1B2CI    (1 << 5)
+#define PRP_INTR_ST_CH1B1CI    (1 << 6)
+#define PRP_INTR_ST_LBOVF      (1 << 7)
+#define PRP_INTR_ST_CH2OVF     (1 << 8)
+
+struct emmaprp_fmt {
+       char    *name;
+       u32     fourcc;
+       /* Types the format can be used for */
+       u32     types;
+};
+
+static struct emmaprp_fmt formats[] = {
+       {
+               .name   = "YUV 4:2:0 Planar",
+               .fourcc = V4L2_PIX_FMT_YUV420,
+               .types  = MEM2MEM_CAPTURE,
+       },
+       {
+               .name   = "4:2:2, packed, YUYV",
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .types  = MEM2MEM_OUTPUT,
+       },
+};
+
+/* Per-queue, driver-specific private data */
+struct emmaprp_q_data {
+       unsigned int            width;
+       unsigned int            height;
+       unsigned int            sizeimage;
+       struct emmaprp_fmt      *fmt;
+};
+
+enum {
+       V4L2_M2M_SRC = 0,
+       V4L2_M2M_DST = 1,
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static struct emmaprp_fmt *find_format(struct v4l2_format *f)
+{
+       struct emmaprp_fmt *fmt;
+       unsigned int k;
+
+       for (k = 0; k < NUM_FORMATS; k++) {
+               fmt = &formats[k];
+               if (fmt->fourcc == f->fmt.pix.pixelformat)
+                       break;
+       }
+
+       if (k == NUM_FORMATS)
+               return NULL;
+
+       return &formats[k];
+}
+
+struct emmaprp_dev {
+       struct v4l2_device      v4l2_dev;
+       struct video_device     *vfd;
+
+       struct mutex            dev_mutex;
+       spinlock_t              irqlock;
+
+       int                     irq_emma;
+       void __iomem            *base_emma;
+       struct clk              *clk_emma;
+       struct resource         *res_emma;
+
+       struct v4l2_m2m_dev     *m2m_dev;
+       struct vb2_alloc_ctx    *alloc_ctx;
+};
+
+struct emmaprp_ctx {
+       struct emmaprp_dev      *dev;
+       /* Abort requested by m2m */
+       int                     aborting;
+       struct emmaprp_q_data   q_data[2];
+       struct v4l2_m2m_ctx     *m2m_ctx;
+};
+
+static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx,
+                                        enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               return &(ctx->q_data[V4L2_M2M_SRC]);
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return &(ctx->q_data[V4L2_M2M_DST]);
+       default:
+               BUG();
+       }
+       return NULL;
+}
+
+/*
+ * mem2mem callbacks
+ */
+static void emmaprp_job_abort(void *priv)
+{
+       struct emmaprp_ctx *ctx = priv;
+       struct emmaprp_dev *pcdev = ctx->dev;
+
+       ctx->aborting = 1;
+
+       dprintk(pcdev, "Aborting task\n");
+
+       v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void emmaprp_lock(void *priv)
+{
+       struct emmaprp_ctx *ctx = priv;
+       struct emmaprp_dev *pcdev = ctx->dev;
+       mutex_lock(&pcdev->dev_mutex);
+}
+
+static void emmaprp_unlock(void *priv)
+{
+       struct emmaprp_ctx *ctx = priv;
+       struct emmaprp_dev *pcdev = ctx->dev;
+       mutex_unlock(&pcdev->dev_mutex);
+}
+
+static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev)
+{
+       dprintk(pcdev,
+               "eMMa-PrP Registers:\n"
+               "  SOURCE_Y_PTR = 0x%08X\n"
+               "  SRC_FRAME_SIZE = 0x%08X\n"
+               "  DEST_Y_PTR = 0x%08X\n"
+               "  DEST_CR_PTR = 0x%08X\n"
+               "  DEST_CB_PTR = 0x%08X\n"
+               "  CH2_OUT_IMAGE_SIZE = 0x%08X\n"
+               "  CNTL = 0x%08X\n",
+               readl(pcdev->base_emma + PRP_SOURCE_Y_PTR),
+               readl(pcdev->base_emma + PRP_SRC_FRAME_SIZE),
+               readl(pcdev->base_emma + PRP_DEST_Y_PTR),
+               readl(pcdev->base_emma + PRP_DEST_CR_PTR),
+               readl(pcdev->base_emma + PRP_DEST_CB_PTR),
+               readl(pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE),
+               readl(pcdev->base_emma + PRP_CNTL));
+}
+
+static void emmaprp_device_run(void *priv)
+{
+       struct emmaprp_ctx *ctx = priv;
+       struct emmaprp_q_data *s_q_data, *d_q_data;
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct emmaprp_dev *pcdev = ctx->dev;
+       unsigned int s_width, s_height;
+       unsigned int d_width, d_height;
+       unsigned int d_size;
+       dma_addr_t p_in, p_out;
+       u32 tmp;
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+       s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       s_width = s_q_data->width;
+       s_height = s_q_data->height;
+
+       d_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       d_width = d_q_data->width;
+       d_height = d_q_data->height;
+       d_size = d_width * d_height;
+
+       p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+       p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+       if (!p_in || !p_out) {
+               v4l2_err(&pcdev->v4l2_dev,
+                        "Acquiring kernel pointers to buffers failed\n");
+               return;
+       }
+
+       /* Input frame parameters */
+       writel(p_in, pcdev->base_emma + PRP_SOURCE_Y_PTR);
+       writel(PRP_SIZE_WIDTH(s_width) | PRP_SIZE_HEIGHT(s_height),
+              pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+
+       /* Output frame parameters */
+       writel(p_out, pcdev->base_emma + PRP_DEST_Y_PTR);
+       writel(p_out + d_size, pcdev->base_emma + PRP_DEST_CB_PTR);
+       writel(p_out + d_size + (d_size >> 2),
+              pcdev->base_emma + PRP_DEST_CR_PTR);
+       writel(PRP_SIZE_WIDTH(d_width) | PRP_SIZE_HEIGHT(d_height),
+              pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
+
+       /* IRQ configuration */
+       tmp = readl(pcdev->base_emma + PRP_INTR_CNTL);
+       writel(tmp | PRP_INTR_RDERR |
+               PRP_INTR_CH2WERR |
+               PRP_INTR_CH2FC,
+               pcdev->base_emma + PRP_INTR_CNTL);
+
+       emmaprp_dump_regs(pcdev);
+
+       /* Enable transfer */
+       tmp = readl(pcdev->base_emma + PRP_CNTL);
+       writel(tmp | PRP_CNTL_CH2_OUT_YUV420 |
+               PRP_CNTL_DATA_IN_YUV422 |
+               PRP_CNTL_CH2EN,
+               pcdev->base_emma + PRP_CNTL);
+}
+
+static irqreturn_t emmaprp_irq(int irq_emma, void *data)
+{
+       struct emmaprp_dev *pcdev = data;
+       struct emmaprp_ctx *curr_ctx;
+       struct vb2_buffer *src_vb, *dst_vb;
+       unsigned long flags;
+       u32 irqst;
+
+       /* Check irq flags and clear irq */
+       irqst = readl(pcdev->base_emma + PRP_INTRSTATUS);
+       writel(irqst, pcdev->base_emma + PRP_INTRSTATUS);
+       dprintk(pcdev, "irqst = 0x%08x\n", irqst);
+
+       curr_ctx = v4l2_m2m_get_curr_priv(pcdev->m2m_dev);
+       if (curr_ctx == NULL) {
+               pr_err("Instance released before the end of transaction\n");
+               return IRQ_HANDLED;
+       }
+
+       if (!curr_ctx->aborting) {
+               if ((irqst & PRP_INTR_ST_RDERR) ||
+               (irqst & PRP_INTR_ST_CH2WERR)) {
+                       pr_err("PrP bus error ocurred, this transfer is probably corrupted\n");
+                       writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
+               } else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */
+                       src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+                       dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+                       spin_lock_irqsave(&pcdev->irqlock, flags);
+                       v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+                       v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+                       spin_unlock_irqrestore(&pcdev->irqlock, flags);
+               }
+       }
+
+       v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
+       return IRQ_HANDLED;
+}
+
+/*
+ * video ioctls
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
+       strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+                         | V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+       int i, num;
+       struct emmaprp_fmt *fmt;
+
+       num = 0;
+
+       for (i = 0; i < NUM_FORMATS; ++i) {
+               if (formats[i].types & type) {
+                       /* index-th format of type type found ? */
+                       if (num == f->index)
+                               break;
+                       /* Correct type but haven't reached our index yet,
+                        * just increment per-type index */
+                       ++num;
+               }
+       }
+
+       if (i < NUM_FORMATS) {
+               /* Format found */
+               fmt = &formats[i];
+               strlcpy(f->description, fmt->name, sizeof(f->description) - 1);
+               f->pixelformat = fmt->fourcc;
+               return 0;
+       }
+
+       /* Format not found */
+       return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       return enum_fmt(f, MEM2MEM_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       return enum_fmt(f, MEM2MEM_OUTPUT);
+}
+
+static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
+{
+       struct vb2_queue *vq;
+       struct emmaprp_q_data *q_data;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = get_q_data(ctx, f->type);
+
+       f->fmt.pix.width        = q_data->width;
+       f->fmt.pix.height       = q_data->height;
+       f->fmt.pix.field        = V4L2_FIELD_NONE;
+       f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+               f->fmt.pix.bytesperline = q_data->width * 3 / 2;
+       else /* YUYV */
+               f->fmt.pix.bytesperline = q_data->width * 2;
+       f->fmt.pix.sizeimage    = q_data->sizeimage;
+
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f)
+{
+       enum v4l2_field field;
+
+
+       if (!find_format(f))
+               return -EINVAL;
+
+       field = f->fmt.pix.field;
+       if (field == V4L2_FIELD_ANY)
+               field = V4L2_FIELD_NONE;
+       else if (V4L2_FIELD_NONE != field)
+               return -EINVAL;
+
+       /* V4L2 specification suggests the driver corrects the format struct
+        * if any of the dimensions is unsupported */
+       f->fmt.pix.field = field;
+
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
+               v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+                                     W_ALIGN_YUV420, &f->fmt.pix.height,
+                                     MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+               f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+       } else {
+               v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+                                     W_ALIGN_OTHERS, &f->fmt.pix.height,
+                                     MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+               f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+       }
+       f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct emmaprp_fmt *fmt;
+       struct emmaprp_ctx *ctx = priv;
+
+       fmt = find_format(f);
+       if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "Fourcc format (0x%08x) invalid.\n",
+                        f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
+
+       return vidioc_try_fmt(f);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct emmaprp_fmt *fmt;
+       struct emmaprp_ctx *ctx = priv;
+
+       fmt = find_format(f);
+       if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "Fourcc format (0x%08x) invalid.\n",
+                        f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
+
+       return vidioc_try_fmt(f);
+}
+
+static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
+{
+       struct emmaprp_q_data *q_data;
+       struct vb2_queue *vq;
+       int ret;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = get_q_data(ctx, f->type);
+       if (!q_data)
+               return -EINVAL;
+
+       if (vb2_is_busy(vq)) {
+               v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+               return -EBUSY;
+       }
+
+       ret = vidioc_try_fmt(f);
+       if (ret)
+               return ret;
+
+       q_data->fmt             = find_format(f);
+       q_data->width           = f->fmt.pix.width;
+       q_data->height          = f->fmt.pix.height;
+       if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
+               q_data->sizeimage = q_data->width * q_data->height * 3 / 2;
+       else /* YUYV */
+               q_data->sizeimage = q_data->width * q_data->height * 2;
+
+       dprintk(ctx->dev,
+               "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+               f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       int ret;
+
+       ret = vidioc_try_fmt_vid_cap(file, priv, f);
+       if (ret)
+               return ret;
+
+       return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       int ret;
+
+       ret = vidioc_try_fmt_vid_out(file, priv, f);
+       if (ret)
+               return ret;
+
+       return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *reqbufs)
+{
+       struct emmaprp_ctx *ctx = priv;
+
+       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *buf)
+{
+       struct emmaprp_ctx *ctx = priv;
+
+       return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct emmaprp_ctx *ctx = priv;
+
+       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct emmaprp_ctx *ctx = priv;
+
+       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type type)
+{
+       struct emmaprp_ctx *ctx = priv;
+
+       return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type type)
+{
+       struct emmaprp_ctx *ctx = priv;
+
+       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
+       .vidioc_querycap        = vidioc_querycap,
+
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .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_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+       .vidioc_g_fmt_vid_out   = vidioc_g_fmt_vid_out,
+       .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
+       .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
+
+       .vidioc_reqbufs         = vidioc_reqbufs,
+       .vidioc_querybuf        = vidioc_querybuf,
+
+       .vidioc_qbuf            = vidioc_qbuf,
+       .vidioc_dqbuf           = vidioc_dqbuf,
+
+       .vidioc_streamon        = vidioc_streamon,
+       .vidioc_streamoff       = vidioc_streamoff,
+};
+
+
+/*
+ * Queue operations
+ */
+static int emmaprp_queue_setup(struct vb2_queue *vq,
+                               const struct v4l2_format *fmt,
+                               unsigned int *nbuffers, unsigned int *nplanes,
+                               unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct emmaprp_ctx *ctx = vb2_get_drv_priv(vq);
+       struct emmaprp_q_data *q_data;
+       unsigned int size, count = *nbuffers;
+
+       q_data = get_q_data(ctx, vq->type);
+
+       if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
+               size = q_data->width * q_data->height * 3 / 2;
+       else
+               size = q_data->width * q_data->height * 2;
+
+       while (size * count > MEM2MEM_VID_MEM_LIMIT)
+               (count)--;
+
+       *nplanes = 1;
+       *nbuffers = count;
+       sizes[0] = size;
+
+       alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+       dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
+
+       return 0;
+}
+
+static int emmaprp_buf_prepare(struct vb2_buffer *vb)
+{
+       struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct emmaprp_q_data *q_data;
+
+       dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
+
+       q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+       if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+               dprintk(ctx->dev, "%s data will not fit into plane"
+                                 "(%lu < %lu)\n", __func__,
+                                 vb2_plane_size(vb, 0),
+                                 (long)q_data->sizeimage);
+               return -EINVAL;
+       }
+
+       vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+       return 0;
+}
+
+static void emmaprp_buf_queue(struct vb2_buffer *vb)
+{
+       struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static struct vb2_ops emmaprp_qops = {
+       .queue_setup     = emmaprp_queue_setup,
+       .buf_prepare     = emmaprp_buf_prepare,
+       .buf_queue       = emmaprp_buf_queue,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+                     struct vb2_queue *dst_vq)
+{
+       struct emmaprp_ctx *ctx = priv;
+       int ret;
+
+       memset(src_vq, 0, sizeof(*src_vq));
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       src_vq->io_modes = VB2_MMAP;
+       src_vq->drv_priv = ctx;
+       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       src_vq->ops = &emmaprp_qops;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+
+       ret = vb2_queue_init(src_vq);
+       if (ret)
+               return ret;
+
+       memset(dst_vq, 0, sizeof(*dst_vq));
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dst_vq->io_modes = VB2_MMAP;
+       dst_vq->drv_priv = ctx;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->ops = &emmaprp_qops;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+       return vb2_queue_init(dst_vq);
+}
+
+/*
+ * File operations
+ */
+static int emmaprp_open(struct file *file)
+{
+       struct emmaprp_dev *pcdev = video_drvdata(file);
+       struct emmaprp_ctx *ctx;
+
+       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       file->private_data = ctx;
+       ctx->dev = pcdev;
+
+       ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
+
+       if (IS_ERR(ctx->m2m_ctx)) {
+               int ret = PTR_ERR(ctx->m2m_ctx);
+
+               kfree(ctx);
+               return ret;
+       }
+
+       clk_enable(pcdev->clk_emma);
+       ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1];
+       ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
+
+       dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+
+       return 0;
+}
+
+static int emmaprp_release(struct file *file)
+{
+       struct emmaprp_dev *pcdev = video_drvdata(file);
+       struct emmaprp_ctx *ctx = file->private_data;
+
+       dprintk(pcdev, "Releasing instance %p\n", ctx);
+
+       clk_disable(pcdev->clk_emma);
+       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       kfree(ctx);
+
+       return 0;
+}
+
+static unsigned int emmaprp_poll(struct file *file,
+                                struct poll_table_struct *wait)
+{
+       struct emmaprp_ctx *ctx = file->private_data;
+
+       return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct emmaprp_ctx *ctx = file->private_data;
+
+       return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations emmaprp_fops = {
+       .owner          = THIS_MODULE,
+       .open           = emmaprp_open,
+       .release        = emmaprp_release,
+       .poll           = emmaprp_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = emmaprp_mmap,
+};
+
+static struct video_device emmaprp_videodev = {
+       .name           = MEM2MEM_NAME,
+       .fops           = &emmaprp_fops,
+       .ioctl_ops      = &emmaprp_ioctl_ops,
+       .minor          = -1,
+       .release        = video_device_release,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+       .device_run     = emmaprp_device_run,
+       .job_abort      = emmaprp_job_abort,
+       .lock           = emmaprp_lock,
+       .unlock         = emmaprp_unlock,
+};
+
+static int emmaprp_probe(struct platform_device *pdev)
+{
+       struct emmaprp_dev *pcdev;
+       struct video_device *vfd;
+       struct resource *res_emma;
+       int irq_emma;
+       int ret;
+
+       pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL);
+       if (!pcdev)
+               return -ENOMEM;
+
+       spin_lock_init(&pcdev->irqlock);
+
+       pcdev->clk_emma = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pcdev->clk_emma)) {
+               ret = PTR_ERR(pcdev->clk_emma);
+               goto free_dev;
+       }
+
+       irq_emma = platform_get_irq(pdev, 0);
+       res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (irq_emma < 0 || res_emma == NULL) {
+               dev_err(&pdev->dev, "Missing platform resources data\n");
+               ret = -ENODEV;
+               goto free_clk;
+       }
+
+       ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
+       if (ret)
+               goto free_clk;
+
+       mutex_init(&pcdev->dev_mutex);
+
+       vfd = video_device_alloc();
+       if (!vfd) {
+               v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n");
+               ret = -ENOMEM;
+               goto unreg_dev;
+       }
+
+       *vfd = emmaprp_videodev;
+       vfd->lock = &pcdev->dev_mutex;
+
+       video_set_drvdata(vfd, pcdev);
+       snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name);
+       pcdev->vfd = vfd;
+       v4l2_info(&pcdev->v4l2_dev, EMMAPRP_MODULE_NAME
+                       " Device registered as /dev/video%d\n", vfd->num);
+
+       platform_set_drvdata(pdev, pcdev);
+
+       if (devm_request_mem_region(&pdev->dev, res_emma->start,
+           resource_size(res_emma), MEM2MEM_NAME) == NULL)
+               goto rel_vdev;
+
+       pcdev->base_emma = devm_ioremap(&pdev->dev, res_emma->start,
+                                       resource_size(res_emma));
+       if (!pcdev->base_emma)
+               goto rel_vdev;
+
+       pcdev->irq_emma = irq_emma;
+       pcdev->res_emma = res_emma;
+
+       if (devm_request_irq(&pdev->dev, pcdev->irq_emma, emmaprp_irq,
+                            0, MEM2MEM_NAME, pcdev) < 0)
+               goto rel_vdev;
+
+       pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(pcdev->alloc_ctx)) {
+               v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n");
+               ret = PTR_ERR(pcdev->alloc_ctx);
+               goto rel_vdev;
+       }
+
+       pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops);
+       if (IS_ERR(pcdev->m2m_dev)) {
+               v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n");
+               ret = PTR_ERR(pcdev->m2m_dev);
+               goto rel_ctx;
+       }
+
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       if (ret) {
+               v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
+               goto rel_m2m;
+       }
+
+       return 0;
+
+
+rel_m2m:
+       v4l2_m2m_release(pcdev->m2m_dev);
+rel_ctx:
+       vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+rel_vdev:
+       video_device_release(vfd);
+unreg_dev:
+       v4l2_device_unregister(&pcdev->v4l2_dev);
+free_clk:
+       clk_put(pcdev->clk_emma);
+free_dev:
+       kfree(pcdev);
+
+       return ret;
+}
+
+static int emmaprp_remove(struct platform_device *pdev)
+{
+       struct emmaprp_dev *pcdev = platform_get_drvdata(pdev);
+
+       v4l2_info(&pcdev->v4l2_dev, "Removing " EMMAPRP_MODULE_NAME);
+
+       video_unregister_device(pcdev->vfd);
+       v4l2_m2m_release(pcdev->m2m_dev);
+       vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+       v4l2_device_unregister(&pcdev->v4l2_dev);
+       clk_put(pcdev->clk_emma);
+       kfree(pcdev);
+
+       return 0;
+}
+
+static struct platform_driver emmaprp_pdrv = {
+       .probe          = emmaprp_probe,
+       .remove         = emmaprp_remove,
+       .driver         = {
+               .name   = MEM2MEM_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static void __exit emmaprp_exit(void)
+{
+       platform_driver_unregister(&emmaprp_pdrv);
+}
+
+static int __init emmaprp_init(void)
+{
+       return platform_driver_register(&emmaprp_pdrv);
+}
+
+module_init(emmaprp_init);
+module_exit(emmaprp_exit);
index 50838bf..440c129 100644 (file)
@@ -725,8 +725,8 @@ static int noon010_probe(struct i2c_client *client,
 
        mutex_init(&info->lock);
        sd = &info->sd;
-       strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
        v4l2_i2c_subdev_init(sd, client, &noon010_ops);
+       strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
 
        sd->internal_ops = &noon010_subdev_internal_ops;
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -844,18 +844,7 @@ static struct i2c_driver noon010_i2c_driver = {
        .id_table       = noon010_id,
 };
 
-static int __init noon010_init(void)
-{
-       return i2c_add_driver(&noon010_i2c_driver);
-}
-
-static void __exit noon010_exit(void)
-{
-       i2c_del_driver(&noon010_i2c_driver);
-}
-
-module_init(noon010_init);
-module_exit(noon010_exit);
+module_i2c_driver(noon010_i2c_driver);
 
 MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
index 1fb7d5b..88cf9d9 100644 (file)
@@ -2268,13 +2268,12 @@ static struct platform_driver omap_vout_driver = {
        .driver = {
                .name = VOUT_NAME,
        },
-       .probe = omap_vout_probe,
        .remove = omap_vout_remove,
 };
 
 static int __init omap_vout_init(void)
 {
-       if (platform_driver_register(&omap_vout_driver) != 0) {
+       if (platform_driver_probe(&omap_vout_driver, omap_vout_probe) != 0) {
                printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n");
                return -EINVAL;
        }
index b5247cb..3c2c5d3 100644 (file)
@@ -1103,21 +1103,7 @@ static struct i2c_driver ov2640_i2c_driver = {
        .id_table = ov2640_id,
 };
 
-/*
- * Module functions
- */
-static int __init ov2640_module_init(void)
-{
-       return i2c_add_driver(&ov2640_i2c_driver);
-}
-
-static void __exit ov2640_module_exit(void)
-{
-       i2c_del_driver(&ov2640_i2c_driver);
-}
-
-module_init(ov2640_module_init);
-module_exit(ov2640_module_exit);
+module_i2c_driver(ov2640_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor");
 MODULE_AUTHOR("Alberto Panizzo");
index bb37ec8..80e0779 100644 (file)
@@ -1068,18 +1068,7 @@ static struct i2c_driver ov5642_i2c_driver = {
        .id_table       = ov5642_id,
 };
 
-static int __init ov5642_mod_init(void)
-{
-       return i2c_add_driver(&ov5642_i2c_driver);
-}
-
-static void __exit ov5642_mod_exit(void)
-{
-       i2c_del_driver(&ov5642_i2c_driver);
-}
-
-module_init(ov5642_mod_init);
-module_exit(ov5642_mod_exit);
+module_i2c_driver(ov5642_i2c_driver);
 
 MODULE_DESCRIPTION("Omnivision OV5642 Camera driver");
 MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
index 3627f32..3e028b1 100644 (file)
@@ -1046,18 +1046,7 @@ static struct i2c_driver ov6650_i2c_driver = {
        .id_table = ov6650_id,
 };
 
-static int __init ov6650_module_init(void)
-{
-       return i2c_add_driver(&ov6650_i2c_driver);
-}
-
-static void __exit ov6650_module_exit(void)
-{
-       i2c_del_driver(&ov6650_i2c_driver);
-}
-
-module_init(ov6650_module_init);
-module_exit(ov6650_module_exit);
+module_i2c_driver(ov6650_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
 MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
index 6a56496..e7c82b2 100644 (file)
@@ -1583,15 +1583,4 @@ static struct i2c_driver ov7670_driver = {
        .id_table       = ov7670_id,
 };
 
-static __init int init_ov7670(void)
-{
-       return i2c_add_driver(&ov7670_driver);
-}
-
-static __exit void exit_ov7670(void)
-{
-       i2c_del_driver(&ov7670_driver);
-}
-
-module_init(init_ov7670);
-module_exit(exit_ov7670);
+module_i2c_driver(ov7670_driver);
index 9f6ce3d..74e77d3 100644 (file)
@@ -1123,22 +1123,7 @@ static struct i2c_driver ov772x_i2c_driver = {
        .id_table = ov772x_id,
 };
 
-/*
- * module function
- */
-
-static int __init ov772x_module_init(void)
-{
-       return i2c_add_driver(&ov772x_i2c_driver);
-}
-
-static void __exit ov772x_module_exit(void)
-{
-       i2c_del_driver(&ov772x_i2c_driver);
-}
-
-module_init(ov772x_module_init);
-module_exit(ov772x_module_exit);
+module_i2c_driver(ov772x_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for ov772x");
 MODULE_AUTHOR("Kuninori Morimoto");
index a4f9979..23412de 100644 (file)
@@ -738,18 +738,7 @@ static struct i2c_driver ov9640_i2c_driver = {
        .id_table = ov9640_id,
 };
 
-static int __init ov9640_module_init(void)
-{
-       return i2c_add_driver(&ov9640_i2c_driver);
-}
-
-static void __exit ov9640_module_exit(void)
-{
-       i2c_del_driver(&ov9640_i2c_driver);
-}
-
-module_init(ov9640_module_init);
-module_exit(ov9640_module_exit);
+module_i2c_driver(ov9640_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx");
 MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
index d9a9f71..3eb07c2 100644 (file)
@@ -998,18 +998,7 @@ static struct i2c_driver ov9740_i2c_driver = {
        .id_table = ov9740_id,
 };
 
-static int __init ov9740_module_init(void)
-{
-       return i2c_add_driver(&ov9740_i2c_driver);
-}
-
-static void __exit ov9740_module_exit(void)
-{
-       i2c_del_driver(&ov9740_i2c_driver);
-}
-
-module_init(ov9740_module_init);
-module_exit(ov9740_module_exit);
+module_i2c_driver(ov9740_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740");
 MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
index c6da8f7..d8c8982 100644 (file)
@@ -320,7 +320,17 @@ static struct tda829x_config tda829x_no_probe = {
        .probe_tuner = TDA829X_DONT_PROBE,
 };
 
+static struct tda18271_std_map hauppauge_tda18271_dvbt_std_map = {
+        .dvbt_6   = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+                      .if_lvl = 1, .rfagc_top = 0x37, },
+        .dvbt_7   = { .if_freq = 3800, .agc_mode = 3, .std = 5,
+                      .if_lvl = 1, .rfagc_top = 0x37, },
+        .dvbt_8   = { .if_freq = 4300, .agc_mode = 3, .std = 6,
+                      .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
 static struct tda18271_config hauppauge_tda18271_dvb_config = {
+       .std_map = &hauppauge_tda18271_dvbt_std_map,
        .gate    = TDA18271_GATE_ANALOG,
        .output_opt = TDA18271_OUTPUT_LT_OFF,
 };
index 6d66617..e1111d9 100644 (file)
@@ -96,7 +96,6 @@ static struct v4l2_capability pvr_capability ={
        .capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
                           V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
                           V4L2_CAP_READWRITE),
-       .reserved       = {0,0,0,0}
 };
 
 static struct v4l2_fmtdesc pvr_fmtdesc [] = {
index f495eeb..2834e3e 100644 (file)
@@ -1146,14 +1146,6 @@ leave:
        return ret;
 }
 
-static int pwc_log_status(struct file *file, void *priv)
-{
-       struct pwc_device *pdev = video_drvdata(file);
-
-       v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME);
-       return 0;
-}
-
 const struct v4l2_ioctl_ops pwc_ioctl_ops = {
        .vidioc_querycap                    = pwc_querycap,
        .vidioc_enum_input                  = pwc_enum_input,
@@ -1169,7 +1161,7 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = {
        .vidioc_dqbuf                       = pwc_dqbuf,
        .vidioc_streamon                    = pwc_streamon,
        .vidioc_streamoff                   = pwc_streamoff,
-       .vidioc_log_status                  = pwc_log_status,
+       .vidioc_log_status                  = v4l2_ctrl_log_status,
        .vidioc_enum_framesizes             = pwc_enum_framesizes,
        .vidioc_enum_frameintervals         = pwc_enum_frameintervals,
        .vidioc_g_parm                      = pwc_g_parm,
index 0bd7da2..5a413f4 100644 (file)
@@ -921,12 +921,12 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
                /* "Safe default" - 13MHz */
                recalculate_fifo_timeout(pcdev, 13000000);
 
-       clk_enable(pcdev->clk);
+       clk_prepare_enable(pcdev->clk);
 }
 
 static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
 {
-       clk_disable(pcdev->clk);
+       clk_disable_unprepare(pcdev->clk);
 }
 
 static irqreturn_t pxa_camera_irq(int irq, void *data)
index 9937386..f6419b2 100644 (file)
@@ -1407,18 +1407,7 @@ static struct i2c_driver rj54n1_i2c_driver = {
        .id_table       = rj54n1_id,
 };
 
-static int __init rj54n1_mod_init(void)
-{
-       return i2c_add_driver(&rj54n1_i2c_driver);
-}
-
-static void __exit rj54n1_mod_exit(void)
-{
-       i2c_del_driver(&rj54n1_i2c_driver);
-}
-
-module_init(rj54n1_mod_init);
-module_exit(rj54n1_mod_exit);
+module_i2c_driver(rj54n1_i2c_driver);
 
 MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
index c1bef61..4894cbb 100644 (file)
 
 /* usb config commands */
 #define IN_DATA_TOKEN  cpu_to_le32(0x2255c0de)
-#define CMD_2255       cpu_to_le32(0xc2255000)
+#define CMD_2255       0xc2255000
 #define CMD_SET_MODE   cpu_to_le32((CMD_2255 | 0x10))
 #define CMD_START      cpu_to_le32((CMD_2255 | 0x20))
 #define CMD_STOP       cpu_to_le32((CMD_2255 | 0x30))
@@ -852,15 +852,13 @@ static int vidioc_querycap(struct file *file, void *priv,
 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
                               struct v4l2_fmtdesc *f)
 {
-       int index = 0;
-       if (f)
-               index = f->index;
+       int index = f->index;
 
        if (index >= ARRAY_SIZE(formats))
                return -EINVAL;
-    if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
-                        (formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
-       return -EINVAL;
+       if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
+                       (formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
+               return -EINVAL;
        dprintk(4, "name %s\n", formats[index].name);
        strlcpy(f->description, formats[index].name, sizeof(f->description));
        f->pixelformat = formats[index].fourcc;
@@ -2027,7 +2025,7 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                                        pdata[1]);
                                offset = jj + PREFIX_SIZE;
                                bframe = 1;
-                               cc = pdword[1];
+                               cc = le32_to_cpu(pdword[1]);
                                if (cc >= MAX_CHANNELS) {
                                        printk(KERN_ERR
                                               "bad channel\n");
@@ -2036,22 +2034,22 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                                /* reverse it */
                                dev->cc = G_chnmap[cc];
                                channel = &dev->channel[dev->cc];
-                               payload =  pdword[3];
+                               payload =  le32_to_cpu(pdword[3]);
                                if (payload > channel->req_image_size) {
                                        channel->bad_payload++;
                                        /* discard the bad frame */
                                        return -EINVAL;
                                }
                                channel->pkt_size = payload;
-                               channel->jpg_size = pdword[4];
+                               channel->jpg_size = le32_to_cpu(pdword[4]);
                                break;
                        case S2255_MARKER_RESPONSE:
 
                                pdata += DEF_USB_BLOCK;
                                jj += DEF_USB_BLOCK;
-                               if (pdword[1] >= MAX_CHANNELS)
+                               if (le32_to_cpu(pdword[1]) >= MAX_CHANNELS)
                                        break;
-                               cc = G_chnmap[pdword[1]];
+                               cc = G_chnmap[le32_to_cpu(pdword[1])];
                                if (cc >= MAX_CHANNELS)
                                        break;
                                channel = &dev->channel[cc];
@@ -2074,11 +2072,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                                        wake_up(&dev->fw_data->wait_fw);
                                        break;
                                case S2255_RESPONSE_STATUS:
-                                       channel->vidstatus = pdword[3];
+                                       channel->vidstatus = le32_to_cpu(pdword[3]);
                                        channel->vidstatus_ready = 1;
                                        wake_up(&channel->wait_vidstatus);
                                        dprintk(5, "got vidstatus %x chan %d\n",
-                                               pdword[3], cc);
+                                               le32_to_cpu(pdword[3]), cc);
                                        break;
                                default:
                                        printk(KERN_INFO "s2255 unknown resp\n");
@@ -2605,10 +2603,11 @@ static int s2255_probe(struct usb_interface *interface,
                __le32 *pRel;
                pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
                printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel);
-               dev->dsp_fw_ver = *pRel;
-               if (*pRel < S2255_CUR_DSP_FWVER)
+               dev->dsp_fw_ver = le32_to_cpu(*pRel);
+               if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER)
                        printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
-               if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER)
+               if (dev->pid == 0x2257 &&
+                               dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
                        printk(KERN_WARNING "s2255: 2257 requires firmware %d"
                               " or above.\n", S2255_MIN_DSP_COLORFILTER);
        }
index 0df7f2a..6625e46 100644 (file)
@@ -1582,8 +1582,8 @@ static int s5k6aa_probe(struct i2c_client *client,
        s5k6aa->inv_vflip = pdata->vert_flip;
 
        sd = &s5k6aa->sd;
-       strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
        v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops);
+       strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
 
        sd->internal_ops = &s5k6aa_subdev_internal_ops;
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -1663,18 +1663,7 @@ static struct i2c_driver s5k6aa_i2c_driver = {
        .id_table       = s5k6aa_id,
 };
 
-static int __init s5k6aa_init(void)
-{
-       return i2c_add_driver(&s5k6aa_i2c_driver);
-}
-
-static void __exit s5k6aa_exit(void)
-{
-       i2c_del_driver(&s5k6aa_i2c_driver);
-}
-
-module_init(s5k6aa_init);
-module_exit(s5k6aa_exit);
+module_i2c_driver(s5k6aa_i2c_driver);
 
 MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
index a9e9653..b06efd2 100644 (file)
@@ -1019,52 +1019,117 @@ static int fimc_cap_dqbuf(struct file *file, void *priv,
        return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK);
 }
 
-static int fimc_cap_cropcap(struct file *file, void *fh,
-                           struct v4l2_cropcap *cr)
+static int fimc_cap_create_bufs(struct file *file, void *priv,
+                               struct v4l2_create_buffers *create)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
 
-       if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-               return -EINVAL;
+       return vb2_create_bufs(&fimc->vid_cap.vbq, create);
+}
 
-       cr->bounds.left         = 0;
-       cr->bounds.top          = 0;
-       cr->bounds.width        = f->o_width;
-       cr->bounds.height       = f->o_height;
-       cr->defrect             = cr->bounds;
+static int fimc_cap_prepare_buf(struct file *file, void *priv,
+                               struct v4l2_buffer *b)
+{
+       struct fimc_dev *fimc = video_drvdata(file);
 
-       return 0;
+       return vb2_prepare_buf(&fimc->vid_cap.vbq, b);
 }
 
-static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+static int fimc_cap_g_selection(struct file *file, void *fh,
+                               struct v4l2_selection *s)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
+       struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+       struct fimc_frame *f = &ctx->s_frame;
 
-       cr->c.left      = f->offs_h;
-       cr->c.top       = f->offs_v;
-       cr->c.width     = f->width;
-       cr->c.height    = f->height;
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return -EINVAL;
 
-       return 0;
+       switch (s->target) {
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               f = &ctx->d_frame;
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = f->o_width;
+               s->r.height = f->o_height;
+               return 0;
+
+       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+               f = &ctx->d_frame;
+       case V4L2_SEL_TGT_CROP_ACTIVE:
+               s->r.left = f->offs_h;
+               s->r.top = f->offs_v;
+               s->r.width = f->width;
+               s->r.height = f->height;
+               return 0;
+       }
+
+       return -EINVAL;
 }
 
-static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
+int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+       if (a->left < b->left || a->top < b->top)
+               return 0;
+       if (a->left + a->width > b->left + b->width)
+               return 0;
+       if (a->top + a->height > b->top + b->height)
+               return 0;
+
+       return 1;
+}
+
+static int fimc_cap_s_selection(struct file *file, void *fh,
+                               struct v4l2_selection *s)
 {
        struct fimc_dev *fimc = video_drvdata(file);
        struct fimc_ctx *ctx = fimc->vid_cap.ctx;
-       struct fimc_frame *ff;
+       struct v4l2_rect rect = s->r;
+       struct fimc_frame *f;
        unsigned long flags;
+       unsigned int pad;
 
-       fimc_capture_try_crop(ctx, &cr->c, FIMC_SD_PAD_SINK);
-       ff = &ctx->s_frame;
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return -EINVAL;
 
+       switch (s->target) {
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+               f = &ctx->d_frame;
+               pad = FIMC_SD_PAD_SOURCE;
+               break;
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP_DEFAULT:
+       case V4L2_SEL_TGT_CROP_ACTIVE:
+               f = &ctx->s_frame;
+               pad = FIMC_SD_PAD_SINK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       fimc_capture_try_crop(ctx, &rect, pad);
+
+       if (s->flags & V4L2_SEL_FLAG_LE &&
+           !enclosed_rectangle(&rect, &s->r))
+               return -ERANGE;
+
+       if (s->flags & V4L2_SEL_FLAG_GE &&
+           !enclosed_rectangle(&s->r, &rect))
+               return -ERANGE;
+
+       s->r = rect;
        spin_lock_irqsave(&fimc->slock, flags);
-       set_frame_crop(ff, cr->c.left, cr->c.top, cr->c.width, cr->c.height);
-       set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+       set_frame_crop(f, s->r.left, s->r.top, s->r.width,
+                      s->r.height);
        spin_unlock_irqrestore(&fimc->slock, flags);
 
+       set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
        return 0;
 }
 
@@ -1082,12 +1147,14 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
        .vidioc_qbuf                    = fimc_cap_qbuf,
        .vidioc_dqbuf                   = fimc_cap_dqbuf,
 
+       .vidioc_prepare_buf             = fimc_cap_prepare_buf,
+       .vidioc_create_bufs             = fimc_cap_create_bufs,
+
        .vidioc_streamon                = fimc_cap_streamon,
        .vidioc_streamoff               = fimc_cap_streamoff,
 
-       .vidioc_g_crop                  = fimc_cap_g_crop,
-       .vidioc_s_crop                  = fimc_cap_s_crop,
-       .vidioc_cropcap                 = fimc_cap_cropcap,
+       .vidioc_g_selection             = fimc_cap_g_selection,
+       .vidioc_s_selection             = fimc_cap_s_selection,
 
        .vidioc_enum_input              = fimc_cap_enum_input,
        .vidioc_s_input                 = fimc_cap_s_input,
index 81bcbb9..e184e65 100644 (file)
@@ -1602,24 +1602,35 @@ static void fimc_clk_put(struct fimc_dev *fimc)
 {
        int i;
        for (i = 0; i < fimc->num_clocks; i++) {
-               if (fimc->clock[i])
-                       clk_put(fimc->clock[i]);
+               if (IS_ERR_OR_NULL(fimc->clock[i]))
+                       continue;
+               clk_unprepare(fimc->clock[i]);
+               clk_put(fimc->clock[i]);
+               fimc->clock[i] = NULL;
        }
 }
 
 static int fimc_clk_get(struct fimc_dev *fimc)
 {
-       int i;
+       int i, ret;
+
        for (i = 0; i < fimc->num_clocks; i++) {
                fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
-               if (!IS_ERR_OR_NULL(fimc->clock[i]))
-                       continue;
-               dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n",
-                       fimc_clocks[i]);
-               return -ENXIO;
+               if (IS_ERR(fimc->clock[i]))
+                       goto err;
+               ret = clk_prepare(fimc->clock[i]);
+               if (ret < 0) {
+                       clk_put(fimc->clock[i]);
+                       fimc->clock[i] = NULL;
+                       goto err;
+               }
        }
-
        return 0;
+err:
+       fimc_clk_put(fimc);
+       dev_err(&fimc->pdev->dev, "failed to get clock: %s\n",
+               fimc_clocks[i]);
+       return -ENXIO;
 }
 
 static int fimc_m2m_suspend(struct fimc_dev *fimc)
@@ -1667,8 +1678,6 @@ static int fimc_probe(struct platform_device *pdev)
        struct s5p_platform_fimc *pdata;
        int ret = 0;
 
-       dev_dbg(&pdev->dev, "%s():\n", __func__);
-
        drv_data = (struct samsung_fimc_driverdata *)
                platform_get_device_id(pdev)->driver_data;
 
@@ -1678,7 +1687,7 @@ static int fimc_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       fimc = kzalloc(sizeof(struct fimc_dev), GFP_KERNEL);
+       fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
        if (!fimc)
                return -ENOMEM;
 
@@ -1689,51 +1698,35 @@ static int fimc_probe(struct platform_device *pdev)
        pdata = pdev->dev.platform_data;
        fimc->pdata = pdata;
 
-
        init_waitqueue_head(&fimc->irq_queue);
        spin_lock_init(&fimc->slock);
        mutex_init(&fimc->lock);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to find the registers\n");
-               ret = -ENOENT;
-               goto err_info;
-       }
-
-       fimc->regs_res = request_mem_region(res->start, resource_size(res),
-                       dev_name(&pdev->dev));
-       if (!fimc->regs_res) {
-               dev_err(&pdev->dev, "failed to obtain register region\n");
-               ret = -ENOENT;
-               goto err_info;
-       }
-
-       fimc->regs = ioremap(res->start, resource_size(res));
-       if (!fimc->regs) {
-               dev_err(&pdev->dev, "failed to map registers\n");
-               ret = -ENXIO;
-               goto err_req_region;
+       fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
+       if (fimc->regs == NULL) {
+               dev_err(&pdev->dev, "Failed to obtain io memory\n");
+               return -ENOENT;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to get IRQ resource\n");
-               ret = -ENXIO;
-               goto err_regs_unmap;
+       if (res == NULL) {
+               dev_err(&pdev->dev, "Failed to get IRQ resource\n");
+               return -ENXIO;
        }
        fimc->irq = res->start;
 
        fimc->num_clocks = MAX_FIMC_CLOCKS;
        ret = fimc_clk_get(fimc);
        if (ret)
-               goto err_regs_unmap;
+               return ret;
        clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
        clk_enable(fimc->clock[CLK_BUS]);
 
        platform_set_drvdata(pdev, fimc);
 
-       ret = request_irq(fimc->irq, fimc_irq_handler, 0, pdev->name, fimc);
+       ret = devm_request_irq(&pdev->dev, fimc->irq, fimc_irq_handler,
+                              0, pdev->name, fimc);
        if (ret) {
                dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
                goto err_clk;
@@ -1742,7 +1735,7 @@ static int fimc_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        ret = pm_runtime_get_sync(&pdev->dev);
        if (ret < 0)
-               goto err_irq;
+               goto err_clk;
        /* Initialize contiguous memory allocator */
        fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
        if (IS_ERR(fimc->alloc_ctx)) {
@@ -1757,17 +1750,8 @@ static int fimc_probe(struct platform_device *pdev)
 
 err_pm:
        pm_runtime_put(&pdev->dev);
-err_irq:
-       free_irq(fimc->irq, fimc);
 err_clk:
        fimc_clk_put(fimc);
-err_regs_unmap:
-       iounmap(fimc->regs);
-err_req_region:
-       release_resource(fimc->regs_res);
-       kfree(fimc->regs_res);
-err_info:
-       kfree(fimc);
        return ret;
 }
 
@@ -1854,11 +1838,6 @@ static int __devexit fimc_remove(struct platform_device *pdev)
 
        clk_disable(fimc->clock[CLK_BUS]);
        fimc_clk_put(fimc);
-       free_irq(fimc->irq, fimc);
-       iounmap(fimc->regs);
-       release_resource(fimc->regs_res);
-       kfree(fimc->regs_res);
-       kfree(fimc);
 
        dev_info(&pdev->dev, "driver unloaded\n");
        return 0;
index 4e20560..a18291e 100644 (file)
@@ -434,7 +434,6 @@ struct fimc_ctx;
  * @num_clocks: the number of clocks managed by this device instance
  * @clock:     clocks required for FIMC operation
  * @regs:      the mapped hardware registers
- * @regs_res:  the resource claimed for IO registers
  * @irq:       FIMC interrupt number
  * @irq_queue: interrupt handler waitqueue
  * @v4l2_dev:  root v4l2_device
@@ -454,7 +453,6 @@ struct fimc_dev {
        u16                             num_clocks;
        struct clk                      *clock[MAX_FIMC_CLOCKS];
        void __iomem                    *regs;
-       struct resource                 *regs_res;
        int                             irq;
        wait_queue_head_t               irq_queue;
        struct v4l2_device              *v4l2_dev;
index 63eccb5..62ed37e 100644 (file)
@@ -750,7 +750,7 @@ static int __devinit fimc_md_probe(struct platform_device *pdev)
        struct fimc_md *fmd;
        int ret;
 
-       fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL);
+       fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL);
        if (!fmd)
                return -ENOMEM;
 
@@ -771,7 +771,7 @@ static int __devinit fimc_md_probe(struct platform_device *pdev)
        ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev);
        if (ret < 0) {
                v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
-               goto err1;
+               return ret;
        }
        ret = media_device_register(&fmd->media_dev);
        if (ret < 0) {
@@ -813,8 +813,6 @@ err3:
        fimc_md_unregister_entities(fmd);
 err2:
        v4l2_device_unregister(&fmd->v4l2_dev);
-err1:
-       kfree(fmd);
        return ret;
 }
 
@@ -828,7 +826,6 @@ static int __devexit fimc_md_remove(struct platform_device *pdev)
        fimc_md_unregister_entities(fmd);
        media_device_unregister(&fmd->media_dev);
        fimc_md_put_clocks(fmd);
-       kfree(fmd);
        return 0;
 }
 
index 130335c..f44f690 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
  *
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
- * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki, <s.nawrocki@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
@@ -100,7 +100,6 @@ enum {
  * @pads: CSIS pads array
  * @sd: v4l2_subdev associated with CSIS device instance
  * @pdev: CSIS platform device
- * @regs_res: requested I/O register memory resource
  * @regs: mmaped I/O registers memory
  * @clock: CSIS clocks
  * @irq: requested s5p-mipi-csis irq number
@@ -113,7 +112,6 @@ struct csis_state {
        struct media_pad pads[CSIS_PADS_NUM];
        struct v4l2_subdev sd;
        struct platform_device *pdev;
-       struct resource *regs_res;
        void __iomem *regs;
        struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
        struct clk *clock[NUM_CSIS_CLOCKS];
@@ -258,26 +256,36 @@ static void s5pcsis_clk_put(struct csis_state *state)
 {
        int i;
 
-       for (i = 0; i < NUM_CSIS_CLOCKS; i++)
-               if (!IS_ERR_OR_NULL(state->clock[i]))
-                       clk_put(state->clock[i]);
+       for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
+               if (IS_ERR_OR_NULL(state->clock[i]))
+                       continue;
+               clk_unprepare(state->clock[i]);
+               clk_put(state->clock[i]);
+               state->clock[i] = NULL;
+       }
 }
 
 static int s5pcsis_clk_get(struct csis_state *state)
 {
        struct device *dev = &state->pdev->dev;
-       int i;
+       int i, ret;
 
        for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
                state->clock[i] = clk_get(dev, csi_clock_name[i]);
-               if (IS_ERR(state->clock[i])) {
-                       s5pcsis_clk_put(state);
-                       dev_err(dev, "failed to get clock: %s\n",
-                               csi_clock_name[i]);
-                       return -ENXIO;
+               if (IS_ERR(state->clock[i]))
+                       goto err;
+               ret = clk_prepare(state->clock[i]);
+               if (ret < 0) {
+                       clk_put(state->clock[i]);
+                       state->clock[i] = NULL;
+                       goto err;
                }
        }
        return 0;
+err:
+       s5pcsis_clk_put(state);
+       dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]);
+       return -ENXIO;
 }
 
 static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
@@ -480,12 +488,11 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
 {
        struct s5p_platform_mipi_csis *pdata;
        struct resource *mem_res;
-       struct resource *regs_res;
        struct csis_state *state;
        int ret = -ENOMEM;
        int i;
 
-       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
        if (!state)
                return -ENOMEM;
 
@@ -495,52 +502,27 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
        pdata = pdev->dev.platform_data;
        if (pdata == NULL || pdata->phy_enable == NULL) {
                dev_err(&pdev->dev, "Platform data not fully specified\n");
-               goto e_free;
+               return -EINVAL;
        }
 
        if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
            pdata->lanes > CSIS0_MAX_LANES) {
-               ret = -EINVAL;
                dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
                        pdata->lanes);
-               goto e_free;
+               return -EINVAL;
        }
 
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem_res) {
-               dev_err(&pdev->dev, "Failed to get IO memory region\n");
-               goto e_free;
+       state->regs = devm_request_and_ioremap(&pdev->dev, mem_res);
+       if (state->regs == NULL) {
+               dev_err(&pdev->dev, "Failed to request and remap io memory\n");
+               return -ENXIO;
        }
 
-       regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
-                                     pdev->name);
-       if (!regs_res) {
-               dev_err(&pdev->dev, "Failed to request IO memory region\n");
-               goto e_free;
-       }
-       state->regs_res = regs_res;
-
-       state->regs = ioremap(mem_res->start, resource_size(mem_res));
-       if (!state->regs) {
-               dev_err(&pdev->dev, "Failed to remap IO region\n");
-               goto e_reqmem;
-       }
-
-       ret = s5pcsis_clk_get(state);
-       if (ret)
-               goto e_unmap;
-
-       clk_enable(state->clock[CSIS_CLK_MUX]);
-       if (pdata->clk_rate)
-               clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
-       else
-               dev_WARN(&pdev->dev, "No clock frequency specified!\n");
-
        state->irq = platform_get_irq(pdev, 0);
        if (state->irq < 0) {
-               ret = state->irq;
                dev_err(&pdev->dev, "Failed to get irq\n");
-               goto e_clkput;
+               return state->irq;
        }
 
        for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
@@ -549,12 +531,22 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
        ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
                                 state->supplies);
        if (ret)
+               return ret;
+
+       ret = s5pcsis_clk_get(state);
+       if (ret)
                goto e_clkput;
 
-       ret = request_irq(state->irq, s5pcsis_irq_handler, 0,
-                         dev_name(&pdev->dev), state);
+       clk_enable(state->clock[CSIS_CLK_MUX]);
+       if (pdata->clk_rate)
+               clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
+       else
+               dev_WARN(&pdev->dev, "No clock frequency specified!\n");
+
+       ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler,
+                              0, dev_name(&pdev->dev), state);
        if (ret) {
-               dev_err(&pdev->dev, "request_irq failed\n");
+               dev_err(&pdev->dev, "Interrupt request failed\n");
                goto e_regput;
        }
 
@@ -573,7 +565,7 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
        ret = media_entity_init(&state->sd.entity,
                                CSIS_PADS_NUM, state->pads, 0);
        if (ret < 0)
-               goto e_irqfree;
+               goto e_clkput;
 
        /* This allows to retrieve the platform device id by the host driver */
        v4l2_set_subdevdata(&state->sd, pdev);
@@ -582,22 +574,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, &state->sd);
 
        pm_runtime_enable(&pdev->dev);
-
        return 0;
 
-e_irqfree:
-       free_irq(state->irq, state);
 e_regput:
        regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
 e_clkput:
        clk_disable(state->clock[CSIS_CLK_MUX]);
        s5pcsis_clk_put(state);
-e_unmap:
-       iounmap(state->regs);
-e_reqmem:
-       release_mem_region(regs_res->start, resource_size(regs_res));
-e_free:
-       kfree(state);
        return ret;
 }
 
@@ -699,21 +682,15 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev)
 {
        struct v4l2_subdev *sd = platform_get_drvdata(pdev);
        struct csis_state *state = sd_to_csis_state(sd);
-       struct resource *res = state->regs_res;
 
        pm_runtime_disable(&pdev->dev);
-       s5pcsis_suspend(&pdev->dev);
+       s5pcsis_pm_suspend(&pdev->dev, false);
        clk_disable(state->clock[CSIS_CLK_MUX]);
        pm_runtime_set_suspended(&pdev->dev);
-
        s5pcsis_clk_put(state);
        regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
 
        media_entity_cleanup(&state->sd.entity);
-       free_irq(state->irq, state);
-       iounmap(state->regs);
-       release_mem_region(res->start, resource_size(res));
-       kfree(state);
 
        return 0;
 }
index 39937cf..5b86cbe 100644 (file)
@@ -77,6 +77,11 @@ void g2d_set_rop4(struct g2d_dev *d, u32 r)
        w(r, ROP4_REG);
 }
 
+void g2d_set_flip(struct g2d_dev *d, u32 r)
+{
+       w(r, SRC_MSK_DIRECT_REG);
+}
+
 u32 g2d_cmd_stretch(u32 e)
 {
        e &= 1;
index febaa67..789de74 100644 (file)
@@ -178,6 +178,9 @@ static int g2d_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx,
                                                                ctrl_handler);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->dev->ctrl_lock, flags);
        switch (ctrl->id) {
        case V4L2_CID_COLORFX:
                if (ctrl->val == V4L2_COLORFX_NEGATIVE)
@@ -185,10 +188,13 @@ static int g2d_s_ctrl(struct v4l2_ctrl *ctrl)
                else
                        ctx->rop = ROP4_COPY;
                break;
-       default:
-               v4l2_err(&ctx->dev->v4l2_dev, "unknown control\n");
-               return -EINVAL;
+
+       case V4L2_CID_HFLIP:
+               ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1);
+               break;
+
        }
+       spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags);
        return 0;
 }
 
@@ -200,11 +206,13 @@ int g2d_setup_ctrls(struct g2d_ctx *ctx)
 {
        struct g2d_dev *dev = ctx->dev;
 
-       v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1);
-       if (ctx->ctrl_handler.error) {
-               v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n");
-               return ctx->ctrl_handler.error;
-       }
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+       ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
+                                               V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+       ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
+                                               V4L2_CID_VFLIP, 0, 1, 1, 0);
 
        v4l2_ctrl_new_std_menu(
                &ctx->ctrl_handler,
@@ -215,10 +223,14 @@ int g2d_setup_ctrls(struct g2d_ctx *ctx)
                V4L2_COLORFX_NONE);
 
        if (ctx->ctrl_handler.error) {
-               v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n");
-               return ctx->ctrl_handler.error;
+               int err = ctx->ctrl_handler.error;
+               v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n");
+               v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+               return err;
        }
 
+       v4l2_ctrl_cluster(2, &ctx->ctrl_hflip);
+
        return 0;
 }
 
@@ -547,6 +559,7 @@ static void device_run(void *prv)
        struct g2d_ctx *ctx = prv;
        struct g2d_dev *dev = ctx->dev;
        struct vb2_buffer *src, *dst;
+       unsigned long flags;
        u32 cmd = 0;
 
        dev->curr = ctx;
@@ -557,6 +570,8 @@ static void device_run(void *prv)
        clk_enable(dev->gate);
        g2d_reset(dev);
 
+       spin_lock_irqsave(&dev->ctrl_lock, flags);
+
        g2d_set_src_size(dev, &ctx->in);
        g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0));
 
@@ -564,11 +579,15 @@ static void device_run(void *prv)
        g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0));
 
        g2d_set_rop4(dev, ctx->rop);
+       g2d_set_flip(dev, ctx->flip);
+
        if (ctx->in.c_width != ctx->out.c_width ||
                ctx->in.c_height != ctx->out.c_height)
                cmd |= g2d_cmd_stretch(1);
        g2d_set_cmd(dev, cmd);
        g2d_start(dev);
+
+       spin_unlock_irqrestore(&dev->ctrl_lock, flags);
 }
 
 static irqreturn_t g2d_isr(int irq, void *prv)
@@ -658,7 +677,7 @@ static int g2d_probe(struct platform_device *pdev)
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
-       spin_lock_init(&dev->irqlock);
+       spin_lock_init(&dev->ctrl_lock);
        mutex_init(&dev->mutex);
        atomic_set(&dev->num_inst, 0);
        init_waitqueue_head(&dev->irq_queue);
@@ -693,18 +712,30 @@ static int g2d_probe(struct platform_device *pdev)
                goto unmap_regs;
        }
 
+       ret = clk_prepare(dev->clk);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to prepare g2d clock\n");
+               goto put_clk;
+       }
+
        dev->gate = clk_get(&pdev->dev, "fimg2d");
        if (IS_ERR_OR_NULL(dev->gate)) {
                dev_err(&pdev->dev, "failed to get g2d clock gate\n");
                ret = -ENXIO;
-               goto put_clk;
+               goto unprep_clk;
+       }
+
+       ret = clk_prepare(dev->gate);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to prepare g2d clock gate\n");
+               goto put_clk_gate;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(&pdev->dev, "failed to find IRQ\n");
                ret = -ENXIO;
-               goto put_clk_gate;
+               goto unprep_clk_gate;
        }
 
        dev->irq = res->start;
@@ -764,8 +795,12 @@ alloc_ctx_cleanup:
        vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
 rel_irq:
        free_irq(dev->irq, dev);
+unprep_clk_gate:
+       clk_unprepare(dev->gate);
 put_clk_gate:
        clk_put(dev->gate);
+unprep_clk:
+       clk_unprepare(dev->clk);
 put_clk:
        clk_put(dev->clk);
 unmap_regs:
@@ -787,7 +822,9 @@ static int g2d_remove(struct platform_device *pdev)
        v4l2_device_unregister(&dev->v4l2_dev);
        vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
        free_irq(dev->irq, dev);
+       clk_unprepare(dev->gate);
        clk_put(dev->gate);
+       clk_unprepare(dev->clk);
        clk_put(dev->clk);
        iounmap(dev->regs);
        release_resource(dev->res_regs);
index 5eae901..1b82065 100644 (file)
@@ -20,7 +20,7 @@ struct g2d_dev {
        struct v4l2_m2m_dev     *m2m_dev;
        struct video_device     *vfd;
        struct mutex            mutex;
-       spinlock_t              irqlock;
+       spinlock_t              ctrl_lock;
        atomic_t                num_inst;
        struct vb2_alloc_ctx    *alloc_ctx;
        struct resource         *res_regs;
@@ -57,8 +57,11 @@ struct g2d_ctx {
        struct v4l2_m2m_ctx     *m2m_ctx;
        struct g2d_frame        in;
        struct g2d_frame        out;
+       struct v4l2_ctrl        *ctrl_hflip;
+       struct v4l2_ctrl        *ctrl_vflip;
        struct v4l2_ctrl_handler ctrl_handler;
        u32 rop;
+       u32 flip;
 };
 
 struct g2d_fmt {
@@ -77,6 +80,7 @@ void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a);
 void g2d_start(struct g2d_dev *d);
 void g2d_clear_int(struct g2d_dev *d);
 void g2d_set_rop4(struct g2d_dev *d, u32 r);
+void g2d_set_flip(struct g2d_dev *d, u32 r);
 u32 g2d_cmd_stretch(u32 e);
 void g2d_set_cmd(struct g2d_dev *d, u32 c);
 
index 1105a87..5a49c30 100644 (file)
 
 static struct s5p_jpeg_fmt formats_enc[] = {
        {
-               .name           = "YUV 4:2:0 planar, YCbCr",
-               .fourcc         = V4L2_PIX_FMT_YUV420,
-               .depth          = 12,
-               .colplanes      = 3,
+               .name           = "JPEG JFIF",
+               .fourcc         = V4L2_PIX_FMT_JPEG,
+               .colplanes      = 1,
                .types          = MEM2MEM_CAPTURE,
        },
        {
@@ -43,7 +42,7 @@ static struct s5p_jpeg_fmt formats_enc[] = {
                .fourcc         = V4L2_PIX_FMT_YUYV,
                .depth          = 16,
                .colplanes      = 1,
-               .types          = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+               .types          = MEM2MEM_OUTPUT,
        },
        {
                .name           = "RGB565",
@@ -203,6 +202,16 @@ static const unsigned char hactblg0[162] = {
        0xf9, 0xfa
 };
 
+static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
+{
+       return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
+}
+
+static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
+{
+       return container_of(fh, struct s5p_jpeg_ctx, fh);
+}
+
 static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
                   unsigned long tab, int len)
 {
@@ -269,6 +278,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
                      struct vb2_queue *dst_vq);
 static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
                                                 __u32 pixelformat);
+static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
 
 static int s5p_jpeg_open(struct file *file)
 {
@@ -276,12 +286,18 @@ static int s5p_jpeg_open(struct file *file)
        struct video_device *vfd = video_devdata(file);
        struct s5p_jpeg_ctx *ctx;
        struct s5p_jpeg_fmt *out_fmt;
+       int ret = 0;
 
        ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
-       file->private_data = ctx;
+       v4l2_fh_init(&ctx->fh, vfd);
+       /* Use separate control handler per file handle */
+       ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+
        ctx->jpeg = jpeg;
        if (vfd == jpeg->vfd_encoder) {
                ctx->mode = S5P_JPEG_ENCODE;
@@ -291,24 +307,35 @@ static int s5p_jpeg_open(struct file *file)
                out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
        }
 
+       ret = s5p_jpeg_controls_create(ctx);
+       if (ret < 0)
+               goto error;
+
        ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
        if (IS_ERR(ctx->m2m_ctx)) {
-               int err = PTR_ERR(ctx->m2m_ctx);
-               kfree(ctx);
-               return err;
+               ret = PTR_ERR(ctx->m2m_ctx);
+               goto error;
        }
 
        ctx->out_q.fmt = out_fmt;
        ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
-
        return 0;
+
+error:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+       return ret;
 }
 
 static int s5p_jpeg_release(struct file *file)
 {
-       struct s5p_jpeg_ctx *ctx = file->private_data;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
 
        v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
        kfree(ctx);
 
        return 0;
@@ -317,14 +344,14 @@ static int s5p_jpeg_release(struct file *file)
 static unsigned int s5p_jpeg_poll(struct file *file,
                                 struct poll_table_struct *wait)
 {
-       struct s5p_jpeg_ctx *ctx = file->private_data;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
 
        return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
 }
 
 static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct s5p_jpeg_ctx *ctx = file->private_data;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
 
        return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
 }
@@ -448,7 +475,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
 static int s5p_jpeg_querycap(struct file *file, void *priv,
                           struct v4l2_capability *cap)
 {
-       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        if (ctx->mode == S5P_JPEG_ENCODE) {
                strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
@@ -497,9 +524,7 @@ static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
 static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
                                   struct v4l2_fmtdesc *f)
 {
-       struct s5p_jpeg_ctx *ctx;
-
-       ctx = priv;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        if (ctx->mode == S5P_JPEG_ENCODE)
                return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
@@ -511,9 +536,7 @@ static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
 static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
                                   struct v4l2_fmtdesc *f)
 {
-       struct s5p_jpeg_ctx *ctx;
-
-       ctx = priv;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        if (ctx->mode == S5P_JPEG_ENCODE)
                return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
@@ -538,7 +561,7 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
        struct vb2_queue *vq;
        struct s5p_jpeg_q_data *q_data = NULL;
        struct v4l2_pix_format *pix = &f->fmt.pix;
-       struct s5p_jpeg_ctx *ct = priv;
+       struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
 
        vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
        if (!vq)
@@ -659,8 +682,8 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
 static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
                                  struct v4l2_format *f)
 {
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
        struct s5p_jpeg_fmt *fmt;
-       struct s5p_jpeg_ctx *ctx = priv;
 
        fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
        if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
@@ -676,8 +699,8 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
 static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
                                  struct v4l2_format *f)
 {
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
        struct s5p_jpeg_fmt *fmt;
-       struct s5p_jpeg_ctx *ctx = priv;
 
        fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
        if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
@@ -728,7 +751,7 @@ static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
        if (ret)
                return ret;
 
-       return s5p_jpeg_s_fmt(priv, f);
+       return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
 }
 
 static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
@@ -740,13 +763,13 @@ static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
        if (ret)
                return ret;
 
-       return s5p_jpeg_s_fmt(priv, f);
+       return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
 }
 
 static int s5p_jpeg_reqbufs(struct file *file, void *priv,
                          struct v4l2_requestbuffers *reqbufs)
 {
-       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 }
@@ -754,14 +777,14 @@ static int s5p_jpeg_reqbufs(struct file *file, void *priv,
 static int s5p_jpeg_querybuf(struct file *file, void *priv,
                           struct v4l2_buffer *buf)
 {
-       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
 }
 
 static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 {
-       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 }
@@ -769,7 +792,7 @@ static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 static int s5p_jpeg_dqbuf(struct file *file, void *priv,
                          struct v4l2_buffer *buf)
 {
-       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
 }
@@ -777,7 +800,7 @@ static int s5p_jpeg_dqbuf(struct file *file, void *priv,
 static int s5p_jpeg_streamon(struct file *file, void *priv,
                           enum v4l2_buf_type type)
 {
-       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
 }
@@ -785,7 +808,7 @@ static int s5p_jpeg_streamon(struct file *file, void *priv,
 static int s5p_jpeg_streamoff(struct file *file, void *priv,
                            enum v4l2_buf_type type)
 {
-       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
 }
@@ -793,7 +816,7 @@ static int s5p_jpeg_streamoff(struct file *file, void *priv,
 int s5p_jpeg_g_selection(struct file *file, void *priv,
                         struct v4l2_selection *s)
 {
-       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
            s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -822,33 +845,89 @@ int s5p_jpeg_g_selection(struct file *file, void *priv,
        return 0;
 }
 
-static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv,
-                              struct v4l2_jpegcompression *compr)
+/*
+ * V4L2 controls
+ */
+
+static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+       struct s5p_jpeg *jpeg = ctx->jpeg;
+       unsigned long flags;
 
-       if (ctx->mode == S5P_JPEG_DECODE)
-               return -ENOTTY;
+       switch (ctrl->id) {
+       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+               spin_lock_irqsave(&jpeg->slock, flags);
 
-       memset(compr, 0, sizeof(*compr));
-       compr->quality = ctx->compr_quality;
+               WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
+               if (ctx->subsampling > 2)
+                       ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
+               else
+                       ctrl->val = ctx->subsampling;
+               spin_unlock_irqrestore(&jpeg->slock, flags);
+               break;
+       }
 
        return 0;
 }
 
-static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv,
-                              struct v4l2_jpegcompression *compr)
+static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+       unsigned long flags;
 
-       if (ctx->mode == S5P_JPEG_DECODE)
-               return -ENOTTY;
+       spin_lock_irqsave(&ctx->jpeg->slock, flags);
 
-       compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST,
-                              S5P_JPEG_COMPR_QUAL_WORST);
+       switch (ctrl->id) {
+       case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+               ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val;
+               break;
+       case V4L2_CID_JPEG_RESTART_INTERVAL:
+               ctx->restart_interval = ctrl->val;
+               break;
+       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+               ctx->subsampling = ctrl->val;
+               break;
+       }
 
-       ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality;
+       spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
+       .g_volatile_ctrl        = s5p_jpeg_g_volatile_ctrl,
+       .s_ctrl                 = s5p_jpeg_s_ctrl,
+};
 
+static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
+{
+       unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
+       struct v4l2_ctrl *ctrl;
+
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+       if (ctx->mode == S5P_JPEG_ENCODE) {
+               v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+                                 V4L2_CID_JPEG_COMPRESSION_QUALITY,
+                                 0, 3, 1, 3);
+
+               v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+                                 V4L2_CID_JPEG_RESTART_INTERVAL,
+                                 0, 3, 0xffff, 0);
+               mask = ~0x06; /* 422, 420 */
+       }
+
+       ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
+                                     V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
+                                     V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
+                                     V4L2_JPEG_CHROMA_SUBSAMPLING_422);
+
+       if (ctx->ctrl_handler.error)
+               return ctx->ctrl_handler.error;
+
+       if (ctx->mode == S5P_JPEG_DECODE)
+               ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
+                       V4L2_CTRL_FLAG_READ_ONLY;
        return 0;
 }
 
@@ -877,9 +956,6 @@ static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
        .vidioc_streamoff               = s5p_jpeg_streamoff,
 
        .vidioc_g_selection             = s5p_jpeg_g_selection,
-
-       .vidioc_g_jpegcomp              = s5p_jpeg_g_jpegcomp,
-       .vidioc_s_jpegcomp              = s5p_jpeg_s_jpegcomp,
 };
 
 /*
@@ -908,13 +984,8 @@ static void s5p_jpeg_device_run(void *priv)
                        jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565);
                else
                        jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422);
-               if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
-                       jpeg_subsampling_mode(jpeg->regs,
-                                             S5P_JPEG_SUBSAMPLING_422);
-               else
-                       jpeg_subsampling_mode(jpeg->regs,
-                                             S5P_JPEG_SUBSAMPLING_420);
-               jpeg_dri(jpeg->regs, 0);
+               jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
+               jpeg_dri(jpeg->regs, ctx->restart_interval);
                jpeg_x(jpeg->regs, ctx->out_q.w);
                jpeg_y(jpeg->regs, ctx->out_q.h);
                jpeg_imgadr(jpeg->regs, src_addr);
@@ -953,14 +1024,18 @@ static void s5p_jpeg_device_run(void *priv)
                jpeg_htbl_dc(jpeg->regs, 2);
                jpeg_htbl_ac(jpeg->regs, 3);
                jpeg_htbl_dc(jpeg->regs, 3);
-       } else {
+       } else { /* S5P_JPEG_DECODE */
                jpeg_rst_int_enable(jpeg->regs, true);
                jpeg_data_num_int_enable(jpeg->regs, true);
                jpeg_final_mcu_num_int_enable(jpeg->regs, true);
-               jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
+               if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
+                       jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
+               else
+                       jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
                jpeg_jpgadr(jpeg->regs, src_addr);
                jpeg_imgadr(jpeg->regs, dst_addr);
        }
+
        jpeg_start(jpeg->regs);
 }
 
@@ -1162,6 +1237,8 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
        bool timer_elapsed = false;
        bool op_completed = false;
 
+       spin_lock(&jpeg->slock);
+
        curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
 
        src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
@@ -1192,6 +1269,9 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
        v4l2_m2m_buf_done(dst_buf, state);
        v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx);
 
+       curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs);
+       spin_unlock(&jpeg->slock);
+
        jpeg_clear_int(jpeg->regs);
 
        return IRQ_HANDLED;
@@ -1215,6 +1295,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        mutex_init(&jpeg->lock);
+       spin_lock_init(&jpeg->slock);
        jpeg->dev = &pdev->dev;
 
        /* memory-mapped registers */
index facad61..38d7367 100644 (file)
@@ -14,6 +14,8 @@
 #define JPEG_CORE_H_
 
 #include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
 
 #define S5P_JPEG_M2M_NAME              "s5p-jpeg"
 
@@ -47,6 +49,7 @@
 /**
  * struct s5p_jpeg - JPEG IP abstraction
  * @lock:              the mutex protecting this structure
+ * @slock:             spinlock protecting the device contexts
  * @v4l2_dev:          v4l2 device for mem2mem mode
  * @vfd_encoder:       video device node for encoder mem2mem mode
  * @vfd_decoder:       video device node for decoder mem2mem mode
@@ -60,6 +63,7 @@
  */
 struct s5p_jpeg {
        struct mutex            lock;
+       struct spinlock         slock;
 
        struct v4l2_device      v4l2_dev;
        struct video_device     *vfd_encoder;
@@ -117,15 +121,20 @@ struct s5p_jpeg_q_data {
  * @out_q:             source (output) queue information
  * @cap_fmt:           destination (capture) queue queue information
  * @hdr_parsed:                set if header has been parsed during decompression
+ * @ctrl_handler:      controls handler
  */
 struct s5p_jpeg_ctx {
        struct s5p_jpeg         *jpeg;
        unsigned int            mode;
-       unsigned int            compr_quality;
+       unsigned short          compr_quality;
+       unsigned short          restart_interval;
+       unsigned short          subsampling;
        struct v4l2_m2m_ctx     *m2m_ctx;
        struct s5p_jpeg_q_data  out_q;
        struct s5p_jpeg_q_data  cap_q;
+       struct v4l2_fh          fh;
        bool                    hdr_parsed;
+       struct v4l2_ctrl_handler ctrl_handler;
 };
 
 /**
index e10c744..f12f0fd 100644 (file)
@@ -13,6 +13,7 @@
 #define JPEG_HW_H_
 
 #include <linux/io.h>
+#include <linux/videodev2.h>
 
 #include "jpeg-hw.h"
 #include "jpeg-regs.h"
@@ -25,8 +26,6 @@
 #define S5P_JPEG_DECODE                        1
 #define S5P_JPEG_RAW_IN_565            0
 #define S5P_JPEG_RAW_IN_422            1
-#define S5P_JPEG_SUBSAMPLING_422       0
-#define S5P_JPEG_SUBSAMPLING_420       1
 #define S5P_JPEG_RAW_OUT_422           0
 #define S5P_JPEG_RAW_OUT_420           1
 
@@ -91,21 +90,26 @@ static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
        writel(reg, regs + S5P_JPGMOD);
 }
 
-static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode)
+static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
 {
        unsigned long reg, m;
 
-       m = S5P_SUBSAMPLING_MODE_422;
-       if (mode == S5P_JPEG_SUBSAMPLING_422)
-               m = S5P_SUBSAMPLING_MODE_422;
-       else if (mode == S5P_JPEG_SUBSAMPLING_420)
+       if (mode == V4L2_JPEG_CHROMA_SUBSAMPLING_420)
                m = S5P_SUBSAMPLING_MODE_420;
+       else
+               m = S5P_SUBSAMPLING_MODE_422;
+
        reg = readl(regs + S5P_JPGMOD);
        reg &= ~S5P_SUBSAMPLING_MODE_MASK;
        reg |= m;
        writel(reg, regs + S5P_JPGMOD);
 }
 
+static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs)
+{
+       return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK;
+}
+
 static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
 {
        unsigned long reg;
index f6a3035..738a607 100644 (file)
@@ -41,15 +41,29 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
        pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME);
        if (IS_ERR(pm->clock_gate)) {
                mfc_err("Failed to get clock-gating control\n");
-               ret = -ENOENT;
+               ret = PTR_ERR(pm->clock_gate);
                goto err_g_ip_clk;
        }
+
+       ret = clk_prepare(pm->clock_gate);
+       if (ret) {
+               mfc_err("Failed to preapre clock-gating control\n");
+               goto err_p_ip_clk;
+       }
+
        pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME);
        if (IS_ERR(pm->clock)) {
                mfc_err("Failed to get MFC clock\n");
-               ret = -ENOENT;
+               ret = PTR_ERR(pm->clock);
                goto err_g_ip_clk_2;
        }
+
+       ret = clk_prepare(pm->clock);
+       if (ret) {
+               mfc_err("Failed to prepare MFC clock\n");
+               goto err_p_ip_clk_2;
+       }
+
        atomic_set(&pm->power, 0);
 #ifdef CONFIG_PM_RUNTIME
        pm->device = &dev->plat_dev->dev;
@@ -59,7 +73,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
        atomic_set(&clk_ref, 0);
 #endif
        return 0;
+err_p_ip_clk_2:
+       clk_put(pm->clock);
 err_g_ip_clk_2:
+       clk_unprepare(pm->clock_gate);
+err_p_ip_clk:
        clk_put(pm->clock_gate);
 err_g_ip_clk:
        return ret;
@@ -67,7 +85,9 @@ err_g_ip_clk:
 
 void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
 {
+       clk_unprepare(pm->clock_gate);
        clk_put(pm->clock_gate);
+       clk_unprepare(pm->clock);
        clk_put(pm->clock);
 #ifdef CONFIG_PM_RUNTIME
        pm_runtime_disable(pm->device);
index f2a0977..f248b28 100644 (file)
@@ -46,6 +46,16 @@ config VIDEO_SAMSUNG_S5P_HDMIPHY
          as module. It is an I2C driver, that exposes a V4L2
          subdev for use by other drivers.
 
+config VIDEO_SAMSUNG_S5P_SII9234
+       tristate "Samsung SII9234 Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+       depends on VIDEO_SAMSUNG_S5P_TV
+       help
+         Say Y here if you want support for the MHL interface
+         in S5P Samsung SoC. The driver can be compiled
+         as module. It is an I2C driver, that exposes a V4L2
+         subdev for use by other drivers.
+
 config VIDEO_SAMSUNG_S5P_SDO
        tristate "Samsung Analog TV Driver"
        depends on VIDEO_DEV && VIDEO_V4L2
index 37e4c17..f49e756 100644 (file)
@@ -8,6 +8,8 @@
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o
 s5p-hdmiphy-y += hdmiphy_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SII9234) += s5p-sii9234.o
+s5p-sii9234-y += sii9234_drv.o
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
 s5p-hdmi-y += hdmi_drv.o
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
index 8b41a04..4865d25 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
 
+#include <media/s5p_hdmi.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-device.h>
@@ -66,6 +67,8 @@ struct hdmi_device {
        struct v4l2_device v4l2_dev;
        /** subdev of HDMIPHY interface */
        struct v4l2_subdev *phy_sd;
+       /** subdev of MHL interface */
+       struct v4l2_subdev *mhl_sd;
        /** configuration of current graphic mode */
        const struct hdmi_preset_conf *cur_conf;
        /** current preset */
@@ -74,10 +77,6 @@ struct hdmi_device {
        struct hdmi_resources res;
 };
 
-struct hdmi_driver_data {
-       int hdmiphy_bus;
-};
-
 struct hdmi_tg_regs {
        u8 cmd;
        u8 h_fsz_l;
@@ -129,23 +128,11 @@ struct hdmi_preset_conf {
        struct v4l2_mbus_framefmt mbus_fmt;
 };
 
-/* I2C module and id for HDMIPHY */
-static struct i2c_board_info hdmiphy_info = {
-       I2C_BOARD_INFO("hdmiphy", 0x38),
-};
-
-static struct hdmi_driver_data hdmi_driver_data[] = {
-       { .hdmiphy_bus = 3 },
-       { .hdmiphy_bus = 8 },
-};
-
 static struct platform_device_id hdmi_driver_types[] = {
        {
                .name           = "s5pv210-hdmi",
-               .driver_data    = (unsigned long)&hdmi_driver_data[0],
        }, {
                .name           = "exynos4-hdmi",
-               .driver_data    = (unsigned long)&hdmi_driver_data[1],
        }, {
                /* end node */
        }
@@ -587,7 +574,15 @@ static int hdmi_streamon(struct hdmi_device *hdev)
        if (tries == 0) {
                dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
                v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
-               hdmi_dumpregs(hdev, "s_stream");
+               hdmi_dumpregs(hdev, "hdmiphy - s_stream");
+               return -EIO;
+       }
+
+       /* starting MHL */
+       ret = v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 1);
+       if (hdev->mhl_sd && ret) {
+               v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+               hdmi_dumpregs(hdev, "mhl - s_stream");
                return -EIO;
        }
 
@@ -618,6 +613,7 @@ static int hdmi_streamoff(struct hdmi_device *hdev)
        clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
        clk_enable(res->sclk_hdmi);
 
+       v4l2_subdev_call(hdev->mhl_sd, video, s_stream, 0);
        v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
 
        hdmi_dumpregs(hdev, "streamoff");
@@ -739,6 +735,7 @@ static int hdmi_runtime_suspend(struct device *dev)
        struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
 
        dev_dbg(dev, "%s\n", __func__);
+       v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0);
        hdmi_resource_poweroff(&hdev->res);
        return 0;
 }
@@ -757,6 +754,11 @@ static int hdmi_runtime_resume(struct device *dev)
        if (ret)
                goto fail;
 
+       /* starting MHL */
+       ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1);
+       if (hdev->mhl_sd && ret)
+               goto fail;
+
        dev_dbg(dev, "poweron succeed\n");
 
        return 0;
@@ -867,15 +869,21 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct resource *res;
-       struct i2c_adapter *phy_adapter;
+       struct i2c_adapter *adapter;
        struct v4l2_subdev *sd;
        struct hdmi_device *hdmi_dev = NULL;
-       struct hdmi_driver_data *drv_data;
+       struct s5p_hdmi_platform_data *pdata = dev->platform_data;
        int ret;
 
        dev_dbg(dev, "probe start\n");
 
-       hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL);
+       if (!pdata) {
+               dev_err(dev, "platform data is missing\n");
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(*hdmi_dev), GFP_KERNEL);
        if (!hdmi_dev) {
                dev_err(dev, "out of memory\n");
                ret = -ENOMEM;
@@ -886,7 +894,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
 
        ret = hdmi_resources_init(hdmi_dev);
        if (ret)
-               goto fail_hdev;
+               goto fail;
 
        /* mapping HDMI registers */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -896,24 +904,26 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
                goto fail_init;
        }
 
-       hdmi_dev->regs = ioremap(res->start, resource_size(res));
+       hdmi_dev->regs = devm_ioremap(&pdev->dev, res->start,
+                                     resource_size(res));
        if (hdmi_dev->regs == NULL) {
                dev_err(dev, "register mapping failed.\n");
                ret = -ENXIO;
-               goto fail_hdev;
+               goto fail_init;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (res == NULL) {
                dev_err(dev, "get interrupt resource failed.\n");
                ret = -ENXIO;
-               goto fail_regs;
+               goto fail_init;
        }
 
-       ret = request_irq(res->start, hdmi_irq_handler, 0, "hdmi", hdmi_dev);
+       ret = devm_request_irq(&pdev->dev, res->start, hdmi_irq_handler, 0,
+                              "hdmi", hdmi_dev);
        if (ret) {
                dev_err(dev, "request interrupt failed.\n");
-               goto fail_regs;
+               goto fail_init;
        }
        hdmi_dev->irq = res->start;
 
@@ -924,28 +934,54 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
        ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
        if (ret) {
                dev_err(dev, "could not register v4l2 device.\n");
-               goto fail_irq;
+               goto fail_init;
        }
 
-       drv_data = (struct hdmi_driver_data *)
-               platform_get_device_id(pdev)->driver_data;
-       phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus);
-       if (phy_adapter == NULL) {
-               dev_err(dev, "adapter request failed\n");
+       /* testing if hdmiphy info is present */
+       if (!pdata->hdmiphy_info) {
+               dev_err(dev, "hdmiphy info is missing in platform data\n");
+               ret = -ENXIO;
+               goto fail_vdev;
+       }
+
+       adapter = i2c_get_adapter(pdata->hdmiphy_bus);
+       if (adapter == NULL) {
+               dev_err(dev, "hdmiphy adapter request failed\n");
                ret = -ENXIO;
                goto fail_vdev;
        }
 
        hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
-               phy_adapter, &hdmiphy_info, NULL);
+               adapter, pdata->hdmiphy_info, NULL);
        /* on failure or not adapter is no longer useful */
-       i2c_put_adapter(phy_adapter);
+       i2c_put_adapter(adapter);
        if (hdmi_dev->phy_sd == NULL) {
                dev_err(dev, "missing subdev for hdmiphy\n");
                ret = -ENODEV;
                goto fail_vdev;
        }
 
+       /* initialization of MHL interface if present */
+       if (pdata->mhl_info) {
+               adapter = i2c_get_adapter(pdata->mhl_bus);
+               if (adapter == NULL) {
+                       dev_err(dev, "MHL adapter request failed\n");
+                       ret = -ENXIO;
+                       goto fail_vdev;
+               }
+
+               hdmi_dev->mhl_sd = v4l2_i2c_new_subdev_board(
+                       &hdmi_dev->v4l2_dev, adapter,
+                       pdata->mhl_info, NULL);
+               /* on failure or not adapter is no longer useful */
+               i2c_put_adapter(adapter);
+               if (hdmi_dev->mhl_sd == NULL) {
+                       dev_err(dev, "missing subdev for MHL\n");
+                       ret = -ENODEV;
+                       goto fail_vdev;
+               }
+       }
+
        clk_enable(hdmi_dev->res.hdmi);
 
        pm_runtime_enable(dev);
@@ -962,25 +998,16 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
        /* storing subdev for call that have only access to struct device */
        dev_set_drvdata(dev, sd);
 
-       dev_info(dev, "probe sucessful\n");
+       dev_info(dev, "probe successful\n");
 
        return 0;
 
 fail_vdev:
        v4l2_device_unregister(&hdmi_dev->v4l2_dev);
 
-fail_irq:
-       free_irq(hdmi_dev->irq, hdmi_dev);
-
-fail_regs:
-       iounmap(hdmi_dev->regs);
-
 fail_init:
        hdmi_resources_cleanup(hdmi_dev);
 
-fail_hdev:
-       kfree(hdmi_dev);
-
 fail:
        dev_err(dev, "probe failed\n");
        return ret;
@@ -996,11 +1023,8 @@ static int __devexit hdmi_remove(struct platform_device *pdev)
        clk_disable(hdmi_dev->res.hdmi);
        v4l2_device_unregister(&hdmi_dev->v4l2_dev);
        disable_irq(hdmi_dev->irq);
-       free_irq(hdmi_dev->irq, hdmi_dev);
-       iounmap(hdmi_dev->regs);
        hdmi_resources_cleanup(hdmi_dev);
-       kfree(hdmi_dev);
-       dev_info(dev, "remove sucessful\n");
+       dev_info(dev, "remove successful\n");
 
        return 0;
 }
index 6693f4a..0afef77 100644 (file)
@@ -175,14 +175,4 @@ static struct i2c_driver hdmiphy_driver = {
        .id_table = hdmiphy_id,
 };
 
-static int __init hdmiphy_init(void)
-{
-       return i2c_add_driver(&hdmiphy_driver);
-}
-module_init(hdmiphy_init);
-
-static void __exit hdmiphy_exit(void)
-{
-       i2c_del_driver(&hdmiphy_driver);
-}
-module_exit(hdmiphy_exit);
+module_i2c_driver(hdmiphy_driver);
index 0064309..a2c0c25 100644 (file)
@@ -444,7 +444,7 @@ static int __devexit mxr_remove(struct platform_device *pdev)
 
        kfree(mdev);
 
-       dev_info(dev, "remove sucessful\n");
+       dev_info(dev, "remove successful\n");
        return 0;
 }
 
index 059e774..f6bca2c 100644 (file)
@@ -301,7 +301,7 @@ static int __devinit sdo_probe(struct platform_device *pdev)
        struct clk *sclk_vpll;
 
        dev_info(dev, "probe start\n");
-       sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+       sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL);
        if (!sdev) {
                dev_err(dev, "not enough memory.\n");
                ret = -ENOMEM;
@@ -314,14 +314,14 @@ static int __devinit sdo_probe(struct platform_device *pdev)
        if (res == NULL) {
                dev_err(dev, "get memory resource failed.\n");
                ret = -ENXIO;
-               goto fail_sdev;
+               goto fail;
        }
 
-       sdev->regs = ioremap(res->start, resource_size(res));
+       sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
        if (sdev->regs == NULL) {
                dev_err(dev, "register mapping failed.\n");
                ret = -ENXIO;
-               goto fail_sdev;
+               goto fail;
        }
 
        /* acquiring interrupt */
@@ -329,12 +329,13 @@ static int __devinit sdo_probe(struct platform_device *pdev)
        if (res == NULL) {
                dev_err(dev, "get interrupt resource failed.\n");
                ret = -ENXIO;
-               goto fail_regs;
+               goto fail;
        }
-       ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev);
+       ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0,
+                              "s5p-sdo", sdev);
        if (ret) {
                dev_err(dev, "request interrupt failed.\n");
-               goto fail_regs;
+               goto fail;
        }
        sdev->irq = res->start;
 
@@ -343,7 +344,7 @@ static int __devinit sdo_probe(struct platform_device *pdev)
        if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
                dev_err(dev, "failed to get clock 'sclk_dac'\n");
                ret = -ENXIO;
-               goto fail_irq;
+               goto fail;
        }
        sdev->dac = clk_get(dev, "dac");
        if (IS_ERR_OR_NULL(sdev->dac)) {
@@ -415,12 +416,6 @@ fail_dac:
        clk_put(sdev->dac);
 fail_sclk_dac:
        clk_put(sdev->sclk_dac);
-fail_irq:
-       free_irq(sdev->irq, sdev);
-fail_regs:
-       iounmap(sdev->regs);
-fail_sdev:
-       kfree(sdev);
 fail:
        dev_info(dev, "probe failed\n");
        return ret;
@@ -439,9 +434,6 @@ static int __devexit sdo_remove(struct platform_device *pdev)
        clk_put(sdev->dacphy);
        clk_put(sdev->dac);
        clk_put(sdev->sclk_dac);
-       free_irq(sdev->irq, sdev);
-       iounmap(sdev->regs);
-       kfree(sdev);
 
        dev_info(&pdev->dev, "remove successful\n");
        return 0;
diff --git a/drivers/media/video/s5p-tv/sii9234_drv.c b/drivers/media/video/s5p-tv/sii9234_drv.c
new file mode 100644 (file)
index 0000000..0f31ecc
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * Samsung MHL interface driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co.Ltd
+ * Author: Tomasz Stanislawski <t.stanislaws@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/delay.h>
+#include <linux/err.h>
+#include <linux/freezer.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/machine.h>
+#include <linux/slab.h>
+
+#include <mach/gpio.h>
+#include <plat/gpio-cfg.h>
+
+#include <media/sii9234.h>
+#include <media/v4l2-subdev.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MHL interface driver");
+MODULE_LICENSE("GPL");
+
+struct sii9234_context {
+       struct i2c_client *client;
+       struct regulator *power;
+       int gpio_n_reset;
+       struct v4l2_subdev sd;
+};
+
+static inline struct sii9234_context *sd_to_context(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct sii9234_context, sd);
+}
+
+static inline int sii9234_readb(struct i2c_client *client, int addr)
+{
+       return i2c_smbus_read_byte_data(client, addr);
+}
+
+static inline int sii9234_writeb(struct i2c_client *client, int addr, int value)
+{
+       return i2c_smbus_write_byte_data(client, addr, value);
+}
+
+static inline int sii9234_writeb_mask(struct i2c_client *client, int addr,
+       int value, int mask)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, addr);
+       if (ret < 0)
+               return ret;
+       ret = (ret & ~mask) | (value & mask);
+       return i2c_smbus_write_byte_data(client, addr, ret);
+}
+
+static inline int sii9234_readb_idx(struct i2c_client *client, int addr)
+{
+       int ret;
+       ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8);
+       if (ret < 0)
+               return ret;
+       ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff);
+       if (ret < 0)
+               return ret;
+       return i2c_smbus_read_byte_data(client, 0xbe);
+}
+
+static inline int sii9234_writeb_idx(struct i2c_client *client, int addr,
+       int value)
+{
+       int ret;
+       ret = i2c_smbus_write_byte_data(client, 0xbc, addr >> 8);
+       if (ret < 0)
+               return ret;
+       ret = i2c_smbus_write_byte_data(client, 0xbd, addr & 0xff);
+       if (ret < 0)
+               return ret;
+       ret = i2c_smbus_write_byte_data(client, 0xbe, value);
+       return ret;
+}
+
+static inline int sii9234_writeb_idx_mask(struct i2c_client *client, int addr,
+       int value, int mask)
+{
+       int ret;
+
+       ret = sii9234_readb_idx(client, addr);
+       if (ret < 0)
+               return ret;
+       ret = (ret & ~mask) | (value & mask);
+       return sii9234_writeb_idx(client, addr, ret);
+}
+
+static int sii9234_reset(struct sii9234_context *ctx)
+{
+       struct i2c_client *client = ctx->client;
+       struct device *dev = &client->dev;
+       int ret, tries;
+
+       gpio_direction_output(ctx->gpio_n_reset, 1);
+       mdelay(1);
+       gpio_direction_output(ctx->gpio_n_reset, 0);
+       mdelay(1);
+       gpio_direction_output(ctx->gpio_n_reset, 1);
+       mdelay(1);
+
+       /* going to TTPI mode */
+       ret = sii9234_writeb(client, 0xc7, 0);
+       if (ret < 0) {
+               dev_err(dev, "failed to set TTPI mode\n");
+               return ret;
+       }
+       for (tries = 0; tries < 100 ; ++tries) {
+               ret = sii9234_readb(client, 0x1b);
+               if (ret > 0)
+                       break;
+               if (ret < 0) {
+                       dev_err(dev, "failed to reset device\n");
+                       return -EIO;
+               }
+               mdelay(1);
+       }
+       if (tries == 100) {
+               dev_err(dev, "maximal number of tries reached\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int sii9234_verify_version(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       int family, rev, tpi_rev, dev_id, sub_id, hdcp, id;
+
+       family = sii9234_readb(client, 0x1b);
+       rev = sii9234_readb(client, 0x1c) & 0x0f;
+       tpi_rev = sii9234_readb(client, 0x1d) & 0x7f;
+       dev_id = sii9234_readb_idx(client, 0x0103);
+       sub_id = sii9234_readb_idx(client, 0x0102);
+       hdcp = sii9234_readb(client, 0x30);
+
+       if (family < 0 || rev < 0 || tpi_rev < 0 || dev_id < 0 ||
+               sub_id < 0 || hdcp < 0) {
+               dev_err(dev, "failed to read chip's version\n");
+               return -EIO;
+       }
+
+       id = (dev_id << 8) | sub_id;
+
+       dev_info(dev, "chip: SiL%02x family: %02x, rev: %02x\n",
+               id, family, rev);
+       dev_info(dev, "tpi_rev:%02x, hdcp: %02x\n", tpi_rev, hdcp);
+       if (id != 0x9234) {
+               dev_err(dev, "not supported chip\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static u8 data[][3] = {
+/* setup from driver created by doonsoo45.kim */
+       { 0x01, 0x05, 0x04 }, /* Enable Auto soft reset on SCDT = 0 */
+       { 0x01, 0x08, 0x35 }, /* Power Up TMDS Tx Core */
+       { 0x01, 0x0d, 0x1c }, /* HDMI Transcode mode enable */
+       { 0x01, 0x2b, 0x01 }, /* Enable HDCP Compliance workaround */
+       { 0x01, 0x79, 0x40 }, /* daniel test...MHL_INT */
+       { 0x01, 0x80, 0x34 }, /* Enable Rx PLL Clock Value */
+       { 0x01, 0x90, 0x27 }, /* Enable CBUS discovery */
+       { 0x01, 0x91, 0xe5 }, /* Skip RGND detection */
+       { 0x01, 0x92, 0x46 }, /* Force MHD mode */
+       { 0x01, 0x93, 0xdc }, /* Disable CBUS pull-up during RGND measurement */
+       { 0x01, 0x94, 0x66 }, /* 1.8V CBUS VTH & GND threshold */
+       { 0x01, 0x95, 0x31 }, /* RGND block & single discovery attempt */
+       { 0x01, 0x96, 0x22 }, /* use 1K and 2K setting */
+       { 0x01, 0xa0, 0x10 }, /* SIMG: Term mode */
+       { 0x01, 0xa1, 0xfc }, /* Disable internal Mobile HD driver */
+       { 0x01, 0xa3, 0xfa }, /* SIMG: Output Swing  default EB, 3x Clk Mult */
+       { 0x01, 0xa5, 0x80 }, /* SIMG: RGND Hysterisis, 3x mode for Beast */
+       { 0x01, 0xa6, 0x0c }, /* SIMG: Swing Offset */
+       { 0x02, 0x3d, 0x3f }, /* Power up CVCC 1.2V core */
+       { 0x03, 0x00, 0x00 }, /* SIMG: correcting HW default */
+       { 0x03, 0x11, 0x01 }, /* Enable TxPLL Clock */
+       { 0x03, 0x12, 0x15 }, /* Enable Tx Clock Path & Equalizer */
+       { 0x03, 0x13, 0x60 }, /* SIMG: Set termination value */
+       { 0x03, 0x14, 0xf0 }, /* SIMG: Change CKDT level */
+       { 0x03, 0x17, 0x07 }, /* SIMG: PLL Calrefsel */
+       { 0x03, 0x1a, 0x20 }, /* VCO Cal */
+       { 0x03, 0x22, 0xe0 }, /* SIMG: Auto EQ */
+       { 0x03, 0x23, 0xc0 }, /* SIMG: Auto EQ */
+       { 0x03, 0x24, 0xa0 }, /* SIMG: Auto EQ */
+       { 0x03, 0x25, 0x80 }, /* SIMG: Auto EQ */
+       { 0x03, 0x26, 0x60 }, /* SIMG: Auto EQ */
+       { 0x03, 0x27, 0x40 }, /* SIMG: Auto EQ */
+       { 0x03, 0x28, 0x20 }, /* SIMG: Auto EQ */
+       { 0x03, 0x29, 0x00 }, /* SIMG: Auto EQ */
+       { 0x03, 0x31, 0x0b }, /* SIMG: Rx PLL BW value from I2C BW ~ 4MHz */
+       { 0x03, 0x45, 0x06 }, /* SIMG: DPLL Mode */
+       { 0x03, 0x4b, 0x06 }, /* SIMG: Correcting HW default */
+       { 0x03, 0x4c, 0xa0 }, /* Manual zone control */
+       { 0x03, 0x4d, 0x02 }, /* SIMG: PLL Mode Value (order is important) */
+};
+
+static int sii9234_set_internal(struct sii9234_context *ctx)
+{
+       struct i2c_client *client = ctx->client;
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(data); ++i) {
+               int addr = (data[i][0] << 8) | data[i][1];
+               ret = sii9234_writeb_idx(client, addr, data[i][2]);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static int sii9234_runtime_suspend(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct sii9234_context *ctx = sd_to_context(sd);
+       struct i2c_client *client = ctx->client;
+
+       dev_info(dev, "suspend start\n");
+
+       sii9234_writeb_mask(client, 0x1e, 3, 3);
+       regulator_disable(ctx->power);
+
+       return 0;
+}
+
+static int sii9234_runtime_resume(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct sii9234_context *ctx = sd_to_context(sd);
+       struct i2c_client *client = ctx->client;
+       int ret;
+
+       dev_info(dev, "resume start\n");
+       regulator_enable(ctx->power);
+
+       ret = sii9234_reset(ctx);
+       if (ret)
+               goto fail;
+
+       /* enable tpi */
+       ret = sii9234_writeb_mask(client, 0x1e, 1, 0);
+       if (ret < 0)
+               goto fail;
+       ret = sii9234_set_internal(ctx);
+       if (ret < 0)
+               goto fail;
+
+       return 0;
+
+fail:
+       dev_err(dev, "failed to resume\n");
+       regulator_disable(ctx->power);
+
+       return ret;
+}
+
+static const struct dev_pm_ops sii9234_pm_ops = {
+       .runtime_suspend = sii9234_runtime_suspend,
+       .runtime_resume  = sii9234_runtime_resume,
+};
+
+static int sii9234_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct sii9234_context *ctx = sd_to_context(sd);
+       int ret;
+
+       if (on)
+               ret = pm_runtime_get_sync(&ctx->client->dev);
+       else
+               ret = pm_runtime_put(&ctx->client->dev);
+       /* only values < 0 indicate errors */
+       return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sii9234_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct sii9234_context *ctx = sd_to_context(sd);
+
+       /* (dis/en)able TDMS output */
+       sii9234_writeb_mask(ctx->client, 0x1a, enable ? 0 : ~0 , 1 << 4);
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops sii9234_core_ops = {
+       .s_power =  sii9234_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sii9234_video_ops = {
+       .s_stream =  sii9234_s_stream,
+};
+
+static const struct v4l2_subdev_ops sii9234_ops = {
+       .core = &sii9234_core_ops,
+       .video = &sii9234_video_ops,
+};
+
+static int __devinit sii9234_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct sii9234_platform_data *pdata = dev->platform_data;
+       struct sii9234_context *ctx;
+       int ret;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               dev_err(dev, "out of memory\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+       ctx->client = client;
+
+       ctx->power = regulator_get(dev, "hdmi-en");
+       if (IS_ERR(ctx->power)) {
+               dev_err(dev, "failed to acquire regulator hdmi-en\n");
+               ret = PTR_ERR(ctx->power);
+               goto fail_ctx;
+       }
+
+       ctx->gpio_n_reset = pdata->gpio_n_reset;
+       ret = gpio_request(ctx->gpio_n_reset, "MHL_RST");
+       if (ret) {
+               dev_err(dev, "failed to acquire MHL_RST gpio\n");
+               goto fail_power;
+       }
+
+       v4l2_i2c_subdev_init(&ctx->sd, client, &sii9234_ops);
+
+       pm_runtime_enable(dev);
+
+       /* enable device */
+       ret = pm_runtime_get_sync(dev);
+       if (ret)
+               goto fail_pm;
+
+       /* verify chip version */
+       ret = sii9234_verify_version(client);
+       if (ret)
+               goto fail_pm_get;
+
+       /* stop processing */
+       pm_runtime_put(dev);
+
+       dev_info(dev, "probe successful\n");
+
+       return 0;
+
+fail_pm_get:
+       pm_runtime_put_sync(dev);
+
+fail_pm:
+       pm_runtime_disable(dev);
+       gpio_free(ctx->gpio_n_reset);
+
+fail_power:
+       regulator_put(ctx->power);
+
+fail_ctx:
+       kfree(ctx);
+
+fail:
+       dev_err(dev, "probe failed\n");
+
+       return ret;
+}
+
+static int __devexit sii9234_remove(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct sii9234_context *ctx = sd_to_context(sd);
+
+       pm_runtime_disable(dev);
+       gpio_free(ctx->gpio_n_reset);
+       regulator_put(ctx->power);
+       kfree(ctx);
+
+       dev_info(dev, "remove successful\n");
+
+       return 0;
+}
+
+
+static const struct i2c_device_id sii9234_id[] = {
+       { "SII9234", 0 },
+       { },
+};
+
+MODULE_DEVICE_TABLE(i2c, sii9234_id);
+static struct i2c_driver sii9234_driver = {
+       .driver = {
+               .name   = "sii9234",
+               .owner  = THIS_MODULE,
+               .pm = &sii9234_pm_ops,
+       },
+       .probe          = sii9234_probe,
+       .remove         = __devexit_p(sii9234_remove),
+       .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);
index 99a2ac1..0caac50 100644 (file)
@@ -539,15 +539,4 @@ static struct i2c_driver saa6588_driver = {
        .id_table       = saa6588_id,
 };
 
-static __init int init_saa6588(void)
-{
-       return i2c_add_driver(&saa6588_driver);
-}
-
-static __exit void exit_saa6588(void)
-{
-       i2c_del_driver(&saa6588_driver);
-}
-
-module_init(init_saa6588);
-module_exit(exit_saa6588);
+module_i2c_driver(saa6588_driver);
index 9966420..51cd4c8 100644 (file)
@@ -491,15 +491,4 @@ static struct i2c_driver saa7110_driver = {
        .id_table       = saa7110_id,
 };
 
-static __init int init_saa7110(void)
-{
-       return i2c_add_driver(&saa7110_driver);
-}
-
-static __exit void exit_saa7110(void)
-{
-       i2c_del_driver(&saa7110_driver);
-}
-
-module_init(init_saa7110);
-module_exit(exit_saa7110);
+module_i2c_driver(saa7110_driver);
index 0ef5484..2107336 100644 (file)
@@ -1724,15 +1724,4 @@ static struct i2c_driver saa711x_driver = {
        .id_table       = saa711x_id,
 };
 
-static __init int init_saa711x(void)
-{
-       return i2c_add_driver(&saa711x_driver);
-}
-
-static __exit void exit_saa711x(void)
-{
-       i2c_del_driver(&saa711x_driver);
-}
-
-module_init(init_saa711x);
-module_exit(exit_saa711x);
+module_i2c_driver(saa711x_driver);
index ad96461..39c90b0 100644 (file)
@@ -852,15 +852,4 @@ static struct i2c_driver saa7127_driver = {
        .id_table       = saa7127_id,
 };
 
-static __init int init_saa7127(void)
-{
-       return i2c_add_driver(&saa7127_driver);
-}
-
-static __exit void exit_saa7127(void)
-{
-       i2c_del_driver(&saa7127_driver);
-}
-
-module_init(init_saa7127);
-module_exit(exit_saa7127);
+module_i2c_driver(saa7127_driver);
index a646ccf..da38993 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
 
 obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/video
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
index f9f29cc..f147b05 100644 (file)
@@ -1001,18 +1001,7 @@ static struct i2c_driver saa6752hs_driver = {
        .id_table       = saa6752hs_id,
 };
 
-static __init int init_saa6752hs(void)
-{
-       return i2c_add_driver(&saa6752hs_driver);
-}
-
-static __exit void exit_saa6752hs(void)
-{
-       i2c_del_driver(&saa6752hs_driver);
-}
-
-module_init(init_saa6752hs);
-module_exit(exit_saa6752hs);
+module_i2c_driver(saa6752hs_driver);
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
index 065d0f6..53aae59 100644 (file)
@@ -33,6 +33,7 @@
 #include "tea5767.h"
 #include "tda18271.h"
 #include "xc5000.h"
+#include "s5h1411.h"
 
 /* commly used strings */
 static char name_mute[]    = "mute";
@@ -5712,6 +5713,36 @@ struct saa7134_board saa7134_boards[] = {
                        .amux   = LINE1,
                } },
        },
+       [SAA7134_BOARD_KWORLD_PC150U] = {
+               .name           = "Kworld PC150-U",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .gpiomask       = 1 << 21,
+               .ts_type        = SAA7134_MPEG_TS_PARALLEL,
+               .inputs = { {
+                       .name   = name_tv,
+                       .vmux   = 1,
+                       .amux   = TV,
+                       .tv     = 1,
+               }, {
+                       .name   = name_comp,
+                       .vmux   = 3,
+                       .amux   = LINE1,
+               }, {
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE2,
+               } },
+               .radio = {
+                       .name   = name_radio,
+                       .amux   = TV,
+                       .gpio   = 0x0000000,
+               },
+       },
 
 };
 
@@ -6306,6 +6337,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .driver_data  = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+               .subvendor    = 0x17de,
+               .subdevice    = 0xa134,
+               .driver_data  = SAA7134_BOARD_KWORLD_PC150U,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x1461,
                .subdevice    = 0x7360,
@@ -7134,6 +7171,23 @@ static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev,
        return 0;
 }
 
+static int saa7134_kworld_pc150u_toggle_agc(struct saa7134_dev *dev,
+                                           enum tda18271_mode mode)
+{
+       switch (mode) {
+       case TDA18271_ANALOG:
+               saa7134_set_gpio(dev, 18, 0);
+               break;
+       case TDA18271_DIGITAL:
+               saa7134_set_gpio(dev, 18, 1);
+               msleep(30);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
                                          int command, int arg)
 {
@@ -7150,6 +7204,9 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
                case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
                        ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg);
                        break;
+               case SAA7134_BOARD_KWORLD_PC150U:
+                       ret = saa7134_kworld_pc150u_toggle_agc(dev, arg);
+                       break;
                default:
                        break;
                }
@@ -7171,6 +7228,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
        case SAA7134_BOARD_HAUPPAUGE_HVR1120:
        case SAA7134_BOARD_AVERMEDIA_M733A:
        case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+       case SAA7134_BOARD_KWORLD_PC150U:
        case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
                /* tda8290 + tda18271 */
                ret = saa7134_tda8290_18271_callback(dev, command, arg);
@@ -7452,6 +7510,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_BEHOLD_X7:
        case SAA7134_BOARD_BEHOLD_H7:
        case SAA7134_BOARD_BEHOLD_A7:
+       case SAA7134_BOARD_KWORLD_PC150U:
                dev->has_remote = SAA7134_REMOTE_I2C;
                break;
        case SAA7134_BOARD_AVERMEDIA_A169_B:
index 089fa0f..aaa5c97 100644 (file)
@@ -61,6 +61,7 @@
 #include "zl10036.h"
 #include "zl10039.h"
 #include "mt312.h"
+#include "s5h1411.h"
 
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
@@ -1158,6 +1159,33 @@ static struct tda18271_config prohdtv_pro2_tda18271_config = {
        .output_opt = TDA18271_OUTPUT_LT_OFF,
 };
 
+static struct tda18271_std_map kworld_tda18271_std_map = {
+       .atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 3,
+                     .if_lvl = 6, .rfagc_top = 0x37 },
+       .qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+                     .if_lvl = 6, .rfagc_top = 0x37 },
+};
+
+static struct tda18271_config kworld_pc150u_tda18271_config = {
+       .std_map = &kworld_tda18271_std_map,
+       .gate    = TDA18271_GATE_ANALOG,
+       .output_opt = TDA18271_OUTPUT_LT_OFF,
+       .config  = 3,   /* Use tuner callback for AGC */
+       .rf_cal_on_startup = 1
+};
+
+static struct s5h1411_config kworld_s5h1411_config = {
+       .output_mode   = S5H1411_PARALLEL_OUTPUT,
+       .gpio          = S5H1411_GPIO_OFF,
+       .qam_if        = S5H1411_IF_4000,
+       .vsb_if        = S5H1411_IF_3250,
+       .inversion     = S5H1411_INVERSION_ON,
+       .status_mode   = S5H1411_DEMODLOCKING,
+       .mpeg_timing   =
+               S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+
 /* ==================================================================
  * Core code
  */
@@ -1438,6 +1466,22 @@ static int dvb_init(struct saa7134_dev *dev)
                                   &dev->i2c_adap, 0x61,
                                   TUNER_PHILIPS_TUV1236D);
                break;
+       case SAA7134_BOARD_KWORLD_PC150U:
+               saa7134_set_gpio(dev, 18, 1); /* Switch to digital mode */
+               saa7134_tuner_callback(dev, 0,
+                                      TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
+               fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+                                              &kworld_s5h1411_config,
+                                              &dev->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda829x_attach, fe0->dvb.frontend,
+                                  &dev->i2c_adap, 0x4b,
+                                  &tda829x_no_probe);
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                                  0x60, &dev->i2c_adap,
+                                  &kworld_pc150u_tda18271_config);
+               }
+               break;
        case SAA7134_BOARD_FLYDVBS_LR300:
                fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
                                               &dev->i2c_adap);
index 2d3f6d2..a176ec3 100644 (file)
@@ -254,7 +254,9 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
                        addr  = msgs[i].addr << 1;
                        if (msgs[i].flags & I2C_M_RD)
                                addr |= 1;
-                       if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) {
+                       if (i > 0 && msgs[i].flags &
+                           I2C_M_RD && msgs[i].addr != 0x40 &&
+                           msgs[i].addr != 0x19) {
                                /* workaround for a saa7134 i2c bug
                                 * needed to talk to the mt352 demux
                                 * thanks to pinnacle for the hint */
@@ -279,6 +281,16 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
                                d1printk("%02x", rc);
                                msgs[i].buf[byte] = rc;
                        }
+                       /* discard mysterious extra byte when reading
+                          from Samsung S5H1411.  i2c bus gets error
+                          if we do not. */
+                       if (0x19 == msgs[i].addr) {
+                               d1printk(" ?");
+                               rc = i2c_recv_byte(dev);
+                               if (rc < 0)
+                                       goto err;
+                               d1printk("%02x", rc);
+                       }
                } else {
                        /* write bytes */
                        d2printk("write bytes\n");
index 22ecd72..48d2878 100644 (file)
@@ -210,6 +210,54 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
        return 1;
 }
 
+/* copied and modified from get_key_msi_tvanywhere_plus() */
+static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key,
+                                       u32 *ir_raw)
+{
+       unsigned char b;
+       unsigned int gpio;
+
+       /* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+       struct saa7134_dev *dev = ir->c->adapter->algo_data;
+       if (dev == NULL) {
+               i2cdprintk("get_key_kworld_pc150u: "
+                          "ir->c->adapter->algo_data is NULL!\n");
+               return -EIO;
+       }
+
+       /* rising SAA7134_GPIO_GPRESCAN reads the status */
+
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+       gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+       /* GPIO&0x100 is pulsed low when a button is pressed. Don't do
+          I2C receive if gpio&0x100 is not low. */
+
+       if (gpio & 0x100)
+               return 0;       /* No button press */
+
+       /* GPIO says there is a button press. Get it. */
+
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
+               i2cdprintk("read error\n");
+               return -EIO;
+       }
+
+       /* No button press */
+
+       if (b == 0xff)
+               return 0;
+
+       /* Button pressed */
+
+       dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b);
+       *ir_key = b;
+       *ir_raw = b;
+       return 1;
+}
+
 static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char b;
@@ -901,6 +949,21 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
                        msg_msi.addr, dev->i2c_adap.name,
                        (1 == rc) ? "yes" : "no");
                break;
+       case SAA7134_BOARD_KWORLD_PC150U:
+               /* copied and modified from MSI TV@nywhere Plus */
+               dev->init_data.name = "Kworld PC150-U";
+               dev->init_data.get_key = get_key_kworld_pc150u;
+               dev->init_data.ir_codes = RC_MAP_KWORLD_PC150U;
+               info.addr = 0x30;
+               /* MSI TV@nywhere Plus controller doesn't seem to
+                  respond to probes unless we read something from
+                  an existing device. Weird...
+                  REVISIT: might no longer be needed */
+               rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+               dprintk("probe 0x%02x @ %s: %s\n",
+                       msg_msi.addr, dev->i2c_adap.name,
+                       (1 == rc) ? "yes" : "no");
+               break;
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
                dev->init_data.name = "HVR 1110";
                dev->init_data.get_key = get_key_hvr1110;
index 42fba4f..f625060 100644 (file)
@@ -126,8 +126,8 @@ struct saa7134_card_ir {
        unsigned                users;
 
        u32                     polling;
-        u32                    last_gpio;
-        u32                    mask_keycode, mask_keydown, mask_keyup;
+       u32                     last_gpio;
+       u32                     mask_keycode, mask_keydown, mask_keyup;
 
        bool                    running;
        bool                    active;
@@ -331,6 +331,7 @@ struct saa7134_card_ir {
 #define SAA7134_BOARD_BEHOLD_501            186
 #define SAA7134_BOARD_BEHOLD_503FM          187
 #define SAA7134_BOARD_SENSORAY811_911       188
+#define SAA7134_BOARD_KWORLD_PC150U         189
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
index ecd5811..068443a 100644 (file)
@@ -4,9 +4,9 @@ saa7164-objs    := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \
 
 obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o
 
-ccflags-y += -Idrivers/media/video
-ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
-ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -I$(srctree)/drivers/media/video
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
 
 ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
index 2fd38a0..a9ed686 100644 (file)
@@ -791,11 +791,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       return 0;
-}
-
 static int fill_queryctrl(struct saa7164_encoder_params *params,
        struct v4l2_queryctrl *c)
 {
@@ -1347,7 +1342,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
        .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_log_status       = vidioc_log_status,
        .vidioc_queryctrl        = vidioc_queryctrl,
        .vidioc_g_chip_ident     = saa7164_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
index e2e0341..273cf80 100644 (file)
@@ -730,11 +730,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       return 0;
-}
-
 static int fill_queryctrl(struct saa7164_vbi_params *params,
        struct v4l2_queryctrl *c)
 {
@@ -1256,7 +1251,6 @@ static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
        .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_log_status       = vidioc_log_status,
        .vidioc_queryctrl        = vidioc_queryctrl,
 #if 0
        .vidioc_g_chip_ident     = saa7164_g_chip_ident,
index b6172c2..1e84466 100644 (file)
@@ -1375,15 +1375,4 @@ static struct i2c_driver saa717x_driver = {
        .id_table       = saa717x_id,
 };
 
-static __init int init_saa717x(void)
-{
-       return i2c_add_driver(&saa717x_driver);
-}
-
-static __exit void exit_saa717x(void)
-{
-       i2c_del_driver(&saa717x_driver);
-}
-
-module_init(init_saa717x);
-module_exit(exit_saa717x);
+module_i2c_driver(saa717x_driver);
index 96f56c2..2c6b65c 100644 (file)
@@ -374,15 +374,4 @@ static struct i2c_driver saa7185_driver = {
        .id_table       = saa7185_id,
 };
 
-static __init int init_saa7185(void)
-{
-       return i2c_add_driver(&saa7185_driver);
-}
-
-static __exit void exit_saa7185(void)
-{
-       i2c_del_driver(&saa7185_driver);
-}
-
-module_init(init_saa7185);
-module_exit(exit_saa7185);
+module_i2c_driver(saa7185_driver);
index 211fa25..d7d1670 100644 (file)
@@ -656,15 +656,4 @@ static struct i2c_driver saa7191_driver = {
        .id_table       = saa7191_id,
 };
 
-static __init int init_saa7191(void)
-{
-       return i2c_add_driver(&saa7191_driver);
-}
-
-static __exit void exit_saa7191(void)
-{
-       i2c_del_driver(&saa7191_driver);
-}
-
-module_init(init_saa7191);
-module_exit(exit_saa7191);
+module_i2c_driver(saa7191_driver);
index f854d85..424dfac 100644 (file)
@@ -112,6 +112,10 @@ struct sh_mobile_ceu_dev {
 
        u32 cflcr;
 
+       /* static max sizes either from platform data or default */
+       int max_width;
+       int max_height;
+
        enum v4l2_field field;
        int sequence;
 
@@ -1081,7 +1085,15 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                if (ret < 0)
                        return ret;
 
-               while ((mf.width > 2560 || mf.height > 1920) && shift < 4) {
+               /*
+                * All currently existing CEU implementations support 2560x1920
+                * or larger frames. If the sensor is proposing too big a frame,
+                * don't bother with possibly supportred by the CEU larger
+                * sizes, just try VGA multiples. If needed, this can be
+                * adjusted in the future.
+                */
+               while ((mf.width > pcdev->max_width ||
+                       mf.height > pcdev->max_height) && shift < 4) {
                        /* Try 2560x1920, 1280x960, 640x480, 320x240 */
                        mf.width        = 2560 >> shift;
                        mf.height       = 1920 >> shift;
@@ -1377,6 +1389,8 @@ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
 static int client_s_fmt(struct soc_camera_device *icd,
                        struct v4l2_mbus_framefmt *mf, bool ceu_can_scale)
 {
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct device *dev = icd->parent;
@@ -1410,8 +1424,8 @@ static int client_s_fmt(struct soc_camera_device *icd,
        if (ret < 0)
                return ret;
 
-       max_width = min(cap.bounds.width, 2560);
-       max_height = min(cap.bounds.height, 1920);
+       max_width = min(cap.bounds.width, pcdev->max_width);
+       max_height = min(cap.bounds.height, pcdev->max_height);
 
        /* Camera set a format, but geometry is not precise, try to improve */
        tmp_w = mf->width;
@@ -1551,7 +1565,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
        if (ret < 0)
                return ret;
 
-       if (mf.width > 2560 || mf.height > 1920)
+       if (mf.width > pcdev->max_width || mf.height > pcdev->max_height)
                return -EINVAL;
 
        /* 4. Calculate camera scales */
@@ -1834,6 +1848,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
 static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
                                 struct v4l2_format *f)
 {
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct sh_mobile_ceu_dev *pcdev = ici->priv;
        const struct soc_camera_format_xlate *xlate;
        struct v4l2_pix_format *pix = &f->fmt.pix;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -1854,8 +1870,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        /* FIXME: calculate using depth and bus width */
 
        /* CFSZR requires height and width to be 4-pixel aligned */
-       v4l_bound_align_image(&pix->width, 2, 2560, 2,
-                             &pix->height, 4, 1920, 2, 0);
+       v4l_bound_align_image(&pix->width, 2, pcdev->max_width, 2,
+                             &pix->height, 4, pcdev->max_height, 2, 0);
 
        width = pix->width;
        height = pix->height;
@@ -1890,8 +1906,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
                         * requested a bigger rectangle, it will not return a
                         * smaller one.
                         */
-                       mf.width = 2560;
-                       mf.height = 1920;
+                       mf.width = pcdev->max_width;
+                       mf.height = pcdev->max_height;
                        ret = v4l2_device_call_until_err(sd->v4l2_dev,
                                        soc_camera_grp_id(icd), video,
                                        try_mbus_fmt, &mf);
@@ -2082,6 +2098,9 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
                goto exit_kfree;
        }
 
+       pcdev->max_width = pcdev->pdata->max_width ? : 2560;
+       pcdev->max_height = pcdev->pdata->max_height ? : 1920;
+
        base = ioremap_nocache(res->start, resource_size(res));
        if (!base) {
                err = -ENXIO;
index b827107..eb25756 100644 (file)
@@ -526,10 +526,6 @@ static int soc_camera_open(struct file *file)
                        },
                };
 
-               ret = soc_camera_power_on(icd, icl);
-               if (ret < 0)
-                       goto epower;
-
                /* The camera could have been already on, try to reset */
                if (icl->reset)
                        icl->reset(icd->pdev);
@@ -540,6 +536,10 @@ static int soc_camera_open(struct file *file)
                        goto eiciadd;
                }
 
+               ret = soc_camera_power_on(icd, icl);
+               if (ret < 0)
+                       goto epower;
+
                pm_runtime_enable(&icd->vdev->dev);
                ret = pm_runtime_resume(&icd->vdev->dev);
                if (ret < 0 && ret != -ENOSYS)
@@ -578,10 +578,10 @@ einitvb:
 esfmt:
        pm_runtime_disable(&icd->vdev->dev);
 eresume:
-       ici->ops->remove(icd);
-eiciadd:
        soc_camera_power_off(icd, icl);
 epower:
+       ici->ops->remove(icd);
+eiciadd:
        icd->use_count--;
        module_put(ici->ops->owner);
 
@@ -1050,6 +1050,14 @@ static int soc_camera_probe(struct soc_camera_device *icd)
        if (ret < 0)
                goto ereg;
 
+       /* The camera could have been already on, try to reset */
+       if (icl->reset)
+               icl->reset(icd->pdev);
+
+       ret = ici->ops->add(icd);
+       if (ret < 0)
+               goto eadd;
+
        /*
         * This will not yet call v4l2_subdev_core_ops::s_power(1), because the
         * subdevice has not been initialised yet. We'll have to call it once
@@ -1060,14 +1068,6 @@ static int soc_camera_probe(struct soc_camera_device *icd)
        if (ret < 0)
                goto epower;
 
-       /* The camera could have been already on, try to reset */
-       if (icl->reset)
-               icl->reset(icd->pdev);
-
-       ret = ici->ops->add(icd);
-       if (ret < 0)
-               goto eadd;
-
        /* Must have icd->vdev before registering the device */
        ret = video_dev_create(icd);
        if (ret < 0)
@@ -1165,10 +1165,10 @@ eadddev:
        video_device_release(icd->vdev);
        icd->vdev = NULL;
 evdc:
-       ici->ops->remove(icd);
-eadd:
        soc_camera_power_off(icd, icl);
 epower:
+       ici->ops->remove(icd);
+eadd:
        regulator_bulk_free(icl->num_regulators, icl->regulators);
 ereg:
        v4l2_ctrl_handler_free(&icd->ctrl_handler);
index d1b07ac..e9d95bd 100644 (file)
@@ -864,18 +864,7 @@ static struct i2c_driver sr030pc30_i2c_driver = {
        .id_table       = sr030pc30_id,
 };
 
-static int __init sr030pc30_init(void)
-{
-       return i2c_add_driver(&sr030pc30_i2c_driver);
-}
-
-static void __exit sr030pc30_exit(void)
-{
-       i2c_del_driver(&sr030pc30_i2c_driver);
-}
-
-module_init(sr030pc30_init);
-module_exit(sr030pc30_exit);
+module_i2c_driver(sr030pc30_i2c_driver);
 
 MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
index bd21854..f7707e6 100644 (file)
@@ -482,15 +482,4 @@ static struct i2c_driver tda7432_driver = {
        .id_table       = tda7432_id,
 };
 
-static __init int init_tda7432(void)
-{
-       return i2c_add_driver(&tda7432_driver);
-}
-
-static __exit void exit_tda7432(void)
-{
-       i2c_del_driver(&tda7432_driver);
-}
-
-module_init(init_tda7432);
-module_exit(exit_tda7432);
+module_i2c_driver(tda7432_driver);
index 22fa820..465d708 100644 (file)
@@ -208,15 +208,4 @@ static struct i2c_driver tda9840_driver = {
        .id_table       = tda9840_id,
 };
 
-static __init int init_tda9840(void)
-{
-       return i2c_add_driver(&tda9840_driver);
-}
-
-static __exit void exit_tda9840(void)
-{
-       i2c_del_driver(&tda9840_driver);
-}
-
-module_init(init_tda9840);
-module_exit(exit_tda9840);
+module_i2c_driver(tda9840_driver);
index 827425c..d1d6ea1 100644 (file)
@@ -184,15 +184,4 @@ static struct i2c_driver tea6415c_driver = {
        .id_table       = tea6415c_id,
 };
 
-static __init int init_tea6415c(void)
-{
-       return i2c_add_driver(&tea6415c_driver);
-}
-
-static __exit void exit_tea6415c(void)
-{
-       i2c_del_driver(&tea6415c_driver);
-}
-
-module_init(init_tea6415c);
-module_exit(exit_tea6415c);
+module_i2c_driver(tea6415c_driver);
index f350b6c..3875721 100644 (file)
@@ -166,15 +166,4 @@ static struct i2c_driver tea6420_driver = {
        .id_table       = tea6420_id,
 };
 
-static __init int init_tea6420(void)
-{
-       return i2c_add_driver(&tea6420_driver);
-}
-
-static __exit void exit_tea6420(void)
-{
-       i2c_del_driver(&tea6420_driver);
-}
-
-module_init(init_tea6420);
-module_exit(exit_tea6420);
+module_i2c_driver(tea6420_driver);
index 61b1dd1..e5c0eed 100644 (file)
@@ -137,16 +137,4 @@ static struct i2c_driver ths7303_driver = {
        .id_table       = ths7303_id,
 };
 
-static int __init ths7303_init(void)
-{
-       return i2c_add_driver(&ths7303_driver);
-}
-
-static void __exit ths7303_exit(void)
-{
-       i2c_del_driver(&ths7303_driver);
-}
-
-module_init(ths7303_init);
-module_exit(ths7303_exit);
-
+module_i2c_driver(ths7303_driver);
index 286ec7e..809a75a 100644 (file)
@@ -227,15 +227,4 @@ static struct i2c_driver tlv320aic23b_driver = {
        .id_table       = tlv320aic23b_id,
 };
 
-static __init int init_tlv320aic23b(void)
-{
-       return i2c_add_driver(&tlv320aic23b_driver);
-}
-
-static __exit void exit_tlv320aic23b(void)
-{
-       i2c_del_driver(&tlv320aic23b_driver);
-}
-
-module_init(init_tlv320aic23b);
-module_exit(exit_tlv320aic23b);
+module_i2c_driver(tlv320aic23b_driver);
index 7844607..859eb90 100644 (file)
@@ -481,8 +481,6 @@ int tm6000_ir_fini(struct tm6000_core *dev)
 
        dprintk(2, "%s\n",__func__);
 
-       rc_unregister_device(ir->rc);
-
        if (!ir->polling)
                __tm6000_ir_int_stop(ir->rc);
 
@@ -492,6 +490,7 @@ int tm6000_ir_fini(struct tm6000_core *dev)
        tm6000_flash_led(dev, 0);
        ir->pwled = 0;
 
+       rc_unregister_device(ir->rc);
 
        kfree(ir);
        dev->ir = NULL;
index 4059ea1..a5c6397 100644 (file)
@@ -380,6 +380,21 @@ static void set_type(struct i2c_client *c, unsigned int type,
                tune_now = 0;
                break;
        }
+       case TUNER_XC5000C:
+       {
+               struct xc5000_config xc5000c_cfg = {
+                       .i2c_address = t->i2c->addr,
+                       /* if_khz will be set at dvb_attach() */
+                       .if_khz   = 0,
+                       .chip_id  = XC5000C,
+               };
+
+               if (!dvb_attach(xc5000_attach,
+                               &t->fe, t->i2c->adapter, &xc5000c_cfg))
+                       goto attach_failed;
+               tune_now = 0;
+               break;
+       }
        case TUNER_NXP_TDA18271:
        {
                struct tda18271_config cfg = {
@@ -1314,18 +1329,7 @@ static struct i2c_driver tuner_driver = {
        .id_table       = tuner_id,
 };
 
-static __init int init_tuner(void)
-{
-       return i2c_add_driver(&tuner_driver);
-}
-
-static __exit void exit_tuner(void)
-{
-       i2c_del_driver(&tuner_driver);
-}
-
-module_init(init_tuner);
-module_exit(exit_tuner);
+module_i2c_driver(tuner_driver);
 
 MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
 MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
index f22dbef..c5b1a73 100644 (file)
@@ -2078,15 +2078,4 @@ static struct i2c_driver tvaudio_driver = {
        .id_table       = tvaudio_id,
 };
 
-static __init int init_tvaudio(void)
-{
-       return i2c_add_driver(&tvaudio_driver);
-}
-
-static __exit void exit_tvaudio(void)
-{
-       i2c_del_driver(&tvaudio_driver);
-}
-
-module_init(init_tvaudio);
-module_exit(exit_tvaudio);
+module_i2c_driver(tvaudio_driver);
index 6103d1b..3b6cf03 100644 (file)
@@ -286,8 +286,16 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,                 "MaxLinear 301"},
        { TUNER_ABSENT,                 "Mirics MSi001"},
        { TUNER_ABSENT,                 "MaxLinear MxL241SF"},
-       { TUNER_ABSENT,                 "Xceive XC5000C"},
+       { TUNER_XC5000C,                "Xceive XC5000C"},
        { TUNER_ABSENT,                 "Montage M68TS2020"},
+       { TUNER_ABSENT,                 "Siano SMS1530"},
+       { TUNER_ABSENT,                 "Dibcom 7090"},
+       { TUNER_ABSENT,                 "Xceive XC5200C"},
+       { TUNER_ABSENT,                 "NXP 18273"},
+       { TUNER_ABSENT,                 "Montage M88TS2022"},
+       /* 180-189 */
+       { TUNER_ABSENT,                 "NXP 18272M"},
+       { TUNER_ABSENT,                 "NXP 18272S"},
 };
 
 /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
index dd26cac..cd615c1 100644 (file)
@@ -1163,15 +1163,4 @@ static struct i2c_driver tvp514x_driver = {
        .id_table = tvp514x_id,
 };
 
-static int __init tvp514x_init(void)
-{
-       return i2c_add_driver(&tvp514x_driver);
-}
-
-static void __exit tvp514x_exit(void)
-{
-       i2c_del_driver(&tvp514x_driver);
-}
-
-module_init(tvp514x_init);
-module_exit(tvp514x_exit);
+module_i2c_driver(tvp514x_driver);
index 6be9910..1326e11 100644 (file)
 
 #include "tvp5150_reg.h"
 
+#define TVP5150_H_MAX          720
+#define TVP5150_V_MAX_525_60   480
+#define TVP5150_V_MAX_OTHERS   576
+#define TVP5150_MAX_CROP_LEFT  511
+#define TVP5150_MAX_CROP_TOP   127
+#define TVP5150_CROP_SHIFT     2
+
 MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL");
@@ -29,6 +36,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
 struct tvp5150 {
        struct v4l2_subdev sd;
        struct v4l2_ctrl_handler hdl;
+       struct v4l2_rect rect;
 
        v4l2_std_id norm;       /* Current set standard */
        u32 input;
@@ -732,6 +740,13 @@ static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
        if (decoder->norm == std)
                return 0;
 
+       /* Change cropping height limits */
+       if (std & V4L2_STD_525_60)
+               decoder->rect.height = TVP5150_V_MAX_525_60;
+       else
+               decoder->rect.height = TVP5150_V_MAX_OTHERS;
+
+
        return tvp5150_set_std(sd, std);
 }
 
@@ -828,11 +843,8 @@ static int tvp5150_mbus_fmt(struct v4l2_subdev *sd,
        else
                std = decoder->norm;
 
-       f->width = 720;
-       if (std & V4L2_STD_525_60)
-               f->height = 480;
-       else
-               f->height = 576;
+       f->width = decoder->rect.width;
+       f->height = decoder->rect.height;
 
        f->code = V4L2_MBUS_FMT_YUYV8_2X8;
        f->field = V4L2_FIELD_SEQ_TB;
@@ -843,6 +855,99 @@ static int tvp5150_mbus_fmt(struct v4l2_subdev *sd,
        return 0;
 }
 
+static int tvp5150_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+       struct v4l2_rect rect = a->c;
+       struct tvp5150 *decoder = to_tvp5150(sd);
+       v4l2_std_id std;
+       int hmax;
+
+       v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n",
+               __func__, rect.left, rect.top, rect.width, rect.height);
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       /* tvp5150 has some special limits */
+       rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
+       rect.width = clamp(rect.width,
+                          TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
+                          TVP5150_H_MAX - rect.left);
+       rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
+
+       /* Calculate height based on current standard */
+       if (decoder->norm == V4L2_STD_ALL)
+               std = tvp5150_read_std(sd);
+       else
+               std = decoder->norm;
+
+       if (std & V4L2_STD_525_60)
+               hmax = TVP5150_V_MAX_525_60;
+       else
+               hmax = TVP5150_V_MAX_OTHERS;
+
+       rect.height = clamp(rect.height,
+                           hmax - TVP5150_MAX_CROP_TOP - rect.top,
+                           hmax - rect.top);
+
+       tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top);
+       tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,
+                     rect.top + rect.height - hmax);
+       tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB,
+                     rect.left >> TVP5150_CROP_SHIFT);
+       tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB,
+                     rect.left | (1 << TVP5150_CROP_SHIFT));
+       tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB,
+                     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
+                     TVP5150_CROP_SHIFT);
+       tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB,
+                     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
+
+       decoder->rect = rect;
+
+       return 0;
+}
+
+static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+       struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+
+       a->c    = decoder->rect;
+       a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       return 0;
+}
+
+static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+       struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+       v4l2_std_id std;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       a->bounds.left                  = 0;
+       a->bounds.top                   = 0;
+       a->bounds.width                 = TVP5150_H_MAX;
+
+       /* Calculate height based on current standard */
+       if (decoder->norm == V4L2_STD_ALL)
+               std = tvp5150_read_std(sd);
+       else
+               std = decoder->norm;
+
+       if (std & V4L2_STD_525_60)
+               a->bounds.height = TVP5150_V_MAX_525_60;
+       else
+               a->bounds.height = TVP5150_V_MAX_OTHERS;
+
+       a->defrect                      = a->bounds;
+       a->pixelaspect.numerator        = 1;
+       a->pixelaspect.denominator      = 1;
+
+       return 0;
+}
+
 /****************************************************************************
                        I2C Command
  ****************************************************************************/
@@ -998,6 +1103,10 @@ static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
        .enum_mbus_fmt = tvp5150_enum_mbus_fmt,
        .s_mbus_fmt = tvp5150_mbus_fmt,
        .try_mbus_fmt = tvp5150_mbus_fmt,
+       .g_mbus_fmt = tvp5150_mbus_fmt,
+       .s_crop = tvp5150_s_crop,
+       .g_crop = tvp5150_g_crop,
+       .cropcap = tvp5150_cropcap,
 };
 
 static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
@@ -1083,6 +1192,15 @@ static int tvp5150_probe(struct i2c_client *c,
        }
        v4l2_ctrl_handler_setup(&core->hdl);
 
+       /* Default is no cropping */
+       core->rect.top = 0;
+       if (tvp5150_read_std(sd) & V4L2_STD_525_60)
+               core->rect.height = TVP5150_V_MAX_525_60;
+       else
+               core->rect.height = TVP5150_V_MAX_OTHERS;
+       core->rect.left = 0;
+       core->rect.width = TVP5150_H_MAX;
+
        if (debug > 1)
                tvp5150_log_status(sd);
        return 0;
@@ -1121,15 +1239,4 @@ static struct i2c_driver tvp5150_driver = {
        .id_table       = tvp5150_id,
 };
 
-static __init int init_tvp5150(void)
-{
-       return i2c_add_driver(&tvp5150_driver);
-}
-
-static __exit void exit_tvp5150(void)
-{
-       i2c_del_driver(&tvp5150_driver);
-}
-
-module_init(init_tvp5150);
-module_exit(exit_tvp5150);
+module_i2c_driver(tvp5150_driver);
index 236c559..d7676d8 100644 (file)
@@ -1069,27 +1069,4 @@ static struct i2c_driver tvp7002_driver = {
        .id_table = tvp7002_id,
 };
 
-/*
- * tvp7002_init - Initialize driver via I2C interface
- *
- * Register the TVP7002 driver.
- * Return 0 on success or error code on failure.
- */
-static int __init tvp7002_init(void)
-{
-       return i2c_add_driver(&tvp7002_driver);
-}
-
-/*
- * tvp7002_exit - Remove driver via I2C interface
- *
- * Unregister the TVP7002 driver.
- * Returns nothing.
- */
-static void __exit tvp7002_exit(void)
-{
-       i2c_del_driver(&tvp7002_driver);
-}
-
-module_init(tvp7002_init);
-module_exit(tvp7002_exit);
+module_i2c_driver(tvp7002_driver);
index a514fa6..8768efb 100644 (file)
@@ -951,21 +951,7 @@ static struct i2c_driver tw9910_i2c_driver = {
        .id_table = tw9910_id,
 };
 
-/*
- * module function
- */
-static int __init tw9910_module_init(void)
-{
-       return i2c_add_driver(&tw9910_i2c_driver);
-}
-
-static void __exit tw9910_module_exit(void)
-{
-       i2c_del_driver(&tw9910_i2c_driver);
-}
-
-module_init(tw9910_module_init);
-module_exit(tw9910_module_exit);
+module_i2c_driver(tw9910_i2c_driver);
 
 MODULE_DESCRIPTION("SoC Camera driver for tw9910");
 MODULE_AUTHOR("Kuninori Morimoto");
index 1aab96a..1e74465 100644 (file)
@@ -271,15 +271,4 @@ static struct i2c_driver upd64031a_driver = {
        .id_table       = upd64031a_id,
 };
 
-static __init int init_upd64031a(void)
-{
-       return i2c_add_driver(&upd64031a_driver);
-}
-
-static __exit void exit_upd64031a(void)
-{
-       i2c_del_driver(&upd64031a_driver);
-}
-
-module_init(init_upd64031a);
-module_exit(exit_upd64031a);
+module_i2c_driver(upd64031a_driver);
index 65d065a..75d6acc 100644 (file)
@@ -243,15 +243,4 @@ static struct i2c_driver upd64083_driver = {
        .id_table       = upd64083_id,
 };
 
-static __init int init_upd64083(void)
-{
-       return i2c_add_driver(&upd64083_driver);
-}
-
-static __exit void exit_upd64083(void)
-{
-       i2c_del_driver(&upd64083_driver);
-}
-
-module_init(init_upd64083);
-module_exit(exit_upd64083);
+module_i2c_driver(upd64083_driver);
index a240d43..1d13172 100644 (file)
@@ -23,6 +23,7 @@
  * codec can't handle MJPEG data.
  */
 
+#include <linux/atomic.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -32,7 +33,6 @@
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <linux/version.h>
-#include <asm/atomic.h>
 #include <asm/unaligned.h>
 
 #include <media/v4l2-common.h>
@@ -2139,6 +2139,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX },
+       /* Dell XPS m1530 */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x05a9,
+         .idProduct            = 0x2640,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_DEF },
        /* Apple Built-In iSight */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
index 518f77d..8f54e24 100644 (file)
@@ -126,7 +126,7 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
                    int drop_corrupted)
 {
        queue->queue.type = type;
-       queue->queue.io_modes = VB2_MMAP;
+       queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
        queue->queue.drv_priv = queue;
        queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
        queue->queue.ops = &uvc_queue_qops;
index 2ae4f88..ff2cddd 100644 (file)
@@ -11,6 +11,7 @@
  *
  */
 
+#include <linux/compat.h>
 #include <linux/kernel.h>
 #include <linux/version.h>
 #include <linux/list.h>
@@ -1012,7 +1013,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        default:
                uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd);
-               return -EINVAL;
+               return -ENOTTY;
        }
 
        return ret;
@@ -1030,6 +1031,207 @@ static long uvc_v4l2_ioctl(struct file *file,
        return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
 }
 
+#ifdef CONFIG_COMPAT
+struct uvc_xu_control_mapping32 {
+       __u32 id;
+       __u8 name[32];
+       __u8 entity[16];
+       __u8 selector;
+
+       __u8 size;
+       __u8 offset;
+       __u32 v4l2_type;
+       __u32 data_type;
+
+       compat_caddr_t menu_info;
+       __u32 menu_count;
+
+       __u32 reserved[4];
+};
+
+static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp,
+                       const struct uvc_xu_control_mapping32 __user *up)
+{
+       struct uvc_menu_info __user *umenus;
+       struct uvc_menu_info __user *kmenus;
+       compat_caddr_t p;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           __copy_from_user(kp, up, offsetof(typeof(*up), menu_info)) ||
+           __get_user(kp->menu_count, &up->menu_count))
+               return -EFAULT;
+
+       memset(kp->reserved, 0, sizeof(kp->reserved));
+
+       if (kp->menu_count == 0) {
+               kp->menu_info = NULL;
+               return 0;
+       }
+
+       if (__get_user(p, &up->menu_info))
+               return -EFAULT;
+       umenus = compat_ptr(p);
+       if (!access_ok(VERIFY_READ, umenus, kp->menu_count * sizeof(*umenus)))
+               return -EFAULT;
+
+       kmenus = compat_alloc_user_space(kp->menu_count * sizeof(*kmenus));
+       if (kmenus == NULL)
+               return -EFAULT;
+       kp->menu_info = kmenus;
+
+       if (copy_in_user(kmenus, umenus, kp->menu_count * sizeof(*umenus)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
+                       struct uvc_xu_control_mapping32 __user *up)
+{
+       struct uvc_menu_info __user *umenus;
+       struct uvc_menu_info __user *kmenus = kp->menu_info;
+       compat_caddr_t p;
+
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) ||
+           __put_user(kp->menu_count, &up->menu_count))
+               return -EFAULT;
+
+       __clear_user(up->reserved, sizeof(up->reserved));
+
+       if (kp->menu_count == 0)
+               return 0;
+
+       if (get_user(p, &up->menu_info))
+               return -EFAULT;
+       umenus = compat_ptr(p);
+       if (!access_ok(VERIFY_WRITE, umenus, kp->menu_count * sizeof(*umenus)))
+               return -EFAULT;
+
+       if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus)))
+               return -EFAULT;
+
+       return 0;
+}
+
+struct uvc_xu_control_query32 {
+       __u8 unit;
+       __u8 selector;
+       __u8 query;
+       __u16 size;
+       compat_caddr_t data;
+};
+
+static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp,
+                       const struct uvc_xu_control_query32 __user *up)
+{
+       u8 __user *udata;
+       u8 __user *kdata;
+       compat_caddr_t p;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           __copy_from_user(kp, up, offsetof(typeof(*up), data)))
+               return -EFAULT;
+
+       if (kp->size == 0) {
+               kp->data = NULL;
+               return 0;
+       }
+
+       if (__get_user(p, &up->data))
+               return -EFAULT;
+       udata = compat_ptr(p);
+       if (!access_ok(VERIFY_READ, udata, kp->size))
+               return -EFAULT;
+
+       kdata = compat_alloc_user_space(kp->size);
+       if (kdata == NULL)
+               return -EFAULT;
+       kp->data = kdata;
+
+       if (copy_in_user(kdata, udata, kp->size))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp,
+                       struct uvc_xu_control_query32 __user *up)
+{
+       u8 __user *udata;
+       u8 __user *kdata = kp->data;
+       compat_caddr_t p;
+
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           __copy_to_user(up, kp, offsetof(typeof(*up), data)))
+               return -EFAULT;
+
+       if (kp->size == 0)
+               return 0;
+
+       if (get_user(p, &up->data))
+               return -EFAULT;
+       udata = compat_ptr(p);
+       if (!access_ok(VERIFY_READ, udata, kp->size))
+               return -EFAULT;
+
+       if (copy_in_user(udata, kdata, kp->size))
+               return -EFAULT;
+
+       return 0;
+}
+
+#define UVCIOC_CTRL_MAP32      _IOWR('u', 0x20, struct uvc_xu_control_mapping32)
+#define UVCIOC_CTRL_QUERY32    _IOWR('u', 0x21, struct uvc_xu_control_query32)
+
+static long uvc_v4l2_compat_ioctl32(struct file *file,
+                    unsigned int cmd, unsigned long arg)
+{
+       union {
+               struct uvc_xu_control_mapping xmap;
+               struct uvc_xu_control_query xqry;
+       } karg;
+       void __user *up = compat_ptr(arg);
+       mm_segment_t old_fs;
+       long ret;
+
+       switch (cmd) {
+       case UVCIOC_CTRL_MAP32:
+               cmd = UVCIOC_CTRL_MAP;
+               ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up);
+               break;
+
+       case UVCIOC_CTRL_QUERY32:
+               cmd = UVCIOC_CTRL_QUERY;
+               ret = uvc_v4l2_get_xu_query(&karg.xqry, up);
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = uvc_v4l2_ioctl(file, cmd, (unsigned long)&karg);
+       set_fs(old_fs);
+
+       if (ret < 0)
+               return ret;
+
+       switch (cmd) {
+       case UVCIOC_CTRL_MAP:
+               ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
+               break;
+
+       case UVCIOC_CTRL_QUERY:
+               ret = uvc_v4l2_put_xu_query(&karg.xqry, up);
+               break;
+       }
+
+       return ret;
+}
+#endif
+
 static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
                    size_t count, loff_t *ppos)
 {
@@ -1076,6 +1278,9 @@ const struct v4l2_file_operations uvc_fops = {
        .open           = uvc_v4l2_open,
        .release        = uvc_v4l2_release,
        .unlocked_ioctl = uvc_v4l2_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl32 = uvc_v4l2_compat_ioctl32,
+#endif
        .read           = uvc_v4l2_read,
        .mmap           = uvc_v4l2_mmap,
        .poll           = uvc_v4l2_poll,
index af4419e..2829d25 100644 (file)
  */
 
 #include <linux/compat.h>
-#include <linux/videodev2.h>
 #include <linux/module.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
 
-#ifdef CONFIG_COMPAT
-
 static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        long ret = -ENOIOCTLCMD;
@@ -937,6 +936,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
 
 long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
 {
+       struct video_device *vdev = video_devdata(file);
        long ret = -ENOIOCTLCMD;
 
        if (!file->f_op->unlocked_ioctl)
@@ -1005,6 +1005,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
        case VIDIOC_G_ENC_INDEX:
        case VIDIOC_ENCODER_CMD:
        case VIDIOC_TRY_ENCODER_CMD:
+       case VIDIOC_DECODER_CMD:
+       case VIDIOC_TRY_DECODER_CMD:
        case VIDIOC_DBG_S_REGISTER:
        case VIDIOC_DBG_G_REGISTER:
        case VIDIOC_DBG_G_CHIP_IDENT:
@@ -1025,14 +1027,16 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
                break;
 
        default:
-               printk(KERN_WARNING "compat_ioctl32: "
-                       "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
-                       _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
+               if (vdev->fops->compat_ioctl32)
+                       ret = vdev->fops->compat_ioctl32(file, cmd, arg);
+
+               if (ret == -ENOIOCTLCMD)
+                       printk(KERN_WARNING "compat_ioctl32: "
+                               "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
+                               _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd),
+                               cmd);
                break;
        }
        return ret;
 }
 EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
-#endif
-
-MODULE_LICENSE("GPL");
index cccd42b..18015c0 100644 (file)
@@ -175,6 +175,15 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                "16-bit CRC",
                NULL
        };
+       static const char * const mpeg_audio_dec_playback[] = {
+               "Auto",
+               "Stereo",
+               "Left",
+               "Right",
+               "Mono",
+               "Swapped Stereo",
+               NULL
+       };
        static const char * const mpeg_video_encoding[] = {
                "MPEG-1",
                "MPEG-2",
@@ -236,8 +245,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
        };
        static const char * const tune_preemphasis[] = {
                "No Preemphasis",
-               "50 useconds",
-               "75 useconds",
+               "50 Microseconds",
+               "75 Microseconds",
                NULL,
        };
        static const char * const header_mode[] = {
@@ -334,7 +343,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
        };
        static const char * const mpeg4_profile[] = {
                "Simple",
-               "Adcanved Simple",
+               "Advanced Simple",
                "Core",
                "Simple Scalable",
                "Advanced Coding Efficency",
@@ -353,6 +362,16 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                NULL,
        };
 
+       static const char * const jpeg_chroma_subsampling[] = {
+               "4:4:4",
+               "4:2:2",
+               "4:2:0",
+               "4:1:1",
+               "4:1:0",
+               "Gray",
+               NULL,
+       };
+
        switch (id) {
        case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
                return mpeg_audio_sampling_freq;
@@ -374,6 +393,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                return mpeg_audio_emphasis;
        case V4L2_CID_MPEG_AUDIO_CRC:
                return mpeg_audio_crc;
+       case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+       case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
+               return mpeg_audio_dec_playback;
        case V4L2_CID_MPEG_VIDEO_ENCODING:
                return mpeg_video_encoding;
        case V4L2_CID_MPEG_VIDEO_ASPECT:
@@ -414,6 +436,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                return mpeg_mpeg4_level;
        case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
                return mpeg4_profile;
+       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+               return jpeg_chroma_subsampling;
+
        default:
                return NULL;
        }
@@ -492,6 +517,8 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_MPEG_AUDIO_MUTE:          return "Audio Mute";
        case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:   return "Audio AAC Bitrate";
        case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:   return "Audio AC-3 Bitrate";
+       case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:  return "Audio Playback";
+       case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: return "Audio Multilingual Playback";
        case V4L2_CID_MPEG_VIDEO_ENCODING:      return "Video Encoding";
        case V4L2_CID_MPEG_VIDEO_ASPECT:        return "Video Aspect";
        case V4L2_CID_MPEG_VIDEO_B_FRAMES:      return "Video B Frames";
@@ -546,6 +573,8 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:            return "Number of MBs in a Slice";
        case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:              return "Slice Partitioning Method";
        case V4L2_CID_MPEG_VIDEO_VBV_SIZE:                      return "VBV Buffer Size";
+       case V4L2_CID_MPEG_VIDEO_DEC_PTS:                       return "Video Decoder PTS";
+       case V4L2_CID_MPEG_VIDEO_DEC_FRAME:                     return "Video Decoder Frame Count";
 
        /* CAMERA controls */
        /* Keep the order of the 'case's the same as in videodev2.h! */
@@ -607,6 +636,14 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_FLASH_CHARGE:             return "Charge";
        case V4L2_CID_FLASH_READY:              return "Ready to Strobe";
 
+       /* JPEG encoder controls */
+       /* Keep the order of the 'case's the same as in videodev2.h! */
+       case V4L2_CID_JPEG_CLASS:               return "JPEG Compression Controls";
+       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:  return "Chroma Subsampling";
+       case V4L2_CID_JPEG_RESTART_INTERVAL:    return "Restart Interval";
+       case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality";
+       case V4L2_CID_JPEG_ACTIVE_MARKER:       return "Active Markers";
+
        default:
                return NULL;
        }
@@ -674,6 +711,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
        case V4L2_CID_MPEG_AUDIO_EMPHASIS:
        case V4L2_CID_MPEG_AUDIO_CRC:
+       case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
+       case V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK:
        case V4L2_CID_MPEG_VIDEO_ENCODING:
        case V4L2_CID_MPEG_VIDEO_ASPECT:
        case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
@@ -693,6 +732,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
        case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
        case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+       case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
                *type = V4L2_CTRL_TYPE_MENU;
                break;
        case V4L2_CID_RDS_TX_PS_NAME:
@@ -704,6 +744,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_MPEG_CLASS:
        case V4L2_CID_FM_TX_CLASS:
        case V4L2_CID_FLASH_CLASS:
+       case V4L2_CID_JPEG_CLASS:
                *type = V4L2_CTRL_TYPE_CTRL_CLASS;
                /* You can neither read not write these */
                *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -717,6 +758,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
                *max = 0xFFFFFF;
                break;
        case V4L2_CID_FLASH_FAULT:
+       case V4L2_CID_JPEG_ACTIVE_MARKER:
                *type = V4L2_CTRL_TYPE_BITMASK;
                break;
        case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
@@ -724,6 +766,11 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
                *type = V4L2_CTRL_TYPE_INTEGER;
                *flags |= V4L2_CTRL_FLAG_READ_ONLY;
                break;
+       case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
+       case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+               *type = V4L2_CTRL_TYPE_INTEGER64;
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE;
+               break;
        default:
                *type = V4L2_CTRL_TYPE_INTEGER;
                break;
@@ -1470,7 +1517,7 @@ EXPORT_SYMBOL(v4l2_ctrl_add_ctrl);
 int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
                          struct v4l2_ctrl_handler *add)
 {
-       struct v4l2_ctrl *ctrl;
+       struct v4l2_ctrl_ref *ref;
        int ret = 0;
 
        /* Do nothing if either handler is NULL or if they are the same */
@@ -1479,7 +1526,9 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
        if (hdl->error)
                return hdl->error;
        mutex_lock(&add->lock);
-       list_for_each_entry(ctrl, &add->ctrls, node) {
+       list_for_each_entry(ref, &add->ctrl_refs, node) {
+               struct v4l2_ctrl *ctrl = ref->ctrl;
+
                /* Skip handler-private controls. */
                if (ctrl->is_private)
                        continue;
@@ -2359,3 +2408,35 @@ void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
        v4l2_ctrl_unlock(ctrl);
 }
 EXPORT_SYMBOL(v4l2_ctrl_del_event);
+
+int v4l2_ctrl_log_status(struct file *file, void *fh)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct v4l2_fh *vfh = file->private_data;
+
+       if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev)
+               v4l2_ctrl_handler_log_status(vfh->ctrl_handler,
+                       vfd->v4l2_dev->name);
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_log_status);
+
+int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
+                               struct v4l2_event_subscription *sub)
+{
+       if (sub->type == V4L2_EVENT_CTRL)
+               return v4l2_event_subscribe(fh, sub, 0);
+       return -EINVAL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
+
+unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       if (v4l2_event_pending(fh))
+               return POLLPRI;
+       poll_wait(file, &fh->wait, wait);
+       return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_poll);
index 8546f81..70bec54 100644 (file)
@@ -787,7 +787,7 @@ static void __exit videodev_exit(void)
        unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
 }
 
-module_init(videodev_init)
+subsys_initcall(videodev_init);
 module_exit(videodev_exit)
 
 MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
index 3f62385..5b2ec1f 100644 (file)
@@ -260,6 +260,8 @@ static const char *v4l2_ioctls[] = {
        [_IOC_NR(VIDIOC_ENCODER_CMD)]      = "VIDIOC_ENCODER_CMD",
        [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)]  = "VIDIOC_TRY_ENCODER_CMD",
 
+       [_IOC_NR(VIDIOC_DECODER_CMD)]      = "VIDIOC_DECODER_CMD",
+       [_IOC_NR(VIDIOC_TRY_DECODER_CMD)]  = "VIDIOC_TRY_DECODER_CMD",
        [_IOC_NR(VIDIOC_DBG_S_REGISTER)]   = "VIDIOC_DBG_S_REGISTER",
        [_IOC_NR(VIDIOC_DBG_G_REGISTER)]   = "VIDIOC_DBG_G_REGISTER",
 
@@ -540,10 +542,12 @@ static long __video_do_ioctl(struct file *file,
                if (!ret)
                        dbgarg(cmd, "driver=%s, card=%s, bus=%s, "
                                        "version=0x%08x, "
-                                       "capabilities=0x%08x\n",
+                                       "capabilities=0x%08x, "
+                                       "device_caps=0x%08x\n",
                                        cap->driver, cap->card, cap->bus_info,
                                        cap->version,
-                                       cap->capabilities);
+                                       cap->capabilities,
+                                       cap->device_caps);
                break;
        }
 
@@ -1762,6 +1766,32 @@ static long __video_do_ioctl(struct file *file,
                        dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
                break;
        }
+       case VIDIOC_DECODER_CMD:
+       {
+               struct v4l2_decoder_cmd *p = arg;
+
+               if (!ops->vidioc_decoder_cmd)
+                       break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
+               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;
+
+               if (!ops->vidioc_try_decoder_cmd)
+                       break;
+               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;
@@ -1909,7 +1939,13 @@ static long __video_do_ioctl(struct file *file,
        {
                if (!ops->vidioc_log_status)
                        break;
+               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;
        }
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -2419,7 +2455,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
        /* Handles IOCTL */
        err = func(file, cmd, parg);
        if (err == -ENOIOCTLCMD)
-               err = -EINVAL;
+               err = -ENOTTY;
 
        if (has_array_args) {
                *kernel_ptr = user_ptr;
index 41d118e..6fe88e9 100644 (file)
@@ -194,8 +194,16 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        }
 #endif
 
-       case VIDIOC_LOG_STATUS:
-               return v4l2_subdev_call(sd, core, log_status);
+       case VIDIOC_LOG_STATUS: {
+               int ret;
+
+               pr_info("%s: =================  START STATUS  =================\n",
+                       sd->name);
+               ret = v4l2_subdev_call(sd, core, log_status);
+               pr_info("%s: ==================  END STATUS  ==================\n",
+                       sd->name);
+               return ret;
+       }
 
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
        case VIDIOC_SUBDEV_G_FMT: {
index 4e789a1..6b5ca6c 100644 (file)
@@ -10,6 +10,7 @@
  * the Free Software Foundation.
  */
 
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
@@ -22,6 +23,7 @@
 struct vb2_vmalloc_buf {
        void                            *vaddr;
        struct page                     **pages;
+       struct vm_area_struct           *vma;
        int                             write;
        unsigned long                   size;
        unsigned int                    n_pages;
@@ -71,6 +73,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
        struct vb2_vmalloc_buf *buf;
        unsigned long first, last;
        int n_pages, offset;
+       struct vm_area_struct *vma;
+       dma_addr_t physp;
 
        buf = kzalloc(sizeof(*buf), GFP_KERNEL);
        if (!buf)
@@ -80,23 +84,37 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
        offset = vaddr & ~PAGE_MASK;
        buf->size = size;
 
-       first = vaddr >> PAGE_SHIFT;
-       last  = (vaddr + size - 1) >> PAGE_SHIFT;
-       buf->n_pages = last - first + 1;
-       buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), GFP_KERNEL);
-       if (!buf->pages)
-               goto fail_pages_array_alloc;
 
-       /* current->mm->mmap_sem is taken by videobuf2 core */
-       n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK,
-                                buf->n_pages, write, 1, /* force */
-                                buf->pages, NULL);
-       if (n_pages != buf->n_pages)
-               goto fail_get_user_pages;
-
-       buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL);
-       if (!buf->vaddr)
-               goto fail_get_user_pages;
+       vma = find_vma(current->mm, vaddr);
+       if (vma && (vma->vm_flags & VM_PFNMAP) && (vma->vm_pgoff)) {
+               if (vb2_get_contig_userptr(vaddr, size, &vma, &physp))
+                       goto fail_pages_array_alloc;
+               buf->vma = vma;
+               buf->vaddr = ioremap_nocache(physp, size);
+               if (!buf->vaddr)
+                       goto fail_pages_array_alloc;
+       } else {
+               first = vaddr >> PAGE_SHIFT;
+               last  = (vaddr + size - 1) >> PAGE_SHIFT;
+               buf->n_pages = last - first + 1;
+               buf->pages = kzalloc(buf->n_pages * sizeof(struct page *),
+                                    GFP_KERNEL);
+               if (!buf->pages)
+                       goto fail_pages_array_alloc;
+
+               /* current->mm->mmap_sem is taken by videobuf2 core */
+               n_pages = get_user_pages(current, current->mm,
+                                        vaddr & PAGE_MASK, buf->n_pages,
+                                        write, 1, /* force */
+                                        buf->pages, NULL);
+               if (n_pages != buf->n_pages)
+                       goto fail_get_user_pages;
+
+               buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1,
+                                       PAGE_KERNEL);
+               if (!buf->vaddr)
+                       goto fail_get_user_pages;
+       }
 
        buf->vaddr += offset;
        return buf;
@@ -120,14 +138,20 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
        unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK;
        unsigned int i;
 
-       if (vaddr)
-               vm_unmap_ram((void *)vaddr, buf->n_pages);
-       for (i = 0; i < buf->n_pages; ++i) {
-               if (buf->write)
-                       set_page_dirty_lock(buf->pages[i]);
-               put_page(buf->pages[i]);
+       if (buf->pages) {
+               if (vaddr)
+                       vm_unmap_ram((void *)vaddr, buf->n_pages);
+               for (i = 0; i < buf->n_pages; ++i) {
+                       if (buf->write)
+                               set_page_dirty_lock(buf->pages[i]);
+                       put_page(buf->pages[i]);
+               }
+               kfree(buf->pages);
+       } else {
+               if (buf->vma)
+                       vb2_put_vma(buf->vma);
+               iounmap(buf->vaddr);
        }
-       kfree(buf->pages);
        kfree(buf);
 }
 
index 7d754fb..5e8b071 100644 (file)
@@ -819,8 +819,9 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strcpy(cap->driver, "vivi");
        strcpy(cap->card, "vivi");
        strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
                            V4L2_CAP_READWRITE;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -958,14 +959,6 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
        return vb2_streamoff(&dev->vb_vidq, i);
 }
 
-static int vidioc_log_status(struct file *file, void *priv)
-{
-       struct vivi_dev *dev = video_drvdata(file);
-
-       v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name);
-       return 0;
-}
-
 static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
 {
        return 0;
@@ -1008,17 +1001,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
        return 0;
 }
 
-static int vidioc_subscribe_event(struct v4l2_fh *fh,
-                               struct v4l2_event_subscription *sub)
-{
-       switch (sub->type) {
-       case V4L2_EVENT_CTRL:
-               return v4l2_event_subscribe(fh, sub, 0);
-       default:
-               return -EINVAL;
-       }
-}
-
 /* --- controls ---------------------------------------------- */
 
 static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -1209,8 +1191,8 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
        .vidioc_s_input       = vidioc_s_input,
        .vidioc_streamon      = vidioc_streamon,
        .vidioc_streamoff     = vidioc_streamoff,
-       .vidioc_log_status    = vidioc_log_status,
-       .vidioc_subscribe_event = vidioc_subscribe_event,
+       .vidioc_log_status    = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
index c15efb6..7cfbc9d 100644 (file)
@@ -208,15 +208,4 @@ static struct i2c_driver vp27smpx_driver = {
        .id_table       = vp27smpx_id,
 };
 
-static __init int init_vp27smpx(void)
-{
-       return i2c_add_driver(&vp27smpx_driver);
-}
-
-static __exit void exit_vp27smpx(void)
-{
-       i2c_del_driver(&vp27smpx_driver);
-}
-
-module_init(init_vp27smpx);
-module_exit(exit_vp27smpx);
+module_i2c_driver(vp27smpx_driver);
index e5cad6f..2f67b4c 100644 (file)
@@ -588,15 +588,4 @@ static struct i2c_driver vpx3220_driver = {
        .id_table       = vpx3220_id,
 };
 
-static __init int init_vpx3220(void)
-{
-       return i2c_add_driver(&vpx3220_driver);
-}
-
-static __exit void exit_vpx3220(void)
-{
-       i2c_del_driver(&vpx3220_driver);
-}
-
-module_init(init_vpx3220);
-module_exit(exit_vpx3220);
+module_i2c_driver(vpx3220_driver);
diff --git a/drivers/media/video/vs6624.c b/drivers/media/video/vs6624.c
new file mode 100644 (file)
index 0000000..42ae9dc
--- /dev/null
@@ -0,0 +1,928 @@
+/*
+ * vs6624.c ST VS6624 CMOS image sensor driver
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+
+#include "vs6624_regs.h"
+
+#define VGA_WIDTH       640
+#define VGA_HEIGHT      480
+#define QVGA_WIDTH      320
+#define QVGA_HEIGHT     240
+#define QQVGA_WIDTH     160
+#define QQVGA_HEIGHT    120
+#define CIF_WIDTH       352
+#define CIF_HEIGHT      288
+#define QCIF_WIDTH      176
+#define QCIF_HEIGHT     144
+#define QQCIF_WIDTH     88
+#define QQCIF_HEIGHT    72
+
+#define MAX_FRAME_RATE  30
+
+struct vs6624 {
+       struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
+       struct v4l2_fract frame_rate;
+       struct v4l2_mbus_framefmt fmt;
+       unsigned ce_pin;
+};
+
+static const struct vs6624_format {
+       enum v4l2_mbus_pixelcode mbus_code;
+       enum v4l2_colorspace colorspace;
+} vs6624_formats[] = {
+       {
+               .mbus_code      = V4L2_MBUS_FMT_UYVY8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+       },
+       {
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+       },
+       {
+               .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+       },
+};
+
+static struct v4l2_mbus_framefmt vs6624_default_fmt = {
+       .width = VGA_WIDTH,
+       .height = VGA_HEIGHT,
+       .code = V4L2_MBUS_FMT_UYVY8_2X8,
+       .field = V4L2_FIELD_NONE,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+};
+
+static const u16 vs6624_p1[] = {
+       0x8104, 0x03,
+       0x8105, 0x01,
+       0xc900, 0x03,
+       0xc904, 0x47,
+       0xc905, 0x10,
+       0xc906, 0x80,
+       0xc907, 0x3a,
+       0x903a, 0x02,
+       0x903b, 0x47,
+       0x903c, 0x15,
+       0xc908, 0x31,
+       0xc909, 0xdc,
+       0xc90a, 0x80,
+       0xc90b, 0x44,
+       0x9044, 0x02,
+       0x9045, 0x31,
+       0x9046, 0xe2,
+       0xc90c, 0x07,
+       0xc90d, 0xe0,
+       0xc90e, 0x80,
+       0xc90f, 0x47,
+       0x9047, 0x90,
+       0x9048, 0x83,
+       0x9049, 0x81,
+       0x904a, 0xe0,
+       0x904b, 0x60,
+       0x904c, 0x08,
+       0x904d, 0x90,
+       0x904e, 0xc0,
+       0x904f, 0x43,
+       0x9050, 0x74,
+       0x9051, 0x01,
+       0x9052, 0xf0,
+       0x9053, 0x80,
+       0x9054, 0x05,
+       0x9055, 0xE4,
+       0x9056, 0x90,
+       0x9057, 0xc0,
+       0x9058, 0x43,
+       0x9059, 0xf0,
+       0x905a, 0x02,
+       0x905b, 0x07,
+       0x905c, 0xec,
+       0xc910, 0x5d,
+       0xc911, 0xca,
+       0xc912, 0x80,
+       0xc913, 0x5d,
+       0x905d, 0xa3,
+       0x905e, 0x04,
+       0x905f, 0xf0,
+       0x9060, 0xa3,
+       0x9061, 0x04,
+       0x9062, 0xf0,
+       0x9063, 0x22,
+       0xc914, 0x72,
+       0xc915, 0x92,
+       0xc916, 0x80,
+       0xc917, 0x64,
+       0x9064, 0x74,
+       0x9065, 0x01,
+       0x9066, 0x02,
+       0x9067, 0x72,
+       0x9068, 0x95,
+       0xc918, 0x47,
+       0xc919, 0xf2,
+       0xc91a, 0x81,
+       0xc91b, 0x69,
+       0x9169, 0x74,
+       0x916a, 0x02,
+       0x916b, 0xf0,
+       0x916c, 0xec,
+       0x916d, 0xb4,
+       0x916e, 0x10,
+       0x916f, 0x0a,
+       0x9170, 0x90,
+       0x9171, 0x80,
+       0x9172, 0x16,
+       0x9173, 0xe0,
+       0x9174, 0x70,
+       0x9175, 0x04,
+       0x9176, 0x90,
+       0x9177, 0xd3,
+       0x9178, 0xc4,
+       0x9179, 0xf0,
+       0x917a, 0x22,
+       0xc91c, 0x0a,
+       0xc91d, 0xbe,
+       0xc91e, 0x80,
+       0xc91f, 0x73,
+       0x9073, 0xfc,
+       0x9074, 0xa3,
+       0x9075, 0xe0,
+       0x9076, 0xf5,
+       0x9077, 0x82,
+       0x9078, 0x8c,
+       0x9079, 0x83,
+       0x907a, 0xa3,
+       0x907b, 0xa3,
+       0x907c, 0xe0,
+       0x907d, 0xfc,
+       0x907e, 0xa3,
+       0x907f, 0xe0,
+       0x9080, 0xc3,
+       0x9081, 0x9f,
+       0x9082, 0xff,
+       0x9083, 0xec,
+       0x9084, 0x9e,
+       0x9085, 0xfe,
+       0x9086, 0x02,
+       0x9087, 0x0a,
+       0x9088, 0xea,
+       0xc920, 0x47,
+       0xc921, 0x38,
+       0xc922, 0x80,
+       0xc923, 0x89,
+       0x9089, 0xec,
+       0x908a, 0xd3,
+       0x908b, 0x94,
+       0x908c, 0x20,
+       0x908d, 0x40,
+       0x908e, 0x01,
+       0x908f, 0x1c,
+       0x9090, 0x90,
+       0x9091, 0xd3,
+       0x9092, 0xd4,
+       0x9093, 0xec,
+       0x9094, 0xf0,
+       0x9095, 0x02,
+       0x9096, 0x47,
+       0x9097, 0x3d,
+       0xc924, 0x45,
+       0xc925, 0xca,
+       0xc926, 0x80,
+       0xc927, 0x98,
+       0x9098, 0x12,
+       0x9099, 0x77,
+       0x909a, 0xd6,
+       0x909b, 0x02,
+       0x909c, 0x45,
+       0x909d, 0xcd,
+       0xc928, 0x20,
+       0xc929, 0xd5,
+       0xc92a, 0x80,
+       0xc92b, 0x9e,
+       0x909e, 0x90,
+       0x909f, 0x82,
+       0x90a0, 0x18,
+       0x90a1, 0xe0,
+       0x90a2, 0xb4,
+       0x90a3, 0x03,
+       0x90a4, 0x0e,
+       0x90a5, 0x90,
+       0x90a6, 0x83,
+       0x90a7, 0xbf,
+       0x90a8, 0xe0,
+       0x90a9, 0x60,
+       0x90aa, 0x08,
+       0x90ab, 0x90,
+       0x90ac, 0x81,
+       0x90ad, 0xfc,
+       0x90ae, 0xe0,
+       0x90af, 0xff,
+       0x90b0, 0xc3,
+       0x90b1, 0x13,
+       0x90b2, 0xf0,
+       0x90b3, 0x90,
+       0x90b4, 0x81,
+       0x90b5, 0xfc,
+       0x90b6, 0xe0,
+       0x90b7, 0xff,
+       0x90b8, 0x02,
+       0x90b9, 0x20,
+       0x90ba, 0xda,
+       0xc92c, 0x70,
+       0xc92d, 0xbc,
+       0xc92e, 0x80,
+       0xc92f, 0xbb,
+       0x90bb, 0x90,
+       0x90bc, 0x82,
+       0x90bd, 0x18,
+       0x90be, 0xe0,
+       0x90bf, 0xb4,
+       0x90c0, 0x03,
+       0x90c1, 0x06,
+       0x90c2, 0x90,
+       0x90c3, 0xc1,
+       0x90c4, 0x06,
+       0x90c5, 0x74,
+       0x90c6, 0x05,
+       0x90c7, 0xf0,
+       0x90c8, 0x90,
+       0x90c9, 0xd3,
+       0x90ca, 0xa0,
+       0x90cb, 0x02,
+       0x90cc, 0x70,
+       0x90cd, 0xbf,
+       0xc930, 0x72,
+       0xc931, 0x21,
+       0xc932, 0x81,
+       0xc933, 0x3b,
+       0x913b, 0x7d,
+       0x913c, 0x02,
+       0x913d, 0x7f,
+       0x913e, 0x7b,
+       0x913f, 0x02,
+       0x9140, 0x72,
+       0x9141, 0x25,
+       0xc934, 0x28,
+       0xc935, 0xae,
+       0xc936, 0x80,
+       0xc937, 0xd2,
+       0x90d2, 0xf0,
+       0x90d3, 0x90,
+       0x90d4, 0xd2,
+       0x90d5, 0x0a,
+       0x90d6, 0x02,
+       0x90d7, 0x28,
+       0x90d8, 0xb4,
+       0xc938, 0x28,
+       0xc939, 0xb1,
+       0xc93a, 0x80,
+       0xc93b, 0xd9,
+       0x90d9, 0x90,
+       0x90da, 0x83,
+       0x90db, 0xba,
+       0x90dc, 0xe0,
+       0x90dd, 0xff,
+       0x90de, 0x90,
+       0x90df, 0xd2,
+       0x90e0, 0x08,
+       0x90e1, 0xe0,
+       0x90e2, 0xe4,
+       0x90e3, 0xef,
+       0x90e4, 0xf0,
+       0x90e5, 0xa3,
+       0x90e6, 0xe0,
+       0x90e7, 0x74,
+       0x90e8, 0xff,
+       0x90e9, 0xf0,
+       0x90ea, 0x90,
+       0x90eb, 0xd2,
+       0x90ec, 0x0a,
+       0x90ed, 0x02,
+       0x90ee, 0x28,
+       0x90ef, 0xb4,
+       0xc93c, 0x29,
+       0xc93d, 0x79,
+       0xc93e, 0x80,
+       0xc93f, 0xf0,
+       0x90f0, 0xf0,
+       0x90f1, 0x90,
+       0x90f2, 0xd2,
+       0x90f3, 0x0e,
+       0x90f4, 0x02,
+       0x90f5, 0x29,
+       0x90f6, 0x7f,
+       0xc940, 0x29,
+       0xc941, 0x7c,
+       0xc942, 0x80,
+       0xc943, 0xf7,
+       0x90f7, 0x90,
+       0x90f8, 0x83,
+       0x90f9, 0xba,
+       0x90fa, 0xe0,
+       0x90fb, 0xff,
+       0x90fc, 0x90,
+       0x90fd, 0xd2,
+       0x90fe, 0x0c,
+       0x90ff, 0xe0,
+       0x9100, 0xe4,
+       0x9101, 0xef,
+       0x9102, 0xf0,
+       0x9103, 0xa3,
+       0x9104, 0xe0,
+       0x9105, 0x74,
+       0x9106, 0xff,
+       0x9107, 0xf0,
+       0x9108, 0x90,
+       0x9109, 0xd2,
+       0x910a, 0x0e,
+       0x910b, 0x02,
+       0x910c, 0x29,
+       0x910d, 0x7f,
+       0xc944, 0x2a,
+       0xc945, 0x42,
+       0xc946, 0x81,
+       0xc947, 0x0e,
+       0x910e, 0xf0,
+       0x910f, 0x90,
+       0x9110, 0xd2,
+       0x9111, 0x12,
+       0x9112, 0x02,
+       0x9113, 0x2a,
+       0x9114, 0x48,
+       0xc948, 0x2a,
+       0xc949, 0x45,
+       0xc94a, 0x81,
+       0xc94b, 0x15,
+       0x9115, 0x90,
+       0x9116, 0x83,
+       0x9117, 0xba,
+       0x9118, 0xe0,
+       0x9119, 0xff,
+       0x911a, 0x90,
+       0x911b, 0xd2,
+       0x911c, 0x10,
+       0x911d, 0xe0,
+       0x911e, 0xe4,
+       0x911f, 0xef,
+       0x9120, 0xf0,
+       0x9121, 0xa3,
+       0x9122, 0xe0,
+       0x9123, 0x74,
+       0x9124, 0xff,
+       0x9125, 0xf0,
+       0x9126, 0x90,
+       0x9127, 0xd2,
+       0x9128, 0x12,
+       0x9129, 0x02,
+       0x912a, 0x2a,
+       0x912b, 0x48,
+       0xc900, 0x01,
+       0x0000, 0x00,
+};
+
+static const u16 vs6624_p2[] = {
+       0x806f, 0x01,
+       0x058c, 0x01,
+       0x0000, 0x00,
+};
+
+static const u16 vs6624_run_setup[] = {
+       0x1d18, 0x00,                           /* Enableconstrainedwhitebalance */
+       VS6624_PEAK_MIN_OUT_G_MSB, 0x3c,        /* Damper PeakGain Output MSB */
+       VS6624_PEAK_MIN_OUT_G_LSB, 0x66,        /* Damper PeakGain Output LSB */
+       VS6624_CM_LOW_THR_MSB, 0x65,            /* Damper Low MSB */
+       VS6624_CM_LOW_THR_LSB, 0xd1,            /* Damper Low LSB */
+       VS6624_CM_HIGH_THR_MSB, 0x66,           /* Damper High MSB */
+       VS6624_CM_HIGH_THR_LSB, 0x62,           /* Damper High LSB */
+       VS6624_CM_MIN_OUT_MSB, 0x00,            /* Damper Min output MSB */
+       VS6624_CM_MIN_OUT_LSB, 0x00,            /* Damper Min output LSB */
+       VS6624_NORA_DISABLE, 0x00,              /* Nora fDisable */
+       VS6624_NORA_USAGE, 0x04,                /* Nora usage */
+       VS6624_NORA_LOW_THR_MSB, 0x63,          /* Damper Low MSB Changed 0x63 to 0x65 */
+       VS6624_NORA_LOW_THR_LSB, 0xd1,          /* Damper Low LSB */
+       VS6624_NORA_HIGH_THR_MSB, 0x68,         /* Damper High MSB */
+       VS6624_NORA_HIGH_THR_LSB, 0xdd,         /* Damper High LSB */
+       VS6624_NORA_MIN_OUT_MSB, 0x3a,          /* Damper Min output MSB */
+       VS6624_NORA_MIN_OUT_LSB, 0x00,          /* Damper Min output LSB */
+       VS6624_F2B_DISABLE, 0x00,               /* Disable */
+       0x1d8a, 0x30,                           /* MAXWeightHigh */
+       0x1d91, 0x62,                           /* fpDamperLowThresholdHigh MSB */
+       0x1d92, 0x4a,                           /* fpDamperLowThresholdHigh LSB */
+       0x1d95, 0x65,                           /* fpDamperHighThresholdHigh MSB */
+       0x1d96, 0x0e,                           /* fpDamperHighThresholdHigh LSB */
+       0x1da1, 0x3a,                           /* fpMinimumDamperOutputLow MSB */
+       0x1da2, 0xb8,                           /* fpMinimumDamperOutputLow LSB */
+       0x1e08, 0x06,                           /* MAXWeightLow */
+       0x1e0a, 0x0a,                           /* MAXWeightHigh */
+       0x1601, 0x3a,                           /* Red A MSB */
+       0x1602, 0x14,                           /* Red A LSB */
+       0x1605, 0x3b,                           /* Blue A MSB */
+       0x1606, 0x85,                           /* BLue A LSB */
+       0x1609, 0x3b,                           /* RED B MSB */
+       0x160a, 0x85,                           /* RED B LSB */
+       0x160d, 0x3a,                           /* Blue B MSB */
+       0x160e, 0x14,                           /* Blue B LSB */
+       0x1611, 0x30,                           /* Max Distance from Locus MSB */
+       0x1612, 0x8f,                           /* Max Distance from Locus MSB */
+       0x1614, 0x01,                           /* Enable constrainer */
+       0x0000, 0x00,
+};
+
+static const u16 vs6624_default[] = {
+       VS6624_CONTRAST0, 0x84,
+       VS6624_SATURATION0, 0x75,
+       VS6624_GAMMA0, 0x11,
+       VS6624_CONTRAST1, 0x84,
+       VS6624_SATURATION1, 0x75,
+       VS6624_GAMMA1, 0x11,
+       VS6624_MAN_RG, 0x80,
+       VS6624_MAN_GG, 0x80,
+       VS6624_MAN_BG, 0x80,
+       VS6624_WB_MODE, 0x1,
+       VS6624_EXPO_COMPENSATION, 0xfe,
+       VS6624_EXPO_METER, 0x0,
+       VS6624_LIGHT_FREQ, 0x64,
+       VS6624_PEAK_GAIN, 0xe,
+       VS6624_PEAK_LOW_THR, 0x28,
+       VS6624_HMIRROR0, 0x0,
+       VS6624_VFLIP0, 0x0,
+       VS6624_ZOOM_HSTEP0_MSB, 0x0,
+       VS6624_ZOOM_HSTEP0_LSB, 0x1,
+       VS6624_ZOOM_VSTEP0_MSB, 0x0,
+       VS6624_ZOOM_VSTEP0_LSB, 0x1,
+       VS6624_PAN_HSTEP0_MSB, 0x0,
+       VS6624_PAN_HSTEP0_LSB, 0xf,
+       VS6624_PAN_VSTEP0_MSB, 0x0,
+       VS6624_PAN_VSTEP0_LSB, 0xf,
+       VS6624_SENSOR_MODE, 0x1,
+       VS6624_SYNC_CODE_SETUP, 0x21,
+       VS6624_DISABLE_FR_DAMPER, 0x0,
+       VS6624_FR_DEN, 0x1,
+       VS6624_FR_NUM_LSB, 0xf,
+       VS6624_INIT_PIPE_SETUP, 0x0,
+       VS6624_IMG_FMT0, 0x0,
+       VS6624_YUV_SETUP, 0x1,
+       VS6624_IMAGE_SIZE0, 0x2,
+       0x0000, 0x00,
+};
+
+static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct vs6624, sd);
+}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
+}
+
+static int vs6624_read(struct v4l2_subdev *sd, u16 index)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 buf[2];
+
+       buf[0] = index >> 8;
+       buf[1] = index;
+       i2c_master_send(client, buf, 2);
+       i2c_master_recv(client, buf, 1);
+
+       return buf[0];
+}
+
+static int vs6624_write(struct v4l2_subdev *sd, u16 index,
+                               u8 value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 buf[3];
+
+       buf[0] = index >> 8;
+       buf[1] = index;
+       buf[2] = value;
+
+       return i2c_master_send(client, buf, 3);
+}
+
+static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
+{
+       u16 reg;
+       u8 data;
+
+       while (*regs != 0x00) {
+               reg = *regs++;
+               data = *regs++;
+
+               vs6624_write(sd, reg, data);
+       }
+       return 0;
+}
+
+static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_subdev *sd = to_sd(ctrl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_CONTRAST:
+               vs6624_write(sd, VS6624_CONTRAST0, ctrl->val);
+               break;
+       case V4L2_CID_SATURATION:
+               vs6624_write(sd, VS6624_SATURATION0, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               vs6624_write(sd, VS6624_HMIRROR0, ctrl->val);
+               break;
+       case V4L2_CID_VFLIP:
+               vs6624_write(sd, VS6624_VFLIP0, ctrl->val);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vs6624_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+                               enum v4l2_mbus_pixelcode *code)
+{
+       if (index >= ARRAY_SIZE(vs6624_formats))
+               return -EINVAL;
+
+       *code = vs6624_formats[index].mbus_code;
+       return 0;
+}
+
+static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_framefmt *fmt)
+{
+       int index;
+
+       for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
+               if (vs6624_formats[index].mbus_code == fmt->code)
+                       break;
+       if (index >= ARRAY_SIZE(vs6624_formats)) {
+               /* default to first format */
+               index = 0;
+               fmt->code = vs6624_formats[0].mbus_code;
+       }
+
+       /* sensor mode is VGA */
+       if (fmt->width > VGA_WIDTH)
+               fmt->width = VGA_WIDTH;
+       if (fmt->height > VGA_HEIGHT)
+               fmt->height = VGA_HEIGHT;
+       fmt->width = fmt->width & (~3);
+       fmt->height = fmt->height & (~3);
+       fmt->field = V4L2_FIELD_NONE;
+       fmt->colorspace = vs6624_formats[index].colorspace;
+       return 0;
+}
+
+static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_framefmt *fmt)
+{
+       struct vs6624 *sensor = to_vs6624(sd);
+       int ret;
+
+       ret = vs6624_try_mbus_fmt(sd, fmt);
+       if (ret)
+               return ret;
+
+       /* set image format */
+       switch (fmt->code) {
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+               vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
+               vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
+               break;
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+               vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
+               vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
+               break;
+       case V4L2_MBUS_FMT_RGB565_2X8_LE:
+               vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
+               vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set image size */
+       if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
+               vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
+       else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
+               vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
+       else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
+               vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
+       else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
+               vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
+       else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
+               vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
+       else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
+               vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
+       else {
+               vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
+               vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
+               vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
+               vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
+               vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
+               vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
+       }
+
+       sensor->fmt = *fmt;
+
+       return 0;
+}
+
+static int vs6624_g_mbus_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_framefmt *fmt)
+{
+       struct vs6624 *sensor = to_vs6624(sd);
+
+       *fmt = sensor->fmt;
+       return 0;
+}
+
+static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+       struct vs6624 *sensor = to_vs6624(sd);
+       struct v4l2_captureparm *cp = &parms->parm.capture;
+
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memset(cp, 0, sizeof(*cp));
+       cp->capability = V4L2_CAP_TIMEPERFRAME;
+       cp->timeperframe.numerator = sensor->frame_rate.denominator;
+       cp->timeperframe.denominator = sensor->frame_rate.numerator;
+       return 0;
+}
+
+static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+       struct vs6624 *sensor = to_vs6624(sd);
+       struct v4l2_captureparm *cp = &parms->parm.capture;
+       struct v4l2_fract *tpf = &cp->timeperframe;
+
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (cp->extendedmode != 0)
+               return -EINVAL;
+
+       if (tpf->numerator == 0 || tpf->denominator == 0
+               || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
+               /* reset to max frame rate */
+               tpf->numerator = 1;
+               tpf->denominator = MAX_FRAME_RATE;
+       }
+       sensor->frame_rate.numerator = tpf->denominator;
+       sensor->frame_rate.denominator = tpf->numerator;
+       vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
+       vs6624_write(sd, VS6624_FR_NUM_MSB,
+                       sensor->frame_rate.numerator >> 8);
+       vs6624_write(sd, VS6624_FR_NUM_LSB,
+                       sensor->frame_rate.numerator & 0xFF);
+       vs6624_write(sd, VS6624_FR_DEN,
+                       sensor->frame_rate.denominator & 0xFF);
+       return 0;
+}
+
+static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       if (enable)
+               vs6624_write(sd, VS6624_USER_CMD, 0x2);
+       else
+               vs6624_write(sd, VS6624_USER_CMD, 0x4);
+       udelay(100);
+       return 0;
+}
+
+static int vs6624_g_chip_ident(struct v4l2_subdev *sd,
+               struct v4l2_dbg_chip_ident *chip)
+{
+       int rev;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       rev = (vs6624_read(sd, VS6624_FW_VSN_MAJOR) << 8)
+               | vs6624_read(sd, VS6624_FW_VSN_MINOR);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VS6624, rev);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       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 = vs6624_read(sd, reg->reg & 0xffff);
+       reg->size = 1;
+       return 0;
+}
+
+static int vs6624_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       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;
+       vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
+       return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
+       .s_ctrl = vs6624_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops vs6624_core_ops = {
+       .g_chip_ident = vs6624_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = vs6624_g_register,
+       .s_register = vs6624_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops vs6624_video_ops = {
+       .enum_mbus_fmt = vs6624_enum_mbus_fmt,
+       .try_mbus_fmt = vs6624_try_mbus_fmt,
+       .s_mbus_fmt = vs6624_s_mbus_fmt,
+       .g_mbus_fmt = vs6624_g_mbus_fmt,
+       .s_parm = vs6624_s_parm,
+       .g_parm = vs6624_g_parm,
+       .s_stream = vs6624_s_stream,
+};
+
+static const struct v4l2_subdev_ops vs6624_ops = {
+       .core = &vs6624_core_ops,
+       .video = &vs6624_video_ops,
+};
+
+static int __devinit vs6624_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct vs6624 *sensor;
+       struct v4l2_subdev *sd;
+       struct v4l2_ctrl_handler *hdl;
+       const unsigned *ce;
+       int ret;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -EIO;
+
+       ce = client->dev.platform_data;
+       if (ce == NULL)
+               return -EINVAL;
+
+       ret = gpio_request(*ce, "VS6624 Chip Enable");
+       if (ret) {
+               v4l_err(client, "failed to request GPIO %d\n", *ce);
+               return ret;
+       }
+       gpio_direction_output(*ce, 1);
+       /* wait 100ms before any further i2c writes are performed */
+       mdelay(100);
+
+       sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+       if (sensor == NULL) {
+               gpio_free(*ce);
+               return -ENOMEM;
+       }
+
+       sd = &sensor->sd;
+       v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
+
+       vs6624_writeregs(sd, vs6624_p1);
+       vs6624_write(sd, VS6624_MICRO_EN, 0x2);
+       vs6624_write(sd, VS6624_DIO_EN, 0x1);
+       mdelay(10);
+       vs6624_writeregs(sd, vs6624_p2);
+
+       vs6624_writeregs(sd, vs6624_default);
+       vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
+       vs6624_writeregs(sd, vs6624_run_setup);
+
+       /* set frame rate */
+       sensor->frame_rate.numerator = MAX_FRAME_RATE;
+       sensor->frame_rate.denominator = 1;
+       vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
+       vs6624_write(sd, VS6624_FR_NUM_MSB,
+                       sensor->frame_rate.numerator >> 8);
+       vs6624_write(sd, VS6624_FR_NUM_LSB,
+                       sensor->frame_rate.numerator & 0xFF);
+       vs6624_write(sd, VS6624_FR_DEN,
+                       sensor->frame_rate.denominator & 0xFF);
+
+       sensor->fmt = vs6624_default_fmt;
+       sensor->ce_pin = *ce;
+
+       v4l_info(client, "chip found @ 0x%02x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       hdl = &sensor->hdl;
+       v4l2_ctrl_handler_init(hdl, 4);
+       v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
+       v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
+       v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+       /* hook the control handler into the driver */
+       sd->ctrl_handler = hdl;
+       if (hdl->error) {
+               int err = hdl->error;
+
+               v4l2_ctrl_handler_free(hdl);
+               kfree(sensor);
+               gpio_free(*ce);
+               return err;
+       }
+
+       /* initialize the hardware to the default control values */
+       ret = v4l2_ctrl_handler_setup(hdl);
+       if (ret) {
+               v4l2_ctrl_handler_free(hdl);
+               kfree(sensor);
+               gpio_free(*ce);
+       }
+       return ret;
+}
+
+static int __devexit vs6624_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct vs6624 *sensor = to_vs6624(sd);
+
+       v4l2_device_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(sd->ctrl_handler);
+       gpio_free(sensor->ce_pin);
+       kfree(sensor);
+       return 0;
+}
+
+static const struct i2c_device_id vs6624_id[] = {
+       {"vs6624", 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, vs6624_id);
+
+static struct i2c_driver vs6624_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "vs6624",
+       },
+       .probe          = vs6624_probe,
+       .remove         = __devexit_p(vs6624_remove),
+       .id_table       = vs6624_id,
+};
+
+static __init int vs6624_init(void)
+{
+       return i2c_add_driver(&vs6624_driver);
+}
+
+static __exit void vs6624_exit(void)
+{
+       i2c_del_driver(&vs6624_driver);
+}
+
+module_init(vs6624_init);
+module_exit(vs6624_exit);
+
+MODULE_DESCRIPTION("VS6624 sensor driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/vs6624_regs.h b/drivers/media/video/vs6624_regs.h
new file mode 100644 (file)
index 0000000..6ba2ee2
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * vs6624 - ST VS6624 CMOS image sensor registers
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _VS6624_REGS_H_
+#define _VS6624_REGS_H_
+
+/* low level control registers */
+#define VS6624_MICRO_EN               0xC003 /* power enable for all MCU clock */
+#define VS6624_DIO_EN                 0xC044 /* enable digital I/O */
+/* device parameters */
+#define VS6624_DEV_ID_MSB             0x0001 /* device id MSB */
+#define VS6624_DEV_ID_LSB             0x0002 /* device id LSB */
+#define VS6624_FW_VSN_MAJOR           0x0004 /* firmware version major */
+#define VS6624_FW_VSN_MINOR           0x0006 /* firmware version minor */
+#define VS6624_PATCH_VSN_MAJOR        0x0008 /* patch version major */
+#define VS6624_PATCH_VSN_MINOR        0x000A /* patch version minor */
+/* host interface manager control */
+#define VS6624_USER_CMD               0x0180 /* user level control of operating states */
+/* host interface manager status */
+#define VS6624_STATE                  0x0202 /* current state of the mode manager */
+/* run mode control */
+#define VS6624_METER_ON               0x0280 /* if false AE and AWB are disabled */
+/* mode setup */
+#define VS6624_ACTIVE_PIPE_SETUP      0x0302 /* select the active bank for non view live mode */
+#define VS6624_SENSOR_MODE            0x0308 /* select the different sensor mode */
+/* pipe setup bank0 */
+#define VS6624_IMAGE_SIZE0            0x0380 /* required output dimension */
+#define VS6624_MAN_HSIZE0_MSB         0x0383 /* input required manual H size MSB */
+#define VS6624_MAN_HSIZE0_LSB         0x0384 /* input required manual H size LSB */
+#define VS6624_MAN_VSIZE0_MSB         0x0387 /* input required manual V size MSB */
+#define VS6624_MAN_VSIZE0_LSB         0x0388 /* input required manual V size LSB */
+#define VS6624_ZOOM_HSTEP0_MSB        0x038B /* set the zoom H step MSB */
+#define VS6624_ZOOM_HSTEP0_LSB        0x038C /* set the zoom H step LSB */
+#define VS6624_ZOOM_VSTEP0_MSB        0x038F /* set the zoom V step MSB */
+#define VS6624_ZOOM_VSTEP0_LSB        0x0390 /* set the zoom V step LSB */
+#define VS6624_ZOOM_CTRL0             0x0392 /* control zoon in, out and stop */
+#define VS6624_PAN_HSTEP0_MSB         0x0395 /* set the pan H step MSB */
+#define VS6624_PAN_HSTEP0_LSB         0x0396 /* set the pan H step LSB */
+#define VS6624_PAN_VSTEP0_MSB         0x0399 /* set the pan V step MSB */
+#define VS6624_PAN_VSTEP0_LSB         0x039A /* set the pan V step LSB */
+#define VS6624_PAN_CTRL0              0x039C /* control pan operation */
+#define VS6624_CROP_CTRL0             0x039E /* select cropping mode */
+#define VS6624_CROP_HSTART0_MSB       0x03A1 /* set the cropping H start address MSB */
+#define VS6624_CROP_HSTART0_LSB       0x03A2 /* set the cropping H start address LSB */
+#define VS6624_CROP_HSIZE0_MSB        0x03A5 /* set the cropping H size MSB */
+#define VS6624_CROP_HSIZE0_LSB        0x03A6 /* set the cropping H size LSB */
+#define VS6624_CROP_VSTART0_MSB       0x03A9 /* set the cropping V start address MSB */
+#define VS6624_CROP_VSTART0_LSB       0x03AA /* set the cropping V start address LSB */
+#define VS6624_CROP_VSIZE0_MSB        0x03AD /* set the cropping V size MSB */
+#define VS6624_CROP_VSIZE0_LSB        0x03AE /* set the cropping V size LSB */
+#define VS6624_IMG_FMT0               0x03B0 /* select required output image format */
+#define VS6624_BAYER_OUT_ALIGN0       0x03B2 /* set bayer output alignment */
+#define VS6624_CONTRAST0              0x03B4 /* contrast control for output */
+#define VS6624_SATURATION0            0x03B6 /* saturation control for output */
+#define VS6624_GAMMA0                 0x03B8 /* gamma settings */
+#define VS6624_HMIRROR0               0x03BA /* horizontal image orientation flip */
+#define VS6624_VFLIP0                 0x03BC /* vertical image orientation flip */
+#define VS6624_CHANNEL_ID0            0x03BE /* logical DMA channel number */
+/* pipe setup bank1 */
+#define VS6624_IMAGE_SIZE1            0x0400 /* required output dimension */
+#define VS6624_MAN_HSIZE1_MSB         0x0403 /* input required manual H size MSB */
+#define VS6624_MAN_HSIZE1_LSB         0x0404 /* input required manual H size LSB */
+#define VS6624_MAN_VSIZE1_MSB         0x0407 /* input required manual V size MSB */
+#define VS6624_MAN_VSIZE1_LSB         0x0408 /* input required manual V size LSB */
+#define VS6624_ZOOM_HSTEP1_MSB        0x040B /* set the zoom H step MSB */
+#define VS6624_ZOOM_HSTEP1_LSB        0x040C /* set the zoom H step LSB */
+#define VS6624_ZOOM_VSTEP1_MSB        0x040F /* set the zoom V step MSB */
+#define VS6624_ZOOM_VSTEP1_LSB        0x0410 /* set the zoom V step LSB */
+#define VS6624_ZOOM_CTRL1             0x0412 /* control zoon in, out and stop */
+#define VS6624_PAN_HSTEP1_MSB         0x0415 /* set the pan H step MSB */
+#define VS6624_PAN_HSTEP1_LSB         0x0416 /* set the pan H step LSB */
+#define VS6624_PAN_VSTEP1_MSB         0x0419 /* set the pan V step MSB */
+#define VS6624_PAN_VSTEP1_LSB         0x041A /* set the pan V step LSB */
+#define VS6624_PAN_CTRL1              0x041C /* control pan operation */
+#define VS6624_CROP_CTRL1             0x041E /* select cropping mode */
+#define VS6624_CROP_HSTART1_MSB       0x0421 /* set the cropping H start address MSB */
+#define VS6624_CROP_HSTART1_LSB       0x0422 /* set the cropping H start address LSB */
+#define VS6624_CROP_HSIZE1_MSB        0x0425 /* set the cropping H size MSB */
+#define VS6624_CROP_HSIZE1_LSB        0x0426 /* set the cropping H size LSB */
+#define VS6624_CROP_VSTART1_MSB       0x0429 /* set the cropping V start address MSB */
+#define VS6624_CROP_VSTART1_LSB       0x042A /* set the cropping V start address LSB */
+#define VS6624_CROP_VSIZE1_MSB        0x042D /* set the cropping V size MSB */
+#define VS6624_CROP_VSIZE1_LSB        0x042E /* set the cropping V size LSB */
+#define VS6624_IMG_FMT1               0x0430 /* select required output image format */
+#define VS6624_BAYER_OUT_ALIGN1       0x0432 /* set bayer output alignment */
+#define VS6624_CONTRAST1              0x0434 /* contrast control for output */
+#define VS6624_SATURATION1            0x0436 /* saturation control for output */
+#define VS6624_GAMMA1                 0x0438 /* gamma settings */
+#define VS6624_HMIRROR1               0x043A /* horizontal image orientation flip */
+#define VS6624_VFLIP1                 0x043C /* vertical image orientation flip */
+#define VS6624_CHANNEL_ID1            0x043E /* logical DMA channel number */
+/* view live control */
+#define VS6624_VIEW_LIVE_EN           0x0480 /* enable view live mode */
+#define VS6624_INIT_PIPE_SETUP        0x0482 /* select initial pipe setup bank */
+/* view live status */
+#define VS6624_CUR_PIPE_SETUP         0x0500 /* indicates most recently applied setup bank */
+/* power management */
+#define VS6624_TIME_TO_POWER_DOWN     0x0580 /* automatically transition time to stop mode */
+/* video timing parameter host inputs */
+#define VS6624_EXT_CLK_FREQ_NUM_MSB   0x0605 /* external clock frequency numerator MSB */
+#define VS6624_EXT_CLK_FREQ_NUM_LSB   0x0606 /* external clock frequency numerator LSB */
+#define VS6624_EXT_CLK_FREQ_DEN       0x0608 /* external clock frequency denominator */
+/* video timing control */
+#define VS6624_SYS_CLK_MODE           0x0880 /* decides system clock frequency */
+/* frame dimension parameter host inputs */
+#define VS6624_LIGHT_FREQ             0x0C80 /* AC frequency used for flicker free time */
+#define VS6624_FLICKER_COMPAT         0x0C82 /* flicker compatible frame length */
+/* static frame rate control */
+#define VS6624_FR_NUM_MSB             0x0D81 /* desired frame rate numerator MSB */
+#define VS6624_FR_NUM_LSB             0x0D82 /* desired frame rate numerator LSB */
+#define VS6624_FR_DEN                 0x0D84 /* desired frame rate denominator */
+/* automatic frame rate control */
+#define VS6624_DISABLE_FR_DAMPER      0x0E80 /* defines frame rate mode */
+#define VS6624_MIN_DAMPER_OUT_MSB     0x0E8C /* minimum frame rate MSB */
+#define VS6624_MIN_DAMPER_OUT_LSB     0x0E8A /* minimum frame rate LSB */
+/* exposure controls */
+#define VS6624_EXPO_MODE              0x1180 /* exposure mode */
+#define VS6624_EXPO_METER             0x1182 /* weights to be associated with the zones */
+#define VS6624_EXPO_TIME_NUM          0x1184 /* exposure time numerator */
+#define VS6624_EXPO_TIME_DEN          0x1186 /* exposure time denominator */
+#define VS6624_EXPO_TIME_MSB          0x1189 /* exposure time for the Manual Mode MSB */
+#define VS6624_EXPO_TIME_LSB          0x118A /* exposure time for the Manual Mode LSB */
+#define VS6624_EXPO_COMPENSATION      0x1190 /* exposure compensation */
+#define VS6624_DIRECT_COARSE_MSB      0x1195 /* coarse integration lines for Direct Mode MSB */
+#define VS6624_DIRECT_COARSE_LSB      0x1196 /* coarse integration lines for Direct Mode LSB */
+#define VS6624_DIRECT_FINE_MSB        0x1199 /* fine integration pixels for Direct Mode MSB */
+#define VS6624_DIRECT_FINE_LSB        0x119A /* fine integration pixels for Direct Mode LSB */
+#define VS6624_DIRECT_ANAL_GAIN_MSB   0x119D /* analog gain for Direct Mode MSB */
+#define VS6624_DIRECT_ANAL_GAIN_LSB   0x119E /* analog gain for Direct Mode LSB */
+#define VS6624_DIRECT_DIGI_GAIN_MSB   0x11A1 /* digital gain for Direct Mode MSB */
+#define VS6624_DIRECT_DIGI_GAIN_LSB   0x11A2 /* digital gain for Direct Mode LSB */
+#define VS6624_FLASH_COARSE_MSB       0x11A5 /* coarse integration lines for Flash Gun Mode MSB */
+#define VS6624_FLASH_COARSE_LSB       0x11A6 /* coarse integration lines for Flash Gun Mode LSB */
+#define VS6624_FLASH_FINE_MSB         0x11A9 /* fine integration pixels for Flash Gun Mode MSB */
+#define VS6624_FLASH_FINE_LSB         0x11AA /* fine integration pixels for Flash Gun Mode LSB */
+#define VS6624_FLASH_ANAL_GAIN_MSB    0x11AD /* analog gain for Flash Gun Mode MSB */
+#define VS6624_FLASH_ANAL_GAIN_LSB    0x11AE /* analog gain for Flash Gun Mode LSB */
+#define VS6624_FLASH_DIGI_GAIN_MSB    0x11B1 /* digital gain for Flash Gun Mode MSB */
+#define VS6624_FLASH_DIGI_GAIN_LSB    0x11B2 /* digital gain for Flash Gun Mode LSB */
+#define VS6624_FREEZE_AE              0x11B4 /* freeze auto exposure */
+#define VS6624_MAX_INT_TIME_MSB       0x11B7 /* user maximum integration time MSB */
+#define VS6624_MAX_INT_TIME_LSB       0x11B8 /* user maximum integration time LSB */
+#define VS6624_FLASH_AG_THR_MSB       0x11BB /* recommend flash gun analog gain threshold MSB */
+#define VS6624_FLASH_AG_THR_LSB       0x11BC /* recommend flash gun analog gain threshold LSB */
+#define VS6624_ANTI_FLICKER_MODE      0x11C0 /* anti flicker mode */
+/* white balance control */
+#define VS6624_WB_MODE                0x1480 /* set white balance mode */
+#define VS6624_MAN_RG                 0x1482 /* user setting for red channel gain */
+#define VS6624_MAN_GG                 0x1484 /* user setting for green channel gain */
+#define VS6624_MAN_BG                 0x1486 /* user setting for blue channel gain */
+#define VS6624_FLASH_RG_MSB           0x148B /* red gain for Flash Gun MSB */
+#define VS6624_FLASH_RG_LSB           0x148C /* red gain for Flash Gun LSB */
+#define VS6624_FLASH_GG_MSB           0x148F /* green gain for Flash Gun MSB */
+#define VS6624_FLASH_GG_LSB           0x1490 /* green gain for Flash Gun LSB */
+#define VS6624_FLASH_BG_MSB           0x1493 /* blue gain for Flash Gun MSB */
+#define VS6624_FLASH_BG_LSB           0x1494 /* blue gain for Flash Gun LSB */
+/* sensor setup */
+#define VS6624_BC_OFFSET              0x1990 /* Black Correction Offset */
+/* image stability */
+#define VS6624_STABLE_WB              0x1900 /* white balance stable */
+#define VS6624_STABLE_EXPO            0x1902 /* exposure stable */
+#define VS6624_STABLE                 0x1906 /* system stable */
+/* flash control */
+#define VS6624_FLASH_MODE             0x1A80 /* flash mode */
+#define VS6624_FLASH_OFF_LINE_MSB     0x1A83 /* off line at flash pulse mode MSB */
+#define VS6624_FLASH_OFF_LINE_LSB     0x1A84 /* off line at flash pulse mode LSB */
+/* flash status */
+#define VS6624_FLASH_RECOM            0x1B00 /* flash gun is recommended */
+#define VS6624_FLASH_GRAB_COMPLETE    0x1B02 /* flash gun image has been grabbed */
+/* scythe filter controls */
+#define VS6624_SCYTHE_FILTER          0x1D80 /* disable scythe defect correction */
+/* jack filter controls */
+#define VS6624_JACK_FILTER            0x1E00 /* disable jack defect correction */
+/* demosaic control */
+#define VS6624_ANTI_ALIAS_FILTER      0x1E80 /* anti alias filter suppress */
+/* color matrix dampers */
+#define VS6624_CM_DISABLE             0x1F00 /* disable color matrix damper */
+#define VS6624_CM_LOW_THR_MSB         0x1F03 /* low threshold for exposure MSB */
+#define VS6624_CM_LOW_THR_LSB         0x1F04 /* low threshold for exposure LSB */
+#define VS6624_CM_HIGH_THR_MSB        0x1F07 /* high threshold for exposure MSB */
+#define VS6624_CM_HIGH_THR_LSB        0x1F08 /* high threshold for exposure LSB */
+#define VS6624_CM_MIN_OUT_MSB         0x1F0B /* minimum possible damper output MSB */
+#define VS6624_CM_MIN_OUT_LSB         0x1F0C /* minimum possible damper output LSB */
+/* peaking control */
+#define VS6624_PEAK_GAIN              0x2000 /* controls peaking gain */
+#define VS6624_PEAK_G_DISABLE         0x2002 /* disable peak gain damping */
+#define VS6624_PEAK_LOW_THR_G_MSB     0x2005 /* low threshold for exposure for gain MSB */
+#define VS6624_PEAK_LOW_THR_G_LSB     0x2006 /* low threshold for exposure for gain LSB */
+#define VS6624_PEAK_HIGH_THR_G_MSB    0x2009 /* high threshold for exposure for gain MSB */
+#define VS6624_PEAK_HIGH_THR_G_LSB    0x200A /* high threshold for exposure for gain LSB */
+#define VS6624_PEAK_MIN_OUT_G_MSB     0x200D /* minimum damper output for gain MSB */
+#define VS6624_PEAK_MIN_OUT_G_LSB     0x200E /* minimum damper output for gain LSB */
+#define VS6624_PEAK_LOW_THR           0x2010 /* adjust degree of coring */
+#define VS6624_PEAK_C_DISABLE         0x2012 /* disable coring damping */
+#define VS6624_PEAK_HIGH_THR          0x2014 /* adjust maximum gain */
+#define VS6624_PEAK_LOW_THR_C_MSB     0x2017 /* low threshold for exposure for coring MSB */
+#define VS6624_PEAK_LOW_THR_C_LSB     0x2018 /* low threshold for exposure for coring LSB */
+#define VS6624_PEAK_HIGH_THR_C_MSB    0x201B /* high threshold for exposure for coring MSB */
+#define VS6624_PEAK_HIGH_THR_C_LSB    0x201C /* high threshold for exposure for coring LSB */
+#define VS6624_PEAK_MIN_OUT_C_MSB     0x201F /* minimum damper output for coring MSB */
+#define VS6624_PEAK_MIN_OUT_C_LSB     0x2020 /* minimum damper output for coring LSB */
+/* pipe 0 RGB to YUV matrix manual control */
+#define VS6624_RYM0_MAN_CTRL          0x2180 /* enable manual RGB to YUV matrix */
+#define VS6624_RYM0_W00_MSB           0x2183 /* row 0 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W00_LSB           0x2184 /* row 0 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W01_MSB           0x2187 /* row 0 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W01_LSB           0x2188 /* row 0 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W02_MSB           0x218C /* row 0 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W02_LSB           0x218D /* row 0 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_W10_MSB           0x2190 /* row 1 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W10_LSB           0x218F /* row 1 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W11_MSB           0x2193 /* row 1 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W11_LSB           0x2194 /* row 1 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W12_MSB           0x2197 /* row 1 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W12_LSB           0x2198 /* row 1 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_W20_MSB           0x219B /* row 2 column 0 of YUV matrix MSB */
+#define VS6624_RYM0_W20_LSB           0x219C /* row 2 column 0 of YUV matrix LSB */
+#define VS6624_RYM0_W21_MSB           0x21A0 /* row 2 column 1 of YUV matrix MSB */
+#define VS6624_RYM0_W21_LSB           0x219F /* row 2 column 1 of YUV matrix LSB */
+#define VS6624_RYM0_W22_MSB           0x21A3 /* row 2 column 2 of YUV matrix MSB */
+#define VS6624_RYM0_W22_LSB           0x21A4 /* row 2 column 2 of YUV matrix LSB */
+#define VS6624_RYM0_YINY_MSB          0x21A7 /* Y in Y MSB */
+#define VS6624_RYM0_YINY_LSB          0x21A8 /* Y in Y LSB */
+#define VS6624_RYM0_YINCB_MSB         0x21AB /* Y in Cb MSB */
+#define VS6624_RYM0_YINCB_LSB         0x21AC /* Y in Cb LSB */
+#define VS6624_RYM0_YINCR_MSB         0x21B0 /* Y in Cr MSB */
+#define VS6624_RYM0_YINCR_LSB         0x21AF /* Y in Cr LSB */
+/* pipe 1 RGB to YUV matrix manual control */
+#define VS6624_RYM1_MAN_CTRL          0x2200 /* enable manual RGB to YUV matrix */
+#define VS6624_RYM1_W00_MSB           0x2203 /* row 0 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W00_LSB           0x2204 /* row 0 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W01_MSB           0x2207 /* row 0 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W01_LSB           0x2208 /* row 0 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W02_MSB           0x220C /* row 0 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W02_LSB           0x220D /* row 0 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_W10_MSB           0x2210 /* row 1 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W10_LSB           0x220F /* row 1 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W11_MSB           0x2213 /* row 1 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W11_LSB           0x2214 /* row 1 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W12_MSB           0x2217 /* row 1 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W12_LSB           0x2218 /* row 1 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_W20_MSB           0x221B /* row 2 column 0 of YUV matrix MSB */
+#define VS6624_RYM1_W20_LSB           0x221C /* row 2 column 0 of YUV matrix LSB */
+#define VS6624_RYM1_W21_MSB           0x2220 /* row 2 column 1 of YUV matrix MSB */
+#define VS6624_RYM1_W21_LSB           0x221F /* row 2 column 1 of YUV matrix LSB */
+#define VS6624_RYM1_W22_MSB           0x2223 /* row 2 column 2 of YUV matrix MSB */
+#define VS6624_RYM1_W22_LSB           0x2224 /* row 2 column 2 of YUV matrix LSB */
+#define VS6624_RYM1_YINY_MSB          0x2227 /* Y in Y MSB */
+#define VS6624_RYM1_YINY_LSB          0x2228 /* Y in Y LSB */
+#define VS6624_RYM1_YINCB_MSB         0x222B /* Y in Cb MSB */
+#define VS6624_RYM1_YINCB_LSB         0x222C /* Y in Cb LSB */
+#define VS6624_RYM1_YINCR_MSB         0x2220 /* Y in Cr MSB */
+#define VS6624_RYM1_YINCR_LSB         0x222F /* Y in Cr LSB */
+/* pipe 0 gamma manual control */
+#define VS6624_GAMMA_MAN_CTRL0        0x2280 /* enable manual gamma setup */
+#define VS6624_GAMMA_PEAK_R0          0x2282 /* peaked red channel gamma value */
+#define VS6624_GAMMA_PEAK_G0          0x2284 /* peaked green channel gamma value */
+#define VS6624_GAMMA_PEAK_B0          0x2286 /* peaked blue channel gamma value */
+#define VS6624_GAMMA_UNPEAK_R0        0x2288 /* unpeaked red channel gamma value */
+#define VS6624_GAMMA_UNPEAK_G0        0x228A /* unpeaked green channel gamma value */
+#define VS6624_GAMMA_UNPEAK_B0        0x228C /* unpeaked blue channel gamma value */
+/* pipe 1 gamma manual control */
+#define VS6624_GAMMA_MAN_CTRL1        0x2300 /* enable manual gamma setup */
+#define VS6624_GAMMA_PEAK_R1          0x2302 /* peaked red channel gamma value */
+#define VS6624_GAMMA_PEAK_G1          0x2304 /* peaked green channel gamma value */
+#define VS6624_GAMMA_PEAK_B1          0x2306 /* peaked blue channel gamma value */
+#define VS6624_GAMMA_UNPEAK_R1        0x2308 /* unpeaked red channel gamma value */
+#define VS6624_GAMMA_UNPEAK_G1        0x230A /* unpeaked green channel gamma value */
+#define VS6624_GAMMA_UNPEAK_B1        0x230C /* unpeaked blue channel gamma value */
+/* fade to black */
+#define VS6624_F2B_DISABLE            0x2480 /* disable fade to black */
+#define VS6624_F2B_BLACK_VAL_MSB      0x2483 /* black value MSB */
+#define VS6624_F2B_BLACK_VAL_LSB      0x2484 /* black value LSB */
+#define VS6624_F2B_LOW_THR_MSB        0x2487 /* low threshold for exposure MSB */
+#define VS6624_F2B_LOW_THR_LSB        0x2488 /* low threshold for exposure LSB */
+#define VS6624_F2B_HIGH_THR_MSB       0x248B /* high threshold for exposure MSB */
+#define VS6624_F2B_HIGH_THR_LSB       0x248C /* high threshold for exposure LSB */
+#define VS6624_F2B_MIN_OUT_MSB        0x248F /* minimum damper output MSB */
+#define VS6624_F2B_MIN_OUT_LSB        0x2490 /* minimum damper output LSB */
+/* output formatter control */
+#define VS6624_CODE_CK_EN             0x2580 /* code check enable */
+#define VS6624_BLANK_FMT              0x2582 /* blank format */
+#define VS6624_SYNC_CODE_SETUP        0x2584 /* sync code setup */
+#define VS6624_HSYNC_SETUP            0x2586 /* H sync setup */
+#define VS6624_VSYNC_SETUP            0x2588 /* V sync setup */
+#define VS6624_PCLK_SETUP             0x258A /* PCLK setup */
+#define VS6624_PCLK_EN                0x258C /* PCLK enable */
+#define VS6624_OPF_SP_SETUP           0x258E /* output formatter sp setup */
+#define VS6624_BLANK_DATA_MSB         0x2590 /* blank data MSB */
+#define VS6624_BLANK_DATA_LSB         0x2592 /* blank data LSB */
+#define VS6624_RGB_SETUP              0x2594 /* RGB setup */
+#define VS6624_YUV_SETUP              0x2596 /* YUV setup */
+#define VS6624_VSYNC_RIS_COARSE_H     0x2598 /* V sync rising coarse high */
+#define VS6624_VSYNC_RIS_COARSE_L     0x259A /* V sync rising coarse low */
+#define VS6624_VSYNC_RIS_FINE_H       0x259C /* V sync rising fine high */
+#define VS6624_VSYNC_RIS_FINE_L       0x259E /* V sync rising fine low */
+#define VS6624_VSYNC_FALL_COARSE_H    0x25A0 /* V sync falling coarse high */
+#define VS6624_VSYNC_FALL_COARSE_L    0x25A2 /* V sync falling coarse low */
+#define VS6624_VSYNC_FALL_FINE_H      0x25A4 /* V sync falling fine high */
+#define VS6624_VSYNC_FALL_FINE_L      0x25A6 /* V sync falling fine low */
+#define VS6624_HSYNC_RIS_H            0x25A8 /* H sync rising high */
+#define VS6624_HSYNC_RIS_L            0x25AA /* H sync rising low */
+#define VS6624_HSYNC_FALL_H           0x25AC /* H sync falling high */
+#define VS6624_HSYNC_FALL_L           0x25AE /* H sync falling low */
+#define VS6624_OUT_IF                 0x25B0 /* output interface */
+#define VS6624_CCP_EXT_DATA           0x25B2 /* CCP extra data */
+/* NoRA controls */
+#define VS6624_NORA_DISABLE           0x2600 /* NoRA control mode */
+#define VS6624_NORA_USAGE             0x2602 /* usage */
+#define VS6624_NORA_SPLIT_KN          0x2604 /* split kn */
+#define VS6624_NORA_SPLIT_NI          0x2606 /* split ni */
+#define VS6624_NORA_TIGHT_G           0x2608 /* tight green */
+#define VS6624_NORA_DISABLE_NP        0x260A /* disable noro promoting */
+#define VS6624_NORA_LOW_THR_MSB       0x260D /* low threshold for exposure MSB */
+#define VS6624_NORA_LOW_THR_LSB       0x260E /* low threshold for exposure LSB */
+#define VS6624_NORA_HIGH_THR_MSB      0x2611 /* high threshold for exposure MSB */
+#define VS6624_NORA_HIGH_THR_LSB      0x2612 /* high threshold for exposure LSB */
+#define VS6624_NORA_MIN_OUT_MSB       0x2615 /* minimum damper output MSB */
+#define VS6624_NORA_MIN_OUT_LSB       0x2616 /* minimum damper output LSB */
+
+#endif
index 453dbbd..7fd7ac5 100644 (file)
@@ -129,9 +129,9 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION("0.33.1");
 
 #ifdef MODULE
-static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
+static char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
 #else
-static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
+static char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
 #endif
 module_param_array(pardev, charp, NULL, 0);
 MODULE_PARM_DESC(pardev, "pardev: where to search for\n"
index a22f765..3bb99e9 100644 (file)
@@ -291,15 +291,4 @@ static struct i2c_driver wm8739_driver = {
        .id_table       = wm8739_id,
 };
 
-static __init int init_wm8739(void)
-{
-       return i2c_add_driver(&wm8739_driver);
-}
-
-static __exit void exit_wm8739(void)
-{
-       i2c_del_driver(&wm8739_driver);
-}
-
-module_init(init_wm8739);
-module_exit(exit_wm8739);
+module_i2c_driver(wm8739_driver);
index 9cedb1e..bee77ea 100644 (file)
@@ -339,15 +339,4 @@ static struct i2c_driver wm8775_driver = {
        .id_table       = wm8775_id,
 };
 
-static __init int init_wm8775(void)
-{
-       return i2c_add_driver(&wm8775_driver);
-}
-
-static __exit void exit_wm8775(void)
-{
-       i2c_del_driver(&wm8775_driver);
-}
-
-module_init(init_wm8775);
-module_exit(exit_wm8775);
+module_i2c_driver(wm8775_driver);
index a7dc467..a5c591f 100644 (file)
@@ -346,7 +346,7 @@ static int mpt_remove_dead_ioc_func(void *arg)
        if ((pdev == NULL))
                return -1;
 
-       pci_remove_bus_device(pdev);
+       pci_stop_and_remove_bus_device(pdev);
        return 0;
 }
 
index 17dfe9b..87bd5ba 100644 (file)
@@ -503,6 +503,101 @@ static void device_irq_exit(struct pm860x_chip *chip)
                free_irq(chip->core_irq, chip);
 }
 
+int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
+{
+       int ret = -EIO;
+       struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
+               chip->client : chip->companion;
+
+       dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
+       dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
+                       __func__, chip->osc_vote,
+                       chip->osc_status);
+
+       mutex_lock(&chip->osc_lock);
+       /* Update voting status */
+       chip->osc_vote |= client;
+       /* If reference group is off - turn on*/
+       if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
+               chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
+               /* Enable Reference group Vsys */
+               if (pm860x_set_bits(i2c, PM8606_VSYS,
+                               PM8606_VSYS_EN, PM8606_VSYS_EN))
+                       goto out;
+
+               /*Enable Internal Oscillator */
+               if (pm860x_set_bits(i2c, PM8606_MISC,
+                               PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
+                       goto out;
+               /* Update status (only if writes succeed) */
+               chip->osc_status = PM8606_REF_GP_OSC_ON;
+       }
+       mutex_unlock(&chip->osc_lock);
+
+       dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
+                       __func__, chip->osc_vote,
+                       chip->osc_status, ret);
+       return 0;
+out:
+       mutex_unlock(&chip->osc_lock);
+       return ret;
+}
+EXPORT_SYMBOL(pm8606_osc_enable);
+
+int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
+{
+       int ret = -EIO;
+       struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
+               chip->client : chip->companion;
+
+       dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);
+       dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",
+                       __func__, chip->osc_vote,
+                       chip->osc_status);
+
+       mutex_lock(&chip->osc_lock);
+       /*Update voting status */
+       chip->osc_vote &= ~(client);
+       /* If reference group is off and this is the last client to release
+        * - turn off */
+       if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
+                       (chip->osc_vote == REF_GP_NO_CLIENTS)) {
+               chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
+               /* Disable Reference group Vsys */
+               if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
+                       goto out;
+               /* Disable Internal Oscillator */
+               if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
+                       goto out;
+               chip->osc_status = PM8606_REF_GP_OSC_OFF;
+       }
+       mutex_unlock(&chip->osc_lock);
+
+       dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",
+                       __func__, chip->osc_vote,
+                       chip->osc_status, ret);
+       return 0;
+out:
+       mutex_unlock(&chip->osc_lock);
+       return ret;
+}
+EXPORT_SYMBOL(pm8606_osc_disable);
+
+static void __devinit device_osc_init(struct i2c_client *i2c)
+{
+       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+
+       mutex_init(&chip->osc_lock);
+       /* init portofino reference group voting and status */
+       /* Disable Reference group Vsys */
+       pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
+       /* Disable Internal Oscillator */
+       pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
+
+       chip->osc_vote = REF_GP_NO_CLIENTS;
+       chip->osc_status = PM8606_REF_GP_OSC_OFF;
+}
+
 static void __devinit device_bk_init(struct pm860x_chip *chip,
                                     struct pm860x_platform_data *pdata)
 {
@@ -767,6 +862,15 @@ out:
        return;
 }
 
+static void __devinit device_8606_init(struct pm860x_chip *chip,
+                                      struct i2c_client *i2c,
+                                      struct pm860x_platform_data *pdata)
+{
+       device_osc_init(i2c);
+       device_bk_init(chip, pdata);
+       device_led_init(chip, pdata);
+}
+
 int __devinit pm860x_device_init(struct pm860x_chip *chip,
                       struct pm860x_platform_data *pdata)
 {
@@ -774,8 +878,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
 
        switch (chip->id) {
        case CHIP_PM8606:
-               device_bk_init(chip, pdata);
-               device_led_init(chip, pdata);
+               device_8606_init(chip, chip->client, pdata);
                break;
        case CHIP_PM8607:
                device_8607_init(chip, chip->client, pdata);
@@ -785,8 +888,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
        if (chip->companion) {
                switch (chip->id) {
                case CHIP_PM8607:
-                       device_bk_init(chip, pdata);
-                       device_led_init(chip, pdata);
+                       device_8606_init(chip, chip->companion, pdata);
                        break;
                case CHIP_PM8606:
                        device_8607_init(chip, chip->companion, pdata);
index f93dd95..b2cfdc4 100644 (file)
@@ -334,10 +334,35 @@ static int __devexit pm860x_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev) && chip->wakeup_flag)
+               enable_irq_wake(chip->core_irq);
+       return 0;
+}
+
+static int pm860x_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct pm860x_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev) && chip->wakeup_flag)
+               disable_irq_wake(chip->core_irq);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);
+
 static struct i2c_driver pm860x_driver = {
        .driver = {
                .name   = "88PM860x",
                .owner  = THIS_MODULE,
+               .pm     = &pm860x_pm_ops,
        },
        .probe          = pm860x_probe,
        .remove         = __devexit_p(pm860x_remove),
index 1489c35..29f463c 100644 (file)
@@ -143,6 +143,21 @@ config TPS6507X
          This driver can also be built as a module.  If so, the module
          will be called tps6507x.
 
+config MFD_TPS65217
+       tristate "TPS65217 Power Management / White LED chips"
+       depends on I2C
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for the TPS65217 series of
+         Power Management / White LED chips.
+         These include voltage regulators, lithium ion/polymer battery
+         charger, wled and other features that are often used in portable
+         devices.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tps65217.
+
 config MFD_TPS6586X
        bool "TPS6586x Power Management chips"
        depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
@@ -162,6 +177,7 @@ config MFD_TPS65910
        depends on I2C=y && GPIOLIB
        select MFD_CORE
        select GPIO_TPS65910
+       select REGMAP_I2C
        help
          if you say yes here you get support for the TPS65910 series of
          Power Management chips.
@@ -171,7 +187,7 @@ config MFD_TPS65912
        depends on GPIOLIB
 
 config MFD_TPS65912_I2C
-       bool "TPS95612 Power Management chip with I2C"
+       bool "TPS65912 Power Management chip with I2C"
        select MFD_CORE
        select MFD_TPS65912
        depends on I2C=y && GPIOLIB
@@ -400,7 +416,7 @@ config MFD_MAX8997
        depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
        help
-         Say yes here to support for Maxim Semiconductor MAX8998/8966.
+         Say yes here to support for Maxim Semiconductor MAX8997/8966.
          This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
          MUIC controls on chip.
          This driver provides common support for accessing the device;
@@ -812,6 +828,18 @@ config MFD_PM8XXX_IRQ
 config TPS65911_COMPARATOR
        tristate
 
+config MFD_TPS65090
+       bool "TPS65090 Power Management chips"
+       depends on I2C=y && GENERIC_HARDIRQS
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for the TPS65090 series of
+         Power Management chips.
+         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_AAT2870_CORE
        bool "Support for the AnalogicTech AAT2870"
        select MFD_CORE
@@ -831,6 +859,28 @@ config MFD_INTEL_MSIC
          Passage) chip. This chip embeds audio, battery, GPIO, etc.
          devices used in Intel Medfield platforms.
 
+config MFD_RC5T583
+       bool "Ricoh RC5T583 Power Management system device"
+       depends on I2C=y && GENERIC_HARDIRQS
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         Select this option to get support for the RICOH583 Power
+         Management system device.
+         This driver provides common support for accessing the device
+         through i2c interface. The device supports multiple sub-devices
+         like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey.
+         Additional drivers must be enabled in order to use the
+         different functionality of the device.
+
+config MFD_ANATOP
+       bool "Support for Freescale i.MX on-chip ANATOP controller"
+       depends on SOC_IMX6Q
+       help
+         Select this option to enable Freescale i.MX on-chip ANATOP
+         MFD controller. This controller embeds regulator and
+         thermal devices for Freescale i.MX platforms.
+
 endmenu
 endif
 
@@ -848,8 +898,9 @@ config MCP_SA11X0
 
 # Chip drivers
 config MCP_UCB1200
-       tristate "Support for UCB1200 / UCB1300"
-       depends on MCP
+       bool "Support for UCB1200 / UCB1300"
+       depends on MCP_SA11X0
+       select MCP
 
 config MCP_UCB1200_TS
        tristate "Touchscreen interface support"
index b953bab..05fa538 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_MFD_WM8994)      += wm8994-core.o wm8994-irq.o wm8994-regmap.o
 obj-$(CONFIG_TPS6105X)         += tps6105x.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_TPS6507X)         += tps6507x.o
+obj-$(CONFIG_MFD_TPS65217)     += tps65217.o
 obj-$(CONFIG_MFD_TPS65910)     += tps65910.o tps65910-irq.o
 tps65912-objs                   := tps65912-core.o tps65912-irq.o
 obj-$(CONFIG_MFD_TPS65912)     += tps65912.o
@@ -109,6 +110,9 @@ obj-$(CONFIG_MFD_OMAP_USB_HOST)     += omap-usb-host.o
 obj-$(CONFIG_MFD_PM8921_CORE)  += pm8921-core.o
 obj-$(CONFIG_MFD_PM8XXX_IRQ)   += pm8xxx-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)      += tps65911-comparator.o
+obj-$(CONFIG_MFD_TPS65090)     += tps65090.o
 obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
 obj-$(CONFIG_MFD_INTEL_MSIC)   += intel_msic.o
+obj-$(CONFIG_MFD_RC5T583)      += rc5t583.o rc5t583-irq.o
 obj-$(CONFIG_MFD_S5M_CORE)     += s5m-core.o s5m-irq.o
+obj-$(CONFIG_MFD_ANATOP)       += anatop-mfd.o
index d295941..1f08704 100644 (file)
@@ -32,6 +32,7 @@
 #define AB8500_IT_SOURCE6_REG          0x05
 #define AB8500_IT_SOURCE7_REG          0x06
 #define AB8500_IT_SOURCE8_REG          0x07
+#define AB9540_IT_SOURCE13_REG         0x0C
 #define AB8500_IT_SOURCE19_REG         0x12
 #define AB8500_IT_SOURCE20_REG         0x13
 #define AB8500_IT_SOURCE21_REG         0x14
@@ -53,6 +54,7 @@
 #define AB8500_IT_LATCH9_REG           0x28
 #define AB8500_IT_LATCH10_REG          0x29
 #define AB8500_IT_LATCH12_REG          0x2B
+#define AB9540_IT_LATCH13_REG          0x2C
 #define AB8500_IT_LATCH19_REG          0x32
 #define AB8500_IT_LATCH20_REG          0x33
 #define AB8500_IT_LATCH21_REG          0x34
 #define AB8500_IT_MASK24_REG           0x57
 
 #define AB8500_REV_REG                 0x80
+#define AB8500_IC_NAME_REG             0x82
 #define AB8500_SWITCH_OFF_STATUS       0x00
 
 #define AB8500_TURN_ON_STATUS          0x00
 
+#define AB9540_MODEM_CTRL2_REG                 0x23
+#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT       BIT(2)
+
 /*
  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
- * numbers are indexed into this array with (num / 8).
+ * numbers are indexed into this array with (num / 8). The interupts are
+ * defined in linux/mfd/ab8500.h
  *
  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
  * offset 0.
  */
+/* AB8500 support */
 static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
        0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
 };
 
+/* AB9540 support */
+static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
+       0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
+};
+
+static const char ab8500_version_str[][7] = {
+       [AB8500_VERSION_AB8500] = "AB8500",
+       [AB8500_VERSION_AB8505] = "AB8505",
+       [AB8500_VERSION_AB9540] = "AB9540",
+       [AB8500_VERSION_AB8540] = "AB8540",
+};
+
 static int ab8500_get_chip_id(struct device *dev)
 {
        struct ab8500 *ab8500;
@@ -127,9 +147,7 @@ static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
 
        dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
 
-       ret = mutex_lock_interruptible(&ab8500->lock);
-       if (ret)
-               return ret;
+       mutex_lock(&ab8500->lock);
 
        ret = ab8500->write(ab8500, addr, data);
        if (ret < 0)
@@ -156,9 +174,7 @@ static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
         * bank on higher 8 bits and reg in lower */
        u16 addr = ((u16)bank) << 8 | reg;
 
-       ret = mutex_lock_interruptible(&ab8500->lock);
-       if (ret)
-               return ret;
+       mutex_lock(&ab8500->lock);
 
        ret = ab8500->read(ab8500, addr);
        if (ret < 0)
@@ -185,31 +201,38 @@ static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
        u8 reg, u8 bitmask, u8 bitvalues)
 {
        int ret;
-       u8 data;
        /* put the u8 bank and u8 reg together into a an u16.
         * bank on higher 8 bits and reg in lower */
        u16 addr = ((u16)bank) << 8 | reg;
 
-       ret = mutex_lock_interruptible(&ab8500->lock);
-       if (ret)
-               return ret;
+       mutex_lock(&ab8500->lock);
 
-       ret = ab8500->read(ab8500, addr);
-       if (ret < 0) {
-               dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
-                       addr, ret);
-               goto out;
-       }
+       if (ab8500->write_masked == NULL) {
+               u8 data;
 
-       data = (u8)ret;
-       data = (~bitmask & data) | (bitmask & bitvalues);
+               ret = ab8500->read(ab8500, addr);
+               if (ret < 0) {
+                       dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
+                               addr, ret);
+                       goto out;
+               }
 
-       ret = ab8500->write(ab8500, addr, data);
-       if (ret < 0)
-               dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
-                       addr, ret);
+               data = (u8)ret;
+               data = (~bitmask & data) | (bitmask & bitvalues);
+
+               ret = ab8500->write(ab8500, addr, data);
+               if (ret < 0)
+                       dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
+                               addr, ret);
 
-       dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data);
+               dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr,
+                       data);
+               goto out;
+       }
+       ret = ab8500->write_masked(ab8500, addr, bitmask, bitvalues);
+       if (ret < 0)
+               dev_err(ab8500->dev, "failed to modify reg %#x: %d\n", addr,
+                       ret);
 out:
        mutex_unlock(&ab8500->lock);
        return ret;
@@ -248,7 +271,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
        struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
        int i;
 
-       for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
+       for (i = 0; i < ab8500->mask_size; i++) {
                u8 old = ab8500->oldmask[i];
                u8 new = ab8500->mask[i];
                int reg;
@@ -256,14 +279,17 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
                if (new == old)
                        continue;
 
-               /* Interrupt register 12 doesn't exist prior to version 2.0 */
-               if (ab8500_irq_regoffset[i] == 11 &&
-                       ab8500->chip_id < AB8500_CUT2P0)
+               /*
+                * Interrupt register 12 doesn't exist prior to AB8500 version
+                * 2.0
+                */
+               if (ab8500->irq_reg_offset[i] == 11 &&
+                       is_ab8500_1p1_or_earlier(ab8500))
                        continue;
 
                ab8500->oldmask[i] = new;
 
-               reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
+               reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
                set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
        }
 
@@ -306,13 +332,16 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
 
        dev_vdbg(ab8500->dev, "interrupt\n");
 
-       for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
-               int regoffset = ab8500_irq_regoffset[i];
+       for (i = 0; i < ab8500->mask_size; i++) {
+               int regoffset = ab8500->irq_reg_offset[i];
                int status;
                u8 value;
 
-               /* Interrupt register 12 doesn't exist prior to version 2.0 */
-               if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
+               /*
+                * Interrupt register 12 doesn't exist prior to AB8500 version
+                * 2.0
+                */
+               if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
                        continue;
 
                status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
@@ -336,8 +365,16 @@ static int ab8500_irq_init(struct ab8500 *ab8500)
 {
        int base = ab8500->irq_base;
        int irq;
+       int num_irqs;
+
+       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;
 
-       for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
+       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);
@@ -356,8 +393,16 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
 {
        int base = ab8500->irq_base;
        int irq;
+       int num_irqs;
 
-       for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
+       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;
+
+       for (irq = base; irq < base + num_irqs; irq++) {
 #ifdef CONFIG_ARM
                set_irq_flags(irq, 0);
 #endif
@@ -366,6 +411,7 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
        }
 }
 
+/* AB8500 GPIO Resources */
 static struct resource __devinitdata ab8500_gpio_resources[] = {
        {
                .name   = "GPIO_INT6",
@@ -375,6 +421,28 @@ static struct resource __devinitdata ab8500_gpio_resources[] = {
        }
 };
 
+/* AB9540 GPIO Resources */
+static struct resource __devinitdata ab9540_gpio_resources[] = {
+       {
+               .name   = "GPIO_INT6",
+               .start  = AB8500_INT_GPIO6R,
+               .end    = AB8500_INT_GPIO41F,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "GPIO_INT14",
+               .start  = AB9540_INT_GPIO50R,
+               .end    = AB9540_INT_GPIO54R,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "GPIO_INT15",
+               .start  = AB9540_INT_GPIO50F,
+               .end    = AB9540_INT_GPIO54F,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
 static struct resource __devinitdata ab8500_gpadc_resources[] = {
        {
                .name   = "HW_CONV_END",
@@ -491,12 +559,6 @@ static struct resource __devinitdata ab8500_charger_resources[] = {
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "USB_CHARGE_DET_DONE",
-               .start = AB8500_INT_USB_CHG_DET_DONE,
-               .end = AB8500_INT_USB_CHG_DET_DONE,
-               .flags = IORESOURCE_IRQ,
-       },
-       {
                .name = "VBUS_OVV",
                .start = AB8500_INT_VBUS_OVV,
                .end = AB8500_INT_VBUS_OVV,
@@ -534,14 +596,8 @@ static struct resource __devinitdata ab8500_charger_resources[] = {
        },
        {
                .name = "USB_CHARGER_NOT_OKR",
-               .start = AB8500_INT_USB_CHARGER_NOT_OK,
-               .end = AB8500_INT_USB_CHARGER_NOT_OK,
-               .flags = IORESOURCE_IRQ,
-       },
-       {
-               .name = "USB_CHARGER_NOT_OKF",
-               .start = AB8500_INT_USB_CHARGER_NOT_OKF,
-               .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .start = AB8500_INT_USB_CHARGER_NOT_OKR,
+               .end = AB8500_INT_USB_CHARGER_NOT_OKR,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -616,6 +672,12 @@ static struct resource __devinitdata ab8500_fg_resources[] = {
                .end = AB8500_INT_CC_INT_CALIB,
                .flags = IORESOURCE_IRQ,
        },
+       {
+               .name = "CCEOC",
+               .start = AB8500_INT_CCEOC,
+               .end = AB8500_INT_CCEOC,
+               .flags = IORESOURCE_IRQ,
+       },
 };
 
 static struct resource __devinitdata ab8500_chargalg_resources[] = {};
@@ -630,8 +692,8 @@ static struct resource __devinitdata ab8500_debug_resources[] = {
        },
        {
                .name   = "IRQ_LAST",
-               .start  = AB8500_INT_USB_CHARGER_NOT_OKF,
-               .end    = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .start  = AB8500_INT_XTAL32K_KO,
+               .end    = AB8500_INT_XTAL32K_KO,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -691,7 +753,7 @@ static struct resource __devinitdata ab8500_temp_resources[] = {
        },
 };
 
-static struct mfd_cell __devinitdata ab8500_devs[] = {
+static struct mfd_cell __devinitdata abx500_common_devs[] = {
 #ifdef CONFIG_DEBUG_FS
        {
                .name = "ab8500-debug",
@@ -706,11 +768,6 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
                .name = "ab8500-regulator",
        },
        {
-               .name = "ab8500-gpio",
-               .num_resources = ARRAY_SIZE(ab8500_gpio_resources),
-               .resources = ab8500_gpio_resources,
-       },
-       {
                .name = "ab8500-gpadc",
                .num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
                .resources = ab8500_gpadc_resources,
@@ -748,11 +805,7 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
        {
                .name = "ab8500-codec",
        },
-       {
-               .name = "ab8500-usb",
-               .num_resources = ARRAY_SIZE(ab8500_usb_resources),
-               .resources = ab8500_usb_resources,
-       },
+
        {
                .name = "ab8500-poweron-key",
                .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
@@ -781,6 +834,32 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
        },
 };
 
+static struct mfd_cell __devinitdata ab8500_devs[] = {
+       {
+               .name = "ab8500-gpio",
+               .num_resources = ARRAY_SIZE(ab8500_gpio_resources),
+               .resources = ab8500_gpio_resources,
+       },
+       {
+               .name = "ab8500-usb",
+               .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+               .resources = ab8500_usb_resources,
+       },
+};
+
+static struct mfd_cell __devinitdata ab9540_devs[] = {
+       {
+               .name = "ab8500-gpio",
+               .num_resources = ARRAY_SIZE(ab9540_gpio_resources),
+               .resources = ab9540_gpio_resources,
+       },
+       {
+               .name = "ab9540-usb",
+               .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+               .resources = ab8500_usb_resources,
+       },
+};
+
 static ssize_t show_chip_id(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
@@ -842,9 +921,64 @@ static ssize_t show_turn_on_status(struct device *dev,
        return sprintf(buf, "%#x\n", value);
 }
 
+static ssize_t show_ab9540_dbbrstn(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct ab8500 *ab8500;
+       int ret;
+       u8 value;
+
+       ab8500 = dev_get_drvdata(dev);
+
+       ret = get_register_interruptible(ab8500, AB8500_REGU_CTRL2,
+               AB9540_MODEM_CTRL2_REG, &value);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n",
+                       (value & AB9540_MODEM_CTRL2_SWDBBRSTN_BIT) ? 1 : 0);
+}
+
+static ssize_t store_ab9540_dbbrstn(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct ab8500 *ab8500;
+       int ret = count;
+       int err;
+       u8 bitvalues;
+
+       ab8500 = dev_get_drvdata(dev);
+
+       if (count > 0) {
+               switch (buf[0]) {
+               case '0':
+                       bitvalues = 0;
+                       break;
+               case '1':
+                       bitvalues = AB9540_MODEM_CTRL2_SWDBBRSTN_BIT;
+                       break;
+               default:
+                       goto exit;
+               }
+
+               err = mask_and_set_register_interruptible(ab8500,
+                       AB8500_REGU_CTRL2, AB9540_MODEM_CTRL2_REG,
+                       AB9540_MODEM_CTRL2_SWDBBRSTN_BIT, bitvalues);
+               if (err)
+                       dev_info(ab8500->dev,
+                               "Failed to set DBBRSTN %c, err %#x\n",
+                               buf[0], err);
+       }
+
+exit:
+       return ret;
+}
+
 static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
 static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
 static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
+static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
+                       show_ab9540_dbbrstn, store_ab9540_dbbrstn);
 
 static struct attribute *ab8500_sysfs_entries[] = {
        &dev_attr_chip_id.attr,
@@ -853,11 +987,23 @@ static struct attribute *ab8500_sysfs_entries[] = {
        NULL,
 };
 
+static struct attribute *ab9540_sysfs_entries[] = {
+       &dev_attr_chip_id.attr,
+       &dev_attr_switch_off_status.attr,
+       &dev_attr_turn_on_status.attr,
+       &dev_attr_dbbrstn.attr,
+       NULL,
+};
+
 static struct attribute_group ab8500_attr_group = {
        .attrs  = ab8500_sysfs_entries,
 };
 
-int __devinit ab8500_init(struct ab8500 *ab8500)
+static struct attribute_group ab9540_attr_group = {
+       .attrs  = ab9540_sysfs_entries,
+};
+
+int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
 {
        struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
        int ret;
@@ -870,25 +1016,45 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
        mutex_init(&ab8500->lock);
        mutex_init(&ab8500->irq_lock);
 
+       if (version != AB8500_VERSION_UNDEFINED)
+               ab8500->version = version;
+       else {
+               ret = get_register_interruptible(ab8500, AB8500_MISC,
+                       AB8500_IC_NAME_REG, &value);
+               if (ret < 0)
+                       return ret;
+
+               ab8500->version = value;
+       }
+
        ret = get_register_interruptible(ab8500, AB8500_MISC,
                AB8500_REV_REG, &value);
        if (ret < 0)
                return ret;
 
-       switch (value) {
-       case AB8500_CUT1P0:
-       case AB8500_CUT1P1:
-       case AB8500_CUT2P0:
-       case AB8500_CUT3P0:
-       case AB8500_CUT3P3:
-               dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
-               break;
-       default:
-               dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
-               return -EINVAL;
-       }
        ab8500->chip_id = value;
 
+       dev_info(ab8500->dev, "detected chip, %s rev. %1x.%1x\n",
+                       ab8500_version_str[ab8500->version],
+                       ab8500->chip_id >> 4,
+                       ab8500->chip_id & 0x0F);
+
+       /* Configure AB8500 or AB9540 IRQ */
+       if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
+               ab8500->mask_size = AB9540_NUM_IRQ_REGS;
+               ab8500->irq_reg_offset = ab9540_irq_regoffset;
+       } else {
+               ab8500->mask_size = AB8500_NUM_IRQ_REGS;
+               ab8500->irq_reg_offset = ab8500_irq_regoffset;
+       }
+       ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
+       if (!ab8500->mask)
+               return -ENOMEM;
+       ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
+       if (!ab8500->oldmask) {
+               ret = -ENOMEM;
+               goto out_freemask;
+       }
        /*
         * ab8500 has switched off due to (SWITCH_OFF_STATUS):
         * 0x01 Swoff bit programming
@@ -911,30 +1077,33 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
                plat->init(ab8500);
 
        /* Clear and mask all interrupts */
-       for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
-               /* Interrupt register 12 doesn't exist prior to version 2.0 */
-               if (ab8500_irq_regoffset[i] == 11 &&
-                       ab8500->chip_id < AB8500_CUT2P0)
+       for (i = 0; i < ab8500->mask_size; i++) {
+               /*
+                * Interrupt register 12 doesn't exist prior to AB8500 version
+                * 2.0
+                */
+               if (ab8500->irq_reg_offset[i] == 11 &&
+                               is_ab8500_1p1_or_earlier(ab8500))
                        continue;
 
                get_register_interruptible(ab8500, AB8500_INTERRUPT,
-                       AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
+                       AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
                        &value);
                set_register_interruptible(ab8500, AB8500_INTERRUPT,
-                       AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
+                       AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
        }
 
        ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
        if (ret)
-               return ret;
+               goto out_freeoldmask;
 
-       for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
+       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)
-                       return ret;
+                       goto out_freeoldmask;
 
                ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
                                           IRQF_ONESHOT | IRQF_NO_SUSPEND,
@@ -943,17 +1112,34 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
                        goto out_removeirq;
        }
 
-       ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
-                             ARRAY_SIZE(ab8500_devs), NULL,
+       ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
+                             ARRAY_SIZE(abx500_common_devs), NULL,
                              ab8500->irq_base);
+
        if (ret)
                goto out_freeirq;
 
-       ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
+       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(ab9540_devs), NULL,
+                             ab8500->irq_base);
        if (ret)
-               dev_err(ab8500->dev, "error creating sysfs entries\n");
+               goto out_freeirq;
 
-       return ret;
+       if (is_ab9540(ab8500))
+               ret = sysfs_create_group(&ab8500->dev->kobj,
+                                       &ab9540_attr_group);
+       else
+               ret = sysfs_create_group(&ab8500->dev->kobj,
+                                       &ab8500_attr_group);
+       if (ret)
+               dev_err(ab8500->dev, "error creating sysfs entries\n");
+       else
+               return ret;
 
 out_freeirq:
        if (ab8500->irq_base)
@@ -961,18 +1147,27 @@ out_freeirq:
 out_removeirq:
        if (ab8500->irq_base)
                ab8500_irq_remove(ab8500);
+out_freeoldmask:
+       kfree(ab8500->oldmask);
+out_freemask:
+       kfree(ab8500->mask);
 
        return ret;
 }
 
 int __devexit ab8500_exit(struct ab8500 *ab8500)
 {
-       sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
+       if (is_ab9540(ab8500))
+               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);
        }
+       kfree(ab8500->oldmask);
+       kfree(ab8500->mask);
 
        return 0;
 }
index 087fecd..b83045f 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/mfd/db8500-prcmu.h>
+#include <linux/mfd/dbx500-prcmu.h>
 
 static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
 {
@@ -23,6 +23,18 @@ 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,
+       u8 data)
+{
+       int ret;
+
+       ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
+               &mask, 1);
+       if (ret < 0)
+               dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
+       return ret;
+}
+
 static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
 {
        int ret;
@@ -38,6 +50,7 @@ static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
 
 static int __devinit ab8500_i2c_probe(struct platform_device *plf)
 {
+       const struct platform_device_id *platid = platform_get_device_id(plf);
        struct ab8500 *ab8500;
        struct resource *resource;
        int ret;
@@ -58,13 +71,15 @@ static int __devinit ab8500_i2c_probe(struct platform_device *plf)
 
        ab8500->read = ab8500_i2c_read;
        ab8500->write = ab8500_i2c_write;
+       ab8500->write_masked = ab8500_i2c_write_masked;
 
        platform_set_drvdata(plf, ab8500);
 
-       ret = ab8500_init(ab8500);
+       ret = ab8500_init(ab8500, platid->driver_data);
        if (ret)
                kfree(ab8500);
 
+
        return ret;
 }
 
@@ -78,13 +93,22 @@ static int __devexit ab8500_i2c_remove(struct platform_device *plf)
        return 0;
 }
 
+static const struct platform_device_id ab8500_id[] = {
+       { "ab8500-i2c", AB8500_VERSION_AB8500 },
+       { "ab8505-i2c", AB8500_VERSION_AB8505 },
+       { "ab9540-i2c", AB8500_VERSION_AB9540 },
+       { "ab8540-i2c", AB8500_VERSION_AB8540 },
+       { }
+};
+
 static struct platform_driver ab8500_i2c_driver = {
        .driver = {
                .name = "ab8500-i2c",
                .owner = THIS_MODULE,
        },
        .probe  = ab8500_i2c_probe,
-       .remove = __devexit_p(ab8500_i2c_remove)
+       .remove = __devexit_p(ab8500_i2c_remove),
+       .id_table = ab8500_id,
 };
 
 static int __init ab8500_i2c_init(void)
diff --git a/drivers/mfd/anatop-mfd.c b/drivers/mfd/anatop-mfd.c
new file mode 100644 (file)
index 0000000..2af4248
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Anatop MFD driver
+ *
+ * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ * Copyright (C) 2012 Linaro
+ *
+ *  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.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/mfd/anatop.h>
+
+u32 anatop_get_bits(struct anatop *adata, u32 addr, int bit_shift,
+                   int bit_width)
+{
+       u32 val, mask;
+
+       if (bit_width == 32)
+               mask = ~0;
+       else
+               mask = (1 << bit_width) - 1;
+
+       val = readl(adata->ioreg + addr);
+       val = (val >> bit_shift) & mask;
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(anatop_get_bits);
+
+void anatop_set_bits(struct anatop *adata, u32 addr, int bit_shift,
+                    int bit_width, u32 data)
+{
+       u32 val, mask;
+
+       if (bit_width == 32)
+               mask = ~0;
+       else
+               mask = (1 << bit_width) - 1;
+
+       spin_lock(&adata->reglock);
+       val = readl(adata->ioreg + addr) & ~(mask << bit_shift);
+       writel((data << bit_shift) | val, adata->ioreg + addr);
+       spin_unlock(&adata->reglock);
+}
+EXPORT_SYMBOL_GPL(anatop_set_bits);
+
+static const struct of_device_id of_anatop_match[] = {
+       { .compatible = "fsl,imx6q-anatop", },
+       { },
+};
+
+static int __devinit of_anatop_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       void *ioreg;
+       struct anatop *drvdata;
+
+       ioreg = of_iomap(np, 0);
+       if (!ioreg)
+               return -EADDRNOTAVAIL;
+       drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+       drvdata->ioreg = ioreg;
+       spin_lock_init(&drvdata->reglock);
+       platform_set_drvdata(pdev, drvdata);
+       of_platform_populate(np, of_anatop_match, NULL, dev);
+
+       return 0;
+}
+
+static int __devexit of_anatop_remove(struct platform_device *pdev)
+{
+       struct anatop *drvdata;
+       drvdata = platform_get_drvdata(pdev);
+       iounmap(drvdata->ioreg);
+
+       return 0;
+}
+
+static struct platform_driver anatop_of_driver = {
+       .driver = {
+               .name = "anatop-mfd",
+               .owner = THIS_MODULE,
+               .of_match_table = of_anatop_match,
+       },
+       .probe          = of_anatop_probe,
+       .remove         = of_anatop_remove,
+};
+
+static int __init anatop_init(void)
+{
+       return platform_driver_register(&anatop_of_driver);
+}
+postcore_initcall(anatop_init);
+
+static void __exit anatop_exit(void)
+{
+       platform_driver_unregister(&anatop_of_driver);
+}
+module_exit(anatop_exit);
+
+MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");
+MODULE_DESCRIPTION("ANATOP MFD driver");
+MODULE_LICENSE("GPL v2");
index b85bbd7..1895cf9 100644 (file)
@@ -525,6 +525,11 @@ static void asic3_gpio_set(struct gpio_chip *chip,
        return;
 }
 
+static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       return (offset < ASIC3_NUM_GPIOS) ? IRQ_BOARD_START + offset : -ENXIO;
+}
+
 static __init int asic3_gpio_probe(struct platform_device *pdev,
                                   u16 *gpio_config, int num)
 {
@@ -976,6 +981,7 @@ static int __init asic3_probe(struct platform_device *pdev)
        asic->gpio.set = asic3_gpio_set;
        asic->gpio.direction_input = asic3_gpio_direction_input;
        asic->gpio.direction_output = asic3_gpio_direction_output;
+       asic->gpio.to_irq = asic3_gpio_to_irq;
 
        ret = asic3_gpio_probe(pdev,
                               pdata->gpio_config,
index 5ddde2a..7ff313f 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/mutex.h>
 #include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -647,8 +646,6 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
        struct irq_desc *desc;
        int ret;
 
-       mutex_init(&da9052->io_lock);
-
        if (pdata && pdata->init != NULL)
                pdata->init(da9052);
 
index 44b97c7..36b88e3 100644 (file)
@@ -74,24 +74,27 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client,
 
        ret = da9052_i2c_enable_multiwrite(da9052);
        if (ret < 0)
-               goto err;
+               goto err_regmap;
 
        ret = da9052_device_init(da9052, id->driver_data);
        if (ret != 0)
-               goto err;
+               goto err_regmap;
 
        return 0;
 
+err_regmap:
+       regmap_exit(da9052->regmap);
 err:
        kfree(da9052);
        return ret;
 }
 
-static int da9052_i2c_remove(struct i2c_client *client)
+static int __devexit da9052_i2c_remove(struct i2c_client *client)
 {
        struct da9052 *da9052 = i2c_get_clientdata(client);
 
        da9052_device_exit(da9052);
+       regmap_exit(da9052->regmap);
        kfree(da9052);
 
        return 0;
@@ -107,7 +110,7 @@ static struct i2c_device_id da9052_i2c_id[] = {
 
 static struct i2c_driver da9052_i2c_driver = {
        .probe = da9052_i2c_probe,
-       .remove = da9052_i2c_remove,
+       .remove = __devexit_p(da9052_i2c_remove),
        .id_table = da9052_i2c_id,
        .driver = {
                .name = "da9052",
index cdbc7ca..6faf149 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <linux/mfd/da9052/da9052.h>
 
-static int da9052_spi_probe(struct spi_device *spi)
+static int __devinit da9052_spi_probe(struct spi_device *spi)
 {
        int ret;
        const struct spi_device_id *id = spi_get_device_id(spi);
@@ -52,20 +52,23 @@ static int da9052_spi_probe(struct spi_device *spi)
 
        ret = da9052_device_init(da9052, id->driver_data);
        if (ret != 0)
-               goto err;
+               goto err_regmap;
 
        return 0;
 
+err_regmap:
+       regmap_exit(da9052->regmap);
 err:
        kfree(da9052);
        return ret;
 }
 
-static int da9052_spi_remove(struct spi_device *spi)
+static int __devexit da9052_spi_remove(struct spi_device *spi)
 {
        struct da9052 *da9052 = dev_get_drvdata(&spi->dev);
 
        da9052_device_exit(da9052);
+       regmap_exit(da9052->regmap);
        kfree(da9052);
 
        return 0;
index af8e0ef..ebc1e86 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/regulator/db8500-prcmu.h>
 #include <linux/regulator/machine.h>
+#include <asm/hardware/gic.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/db8500-regs.h>
 /* Offset for the firmware version within the TCPM */
 #define PRCMU_FW_VERSION_OFFSET 0xA4
 
-/* PRCMU project numbers, defined by PRCMU FW */
-#define PRCMU_PROJECT_ID_8500V1_0 1
-#define PRCMU_PROJECT_ID_8500V2_0 2
-#define PRCMU_PROJECT_ID_8400V2_0 3
-
 /* Index of different voltages to be used when accessing AVSData */
 #define PRCM_AVS_BASE          0x2FC
 #define PRCM_AVS_VBB_RET       (PRCM_AVS_BASE + 0x0)
 #define PRCM_REQ_MB1_ARM_OPP                   (PRCM_REQ_MB1 + 0x0)
 #define PRCM_REQ_MB1_APE_OPP                   (PRCM_REQ_MB1 + 0x1)
 #define PRCM_REQ_MB1_PLL_ON_OFF                        (PRCM_REQ_MB1 + 0x4)
+#define PLL_SOC0_OFF   0x1
+#define PLL_SOC0_ON    0x2
 #define PLL_SOC1_OFF   0x4
 #define PLL_SOC1_ON    0x8
 
 #define WAKEUP_BIT_GPIO7 BIT(30)
 #define WAKEUP_BIT_GPIO8 BIT(31)
 
+static struct {
+       bool valid;
+       struct prcmu_fw_version version;
+} fw_info;
+
 /*
  * This vector maps irq numbers to the bits in the bit field used in
  * communication with the PRCMU firmware.
@@ -341,11 +344,13 @@ static struct {
  * mb1_transfer - state needed for mailbox 1 communication.
  * @lock:      The transaction lock.
  * @work:      The transaction completion structure.
+ * @ape_opp:   The current APE OPP.
  * @ack:       Reply ("acknowledge") data.
  */
 static struct {
        struct mutex lock;
        struct completion work;
+       u8 ape_opp;
        struct {
                u8 header;
                u8 arm_opp;
@@ -413,79 +418,102 @@ static struct {
 static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
 
 /* Spinlocks */
+static DEFINE_SPINLOCK(prcmu_lock);
 static DEFINE_SPINLOCK(clkout_lock);
-static DEFINE_SPINLOCK(gpiocr_lock);
 
 /* Global var to runtime determine TCDM base for v2 or v1 */
 static __iomem void *tcdm_base;
 
 struct clk_mgt {
-       unsigned int offset;
+       void __iomem *reg;
        u32 pllsw;
+       int branch;
+       bool clk38div;
+};
+
+enum {
+       PLL_RAW,
+       PLL_FIX,
+       PLL_DIV
 };
 
 static DEFINE_SPINLOCK(clk_mgt_lock);
 
-#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT_OFF), 0 }
+#define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \
+       { (PRCM_##_name##_MGT), 0 , _branch, _clk38div}
 struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
-       CLK_MGT_ENTRY(SGACLK),
-       CLK_MGT_ENTRY(UARTCLK),
-       CLK_MGT_ENTRY(MSP02CLK),
-       CLK_MGT_ENTRY(MSP1CLK),
-       CLK_MGT_ENTRY(I2CCLK),
-       CLK_MGT_ENTRY(SDMMCCLK),
-       CLK_MGT_ENTRY(SLIMCLK),
-       CLK_MGT_ENTRY(PER1CLK),
-       CLK_MGT_ENTRY(PER2CLK),
-       CLK_MGT_ENTRY(PER3CLK),
-       CLK_MGT_ENTRY(PER5CLK),
-       CLK_MGT_ENTRY(PER6CLK),
-       CLK_MGT_ENTRY(PER7CLK),
-       CLK_MGT_ENTRY(LCDCLK),
-       CLK_MGT_ENTRY(BMLCLK),
-       CLK_MGT_ENTRY(HSITXCLK),
-       CLK_MGT_ENTRY(HSIRXCLK),
-       CLK_MGT_ENTRY(HDMICLK),
-       CLK_MGT_ENTRY(APEATCLK),
-       CLK_MGT_ENTRY(APETRACECLK),
-       CLK_MGT_ENTRY(MCDECLK),
-       CLK_MGT_ENTRY(IPI2CCLK),
-       CLK_MGT_ENTRY(DSIALTCLK),
-       CLK_MGT_ENTRY(DMACLK),
-       CLK_MGT_ENTRY(B2R2CLK),
-       CLK_MGT_ENTRY(TVCLK),
-       CLK_MGT_ENTRY(SSPCLK),
-       CLK_MGT_ENTRY(RNGCLK),
-       CLK_MGT_ENTRY(UICCCLK),
+       CLK_MGT_ENTRY(SGACLK, PLL_DIV, false),
+       CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(MSP1CLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(I2CCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(SDMMCCLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(SLIMCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(PER1CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(PER2CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(PER3CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(PER5CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(HDMICLK, PLL_FIX, false),
+       CLK_MGT_ENTRY(APEATCLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(APETRACECLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(MCDECLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(IPI2CCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(DSIALTCLK, PLL_FIX, false),
+       CLK_MGT_ENTRY(DMACLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(B2R2CLK, PLL_DIV, true),
+       CLK_MGT_ENTRY(TVCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(SSPCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(RNGCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(UICCCLK, PLL_FIX, false),
+};
+
+struct dsiclk {
+       u32 divsel_mask;
+       u32 divsel_shift;
+       u32 divsel;
+};
+
+static struct dsiclk dsiclk[2] = {
+       {
+               .divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK,
+               .divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT,
+               .divsel = PRCM_DSI_PLLOUT_SEL_PHI,
+       },
+       {
+               .divsel_mask = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK,
+               .divsel_shift = PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT,
+               .divsel = PRCM_DSI_PLLOUT_SEL_PHI,
+       }
 };
 
-static struct regulator *hwacc_regulator[NUM_HW_ACC];
-static struct regulator *hwacc_ret_regulator[NUM_HW_ACC];
-
-static bool hwacc_enabled[NUM_HW_ACC];
-static bool hwacc_ret_enabled[NUM_HW_ACC];
-
-static const char *hwacc_regulator_name[NUM_HW_ACC] = {
-       [HW_ACC_SVAMMDSP]       = "hwacc-sva-mmdsp",
-       [HW_ACC_SVAPIPE]        = "hwacc-sva-pipe",
-       [HW_ACC_SIAMMDSP]       = "hwacc-sia-mmdsp",
-       [HW_ACC_SIAPIPE]        = "hwacc-sia-pipe",
-       [HW_ACC_SGA]            = "hwacc-sga",
-       [HW_ACC_B2R2]           = "hwacc-b2r2",
-       [HW_ACC_MCDE]           = "hwacc-mcde",
-       [HW_ACC_ESRAM1]         = "hwacc-esram1",
-       [HW_ACC_ESRAM2]         = "hwacc-esram2",
-       [HW_ACC_ESRAM3]         = "hwacc-esram3",
-       [HW_ACC_ESRAM4]         = "hwacc-esram4",
+struct dsiescclk {
+       u32 en;
+       u32 div_mask;
+       u32 div_shift;
 };
 
-static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
-       [HW_ACC_SVAMMDSP]       = "hwacc-sva-mmdsp-ret",
-       [HW_ACC_SIAMMDSP]       = "hwacc-sia-mmdsp-ret",
-       [HW_ACC_ESRAM1]         = "hwacc-esram1-ret",
-       [HW_ACC_ESRAM2]         = "hwacc-esram2-ret",
-       [HW_ACC_ESRAM3]         = "hwacc-esram3-ret",
-       [HW_ACC_ESRAM4]         = "hwacc-esram4-ret",
+static struct dsiescclk dsiescclk[3] = {
+       {
+               .en = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN,
+               .div_mask = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK,
+               .div_shift = PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT,
+       },
+       {
+               .en = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN,
+               .div_mask = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK,
+               .div_shift = PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT,
+       },
+       {
+               .en = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN,
+               .div_mask = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK,
+               .div_shift = PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT,
+       }
 };
 
 /*
@@ -503,9 +531,6 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
 /* PLLDIV=12, PLLSW=4 (PLLDDR) */
 #define PRCMU_DSI_CLOCK_SETTING                0x0000008C
 
-/* PLLDIV=8, PLLSW=4 (PLLDDR) */
-#define PRCMU_DSI_CLOCK_SETTING_U8400  0x00000088
-
 /* DPI 50000000 Hz */
 #define PRCMU_DPI_CLOCK_SETTING                ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
                                          (16 << PRCMU_CLK_PLL_DIV_SHIFT))
@@ -514,9 +539,6 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
 /* D=101, N=1, R=4, SELDIV2=0 */
 #define PRCMU_PLLDSI_FREQ_SETTING      0x00040165
 
-/* D=70, N=1, R=3, SELDIV2=0 */
-#define PRCMU_PLLDSI_FREQ_SETTING_U8400        0x00030146
-
 #define PRCMU_ENABLE_PLLDSI            0x00000001
 #define PRCMU_DISABLE_PLLDSI           0x00000000
 #define PRCMU_RELEASE_RESET_DSS                0x0000400C
@@ -528,30 +550,17 @@ static const char *hwacc_ret_regulator_name[NUM_HW_ACC] = {
 
 #define PRCMU_PLLDSI_LOCKP_LOCKED      0x3
 
-static struct {
-       u8 project_number;
-       u8 api_version;
-       u8 func_version;
-       u8 errata;
-} prcmu_version;
-
-
 int db8500_prcmu_enable_dsipll(void)
 {
        int i;
-       unsigned int plldsifreq;
 
        /* Clear DSIPLL_RESETN */
        writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
        /* Unclamp DSIPLL in/out */
        writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
 
-       if (prcmu_is_u8400())
-               plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400;
-       else
-               plldsifreq = PRCMU_PLLDSI_FREQ_SETTING;
        /* Set DSI PLL FREQ */
-       writel(plldsifreq, PRCM_PLLDSI_FREQ);
+       writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
        writel(PRCMU_DSI_PLLOUT_SEL_SETTING, PRCM_DSI_PLLOUT_SEL);
        /* Enable Escape clocks */
        writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
@@ -583,12 +592,6 @@ int db8500_prcmu_disable_dsipll(void)
 int db8500_prcmu_set_display_clocks(void)
 {
        unsigned long flags;
-       unsigned int dsiclk;
-
-       if (prcmu_is_u8400())
-               dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400;
-       else
-               dsiclk = PRCMU_DSI_CLOCK_SETTING;
 
        spin_lock_irqsave(&clk_mgt_lock, flags);
 
@@ -596,7 +599,7 @@ int db8500_prcmu_set_display_clocks(void)
        while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
                cpu_relax();
 
-       writel(dsiclk, PRCM_HDMICLK_MGT);
+       writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
        writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
        writel(PRCMU_DPI_CLOCK_SETTING, PRCM_LCDCLK_MGT);
 
@@ -608,43 +611,41 @@ int db8500_prcmu_set_display_clocks(void)
        return 0;
 }
 
-/**
- * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
- */
-void prcmu_enable_spi2(void)
+u32 db8500_prcmu_read(unsigned int reg)
+{
+       return readl(_PRCMU_BASE + reg);
+}
+
+void db8500_prcmu_write(unsigned int reg, u32 value)
 {
-       u32 reg;
        unsigned long flags;
 
-       spin_lock_irqsave(&gpiocr_lock, flags);
-       reg = readl(PRCM_GPIOCR);
-       writel(reg | PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
-       spin_unlock_irqrestore(&gpiocr_lock, flags);
+       spin_lock_irqsave(&prcmu_lock, flags);
+       writel(value, (_PRCMU_BASE + reg));
+       spin_unlock_irqrestore(&prcmu_lock, flags);
 }
 
-/**
- * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
- */
-void prcmu_disable_spi2(void)
+void db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
 {
-       u32 reg;
+       u32 val;
        unsigned long flags;
 
-       spin_lock_irqsave(&gpiocr_lock, flags);
-       reg = readl(PRCM_GPIOCR);
-       writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, PRCM_GPIOCR);
-       spin_unlock_irqrestore(&gpiocr_lock, flags);
+       spin_lock_irqsave(&prcmu_lock, flags);
+       val = readl(_PRCMU_BASE + reg);
+       val = ((val & ~mask) | (value & mask));
+       writel(val, (_PRCMU_BASE + reg));
+       spin_unlock_irqrestore(&prcmu_lock, flags);
 }
 
-bool prcmu_has_arm_maxopp(void)
+struct prcmu_fw_version *prcmu_get_fw_version(void)
 {
-       return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
-               PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
+       return fw_info.valid ? &fw_info.version : NULL;
 }
 
-bool prcmu_is_u8400(void)
+bool prcmu_has_arm_maxopp(void)
 {
-       return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0;
+       return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
+               PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
 }
 
 /**
@@ -787,6 +788,124 @@ int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
        return 0;
 }
 
+u8 db8500_prcmu_get_power_state_result(void)
+{
+       return readb(tcdm_base + PRCM_ACK_MB0_AP_PWRSTTR_STATUS);
+}
+
+/* This function decouple the gic from the prcmu */
+int db8500_prcmu_gic_decouple(void)
+{
+       u32 val = readl(PRCM_A9_MASK_REQ);
+
+       /* Set bit 0 register value to 1 */
+       writel(val | PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ,
+              PRCM_A9_MASK_REQ);
+
+       /* Make sure the register is updated */
+       readl(PRCM_A9_MASK_REQ);
+
+       /* Wait a few cycles for the gic mask completion */
+       udelay(1);
+
+       return 0;
+}
+
+/* This function recouple the gic with the prcmu */
+int db8500_prcmu_gic_recouple(void)
+{
+       u32 val = readl(PRCM_A9_MASK_REQ);
+
+       /* Set bit 0 register value to 0 */
+       writel(val & ~PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, PRCM_A9_MASK_REQ);
+
+       return 0;
+}
+
+#define PRCMU_GIC_NUMBER_REGS 5
+
+/*
+ * This function checks if there are pending irq on the gic. It only
+ * makes sense if the gic has been decoupled before with the
+ * db8500_prcmu_gic_decouple function. Disabling an interrupt only
+ * disables the forwarding of the interrupt to any CPU interface. It
+ * does not prevent the interrupt from changing state, for example
+ * becoming pending, or active and pending if it is already
+ * active. Hence, we have to check the interrupt is pending *and* is
+ * active.
+ */
+bool db8500_prcmu_gic_pending_irq(void)
+{
+       u32 pr; /* Pending register */
+       u32 er; /* Enable register */
+       void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+       int i;
+
+        /* 5 registers. STI & PPI not skipped */
+       for (i = 0; i < PRCMU_GIC_NUMBER_REGS; i++) {
+
+               pr = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i * 4);
+               er = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+               if (pr & er)
+                       return true; /* There is a pending interrupt */
+       }
+
+       return false;
+}
+
+/*
+ * This function checks if there are pending interrupt on the
+ * prcmu which has been delegated to monitor the irqs with the
+ * db8500_prcmu_copy_gic_settings function.
+ */
+bool db8500_prcmu_pending_irq(void)
+{
+       u32 it, im;
+       int i;
+
+       for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+               it = readl(PRCM_ARMITVAL31TO0 + i * 4);
+               im = readl(PRCM_ARMITMSK31TO0 + i * 4);
+               if (it & im)
+                       return true; /* There is a pending interrupt */
+       }
+
+       return false;
+}
+
+/*
+ * This function checks if the specified cpu is in in WFI. It's usage
+ * makes sense only if the gic is decoupled with the db8500_prcmu_gic_decouple
+ * function. Of course passing smp_processor_id() to this function will
+ * always return false...
+ */
+bool db8500_prcmu_is_cpu_in_wfi(int cpu)
+{
+       return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
+                    PRCM_ARM_WFI_STANDBY_WFI0;
+}
+
+/*
+ * This function copies the gic SPI settings to the prcmu in order to
+ * monitor them and abort/finish the retention/off sequence or state.
+ */
+int db8500_prcmu_copy_gic_settings(void)
+{
+       u32 er; /* Enable register */
+       void __iomem *dist_base = __io_address(U8500_GIC_DIST_BASE);
+       int i;
+
+        /* We skip the STI and PPI */
+       for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) {
+               er = readl_relaxed(dist_base +
+                                  GIC_DIST_ENABLE_SET + (i + 1) * 4);
+               writel(er, PRCM_ARMITMSK31TO0 + i * 4);
+       }
+
+       return 0;
+}
+
 /* This function should only be called while mb0_transfer.lock is held. */
 static void config_wakeups(void)
 {
@@ -909,23 +1028,23 @@ int db8500_prcmu_get_arm_opp(void)
 }
 
 /**
- * prcmu_get_ddr_opp - get the current DDR OPP
+ * db8500_prcmu_get_ddr_opp - get the current DDR OPP
  *
  * Returns: the current DDR OPP
  */
-int prcmu_get_ddr_opp(void)
+int db8500_prcmu_get_ddr_opp(void)
 {
        return readb(PRCM_DDR_SUBSYS_APE_MINBW);
 }
 
 /**
- * set_ddr_opp - set the appropriate DDR OPP
+ * db8500_set_ddr_opp - set the appropriate DDR OPP
  * @opp: The new DDR operating point to which transition is to be made
  * Returns: 0 on success, non-zero on failure
  *
  * This function sets the operating point of the DDR.
  */
-int prcmu_set_ddr_opp(u8 opp)
+int db8500_prcmu_set_ddr_opp(u8 opp)
 {
        if (opp < DDR_100_OPP || opp > DDR_25_OPP)
                return -EINVAL;
@@ -935,25 +1054,82 @@ int prcmu_set_ddr_opp(u8 opp)
 
        return 0;
 }
+
+/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */
+static void request_even_slower_clocks(bool enable)
+{
+       void __iomem *clock_reg[] = {
+               PRCM_ACLK_MGT,
+               PRCM_DMACLK_MGT
+       };
+       unsigned long flags;
+       unsigned int i;
+
+       spin_lock_irqsave(&clk_mgt_lock, flags);
+
+       /* Grab the HW semaphore. */
+       while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+               cpu_relax();
+
+       for (i = 0; i < ARRAY_SIZE(clock_reg); i++) {
+               u32 val;
+               u32 div;
+
+               val = readl(clock_reg[i]);
+               div = (val & PRCM_CLK_MGT_CLKPLLDIV_MASK);
+               if (enable) {
+                       if ((div <= 1) || (div > 15)) {
+                               pr_err("prcmu: Bad clock divider %d in %s\n",
+                                       div, __func__);
+                               goto unlock_and_return;
+                       }
+                       div <<= 1;
+               } else {
+                       if (div <= 2)
+                               goto unlock_and_return;
+                       div >>= 1;
+               }
+               val = ((val & ~PRCM_CLK_MGT_CLKPLLDIV_MASK) |
+                       (div & PRCM_CLK_MGT_CLKPLLDIV_MASK));
+               writel(val, clock_reg[i]);
+       }
+
+unlock_and_return:
+       /* Release the HW semaphore. */
+       writel(0, PRCM_SEM);
+
+       spin_unlock_irqrestore(&clk_mgt_lock, flags);
+}
+
 /**
- * set_ape_opp - set the appropriate APE OPP
+ * db8500_set_ape_opp - set the appropriate APE OPP
  * @opp: The new APE operating point to which transition is to be made
  * Returns: 0 on success, non-zero on failure
  *
  * This function sets the operating point of the APE.
  */
-int prcmu_set_ape_opp(u8 opp)
+int db8500_prcmu_set_ape_opp(u8 opp)
 {
        int r = 0;
 
+       if (opp == mb1_transfer.ape_opp)
+               return 0;
+
        mutex_lock(&mb1_transfer.lock);
 
+       if (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)
+               request_even_slower_clocks(false);
+
+       if ((opp != APE_100_OPP) && (mb1_transfer.ape_opp != APE_100_OPP))
+               goto skip_message;
+
        while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
                cpu_relax();
 
        writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
        writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
-       writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+       writeb(((opp == APE_50_PARTLY_25_OPP) ? APE_50_OPP : opp),
+               (tcdm_base + PRCM_REQ_MB1_APE_OPP));
 
        writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
        wait_for_completion(&mb1_transfer.work);
@@ -962,17 +1138,24 @@ int prcmu_set_ape_opp(u8 opp)
                (mb1_transfer.ack.ape_opp != opp))
                r = -EIO;
 
+skip_message:
+       if ((!r && (opp == APE_50_PARTLY_25_OPP)) ||
+               (r && (mb1_transfer.ape_opp == APE_50_PARTLY_25_OPP)))
+               request_even_slower_clocks(true);
+       if (!r)
+               mb1_transfer.ape_opp = opp;
+
        mutex_unlock(&mb1_transfer.lock);
 
        return r;
 }
 
 /**
- * prcmu_get_ape_opp - get the current APE OPP
+ * db8500_prcmu_get_ape_opp - get the current APE OPP
  *
  * Returns: the current APE OPP
  */
-int prcmu_get_ape_opp(void)
+int db8500_prcmu_get_ape_opp(void)
 {
        return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
 }
@@ -1056,7 +1239,9 @@ static int request_pll(u8 clock, bool enable)
 {
        int r = 0;
 
-       if (clock == PRCMU_PLLSOC1)
+       if (clock == PRCMU_PLLSOC0)
+               clock = (enable ? PLL_SOC0_ON : PLL_SOC0_OFF);
+       else if (clock == PRCMU_PLLSOC1)
                clock = (enable ? PLL_SOC1_ON : PLL_SOC1_OFF);
        else
                return -EINVAL;
@@ -1081,132 +1266,6 @@ static int request_pll(u8 clock, bool enable)
 }
 
 /**
- * prcmu_set_hwacc - set the power state of a h/w accelerator
- * @hwacc_dev: The hardware accelerator (enum hw_acc_dev).
- * @state: The new power state (enum hw_acc_state).
- *
- * This function sets the power state of a hardware accelerator.
- * This function should not be called from interrupt context.
- *
- * NOTE! Deprecated, to be removed when all users switched over to use the
- * regulator framework API.
- */
-int prcmu_set_hwacc(u16 hwacc_dev, u8 state)
-{
-       int r = 0;
-       bool ram_retention = false;
-       bool enable, enable_ret;
-
-       /* check argument */
-       BUG_ON(hwacc_dev >= NUM_HW_ACC);
-
-       /* get state of switches */
-       enable = hwacc_enabled[hwacc_dev];
-       enable_ret = hwacc_ret_enabled[hwacc_dev];
-
-       /* set flag if retention is possible */
-       switch (hwacc_dev) {
-       case HW_ACC_SVAMMDSP:
-       case HW_ACC_SIAMMDSP:
-       case HW_ACC_ESRAM1:
-       case HW_ACC_ESRAM2:
-       case HW_ACC_ESRAM3:
-       case HW_ACC_ESRAM4:
-               ram_retention = true;
-               break;
-       }
-
-       /* check argument */
-       BUG_ON(state > HW_ON);
-       BUG_ON(state == HW_OFF_RAMRET && !ram_retention);
-
-       /* modify enable flags */
-       switch (state) {
-       case HW_OFF:
-               enable_ret = false;
-               enable = false;
-               break;
-       case HW_ON:
-               enable = true;
-               break;
-       case HW_OFF_RAMRET:
-               enable_ret = true;
-               enable = false;
-               break;
-       }
-
-       /* get regulator (lazy) */
-       if (hwacc_regulator[hwacc_dev] == NULL) {
-               hwacc_regulator[hwacc_dev] = regulator_get(NULL,
-                       hwacc_regulator_name[hwacc_dev]);
-               if (IS_ERR(hwacc_regulator[hwacc_dev])) {
-                       pr_err("prcmu: failed to get supply %s\n",
-                               hwacc_regulator_name[hwacc_dev]);
-                       r = PTR_ERR(hwacc_regulator[hwacc_dev]);
-                       goto out;
-               }
-       }
-
-       if (ram_retention) {
-               if (hwacc_ret_regulator[hwacc_dev] == NULL) {
-                       hwacc_ret_regulator[hwacc_dev] = regulator_get(NULL,
-                               hwacc_ret_regulator_name[hwacc_dev]);
-                       if (IS_ERR(hwacc_ret_regulator[hwacc_dev])) {
-                               pr_err("prcmu: failed to get supply %s\n",
-                                       hwacc_ret_regulator_name[hwacc_dev]);
-                               r = PTR_ERR(hwacc_ret_regulator[hwacc_dev]);
-                               goto out;
-                       }
-               }
-       }
-
-       /* set regulators */
-       if (ram_retention) {
-               if (enable_ret && !hwacc_ret_enabled[hwacc_dev]) {
-                       r = regulator_enable(hwacc_ret_regulator[hwacc_dev]);
-                       if (r < 0) {
-                               pr_err("prcmu_set_hwacc: ret enable failed\n");
-                               goto out;
-                       }
-                       hwacc_ret_enabled[hwacc_dev] = true;
-               }
-       }
-
-       if (enable && !hwacc_enabled[hwacc_dev]) {
-               r = regulator_enable(hwacc_regulator[hwacc_dev]);
-               if (r < 0) {
-                       pr_err("prcmu_set_hwacc: enable failed\n");
-                       goto out;
-               }
-               hwacc_enabled[hwacc_dev] = true;
-       }
-
-       if (!enable && hwacc_enabled[hwacc_dev]) {
-               r = regulator_disable(hwacc_regulator[hwacc_dev]);
-               if (r < 0) {
-                       pr_err("prcmu_set_hwacc: disable failed\n");
-                       goto out;
-               }
-               hwacc_enabled[hwacc_dev] = false;
-       }
-
-       if (ram_retention) {
-               if (!enable_ret && hwacc_ret_enabled[hwacc_dev]) {
-                       r = regulator_disable(hwacc_ret_regulator[hwacc_dev]);
-                       if (r < 0) {
-                               pr_err("prcmu_set_hwacc: ret disable failed\n");
-                               goto out;
-                       }
-                       hwacc_ret_enabled[hwacc_dev] = false;
-               }
-       }
-
-out:
-       return r;
-}
-EXPORT_SYMBOL(prcmu_set_hwacc);
-
-/**
  * db8500_prcmu_set_epod - set the state of a EPOD (power domain)
  * @epod_id: The EPOD to set
  * @epod_state: The new EPOD state
@@ -1375,7 +1434,7 @@ static int request_timclk(bool enable)
        return 0;
 }
 
-static int request_reg_clock(u8 clock, bool enable)
+static int request_clock(u8 clock, bool enable)
 {
        u32 val;
        unsigned long flags;
@@ -1386,14 +1445,14 @@ static int request_reg_clock(u8 clock, bool enable)
        while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
                cpu_relax();
 
-       val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+       val = readl(clk_mgt[clock].reg);
        if (enable) {
                val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
        } else {
                clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
                val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
        }
-       writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+       writel(val, clk_mgt[clock].reg);
 
        /* Release the HW semaphore. */
        writel(0, PRCM_SEM);
@@ -1413,7 +1472,7 @@ static int request_sga_clock(u8 clock, bool enable)
                writel(val | PRCM_CGATING_BYPASS_ICN2, PRCM_CGATING_BYPASS);
        }
 
-       ret = request_reg_clock(clock, enable);
+       ret = request_clock(clock, enable);
 
        if (!ret && !enable) {
                val = readl(PRCM_CGATING_BYPASS);
@@ -1423,6 +1482,78 @@ static int request_sga_clock(u8 clock, bool enable)
        return ret;
 }
 
+static inline bool plldsi_locked(void)
+{
+       return (readl(PRCM_PLLDSI_LOCKP) &
+               (PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
+                PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3)) ==
+               (PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10 |
+                PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3);
+}
+
+static int request_plldsi(bool enable)
+{
+       int r = 0;
+       u32 val;
+
+       writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
+               PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI), (enable ?
+               PRCM_MMIP_LS_CLAMP_CLR : PRCM_MMIP_LS_CLAMP_SET));
+
+       val = readl(PRCM_PLLDSI_ENABLE);
+       if (enable)
+               val |= PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+       else
+               val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+       writel(val, PRCM_PLLDSI_ENABLE);
+
+       if (enable) {
+               unsigned int i;
+               bool locked = plldsi_locked();
+
+               for (i = 10; !locked && (i > 0); --i) {
+                       udelay(100);
+                       locked = plldsi_locked();
+               }
+               if (locked) {
+                       writel(PRCM_APE_RESETN_DSIPLL_RESETN,
+                               PRCM_APE_RESETN_SET);
+               } else {
+                       writel((PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP |
+                               PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI),
+                               PRCM_MMIP_LS_CLAMP_SET);
+                       val &= ~PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE;
+                       writel(val, PRCM_PLLDSI_ENABLE);
+                       r = -EAGAIN;
+               }
+       } else {
+               writel(PRCM_APE_RESETN_DSIPLL_RESETN, PRCM_APE_RESETN_CLR);
+       }
+       return r;
+}
+
+static int request_dsiclk(u8 n, bool enable)
+{
+       u32 val;
+
+       val = readl(PRCM_DSI_PLLOUT_SEL);
+       val &= ~dsiclk[n].divsel_mask;
+       val |= ((enable ? dsiclk[n].divsel : PRCM_DSI_PLLOUT_SEL_OFF) <<
+               dsiclk[n].divsel_shift);
+       writel(val, PRCM_DSI_PLLOUT_SEL);
+       return 0;
+}
+
+static int request_dsiescclk(u8 n, bool enable)
+{
+       u32 val;
+
+       val = readl(PRCM_DSITVCLK_DIV);
+       enable ? (val |= dsiescclk[n].en) : (val &= ~dsiescclk[n].en);
+       writel(val, PRCM_DSITVCLK_DIV);
+       return 0;
+}
+
 /**
  * db8500_prcmu_request_clock() - Request for a clock to be enabled or disabled.
  * @clock:      The clock for which the request is made.
@@ -1433,21 +1564,435 @@ static int request_sga_clock(u8 clock, bool enable)
  */
 int db8500_prcmu_request_clock(u8 clock, bool enable)
 {
-       switch(clock) {
-       case PRCMU_SGACLK:
+       if (clock == PRCMU_SGACLK)
                return request_sga_clock(clock, enable);
-       case PRCMU_TIMCLK:
+       else if (clock < PRCMU_NUM_REG_CLOCKS)
+               return request_clock(clock, enable);
+       else if (clock == PRCMU_TIMCLK)
                return request_timclk(enable);
-       case PRCMU_SYSCLK:
+       else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+               return request_dsiclk((clock - PRCMU_DSI0CLK), enable);
+       else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+               return request_dsiescclk((clock - PRCMU_DSI0ESCCLK), enable);
+       else if (clock == PRCMU_PLLDSI)
+               return request_plldsi(enable);
+       else if (clock == PRCMU_SYSCLK)
                return request_sysclk(enable);
-       case PRCMU_PLLSOC1:
+       else if ((clock == PRCMU_PLLSOC0) || (clock == PRCMU_PLLSOC1))
                return request_pll(clock, enable);
+       else
+               return -EINVAL;
+}
+
+static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate,
+       int branch)
+{
+       u64 rate;
+       u32 val;
+       u32 d;
+       u32 div = 1;
+
+       val = readl(reg);
+
+       rate = src_rate;
+       rate *= ((val & PRCM_PLL_FREQ_D_MASK) >> PRCM_PLL_FREQ_D_SHIFT);
+
+       d = ((val & PRCM_PLL_FREQ_N_MASK) >> PRCM_PLL_FREQ_N_SHIFT);
+       if (d > 1)
+               div *= d;
+
+       d = ((val & PRCM_PLL_FREQ_R_MASK) >> PRCM_PLL_FREQ_R_SHIFT);
+       if (d > 1)
+               div *= d;
+
+       if (val & PRCM_PLL_FREQ_SELDIV2)
+               div *= 2;
+
+       if ((branch == PLL_FIX) || ((branch == PLL_DIV) &&
+               (val & PRCM_PLL_FREQ_DIV2EN) &&
+               ((reg == PRCM_PLLSOC0_FREQ) ||
+                (reg == PRCM_PLLDDR_FREQ))))
+               div *= 2;
+
+       (void)do_div(rate, div);
+
+       return (unsigned long)rate;
+}
+
+#define ROOT_CLOCK_RATE 38400000
+
+static unsigned long clock_rate(u8 clock)
+{
+       u32 val;
+       u32 pllsw;
+       unsigned long rate = ROOT_CLOCK_RATE;
+
+       val = readl(clk_mgt[clock].reg);
+
+       if (val & PRCM_CLK_MGT_CLK38) {
+               if (clk_mgt[clock].clk38div && (val & PRCM_CLK_MGT_CLK38DIV))
+                       rate /= 2;
+               return rate;
+       }
+
+       val |= clk_mgt[clock].pllsw;
+       pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
+
+       if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC0)
+               rate = pll_rate(PRCM_PLLSOC0_FREQ, rate, clk_mgt[clock].branch);
+       else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_SOC1)
+               rate = pll_rate(PRCM_PLLSOC1_FREQ, rate, clk_mgt[clock].branch);
+       else if (pllsw == PRCM_CLK_MGT_CLKPLLSW_DDR)
+               rate = pll_rate(PRCM_PLLDDR_FREQ, rate, clk_mgt[clock].branch);
+       else
+               return 0;
+
+       if ((clock == PRCMU_SGACLK) &&
+               (val & PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN)) {
+               u64 r = (rate * 10);
+
+               (void)do_div(r, 25);
+               return (unsigned long)r;
+       }
+       val &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
+       if (val)
+               return rate / val;
+       else
+               return 0;
+}
+
+static unsigned long dsiclk_rate(u8 n)
+{
+       u32 divsel;
+       u32 div = 1;
+
+       divsel = readl(PRCM_DSI_PLLOUT_SEL);
+       divsel = ((divsel & dsiclk[n].divsel_mask) >> dsiclk[n].divsel_shift);
+
+       if (divsel == PRCM_DSI_PLLOUT_SEL_OFF)
+               divsel = dsiclk[n].divsel;
+
+       switch (divsel) {
+       case PRCM_DSI_PLLOUT_SEL_PHI_4:
+               div *= 2;
+       case PRCM_DSI_PLLOUT_SEL_PHI_2:
+               div *= 2;
+       case PRCM_DSI_PLLOUT_SEL_PHI:
+               return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+                       PLL_RAW) / div;
        default:
-               break;
+               return 0;
+       }
+}
+
+static unsigned long dsiescclk_rate(u8 n)
+{
+       u32 div;
+
+       div = readl(PRCM_DSITVCLK_DIV);
+       div = ((div & dsiescclk[n].div_mask) >> (dsiescclk[n].div_shift));
+       return clock_rate(PRCMU_TVCLK) / max((u32)1, div);
+}
+
+unsigned long prcmu_clock_rate(u8 clock)
+{
+       if (clock < PRCMU_NUM_REG_CLOCKS)
+               return clock_rate(clock);
+       else if (clock == PRCMU_TIMCLK)
+               return ROOT_CLOCK_RATE / 16;
+       else if (clock == PRCMU_SYSCLK)
+               return ROOT_CLOCK_RATE;
+       else if (clock == PRCMU_PLLSOC0)
+               return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+       else if (clock == PRCMU_PLLSOC1)
+               return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+       else if (clock == PRCMU_PLLDDR)
+               return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+       else if (clock == PRCMU_PLLDSI)
+               return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+                       PLL_RAW);
+       else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+               return dsiclk_rate(clock - PRCMU_DSI0CLK);
+       else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+               return dsiescclk_rate(clock - PRCMU_DSI0ESCCLK);
+       else
+               return 0;
+}
+
+static unsigned long clock_source_rate(u32 clk_mgt_val, int branch)
+{
+       if (clk_mgt_val & PRCM_CLK_MGT_CLK38)
+               return ROOT_CLOCK_RATE;
+       clk_mgt_val &= PRCM_CLK_MGT_CLKPLLSW_MASK;
+       if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC0)
+               return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, branch);
+       else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_SOC1)
+               return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, branch);
+       else if (clk_mgt_val == PRCM_CLK_MGT_CLKPLLSW_DDR)
+               return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, branch);
+       else
+               return 0;
+}
+
+static u32 clock_divider(unsigned long src_rate, unsigned long rate)
+{
+       u32 div;
+
+       div = (src_rate / rate);
+       if (div == 0)
+               return 1;
+       if (rate < (src_rate / div))
+               div++;
+       return div;
+}
+
+static long round_clock_rate(u8 clock, unsigned long rate)
+{
+       u32 val;
+       u32 div;
+       unsigned long src_rate;
+       long rounded_rate;
+
+       val = readl(clk_mgt[clock].reg);
+       src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
+               clk_mgt[clock].branch);
+       div = clock_divider(src_rate, rate);
+       if (val & PRCM_CLK_MGT_CLK38) {
+               if (clk_mgt[clock].clk38div) {
+                       if (div > 2)
+                               div = 2;
+               } else {
+                       div = 1;
+               }
+       } else if ((clock == PRCMU_SGACLK) && (div == 3)) {
+               u64 r = (src_rate * 10);
+
+               (void)do_div(r, 25);
+               if (r <= rate)
+                       return (unsigned long)r;
+       }
+       rounded_rate = (src_rate / min(div, (u32)31));
+
+       return rounded_rate;
+}
+
+#define MIN_PLL_VCO_RATE 600000000ULL
+#define MAX_PLL_VCO_RATE 1680640000ULL
+
+static long round_plldsi_rate(unsigned long rate)
+{
+       long rounded_rate = 0;
+       unsigned long src_rate;
+       unsigned long rem;
+       u32 r;
+
+       src_rate = clock_rate(PRCMU_HDMICLK);
+       rem = rate;
+
+       for (r = 7; (rem > 0) && (r > 0); r--) {
+               u64 d;
+
+               d = (r * rate);
+               (void)do_div(d, src_rate);
+               if (d < 6)
+                       d = 6;
+               else if (d > 255)
+                       d = 255;
+               d *= src_rate;
+               if (((2 * d) < (r * MIN_PLL_VCO_RATE)) ||
+                       ((r * MAX_PLL_VCO_RATE) < (2 * d)))
+                       continue;
+               (void)do_div(d, r);
+               if (rate < d) {
+                       if (rounded_rate == 0)
+                               rounded_rate = (long)d;
+                       break;
+               }
+               if ((rate - d) < rem) {
+                       rem = (rate - d);
+                       rounded_rate = (long)d;
+               }
+       }
+       return rounded_rate;
+}
+
+static long round_dsiclk_rate(unsigned long rate)
+{
+       u32 div;
+       unsigned long src_rate;
+       long rounded_rate;
+
+       src_rate = pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK),
+               PLL_RAW);
+       div = clock_divider(src_rate, rate);
+       rounded_rate = (src_rate / ((div > 2) ? 4 : div));
+
+       return rounded_rate;
+}
+
+static long round_dsiescclk_rate(unsigned long rate)
+{
+       u32 div;
+       unsigned long src_rate;
+       long rounded_rate;
+
+       src_rate = clock_rate(PRCMU_TVCLK);
+       div = clock_divider(src_rate, rate);
+       rounded_rate = (src_rate / min(div, (u32)255));
+
+       return rounded_rate;
+}
+
+long prcmu_round_clock_rate(u8 clock, unsigned long rate)
+{
+       if (clock < PRCMU_NUM_REG_CLOCKS)
+               return round_clock_rate(clock, rate);
+       else if (clock == PRCMU_PLLDSI)
+               return round_plldsi_rate(rate);
+       else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+               return round_dsiclk_rate(rate);
+       else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+               return round_dsiescclk_rate(rate);
+       else
+               return (long)prcmu_clock_rate(clock);
+}
+
+static void set_clock_rate(u8 clock, unsigned long rate)
+{
+       u32 val;
+       u32 div;
+       unsigned long src_rate;
+       unsigned long flags;
+
+       spin_lock_irqsave(&clk_mgt_lock, flags);
+
+       /* Grab the HW semaphore. */
+       while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+               cpu_relax();
+
+       val = readl(clk_mgt[clock].reg);
+       src_rate = clock_source_rate((val | clk_mgt[clock].pllsw),
+               clk_mgt[clock].branch);
+       div = clock_divider(src_rate, rate);
+       if (val & PRCM_CLK_MGT_CLK38) {
+               if (clk_mgt[clock].clk38div) {
+                       if (div > 1)
+                               val |= PRCM_CLK_MGT_CLK38DIV;
+                       else
+                               val &= ~PRCM_CLK_MGT_CLK38DIV;
+               }
+       } else if (clock == PRCMU_SGACLK) {
+               val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK |
+                       PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN);
+               if (div == 3) {
+                       u64 r = (src_rate * 10);
+
+                       (void)do_div(r, 25);
+                       if (r <= rate) {
+                               val |= PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN;
+                               div = 0;
+                       }
+               }
+               val |= min(div, (u32)31);
+       } else {
+               val &= ~PRCM_CLK_MGT_CLKPLLDIV_MASK;
+               val |= min(div, (u32)31);
+       }
+       writel(val, clk_mgt[clock].reg);
+
+       /* Release the HW semaphore. */
+       writel(0, PRCM_SEM);
+
+       spin_unlock_irqrestore(&clk_mgt_lock, flags);
+}
+
+static int set_plldsi_rate(unsigned long rate)
+{
+       unsigned long src_rate;
+       unsigned long rem;
+       u32 pll_freq = 0;
+       u32 r;
+
+       src_rate = clock_rate(PRCMU_HDMICLK);
+       rem = rate;
+
+       for (r = 7; (rem > 0) && (r > 0); r--) {
+               u64 d;
+               u64 hwrate;
+
+               d = (r * rate);
+               (void)do_div(d, src_rate);
+               if (d < 6)
+                       d = 6;
+               else if (d > 255)
+                       d = 255;
+               hwrate = (d * src_rate);
+               if (((2 * hwrate) < (r * MIN_PLL_VCO_RATE)) ||
+                       ((r * MAX_PLL_VCO_RATE) < (2 * hwrate)))
+                       continue;
+               (void)do_div(hwrate, r);
+               if (rate < hwrate) {
+                       if (pll_freq == 0)
+                               pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
+                                       (r << PRCM_PLL_FREQ_R_SHIFT));
+                       break;
+               }
+               if ((rate - hwrate) < rem) {
+                       rem = (rate - hwrate);
+                       pll_freq = (((u32)d << PRCM_PLL_FREQ_D_SHIFT) |
+                               (r << PRCM_PLL_FREQ_R_SHIFT));
+               }
        }
+       if (pll_freq == 0)
+               return -EINVAL;
+
+       pll_freq |= (1 << PRCM_PLL_FREQ_N_SHIFT);
+       writel(pll_freq, PRCM_PLLDSI_FREQ);
+
+       return 0;
+}
+
+static void set_dsiclk_rate(u8 n, unsigned long rate)
+{
+       u32 val;
+       u32 div;
+
+       div = clock_divider(pll_rate(PRCM_PLLDSI_FREQ,
+                       clock_rate(PRCMU_HDMICLK), PLL_RAW), rate);
+
+       dsiclk[n].divsel = (div == 1) ? PRCM_DSI_PLLOUT_SEL_PHI :
+                          (div == 2) ? PRCM_DSI_PLLOUT_SEL_PHI_2 :
+                          /* else */   PRCM_DSI_PLLOUT_SEL_PHI_4;
+
+       val = readl(PRCM_DSI_PLLOUT_SEL);
+       val &= ~dsiclk[n].divsel_mask;
+       val |= (dsiclk[n].divsel << dsiclk[n].divsel_shift);
+       writel(val, PRCM_DSI_PLLOUT_SEL);
+}
+
+static void set_dsiescclk_rate(u8 n, unsigned long rate)
+{
+       u32 val;
+       u32 div;
+
+       div = clock_divider(clock_rate(PRCMU_TVCLK), rate);
+       val = readl(PRCM_DSITVCLK_DIV);
+       val &= ~dsiescclk[n].div_mask;
+       val |= (min(div, (u32)255) << dsiescclk[n].div_shift);
+       writel(val, PRCM_DSITVCLK_DIV);
+}
+
+int prcmu_set_clock_rate(u8 clock, unsigned long rate)
+{
        if (clock < PRCMU_NUM_REG_CLOCKS)
-               return request_reg_clock(clock, enable);
-       return -EINVAL;
+               set_clock_rate(clock, rate);
+       else if (clock == PRCMU_PLLDSI)
+               return set_plldsi_rate(rate);
+       else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
+               set_dsiclk_rate((clock - PRCMU_DSI0CLK), rate);
+       else if ((PRCMU_DSI0ESCCLK <= clock) && (clock <= PRCMU_DSI2ESCCLK))
+               set_dsiescclk_rate((clock - PRCMU_DSI0ESCCLK), rate);
+       return 0;
 }
 
 int db8500_prcmu_config_esram0_deep_sleep(u8 state)
@@ -1476,7 +2021,7 @@ int db8500_prcmu_config_esram0_deep_sleep(u8 state)
        return 0;
 }
 
-int prcmu_config_hotdog(u8 threshold)
+int db8500_prcmu_config_hotdog(u8 threshold)
 {
        mutex_lock(&mb4_transfer.lock);
 
@@ -1494,7 +2039,7 @@ int prcmu_config_hotdog(u8 threshold)
        return 0;
 }
 
-int prcmu_config_hotmon(u8 low, u8 high)
+int db8500_prcmu_config_hotmon(u8 low, u8 high)
 {
        mutex_lock(&mb4_transfer.lock);
 
@@ -1533,7 +2078,7 @@ static int config_hot_period(u16 val)
        return 0;
 }
 
-int prcmu_start_temp_sense(u16 cycles32k)
+int db8500_prcmu_start_temp_sense(u16 cycles32k)
 {
        if (cycles32k == 0xFFFF)
                return -EINVAL;
@@ -1541,7 +2086,7 @@ int prcmu_start_temp_sense(u16 cycles32k)
        return config_hot_period(cycles32k);
 }
 
-int prcmu_stop_temp_sense(void)
+int db8500_prcmu_stop_temp_sense(void)
 {
        return config_hot_period(0xFFFF);
 }
@@ -1570,7 +2115,7 @@ static int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3)
 
 }
 
-int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
 {
        BUG_ON(num == 0 || num > 0xf);
        return prcmu_a9wdog(MB4H_A9WDOG_CONF, num, 0, 0,
@@ -1578,17 +2123,17 @@ int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
                            A9WDOG_AUTO_OFF_DIS);
 }
 
-int prcmu_enable_a9wdog(u8 id)
+int db8500_prcmu_enable_a9wdog(u8 id)
 {
        return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0);
 }
 
-int prcmu_disable_a9wdog(u8 id)
+int db8500_prcmu_disable_a9wdog(u8 id)
 {
        return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0);
 }
 
-int prcmu_kick_a9wdog(u8 id)
+int db8500_prcmu_kick_a9wdog(u8 id)
 {
        return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0);
 }
@@ -1596,16 +2141,8 @@ int prcmu_kick_a9wdog(u8 id)
 /*
  * timeout is 28 bit, in ms.
  */
-#define MAX_WATCHDOG_TIMEOUT 131000
-int prcmu_load_a9wdog(u8 id, u32 timeout)
+int db8500_prcmu_load_a9wdog(u8 id, u32 timeout)
 {
-       if (timeout > MAX_WATCHDOG_TIMEOUT)
-               /*
-                * Due to calculation bug in prcmu fw, timeouts
-                * can't be bigger than 131 seconds.
-                */
-               return -EINVAL;
-
        return prcmu_a9wdog(MB4H_A9WDOG_LOAD,
                            (id & A9WDOG_ID_MASK) |
                            /*
@@ -1619,41 +2156,6 @@ int prcmu_load_a9wdog(u8 id, u32 timeout)
 }
 
 /**
- * prcmu_set_clock_divider() - Configure the clock divider.
- * @clock:     The clock for which the request is made.
- * @divider:   The clock divider. (< 32)
- *
- * This function should only be used by the clock implementation.
- * Do not use it from any other place!
- */
-int prcmu_set_clock_divider(u8 clock, u8 divider)
-{
-       u32 val;
-       unsigned long flags;
-
-       if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider))
-               return -EINVAL;
-
-       spin_lock_irqsave(&clk_mgt_lock, flags);
-
-       /* Grab the HW semaphore. */
-       while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
-               cpu_relax();
-
-       val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
-       val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK);
-       val |= (u32)divider;
-       writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
-
-       /* Release the HW semaphore. */
-       writel(0, PRCM_SEM);
-
-       spin_unlock_irqrestore(&clk_mgt_lock, flags);
-
-       return 0;
-}
-
-/**
  * prcmu_abb_read() - Read register value(s) from the ABB.
  * @slave:     The I2C slave address.
  * @reg:       The (start) register address.
@@ -1675,6 +2177,7 @@ int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
        while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
                cpu_relax();
 
+       writeb(0, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
        writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
        writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
        writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
@@ -1700,16 +2203,19 @@ int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
 }
 
 /**
- * prcmu_abb_write() - Write register value(s) to the ABB.
+ * prcmu_abb_write_masked() - Write masked register value(s) to the ABB.
  * @slave:     The I2C slave address.
  * @reg:       The (start) register address.
  * @value:     The value(s) to write.
+ * @mask:      The mask(s) to use.
  * @size:      The number of registers to write.
  *
- * Reads register value(s) from the ABB.
+ * Writes masked register value(s) to the ABB.
+ * For each @value, only the bits set to 1 in the corresponding @mask
+ * will be written. The other bits are not changed.
  * @size has to be 1 for the current firmware version.
  */
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size)
 {
        int r;
 
@@ -1721,6 +2227,7 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
        while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
                cpu_relax();
 
+       writeb(~*mask, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB5));
        writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
        writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
        writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
@@ -1743,6 +2250,23 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
 }
 
 /**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The value(s) to write.
+ * @size:      The number of registers to write.
+ *
+ * Writes register value(s) to the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       u8 mask = ~0;
+
+       return prcmu_abb_write_masked(slave, reg, value, &mask, size);
+}
+
+/**
  * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
  */
 void prcmu_ac_wake_req(void)
@@ -1850,9 +2374,9 @@ u16 db8500_prcmu_get_reset_code(void)
 }
 
 /**
- * prcmu_reset_modem - ask the PRCMU to reset modem
+ * db8500_prcmu_reset_modem - ask the PRCMU to reset modem
  */
-void prcmu_modem_reset(void)
+void db8500_prcmu_modem_reset(void)
 {
        mutex_lock(&mb1_transfer.lock);
 
@@ -2099,6 +2623,26 @@ static struct irq_chip prcmu_irq_chip = {
        .irq_unmask     = prcmu_irq_unmask,
 };
 
+static char *fw_project_name(u8 project)
+{
+       switch (project) {
+       case PRCMU_FW_PROJECT_U8500:
+               return "U8500";
+       case PRCMU_FW_PROJECT_U8500_C2:
+               return "U8500 C2";
+       case PRCMU_FW_PROJECT_U9500:
+               return "U9500";
+       case PRCMU_FW_PROJECT_U9500_C2:
+               return "U9500 C2";
+       case PRCMU_FW_PROJECT_U8520:
+               return "U8520";
+       case PRCMU_FW_PROJECT_U8420:
+               return "U8420";
+       default:
+               return "Unknown";
+       }
+}
+
 void __init db8500_prcmu_early_init(void)
 {
        unsigned int i;
@@ -2108,11 +2652,13 @@ void __init db8500_prcmu_early_init(void)
                if (tcpm_base != NULL) {
                        u32 version;
                        version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
-                       prcmu_version.project_number = version & 0xFF;
-                       prcmu_version.api_version = (version >> 8) & 0xFF;
-                       prcmu_version.func_version = (version >> 16) & 0xFF;
-                       prcmu_version.errata = (version >> 24) & 0xFF;
-                       pr_info("PRCMU firmware version %d.%d.%d\n",
+                       fw_info.version.project = version & 0xFF;
+                       fw_info.version.api_version = (version >> 8) & 0xFF;
+                       fw_info.version.func_version = (version >> 16) & 0xFF;
+                       fw_info.version.errata = (version >> 24) & 0xFF;
+                       fw_info.valid = true;
+                       pr_info("PRCMU firmware: %s, version %d.%d.%d\n",
+                               fw_project_name(fw_info.version.project),
                                (version >> 8) & 0xFF, (version >> 16) & 0xFF,
                                (version >> 24) & 0xFF);
                        iounmap(tcpm_base);
@@ -2130,6 +2676,7 @@ void __init db8500_prcmu_early_init(void)
        init_completion(&mb0_transfer.ac_wake_work);
        mutex_init(&mb1_transfer.lock);
        init_completion(&mb1_transfer.work);
+       mb1_transfer.ape_opp = APE_NO_CHANGE;
        mutex_init(&mb2_transfer.lock);
        init_completion(&mb2_transfer.work);
        spin_lock_init(&mb2_transfer.auto_pm_lock);
@@ -2154,7 +2701,7 @@ void __init db8500_prcmu_early_init(void)
        }
 }
 
-static void __init db8500_prcmu_init_clkforce(void)
+static void __init init_prcm_registers(void)
 {
        u32 val;
 
@@ -2186,19 +2733,17 @@ static struct regulator_consumer_supply db8500_vape_consumers[] = {
        REGULATOR_SUPPLY("vcore", "uart1"),
        REGULATOR_SUPPLY("vcore", "uart2"),
        REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
+       REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"),
 };
 
 static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
-       /* CG2900 and CW1200 power to off-chip peripherals */
-       REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"),
-       REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"),
        REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
        /* AV8100 regulator */
        REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
 };
 
 static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
-       REGULATOR_SUPPLY("vsupply", "b2r2.0"),
+       REGULATOR_SUPPLY("vsupply", "b2r2_bus"),
        REGULATOR_SUPPLY("vsupply", "mcde"),
 };
 
@@ -2235,6 +2780,7 @@ static struct regulator_consumer_supply db8500_esram12_consumers[] = {
 static struct regulator_consumer_supply db8500_esram34_consumers[] = {
        REGULATOR_SUPPLY("v-esram34", "mcde"),
        REGULATOR_SUPPLY("esram34", "cm_control"),
+       REGULATOR_SUPPLY("lcla_esram", "dma40.0"),
 };
 
 static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
@@ -2291,7 +2837,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                },
        },
        [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
-               .supply_regulator = "db8500-vape",
+               /* dependency to u8500-vape is handled outside regulator framework */
                .constraints = {
                        .name = "db8500-sva-mmdsp",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2307,7 +2853,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                },
        },
        [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
-               .supply_regulator = "db8500-vape",
+               /* dependency to u8500-vape is handled outside regulator framework */
                .constraints = {
                        .name = "db8500-sva-pipe",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2316,7 +2862,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                .num_consumer_supplies = ARRAY_SIZE(db8500_svapipe_consumers),
        },
        [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
-               .supply_regulator = "db8500-vape",
+               /* dependency to u8500-vape is handled outside regulator framework */
                .constraints = {
                        .name = "db8500-sia-mmdsp",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2331,7 +2877,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                },
        },
        [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
-               .supply_regulator = "db8500-vape",
+               /* dependency to u8500-vape is handled outside regulator framework */
                .constraints = {
                        .name = "db8500-sia-pipe",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2359,7 +2905,10 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                .num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
        },
        [DB8500_REGULATOR_SWITCH_ESRAM12] = {
-               .supply_regulator = "db8500-vape",
+               /*
+                * esram12 is set in retention and supplied by Vsafe when Vape is off,
+                * no need to hold Vape
+                */
                .constraints = {
                        .name = "db8500-esram12",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2374,7 +2923,10 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
                },
        },
        [DB8500_REGULATOR_SWITCH_ESRAM34] = {
-               .supply_regulator = "db8500-vape",
+               /*
+                * esram34 is set in retention and supplied by Vsafe when Vape is off,
+                * no need to hold Vape
+                */
                .constraints = {
                        .name = "db8500-esram34",
                        .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -2412,7 +2964,7 @@ static int __init db8500_prcmu_probe(struct platform_device *pdev)
        if (ux500_is_svp())
                return -ENODEV;
 
-       db8500_prcmu_init_clkforce();
+       init_prcm_registers();
 
        /* Clean up the mailbox interrupts after pre-kernel code. */
        writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
index ec22e9f..3a0bf91 100644 (file)
 
 #define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
 
-#define PRCM_SVACLK_MGT_OFF            0x008
-#define PRCM_SIACLK_MGT_OFF            0x00C
-#define PRCM_SGACLK_MGT_OFF            0x014
-#define PRCM_UARTCLK_MGT_OFF           0x018
-#define PRCM_MSP02CLK_MGT_OFF          0x01C
-#define PRCM_I2CCLK_MGT_OFF            0x020
-#define PRCM_SDMMCCLK_MGT_OFF          0x024
-#define PRCM_SLIMCLK_MGT_OFF           0x028
-#define PRCM_PER1CLK_MGT_OFF           0x02C
-#define PRCM_PER2CLK_MGT_OFF           0x030
-#define PRCM_PER3CLK_MGT_OFF           0x034
-#define PRCM_PER5CLK_MGT_OFF           0x038
-#define PRCM_PER6CLK_MGT_OFF           0x03C
-#define PRCM_PER7CLK_MGT_OFF           0x040
-#define PRCM_PWMCLK_MGT_OFF            0x044 /* for DB5500 */
-#define PRCM_IRDACLK_MGT_OFF           0x048 /* for DB5500 */
-#define PRCM_IRRCCLK_MGT_OFF           0x04C /* for DB5500 */
-#define PRCM_LCDCLK_MGT_OFF            0x044
-#define PRCM_BMLCLK_MGT_OFF            0x04C
-#define PRCM_HSITXCLK_MGT_OFF          0x050
-#define PRCM_HSIRXCLK_MGT_OFF          0x054
-#define PRCM_HDMICLK_MGT_OFF           0x058
-#define PRCM_APEATCLK_MGT_OFF          0x05C
-#define PRCM_APETRACECLK_MGT_OFF       0x060
-#define PRCM_MCDECLK_MGT_OFF           0x064
-#define PRCM_IPI2CCLK_MGT_OFF          0x068
-#define PRCM_DSIALTCLK_MGT_OFF         0x06C
-#define PRCM_DMACLK_MGT_OFF            0x074
-#define PRCM_B2R2CLK_MGT_OFF           0x078
-#define PRCM_TVCLK_MGT_OFF             0x07C
-#define PRCM_UNIPROCLK_MGT_OFF         0x278
-#define PRCM_SSPCLK_MGT_OFF            0x280
-#define PRCM_RNGCLK_MGT_OFF            0x284
-#define PRCM_UICCCLK_MGT_OFF           0x27C
-#define PRCM_MSP1CLK_MGT_OFF           0x288
+#define PRCM_CLK_MGT(_offset) (void __iomem *)(IO_ADDRESS(U8500_PRCMU_BASE) \
+       + _offset)
+#define PRCM_ACLK_MGT          PRCM_CLK_MGT(0x004)
+#define PRCM_SVACLK_MGT                PRCM_CLK_MGT(0x008)
+#define PRCM_SIACLK_MGT                PRCM_CLK_MGT(0x00C)
+#define PRCM_SGACLK_MGT                PRCM_CLK_MGT(0x014)
+#define PRCM_UARTCLK_MGT       PRCM_CLK_MGT(0x018)
+#define PRCM_MSP02CLK_MGT      PRCM_CLK_MGT(0x01C)
+#define PRCM_I2CCLK_MGT                PRCM_CLK_MGT(0x020)
+#define PRCM_SDMMCCLK_MGT      PRCM_CLK_MGT(0x024)
+#define PRCM_SLIMCLK_MGT       PRCM_CLK_MGT(0x028)
+#define PRCM_PER1CLK_MGT       PRCM_CLK_MGT(0x02C)
+#define PRCM_PER2CLK_MGT       PRCM_CLK_MGT(0x030)
+#define PRCM_PER3CLK_MGT       PRCM_CLK_MGT(0x034)
+#define PRCM_PER5CLK_MGT       PRCM_CLK_MGT(0x038)
+#define PRCM_PER6CLK_MGT       PRCM_CLK_MGT(0x03C)
+#define PRCM_PER7CLK_MGT       PRCM_CLK_MGT(0x040)
+#define PRCM_LCDCLK_MGT                PRCM_CLK_MGT(0x044)
+#define PRCM_BMLCLK_MGT                PRCM_CLK_MGT(0x04C)
+#define PRCM_HSITXCLK_MGT      PRCM_CLK_MGT(0x050)
+#define PRCM_HSIRXCLK_MGT      PRCM_CLK_MGT(0x054)
+#define PRCM_HDMICLK_MGT       PRCM_CLK_MGT(0x058)
+#define PRCM_APEATCLK_MGT      PRCM_CLK_MGT(0x05C)
+#define PRCM_APETRACECLK_MGT   PRCM_CLK_MGT(0x060)
+#define PRCM_MCDECLK_MGT       PRCM_CLK_MGT(0x064)
+#define PRCM_IPI2CCLK_MGT      PRCM_CLK_MGT(0x068)
+#define PRCM_DSIALTCLK_MGT     PRCM_CLK_MGT(0x06C)
+#define PRCM_DMACLK_MGT                PRCM_CLK_MGT(0x074)
+#define PRCM_B2R2CLK_MGT       PRCM_CLK_MGT(0x078)
+#define PRCM_TVCLK_MGT         PRCM_CLK_MGT(0x07C)
+#define PRCM_UNIPROCLK_MGT     PRCM_CLK_MGT(0x278)
+#define PRCM_SSPCLK_MGT                PRCM_CLK_MGT(0x280)
+#define PRCM_RNGCLK_MGT                PRCM_CLK_MGT(0x284)
+#define PRCM_UICCCLK_MGT       PRCM_CLK_MGT(0x27C)
+#define PRCM_MSP1CLK_MGT       PRCM_CLK_MGT(0x288)
 
 #define PRCM_ARM_PLLDIVPS      (_PRCMU_BASE + 0x118)
 #define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE         0x3f
@@ -79,6 +79,8 @@
 
 /* ARM WFI Standby signal register */
 #define PRCM_ARM_WFI_STANDBY    (_PRCMU_BASE + 0x130)
+#define PRCM_ARM_WFI_STANDBY_WFI0               0x08
+#define PRCM_ARM_WFI_STANDBY_WFI1               0x10
 #define PRCM_IOCR              (_PRCMU_BASE + 0x310)
 #define PRCM_IOCR_IOFORCE                      0x1
 
 #define PRCM_MMIP_LS_CLAMP_SET     (_PRCMU_BASE + 0x420)
 #define PRCM_MMIP_LS_CLAMP_CLR     (_PRCMU_BASE + 0x424)
 
+#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMP                BIT(11)
+#define PRCM_MMIP_LS_CLAMP_DSIPLL_CLAMPI       BIT(22)
+
 /* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLSOC0_FREQ         (_PRCMU_BASE + 0x080)
+#define PRCM_PLLSOC1_FREQ         (_PRCMU_BASE + 0x084)
+#define PRCM_PLLDDR_FREQ          (_PRCMU_BASE + 0x08C)
+#define PRCM_PLL_FREQ_D_SHIFT  0
+#define PRCM_PLL_FREQ_D_MASK   BITS(0, 7)
+#define PRCM_PLL_FREQ_N_SHIFT  8
+#define PRCM_PLL_FREQ_N_MASK   BITS(8, 13)
+#define PRCM_PLL_FREQ_R_SHIFT  16
+#define PRCM_PLL_FREQ_R_MASK   BITS(16, 18)
+#define PRCM_PLL_FREQ_SELDIV2  BIT(24)
+#define PRCM_PLL_FREQ_DIV2EN   BIT(25)
+
 #define PRCM_PLLDSI_FREQ           (_PRCMU_BASE + 0x500)
 #define PRCM_PLLDSI_ENABLE         (_PRCMU_BASE + 0x504)
 #define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
-#define PRCM_LCDCLK_MGT            (_PRCMU_BASE + PRCM_LCDCLK_MGT_OFF)
-#define PRCM_MCDECLK_MGT           (_PRCMU_BASE + PRCM_MCDECLK_MGT_OFF)
-#define PRCM_HDMICLK_MGT           (_PRCMU_BASE + PRCM_HDMICLK_MGT_OFF)
-#define PRCM_TVCLK_MGT             (_PRCMU_BASE + PRCM_TVCLK_MGT_OFF)
 #define PRCM_DSI_PLLOUT_SEL        (_PRCMU_BASE + 0x530)
 #define PRCM_DSITVCLK_DIV          (_PRCMU_BASE + 0x52C)
 #define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
 #define PRCM_APE_RESETN_SET        (_PRCMU_BASE + 0x1E4)
 #define PRCM_APE_RESETN_CLR        (_PRCMU_BASE + 0x1E8)
 
+#define PRCM_PLLDSI_ENABLE_PRCM_PLLDSI_ENABLE BIT(0)
+
+#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP10  BIT(0)
+#define PRCM_PLLDSI_LOCKP_PRCM_PLLDSI_LOCKP3   BIT(1)
+
+#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_SHIFT   0
+#define PRCM_DSI_PLLOUT_SEL_DSI0_PLLOUT_DIVSEL_MASK    BITS(0, 2)
+#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_SHIFT   8
+#define PRCM_DSI_PLLOUT_SEL_DSI1_PLLOUT_DIVSEL_MASK    BITS(8, 10)
+
+#define PRCM_DSI_PLLOUT_SEL_OFF                0
+#define PRCM_DSI_PLLOUT_SEL_PHI                1
+#define PRCM_DSI_PLLOUT_SEL_PHI_2      2
+#define PRCM_DSI_PLLOUT_SEL_PHI_4      3
+
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_SHIFT       0
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_DIV_MASK                BITS(0, 7)
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_SHIFT       8
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_DIV_MASK                BITS(8, 15)
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_SHIFT       16
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_DIV_MASK                BITS(16, 23)
+#define PRCM_DSITVCLK_DIV_DSI0_ESC_CLK_EN              BIT(24)
+#define PRCM_DSITVCLK_DIV_DSI1_ESC_CLK_EN              BIT(25)
+#define PRCM_DSITVCLK_DIV_DSI2_ESC_CLK_EN              BIT(26)
+
+#define PRCM_APE_RESETN_DSIPLL_RESETN BIT(14)
+
 #define PRCM_CLKOCR               (_PRCMU_BASE + 0x1CC)
 #define PRCM_CLKOCR_CLKOUT0_REF_CLK    (1 << 0)
 #define PRCM_CLKOCR_CLKOUT0_MASK       BITS(0, 13)
 #define PRCM_CLKOCR_CLKOSEL1_MASK      BITS(22, 24)
 #define PRCM_CLKOCR_CLK1TYPE           BIT(28)
 
-#define PRCM_CLK_MGT_CLKPLLDIV_MASK    BITS(0, 4)
-#define PRCM_CLK_MGT_CLKPLLSW_MASK     BITS(5, 7)
-#define PRCM_CLK_MGT_CLKEN             BIT(8)
+#define PRCM_CLK_MGT_CLKPLLDIV_MASK            BITS(0, 4)
+#define PRCM_CLK_MGT_CLKPLLSW_SOC0             BIT(5)
+#define PRCM_CLK_MGT_CLKPLLSW_SOC1             BIT(6)
+#define PRCM_CLK_MGT_CLKPLLSW_DDR              BIT(7)
+#define PRCM_CLK_MGT_CLKPLLSW_MASK             BITS(5, 7)
+#define PRCM_CLK_MGT_CLKEN                     BIT(8)
+#define PRCM_CLK_MGT_CLK38                     BIT(9)
+#define PRCM_CLK_MGT_CLK38DIV                  BIT(11)
+#define PRCM_SGACLK_MGT_SGACLKDIV_BY_2_5_EN    BIT(12)
 
 /* GPIOCR register */
 #define PRCM_GPIOCR_SPI2_SELECT BIT(23)
index 7122386..9fd4f63 100644 (file)
@@ -560,6 +560,8 @@ EXPORT_SYMBOL(mc13xxx_get_flags);
 
 #define MC13XXX_ADC1_CHAN0_SHIFT       5
 #define MC13XXX_ADC1_CHAN1_SHIFT       8
+#define MC13783_ADC1_ATO_SHIFT         11
+#define MC13783_ADC1_ATOX              (1 << 19)
 
 struct mc13xxx_adcdone_data {
        struct mc13xxx *mc13xxx;
@@ -580,7 +582,8 @@ static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data)
 #define MC13XXX_ADC_WORKING (1 << 0)
 
 int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
-               unsigned int channel, unsigned int *sample)
+               unsigned int channel, u8 ato, bool atox,
+               unsigned int *sample)
 {
        u32 adc0, adc1, old_adc0;
        int i, ret;
@@ -631,6 +634,9 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
                return -EINVAL;
        }
 
+       adc1 |= ato << MC13783_ADC1_ATO_SHIFT;
+       if (atox)
+               adc1 |= MC13783_ADC1_ATOX;
        dev_dbg(&mc13xxx->spidev->dev, "%s: request irq\n", __func__);
        mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
                        mc13xxx_handler_adcdone, __func__, &adcdone_data);
@@ -813,7 +819,8 @@ err_revision:
                mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
 
        if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
-               mc13xxx_add_subdevice(mc13xxx, "%s-ts");
+               mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
+                               &pdata->touch, sizeof(pdata->touch));
 
        if (pdata) {
                mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
index 32c82de..62e5e36 100644 (file)
@@ -19,8 +19,6 @@
 #include <linux/string.h>
 #include <linux/mfd/mcp.h>
 
-#include <mach/dma.h>
-
 
 #define to_mcp(d)              container_of(d, struct mcp, attached_device)
 #define to_mcp_driver(d)       container_of(d, struct mcp_driver, drv)
@@ -47,39 +45,11 @@ static int mcp_bus_remove(struct device *dev)
        return 0;
 }
 
-static int mcp_bus_suspend(struct device *dev, pm_message_t state)
-{
-       struct mcp *mcp = to_mcp(dev);
-       int ret = 0;
-
-       if (dev->driver) {
-               struct mcp_driver *drv = to_mcp_driver(dev->driver);
-
-               ret = drv->suspend(mcp, state);
-       }
-       return ret;
-}
-
-static int mcp_bus_resume(struct device *dev)
-{
-       struct mcp *mcp = to_mcp(dev);
-       int ret = 0;
-
-       if (dev->driver) {
-               struct mcp_driver *drv = to_mcp_driver(dev->driver);
-
-               ret = drv->resume(mcp);
-       }
-       return ret;
-}
-
 static struct bus_type mcp_bus_type = {
        .name           = "mcp",
        .match          = mcp_bus_match,
        .probe          = mcp_bus_probe,
        .remove         = mcp_bus_remove,
-       .suspend        = mcp_bus_suspend,
-       .resume         = mcp_bus_resume,
 };
 
 /**
@@ -207,6 +177,7 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
        mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
        if (mcp) {
                spin_lock_init(&mcp->lock);
+               device_initialize(&mcp->attached_device);
                mcp->attached_device.parent = parent;
                mcp->attached_device.bus = &mcp_bus_type;
                mcp->attached_device.dma_mask = parent->dma_mask;
@@ -216,18 +187,25 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
 }
 EXPORT_SYMBOL(mcp_host_alloc);
 
-int mcp_host_register(struct mcp *mcp)
+int mcp_host_add(struct mcp *mcp, void *pdata)
 {
+       mcp->attached_device.platform_data = pdata;
        dev_set_name(&mcp->attached_device, "mcp0");
-       return device_register(&mcp->attached_device);
+       return device_add(&mcp->attached_device);
+}
+EXPORT_SYMBOL(mcp_host_add);
+
+void mcp_host_del(struct mcp *mcp)
+{
+       device_del(&mcp->attached_device);
 }
-EXPORT_SYMBOL(mcp_host_register);
+EXPORT_SYMBOL(mcp_host_del);
 
-void mcp_host_unregister(struct mcp *mcp)
+void mcp_host_free(struct mcp *mcp)
 {
-       device_unregister(&mcp->attached_device);
+       put_device(&mcp->attached_device);
 }
-EXPORT_SYMBOL(mcp_host_unregister);
+EXPORT_SYMBOL(mcp_host_free);
 
 int mcp_driver_register(struct mcp_driver *mcpdrv)
 {
index 4a27c2b..c54e244 100644 (file)
  */
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/mfd/mcp.h>
 
-#include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <mach/mcp.h>
 
-#include <mach/assabet.h>
-
+#define DRIVER_NAME "sa11x0-mcp"
 
 struct mcp_sa11x0 {
-       u32     mccr0;
-       u32     mccr1;
+       void __iomem    *base0;
+       void __iomem    *base1;
+       u32             mccr0;
+       u32             mccr1;
 };
 
+/* Register offsets */
+#define MCCR0(m)       ((m)->base0 + 0x00)
+#define MCDR0(m)       ((m)->base0 + 0x08)
+#define MCDR1(m)       ((m)->base0 + 0x0c)
+#define MCDR2(m)       ((m)->base0 + 0x10)
+#define MCSR(m)                ((m)->base0 + 0x18)
+#define MCCR1(m)       ((m)->base1 + 0x00)
+
 #define priv(mcp)      ((struct mcp_sa11x0 *)mcp_priv(mcp))
 
 static void
 mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
 {
-       unsigned int mccr0;
+       struct mcp_sa11x0 *m = priv(mcp);
 
        divisor /= 32;
 
-       mccr0 = Ser4MCCR0 & ~0x00007f00;
-       mccr0 |= divisor << 8;
-       Ser4MCCR0 = mccr0;
+       m->mccr0 &= ~0x00007f00;
+       m->mccr0 |= divisor << 8;
+       writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 static void
 mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
 {
-       unsigned int mccr0;
+       struct mcp_sa11x0 *m = priv(mcp);
 
        divisor /= 32;
 
-       mccr0 = Ser4MCCR0 & ~0x0000007f;
-       mccr0 |= divisor;
-       Ser4MCCR0 = mccr0;
+       m->mccr0 &= ~0x0000007f;
+       m->mccr0 |= divisor;
+       writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 /*
@@ -68,14 +78,15 @@ mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
 static void
 mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
 {
+       struct mcp_sa11x0 *m = priv(mcp);
        int ret = -ETIME;
        int i;
 
-       Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
+       writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m));
 
        for (i = 0; i < 2; i++) {
                udelay(mcp->rw_timeout);
-               if (Ser4MCSR & MCSR_CWC) {
+               if (readl_relaxed(MCSR(m)) & MCSR_CWC) {
                        ret = 0;
                        break;
                }
@@ -94,15 +105,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
 static unsigned int
 mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 {
+       struct mcp_sa11x0 *m = priv(mcp);
        int ret = -ETIME;
        int i;
 
-       Ser4MCDR2 = reg << 17 | MCDR2_Rd;
+       writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m));
 
        for (i = 0; i < 2; i++) {
                udelay(mcp->rw_timeout);
-               if (Ser4MCSR & MCSR_CRC) {
-                       ret = Ser4MCDR2 & 0xffff;
+               if (readl_relaxed(MCSR(m)) & MCSR_CRC) {
+                       ret = readl_relaxed(MCDR2(m)) & 0xffff;
                        break;
                }
        }
@@ -115,13 +127,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 
 static void mcp_sa11x0_enable(struct mcp *mcp)
 {
-       Ser4MCSR = -1;
-       Ser4MCCR0 |= MCCR0_MCE;
+       struct mcp_sa11x0 *m = priv(mcp);
+
+       writel(-1, MCSR(m));
+       m->mccr0 |= MCCR0_MCE;
+       writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 static void mcp_sa11x0_disable(struct mcp *mcp)
 {
-       Ser4MCCR0 &= ~MCCR0_MCE;
+       struct mcp_sa11x0 *m = priv(mcp);
+
+       m->mccr0 &= ~MCCR0_MCE;
+       writel_relaxed(m->mccr0, MCCR0(m));
 }
 
 /*
@@ -136,55 +154,64 @@ static struct mcp_ops mcp_sa11x0 = {
        .disable                = mcp_sa11x0_disable,
 };
 
-static int mcp_sa11x0_probe(struct platform_device *pdev)
+static int mcp_sa11x0_probe(struct platform_device *dev)
 {
-       struct mcp_plat_data *data = pdev->dev.platform_data;
+       struct mcp_plat_data *data = dev->dev.platform_data;
+       struct resource *mem0, *mem1;
+       struct mcp_sa11x0 *m;
        struct mcp *mcp;
        int ret;
 
        if (!data)
                return -ENODEV;
 
-       if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
-               return -EBUSY;
+       mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
+       if (!mem0 || !mem1)
+               return -ENXIO;
+
+       if (!request_mem_region(mem0->start, resource_size(mem0),
+                               DRIVER_NAME)) {
+               ret = -EBUSY;
+               goto err_mem0;
+       }
 
-       mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
+       if (!request_mem_region(mem1->start, resource_size(mem1),
+                               DRIVER_NAME)) {
+               ret = -EBUSY;
+               goto err_mem1;
+       }
+
+       mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0));
        if (!mcp) {
                ret = -ENOMEM;
-               goto release;
+               goto err_alloc;
        }
 
        mcp->owner              = THIS_MODULE;
        mcp->ops                = &mcp_sa11x0;
        mcp->sclk_rate          = data->sclk_rate;
-       mcp->dma_audio_rd       = DMA_Ser4MCP0Rd;
-       mcp->dma_audio_wr       = DMA_Ser4MCP0Wr;
-       mcp->dma_telco_rd       = DMA_Ser4MCP1Rd;
-       mcp->dma_telco_wr       = DMA_Ser4MCP1Wr;
-       mcp->gpio_base          = data->gpio_base;
 
-       platform_set_drvdata(pdev, mcp);
+       m = priv(mcp);
+       m->mccr0 = data->mccr0 | 0x7f7f;
+       m->mccr1 = data->mccr1;
 
-       if (machine_is_assabet()) {
-               ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
+       m->base0 = ioremap(mem0->start, resource_size(mem0));
+       m->base1 = ioremap(mem1->start, resource_size(mem1));
+       if (!m->base0 || !m->base1) {
+               ret = -ENOMEM;
+               goto err_ioremap;
        }
 
-       /*
-        * Setup the PPC unit correctly.
-        */
-       PPDR &= ~PPC_RXD4;
-       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
-       PSDR |= PPC_RXD4;
-       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       platform_set_drvdata(dev, mcp);
 
        /*
         * Initialise device.  Note that we initially
         * set the sampling rate to minimum.
         */
-       Ser4MCSR = -1;
-       Ser4MCCR1 = data->mccr1;
-       Ser4MCCR0 = data->mccr0 | 0x7f7f;
+       writel_relaxed(-1, MCSR(m));
+       writel_relaxed(m->mccr1, MCCR1(m));
+       writel_relaxed(m->mccr0, MCCR0(m));
 
        /*
         * Calculate the read/write timeout (us) from the bit clock
@@ -194,62 +221,90 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
        mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
                          mcp->sclk_rate;
 
-       ret = mcp_host_register(mcp);
+       ret = mcp_host_add(mcp, data->codec_pdata);
        if (ret == 0)
-               goto out;
+               return 0;
 
- release:
-       release_mem_region(0x80060000, 0x60);
-       platform_set_drvdata(pdev, NULL);
+       platform_set_drvdata(dev, NULL);
 
- out:
+ err_ioremap:
+       iounmap(m->base1);
+       iounmap(m->base0);
+       mcp_host_free(mcp);
+ err_alloc:
+       release_mem_region(mem1->start, resource_size(mem1));
+ err_mem1:
+       release_mem_region(mem0->start, resource_size(mem0));
+ err_mem0:
        return ret;
 }
 
 static int mcp_sa11x0_remove(struct platform_device *dev)
 {
        struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp_sa11x0 *m = priv(mcp);
+       struct resource *mem0, *mem1;
+
+       if (m->mccr0 & MCCR0_MCE)
+               dev_warn(&dev->dev,
+                        "device left active (missing disable call?)\n");
+
+       mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
 
        platform_set_drvdata(dev, NULL);
-       mcp_host_unregister(mcp);
-       release_mem_region(0x80060000, 0x60);
+       mcp_host_del(mcp);
+       iounmap(m->base1);
+       iounmap(m->base0);
+       mcp_host_free(mcp);
+       release_mem_region(mem1->start, resource_size(mem1));
+       release_mem_region(mem0->start, resource_size(mem0));
 
        return 0;
 }
 
-static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int mcp_sa11x0_suspend(struct device *dev)
 {
-       struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
+
+       if (m->mccr0 & MCCR0_MCE)
+               dev_warn(dev, "device left active (missing disable call?)\n");
 
-       priv(mcp)->mccr0 = Ser4MCCR0;
-       priv(mcp)->mccr1 = Ser4MCCR1;
-       Ser4MCCR0 &= ~MCCR0_MCE;
+       writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m));
 
        return 0;
 }
 
-static int mcp_sa11x0_resume(struct platform_device *dev)
+static int mcp_sa11x0_resume(struct device *dev)
 {
-       struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
 
-       Ser4MCCR1 = priv(mcp)->mccr1;
-       Ser4MCCR0 = priv(mcp)->mccr0;
+       writel_relaxed(m->mccr1, MCCR1(m));
+       writel_relaxed(m->mccr0, MCCR0(m));
 
        return 0;
 }
-
-/*
- * The driver for the SA11x0 MCP port.
- */
-MODULE_ALIAS("platform:sa11x0-mcp");
+#endif
+
+static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+       .suspend = mcp_sa11x0_suspend,
+       .freeze = mcp_sa11x0_suspend,
+       .poweroff = mcp_sa11x0_suspend,
+       .resume_noirq = mcp_sa11x0_resume,
+       .thaw_noirq = mcp_sa11x0_resume,
+       .restore_noirq = mcp_sa11x0_resume,
+#endif
+};
 
 static struct platform_driver mcp_sa11x0_driver = {
        .probe          = mcp_sa11x0_probe,
        .remove         = mcp_sa11x0_remove,
-       .suspend        = mcp_sa11x0_suspend,
-       .resume         = mcp_sa11x0_resume,
        .driver         = {
-               .name   = "sa11x0-mcp",
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &mcp_sa11x0_pm_ops,
        },
 };
 
@@ -258,6 +313,7 @@ static struct platform_driver mcp_sa11x0_driver = {
  */
 module_platform_driver(mcp_sa11x0_driver);
 
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
 MODULE_LICENSE("GPL");
index 411f523..ffc3d48 100644 (file)
@@ -162,7 +162,7 @@ int mfd_add_devices(struct device *parent, int id,
        atomic_t *cnts;
 
        /* initialize reference counting for all cells */
-       cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL);
+       cnts = kcalloc(n_devs, sizeof(*cnts), GFP_KERNEL);
        if (!cnts)
                return -ENOMEM;
 
index 68ac2c5..95a2e54 100644 (file)
@@ -170,7 +170,7 @@ struct usbhs_hcd_omap {
 /*-------------------------------------------------------------------------*/
 
 const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
-static u64 usbhs_dmamask = ~(u32)0;
+static u64 usbhs_dmamask = DMA_BIT_MASK(32);
 
 /*-------------------------------------------------------------------------*/
 
@@ -223,7 +223,7 @@ static struct platform_device *omap_usbhs_alloc_child(const char *name,
        }
 
        child->dev.dma_mask             = &usbhs_dmamask;
-       child->dev.coherent_dma_mask    = 0xffffffff;
+       dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
        child->dev.parent               = dev;
 
        ret = platform_device_add(child);
@@ -799,14 +799,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, omap);
 
+       omap_usbhs_init(dev);
        ret = omap_usbhs_alloc_children(pdev);
        if (ret) {
                dev_err(dev, "omap_usbhs_alloc_children failed\n");
                goto err_alloc;
        }
 
-       omap_usbhs_init(dev);
-
        goto end_probe;
 
 err_alloc:
index ff1a7e7..189c2f0 100644 (file)
@@ -46,13 +46,7 @@ EXPORT_SYMBOL_GPL(pcf50633_read_block);
 int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
                                        int nr_regs, u8 *data)
 {
-       int ret;
-
-       ret = regmap_raw_write(pcf->regmap, reg, data, nr_regs);
-       if (ret != 0)
-               return ret;
-
-       return nr_regs;
+       return regmap_raw_write(pcf->regmap, reg, data, nr_regs);
 }
 EXPORT_SYMBOL_GPL(pcf50633_write_block);
 
index 9ab19a8..d02ddf2 100644 (file)
 
 #include <linux/mfd/pcf50633/core.h>
 #include <linux/mfd/pcf50633/gpio.h>
-
-enum pcf50633_regulator_id {
-       PCF50633_REGULATOR_AUTO,
-       PCF50633_REGULATOR_DOWN1,
-       PCF50633_REGULATOR_DOWN2,
-       PCF50633_REGULATOR_LDO1,
-       PCF50633_REGULATOR_LDO2,
-       PCF50633_REGULATOR_LDO3,
-       PCF50633_REGULATOR_LDO4,
-       PCF50633_REGULATOR_LDO5,
-       PCF50633_REGULATOR_LDO6,
-       PCF50633_REGULATOR_HCLDO,
-       PCF50633_REGULATOR_MEMLDO,
-};
-
-#define PCF50633_REG_AUTOOUT   0x1a
-#define PCF50633_REG_DOWN1OUT  0x1e
-#define PCF50633_REG_DOWN2OUT  0x22
-#define PCF50633_REG_MEMLDOOUT 0x26
-#define PCF50633_REG_LDO1OUT   0x2d
-#define PCF50633_REG_LDO2OUT   0x2f
-#define PCF50633_REG_LDO3OUT   0x31
-#define PCF50633_REG_LDO4OUT   0x33
-#define PCF50633_REG_LDO5OUT   0x35
-#define PCF50633_REG_LDO6OUT   0x37
-#define PCF50633_REG_HCLDOOUT  0x39
+#include <linux/mfd/pcf50633/pmic.h>
 
 static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
        [PCF50633_REGULATOR_AUTO]       = PCF50633_REG_AUTOOUT,
index 048a3b9..498286c 100644 (file)
 #include <linux/slab.h>
 
 #include <linux/mfd/pcf50633/core.h>
-
-/* Two MBCS registers used during cold start */
-#define PCF50633_REG_MBCS1             0x4b
-#define PCF50633_REG_MBCS2             0x4c
-#define PCF50633_MBCS1_USBPRES                 0x01
-#define PCF50633_MBCS1_ADAPTPRES       0x01
+#include <linux/mfd/pcf50633/mbc.h>
 
 int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
                        void (*handler) (int, void *), void *data)
diff --git a/drivers/mfd/rc5t583-irq.c b/drivers/mfd/rc5t583-irq.c
new file mode 100644 (file)
index 0000000..fa6f80f
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * Interrupt driver for RICOH583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * based on code
+ *      Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mfd/rc5t583.h>
+
+enum int_type {
+       SYS_INT  = 0x1,
+       DCDC_INT = 0x2,
+       RTC_INT  = 0x4,
+       ADC_INT  = 0x8,
+       GPIO_INT = 0x10,
+};
+
+static int gpedge_add[] = {
+       RC5T583_GPIO_GPEDGE2,
+       RC5T583_GPIO_GPEDGE2
+};
+
+static int irq_en_add[] = {
+       RC5T583_INT_EN_SYS1,
+       RC5T583_INT_EN_SYS2,
+       RC5T583_INT_EN_DCDC,
+       RC5T583_INT_EN_RTC,
+       RC5T583_INT_EN_ADC1,
+       RC5T583_INT_EN_ADC2,
+       RC5T583_INT_EN_ADC3,
+       RC5T583_GPIO_EN_INT
+};
+
+static int irq_mon_add[] = {
+       RC5T583_INT_MON_SYS1,
+       RC5T583_INT_MON_SYS2,
+       RC5T583_INT_MON_DCDC,
+       RC5T583_INT_MON_RTC,
+       RC5T583_INT_IR_ADCL,
+       RC5T583_INT_IR_ADCH,
+       RC5T583_INT_IR_ADCEND,
+       RC5T583_INT_IR_GPIOF,
+       RC5T583_INT_IR_GPIOR
+};
+
+static int irq_clr_add[] = {
+       RC5T583_INT_IR_SYS1,
+       RC5T583_INT_IR_SYS2,
+       RC5T583_INT_IR_DCDC,
+       RC5T583_INT_IR_RTC,
+       RC5T583_INT_IR_ADCL,
+       RC5T583_INT_IR_ADCH,
+       RC5T583_INT_IR_ADCEND,
+       RC5T583_INT_IR_GPIOF,
+       RC5T583_INT_IR_GPIOR
+};
+
+static int main_int_type[] = {
+       SYS_INT,
+       SYS_INT,
+       DCDC_INT,
+       RTC_INT,
+       ADC_INT,
+       ADC_INT,
+       ADC_INT,
+       GPIO_INT,
+       GPIO_INT,
+};
+
+struct rc5t583_irq_data {
+       u8      int_type;
+       u8      master_bit;
+       u8      int_en_bit;
+       u8      mask_reg_index;
+       int     grp_index;
+};
+
+#define RC5T583_IRQ(_int_type, _master_bit, _grp_index, \
+                       _int_bit, _mask_ind)            \
+       {                                               \
+               .int_type       = _int_type,            \
+               .master_bit     = _master_bit,          \
+               .grp_index      = _grp_index,           \
+               .int_en_bit     = _int_bit,             \
+               .mask_reg_index = _mask_ind,            \
+       }
+
+static const struct rc5t583_irq_data rc5t583_irqs[RC5T583_MAX_IRQS] = {
+       [RC5T583_IRQ_ONKEY]             = RC5T583_IRQ(SYS_INT,  0, 0, 0, 0),
+       [RC5T583_IRQ_ACOK]              = RC5T583_IRQ(SYS_INT,  0, 1, 1, 0),
+       [RC5T583_IRQ_LIDOPEN]           = RC5T583_IRQ(SYS_INT,  0, 2, 2, 0),
+       [RC5T583_IRQ_PREOT]             = RC5T583_IRQ(SYS_INT,  0, 3, 3, 0),
+       [RC5T583_IRQ_CLKSTP]            = RC5T583_IRQ(SYS_INT,  0, 4, 4, 0),
+       [RC5T583_IRQ_ONKEY_OFF]         = RC5T583_IRQ(SYS_INT,  0, 5, 5, 0),
+       [RC5T583_IRQ_WD]                = RC5T583_IRQ(SYS_INT,  0, 7, 7, 0),
+       [RC5T583_IRQ_EN_PWRREQ1]        = RC5T583_IRQ(SYS_INT,  0, 8, 0, 1),
+       [RC5T583_IRQ_EN_PWRREQ2]        = RC5T583_IRQ(SYS_INT,  0, 9, 1, 1),
+       [RC5T583_IRQ_PRE_VINDET]        = RC5T583_IRQ(SYS_INT,  0, 10, 2, 1),
+
+       [RC5T583_IRQ_DC0LIM]            = RC5T583_IRQ(DCDC_INT, 1, 0, 0, 2),
+       [RC5T583_IRQ_DC1LIM]            = RC5T583_IRQ(DCDC_INT, 1, 1, 1, 2),
+       [RC5T583_IRQ_DC2LIM]            = RC5T583_IRQ(DCDC_INT, 1, 2, 2, 2),
+       [RC5T583_IRQ_DC3LIM]            = RC5T583_IRQ(DCDC_INT, 1, 3, 3, 2),
+
+       [RC5T583_IRQ_CTC]               = RC5T583_IRQ(RTC_INT,  2, 0, 0, 3),
+       [RC5T583_IRQ_YALE]              = RC5T583_IRQ(RTC_INT,  2, 5, 5, 3),
+       [RC5T583_IRQ_DALE]              = RC5T583_IRQ(RTC_INT,  2, 6, 6, 3),
+       [RC5T583_IRQ_WALE]              = RC5T583_IRQ(RTC_INT,  2, 7, 7, 3),
+
+       [RC5T583_IRQ_AIN1L]             = RC5T583_IRQ(ADC_INT,  3, 0, 0, 4),
+       [RC5T583_IRQ_AIN2L]             = RC5T583_IRQ(ADC_INT,  3, 1, 1, 4),
+       [RC5T583_IRQ_AIN3L]             = RC5T583_IRQ(ADC_INT,  3, 2, 2, 4),
+       [RC5T583_IRQ_VBATL]             = RC5T583_IRQ(ADC_INT,  3, 3, 3, 4),
+       [RC5T583_IRQ_VIN3L]             = RC5T583_IRQ(ADC_INT,  3, 4, 4, 4),
+       [RC5T583_IRQ_VIN8L]             = RC5T583_IRQ(ADC_INT,  3, 5, 5, 4),
+       [RC5T583_IRQ_AIN1H]             = RC5T583_IRQ(ADC_INT,  3, 6, 0, 5),
+       [RC5T583_IRQ_AIN2H]             = RC5T583_IRQ(ADC_INT,  3, 7, 1, 5),
+       [RC5T583_IRQ_AIN3H]             = RC5T583_IRQ(ADC_INT,  3, 8, 2, 5),
+       [RC5T583_IRQ_VBATH]             = RC5T583_IRQ(ADC_INT,  3, 9, 3, 5),
+       [RC5T583_IRQ_VIN3H]             = RC5T583_IRQ(ADC_INT,  3, 10, 4, 5),
+       [RC5T583_IRQ_VIN8H]             = RC5T583_IRQ(ADC_INT,  3, 11, 5, 5),
+       [RC5T583_IRQ_ADCEND]            = RC5T583_IRQ(ADC_INT,  3, 12, 0, 6),
+
+       [RC5T583_IRQ_GPIO0]             = RC5T583_IRQ(GPIO_INT, 4, 0, 0, 7),
+       [RC5T583_IRQ_GPIO1]             = RC5T583_IRQ(GPIO_INT, 4, 1, 1, 7),
+       [RC5T583_IRQ_GPIO2]             = RC5T583_IRQ(GPIO_INT, 4, 2, 2, 7),
+       [RC5T583_IRQ_GPIO3]             = RC5T583_IRQ(GPIO_INT, 4, 3, 3, 7),
+       [RC5T583_IRQ_GPIO4]             = RC5T583_IRQ(GPIO_INT, 4, 4, 4, 7),
+       [RC5T583_IRQ_GPIO5]             = RC5T583_IRQ(GPIO_INT, 4, 5, 5, 7),
+       [RC5T583_IRQ_GPIO6]             = RC5T583_IRQ(GPIO_INT, 4, 6, 6, 7),
+       [RC5T583_IRQ_GPIO7]             = RC5T583_IRQ(GPIO_INT, 4, 7, 7, 7),
+};
+
+static void rc5t583_irq_lock(struct irq_data *irq_data)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       mutex_lock(&rc5t583->irq_lock);
+}
+
+static void rc5t583_irq_unmask(struct irq_data *irq_data)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+       const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+
+       rc5t583->group_irq_en[data->grp_index] |= 1 << data->grp_index;
+       rc5t583->intc_inten_reg |= 1 << data->master_bit;
+       rc5t583->irq_en_reg[data->mask_reg_index] |= 1 << data->int_en_bit;
+}
+
+static void rc5t583_irq_mask(struct irq_data *irq_data)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+       const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+
+       rc5t583->group_irq_en[data->grp_index] &= ~(1 << data->grp_index);
+       if (!rc5t583->group_irq_en[data->grp_index])
+               rc5t583->intc_inten_reg &= ~(1 << data->master_bit);
+
+       rc5t583->irq_en_reg[data->mask_reg_index] &= ~(1 << data->int_en_bit);
+}
+
+static int rc5t583_irq_set_type(struct irq_data *irq_data, unsigned int type)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - rc5t583->irq_base;
+       const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
+       int val = 0;
+       int gpedge_index;
+       int gpedge_bit_pos;
+
+       /* Supporting only trigger level inetrrupt */
+       if ((data->int_type & GPIO_INT) && (type & IRQ_TYPE_EDGE_BOTH)) {
+               gpedge_index = data->int_en_bit / 4;
+               gpedge_bit_pos = data->int_en_bit % 4;
+
+               if (type & IRQ_TYPE_EDGE_FALLING)
+                       val |= 0x2;
+
+               if (type & IRQ_TYPE_EDGE_RISING)
+                       val |= 0x1;
+
+               rc5t583->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
+               rc5t583->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
+               rc5t583_irq_unmask(irq_data);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static void rc5t583_irq_sync_unlock(struct irq_data *irq_data)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       int i;
+       int ret;
+
+       for (i = 0; i < ARRAY_SIZE(rc5t583->gpedge_reg); i++) {
+               ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
+                               rc5t583->gpedge_reg[i]);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               gpedge_add[i], ret);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(rc5t583->irq_en_reg); i++) {
+               ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
+                                       rc5t583->irq_en_reg[i]);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               irq_en_add[i], ret);
+       }
+
+       ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN,
+                               rc5t583->intc_inten_reg);
+       if (ret < 0)
+               dev_warn(rc5t583->dev,
+                       "Error in writing reg 0x%02x error: %d\n",
+                       RC5T583_INTC_INTEN, ret);
+
+       mutex_unlock(&rc5t583->irq_lock);
+}
+#ifdef CONFIG_PM_SLEEP
+static int rc5t583_irq_set_wake(struct irq_data *irq_data, unsigned int on)
+{
+       struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
+       return irq_set_irq_wake(rc5t583->chip_irq, on);
+}
+#else
+#define rc5t583_irq_set_wake NULL
+#endif
+
+static irqreturn_t rc5t583_irq(int irq, void *data)
+{
+       struct rc5t583 *rc5t583 = data;
+       uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS];
+       uint8_t master_int;
+       int i;
+       int ret;
+       unsigned int rtc_int_sts = 0;
+
+       /* Clear the status */
+       for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)
+               int_sts[i] = 0;
+
+       ret  = rc5t583_read(rc5t583->dev, RC5T583_INTC_INTMON, &master_int);
+       if (ret < 0) {
+               dev_err(rc5t583->dev,
+                       "Error in reading reg 0x%02x error: %d\n",
+                       RC5T583_INTC_INTMON, ret);
+               return IRQ_HANDLED;
+       }
+
+       for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; ++i) {
+               if (!(master_int & main_int_type[i]))
+                       continue;
+
+               ret = rc5t583_read(rc5t583->dev, irq_mon_add[i], &int_sts[i]);
+               if (ret < 0) {
+                       dev_warn(rc5t583->dev,
+                               "Error in reading reg 0x%02x error: %d\n",
+                               irq_mon_add[i], ret);
+                       int_sts[i] = 0;
+                       continue;
+               }
+
+               if (main_int_type[i] & RTC_INT) {
+                       rtc_int_sts = 0;
+                       if (int_sts[i] & 0x1)
+                               rtc_int_sts |= BIT(6);
+                       if (int_sts[i] & 0x2)
+                               rtc_int_sts |= BIT(7);
+                       if (int_sts[i] & 0x4)
+                               rtc_int_sts |= BIT(0);
+                       if (int_sts[i] & 0x8)
+                               rtc_int_sts |= BIT(5);
+               }
+
+               ret = rc5t583_write(rc5t583->dev, irq_clr_add[i],
+                               ~int_sts[i]);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in reading reg 0x%02x error: %d\n",
+                               irq_clr_add[i], ret);
+
+               if (main_int_type[i] & RTC_INT)
+                       int_sts[i] = rtc_int_sts;
+       }
+
+       /* Merge gpio interrupts for rising and falling case*/
+       int_sts[7] |= int_sts[8];
+
+       /* Call interrupt handler if enabled */
+       for (i = 0; i < RC5T583_MAX_IRQS; ++i) {
+               const struct rc5t583_irq_data *data = &rc5t583_irqs[i];
+               if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
+                       (rc5t583->group_irq_en[data->master_bit] &
+                                       (1 << data->grp_index)))
+                       handle_nested_irq(rc5t583->irq_base + i);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static struct irq_chip rc5t583_irq_chip = {
+       .name = "rc5t583-irq",
+       .irq_mask = rc5t583_irq_mask,
+       .irq_unmask = rc5t583_irq_unmask,
+       .irq_bus_lock = rc5t583_irq_lock,
+       .irq_bus_sync_unlock = rc5t583_irq_sync_unlock,
+       .irq_set_type = rc5t583_irq_set_type,
+       .irq_set_wake = rc5t583_irq_set_wake,
+};
+
+int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base)
+{
+       int i, ret;
+
+       if (!irq_base) {
+               dev_warn(rc5t583->dev, "No interrupt support on IRQ base\n");
+               return -EINVAL;
+       }
+
+       mutex_init(&rc5t583->irq_lock);
+
+       /* Initailize all int register to 0 */
+       for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)  {
+               ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
+                               rc5t583->irq_en_reg[i]);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               irq_en_add[i], ret);
+       }
+
+       for (i = 0; i < RC5T583_MAX_GPEDGE_REG; i++)  {
+               ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
+                               rc5t583->gpedge_reg[i]);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               gpedge_add[i], ret);
+       }
+
+       ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN, 0x0);
+       if (ret < 0)
+               dev_warn(rc5t583->dev,
+                       "Error in writing reg 0x%02x error: %d\n",
+                       RC5T583_INTC_INTEN, ret);
+
+       /* Clear all interrupts in case they woke up active. */
+       for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)  {
+               ret = rc5t583_write(rc5t583->dev, irq_clr_add[i], 0);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               irq_clr_add[i], ret);
+       }
+
+       rc5t583->irq_base = irq_base;
+       rc5t583->chip_irq = irq;
+
+       for (i = 0; i < RC5T583_MAX_IRQS; i++) {
+               int __irq = i + rc5t583->irq_base;
+               irq_set_chip_data(__irq, rc5t583);
+               irq_set_chip_and_handler(__irq, &rc5t583_irq_chip,
+                                        handle_simple_irq);
+               irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+               set_irq_flags(__irq, IRQF_VALID);
+#endif
+       }
+
+       ret = request_threaded_irq(irq, NULL, rc5t583_irq, IRQF_ONESHOT,
+                               "rc5t583", rc5t583);
+       if (ret < 0)
+               dev_err(rc5t583->dev,
+                       "Error in registering interrupt error: %d\n", ret);
+       return ret;
+}
+
+int rc5t583_irq_exit(struct rc5t583 *rc5t583)
+{
+       if (rc5t583->chip_irq)
+               free_irq(rc5t583->chip_irq, rc5t583);
+       return 0;
+}
diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c
new file mode 100644 (file)
index 0000000..99ef944
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Core driver access RC5T583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on code
+ *     Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rc5t583.h>
+#include <linux/regmap.h>
+
+#define RICOH_ONOFFSEL_REG     0x10
+#define RICOH_SWCTL_REG                0x5E
+
+struct deepsleep_control_data {
+       u8 reg_add;
+       u8 ds_pos_bit;
+};
+
+#define DEEPSLEEP_INIT(_id, _reg, _pos)                \
+       {                                       \
+               .reg_add = RC5T583_##_reg,      \
+               .ds_pos_bit = _pos,             \
+       }
+
+static struct deepsleep_control_data deepsleep_data[] = {
+       DEEPSLEEP_INIT(DC0, SLPSEQ1, 0),
+       DEEPSLEEP_INIT(DC1, SLPSEQ1, 4),
+       DEEPSLEEP_INIT(DC2, SLPSEQ2, 0),
+       DEEPSLEEP_INIT(DC3, SLPSEQ2, 4),
+       DEEPSLEEP_INIT(LDO0, SLPSEQ3, 0),
+       DEEPSLEEP_INIT(LDO1, SLPSEQ3, 4),
+       DEEPSLEEP_INIT(LDO2, SLPSEQ4, 0),
+       DEEPSLEEP_INIT(LDO3, SLPSEQ4, 4),
+       DEEPSLEEP_INIT(LDO4, SLPSEQ5, 0),
+       DEEPSLEEP_INIT(LDO5, SLPSEQ5, 4),
+       DEEPSLEEP_INIT(LDO6, SLPSEQ6, 0),
+       DEEPSLEEP_INIT(LDO7, SLPSEQ6, 4),
+       DEEPSLEEP_INIT(LDO8, SLPSEQ7, 0),
+       DEEPSLEEP_INIT(LDO9, SLPSEQ7, 4),
+       DEEPSLEEP_INIT(PSO0, SLPSEQ8, 0),
+       DEEPSLEEP_INIT(PSO1, SLPSEQ8, 4),
+       DEEPSLEEP_INIT(PSO2, SLPSEQ9, 0),
+       DEEPSLEEP_INIT(PSO3, SLPSEQ9, 4),
+       DEEPSLEEP_INIT(PSO4, SLPSEQ10, 0),
+       DEEPSLEEP_INIT(PSO5, SLPSEQ10, 4),
+       DEEPSLEEP_INIT(PSO6, SLPSEQ11, 0),
+       DEEPSLEEP_INIT(PSO7, SLPSEQ11, 4),
+};
+
+#define EXT_PWR_REQ            \
+       (RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL)
+
+static struct mfd_cell rc5t583_subdevs[] = {
+       {.name = "rc5t583-regulator",},
+       {.name = "rc5t583-rtc",      },
+       {.name = "rc5t583-key",      }
+};
+
+int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val)
+{
+       struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+       return regmap_write(rc5t583->regmap, reg, val);
+}
+
+int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val)
+{
+       struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+       unsigned int ival;
+       int ret;
+       ret = regmap_read(rc5t583->regmap, reg, &ival);
+       if (!ret)
+               *val = (uint8_t)ival;
+       return ret;
+}
+
+int rc5t583_set_bits(struct device *dev, unsigned int reg,
+                       unsigned int bit_mask)
+{
+       struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+       return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask);
+}
+
+int rc5t583_clear_bits(struct device *dev, unsigned int reg,
+                       unsigned int bit_mask)
+{
+       struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+       return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0);
+}
+
+int rc5t583_update(struct device *dev, unsigned int reg,
+               unsigned int val, unsigned int mask)
+{
+       struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
+       return regmap_update_bits(rc5t583->regmap, reg, mask, val);
+}
+
+static int __rc5t583_set_ext_pwrreq1_control(struct device *dev,
+       int id, int ext_pwr, int slots)
+{
+       int ret;
+       uint8_t sleepseq_val;
+       unsigned int en_bit;
+       unsigned int slot_bit;
+
+       if (id == RC5T583_DS_DC0) {
+               dev_err(dev, "PWRREQ1 is invalid control for rail %d\n", id);
+               return -EINVAL;
+       }
+
+       en_bit = deepsleep_data[id].ds_pos_bit;
+       slot_bit = en_bit + 1;
+       ret = rc5t583_read(dev, deepsleep_data[id].reg_add, &sleepseq_val);
+       if (ret < 0) {
+               dev_err(dev, "Error in reading reg 0x%x\n",
+                               deepsleep_data[id].reg_add);
+               return ret;
+       }
+
+       sleepseq_val &= ~(0xF << en_bit);
+       sleepseq_val |= BIT(en_bit);
+       sleepseq_val |= ((slots & 0x7) << slot_bit);
+       ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(1));
+       if (ret < 0) {
+               dev_err(dev, "Error in updating the 0x%02x register\n",
+                               RICOH_ONOFFSEL_REG);
+               return ret;
+       }
+
+       ret = rc5t583_write(dev, deepsleep_data[id].reg_add, sleepseq_val);
+       if (ret < 0) {
+               dev_err(dev, "Error in writing reg 0x%x\n",
+                               deepsleep_data[id].reg_add);
+               return ret;
+       }
+
+       if (id == RC5T583_DS_LDO4) {
+               ret = rc5t583_write(dev, RICOH_SWCTL_REG, 0x1);
+               if (ret < 0)
+                       dev_err(dev, "Error in writing reg 0x%x\n",
+                               RICOH_SWCTL_REG);
+       }
+       return ret;
+}
+
+static int __rc5t583_set_ext_pwrreq2_control(struct device *dev,
+       int id, int ext_pwr)
+{
+       int ret;
+
+       if (id != RC5T583_DS_DC0) {
+               dev_err(dev, "PWRREQ2 is invalid control for rail %d\n", id);
+               return -EINVAL;
+       }
+
+       ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(2));
+       if (ret < 0)
+               dev_err(dev, "Error in updating the ONOFFSEL 0x10 register\n");
+       return ret;
+}
+
+int rc5t583_ext_power_req_config(struct device *dev, int ds_id,
+       int ext_pwr_req, int deepsleep_slot_nr)
+{
+       if ((ext_pwr_req & EXT_PWR_REQ) == EXT_PWR_REQ)
+               return -EINVAL;
+
+       if (ext_pwr_req & RC5T583_EXT_PWRREQ1_CONTROL)
+               return __rc5t583_set_ext_pwrreq1_control(dev, ds_id,
+                               ext_pwr_req, deepsleep_slot_nr);
+
+       if (ext_pwr_req & RC5T583_EXT_PWRREQ2_CONTROL)
+               return __rc5t583_set_ext_pwrreq2_control(dev,
+                       ds_id, ext_pwr_req);
+       return 0;
+}
+
+static int rc5t583_clear_ext_power_req(struct rc5t583 *rc5t583,
+       struct rc5t583_platform_data *pdata)
+{
+       int ret;
+       int i;
+       uint8_t on_off_val = 0;
+
+       /*  Clear ONOFFSEL register */
+       if (pdata->enable_shutdown)
+               on_off_val = 0x1;
+
+       ret = rc5t583_write(rc5t583->dev, RICOH_ONOFFSEL_REG, on_off_val);
+       if (ret < 0)
+               dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
+                                       RICOH_ONOFFSEL_REG, ret);
+
+       ret = rc5t583_write(rc5t583->dev, RICOH_SWCTL_REG, 0x0);
+       if (ret < 0)
+               dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
+                                       RICOH_SWCTL_REG, ret);
+
+       /* Clear sleep sequence register */
+       for (i = RC5T583_SLPSEQ1; i <= RC5T583_SLPSEQ11; ++i) {
+               ret = rc5t583_write(rc5t583->dev, i, 0x0);
+               if (ret < 0)
+                       dev_warn(rc5t583->dev,
+                               "Error in writing reg 0x%02x error: %d\n",
+                               i, ret);
+       }
+       return 0;
+}
+
+static bool volatile_reg(struct device *dev, unsigned int reg)
+{
+       /* Enable caching in interrupt registers */
+       switch (reg) {
+       case RC5T583_INT_EN_SYS1:
+       case RC5T583_INT_EN_SYS2:
+       case RC5T583_INT_EN_DCDC:
+       case RC5T583_INT_EN_RTC:
+       case RC5T583_INT_EN_ADC1:
+       case RC5T583_INT_EN_ADC2:
+       case RC5T583_INT_EN_ADC3:
+       case RC5T583_GPIO_GPEDGE1:
+       case RC5T583_GPIO_GPEDGE2:
+       case RC5T583_GPIO_EN_INT:
+               return false;
+
+       case RC5T583_GPIO_MON_IOIN:
+               /* This is gpio input register */
+               return true;
+
+       default:
+               /* Enable caching in gpio registers */
+               if ((reg >= RC5T583_GPIO_IOSEL) &&
+                               (reg <= RC5T583_GPIO_GPOFUNC))
+                       return false;
+
+               /* Enable caching in sleep seq registers */
+               if ((reg >= RC5T583_SLPSEQ1) && (reg <= RC5T583_SLPSEQ11))
+                       return false;
+
+               /* Enable caching of regulator registers */
+               if ((reg >= RC5T583_REG_DC0CTL) && (reg <= RC5T583_REG_SR3CTL))
+                       return false;
+               if ((reg >= RC5T583_REG_LDOEN1) &&
+                                       (reg <= RC5T583_REG_LDO9DAC_DS))
+                       return false;
+
+               break;
+       }
+
+       return true;
+}
+
+static const struct regmap_config rc5t583_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .volatile_reg = volatile_reg,
+       .max_register = RC5T583_MAX_REGS,
+       .num_reg_defaults_raw = RC5T583_MAX_REGS,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
+                             const struct i2c_device_id *id)
+{
+       struct rc5t583 *rc5t583;
+       struct rc5t583_platform_data *pdata = i2c->dev.platform_data;
+       int ret;
+       bool irq_init_success = false;
+
+       if (!pdata) {
+               dev_err(&i2c->dev, "Err: Platform data not found\n");
+               return -EINVAL;
+       }
+
+       rc5t583 = devm_kzalloc(&i2c->dev, sizeof(struct rc5t583), GFP_KERNEL);
+       if (!rc5t583) {
+               dev_err(&i2c->dev, "Memory allocation failed\n");
+               return -ENOMEM;
+       }
+
+       rc5t583->dev = &i2c->dev;
+       i2c_set_clientdata(i2c, rc5t583);
+
+       rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
+       if (IS_ERR(rc5t583->regmap)) {
+               ret = PTR_ERR(rc5t583->regmap);
+               dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = rc5t583_clear_ext_power_req(rc5t583, pdata);
+       if (ret < 0)
+               goto err_irq_init;
+
+       if (i2c->irq) {
+               ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base);
+               /* Still continue with waring if irq init fails */
+               if (ret)
+                       dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret);
+               else
+                       irq_init_success = true;
+       }
+
+       ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs,
+                       ARRAY_SIZE(rc5t583_subdevs), NULL, 0);
+       if (ret) {
+               dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret);
+               goto err_add_devs;
+       }
+
+       return 0;
+
+err_add_devs:
+       if (irq_init_success)
+               rc5t583_irq_exit(rc5t583);
+err_irq_init:
+       regmap_exit(rc5t583->regmap);
+       return ret;
+}
+
+static int  __devexit rc5t583_i2c_remove(struct i2c_client *i2c)
+{
+       struct rc5t583 *rc5t583 = i2c_get_clientdata(i2c);
+
+       mfd_remove_devices(rc5t583->dev);
+       rc5t583_irq_exit(rc5t583);
+       regmap_exit(rc5t583->regmap);
+       return 0;
+}
+
+static const struct i2c_device_id rc5t583_i2c_id[] = {
+       {.name = "rc5t583", .driver_data = 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, rc5t583_i2c_id);
+
+static struct i2c_driver rc5t583_i2c_driver = {
+       .driver = {
+                  .name = "rc5t583",
+                  .owner = THIS_MODULE,
+                  },
+       .probe = rc5t583_i2c_probe,
+       .remove = __devexit_p(rc5t583_i2c_remove),
+       .id_table = rc5t583_i2c_id,
+};
+
+static int __init rc5t583_i2c_init(void)
+{
+       return i2c_add_driver(&rc5t583_i2c_driver);
+}
+subsys_initcall(rc5t583_i2c_init);
+
+static void __exit rc5t583_i2c_exit(void)
+{
+       i2c_del_driver(&rc5t583_i2c_driver);
+}
+
+module_exit(rc5t583_i2c_exit);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("RICOH RC5T583 power management system device driver");
+MODULE_LICENSE("GPL v2");
index caadabe..48949d9 100644 (file)
 #include <linux/mfd/s5m87xx/s5m-rtc.h>
 #include <linux/regmap.h>
 
-static struct mfd_cell s5m87xx_devs[] = {
+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",
        }, {
@@ -42,7 +62,7 @@ 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);;
+       return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);
 }
 EXPORT_SYMBOL_GPL(s5m_bulk_read);
 
@@ -54,7 +74,7 @@ EXPORT_SYMBOL_GPL(s5m_reg_write);
 
 int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
 {
-       return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
+       return regmap_raw_write(s5m87xx->regmap, reg, buf, count);
 }
 EXPORT_SYMBOL_GPL(s5m_bulk_write);
 
@@ -74,10 +94,10 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
 {
        struct s5m_platform_data *pdata = i2c->dev.platform_data;
        struct s5m87xx_dev *s5m87xx;
-       int ret = 0;
-       int error;
+       int ret;
 
-       s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
+       s5m87xx = devm_kzalloc(&i2c->dev, sizeof(struct s5m87xx_dev),
+                               GFP_KERNEL);
        if (s5m87xx == NULL)
                return -ENOMEM;
 
@@ -96,9 +116,9 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
 
        s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
        if (IS_ERR(s5m87xx->regmap)) {
-               error = PTR_ERR(s5m87xx->regmap);
+               ret = PTR_ERR(s5m87xx->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
-                       error);
+                       ret);
                goto err;
        }
 
@@ -112,9 +132,23 @@ static int s5m87xx_i2c_probe(struct i2c_client *i2c,
 
        pm_runtime_set_active(s5m87xx->dev);
 
-       ret = mfd_add_devices(s5m87xx->dev, -1,
-                               s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
-                               NULL, 0);
+       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;
@@ -126,7 +160,6 @@ err:
        s5m_irq_exit(s5m87xx);
        i2c_unregister_device(s5m87xx->rtc);
        regmap_exit(s5m87xx->regmap);
-       kfree(s5m87xx);
        return ret;
 }
 
@@ -138,7 +171,6 @@ static int s5m87xx_i2c_remove(struct i2c_client *i2c)
        s5m_irq_exit(s5m87xx);
        i2c_unregister_device(s5m87xx->rtc);
        regmap_exit(s5m87xx->regmap);
-       kfree(s5m87xx);
        return 0;
 }
 
index de76dfb..0236676 100644 (file)
@@ -342,7 +342,10 @@ int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
                        s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
                        break;
                default:
-                       break;
+                       dev_err(s5m87xx->dev,
+                               "Unknown device type %d\n",
+                               s5m87xx->device_type);
+                       return -EINVAL;
 
                }
        }
@@ -444,7 +447,9 @@ int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
                }
                break;
        default:
-               break;
+               dev_err(s5m87xx->dev,
+                       "Unknown device type %d\n", s5m87xx->device_type);
+               return -EINVAL;
        }
 
        if (!s5m87xx->ono)
@@ -467,12 +472,15 @@ int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
                                        IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
                break;
        default:
+               ret = -EINVAL;
                break;
        }
 
-       if (ret)
+       if (ret) {
                dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
                        s5m87xx->ono, ret);
+               return ret;
+       }
 
        return 0;
 }
index f4d8611..d927dd4 100644 (file)
@@ -387,14 +387,6 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
 
 EXPORT_SYMBOL_GPL(sm501_unit_power);
 
-
-/* Perform a rounded division. */
-static long sm501fb_round_div(long num, long denom)
-{
-        /* n / d + 1 / 2 = (2n + d) / 2d */
-        return (2 * num + denom) / (2 * denom);
-}
-
 /* clock value structure. */
 struct sm501_clock {
        unsigned long mclk;
@@ -428,7 +420,7 @@ static int sm501_calc_clock(unsigned long freq,
                /* try all 8 shift values.*/
                for (shift = 0; shift < 8; shift++) {
                        /* Calculate difference to requested clock */
-                       diff = sm501fb_round_div(mclk, divider << shift) - freq;
+                       diff = DIV_ROUND_CLOSEST(mclk, divider << shift) - freq;
                        if (diff < 0)
                                diff = -diff;
 
index e07947e..2dd8d49 100644 (file)
@@ -298,6 +298,11 @@ static struct mfd_cell stmpe_gpio_cell = {
        .num_resources  = ARRAY_SIZE(stmpe_gpio_resources),
 };
 
+static struct mfd_cell stmpe_gpio_cell_noirq = {
+       .name           = "stmpe-gpio",
+       /* gpio cell resources consist of an irq only so no resources here */
+};
+
 /*
  * Keypad (1601, 2401, 2403)
  */
@@ -346,6 +351,13 @@ static struct stmpe_variant_block stmpe801_blocks[] = {
        },
 };
 
+static struct stmpe_variant_block stmpe801_blocks_noirq[] = {
+       {
+               .cell   = &stmpe_gpio_cell_noirq,
+               .block  = STMPE_BLOCK_GPIO,
+       },
+};
+
 static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
                           bool enable)
 {
@@ -367,6 +379,17 @@ static struct stmpe_variant_info stmpe801 = {
        .enable         = stmpe801_enable,
 };
 
+static struct stmpe_variant_info stmpe801_noirq = {
+       .name           = "stmpe801",
+       .id_val         = STMPE801_ID,
+       .id_mask        = 0xffff,
+       .num_gpios      = 8,
+       .regs           = stmpe801_regs,
+       .blocks         = stmpe801_blocks_noirq,
+       .num_blocks     = ARRAY_SIZE(stmpe801_blocks_noirq),
+       .enable         = stmpe801_enable,
+};
+
 /*
  * Touchscreen (STMPE811 or STMPE610)
  */
@@ -712,7 +735,7 @@ static struct stmpe_variant_info stmpe2403 = {
        .enable_autosleep       = stmpe1601_autosleep, /* same as stmpe1601 */
 };
 
-static struct stmpe_variant_info *stmpe_variant_info[] = {
+static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = {
        [STMPE610]      = &stmpe610,
        [STMPE801]      = &stmpe801,
        [STMPE811]      = &stmpe811,
@@ -721,6 +744,16 @@ static struct stmpe_variant_info *stmpe_variant_info[] = {
        [STMPE2403]     = &stmpe2403,
 };
 
+/*
+ * These devices can be connected in a 'no-irq' configuration - the irq pin
+ * is not used and the device cannot interrupt the CPU. Here we only list
+ * devices which support this configuration - the driver will fail probing
+ * for any devices not listed here which are configured in this way.
+ */
+static struct stmpe_variant_info *stmpe_noirq_variant_info[STMPE_NBR_PARTS] = {
+       [STMPE801]      = &stmpe801_noirq,
+};
+
 static irqreturn_t stmpe_irq(int irq, void *data)
 {
        struct stmpe *stmpe = data;
@@ -864,7 +897,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
        unsigned int irq_trigger = stmpe->pdata->irq_trigger;
        int autosleep_timeout = stmpe->pdata->autosleep_timeout;
        struct stmpe_variant_info *variant = stmpe->variant;
-       u8 icr;
+       u8 icr = 0;
        unsigned int id;
        u8 data[2];
        int ret;
@@ -887,31 +920,33 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
        if (ret)
                return ret;
 
-       if (id == STMPE801_ID)
-               icr = STMPE801_REG_SYS_CTRL_INT_EN;
-       else
-               icr = STMPE_ICR_LSB_GIM;
-
-       /* STMPE801 doesn't support Edge interrupts */
-       if (id != STMPE801_ID) {
-               if (irq_trigger == IRQF_TRIGGER_FALLING ||
-                               irq_trigger == IRQF_TRIGGER_RISING)
-                       icr |= STMPE_ICR_LSB_EDGE;
-       }
-
-       if (irq_trigger == IRQF_TRIGGER_RISING ||
-                       irq_trigger == IRQF_TRIGGER_HIGH) {
+       if (stmpe->irq >= 0) {
                if (id == STMPE801_ID)
-                       icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+                       icr = STMPE801_REG_SYS_CTRL_INT_EN;
                else
-                       icr |= STMPE_ICR_LSB_HIGH;
-       }
+                       icr = STMPE_ICR_LSB_GIM;
 
-       if (stmpe->pdata->irq_invert_polarity) {
-               if (id == STMPE801_ID)
-                       icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
-               else
-                       icr ^= STMPE_ICR_LSB_HIGH;
+               /* STMPE801 doesn't support Edge interrupts */
+               if (id != STMPE801_ID) {
+                       if (irq_trigger == IRQF_TRIGGER_FALLING ||
+                                       irq_trigger == IRQF_TRIGGER_RISING)
+                               icr |= STMPE_ICR_LSB_EDGE;
+               }
+
+               if (irq_trigger == IRQF_TRIGGER_RISING ||
+                               irq_trigger == IRQF_TRIGGER_HIGH) {
+                       if (id == STMPE801_ID)
+                               icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+                       else
+                               icr |= STMPE_ICR_LSB_HIGH;
+               }
+
+               if (stmpe->pdata->irq_invert_polarity) {
+                       if (id == STMPE801_ID)
+                               icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
+                       else
+                               icr ^= STMPE_ICR_LSB_HIGH;
+               }
        }
 
        if (stmpe->pdata->autosleep) {
@@ -1001,19 +1036,38 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
                stmpe->irq = ci->irq;
        }
 
+       if (stmpe->irq < 0) {
+               /* use alternate variant info for no-irq mode, if supported */
+               dev_info(stmpe->dev,
+                       "%s configured in no-irq mode by platform data\n",
+                       stmpe->variant->name);
+               if (!stmpe_noirq_variant_info[stmpe->partnum]) {
+                       dev_err(stmpe->dev,
+                               "%s does not support no-irq mode!\n",
+                               stmpe->variant->name);
+                       ret = -ENODEV;
+                       goto free_gpio;
+               }
+               stmpe->variant = stmpe_noirq_variant_info[stmpe->partnum];
+       }
+
        ret = stmpe_chip_init(stmpe);
        if (ret)
                goto free_gpio;
 
-       ret = stmpe_irq_init(stmpe);
-       if (ret)
-               goto free_gpio;
+       if (stmpe->irq >= 0) {
+               ret = stmpe_irq_init(stmpe);
+               if (ret)
+                       goto free_gpio;
 
-       ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
-                       pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
-       if (ret) {
-               dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
-               goto out_removeirq;
+               ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
+                               pdata->irq_trigger | IRQF_ONESHOT,
+                               "stmpe", stmpe);
+               if (ret) {
+                       dev_err(stmpe->dev, "failed to request IRQ: %d\n",
+                                       ret);
+                       goto out_removeirq;
+               }
        }
 
        ret = stmpe_devices_init(stmpe);
@@ -1026,9 +1080,11 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
 
 out_removedevs:
        mfd_remove_devices(stmpe->dev);
-       free_irq(stmpe->irq, stmpe);
+       if (stmpe->irq >= 0)
+               free_irq(stmpe->irq, stmpe);
 out_removeirq:
-       stmpe_irq_remove(stmpe);
+       if (stmpe->irq >= 0)
+               stmpe_irq_remove(stmpe);
 free_gpio:
        if (pdata->irq_over_gpio)
                gpio_free(pdata->irq_gpio);
@@ -1041,8 +1097,10 @@ int stmpe_remove(struct stmpe *stmpe)
 {
        mfd_remove_devices(stmpe->dev);
 
-       free_irq(stmpe->irq, stmpe);
-       stmpe_irq_remove(stmpe);
+       if (stmpe->irq >= 0) {
+               free_irq(stmpe->irq, stmpe);
+               stmpe_irq_remove(stmpe);
+       }
 
        if (stmpe->pdata->irq_over_gpio)
                gpio_free(stmpe->pdata->irq_gpio);
@@ -1057,7 +1115,7 @@ static int stmpe_suspend(struct device *dev)
 {
        struct stmpe *stmpe = dev_get_drvdata(dev);
 
-       if (device_may_wakeup(dev))
+       if (stmpe->irq >= 0 && device_may_wakeup(dev))
                enable_irq_wake(stmpe->irq);
 
        return 0;
@@ -1067,7 +1125,7 @@ static int stmpe_resume(struct device *dev)
 {
        struct stmpe *stmpe = dev_get_drvdata(dev);
 
-       if (device_may_wakeup(dev))
+       if (stmpe->irq >= 0 && device_may_wakeup(dev))
                disable_irq_wake(stmpe->irq);
 
        return 0;
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c
new file mode 100644 (file)
index 0000000..a66d4df
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Core driver for TI TPS65090 PMIC family
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+
+ * 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65090.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+
+#define NUM_INT_REG 2
+#define TOTAL_NUM_REG 0x18
+
+/* interrupt status registers */
+#define TPS65090_INT_STS       0x0
+#define TPS65090_INT_STS2      0x1
+
+/* interrupt mask registers */
+#define TPS65090_INT_MSK       0x2
+#define TPS65090_INT_MSK2      0x3
+
+struct tps65090_irq_data {
+       u8              mask_reg;
+       u8              mask_pos;
+};
+
+#define TPS65090_IRQ(_reg, _mask_pos)          \
+       {                                       \
+               .mask_reg       = (_reg),       \
+               .mask_pos       = (_mask_pos),  \
+       }
+
+static const struct tps65090_irq_data tps65090_irqs[] = {
+       [0]             = TPS65090_IRQ(0, 0),
+       [1]             = TPS65090_IRQ(0, 1),
+       [2]             = TPS65090_IRQ(0, 2),
+       [3]             = TPS65090_IRQ(0, 3),
+       [4]             = TPS65090_IRQ(0, 4),
+       [5]             = TPS65090_IRQ(0, 5),
+       [6]             = TPS65090_IRQ(0, 6),
+       [7]             = TPS65090_IRQ(0, 7),
+       [8]             = TPS65090_IRQ(1, 0),
+       [9]             = TPS65090_IRQ(1, 1),
+       [10]            = TPS65090_IRQ(1, 2),
+       [11]            = TPS65090_IRQ(1, 3),
+       [12]            = TPS65090_IRQ(1, 4),
+       [13]            = TPS65090_IRQ(1, 5),
+       [14]            = TPS65090_IRQ(1, 6),
+       [15]            = TPS65090_IRQ(1, 7),
+};
+
+static struct mfd_cell tps65090s[] = {
+       {
+               .name = "tps65910-pmic",
+       },
+       {
+               .name = "tps65910-regulator",
+       },
+};
+
+struct tps65090 {
+       struct mutex            lock;
+       struct device           *dev;
+       struct i2c_client       *client;
+       struct regmap           *rmap;
+       struct irq_chip         irq_chip;
+       struct mutex            irq_lock;
+       int                     irq_base;
+       unsigned int            id;
+};
+
+int tps65090_write(struct device *dev, int reg, uint8_t val)
+{
+       struct tps65090 *tps = dev_get_drvdata(dev);
+       return regmap_write(tps->rmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65090_write);
+
+int tps65090_read(struct device *dev, int reg, uint8_t *val)
+{
+       struct tps65090 *tps = dev_get_drvdata(dev);
+       unsigned int temp_val;
+       int ret;
+       ret = regmap_read(tps->rmap, reg, &temp_val);
+       if (!ret)
+               *val = temp_val;
+       return ret;
+}
+EXPORT_SYMBOL_GPL(tps65090_read);
+
+int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num)
+{
+       struct tps65090 *tps = dev_get_drvdata(dev);
+       return regmap_update_bits(tps->rmap, reg, BIT(bit_num), ~0u);
+}
+EXPORT_SYMBOL_GPL(tps65090_set_bits);
+
+int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num)
+{
+       struct tps65090 *tps = dev_get_drvdata(dev);
+       return regmap_update_bits(tps->rmap, reg, BIT(bit_num), 0u);
+}
+EXPORT_SYMBOL_GPL(tps65090_clr_bits);
+
+static void tps65090_irq_lock(struct irq_data *data)
+{
+       struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&tps65090->irq_lock);
+}
+
+static void tps65090_irq_mask(struct irq_data *irq_data)
+{
+       struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->hwirq;
+       const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
+
+       tps65090_set_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+               data->mask_pos);
+}
+
+static void tps65090_irq_unmask(struct irq_data *irq_data)
+{
+       struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
+       unsigned int __irq = irq_data->irq - tps65090->irq_base;
+       const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
+
+       tps65090_clr_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+               data->mask_pos);
+}
+
+static void tps65090_irq_sync_unlock(struct irq_data *data)
+{
+       struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
+
+       mutex_unlock(&tps65090->irq_lock);
+}
+
+static irqreturn_t tps65090_irq(int irq, void *data)
+{
+       struct tps65090 *tps65090 = data;
+       int ret = 0;
+       u8 status, mask;
+       unsigned long int acks = 0;
+       int i;
+
+       for (i = 0; i < NUM_INT_REG; i++) {
+               ret = tps65090_read(tps65090->dev, TPS65090_INT_MSK + i, &mask);
+               if (ret < 0) {
+                       dev_err(tps65090->dev,
+                               "failed to read mask reg [addr:%d]\n",
+                               TPS65090_INT_MSK + i);
+                       return IRQ_NONE;
+               }
+               ret = tps65090_read(tps65090->dev, TPS65090_INT_STS + i,
+                       &status);
+               if (ret < 0) {
+                       dev_err(tps65090->dev,
+                               "failed to read status reg [addr:%d]\n",
+                                TPS65090_INT_STS + i);
+                       return IRQ_NONE;
+               }
+               if (status) {
+                       /* Ack only those interrupts which are not masked */
+                       status &= (~mask);
+                       ret = tps65090_write(tps65090->dev,
+                                       TPS65090_INT_STS + i, status);
+                       if (ret < 0) {
+                               dev_err(tps65090->dev,
+                                       "failed to write interrupt status\n");
+                               return IRQ_NONE;
+                       }
+                       acks |= (status << (i * 8));
+               }
+       }
+
+       for_each_set_bit(i, &acks, ARRAY_SIZE(tps65090_irqs))
+               handle_nested_irq(tps65090->irq_base + i);
+       return acks ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq,
+       int irq_base)
+{
+       int i, ret;
+
+       if (!irq_base) {
+               dev_err(tps65090->dev, "IRQ base not set\n");
+               return -EINVAL;
+       }
+
+       mutex_init(&tps65090->irq_lock);
+
+       for (i = 0; i < NUM_INT_REG; i++)
+               tps65090_write(tps65090->dev, TPS65090_INT_MSK + i, 0xFF);
+
+       for (i = 0; i < NUM_INT_REG; i++)
+               tps65090_write(tps65090->dev, TPS65090_INT_STS + i, 0xff);
+
+       tps65090->irq_base = irq_base;
+       tps65090->irq_chip.name = "tps65090";
+       tps65090->irq_chip.irq_mask = tps65090_irq_mask;
+       tps65090->irq_chip.irq_unmask = tps65090_irq_unmask;
+       tps65090->irq_chip.irq_bus_lock = tps65090_irq_lock;
+       tps65090->irq_chip.irq_bus_sync_unlock = tps65090_irq_sync_unlock;
+
+       for (i = 0; i < ARRAY_SIZE(tps65090_irqs); i++) {
+               int __irq = i + tps65090->irq_base;
+               irq_set_chip_data(__irq, tps65090);
+               irq_set_chip_and_handler(__irq, &tps65090->irq_chip,
+                                        handle_simple_irq);
+               irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+               set_irq_flags(__irq, IRQF_VALID);
+#endif
+       }
+
+       ret = request_threaded_irq(irq, NULL, tps65090_irq, IRQF_ONESHOT,
+                               "tps65090", tps65090);
+       if (!ret) {
+               device_init_wakeup(tps65090->dev, 1);
+               enable_irq_wake(irq);
+       }
+
+       return ret;
+}
+
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS))
+               return true;
+       else
+               return false;
+}
+
+static const struct regmap_config tps65090_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = TOTAL_NUM_REG,
+       .num_reg_defaults_raw = TOTAL_NUM_REG,
+       .cache_type = REGCACHE_RBTREE,
+       .volatile_reg = is_volatile_reg,
+};
+
+static int __devinit tps65090_i2c_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct tps65090_platform_data *pdata = client->dev.platform_data;
+       struct tps65090 *tps65090;
+       int ret;
+
+       if (!pdata) {
+               dev_err(&client->dev, "tps65090 requires platform data\n");
+               return -EINVAL;
+       }
+
+       tps65090 = devm_kzalloc(&client->dev, sizeof(struct tps65090),
+               GFP_KERNEL);
+       if (tps65090 == NULL)
+               return -ENOMEM;
+
+       tps65090->client = client;
+       tps65090->dev = &client->dev;
+       i2c_set_clientdata(client, tps65090);
+
+       mutex_init(&tps65090->lock);
+
+       if (client->irq) {
+               ret = tps65090_irq_init(tps65090, client->irq, pdata->irq_base);
+               if (ret) {
+                       dev_err(&client->dev, "IRQ init failed with err: %d\n",
+                               ret);
+                       goto err_exit;
+               }
+       }
+
+       tps65090->rmap = regmap_init_i2c(tps65090->client,
+               &tps65090_regmap_config);
+       if (IS_ERR(tps65090->rmap)) {
+               dev_err(&client->dev, "regmap_init failed with err: %ld\n",
+                       PTR_ERR(tps65090->rmap));
+               goto err_irq_exit;
+       };
+
+       ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
+               ARRAY_SIZE(tps65090s), NULL, 0);
+       if (ret) {
+               dev_err(&client->dev, "add mfd devices failed with err: %d\n",
+                       ret);
+               goto err_regmap_exit;
+       }
+
+       return 0;
+
+err_regmap_exit:
+       regmap_exit(tps65090->rmap);
+
+err_irq_exit:
+       if (client->irq)
+               free_irq(client->irq, tps65090);
+err_exit:
+       return ret;
+}
+
+static int __devexit tps65090_i2c_remove(struct i2c_client *client)
+{
+       struct tps65090 *tps65090 = i2c_get_clientdata(client);
+
+       mfd_remove_devices(tps65090->dev);
+       regmap_exit(tps65090->rmap);
+       if (client->irq)
+               free_irq(client->irq, tps65090);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int tps65090_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+       if (client->irq)
+               disable_irq(client->irq);
+       return 0;
+}
+
+static int tps65090_i2c_resume(struct i2c_client *client)
+{
+       if (client->irq)
+               enable_irq(client->irq);
+       return 0;
+}
+#endif
+
+static const struct i2c_device_id tps65090_id_table[] = {
+       { "tps65090", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, tps65090_id_table);
+
+static struct i2c_driver tps65090_driver = {
+       .driver = {
+               .name   = "tps65090",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = tps65090_i2c_probe,
+       .remove         = __devexit_p(tps65090_i2c_remove),
+#ifdef CONFIG_PM
+       .suspend        = tps65090_i2c_suspend,
+       .resume         = tps65090_i2c_resume,
+#endif
+       .id_table       = tps65090_id_table,
+};
+
+static int __init tps65090_init(void)
+{
+       return i2c_add_driver(&tps65090_driver);
+}
+subsys_initcall(tps65090_init);
+
+static void __exit tps65090_exit(void)
+{
+       i2c_del_driver(&tps65090_driver);
+}
+module_exit(tps65090_exit);
+
+MODULE_DESCRIPTION("TPS65090 core driver");
+MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
new file mode 100644 (file)
index 0000000..f7d854e
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * tps65217.c
+ *
+ * TPS65217 chip family multi-function driver
+ *
+ * Copyright (C) 2011 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/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65217.h>
+
+/**
+ * tps65217_reg_read: Read a single tps65217 register.
+ *
+ * @tps: Device to read from.
+ * @reg: Register to read.
+ * @val: Contians the value
+ */
+int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
+                       unsigned int *val)
+{
+       return regmap_read(tps->regmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65217_reg_read);
+
+/**
+ * tps65217_reg_write: Write a single tps65217 register.
+ *
+ * @tps65217: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
+                       unsigned int val, unsigned int level)
+{
+       int ret;
+       unsigned int xor_reg_val;
+
+       switch (level) {
+       case TPS65217_PROTECT_NONE:
+               return regmap_write(tps->regmap, reg, val);
+       case TPS65217_PROTECT_L1:
+               xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
+               ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+                                                       xor_reg_val);
+               if (ret < 0)
+                       return ret;
+
+               return regmap_write(tps->regmap, reg, val);
+       case TPS65217_PROTECT_L2:
+               xor_reg_val = reg ^ TPS65217_PASSWORD_REGS_UNLOCK;
+               ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+                                                       xor_reg_val);
+               if (ret < 0)
+                       return ret;
+               ret = regmap_write(tps->regmap, reg, val);
+               if (ret < 0)
+                       return ret;
+               ret = regmap_write(tps->regmap, TPS65217_REG_PASSWORD,
+                                                       xor_reg_val);
+               if (ret < 0)
+                       return ret;
+               return regmap_write(tps->regmap, reg, val);
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL_GPL(tps65217_reg_write);
+
+/**
+ * tps65217_update_bits: Modify bits w.r.t mask, val and level.
+ *
+ * @tps65217: Device to write to.
+ * @reg: Register to read-write to.
+ * @mask: Mask.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65217_update_bits(struct tps65217 *tps, unsigned int reg,
+               unsigned int mask, unsigned int val, unsigned int level)
+{
+       int ret;
+       unsigned int data;
+
+       ret = tps65217_reg_read(tps, reg, &data);
+       if (ret) {
+               dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
+               return ret;
+       }
+
+       data &= ~mask;
+       data |= val & mask;
+
+       ret = tps65217_reg_write(tps, reg, data, level);
+       if (ret)
+               dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
+
+       return ret;
+}
+
+int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
+               unsigned int mask, unsigned int val, unsigned int level)
+{
+       return tps65217_update_bits(tps, reg, mask, val, level);
+}
+EXPORT_SYMBOL_GPL(tps65217_set_bits);
+
+int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
+               unsigned int mask, unsigned int level)
+{
+       return tps65217_update_bits(tps, reg, mask, 0, level);
+}
+EXPORT_SYMBOL_GPL(tps65217_clear_bits);
+
+static struct regmap_config tps65217_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int __devinit tps65217_probe(struct i2c_client *client,
+                               const struct i2c_device_id *ids)
+{
+       struct tps65217 *tps;
+       struct tps65217_board *pdata = client->dev.platform_data;
+       int i, ret;
+       unsigned int version;
+
+       tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+       if (!tps)
+               return -ENOMEM;
+
+       tps->pdata = pdata;
+       tps->regmap = regmap_init_i2c(client, &tps65217_regmap_config);
+       if (IS_ERR(tps->regmap)) {
+               ret = PTR_ERR(tps->regmap);
+               dev_err(tps->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(client, tps);
+       tps->dev = &client->dev;
+
+       ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
+       if (ret < 0) {
+               dev_err(tps->dev, "Failed to read revision"
+                                       " register: %d\n", ret);
+               goto err_regmap;
+       }
+
+       dev_info(tps->dev, "TPS65217 ID %#x version 1.%d\n",
+                       (version & TPS65217_CHIPID_CHIP_MASK) >> 4,
+                       version & TPS65217_CHIPID_REV_MASK);
+
+       for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
+               struct platform_device *pdev;
+
+               pdev = platform_device_alloc("tps65217-pmic", i);
+               if (!pdev) {
+                       dev_err(tps->dev, "Cannot create regulator %d\n", i);
+                       continue;
+               }
+
+               pdev->dev.parent = tps->dev;
+               platform_device_add_data(pdev, &pdata->tps65217_init_data[i],
+                                       sizeof(pdata->tps65217_init_data[i]));
+               tps->regulator_pdev[i] = pdev;
+
+               platform_device_add(pdev);
+       }
+
+       return 0;
+
+err_regmap:
+       regmap_exit(tps->regmap);
+
+       return ret;
+}
+
+static int __devexit tps65217_remove(struct i2c_client *client)
+{
+       struct tps65217 *tps = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
+               platform_device_unregister(tps->regulator_pdev[i]);
+
+       regmap_exit(tps->regmap);
+
+       return 0;
+}
+
+static const struct i2c_device_id tps65217_id_table[] = {
+       {"tps65217", 0xF0},
+       {/* end of list */}
+};
+MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
+
+static struct i2c_driver tps65217_driver = {
+       .driver         = {
+               .name   = "tps65217",
+       },
+       .id_table       = tps65217_id_table,
+       .probe          = tps65217_probe,
+       .remove         = __devexit_p(tps65217_remove),
+};
+
+static int __init tps65217_init(void)
+{
+       return i2c_add_driver(&tps65217_driver);
+}
+subsys_initcall(tps65217_init);
+
+static void __exit tps65217_exit(void)
+{
+       i2c_del_driver(&tps65217_driver);
+}
+module_exit(tps65217_exit);
+
+MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
+MODULE_DESCRIPTION("TPS65217 chip family multi-function driver");
+MODULE_LICENSE("GPL v2");
index 95c0d79..c9ed5c0 100644 (file)
@@ -145,12 +145,23 @@ static void tps65910_irq_disable(struct irq_data *data)
        tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable)
+{
+       struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+       return irq_set_irq_wake(tps65910->chip_irq, enable);
+}
+#else
+#define tps65910_irq_set_wake NULL
+#endif
+
 static struct irq_chip tps65910_irq_chip = {
        .name = "tps65910",
        .irq_bus_lock = tps65910_irq_lock,
        .irq_bus_sync_unlock = tps65910_irq_sync_unlock,
        .irq_disable = tps65910_irq_disable,
        .irq_enable = tps65910_irq_enable,
+       .irq_set_wake = tps65910_irq_set_wake,
 };
 
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
index 4392f6b..bf2b25e 100644 (file)
 #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/gpio.h>
 #include <linux/mfd/core.h>
+#include <linux/regmap.h>
 #include <linux/mfd/tps65910.h>
 
 static struct mfd_cell tps65910s[] = {
@@ -38,99 +40,56 @@ static struct mfd_cell tps65910s[] = {
 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
                                  int bytes, void *dest)
 {
-       struct i2c_client *i2c = tps65910->i2c_client;
-       struct i2c_msg xfer[2];
-       int ret;
-
-       /* Write register */
-       xfer[0].addr = i2c->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 1;
-       xfer[0].buf = &reg;
-
-       /* Read data */
-       xfer[1].addr = i2c->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = bytes;
-       xfer[1].buf = dest;
-
-       ret = i2c_transfer(i2c->adapter, xfer, 2);
-       if (ret == 2)
-               ret = 0;
-       else if (ret >= 0)
-               ret = -EIO;
-
-       return ret;
+       return regmap_bulk_read(tps65910->regmap, reg, dest, bytes);
 }
 
 static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
-                                  int bytes, void *src)
+                                 int bytes, void *src)
 {
-       struct i2c_client *i2c = tps65910->i2c_client;
-       /* we add 1 byte for device register */
-       u8 msg[TPS65910_MAX_REGISTER + 1];
-       int ret;
-
-       if (bytes > TPS65910_MAX_REGISTER)
-               return -EINVAL;
-
-       msg[0] = reg;
-       memcpy(&msg[1], src, bytes);
-
-       ret = i2c_master_send(i2c, msg, bytes + 1);
-       if (ret < 0)
-               return ret;
-       if (ret != bytes + 1)
-               return -EIO;
-       return 0;
+       return regmap_bulk_write(tps65910->regmap, reg, src, bytes);
 }
 
 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
-       u8 data;
-       int err;
-
-       mutex_lock(&tps65910->io_mutex);
-       err = tps65910_i2c_read(tps65910, reg, 1, &data);
-       if (err) {
-               dev_err(tps65910->dev, "read from reg %x failed\n", reg);
-               goto out;
-       }
-
-       data |= mask;
-       err = tps65910_i2c_write(tps65910, reg, 1, &data);
-       if (err)
-               dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
-       mutex_unlock(&tps65910->io_mutex);
-       return err;
+       return regmap_update_bits(tps65910->regmap, reg, mask, mask);
 }
 EXPORT_SYMBOL_GPL(tps65910_set_bits);
 
 int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
-       u8 data;
-       int err;
-
-       mutex_lock(&tps65910->io_mutex);
-       err = tps65910_i2c_read(tps65910, reg, 1, &data);
-       if (err) {
-               dev_err(tps65910->dev, "read from reg %x failed\n", reg);
-               goto out;
-       }
-
-       data &= ~mask;
-       err = tps65910_i2c_write(tps65910, reg, 1, &data);
-       if (err)
-               dev_err(tps65910->dev, "write to reg %x failed\n", reg);
-
-out:
-       mutex_unlock(&tps65910->io_mutex);
-       return err;
+       return regmap_update_bits(tps65910->regmap, reg, mask, 0);
 }
 EXPORT_SYMBOL_GPL(tps65910_clear_bits);
 
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       struct tps65910 *tps65910 = dev_get_drvdata(dev);
+
+       /*
+        * Caching all regulator registers.
+        * All regualator register address range is same for
+        * TPS65910 and TPS65911
+        */
+       if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) {
+               /* Check for non-existing register */
+               if (tps65910_chip_id(tps65910) == TPS65910)
+                       if ((reg == TPS65911_VDDCTRL_OP) ||
+                               (reg == TPS65911_VDDCTRL_SR))
+                               return true;
+               return false;
+       }
+       return true;
+}
+
+static const struct regmap_config tps65910_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .volatile_reg = is_volatile_reg,
+       .max_register = TPS65910_MAX_REGISTER,
+       .num_reg_defaults_raw = TPS65910_MAX_REGISTER,
+       .cache_type = REGCACHE_RBTREE,
+};
+
 static int tps65910_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -161,6 +120,13 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        tps65910->write = tps65910_i2c_write;
        mutex_init(&tps65910->io_mutex);
 
+       tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config);
+       if (IS_ERR(tps65910->regmap)) {
+               ret = PTR_ERR(tps65910->regmap);
+               dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+               goto regmap_err;
+       }
+
        ret = mfd_add_devices(tps65910->dev, -1,
                              tps65910s, ARRAY_SIZE(tps65910s),
                              NULL, 0);
@@ -178,6 +144,8 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        return ret;
 
 err:
+       regmap_exit(tps65910->regmap);
+regmap_err:
        kfree(tps65910);
        kfree(init_data);
        return ret;
@@ -189,6 +157,7 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
 
        tps65910_irq_exit(tps65910);
        mfd_remove_devices(tps65910->dev);
+       regmap_exit(tps65910->regmap);
        kfree(tps65910);
 
        return 0;
index 806680d..7c2267e 100644 (file)
@@ -46,9 +46,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c/twl.h>
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-#include <plat/cpu.h>
-#endif
+#include "twl-core.h"
 
 /*
  * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
 #define twl_has_watchdog()        false
 #endif
 
-#if defined(CONFIG_MFD_TWL4030_AUDIO) || defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) ||\
-       defined(CONFIG_TWL6040_CORE) || defined(CONFIG_TWL6040_CORE_MODULE)
+#if defined(CONFIG_MFD_TWL4030_AUDIO) || \
+       defined(CONFIG_MFD_TWL4030_AUDIO_MODULE)
 #define twl_has_codec()        true
 #else
 #define twl_has_codec()        false
 #define SUB_CHIP_ID1 1
 #define SUB_CHIP_ID2 2
 #define SUB_CHIP_ID3 3
+#define SUB_CHIP_ID_INVAL 0xff
 
 #define TWL_MODULE_LAST TWL4030_MODULE_LAST
 
-#define TWL4030_NR_IRQS    34 /* core:8, power:8, gpio: 18 */
-#define TWL6030_NR_IRQS    20
-
 /* Base Address defns for twl4030_map[] */
 
 /* subchip/slave 0 - USB ID */
@@ -314,7 +310,7 @@ static struct twl_mapping twl6030_map[] = {
         * so they continue to match the order in this table.
         */
        { SUB_CHIP_ID1, TWL6030_BASEADD_USB },
-       { SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO },
+       { SUB_CHIP_ID_INVAL, TWL6030_BASEADD_AUDIO },
        { SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
        { SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
        { SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
@@ -376,6 +372,11 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
                return -EPERM;
        }
        sid = twl_map[mod_no].sid;
+       if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
+               pr_err("%s: module %d is not part of the pmic\n",
+                      DRIVER_NAME, mod_no);
+               return -EINVAL;
+       }
        twl = &twl_modules[sid];
 
        mutex_lock(&twl->xfer_lock);
@@ -433,6 +434,11 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
                return -EPERM;
        }
        sid = twl_map[mod_no].sid;
+       if (unlikely(sid == SUB_CHIP_ID_INVAL)) {
+               pr_err("%s: module %d is not part of the pmic\n",
+                      DRIVER_NAME, mod_no);
+               return -EINVAL;
+       }
        twl = &twl_modules[sid];
 
        mutex_lock(&twl->xfer_lock);
@@ -663,7 +669,8 @@ add_regulator(int num, struct regulator_init_data *pdata,
  */
 
 static int
-add_children(struct twl4030_platform_data *pdata, unsigned long features)
+add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
+               unsigned long features)
 {
        struct device   *child;
        unsigned sub_chip_id;
@@ -671,7 +678,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
        if (twl_has_gpio() && pdata->gpio) {
                child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
                                pdata->gpio, sizeof(*pdata->gpio),
-                               false, pdata->irq_base + GPIO_INTR_OFFSET, 0);
+                               false, irq_base + GPIO_INTR_OFFSET, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -679,7 +686,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
        if (twl_has_keypad() && pdata->keypad) {
                child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
                                pdata->keypad, sizeof(*pdata->keypad),
-                               true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0);
+                               true, irq_base + KEYPAD_INTR_OFFSET, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -687,7 +694,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
        if (twl_has_madc() && pdata->madc) {
                child = add_child(2, "twl4030_madc",
                                pdata->madc, sizeof(*pdata->madc),
-                               true, pdata->irq_base + MADC_INTR_OFFSET, 0);
+                               true, irq_base + MADC_INTR_OFFSET, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -703,7 +710,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
                child = add_child(sub_chip_id, "twl_rtc",
                                NULL, 0,
-                               true, pdata->irq_base + RTC_INTR_OFFSET, 0);
+                               true, irq_base + RTC_INTR_OFFSET, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -756,8 +763,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                                pdata->usb, sizeof(*pdata->usb),
                                true,
                                /* irq0 = USB_PRES, irq1 = USB */
-                               pdata->irq_base + USB_PRES_INTR_OFFSET,
-                               pdata->irq_base + USB_INTR_OFFSET);
+                               irq_base + USB_PRES_INTR_OFFSET,
+                               irq_base + USB_INTR_OFFSET);
 
                if (IS_ERR(child))
                        return PTR_ERR(child);
@@ -805,8 +812,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                        pdata->usb, sizeof(*pdata->usb),
                        true,
                        /* irq1 = VBUS_PRES, irq0 = USB ID */
-                       pdata->irq_base + USBOTG_INTR_OFFSET,
-                       pdata->irq_base + USB_PRES_INTR_OFFSET);
+                       irq_base + USBOTG_INTR_OFFSET,
+                       irq_base + USB_PRES_INTR_OFFSET);
 
                if (IS_ERR(child))
                        return PTR_ERR(child);
@@ -833,7 +840,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
        if (twl_has_pwrbutton() && twl_class_is_4030()) {
                child = add_child(1, "twl4030_pwrbutton",
-                               NULL, 0, true, pdata->irq_base + 8 + 0, 0);
+                               NULL, 0, true, irq_base + 8 + 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -847,15 +854,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                        return PTR_ERR(child);
        }
 
-       if (twl_has_codec() && pdata->audio && twl_class_is_6030()) {
-               sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-               child = add_child(sub_chip_id, "twl6040",
-                               pdata->audio, sizeof(*pdata->audio),
-                               false, 0, 0);
-               if (IS_ERR(child))
-                       return PTR_ERR(child);
-       }
-
        /* twl4030 regulators */
        if (twl_has_regulator() && twl_class_is_4030()) {
                child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
@@ -1092,8 +1090,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
                child = add_child(3, "twl4030_bci",
                                pdata->bci, sizeof(*pdata->bci), false,
                                /* irq0 = CHG_PRES, irq1 = BCI */
-                               pdata->irq_base + BCI_PRES_INTR_OFFSET,
-                               pdata->irq_base + BCI_INTR_OFFSET);
+                               irq_base + BCI_PRES_INTR_OFFSET,
+                               irq_base + BCI_INTR_OFFSET);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
@@ -1193,26 +1191,24 @@ static void clocks_init(struct device *dev,
 
 /*----------------------------------------------------------------------*/
 
-int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl4030_exit_irq(void);
-int twl4030_init_chip_irq(const char *chip);
-int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
-int twl6030_exit_irq(void);
 
 static int twl_remove(struct i2c_client *client)
 {
-       unsigned i;
+       unsigned i, num_slaves;
        int status;
 
-       if (twl_class_is_4030())
+       if (twl_class_is_4030()) {
                status = twl4030_exit_irq();
-       else
+               num_slaves = TWL_NUM_SLAVES;
+       } else {
                status = twl6030_exit_irq();
+               num_slaves = TWL_NUM_SLAVES - 1;
+       }
 
        if (status < 0)
                return status;
 
-       for (i = 0; i < TWL_NUM_SLAVES; i++) {
+       for (i = 0; i < num_slaves; i++) {
                struct twl_client       *twl = &twl_modules[i];
 
                if (twl->client && twl->client != client)
@@ -1223,20 +1219,15 @@ static int twl_remove(struct i2c_client *client)
        return 0;
 }
 
-/* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
+/* NOTE: This driver only handles a single twl4030/tps659x0 chip */
 static int __devinit
 twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-       int                             status;
-       unsigned                        i;
        struct twl4030_platform_data    *pdata = client->dev.platform_data;
        struct device_node              *node = client->dev.of_node;
-       u8 temp;
-       int ret = 0;
-       int nr_irqs = TWL4030_NR_IRQS;
-
-       if ((id->driver_data) & TWL6030_CLASS)
-               nr_irqs = TWL6030_NR_IRQS;
+       int                             irq_base = 0;
+       int                             status;
+       unsigned                        i, num_slaves;
 
        if (node && !pdata) {
                /*
@@ -1255,17 +1246,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                return -EINVAL;
        }
 
-       status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
-       if (IS_ERR_VALUE(status)) {
-               dev_err(&client->dev, "Fail to allocate IRQ descs\n");
-               return status;
-       }
-
-       pdata->irq_base = status;
-       pdata->irq_end = pdata->irq_base + nr_irqs;
-       irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0,
-                             &irq_domain_simple_ops, NULL);
-
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
                dev_dbg(&client->dev, "can't talk I2C?\n");
                return -EIO;
@@ -1276,13 +1256,23 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                return -EBUSY;
        }
 
-       for (i = 0; i < TWL_NUM_SLAVES; i++) {
-               struct twl_client       *twl = &twl_modules[i];
+       if ((id->driver_data) & TWL6030_CLASS) {
+               twl_id = TWL6030_CLASS_ID;
+               twl_map = &twl6030_map[0];
+               num_slaves = TWL_NUM_SLAVES - 1;
+       } else {
+               twl_id = TWL4030_CLASS_ID;
+               twl_map = &twl4030_map[0];
+               num_slaves = TWL_NUM_SLAVES;
+       }
+
+       for (i = 0; i < num_slaves; i++) {
+               struct twl_client *twl = &twl_modules[i];
 
                twl->address = client->addr + i;
-               if (i == 0)
+               if (i == 0) {
                        twl->client = client;
-               else {
+               } else {
                        twl->client = i2c_new_dummy(client->adapter,
                                        twl->address);
                        if (!twl->client) {
@@ -1294,22 +1284,16 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                }
                mutex_init(&twl->xfer_lock);
        }
+
        inuse = true;
-       if ((id->driver_data) & TWL6030_CLASS) {
-               twl_id = TWL6030_CLASS_ID;
-               twl_map = &twl6030_map[0];
-       } else {
-               twl_id = TWL4030_CLASS_ID;
-               twl_map = &twl4030_map[0];
-       }
 
        /* setup clock framework */
        clocks_init(&client->dev, pdata->clock);
 
        /* read TWL IDCODE Register */
        if (twl_id == TWL4030_CLASS_ID) {
-               ret = twl_read_idcode_register();
-               WARN(ret < 0, "Error: reading twl_idcode register value\n");
+               status = twl_read_idcode_register();
+               WARN(status < 0, "Error: reading twl_idcode register value\n");
        }
 
        /* load power event scripts */
@@ -1317,31 +1301,31 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                twl4030_power_init(pdata->power);
 
        /* Maybe init the T2 Interrupt subsystem */
-       if (client->irq
-                       && pdata->irq_base
-                       && pdata->irq_end > pdata->irq_base) {
+       if (client->irq) {
                if (twl_class_is_4030()) {
                        twl4030_init_chip_irq(id->name);
-                       status = twl4030_init_irq(client->irq, pdata->irq_base,
-                       pdata->irq_end);
+                       irq_base = twl4030_init_irq(&client->dev, client->irq);
                } else {
-                       status = twl6030_init_irq(client->irq, pdata->irq_base,
-                       pdata->irq_end);
+                       irq_base = twl6030_init_irq(&client->dev, client->irq);
                }
 
-               if (status < 0)
+               if (irq_base < 0) {
+                       status = irq_base;
                        goto fail;
+               }
        }
 
-       /* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
+       /*
+        * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
         * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
         * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
         */
-
        if (twl_class_is_4030()) {
+               u8 temp;
+
                twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
                temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
-               I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
+                       I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
                twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
        }
 
@@ -1349,11 +1333,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
        if (node)
                status = of_platform_populate(node, NULL, NULL, &client->dev);
        if (status)
-               status = add_children(pdata, id->driver_data);
+               status = add_children(pdata, irq_base, id->driver_data);
 
 fail:
        if (status < 0)
                twl_remove(client);
+
        return status;
 }
 
index 8c50a55..6ff99dc 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef __TWL_CORE_H__
 #define __TWL_CORE_H__
 
-extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl6030_init_irq(struct device *dev, int irq_num);
 extern int twl6030_exit_irq(void);
-extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
+extern int twl4030_init_irq(struct device *dev, int irq_num);
 extern int twl4030_exit_irq(void);
 extern int twl4030_init_chip_irq(const char *chip);
 
index b69bb51..5d656e8 100644 (file)
  */
 
 #include <linux/init.h>
+#include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
-
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 #include <linux/i2c/twl.h>
 
 #include "twl-core.h"
  *     base + 8  .. base + 15  SIH for PWR_INT
  *     base + 16 .. base + 33  SIH for GPIO
  */
+#define TWL4030_CORE_NR_IRQS   8
+#define TWL4030_PWR_NR_IRQS    8
 
 /* PIH register offsets */
 #define REG_PIH_ISR_P1                 0x01
 #define REG_PIH_ISR_P2                 0x02
 #define REG_PIH_SIR                    0x03    /* for testing */
 
-
 /* Linux could (eventually) use either IRQ line */
 static int irq_line;
 
@@ -111,7 +114,8 @@ static int nr_sih_modules;
 #define TWL4030_MODULE_INT_PWR         TWL4030_MODULE_INT
 
 
-/* Order in this table matches order in PIH_ISR.  That is,
+/*
+ * Order in this table matches order in PIH_ISR.  That is,
  * BIT(n) in PIH_ISR is sih_modules[n].
  */
 /* sih_modules_twl4030 is used both in twl4030 and twl5030 */
@@ -288,7 +292,6 @@ static unsigned twl4030_irq_base;
  */
 static irqreturn_t handle_twl4030_pih(int irq, void *devid)
 {
-       int             module_irq;
        irqreturn_t     ret;
        u8              pih_isr;
 
@@ -299,16 +302,18 @@ static irqreturn_t handle_twl4030_pih(int irq, void *devid)
                return IRQ_NONE;
        }
 
-       /* these handlers deal with the relevant SIH irq status */
-       for (module_irq = twl4030_irq_base;
-                       pih_isr;
-                       pih_isr >>= 1, module_irq++) {
-               if (pih_isr & 0x1)
-                       handle_nested_irq(module_irq);
+       while (pih_isr) {
+               unsigned long   pending = __ffs(pih_isr);
+               unsigned int    irq;
+
+               pih_isr &= ~BIT(pending);
+               irq = pending + twl4030_irq_base;
+               handle_nested_irq(irq);
        }
 
        return IRQ_HANDLED;
 }
+
 /*----------------------------------------------------------------------*/
 
 /*
@@ -337,7 +342,6 @@ static int twl4030_init_sih_modules(unsigned line)
        memset(buf, 0xff, sizeof buf);
        sih = sih_modules;
        for (i = 0; i < nr_sih_modules; i++, sih++) {
-
                /* skip USB -- it's funky */
                if (!sih->bytes_ixr)
                        continue;
@@ -352,7 +356,8 @@ static int twl4030_init_sih_modules(unsigned line)
                        pr_err("twl4030: err %d initializing %s %s\n",
                                        status, sih->name, "IMR");
 
-               /* Maybe disable "exclusive" mode; buffer second pending irq;
+               /*
+                * Maybe disable "exclusive" mode; buffer second pending irq;
                 * set Clear-On-Read (COR) bit.
                 *
                 * NOTE that sometimes COR polarity is documented as being
@@ -382,7 +387,8 @@ static int twl4030_init_sih_modules(unsigned line)
                if (sih->irq_lines <= line)
                        continue;
 
-               /* Clear pending interrupt status.  Either the read was
+               /*
+                * Clear pending interrupt status.  Either the read was
                 * enough, or we need to write those bits.  Repeat, in
                 * case an IRQ is pending (PENDDIS=0) ... that's not
                 * uncommon with PWR_INT.PWRON.
@@ -398,7 +404,8 @@ static int twl4030_init_sih_modules(unsigned line)
                                status = twl_i2c_write(sih->module, buf,
                                        sih->mask[line].isr_offset,
                                        sih->bytes_ixr);
-                       /* else COR=1 means read sufficed.
+                       /*
+                        * else COR=1 means read sufficed.
                         * (for most SIH modules...)
                         */
                }
@@ -410,7 +417,8 @@ static int twl4030_init_sih_modules(unsigned line)
 static inline void activate_irq(int irq)
 {
 #ifdef CONFIG_ARM
-       /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+       /*
+        * ARM requires an extra step to clear IRQ_NOREQUEST, which it
         * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
         */
        set_irq_flags(irq, IRQF_VALID);
@@ -620,33 +628,24 @@ static irqreturn_t handle_twl4030_sih(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static unsigned twl4030_irq_next;
-
-/* returns the first IRQ used by this SIH bank,
- * or negative errno
- */
-int twl4030_sih_setup(int module)
+/* returns the first IRQ used by this SIH bank, or negative errno */
+int twl4030_sih_setup(struct device *dev, int module, int irq_base)
 {
        int                     sih_mod;
        const struct sih        *sih = NULL;
        struct sih_agent        *agent;
        int                     i, irq;
        int                     status = -EINVAL;
-       unsigned                irq_base = twl4030_irq_next;
 
        /* only support modules with standard clear-on-read for now */
-       for (sih_mod = 0, sih = sih_modules;
-                       sih_mod < nr_sih_modules;
+       for (sih_mod = 0, sih = sih_modules; sih_mod < nr_sih_modules;
                        sih_mod++, sih++) {
                if (sih->module == module && sih->set_cor) {
-                       if (!WARN((irq_base + sih->bits) > NR_IRQS,
-                                       "irq %d for %s too big\n",
-                                       irq_base + sih->bits,
-                                       sih->name))
-                               status = 0;
+                       status = 0;
                        break;
                }
        }
+
        if (status < 0)
                return status;
 
@@ -654,8 +653,6 @@ int twl4030_sih_setup(int module)
        if (!agent)
                return -ENOMEM;
 
-       status = 0;
-
        agent->irq_base = irq_base;
        agent->sih = sih;
        agent->imr = ~0;
@@ -671,8 +668,6 @@ int twl4030_sih_setup(int module)
                activate_irq(irq);
        }
 
-       twl4030_irq_next += i;
-
        /* replace generic PIH handler (handle_simple_irq) */
        irq = sih_mod + twl4030_irq_base;
        irq_set_handler_data(irq, agent);
@@ -680,26 +675,43 @@ int twl4030_sih_setup(int module)
        status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
                                      agent->irq_name ?: sih->name, NULL);
 
-       pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name,
-                       irq, irq_base, twl4030_irq_next - 1);
+       dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name,
+                       irq, irq_base, irq_base + i - 1);
 
        return status < 0 ? status : irq_base;
 }
 
 /* FIXME need a call to reverse twl4030_sih_setup() ... */
 
-
 /*----------------------------------------------------------------------*/
 
 /* FIXME pass in which interrupt line we'll use ... */
 #define twl_irq_line   0
 
-int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl4030_init_irq(struct device *dev, int irq_num)
 {
        static struct irq_chip  twl4030_irq_chip;
+       int                     status, i;
+       int                     irq_base, irq_end, nr_irqs;
+       struct                  device_node *node = dev->of_node;
 
-       int                     status;
-       int                     i;
+       /*
+        * TWL core and pwr interrupts must be contiguous because
+        * the hwirqs numbers are defined contiguously from 1 to 15.
+        * Create only one domain for both.
+        */
+       nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;
+
+       irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+       if (IS_ERR_VALUE(irq_base)) {
+               dev_err(dev, "Fail to allocate IRQ descs\n");
+               return irq_base;
+       }
+
+       irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+                             &irq_domain_simple_ops, NULL);
+
+       irq_end = irq_base + TWL4030_CORE_NR_IRQS;
 
        /*
         * Mask and clear all TWL4030 interrupts since initially we do
@@ -711,7 +723,8 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 
        twl4030_irq_base = irq_base;
 
-       /* install an irq handler for each of the SIH modules;
+       /*
+        * Install an irq handler for each of the SIH modules;
         * clone dummy irq_chip since PIH can't *do* anything
         */
        twl4030_irq_chip = dummy_irq_chip;
@@ -725,14 +738,14 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
                irq_set_nested_thread(i, 1);
                activate_irq(i);
        }
-       twl4030_irq_next = i;
-       pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
-                       irq_num, irq_base, twl4030_irq_next - 1);
+
+       dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", "PIH",
+                       irq_num, irq_base, irq_end);
 
        /* ... and the PWR_INT module ... */
-       status = twl4030_sih_setup(TWL4030_MODULE_INT);
+       status = twl4030_sih_setup(dev, TWL4030_MODULE_INT, irq_end);
        if (status < 0) {
-               pr_err("twl4030: sih_setup PWR INT --> %d\n", status);
+               dev_err(dev, "sih_setup PWR INT --> %d\n", status);
                goto fail;
        }
 
@@ -741,11 +754,11 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
                                      IRQF_ONESHOT,
                                      "TWL4030-PIH", NULL);
        if (status < 0) {
-               pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status);
+               dev_err(dev, "could not claim irq%d: %d\n", irq_num, status);
                goto fail_rqirq;
        }
 
-       return status;
+       return irq_base;
 fail_rqirq:
        /* clean up twl4030_sih_setup */
 fail:
index c6b456a..b76902f 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/i2c/twl.h>
 #include <linux/platform_device.h>
 #include <linux/suspend.h>
+#include <linux/of.h>
+#include <linux/irqdomain.h>
 
 #include "twl-core.h"
 
@@ -51,8 +53,8 @@
  *
  * We set up IRQs starting at a platform-specified base. An interrupt map table,
  * specifies mapping between interrupt number and the associated module.
- *
  */
+#define TWL6030_NR_IRQS    20
 
 static int twl6030_interrupt_mapping[24] = {
        PWR_INTR_OFFSET,        /* Bit 0        PWRON                   */
@@ -185,8 +187,17 @@ static int twl6030_irq_thread(void *data)
                        }
                local_irq_enable();
                }
-               ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes,
-                               REG_INT_STS_A, 3); /* clear INT_STS_A */
+
+               /*
+                * NOTE:
+                * Simulation confirms that documentation is wrong w.r.t the
+                * interrupt status clear operation. A single *byte* write to
+                * any one of STS_A to STS_C register results in all three
+                * STS registers being reset. Since it does not matter which
+                * value is written, all three registers are cleared on a
+                * single byte write, so we just use 0x0 to clear.
+                */
+               ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);
                if (ret)
                        pr_warning("twl6030: I2C error in clearing PIH ISR\n");
 
@@ -227,7 +238,7 @@ static inline void activate_irq(int irq)
 #endif
 }
 
-int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
+static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
 {
        if (on)
                atomic_inc(&twl6030_wakeirqs);
@@ -237,11 +248,6 @@ int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
        return 0;
 }
 
-/*----------------------------------------------------------------------*/
-
-static unsigned twl6030_irq_next;
-
-/*----------------------------------------------------------------------*/
 int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
 {
        int ret;
@@ -311,7 +317,8 @@ int twl6030_mmc_card_detect_config(void)
                                                                        ret);
                return ret;
        }
-       return 0;
+
+       return twl6030_irq_base + MMCDETECT_INTR_OFFSET;
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
 
@@ -340,29 +347,44 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect);
 
-int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+int twl6030_init_irq(struct device *dev, int irq_num)
 {
-
-       int     status = 0;
-       int     i;
+       struct                  device_node *node = dev->of_node;
+       int                     nr_irqs, irq_base, irq_end;
        struct task_struct      *task;
-       int ret;
-       u8 mask[4];
+       static struct irq_chip  twl6030_irq_chip;
+       int                     status = 0;
+       int                     i;
+       u8                      mask[4];
+
+       nr_irqs = TWL6030_NR_IRQS;
+
+       irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+       if (IS_ERR_VALUE(irq_base)) {
+               dev_err(dev, "Fail to allocate IRQ descs\n");
+               return irq_base;
+       }
+
+       irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
+                             &irq_domain_simple_ops, NULL);
+
+       irq_end = irq_base + nr_irqs;
 
-       static struct irq_chip  twl6030_irq_chip;
        mask[1] = 0xFF;
        mask[2] = 0xFF;
        mask[3] = 0xFF;
-       ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-                       REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */
-       ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-                       REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */
-       ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
-                       REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */
+
+       /* mask all int lines */
+       twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
+       /* mask all int sts */
+       twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
+       /* clear INT_STS_A,B,C */
+       twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
 
        twl6030_irq_base = irq_base;
 
-       /* install an irq handler for each of the modules;
+       /*
+        * install an irq handler for each of the modules;
         * clone dummy irq_chip since PIH can't *do* anything
         */
        twl6030_irq_chip = dummy_irq_chip;
@@ -377,30 +399,29 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
                activate_irq(i);
        }
 
-       twl6030_irq_next = i;
-       pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
-                       irq_num, irq_base, twl6030_irq_next - 1);
+       dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
+                       irq_num, irq_base, irq_end);
 
        /* install an irq handler to demultiplex the TWL6030 interrupt */
        init_completion(&irq_event);
 
-       status = request_irq(irq_num, handle_twl6030_pih, 0,
-                               "TWL6030-PIH", &irq_event);
+       status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
+                            &irq_event);
        if (status < 0) {
-               pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
+               dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
                goto fail_irq;
        }
 
        task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
        if (IS_ERR(task)) {
-               pr_err("twl6030: could not create irq %d thread!\n", irq_num);
+               dev_err(dev, "could not create irq %d thread!\n", irq_num);
                status = PTR_ERR(task);
                goto fail_kthread;
        }
 
        twl_irq = irq_num;
        register_pm_notifier(&twl6030_irq_pm_notifier_block);
-       return status;
+       return irq_base;
 
 fail_kthread:
        free_irq(irq_num, &irq_event);
@@ -408,6 +429,7 @@ fail_kthread:
 fail_irq:
        for (i = irq_base; i < irq_end; i++)
                irq_set_chip_and_handler(i, NULL, NULL);
+
        return status;
 }
 
index cea9da6..b63c075 100644 (file)
  */
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
 #include <linux/fs.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
 #include <linux/proc_fs.h>
-#include <linux/device.h>
 #include <linux/mfd/ucb1x00.h>
 
-#include <mach/dma.h>
-
-
 #define UCB1X00_ATTR(name,input)\
 static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
                           char *buf)   \
@@ -38,14 +39,45 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
 
 static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
 {
-       device_create_file(&dev->ucb->dev, &dev_attr_vbatt);
-       device_create_file(&dev->ucb->dev, &dev_attr_vcharger);
-       device_create_file(&dev->ucb->dev, &dev_attr_batt_temp);
+       struct ucb1x00 *ucb = dev->ucb;
+       struct platform_device *pdev;
+       struct gpio_keys_platform_data keys;
+       static struct gpio_keys_button buttons[6];
+       unsigned i;
+
+       memset(buttons, 0, sizeof(buttons));
+       memset(&keys, 0, sizeof(keys));
+
+       for (i = 0; i < ARRAY_SIZE(buttons); i++) {
+               buttons[i].code = BTN_0 + i;
+               buttons[i].gpio = ucb->gpio.base + i;
+               buttons[i].type = EV_KEY;
+               buttons[i].can_disable = true;
+       }
+
+       keys.buttons = buttons;
+       keys.nbuttons = ARRAY_SIZE(buttons);
+       keys.poll_interval = 50;
+       keys.name = "ucb1x00";
+
+       pdev = platform_device_register_data(&ucb->dev, "gpio-keys", -1,
+               &keys, sizeof(keys));
+
+       device_create_file(&ucb->dev, &dev_attr_vbatt);
+       device_create_file(&ucb->dev, &dev_attr_vcharger);
+       device_create_file(&ucb->dev, &dev_attr_batt_temp);
+
+       dev->priv = pdev;
        return 0;
 }
 
 static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev)
 {
+       struct platform_device *pdev = dev->priv;
+
+       if (!IS_ERR(pdev))
+               platform_device_unregister(pdev);
+
        device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp);
        device_remove_file(&dev->ucb->dev, &dev_attr_vcharger);
        device_remove_file(&dev->ucb->dev, &dev_attr_vbatt);
index febc90c..70f02da 100644 (file)
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/mfd/ucb1x00.h>
+#include <linux/pm.h>
 #include <linux/gpio.h>
-#include <linux/semaphore.h>
-
-#include <mach/dma.h>
-#include <mach/hardware.h>
 
 static DEFINE_MUTEX(ucb1x00_mutex);
 static LIST_HEAD(ucb1x00_drivers);
@@ -102,7 +100,7 @@ void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear)
  *     ucb1x00_enable must have been called to enable the comms
  *     before using this function.
  *
- *     This function does not take any semaphores or spinlocks.
+ *     This function does not take any mutexes or spinlocks.
  */
 unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
 {
@@ -120,14 +118,22 @@ static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        else
                ucb->io_out &= ~(1 << offset);
 
+       ucb1x00_enable(ucb);
        ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
+       ucb1x00_disable(ucb);
        spin_unlock_irqrestore(&ucb->io_lock, flags);
 }
 
 static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
-       return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset);
+       unsigned val;
+
+       ucb1x00_enable(ucb);
+       val = ucb1x00_reg_read(ucb, UCB_IO_DATA);
+       ucb1x00_disable(ucb);
+
+       return val & (1 << offset);
 }
 
 static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -137,7 +143,9 @@ static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 
        spin_lock_irqsave(&ucb->io_lock, flags);
        ucb->io_dir &= ~(1 << offset);
+       ucb1x00_enable(ucb);
        ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+       ucb1x00_disable(ucb);
        spin_unlock_irqrestore(&ucb->io_lock, flags);
 
        return 0;
@@ -157,6 +165,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
        else
                ucb->io_out &= ~mask;
 
+       ucb1x00_enable(ucb);
        if (old != ucb->io_out)
                ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
 
@@ -164,11 +173,19 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
                ucb->io_dir |= mask;
                ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
        }
+       ucb1x00_disable(ucb);
        spin_unlock_irqrestore(&ucb->io_lock, flags);
 
        return 0;
 }
 
+static int ucb1x00_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
+
+       return ucb->irq_base > 0 ? ucb->irq_base + offset : -ENXIO;
+}
+
 /*
  * UCB1300 data sheet says we must:
  *  1. enable ADC      => 5us (including reference startup time)
@@ -186,7 +203,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
  *     Any code wishing to use the ADC converter must call this
  *     function prior to using it.
  *
- *     This function takes the ADC semaphore to prevent two or more
+ *     This function takes the ADC mutex to prevent two or more
  *     concurrent uses, and therefore may sleep.  As a result, it
  *     can only be called from process context, not interrupt
  *     context.
@@ -196,7 +213,7 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
  */
 void ucb1x00_adc_enable(struct ucb1x00 *ucb)
 {
-       down(&ucb->adc_sem);
+       mutex_lock(&ucb->adc_mutex);
 
        ucb->adc_cr |= UCB_ADC_ENA;
 
@@ -218,7 +235,7 @@ void ucb1x00_adc_enable(struct ucb1x00 *ucb)
  *     complete (2 frames max without sync).
  *
  *     If called for a synchronised ADC conversion, it may sleep
- *     with the ADC semaphore held.
+ *     with the ADC mutex held.
  */
 unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
 {
@@ -246,7 +263,7 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
  *     ucb1x00_adc_disable - disable the ADC converter
  *     @ucb: UCB1x00 structure describing chip
  *
- *     Disable the ADC converter and release the ADC semaphore.
+ *     Disable the ADC converter and release the ADC mutex.
  */
 void ucb1x00_adc_disable(struct ucb1x00 *ucb)
 {
@@ -254,7 +271,7 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb)
        ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
        ucb1x00_disable(ucb);
 
-       up(&ucb->adc_sem);
+       mutex_unlock(&ucb->adc_mutex);
 }
 
 /*
@@ -265,10 +282,9 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb)
  * SIBCLK to talk to the chip.  We leave the clock running until
  * we have finished processing all interrupts from the chip.
  */
-static irqreturn_t ucb1x00_irq(int irqnr, void *devid)
+static void ucb1x00_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct ucb1x00 *ucb = devid;
-       struct ucb1x00_irq *irq;
+       struct ucb1x00 *ucb = irq_desc_get_handler_data(desc);
        unsigned int isr, i;
 
        ucb1x00_enable(ucb);
@@ -276,157 +292,104 @@ static irqreturn_t ucb1x00_irq(int irqnr, void *devid)
        ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
        ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
 
-       for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++)
-               if (isr & 1 && irq->fn)
-                       irq->fn(i, irq->devid);
+       for (i = 0; i < 16 && isr; i++, isr >>= 1, irq++)
+               if (isr & 1)
+                       generic_handle_irq(ucb->irq_base + i);
        ucb1x00_disable(ucb);
-
-       return IRQ_HANDLED;
 }
 
-/**
- *     ucb1x00_hook_irq - hook a UCB1x00 interrupt
- *     @ucb:   UCB1x00 structure describing chip
- *     @idx:   interrupt index
- *     @fn:    function to call when interrupt is triggered
- *     @devid: device id to pass to interrupt handler
- *
- *     Hook the specified interrupt.  You can only register one handler
- *     for each interrupt source.  The interrupt source is not enabled
- *     by this function; use ucb1x00_enable_irq instead.
- *
- *     Interrupt handlers will be called with other interrupts enabled.
- *
- *     Returns zero on success, or one of the following errors:
- *      -EINVAL if the interrupt index is invalid
- *      -EBUSY if the interrupt has already been hooked
- */
-int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid)
+static void ucb1x00_irq_update(struct ucb1x00 *ucb, unsigned mask)
 {
-       struct ucb1x00_irq *irq;
-       int ret = -EINVAL;
-
-       if (idx < 16) {
-               irq = ucb->irq_handler + idx;
-               ret = -EBUSY;
-
-               spin_lock_irq(&ucb->lock);
-               if (irq->fn == NULL) {
-                       irq->devid = devid;
-                       irq->fn = fn;
-                       ret = 0;
-               }
-               spin_unlock_irq(&ucb->lock);
-       }
-       return ret;
+       ucb1x00_enable(ucb);
+       if (ucb->irq_ris_enbl & mask)
+               ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+                                 ucb->irq_mask);
+       if (ucb->irq_fal_enbl & mask)
+               ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+                                 ucb->irq_mask);
+       ucb1x00_disable(ucb);
 }
 
-/**
- *     ucb1x00_enable_irq - enable an UCB1x00 interrupt source
- *     @ucb: UCB1x00 structure describing chip
- *     @idx: interrupt index
- *     @edges: interrupt edges to enable
- *
- *     Enable the specified interrupt to trigger on %UCB_RISING,
- *     %UCB_FALLING or both edges.  The interrupt should have been
- *     hooked by ucb1x00_hook_irq.
- */
-void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
+static void ucb1x00_irq_noop(struct irq_data *data)
 {
-       unsigned long flags;
+}
 
-       if (idx < 16) {
-               spin_lock_irqsave(&ucb->lock, flags);
+static void ucb1x00_irq_mask(struct irq_data *data)
+{
+       struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+       unsigned mask = 1 << (data->irq - ucb->irq_base);
 
-               ucb1x00_enable(ucb);
-               if (edges & UCB_RISING) {
-                       ucb->irq_ris_enbl |= 1 << idx;
-                       ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-               }
-               if (edges & UCB_FALLING) {
-                       ucb->irq_fal_enbl |= 1 << idx;
-                       ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-               }
-               ucb1x00_disable(ucb);
-               spin_unlock_irqrestore(&ucb->lock, flags);
-       }
+       raw_spin_lock(&ucb->irq_lock);
+       ucb->irq_mask &= ~mask;
+       ucb1x00_irq_update(ucb, mask);
+       raw_spin_unlock(&ucb->irq_lock);
 }
 
-/**
- *     ucb1x00_disable_irq - disable an UCB1x00 interrupt source
- *     @ucb: UCB1x00 structure describing chip
- *     @edges: interrupt edges to disable
- *
- *     Disable the specified interrupt triggering on the specified
- *     (%UCB_RISING, %UCB_FALLING or both) edges.
- */
-void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
+static void ucb1x00_irq_unmask(struct irq_data *data)
 {
-       unsigned long flags;
+       struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+       unsigned mask = 1 << (data->irq - ucb->irq_base);
 
-       if (idx < 16) {
-               spin_lock_irqsave(&ucb->lock, flags);
-
-               ucb1x00_enable(ucb);
-               if (edges & UCB_RISING) {
-                       ucb->irq_ris_enbl &= ~(1 << idx);
-                       ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-               }
-               if (edges & UCB_FALLING) {
-                       ucb->irq_fal_enbl &= ~(1 << idx);
-                       ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-               }
-               ucb1x00_disable(ucb);
-               spin_unlock_irqrestore(&ucb->lock, flags);
-       }
+       raw_spin_lock(&ucb->irq_lock);
+       ucb->irq_mask |= mask;
+       ucb1x00_irq_update(ucb, mask);
+       raw_spin_unlock(&ucb->irq_lock);
 }
 
-/**
- *     ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt
- *     @ucb: UCB1x00 structure describing chip
- *     @idx: interrupt index
- *     @devid: device id.
- *
- *     Disable the interrupt source and remove the handler.  devid must
- *     match the devid passed when hooking the interrupt.
- *
- *     Returns zero on success, or one of the following errors:
- *      -EINVAL if the interrupt index is invalid
- *      -ENOENT if devid does not match
- */
-int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid)
+static int ucb1x00_irq_set_type(struct irq_data *data, unsigned int type)
 {
-       struct ucb1x00_irq *irq;
-       int ret;
+       struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+       unsigned mask = 1 << (data->irq - ucb->irq_base);
 
-       if (idx >= 16)
-               goto bad;
+       raw_spin_lock(&ucb->irq_lock);
+       if (type & IRQ_TYPE_EDGE_RISING)
+               ucb->irq_ris_enbl |= mask;
+       else
+               ucb->irq_ris_enbl &= ~mask;
 
-       irq = ucb->irq_handler + idx;
-       ret = -ENOENT;
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               ucb->irq_fal_enbl |= mask;
+       else
+               ucb->irq_fal_enbl &= ~mask;
+       if (ucb->irq_mask & mask) {
+               ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+                                 ucb->irq_mask);
+               ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+                                 ucb->irq_mask);
+       }
+       raw_spin_unlock(&ucb->irq_lock);
 
-       spin_lock_irq(&ucb->lock);
-       if (irq->devid == devid) {
-               ucb->irq_ris_enbl &= ~(1 << idx);
-               ucb->irq_fal_enbl &= ~(1 << idx);
+       return 0;
+}
 
-               ucb1x00_enable(ucb);
-               ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-               ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-               ucb1x00_disable(ucb);
+static int ucb1x00_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+       struct ucb1x00 *ucb = irq_data_get_irq_chip_data(data);
+       struct ucb1x00_plat_data *pdata = ucb->mcp->attached_device.platform_data;
+       unsigned mask = 1 << (data->irq - ucb->irq_base);
 
-               irq->fn = NULL;
-               irq->devid = NULL;
-               ret = 0;
-       }
-       spin_unlock_irq(&ucb->lock);
-       return ret;
+       if (!pdata || !pdata->can_wakeup)
+               return -EINVAL;
 
-bad:
-       printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx);
-       return -EINVAL;
+       raw_spin_lock(&ucb->irq_lock);
+       if (on)
+               ucb->irq_wake |= mask;
+       else
+               ucb->irq_wake &= ~mask;
+       raw_spin_unlock(&ucb->irq_lock);
+
+       return 0;
 }
 
+static struct irq_chip ucb1x00_irqchip = {
+       .name = "ucb1x00",
+       .irq_ack = ucb1x00_irq_noop,
+       .irq_mask = ucb1x00_irq_mask,
+       .irq_unmask = ucb1x00_irq_unmask,
+       .irq_set_type = ucb1x00_irq_set_type,
+       .irq_set_wake = ucb1x00_irq_set_wake,
+};
+
 static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
 {
        struct ucb1x00_dev *dev;
@@ -440,8 +403,8 @@ static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
                ret = drv->add(dev);
 
                if (ret == 0) {
-                       list_add(&dev->dev_node, &ucb->devs);
-                       list_add(&dev->drv_node, &drv->devs);
+                       list_add_tail(&dev->dev_node, &ucb->devs);
+                       list_add_tail(&dev->drv_node, &drv->devs);
                } else {
                        kfree(dev);
                }
@@ -533,98 +496,126 @@ static struct class ucb1x00_class = {
 
 static int ucb1x00_probe(struct mcp *mcp)
 {
-       struct ucb1x00 *ucb;
+       struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
        struct ucb1x00_driver *drv;
-       unsigned int id;
+       struct ucb1x00 *ucb;
+       unsigned id, i, irq_base;
        int ret = -ENODEV;
-       int temp;
+
+       /* Tell the platform to deassert the UCB1x00 reset */
+       if (pdata && pdata->reset)
+               pdata->reset(UCB_RST_PROBE);
 
        mcp_enable(mcp);
        id = mcp_reg_read(mcp, UCB_ID);
+       mcp_disable(mcp);
 
        if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
                printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
-               goto err_disable;
+               goto out;
        }
 
        ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL);
        ret = -ENOMEM;
        if (!ucb)
-               goto err_disable;
-
+               goto out;
 
+       device_initialize(&ucb->dev);
        ucb->dev.class = &ucb1x00_class;
        ucb->dev.parent = &mcp->attached_device;
        dev_set_name(&ucb->dev, "ucb1x00");
 
-       spin_lock_init(&ucb->lock);
+       raw_spin_lock_init(&ucb->irq_lock);
        spin_lock_init(&ucb->io_lock);
-       sema_init(&ucb->adc_sem, 1);
+       mutex_init(&ucb->adc_mutex);
 
        ucb->id  = id;
        ucb->mcp = mcp;
+
+       ret = device_add(&ucb->dev);
+       if (ret)
+               goto err_dev_add;
+
+       ucb1x00_enable(ucb);
        ucb->irq = ucb1x00_detect_irq(ucb);
+       ucb1x00_disable(ucb);
        if (ucb->irq == NO_IRQ) {
-               printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
+               dev_err(&ucb->dev, "IRQ probe failed\n");
                ret = -ENODEV;
-               goto err_free;
+               goto err_no_irq;
        }
 
        ucb->gpio.base = -1;
-       if (mcp->gpio_base != 0) {
+       irq_base = pdata ? pdata->irq_base : 0;
+       ucb->irq_base = irq_alloc_descs(-1, irq_base, 16, -1);
+       if (ucb->irq_base < 0) {
+               dev_err(&ucb->dev, "unable to allocate 16 irqs: %d\n",
+                       ucb->irq_base);
+               goto err_irq_alloc;
+       }
+
+       for (i = 0; i < 16; i++) {
+               unsigned irq = ucb->irq_base + i;
+
+               irq_set_chip_and_handler(irq, &ucb1x00_irqchip, handle_edge_irq);
+               irq_set_chip_data(irq, ucb);
+               set_irq_flags(irq, IRQF_VALID | IRQ_NOREQUEST);
+       }
+
+       irq_set_irq_type(ucb->irq, IRQ_TYPE_EDGE_RISING);
+       irq_set_handler_data(ucb->irq, ucb);
+       irq_set_chained_handler(ucb->irq, ucb1x00_irq);
+
+       if (pdata && pdata->gpio_base) {
                ucb->gpio.label = dev_name(&ucb->dev);
-               ucb->gpio.base = mcp->gpio_base;
+               ucb->gpio.dev = &ucb->dev;
+               ucb->gpio.owner = THIS_MODULE;
+               ucb->gpio.base = pdata->gpio_base;
                ucb->gpio.ngpio = 10;
                ucb->gpio.set = ucb1x00_gpio_set;
                ucb->gpio.get = ucb1x00_gpio_get;
                ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
                ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
+               ucb->gpio.to_irq = ucb1x00_to_irq;
                ret = gpiochip_add(&ucb->gpio);
                if (ret)
-                       goto err_free;
+                       goto err_gpio_add;
        } else
                dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
 
-       ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
-                         "UCB1x00", ucb);
-       if (ret) {
-               printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
-                       ucb->irq, ret);
-               goto err_gpio;
-       }
-
        mcp_set_drvdata(mcp, ucb);
 
-       ret = device_register(&ucb->dev);
-       if (ret)
-               goto err_irq;
-
+       if (pdata)
+               device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup);
 
        INIT_LIST_HEAD(&ucb->devs);
        mutex_lock(&ucb1x00_mutex);
-       list_add(&ucb->node, &ucb1x00_devices);
+       list_add_tail(&ucb->node, &ucb1x00_devices);
        list_for_each_entry(drv, &ucb1x00_drivers, node) {
                ucb1x00_add_dev(ucb, drv);
        }
        mutex_unlock(&ucb1x00_mutex);
 
-       goto out;
+       return ret;
 
- err_irq:
-       free_irq(ucb->irq, ucb);
- err_gpio:
-       if (ucb->gpio.base != -1)
-               temp = gpiochip_remove(&ucb->gpio);
- err_free:
-       kfree(ucb);
- err_disable:
-       mcp_disable(mcp);
+ err_gpio_add:
+       irq_set_chained_handler(ucb->irq, NULL);
+ err_irq_alloc:
+       if (ucb->irq_base > 0)
+               irq_free_descs(ucb->irq_base, 16);
+ err_no_irq:
+       device_del(&ucb->dev);
+ err_dev_add:
+       put_device(&ucb->dev);
  out:
+       if (pdata && pdata->reset)
+               pdata->reset(UCB_RST_PROBE_FAIL);
        return ret;
 }
 
 static void ucb1x00_remove(struct mcp *mcp)
 {
+       struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
        struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
        struct list_head *l, *n;
        int ret;
@@ -643,8 +634,12 @@ static void ucb1x00_remove(struct mcp *mcp)
                        dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
        }
 
-       free_irq(ucb->irq, ucb);
+       irq_set_chained_handler(ucb->irq, NULL);
+       irq_free_descs(ucb->irq_base, 16);
        device_unregister(&ucb->dev);
+
+       if (pdata && pdata->reset)
+               pdata->reset(UCB_RST_REMOVE);
 }
 
 int ucb1x00_register_driver(struct ucb1x00_driver *drv)
@@ -653,7 +648,7 @@ int ucb1x00_register_driver(struct ucb1x00_driver *drv)
 
        INIT_LIST_HEAD(&drv->devs);
        mutex_lock(&ucb1x00_mutex);
-       list_add(&drv->node, &ucb1x00_drivers);
+       list_add_tail(&drv->node, &ucb1x00_drivers);
        list_for_each_entry(ucb, &ucb1x00_devices, node) {
                ucb1x00_add_dev(ucb, drv);
        }
@@ -674,44 +669,86 @@ void ucb1x00_unregister_driver(struct ucb1x00_driver *drv)
        mutex_unlock(&ucb1x00_mutex);
 }
 
-static int ucb1x00_suspend(struct mcp *mcp, pm_message_t state)
+static int ucb1x00_suspend(struct device *dev)
 {
-       struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
-       struct ucb1x00_dev *dev;
+       struct ucb1x00_plat_data *pdata = dev->platform_data;
+       struct ucb1x00 *ucb = dev_get_drvdata(dev);
+       struct ucb1x00_dev *udev;
 
        mutex_lock(&ucb1x00_mutex);
-       list_for_each_entry(dev, &ucb->devs, dev_node) {
-               if (dev->drv->suspend)
-                       dev->drv->suspend(dev, state);
+       list_for_each_entry(udev, &ucb->devs, dev_node) {
+               if (udev->drv->suspend)
+                       udev->drv->suspend(udev);
        }
        mutex_unlock(&ucb1x00_mutex);
+
+       if (ucb->irq_wake) {
+               unsigned long flags;
+
+               raw_spin_lock_irqsave(&ucb->irq_lock, flags);
+               ucb1x00_enable(ucb);
+               ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+                                 ucb->irq_wake);
+               ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+                                 ucb->irq_wake);
+               ucb1x00_disable(ucb);
+               raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
+
+               enable_irq_wake(ucb->irq);
+       } else if (pdata && pdata->reset)
+               pdata->reset(UCB_RST_SUSPEND);
+
        return 0;
 }
 
-static int ucb1x00_resume(struct mcp *mcp)
+static int ucb1x00_resume(struct device *dev)
 {
-       struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
-       struct ucb1x00_dev *dev;
+       struct ucb1x00_plat_data *pdata = dev->platform_data;
+       struct ucb1x00 *ucb = dev_get_drvdata(dev);
+       struct ucb1x00_dev *udev;
+
+       if (!ucb->irq_wake && pdata && pdata->reset)
+               pdata->reset(UCB_RST_RESUME);
 
+       ucb1x00_enable(ucb);
        ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
        ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+
+       if (ucb->irq_wake) {
+               unsigned long flags;
+
+               raw_spin_lock_irqsave(&ucb->irq_lock, flags);
+               ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl &
+                                 ucb->irq_mask);
+               ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl &
+                                 ucb->irq_mask);
+               raw_spin_unlock_irqrestore(&ucb->irq_lock, flags);
+
+               disable_irq_wake(ucb->irq);
+       }
+       ucb1x00_disable(ucb);
+
        mutex_lock(&ucb1x00_mutex);
-       list_for_each_entry(dev, &ucb->devs, dev_node) {
-               if (dev->drv->resume)
-                       dev->drv->resume(dev);
+       list_for_each_entry(udev, &ucb->devs, dev_node) {
+               if (udev->drv->resume)
+                       udev->drv->resume(udev);
        }
        mutex_unlock(&ucb1x00_mutex);
        return 0;
 }
 
+static const struct dev_pm_ops ucb1x00_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume)
+};
+
 static struct mcp_driver ucb1x00_driver = {
        .drv            = {
                .name   = "ucb1x00",
+               .owner  = THIS_MODULE,
+               .pm     = &ucb1x00_pm_ops,
        },
        .probe          = ucb1x00_probe,
        .remove         = ucb1x00_remove,
-       .suspend        = ucb1x00_suspend,
-       .resume         = ucb1x00_resume,
 };
 
 static int __init ucb1x00_init(void)
@@ -742,14 +779,10 @@ EXPORT_SYMBOL(ucb1x00_adc_enable);
 EXPORT_SYMBOL(ucb1x00_adc_read);
 EXPORT_SYMBOL(ucb1x00_adc_disable);
 
-EXPORT_SYMBOL(ucb1x00_hook_irq);
-EXPORT_SYMBOL(ucb1x00_free_irq);
-EXPORT_SYMBOL(ucb1x00_enable_irq);
-EXPORT_SYMBOL(ucb1x00_disable_irq);
-
 EXPORT_SYMBOL(ucb1x00_register_driver);
 EXPORT_SYMBOL(ucb1x00_unregister_driver);
 
+MODULE_ALIAS("mcp:ucb1x00");
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("UCB1x00 core driver");
 MODULE_LICENSE("GPL");
index 63a3cbd..1e0e20c 100644 (file)
@@ -20,8 +20,9 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/smp.h>
+#include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/string.h>
@@ -32,7 +33,6 @@
 #include <linux/kthread.h>
 #include <linux/mfd/ucb1x00.h>
 
-#include <mach/dma.h>
 #include <mach/collie.h>
 #include <asm/mach-types.h>
 
@@ -42,6 +42,8 @@ struct ucb1x00_ts {
        struct input_dev        *idev;
        struct ucb1x00          *ucb;
 
+       spinlock_t              irq_lock;
+       unsigned                irq_disabled;
        wait_queue_head_t       irq_wait;
        struct task_struct      *rtask;
        u16                     x_res;
@@ -238,7 +240,12 @@ static int ucb1x00_thread(void *_ts)
                if (ucb1x00_ts_pen_down(ts)) {
                        set_current_state(TASK_INTERRUPTIBLE);
 
-                       ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
+                       spin_lock_irq(&ts->irq_lock);
+                       if (ts->irq_disabled) {
+                               ts->irq_disabled = 0;
+                               enable_irq(ts->ucb->irq_base + UCB_IRQ_TSPX);
+                       }
+                       spin_unlock_irq(&ts->irq_lock);
                        ucb1x00_disable(ts->ucb);
 
                        /*
@@ -281,23 +288,37 @@ static int ucb1x00_thread(void *_ts)
  * We only detect touch screen _touches_ with this interrupt
  * handler, and even then we just schedule our task.
  */
-static void ucb1x00_ts_irq(int idx, void *id)
+static irqreturn_t ucb1x00_ts_irq(int irq, void *id)
 {
        struct ucb1x00_ts *ts = id;
 
-       ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
+       spin_lock(&ts->irq_lock);
+       ts->irq_disabled = 1;
+       disable_irq_nosync(ts->ucb->irq_base + UCB_IRQ_TSPX);
+       spin_unlock(&ts->irq_lock);
        wake_up(&ts->irq_wait);
+
+       return IRQ_HANDLED;
 }
 
 static int ucb1x00_ts_open(struct input_dev *idev)
 {
        struct ucb1x00_ts *ts = input_get_drvdata(idev);
+       unsigned long flags = 0;
        int ret = 0;
 
        BUG_ON(ts->rtask);
 
+       if (machine_is_collie())
+               flags = IRQF_TRIGGER_RISING;
+       else
+               flags = IRQF_TRIGGER_FALLING;
+
+       ts->irq_disabled = 0;
+
        init_waitqueue_head(&ts->irq_wait);
-       ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
+       ret = request_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ucb1x00_ts_irq,
+                         flags, "ucb1x00-ts", ts);
        if (ret < 0)
                goto out;
 
@@ -314,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev)
        if (!IS_ERR(ts->rtask)) {
                ret = 0;
        } else {
-               ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
+               free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
                ts->rtask = NULL;
                ret = -EFAULT;
        }
@@ -334,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev)
                kthread_stop(ts->rtask);
 
        ucb1x00_enable(ts->ucb);
-       ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
+       free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
        ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
        ucb1x00_disable(ts->ucb);
 }
@@ -359,11 +380,13 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
        ts->ucb = dev->ucb;
        ts->idev = idev;
        ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
+       spin_lock_init(&ts->irq_lock);
 
        idev->name       = "Touchscreen panel";
        idev->id.product = ts->ucb->id;
        idev->open       = ucb1x00_ts_open;
        idev->close      = ucb1x00_ts_close;
+       idev->dev.parent = &ts->ucb->dev;
 
        idev->evbit[0]   = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
        idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
index 745c879..4bceee9 100644 (file)
@@ -89,7 +89,7 @@ static const struct spi_device_id wm831x_spi_ids[] = {
        { "wm8326", WM8326 },
        { },
 };
-MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
+MODULE_DEVICE_TABLE(spi, wm831x_spi_ids);
 
 static struct spi_driver wm831x_spi_driver = {
        .driver = {
index 237764a..1189a17 100644 (file)
@@ -271,8 +271,7 @@ static int wm8400_init(struct wm8400 *wm8400,
                return -EIO;
        }
        if (i != reg_data[WM8400_RESET_ID].default_val) {
-               dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
-                       reg);
+               dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n", i);
                return -ENODEV;
        }
 
index 98733d4..9d7ca1e 100644 (file)
@@ -639,7 +639,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
        }
 
        pm_runtime_enable(wm8994->dev);
-       pm_runtime_resume(wm8994->dev);
+       pm_runtime_idle(wm8994->dev);
 
        return 0;
 
index bc0c509..bfd25af 100644 (file)
 #include <linux/mfd/wm8994/core.h>
 #include <linux/mfd/wm8994/registers.h>
 #include <linux/regmap.h>
+#include <linux/device.h>
 
 #include "wm8994.h"
 
 static struct reg_default wm1811_defaults[] = {
-       { 0x0000, 0x1811 },    /* R0    - Software Reset */
        { 0x0001, 0x0000 },    /* R1    - Power Management (1) */
        { 0x0002, 0x6000 },    /* R2    - Power Management (2) */
        { 0x0003, 0x0000 },    /* R3    - Power Management (3) */
@@ -60,7 +60,7 @@ static struct reg_default wm1811_defaults[] = {
        { 0x0036, 0x0000 },    /* R54   - Speaker Mixer */
        { 0x0037, 0x0000 },    /* R55   - Additional Control */
        { 0x0038, 0x0000 },    /* R56   - AntiPOP (1) */
-       { 0x0039, 0x0180 },    /* R57   - AntiPOP (2) */
+       { 0x0039, 0x0000 },    /* R57   - AntiPOP (2) */
        { 0x003B, 0x000D },    /* R59   - LDO 1 */
        { 0x003C, 0x0003 },    /* R60   - LDO 2 */
        { 0x003D, 0x0039 },    /* R61   - MICBIAS1 */
@@ -68,16 +68,12 @@ static struct reg_default wm1811_defaults[] = {
        { 0x004C, 0x1F25 },    /* R76   - Charge Pump (1) */
        { 0x004D, 0xAB19 },    /* R77   - Charge Pump (2) */
        { 0x0051, 0x0004 },    /* R81   - Class W (1) */
-       { 0x0054, 0x0000 },    /* R84   - DC Servo (1) */
        { 0x0055, 0x054A },    /* R85   - DC Servo (2) */
-       { 0x0058, 0x0000 },    /* R88   - DC Servo Readback */
        { 0x0059, 0x0000 },    /* R89   - DC Servo (4) */
        { 0x0060, 0x0000 },    /* R96   - Analogue HP (1) */
        { 0x00C5, 0x0000 },    /* R197  - Class D Test (5) */
        { 0x00D0, 0x7600 },    /* R208  - Mic Detect 1 */
        { 0x00D1, 0x007F },    /* R209  - Mic Detect 2 */
-       { 0x00D2, 0x0000 },    /* R210  - Mic Detect 3 */
-       { 0x0100, 0x0100 },    /* R256  - Chip Revision */
        { 0x0101, 0x8004 },    /* R257  - Control Interface */
        { 0x0200, 0x0000 },    /* R512  - AIF1 Clocking (1) */
        { 0x0201, 0x0000 },    /* R513  - AIF1 Clocking (2) */
@@ -87,7 +83,6 @@ static struct reg_default wm1811_defaults[] = {
        { 0x0209, 0x0000 },    /* R521  - Clocking (2) */
        { 0x0210, 0x0083 },    /* R528  - AIF1 Rate */
        { 0x0211, 0x0083 },    /* R529  - AIF2 Rate */
-       { 0x0212, 0x0000 },    /* R530  - Rate Status */
        { 0x0220, 0x0000 },    /* R544  - FLL1 Control (1) */
        { 0x0221, 0x0000 },    /* R545  - FLL1 Control (2) */
        { 0x0222, 0x0000 },    /* R546  - FLL1 Control (3) */
@@ -217,8 +212,6 @@ static struct reg_default wm1811_defaults[] = {
        { 0x070A, 0xA101 },    /* R1802 - GPIO 11 */
        { 0x0720, 0x0000 },    /* R1824 - Pull Control (1) */
        { 0x0721, 0x0156 },    /* R1825 - Pull Control (2) */
-       { 0x0730, 0x0000 },    /* R1840 - Interrupt Status 1 */
-       { 0x0731, 0x0000 },    /* R1841 - Interrupt Status 2 */
        { 0x0732, 0x0000 },    /* R1842 - Interrupt Raw Status 2 */
        { 0x0738, 0x07FF },    /* R1848 - Interrupt Status 1 Mask */
        { 0x0739, 0xDFEF },    /* R1849 - Interrupt Status 2 Mask */
@@ -227,7 +220,6 @@ static struct reg_default wm1811_defaults[] = {
 };
 
 static struct reg_default wm8994_defaults[] = {
-       { 0x0000, 0x8994 },    /* R0     - Software Reset */ 
        { 0x0001, 0x0000 },    /* R1     - Power Management (1) */ 
        { 0x0002, 0x6000 },    /* R2     - Power Management (2) */ 
        { 0x0003, 0x0000 },    /* R3     - Power Management (3) */ 
@@ -274,12 +266,9 @@ static struct reg_default wm8994_defaults[] = {
        { 0x003C, 0x0003 },    /* R60    - LDO 2 */ 
        { 0x004C, 0x1F25 },    /* R76    - Charge Pump (1) */ 
        { 0x0051, 0x0004 },    /* R81    - Class W (1) */ 
-       { 0x0054, 0x0000 },    /* R84    - DC Servo (1) */ 
        { 0x0055, 0x054A },    /* R85    - DC Servo (2) */ 
        { 0x0057, 0x0000 },    /* R87    - DC Servo (4) */ 
-       { 0x0058, 0x0000 },    /* R88    - DC Servo Readback */ 
        { 0x0060, 0x0000 },    /* R96    - Analogue HP (1) */ 
-       { 0x0100, 0x0003 },    /* R256   - Chip Revision */ 
        { 0x0101, 0x8004 },    /* R257   - Control Interface */ 
        { 0x0110, 0x0000 },    /* R272   - Write Sequencer Ctrl (1) */ 
        { 0x0111, 0x0000 },    /* R273   - Write Sequencer Ctrl (2) */ 
@@ -291,7 +280,6 @@ static struct reg_default wm8994_defaults[] = {
        { 0x0209, 0x0000 },    /* R521   - Clocking (2) */ 
        { 0x0210, 0x0083 },    /* R528   - AIF1 Rate */ 
        { 0x0211, 0x0083 },    /* R529   - AIF2 Rate */ 
-       { 0x0212, 0x0000 },    /* R530   - Rate Status */ 
        { 0x0220, 0x0000 },    /* R544   - FLL1 Control (1) */ 
        { 0x0221, 0x0000 },    /* R545   - FLL1 Control (2) */ 
        { 0x0222, 0x0000 },    /* R546   - FLL1 Control (3) */ 
@@ -444,9 +432,6 @@ static struct reg_default wm8994_defaults[] = {
        { 0x070A, 0xA101 },    /* R1802  - GPIO 11 */ 
        { 0x0720, 0x0000 },    /* R1824  - Pull Control (1) */ 
        { 0x0721, 0x0156 },    /* R1825  - Pull Control (2) */ 
-       { 0x0730, 0x0000 },    /* R1840  - Interrupt Status 1 */ 
-       { 0x0731, 0x0000 },    /* R1841  - Interrupt Status 2 */ 
-       { 0x0732, 0x0000 },    /* R1842  - Interrupt Raw Status 2 */ 
        { 0x0738, 0x07FF },    /* R1848  - Interrupt Status 1 Mask */ 
        { 0x0739, 0xFFFF },    /* R1849  - Interrupt Status 2 Mask */ 
        { 0x0740, 0x0000 },    /* R1856  - Interrupt Control */ 
@@ -454,7 +439,6 @@ static struct reg_default wm8994_defaults[] = {
 };
 
 static struct reg_default wm8958_defaults[] = {
-       { 0x0000, 0x8958 },    /* R0     - Software Reset */ 
        { 0x0001, 0x0000 },    /* R1     - Power Management (1) */
        { 0x0002, 0x6000 },    /* R2     - Power Management (2) */
        { 0x0003, 0x0000 },    /* R3     - Power Management (3) */
@@ -969,6 +953,7 @@ static bool wm8994_readable_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM8994_DC_SERVO_READBACK:
+       case WM8994_MICBIAS:
        case WM8994_WRITE_SEQUENCER_CTRL_1:
        case WM8994_WRITE_SEQUENCER_CTRL_2:
        case WM8994_AIF1_ADC2_LEFT_VOLUME:
index 4bcfc37..c8d8e38 100644 (file)
@@ -6,12 +6,10 @@
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/export.h>
-
-/* Number of bytes to reserve for the iomem resource */
-#define ATMEL_TC_IOMEM_SIZE    256
-
+#include <linux/of.h>
 
 /*
  * This is a thin library to solve the problem of how to portably allocate
@@ -48,10 +46,17 @@ struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
        struct atmel_tc         *tc;
        struct platform_device  *pdev = NULL;
        struct resource         *r;
+       size_t                  size;
 
        spin_lock(&tc_list_lock);
        list_for_each_entry(tc, &tc_list, node) {
-               if (tc->pdev->id == block) {
+               if (tc->pdev->dev.of_node) {
+                       if (of_alias_get_id(tc->pdev->dev.of_node, "tcb")
+                                       == block) {
+                               pdev = tc->pdev;
+                               break;
+                       }
+               } else if (tc->pdev->id == block) {
                        pdev = tc->pdev;
                        break;
                }
@@ -61,11 +66,15 @@ struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
                goto fail;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name);
        if (!r)
                goto fail;
 
-       tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE);
+       size = resource_size(r);
+       r = request_mem_region(r->start, size, name);
+       if (!r)
+               goto fail;
+
+       tc->regs = ioremap(r->start, size);
        if (!tc->regs)
                goto fail_ioremap;
 
@@ -76,7 +85,7 @@ out:
        return tc;
 
 fail_ioremap:
-       release_mem_region(r->start, ATMEL_TC_IOMEM_SIZE);
+       release_mem_region(r->start, size);
 fail:
        tc = NULL;
        goto out;
@@ -96,7 +105,7 @@ void atmel_tc_free(struct atmel_tc *tc)
        spin_lock(&tc_list_lock);
        if (tc->regs) {
                iounmap(tc->regs);
-               release_mem_region(tc->iomem->start, ATMEL_TC_IOMEM_SIZE);
+               release_mem_region(tc->iomem->start, resource_size(tc->iomem));
                tc->regs = NULL;
                tc->iomem = NULL;
        }
@@ -104,6 +113,30 @@ void atmel_tc_free(struct atmel_tc *tc)
 }
 EXPORT_SYMBOL_GPL(atmel_tc_free);
 
+#if defined(CONFIG_OF)
+static struct atmel_tcb_config tcb_rm9200_config = {
+       .counter_width = 16,
+};
+
+static struct atmel_tcb_config tcb_sam9x5_config = {
+       .counter_width = 32,
+};
+
+static const struct of_device_id atmel_tcb_dt_ids[] = {
+       {
+               .compatible = "atmel,at91rm9200-tcb",
+               .data = &tcb_rm9200_config,
+       }, {
+               .compatible = "atmel,at91sam9x5-tcb",
+               .data = &tcb_sam9x5_config,
+       }, {
+               /* sentinel */
+       }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_tcb_dt_ids);
+#endif
+
 static int __init tc_probe(struct platform_device *pdev)
 {
        struct atmel_tc *tc;
@@ -129,6 +162,14 @@ static int __init tc_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       /* Now take SoC information if available */
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(atmel_tcb_dt_ids, pdev->dev.of_node);
+               if (match)
+                       tc->tcb_config = match->data;
+       }
+
        tc->clk[0] = clk;
        tc->clk[1] = clk_get(&pdev->dev, "t1_clk");
        if (IS_ERR(tc->clk[1]))
@@ -153,7 +194,10 @@ static int __init tc_probe(struct platform_device *pdev)
 }
 
 static struct platform_driver tc_driver = {
-       .driver.name    = "atmel_tcb",
+       .driver = {
+               .name   = "atmel_tcb",
+               .of_match_table = of_match_ptr(atmel_tcb_dt_ids),
+       },
 };
 
 static int __init tc_init(void)
index 00fcbed..ecbee9b 100644 (file)
@@ -395,7 +395,7 @@ config MMC_SPI
 
 config MMC_S3C
        tristate "Samsung S3C SD/MMC Card Interface support"
-       depends on ARCH_S3C2410
+       depends on ARCH_S3C24XX
        help
          This selects a driver for the MCI interface found in
           Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
index 947faa5..efdb81d 100644 (file)
@@ -86,7 +86,6 @@ static inline int at91mci_is_mci1rev2xx(void)
 {
        return (   cpu_is_at91sam9260()
                || cpu_is_at91sam9263()
-               || cpu_is_at91cap9()
                || cpu_is_at91sam9rl()
                || cpu_is_at91sam9g10()
                || cpu_is_at91sam9g20()
index 11e589c..983e244 100644 (file)
@@ -53,6 +53,8 @@ static unsigned int fmax = 515633;
  * @sdio: variant supports SDIO
  * @st_clkdiv: true if using a ST-specific clock divider algorithm
  * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
+ * @pwrreg_powerup: power up value for MMCIPOWER register
+ * @signal_direction: input/out direction of bus signals can be indicated
  */
 struct variant_data {
        unsigned int            clkreg;
@@ -63,18 +65,22 @@ struct variant_data {
        bool                    sdio;
        bool                    st_clkdiv;
        bool                    blksz_datactrl16;
+       u32                     pwrreg_powerup;
+       bool                    signal_direction;
 };
 
 static struct variant_data variant_arm = {
        .fifosize               = 16 * 4,
        .fifohalfsize           = 8 * 4,
        .datalength_bits        = 16,
+       .pwrreg_powerup         = MCI_PWR_UP,
 };
 
 static struct variant_data variant_arm_extended_fifo = {
        .fifosize               = 128 * 4,
        .fifohalfsize           = 64 * 4,
        .datalength_bits        = 16,
+       .pwrreg_powerup         = MCI_PWR_UP,
 };
 
 static struct variant_data variant_u300 = {
@@ -83,6 +89,8 @@ static struct variant_data variant_u300 = {
        .clkreg_enable          = MCI_ST_U300_HWFCEN,
        .datalength_bits        = 16,
        .sdio                   = true,
+       .pwrreg_powerup         = MCI_PWR_ON,
+       .signal_direction       = true,
 };
 
 static struct variant_data variant_ux500 = {
@@ -93,6 +101,8 @@ static struct variant_data variant_ux500 = {
        .datalength_bits        = 24,
        .sdio                   = true,
        .st_clkdiv              = true,
+       .pwrreg_powerup         = MCI_PWR_ON,
+       .signal_direction       = true,
 };
 
 static struct variant_data variant_ux500v2 = {
@@ -104,11 +114,35 @@ static struct variant_data variant_ux500v2 = {
        .sdio                   = true,
        .st_clkdiv              = true,
        .blksz_datactrl16       = true,
+       .pwrreg_powerup         = MCI_PWR_ON,
+       .signal_direction       = true,
 };
 
 /*
  * This must be called with host->lock held
  */
+static void mmci_write_clkreg(struct mmci_host *host, u32 clk)
+{
+       if (host->clk_reg != clk) {
+               host->clk_reg = clk;
+               writel(clk, host->base + MMCICLOCK);
+       }
+}
+
+/*
+ * This must be called with host->lock held
+ */
+static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
+{
+       if (host->pwr_reg != pwr) {
+               host->pwr_reg = pwr;
+               writel(pwr, host->base + MMCIPOWER);
+       }
+}
+
+/*
+ * This must be called with host->lock held
+ */
 static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
 {
        struct variant_data *variant = host->variant;
@@ -153,7 +187,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
        if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
                clk |= MCI_ST_8BIT_BUS;
 
-       writel(clk, host->base + MMCICLOCK);
+       mmci_write_clkreg(host, clk);
 }
 
 static void
@@ -166,14 +200,10 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
        host->mrq = NULL;
        host->cmd = NULL;
 
-       /*
-        * Need to drop the host lock here; mmc_request_done may call
-        * back into the driver...
-        */
-       spin_unlock(&host->lock);
-       pm_runtime_put(mmc_dev(host->mmc));
        mmc_request_done(host->mmc, mrq);
-       spin_lock(&host->lock);
+
+       pm_runtime_mark_last_busy(mmc_dev(host->mmc));
+       pm_runtime_put_autosuspend(mmc_dev(host->mmc));
 }
 
 static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
@@ -607,6 +637,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
        if (data->flags & MMC_DATA_READ)
                datactrl |= MCI_DPSM_DIRECTION;
 
+       /* The ST Micro variants has a special bit to enable SDIO */
+       if (variant->sdio && host->mmc->card)
+               if (mmc_card_sdio(host->mmc->card))
+                       datactrl |= MCI_ST_DPSM_SDIOEN;
+
        /*
         * Attempt to use DMA operation mode, if this
         * should fail, fall back to PIO mode
@@ -635,11 +670,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
                irqmask = MCI_TXFIFOHALFEMPTYMASK;
        }
 
-       /* The ST Micro variants has a special bit to enable SDIO */
-       if (variant->sdio && host->mmc->card)
-               if (mmc_card_sdio(host->mmc->card))
-                       datactrl |= MCI_ST_DPSM_SDIOEN;
-
        writel(datactrl, base + MMCIDATACTRL);
        writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
        mmci_set_mask1(host, irqmask);
@@ -786,7 +816,24 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
                if (count <= 0)
                        break;
 
-               readsl(base + MMCIFIFO, ptr, count >> 2);
+               /*
+                * SDIO especially may want to send something that is
+                * not divisible by 4 (as opposed to card sectors
+                * etc). Therefore make sure to always read the last bytes
+                * while only doing full 32-bit reads towards the FIFO.
+                */
+               if (unlikely(count & 0x3)) {
+                       if (count < 4) {
+                               unsigned char buf[4];
+                               readsl(base + MMCIFIFO, buf, 1);
+                               memcpy(ptr, buf, count);
+                       } else {
+                               readsl(base + MMCIFIFO, ptr, count >> 2);
+                               count &= ~0x3;
+                       }
+               } else {
+                       readsl(base + MMCIFIFO, ptr, count >> 2);
+               }
 
                ptr += count;
                remain -= count;
@@ -821,14 +868,13 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
                 */
                if (variant->sdio &&
                    mmc_card_sdio(host->mmc->card)) {
+                       u32 clk;
                        if (count < 8)
-                               writel(readl(host->base + MMCICLOCK) &
-                                       ~variant->clkreg_enable,
-                                       host->base + MMCICLOCK);
+                               clk = host->clk_reg & ~variant->clkreg_enable;
                        else
-                               writel(readl(host->base + MMCICLOCK) |
-                                       variant->clkreg_enable,
-                                       host->base + MMCICLOCK);
+                               clk = host->clk_reg | variant->clkreg_enable;
+
+                       mmci_write_clkreg(host, clk);
                }
 
                /*
@@ -1015,10 +1061,17 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct mmci_host *host = mmc_priv(mmc);
+       struct variant_data *variant = host->variant;
        u32 pwr = 0;
        unsigned long flags;
        int ret;
 
+       pm_runtime_get_sync(mmc_dev(mmc));
+
+       if (host->plat->ios_handler &&
+               host->plat->ios_handler(mmc_dev(mmc), ios))
+                       dev_err(mmc_dev(mmc), "platform ios_handler failed\n");
+
        switch (ios->power_mode) {
        case MMC_POWER_OFF:
                if (host->vcc)
@@ -1035,22 +1088,38 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                                 * power should be rare so we print an error
                                 * and return here.
                                 */
-                               return;
+                               goto out;
                        }
                }
-               if (host->plat->vdd_handler)
-                       pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
-                                                      ios->power_mode);
-               /* The ST version does not have this, fall through to POWER_ON */
-               if (host->hw_designer != AMBA_VENDOR_ST) {
-                       pwr |= MCI_PWR_UP;
-                       break;
-               }
+               /*
+                * The ST Micro variant doesn't have the PL180s MCI_PWR_UP
+                * and instead uses MCI_PWR_ON so apply whatever value is
+                * configured in the variant data.
+                */
+               pwr |= variant->pwrreg_powerup;
+
+               break;
        case MMC_POWER_ON:
                pwr |= MCI_PWR_ON;
                break;
        }
 
+       if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) {
+               /*
+                * The ST Micro variant has some additional bits
+                * indicating signal direction for the signals in
+                * the SD/MMC bus and feedback-clock usage.
+                */
+               pwr |= host->plat->sigdir;
+
+               if (ios->bus_width == MMC_BUS_WIDTH_4)
+                       pwr &= ~MCI_ST_DATA74DIREN;
+               else if (ios->bus_width == MMC_BUS_WIDTH_1)
+                       pwr &= (~MCI_ST_DATA74DIREN &
+                               ~MCI_ST_DATA31DIREN &
+                               ~MCI_ST_DATA2DIREN);
+       }
+
        if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
                if (host->hw_designer != AMBA_VENDOR_ST)
                        pwr |= MCI_ROD;
@@ -1066,13 +1135,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        spin_lock_irqsave(&host->lock, flags);
 
        mmci_set_clkreg(host, ios->clock);
-
-       if (host->pwr != pwr) {
-               host->pwr = pwr;
-               writel(pwr, host->base + MMCIPOWER);
-       }
+       mmci_write_pwrreg(host, pwr);
 
        spin_unlock_irqrestore(&host->lock, flags);
+
+ out:
+       pm_runtime_mark_last_busy(mmc_dev(mmc));
+       pm_runtime_put_autosuspend(mmc_dev(mmc));
 }
 
 static int mmci_get_ro(struct mmc_host *mmc)
@@ -1326,7 +1395,7 @@ static int __devinit mmci_probe(struct amba_device *dev,
        if (ret)
                goto unmap;
 
-       if (dev->irq[1] == NO_IRQ)
+       if (dev->irq[1] == NO_IRQ || !dev->irq[1])
                host->singleirq = true;
        else {
                ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED,
@@ -1346,6 +1415,8 @@ static int __devinit mmci_probe(struct amba_device *dev,
 
        mmci_dma_setup(host);
 
+       pm_runtime_set_autosuspend_delay(&dev->dev, 50);
+       pm_runtime_use_autosuspend(&dev->dev);
        pm_runtime_put(&dev->dev);
 
        mmc_add_host(mmc);
@@ -1430,43 +1501,49 @@ static int __devexit mmci_remove(struct amba_device *dev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int mmci_suspend(struct amba_device *dev, pm_message_t state)
+#ifdef CONFIG_SUSPEND
+static int mmci_suspend(struct device *dev)
 {
-       struct mmc_host *mmc = amba_get_drvdata(dev);
+       struct amba_device *adev = to_amba_device(dev);
+       struct mmc_host *mmc = amba_get_drvdata(adev);
        int ret = 0;
 
        if (mmc) {
                struct mmci_host *host = mmc_priv(mmc);
 
                ret = mmc_suspend_host(mmc);
-               if (ret == 0)
+               if (ret == 0) {
+                       pm_runtime_get_sync(dev);
                        writel(0, host->base + MMCIMASK0);
+               }
        }
 
        return ret;
 }
 
-static int mmci_resume(struct amba_device *dev)
+static int mmci_resume(struct device *dev)
 {
-       struct mmc_host *mmc = amba_get_drvdata(dev);
+       struct amba_device *adev = to_amba_device(dev);
+       struct mmc_host *mmc = amba_get_drvdata(adev);
        int ret = 0;
 
        if (mmc) {
                struct mmci_host *host = mmc_priv(mmc);
 
                writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+               pm_runtime_put(dev);
 
                ret = mmc_resume_host(mmc);
        }
 
        return ret;
 }
-#else
-#define mmci_suspend   NULL
-#define mmci_resume    NULL
 #endif
 
+static const struct dev_pm_ops mmci_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume)
+};
+
 static struct amba_id mmci_ids[] = {
        {
                .id     = 0x00041180,
@@ -1512,26 +1589,15 @@ MODULE_DEVICE_TABLE(amba, mmci_ids);
 static struct amba_driver mmci_driver = {
        .drv            = {
                .name   = DRIVER_NAME,
+               .pm     = &mmci_dev_pm_ops,
        },
        .probe          = mmci_probe,
        .remove         = __devexit_p(mmci_remove),
-       .suspend        = mmci_suspend,
-       .resume         = mmci_resume,
        .id_table       = mmci_ids,
 };
 
-static int __init mmci_init(void)
-{
-       return amba_driver_register(&mmci_driver);
-}
-
-static void __exit mmci_exit(void)
-{
-       amba_driver_unregister(&mmci_driver);
-}
+module_amba_driver(mmci_driver);
 
-module_init(mmci_init);
-module_exit(mmci_exit);
 module_param(fmax, uint, 0444);
 
 MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
index 79e4143..d437ccf 100644 (file)
 #define MCI_PWR_ON             0x03
 #define MCI_OD                 (1 << 6)
 #define MCI_ROD                        (1 << 7)
-/*
- * The ST Micro version does not have ROD and reuse the voltage registers
- * for direction settings
- */
-#define MCI_ST_DATA2DIREN      (1 << 2)
-#define MCI_ST_CMDDIREN                (1 << 3)
-#define MCI_ST_DATA0DIREN      (1 << 4)
-#define MCI_ST_DATA31DIREN     (1 << 5)
-#define MCI_ST_FBCLKEN         (1 << 7)
-#define MCI_ST_DATA74DIREN     (1 << 8)
 
 #define MMCICLOCK              0x004
 #define MCI_CLK_ENABLE         (1 << 8)
        (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
         MCI_TXFIFOHALFEMPTYMASK)
 
-#define NR_SG          16
+#define NR_SG          128
 
 struct clk;
 struct variant_data;
@@ -189,7 +179,8 @@ struct mmci_host {
 
        unsigned int            mclk;
        unsigned int            cclk;
-       u32                     pwr;
+       u32                     pwr_reg;
+       u32                     clk_reg;
        struct mmci_platform_data *plat;
        struct variant_data     *variant;
 
index 0be4e20..6193a0d 100644 (file)
@@ -464,7 +464,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
                err = PTR_ERR(clk);
                goto err_clk_get;
        }
-       clk_enable(clk);
+       clk_prepare_enable(clk);
        pltfm_host->clk = clk;
 
        if (!is_imx25_esdhc(imx_data))
@@ -559,7 +559,7 @@ no_card_detect_irq:
                gpio_free(boarddata->wp_gpio);
 no_card_detect_pin:
 no_board_data:
-       clk_disable(pltfm_host->clk);
+       clk_disable_unprepare(pltfm_host->clk);
        clk_put(pltfm_host->clk);
 err_clk_get:
        kfree(imx_data);
@@ -586,7 +586,7 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
                gpio_free(boarddata->cd_gpio);
        }
 
-       clk_disable(pltfm_host->clk);
+       clk_disable_unprepare(pltfm_host->clk);
        clk_put(pltfm_host->clk);
        kfree(imx_data);
 
index 1af756e..b19e7d4 100644 (file)
@@ -518,9 +518,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT)
                host->mmc->caps = MMC_CAP_NONREMOVABLE;
 
-       if (pdata->host_caps)
-               host->mmc->caps |= pdata->host_caps;
-
        if (pdata->pm_caps)
                host->mmc->pm_caps |= pdata->pm_caps;
 
@@ -544,6 +541,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        if (pdata->host_caps)
                host->mmc->caps |= pdata->host_caps;
 
+       if (pdata->host_caps2)
+               host->mmc->caps2 |= pdata->host_caps2;
+
        ret = sdhci_add_host(host);
        if (ret) {
                dev_err(dev, "sdhci_add_host() failed\n");
index 78a36eb..cb34856 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/gpio.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
-#include <linux/module.h>
 
 #include <asm/gpio.h>
 
index 1be6218..284cf34 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig MTD
        tristate "Memory Technology Device (MTD) support"
-       depends on HAS_IOMEM
+       depends on GENERIC_IO
        help
          Memory Technology Devices are flash, RAM and similar chips, often
          used for solid state file systems on embedded devices. This option
index e1e122f..9bcd1f4 100644 (file)
@@ -2526,12 +2526,10 @@ static void cfi_intelext_restore_locks(struct mtd_info *mtd)
                if (!region->lockmap)
                        continue;
 
-               for (block = 0; block < region->numblocks; block++) {
+               for_each_clear_bit(block, region->lockmap, region->numblocks) {
                        len = region->erasesize;
                        adr = region->offset + block * len;
-
-                       if (!test_bit(block, region->lockmap))
-                               cfi_intelext_unlock(mtd, adr, len);
+                       cfi_intelext_unlock(mtd, adr, len);
                }
        }
 }
index 37b05c3..8d3dac4 100644 (file)
@@ -1,5 +1,6 @@
 menu "Self-contained MTD device drivers"
        depends on MTD!=n
+       depends on HAS_IOMEM
 
 config MTD_PMC551
        tristate "Ramix PMC551 PCI Mezzanine RAM card support"
index 6c5c431..8af67cf 100644 (file)
@@ -1,5 +1,6 @@
 menu "Mapping drivers for chip access"
        depends on MTD!=n
+       depends on HAS_IOMEM
 
 config MTD_COMPLEX_MAPPINGS
        bool "Support non-linear mappings of flash chips"
index 5028219..cbc3b78 100644 (file)
 #include <asm/sizes.h>
 #include <asm/mach/flash.h>
 
-#if 0
-/*
- * This is here for documentation purposes only - until these people
- * submit their machine types.  It will be gone January 2005.
- */
-static struct mtd_partition consus_partitions[] = {
-       {
-               .name           = "Consus boot firmware",
-               .offset         = 0,
-               .size           = 0x00040000,
-               .mask_flags     = MTD_WRITABLE, /* force read-only */
-       }, {
-               .name           = "Consus kernel",
-               .offset         = 0x00040000,
-               .size           = 0x00100000,
-               .mask_flags     = 0,
-       }, {
-               .name           = "Consus disk",
-               .offset         = 0x00140000,
-               /* The rest (up to 16M) for jffs.  We could put 0 and
-                  make it find the size automatically, but right now
-                  i have 32 megs.  jffs will use all 32 megs if given
-                  the chance, and this leads to horrible problems
-                  when you try to re-flash the image because blob
-                  won't erase the whole partition. */
-               .size           = 0x01000000 - 0x00140000,
-               .mask_flags     = 0,
-       }, {
-               /* this disk is a secondary disk, which can be used as
-                  needed, for simplicity, make it the size of the other
-                  consus partition, although realistically it could be
-                  the remainder of the disk (depending on the file
-                  system used) */
-                .name          = "Consus disk2",
-                .offset        = 0x01000000,
-                .size          = 0x01000000 - 0x00140000,
-                .mask_flags    = 0,
-       }
-};
-
-/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
-static struct mtd_partition frodo_partitions[] =
-{
-       {
-               .name           = "bootloader",
-               .size           = 0x00040000,
-               .offset         = 0x00000000,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "bootloader params",
-               .size           = 0x00040000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "kernel",
-               .size           = 0x00100000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "ramdisk",
-               .size           = 0x00400000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "file system",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND
-       }
-};
-
-static struct mtd_partition jornada56x_partitions[] = {
-       {
-               .name           = "bootldr",
-               .size           = 0x00040000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "rootfs",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-
-static void jornada56x_set_vpp(int vpp)
-{
-       if (vpp)
-               GPSR = GPIO_GPIO26;
-       else
-               GPCR = GPIO_GPIO26;
-       GPDR |= GPIO_GPIO26;
-}
-
-/*
- * Machine        Phys          Size    set_vpp
- * Consus    : SA1100_CS0_PHYS SZ_32M
- * Frodo     : SA1100_CS0_PHYS SZ_32M
- * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
- */
-#endif
-
 struct sa_subdev_info {
        char name[16];
        struct map_info map;
@@ -373,21 +273,9 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static void sa1100_mtd_shutdown(struct platform_device *dev)
-{
-       struct sa_info *info = platform_get_drvdata(dev);
-       if (info && mtd_suspend(info->mtd) == 0)
-               mtd_resume(info->mtd);
-}
-#else
-#define sa1100_mtd_shutdown NULL
-#endif
-
 static struct platform_driver sa1100_mtd_driver = {
        .probe          = sa1100_mtd_probe,
        .remove         = __exit_p(sa1100_mtd_remove),
-       .shutdown       = sa1100_mtd_shutdown,
        .driver         = {
                .name   = "sa1100-mtd",
                .owner  = THIS_MODULE,
index 50c6a1e..c57ae92 100644 (file)
 #include <linux/compat.h>
 #include <linux/mount.h>
 #include <linux/blkpg.h>
+#include <linux/magic.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/map.h>
 
 #include <asm/uaccess.h>
 
-#define MTD_INODE_FS_MAGIC 0x11307854
 static DEFINE_MUTEX(mtd_mutex);
 static struct vfsmount *mtd_inode_mnt __read_mostly;
 
index 3b1d6da..a3c4de5 100644 (file)
@@ -187,7 +187,7 @@ config MTD_NAND_PPCHAMELEONEVB
 
 config MTD_NAND_S3C2410
        tristate "NAND Flash support for Samsung S3C SoCs"
-       depends on ARCH_S3C2410 || ARCH_S3C64XX
+       depends on ARCH_S3C24XX || ARCH_S3C64XX
        help
          This enables the NAND flash controller on the S3C24xx and S3C64xx
          SoCs
@@ -246,6 +246,7 @@ config MTD_NAND_BCM_UMI_HWCS
 config MTD_NAND_DISKONCHIP
        tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
        depends on EXPERIMENTAL
+       depends on HAS_IOMEM
        select REED_SOLOMON
        select REED_SOLOMON_DEC16
        help
@@ -431,6 +432,7 @@ config MTD_NAND_GPMI_NAND
 
 config MTD_NAND_PLATFORM
        tristate "Support for generic platform NAND driver"
+       depends on HAS_IOMEM
        help
          This implements a generic NAND driver for on-SOC platform
          devices. You will need to provide platform-specific functions
index 3197e97..7341695 100644 (file)
@@ -26,7 +26,7 @@
 #include <asm/io.h>
 #include <mach/hardware.h>
 #include <asm/sizes.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 #include <plat/board-ams-delta.h>
 
 /*
@@ -34,8 +34,6 @@
  */
 static struct mtd_info *ams_delta_mtd = NULL;
 
-#define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP)
-
 /*
  * Define partitions for flash devices
  */
@@ -68,10 +66,9 @@ static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
 
        writew(0, io_base + OMAP_MPUIO_IO_CNTL);
        writew(byte, this->IO_ADDR_W);
-       ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0);
+       gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 0);
        ndelay(40);
-       ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE,
-                              AMS_DELTA_LATCH2_NAND_NWE);
+       gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NWE, 1);
 }
 
 static u_char ams_delta_read_byte(struct mtd_info *mtd)
@@ -80,12 +77,11 @@ static u_char ams_delta_read_byte(struct mtd_info *mtd)
        struct nand_chip *this = mtd->priv;
        void __iomem *io_base = this->priv;
 
-       ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0);
+       gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 0);
        ndelay(40);
        writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
        res = readw(this->IO_ADDR_R);
-       ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE,
-                              AMS_DELTA_LATCH2_NAND_NRE);
+       gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NRE, 1);
 
        return res;
 }
@@ -132,15 +128,12 @@ static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
 {
 
        if (ctrl & NAND_CTRL_CHANGE) {
-               unsigned long bits;
-
-               bits = (~ctrl & NAND_NCE) ? AMS_DELTA_LATCH2_NAND_NCE : 0;
-               bits |= (ctrl & NAND_CLE) ? AMS_DELTA_LATCH2_NAND_CLE : 0;
-               bits |= (ctrl & NAND_ALE) ? AMS_DELTA_LATCH2_NAND_ALE : 0;
-
-               ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE |
-                               AMS_DELTA_LATCH2_NAND_ALE |
-                               AMS_DELTA_LATCH2_NAND_NCE, bits);
+               gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_NCE,
+                               (ctrl & NAND_NCE) == 0);
+               gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_CLE,
+                               (ctrl & NAND_CLE) != 0);
+               gpio_set_value(AMS_DELTA_GPIO_PIN_NAND_ALE,
+                               (ctrl & NAND_ALE) != 0);
        }
 
        if (cmd != NAND_CMD_NONE)
@@ -152,6 +145,39 @@ static int ams_delta_nand_ready(struct mtd_info *mtd)
        return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
 }
 
+static const struct gpio _mandatory_gpio[] = {
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_NAND_NCE,
+               .flags  = GPIOF_OUT_INIT_HIGH,
+               .label  = "nand_nce",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_NAND_NRE,
+               .flags  = GPIOF_OUT_INIT_HIGH,
+               .label  = "nand_nre",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_NAND_NWP,
+               .flags  = GPIOF_OUT_INIT_HIGH,
+               .label  = "nand_nwp",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_NAND_NWE,
+               .flags  = GPIOF_OUT_INIT_HIGH,
+               .label  = "nand_nwe",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_NAND_ALE,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "nand_ale",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_NAND_CLE,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "nand_cle",
+       },
+};
+
 /*
  * Main initialization routine
  */
@@ -223,10 +249,9 @@ static int __devinit ams_delta_init(struct platform_device *pdev)
        platform_set_drvdata(pdev, io_base);
 
        /* Set chip enabled, but  */
-       ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
-                                         AMS_DELTA_LATCH2_NAND_NWE |
-                                         AMS_DELTA_LATCH2_NAND_NCE |
-                                         AMS_DELTA_LATCH2_NAND_NWP);
+       err = gpio_request_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+       if (err)
+               goto out_gpio;
 
        /* Scan to find existence of the device */
        if (nand_scan(ams_delta_mtd, 1)) {
@@ -241,7 +266,10 @@ static int __devinit ams_delta_init(struct platform_device *pdev)
        goto out;
 
  out_mtd:
+       gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+out_gpio:
        platform_set_drvdata(pdev, NULL);
+       gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
        iounmap(io_base);
 out_release_io:
        release_mem_region(res->start, resource_size(res));
@@ -262,6 +290,8 @@ static int __devexit ams_delta_cleanup(struct platform_device *pdev)
        /* Release resources, unregister device */
        nand_release(ams_delta_mtd);
 
+       gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
+       gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
        iounmap(io_base);
        release_mem_region(res->start, resource_size(res));
 
index 35b4fb5..ae7e37d 100644 (file)
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_mtd.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/dmaengine.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <linux/platform_data/atmel.h>
 
-#include <mach/board.h>
 #include <mach/cpu.h>
 
-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW
-#define hard_ecc       1
-#else
-#define hard_ecc       0
-#endif
-
-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE
-#define no_ecc         1
-#else
-#define no_ecc         0
-#endif
-
 static int use_dma = 1;
 module_param(use_dma, int, 0);
 
@@ -95,7 +87,7 @@ struct atmel_nand_host {
        struct mtd_info         mtd;
        void __iomem            *io_base;
        dma_addr_t              io_phys;
-       struct atmel_nand_data  *board;
+       struct atmel_nand_data  board;
        struct device           *dev;
        void __iomem            *ecc;
 
@@ -113,8 +105,8 @@ static int cpu_has_dma(void)
  */
 static void atmel_nand_enable(struct atmel_nand_host *host)
 {
-       if (gpio_is_valid(host->board->enable_pin))
-               gpio_set_value(host->board->enable_pin, 0);
+       if (gpio_is_valid(host->board.enable_pin))
+               gpio_set_value(host->board.enable_pin, 0);
 }
 
 /*
@@ -122,8 +114,8 @@ static void atmel_nand_enable(struct atmel_nand_host *host)
  */
 static void atmel_nand_disable(struct atmel_nand_host *host)
 {
-       if (gpio_is_valid(host->board->enable_pin))
-               gpio_set_value(host->board->enable_pin, 1);
+       if (gpio_is_valid(host->board.enable_pin))
+               gpio_set_value(host->board.enable_pin, 1);
 }
 
 /*
@@ -144,9 +136,9 @@ static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl
                return;
 
        if (ctrl & NAND_CLE)
-               writeb(cmd, host->io_base + (1 << host->board->cle));
+               writeb(cmd, host->io_base + (1 << host->board.cle));
        else
-               writeb(cmd, host->io_base + (1 << host->board->ale));
+               writeb(cmd, host->io_base + (1 << host->board.ale));
 }
 
 /*
@@ -157,8 +149,8 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
        struct nand_chip *nand_chip = mtd->priv;
        struct atmel_nand_host *host = nand_chip->priv;
 
-       return gpio_get_value(host->board->rdy_pin) ^
-                !!host->board->rdy_pin_active_low;
+       return gpio_get_value(host->board.rdy_pin) ^
+                !!host->board.rdy_pin_active_low;
 }
 
 /*
@@ -273,7 +265,7 @@ static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
                if (atmel_nand_dma_op(mtd, buf, len, 1) == 0)
                        return;
 
-       if (host->board->bus_width_16)
+       if (host->board.bus_width_16)
                atmel_read_buf16(mtd, buf, len);
        else
                atmel_read_buf8(mtd, buf, len);
@@ -289,7 +281,7 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
                if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0)
                        return;
 
-       if (host->board->bus_width_16)
+       if (host->board.bus_width_16)
                atmel_write_buf16(mtd, buf, len);
        else
                atmel_write_buf8(mtd, buf, len);
@@ -481,6 +473,56 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
        }
 }
 
+#if defined(CONFIG_OF)
+static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+                                        struct device_node *np)
+{
+       u32 val;
+       int ecc_mode;
+       struct atmel_nand_data *board = &host->board;
+       enum of_gpio_flags flags;
+
+       if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
+               if (val >= 32) {
+                       dev_err(host->dev, "invalid addr-offset %u\n", val);
+                       return -EINVAL;
+               }
+               board->ale = val;
+       }
+
+       if (of_property_read_u32(np, "atmel,nand-cmd-offset", &val) == 0) {
+               if (val >= 32) {
+                       dev_err(host->dev, "invalid cmd-offset %u\n", val);
+                       return -EINVAL;
+               }
+               board->cle = val;
+       }
+
+       ecc_mode = of_get_nand_ecc_mode(np);
+
+       board->ecc_mode = ecc_mode < 0 ? NAND_ECC_SOFT : ecc_mode;
+
+       board->on_flash_bbt = of_get_nand_on_flash_bbt(np);
+
+       if (of_get_nand_bus_width(np) == 16)
+               board->bus_width_16 = 1;
+
+       board->rdy_pin = of_get_gpio_flags(np, 0, &flags);
+       board->rdy_pin_active_low = (flags == OF_GPIO_ACTIVE_LOW);
+
+       board->enable_pin = of_get_gpio(np, 1);
+       board->det_pin = of_get_gpio(np, 2);
+
+       return 0;
+}
+#else
+static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+                                        struct device_node *np)
+{
+       return -EINVAL;
+}
+#endif
+
 /*
  * Probe for the NAND device.
  */
@@ -491,6 +533,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        struct nand_chip *nand_chip;
        struct resource *regs;
        struct resource *mem;
+       struct mtd_part_parser_data ppdata = {};
        int res;
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -517,8 +560,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 
        mtd = &host->mtd;
        nand_chip = &host->nand_chip;
-       host->board = pdev->dev.platform_data;
        host->dev = &pdev->dev;
+       if (pdev->dev.of_node) {
+               res = atmel_of_init_port(host, pdev->dev.of_node);
+               if (res)
+                       goto err_nand_ioremap;
+       } else {
+               memcpy(&host->board, pdev->dev.platform_data,
+                      sizeof(struct atmel_nand_data));
+       }
 
        nand_chip->priv = host;         /* link the private data structures */
        mtd->priv = nand_chip;
@@ -529,26 +579,25 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        nand_chip->IO_ADDR_W = host->io_base;
        nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 
-       if (gpio_is_valid(host->board->rdy_pin))
+       if (gpio_is_valid(host->board.rdy_pin))
                nand_chip->dev_ready = atmel_nand_device_ready;
 
+       nand_chip->ecc.mode = host->board.ecc_mode;
+
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (!regs && hard_ecc) {
+       if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) {
                printk(KERN_ERR "atmel_nand: can't get I/O resource "
                                "regs\nFalling back on software ECC\n");
+               nand_chip->ecc.mode = NAND_ECC_SOFT;
        }
 
-       nand_chip->ecc.mode = NAND_ECC_SOFT;    /* enable ECC */
-       if (no_ecc)
-               nand_chip->ecc.mode = NAND_ECC_NONE;
-       if (hard_ecc && regs) {
+       if (nand_chip->ecc.mode == NAND_ECC_HW) {
                host->ecc = ioremap(regs->start, resource_size(regs));
                if (host->ecc == NULL) {
                        printk(KERN_ERR "atmel_nand: ioremap failed\n");
                        res = -EIO;
                        goto err_ecc_ioremap;
                }
-               nand_chip->ecc.mode = NAND_ECC_HW;
                nand_chip->ecc.calculate = atmel_nand_calculate;
                nand_chip->ecc.correct = atmel_nand_correct;
                nand_chip->ecc.hwctl = atmel_nand_hwctl;
@@ -558,7 +607,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
 
        nand_chip->chip_delay = 20;             /* 20us command delay time */
 
-       if (host->board->bus_width_16)  /* 16-bit bus width */
+       if (host->board.bus_width_16)   /* 16-bit bus width */
                nand_chip->options |= NAND_BUSWIDTH_16;
 
        nand_chip->read_buf = atmel_read_buf;
@@ -567,15 +616,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, host);
        atmel_nand_enable(host);
 
-       if (gpio_is_valid(host->board->det_pin)) {
-               if (gpio_get_value(host->board->det_pin)) {
+       if (gpio_is_valid(host->board.det_pin)) {
+               if (gpio_get_value(host->board.det_pin)) {
                        printk(KERN_INFO "No SmartMedia card inserted.\n");
                        res = -ENXIO;
                        goto err_no_card;
                }
        }
 
-       if (on_flash_bbt) {
+       if (host->board.on_flash_bbt || on_flash_bbt) {
                printk(KERN_INFO "atmel_nand: Use On Flash BBT\n");
                nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
        }
@@ -650,8 +699,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        }
 
        mtd->name = "atmel_nand";
-       res = mtd_device_parse_register(mtd, NULL, 0,
-                       host->board->parts, host->board->num_parts);
+       ppdata.of_node = pdev->dev.of_node;
+       res = mtd_device_parse_register(mtd, NULL, &ppdata,
+                       host->board.parts, host->board.num_parts);
        if (!res)
                return res;
 
@@ -695,11 +745,21 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_nand_dt_ids[] = {
+       { .compatible = "atmel,at91rm9200-nand" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
+#endif
+
 static struct platform_driver atmel_nand_driver = {
        .remove         = __exit_p(atmel_nand_remove),
        .driver         = {
                .name   = "atmel_nand",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(atmel_nand_dt_ids),
        },
 };
 
index 772ad29..91467bb 100644 (file)
@@ -1,6 +1,7 @@
 menuconfig MTD_ONENAND
        tristate "OneNAND Device Support"
        depends on MTD
+       depends on HAS_IOMEM
        help
          This enables support for accessing all type of OneNAND flash
          devices. For further information see
index 115749f..0fde9fc 100644 (file)
@@ -945,12 +945,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
                goto out_free;
 
        err = -ENOMEM;
-       ubi->peb_buf1 = vmalloc(ubi->peb_size);
-       if (!ubi->peb_buf1)
-               goto out_free;
-
-       ubi->peb_buf2 = vmalloc(ubi->peb_size);
-       if (!ubi->peb_buf2)
+       ubi->peb_buf = vmalloc(ubi->peb_size);
+       if (!ubi->peb_buf)
                goto out_free;
 
        err = ubi_debugging_init_dev(ubi);
@@ -1029,8 +1025,7 @@ out_detach:
 out_debugging:
        ubi_debugging_exit_dev(ubi);
 out_free:
-       vfree(ubi->peb_buf1);
-       vfree(ubi->peb_buf2);
+       vfree(ubi->peb_buf);
        if (ref)
                put_device(&ubi->dev);
        else
@@ -1101,8 +1096,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
        vfree(ubi->vtbl);
        put_mtd_device(ubi->mtd);
        ubi_debugging_exit_dev(ubi);
-       vfree(ubi->peb_buf1);
-       vfree(ubi->peb_buf2);
+       vfree(ubi->peb_buf);
        ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
        put_device(&ubi->dev);
        return 0;
index cd26da8..2455d62 100644 (file)
@@ -529,18 +529,18 @@ retry:
 
        data_size = offset + len;
        mutex_lock(&ubi->buf_mutex);
-       memset(ubi->peb_buf1 + offset, 0xFF, len);
+       memset(ubi->peb_buf + offset, 0xFF, len);
 
        /* Read everything before the area where the write failure happened */
        if (offset > 0) {
-               err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset);
+               err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, offset);
                if (err && err != UBI_IO_BITFLIPS)
                        goto out_unlock;
        }
 
-       memcpy(ubi->peb_buf1 + offset, buf, len);
+       memcpy(ubi->peb_buf + offset, buf, len);
 
-       err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size);
+       err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
        if (err) {
                mutex_unlock(&ubi->buf_mutex);
                goto write_error;
@@ -979,7 +979,7 @@ static int is_error_sane(int err)
  * physical eraseblock @to. The @vid_hdr buffer may be changed by this
  * function. Returns:
  *   o %0 in case of success;
- *   o %MOVE_CANCEL_RACE, %MOVE_TARGET_WR_ERR, %MOVE_CANCEL_BITFLIPS, etc;
+ *   o %MOVE_CANCEL_RACE, %MOVE_TARGET_WR_ERR, %MOVE_TARGET_BITFLIPS, etc;
  *   o a negative error code in case of failure.
  */
 int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
@@ -1053,13 +1053,13 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
 
        /*
         * OK, now the LEB is locked and we can safely start moving it. Since
-        * this function utilizes the @ubi->peb_buf1 buffer which is shared
+        * this function utilizes the @ubi->peb_buf buffer which is shared
         * with some other functions - we lock the buffer by taking the
         * @ubi->buf_mutex.
         */
        mutex_lock(&ubi->buf_mutex);
        dbg_wl("read %d bytes of data", aldata_size);
-       err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
+       err = ubi_io_read_data(ubi, ubi->peb_buf, from, 0, aldata_size);
        if (err && err != UBI_IO_BITFLIPS) {
                ubi_warn("error %d while reading data from PEB %d",
                         err, from);
@@ -1079,10 +1079,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
         */
        if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
                aldata_size = data_size =
-                       ubi_calc_data_len(ubi, ubi->peb_buf1, data_size);
+                       ubi_calc_data_len(ubi, ubi->peb_buf, data_size);
 
        cond_resched();
-       crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size);
+       crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size);
        cond_resched();
 
        /*
@@ -1116,12 +1116,12 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                        if (is_error_sane(err))
                                err = MOVE_TARGET_RD_ERR;
                } else
-                       err = MOVE_CANCEL_BITFLIPS;
+                       err = MOVE_TARGET_BITFLIPS;
                goto out_unlock_buf;
        }
 
        if (data_size > 0) {
-               err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
+               err = ubi_io_write_data(ubi, ubi->peb_buf, to, 0, aldata_size);
                if (err) {
                        if (err == -EIO)
                                err = MOVE_TARGET_WR_ERR;
@@ -1134,8 +1134,8 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                 * We've written the data and are going to read it back to make
                 * sure it was written correctly.
                 */
-
-               err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size);
+               memset(ubi->peb_buf, 0xFF, aldata_size);
+               err = ubi_io_read_data(ubi, ubi->peb_buf, to, 0, aldata_size);
                if (err) {
                        if (err != UBI_IO_BITFLIPS) {
                                ubi_warn("error %d while reading data back "
@@ -1143,13 +1143,13 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                                if (is_error_sane(err))
                                        err = MOVE_TARGET_RD_ERR;
                        } else
-                               err = MOVE_CANCEL_BITFLIPS;
+                               err = MOVE_TARGET_BITFLIPS;
                        goto out_unlock_buf;
                }
 
                cond_resched();
 
-               if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
+               if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size)) {
                        ubi_warn("read data back from PEB %d and it is "
                                 "different", to);
                        err = -EINVAL;
index 5cde4e5..43f1a00 100644 (file)
@@ -431,11 +431,11 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
                        goto out;
 
                /* Make sure the PEB contains only 0xFF bytes */
-               err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
+               err = ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
                if (err)
                        goto out;
 
-               err = ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size);
+               err = ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->peb_size);
                if (err == 0) {
                        ubi_err("erased PEB %d, but a non-0xFF byte found",
                                pnum);
@@ -444,17 +444,17 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
                }
 
                /* Write a pattern and check it */
-               memset(ubi->peb_buf1, patterns[i], ubi->peb_size);
-               err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
+               memset(ubi->peb_buf, patterns[i], ubi->peb_size);
+               err = ubi_io_write(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
                if (err)
                        goto out;
 
-               memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size);
-               err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
+               memset(ubi->peb_buf, ~patterns[i], ubi->peb_size);
+               err = ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
                if (err)
                        goto out;
 
-               err = ubi_check_pattern(ubi->peb_buf1, patterns[i],
+               err = ubi_check_pattern(ubi->peb_buf, patterns[i],
                                        ubi->peb_size);
                if (err == 0) {
                        ubi_err("pattern %x checking failed for PEB %d",
index 0cb17d9..12c43b4 100644 (file)
@@ -789,9 +789,9 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
        int err;
 
        mutex_lock(&ubi->buf_mutex);
-       memset(ubi->peb_buf1, 0x00, ubi->leb_size);
+       memset(ubi->peb_buf, 0x00, ubi->leb_size);
 
-       err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start,
+       err = ubi_io_read(ubi, ubi->peb_buf, pnum, ubi->leb_start,
                          ubi->leb_size);
        if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {
                /*
@@ -808,7 +808,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
        if (err)
                goto out_unlock;
 
-       if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size))
+       if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size))
                goto out_unlock;
 
        ubi_err("PEB %d contains corrupted VID header, and the data does not "
@@ -818,7 +818,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
        dbg_msg("hexdump of PEB %d offset %d, length %d",
                pnum, ubi->leb_start, ubi->leb_size);
        ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
-                              ubi->peb_buf1, ubi->leb_size, 1);
+                              ubi->peb_buf, ubi->leb_size, 1);
        err = 1;
 
 out_unlock:
@@ -1174,7 +1174,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
 
        ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
        if (!ech)
-               goto out_slab;
+               goto out_si;
 
        vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
        if (!vidh)
@@ -1235,8 +1235,6 @@ out_vidh:
        ubi_free_vid_hdr(ubi, vidh);
 out_ech:
        kfree(ech);
-out_slab:
-       kmem_cache_destroy(si->scan_leb_slab);
 out_si:
        ubi_scan_destroy_si(si);
        return ERR_PTR(err);
@@ -1325,7 +1323,9 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
                }
        }
 
-       kmem_cache_destroy(si->scan_leb_slab);
+       if (si->scan_leb_slab)
+               kmem_cache_destroy(si->scan_leb_slab);
+
        kfree(si);
 }
 
index d51d75d..b162790 100644 (file)
@@ -118,7 +118,7 @@ enum {
  *                     PEB
  * MOVE_TARGET_WR_ERR: canceled because there was a write error to the target
  *                     PEB
- * MOVE_CANCEL_BITFLIPS: canceled because a bit-flip was detected in the
+ * MOVE_TARGET_BITFLIPS: canceled because a bit-flip was detected in the
  *                       target PEB
  * MOVE_RETRY: retry scrubbing the PEB
  */
@@ -127,7 +127,7 @@ enum {
        MOVE_SOURCE_RD_ERR,
        MOVE_TARGET_RD_ERR,
        MOVE_TARGET_WR_ERR,
-       MOVE_CANCEL_BITFLIPS,
+       MOVE_TARGET_BITFLIPS,
        MOVE_RETRY,
 };
 
@@ -387,9 +387,8 @@ struct ubi_wl_entry;
  *                  time (MTD write buffer size)
  * @mtd: MTD device descriptor
  *
- * @peb_buf1: a buffer of PEB size used for different purposes
- * @peb_buf2: another buffer of PEB size used for different purposes
- * @buf_mutex: protects @peb_buf1 and @peb_buf2
+ * @peb_buf: a buffer of PEB size used for different purposes
+ * @buf_mutex: protects @peb_buf
  * @ckvol_mutex: serializes static volume checking when opening
  *
  * @dbg: debugging information for this UBI device
@@ -471,8 +470,7 @@ struct ubi_device {
        int max_write_size;
        struct mtd_info *mtd;
 
-       void *peb_buf1;
-       void *peb_buf2;
+       void *peb_buf;
        struct mutex buf_mutex;
        struct mutex ckvol_mutex;
 
index 0696e36..7c1a9bf 100644 (file)
@@ -350,18 +350,19 @@ static void prot_queue_add(struct ubi_device *ubi, struct ubi_wl_entry *e)
 /**
  * find_wl_entry - find wear-leveling entry closest to certain erase counter.
  * @root: the RB-tree where to look for
- * @max: highest possible erase counter
+ * @diff: maximum possible difference from the smallest erase counter
  *
  * This function looks for a wear leveling entry with erase counter closest to
- * @max and less than @max.
+ * min + @diff, where min is the smallest erase counter.
  */
-static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max)
+static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int diff)
 {
        struct rb_node *p;
        struct ubi_wl_entry *e;
+       int max;
 
        e = rb_entry(rb_first(root), struct ubi_wl_entry, u.rb);
-       max += e->ec;
+       max = e->ec + diff;
 
        p = root->rb_node;
        while (p) {
@@ -389,7 +390,7 @@ static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max)
  */
 int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
 {
-       int err, medium_ec;
+       int err;
        struct ubi_wl_entry *e, *first, *last;
 
        ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
@@ -427,7 +428,7 @@ retry:
                 * For unknown data we pick a physical eraseblock with medium
                 * erase counter. But we by no means can pick a physical
                 * eraseblock with erase counter greater or equivalent than the
-                * lowest erase counter plus %WL_FREE_MAX_DIFF.
+                * lowest erase counter plus %WL_FREE_MAX_DIFF/2.
                 */
                first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry,
                                        u.rb);
@@ -436,10 +437,8 @@ retry:
                if (last->ec - first->ec < WL_FREE_MAX_DIFF)
                        e = rb_entry(ubi->free.rb_node,
                                        struct ubi_wl_entry, u.rb);
-               else {
-                       medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2;
-                       e = find_wl_entry(&ubi->free, medium_ec);
-               }
+               else
+                       e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
                break;
        case UBI_SHORTTERM:
                /*
@@ -799,7 +798,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                        scrubbing = 1;
                        goto out_not_moved;
                }
-               if (err == MOVE_CANCEL_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
+               if (err == MOVE_TARGET_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
                    err == MOVE_TARGET_RD_ERR) {
                        /*
                         * Target PEB had bit-flips or write error - torture it.
index 068c356..88bbd8f 100644 (file)
@@ -190,8 +190,10 @@ static struct devprobe2 isa_probes[] __initdata = {
        {seeq8005_probe, 0},
 #endif
 #ifdef CONFIG_CS89x0
+#ifndef CONFIG_CS89x0_PLATFORM
        {cs89x0_probe, 0},
 #endif
+#endif
 #ifdef CONFIG_AT1700
        {at1700_probe, 0},
 #endif
index d6e8586..0c76186 100644 (file)
@@ -2572,12 +2572,16 @@ re_arm:
 static int bond_has_this_ip(struct bonding *bond, __be32 ip)
 {
        struct vlan_entry *vlan;
+       struct net_device *vlan_dev;
 
-       if (ip == bond->master_ip)
+       if (ip == bond_confirm_addr(bond->dev, 0, ip))
                return 1;
 
        list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               if (ip == vlan->vlan_ip)
+               rcu_read_lock();
+               vlan_dev = __vlan_find_dev_deep(bond->dev, vlan->vlan_id);
+               rcu_read_unlock();
+               if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip))
                        return 1;
        }
 
@@ -2619,17 +2623,19 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
        int i, vlan_id;
        __be32 *targets = bond->params.arp_targets;
        struct vlan_entry *vlan;
-       struct net_device *vlan_dev;
+       struct net_device *vlan_dev = NULL;
        struct rtable *rt;
 
        for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) {
+               __be32 addr;
                if (!targets[i])
                        break;
                pr_debug("basa: target %x\n", targets[i]);
                if (!bond_vlan_used(bond)) {
                        pr_debug("basa: empty vlan: arp_send\n");
+                       addr = bond_confirm_addr(bond->dev, targets[i], 0);
                        bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
-                                     bond->master_ip, 0);
+                                     addr, 0);
                        continue;
                }
 
@@ -2654,8 +2660,9 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
                if (rt->dst.dev == bond->dev) {
                        ip_rt_put(rt);
                        pr_debug("basa: rtdev == bond->dev: arp_send\n");
+                       addr = bond_confirm_addr(bond->dev, targets[i], 0);
                        bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
-                                     bond->master_ip, 0);
+                                     addr, 0);
                        continue;
                }
 
@@ -2673,10 +2680,11 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
                        }
                }
 
-               if (vlan_id) {
+               if (vlan_id && vlan_dev) {
                        ip_rt_put(rt);
+                       addr = bond_confirm_addr(vlan_dev, targets[i], 0);
                        bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
-                                     vlan->vlan_ip, vlan_id);
+                                     addr, vlan_id);
                        continue;
                }
 
@@ -3298,68 +3306,10 @@ static int bond_netdev_event(struct notifier_block *this,
        return NOTIFY_DONE;
 }
 
-/*
- * bond_inetaddr_event: handle inetaddr notifier chain events.
- *
- * We keep track of device IPs primarily to use as source addresses in
- * ARP monitor probes (rather than spewing out broadcasts all the time).
- *
- * We track one IP for the main device (if it has one), plus one per VLAN.
- */
-static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
-       struct in_ifaddr *ifa = ptr;
-       struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev;
-       struct bond_net *bn = net_generic(dev_net(event_dev), bond_net_id);
-       struct bonding *bond;
-       struct vlan_entry *vlan;
-
-       /* we only care about primary address */
-       if(ifa->ifa_flags & IFA_F_SECONDARY)
-               return NOTIFY_DONE;
-
-       list_for_each_entry(bond, &bn->dev_list, bond_list) {
-               if (bond->dev == event_dev) {
-                       switch (event) {
-                       case NETDEV_UP:
-                               bond->master_ip = ifa->ifa_local;
-                               return NOTIFY_OK;
-                       case NETDEV_DOWN:
-                               bond->master_ip = 0;
-                               return NOTIFY_OK;
-                       default:
-                               return NOTIFY_DONE;
-                       }
-               }
-
-               list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-                       vlan_dev = __vlan_find_dev_deep(bond->dev,
-                                                       vlan->vlan_id);
-                       if (vlan_dev == event_dev) {
-                               switch (event) {
-                               case NETDEV_UP:
-                                       vlan->vlan_ip = ifa->ifa_local;
-                                       return NOTIFY_OK;
-                               case NETDEV_DOWN:
-                                       vlan->vlan_ip = 0;
-                                       return NOTIFY_OK;
-                               default:
-                                       return NOTIFY_DONE;
-                               }
-                       }
-               }
-       }
-       return NOTIFY_DONE;
-}
-
 static struct notifier_block bond_netdev_notifier = {
        .notifier_call = bond_netdev_event,
 };
 
-static struct notifier_block bond_inetaddr_notifier = {
-       .notifier_call = bond_inetaddr_event,
-};
-
 /*---------------------------- Hashing Policies -----------------------------*/
 
 /*
@@ -4928,7 +4878,6 @@ static int __init bonding_init(void)
        }
 
        register_netdevice_notifier(&bond_netdev_notifier);
-       register_inetaddr_notifier(&bond_inetaddr_notifier);
 out:
        return res;
 err:
@@ -4942,7 +4891,6 @@ err_link:
 static void __exit bonding_exit(void)
 {
        unregister_netdevice_notifier(&bond_netdev_notifier);
-       unregister_inetaddr_notifier(&bond_inetaddr_notifier);
 
        bond_destroy_debugfs();
 
index 1aecc37..9f2bae6 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/cpumask.h>
 #include <linux/in6.h>
 #include <linux/netpoll.h>
+#include <linux/inetdevice.h>
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
@@ -166,7 +167,6 @@ struct bond_parm_tbl {
 
 struct vlan_entry {
        struct list_head vlan_list;
-       __be32 vlan_ip;
        unsigned short vlan_id;
 };
 
@@ -232,7 +232,6 @@ struct bonding {
        struct   list_head bond_list;
        struct   netdev_hw_addr_list mc_list;
        int      (*xmit_hash_policy)(struct sk_buff *, int);
-       __be32   master_ip;
        u16      rr_tx_counter;
        struct   ad_bond_info ad_info;
        struct   alb_bond_info alb_info;
@@ -378,6 +377,21 @@ static inline bool bond_is_slave_inactive(struct slave *slave)
        return slave->inactive;
 }
 
+static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be32 local)
+{
+       struct in_device *in_dev;
+       __be32 addr = 0;
+
+       rcu_read_lock();
+       in_dev = __in_dev_get_rcu(dev);
+
+       if (in_dev)
+               addr = inet_confirm_addr(in_dev, dst, local, RT_SCOPE_HOST);
+
+       rcu_read_unlock();
+       return addr;
+}
+
 struct bond_net;
 
 struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
index 7b65716..c95e7b5 100644 (file)
@@ -47,6 +47,7 @@
 #include "bnx2x/bnx2x_hsi.h"
 #include "../../../scsi/bnx2i/57xx_iscsi_constants.h"
 #include "../../../scsi/bnx2i/57xx_iscsi_hsi.h"
+#include "../../../scsi/bnx2fc/bnx2fc_constants.h"
 #include "cnic.h"
 #include "cnic_defs.h"
 
@@ -2547,7 +2548,7 @@ static void cnic_bnx2x_kwqe_err(struct cnic_dev *dev, struct kwqe *kwqe)
                }
                kcqe.kcqe_op_flag = kcqe_op << KCQE_FLAGS_OPCODE_SHIFT;
                kcqe.kcqe_op_flag |= KCQE_FLAGS_LAYER_MASK_L5_FCOE;
-               kcqe.kcqe_info1 = FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR;
+               kcqe.kcqe_info1 = FCOE_KCQE_COMPLETION_STATUS_PARITY_ERROR;
                kcqe.kcqe_info2 = cid;
                kcqe.kcqe_info0 = l5_cid;
 
@@ -2558,7 +2559,7 @@ static void cnic_bnx2x_kwqe_err(struct cnic_dev *dev, struct kwqe *kwqe)
 
                kcqe.kcqe_op_flag = (opcode + 0x10) << KCQE_FLAGS_OPCODE_SHIFT;
                kcqe.kcqe_op_flag |= KCQE_FLAGS_LAYER_MASK_L5_ISCSI;
-               kcqe.kcqe_info1 = ISCSI_KCQE_COMPLETION_STATUS_NIC_ERROR;
+               kcqe.kcqe_info1 = ISCSI_KCQE_COMPLETION_STATUS_PARITY_ERR;
                kcqe.kcqe_info2 = cid;
                cnic_get_l5_cid(cp, BNX2X_SW_CID(cid), &kcqe.kcqe_info0);
 
@@ -2577,7 +2578,7 @@ static void cnic_bnx2x_kwqe_err(struct cnic_dev *dev, struct kwqe *kwqe)
 
                kcqe.kcqe_op_flag = (kcqe_op << KCQE_FLAGS_OPCODE_SHIFT) |
                                    KCQE_FLAGS_LAYER_MASK_L4;
-               l4kcqe->status = L4_KCQE_COMPLETION_STATUS_NIC_ERROR;
+               l4kcqe->status = L4_KCQE_COMPLETION_STATUS_PARITY_ERROR;
                l4kcqe->cid = cid;
                cnic_get_l5_cid(cp, BNX2X_SW_CID(cid), &l4kcqe->conn_id);
        } else {
@@ -3933,7 +3934,8 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
        case L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE:
                if (l4kcqe->status == 0)
                        set_bit(SK_F_OFFLD_COMPLETE, &csk->flags);
-               else if (l4kcqe->status == L4_KCQE_COMPLETION_STATUS_NIC_ERROR)
+               else if (l4kcqe->status ==
+                        L4_KCQE_COMPLETION_STATUS_PARITY_ERROR)
                        set_bit(SK_F_HW_ERR, &csk->flags);
 
                smp_mb__before_clear_bit();
@@ -3946,7 +3948,7 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
        case L4_KCQE_OPCODE_VALUE_RESET_COMP:
        case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
        case L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD:
-               if (l4kcqe->status == L4_KCQE_COMPLETION_STATUS_NIC_ERROR)
+               if (l4kcqe->status == L4_KCQE_COMPLETION_STATUS_PARITY_ERROR)
                        set_bit(SK_F_HW_ERR, &csk->flags);
 
                cp->close_conn(csk, opcode);
index 06ca002..382c98b 100644 (file)
 #define L5CM_RAMROD_CMD_ID_SEARCHER_DELETE     (L5CM_RAMROD_CMD_ID_BASE + 14)
 #define L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD   (L5CM_RAMROD_CMD_ID_BASE + 15)
 
-#define FCOE_KCQE_OPCODE_INIT_FUNC                     (0x10)
-#define FCOE_KCQE_OPCODE_DESTROY_FUNC                  (0x11)
-#define FCOE_KCQE_OPCODE_STAT_FUNC                     (0x12)
-#define FCOE_KCQE_OPCODE_OFFLOAD_CONN                  (0x15)
-#define FCOE_KCQE_OPCODE_ENABLE_CONN                   (0x16)
-#define FCOE_KCQE_OPCODE_DISABLE_CONN                  (0x17)
-#define FCOE_KCQE_OPCODE_DESTROY_CONN                  (0x18)
-#define FCOE_KCQE_OPCODE_CQ_EVENT_NOTIFICATION  (0x20)
-#define FCOE_KCQE_OPCODE_FCOE_ERROR                            (0x21)
-
 #define FCOE_RAMROD_CMD_ID_INIT_FUNC           (FCOE_KCQE_OPCODE_INIT_FUNC)
 #define FCOE_RAMROD_CMD_ID_DESTROY_FUNC                (FCOE_KCQE_OPCODE_DESTROY_FUNC)
 #define FCOE_RAMROD_CMD_ID_STAT_FUNC           (FCOE_KCQE_OPCODE_STAT_FUNC)
 #define FCOE_RAMROD_CMD_ID_DESTROY_CONN                (FCOE_KCQE_OPCODE_DESTROY_CONN)
 #define FCOE_RAMROD_CMD_ID_TERMINATE_CONN      (0x81)
 
-#define FCOE_KWQE_OPCODE_INIT1                  (0)
-#define FCOE_KWQE_OPCODE_INIT2                  (1)
-#define FCOE_KWQE_OPCODE_INIT3                  (2)
-#define FCOE_KWQE_OPCODE_OFFLOAD_CONN1  (3)
-#define FCOE_KWQE_OPCODE_OFFLOAD_CONN2  (4)
-#define FCOE_KWQE_OPCODE_OFFLOAD_CONN3  (5)
-#define FCOE_KWQE_OPCODE_OFFLOAD_CONN4  (6)
-#define FCOE_KWQE_OPCODE_ENABLE_CONN   (7)
-#define FCOE_KWQE_OPCODE_DISABLE_CONN  (8)
-#define FCOE_KWQE_OPCODE_DESTROY_CONN  (9)
-#define FCOE_KWQE_OPCODE_DESTROY               (10)
-#define FCOE_KWQE_OPCODE_STAT                  (11)
-
-#define FCOE_KCQE_COMPLETION_STATUS_ERROR      (0x1)
-#define FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE  (0x3)
-#define FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR  (0x5)
-
 /* KCQ (kernel completion queue) response op codes */
 #define L4_KCQE_OPCODE_VALUE_CLOSE_COMP             (53)
 #define L4_KCQE_OPCODE_VALUE_RESET_COMP             (54)
@@ -87,6 +60,7 @@
 /* KCQ (kernel completion queue) completion status */
 #define L4_KCQE_COMPLETION_STATUS_SUCCESS           (0)
 #define L4_KCQE_COMPLETION_STATUS_NIC_ERROR         (4)
+#define L4_KCQE_COMPLETION_STATUS_PARITY_ERROR     (0x81)
 #define L4_KCQE_COMPLETION_STATUS_TIMEOUT           (0x93)
 
 #define L4_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAIL    (0x83)
index 60deb84..289274e 100644 (file)
@@ -12,8 +12,8 @@
 #ifndef CNIC_IF_H
 #define CNIC_IF_H
 
-#define CNIC_MODULE_VERSION    "2.5.9"
-#define CNIC_MODULE_RELDATE    "Feb 8, 2012"
+#define CNIC_MODULE_VERSION    "2.5.10"
+#define CNIC_MODULE_RELDATE    "March 21, 2012"
 
 #define CNIC_ULP_RDMA          0
 #define CNIC_ULP_ISCSI         1
index a374f27..4e4bb38 100644 (file)
@@ -88,10 +88,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 
 #define DRV_MODULE_NAME                "tg3"
 #define TG3_MAJ_NUM                    3
-#define TG3_MIN_NUM                    122
+#define TG3_MIN_NUM                    123
 #define DRV_MODULE_VERSION     \
        __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE     "December 7, 2011"
+#define DRV_MODULE_RELDATE     "March 21, 2012"
 
 #define RESET_KIND_SHUTDOWN    0
 #define RESET_KIND_INIT                1
@@ -5952,8 +5952,10 @@ next_pkt_nopost:
                tpr->rx_std_prod_idx = std_prod_idx & tp->rx_std_ring_mask;
                tpr->rx_jmb_prod_idx = jmb_prod_idx & tp->rx_jmb_ring_mask;
 
-               if (tnapi != &tp->napi[1])
+               if (tnapi != &tp->napi[1]) {
+                       tp->rx_refill = true;
                        napi_schedule(&tp->napi[1].napi);
+               }
        }
 
        return received;
@@ -6133,6 +6135,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
                u32 std_prod_idx = dpr->rx_std_prod_idx;
                u32 jmb_prod_idx = dpr->rx_jmb_prod_idx;
 
+               tp->rx_refill = false;
                for (i = 1; i < tp->irq_cnt; i++)
                        err |= tg3_rx_prodring_xfer(tp, dpr,
                                                    &tp->napi[i].prodring);
@@ -6196,9 +6199,25 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget)
                /* check for RX/TX work to do */
                if (likely(sblk->idx[0].tx_consumer == tnapi->tx_cons &&
                           *(tnapi->rx_rcb_prod_idx) == tnapi->rx_rcb_ptr)) {
+
+                       /* This test here is not race free, but will reduce
+                        * the number of interrupts by looping again.
+                        */
+                       if (tnapi == &tp->napi[1] && tp->rx_refill)
+                               continue;
+
                        napi_complete(napi);
                        /* Reenable interrupts. */
                        tw32_mailbox(tnapi->int_mbox, tnapi->last_tag << 24);
+
+                       /* This test here is synchronized by napi_schedule()
+                        * and napi_complete() to close the race condition.
+                        */
+                       if (unlikely(tnapi == &tp->napi[1] && tp->rx_refill)) {
+                               tw32(HOSTCC_MODE, tp->coalesce_mode |
+                                                 HOSTCC_MODE_ENABLE |
+                                                 tnapi->coal_now);
+                       }
                        mmiowb();
                        break;
                }
index 66bcfca..93865f8 100644 (file)
@@ -3007,6 +3007,7 @@ struct tg3 {
        u32                             rx_std_max_post;
        u32                             rx_offset;
        u32                             rx_pkt_map_sz;
+       bool                            rx_refill;
 
 
        /* begin "everything else" cacheline(s) section */
index 1f8648f..8388e36 100644 (file)
@@ -5,8 +5,7 @@
 config NET_VENDOR_CIRRUS
        bool "Cirrus devices"
        default y
-       depends on ISA || EISA || MACH_IXDP2351 || ARCH_IXDP2X01 \
-               || MACH_MX31ADS || MACH_QQ2440 || (ARM && ARCH_EP93XX) || MAC
+       depends on ISA || EISA || ARM || MAC
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y
          and read the Ethernet-HOWTO, available from
@@ -21,8 +20,7 @@ if NET_VENDOR_CIRRUS
 
 config CS89x0
        tristate "CS89x0 support"
-       depends on (ISA || EISA || MACH_IXDP2351 \
-               || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440)
+       depends on ISA || EISA || ARM
        ---help---
          Support for CS89x0 chipset based Ethernet cards. If you have a
          network (Ethernet) card of this type, say Y and read the
@@ -33,10 +31,15 @@ config CS89x0
          To compile this driver as a module, choose M here. The module
          will be called cs89x0.
 
-config CS89x0_NONISA_IRQ
-       def_bool y
-       depends on CS89x0 != n
-       depends on MACH_IXDP2351 || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440
+config CS89x0_PLATFORM
+       bool "CS89x0 platform driver support"
+       depends on CS89x0
+       help
+         Say Y to compile the cs89x0 driver as a platform driver. This
+         makes this driver suitable for use on certain evaluation boards
+         such as the iMX21ADS.
+
+         If you are unsure, say N.
 
 config EP93XX_ETH
        tristate "EP93xx Ethernet support"
index 98c171b..b9406cb 100644 (file)
 
 */
 
-/* Always include 'config.h' first in case the user wants to turn on
-   or override something. */
-#include <linux/module.h>
 
 /*
  * Set this to zero to disable DMA code
 
 */
 
+#include <linux/module.h>
+#include <linux/printk.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/atomic.h>
 #if ALLOW_DMA
 #include <asm/dma.h>
 #endif
@@ -173,26 +174,20 @@ static char version[] __initdata =
    them to system IRQ numbers. This mapping is card specific and is set to
    the configuration of the Cirrus Eval board for this chip. */
 #if defined(CONFIG_MACH_IXDP2351)
+#define CS89x0_NONISA_IRQ
 static unsigned int netcard_portlist[] __used __initdata = {IXDP2351_VIRT_CS8900_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0};
 #elif defined(CONFIG_ARCH_IXDP2X01)
+#define CS89x0_NONISA_IRQ
 static unsigned int netcard_portlist[] __used __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
 static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
-#elif defined(CONFIG_MACH_QQ2440)
-#include <mach/qq2440.h>
-static unsigned int netcard_portlist[] __used __initdata = { QQ2440_CS8900_VIRT_BASE + 0x300, 0 };
-static unsigned int cs8900_irq_map[] = { QQ2440_CS8900_IRQ, 0, 0, 0 };
-#elif defined(CONFIG_MACH_MX31ADS)
-#include <mach/board-mx31ads.h>
-static unsigned int netcard_portlist[] __used __initdata = {
-       PBC_BASE_ADDRESS + PBC_CS8900A_IOBASE + 0x300, 0
-};
-static unsigned cs8900_irq_map[] = {EXPIO_INT_ENET_INT, 0, 0, 0};
 #else
+#ifndef CONFIG_CS89x0_PLATFORM
 static unsigned int netcard_portlist[] __used __initdata =
    { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
 static unsigned int cs8900_irq_map[] = {10,11,12,5};
 #endif
+#endif
 
 #if DEBUGGING
 static unsigned int net_debug = DEBUGGING;
@@ -235,11 +230,16 @@ struct net_local {
        unsigned char *end_dma_buff;    /* points to the end of the buffer */
        unsigned char *rx_dma_ptr;      /* points to the next packet  */
 #endif
+#ifdef CONFIG_CS89x0_PLATFORM
+       void __iomem *virt_addr;/* Virtual address for accessing the CS89x0. */
+       unsigned long phys_addr;/* Physical address for accessing the CS89x0. */
+       unsigned long size;     /* Length of CS89x0 memory region. */
+#endif
 };
 
 /* Index to functions, as function prototypes. */
 
-static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular);
+static int cs89x0_probe1(struct net_device *dev, unsigned long ioaddr, int modular);
 static int net_open(struct net_device *dev);
 static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t net_interrupt(int irq, void *dev_id);
@@ -293,6 +293,7 @@ static int __init media_fn(char *str)
 __setup("cs89x0_media=", media_fn);
 
 
+#ifndef CONFIG_CS89x0_PLATFORM
 /* Check for a network adaptor of this type, and return '0' iff one exists.
    If dev->base_addr == 0, probe all likely locations.
    If dev->base_addr == 1, always return failure.
@@ -342,6 +343,7 @@ out:
        return ERR_PTR(err);
 }
 #endif
+#endif
 
 #if defined(CONFIG_MACH_IXDP2351)
 static u16
@@ -503,7 +505,7 @@ static const struct net_device_ops net_ops = {
  */
 
 static int __init
-cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
+cs89x0_probe1(struct net_device *dev, unsigned long ioaddr, int modular)
 {
        struct net_local *lp = netdev_priv(dev);
        static unsigned version_printed;
@@ -528,15 +530,12 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
                lp->force = g_cs89x0_media__force;
 #endif
 
-#if defined(CONFIG_MACH_QQ2440)
-               lp->force |= FORCE_RJ45 | FORCE_FULL;
-#endif
         }
 
        /* Grab the region so we can find another board if autoIRQ fails. */
        /* WTF is going on here? */
        if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
-               printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n",
+               printk(KERN_ERR "%s: request_region(0x%lx, 0x%x) failed\n",
                                DRV_NAME, ioaddr, NETCARD_IO_EXTENT);
                retval = -EBUSY;
                goto out1;
@@ -548,7 +547,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
           will skip the test for the ADD_PORT. */
        if (ioaddr & 1) {
                if (net_debug > 1)
-                       printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr);
+                       printk(KERN_INFO "%s: odd ioaddr 0x%lx\n", dev->name, ioaddr);
                if ((ioaddr & 2) != 2)
                        if ((readword(ioaddr & ~3, ADD_PORT) & ADD_MASK) != ADD_SIG) {
                                printk(KERN_ERR "%s: bad signature 0x%x\n",
@@ -559,13 +558,13 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
        }
 
        ioaddr &= ~3;
-       printk(KERN_DEBUG "PP_addr at %x[%x]: 0x%x\n",
+       printk(KERN_DEBUG "PP_addr at %lx[%x]: 0x%x\n",
                        ioaddr, ADD_PORT, readword(ioaddr, ADD_PORT));
        writeword(ioaddr, ADD_PORT, PP_ChipID);
 
        tmp = readword(ioaddr, DATA_PORT);
        if (tmp != CHIP_EISA_ID_SIG) {
-               printk(KERN_DEBUG "%s: incorrect signature at %x[%x]: 0x%x!="
+               printk(KERN_DEBUG "%s: incorrect signature at %lx[%x]: 0x%x!="
                        CHIP_EISA_ID_SIG_STR "\n",
                        dev->name, ioaddr, DATA_PORT, tmp);
                retval = -ENODEV;
@@ -735,8 +734,9 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
                        dev->irq = i;
        } else {
                i = lp->isa_config & INT_NO_MASK;
+#ifndef CONFIG_CS89x0_PLATFORM
                if (lp->chip_type == CS8900) {
-#ifdef CONFIG_CS89x0_NONISA_IRQ
+#ifdef CS89x0_NONISA_IRQ
                        i = cs8900_irq_map[0];
 #else
                        /* Translate the IRQ using the IRQ mapping table. */
@@ -757,6 +757,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
                        }
 #endif
                }
+#endif
                if (!dev->irq)
                        dev->irq = i;
        }
@@ -1167,6 +1168,7 @@ write_irq(struct net_device *dev, int chip_type, int irq)
        int i;
 
        if (chip_type == CS8900) {
+#ifndef CONFIG_CS89x0_PLATFORM
                /* Search the mapping table for the corresponding IRQ pin. */
                for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++)
                        if (cs8900_irq_map[i] == irq)
@@ -1174,6 +1176,10 @@ write_irq(struct net_device *dev, int chip_type, int irq)
                /* Not found */
                if (i == ARRAY_SIZE(cs8900_irq_map))
                        i = 3;
+#else
+               /* INTRQ0 pin is used for interrupt generation. */
+               i = 0;
+#endif
                writereg(dev, PP_CS8900_ISAINT, i);
        } else {
                writereg(dev, PP_CS8920_ISAINT, irq);
@@ -1227,7 +1233,7 @@ net_open(struct net_device *dev)
        }
        else
        {
-#ifndef CONFIG_CS89x0_NONISA_IRQ
+#if !defined(CS89x0_NONISA_IRQ) && !defined(CONFIG_CS89x0_PLATFORM)
                if (((1 << dev->irq) & lp->irq_map) == 0) {
                        printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
@@ -1745,7 +1751,7 @@ static int set_mac_address(struct net_device *dev, void *p)
        return 0;
 }
 
-#ifdef MODULE
+#if defined(MODULE) && !defined(CONFIG_CS89x0_PLATFORM)
 
 static struct net_device *dev_cs89x0;
 
@@ -1899,7 +1905,97 @@ cleanup_module(void)
        release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT);
        free_netdev(dev_cs89x0);
 }
-#endif /* MODULE */
+#endif /* MODULE && !CONFIG_CS89x0_PLATFORM */
+
+#ifdef CONFIG_CS89x0_PLATFORM
+static int __init cs89x0_platform_probe(struct platform_device *pdev)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
+       struct net_local *lp;
+       struct resource *mem_res;
+       int err;
+
+       if (!dev)
+               return -ENOMEM;
+
+       lp = netdev_priv(dev);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dev->irq = platform_get_irq(pdev, 0);
+       if (mem_res == NULL || dev->irq <= 0) {
+               dev_warn(&dev->dev, "memory/interrupt resource missing.\n");
+               err = -ENXIO;
+               goto free;
+       }
+
+       lp->phys_addr = mem_res->start;
+       lp->size = resource_size(mem_res);
+       if (!request_mem_region(lp->phys_addr, lp->size, DRV_NAME)) {
+               dev_warn(&dev->dev, "request_mem_region() failed.\n");
+               err = -EBUSY;
+               goto free;
+       }
+
+       lp->virt_addr = ioremap(lp->phys_addr, lp->size);
+       if (!lp->virt_addr) {
+               dev_warn(&dev->dev, "ioremap() failed.\n");
+               err = -ENOMEM;
+               goto release;
+       }
+
+       err = cs89x0_probe1(dev, (unsigned long)lp->virt_addr, 0);
+       if (err) {
+               dev_warn(&dev->dev, "no cs8900 or cs8920 detected.\n");
+               goto unmap;
+       }
+
+       platform_set_drvdata(pdev, dev);
+       return 0;
+
+unmap:
+       iounmap(lp->virt_addr);
+release:
+       release_mem_region(lp->phys_addr, lp->size);
+free:
+       free_netdev(dev);
+       return err;
+}
+
+static int cs89x0_platform_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct net_local *lp = netdev_priv(dev);
+
+       unregister_netdev(dev);
+       iounmap(lp->virt_addr);
+       release_mem_region(lp->phys_addr, lp->size);
+       free_netdev(dev);
+       return 0;
+}
+
+static struct platform_driver cs89x0_driver = {
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .remove = cs89x0_platform_remove,
+};
+
+static int __init cs89x0_init(void)
+{
+       return platform_driver_probe(&cs89x0_driver, cs89x0_platform_probe);
+}
+
+module_init(cs89x0_init);
+
+static void __exit cs89x0_cleanup(void)
+{
+       platform_driver_unregister(&cs89x0_driver);
+}
+
+module_exit(cs89x0_cleanup);
+
+#endif /* CONFIG_CS89x0_PLATFORM */
 
 /*
  * Local variables:
index d9428f0..e7bed53 100644 (file)
@@ -968,7 +968,6 @@ static int gfar_probe(struct platform_device *ofdev)
        struct gfar_private *priv = NULL;
        struct gfar __iomem *regs = NULL;
        int err = 0, i, grp_idx = 0;
-       int len_devname;
        u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0;
        u32 isrg = 0;
        u32 __iomem *baddr;
@@ -1169,40 +1168,16 @@ static int gfar_probe(struct platform_device *ofdev)
                priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
        /* fill out IRQ number and name fields */
-       len_devname = strlen(dev->name);
        for (i = 0; i < priv->num_grps; i++) {
-               strncpy(&priv->gfargrp[i].int_name_tx[0], dev->name,
-                               len_devname);
                if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-                       strncpy(&priv->gfargrp[i].int_name_tx[len_devname],
-                               "_g", sizeof("_g"));
-                       priv->gfargrp[i].int_name_tx[
-                               strlen(priv->gfargrp[i].int_name_tx)] = i+48;
-                       strncpy(&priv->gfargrp[i].int_name_tx[strlen(
-                               priv->gfargrp[i].int_name_tx)],
-                               "_tx", sizeof("_tx") + 1);
-
-                       strncpy(&priv->gfargrp[i].int_name_rx[0], dev->name,
-                                       len_devname);
-                       strncpy(&priv->gfargrp[i].int_name_rx[len_devname],
-                                       "_g", sizeof("_g"));
-                       priv->gfargrp[i].int_name_rx[
-                               strlen(priv->gfargrp[i].int_name_rx)] = i+48;
-                       strncpy(&priv->gfargrp[i].int_name_rx[strlen(
-                               priv->gfargrp[i].int_name_rx)],
-                               "_rx", sizeof("_rx") + 1);
-
-                       strncpy(&priv->gfargrp[i].int_name_er[0], dev->name,
-                                       len_devname);
-                       strncpy(&priv->gfargrp[i].int_name_er[len_devname],
-                               "_g", sizeof("_g"));
-                       priv->gfargrp[i].int_name_er[strlen(
-                                       priv->gfargrp[i].int_name_er)] = i+48;
-                       strncpy(&priv->gfargrp[i].int_name_er[strlen(\
-                               priv->gfargrp[i].int_name_er)],
-                               "_er", sizeof("_er") + 1);
+                       sprintf(priv->gfargrp[i].int_name_tx, "%s%s%c%s",
+                               dev->name, "_g", '0' + i, "_tx");
+                       sprintf(priv->gfargrp[i].int_name_rx, "%s%s%c%s",
+                               dev->name, "_g", '0' + i, "_rx");
+                       sprintf(priv->gfargrp[i].int_name_er, "%s%s%c%s",
+                               dev->name, "_g", '0' + i, "_er");
                } else
-                       priv->gfargrp[i].int_name_tx[len_devname] = '\0';
+                       strcpy(priv->gfargrp[i].int_name_tx, dev->name);
        }
 
        /* Initialize the filer table */
index fc2488a..4c9f8d4 100644 (file)
@@ -517,7 +517,7 @@ extern const char gfar_driver_version[];
 #define RXFCB_PERR_MASK                0x000c
 #define RXFCB_PERR_BADL3       0x0008
 
-#define GFAR_INT_NAME_MAX      IFNAMSIZ + 4
+#define GFAR_INT_NAME_MAX      (IFNAMSIZ + 6)  /* '_g#_xx' */
 
 struct txbd8
 {
index e877371..9010cea 100644 (file)
@@ -1616,11 +1616,8 @@ static struct vio_driver ibmveth_driver = {
        .probe          = ibmveth_probe,
        .remove         = ibmveth_remove,
        .get_desired_dma = ibmveth_get_desired_dma,
-       .driver         = {
-               .name   = ibmveth_driver_name,
-               .owner  = THIS_MODULE,
-               .pm = &ibmveth_pm_ops,
-       }
+       .name           = ibmveth_driver_name,
+       .pm             = &ibmveth_pm_ops,
 };
 
 static int __init ibmveth_module_init(void)
index 82c2c86..423a1a2 100644 (file)
@@ -95,6 +95,10 @@ static int disable_msi = 0;
 module_param(disable_msi, int, 0);
 MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
 
+static int legacy_pme = 0;
+module_param(legacy_pme, int, 0);
+MODULE_PARM_DESC(legacy_pme, "Legacy power management");
+
 static DEFINE_PCI_DEVICE_TABLE(sky2_id_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, /* SK-9Sxx */
        { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */
@@ -867,6 +871,13 @@ static void sky2_wol_init(struct sky2_port *sky2)
        /* Disable PiG firmware */
        sky2_write16(hw, B0_CTST, Y2_HW_WOL_OFF);
 
+       /* Needed by some broken BIOSes, use PCI rather than PCI-e for WOL */
+       if (legacy_pme) {
+               u32 reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+               reg1 |= PCI_Y2_PME_LEGACY;
+               sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+       }
+
        /* block receiver */
        sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
        sky2_read32(hw, B0_CTST);
index 2b5af22..385a4d5 100644 (file)
@@ -36,8 +36,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 25
-#define QLCNIC_LINUX_VERSIONID  "5.0.26"
+#define _QLCNIC_LINUX_SUBVERSION 27
+#define QLCNIC_LINUX_VERSIONID  "5.0.27"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
index 81bb1a6..75c32e8 100644 (file)
@@ -1458,8 +1458,10 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter)
 
                if (netif_running(netdev)) {
                        err = qlcnic_attach(adapter);
-                       if (!err)
+                       if (!err) {
                                __qlcnic_up(adapter, netdev);
+                               qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+                       }
                }
 
                netif_device_attach(netdev);
index 1dc4fad..fee4493 100644 (file)
@@ -2280,7 +2280,7 @@ static int __devinit smc_drv_probe(struct platform_device *pdev)
        if (ret)
                goto out_release_io;
 #if defined(CONFIG_SA1100_ASSABET)
-       NCR_0 |= NCR_ENET_OSC_EN;
+       neponset_ncr_set(NCR_ENET_OSC_EN);
 #endif
        platform_set_drvdata(pdev, ndev);
        ret = smc_enable_device(pdev);
index 92a037a..38e3ae9 100644 (file)
@@ -1259,10 +1259,7 @@ static struct vio_driver vnet_port_driver = {
        .id_table       = vnet_port_match,
        .probe          = vnet_port_probe,
        .remove         = vnet_port_remove,
-       .driver         = {
-               .name   = "vnet_port",
-               .owner  = THIS_MODULE,
-       }
+       .name           = "vnet_port",
 };
 
 static int __init vnet_init(void)
index e535137..4680478 100644 (file)
@@ -356,7 +356,7 @@ config VLSI_FIR
 
 config SA1100_FIR
        tristate "SA1100 Internal IR"
-       depends on ARCH_SA1100 && IRDA
+       depends on ARCH_SA1100 && IRDA && DMA_SA11X0
 
 config VIA_FIR
        tristate "VIA VT8231/VT1211 SIR/MIR/FIR"
index da27050..a0d1913 100644 (file)
@@ -15,7 +15,7 @@
  *  This driver takes one kernel command line parameter, sa1100ir=, with
  *  the following options:
  *     max_rate:baudrate       - set the maximum baud rate
- *     power_leve:level        - set the transmitter power level
+ *     power_level:level       - set the transmitter power level
  *     tx_lpm:0|1              - set transmit low power mode
  */
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/sa11x0-dma.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/wrapper.h>
 #include <net/irda/irda_device.h>
 
-#include <asm/irq.h>
-#include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/mach/irda.h>
 
@@ -44,8 +44,15 @@ static int power_level = 3;
 static int tx_lpm;
 static int max_rate = 4000000;
 
+struct sa1100_buf {
+       struct device           *dev;
+       struct sk_buff          *skb;
+       struct scatterlist      sg;
+       struct dma_chan         *chan;
+       dma_cookie_t            cookie;
+};
+
 struct sa1100_irda {
-       unsigned char           hscr0;
        unsigned char           utcr4;
        unsigned char           power;
        unsigned char           open;
@@ -53,12 +60,8 @@ struct sa1100_irda {
        int                     speed;
        int                     newspeed;
 
-       struct sk_buff          *txskb;
-       struct sk_buff          *rxskb;
-       dma_addr_t              txbuf_dma;
-       dma_addr_t              rxbuf_dma;
-       dma_regs_t              *txdma;
-       dma_regs_t              *rxdma;
+       struct sa1100_buf       dma_rx;
+       struct sa1100_buf       dma_tx;
 
        struct device           *dev;
        struct irda_platform_data *pdata;
@@ -67,23 +70,103 @@ struct sa1100_irda {
 
        iobuff_t                tx_buff;
        iobuff_t                rx_buff;
+
+       int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *);
+       irqreturn_t (*irq)(struct net_device *, struct sa1100_irda *);
 };
 
+static int sa1100_irda_set_speed(struct sa1100_irda *, int);
+
 #define IS_FIR(si)             ((si)->speed >= 4000000)
 
 #define HPSIR_MAX_RXLEN                2047
 
+static struct dma_slave_config sa1100_irda_sir_tx = {
+       .direction      = DMA_TO_DEVICE,
+       .dst_addr       = __PREG(Ser2UTDR),
+       .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+       .dst_maxburst   = 4,
+};
+
+static struct dma_slave_config sa1100_irda_fir_rx = {
+       .direction      = DMA_FROM_DEVICE,
+       .src_addr       = __PREG(Ser2HSDR),
+       .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+       .src_maxburst   = 8,
+};
+
+static struct dma_slave_config sa1100_irda_fir_tx = {
+       .direction      = DMA_TO_DEVICE,
+       .dst_addr       = __PREG(Ser2HSDR),
+       .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+       .dst_maxburst   = 8,
+};
+
+static unsigned sa1100_irda_dma_xferred(struct sa1100_buf *buf)
+{
+       struct dma_chan *chan = buf->chan;
+       struct dma_tx_state state;
+       enum dma_status status;
+
+       status = chan->device->device_tx_status(chan, buf->cookie, &state);
+       if (status != DMA_PAUSED)
+               return 0;
+
+       return sg_dma_len(&buf->sg) - state.residue;
+}
+
+static int sa1100_irda_dma_request(struct device *dev, struct sa1100_buf *buf,
+       const char *name, struct dma_slave_config *cfg)
+{
+       dma_cap_mask_t m;
+       int ret;
+
+       dma_cap_zero(m);
+       dma_cap_set(DMA_SLAVE, m);
+
+       buf->chan = dma_request_channel(m, sa11x0_dma_filter_fn, (void *)name);
+       if (!buf->chan) {
+               dev_err(dev, "unable to request DMA channel for %s\n",
+                       name);
+               return -ENOENT;
+       }
+
+       ret = dmaengine_slave_config(buf->chan, cfg);
+       if (ret)
+               dev_warn(dev, "DMA slave_config for %s returned %d\n",
+                       name, ret);
+
+       buf->dev = buf->chan->device->dev;
+
+       return 0;
+}
+
+static void sa1100_irda_dma_start(struct sa1100_buf *buf,
+       enum dma_transfer_direction dir, dma_async_tx_callback cb, void *cb_p)
+{
+       struct dma_async_tx_descriptor *desc;
+       struct dma_chan *chan = buf->chan;
+
+       desc = chan->device->device_prep_slave_sg(chan, &buf->sg, 1, dir,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (desc) {
+               desc->callback = cb;
+               desc->callback_param = cb_p;
+               buf->cookie = dmaengine_submit(desc);
+               dma_async_issue_pending(chan);
+       }
+}
+
 /*
  * Allocate and map the receive buffer, unless it is already allocated.
  */
 static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
 {
-       if (si->rxskb)
+       if (si->dma_rx.skb)
                return 0;
 
-       si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
-
-       if (!si->rxskb) {
+       si->dma_rx.skb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
+       if (!si->dma_rx.skb) {
                printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n");
                return -ENOMEM;
        }
@@ -92,11 +175,14 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
         * Align any IP headers that may be contained
         * within the frame.
         */
-       skb_reserve(si->rxskb, 1);
+       skb_reserve(si->dma_rx.skb, 1);
+
+       sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN);
+       if (dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) {
+               dev_kfree_skb_any(si->dma_rx.skb);
+               return -ENOMEM;
+       }
 
-       si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
-                                       HPSIR_MAX_RXLEN,
-                                       DMA_FROM_DEVICE);
        return 0;
 }
 
@@ -106,7 +192,7 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
  */
 static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
 {
-       if (!si->rxskb) {
+       if (!si->dma_rx.skb) {
                printk(KERN_ERR "sa1100_ir: rx buffer went missing\n");
                return;
        }
@@ -114,254 +200,87 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
        /*
         * First empty receive FIFO
         */
-       Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
+       Ser2HSCR0 = HSCR0_HSSP;
 
        /*
         * Enable the DMA, receiver and receive interrupt.
         */
-       sa1100_clear_dma(si->rxdma);
-       sa1100_start_dma(si->rxdma, si->rxbuf_dma, HPSIR_MAX_RXLEN);
-       Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE;
+       dmaengine_terminate_all(si->dma_rx.chan);
+       sa1100_irda_dma_start(&si->dma_rx, DMA_DEV_TO_MEM, NULL, NULL);
+
+       Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE;
 }
 
-/*
- * Set the IrDA communications speed.
- */
-static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
+static void sa1100_irda_check_speed(struct sa1100_irda *si)
 {
-       unsigned long flags;
-       int brd, ret = -EINVAL;
-
-       switch (speed) {
-       case 9600:      case 19200:     case 38400:
-       case 57600:     case 115200:
-               brd = 3686400 / (16 * speed) - 1;
-
-               /*
-                * Stop the receive DMA.
-                */
-               if (IS_FIR(si))
-                       sa1100_stop_dma(si->rxdma);
-
-               local_irq_save(flags);
-
-               Ser2UTCR3 = 0;
-               Ser2HSCR0 = HSCR0_UART;
-
-               Ser2UTCR1 = brd >> 8;
-               Ser2UTCR2 = brd;
-
-               /*
-                * Clear status register
-                */
-               Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
-               Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
-
-               if (si->pdata->set_speed)
-                       si->pdata->set_speed(si->dev, speed);
-
-               si->speed = speed;
-
-               local_irq_restore(flags);
-               ret = 0;
-               break;
-
-       case 4000000:
-               local_irq_save(flags);
-
-               si->hscr0 = 0;
-
-               Ser2HSSR0 = 0xff;
-               Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
-               Ser2UTCR3 = 0;
-
-               si->speed = speed;
-
-               if (si->pdata->set_speed)
-                       si->pdata->set_speed(si->dev, speed);
-
-               sa1100_irda_rx_alloc(si);
-               sa1100_irda_rx_dma_start(si);
-
-               local_irq_restore(flags);
-
-               break;
-
-       default:
-               break;
+       if (si->newspeed) {
+               sa1100_irda_set_speed(si, si->newspeed);
+               si->newspeed = 0;
        }
-
-       return ret;
 }
 
 /*
- * Control the power state of the IrDA transmitter.
- * State:
- *  0 - off
- *  1 - short range, lowest power
- *  2 - medium range, medium power
- *  3 - maximum range, high power
- *
- * Currently, only assabet is known to support this.
+ * HP-SIR format support.
  */
-static int
-__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state)
-{
-       int ret = 0;
-       if (si->pdata->set_power)
-               ret = si->pdata->set_power(si->dev, state);
-       return ret;
-}
-
-static inline int
-sa1100_set_power(struct sa1100_irda *si, unsigned int state)
+static void sa1100_irda_sirtxdma_irq(void *id)
 {
-       int ret;
-
-       ret = __sa1100_irda_set_power(si, state);
-       if (ret == 0)
-               si->power = state;
-
-       return ret;
-}
+       struct net_device *dev = id;
+       struct sa1100_irda *si = netdev_priv(dev);
 
-static int sa1100_irda_startup(struct sa1100_irda *si)
-{
-       int ret;
+       dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE);
+       dev_kfree_skb(si->dma_tx.skb);
+       si->dma_tx.skb = NULL;
 
-       /*
-        * Ensure that the ports for this device are setup correctly.
-        */
-       if (si->pdata->startup) {
-               ret = si->pdata->startup(si->dev);
-               if (ret)
-                       return ret;
-       }
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += sg_dma_len(&si->dma_tx.sg);
 
-       /*
-        * Configure PPC for IRDA - we want to drive TXD2 low.
-        * We also want to drive this pin low during sleep.
-        */
-       PPSR &= ~PPC_TXD2;
-       PSDR &= ~PPC_TXD2;
-       PPDR |= PPC_TXD2;
-
-       /*
-        * Enable HP-SIR modulation, and ensure that the port is disabled.
-        */
-       Ser2UTCR3 = 0;
-       Ser2HSCR0 = HSCR0_UART;
-       Ser2UTCR4 = si->utcr4;
-       Ser2UTCR0 = UTCR0_8BitData;
-       Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL;
+       /* We need to ensure that the transmitter has finished. */
+       do
+               rmb();
+       while (Ser2UTSR1 & UTSR1_TBY);
 
        /*
-        * Clear status register
+        * Ok, we've finished transmitting.  Now enable the receiver.
+        * Sometimes we get a receive IRQ immediately after a transmit...
         */
        Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
+       Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
 
-       ret = sa1100_irda_set_speed(si, si->speed = 9600);
-       if (ret) {
-               Ser2UTCR3 = 0;
-               Ser2HSCR0 = 0;
+       sa1100_irda_check_speed(si);
 
-               if (si->pdata->shutdown)
-                       si->pdata->shutdown(si->dev);
-       }
-
-       return ret;
-}
-
-static void sa1100_irda_shutdown(struct sa1100_irda *si)
-{
-       /*
-        * Stop all DMA activity.
-        */
-       sa1100_stop_dma(si->rxdma);
-       sa1100_stop_dma(si->txdma);
-
-       /* Disable the port. */
-       Ser2UTCR3 = 0;
-       Ser2HSCR0 = 0;
-
-       if (si->pdata->shutdown)
-               si->pdata->shutdown(si->dev);
+       /* I'm hungry! */
+       netif_wake_queue(dev);
 }
 
-#ifdef CONFIG_PM
-/*
- * Suspend the IrDA interface.
- */
-static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state)
+static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev,
+       struct sa1100_irda *si)
 {
-       struct net_device *dev = platform_get_drvdata(pdev);
-       struct sa1100_irda *si;
-
-       if (!dev)
-               return 0;
-
-       si = netdev_priv(dev);
-       if (si->open) {
-               /*
-                * Stop the transmit queue
-                */
-               netif_device_detach(dev);
-               disable_irq(dev->irq);
-               sa1100_irda_shutdown(si);
-               __sa1100_irda_set_power(si, 0);
+       si->tx_buff.data = si->tx_buff.head;
+       si->tx_buff.len  = async_wrap_skb(skb, si->tx_buff.data,
+                                         si->tx_buff.truesize);
+
+       si->dma_tx.skb = skb;
+       sg_set_buf(&si->dma_tx.sg, si->tx_buff.data, si->tx_buff.len);
+       if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
+               si->dma_tx.skb = NULL;
+               netif_wake_queue(dev);
+               dev->stats.tx_dropped++;
+               return NETDEV_TX_OK;
        }
 
-       return 0;
-}
-
-/*
- * Resume the IrDA interface.
- */
-static int sa1100_irda_resume(struct platform_device *pdev)
-{
-       struct net_device *dev = platform_get_drvdata(pdev);
-       struct sa1100_irda *si;
-
-       if (!dev)
-               return 0;
-
-       si = netdev_priv(dev);
-       if (si->open) {
-               /*
-                * If we missed a speed change, initialise at the new speed
-                * directly.  It is debatable whether this is actually
-                * required, but in the interests of continuing from where
-                * we left off it is desirable.  The converse argument is
-                * that we should re-negotiate at 9600 baud again.
-                */
-               if (si->newspeed) {
-                       si->speed = si->newspeed;
-                       si->newspeed = 0;
-               }
-
-               sa1100_irda_startup(si);
-               __sa1100_irda_set_power(si, si->power);
-               enable_irq(dev->irq);
+       sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_sirtxdma_irq, dev);
 
-               /*
-                * This automatically wakes up the queue
-                */
-               netif_device_attach(dev);
-       }
+       /*
+        * The mean turn-around time is enforced by XBOF padding,
+        * so we don't have to do anything special here.
+        */
+       Ser2UTCR3 = UTCR3_TXE;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
-#else
-#define sa1100_irda_suspend    NULL
-#define sa1100_irda_resume     NULL
-#endif
 
-/*
- * HP-SIR format interrupt service routines.
- */
-static void sa1100_irda_hpsir_irq(struct net_device *dev)
+static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si)
 {
-       struct sa1100_irda *si = netdev_priv(dev);
        int status;
 
        status = Ser2UTSR0;
@@ -414,51 +333,96 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev)
 
        }
 
-       if (status & UTSR0_TFS && si->tx_buff.len) {
-               /*
-                * Transmitter FIFO is not full
-                */
-               do {
-                       Ser2UTDR = *si->tx_buff.data++;
-                       si->tx_buff.len -= 1;
-               } while (Ser2UTSR1 & UTSR1_TNF && si->tx_buff.len);
+       return IRQ_HANDLED;
+}
 
-               if (si->tx_buff.len == 0) {
-                       dev->stats.tx_packets++;
-                       dev->stats.tx_bytes += si->tx_buff.data -
-                                             si->tx_buff.head;
+/*
+ * FIR format support.
+ */
+static void sa1100_irda_firtxdma_irq(void *id)
+{
+       struct net_device *dev = id;
+       struct sa1100_irda *si = netdev_priv(dev);
+       struct sk_buff *skb;
 
-                       /*
-                        * We need to ensure that the transmitter has
-                        * finished.
-                        */
-                       do
-                               rmb();
-                       while (Ser2UTSR1 & UTSR1_TBY);
+       /*
+        * Wait for the transmission to complete.  Unfortunately,
+        * the hardware doesn't give us an interrupt to indicate
+        * "end of frame".
+        */
+       do
+               rmb();
+       while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY);
 
-                       /*
-                        * Ok, we've finished transmitting.  Now enable
-                        * the receiver.  Sometimes we get a receive IRQ
-                        * immediately after a transmit...
-                        */
-                       Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
-                       Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
+       /*
+        * Clear the transmit underrun bit.
+        */
+       Ser2HSSR0 = HSSR0_TUR;
 
-                       if (si->newspeed) {
-                               sa1100_irda_set_speed(si, si->newspeed);
-                               si->newspeed = 0;
-                       }
+       /*
+        * Do we need to change speed?  Note that we're lazy
+        * here - we don't free the old dma_rx.skb.  We don't need
+        * to allocate a buffer either.
+        */
+       sa1100_irda_check_speed(si);
 
-                       /* I'm hungry! */
-                       netif_wake_queue(dev);
-               }
+       /*
+        * Start reception.  This disables the transmitter for
+        * us.  This will be using the existing RX buffer.
+        */
+       sa1100_irda_rx_dma_start(si);
+
+       /* Account and free the packet. */
+       skb = si->dma_tx.skb;
+       if (skb) {
+               dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
+                            DMA_TO_DEVICE);
+               dev->stats.tx_packets ++;
+               dev->stats.tx_bytes += skb->len;
+               dev_kfree_skb_irq(skb);
+               si->dma_tx.skb = NULL;
        }
+
+       /*
+        * Make sure that the TX queue is available for sending
+        * (for retries).  TX has priority over RX at all times.
+        */
+       netif_wake_queue(dev);
+}
+
+static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev,
+       struct sa1100_irda *si)
+{
+       int mtt = irda_get_mtt(skb);
+
+       si->dma_tx.skb = skb;
+       sg_set_buf(&si->dma_tx.sg, skb->data, skb->len);
+       if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) {
+               si->dma_tx.skb = NULL;
+               netif_wake_queue(dev);
+               dev->stats.tx_dropped++;
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_firtxdma_irq, dev);
+
+       /*
+        * If we have a mean turn-around time, impose the specified
+        * specified delay.  We could shorten this by timing from
+        * the point we received the packet.
+        */
+       if (mtt)
+               udelay(mtt);
+
+       Ser2HSCR0 = HSCR0_HSSP | HSCR0_TXE;
+
+       return NETDEV_TX_OK;
 }
 
 static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev)
 {
-       struct sk_buff *skb = si->rxskb;
-       dma_addr_t dma_addr;
+       struct sk_buff *skb = si->dma_rx.skb;
        unsigned int len, stat, data;
 
        if (!skb) {
@@ -469,11 +433,10 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
        /*
         * Get the current data position.
         */
-       dma_addr = sa1100_get_dma_pos(si->rxdma);
-       len = dma_addr - si->rxbuf_dma;
+       len = sa1100_irda_dma_xferred(&si->dma_rx);
        if (len > HPSIR_MAX_RXLEN)
                len = HPSIR_MAX_RXLEN;
-       dma_unmap_single(si->dev, si->rxbuf_dma, len, DMA_FROM_DEVICE);
+       dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
 
        do {
                /*
@@ -501,7 +464,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
        } while (Ser2HSSR0 & HSSR0_EIF);
 
        if (stat & HSSR1_EOF) {
-               si->rxskb = NULL;
+               si->dma_rx.skb = NULL;
 
                skb_put(skb, len);
                skb->dev = dev;
@@ -518,28 +481,23 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
                netif_rx(skb);
        } else {
                /*
-                * Remap the buffer.
+                * Remap the buffer - it was previously mapped, and we
+                * hope that this succeeds.
                 */
-               si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
-                                               HPSIR_MAX_RXLEN,
-                                               DMA_FROM_DEVICE);
+               dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE);
        }
 }
 
 /*
- * FIR format interrupt service routine.  We only have to
- * handle RX events; transmit events go via the TX DMA handler.
- *
- * No matter what, we disable RX, process, and the restart RX.
+ * We only have to handle RX events here; transmit events go via the TX
+ * DMA handler. We disable RX, process, and the restart RX.
  */
-static void sa1100_irda_fir_irq(struct net_device *dev)
+static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si)
 {
-       struct sa1100_irda *si = netdev_priv(dev);
-
        /*
         * Stop RX DMA
         */
-       sa1100_stop_dma(si->rxdma);
+       dmaengine_pause(si->dma_rx.chan);
 
        /*
         * Framing error - we throw away the packet completely.
@@ -555,7 +513,7 @@ static void sa1100_irda_fir_irq(struct net_device *dev)
                /*
                 * Clear out the DMA...
                 */
-               Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
+               Ser2HSCR0 = HSCR0_HSSP;
 
                /*
                 * Clear selected status bits now, so we
@@ -577,74 +535,124 @@ static void sa1100_irda_fir_irq(struct net_device *dev)
         * No matter what happens, we must restart reception.
         */
        sa1100_irda_rx_dma_start(si);
+
+       return IRQ_HANDLED;
 }
 
-static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
+/*
+ * Set the IrDA communications speed.
+ */
+static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
 {
-       struct net_device *dev = dev_id;
-       if (IS_FIR(((struct sa1100_irda *)netdev_priv(dev))))
-               sa1100_irda_fir_irq(dev);
-       else
-               sa1100_irda_hpsir_irq(dev);
-       return IRQ_HANDLED;
+       unsigned long flags;
+       int brd, ret = -EINVAL;
+
+       switch (speed) {
+       case 9600:      case 19200:     case 38400:
+       case 57600:     case 115200:
+               brd = 3686400 / (16 * speed) - 1;
+
+               /* Stop the receive DMA, and configure transmit. */
+               if (IS_FIR(si)) {
+                       dmaengine_terminate_all(si->dma_rx.chan);
+                       dmaengine_slave_config(si->dma_tx.chan,
+                                               &sa1100_irda_sir_tx);
+               }
+
+               local_irq_save(flags);
+
+               Ser2UTCR3 = 0;
+               Ser2HSCR0 = HSCR0_UART;
+
+               Ser2UTCR1 = brd >> 8;
+               Ser2UTCR2 = brd;
+
+               /*
+                * Clear status register
+                */
+               Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
+               Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
+
+               if (si->pdata->set_speed)
+                       si->pdata->set_speed(si->dev, speed);
+
+               si->speed = speed;
+               si->tx_start = sa1100_irda_sir_tx_start;
+               si->irq = sa1100_irda_sir_irq;
+
+               local_irq_restore(flags);
+               ret = 0;
+               break;
+
+       case 4000000:
+               if (!IS_FIR(si))
+                       dmaengine_slave_config(si->dma_tx.chan,
+                                               &sa1100_irda_fir_tx);
+
+               local_irq_save(flags);
+
+               Ser2HSSR0 = 0xff;
+               Ser2HSCR0 = HSCR0_HSSP;
+               Ser2UTCR3 = 0;
+
+               si->speed = speed;
+               si->tx_start = sa1100_irda_fir_tx_start;
+               si->irq = sa1100_irda_fir_irq;
+
+               if (si->pdata->set_speed)
+                       si->pdata->set_speed(si->dev, speed);
+
+               sa1100_irda_rx_alloc(si);
+               sa1100_irda_rx_dma_start(si);
+
+               local_irq_restore(flags);
+
+               break;
+
+       default:
+               break;
+       }
+
+       return ret;
 }
 
 /*
- * TX DMA completion handler.
+ * Control the power state of the IrDA transmitter.
+ * State:
+ *  0 - off
+ *  1 - short range, lowest power
+ *  2 - medium range, medium power
+ *  3 - maximum range, high power
+ *
+ * Currently, only assabet is known to support this.
  */
-static void sa1100_irda_txdma_irq(void *id)
+static int
+__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state)
 {
-       struct net_device *dev = id;
-       struct sa1100_irda *si = netdev_priv(dev);
-       struct sk_buff *skb = si->txskb;
-
-       si->txskb = NULL;
-
-       /*
-        * Wait for the transmission to complete.  Unfortunately,
-        * the hardware doesn't give us an interrupt to indicate
-        * "end of frame".
-        */
-       do
-               rmb();
-       while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY);
+       int ret = 0;
+       if (si->pdata->set_power)
+               ret = si->pdata->set_power(si->dev, state);
+       return ret;
+}
 
-       /*
-        * Clear the transmit underrun bit.
-        */
-       Ser2HSSR0 = HSSR0_TUR;
+static inline int
+sa1100_set_power(struct sa1100_irda *si, unsigned int state)
+{
+       int ret;
 
-       /*
-        * Do we need to change speed?  Note that we're lazy
-        * here - we don't free the old rxskb.  We don't need
-        * to allocate a buffer either.
-        */
-       if (si->newspeed) {
-               sa1100_irda_set_speed(si, si->newspeed);
-               si->newspeed = 0;
-       }
+       ret = __sa1100_irda_set_power(si, state);
+       if (ret == 0)
+               si->power = state;
 
-       /*
-        * Start reception.  This disables the transmitter for
-        * us.  This will be using the existing RX buffer.
-        */
-       sa1100_irda_rx_dma_start(si);
+       return ret;
+}
 
-       /*
-        * Account and free the packet.
-        */
-       if (skb) {
-               dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE);
-               dev->stats.tx_packets ++;
-               dev->stats.tx_bytes += skb->len;
-               dev_kfree_skb_irq(skb);
-       }
+static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct sa1100_irda *si = netdev_priv(dev);
 
-       /*
-        * Make sure that the TX queue is available for sending
-        * (for retries).  TX has priority over RX at all times.
-        */
-       netif_wake_queue(dev);
+       return si->irq(dev, si);
 }
 
 static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -660,62 +668,19 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
        if (speed != si->speed && speed != -1)
                si->newspeed = speed;
 
-       /*
-        * If this is an empty frame, we can bypass a lot.
-        */
+       /* If this is an empty frame, we can bypass a lot. */
        if (skb->len == 0) {
-               if (si->newspeed) {
-                       si->newspeed = 0;
-                       sa1100_irda_set_speed(si, speed);
-               }
+               sa1100_irda_check_speed(si);
                dev_kfree_skb(skb);
                return NETDEV_TX_OK;
        }
 
-       if (!IS_FIR(si)) {
-               netif_stop_queue(dev);
-
-               si->tx_buff.data = si->tx_buff.head;
-               si->tx_buff.len  = async_wrap_skb(skb, si->tx_buff.data,
-                                                 si->tx_buff.truesize);
-
-               /*
-                * Set the transmit interrupt enable.  This will fire
-                * off an interrupt immediately.  Note that we disable
-                * the receiver so we won't get spurious characteres
-                * received.
-                */
-               Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE;
-
-               dev_kfree_skb(skb);
-       } else {
-               int mtt = irda_get_mtt(skb);
-
-               /*
-                * We must not be transmitting...
-                */
-               BUG_ON(si->txskb);
-
-               netif_stop_queue(dev);
-
-               si->txskb = skb;
-               si->txbuf_dma = dma_map_single(si->dev, skb->data,
-                                        skb->len, DMA_TO_DEVICE);
-
-               sa1100_start_dma(si->txdma, si->txbuf_dma, skb->len);
-
-               /*
-                * If we have a mean turn-around time, impose the specified
-                * specified delay.  We could shorten this by timing from
-                * the point we received the packet.
-                */
-               if (mtt)
-                       udelay(mtt);
+       netif_stop_queue(dev);
 
-               Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE;
-       }
+       /* We must not already have a skb to transmit... */
+       BUG_ON(si->dma_tx.skb);
 
-       return NETDEV_TX_OK;
+       return si->tx_start(skb, dev, si);
 }
 
 static int
@@ -762,6 +727,69 @@ sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
        return ret;
 }
 
+static int sa1100_irda_startup(struct sa1100_irda *si)
+{
+       int ret;
+
+       /*
+        * Ensure that the ports for this device are setup correctly.
+        */
+       if (si->pdata->startup) {
+               ret = si->pdata->startup(si->dev);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * Configure PPC for IRDA - we want to drive TXD2 low.
+        * We also want to drive this pin low during sleep.
+        */
+       PPSR &= ~PPC_TXD2;
+       PSDR &= ~PPC_TXD2;
+       PPDR |= PPC_TXD2;
+
+       /*
+        * Enable HP-SIR modulation, and ensure that the port is disabled.
+        */
+       Ser2UTCR3 = 0;
+       Ser2HSCR0 = HSCR0_UART;
+       Ser2UTCR4 = si->utcr4;
+       Ser2UTCR0 = UTCR0_8BitData;
+       Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL;
+
+       /*
+        * Clear status register
+        */
+       Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
+
+       ret = sa1100_irda_set_speed(si, si->speed = 9600);
+       if (ret) {
+               Ser2UTCR3 = 0;
+               Ser2HSCR0 = 0;
+
+               if (si->pdata->shutdown)
+                       si->pdata->shutdown(si->dev);
+       }
+
+       return ret;
+}
+
+static void sa1100_irda_shutdown(struct sa1100_irda *si)
+{
+       /*
+        * Stop all DMA activity.
+        */
+       dmaengine_terminate_all(si->dma_rx.chan);
+       dmaengine_terminate_all(si->dma_tx.chan);
+
+       /* Disable the port. */
+       Ser2UTCR3 = 0;
+       Ser2HSCR0 = 0;
+
+       if (si->pdata->shutdown)
+               si->pdata->shutdown(si->dev);
+}
+
 static int sa1100_irda_start(struct net_device *dev)
 {
        struct sa1100_irda *si = netdev_priv(dev);
@@ -769,26 +797,17 @@ static int sa1100_irda_start(struct net_device *dev)
 
        si->speed = 9600;
 
-       err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);
-       if (err)
-               goto err_irq;
-
-       err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive",
-                                NULL, NULL, &si->rxdma);
+       err = sa1100_irda_dma_request(si->dev, &si->dma_rx, "Ser2ICPRc",
+                               &sa1100_irda_fir_rx);
        if (err)
                goto err_rx_dma;
 
-       err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit",
-                                sa1100_irda_txdma_irq, dev, &si->txdma);
+       err = sa1100_irda_dma_request(si->dev, &si->dma_tx, "Ser2ICPTr",
+                               &sa1100_irda_sir_tx);
        if (err)
                goto err_tx_dma;
 
        /*
-        * The interrupt must remain disabled for now.
-        */
-       disable_irq(dev->irq);
-
-       /*
         * Setup the serial port for the specified speed.
         */
        err = sa1100_irda_startup(si);
@@ -803,44 +822,60 @@ static int sa1100_irda_start(struct net_device *dev)
        if (!si->irlap)
                goto err_irlap;
 
+       err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);
+       if (err)
+               goto err_irq;
+
        /*
         * Now enable the interrupt and start the queue
         */
        si->open = 1;
        sa1100_set_power(si, power_level); /* low power mode */
-       enable_irq(dev->irq);
+
        netif_start_queue(dev);
        return 0;
 
+err_irq:
+       irlap_close(si->irlap);
 err_irlap:
        si->open = 0;
        sa1100_irda_shutdown(si);
 err_startup:
-       sa1100_free_dma(si->txdma);
+       dma_release_channel(si->dma_tx.chan);
 err_tx_dma:
-       sa1100_free_dma(si->rxdma);
+       dma_release_channel(si->dma_rx.chan);
 err_rx_dma:
-       free_irq(dev->irq, dev);
-err_irq:
        return err;
 }
 
 static int sa1100_irda_stop(struct net_device *dev)
 {
        struct sa1100_irda *si = netdev_priv(dev);
+       struct sk_buff *skb;
 
-       disable_irq(dev->irq);
+       netif_stop_queue(dev);
+
+       si->open = 0;
        sa1100_irda_shutdown(si);
 
        /*
-        * If we have been doing DMA receive, make sure we
+        * If we have been doing any DMA activity, make sure we
         * tidy that up cleanly.
         */
-       if (si->rxskb) {
-               dma_unmap_single(si->dev, si->rxbuf_dma, HPSIR_MAX_RXLEN,
-                                DMA_FROM_DEVICE);
-               dev_kfree_skb(si->rxskb);
-               si->rxskb = NULL;
+       skb = si->dma_rx.skb;
+       if (skb) {
+               dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1,
+                            DMA_FROM_DEVICE);
+               dev_kfree_skb(skb);
+               si->dma_rx.skb = NULL;
+       }
+
+       skb = si->dma_tx.skb;
+       if (skb) {
+               dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1,
+                            DMA_TO_DEVICE);
+               dev_kfree_skb(skb);
+               si->dma_tx.skb = NULL;
        }
 
        /* Stop IrLAP */
@@ -849,14 +884,11 @@ static int sa1100_irda_stop(struct net_device *dev)
                si->irlap = NULL;
        }
 
-       netif_stop_queue(dev);
-       si->open = 0;
-
        /*
         * Free resources
         */
-       sa1100_free_dma(si->txdma);
-       sa1100_free_dma(si->rxdma);
+       dma_release_channel(si->dma_tx.chan);
+       dma_release_channel(si->dma_rx.chan);
        free_irq(dev->irq, dev);
 
        sa1100_set_power(si, 0);
@@ -888,11 +920,15 @@ static int sa1100_irda_probe(struct platform_device *pdev)
        struct net_device *dev;
        struct sa1100_irda *si;
        unsigned int baudrate_mask;
-       int err;
+       int err, irq;
 
        if (!pdev->dev.platform_data)
                return -EINVAL;
 
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0)
+               return irq < 0 ? irq : -ENXIO;
+
        err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY;
        if (err)
                goto err_mem_1;
@@ -907,22 +943,27 @@ static int sa1100_irda_probe(struct platform_device *pdev)
        if (!dev)
                goto err_mem_4;
 
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
        si = netdev_priv(dev);
        si->dev = &pdev->dev;
        si->pdata = pdev->dev.platform_data;
 
+       sg_init_table(&si->dma_rx.sg, 1);
+       sg_init_table(&si->dma_tx.sg, 1);
+
        /*
         * Initialise the HP-SIR buffers
         */
        err = sa1100_irda_init_iobuf(&si->rx_buff, 14384);
        if (err)
                goto err_mem_5;
-       err = sa1100_irda_init_iobuf(&si->tx_buff, 4000);
+       err = sa1100_irda_init_iobuf(&si->tx_buff, IRDA_SIR_MAX_FRAME);
        if (err)
                goto err_mem_5;
 
        dev->netdev_ops = &sa1100_irda_netdev_ops;
-       dev->irq        = IRQ_Ser2ICP;
+       dev->irq        = irq;
 
        irda_init_max_qos_capabilies(&si->qos);
 
@@ -996,6 +1037,74 @@ static int sa1100_irda_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+/*
+ * Suspend the IrDA interface.
+ */
+static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct sa1100_irda *si;
+
+       if (!dev)
+               return 0;
+
+       si = netdev_priv(dev);
+       if (si->open) {
+               /*
+                * Stop the transmit queue
+                */
+               netif_device_detach(dev);
+               disable_irq(dev->irq);
+               sa1100_irda_shutdown(si);
+               __sa1100_irda_set_power(si, 0);
+       }
+
+       return 0;
+}
+
+/*
+ * Resume the IrDA interface.
+ */
+static int sa1100_irda_resume(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct sa1100_irda *si;
+
+       if (!dev)
+               return 0;
+
+       si = netdev_priv(dev);
+       if (si->open) {
+               /*
+                * If we missed a speed change, initialise at the new speed
+                * directly.  It is debatable whether this is actually
+                * required, but in the interests of continuing from where
+                * we left off it is desirable.  The converse argument is
+                * that we should re-negotiate at 9600 baud again.
+                */
+               if (si->newspeed) {
+                       si->speed = si->newspeed;
+                       si->newspeed = 0;
+               }
+
+               sa1100_irda_startup(si);
+               __sa1100_irda_set_power(si, si->power);
+               enable_irq(dev->irq);
+
+               /*
+                * This automatically wakes up the queue
+                */
+               netif_device_attach(dev);
+       }
+
+       return 0;
+}
+#else
+#define sa1100_irda_suspend    NULL
+#define sa1100_irda_resume     NULL
+#endif
+
 static struct platform_driver sa1100ir_driver = {
        .probe          = sa1100_irda_probe,
        .remove         = sa1100_irda_remove,
index 790cbde..3886b30 100644 (file)
@@ -164,12 +164,14 @@ static void rx_complete(struct urb *req)
                                /* Can't use pskb_pull() on page in IRQ */
                                memcpy(skb_put(skb, 1), page_address(page), 1);
                                skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
-                                               page, 1, req->actual_length);
+                                               page, 1, req->actual_length,
+                                               req->actual_length);
                                page = NULL;
                        }
                } else {
                        skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
-                                       page, 0, req->actual_length);
+                                       page, 0, req->actual_length,
+                                       req->actual_length);
                        page = NULL;
                }
                if (req->actual_length < PAGE_SIZE)
index aac68f5..552d24b 100644 (file)
@@ -409,6 +409,42 @@ static const struct usb_device_id products[] = {
                .bInterfaceProtocol = 0xff,
                .driver_info        = (unsigned long)&qmi_wwan_force_int4,
        },
+       {       /* ZTE (Vodafone) K3565-Z */
+               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = 0x19d2,
+               .idProduct          = 0x0063,
+               .bInterfaceClass    = 0xff,
+               .bInterfaceSubClass = 0xff,
+               .bInterfaceProtocol = 0xff,
+               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
+       },
+       {       /* ZTE (Vodafone) K3570-Z */
+               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = 0x19d2,
+               .idProduct          = 0x1008,
+               .bInterfaceClass    = 0xff,
+               .bInterfaceSubClass = 0xff,
+               .bInterfaceProtocol = 0xff,
+               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
+       },
+       {       /* ZTE (Vodafone) K3571-Z */
+               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = 0x19d2,
+               .idProduct          = 0x1010,
+               .bInterfaceClass    = 0xff,
+               .bInterfaceSubClass = 0xff,
+               .bInterfaceProtocol = 0xff,
+               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
+       },
+       {       /* ZTE (Vodafone) K4505-Z */
+               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = 0x19d2,
+               .idProduct          = 0x0104,
+               .bInterfaceClass    = 0xff,
+               .bInterfaceSubClass = 0xff,
+               .bInterfaceProtocol = 0xff,
+               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
+       },
        {QMI_GOBI_DEVICE(0x05c6, 0x9212)},      /* Acer Gobi Modem Device */
        {QMI_GOBI_DEVICE(0x03f0, 0x1f1d)},      /* HP un2400 Gobi Modem Device */
        {QMI_GOBI_DEVICE(0x03f0, 0x371d)},      /* HP un2430 Mobile Broadband Module */
index 4b8b52c..b7b3f5b 100644 (file)
@@ -493,6 +493,7 @@ block:
                if (netif_running (dev->net) &&
                    !test_bit (EVENT_RX_HALT, &dev->flags)) {
                        rx_submit (dev, urb, GFP_ATOMIC);
+                       usb_mark_last_busy(dev->udev);
                        return;
                }
                usb_free_urb (urb);
@@ -589,6 +590,14 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
                entry = (struct skb_data *) skb->cb;
                urb = entry->urb;
 
+               /*
+                * Get reference count of the URB to avoid it to be
+                * freed during usb_unlink_urb, which may trigger
+                * use-after-free problem inside usb_unlink_urb since
+                * usb_unlink_urb is always racing with .complete
+                * handler(include defer_bh).
+                */
+               usb_get_urb(urb);
                spin_unlock_irqrestore(&q->lock, flags);
                // during some PM-driven resume scenarios,
                // these (async) unlinks complete immediately
@@ -597,6 +606,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
                        netdev_dbg(dev->net, "unlink urb err, %d\n", retval);
                else
                        count++;
+               usb_put_urb(urb);
                spin_lock_irqsave(&q->lock, flags);
        }
        spin_unlock_irqrestore (&q->lock, flags);
@@ -1028,7 +1038,6 @@ static void tx_complete (struct urb *urb)
        }
 
        usb_autopm_put_interface_async(dev->intf);
-       urb->dev = NULL;
        entry->state = tx_done;
        defer_bh(dev, skb, &dev->txq);
 }
index c5b1d19..b25c01b 100644 (file)
@@ -499,7 +499,8 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
                                      le32_to_cpu(rx_end->status), stats);
 
        skb_add_rx_frag(skb, 0, rxb->page,
-                       (void *)rx_hdr->payload - (void *)pkt, len);
+                       (void *)rx_hdr->payload - (void *)pkt, len,
+                       len);
 
        il_update_stats(il, false, fc, len);
        memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
index 7b54dbb..17f1c68 100644 (file)
@@ -596,7 +596,8 @@ il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr,
                return;
        }
 
-       skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
+       skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len,
+                       len);
 
        il_update_stats(il, false, fc, len);
        memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
index 44c6f71..f4b84d1 100644 (file)
@@ -796,7 +796,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
 
        offset = (void *)hdr - rxb_addr(rxb);
        p = rxb_steal_page(rxb);
-       skb_add_rx_frag(skb, 0, p, offset, len);
+       skb_add_rx_frag(skb, 0, p, offset, len, len);
 
        iwl_update_stats(priv, false, fc, len);
 
index b161750..663b32c 100644 (file)
@@ -47,6 +47,7 @@
 #include <xen/xenbus.h>
 #include <xen/events.h>
 #include <xen/page.h>
+#include <xen/platform_pci.h>
 #include <xen/grant_table.h>
 
 #include <xen/interface/io/netif.h>
@@ -1964,6 +1965,9 @@ static int __init netif_init(void)
        if (xen_initial_domain())
                return 0;
 
+       if (!xen_platform_pci_unplug)
+               return -ENODEV;
+
        printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
 
        return xenbus_register_frontend(&netfront_driver);
index 6ea51dc..8e84ce9 100644 (file)
@@ -91,4 +91,8 @@ config OF_PCI_IRQ
        help
          OpenFirmware PCI IRQ routing helpers
 
+config OF_MTD
+       depends on MTD
+       def_bool y
+
 endmenu # OF
index a73f5a5..aa90e60 100644 (file)
@@ -12,3 +12,4 @@ obj-$(CONFIG_OF_SELFTEST) += selftest.o
 obj-$(CONFIG_OF_MDIO)  += of_mdio.o
 obj-$(CONFIG_OF_PCI)   += of_pci.o
 obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
+obj-$(CONFIG_OF_MTD)   += of_mtd.o
index 7e62d15..bba8121 100644 (file)
@@ -78,8 +78,9 @@ err0:
 EXPORT_SYMBOL(of_get_named_gpio_flags);
 
 /**
- * of_gpio_count - Count GPIOs for a device
+ * of_gpio_named_count - Count GPIOs for a device
  * @np:                device node to count GPIOs for
+ * @propname:  property name containing gpio specifier(s)
  *
  * The function returns the count of GPIOs specified for a node.
  *
@@ -93,14 +94,14 @@ EXPORT_SYMBOL(of_get_named_gpio_flags);
  * defines four GPIOs (so this function will return 4), two of which
  * are not specified.
  */
-unsigned int of_gpio_count(struct device_node *np)
+unsigned int of_gpio_named_count(struct device_node *np, const char* propname)
 {
        unsigned int cnt = 0;
 
        do {
                int ret;
 
-               ret = of_parse_phandle_with_args(np, "gpios", "#gpio-cells",
+               ret = of_parse_phandle_with_args(np, propname, "#gpio-cells",
                                                 cnt, NULL);
                /* A hole in the gpios = <> counts anyway. */
                if (ret < 0 && ret != -EEXIST)
@@ -109,7 +110,7 @@ unsigned int of_gpio_count(struct device_node *np)
 
        return cnt;
 }
-EXPORT_SYMBOL(of_gpio_count);
+EXPORT_SYMBOL(of_gpio_named_count);
 
 /**
  * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
@@ -228,7 +229,7 @@ void of_gpiochip_remove(struct gpio_chip *chip)
 }
 
 /* Private function for resolving node pointer to gpio_chip */
-static int of_gpiochip_is_match(struct gpio_chip *chip, void *data)
+static int of_gpiochip_is_match(struct gpio_chip *chip, const void *data)
 {
        return chip->of_node == data;
 }
diff --git a/drivers/of/of_mtd.c b/drivers/of/of_mtd.c
new file mode 100644 (file)
index 0000000..e7cad62
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * OF helpers for mtd.
+ *
+ * This file is released under the GPLv2
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/of_mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/export.h>
+
+/**
+ * It maps 'enum nand_ecc_modes_t' found in include/linux/mtd/nand.h
+ * into the device tree binding of 'nand-ecc', so that MTD
+ * device driver can get nand ecc from device tree.
+ */
+static const char *nand_ecc_modes[] = {
+       [NAND_ECC_NONE]         = "none",
+       [NAND_ECC_SOFT]         = "soft",
+       [NAND_ECC_HW]           = "hw",
+       [NAND_ECC_HW_SYNDROME]  = "hw_syndrome",
+       [NAND_ECC_HW_OOB_FIRST] = "hw_oob_first",
+       [NAND_ECC_SOFT_BCH]     = "soft_bch",
+};
+
+/**
+ * of_get_nand_ecc_mode - Get nand ecc mode for given device_node
+ * @np:        Pointer to the given device_node
+ *
+ * The function gets ecc mode string from property 'nand-ecc-mode',
+ * and return its index in nand_ecc_modes table, or errno in error case.
+ */
+const int of_get_nand_ecc_mode(struct device_node *np)
+{
+       const char *pm;
+       int err, i;
+
+       err = of_property_read_string(np, "nand-ecc-mode", &pm);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < ARRAY_SIZE(nand_ecc_modes); i++)
+               if (!strcasecmp(pm, nand_ecc_modes[i]))
+                       return i;
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
+
+/**
+ * of_get_nand_bus_width - Get nand bus witdh for given device_node
+ * @np:        Pointer to the given device_node
+ *
+ * return bus width option, or errno in error case.
+ */
+int of_get_nand_bus_width(struct device_node *np)
+{
+       u32 val;
+
+       if (of_property_read_u32(np, "nand-bus-width", &val))
+               return 8;
+
+       switch(val) {
+       case 8:
+       case 16:
+               return val;
+       default:
+               return -EIO;
+       }
+}
+EXPORT_SYMBOL_GPL(of_get_nand_bus_width);
+
+/**
+ * of_get_nand_on_flash_bbt - Get nand on flash bbt for given device_node
+ * @np:        Pointer to the given device_node
+ *
+ * return true if present false other wise
+ */
+bool of_get_nand_on_flash_bbt(struct device_node *np)
+{
+       return of_property_read_bool(np, "nand-on-flash-bbt");
+}
+EXPORT_SYMBOL_GPL(of_get_nand_on_flash_bbt);
index 20fbebd..343ad29 100644 (file)
@@ -253,7 +253,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
        if (!of_device_is_available(node))
                return NULL;
 
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       dev = amba_device_alloc(NULL, 0, 0);
        if (!dev)
                return NULL;
 
@@ -283,14 +283,14 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
        if (ret)
                goto err_free;
 
-       ret = amba_device_register(dev, &iomem_resource);
+       ret = amba_device_add(dev, &iomem_resource);
        if (ret)
                goto err_free;
 
        return dev;
 
 err_free:
-       kfree(dev);
+       amba_device_put(dev);
        return NULL;
 }
 #else /* CONFIG_ARM_AMBA */
index 9c5aae5..432d4bb 100644 (file)
@@ -552,7 +552,6 @@ dino_fixup_bus(struct pci_bus *bus)
        struct list_head *ln;
         struct pci_dev *dev;
         struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge));
-       int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num);
 
        DBG(KERN_WARNING "%s(0x%p) bus %d platform_data 0x%p\n",
            __func__, bus, bus->secondary,
@@ -598,8 +597,6 @@ dino_fixup_bus(struct pci_bus *bus)
 
 
        list_for_each(ln, &bus->devices) {
-               int i;
-
                dev = pci_dev_b(ln);
                if (is_card_dino(&dino_dev->hba.dev->id))
                        dino_card_fixup(dev);
@@ -611,21 +608,6 @@ dino_fixup_bus(struct pci_bus *bus)
                if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
                        continue;
 
-               /* Adjust the I/O Port space addresses */
-               for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-                       struct resource *res = &dev->resource[i];
-                       if (res->flags & IORESOURCE_IO) {
-                               res->start |= port_base;
-                               res->end |= port_base;
-                       }
-#ifdef __LP64__
-                       /* Sign Extend MMIO addresses */
-                       else if (res->flags & IORESOURCE_MEM) {
-                               res->start |= F_EXTEND(0UL);
-                               res->end   |= F_EXTEND(0UL);
-                       }
-#endif
-               }
                /* null out the ROM resource if there is one (we don't
                 * care about an expansion rom on parisc, since it
                 * usually contains (x86) bios code) */
@@ -990,11 +972,14 @@ static int __init dino_probe(struct parisc_device *dev)
 
        dev->dev.platform_data = dino_dev;
 
-       pci_add_resource(&resources, &dino_dev->hba.io_space);
+       pci_add_resource_offset(&resources, &dino_dev->hba.io_space,
+                               HBA_PORT_BASE(dino_dev->hba.hba_num));
        if (dino_dev->hba.lmmio_space.flags)
-               pci_add_resource(&resources, &dino_dev->hba.lmmio_space);
+               pci_add_resource_offset(&resources, &dino_dev->hba.lmmio_space,
+                                       dino_dev->hba.lmmio_space_offset);
        if (dino_dev->hba.elmmio_space.flags)
-               pci_add_resource(&resources, &dino_dev->hba.elmmio_space);
+               pci_add_resource_offset(&resources, &dino_dev->hba.elmmio_space,
+                                       dino_dev->hba.lmmio_space_offset);
        if (dino_dev->hba.gmmio_space.flags)
                pci_add_resource(&resources, &dino_dev->hba.gmmio_space);
 
index 320e43a..052fa23 100644 (file)
@@ -634,7 +634,6 @@ lba_fixup_bus(struct pci_bus *bus)
        u16 status;
 #endif
        struct lba_device *ldev = LBA_DEV(parisc_walk_tree(bus->bridge));
-       int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num);
 
        DBG("lba_fixup_bus(0x%p) bus %d platform_data 0x%p\n",
                bus, bus->secondary, bus->bridge->platform_data);
@@ -725,27 +724,6 @@ lba_fixup_bus(struct pci_bus *bus)
                        if (!res->start)
                                continue;
 
-                       if (res->flags & IORESOURCE_IO) {
-                               DBG("lba_fixup_bus() I/O Ports [%lx/%lx] -> ",
-                                       res->start, res->end);
-                               res->start |= lba_portbase;
-                               res->end   |= lba_portbase;
-                               DBG("[%lx/%lx]\n", res->start, res->end);
-                       } else if (res->flags & IORESOURCE_MEM) {
-                               /*
-                               ** Convert PCI (IO_VIEW) addresses to
-                               ** processor (PA_VIEW) addresses
-                                */
-                               DBG("lba_fixup_bus() MMIO [%lx/%lx] -> ",
-                                       res->start, res->end);
-                               res->start = PCI_HOST_ADDR(HBA_DATA(ldev), res->start);
-                               res->end   = PCI_HOST_ADDR(HBA_DATA(ldev), res->end);
-                               DBG("[%lx/%lx]\n", res->start, res->end);
-                       } else {
-                               DBG("lba_fixup_bus() WTF? 0x%lx [%lx/%lx] XXX",
-                                       res->flags, res->start, res->end);
-                       }
-
                        /*
                        ** FIXME: this will result in whinging for devices
                        ** that share expansion ROMs (think quad tulip), but
@@ -1513,11 +1491,14 @@ lba_driver_probe(struct parisc_device *dev)
                lba_dev->hba.lmmio_space.flags = 0;
        }
 
-       pci_add_resource(&resources, &lba_dev->hba.io_space);
+       pci_add_resource_offset(&resources, &lba_dev->hba.io_space,
+                               HBA_PORT_BASE(lba_dev->hba.hba_num));
        if (lba_dev->hba.elmmio_space.start)
-               pci_add_resource(&resources, &lba_dev->hba.elmmio_space);
+               pci_add_resource_offset(&resources, &lba_dev->hba.elmmio_space,
+                                       lba_dev->hba.lmmio_space_offset);
        if (lba_dev->hba.lmmio_space.flags)
-               pci_add_resource(&resources, &lba_dev->hba.lmmio_space);
+               pci_add_resource_offset(&resources, &lba_dev->hba.lmmio_space,
+                                       lba_dev->hba.lmmio_space_offset);
        if (lba_dev->hba.gmmio_space.flags)
                pci_add_resource(&resources, &lba_dev->hba.gmmio_space);
 
index 37856f7..848bfb8 100644 (file)
@@ -31,6 +31,19 @@ config PCI_DEBUG
 
          When in doubt, say N.
 
+config PCI_REALLOC_ENABLE_AUTO
+       bool "Enable PCI resource re-allocation detection"
+       depends on PCI
+       help
+         Say Y here if you want the PCI core to detect if PCI resource
+         re-allocation needs to be enabled. You can always use pci=realloc=on
+          or pci=realloc=off to override it.  Note this feature is a no-op
+          unless PCI_IOV support is also enabled; in that case it will
+          automatically re-allocate PCI resources if SR-IOV BARs have not
+          been allocated by the BIOS.
+
+         When in doubt, say N.
+
 config PCI_STUB
        tristate "PCI Stub driver"
        depends on PCI
index 398f5d8..4ce5ef2 100644 (file)
 
 #include "pci.h"
 
-void pci_add_resource(struct list_head *resources, struct resource *res)
+void pci_add_resource_offset(struct list_head *resources, struct resource *res,
+                            resource_size_t offset)
 {
-       struct pci_bus_resource *bus_res;
+       struct pci_host_bridge_window *window;
 
-       bus_res = kzalloc(sizeof(struct pci_bus_resource), GFP_KERNEL);
-       if (!bus_res) {
-               printk(KERN_ERR "PCI: can't add bus resource %pR\n", res);
+       window = kzalloc(sizeof(struct pci_host_bridge_window), GFP_KERNEL);
+       if (!window) {
+               printk(KERN_ERR "PCI: can't add host bridge window %pR\n", res);
                return;
        }
 
-       bus_res->res = res;
-       list_add_tail(&bus_res->list, resources);
+       window->res = res;
+       window->offset = offset;
+       list_add_tail(&window->list, resources);
+}
+EXPORT_SYMBOL(pci_add_resource_offset);
+
+void pci_add_resource(struct list_head *resources, struct resource *res)
+{
+       pci_add_resource_offset(resources, res, 0);
 }
 EXPORT_SYMBOL(pci_add_resource);
 
 void pci_free_resource_list(struct list_head *resources)
 {
-       struct pci_bus_resource *bus_res, *tmp;
+       struct pci_host_bridge_window *window, *tmp;
 
-       list_for_each_entry_safe(bus_res, tmp, resources, list) {
-               list_del(&bus_res->list);
-               kfree(bus_res);
+       list_for_each_entry_safe(window, tmp, resources, list) {
+               list_del(&window->list);
+               kfree(window);
        }
 }
 EXPORT_SYMBOL(pci_free_resource_list);
index 9ddf69e..806c44f 100644 (file)
@@ -800,20 +800,10 @@ static int __ref enable_device(struct acpiphp_slot *slot)
        if (slot->flags & SLOT_ENABLED)
                goto err_exit;
 
-       /* sanity check: dev should be NULL when hot-plugged in */
-       dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
-       if (dev) {
-               /* This case shouldn't happen */
-               err("pci_dev structure already exists.\n");
-               pci_dev_put(dev);
-               retval = -1;
-               goto err_exit;
-       }
-
        num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
        if (num == 0) {
-               err("No new device found\n");
-               retval = -1;
+               /* Maybe only part of funcs are added. */
+               dbg("No new device found\n");
                goto err_exit;
        }
 
@@ -848,11 +838,16 @@ static int __ref enable_device(struct acpiphp_slot *slot)
 
        pci_bus_add_devices(bus);
 
+       slot->flags |= SLOT_ENABLED;
        list_for_each_entry(func, &slot->funcs, sibling) {
                dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
                                                  func->function));
-               if (!dev)
+               if (!dev) {
+                       /* Do not set SLOT_ENABLED flag if some funcs
+                          are not added. */
+                       slot->flags &= (~SLOT_ENABLED);
                        continue;
+               }
 
                if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
                    dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) {
@@ -867,7 +862,6 @@ static int __ref enable_device(struct acpiphp_slot *slot)
                pci_dev_put(dev);
        }
 
-       slot->flags |= SLOT_ENABLED;
 
  err_exit:
        return retval;
@@ -892,9 +886,12 @@ static int disable_device(struct acpiphp_slot *slot)
 {
        struct acpiphp_func *func;
        struct pci_dev *pdev;
+       struct pci_bus *bus = slot->bridge->pci_bus;
 
-       /* is this slot already disabled? */
-       if (!(slot->flags & SLOT_ENABLED))
+       /* The slot will be enabled when func 0 is added, so check
+          func 0 before disable the slot. */
+       pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
+       if (!pdev)
                goto err_exit;
 
        list_for_each_entry(func, &slot->funcs, sibling) {
@@ -913,7 +910,7 @@ static int disable_device(struct acpiphp_slot *slot)
                                disable_bridges(pdev->subordinate);
                                pci_disable_device(pdev);
                        }
-                       pci_remove_bus_device(pdev);
+                       __pci_remove_bus_device(pdev);
                        pci_dev_put(pdev);
                }
        }
@@ -1070,7 +1067,7 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
                                        res->end) {
                                /* Could not assign a required resources
                                 * for this device, remove it */
-                               pci_remove_bus_device(dev);
+                               pci_stop_and_remove_bus_device(dev);
                                break;
                        }
                }
index 829c327..ae853cc 100644 (file)
@@ -341,7 +341,7 @@ int cpci_unconfigure_slot(struct slot* slot)
                dev = pci_get_slot(slot->bus,
                                    PCI_DEVFN(PCI_SLOT(slot->devfn), i));
                if (dev) {
-                       pci_remove_bus_device(dev);
+                       pci_stop_and_remove_bus_device(dev);
                        pci_dev_put(dev);
                }
        }
index fb3f846..81af764 100644 (file)
@@ -62,7 +62,7 @@
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
 
 /* local variables */
-static int debug;
+static bool debug;
 static char *bridge;
 static u8 bridge_busnr;
 static u8 bridge_slot;
index 6173b9a..1c84940 100644 (file)
@@ -127,7 +127,7 @@ int cpqhp_unconfigure_device(struct pci_func* func)
                struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j));
                if (temp) {
                        pci_dev_put(temp);
-                       pci_remove_bus_device(temp);
+                       pci_stop_and_remove_bus_device(temp);
                }
        }
        return 0;
index 17d10e2..a019c9a 100644 (file)
@@ -40,7 +40,7 @@ static ssize_t legacy_show(struct kobject *kobj, struct attribute *attr,
 
 static void remove_callback(void *data)
 {
-       pci_remove_bus_device((struct pci_dev *)data);
+       pci_stop_and_remove_bus_device((struct pci_dev *)data);
 }
 
 static ssize_t legacy_store(struct kobject *kobj, struct attribute *attr,
index 5506e0e..4fda7e6 100644 (file)
@@ -721,7 +721,7 @@ static void ibm_unconfigure_device(struct pci_func *func)
        for (j = 0; j < 0x08; j++) {
                temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j);
                if (temp) {
-                       pci_remove_bus_device(temp);
+                       pci_stop_and_remove_bus_device(temp);
                        pci_dev_put(temp);
                }
        }
index 2850e64..714ca5c 100644 (file)
@@ -368,8 +368,10 @@ int __init ibmphp_access_ebda (void)
                        debug ("rio blk id: %x\n", blk_id);
 
                        rio_table_ptr = kzalloc(sizeof(struct rio_table_hdr), GFP_KERNEL);
-                       if (!rio_table_ptr)
-                               return -ENOMEM; 
+                       if (!rio_table_ptr) {
+                               rc = -ENOMEM;
+                               goto out;
+                       }
                        rio_table_ptr->ver_num = readb (io_mem + offset);
                        rio_table_ptr->scal_count = readb (io_mem + offset + 1);
                        rio_table_ptr->riodev_count = readb (io_mem + offset + 2);
index bcdbb16..a960fae 100644 (file)
@@ -241,34 +241,79 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
        return retval;
 }
 
-static inline int check_link_active(struct controller *ctrl)
+static bool check_link_active(struct controller *ctrl)
 {
-       u16 link_status;
+       bool ret = false;
+       u16 lnk_status;
 
-       if (pciehp_readw(ctrl, PCI_EXP_LNKSTA, &link_status))
-               return 0;
-       return !!(link_status & PCI_EXP_LNKSTA_DLLLA);
+       if (pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status))
+               return ret;
+
+       ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
+
+       if (ret)
+               ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
+
+       return ret;
 }
 
-static void pcie_wait_link_active(struct controller *ctrl)
+static void __pcie_wait_link_active(struct controller *ctrl, bool active)
 {
        int timeout = 1000;
 
-       if (check_link_active(ctrl))
+       if (check_link_active(ctrl) == active)
                return;
        while (timeout > 0) {
                msleep(10);
                timeout -= 10;
-               if (check_link_active(ctrl))
+               if (check_link_active(ctrl) == active)
                        return;
        }
-       ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n");
+       ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
+                       active ? "set" : "cleared");
+}
+
+static void pcie_wait_link_active(struct controller *ctrl)
+{
+       __pcie_wait_link_active(ctrl, true);
+}
+
+static void pcie_wait_link_not_active(struct controller *ctrl)
+{
+       __pcie_wait_link_active(ctrl, false);
+}
+
+static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
+{
+       u32 l;
+       int count = 0;
+       int delay = 1000, step = 20;
+       bool found = false;
+
+       do {
+               found = pci_bus_read_dev_vendor_id(bus, devfn, &l, 0);
+               count++;
+
+               if (found)
+                       break;
+
+               msleep(step);
+               delay -= step;
+       } while (delay > 0);
+
+       if (count > 1 && pciehp_debug)
+               printk(KERN_DEBUG "pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n",
+                       pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
+                       PCI_FUNC(devfn), count, step, l);
+
+       return found;
 }
 
 int pciehp_check_link_status(struct controller *ctrl)
 {
        u16 lnk_status;
        int retval = 0;
+       bool found = false;
 
         /*
          * Data Link Layer Link Active Reporting must be capable for
@@ -280,13 +325,10 @@ int pciehp_check_link_status(struct controller *ctrl)
         else
                 msleep(1000);
 
-       /*
-        * Need to wait for 1000 ms after Data Link Layer Link Active
-        * (DLLLA) bit reads 1b before sending configuration request.
-        * We need it before checking Link Training (LT) bit becuase
-        * LT is still set even after DLLLA bit is set on some platform.
-        */
-       msleep(1000);
+       /* wait 100ms before read pci conf, and try in 1s */
+       msleep(100);
+       found = pci_bus_check_dev(ctrl->pcie->port->subordinate,
+                                       PCI_DEVFN(0, 0));
 
        retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
        if (retval) {
@@ -302,19 +344,50 @@ int pciehp_check_link_status(struct controller *ctrl)
                return retval;
        }
 
-       /*
-        * If the port supports Link speeds greater than 5.0 GT/s, we
-        * must wait for 100 ms after Link training completes before
-        * sending configuration request.
-        */
-       if (ctrl->pcie->port->subordinate->max_bus_speed > PCIE_SPEED_5_0GT)
-               msleep(100);
-
        pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status);
 
+       if (!found && !retval)
+               retval = -1;
+
        return retval;
 }
 
+static int __pciehp_link_set(struct controller *ctrl, bool enable)
+{
+       u16 lnk_ctrl;
+       int retval = 0;
+
+       retval = pciehp_readw(ctrl, PCI_EXP_LNKCTL, &lnk_ctrl);
+       if (retval) {
+               ctrl_err(ctrl, "Cannot read LNKCTRL register\n");
+               return retval;
+       }
+
+       if (enable)
+               lnk_ctrl &= ~PCI_EXP_LNKCTL_LD;
+       else
+               lnk_ctrl |= PCI_EXP_LNKCTL_LD;
+
+       retval = pciehp_writew(ctrl, PCI_EXP_LNKCTL, lnk_ctrl);
+       if (retval) {
+               ctrl_err(ctrl, "Cannot write LNKCTRL register\n");
+               return retval;
+       }
+       ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl);
+
+       return retval;
+}
+
+static int pciehp_link_enable(struct controller *ctrl)
+{
+       return __pciehp_link_set(ctrl, true);
+}
+
+static int pciehp_link_disable(struct controller *ctrl)
+{
+       return __pciehp_link_set(ctrl, false);
+}
+
 int pciehp_get_attention_status(struct slot *slot, u8 *status)
 {
        struct controller *ctrl = slot->ctrl;
@@ -533,6 +606,10 @@ int pciehp_power_on_slot(struct slot * slot)
        ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
                 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
 
+       retval = pciehp_link_enable(ctrl);
+       if (retval)
+               ctrl_err(ctrl, "%s: Can not enable the link!\n", __func__);
+
        return retval;
 }
 
@@ -543,6 +620,14 @@ int pciehp_power_off_slot(struct slot * slot)
        u16 cmd_mask;
        int retval;
 
+       /* Disable the link at first */
+       pciehp_link_disable(ctrl);
+       /* wait the link is down */
+       if (ctrl->link_active_reporting)
+               pcie_wait_link_not_active(ctrl);
+       else
+               msleep(1000);
+
        slot_cmd = POWER_OFF;
        cmd_mask = PCI_EXP_SLTCTL_PCC;
        retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
index a4031df..47d9dc0 100644 (file)
@@ -141,7 +141,7 @@ int pciehp_unconfigure_device(struct slot *p_slot)
                                break;
                        }
                }
-               pci_remove_bus_device(temp);
+               pci_stop_and_remove_bus_device(temp);
                /*
                 * Ensure that no new Requests will be generated from
                 * the device.
index c56a941..1e117c2 100644 (file)
@@ -389,7 +389,7 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
        BUG_ON(!bus->self);
        pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
        eeh_remove_bus_device(bus->self);
-       pci_remove_bus_device(bus->self);
+       pci_stop_and_remove_bus_device(bus->self);
 
        return 0;
 }
index 72d507b..de57311 100644 (file)
@@ -554,7 +554,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
                                             PCI_FUNC(func)));
                if (dev) {
                        sn_bus_free_data(dev);
-                       pci_remove_bus_device(dev);
+                       pci_stop_and_remove_bus_device(dev);
                        pci_dev_put(dev);
                }
        }
index a2ccfcd..df7e4bf 100644 (file)
@@ -124,7 +124,7 @@ int shpchp_unconfigure_device(struct slot *p_slot)
                                break;
                        }
                }
-               pci_remove_bus_device(temp);
+               pci_stop_and_remove_bus_device(temp);
                pci_dev_put(temp);
        }
        return rc;
index 0dab5ec..6554e1a 100644 (file)
@@ -142,7 +142,7 @@ failed2:
 failed1:
        pci_dev_put(dev);
        mutex_lock(&iov->dev->sriov->lock);
-       pci_remove_bus_device(virtfn);
+       pci_stop_and_remove_bus_device(virtfn);
        virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
        mutex_unlock(&iov->dev->sriov->lock);
 
@@ -173,10 +173,16 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
 
        sprintf(buf, "virtfn%u", id);
        sysfs_remove_link(&dev->dev.kobj, buf);
-       sysfs_remove_link(&virtfn->dev.kobj, "physfn");
+       /*
+        * pci_stop_dev() could have been called for this virtfn already,
+        * so the directory for the virtfn may have been removed before.
+        * Double check to avoid spurious sysfs warnings.
+        */
+       if (virtfn->dev.kobj.sd)
+               sysfs_remove_link(&virtfn->dev.kobj, "physfn");
 
        mutex_lock(&iov->dev->sriov->lock);
-       pci_remove_bus_device(virtfn);
+       pci_stop_and_remove_bus_device(virtfn);
        virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
        mutex_unlock(&iov->dev->sriov->lock);
 
index 8d9616b..6b54b23 100644 (file)
@@ -419,6 +419,16 @@ static void pci_device_shutdown(struct device *dev)
                drv->shutdown(pci_dev);
        pci_msi_shutdown(pci_dev);
        pci_msix_shutdown(pci_dev);
+
+       /*
+        * Devices may be enabled to wake up by runtime PM, but they need not
+        * be supposed to wake up the system from its "power off" state (e.g.
+        * ACPI S5).  Therefore disable wakeup for all devices that aren't
+        * supposed to wake up the system at this point.  The state argument
+        * will be ignored by pci_enable_wake().
+        */
+       if (!device_may_wakeup(dev))
+               pci_enable_wake(pci_dev, PCI_UNKNOWN, false);
 }
 
 #ifdef CONFIG_PM
index a3cd8ca..a55e248 100644 (file)
@@ -330,7 +330,7 @@ static void remove_callback(struct device *dev)
        struct pci_dev *pdev = to_pci_dev(dev);
 
        mutex_lock(&pci_remove_rescan_mutex);
-       pci_remove_bus_device(pdev);
+       pci_stop_and_remove_bus_device(pdev);
        mutex_unlock(&pci_remove_rescan_mutex);
 }
 
@@ -366,7 +366,10 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
 
        if (val) {
                mutex_lock(&pci_remove_rescan_mutex);
-               pci_rescan_bus(bus);
+               if (!pci_is_root_bus(bus) && list_empty(&bus->devices))
+                       pci_rescan_bus_bridge_resize(bus->self);
+               else
+                       pci_rescan_bus(bus);
                mutex_unlock(&pci_remove_rescan_mutex);
        }
        return count;
index 053670e..8156744 100644 (file)
@@ -94,6 +94,9 @@ u8 pci_cache_line_size;
  */
 unsigned int pcibios_max_latency = 255;
 
+/* If set, the PCIe ARI capability will not be used. */
+static bool pcie_ari_disabled;
+
 /**
  * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
  * @bus: pointer to PCI bus structure to search
@@ -825,6 +828,19 @@ EXPORT_SYMBOL(pci_choose_state);
 #define pcie_cap_has_sltctl2(type, flags)              \
                ((flags & PCI_EXP_FLAGS_VERS) > 1)
 
+static struct pci_cap_saved_state *pci_find_saved_cap(
+       struct pci_dev *pci_dev, char cap)
+{
+       struct pci_cap_saved_state *tmp;
+       struct hlist_node *pos;
+
+       hlist_for_each_entry(tmp, pos, &pci_dev->saved_cap_space, next) {
+               if (tmp->cap.cap_nr == cap)
+                       return tmp;
+       }
+       return NULL;
+}
+
 static int pci_save_pcie_state(struct pci_dev *dev)
 {
        int pos, i = 0;
@@ -959,6 +975,7 @@ void pci_restore_state(struct pci_dev *dev)
 {
        int i;
        u32 val;
+       int tries;
 
        if (!dev->state_saved)
                return;
@@ -973,12 +990,16 @@ void pci_restore_state(struct pci_dev *dev)
         */
        for (i = 15; i >= 0; i--) {
                pci_read_config_dword(dev, i * 4, &val);
-               if (val != dev->saved_config_space[i]) {
+               tries = 10;             
+               while (tries && val != dev->saved_config_space[i]) {
                        dev_dbg(&dev->dev, "restoring config "
                                "space at offset %#x (was %#x, writing %#x)\n",
                                i, val, (int)dev->saved_config_space[i]);
                        pci_write_config_dword(dev,i * 4,
                                dev->saved_config_space[i]);
+                       pci_read_config_dword(dev, i * 4, &val);
+                       mdelay(10);
+                       tries--;
                }
        }
        pci_restore_pcix_state(dev);
@@ -1864,6 +1885,12 @@ void platform_pci_wakeup_init(struct pci_dev *dev)
        platform_pci_sleep_wake(dev, false);
 }
 
+static void pci_add_saved_cap(struct pci_dev *pci_dev,
+       struct pci_cap_saved_state *new_cap)
+{
+       hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
+}
+
 /**
  * pci_add_save_buffer - allocate buffer for saving given capability registers
  * @dev: the PCI device
@@ -1911,6 +1938,15 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
                        "unable to preallocate PCI-X save buffer\n");
 }
 
+void pci_free_cap_save_buffers(struct pci_dev *dev)
+{
+       struct pci_cap_saved_state *tmp;
+       struct hlist_node *pos, *n;
+
+       hlist_for_each_entry_safe(tmp, pos, n, &dev->saved_cap_space, next)
+               kfree(tmp);
+}
+
 /**
  * pci_enable_ari - enable ARI forwarding if hardware support it
  * @dev: the PCI device
@@ -1922,7 +1958,7 @@ void pci_enable_ari(struct pci_dev *dev)
        u16 flags, ctrl;
        struct pci_dev *bridge;
 
-       if (!pci_is_pcie(dev) || dev->devfn)
+       if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
                return;
 
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
@@ -3661,6 +3697,68 @@ int pci_is_reassigndev(struct pci_dev *dev)
        return (pci_specified_resource_alignment(dev) != 0);
 }
 
+/*
+ * This function disables memory decoding and releases memory resources
+ * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
+ * It also rounds up size to specified alignment.
+ * Later on, the kernel will assign page-aligned memory resource back
+ * to the device.
+ */
+void pci_reassigndev_resource_alignment(struct pci_dev *dev)
+{
+       int i;
+       struct resource *r;
+       resource_size_t align, size;
+       u16 command;
+
+       if (!pci_is_reassigndev(dev))
+               return;
+
+       if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
+               dev_warn(&dev->dev,
+                       "Can't reassign resources to host bridge.\n");
+               return;
+       }
+
+       dev_info(&dev->dev,
+               "Disabling memory decoding and releasing memory resources.\n");
+       pci_read_config_word(dev, PCI_COMMAND, &command);
+       command &= ~PCI_COMMAND_MEMORY;
+       pci_write_config_word(dev, PCI_COMMAND, command);
+
+       align = pci_specified_resource_alignment(dev);
+       for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
+               r = &dev->resource[i];
+               if (!(r->flags & IORESOURCE_MEM))
+                       continue;
+               size = resource_size(r);
+               if (size < align) {
+                       size = align;
+                       dev_info(&dev->dev,
+                               "Rounding up size of resource #%d to %#llx.\n",
+                               i, (unsigned long long)size);
+               }
+               r->end = size - 1;
+               r->start = 0;
+       }
+       /* Need to disable bridge's resource window,
+        * to enable the kernel to reassign new resource
+        * window later on.
+        */
+       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+               for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+                       r = &dev->resource[i];
+                       if (!(r->flags & IORESOURCE_MEM))
+                               continue;
+                       r->end = resource_size(r) - 1;
+                       r->start = 0;
+               }
+               pci_disable_bridge_window(dev);
+       }
+}
+
 ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
 {
        if (count > RESOURCE_ALIGNMENT_PARAM_SIZE - 1)
@@ -3739,10 +3837,14 @@ static int __init pci_setup(char *str)
                                pci_no_msi();
                        } else if (!strcmp(str, "noaer")) {
                                pci_no_aer();
+                       } else if (!strncmp(str, "realloc=", 8)) {
+                               pci_realloc_get_opt(str + 8);
                        } else if (!strncmp(str, "realloc", 7)) {
-                               pci_realloc();
+                               pci_realloc_get_opt("on");
                        } else if (!strcmp(str, "nodomains")) {
                                pci_no_domains();
+                       } else if (!strncmp(str, "noari", 5)) {
+                               pcie_ari_disabled = true;
                        } else if (!strncmp(str, "cbiosize=", 9)) {
                                pci_cardbus_io_size = memparse(str + 9, &str);
                        } else if (!strncmp(str, "cbmemsize=", 10)) {
index 1009a5e..e494347 100644 (file)
@@ -73,6 +73,7 @@ extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
 extern void pci_pm_init(struct pci_dev *dev);
 extern void platform_pci_wakeup_init(struct pci_dev *dev);
 extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
+void pci_free_cap_save_buffers(struct pci_dev *dev);
 
 static inline void pci_wakeup_event(struct pci_dev *dev)
 {
@@ -148,7 +149,7 @@ static inline void pci_no_msi(void) { }
 static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
 #endif
 
-extern void pci_realloc(void);
+void pci_realloc_get_opt(char *);
 
 static inline int pci_no_d1d2(struct pci_dev *dev)
 {
@@ -207,6 +208,8 @@ enum pci_bar_type {
        pci_bar_mem64,          /* A 64-bit memory BAR */
 };
 
+bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
+                               int crs_timeout);
 extern int pci_setup_device(struct pci_dev *dev);
 extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                                struct resource *res, unsigned int reg);
@@ -225,11 +228,8 @@ static inline int pci_ari_enabled(struct pci_bus *bus)
        return bus->self && bus->self->ari_enabled;
 }
 
-#ifdef CONFIG_PCI_QUIRKS
-extern int pci_is_reassigndev(struct pci_dev *dev);
-resource_size_t pci_specified_resource_alignment(struct pci_dev *dev);
+void pci_reassigndev_resource_alignment(struct pci_dev *dev);
 extern void pci_disable_bridge_window(struct pci_dev *dev);
-#endif
 
 /* Single Root I/O Virtualization */
 struct pci_sriov {
index 72962cc..6c8bc58 100644 (file)
@@ -55,6 +55,31 @@ config PCIEASPM_DEBUG
          This enables PCI Express ASPM debug support. It will add per-device
          interface to control ASPM.
 
+choice
+       prompt "Default ASPM policy"
+       default PCIEASPM_DEFAULT
+       depends on PCIEASPM
+
+config PCIEASPM_DEFAULT
+        bool "BIOS default"
+       depends on PCIEASPM
+       help
+         Use the BIOS defaults for PCI Express ASPM.
+
+config PCIEASPM_POWERSAVE
+        bool "Powersave"
+       depends on PCIEASPM
+       help
+         Enable PCI Express ASPM L0s and L1 where possible, even if the
+         BIOS did not.
+
+config PCIEASPM_PERFORMANCE
+        bool "Performance"
+       depends on PCIEASPM
+       help
+         Disable PCI Express ASPM L0s and L1, even if the BIOS enabled them.
+endchoice
+
 config PCIE_PME
        def_bool y
        depends on PCIEPORTBUS && PM_RUNTIME && EXPERIMENTAL && ACPI
index 24f049e..4bdef24 100644 (file)
@@ -76,7 +76,15 @@ static LIST_HEAD(link_list);
 #define POLICY_DEFAULT 0       /* BIOS default setting */
 #define POLICY_PERFORMANCE 1   /* high performance */
 #define POLICY_POWERSAVE 2     /* high power saving */
+
+#ifdef CONFIG_PCIEASPM_PERFORMANCE
+static int aspm_policy = POLICY_PERFORMANCE;
+#elif defined CONFIG_PCIEASPM_POWERSAVE
+static int aspm_policy = POLICY_POWERSAVE;
+#else
 static int aspm_policy;
+#endif
+
 static const char *policy_str[] = {
        [POLICY_DEFAULT] = "default",
        [POLICY_PERFORMANCE] = "performance",
index bd00a01..eea2ca2 100644 (file)
@@ -34,6 +34,18 @@ struct pci_dev;
 
 extern void pcie_clear_root_pme_status(struct pci_dev *dev);
 
+#ifdef CONFIG_HOTPLUG_PCI_PCIE
+extern bool pciehp_msi_disabled;
+
+static inline bool pciehp_no_msi(void)
+{
+       return pciehp_msi_disabled;
+}
+
+#else  /* !CONFIG_HOTPLUG_PCI_PCIE */
+static inline bool pciehp_no_msi(void) { return false; }
+#endif /* !CONFIG_HOTPLUG_PCI_PCIE */
+
 #ifdef CONFIG_PCIE_PME
 extern bool pcie_pme_msi_disabled;
 
index 595654a..2f589a5 100644 (file)
 #include "../pci.h"
 #include "portdrv.h"
 
+bool pciehp_msi_disabled;
+
+static int __init pciehp_setup(char *str)
+{
+       if (!strncmp(str, "nomsi", 5))
+               pciehp_msi_disabled = true;
+
+       return 1;
+}
+__setup("pcie_hp=", pciehp_setup);
+
 /**
  * release_pcie_device - free PCI Express port service device structure
  * @dev: Port service device to release
@@ -189,8 +200,9 @@ static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
 {
        int i, irq = -1;
 
-       /* We have to use INTx if MSI cannot be used for PCIe PME. */
-       if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) {
+       /* We have to use INTx if MSI cannot be used for PCIe PME or pciehp. */
+       if (((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) ||
+           ((mask & PCIE_PORT_SERVICE_HP) && pciehp_no_msi())) {
                if (dev->pin)
                        irq = dev->irq;
                goto no_msi;
index 71eac9c..5e1ca3c 100644 (file)
@@ -15,6 +15,8 @@
 #define CARDBUS_LATENCY_TIMER  176     /* secondary latency timer */
 #define CARDBUS_RESERVE_BUSNR  3
 
+static LIST_HEAD(pci_host_bridges);
+
 /* Ugh.  Need to stop exporting this to modules. */
 LIST_HEAD(pci_root_buses);
 EXPORT_SYMBOL(pci_root_buses);
@@ -42,6 +44,82 @@ int no_pci_devices(void)
 }
 EXPORT_SYMBOL(no_pci_devices);
 
+static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev)
+{
+       struct pci_bus *bus;
+       struct pci_host_bridge *bridge;
+
+       bus = dev->bus;
+       while (bus->parent)
+               bus = bus->parent;
+
+       list_for_each_entry(bridge, &pci_host_bridges, list) {
+               if (bridge->bus == bus)
+                       return bridge;
+       }
+
+       return NULL;
+}
+
+static bool resource_contains(struct resource *res1, struct resource *res2)
+{
+       return res1->start <= res2->start && res1->end >= res2->end;
+}
+
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+                            struct resource *res)
+{
+       struct pci_host_bridge *bridge = pci_host_bridge(dev);
+       struct pci_host_bridge_window *window;
+       resource_size_t offset = 0;
+
+       list_for_each_entry(window, &bridge->windows, list) {
+               if (resource_type(res) != resource_type(window->res))
+                       continue;
+
+               if (resource_contains(window->res, res)) {
+                       offset = window->offset;
+                       break;
+               }
+       }
+
+       region->start = res->start - offset;
+       region->end = res->end - offset;
+}
+EXPORT_SYMBOL(pcibios_resource_to_bus);
+
+static bool region_contains(struct pci_bus_region *region1,
+                           struct pci_bus_region *region2)
+{
+       return region1->start <= region2->start && region1->end >= region2->end;
+}
+
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+                            struct pci_bus_region *region)
+{
+       struct pci_host_bridge *bridge = pci_host_bridge(dev);
+       struct pci_host_bridge_window *window;
+       struct pci_bus_region bus_region;
+       resource_size_t offset = 0;
+
+       list_for_each_entry(window, &bridge->windows, list) {
+               if (resource_type(res) != resource_type(window->res))
+                       continue;
+
+               bus_region.start = window->res->start - window->offset;
+               bus_region.end = window->res->end - window->offset;
+
+               if (region_contains(&bus_region, region)) {
+                       offset = window->offset;
+                       break;
+               }
+       }
+
+       res->start = region->start + offset;
+       res->end = region->end + offset;
+}
+EXPORT_SYMBOL(pcibios_bus_to_resource);
+
 /*
  * PCI Bus Class
  */
@@ -135,6 +213,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
 {
        u32 l, sz, mask;
        u16 orig_cmd;
+       struct pci_bus_region region;
 
        mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
 
@@ -214,11 +293,13 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                        /* Address above 32-bit boundary; disable the BAR */
                        pci_write_config_dword(dev, pos, 0);
                        pci_write_config_dword(dev, pos + 4, 0);
-                       res->start = 0;
-                       res->end = sz64;
+                       region.start = 0;
+                       region.end = sz64;
+                       pcibios_bus_to_resource(dev, res, &region);
                } else {
-                       res->start = l64;
-                       res->end = l64 + sz64;
+                       region.start = l64;
+                       region.end = l64 + sz64;
+                       pcibios_bus_to_resource(dev, res, &region);
                        dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n",
                                   pos, res);
                }
@@ -228,8 +309,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                if (!sz)
                        goto fail;
 
-               res->start = l;
-               res->end = l + sz;
+               region.start = l;
+               region.end = l + sz;
+               pcibios_bus_to_resource(dev, res, &region);
 
                dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res);
        }
@@ -266,7 +348,8 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
        struct pci_dev *dev = child->self;
        u8 io_base_lo, io_limit_lo;
        unsigned long base, limit;
-       struct resource *res;
+       struct pci_bus_region region;
+       struct resource *res, res2;
 
        res = child->resource[0];
        pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
@@ -284,10 +367,14 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
 
        if (base && base <= limit) {
                res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+               res2.flags = res->flags;
+               region.start = base;
+               region.end = limit + 0xfff;
+               pcibios_bus_to_resource(dev, &res2, &region);
                if (!res->start)
-                       res->start = base;
+                       res->start = res2.start;
                if (!res->end)
-                       res->end = limit + 0xfff;
+                       res->end = res2.end;
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
        }
 }
@@ -297,6 +384,7 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
        struct pci_dev *dev = child->self;
        u16 mem_base_lo, mem_limit_lo;
        unsigned long base, limit;
+       struct pci_bus_region region;
        struct resource *res;
 
        res = child->resource[1];
@@ -306,8 +394,9 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
        limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
        if (base && base <= limit) {
                res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
-               res->start = base;
-               res->end = limit + 0xfffff;
+               region.start = base;
+               region.end = limit + 0xfffff;
+               pcibios_bus_to_resource(dev, res, &region);
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
        }
 }
@@ -317,6 +406,7 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
        struct pci_dev *dev = child->self;
        u16 mem_base_lo, mem_limit_lo;
        unsigned long base, limit;
+       struct pci_bus_region region;
        struct resource *res;
 
        res = child->resource[2];
@@ -353,8 +443,9 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
                                         IORESOURCE_MEM | IORESOURCE_PREFETCH;
                if (res->flags & PCI_PREF_RANGE_TYPE_64)
                        res->flags |= IORESOURCE_MEM_64;
-               res->start = base;
-               res->end = limit + 0xfffff;
+               region.start = base;
+               region.end = limit + 0xfffff;
+               pcibios_bus_to_resource(dev, res, &region);
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
        }
 }
@@ -900,6 +991,8 @@ int pci_setup_device(struct pci_dev *dev)
        u8 hdr_type;
        struct pci_slot *slot;
        int pos = 0;
+       struct pci_bus_region region;
+       struct resource *res;
 
        if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
                return -EIO;
@@ -926,12 +1019,10 @@ int pci_setup_device(struct pci_dev *dev)
 
        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
        dev->revision = class & 0xff;
-       class >>= 8;                                /* upper 3 bytes */
-       dev->class = class;
-       class >>= 8;
+       dev->class = class >> 8;                    /* upper 3 bytes */
 
-       dev_printk(KERN_DEBUG, &dev->dev, "[%04x:%04x] type %d class %#08x\n",
-                  dev->vendor, dev->device, dev->hdr_type, class);
+       dev_printk(KERN_DEBUG, &dev->dev, "[%04x:%04x] type %02x class %#08x\n",
+                  dev->vendor, dev->device, dev->hdr_type, dev->class);
 
        /* need to have dev->class ready */
        dev->cfg_size = pci_cfg_space_size(dev);
@@ -963,20 +1054,28 @@ int pci_setup_device(struct pci_dev *dev)
                        u8 progif;
                        pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
                        if ((progif & 1) == 0) {
-                               dev->resource[0].start = 0x1F0;
-                               dev->resource[0].end = 0x1F7;
-                               dev->resource[0].flags = LEGACY_IO_RESOURCE;
-                               dev->resource[1].start = 0x3F6;
-                               dev->resource[1].end = 0x3F6;
-                               dev->resource[1].flags = LEGACY_IO_RESOURCE;
+                               region.start = 0x1F0;
+                               region.end = 0x1F7;
+                               res = &dev->resource[0];
+                               res->flags = LEGACY_IO_RESOURCE;
+                               pcibios_bus_to_resource(dev, res, &region);
+                               region.start = 0x3F6;
+                               region.end = 0x3F6;
+                               res = &dev->resource[1];
+                               res->flags = LEGACY_IO_RESOURCE;
+                               pcibios_bus_to_resource(dev, res, &region);
                        }
                        if ((progif & 4) == 0) {
-                               dev->resource[2].start = 0x170;
-                               dev->resource[2].end = 0x177;
-                               dev->resource[2].flags = LEGACY_IO_RESOURCE;
-                               dev->resource[3].start = 0x376;
-                               dev->resource[3].end = 0x376;
-                               dev->resource[3].flags = LEGACY_IO_RESOURCE;
+                               region.start = 0x170;
+                               region.end = 0x177;
+                               res = &dev->resource[2];
+                               res->flags = LEGACY_IO_RESOURCE;
+                               pcibios_bus_to_resource(dev, res, &region);
+                               region.start = 0x376;
+                               region.end = 0x376;
+                               res = &dev->resource[3];
+                               res->flags = LEGACY_IO_RESOURCE;
+                               pcibios_bus_to_resource(dev, res, &region);
                        }
                }
                break;
@@ -1013,8 +1112,8 @@ int pci_setup_device(struct pci_dev *dev)
                return -EIO;
 
        bad:
-               dev_err(&dev->dev, "ignoring class %02x (doesn't match header "
-                       "type %02x)\n", class, dev->hdr_type);
+               dev_err(&dev->dev, "ignoring class %#08x (doesn't match header "
+                       "type %02x)\n", dev->class, dev->hdr_type);
                dev->class = PCI_CLASS_NOT_DEFINED;
        }
 
@@ -1026,6 +1125,7 @@ static void pci_release_capabilities(struct pci_dev *dev)
 {
        pci_vpd_release(dev);
        pci_iov_release(dev);
+       pci_free_cap_save_buffers(dev);
 }
 
 /**
@@ -1118,40 +1218,54 @@ struct pci_dev *alloc_pci_dev(void)
 }
 EXPORT_SYMBOL(alloc_pci_dev);
 
-/*
- * Read the config data for a PCI device, sanity-check it
- * and fill in the dev structure...
- */
-static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
+bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
+                                int crs_timeout)
 {
-       struct pci_dev *dev;
-       u32 l;
        int delay = 1;
 
-       if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
-               return NULL;
+       if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
+               return false;
 
        /* some broken boards return 0 or ~0 if a slot is empty: */
-       if (l == 0xffffffff || l == 0x00000000 ||
-           l == 0x0000ffff || l == 0xffff0000)
-               return NULL;
+       if (*l == 0xffffffff || *l == 0x00000000 ||
+           *l == 0x0000ffff || *l == 0xffff0000)
+               return false;
 
        /* Configuration request Retry Status */
-       while (l == 0xffff0001) {
+       while (*l == 0xffff0001) {
+               if (!crs_timeout)
+                       return false;
+
                msleep(delay);
                delay *= 2;
-               if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
-                       return NULL;
+               if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, l))
+                       return false;
                /* Card hasn't responded in 60 seconds?  Must be stuck. */
-               if (delay > 60 * 1000) {
+               if (delay > crs_timeout) {
                        printk(KERN_WARNING "pci %04x:%02x:%02x.%d: not "
                                        "responding\n", pci_domain_nr(bus),
                                        bus->number, PCI_SLOT(devfn),
                                        PCI_FUNC(devfn));
-                       return NULL;
+                       return false;
                }
        }
 
+       return true;
+}
+EXPORT_SYMBOL(pci_bus_read_dev_vendor_id);
+
+/*
+ * Read the config data for a PCI device, sanity-check it
+ * and fill in the dev structure...
+ */
+static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
+{
+       struct pci_dev *dev;
+       u32 l;
+
+       if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000))
+               return NULL;
+
        dev = alloc_pci_dev();
        if (!dev)
                return NULL;
@@ -1212,6 +1326,9 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
        /* Fix up broken headers */
        pci_fixup_device(pci_fixup_header, dev);
 
+       /* moved out from quirk header fixup code */
+       pci_reassigndev_resource_alignment(dev);
+
        /* Clear the state_saved flag. */
        dev->state_saved = false;
 
@@ -1530,21 +1647,27 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
 struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
                struct pci_ops *ops, void *sysdata, struct list_head *resources)
 {
-       int error, i;
+       int error;
+       struct pci_host_bridge *bridge;
        struct pci_bus *b, *b2;
        struct device *dev;
-       struct pci_bus_resource *bus_res, *n;
+       struct pci_host_bridge_window *window, *n;
        struct resource *res;
+       resource_size_t offset;
+       char bus_addr[64];
+       char *fmt;
+
+       bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+       if (!bridge)
+               return NULL;
 
        b = pci_alloc_bus();
        if (!b)
-               return NULL;
+               goto err_bus;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev) {
-               kfree(b);
-               return NULL;
-       }
+       if (!dev)
+               goto err_dev;
 
        b->sysdata = sysdata;
        b->ops = ops;
@@ -1556,10 +1679,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
                goto err_out;
        }
 
-       down_write(&pci_bus_sem);
-       list_add_tail(&b->node, &pci_root_buses);
-       up_write(&pci_bus_sem);
-
        dev->parent = parent;
        dev->release = pci_release_bus_bridge_dev;
        dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus);
@@ -1585,31 +1704,53 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 
        b->number = b->secondary = bus;
 
-       /* Add initial resources to the bus */
-       list_for_each_entry_safe(bus_res, n, resources, list)
-               list_move_tail(&bus_res->list, &b->resources);
+       bridge->bus = b;
+       INIT_LIST_HEAD(&bridge->windows);
 
        if (parent)
                dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
        else
                printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));
 
-       pci_bus_for_each_resource(b, res, i) {
-               if (res)
-                       dev_info(&b->dev, "root bus resource %pR\n", res);
+       /* Add initial resources to the bus */
+       list_for_each_entry_safe(window, n, resources, list) {
+               list_move_tail(&window->list, &bridge->windows);
+               res = window->res;
+               offset = window->offset;
+               pci_bus_add_resource(b, res, 0);
+               if (offset) {
+                       if (resource_type(res) == IORESOURCE_IO)
+                               fmt = " (bus address [%#06llx-%#06llx])";
+                       else
+                               fmt = " (bus address [%#010llx-%#010llx])";
+                       snprintf(bus_addr, sizeof(bus_addr), fmt,
+                                (unsigned long long) (res->start - offset),
+                                (unsigned long long) (res->end - offset));
+               } else
+                       bus_addr[0] = '\0';
+               dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr);
        }
 
+       down_write(&pci_bus_sem);
+       list_add_tail(&bridge->list, &pci_host_bridges);
+       list_add_tail(&b->node, &pci_root_buses);
+       up_write(&pci_bus_sem);
+
        return b;
 
 class_dev_reg_err:
        device_unregister(dev);
 dev_reg_err:
        down_write(&pci_bus_sem);
+       list_del(&bridge->list);
        list_del(&b->node);
        up_write(&pci_bus_sem);
 err_out:
        kfree(dev);
+err_dev:
        kfree(b);
+err_bus:
+       kfree(bridge);
        return NULL;
 }
 
@@ -1667,36 +1808,29 @@ EXPORT_SYMBOL(pci_scan_bus);
 
 #ifdef CONFIG_HOTPLUG
 /**
- * pci_rescan_bus - scan a PCI bus for devices.
- * @bus: PCI bus to scan
+ * pci_rescan_bus_bridge_resize - scan a PCI bus for devices.
+ * @bridge: PCI bridge for the bus to scan
  *
- * Scan a PCI bus and child buses for new devices, adds them,
- * and enables them.
+ * Scan a PCI bus and child buses for new devices, add them,
+ * and enable them, resizing bridge mmio/io resource if necessary
+ * and possible.  The caller must ensure the child devices are already
+ * removed for resizing to occur.
  *
  * Returns the max number of subordinate bus discovered.
  */
-unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
+unsigned int __ref pci_rescan_bus_bridge_resize(struct pci_dev *bridge)
 {
        unsigned int max;
-       struct pci_dev *dev;
+       struct pci_bus *bus = bridge->subordinate;
 
        max = pci_scan_child_bus(bus);
 
-       down_read(&pci_bus_sem);
-       list_for_each_entry(dev, &bus->devices, bus_list)
-               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
-                   dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
-                       if (dev->subordinate)
-                               pci_bus_size_bridges(dev->subordinate);
-       up_read(&pci_bus_sem);
+       pci_assign_unassigned_bridge_resources(bridge);
 
-       pci_bus_assign_resources(bus);
-       pci_enable_bridges(bus);
        pci_bus_add_devices(bus);
 
        return max;
 }
-EXPORT_SYMBOL_GPL(pci_rescan_bus);
 
 EXPORT_SYMBOL(pci_add_new_bus);
 EXPORT_SYMBOL(pci_scan_slot);
index f722c5f..4bf7102 100644 (file)
 #include <linux/dmi.h>
 #include <linux/pci-aspm.h>
 #include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/ktime.h>
 #include <asm/dma.h>   /* isa_dma_bridge_buggy */
 #include "pci.h"
 
 /*
- * This quirk function disables memory decoding and releases memory resources
- * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
- * It also rounds up size to specified alignment.
- * Later on, the kernel will assign page-aligned memory resource back
- * to the device.
- */
-static void __devinit quirk_resource_alignment(struct pci_dev *dev)
-{
-       int i;
-       struct resource *r;
-       resource_size_t align, size;
-       u16 command;
-
-       if (!pci_is_reassigndev(dev))
-               return;
-
-       if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
-           (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
-               dev_warn(&dev->dev,
-                       "Can't reassign resources to host bridge.\n");
-               return;
-       }
-
-       dev_info(&dev->dev,
-               "Disabling memory decoding and releasing memory resources.\n");
-       pci_read_config_word(dev, PCI_COMMAND, &command);
-       command &= ~PCI_COMMAND_MEMORY;
-       pci_write_config_word(dev, PCI_COMMAND, command);
-
-       align = pci_specified_resource_alignment(dev);
-       for (i=0; i < PCI_BRIDGE_RESOURCES; i++) {
-               r = &dev->resource[i];
-               if (!(r->flags & IORESOURCE_MEM))
-                       continue;
-               size = resource_size(r);
-               if (size < align) {
-                       size = align;
-                       dev_info(&dev->dev,
-                               "Rounding up size of resource #%d to %#llx.\n",
-                               i, (unsigned long long)size);
-               }
-               r->end = size - 1;
-               r->start = 0;
-       }
-       /* Need to disable bridge's resource window,
-        * to enable the kernel to reassign new resource
-        * window later on.
-        */
-       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
-           (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
-               for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
-                       r = &dev->resource[i];
-                       if (!(r->flags & IORESOURCE_MEM))
-                               continue;
-                       r->end = resource_size(r) - 1;
-                       r->start = 0;
-               }
-               pci_disable_bridge_window(dev);
-       }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment);
-
-/*
  * Decoding should be disabled for a PCI device during BAR sizing to avoid
  * conflict. But doing so may cause problems on host bridge and perhaps other
  * key system devices. For devices that need to have mmio decoding always-on,
@@ -100,10 +39,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment);
  */
 static void __devinit quirk_mmio_always_on(struct pci_dev *dev)
 {
-       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
-               dev->mmio_always_on = 1;
+       dev->mmio_always_on = 1;
 }
-DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, quirk_mmio_always_on);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
+                               PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
 
 /* The Mellanox Tavor device gives false positive parity errors
  * Mark this device with a broken_parity_status, to allow
@@ -1002,12 +941,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C597_0,     quirk_vt
  */
 static void quirk_cardbus_legacy(struct pci_dev *dev)
 {
-       if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
-               return;
        pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
-DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+                       PCI_CLASS_BRIDGE_CARDBUS, 8, quirk_cardbus_legacy);
+DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(PCI_ANY_ID, PCI_ANY_ID,
+                       PCI_CLASS_BRIDGE_CARDBUS, 8, quirk_cardbus_legacy);
 
 /*
  * Following the PCI ordering rules is optional on the AMD762. I'm not
@@ -1164,17 +1103,20 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, qui
 
 static void __devinit quirk_no_ata_d3(struct pci_dev *pdev)
 {
-       /* Quirk the legacy ATA devices only. The AHCI ones are ok */
-       if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE)
-               pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
+       pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
 }
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID, quirk_no_ata_d3);
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID, quirk_no_ata_d3);
+/* Quirk the legacy ATA devices only. The AHCI ones are ok */
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_ANY_ID,
+                               PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+                               PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
 /* ALi loses some register settings that we cannot then restore */
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, PCI_ANY_ID, quirk_no_ata_d3);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AL, PCI_ANY_ID,
+                               PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
 /* VIA comes back fine but we need to keep it alive or ACPI GTM failures
    occur when mode detecting */
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_no_ata_d3);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID,
+                               PCI_CLASS_STORAGE_IDE, 8, quirk_no_ata_d3);
 
 /* This was originally an Alpha specific thing, but it really fits here.
  * The i82375 PCI/EISA bridge appears as non-classified. Fix that.
@@ -1873,8 +1815,7 @@ static void __devinit quirk_netmos(struct pci_dev *dev)
        case PCI_DEVICE_ID_NETMOS_9745:
        case PCI_DEVICE_ID_NETMOS_9845:
        case PCI_DEVICE_ID_NETMOS_9855:
-               if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
-                   num_parallel) {
+               if (num_parallel) {
                        dev_info(&dev->dev, "Netmos %04x (%u parallel, "
                                "%u serial); changing class SERIAL to OTHER "
                                "(use parport_serial)\n",
@@ -1884,7 +1825,8 @@ static void __devinit quirk_netmos(struct pci_dev *dev)
                }
        }
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID,
+                        PCI_CLASS_COMMUNICATION_SERIAL, 8, quirk_netmos);
 
 static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
 {
@@ -1952,7 +1894,8 @@ static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
 
        iounmap(csr);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_e100_interrupt);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
+                       PCI_CLASS_NETWORK_ETHERNET, 8, quirk_e100_interrupt);
 
 /*
  * The 82575 and 82598 may experience data corruption issues when transitioning
@@ -2834,12 +2777,11 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors);
 static void __devinit fixup_ti816x_class(struct pci_dev* dev)
 {
        /* TI 816x devices do not have class code set when in PCIe boot mode */
-       if (dev->class == PCI_CLASS_NOT_DEFINED) {
-               dev_info(&dev->dev, "Setting PCI class for 816x PCIe device\n");
-               dev->class = PCI_CLASS_MULTIMEDIA_VIDEO;
-       }
+       dev_info(&dev->dev, "Setting PCI class for 816x PCIe device\n");
+       dev->class = PCI_CLASS_MULTIMEDIA_VIDEO;
 }
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_TI, 0xb800, fixup_ti816x_class);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_TI, 0xb800,
+                                PCI_CLASS_NOT_DEFINED, 0, fixup_ti816x_class);
 
 /* Some PCIe devices do not work reliably with the claimed maximum
  * payload size supported.
@@ -2924,17 +2866,73 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f8, quirk_intel_mc_errata);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
 
+
+static void do_one_fixup_debug(void (*fn)(struct pci_dev *dev), struct pci_dev *dev)
+{
+       ktime_t calltime, delta, rettime;
+       unsigned long long duration;
+
+       printk(KERN_DEBUG "calling  %pF @ %i for %s\n",
+                       fn, task_pid_nr(current), dev_name(&dev->dev));
+       calltime = ktime_get();
+       fn(dev);
+       rettime = ktime_get();
+       delta = ktime_sub(rettime, calltime);
+       duration = (unsigned long long) ktime_to_ns(delta) >> 10;
+       printk(KERN_DEBUG "pci fixup %pF returned after %lld usecs for %s\n",
+                       fn, duration, dev_name(&dev->dev));
+}
+
+/*
+ * Some BIOS implementations leave the Intel GPU interrupts enabled,
+ * even though no one is handling them (f.e. i915 driver is never loaded).
+ * Additionally the interrupt destination is not set up properly
+ * and the interrupt ends up -somewhere-.
+ *
+ * These spurious interrupts are "sticky" and the kernel disables
+ * the (shared) interrupt line after 100.000+ generated interrupts.
+ *
+ * Fix it by disabling the still enabled interrupts.
+ * This resolves crashes often seen on monitor unplug.
+ */
+#define I915_DEIER_REG 0x4400c
+static void __devinit disable_igfx_irq(struct pci_dev *dev)
+{
+       void __iomem *regs = pci_iomap(dev, 0, 0);
+       if (regs == NULL) {
+               dev_warn(&dev->dev, "igfx quirk: Can't iomap PCI device\n");
+               return;
+       }
+
+       /* Check if any interrupt line is still enabled */
+       if (readl(regs + I915_DEIER_REG) != 0) {
+               dev_warn(&dev->dev, "BIOS left Intel GPU interrupts enabled; "
+                       "disabling\n");
+
+               writel(0, regs + I915_DEIER_REG);
+       }
+
+       pci_iounmap(dev, regs);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
                          struct pci_fixup *end)
 {
-       while (f < end) {
-               if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
-                   (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
+       for (; f < end; f++)
+               if ((f->class == (u32) (dev->class >> f->class_shift) ||
+                    f->class == (u32) PCI_ANY_ID) &&
+                   (f->vendor == dev->vendor ||
+                    f->vendor == (u16) PCI_ANY_ID) &&
+                   (f->device == dev->device ||
+                    f->device == (u16) PCI_ANY_ID)) {
                        dev_dbg(&dev->dev, "calling %pF\n", f->hook);
-                       f->hook(dev);
+                       if (initcall_debug)
+                               do_one_fixup_debug(f->hook, dev);
+                       else
+                               f->hook(dev);
                }
-               f++;
-       }
 }
 
 extern struct pci_fixup __start_pci_fixups_early[];
index ef8b18c..fd77e2b 100644 (file)
@@ -79,7 +79,7 @@ EXPORT_SYMBOL(pci_remove_bus);
 
 static void __pci_remove_behind_bridge(struct pci_dev *dev);
 /**
- * pci_remove_bus_device - remove a PCI device and any children
+ * pci_stop_and_remove_bus_device - remove a PCI device and any children
  * @dev: the device to remove
  *
  * Remove a PCI device from the device lists, informing the drivers
@@ -90,7 +90,7 @@ static void __pci_remove_behind_bridge(struct pci_dev *dev);
  * device lists, remove the /proc entry, and notify userspace
  * (/sbin/hotplug).
  */
-static void __pci_remove_bus_device(struct pci_dev *dev)
+void __pci_remove_bus_device(struct pci_dev *dev)
 {
        if (dev->subordinate) {
                struct pci_bus *b = dev->subordinate;
@@ -102,7 +102,9 @@ static void __pci_remove_bus_device(struct pci_dev *dev)
 
        pci_destroy_dev(dev);
 }
-void pci_remove_bus_device(struct pci_dev *dev)
+EXPORT_SYMBOL(__pci_remove_bus_device);
+
+void pci_stop_and_remove_bus_device(struct pci_dev *dev)
 {
        pci_stop_bus_device(dev);
        __pci_remove_bus_device(dev);
@@ -127,14 +129,15 @@ static void pci_stop_behind_bridge(struct pci_dev *dev)
 }
 
 /**
- * pci_remove_behind_bridge - remove all devices behind a PCI bridge
+ * pci_stop_and_remove_behind_bridge - stop and remove all devices behind
+ *                                      a PCI bridge
  * @dev: PCI bridge device
  *
  * Remove all devices on the bus, except for the parent bridge.
  * This also removes any child buses, and any devices they may
  * contain in a depth-first manner.
  */
-void pci_remove_behind_bridge(struct pci_dev *dev)
+void pci_stop_and_remove_behind_bridge(struct pci_dev *dev)
 {
        pci_stop_behind_bridge(dev);
        __pci_remove_behind_bridge(dev);
@@ -144,7 +147,15 @@ static void pci_stop_bus_devices(struct pci_bus *bus)
 {
        struct list_head *l, *n;
 
-       list_for_each_safe(l, n, &bus->devices) {
+       /*
+        * VFs could be removed by pci_stop_and_remove_bus_device() in the
+        *  pci_stop_bus_devices() code path for PF.
+        *  aka, bus->devices get updated in the process.
+        * but VFs are inserted after PFs when SRIOV is enabled for PF,
+        * We can iterate the list backwards to get prev valid PF instead
+        *  of removed VF.
+        */
+       list_for_each_prev_safe(l, n, &bus->devices) {
                struct pci_dev *dev = pci_dev_b(l);
                pci_stop_bus_device(dev);
        }
@@ -166,6 +177,6 @@ void pci_stop_bus_device(struct pci_dev *dev)
        pci_stop_dev(dev);
 }
 
-EXPORT_SYMBOL(pci_remove_bus_device);
-EXPORT_SYMBOL(pci_remove_behind_bridge);
+EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
+EXPORT_SYMBOL(pci_stop_and_remove_behind_bridge);
 EXPORT_SYMBOL_GPL(pci_stop_bus_device);
index 86b69f8..8fa2d4b 100644 (file)
 #include <linux/ioport.h>
 #include <linux/cache.h>
 #include <linux/slab.h>
+#include <asm-generic/pci-bridge.h>
 #include "pci.h"
 
-struct resource_list_x {
-       struct resource_list_x *next;
+unsigned int pci_flags;
+
+struct pci_dev_resource {
+       struct list_head list;
        struct resource *res;
        struct pci_dev *dev;
        resource_size_t start;
@@ -38,21 +41,14 @@ struct resource_list_x {
        unsigned long flags;
 };
 
-#define free_list(type, head) do {                      \
-       struct type *list, *tmp;                        \
-       for (list = (head)->next; list;) {              \
-               tmp = list;                             \
-               list = list->next;                      \
-               kfree(tmp);                             \
-       }                                               \
-       (head)->next = NULL;                            \
-} while (0)
-
-int pci_realloc_enable = 0;
-#define pci_realloc_enabled() pci_realloc_enable
-void pci_realloc(void)
+static void free_list(struct list_head *head)
 {
-       pci_realloc_enable = 1;
+       struct pci_dev_resource *dev_res, *tmp;
+
+       list_for_each_entry_safe(dev_res, tmp, head, list) {
+               list_del(&dev_res->list);
+               kfree(dev_res);
+       }
 }
 
 /**
@@ -64,21 +60,18 @@ void pci_realloc(void)
  * @add_size:  additional size to be optionally added
  *              to the resource
  */
-static void add_to_list(struct resource_list_x *head,
+static int add_to_list(struct list_head *head,
                 struct pci_dev *dev, struct resource *res,
                 resource_size_t add_size, resource_size_t min_align)
 {
-       struct resource_list_x *list = head;
-       struct resource_list_x *ln = list->next;
-       struct resource_list_x *tmp;
+       struct pci_dev_resource *tmp;
 
-       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+       tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
        if (!tmp) {
                pr_warning("add_to_list: kmalloc() failed!\n");
-               return;
+               return -ENOMEM;
        }
 
-       tmp->next = ln;
        tmp->res = res;
        tmp->dev = dev;
        tmp->start = res->start;
@@ -86,19 +79,100 @@ static void add_to_list(struct resource_list_x *head,
        tmp->flags = res->flags;
        tmp->add_size = add_size;
        tmp->min_align = min_align;
-       list->next = tmp;
+
+       list_add(&tmp->list, head);
+
+       return 0;
 }
 
-static void add_to_failed_list(struct resource_list_x *head,
-                               struct pci_dev *dev, struct resource *res)
+static void remove_from_list(struct list_head *head,
+                                struct resource *res)
 {
-       add_to_list(head, dev, res,
-                       0 /* dont care */,
-                       0 /* dont care */);
+       struct pci_dev_resource *dev_res, *tmp;
+
+       list_for_each_entry_safe(dev_res, tmp, head, list) {
+               if (dev_res->res == res) {
+                       list_del(&dev_res->list);
+                       kfree(dev_res);
+                       break;
+               }
+       }
+}
+
+static resource_size_t get_res_add_size(struct list_head *head,
+                                       struct resource *res)
+{
+       struct pci_dev_resource *dev_res;
+
+       list_for_each_entry(dev_res, head, list) {
+               if (dev_res->res == res) {
+                       int idx = res - &dev_res->dev->resource[0];
+
+                       dev_printk(KERN_DEBUG, &dev_res->dev->dev,
+                                "res[%d]=%pR get_res_add_size add_size %llx\n",
+                                idx, dev_res->res,
+                                (unsigned long long)dev_res->add_size);
+
+                       return dev_res->add_size;
+               }
+       }
+
+       return 0;
+}
+
+/* Sort resources by alignment */
+static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
+{
+       int i;
+
+       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+               struct resource *r;
+               struct pci_dev_resource *dev_res, *tmp;
+               resource_size_t r_align;
+               struct list_head *n;
+
+               r = &dev->resource[i];
+
+               if (r->flags & IORESOURCE_PCI_FIXED)
+                       continue;
+
+               if (!(r->flags) || r->parent)
+                       continue;
+
+               r_align = pci_resource_alignment(dev, r);
+               if (!r_align) {
+                       dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n",
+                                i, r);
+                       continue;
+               }
+
+               tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+               if (!tmp)
+                       panic("pdev_sort_resources(): "
+                             "kmalloc() failed!\n");
+               tmp->res = r;
+               tmp->dev = dev;
+
+               /* fallback is smallest one or list is empty*/
+               n = head;
+               list_for_each_entry(dev_res, head, list) {
+                       resource_size_t align;
+
+                       align = pci_resource_alignment(dev_res->dev,
+                                                        dev_res->res);
+
+                       if (r_align > align) {
+                               n = &dev_res->list;
+                               break;
+                       }
+               }
+               /* Insert it just before n*/
+               list_add_tail(&tmp->list, n);
+       }
 }
 
 static void __dev_sort_resources(struct pci_dev *dev,
-                                struct resource_list *head)
+                                struct list_head *head)
 {
        u16 class = dev->class >> 8;
 
@@ -136,49 +210,54 @@ static inline void reset_resource(struct resource *res)
  * additional resources for the element, provided the element
  * is in the head list.
  */
-static void reassign_resources_sorted(struct resource_list_x *realloc_head,
-               struct resource_list *head)
+static void reassign_resources_sorted(struct list_head *realloc_head,
+               struct list_head *head)
 {
        struct resource *res;
-       struct resource_list_x *list, *tmp, *prev;
-       struct resource_list *hlist;
+       struct pci_dev_resource *add_res, *tmp;
+       struct pci_dev_resource *dev_res;
        resource_size_t add_size;
        int idx;
 
-       prev = realloc_head;
-       for (list = realloc_head->next; list;) {
-               res = list->res;
+       list_for_each_entry_safe(add_res, tmp, realloc_head, list) {
+               bool found_match = false;
+
+               res = add_res->res;
                /* skip resource that has been reset */
                if (!res->flags)
                        goto out;
 
                /* skip this resource if not found in head list */
-               for (hlist = head->next; hlist && hlist->res != res;
-                               hlist = hlist->next);
-               if (!hlist) { /* just skip */
-                       prev = list;
-                       list = list->next;
-                       continue;
+               list_for_each_entry(dev_res, head, list) {
+                       if (dev_res->res == res) {
+                               found_match = true;
+                               break;
+                       }
                }
+               if (!found_match)/* just skip */
+                       continue;
 
-               idx = res - &list->dev->resource[0];
-               add_size=list->add_size;
+               idx = res - &add_res->dev->resource[0];
+               add_size = add_res->add_size;
                if (!resource_size(res)) {
-                       res->start = list->start;
+                       res->start = add_res->start;
                        res->end = res->start + add_size - 1;
-                       if(pci_assign_resource(list->dev, idx))
+                       if (pci_assign_resource(add_res->dev, idx))
                                reset_resource(res);
                } else {
-                       resource_size_t align = list->min_align;
-                       res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
-                       if (pci_reassign_resource(list->dev, idx, add_size, align))
-                               dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n",
-                                                       res);
+                       resource_size_t align = add_res->min_align;
+                       res->flags |= add_res->flags &
+                                (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
+                       if (pci_reassign_resource(add_res->dev, idx,
+                                                 add_size, align))
+                               dev_printk(KERN_DEBUG, &add_res->dev->dev,
+                                          "failed to add %llx res[%d]=%pR\n",
+                                          (unsigned long long)add_size,
+                                          idx, res);
                }
 out:
-               tmp = list;
-               prev->next = list = list->next;
-               kfree(tmp);
+               list_del(&add_res->list);
+               kfree(add_res);
        }
 }
 
@@ -192,35 +271,99 @@ out:
  * Satisfy resource requests of each element in the list. Add
  * requests that could not satisfied to the failed_list.
  */
-static void assign_requested_resources_sorted(struct resource_list *head,
-                                struct resource_list_x *fail_head)
+static void assign_requested_resources_sorted(struct list_head *head,
+                                struct list_head *fail_head)
 {
        struct resource *res;
-       struct resource_list *list;
+       struct pci_dev_resource *dev_res;
        int idx;
 
-       for (list = head->next; list; list = list->next) {
-               res = list->res;
-               idx = res - &list->dev->resource[0];
-               if (resource_size(res) && pci_assign_resource(list->dev, idx)) {
-                       if (fail_head && !pci_is_root_bus(list->dev->bus)) {
+       list_for_each_entry(dev_res, head, list) {
+               res = dev_res->res;
+               idx = res - &dev_res->dev->resource[0];
+               if (resource_size(res) &&
+                   pci_assign_resource(dev_res->dev, idx)) {
+                       if (fail_head && !pci_is_root_bus(dev_res->dev->bus)) {
                                /*
                                 * if the failed res is for ROM BAR, and it will
                                 * be enabled later, don't add it to the list
                                 */
                                if (!((idx == PCI_ROM_RESOURCE) &&
                                      (!(res->flags & IORESOURCE_ROM_ENABLE))))
-                                       add_to_failed_list(fail_head, list->dev, res);
+                                       add_to_list(fail_head,
+                                                   dev_res->dev, res,
+                                                   0 /* dont care */,
+                                                   0 /* dont care */);
                        }
                        reset_resource(res);
                }
        }
 }
 
-static void __assign_resources_sorted(struct resource_list *head,
-                                struct resource_list_x *realloc_head,
-                                struct resource_list_x *fail_head)
+static void __assign_resources_sorted(struct list_head *head,
+                                struct list_head *realloc_head,
+                                struct list_head *fail_head)
 {
+       /*
+        * Should not assign requested resources at first.
+        *   they could be adjacent, so later reassign can not reallocate
+        *   them one by one in parent resource window.
+        * Try to assign requested + add_size at begining
+        *  if could do that, could get out early.
+        *  if could not do that, we still try to assign requested at first,
+        *    then try to reassign add_size for some resources.
+        */
+       LIST_HEAD(save_head);
+       LIST_HEAD(local_fail_head);
+       struct pci_dev_resource *save_res;
+       struct pci_dev_resource *dev_res;
+
+       /* Check if optional add_size is there */
+       if (!realloc_head || list_empty(realloc_head))
+               goto requested_and_reassign;
+
+       /* Save original start, end, flags etc at first */
+       list_for_each_entry(dev_res, head, list) {
+               if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) {
+                       free_list(&save_head);
+                       goto requested_and_reassign;
+               }
+       }
+
+       /* Update res in head list with add_size in realloc_head list */
+       list_for_each_entry(dev_res, head, list)
+               dev_res->res->end += get_res_add_size(realloc_head,
+                                                       dev_res->res);
+
+       /* Try updated head list with add_size added */
+       assign_requested_resources_sorted(head, &local_fail_head);
+
+       /* all assigned with add_size ? */
+       if (list_empty(&local_fail_head)) {
+               /* Remove head list from realloc_head list */
+               list_for_each_entry(dev_res, head, list)
+                       remove_from_list(realloc_head, dev_res->res);
+               free_list(&save_head);
+               free_list(head);
+               return;
+       }
+
+       free_list(&local_fail_head);
+       /* Release assigned resource */
+       list_for_each_entry(dev_res, head, list)
+               if (dev_res->res->parent)
+                       release_resource(dev_res->res);
+       /* Restore start/end/flags from saved list */
+       list_for_each_entry(save_res, &save_head, list) {
+               struct resource *res = save_res->res;
+
+               res->start = save_res->start;
+               res->end = save_res->end;
+               res->flags = save_res->flags;
+       }
+       free_list(&save_head);
+
+requested_and_reassign:
        /* Satisfy the must-have resource requests */
        assign_requested_resources_sorted(head, fail_head);
 
@@ -228,28 +371,27 @@ static void __assign_resources_sorted(struct resource_list *head,
                requests */
        if (realloc_head)
                reassign_resources_sorted(realloc_head, head);
-       free_list(resource_list, head);
+       free_list(head);
 }
 
 static void pdev_assign_resources_sorted(struct pci_dev *dev,
-                                struct resource_list_x *fail_head)
+                                struct list_head *add_head,
+                                struct list_head *fail_head)
 {
-       struct resource_list head;
+       LIST_HEAD(head);
 
-       head.next = NULL;
        __dev_sort_resources(dev, &head);
-       __assign_resources_sorted(&head, NULL, fail_head);
+       __assign_resources_sorted(&head, add_head, fail_head);
 
 }
 
 static void pbus_assign_resources_sorted(const struct pci_bus *bus,
-                                        struct resource_list_x *realloc_head,
-                                        struct resource_list_x *fail_head)
+                                        struct list_head *realloc_head,
+                                        struct list_head *fail_head)
 {
        struct pci_dev *dev;
-       struct resource_list head;
+       LIST_HEAD(head);
 
-       head.next = NULL;
        list_for_each_entry(dev, &bus->devices, bus_list)
                __dev_sort_resources(dev, &head);
 
@@ -548,20 +690,6 @@ static resource_size_t calculate_memsize(resource_size_t size,
        return size;
 }
 
-static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
-                                       struct resource *res)
-{
-       struct resource_list_x *list;
-
-       /* check if it is in realloc_head list */
-       for (list = realloc_head->next; list && list->res != res;
-                       list = list->next);
-       if (list)
-               return list->add_size;
-
-       return 0;
-}
-
 /**
  * pbus_size_io() - size the io window of a given bus
  *
@@ -576,7 +704,7 @@ static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
  * We must be careful with the ISA aliasing though.
  */
 static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
-               resource_size_t add_size, struct resource_list_x *realloc_head)
+               resource_size_t add_size, struct list_head *realloc_head)
 {
        struct pci_dev *dev;
        struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
@@ -612,7 +740,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
        if (children_add_size > add_size)
                add_size = children_add_size;
        size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
-               calculate_iosize(size, min_size+add_size, size1,
+               calculate_iosize(size, min_size, add_size + size1,
                        resource_size(b_res), 4096);
        if (!size0 && !size1) {
                if (b_res->start || b_res->end)
@@ -626,8 +754,12 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
        b_res->start = 4096;
        b_res->end = b_res->start + size0 - 1;
        b_res->flags |= IORESOURCE_STARTALIGN;
-       if (size1 > size0 && realloc_head)
+       if (size1 > size0 && realloc_head) {
                add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096);
+               dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
+                                "%pR to [bus %02x-%02x] add_size %lx\n", b_res,
+                                bus->secondary, bus->subordinate, size1-size0);
+       }
 }
 
 /**
@@ -644,7 +776,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
 static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
                         unsigned long type, resource_size_t min_size,
                        resource_size_t add_size,
-                       struct resource_list_x *realloc_head)
+                       struct list_head *realloc_head)
 {
        struct pci_dev *dev;
        resource_size_t min_align, align, size, size0, size1;
@@ -726,7 +858,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        if (children_add_size > add_size)
                add_size = children_add_size;
        size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
-               calculate_memsize(size, min_size+add_size, 0,
+               calculate_memsize(size, min_size, add_size,
                                resource_size(b_res), min_align);
        if (!size0 && !size1) {
                if (b_res->start || b_res->end)
@@ -739,8 +871,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
        b_res->start = min_align;
        b_res->end = size0 + min_align - 1;
        b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask;
-       if (size1 > size0 && realloc_head)
+       if (size1 > size0 && realloc_head) {
                add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
+               dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
+                                "%pR to [bus %02x-%02x] add_size %llx\n", b_res,
+                                bus->secondary, bus->subordinate, (unsigned long long)size1-size0);
+       }
        return 1;
 }
 
@@ -754,25 +890,48 @@ unsigned long pci_cardbus_resource_alignment(struct resource *res)
 }
 
 static void pci_bus_size_cardbus(struct pci_bus *bus,
-                       struct resource_list_x *realloc_head)
+                       struct list_head *realloc_head)
 {
        struct pci_dev *bridge = bus->self;
        struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
+       resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
        u16 ctrl;
 
+       if (b_res[0].parent)
+               goto handle_b_res_1;
        /*
         * Reserve some resources for CardBus.  We reserve
         * a fixed amount of bus space for CardBus bridges.
         */
-       b_res[0].start = 0;
-       b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
-       if (realloc_head)
-               add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, 0 /* dont care */);
+       b_res[0].start = pci_cardbus_io_size;
+       b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1;
+       b_res[0].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
+       if (realloc_head) {
+               b_res[0].end -= pci_cardbus_io_size;
+               add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
+                               pci_cardbus_io_size);
+       }
 
-       b_res[1].start = 0;
-       b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
-       if (realloc_head)
-               add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size, 0 /* dont care */);
+handle_b_res_1:
+       if (b_res[1].parent)
+               goto handle_b_res_2;
+       b_res[1].start = pci_cardbus_io_size;
+       b_res[1].end = b_res[1].start + pci_cardbus_io_size - 1;
+       b_res[1].flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
+       if (realloc_head) {
+               b_res[1].end -= pci_cardbus_io_size;
+               add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size,
+                                pci_cardbus_io_size);
+       }
+
+handle_b_res_2:
+       /* MEM1 must not be pref mmio */
+       pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+       if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
+               ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
+               pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
+               pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+       }
 
        /*
         * Check whether prefetchable memory is supported
@@ -785,38 +944,46 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
                pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
        }
 
+       if (b_res[2].parent)
+               goto handle_b_res_3;
        /*
         * If we have prefetchable memory support, allocate
         * two regions.  Otherwise, allocate one region of
         * twice the size.
         */
        if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
-               b_res[2].start = 0;
-               b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN;
-               if (realloc_head)
-                       add_to_list(realloc_head, bridge, b_res+2, pci_cardbus_mem_size, 0 /* dont care */);
-
-               b_res[3].start = 0;
-               b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
-               if (realloc_head)
-                       add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size, 0 /* dont care */);
-       } else {
-               b_res[3].start = 0;
-               b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
-               if (realloc_head)
-                       add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size * 2, 0 /* dont care */);
+               b_res[2].start = pci_cardbus_mem_size;
+               b_res[2].end = b_res[2].start + pci_cardbus_mem_size - 1;
+               b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
+                                 IORESOURCE_STARTALIGN;
+               if (realloc_head) {
+                       b_res[2].end -= pci_cardbus_mem_size;
+                       add_to_list(realloc_head, bridge, b_res+2,
+                                pci_cardbus_mem_size, pci_cardbus_mem_size);
+               }
+
+               /* reduce that to half */
+               b_res_3_size = pci_cardbus_mem_size;
+       }
+
+handle_b_res_3:
+       if (b_res[3].parent)
+               goto handle_done;
+       b_res[3].start = pci_cardbus_mem_size;
+       b_res[3].end = b_res[3].start + b_res_3_size - 1;
+       b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
+       if (realloc_head) {
+               b_res[3].end -= b_res_3_size;
+               add_to_list(realloc_head, bridge, b_res+3, b_res_3_size,
+                                pci_cardbus_mem_size);
        }
 
-       /* set the size of the resource to zero, so that the resource does not
-        * get assigned during required-resource allocation cycle but gets assigned
-        * during the optional-resource allocation cycle.
-        */
-       b_res[0].start = b_res[1].start = b_res[2].start = b_res[3].start = 1;
-       b_res[0].end = b_res[1].end = b_res[2].end = b_res[3].end = 0;
+handle_done:
+       ;
 }
 
 void __ref __pci_bus_size_bridges(struct pci_bus *bus,
-                       struct resource_list_x *realloc_head)
+                       struct list_head *realloc_head)
 {
        struct pci_dev *dev;
        unsigned long mask, prefmask;
@@ -858,7 +1025,8 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
                 * Follow thru
                 */
        default:
-               pbus_size_io(bus, 0, additional_io_size, realloc_head);
+               pbus_size_io(bus, realloc_head ? 0 : additional_io_size,
+                            additional_io_size, realloc_head);
                /* If the bridge supports prefetchable range, size it
                   separately. If it doesn't, or its prefetchable window
                   has already been allocated by arch code, try
@@ -866,11 +1034,15 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
                   resources. */
                mask = IORESOURCE_MEM;
                prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
-               if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, realloc_head))
+               if (pbus_size_mem(bus, prefmask, prefmask,
+                                 realloc_head ? 0 : additional_mem_size,
+                                 additional_mem_size, realloc_head))
                        mask = prefmask; /* Success, size non-prefetch only. */
                else
                        additional_mem_size += additional_mem_size;
-               pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, realloc_head);
+               pbus_size_mem(bus, mask, IORESOURCE_MEM,
+                               realloc_head ? 0 : additional_mem_size,
+                               additional_mem_size, realloc_head);
                break;
        }
 }
@@ -882,8 +1054,8 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
 static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
-                                        struct resource_list_x *realloc_head,
-                                        struct resource_list_x *fail_head)
+                                        struct list_head *realloc_head,
+                                        struct list_head *fail_head)
 {
        struct pci_bus *b;
        struct pci_dev *dev;
@@ -922,17 +1094,19 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus)
 EXPORT_SYMBOL(pci_bus_assign_resources);
 
 static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
-                                        struct resource_list_x *fail_head)
+                                        struct list_head *add_head,
+                                        struct list_head *fail_head)
 {
        struct pci_bus *b;
 
-       pdev_assign_resources_sorted((struct pci_dev *)bridge, fail_head);
+       pdev_assign_resources_sorted((struct pci_dev *)bridge,
+                                        add_head, fail_head);
 
        b = bridge->subordinate;
        if (!b)
                return;
 
-       __pci_bus_assign_resources(b, NULL, fail_head);
+       __pci_bus_assign_resources(b, add_head, fail_head);
 
        switch (bridge->class >> 8) {
        case PCI_CLASS_BRIDGE_PCI:
@@ -1095,6 +1269,58 @@ static int __init pci_get_max_depth(void)
        return depth;
 }
 
+/*
+ * -1: undefined, will auto detect later
+ *  0: disabled by user
+ *  1: disabled by auto detect
+ *  2: enabled by user
+ *  3: enabled by auto detect
+ */
+enum enable_type {
+       undefined = -1,
+       user_disabled,
+       auto_disabled,
+       user_enabled,
+       auto_enabled,
+};
+
+static enum enable_type pci_realloc_enable __initdata = undefined;
+void __init pci_realloc_get_opt(char *str)
+{
+       if (!strncmp(str, "off", 3))
+               pci_realloc_enable = user_disabled;
+       else if (!strncmp(str, "on", 2))
+               pci_realloc_enable = user_enabled;
+}
+static bool __init pci_realloc_enabled(void)
+{
+       return pci_realloc_enable >= user_enabled;
+}
+
+static void __init pci_realloc_detect(void)
+{
+#if defined(CONFIG_PCI_IOV) && defined(CONFIG_PCI_REALLOC_ENABLE_AUTO)
+       struct pci_dev *dev = NULL;
+
+       if (pci_realloc_enable != undefined)
+               return;
+
+       for_each_pci_dev(dev) {
+               int i;
+
+               for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
+                       struct resource *r = &dev->resource[i];
+
+                       /* Not assigned, or rejected by kernel ? */
+                       if (r->flags && !r->start) {
+                               pci_realloc_enable = auto_enabled;
+
+                               return;
+                       }
+               }
+       }
+#endif
+}
 
 /*
  * first try will not touch pci bridge res
@@ -1105,59 +1331,57 @@ void __init
 pci_assign_unassigned_resources(void)
 {
        struct pci_bus *bus;
-       struct resource_list_x realloc_list; /* list of resources that
+       LIST_HEAD(realloc_head); /* list of resources that
                                        want additional resources */
+       struct list_head *add_list = NULL;
        int tried_times = 0;
        enum release_type rel_type = leaf_only;
-       struct resource_list_x head, *list;
+       LIST_HEAD(fail_head);
+       struct pci_dev_resource *fail_res;
        unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
                                  IORESOURCE_PREFETCH;
-       unsigned long failed_type;
-       int max_depth = pci_get_max_depth();
-       int pci_try_num;
-
+       int pci_try_num = 1;
 
-       head.next = NULL;
-       realloc_list.next = NULL;
+       /* don't realloc if asked to do so */
+       pci_realloc_detect();
+       if (pci_realloc_enabled()) {
+               int max_depth = pci_get_max_depth();
 
-       pci_try_num = max_depth + 1;
-       printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
-                max_depth, pci_try_num);
+               pci_try_num = max_depth + 1;
+               printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
+                        max_depth, pci_try_num);
+       }
 
 again:
+       /*
+        * last try will use add_list, otherwise will try good to have as
+        * must have, so can realloc parent bridge resource
+        */
+       if (tried_times + 1 == pci_try_num)
+               add_list = &realloc_head;
        /* Depth first, calculate sizes and alignments of all
           subordinate buses. */
        list_for_each_entry(bus, &pci_root_buses, node)
-               __pci_bus_size_bridges(bus, &realloc_list);
+               __pci_bus_size_bridges(bus, add_list);
 
        /* Depth last, allocate resources and update the hardware. */
        list_for_each_entry(bus, &pci_root_buses, node)
-               __pci_bus_assign_resources(bus, &realloc_list, &head);
-       BUG_ON(realloc_list.next);
+               __pci_bus_assign_resources(bus, add_list, &fail_head);
+       if (add_list)
+               BUG_ON(!list_empty(add_list));
        tried_times++;
 
        /* any device complain? */
-       if (!head.next)
+       if (list_empty(&fail_head))
                goto enable_and_dump;
 
-       /* don't realloc if asked to do so */
-       if (!pci_realloc_enabled()) {
-               free_list(resource_list_x, &head);
-               goto enable_and_dump;
-       }
+       if (tried_times >= pci_try_num) {
+               if (pci_realloc_enable == undefined)
+                       printk(KERN_INFO "Some PCI device resources are unassigned, try booting with pci=realloc\n");
+               else if (pci_realloc_enable == auto_enabled)
+                       printk(KERN_INFO "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
 
-       failed_type = 0;
-       for (list = head.next; list;) {
-               failed_type |= list->flags;
-               list = list->next;
-       }
-       /*
-        * io port are tight, don't try extra
-        * or if reach the limit, don't want to try more
-        */
-       failed_type &= type_mask;
-       if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {
-               free_list(resource_list_x, &head);
+               free_list(&fail_head);
                goto enable_and_dump;
        }
 
@@ -1172,25 +1396,23 @@ again:
         * Try to release leaf bridge's resources that doesn't fit resource of
         * child device under that bridge
         */
-       for (list = head.next; list;) {
-               bus = list->dev->bus;
-               pci_bus_release_bridge_resources(bus, list->flags & type_mask,
-                                                 rel_type);
-               list = list->next;
+       list_for_each_entry(fail_res, &fail_head, list) {
+               bus = fail_res->dev->bus;
+               pci_bus_release_bridge_resources(bus,
+                                                fail_res->flags & type_mask,
+                                                rel_type);
        }
        /* restore size and flags */
-       for (list = head.next; list;) {
-               struct resource *res = list->res;
+       list_for_each_entry(fail_res, &fail_head, list) {
+               struct resource *res = fail_res->res;
 
-               res->start = list->start;
-               res->end = list->end;
-               res->flags = list->flags;
-               if (list->dev->subordinate)
+               res->start = fail_res->start;
+               res->end = fail_res->end;
+               res->flags = fail_res->flags;
+               if (fail_res->dev->subordinate)
                        res->flags = 0;
-
-               list = list->next;
        }
-       free_list(resource_list_x, &head);
+       free_list(&fail_head);
 
        goto again;
 
@@ -1207,26 +1429,27 @@ enable_and_dump:
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
 {
        struct pci_bus *parent = bridge->subordinate;
+       LIST_HEAD(add_list); /* list of resources that
+                                       want additional resources */
        int tried_times = 0;
-       struct resource_list_x head, *list;
+       LIST_HEAD(fail_head);
+       struct pci_dev_resource *fail_res;
        int retval;
        unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
                                  IORESOURCE_PREFETCH;
 
-       head.next = NULL;
-
 again:
-       pci_bus_size_bridges(parent);
-       __pci_bridge_assign_resources(bridge, &head);
-
+       __pci_bus_size_bridges(parent, &add_list);
+       __pci_bridge_assign_resources(bridge, &add_list, &fail_head);
+       BUG_ON(!list_empty(&add_list));
        tried_times++;
 
-       if (!head.next)
+       if (list_empty(&fail_head))
                goto enable_all;
 
        if (tried_times >= 2) {
                /* still fail, don't need to try more */
-               free_list(resource_list_x, &head);
+               free_list(&fail_head);
                goto enable_all;
        }
 
@@ -1237,27 +1460,24 @@ again:
         * Try to release leaf bridge's resources that doesn't fit resource of
         * child device under that bridge
         */
-       for (list = head.next; list;) {
-               struct pci_bus *bus = list->dev->bus;
-               unsigned long flags = list->flags;
+       list_for_each_entry(fail_res, &fail_head, list) {
+               struct pci_bus *bus = fail_res->dev->bus;
+               unsigned long flags = fail_res->flags;
 
                pci_bus_release_bridge_resources(bus, flags & type_mask,
                                                 whole_subtree);
-               list = list->next;
        }
        /* restore size and flags */
-       for (list = head.next; list;) {
-               struct resource *res = list->res;
+       list_for_each_entry(fail_res, &fail_head, list) {
+               struct resource *res = fail_res->res;
 
-               res->start = list->start;
-               res->end = list->end;
-               res->flags = list->flags;
-               if (list->dev->subordinate)
+               res->start = fail_res->start;
+               res->end = fail_res->end;
+               res->flags = fail_res->flags;
+               if (fail_res->dev->subordinate)
                        res->flags = 0;
-
-               list = list->next;
        }
-       free_list(resource_list_x, &head);
+       free_list(&fail_head);
 
        goto again;
 
@@ -1267,3 +1487,41 @@ enable_all:
        pci_enable_bridges(parent);
 }
 EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
+
+#ifdef CONFIG_HOTPLUG
+/**
+ * pci_rescan_bus - scan a PCI bus for devices.
+ * @bus: PCI bus to scan
+ *
+ * Scan a PCI bus and child buses for new devices, adds them,
+ * and enables them.
+ *
+ * Returns the max number of subordinate bus discovered.
+ */
+unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
+{
+       unsigned int max;
+       struct pci_dev *dev;
+       LIST_HEAD(add_list); /* list of resources that
+                                       want additional resources */
+
+       max = pci_scan_child_bus(bus);
+
+       down_read(&pci_bus_sem);
+       list_for_each_entry(dev, &bus->devices, bus_list)
+               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+                   dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+                       if (dev->subordinate)
+                               __pci_bus_size_bridges(dev->subordinate,
+                                                        &add_list);
+       up_read(&pci_bus_sem);
+       __pci_bus_assign_resources(bus, &add_list, NULL);
+       BUG_ON(!list_empty(&add_list));
+
+       pci_enable_bridges(bus);
+       pci_bus_add_devices(bus);
+
+       return max;
+}
+EXPORT_SYMBOL_GPL(pci_rescan_bus);
+#endif
index b66bfdb..eea85da 100644 (file)
@@ -114,7 +114,6 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
 }
 EXPORT_SYMBOL(pci_claim_resource);
 
-#ifdef CONFIG_PCI_QUIRKS
 void pci_disable_bridge_window(struct pci_dev *dev)
 {
        dev_info(&dev->dev, "disabling bridge mem windows\n");
@@ -127,9 +126,6 @@ void pci_disable_bridge_window(struct pci_dev *dev)
        pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0);
        pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff);
 }
-#endif /* CONFIG_PCI_QUIRKS */
-
-
 
 static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
                int resno, resource_size_t size, resource_size_t align)
@@ -158,22 +154,44 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
        return ret;
 }
 
+/*
+ * Generic function that returns a value indicating that the device's
+ * original BIOS BAR address was not saved and so is not available for
+ * reinstatement.
+ *
+ * Can be over-ridden by architecture specific code that implements
+ * reinstatement functionality rather than leaving it disabled when
+ * normal allocation attempts fail.
+ */
+resource_size_t __weak pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
+{
+       return 0;
+}
+
 static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev, 
                int resno, resource_size_t size)
 {
        struct resource *root, *conflict;
-       resource_size_t start, end;
+       resource_size_t fw_addr, start, end;
        int ret = 0;
 
-       if (res->flags & IORESOURCE_IO)
-               root = &ioport_resource;
-       else
-               root = &iomem_resource;
+       fw_addr = pcibios_retrieve_fw_addr(dev, resno);
+       if (!fw_addr)
+               return 1;
 
        start = res->start;
        end = res->end;
-       res->start = dev->fw_addr[resno];
+       res->start = fw_addr;
        res->end = res->start + size - 1;
+
+       root = pci_find_parent_resource(dev, res);
+       if (!root) {
+               if (res->flags & IORESOURCE_IO)
+                       root = &ioport_resource;
+               else
+                       root = &iomem_resource;
+       }
+
        dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
                 resno, res);
        conflict = request_resource_conflict(root, res);
@@ -228,16 +246,17 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
        int ret;
 
        if (!res->parent) {
-               dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resouce %pR "
+               dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resource %pR "
                         "\n", resno, res);
                return -EINVAL;
        }
 
-       new_size = resource_size(res) + addsize + min_align;
+       /* already aligned with min_align */
+       new_size = resource_size(res) + addsize;
        ret = _pci_assign_resource(dev, resno, new_size, min_align);
        if (!ret) {
                res->flags &= ~IORESOURCE_STARTALIGN;
-               dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
+               dev_info(&dev->dev, "BAR %d: reassigned %pR\n", resno, res);
                if (resno < PCI_BRIDGE_RESOURCES)
                        pci_update_resource(dev, resno);
        }
@@ -267,7 +286,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
         * where firmware left it.  That at least has a chance of
         * working, which is better than just leaving it disabled.
         */
-       if (ret < 0 && dev->fw_addr[resno])
+       if (ret < 0)
                ret = pci_revert_fw_address(res, dev, resno, size);
 
        if (!ret) {
@@ -279,53 +298,6 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
        return ret;
 }
 
-
-/* Sort resources by alignment */
-void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
-{
-       int i;
-
-       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-               struct resource *r;
-               struct resource_list *list, *tmp;
-               resource_size_t r_align;
-
-               r = &dev->resource[i];
-
-               if (r->flags & IORESOURCE_PCI_FIXED)
-                       continue;
-
-               if (!(r->flags) || r->parent)
-                       continue;
-
-               r_align = pci_resource_alignment(dev, r);
-               if (!r_align) {
-                       dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n",
-                                i, r);
-                       continue;
-               }
-               for (list = head; ; list = list->next) {
-                       resource_size_t align = 0;
-                       struct resource_list *ln = list->next;
-
-                       if (ln)
-                               align = pci_resource_alignment(ln->dev, ln->res);
-
-                       if (r_align > align) {
-                               tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
-                               if (!tmp)
-                                       panic("pdev_sort_resources(): "
-                                             "kmalloc() failed!\n");
-                               tmp->next = ln;
-                               tmp->res = r;
-                               tmp->dev = dev;
-                               list->next = tmp;
-                               break;
-                       }
-               }
-       }
-}
-
 int pci_enable_resources(struct pci_dev *dev, int mask)
 {
        u16 cmd, old_cmd;
index 4010901..fd00ff0 100644 (file)
@@ -544,7 +544,7 @@ static void free_root_bus_devs(struct pci_bus *bus)
                dev = container_of(bus->devices.next, struct pci_dev,
                                   bus_list);
                dev_dbg(&dev->dev, "removing device\n");
-               pci_remove_bus_device(dev);
+               pci_stop_and_remove_bus_device(dev);
        }
 }
 
@@ -1044,7 +1044,7 @@ static int pcifront_detach_devices(struct pcifront_device *pdev)
                                domain, bus, slot, func);
                        continue;
                }
-               pci_remove_bus_device(pci_dev);
+               pci_stop_and_remove_bus_device(pci_dev);
                pci_dev_put(pci_dev);
 
                dev_dbg(&pdev->xdev->dev,
index f9e3fb3..bba3ab2 100644 (file)
@@ -183,10 +183,14 @@ config PCMCIA_BCM63XX
 config PCMCIA_SOC_COMMON
        tristate
 
+config PCMCIA_SA11XX_BASE
+       tristate
+
 config PCMCIA_SA1100
        tristate "SA1100 support"
        depends on ARM && ARCH_SA1100 && PCMCIA
        select PCMCIA_SOC_COMMON
+       select PCMCIA_SA11XX_BASE
        help
          Say Y here to include support for SA11x0-based PCMCIA or CF
          sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/
@@ -196,8 +200,9 @@ config PCMCIA_SA1100
 
 config PCMCIA_SA1111
        tristate "SA1111 support"
-       depends on ARM && ARCH_SA1100 && SA1111 && PCMCIA
+       depends on ARM && SA1111 && PCMCIA
        select PCMCIA_SOC_COMMON
+       select PCMCIA_SA11XX_BASE if ARCH_SA1100
        help
          Say Y  here to include support for SA1111-based PCMCIA or CF
          sockets, found on the Jornada 720, Graphicsmaster and other
@@ -213,6 +218,7 @@ config PCMCIA_PXA2XX
                    || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
                    || MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
                    || MACH_COLIBRI320)
+       select PCMCIA_SA1111 if ARCH_LUBBOCK && SA1111
        select PCMCIA_SOC_COMMON
        help
          Say Y here to include support for the PXA2xx PCMCIA controller
index ec543a4..47525de 100644 (file)
@@ -25,8 +25,9 @@ obj-$(CONFIG_I82092)                          += i82092.o
 obj-$(CONFIG_TCIC)                             += tcic.o
 obj-$(CONFIG_PCMCIA_M8XX)                      += m8xx_pcmcia.o
 obj-$(CONFIG_PCMCIA_SOC_COMMON)                        += soc_common.o
-obj-$(CONFIG_PCMCIA_SA1100)                    += sa11xx_base.o sa1100_cs.o
-obj-$(CONFIG_PCMCIA_SA1111)                    += sa11xx_base.o sa1111_cs.o
+obj-$(CONFIG_PCMCIA_SA11XX_BASE)               += sa11xx_base.o
+obj-$(CONFIG_PCMCIA_SA1100)                    += sa1100_cs.o
+obj-$(CONFIG_PCMCIA_SA1111)                    += sa1111_cs.o
 obj-$(CONFIG_M32R_PCC)                         += m32r_pcc.o
 obj-$(CONFIG_M32R_CFC)                         += m32r_cfc.o
 obj-$(CONFIG_PCMCIA_BCM63XX)                   += bcm63xx_pcmcia.o
@@ -39,9 +40,10 @@ obj-$(CONFIG_ELECTRA_CF)                     += electra_cf.o
 obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD)          += db1xxx_ss.o
 
 sa1111_cs-y                                    += sa1111_generic.o
-sa1111_cs-$(CONFIG_ASSABET_NEPONSET)           += sa1100_neponset.o
-sa1111_cs-$(CONFIG_SA1100_BADGE4)              += sa1100_badge4.o
-sa1111_cs-$(CONFIG_SA1100_JORNADA720)          += sa1100_jornada720.o
+sa1111_cs-$(CONFIG_ASSABET_NEPONSET)           += sa1111_neponset.o
+sa1111_cs-$(CONFIG_SA1100_BADGE4)              += sa1111_badge4.o
+sa1111_cs-$(CONFIG_SA1100_JORNADA720)          += sa1111_jornada720.o
+sa1111_cs-$(CONFIG_ARCH_LUBBOCK)               += sa1111_lubbock.o
 
 sa1100_cs-y                                    += sa1100_generic.o
 sa1100_cs-$(CONFIG_SA1100_ASSABET)             += sa1100_assabet.o
@@ -52,9 +54,7 @@ sa1100_cs-$(CONFIG_SA1100_NANOENGINE)         += sa1100_nanoengine.o
 sa1100_cs-$(CONFIG_SA1100_SHANNON)             += sa1100_shannon.o
 sa1100_cs-$(CONFIG_SA1100_SIMPAD)              += sa1100_simpad.o
 
-pxa2xx_lubbock_cs-y                            += pxa2xx_lubbock.o sa1111_generic.o
 pxa2xx_cm_x2xx_cs-y                            += pxa2xx_cm_x2xx.o pxa2xx_cm_x255.o pxa2xx_cm_x270.o
-pxa2xx-obj-$(CONFIG_ARCH_LUBBOCK)              += pxa2xx_lubbock_cs.o
 pxa2xx-obj-$(CONFIG_MACH_MAINSTONE)            += pxa2xx_mainstone.o
 pxa2xx-obj-$(CONFIG_PXA_SHARPSL)               += pxa2xx_sharpsl.o
 pxa2xx-obj-$(CONFIG_MACH_ARMCORE)              += pxa2xx_cm_x2xx_cs.o
index 4902206..1dd68f5 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/at91_ramc.h>
 
 
 /*
@@ -156,7 +157,7 @@ static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
        /*
         * Use 16 bit accesses unless/until we need 8-bit i/o space.
         */
-       csr = at91_sys_read(AT91_SMC_CSR(cf->board->chipselect)) & ~AT91_SMC_DBW;
+       csr = at91_ramc_read(0, AT91_SMC_CSR(cf->board->chipselect)) & ~AT91_SMC_DBW;
 
        /*
         * NOTE: this CF controller ignores IOIS16, so we can't really do
@@ -175,7 +176,7 @@ static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
                csr |= AT91_SMC_DBW_16;
                pr_debug("%s: 16bit i/o bus\n", driver_name);
        }
-       at91_sys_write(AT91_SMC_CSR(cf->board->chipselect), csr);
+       at91_ramc_write(0, AT91_SMC_CSR(cf->board->chipselect), csr);
 
        io->start = cf->socket.io_offset;
        io->stop = io->start + SZ_2K - 1;
index 9a58862..6e75153 100644 (file)
@@ -108,5 +108,5 @@ void cb_free(struct pcmcia_socket *s)
        struct pci_dev *bridge = s->cb_dev;
 
        if (bridge)
-               pci_remove_behind_bridge(bridge);
+               pci_stop_and_remove_behind_bridge(bridge);
 }
index 22a75e6..2ef576c 100644 (file)
 
 #include "soc_common.h"
 
-/*
- * These are a list of interrupt sources that provokes a polled
- * check of status
- */
-static struct pcmcia_irqs irqs[] = {
-       { 0, BALLOON3_S0_CD_IRQ, "PCMCIA0 CD" },
-       { 0, BALLOON3_BP_NSTSCHG_IRQ, "PCMCIA0 STSCHG" },
-};
-
 static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        uint16_t ver;
@@ -49,12 +40,12 @@ static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
                        ver);
 
        skt->socket.pci_irq = BALLOON3_BP_CF_NRDY_IRQ;
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
+       skt->stat[SOC_STAT_CD].gpio = BALLOON3_GPIO_S0_CD;
+       skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+       skt->stat[SOC_STAT_BVD1].irq = BALLOON3_BP_NSTSCHG_IRQ;
+       skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG";
 
-static void balloon3_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+       return 0;
 }
 
 static unsigned long balloon3_pcmcia_status[2] = {
@@ -85,13 +76,11 @@ static void balloon3_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                        disable_irq(BALLOON3_BP_NSTSCHG_IRQ);
        }
 
-       state->detect   = !gpio_get_value(BALLOON3_GPIO_S0_CD);
        state->ready    = !!(status & BALLOON3_CF_nIRQ);
        state->bvd1     = !!(status & BALLOON3_CF_nSTSCHG_BVD1);
        state->bvd2     = 0;    /* not available */
        state->vs_3v    = 1;    /* Always true its a CF card */
        state->vs_Xv    = 0;    /* not available */
-       state->wrprot   = 0;    /* not available */
 }
 
 static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
@@ -106,7 +95,6 @@ static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 static struct pcmcia_low_level balloon3_pcmcia_ops = {
        .owner                  = THIS_MODULE,
        .hw_init                = balloon3_pcmcia_hw_init,
-       .hw_shutdown            = balloon3_pcmcia_hw_shutdown,
        .socket_state           = balloon3_pcmcia_socket_state,
        .configure_socket       = balloon3_pcmcia_configure_socket,
        .first                  = 0,
index 85ac095..490bb82 100644 (file)
@@ -317,10 +317,7 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
 
                skt->nr = ops->first + i;
                skt->clk = clk;
-               skt->ops = ops;
-               skt->socket.owner = ops->owner;
-               skt->socket.dev.parent = &dev->dev;
-               skt->socket.pci_irq = NO_IRQ;
+               soc_pcmcia_init_one(skt, ops, &dev->dev);
 
                ret = pxa2xx_drv_pcmcia_add_one(skt);
                if (ret)
index 31ab6dd..da40908 100644 (file)
 #define GPIO_PCMCIA_S1_RDYINT  (8)
 #define GPIO_PCMCIA_RESET      (9)
 
-#define PCMCIA_S0_CD_VALID     gpio_to_irq(GPIO_PCMCIA_S0_CD_VALID)
-#define PCMCIA_S1_CD_VALID     gpio_to_irq(GPIO_PCMCIA_S1_CD_VALID)
-#define PCMCIA_S0_RDYINT       gpio_to_irq(GPIO_PCMCIA_S0_RDYINT)
-#define PCMCIA_S1_RDYINT       gpio_to_irq(GPIO_PCMCIA_S1_RDYINT)
-
-
-static struct pcmcia_irqs irqs[] = {
-       { .sock = 0, .str = "PCMCIA0 CD" },
-       { .sock = 1, .str = "PCMCIA1 CD" },
-};
-
 static int cmx255_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        int ret = gpio_request(GPIO_PCMCIA_RESET, "PCCard reset");
@@ -43,19 +32,23 @@ static int cmx255_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
                return ret;
        gpio_direction_output(GPIO_PCMCIA_RESET, 0);
 
-       skt->socket.pci_irq = skt->nr == 0 ? PCMCIA_S0_RDYINT : PCMCIA_S1_RDYINT;
-       irqs[0].irq = PCMCIA_S0_CD_VALID;
-       irqs[1].irq = PCMCIA_S1_CD_VALID;
-       ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-       if (!ret)
-               gpio_free(GPIO_PCMCIA_RESET);
+       if (skt->nr == 0) {
+               skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S0_CD_VALID;
+               skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+               skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S0_RDYINT;
+               skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY";
+       } else {
+               skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S1_CD_VALID;
+               skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD";
+               skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S1_RDYINT;
+               skt->stat[SOC_STAT_RDY].name = "PCMCIA1 RDY";
+       }
 
-       return ret;
+       return 0;
 }
 
 static void cmx255_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
 {
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
        gpio_free(GPIO_PCMCIA_RESET);
 }
 
@@ -63,16 +56,8 @@ static void cmx255_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
 static void cmx255_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                       struct pcmcia_state *state)
 {
-       int cd = skt->nr ? GPIO_PCMCIA_S1_CD_VALID : GPIO_PCMCIA_S0_CD_VALID;
-       int rdy = skt->nr ? GPIO_PCMCIA_S1_RDYINT : GPIO_PCMCIA_S0_RDYINT;
-
-       state->detect = !gpio_get_value(cd);
-       state->ready  = !!gpio_get_value(rdy);
-       state->bvd1   = 1;
-       state->bvd2   = 1;
        state->vs_3v  = 0;
        state->vs_Xv  = 0;
-       state->wrprot = 0;  /* not available */
 }
 
 
index 3dc7621..f59223f 100644 (file)
 #define GPIO_PCMCIA_S0_RDYINT  (82)
 #define GPIO_PCMCIA_RESET      (53)
 
-#define PCMCIA_S0_CD_VALID     gpio_to_irq(GPIO_PCMCIA_S0_CD_VALID)
-#define PCMCIA_S0_RDYINT       gpio_to_irq(GPIO_PCMCIA_S0_RDYINT)
-
-
-static struct pcmcia_irqs irqs[] = {
-       { .sock = 0, .str = "PCMCIA0 CD" },
-};
-
 static int cmx270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        int ret = gpio_request(GPIO_PCMCIA_RESET, "PCCard reset");
@@ -37,18 +29,16 @@ static int cmx270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
                return ret;
        gpio_direction_output(GPIO_PCMCIA_RESET, 0);
 
-       skt->socket.pci_irq = PCMCIA_S0_RDYINT;
-       irqs[0].irq = PCMCIA_S0_CD_VALID;
-       ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-       if (!ret)
-               gpio_free(GPIO_PCMCIA_RESET);
+       skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S0_CD_VALID;
+       skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+       skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S0_RDYINT;
+       skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY";
 
        return ret;
 }
 
 static void cmx270_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
 {
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
        gpio_free(GPIO_PCMCIA_RESET);
 }
 
@@ -56,13 +46,8 @@ static void cmx270_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
 static void cmx270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                       struct pcmcia_state *state)
 {
-       state->detect = (gpio_get_value(GPIO_PCMCIA_S0_CD_VALID) == 0) ? 1 : 0;
-       state->ready  = (gpio_get_value(GPIO_PCMCIA_S0_RDYINT) == 0) ? 0 : 1;
-       state->bvd1   = 1;
-       state->bvd2   = 1;
        state->vs_3v  = 0;
        state->vs_Xv  = 0;
-       state->wrprot = 0;  /* not available */
 }
 
 
index c6dec57..4dee7b2 100644 (file)
@@ -53,13 +53,6 @@ static struct gpio colibri_pcmcia_gpios[] = {
        { 0,    GPIOF_INIT_HIGH,"PCMCIA Reset" },
 };
 
-static struct pcmcia_irqs colibri_irqs[] = {
-       {
-               .sock = 0,
-               .str  = "PCMCIA CD"
-       },
-};
-
 static int colibri_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        int ret;
@@ -69,19 +62,10 @@ static int colibri_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        if (ret)
                goto err1;
 
-       colibri_irqs[0].irq = gpio_to_irq(colibri_pcmcia_gpios[DETECT].gpio);
        skt->socket.pci_irq = gpio_to_irq(colibri_pcmcia_gpios[READY].gpio);
+       skt->stat[SOC_STAT_CD].irq = gpio_to_irq(colibri_pcmcia_gpios[DETECT].gpio);
+       skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
 
-       ret = soc_pcmcia_request_irqs(skt, colibri_irqs,
-                                       ARRAY_SIZE(colibri_irqs));
-       if (ret)
-               goto err2;
-
-       return ret;
-
-err2:
-       gpio_free_array(colibri_pcmcia_gpios,
-                       ARRAY_SIZE(colibri_pcmcia_gpios));
 err1:
        return ret;
 }
@@ -100,7 +84,6 @@ static void colibri_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
        state->ready  = !!gpio_get_value(colibri_pcmcia_gpios[READY].gpio);
        state->bvd1   = !!gpio_get_value(colibri_pcmcia_gpios[BVD1].gpio);
        state->bvd2   = !!gpio_get_value(colibri_pcmcia_gpios[BVD2].gpio);
-       state->wrprot = 0;
        state->vs_3v  = 1;
        state->vs_Xv  = 0;
 }
index 17cd2ce..8751a32 100644 (file)
 
 #include "soc_common.h"
 
-static struct pcmcia_irqs cd_irqs[] = {
-       {
-               .sock = 0,
-               .str  = "CF card detect"
-       },
-       {
-               .sock = 1,
-               .str  = "Wifi switch"
-       },
-};
-
 static int e740_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-       if (skt->nr == 0)
-               skt->socket.pci_irq = gpio_to_irq(GPIO_E740_PCMCIA_RDY0);
-       else
-               skt->socket.pci_irq = gpio_to_irq(GPIO_E740_PCMCIA_RDY1);
-
-       cd_irqs[0].irq = gpio_to_irq(GPIO_E740_PCMCIA_CD0);
-       cd_irqs[1].irq = gpio_to_irq(GPIO_E740_PCMCIA_CD1);
-
-       return soc_pcmcia_request_irqs(skt, &cd_irqs[skt->nr], 1);
-}
+       if (skt->nr == 0) {
+               skt->stat[SOC_STAT_CD].gpio = GPIO_E740_PCMCIA_CD0;
+               skt->stat[SOC_STAT_CD].name = "CF card detect";
+               skt->stat[SOC_STAT_RDY].gpio = GPIO_E740_PCMCIA_RDY0;
+               skt->stat[SOC_STAT_RDY].name = "CF ready";
+       } else {
+               skt->stat[SOC_STAT_CD].gpio = GPIO_E740_PCMCIA_CD1;
+               skt->stat[SOC_STAT_CD].name = "Wifi switch";
+               skt->stat[SOC_STAT_RDY].gpio = GPIO_E740_PCMCIA_RDY1;
+               skt->stat[SOC_STAT_RDY].name = "Wifi ready";
+       }
 
-/*
- * Release all resources.
- */
-static void e740_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_free_irqs(skt, &cd_irqs[skt->nr], 1);
+       return 0;
 }
 
 static void e740_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                        struct pcmcia_state *state)
 {
-       if (skt->nr == 0) {
-               state->detect = gpio_get_value(GPIO_E740_PCMCIA_CD0) ? 0 : 1;
-               state->ready  = gpio_get_value(GPIO_E740_PCMCIA_RDY0) ? 1 : 0;
-       } else {
-               state->detect = gpio_get_value(GPIO_E740_PCMCIA_CD1) ? 0 : 1;
-               state->ready  = gpio_get_value(GPIO_E740_PCMCIA_RDY1) ? 1 : 0;
-       }
-
        state->vs_3v  = 1;
-       state->bvd1   = 1;
-       state->bvd2   = 1;
-       state->wrprot = 0;
        state->vs_Xv  = 0;
 }
 
@@ -109,32 +83,11 @@ static int e740_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-/*
- * Enable card status IRQs on (re-)initialisation.  This can
- * be called at initialisation, power management event, or
- * pcmcia event.
- */
-static void e740_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_enable_irqs(skt, cd_irqs, ARRAY_SIZE(cd_irqs));
-}
-
-/*
- * Disable card status IRQs on suspend.
- */
-static void e740_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_disable_irqs(skt, cd_irqs, ARRAY_SIZE(cd_irqs));
-}
-
 static struct pcmcia_low_level e740_pcmcia_ops = {
        .owner            = THIS_MODULE,
        .hw_init          = e740_pcmcia_hw_init,
-       .hw_shutdown      = e740_pcmcia_hw_shutdown,
        .socket_state     = e740_pcmcia_socket_state,
        .configure_socket = e740_pcmcia_configure_socket,
-       .socket_init      = e740_pcmcia_socket_init,
-       .socket_suspend   = e740_pcmcia_socket_suspend,
        .nr               = 2,
 };
 
diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c
deleted file mode 100644 (file)
index c21888e..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * linux/drivers/pcmcia/pxa2xx_lubbock.c
- *
- * Author:     George Davis
- * Created:    Jan 10, 2002
- * Copyright:  MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c
- *
- * Lubbock PCMCIA specific routines.
- *
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <mach/hardware.h>
-#include <asm/hardware/sa1111.h>
-#include <asm/mach-types.h>
-#include <mach/lubbock.h>
-
-#include "sa1111_generic.h"
-
-static int
-lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
-                               const socket_state_t *state)
-{
-       struct sa1111_pcmcia_socket *s = to_skt(skt);
-       unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
-       int ret = 0;
-
-       pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
-
-       /* Lubbock uses the Maxim MAX1602, with the following connections:
-        *
-        * Socket 0 (PCMCIA):
-        *      MAX1602 Lubbock         Register
-        *      Pin     Signal
-        *      -----   -------         ----------------------
-        *      A0VPP   S0_PWR0         SA-1111 GPIO A<0>
-        *      A1VPP   S0_PWR1         SA-1111 GPIO A<1>
-        *      A0VCC   S0_PWR2         SA-1111 GPIO A<2>
-        *      A1VCC   S0_PWR3         SA-1111 GPIO A<3>
-        *      VX      VCC
-        *      VY      +3.3V
-        *      12IN    +12V
-        *      CODE    +3.3V           Cirrus  Code, CODE = High (VY)
-        *
-        * Socket 1 (CF):
-        *      MAX1602 Lubbock         Register
-        *      Pin     Signal
-        *      -----   -------         ----------------------
-        *      A0VPP   GND             VPP is not connected
-        *      A1VPP   GND             VPP is not connected
-        *      A0VCC   S1_PWR0         MISC_WR<14>
-        *      A1VCC   S1_PWR1         MISC_WR<15>
-        *      VX      VCC
-        *      VY      +3.3V
-        *      12IN    GND             VPP is not connected
-        *      CODE    +3.3V           Cirrus  Code, CODE = High (VY)
-        *
-        */
-
- again:
-       switch (skt->nr) {
-       case 0:
-               pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
-
-               switch (state->Vcc) {
-               case 0: /* Hi-Z */
-                       break;
-
-               case 33: /* VY */
-                       pa_dwr_set |= GPIO_A3;
-                       break;
-
-               case 50: /* VX */
-                       pa_dwr_set |= GPIO_A2;
-                       break;
-
-               default:
-                       printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-                              __func__, state->Vcc);
-                       ret = -1;
-               }
-
-               switch (state->Vpp) {
-               case 0: /* Hi-Z */
-                       break;
-
-               case 120: /* 12IN */
-                       pa_dwr_set |= GPIO_A1;
-                       break;
-
-               default: /* VCC */
-                       if (state->Vpp == state->Vcc)
-                               pa_dwr_set |= GPIO_A0;
-                       else {
-                               printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
-                                      __func__, state->Vpp);
-                               ret = -1;
-                               break;
-                       }
-               }
-               break;
-
-       case 1:
-               misc_mask = (1 << 15) | (1 << 14);
-
-               switch (state->Vcc) {
-               case 0: /* Hi-Z */
-                       break;
-
-               case 33: /* VY */
-                       misc_set |= 1 << 15;
-                       break;
-
-               case 50: /* VX */
-                       misc_set |= 1 << 14;
-                       break;
-
-               default:
-                       printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
-                              __func__, state->Vcc);
-                       ret = -1;
-                       break;
-               }
-
-               if (state->Vpp != state->Vcc && state->Vpp != 0) {
-                       printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
-                              __func__, state->Vpp);
-                       ret = -1;
-                       break;
-               }
-               break;
-
-       default:
-               ret = -1;
-       }
-
-       if (ret == 0)
-               ret = sa1111_pcmcia_configure_socket(skt, state);
-
-       if (ret == 0) {
-               lubbock_set_misc_wr(misc_mask, misc_set);
-               sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
-       }
-
-#if 1
-       if (ret == 0 && state->Vcc == 33) {
-               struct pcmcia_state new_state;
-
-               /*
-                * HACK ALERT:
-                * We can't sense the voltage properly on Lubbock before
-                * actually applying some power to the socket (catch 22).
-                * Resense the socket Voltage Sense pins after applying
-                * socket power.
-                *
-                * Note: It takes about 2.5ms for the MAX1602 VCC output
-                * to rise.
-                */
-               mdelay(3);
-
-               sa1111_pcmcia_socket_state(skt, &new_state);
-
-               if (!new_state.vs_3v && !new_state.vs_Xv) {
-                       /*
-                        * Switch to 5V,  Configure socket with 5V voltage
-                        */
-                       lubbock_set_misc_wr(misc_mask, 0);
-                       sa1111_set_io(s->dev, pa_dwr_mask, 0);
-
-                       /*
-                        * It takes about 100ms to turn off Vcc.
-                        */
-                       mdelay(100);
-
-                       /*
-                        * We need to hack around the const qualifier as
-                        * well to keep this ugly workaround localized and
-                        * not force it to the rest of the code. Barf bags
-                        * available in the seat pocket in front of you!
-                        */
-                       ((socket_state_t *)state)->Vcc = 50;
-                       ((socket_state_t *)state)->Vpp = 50;
-                       goto again;
-               }
-       }
-#endif
-
-       return ret;
-}
-
-static struct pcmcia_low_level lubbock_pcmcia_ops = {
-       .owner                  = THIS_MODULE,
-       .configure_socket       = lubbock_pcmcia_configure_socket,
-       .socket_init            = sa1111_pcmcia_socket_init,
-       .first                  = 0,
-       .nr                     = 2,
-};
-
-#include "pxa2xx_base.h"
-
-int pcmcia_lubbock_init(struct sa1111_dev *sadev)
-{
-       int ret = -ENODEV;
-
-       if (machine_is_lubbock()) {
-               /*
-                * Set GPIO_A<3:0> to be outputs for the MAX1600,
-                * and switch to standby mode.
-                */
-               sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
-               sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-               sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-
-               /* Set CF Socket 1 power to standby mode. */
-               lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
-
-               pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
-               pxa2xx_configure_sockets(&sadev->dev);
-               ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
-                               pxa2xx_drv_pcmcia_add_one);
-       }
-
-       return ret;
-}
-
-MODULE_LICENSE("GPL");
index aded706..7e32e25 100644 (file)
 #include "soc_common.h"
 
 
-static struct pcmcia_irqs irqs[] = {
-       { 0, MAINSTONE_S0_CD_IRQ, "PCMCIA0 CD" },
-       { 1, MAINSTONE_S1_CD_IRQ, "PCMCIA1 CD" },
-       { 0, MAINSTONE_S0_STSCHG_IRQ, "PCMCIA0 STSCHG" },
-       { 1, MAINSTONE_S1_STSCHG_IRQ, "PCMCIA1 STSCHG" },
-};
-
 static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        /*
         * Setup default state of GPIO outputs
         * before we enable them as outputs.
         */
-
-       skt->socket.pci_irq = (skt->nr == 0) ? MAINSTONE_S0_IRQ : MAINSTONE_S1_IRQ;
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void mst_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+       if (skt->nr == 0) {
+               skt->socket.pci_irq = MAINSTONE_S0_IRQ;
+               skt->stat[SOC_STAT_CD].irq = MAINSTONE_S0_CD_IRQ;
+               skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+               skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S0_STSCHG_IRQ;
+               skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG";
+       } else {
+               skt->socket.pci_irq = MAINSTONE_S1_IRQ;
+               skt->stat[SOC_STAT_CD].irq = MAINSTONE_S1_CD_IRQ;
+               skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD";
+               skt->stat[SOC_STAT_BVD1].irq = MAINSTONE_S1_STSCHG_IRQ;
+               skt->stat[SOC_STAT_BVD1].name = "PCMCIA1 STSCHG";
+       }
+       return 0;
 }
 
 static unsigned long mst_pcmcia_status[2];
@@ -84,7 +83,6 @@ static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
        state->bvd2   = (status & MST_PCMCIA_nSPKR_BVD2) ? 1 : 0;
        state->vs_3v  = (status & MST_PCMCIA_nVS1) ? 0 : 1;
        state->vs_Xv  = (status & MST_PCMCIA_nVS2) ? 0 : 1;
-       state->wrprot = 0;  /* not available */
 }
 
 static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
@@ -131,7 +129,6 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 static struct pcmcia_low_level mst_pcmcia_ops __initdata = {
        .owner                  = THIS_MODULE,
        .hw_init                = mst_pcmcia_hw_init,
-       .hw_shutdown            = mst_pcmcia_hw_shutdown,
        .socket_state           = mst_pcmcia_socket_state,
        .configure_socket       = mst_pcmcia_configure_socket,
        .nr                     = 2,
index 6a8e011..ed7d4db 100644 (file)
@@ -23,7 +23,6 @@
 static struct gpio palmld_pcmcia_gpios[] = {
        { GPIO_NR_PALMLD_PCMCIA_POWER,  GPIOF_INIT_LOW, "PCMCIA Power" },
        { GPIO_NR_PALMLD_PCMCIA_RESET,  GPIOF_INIT_HIGH,"PCMCIA Reset" },
-       { GPIO_NR_PALMLD_PCMCIA_READY,  GPIOF_IN,       "PCMCIA Ready" },
 };
 
 static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
@@ -33,7 +32,8 @@ static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        ret = gpio_request_array(palmld_pcmcia_gpios,
                                ARRAY_SIZE(palmld_pcmcia_gpios));
 
-       skt->socket.pci_irq = gpio_to_irq(GPIO_NR_PALMLD_PCMCIA_READY);
+       skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMLD_PCMCIA_READY;
+       skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
 
        return ret;
 }
@@ -47,10 +47,6 @@ static void palmld_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                        struct pcmcia_state *state)
 {
        state->detect = 1; /* always inserted */
-       state->ready  = !!gpio_get_value(GPIO_NR_PALMLD_PCMCIA_READY);
-       state->bvd1   = 1;
-       state->bvd2   = 1;
-       state->wrprot = 0;
        state->vs_3v  = 1;
        state->vs_Xv  = 0;
 }
index 9e38de7..81225a7 100644 (file)
@@ -26,7 +26,6 @@ static struct gpio palmtc_pcmcia_gpios[] = {
        { GPIO_NR_PALMTC_PCMCIA_POWER2, GPIOF_INIT_LOW, "PCMCIA Power 2" },
        { GPIO_NR_PALMTC_PCMCIA_POWER3, GPIOF_INIT_LOW, "PCMCIA Power 3" },
        { GPIO_NR_PALMTC_PCMCIA_RESET,  GPIOF_INIT_HIGH,"PCMCIA Reset" },
-       { GPIO_NR_PALMTC_PCMCIA_READY,  GPIOF_IN,       "PCMCIA Ready" },
        { GPIO_NR_PALMTC_PCMCIA_PWRREADY, GPIOF_IN,     "PCMCIA Power Ready" },
 };
 
@@ -37,7 +36,8 @@ static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        ret = gpio_request_array(palmtc_pcmcia_gpios,
                                ARRAY_SIZE(palmtc_pcmcia_gpios));
 
-       skt->socket.pci_irq = gpio_to_irq(GPIO_NR_PALMTC_PCMCIA_READY);
+       skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTC_PCMCIA_READY;
+       skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
 
        return ret;
 }
@@ -51,10 +51,6 @@ static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                        struct pcmcia_state *state)
 {
        state->detect = 1; /* always inserted */
-       state->ready  = !!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_READY);
-       state->bvd1   = 1;
-       state->bvd2   = 1;
-       state->wrprot = 0;
        state->vs_3v  = 1;
        state->vs_Xv  = 0;
 }
index 80645a6..069b6bb 100644 (file)
@@ -23,7 +23,6 @@ static struct gpio palmtx_pcmcia_gpios[] = {
        { GPIO_NR_PALMTX_PCMCIA_POWER1, GPIOF_INIT_LOW, "PCMCIA Power 1" },
        { GPIO_NR_PALMTX_PCMCIA_POWER2, GPIOF_INIT_LOW, "PCMCIA Power 2" },
        { GPIO_NR_PALMTX_PCMCIA_RESET,  GPIOF_INIT_HIGH,"PCMCIA Reset" },
-       { GPIO_NR_PALMTX_PCMCIA_READY,  GPIOF_IN,       "PCMCIA Ready" },
 };
 
 static int palmtx_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
@@ -33,7 +32,8 @@ static int palmtx_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        ret = gpio_request_array(palmtx_pcmcia_gpios,
                                ARRAY_SIZE(palmtx_pcmcia_gpios));
 
-       skt->socket.pci_irq = gpio_to_irq(GPIO_NR_PALMTX_PCMCIA_READY);
+       skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTX_PCMCIA_READY;
+       skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
 
        return ret;
 }
@@ -47,10 +47,6 @@ static void palmtx_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                        struct pcmcia_state *state)
 {
        state->detect = 1; /* always inserted */
-       state->ready  = !!gpio_get_value(GPIO_NR_PALMTX_PCMCIA_READY);
-       state->bvd1   = 1;
-       state->bvd2   = 1;
-       state->wrprot = 0;
        state->vs_3v  = 1;
        state->vs_Xv  = 0;
 }
index 69ae2fd..b066273 100644 (file)
@@ -46,21 +46,9 @@ static void sharpsl_pcmcia_init_reset(struct soc_pcmcia_socket *skt)
 
 static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-       int ret;
-
-       /* Register interrupts */
        if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
-               struct pcmcia_irqs cd_irq;
-
-               cd_irq.sock = skt->nr;
-               cd_irq.irq  = SCOOP_DEV[skt->nr].cd_irq;
-               cd_irq.str  = SCOOP_DEV[skt->nr].cd_irq_str;
-               ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1);
-
-               if (ret) {
-                       printk(KERN_ERR "Request for Compact Flash IRQ failed\n");
-                       return ret;
-               }
+               skt->stat[SOC_STAT_CD].irq = SCOOP_DEV[skt->nr].cd_irq;
+               skt->stat[SOC_STAT_CD].name = SCOOP_DEV[skt->nr].cd_irq_str;
        }
 
        skt->socket.pci_irq = SCOOP_DEV[skt->nr].irq;
@@ -68,19 +56,6 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        return 0;
 }
 
-static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-       if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
-               struct pcmcia_irqs cd_irq;
-
-               cd_irq.sock = skt->nr;
-               cd_irq.irq  = SCOOP_DEV[skt->nr].cd_irq;
-               cd_irq.str  = SCOOP_DEV[skt->nr].cd_irq_str;
-               soc_pcmcia_free_irqs(skt, &cd_irq, 1);
-       }
-}
-
-
 static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                    struct pcmcia_state *state)
 {
@@ -222,7 +197,6 @@ static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 static struct pcmcia_low_level sharpsl_pcmcia_ops __initdata = {
        .owner                  = THIS_MODULE,
        .hw_init                = sharpsl_pcmcia_hw_init,
-       .hw_shutdown            = sharpsl_pcmcia_hw_shutdown,
        .socket_state           = sharpsl_pcmcia_socket_state,
        .configure_socket       = sharpsl_pcmcia_configure_socket,
        .socket_init            = sharpsl_pcmcia_socket_init,
index 6c2366b..1d73c44 100644 (file)
 #define SG2_S0_GPIO_DETECT     53
 #define SG2_S0_GPIO_READY      81
 
-static struct pcmcia_irqs irqs[] = {
-       {.sock = 0, .str = "PCMCIA0 CD" },
-};
-
 static struct gpio sg2_pcmcia_gpios[] = {
        { SG2_S0_GPIO_RESET, GPIOF_OUT_INIT_HIGH, "PCMCIA Reset" },
        { SG2_S0_POWER_CTL, GPIOF_OUT_INIT_HIGH, "PCMCIA Power Ctrl" },
@@ -44,27 +40,20 @@ static struct gpio sg2_pcmcia_gpios[] = {
 
 static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-       skt->socket.pci_irq = gpio_to_irq(SG2_S0_GPIO_READY);
-       irqs[0].irq = gpio_to_irq(SG2_S0_GPIO_DETECT);
-
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void sg2_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+       skt->stat[SOC_STAT_CD].gpio = SG2_S0_GPIO_DETECT;
+       skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
+       skt->stat[SOC_STAT_RDY].gpio = SG2_S0_GPIO_READY;
+       skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY";
+       return 0;
 }
 
 static void sg2_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                    struct pcmcia_state *state)
 {
-       state->detect = !gpio_get_value(SG2_S0_GPIO_DETECT);
-       state->ready  = !!gpio_get_value(SG2_S0_GPIO_READY);
        state->bvd1   = 0; /* not available - battery detect on card */
        state->bvd2   = 0; /* not available */
        state->vs_3v  = 1; /* not available - voltage detect for card */
        state->vs_Xv  = 0; /* not available */
-       state->wrprot = 0; /* not available - write protect */
 }
 
 static int sg2_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
@@ -94,24 +83,11 @@ static int sg2_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void sg2_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void sg2_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 static struct pcmcia_low_level sg2_pcmcia_ops __initdata = {
        .owner                  = THIS_MODULE,
        .hw_init                = sg2_pcmcia_hw_init,
-       .hw_shutdown            = sg2_pcmcia_hw_shutdown,
        .socket_state           = sg2_pcmcia_socket_state,
        .configure_socket       = sg2_pcmcia_configure_socket,
-       .socket_init            = sg2_pcmcia_socket_init,
-       .socket_suspend         = sg2_pcmcia_socket_suspend,
        .nr                     = 1,
 };
 
index 7c33f89..d326ba1 100644 (file)
 
 extern void board_pcmcia_power(int power);
 
-static struct pcmcia_irqs irqs[] = {
-       { .sock = 0, .str = "cs0_cd" }
-       /* on other baseboards we can have more inputs */
-};
-
 static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-       int ret, i;
        /* we dont have voltage/card/ready detection
         * so we dont need interrupts for it
         */
        switch (skt->nr) {
        case 0:
-               if (gpio_request(GPIO_PRDY, "cf_irq") < 0) {
-                       pr_err("%s: sock %d unable to request gpio %d\n", __func__,
-                               skt->nr, GPIO_PRDY);
-                       return -EBUSY;
-               }
-               if (gpio_direction_input(GPIO_PRDY) < 0) {
-                       pr_err("%s: sock %d unable to set input gpio %d\n", __func__,
-                               skt->nr, GPIO_PRDY);
-                       gpio_free(GPIO_PRDY);
-                       return -EINVAL;
-               }
-               skt->socket.pci_irq = gpio_to_irq(GPIO_PRDY);
-               irqs[0].irq = gpio_to_irq(GPIO_PCD);
+               skt->stat[SOC_STAT_CD].gpio = GPIO_PCD;
+               skt->stat[SOC_STAT_CD].name = "cs0_cd";
+               skt->stat[SOC_STAT_RDY].gpio = GPIO_PRDY;
+               skt->stat[SOC_STAT_RDY].name = "cs0_rdy";
                break;
        default:
                break;
@@ -62,39 +47,7 @@ static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        /* release the reset of this card */
        pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->socket.pci_irq);
 
-       /* supplementory irqs for the socket */
-       for (i = 0; i < ARRAY_SIZE(irqs); i++) {
-               if (irqs[i].sock != skt->nr)
-                       continue;
-               if (gpio_request(irq_to_gpio(irqs[i].irq), irqs[i].str) < 0) {
-                       pr_err("%s: sock %d unable to request gpio %d\n",
-                               __func__, skt->nr, irq_to_gpio(irqs[i].irq));
-                       ret = -EBUSY;
-                       goto error;
-               }
-               if (gpio_direction_input(irq_to_gpio(irqs[i].irq)) < 0) {
-                       pr_err("%s: sock %d unable to set input gpio %d\n",
-                               __func__, skt->nr, irq_to_gpio(irqs[i].irq));
-                       ret = -EINVAL;
-                       goto error;
-               }
-       }
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-
-error:
-       for (; i >= 0; i--) {
-               gpio_free(irq_to_gpio(irqs[i].irq));
-       }
-       return (ret);
-}
-
-static void trizeps_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-       int i;
-       /* free allocated gpio's */
-       gpio_free(GPIO_PRDY);
-       for (i = 0; i < ARRAY_SIZE(irqs); i++)
-               gpio_free(irq_to_gpio(irqs[i].irq));
+       return 0;
 }
 
 static unsigned long trizeps_pcmcia_status[2];
@@ -118,13 +71,10 @@ static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
        switch (skt->nr) {
        case 0:
                /* just fill in fix states */
-               state->detect = gpio_get_value(GPIO_PCD) ? 0 : 1;
-               state->ready  = gpio_get_value(GPIO_PRDY) ? 1 : 0;
                state->bvd1   = (status & ConXS_CFSR_BVD1) ? 1 : 0;
                state->bvd2   = (status & ConXS_CFSR_BVD2) ? 1 : 0;
                state->vs_3v  = (status & ConXS_CFSR_VS1) ? 0 : 1;
                state->vs_Xv  = (status & ConXS_CFSR_VS2) ? 0 : 1;
-               state->wrprot = 0;      /* not available */
                break;
 
 #ifndef CONFIG_MACH_TRIZEPS_CONXS
@@ -136,7 +86,6 @@ static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                state->bvd2   = 0;
                state->vs_3v  = 0;
                state->vs_Xv  = 0;
-               state->wrprot = 0;
                break;
 
 #endif
@@ -204,7 +153,6 @@ static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 static struct pcmcia_low_level trizeps_pcmcia_ops = {
        .owner                  = THIS_MODULE,
        .hw_init                = trizeps_pcmcia_hw_init,
-       .hw_shutdown            = trizeps_pcmcia_hw_shutdown,
        .socket_state           = trizeps_pcmcia_socket_state,
        .configure_socket       = trizeps_pcmcia_configure_socket,
        .socket_init            = trizeps_pcmcia_socket_init,
index 1064b1c..adfae49 100644 (file)
 
 static struct platform_device *arcom_pcmcia_dev;
 
-static struct pcmcia_irqs irqs[] = {
-       {
-               .sock   = 0,
-               .str    = "PCMCIA_CD",
-       },
-};
-
 static inline struct arcom_pcmcia_pdata *viper_get_pdata(void)
 {
        return arcom_pcmcia_dev->dev.platform_data;
@@ -49,38 +42,28 @@ static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
        struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
        unsigned long flags;
 
-       skt->socket.pci_irq = gpio_to_irq(pdata->rdy_gpio);
-       irqs[0].irq = gpio_to_irq(pdata->cd_gpio);
-
-       if (gpio_request(pdata->cd_gpio, "CF detect"))
-               goto err_request_cd;
-
-       if (gpio_request(pdata->rdy_gpio, "CF ready"))
-               goto err_request_rdy;
+       skt->stat[SOC_STAT_CD].gpio = pdata->cd_gpio;
+       skt->stat[SOC_STAT_CD].name = "PCMCIA_CD";
+       skt->stat[SOC_STAT_RDY].gpio = pdata->rdy_gpio;
+       skt->stat[SOC_STAT_RDY].name = "CF ready";
 
        if (gpio_request(pdata->pwr_gpio, "CF power"))
                goto err_request_pwr;
 
        local_irq_save(flags);
 
-       if (gpio_direction_output(pdata->pwr_gpio, 0) ||
-           gpio_direction_input(pdata->cd_gpio) ||
-           gpio_direction_input(pdata->rdy_gpio)) {
+       if (gpio_direction_output(pdata->pwr_gpio, 0)) {
                local_irq_restore(flags);
                goto err_dir;
        }
 
        local_irq_restore(flags);
 
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+       return 0;
 
 err_dir:
        gpio_free(pdata->pwr_gpio);
 err_request_pwr:
-       gpio_free(pdata->rdy_gpio);
-err_request_rdy:
-       gpio_free(pdata->cd_gpio);
-err_request_cd:
        dev_err(&arcom_pcmcia_dev->dev, "Failed to setup PCMCIA GPIOs\n");
        return -1;
 }
@@ -92,22 +75,12 @@ static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
        struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
 
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
        gpio_free(pdata->pwr_gpio);
-       gpio_free(pdata->rdy_gpio);
-       gpio_free(pdata->cd_gpio);
 }
 
 static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                      struct pcmcia_state *state)
 {
-       struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
-
-       state->detect = !gpio_get_value(pdata->cd_gpio);
-       state->ready  = !!gpio_get_value(pdata->rdy_gpio);
-       state->bvd1   = 1;
-       state->bvd2   = 1;
-       state->wrprot = 0;
        state->vs_3v  = 1; /* Can only apply 3.3V */
        state->vs_Xv  = 0;
 }
index 61b17d2..a47dcd2 100644 (file)
 #include "soc_common.h"
 
 static struct gpio vpac270_pcmcia_gpios[] = {
-       { GPIO84_VPAC270_PCMCIA_CD,     GPIOF_IN,       "PCMCIA Card Detect" },
-       { GPIO35_VPAC270_PCMCIA_RDY,    GPIOF_IN,       "PCMCIA Ready" },
        { GPIO107_VPAC270_PCMCIA_PPEN,  GPIOF_INIT_LOW, "PCMCIA PPEN" },
        { GPIO11_VPAC270_PCMCIA_RESET,  GPIOF_INIT_LOW, "PCMCIA Reset" },
 };
 
 static struct gpio vpac270_cf_gpios[] = {
-       { GPIO17_VPAC270_CF_CD,         GPIOF_IN,       "CF Card Detect" },
-       { GPIO12_VPAC270_CF_RDY,        GPIOF_IN,       "CF Ready" },
        { GPIO16_VPAC270_CF_RESET,      GPIOF_INIT_LOW, "CF Reset" },
 };
 
-static struct pcmcia_irqs cd_irqs[] = {
-       {
-               .sock = 0,
-               .str  = "PCMCIA CD"
-       },
-       {
-               .sock = 1,
-               .str  = "CF CD"
-       },
-};
-
 static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        int ret;
@@ -54,20 +39,18 @@ static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
                ret = gpio_request_array(vpac270_pcmcia_gpios,
                                ARRAY_SIZE(vpac270_pcmcia_gpios));
 
-               skt->socket.pci_irq = gpio_to_irq(GPIO35_VPAC270_PCMCIA_RDY);
-               cd_irqs[0].irq = gpio_to_irq(GPIO84_VPAC270_PCMCIA_CD);
-
-               if (!ret)
-                       ret = soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1);
+               skt->stat[SOC_STAT_CD].gpio = GPIO84_VPAC270_PCMCIA_CD;
+               skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
+               skt->stat[SOC_STAT_RDY].gpio = GPIO35_VPAC270_PCMCIA_RDY;
+               skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
        } else {
                ret = gpio_request_array(vpac270_cf_gpios,
                                ARRAY_SIZE(vpac270_cf_gpios));
 
-               skt->socket.pci_irq = gpio_to_irq(GPIO12_VPAC270_CF_RDY);
-               cd_irqs[1].irq = gpio_to_irq(GPIO17_VPAC270_CF_CD);
-
-               if (!ret)
-                       ret = soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1);
+               skt->stat[SOC_STAT_CD].gpio = GPIO17_VPAC270_CF_CD;
+               skt->stat[SOC_STAT_CD].name = "CF CD";
+               skt->stat[SOC_STAT_RDY].gpio = GPIO12_VPAC270_CF_RDY;
+               skt->stat[SOC_STAT_RDY].name = "CF Ready";
        }
 
        return ret;
@@ -86,16 +69,6 @@ static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                        struct pcmcia_state *state)
 {
-       if (skt->nr == 0) {
-               state->detect = !gpio_get_value(GPIO84_VPAC270_PCMCIA_CD);
-               state->ready  = !!gpio_get_value(GPIO35_VPAC270_PCMCIA_RDY);
-       } else {
-               state->detect = !gpio_get_value(GPIO17_VPAC270_CF_CD);
-               state->ready  = !!gpio_get_value(GPIO12_VPAC270_CF_RDY);
-       }
-       state->bvd1   = 1;
-       state->bvd2   = 1;
-       state->wrprot = 0;
        state->vs_3v  = 1;
        state->vs_Xv  = 0;
 }
@@ -117,14 +90,6 @@ vpac270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void vpac270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void vpac270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level vpac270_pcmcia_ops = {
        .owner                  = THIS_MODULE,
 
@@ -136,9 +101,6 @@ static struct pcmcia_low_level vpac270_pcmcia_ops = {
 
        .socket_state           = vpac270_pcmcia_socket_state,
        .configure_socket       = vpac270_pcmcia_configure_socket,
-
-       .socket_init            = vpac270_pcmcia_socket_init,
-       .socket_suspend         = vpac270_pcmcia_socket_suspend,
 };
 
 static struct platform_device *vpac270_pcmcia_device;
index f1e8822..ba8557e 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
-#include <asm/signal.h>
 #include <mach/assabet.h>
 
 #include "sa1100_generic.h"
 
-static struct pcmcia_irqs irqs[] = {
-       { 1, ASSABET_IRQ_GPIO_CF_CD,   "CF CD"   },
-       { 1, ASSABET_IRQ_GPIO_CF_BVD2, "CF BVD2" },
-       { 1, ASSABET_IRQ_GPIO_CF_BVD1, "CF BVD1" },
-};
-
 static int assabet_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-       skt->socket.pci_irq = ASSABET_IRQ_GPIO_CF_IRQ;
-
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
+       skt->stat[SOC_STAT_CD].gpio = ASSABET_GPIO_CF_CD;
+       skt->stat[SOC_STAT_CD].name = "CF CD";
+       skt->stat[SOC_STAT_BVD1].gpio = ASSABET_GPIO_CF_BVD1;
+       skt->stat[SOC_STAT_BVD1].name = "CF BVD1";
+       skt->stat[SOC_STAT_BVD2].gpio = ASSABET_GPIO_CF_BVD2;
+       skt->stat[SOC_STAT_BVD2].name = "CF BVD2";
+       skt->stat[SOC_STAT_RDY].gpio = ASSABET_GPIO_CF_IRQ;
+       skt->stat[SOC_STAT_RDY].name = "CF RDY";
 
-/*
- * Release all resources.
- */
-static void assabet_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+       return 0;
 }
 
 static void
 assabet_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-       unsigned long levels = GPLR;
-
-       state->detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1;
-       state->ready  = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0;
-       state->bvd1   = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0;
-       state->bvd2   = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0;
-       state->wrprot = 0; /* Not available on Assabet. */
        state->vs_3v  = 1; /* Can only apply 3.3V on Assabet. */
        state->vs_Xv  = 0;
 }
@@ -78,38 +62,24 @@ assabet_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_stat
                return -1;
        }
 
-       /* Silently ignore Vpp, output enable, speaker enable. */
+       /* Silently ignore Vpp, speaker enable. */
 
        if (state->flags & SS_RESET)
                mask |= ASSABET_BCR_CF_RST;
+       if (!(state->flags & SS_OUTPUT_ENA))
+               mask |= ASSABET_BCR_CF_BUS_OFF;
 
-       ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask);
+       ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR |
+                       ASSABET_BCR_CF_BUS_OFF, mask);
 
        return 0;
 }
 
 /*
- * Enable card status IRQs on (re-)initialisation.  This can
- * be called at initialisation, power management event, or
- * pcmcia event.
- */
-static void assabet_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-       /*
-        * Enable CF bus
-        */
-       ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
-
-       soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-/*
  * Disable card status IRQs on suspend.
  */
 static void assabet_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
-       soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-
        /*
         * Tristate the CF bus signals.  Also assert CF
         * reset as per user guide page 4-11.
@@ -119,14 +89,9 @@ static void assabet_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 
 static struct pcmcia_low_level assabet_pcmcia_ops = { 
        .owner                  = THIS_MODULE,
-
        .hw_init                = assabet_pcmcia_hw_init,
-       .hw_shutdown            = assabet_pcmcia_hw_shutdown,
-
        .socket_state           = assabet_pcmcia_socket_state,
        .configure_socket       = assabet_pcmcia_configure_socket,
-
-       .socket_init            = assabet_pcmcia_socket_init,
        .socket_suspend         = assabet_pcmcia_socket_suspend,
 };
 
diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c
deleted file mode 100644 (file)
index 1ce53f4..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * linux/drivers/pcmcia/sa1100_badge4.c
- *
- * BadgePAD 4 PCMCIA specific routines
- *
- *   Christopher Hoover <ch@hpl.hp.com>
- *
- * Copyright (C) 2002 Hewlett-Packard Company
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <mach/badge4.h>
-#include <asm/hardware/sa1111.h>
-
-#include "sa1111_generic.h"
-
-/*
- * BadgePAD 4 Details
- *
- * PCM Vcc:
- *
- *  PCM Vcc on BadgePAD 4 can be jumpered for 3v3 (short pins 1 and 3
- *  on JP6) or 5v0 (short pins 3 and 5 on JP6).
- *
- * PCM Vpp:
- *
- *  PCM Vpp on BadgePAD 4 can be jumpered for 12v0 (short pins 4 and 6
- *  on JP6) or tied to PCM Vcc (short pins 2 and 4 on JP6).  N.B.,
- *  12v0 operation requires that the power supply actually supply 12v0
- *  via pin 7 of JP7.
- *
- * CF Vcc:
- *
- *  CF Vcc on BadgePAD 4 can be jumpered either for 3v3 (short pins 1
- *  and 2 on JP10) or 5v0 (short pins 2 and 3 on JP10).
- *
- * Unfortunately there's no way programmatically to determine how a
- * given board is jumpered.  This code assumes a default jumpering
- * as described below.
- *
- * If the defaults aren't correct, you may override them with a pcmv
- * setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf vcc>.  The units are
- * tenths of volts; e.g. pcmv=33,120,50 indicates 3v3 PCM Vcc, 12v0
- * PCM Vpp, and 5v0 CF Vcc.
- *
- */
-
-static int badge4_pcmvcc = 50;  /* pins 3 and 5 jumpered on JP6 */
-static int badge4_pcmvpp = 50;  /* pins 2 and 4 jumpered on JP6 */
-static int badge4_cfvcc = 33;   /* pins 1 and 2 jumpered on JP10 */
-
-static void complain_about_jumpering(const char *whom,
-                                    const char *supply,
-                                    int given, int wanted)
-{
-       printk(KERN_ERR
-        "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation"
-        "; re-jumper the board and/or use pcmv=xx,xx,xx\n",
-              whom, supply,
-              wanted / 10, wanted % 10,
-              supply,
-              given / 10, given % 10);
-}
-
-static int
-badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
-{
-       int ret;
-
-       switch (skt->nr) {
-       case 0:
-               if ((state->Vcc != 0) &&
-                   (state->Vcc != badge4_pcmvcc)) {
-                       complain_about_jumpering(__func__, "pcmvcc",
-                                                badge4_pcmvcc, state->Vcc);
-                       // Apply power regardless of the jumpering.
-                       // return -1;
-               }
-               if ((state->Vpp != 0) &&
-                   (state->Vpp != badge4_pcmvpp)) {
-                       complain_about_jumpering(__func__, "pcmvpp",
-                                                badge4_pcmvpp, state->Vpp);
-                       return -1;
-               }
-               break;
-
-       case 1:
-               if ((state->Vcc != 0) &&
-                   (state->Vcc != badge4_cfvcc)) {
-                       complain_about_jumpering(__func__, "cfvcc",
-                                                badge4_cfvcc, state->Vcc);
-                       return -1;
-               }
-               break;
-
-       default:
-               return -1;
-       }
-
-       ret = sa1111_pcmcia_configure_socket(skt, state);
-       if (ret == 0) {
-               unsigned long flags;
-               int need5V;
-
-               local_irq_save(flags);
-
-               need5V = ((state->Vcc == 50) || (state->Vpp == 50));
-
-               badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V);
-
-               local_irq_restore(flags);
-       }
-
-       return 0;
-}
-
-static struct pcmcia_low_level badge4_pcmcia_ops = {
-       .owner                  = THIS_MODULE,
-       .configure_socket       = badge4_pcmcia_configure_socket,
-       .socket_init            = sa1111_pcmcia_socket_init,
-       .first                  = 0,
-       .nr                     = 2,
-};
-
-int pcmcia_badge4_init(struct device *dev)
-{
-       int ret = -ENODEV;
-
-       if (machine_is_badge4()) {
-               printk(KERN_INFO
-                      "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
-                      __func__,
-                      badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
-
-               sa11xx_drv_pcmcia_ops(&badge4_pcmcia_ops);
-               ret = sa1111_pcmcia_add(dev, &badge4_pcmcia_ops,
-                               sa11xx_drv_pcmcia_add_one);
-       }
-
-       return ret;
-}
-
-static int __init pcmv_setup(char *s)
-{
-       int v[4];
-
-       s = get_options(s, ARRAY_SIZE(v), v);
-
-       if (v[0] >= 1) badge4_pcmvcc = v[1];
-       if (v[0] >= 2) badge4_pcmvpp = v[2];
-       if (v[0] >= 3) badge4_cfvcc = v[3];
-
-       return 1;
-}
-
-__setup("pcmv=", pcmv_setup);
index 30560df..c59c449 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 
 #define CERF_SOCKET    1
 
-static struct pcmcia_irqs irqs[] = {
-       { CERF_SOCKET, CERF_IRQ_GPIO_CF_CD,   "CF_CD"   },
-       { CERF_SOCKET, CERF_IRQ_GPIO_CF_BVD2, "CF_BVD2" },
-       { CERF_SOCKET, CERF_IRQ_GPIO_CF_BVD1, "CF_BVD1" }
-};
-
 static int cerf_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
-       skt->socket.pci_irq = CERF_IRQ_GPIO_CF_IRQ;
+       int ret;
+
+       ret = gpio_request_one(CERF_GPIO_CF_RESET, GPIOF_OUT_INIT_LOW, "CF_RESET");
+       if (ret)
+               return ret;
+
+       skt->stat[SOC_STAT_CD].gpio = CERF_GPIO_CF_CD;
+       skt->stat[SOC_STAT_CD].name = "CF_CD";
+       skt->stat[SOC_STAT_BVD1].gpio = CERF_GPIO_CF_BVD1;
+       skt->stat[SOC_STAT_BVD1].name = "CF_BVD1";
+       skt->stat[SOC_STAT_BVD2].gpio = CERF_GPIO_CF_BVD2;
+       skt->stat[SOC_STAT_BVD2].name = "CF_BVD2";
+       skt->stat[SOC_STAT_RDY].gpio = CERF_GPIO_CF_IRQ;
+       skt->stat[SOC_STAT_RDY].name = "CF_IRQ";
 
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+       return 0;
 }
 
 static void cerf_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+       gpio_free(CERF_GPIO_CF_RESET);
 }
 
 static void
 cerf_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-       unsigned long levels = GPLR;
-
-       state->detect   = (levels & CERF_GPIO_CF_CD)  ?0:1;
-       state->ready    = (levels & CERF_GPIO_CF_IRQ) ?1:0;
-       state->bvd1     = (levels & CERF_GPIO_CF_BVD1)?1:0;
-       state->bvd2     = (levels & CERF_GPIO_CF_BVD2)?1:0;
-       state->wrprot   = 0;
        state->vs_3v    = 1;
        state->vs_Xv    = 0;
 }
@@ -67,34 +68,17 @@ cerf_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                return -1;
        }
 
-       if (state->flags & SS_RESET) {
-               GPSR = CERF_GPIO_CF_RESET;
-       } else {
-               GPCR = CERF_GPIO_CF_RESET;
-       }
+       gpio_set_value(CERF_GPIO_CF_RESET, !!(state->flags & SS_RESET));
 
        return 0;
 }
 
-static void cerf_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void cerf_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 static struct pcmcia_low_level cerf_pcmcia_ops = { 
        .owner                  = THIS_MODULE,
        .hw_init                = cerf_pcmcia_hw_init,
        .hw_shutdown            = cerf_pcmcia_hw_shutdown,
        .socket_state           = cerf_pcmcia_socket_state,
        .configure_socket       = cerf_pcmcia_configure_socket,
-
-       .socket_init            = cerf_pcmcia_socket_init,
-       .socket_suspend         = cerf_pcmcia_socket_suspend,
 };
 
 int __devinit pcmcia_cerf_init(struct device *dev)
index edf8f00..d9c7337 100644 (file)
 
 #include "sa1100_generic.h"
 
-static struct pcmcia_irqs irqs[] = {
-       { .sock = 0, .str = "PCMCIA CD0" }, /* .irq will be filled later */
-       { .sock = 1, .str = "PCMCIA CD1" }
-};
-
 static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        int err;
 
        switch (skt->nr) {
        case 0:
-               err = gpio_request(H3XXX_GPIO_PCMCIA_IRQ0, "PCMCIA IRQ0");
-               if (err)
-                       goto err00;
-               err = gpio_direction_input(H3XXX_GPIO_PCMCIA_IRQ0);
-               if (err)
-                       goto err01;
-               skt->socket.pci_irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_IRQ0);
-
-               err = gpio_request(H3XXX_GPIO_PCMCIA_CD0, "PCMCIA CD0");
-               if (err)
-                       goto err01;
-               err = gpio_direction_input(H3XXX_GPIO_PCMCIA_CD0);
-               if (err)
-                       goto err02;
-               irqs[0].irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_CD0);
+               skt->stat[SOC_STAT_CD].gpio = H3XXX_GPIO_PCMCIA_CD0;
+               skt->stat[SOC_STAT_CD].name = "PCMCIA CD0";
+               skt->stat[SOC_STAT_RDY].gpio = H3XXX_GPIO_PCMCIA_IRQ0;
+               skt->stat[SOC_STAT_RDY].name = "PCMCIA IRQ0";
 
                err = gpio_request(H3XXX_EGPIO_OPT_NVRAM_ON, "OPT NVRAM ON");
                if (err)
-                       goto err02;
+                       goto err01;
                err = gpio_direction_output(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
                if (err)
                        goto err03;
@@ -70,30 +54,12 @@ static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
                err = gpio_direction_output(H3XXX_EGPIO_CARD_RESET, 0);
                if (err)
                        goto err06;
-               err = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-               if (err)
-                       goto err06;
                break;
        case 1:
-               err = gpio_request(H3XXX_GPIO_PCMCIA_IRQ1, "PCMCIA IRQ1");
-               if (err)
-                       goto err10;
-               err = gpio_direction_input(H3XXX_GPIO_PCMCIA_IRQ1);
-               if (err)
-                       goto err11;
-               skt->socket.pci_irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_IRQ1);
-
-               err = gpio_request(H3XXX_GPIO_PCMCIA_CD1, "PCMCIA CD1");
-               if (err)
-                       goto err11;
-               err = gpio_direction_input(H3XXX_GPIO_PCMCIA_CD1);
-               if (err)
-                       goto err12;
-               irqs[1].irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_CD1);
-
-               err = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-               if (err)
-                       goto err12;
+               skt->stat[SOC_STAT_CD].gpio = H3XXX_GPIO_PCMCIA_CD1;
+               skt->stat[SOC_STAT_CD].name = "PCMCIA CD1";
+               skt->stat[SOC_STAT_RDY].gpio = H3XXX_GPIO_PCMCIA_IRQ1;
+               skt->stat[SOC_STAT_RDY].name = "PCMCIA IRQ1";
                break;
        }
        return 0;
@@ -102,19 +68,12 @@ err06:     gpio_free(H3XXX_EGPIO_CARD_RESET);
 err05: gpio_free(H3XXX_EGPIO_OPT_RESET);
 err04: gpio_free(H3XXX_EGPIO_OPT_ON);
 err03: gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON);
-err02: gpio_free(H3XXX_GPIO_PCMCIA_CD0);
 err01: gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
-err00: return err;
-
-err12: gpio_free(H3XXX_GPIO_PCMCIA_CD0);
-err11: gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
-err10: return err;
+       return err;
 }
 
 static void h3600_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
-  
        switch (skt->nr) {
        case 0:
                /* Disable CF bus: */
@@ -126,12 +85,8 @@ static void h3600_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
                gpio_free(H3XXX_EGPIO_OPT_RESET);
                gpio_free(H3XXX_EGPIO_OPT_ON);
                gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON);
-               gpio_free(H3XXX_GPIO_PCMCIA_CD0);
-               gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
                break;
        case 1:
-               gpio_free(H3XXX_GPIO_PCMCIA_CD1);
-               gpio_free(H3XXX_GPIO_PCMCIA_IRQ1);
                break;
        }
 }
@@ -139,27 +94,10 @@ static void h3600_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 static void
 h3600_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-       switch (skt->nr) {
-       case 0:
-               state->detect = !gpio_get_value(H3XXX_GPIO_PCMCIA_CD0);
-               state->ready = !!gpio_get_value(H3XXX_GPIO_PCMCIA_IRQ0);
-               state->bvd1 = 0;
-               state->bvd2 = 0;
-               state->wrprot = 0; /* Not available on H3600. */
-               state->vs_3v = 0;
-               state->vs_Xv = 0;
-               break;
-
-       case 1:
-               state->detect = !gpio_get_value(H3XXX_GPIO_PCMCIA_CD1);
-               state->ready = !!gpio_get_value(H3XXX_GPIO_PCMCIA_IRQ1);
-               state->bvd1 = 0;
-               state->bvd2 = 0;
-               state->wrprot = 0; /* Not available on H3600. */
-               state->vs_3v = 0;
-               state->vs_Xv = 0;
-               break;
-       }
+       state->bvd1 = 0;
+       state->bvd2 = 0;
+       state->vs_3v = 0;
+       state->vs_Xv = 0;
 }
 
 static int
@@ -186,14 +124,10 @@ static void h3600_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
        gpio_set_value(H3XXX_EGPIO_OPT_RESET, 0);
 
        msleep(10);
-
-       soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 }
 
 static void h3600_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
-       soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-
        /*
         * FIXME:  This doesn't fit well.  We don't have the mechanism in
         * the generic PCMCIA layer to deal with the idea of two sockets
diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c
deleted file mode 100644 (file)
index 6bcabee..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * drivers/pcmcia/sa1100_jornada720.c
- *
- * Jornada720 PCMCIA specific routines
- *
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/hardware/sa1111.h>
-#include <asm/mach-types.h>
-
-#include "sa1111_generic.h"
-
-/* Does SOCKET1_3V actually do anything? */
-#define SOCKET0_POWER  GPIO_GPIO0
-#define SOCKET0_3V     GPIO_GPIO2
-#define SOCKET1_POWER  (GPIO_GPIO1 | GPIO_GPIO3)
-#define SOCKET1_3V     GPIO_GPIO3
-
-static int
-jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
-{
-       struct sa1111_pcmcia_socket *s = to_skt(skt);
-       unsigned int pa_dwr_mask, pa_dwr_set;
-       int ret;
-
-       printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
-               skt->nr, state->Vcc, state->Vpp);
-
-       switch (skt->nr) {
-       case 0:
-               pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
-
-               switch (state->Vcc) {
-               default:
-               case  0:
-                       pa_dwr_set = 0;
-                       break;
-               case 33:
-                       pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;
-                       break;
-               case 50:
-                       pa_dwr_set = SOCKET0_POWER;
-                       break;
-               }
-               break;
-
-       case 1:
-               pa_dwr_mask = SOCKET1_POWER;
-
-               switch (state->Vcc) {
-               default:
-               case 0:
-                       pa_dwr_set = 0;
-                       break;
-               case 33:
-                       pa_dwr_set = SOCKET1_POWER;
-                       break;
-               case 50:
-                       pa_dwr_set = SOCKET1_POWER;
-                       break;
-               }
-               break;
-
-       default:
-               return -1;
-       }
-
-       if (state->Vpp != state->Vcc && state->Vpp != 0) {
-               printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
-                       __func__, state->Vpp);
-               return -EPERM;
-       }
-
-       ret = sa1111_pcmcia_configure_socket(skt, state);
-       if (ret == 0) {
-               unsigned long flags;
-
-               local_irq_save(flags);
-               sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
-               local_irq_restore(flags);
-       }
-
-       return ret;
-}
-
-static struct pcmcia_low_level jornada720_pcmcia_ops = {
-       .owner                  = THIS_MODULE,
-       .configure_socket       = jornada720_pcmcia_configure_socket,
-       .socket_init            = sa1111_pcmcia_socket_init,
-       .first                  = 0,
-       .nr                     = 2,
-};
-
-int __devinit pcmcia_jornada720_init(struct device *dev)
-{
-       int ret = -ENODEV;
-
-       if (machine_is_jornada720()) {
-               unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
-
-               GRER |= 0x00000002;
-
-               /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
-               sa1111_set_io_dir(dev, pin, 0, 0);
-               sa1111_set_io(dev, pin, 0);
-               sa1111_set_sleep_io(dev, pin, 0);
-
-               sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
-               ret = sa1111_pcmcia_add(dev, &jornada720_pcmcia_ops,
-                               sa11xx_drv_pcmcia_add_one);
-       }
-
-       return ret;
-}
index 93b9c9b..35c30ff 100644 (file)
@@ -19,6 +19,7 @@
  */
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/init.h>
 
 #include "sa1100_generic.h"
 
-static struct pcmcia_irqs irqs_skt0[] = {
-       /* socket, IRQ, name */
-       { 0, NANOENGINE_IRQ_GPIO_PC_CD0, "PC CD0" },
-};
-
-static struct pcmcia_irqs irqs_skt1[] = {
-       /* socket, IRQ, name */
-       { 1, NANOENGINE_IRQ_GPIO_PC_CD1, "PC CD1" },
-};
-
 struct nanoengine_pins {
-       unsigned input_pins;
        unsigned output_pins;
        unsigned clear_outputs;
-       unsigned transition_pins;
-       unsigned pci_irq;
-       struct pcmcia_irqs *pcmcia_irqs;
-       unsigned pcmcia_irqs_size;
+       int gpio_rst;
+       int gpio_cd;
+       int gpio_rdy;
 };
 
 static struct nanoengine_pins nano_skts[] = {
        {
-               .input_pins             = GPIO_PC_READY0 | GPIO_PC_CD0,
-               .output_pins            = GPIO_PC_RESET0,
-               .clear_outputs          = GPIO_PC_RESET0,
-               .transition_pins        = NANOENGINE_IRQ_GPIO_PC_CD0,
-               .pci_irq                = NANOENGINE_IRQ_GPIO_PC_READY0,
-               .pcmcia_irqs            = irqs_skt0,
-               .pcmcia_irqs_size       = ARRAY_SIZE(irqs_skt0)
+               .gpio_rst               = GPIO_PC_RESET0,
+               .gpio_cd                = GPIO_PC_CD0,
+               .gpio_rdy               = GPIO_PC_READY0,
        }, {
-               .input_pins             = GPIO_PC_READY1 | GPIO_PC_CD1,
-               .output_pins            = GPIO_PC_RESET1,
-               .clear_outputs          = GPIO_PC_RESET1,
-               .transition_pins        = NANOENGINE_IRQ_GPIO_PC_CD1,
-               .pci_irq                = NANOENGINE_IRQ_GPIO_PC_READY1,
-               .pcmcia_irqs            = irqs_skt1,
-               .pcmcia_irqs_size       = ARRAY_SIZE(irqs_skt1)
+               .gpio_rst               = GPIO_PC_RESET1,
+               .gpio_cd                = GPIO_PC_CD1,
+               .gpio_rdy               = GPIO_PC_READY1,
        }
 };
 
@@ -79,58 +60,38 @@ unsigned num_nano_pcmcia_sockets = ARRAY_SIZE(nano_skts);
 static int nanoengine_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        unsigned i = skt->nr;
+       int ret;
 
        if (i >= num_nano_pcmcia_sockets)
                return -ENXIO;
 
-       GPDR &= ~nano_skts[i].input_pins;
-       GPDR |= nano_skts[i].output_pins;
-       GPCR = nano_skts[i].clear_outputs;
-       irq_set_irq_type(nano_skts[i].transition_pins, IRQ_TYPE_EDGE_BOTH);
-       skt->socket.pci_irq = nano_skts[i].pci_irq;
+       ret = gpio_request_one(nano_skts[i].gpio_rst, GPIOF_OUT_INIT_LOW,
+               i ? "PC RST1" : "PC RST0");
+       if (ret)
+               return ret;
+
+       skt->stat[SOC_STAT_CD].gpio = nano_skts[i].gpio_cd;
+       skt->stat[SOC_STAT_CD].name = i ? "PC CD1" : "PC CD0";
+       skt->stat[SOC_STAT_RDY].gpio = nano_skts[i].gpio_rdy;
+       skt->stat[SOC_STAT_RDY].name = i ? "PC RDY1" : "PC RDY0";
 
-       return soc_pcmcia_request_irqs(skt,
-               nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
+       return 0;
 }
 
-/*
- * Release all resources.
- */
 static void nanoengine_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-       unsigned i = skt->nr;
-
-       if (i >= num_nano_pcmcia_sockets)
-               return;
-
-       soc_pcmcia_free_irqs(skt,
-               nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
+       gpio_free(nano_skts[skt->nr].gpio_rst);
 }
 
 static int nanoengine_pcmcia_configure_socket(
        struct soc_pcmcia_socket *skt, const socket_state_t *state)
 {
-       unsigned reset;
        unsigned i = skt->nr;
 
        if (i >= num_nano_pcmcia_sockets)
                return -ENXIO;
 
-       switch (i) {
-       case 0:
-               reset = GPIO_PC_RESET0;
-               break;
-       case 1:
-               reset = GPIO_PC_RESET1;
-               break;
-       default:
-               return -ENXIO;
-       }
-
-       if (state->flags & SS_RESET)
-               GPSR = reset;
-       else
-               GPCR = reset;
+       gpio_set_value(nano_skts[skt->nr].gpio_rst, !!(state->flags & SS_RESET));
 
        return 0;
 }
@@ -138,62 +99,17 @@ static int nanoengine_pcmcia_configure_socket(
 static void nanoengine_pcmcia_socket_state(
        struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
-       unsigned long levels = GPLR;
        unsigned i = skt->nr;
 
        if (i >= num_nano_pcmcia_sockets)
                return;
 
-       memset(state, 0, sizeof(struct pcmcia_state));
-       switch (i) {
-       case 0:
-               state->ready = (levels & GPIO_PC_READY0) ? 1 : 0;
-               state->detect = !(levels & GPIO_PC_CD0) ? 1 : 0;
-               break;
-       case 1:
-               state->ready = (levels & GPIO_PC_READY1) ? 1 : 0;
-               state->detect = !(levels & GPIO_PC_CD1) ? 1 : 0;
-               break;
-       default:
-               return;
-       }
        state->bvd1 = 1;
        state->bvd2 = 1;
-       state->wrprot = 0; /* Not available */
        state->vs_3v = 1; /* Can only apply 3.3V */
        state->vs_Xv = 0;
 }
 
-/*
- * Enable card status IRQs on (re-)initialisation.  This can
- * be called at initialisation, power management event, or
- * pcmcia event.
- */
-static void nanoengine_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-       unsigned i = skt->nr;
-
-       if (i >= num_nano_pcmcia_sockets)
-               return;
-
-       soc_pcmcia_enable_irqs(skt,
-               nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
-}
-
-/*
- * Disable card status IRQs on suspend.
- */
-static void nanoengine_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-       unsigned i = skt->nr;
-
-       if (i >= num_nano_pcmcia_sockets)
-               return;
-
-       soc_pcmcia_disable_irqs(skt,
-               nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
-}
-
 static struct pcmcia_low_level nanoengine_pcmcia_ops = {
        .owner                  = THIS_MODULE,
 
@@ -202,8 +118,6 @@ static struct pcmcia_low_level nanoengine_pcmcia_ops = {
 
        .configure_socket       = nanoengine_pcmcia_configure_socket,
        .socket_state           = nanoengine_pcmcia_socket_state,
-       .socket_init            = nanoengine_pcmcia_socket_init,
-       .socket_suspend         = nanoengine_pcmcia_socket_suspend,
 };
 
 int pcmcia_nanoengine_init(struct device *dev)
diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c
deleted file mode 100644 (file)
index c95639b..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * linux/drivers/pcmcia/sa1100_neponset.c
- *
- * Neponset PCMCIA specific routines
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <mach/neponset.h>
-#include <asm/hardware/sa1111.h>
-
-#include "sa1111_generic.h"
-
-/*
- * Neponset uses the Maxim MAX1600, with the following connections:
- *
- *   MAX1600      Neponset
- *
- *    A0VCC        SA-1111 GPIO A<1>
- *    A1VCC        SA-1111 GPIO A<0>
- *    A0VPP        CPLD NCR A0VPP
- *    A1VPP        CPLD NCR A1VPP
- *    B0VCC        SA-1111 GPIO A<2>
- *    B1VCC        SA-1111 GPIO A<3>
- *    B0VPP        ground (slot B is CF)
- *    B1VPP        ground (slot B is CF)
- *
- *     VX          VCC (5V)
- *     VY          VCC3_3 (3.3V)
- *     12INA       12V
- *     12INB       ground (slot B is CF)
- *
- * The MAX1600 CODE pin is tied to ground, placing the device in 
- * "Standard Intel code" mode. Refer to the Maxim data sheet for
- * the corresponding truth table.
- */
-
-static int
-neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
-{
-       struct sa1111_pcmcia_socket *s = to_skt(skt);
-       unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
-       int ret;
-
-       switch (skt->nr) {
-       case 0:
-               pa_dwr_mask = GPIO_A0 | GPIO_A1;
-               ncr_mask = NCR_A0VPP | NCR_A1VPP;
-
-               if (state->Vpp == 0)
-                       ncr_set = 0;
-               else if (state->Vpp == 120)
-                       ncr_set = NCR_A1VPP;
-               else if (state->Vpp == state->Vcc)
-                       ncr_set = NCR_A0VPP;
-               else {
-                       printk(KERN_ERR "%s(): unrecognized VPP %u\n",
-                              __func__, state->Vpp);
-                       return -1;
-               }
-               break;
-
-       case 1:
-               pa_dwr_mask = GPIO_A2 | GPIO_A3;
-               ncr_mask = 0;
-               ncr_set = 0;
-
-               if (state->Vpp != state->Vcc && state->Vpp != 0) {
-                       printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
-                              __func__, state->Vpp);
-                       return -1;
-               }
-               break;
-
-       default:
-               return -1;
-       }
-
-       /*
-        * pa_dwr_set is the mask for selecting Vcc on both sockets.
-        * pa_dwr_mask selects which bits (and therefore socket) we change.
-        */
-       switch (state->Vcc) {
-       default:
-       case 0:  pa_dwr_set = 0;                break;
-       case 33: pa_dwr_set = GPIO_A1|GPIO_A2;  break;
-       case 50: pa_dwr_set = GPIO_A0|GPIO_A3;  break;
-       }
-
-       ret = sa1111_pcmcia_configure_socket(skt, state);
-       if (ret == 0) {
-               unsigned long flags;
-
-               local_irq_save(flags);
-               NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set;
-
-               local_irq_restore(flags);
-               sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
-       }
-
-       return 0;
-}
-
-static void neponset_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-       if (skt->nr == 0)
-               NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
-
-       sa1111_pcmcia_socket_init(skt);
-}
-
-static struct pcmcia_low_level neponset_pcmcia_ops = {
-       .owner                  = THIS_MODULE,
-       .configure_socket       = neponset_pcmcia_configure_socket,
-       .socket_init            = neponset_pcmcia_socket_init,
-       .first                  = 0,
-       .nr                     = 2,
-};
-
-int pcmcia_neponset_init(struct sa1111_dev *sadev)
-{
-       int ret = -ENODEV;
-
-       if (machine_is_assabet()) {
-               /*
-                * Set GPIO_A<3:0> to be outputs for the MAX1600,
-                * and switch to standby mode.
-                */
-               sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
-               sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-               sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
-               sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops);
-               ret = sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops,
-                               sa11xx_drv_pcmcia_add_one);
-       }
-
-       return ret;
-}
index 7ff1b43..decb347 100644 (file)
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
-static struct pcmcia_irqs irqs[] = {
-       { 0, SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" },
-       { 1, SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" },
-};
-
 static int shannon_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        /* All those are inputs */
-       GPDR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | 
-                 SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
-       GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | 
-                 SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1);
-
-       skt->socket.pci_irq = skt->nr ? SHANNON_IRQ_GPIO_RDY_1 : SHANNON_IRQ_GPIO_RDY_0;
-
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
+       GAFR &= ~(GPIO_GPIO(SHANNON_GPIO_EJECT_0) |
+                 GPIO_GPIO(SHANNON_GPIO_EJECT_1) |
+                 GPIO_GPIO(SHANNON_GPIO_RDY_0) |
+                 GPIO_GPIO(SHANNON_GPIO_RDY_1));
+
+       if (skt->nr == 0) {
+               skt->stat[SOC_STAT_CD].gpio = SHANNON_GPIO_EJECT_0;
+               skt->stat[SOC_STAT_CD].name = "PCMCIA_CD_0";
+               skt->stat[SOC_STAT_RDY].gpio = SHANNON_GPIO_RDY_0;
+               skt->stat[SOC_STAT_RDY].name = "PCMCIA_RDY_0";
+       } else {
+               skt->stat[SOC_STAT_CD].gpio = SHANNON_GPIO_EJECT_1;
+               skt->stat[SOC_STAT_CD].name = "PCMCIA_CD_1";
+               skt->stat[SOC_STAT_RDY].gpio = SHANNON_GPIO_RDY_1;
+               skt->stat[SOC_STAT_RDY].name = "PCMCIA_RDY_1";
+       }
 
-static void shannon_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+       return 0;
 }
 
 static void
 shannon_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                            struct pcmcia_state *state)
 {
-       unsigned long levels = GPLR;
-
        switch (skt->nr) {
        case 0:
-               state->detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1;
-               state->ready  = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0;
-               state->wrprot = 0; /* Not available on Shannon. */
                state->bvd1   = 1; 
                state->bvd2   = 1; 
                state->vs_3v  = 1; /* FIXME Can only apply 3.3V on Shannon. */
@@ -56,9 +51,6 @@ shannon_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                break;
 
        case 1:
-               state->detect = (levels & SHANNON_GPIO_EJECT_1) ? 0 : 1;
-               state->ready  = (levels & SHANNON_GPIO_RDY_1) ? 1 : 0;
-               state->wrprot = 0; /* Not available on Shannon. */
                state->bvd1   = 1; 
                state->bvd2   = 1; 
                state->vs_3v  = 1; /* FIXME Can only apply 3.3V on Shannon. */
@@ -92,25 +84,11 @@ shannon_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void shannon_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void shannon_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 static struct pcmcia_low_level shannon_pcmcia_ops = {
        .owner                  = THIS_MODULE,
        .hw_init                = shannon_pcmcia_hw_init,
-       .hw_shutdown            = shannon_pcmcia_hw_shutdown,
        .socket_state           = shannon_pcmcia_socket_state,
        .configure_socket       = shannon_pcmcia_configure_socket,
-
-       .socket_init            = shannon_pcmcia_socket_init,
-       .socket_suspend         = shannon_pcmcia_socket_suspend,
 };
 
 int __devinit pcmcia_shannon_init(struct device *dev)
index 0fac965..8647b17 100644 (file)
 #include <mach/simpad.h>
 #include "sa1100_generic.h"
  
-static struct pcmcia_irqs irqs[] = {
-       { 1, IRQ_GPIO_CF_CD, "CF_CD" },
-};
-
 static int simpad_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 
        simpad_clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
 
-       skt->socket.pci_irq = IRQ_GPIO_CF_IRQ;
+       skt->stat[SOC_STAT_CD].gpio = GPIO_CF_CD;
+       skt->stat[SOC_STAT_CD].name = "CF_CD";
+       skt->stat[SOC_STAT_RDY].gpio = GPIO_CF_IRQ;
+       skt->stat[SOC_STAT_RDY].name = "CF_RDY";
 
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+       return 0;
 }
 
 static void simpad_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
-
        /* Disable CF bus: */
        /*simpad_set_cs3_bit(PCMCIA_BUFF_DIS);*/
        simpad_clear_cs3_bit(PCMCIA_RESET);
@@ -42,14 +39,13 @@ static void
 simpad_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                           struct pcmcia_state *state)
 {
-       unsigned long levels = GPLR;
        long cs3reg = simpad_get_cs3_ro();
 
-       state->detect=((levels & GPIO_CF_CD)==0)?1:0;
-       state->ready=(levels & GPIO_CF_IRQ)?1:0;
+       /* the detect signal is inverted - fix that up here */
+       state->detect = !state->detect;
+
        state->bvd1 = 1; /* Might be cs3reg & PCMCIA_BVD1 */
        state->bvd2 = 1; /* Might be cs3reg & PCMCIA_BVD2 */
-       state->wrprot=0; /* Not available on Simpad. */
 
        if ((cs3reg & (PCMCIA_VS1|PCMCIA_VS2)) ==
                        (PCMCIA_VS1|PCMCIA_VS2)) {
@@ -99,14 +95,8 @@ simpad_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void simpad_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 static void simpad_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
-       soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
        simpad_set_cs3_bit(PCMCIA_RESET);
 }
 
@@ -116,7 +106,6 @@ static struct pcmcia_low_level simpad_pcmcia_ops = {
        .hw_shutdown            = simpad_pcmcia_hw_shutdown,
        .socket_state           = simpad_pcmcia_socket_state,
        .configure_socket       = simpad_pcmcia_configure_socket,
-       .socket_init            = simpad_pcmcia_socket_init,
        .socket_suspend         = simpad_pcmcia_socket_suspend,
 };
 
diff --git a/drivers/pcmcia/sa1111_badge4.c b/drivers/pcmcia/sa1111_badge4.c
new file mode 100644 (file)
index 0000000..4d206f4
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * linux/drivers/pcmcia/sa1100_badge4.c
+ *
+ * BadgePAD 4 PCMCIA specific routines
+ *
+ *   Christopher Hoover <ch@hpl.hp.com>
+ *
+ * Copyright (C) 2002 Hewlett-Packard Company
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <mach/badge4.h>
+#include <asm/hardware/sa1111.h>
+
+#include "sa1111_generic.h"
+
+/*
+ * BadgePAD 4 Details
+ *
+ * PCM Vcc:
+ *
+ *  PCM Vcc on BadgePAD 4 can be jumpered for 3v3 (short pins 1 and 3
+ *  on JP6) or 5v0 (short pins 3 and 5 on JP6).
+ *
+ * PCM Vpp:
+ *
+ *  PCM Vpp on BadgePAD 4 can be jumpered for 12v0 (short pins 4 and 6
+ *  on JP6) or tied to PCM Vcc (short pins 2 and 4 on JP6).  N.B.,
+ *  12v0 operation requires that the power supply actually supply 12v0
+ *  via pin 7 of JP7.
+ *
+ * CF Vcc:
+ *
+ *  CF Vcc on BadgePAD 4 can be jumpered either for 3v3 (short pins 1
+ *  and 2 on JP10) or 5v0 (short pins 2 and 3 on JP10).
+ *
+ * Unfortunately there's no way programmatically to determine how a
+ * given board is jumpered.  This code assumes a default jumpering
+ * as described below.
+ *
+ * If the defaults aren't correct, you may override them with a pcmv
+ * setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf vcc>.  The units are
+ * tenths of volts; e.g. pcmv=33,120,50 indicates 3v3 PCM Vcc, 12v0
+ * PCM Vpp, and 5v0 CF Vcc.
+ *
+ */
+
+static int badge4_pcmvcc = 50;  /* pins 3 and 5 jumpered on JP6 */
+static int badge4_pcmvpp = 50;  /* pins 2 and 4 jumpered on JP6 */
+static int badge4_cfvcc = 33;   /* pins 1 and 2 jumpered on JP10 */
+
+static void complain_about_jumpering(const char *whom,
+                                    const char *supply,
+                                    int given, int wanted)
+{
+       printk(KERN_ERR
+        "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation"
+        "; re-jumper the board and/or use pcmv=xx,xx,xx\n",
+              whom, supply,
+              wanted / 10, wanted % 10,
+              supply,
+              given / 10, given % 10);
+}
+
+static int
+badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+       int ret;
+
+       switch (skt->nr) {
+       case 0:
+               if ((state->Vcc != 0) &&
+                   (state->Vcc != badge4_pcmvcc)) {
+                       complain_about_jumpering(__func__, "pcmvcc",
+                                                badge4_pcmvcc, state->Vcc);
+                       // Apply power regardless of the jumpering.
+                       // return -1;
+               }
+               if ((state->Vpp != 0) &&
+                   (state->Vpp != badge4_pcmvpp)) {
+                       complain_about_jumpering(__func__, "pcmvpp",
+                                                badge4_pcmvpp, state->Vpp);
+                       return -1;
+               }
+               break;
+
+       case 1:
+               if ((state->Vcc != 0) &&
+                   (state->Vcc != badge4_cfvcc)) {
+                       complain_about_jumpering(__func__, "cfvcc",
+                                                badge4_cfvcc, state->Vcc);
+                       return -1;
+               }
+               break;
+
+       default:
+               return -1;
+       }
+
+       ret = sa1111_pcmcia_configure_socket(skt, state);
+       if (ret == 0) {
+               unsigned long flags;
+               int need5V;
+
+               local_irq_save(flags);
+
+               need5V = ((state->Vcc == 50) || (state->Vpp == 50));
+
+               badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V);
+
+               local_irq_restore(flags);
+       }
+
+       return ret;
+}
+
+static struct pcmcia_low_level badge4_pcmcia_ops = {
+       .owner                  = THIS_MODULE,
+       .configure_socket       = badge4_pcmcia_configure_socket,
+       .first                  = 0,
+       .nr                     = 2,
+};
+
+int pcmcia_badge4_init(struct device *dev)
+{
+       int ret = -ENODEV;
+
+       if (machine_is_badge4()) {
+               printk(KERN_INFO
+                      "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
+                      __func__,
+                      badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
+
+               sa11xx_drv_pcmcia_ops(&badge4_pcmcia_ops);
+               ret = sa1111_pcmcia_add(dev, &badge4_pcmcia_ops,
+                               sa11xx_drv_pcmcia_add_one);
+       }
+
+       return ret;
+}
+
+static int __init pcmv_setup(char *s)
+{
+       int v[4];
+
+       s = get_options(s, ARRAY_SIZE(v), v);
+
+       if (v[0] >= 1) badge4_pcmvcc = v[1];
+       if (v[0] >= 2) badge4_pcmvpp = v[2];
+       if (v[0] >= 3) badge4_cfvcc = v[3];
+
+       return 1;
+}
+
+__setup("pcmv=", pcmv_setup);
index 27f2fe3..70f728c 100644 (file)
 
 #include "sa1111_generic.h"
 
+/*
+ * These are offsets from the above base.
+ */
+#define PCCR   0x0000
+#define PCSSR  0x0004
+#define PCSR   0x0008
+
+#define PCSR_S0_READY  (1<<0)
+#define PCSR_S1_READY  (1<<1)
+#define PCSR_S0_DETECT (1<<2)
+#define PCSR_S1_DETECT (1<<3)
+#define PCSR_S0_VS1    (1<<4)
+#define PCSR_S0_VS2    (1<<5)
+#define PCSR_S1_VS1    (1<<6)
+#define PCSR_S1_VS2    (1<<7)
+#define PCSR_S0_WP     (1<<8)
+#define PCSR_S1_WP     (1<<9)
+#define PCSR_S0_BVD1   (1<<10)
+#define PCSR_S0_BVD2   (1<<11)
+#define PCSR_S1_BVD1   (1<<12)
+#define PCSR_S1_BVD2   (1<<13)
+
+#define PCCR_S0_RST    (1<<0)
+#define PCCR_S1_RST    (1<<1)
+#define PCCR_S0_FLT    (1<<2)
+#define PCCR_S1_FLT    (1<<3)
+#define PCCR_S0_PWAITEN        (1<<4)
+#define PCCR_S1_PWAITEN        (1<<5)
+#define PCCR_S0_PSE    (1<<6)
+#define PCCR_S1_PSE    (1<<7)
+
+#define PCSSR_S0_SLEEP (1<<0)
+#define PCSSR_S1_SLEEP (1<<1)
+
 #define IDX_IRQ_S0_READY_NINT  (0)
 #define IDX_IRQ_S0_CD_VALID    (1)
 #define IDX_IRQ_S0_BVD1_STSCHG (2)
 #define IDX_IRQ_S1_CD_VALID    (4)
 #define IDX_IRQ_S1_BVD1_STSCHG (5)
 
-static struct pcmcia_irqs irqs[] = {
-       { 0, NO_IRQ, "SA1111 PCMCIA card detect" },
-       { 0, NO_IRQ, "SA1111 PCMCIA BVD1"        },
-       { 1, NO_IRQ, "SA1111 CF card detect"     },
-       { 1, NO_IRQ, "SA1111 CF BVD1"            },
-};
-
-static int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
-{
-       return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 {
        struct sa1111_pcmcia_socket *s = to_skt(skt);
-       unsigned long status = sa1111_readl(s->dev->mapbase + SA1111_PCSR);
+       unsigned long status = sa1111_readl(s->dev->mapbase + PCSR);
 
        switch (skt->nr) {
        case 0:
@@ -105,35 +122,22 @@ int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s
                pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT;
 
        local_irq_save(flags);
-       val = sa1111_readl(s->dev->mapbase + SA1111_PCCR);
+       val = sa1111_readl(s->dev->mapbase + PCCR);
        val &= ~pccr_skt_mask;
        val |= pccr_set_mask & pccr_skt_mask;
-       sa1111_writel(val, s->dev->mapbase + SA1111_PCCR);
+       sa1111_writel(val, s->dev->mapbase + PCCR);
        local_irq_restore(flags);
 
        return 0;
 }
 
-void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
-static void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-       soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
-}
-
 int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
        int (*add)(struct soc_pcmcia_socket *))
 {
        struct sa1111_pcmcia_socket *s;
        int i, ret = 0;
 
-       ops->hw_init = sa1111_pcmcia_hw_init;
-       ops->hw_shutdown = sa1111_pcmcia_hw_shutdown;
        ops->socket_state = sa1111_pcmcia_socket_state;
-       ops->socket_suspend = sa1111_pcmcia_socket_suspend;
 
        for (i = 0; i < ops->nr; i++) {
                s = kzalloc(sizeof(*s), GFP_KERNEL);
@@ -141,13 +145,21 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
                        return -ENOMEM;
 
                s->soc.nr = ops->first + i;
-               s->soc.ops = ops;
-               s->soc.socket.owner = ops->owner;
-               s->soc.socket.dev.parent = &dev->dev;
-               s->soc.socket.pci_irq = s->soc.nr ?
-                               dev->irq[IDX_IRQ_S0_READY_NINT] :
-                               dev->irq[IDX_IRQ_S1_READY_NINT];
+               soc_pcmcia_init_one(&s->soc, ops, &dev->dev);
                s->dev = dev;
+               if (s->soc.nr) {
+                       s->soc.socket.pci_irq = dev->irq[IDX_IRQ_S1_READY_NINT];
+                       s->soc.stat[SOC_STAT_CD].irq = dev->irq[IDX_IRQ_S1_CD_VALID];
+                       s->soc.stat[SOC_STAT_CD].name = "SA1111 CF card detect";
+                       s->soc.stat[SOC_STAT_BVD1].irq = dev->irq[IDX_IRQ_S1_BVD1_STSCHG];
+                       s->soc.stat[SOC_STAT_BVD1].name = "SA1111 CF BVD1";
+               } else {
+                       s->soc.socket.pci_irq = dev->irq[IDX_IRQ_S0_READY_NINT];
+                       s->soc.stat[SOC_STAT_CD].irq = dev->irq[IDX_IRQ_S0_CD_VALID];
+                       s->soc.stat[SOC_STAT_CD].name = "SA1111 PCMCIA card detect";
+                       s->soc.stat[SOC_STAT_BVD1].irq = dev->irq[IDX_IRQ_S0_BVD1_STSCHG];
+                       s->soc.stat[SOC_STAT_BVD1].name = "SA1111 PCMCIA BVD1";
+               }
 
                ret = add(&s->soc);
                if (ret == 0) {
@@ -163,26 +175,26 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
 static int pcmcia_probe(struct sa1111_dev *dev)
 {
        void __iomem *base;
+       int ret;
+
+       ret = sa1111_enable_device(dev);
+       if (ret)
+               return ret;
 
        dev_set_drvdata(&dev->dev, NULL);
 
-       if (!request_mem_region(dev->res.start, 512,
-                               SA1111_DRIVER_NAME(dev)))
+       if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) {
+               sa1111_disable_device(dev);
                return -EBUSY;
+       }
 
        base = dev->mapbase;
 
-       /* Initialize PCMCIA IRQs */
-       irqs[0].irq = dev->irq[IDX_IRQ_S0_CD_VALID];
-       irqs[1].irq = dev->irq[IDX_IRQ_S0_BVD1_STSCHG];
-       irqs[2].irq = dev->irq[IDX_IRQ_S1_CD_VALID];
-       irqs[3].irq = dev->irq[IDX_IRQ_S1_BVD1_STSCHG];
-
        /*
         * Initialise the suspend state.
         */
-       sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR);
-       sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR);
+       sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + PCSSR);
+       sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + PCCR);
 
 #ifdef CONFIG_SA1100_BADGE4
        pcmcia_badge4_init(&dev->dev);
@@ -212,6 +224,7 @@ static int __devexit pcmcia_remove(struct sa1111_dev *dev)
        }
 
        release_mem_region(dev->res.start, 512);
+       sa1111_disable_device(dev);
        return 0;
 }
 
index 02dc857..f6376e3 100644 (file)
@@ -17,7 +17,6 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
 
 extern void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *, struct pcmcia_state *);
 extern int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *, const socket_state_t *);
-extern void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *);
 
 extern int pcmcia_badge4_init(struct device *);
 extern int pcmcia_jornada720_init(struct device *);
diff --git a/drivers/pcmcia/sa1111_jornada720.c b/drivers/pcmcia/sa1111_jornada720.c
new file mode 100644 (file)
index 0000000..69428d1
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * drivers/pcmcia/sa1100_jornada720.c
+ *
+ * Jornada720 PCMCIA specific routines
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/mach-types.h>
+
+#include "sa1111_generic.h"
+
+/* Does SOCKET1_3V actually do anything? */
+#define SOCKET0_POWER  GPIO_GPIO0
+#define SOCKET0_3V     GPIO_GPIO2
+#define SOCKET1_POWER  (GPIO_GPIO1 | GPIO_GPIO3)
+#define SOCKET1_3V     GPIO_GPIO3
+
+static int
+jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+       struct sa1111_pcmcia_socket *s = to_skt(skt);
+       unsigned int pa_dwr_mask, pa_dwr_set;
+       int ret;
+
+       printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
+               skt->nr, state->Vcc, state->Vpp);
+
+       switch (skt->nr) {
+       case 0:
+               pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
+
+               switch (state->Vcc) {
+               default:
+               case  0:
+                       pa_dwr_set = 0;
+                       break;
+               case 33:
+                       pa_dwr_set = SOCKET0_POWER | SOCKET0_3V;
+                       break;
+               case 50:
+                       pa_dwr_set = SOCKET0_POWER;
+                       break;
+               }
+               break;
+
+       case 1:
+               pa_dwr_mask = SOCKET1_POWER;
+
+               switch (state->Vcc) {
+               default:
+               case 0:
+                       pa_dwr_set = 0;
+                       break;
+               case 33:
+                       pa_dwr_set = SOCKET1_POWER;
+                       break;
+               case 50:
+                       pa_dwr_set = SOCKET1_POWER;
+                       break;
+               }
+               break;
+
+       default:
+               return -1;
+       }
+
+       if (state->Vpp != state->Vcc && state->Vpp != 0) {
+               printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
+                       __func__, state->Vpp);
+               return -EPERM;
+       }
+
+       ret = sa1111_pcmcia_configure_socket(skt, state);
+       if (ret == 0)
+               sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
+
+       return ret;
+}
+
+static struct pcmcia_low_level jornada720_pcmcia_ops = {
+       .owner                  = THIS_MODULE,
+       .configure_socket       = jornada720_pcmcia_configure_socket,
+       .first                  = 0,
+       .nr                     = 2,
+};
+
+int __devinit pcmcia_jornada720_init(struct device *dev)
+{
+       int ret = -ENODEV;
+
+       if (machine_is_jornada720()) {
+               unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
+
+               GRER |= 0x00000002;
+
+               /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
+               sa1111_set_io_dir(dev, pin, 0, 0);
+               sa1111_set_io(dev, pin, 0);
+               sa1111_set_sleep_io(dev, pin, 0);
+
+               sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
+               ret = sa1111_pcmcia_add(dev, &jornada720_pcmcia_ops,
+                               sa11xx_drv_pcmcia_add_one);
+       }
+
+       return ret;
+}
diff --git a/drivers/pcmcia/sa1111_lubbock.c b/drivers/pcmcia/sa1111_lubbock.c
new file mode 100644 (file)
index 0000000..c5caf57
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_lubbock.c
+ *
+ * Author:     George Davis
+ * Created:    Jan 10, 2002
+ * Copyright:  MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c
+ *
+ * Lubbock PCMCIA specific routines.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/mach-types.h>
+#include <mach/lubbock.h>
+
+#include "sa1111_generic.h"
+
+static int
+lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+                               const socket_state_t *state)
+{
+       struct sa1111_pcmcia_socket *s = to_skt(skt);
+       unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set;
+       int ret = 0;
+
+       pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0;
+
+       /* Lubbock uses the Maxim MAX1602, with the following connections:
+        *
+        * Socket 0 (PCMCIA):
+        *      MAX1602 Lubbock         Register
+        *      Pin     Signal
+        *      -----   -------         ----------------------
+        *      A0VPP   S0_PWR0         SA-1111 GPIO A<0>
+        *      A1VPP   S0_PWR1         SA-1111 GPIO A<1>
+        *      A0VCC   S0_PWR2         SA-1111 GPIO A<2>
+        *      A1VCC   S0_PWR3         SA-1111 GPIO A<3>
+        *      VX      VCC
+        *      VY      +3.3V
+        *      12IN    +12V
+        *      CODE    +3.3V           Cirrus  Code, CODE = High (VY)
+        *
+        * Socket 1 (CF):
+        *      MAX1602 Lubbock         Register
+        *      Pin     Signal
+        *      -----   -------         ----------------------
+        *      A0VPP   GND             VPP is not connected
+        *      A1VPP   GND             VPP is not connected
+        *      A0VCC   S1_PWR0         MISC_WR<14>
+        *      A1VCC   S1_PWR1         MISC_WR<15>
+        *      VX      VCC
+        *      VY      +3.3V
+        *      12IN    GND             VPP is not connected
+        *      CODE    +3.3V           Cirrus  Code, CODE = High (VY)
+        *
+        */
+
+ again:
+       switch (skt->nr) {
+       case 0:
+               pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3;
+
+               switch (state->Vcc) {
+               case 0: /* Hi-Z */
+                       break;
+
+               case 33: /* VY */
+                       pa_dwr_set |= GPIO_A3;
+                       break;
+
+               case 50: /* VX */
+                       pa_dwr_set |= GPIO_A2;
+                       break;
+
+               default:
+                       printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+                              __func__, state->Vcc);
+                       ret = -1;
+               }
+
+               switch (state->Vpp) {
+               case 0: /* Hi-Z */
+                       break;
+
+               case 120: /* 12IN */
+                       pa_dwr_set |= GPIO_A1;
+                       break;
+
+               default: /* VCC */
+                       if (state->Vpp == state->Vcc)
+                               pa_dwr_set |= GPIO_A0;
+                       else {
+                               printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
+                                      __func__, state->Vpp);
+                               ret = -1;
+                               break;
+                       }
+               }
+               break;
+
+       case 1:
+               misc_mask = (1 << 15) | (1 << 14);
+
+               switch (state->Vcc) {
+               case 0: /* Hi-Z */
+                       break;
+
+               case 33: /* VY */
+                       misc_set |= 1 << 15;
+                       break;
+
+               case 50: /* VX */
+                       misc_set |= 1 << 14;
+                       break;
+
+               default:
+                       printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
+                              __func__, state->Vcc);
+                       ret = -1;
+                       break;
+               }
+
+               if (state->Vpp != state->Vcc && state->Vpp != 0) {
+                       printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
+                              __func__, state->Vpp);
+                       ret = -1;
+                       break;
+               }
+               break;
+
+       default:
+               ret = -1;
+       }
+
+       if (ret == 0)
+               ret = sa1111_pcmcia_configure_socket(skt, state);
+
+       if (ret == 0) {
+               lubbock_set_misc_wr(misc_mask, misc_set);
+               sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
+       }
+
+#if 1
+       if (ret == 0 && state->Vcc == 33) {
+               struct pcmcia_state new_state;
+
+               /*
+                * HACK ALERT:
+                * We can't sense the voltage properly on Lubbock before
+                * actually applying some power to the socket (catch 22).
+                * Resense the socket Voltage Sense pins after applying
+                * socket power.
+                *
+                * Note: It takes about 2.5ms for the MAX1602 VCC output
+                * to rise.
+                */
+               mdelay(3);
+
+               sa1111_pcmcia_socket_state(skt, &new_state);
+
+               if (!new_state.vs_3v && !new_state.vs_Xv) {
+                       /*
+                        * Switch to 5V,  Configure socket with 5V voltage
+                        */
+                       lubbock_set_misc_wr(misc_mask, 0);
+                       sa1111_set_io(s->dev, pa_dwr_mask, 0);
+
+                       /*
+                        * It takes about 100ms to turn off Vcc.
+                        */
+                       mdelay(100);
+
+                       /*
+                        * We need to hack around the const qualifier as
+                        * well to keep this ugly workaround localized and
+                        * not force it to the rest of the code. Barf bags
+                        * available in the seat pocket in front of you!
+                        */
+                       ((socket_state_t *)state)->Vcc = 50;
+                       ((socket_state_t *)state)->Vpp = 50;
+                       goto again;
+               }
+       }
+#endif
+
+       return ret;
+}
+
+static struct pcmcia_low_level lubbock_pcmcia_ops = {
+       .owner                  = THIS_MODULE,
+       .configure_socket       = lubbock_pcmcia_configure_socket,
+       .first                  = 0,
+       .nr                     = 2,
+};
+
+#include "pxa2xx_base.h"
+
+int pcmcia_lubbock_init(struct sa1111_dev *sadev)
+{
+       int ret = -ENODEV;
+
+       if (machine_is_lubbock()) {
+               /*
+                * Set GPIO_A<3:0> to be outputs for the MAX1600,
+                * and switch to standby mode.
+                */
+               sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
+               sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+               sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+
+               /* Set CF Socket 1 power to standby mode. */
+               lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
+
+               pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
+               pxa2xx_configure_sockets(&sadev->dev);
+               ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
+                               pxa2xx_drv_pcmcia_add_one);
+       }
+
+       return ret;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/sa1111_neponset.c b/drivers/pcmcia/sa1111_neponset.c
new file mode 100644 (file)
index 0000000..1d78739
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * linux/drivers/pcmcia/sa1100_neponset.c
+ *
+ * Neponset PCMCIA specific routines
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <mach/neponset.h>
+#include <asm/hardware/sa1111.h>
+
+#include "sa1111_generic.h"
+
+/*
+ * Neponset uses the Maxim MAX1600, with the following connections:
+ *
+ *   MAX1600      Neponset
+ *
+ *    A0VCC        SA-1111 GPIO A<1>
+ *    A1VCC        SA-1111 GPIO A<0>
+ *    A0VPP        CPLD NCR A0VPP
+ *    A1VPP        CPLD NCR A1VPP
+ *    B0VCC        SA-1111 GPIO A<2>
+ *    B1VCC        SA-1111 GPIO A<3>
+ *    B0VPP        ground (slot B is CF)
+ *    B1VPP        ground (slot B is CF)
+ *
+ *     VX          VCC (5V)
+ *     VY          VCC3_3 (3.3V)
+ *     12INA       12V
+ *     12INB       ground (slot B is CF)
+ *
+ * The MAX1600 CODE pin is tied to ground, placing the device in 
+ * "Standard Intel code" mode. Refer to the Maxim data sheet for
+ * the corresponding truth table.
+ */
+
+static int
+neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
+{
+       struct sa1111_pcmcia_socket *s = to_skt(skt);
+       unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set;
+       int ret;
+
+       switch (skt->nr) {
+       case 0:
+               pa_dwr_mask = GPIO_A0 | GPIO_A1;
+               ncr_mask = NCR_A0VPP | NCR_A1VPP;
+
+               if (state->Vpp == 0)
+                       ncr_set = 0;
+               else if (state->Vpp == 120)
+                       ncr_set = NCR_A1VPP;
+               else if (state->Vpp == state->Vcc)
+                       ncr_set = NCR_A0VPP;
+               else {
+                       printk(KERN_ERR "%s(): unrecognized VPP %u\n",
+                              __func__, state->Vpp);
+                       return -1;
+               }
+               break;
+
+       case 1:
+               pa_dwr_mask = GPIO_A2 | GPIO_A3;
+               ncr_mask = 0;
+               ncr_set = 0;
+
+               if (state->Vpp != state->Vcc && state->Vpp != 0) {
+                       printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
+                              __func__, state->Vpp);
+                       return -1;
+               }
+               break;
+
+       default:
+               return -1;
+       }
+
+       /*
+        * pa_dwr_set is the mask for selecting Vcc on both sockets.
+        * pa_dwr_mask selects which bits (and therefore socket) we change.
+        */
+       switch (state->Vcc) {
+       default:
+       case 0:  pa_dwr_set = 0;                break;
+       case 33: pa_dwr_set = GPIO_A1|GPIO_A2;  break;
+       case 50: pa_dwr_set = GPIO_A0|GPIO_A3;  break;
+       }
+
+       ret = sa1111_pcmcia_configure_socket(skt, state);
+       if (ret == 0) {
+               neponset_ncr_frob(ncr_mask, ncr_set);
+               sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set);
+       }
+
+       return ret;
+}
+
+static struct pcmcia_low_level neponset_pcmcia_ops = {
+       .owner                  = THIS_MODULE,
+       .configure_socket       = neponset_pcmcia_configure_socket,
+       .first                  = 0,
+       .nr                     = 2,
+};
+
+int pcmcia_neponset_init(struct sa1111_dev *sadev)
+{
+       int ret = -ENODEV;
+
+       if (machine_is_assabet()) {
+               /*
+                * Set GPIO_A<3:0> to be outputs for the MAX1600,
+                * and switch to standby mode.
+                */
+               sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0);
+               sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+               sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0);
+               sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops);
+               ret = sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops,
+                               sa11xx_drv_pcmcia_add_one);
+       }
+
+       return ret;
+}
index 79ecc23..6eecd7c 100644 (file)
@@ -235,10 +235,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
                skt = &sinfo->skt[i];
 
                skt->nr = first + i;
-               skt->ops = ops;
-               skt->socket.owner = ops->owner;
-               skt->socket.dev.parent = dev;
-               skt->socket.pci_irq = NO_IRQ;
+               soc_pcmcia_init_one(skt, ops, dev);
 
                ret = sa11xx_drv_pcmcia_add_one(skt);
                if (ret)
index 5d22c6a..a2bc6ee 100644 (file)
@@ -32,6 +32,7 @@
 
 
 #include <linux/cpufreq.h>
+#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -48,6 +49,8 @@
 
 #include "soc_common.h"
 
+static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev);
+
 #ifdef CONFIG_PCMCIA_DEBUG
 
 static int pc_debug;
@@ -103,6 +106,93 @@ void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt,
 }
 EXPORT_SYMBOL(soc_common_pcmcia_get_timing);
 
+static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt,
+       unsigned int nr)
+{
+       unsigned int i;
+
+       for (i = 0; i < nr; i++) {
+               if (skt->stat[i].irq)
+                       free_irq(skt->stat[i].irq, skt);
+               if (gpio_is_valid(skt->stat[i].gpio))
+                       gpio_free(skt->stat[i].gpio);
+       }
+
+       if (skt->ops->hw_shutdown)
+               skt->ops->hw_shutdown(skt);
+}
+
+static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+       __soc_pcmcia_hw_shutdown(skt, ARRAY_SIZE(skt->stat));
+}
+
+static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+       int ret = 0, i;
+
+       if (skt->ops->hw_init) {
+               ret = skt->ops->hw_init(skt);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
+               if (gpio_is_valid(skt->stat[i].gpio)) {
+                       int irq;
+
+                       ret = gpio_request_one(skt->stat[i].gpio, GPIOF_IN,
+                                              skt->stat[i].name);
+                       if (ret) {
+                               __soc_pcmcia_hw_shutdown(skt, i);
+                               return ret;
+                       }
+
+                       irq = gpio_to_irq(skt->stat[i].gpio);
+
+                       if (i == SOC_STAT_RDY)
+                               skt->socket.pci_irq = irq;
+                       else
+                               skt->stat[i].irq = irq;
+               }
+
+               if (skt->stat[i].irq) {
+                       ret = request_irq(skt->stat[i].irq,
+                                         soc_common_pcmcia_interrupt,
+                                         IRQF_TRIGGER_NONE,
+                                         skt->stat[i].name, skt);
+                       if (ret) {
+                               if (gpio_is_valid(skt->stat[i].gpio))
+                                       gpio_free(skt->stat[i].gpio);
+                               __soc_pcmcia_hw_shutdown(skt, i);
+                               return ret;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static void soc_pcmcia_hw_enable(struct soc_pcmcia_socket *skt)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
+               if (skt->stat[i].irq) {
+                       irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_RISING);
+                       irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_BOTH);
+               }
+}
+
+static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
+               if (skt->stat[i].irq)
+                       irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE);
+}
+
 static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
 {
        struct pcmcia_state state;
@@ -110,6 +200,22 @@ static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
 
        memset(&state, 0, sizeof(struct pcmcia_state));
 
+       /* Make battery voltage state report 'good' */
+       state.bvd1 = 1;
+       state.bvd2 = 1;
+
+       /* CD is active low by default */
+       if (gpio_is_valid(skt->stat[SOC_STAT_CD].gpio))
+               state.detect = !gpio_get_value(skt->stat[SOC_STAT_CD].gpio);
+
+       /* RDY and BVD are active high by default */
+       if (gpio_is_valid(skt->stat[SOC_STAT_RDY].gpio))
+               state.ready = !!gpio_get_value(skt->stat[SOC_STAT_RDY].gpio);
+       if (gpio_is_valid(skt->stat[SOC_STAT_BVD1].gpio))
+               state.bvd1 = !!gpio_get_value(skt->stat[SOC_STAT_BVD1].gpio);
+       if (gpio_is_valid(skt->stat[SOC_STAT_BVD2].gpio))
+               state.bvd2 = !!gpio_get_value(skt->stat[SOC_STAT_BVD2].gpio);
+
        skt->ops->socket_state(skt, &state);
 
        stat = state.detect  ? SS_DETECT : 0;
@@ -187,6 +293,7 @@ static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
        debug(skt, 2, "initializing socket\n");
        if (skt->ops->socket_init)
                skt->ops->socket_init(skt);
+       soc_pcmcia_hw_enable(skt);
        return 0;
 }
 
@@ -206,6 +313,7 @@ static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
 
        debug(skt, 2, "suspending socket\n");
 
+       soc_pcmcia_hw_disable(skt);
        if (skt->ops->socket_suspend)
                skt->ops->socket_suspend(skt);
 
@@ -525,69 +633,6 @@ static struct pccard_operations soc_common_pcmcia_operations = {
 };
 
 
-int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt,
-                           struct pcmcia_irqs *irqs, int nr)
-{
-       int i, res = 0;
-
-       for (i = 0; i < nr; i++) {
-               if (irqs[i].sock != skt->nr)
-                       continue;
-               res = request_irq(irqs[i].irq, soc_common_pcmcia_interrupt,
-                                 IRQF_DISABLED, irqs[i].str, skt);
-               if (res)
-                       break;
-               irq_set_irq_type(irqs[i].irq, IRQ_TYPE_NONE);
-       }
-
-       if (res) {
-               printk(KERN_ERR "PCMCIA: request for IRQ%d failed (%d)\n",
-                       irqs[i].irq, res);
-
-               while (i--)
-                       if (irqs[i].sock == skt->nr)
-                               free_irq(irqs[i].irq, skt);
-       }
-       return res;
-}
-EXPORT_SYMBOL(soc_pcmcia_request_irqs);
-
-void soc_pcmcia_free_irqs(struct soc_pcmcia_socket *skt,
-                         struct pcmcia_irqs *irqs, int nr)
-{
-       int i;
-
-       for (i = 0; i < nr; i++)
-               if (irqs[i].sock == skt->nr)
-                       free_irq(irqs[i].irq, skt);
-}
-EXPORT_SYMBOL(soc_pcmcia_free_irqs);
-
-void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt,
-                            struct pcmcia_irqs *irqs, int nr)
-{
-       int i;
-
-       for (i = 0; i < nr; i++)
-               if (irqs[i].sock == skt->nr)
-                       irq_set_irq_type(irqs[i].irq, IRQ_TYPE_NONE);
-}
-EXPORT_SYMBOL(soc_pcmcia_disable_irqs);
-
-void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt,
-                           struct pcmcia_irqs *irqs, int nr)
-{
-       int i;
-
-       for (i = 0; i < nr; i++)
-               if (irqs[i].sock == skt->nr) {
-                       irq_set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_RISING);
-                       irq_set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_BOTH);
-               }
-}
-EXPORT_SYMBOL(soc_pcmcia_enable_irqs);
-
-
 static LIST_HEAD(soc_pcmcia_sockets);
 static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
 
@@ -634,6 +679,21 @@ module_exit(soc_pcmcia_cpufreq_unregister);
 
 #endif
 
+void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
+       struct pcmcia_low_level *ops, struct device *dev)
+{
+       int i;
+
+       skt->ops = ops;
+       skt->socket.owner = ops->owner;
+       skt->socket.dev.parent = dev;
+       skt->socket.pci_irq = NO_IRQ;
+
+       for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
+               skt->stat[i].gpio = -EINVAL;
+}
+EXPORT_SYMBOL(soc_pcmcia_init_one);
+
 void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
 {
        mutex_lock(&soc_pcmcia_sockets_lock);
@@ -641,8 +701,9 @@ void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
 
        pcmcia_unregister_socket(&skt->socket);
 
-       skt->ops->hw_shutdown(skt);
+       soc_pcmcia_hw_shutdown(skt);
 
+       /* should not be required; violates some lowlevel drivers */
        soc_common_pcmcia_config_skt(skt, &dead_socket);
 
        list_del(&skt->node);
@@ -699,7 +760,7 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
         */
        skt->ops->set_timing(skt);
 
-       ret = skt->ops->hw_init(skt);
+       ret = soc_pcmcia_hw_init(skt);
        if (ret)
                goto out_err_6;
 
@@ -732,7 +793,7 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
        pcmcia_unregister_socket(&skt->socket);
 
  out_err_7:
-       skt->ops->hw_shutdown(skt);
+       soc_pcmcia_hw_shutdown(skt);
  out_err_6:
        list_del(&skt->node);
        mutex_unlock(&soc_pcmcia_sockets_lock);
index 9daa736..e6fcbea 100644 (file)
@@ -50,6 +50,16 @@ struct soc_pcmcia_socket {
        struct resource         res_attr;
        void __iomem            *virt_io;
 
+       struct {
+               int             gpio;
+               unsigned int    irq;
+               const char      *name;
+       } stat[4];
+#define SOC_STAT_CD            0       /* Card detect */
+#define SOC_STAT_BVD1          1       /* BATDEAD / IOSTSCHG */
+#define SOC_STAT_BVD2          2       /* BATWARN / IOSPKR */
+#define SOC_STAT_RDY           3       /* Ready / Interrupt */
+
        unsigned int            irq_state;
 
        struct timer_list       poll_timer;
@@ -115,25 +125,16 @@ struct pcmcia_low_level {
 };
 
 
-struct pcmcia_irqs {
-       int sock;
-       int irq;
-       const char *str;
-};
-
 struct soc_pcmcia_timing {
        unsigned short io;
        unsigned short mem;
        unsigned short attr;
 };
 
-extern int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
-extern void soc_pcmcia_free_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
-extern void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
-extern void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
 extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *);
 
-
+void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
+       struct pcmcia_low_level *ops, struct device *dev);
 void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt);
 int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt);
 
index 2dc02c9..2a262f5 100644 (file)
@@ -26,6 +26,10 @@ config ACER_WMI
        depends on RFKILL || RFKILL = n
        depends on ACPI_WMI
        select INPUT_SPARSEKMAP
+       # Acer WMI depends on ACPI_VIDEO when ACPI is enabled
+       # but for select to work, need to select ACPI_VIDEO's dependencies, ick
+        select VIDEO_OUTPUT_CONTROL if ACPI
+        select ACPI_VIDEO if ACPI
        ---help---
          This is a driver for newer Acer (and Wistron) laptops. It adds
          wireless radio and bluetooth control, and on some laptops,
@@ -54,7 +58,6 @@ config ACERHDF
 config ASUS_LAPTOP
        tristate "Asus Laptop Extras"
        depends on ACPI
-       depends on !ACPI_ASUS
        select LEDS_CLASS
        select NEW_LEDS
        select BACKLIGHT_CLASS_DEVICE
@@ -460,10 +463,9 @@ config INTEL_MENLOW
          If unsure, say N.
 
 config EEEPC_LAPTOP
-       tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
+       tristate "Eee PC Hotkey Driver"
        depends on ACPI
        depends on INPUT
-       depends on EXPERIMENTAL
        depends on RFKILL || RFKILL = n
        depends on HOTPLUG_PCI
        select BACKLIGHT_CLASS_DEVICE
@@ -482,11 +484,10 @@ config EEEPC_LAPTOP
          doesn't work on your Eee PC, try eeepc-wmi instead.
 
 config ASUS_WMI
-       tristate "ASUS WMI Driver (EXPERIMENTAL)"
+       tristate "ASUS WMI Driver"
        depends on ACPI_WMI
        depends on INPUT
        depends on HWMON
-       depends on EXPERIMENTAL
        depends on BACKLIGHT_CLASS_DEVICE
        depends on RFKILL || RFKILL = n
        depends on HOTPLUG_PCI
@@ -501,7 +502,7 @@ config ASUS_WMI
          be called asus-wmi.
 
 config ASUS_NB_WMI
-       tristate "Asus Notebook WMI Driver (EXPERIMENTAL)"
+       tristate "Asus Notebook WMI Driver"
        depends on ASUS_WMI
        ---help---
          This is a driver for newer Asus notebooks. It adds extra features
@@ -514,7 +515,7 @@ config ASUS_NB_WMI
          here.
 
 config EEEPC_WMI
-       tristate "Eee PC WMI Driver (EXPERIMENTAL)"
+       tristate "Eee PC WMI Driver"
        depends on ASUS_WMI
        ---help---
          This is a driver for newer Eee PC laptops. It adds extra features
@@ -559,38 +560,6 @@ config MSI_WMI
         To compile this driver as a module, choose M here: the module will
         be called msi-wmi.
 
-config ACPI_ASUS
-       tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
-       depends on ACPI
-       select BACKLIGHT_CLASS_DEVICE
-       ---help---
-         This driver provides support for extra features of ACPI-compatible
-         ASUS laptops. As some of Medion laptops are made by ASUS, it may also
-         support some Medion laptops (such as 9675 for example).  It makes all
-         the extra buttons generate standard ACPI events that go through
-         /proc/acpi/events, and (on some models) adds support for changing the
-         display brightness and output, switching the LCD backlight on and off,
-         and most importantly, allows you to blink those fancy LEDs intended
-         for reporting mail and wireless status.
-
-         Note: display switching code is currently considered EXPERIMENTAL,
-         toying with these values may even lock your machine.
-
-         All settings are changed via /proc/acpi/asus directory entries. Owner
-         and group for these entries can be set with asus_uid and asus_gid
-         parameters.
-
-         More information and a userspace daemon for handling the extra buttons
-         at <http://acpi4asus.sf.net>.
-
-         If you have an ACPI-compatible ASUS laptop, say Y or M here. This
-         driver is still under development, so if your laptop is unsupported or
-         something works not quite as expected, please use the mailing list
-         available on the above page (acpi4asus-user@lists.sourceforge.net).
-
-         NOTE: This driver is deprecated and will probably be removed soon,
-         use asus-laptop instead.
-
 config TOPSTAR_LAPTOP
        tristate "Topstar Laptop Extras"
        depends on ACPI
@@ -604,6 +573,7 @@ config TOPSTAR_LAPTOP
 config ACPI_TOSHIBA
        tristate "Toshiba Laptop Extras"
        depends on ACPI
+       depends on ACPI_WMI
        select LEDS_CLASS
        select NEW_LEDS
        depends on BACKLIGHT_CLASS_DEVICE
@@ -746,13 +716,18 @@ config XO15_EBOOK
 
 config SAMSUNG_LAPTOP
        tristate "Samsung Laptop driver"
-       depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
+       depends on X86
+       depends on RFKILL || RFKILL = n
+       depends on BACKLIGHT_CLASS_DEVICE
+       select LEDS_CLASS
+       select NEW_LEDS
        ---help---
          This module implements a driver for a wide range of different
          Samsung laptops.  It offers control over the different
-         function keys, wireless LED, LCD backlight level, and
-         sometimes provides a "performance_control" sysfs file to allow
-         the performance level of the laptop to be changed.
+         function keys, wireless LED, LCD backlight level.
+
+         It may also provide some sysfs files described in
+         <file:Documentation/ABI/testing/sysfs-platform-samsung-laptop>
 
          To compile this driver as a module, choose M here: the module
          will be called samsung-laptop.
@@ -781,4 +756,14 @@ config SAMSUNG_Q10
          This driver provides support for backlight control on Samsung Q10
          and related laptops, including Dell Latitude X200.
 
+config APPLE_GMUX
+       tristate "Apple Gmux Driver"
+       depends on PNP
+       select BACKLIGHT_CLASS_DEVICE
+       ---help---
+         This driver provides support for the gmux device found on many
+         Apple laptops, which controls the display mux for the hybrid
+         graphics as well as the backlight. Currently only backlight
+         control is supported by the driver.
+
 endif # X86_PLATFORM_DEVICES
index bb94765..bf7e4f9 100644 (file)
@@ -29,9 +29,12 @@ obj-$(CONFIG_PANASONIC_LAPTOP)       += panasonic-laptop.o
 obj-$(CONFIG_INTEL_MENLOW)     += intel_menlow.o
 obj-$(CONFIG_ACPI_WMI)         += wmi.o
 obj-$(CONFIG_MSI_WMI)          += msi-wmi.o
-obj-$(CONFIG_ACPI_ASUS)                += asus_acpi.o
 obj-$(CONFIG_TOPSTAR_LAPTOP)   += topstar-laptop.o
+
+# toshiba_acpi must link after wmi to ensure that wmi devices are found
+# before toshiba_acpi initializes
 obj-$(CONFIG_ACPI_TOSHIBA)     += toshiba_acpi.o
+
 obj-$(CONFIG_TOSHIBA_BT_RFKILL)        += toshiba_bluetooth.o
 obj-$(CONFIG_INTEL_SCU_IPC)    += intel_scu_ipc.o
 obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
@@ -46,3 +49,4 @@ obj-$(CONFIG_MXM_WMI)         += mxm-wmi.o
 obj-$(CONFIG_INTEL_MID_POWER_BUTTON)   += intel_mid_powerbtn.o
 obj-$(CONFIG_INTEL_OAKTRAIL)   += intel_oaktrail.o
 obj-$(CONFIG_SAMSUNG_Q10)      += samsung-q10.o
+obj-$(CONFIG_APPLE_GMUX)       += apple-gmux.o
index 1e5290b..c1a3fd8 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/input/sparse-keymap.h>
 
 #include <acpi/acpi_drivers.h>
+#include <acpi/video.h>
 
 MODULE_AUTHOR("Carlos Corbacho");
 MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
@@ -105,13 +106,19 @@ static const struct key_entry acer_wmi_keymap[] = {
        {KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */
        {KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
        {KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
+       {KE_KEY, 0x29, {KEY_PROG3} },    /* P_Key for TM8372 */
        {KE_IGNORE, 0x41, {KEY_MUTE} },
        {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
+       {KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
        {KE_IGNORE, 0x43, {KEY_NEXTSONG} },
+       {KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
        {KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
+       {KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
        {KE_IGNORE, 0x45, {KEY_STOP} },
+       {KE_IGNORE, 0x50, {KEY_STOP} },
        {KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
        {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
+       {KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
        {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
        {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
        {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
@@ -153,7 +160,14 @@ struct lm_return_value {
        u16 reserved;
 } __attribute__((packed));
 
-struct wmid3_gds_input_param { /* Get Device Status input parameter */
+struct wmid3_gds_set_input_param {     /* Set Device Status input parameter */
+       u8 function_num;        /* Function Number */
+       u8 hotkey_number;       /* Hotkey Number */
+       u16 devices;            /* Set Device */
+       u8 volume_value;        /* Volume Value */
+} __attribute__((packed));
+
+struct wmid3_gds_get_input_param {     /* Get Device Status input parameter */
        u8 function_num;        /* Function Number */
        u8 hotkey_number;       /* Hotkey Number */
        u16 devices;            /* Get Device */
@@ -171,6 +185,11 @@ struct hotkey_function_type_aa {
        u8 length;
        u16 handle;
        u16 commun_func_bitmap;
+       u16 application_func_bitmap;
+       u16 media_func_bitmap;
+       u16 display_func_bitmap;
+       u16 others_func_bitmap;
+       u8 commun_fn_key_number;
 } __attribute__((packed));
 
 /*
@@ -207,6 +226,7 @@ static int force_series;
 static bool ec_raw_mode;
 static bool has_type_aa;
 static u16 commun_func_bitmap;
+static u8 commun_fn_key_number;
 
 module_param(mailled, int, 0444);
 module_param(brightness, int, 0444);
@@ -468,6 +488,15 @@ static struct dmi_system_id acer_quirks[] = {
        },
        {
                .callback = dmi_matched,
+               .ident = "Lenovo Ideapad S205 (Brazos)",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
+               },
+               .driver_data = &quirk_lenovo_ideapad_s205,
+       },
+       {
+               .callback = dmi_matched,
                .ident = "Lenovo 3000 N200",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -478,6 +507,25 @@ static struct dmi_system_id acer_quirks[] = {
        {}
 };
 
+static int video_set_backlight_video_vendor(const struct dmi_system_id *d)
+{
+       interface->capability &= ~ACER_CAP_BRIGHTNESS;
+       pr_info("Brightness must be controlled by generic video driver\n");
+       return 0;
+}
+
+static const struct dmi_system_id video_vendor_dmi_table[] = {
+       {
+               .callback = video_set_backlight_video_vendor,
+               .ident = "Acer TravelMate 4750",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
+               },
+       },
+       {}
+};
+
 /* Find which quirks are needed for a particular vendor/ model pair */
 static void find_quirks(void)
 {
@@ -536,8 +584,7 @@ struct acpi_buffer *result)
        return status;
 }
 
-static acpi_status AMW0_get_u32(u32 *value, u32 cap,
-struct wmi_interface *iface)
+static acpi_status AMW0_get_u32(u32 *value, u32 cap)
 {
        int err;
        u8 result;
@@ -607,7 +654,7 @@ struct wmi_interface *iface)
        return AE_OK;
 }
 
-static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
+static acpi_status AMW0_set_u32(u32 value, u32 cap)
 {
        struct wmab_args args;
 
@@ -692,6 +739,7 @@ static const struct acpi_device_id norfkill_ids[] = {
        { "VPC2004", 0},
        { "IBM0068", 0},
        { "LEN0068", 0},
+       { "SNY5001", 0},        /* sony-laptop in charge */
        { "", 0},
 };
 
@@ -827,8 +875,7 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out)
        return status;
 }
 
-static acpi_status WMID_get_u32(u32 *value, u32 cap,
-struct wmi_interface *iface)
+static acpi_status WMID_get_u32(u32 *value, u32 cap)
 {
        acpi_status status;
        u8 tmp;
@@ -864,7 +911,7 @@ struct wmi_interface *iface)
        return status;
 }
 
-static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
+static acpi_status WMID_set_u32(u32 value, u32 cap)
 {
        u32 method_id = 0;
        char param;
@@ -912,13 +959,13 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
        struct wmid3_gds_return_value return_value;
        acpi_status status;
        union acpi_object *obj;
-       struct wmid3_gds_input_param params = {
+       struct wmid3_gds_get_input_param params = {
                .function_num = 0x1,
-               .hotkey_number = 0x01,
+               .hotkey_number = commun_fn_key_number,
                .devices = device,
        };
        struct acpi_buffer input = {
-               sizeof(struct wmid3_gds_input_param),
+               sizeof(struct wmid3_gds_get_input_param),
                &params
        };
        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -981,19 +1028,28 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
        acpi_status status;
        union acpi_object *obj;
        u16 devices;
-       struct wmid3_gds_input_param params = {
+       struct wmid3_gds_get_input_param get_params = {
                .function_num = 0x1,
-               .hotkey_number = 0x01,
+               .hotkey_number = commun_fn_key_number,
                .devices = commun_func_bitmap,
        };
-       struct acpi_buffer input = {
-               sizeof(struct wmid3_gds_input_param),
-               &params
+       struct acpi_buffer get_input = {
+               sizeof(struct wmid3_gds_get_input_param),
+               &get_params
+       };
+       struct wmid3_gds_set_input_param set_params = {
+               .function_num = 0x2,
+               .hotkey_number = commun_fn_key_number,
+               .devices = commun_func_bitmap,
+       };
+       struct acpi_buffer set_input = {
+               sizeof(struct wmid3_gds_set_input_param),
+               &set_params
        };
        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
        struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
 
-       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
        if (ACPI_FAILURE(status))
                return status;
 
@@ -1006,7 +1062,7 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
                return AE_ERROR;
        }
        if (obj->buffer.length != 8) {
-               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
                kfree(obj);
                return AE_ERROR;
        }
@@ -1015,18 +1071,16 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
        kfree(obj);
 
        if (return_value.error_code || return_value.ec_return_value) {
-               pr_warning("Get Current Device Status failed: "
-                       "0x%x - 0x%x\n", return_value.error_code,
+               pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
+                       return_value.error_code,
                        return_value.ec_return_value);
                return status;
        }
 
        devices = return_value.devices;
-       params.function_num = 0x2;
-       params.hotkey_number = 0x01;
-       params.devices = (value) ? (devices | device) : (devices & ~device);
+       set_params.devices = (value) ? (devices | device) : (devices & ~device);
 
-       status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
        if (ACPI_FAILURE(status))
                return status;
 
@@ -1039,7 +1093,7 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
                return AE_ERROR;
        }
        if (obj->buffer.length != 4) {
-               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
+               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
                kfree(obj);
                return AE_ERROR;
        }
@@ -1048,8 +1102,8 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
        kfree(obj);
 
        if (return_value.error_code || return_value.ec_return_value)
-               pr_warning("Set Device Status failed: "
-                       "0x%x - 0x%x\n", return_value.error_code,
+               pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
+                       return_value.error_code,
                        return_value.ec_return_value);
 
        return status;
@@ -1096,6 +1150,8 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
                interface->capability |= ACER_CAP_THREEG;
        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
                interface->capability |= ACER_CAP_BLUETOOTH;
+
+       commun_fn_key_number = type_aa->commun_fn_key_number;
 }
 
 static acpi_status WMID_set_capabilities(void)
@@ -1154,15 +1210,15 @@ static acpi_status get_u32(u32 *value, u32 cap)
 
        switch (interface->type) {
        case ACER_AMW0:
-               status = AMW0_get_u32(value, cap, interface);
+               status = AMW0_get_u32(value, cap);
                break;
        case ACER_AMW0_V2:
                if (cap == ACER_CAP_MAILLED) {
-                       status = AMW0_get_u32(value, cap, interface);
+                       status = AMW0_get_u32(value, cap);
                        break;
                }
        case ACER_WMID:
-               status = WMID_get_u32(value, cap, interface);
+               status = WMID_get_u32(value, cap);
                break;
        case ACER_WMID_v2:
                if (cap & (ACER_CAP_WIRELESS |
@@ -1170,7 +1226,7 @@ static acpi_status get_u32(u32 *value, u32 cap)
                           ACER_CAP_THREEG))
                        status = wmid_v2_get_u32(value, cap);
                else if (wmi_has_guid(WMID_GUID2))
-                       status = WMID_get_u32(value, cap, interface);
+                       status = WMID_get_u32(value, cap);
                break;
        }
 
@@ -1184,10 +1240,10 @@ static acpi_status set_u32(u32 value, u32 cap)
        if (interface->capability & cap) {
                switch (interface->type) {
                case ACER_AMW0:
-                       return AMW0_set_u32(value, cap, interface);
+                       return AMW0_set_u32(value, cap);
                case ACER_AMW0_V2:
                        if (cap == ACER_CAP_MAILLED)
-                               return AMW0_set_u32(value, cap, interface);
+                               return AMW0_set_u32(value, cap);
 
                        /*
                         * On some models, some WMID methods don't toggle
@@ -1197,21 +1253,21 @@ static acpi_status set_u32(u32 value, u32 cap)
                         */
                        if (cap == ACER_CAP_WIRELESS ||
                                cap == ACER_CAP_BLUETOOTH) {
-                               status = WMID_set_u32(value, cap, interface);
+                               status = WMID_set_u32(value, cap);
                                if (ACPI_FAILURE(status))
                                        return status;
 
-                               return AMW0_set_u32(value, cap, interface);
+                               return AMW0_set_u32(value, cap);
                        }
                case ACER_WMID:
-                       return WMID_set_u32(value, cap, interface);
+                       return WMID_set_u32(value, cap);
                case ACER_WMID_v2:
                        if (cap & (ACER_CAP_WIRELESS |
                                   ACER_CAP_BLUETOOTH |
                                   ACER_CAP_THREEG))
                                return wmid_v2_set_u32(value, cap);
                        else if (wmi_has_guid(WMID_GUID2))
-                               return WMID_set_u32(value, cap, interface);
+                               return WMID_set_u32(value, cap);
                default:
                        return AE_BAD_PARAMETER;
                }
@@ -1488,8 +1544,8 @@ static ssize_t show_bool_threeg(struct device *dev,
        u32 result; \
        acpi_status status;
 
-       pr_info("This threeg sysfs will be removed in 2012"
-               " - used by: %s\n", current->comm);
+       pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+               current->comm);
        status = get_u32(&result, ACER_CAP_THREEG);
        if (ACPI_SUCCESS(status))
                return sprintf(buf, "%u\n", result);
@@ -1501,8 +1557,8 @@ static ssize_t set_bool_threeg(struct device *dev,
 {
        u32 tmp = simple_strtoul(buf, NULL, 10);
        acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
-       pr_info("This threeg sysfs will be removed in 2012"
-               " - used by: %s\n", current->comm);
+       pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+               current->comm);
        if (ACPI_FAILURE(status))
                return -EINVAL;
        return count;
@@ -1513,8 +1569,8 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
        char *buf)
 {
-       pr_info("This interface sysfs will be removed in 2012"
-               " - used by: %s\n", current->comm);
+       pr_info("This interface sysfs will be removed in 2012 - used by: %s\n",
+               current->comm);
        switch (interface->type) {
        case ACER_AMW0:
                return sprintf(buf, "AMW0\n");
@@ -1981,9 +2037,13 @@ static int __init acer_wmi_init(void)
        set_quirks();
 
        if (acpi_video_backlight_support()) {
-               interface->capability &= ~ACER_CAP_BRIGHTNESS;
-               pr_info("Brightness must be controlled by "
-                      "generic video driver\n");
+               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");
+               }
        }
 
        if (wmi_has_guid(WMID_GUID3)) {
@@ -2008,7 +2068,7 @@ static int __init acer_wmi_init(void)
 
        err = platform_driver_register(&acer_platform_driver);
        if (err) {
-               pr_err("Unable to register platform driver.\n");
+               pr_err("Unable to register platform driver\n");
                goto error_platform_register;
        }
 
index 760c6d7..bc8384c 100644 (file)
@@ -244,12 +244,11 @@ static void acerhdf_change_fanstate(int state)
        unsigned char cmd;
 
        if (verbose)
-               pr_notice("fan %s\n", (state == ACERHDF_FAN_OFF) ?
-                               "OFF" : "ON");
+               pr_notice("fan %s\n", state == ACERHDF_FAN_OFF ? "OFF" : "ON");
 
        if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) {
                pr_err("invalid fan state %d requested, setting to auto!\n",
-                       state);
+                      state);
                state = ACERHDF_FAN_AUTO;
        }
 
@@ -264,19 +263,18 @@ static void acerhdf_check_param(struct thermal_zone_device *thermal)
 {
        if (fanon > ACERHDF_MAX_FANON) {
                pr_err("fanon temperature too high, set to %d\n",
-                               ACERHDF_MAX_FANON);
+                      ACERHDF_MAX_FANON);
                fanon = ACERHDF_MAX_FANON;
        }
 
        if (kernelmode && prev_interval != interval) {
                if (interval > ACERHDF_MAX_INTERVAL) {
                        pr_err("interval too high, set to %d\n",
-                               ACERHDF_MAX_INTERVAL);
+                              ACERHDF_MAX_INTERVAL);
                        interval = ACERHDF_MAX_INTERVAL;
                }
                if (verbose)
-                       pr_notice("interval changed to: %d\n",
-                                       interval);
+                       pr_notice("interval changed to: %d\n", interval);
                thermal->polling_delay = interval*1000;
                prev_interval = interval;
        }
@@ -587,8 +585,8 @@ static int acerhdf_check_hardware(void)
        }
 
        if (!bios_cfg) {
-               pr_err("unknown (unsupported) BIOS version %s/%s/%s, "
-                       "please report, aborting!\n", vendor, product, version);
+               pr_err("unknown (unsupported) BIOS version %s/%s/%s, please report, aborting!\n",
+                      vendor, product, version);
                return -EINVAL;
        }
 
@@ -598,8 +596,7 @@ static int acerhdf_check_hardware(void)
         */
        if (!kernelmode) {
                pr_notice("Fan control off, to enable do:\n");
-               pr_notice("echo -n \"enabled\" > "
-                       "/sys/class/thermal/thermal_zone0/mode\n");
+               pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zone0/mode\n");
        }
 
        return 0;
index 19170bb..a514bf6 100644 (file)
@@ -97,9 +97,12 @@ static struct rfkill *amilo_rfkill_dev;
 
 static int __devinit amilo_rfkill_probe(struct platform_device *device)
 {
+       int rc;
        const struct dmi_system_id *system_id =
                dmi_first_match(amilo_rfkill_id_table);
-       int rc;
+
+       if (!system_id)
+               return -ENXIO;
 
        amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev,
                                        RFKILL_TYPE_WLAN,
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
new file mode 100644 (file)
index 0000000..8a582bd
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ *  Gmux driver for Apple laptops
+ *
+ *  Copyright (C) Canonical Ltd. <seth.forshee@canonical.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/backlight.h>
+#include <linux/acpi.h>
+#include <linux/pnp.h>
+#include <linux/apple_bl.h>
+#include <linux/slab.h>
+#include <acpi/video.h>
+#include <asm/io.h>
+
+struct apple_gmux_data {
+       unsigned long iostart;
+       unsigned long iolen;
+
+       struct backlight_device *bdev;
+};
+
+/*
+ * gmux port offsets. Many of these are not yet used, but may be in the
+ * future, and it's useful to have them documented here anyhow.
+ */
+#define GMUX_PORT_VERSION_MAJOR                0x04
+#define GMUX_PORT_VERSION_MINOR                0x05
+#define GMUX_PORT_VERSION_RELEASE      0x06
+#define GMUX_PORT_SWITCH_DISPLAY       0x10
+#define GMUX_PORT_SWITCH_GET_DISPLAY   0x11
+#define GMUX_PORT_INTERRUPT_ENABLE     0x14
+#define GMUX_PORT_INTERRUPT_STATUS     0x16
+#define GMUX_PORT_SWITCH_DDC           0x28
+#define GMUX_PORT_SWITCH_EXTERNAL      0x40
+#define GMUX_PORT_SWITCH_GET_EXTERNAL  0x41
+#define GMUX_PORT_DISCRETE_POWER       0x50
+#define GMUX_PORT_MAX_BRIGHTNESS       0x70
+#define GMUX_PORT_BRIGHTNESS           0x74
+
+#define GMUX_MIN_IO_LEN                        (GMUX_PORT_BRIGHTNESS + 4)
+
+#define GMUX_INTERRUPT_ENABLE          0xff
+#define GMUX_INTERRUPT_DISABLE         0x00
+
+#define GMUX_INTERRUPT_STATUS_ACTIVE   0
+#define GMUX_INTERRUPT_STATUS_DISPLAY  (1 << 0)
+#define GMUX_INTERRUPT_STATUS_POWER    (1 << 2)
+#define GMUX_INTERRUPT_STATUS_HOTPLUG  (1 << 3)
+
+#define GMUX_BRIGHTNESS_MASK           0x00ffffff
+#define GMUX_MAX_BRIGHTNESS            GMUX_BRIGHTNESS_MASK
+
+static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
+{
+       return inb(gmux_data->iostart + port);
+}
+
+static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port,
+                              u8 val)
+{
+       outb(val, gmux_data->iostart + port);
+}
+
+static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
+{
+       return inl(gmux_data->iostart + port);
+}
+
+static int gmux_get_brightness(struct backlight_device *bd)
+{
+       struct apple_gmux_data *gmux_data = bl_get_data(bd);
+       return gmux_read32(gmux_data, GMUX_PORT_BRIGHTNESS) &
+              GMUX_BRIGHTNESS_MASK;
+}
+
+static int gmux_update_status(struct backlight_device *bd)
+{
+       struct apple_gmux_data *gmux_data = bl_get_data(bd);
+       u32 brightness = bd->props.brightness;
+
+       /*
+        * Older gmux versions require writing out lower bytes first then
+        * setting the upper byte to 0 to flush the values. Newer versions
+        * accept a single u32 write, but the old method also works, so we
+        * just use the old method for all gmux versions.
+        */
+       gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
+       gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 1, brightness >> 8);
+       gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 2, brightness >> 16);
+       gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 3, 0);
+
+       return 0;
+}
+
+static const struct backlight_ops gmux_bl_ops = {
+       .get_brightness = gmux_get_brightness,
+       .update_status = gmux_update_status,
+};
+
+static int __devinit gmux_probe(struct pnp_dev *pnp,
+                               const struct pnp_device_id *id)
+{
+       struct apple_gmux_data *gmux_data;
+       struct resource *res;
+       struct backlight_properties props;
+       struct backlight_device *bdev;
+       u8 ver_major, ver_minor, ver_release;
+       int ret = -ENXIO;
+
+       gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
+       if (!gmux_data)
+               return -ENOMEM;
+       pnp_set_drvdata(pnp, gmux_data);
+
+       res = pnp_get_resource(pnp, IORESOURCE_IO, 0);
+       if (!res) {
+               pr_err("Failed to find gmux I/O resource\n");
+               goto err_free;
+       }
+
+       gmux_data->iostart = res->start;
+       gmux_data->iolen = res->end - res->start;
+
+       if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
+               pr_err("gmux I/O region too small (%lu < %u)\n",
+                      gmux_data->iolen, GMUX_MIN_IO_LEN);
+               goto err_free;
+       }
+
+       if (!request_region(gmux_data->iostart, gmux_data->iolen,
+                           "Apple gmux")) {
+               pr_err("gmux I/O already in use\n");
+               goto err_free;
+       }
+
+       /*
+        * On some machines the gmux is in ACPI even thought the machine
+        * doesn't really have a gmux. Check for invalid version information
+        * to detect this.
+        */
+       ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
+       ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
+       ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
+       if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
+               pr_info("gmux device not present\n");
+               ret = -ENODEV;
+               goto err_release;
+       }
+
+       pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
+               ver_release);
+
+       memset(&props, 0, sizeof(props));
+       props.type = BACKLIGHT_PLATFORM;
+       props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
+
+       /*
+        * Currently it's assumed that the maximum brightness is less than
+        * 2^24 for compatibility with old gmux versions. Cap the max
+        * brightness at this value, but print a warning if the hardware
+        * reports something higher so that it can be fixed.
+        */
+       if (WARN_ON(props.max_brightness > GMUX_MAX_BRIGHTNESS))
+               props.max_brightness = GMUX_MAX_BRIGHTNESS;
+
+       bdev = backlight_device_register("gmux_backlight", &pnp->dev,
+                                        gmux_data, &gmux_bl_ops, &props);
+       if (IS_ERR(bdev)) {
+               ret = PTR_ERR(bdev);
+               goto err_release;
+       }
+
+       gmux_data->bdev = bdev;
+       bdev->props.brightness = gmux_get_brightness(bdev);
+       backlight_update_status(bdev);
+
+       /*
+        * The backlight situation on Macs is complicated. If the gmux is
+        * present it's the best choice, because it always works for
+        * backlight control and supports more levels than other options.
+        * Disable the other backlight choices.
+        */
+       acpi_video_unregister();
+       apple_bl_unregister();
+
+       return 0;
+
+err_release:
+       release_region(gmux_data->iostart, gmux_data->iolen);
+err_free:
+       kfree(gmux_data);
+       return ret;
+}
+
+static void __devexit gmux_remove(struct pnp_dev *pnp)
+{
+       struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
+
+       backlight_device_unregister(gmux_data->bdev);
+       release_region(gmux_data->iostart, gmux_data->iolen);
+       kfree(gmux_data);
+
+       acpi_video_register();
+       apple_bl_register();
+}
+
+static const struct pnp_device_id gmux_device_ids[] = {
+       {"APP000B", 0},
+       {"", 0}
+};
+
+static struct pnp_driver gmux_pnp_driver = {
+       .name           = "apple-gmux",
+       .probe          = gmux_probe,
+       .remove         = __devexit_p(gmux_remove),
+       .id_table       = gmux_device_ids,
+};
+
+static int __init apple_gmux_init(void)
+{
+       return pnp_register_driver(&gmux_pnp_driver);
+}
+
+static void __exit apple_gmux_exit(void)
+{
+       pnp_unregister_driver(&gmux_pnp_driver);
+}
+
+module_init(apple_gmux_init);
+module_exit(apple_gmux_exit);
+
+MODULE_AUTHOR("Seth Forshee <seth.forshee@canonical.com>");
+MODULE_DESCRIPTION("Apple Gmux Driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pnp, gmux_device_ids);
index b7944f9..e38f91b 100644 (file)
@@ -81,6 +81,19 @@ static uint wapf = 1;
 module_param(wapf, uint, 0444);
 MODULE_PARM_DESC(wapf, "WAPF value");
 
+static char *wled_type = "unknown";
+static char *bled_type = "unknown";
+
+module_param(wled_type, charp, 0444);
+MODULE_PARM_DESC(wlan_status, "Set the wled type on boot "
+                "(unknown, led or rfkill). "
+                "default is unknown");
+
+module_param(bled_type, charp, 0444);
+MODULE_PARM_DESC(bled_type, "Set the bled type on boot "
+                "(unknown, led or rfkill). "
+                "default is unknown");
+
 static int wlan_status = 1;
 static int bluetooth_status = 1;
 static int wimax_status = -1;
@@ -137,6 +150,11 @@ MODULE_PARM_DESC(als_status, "Set the ALS status on boot "
 #define WM_RSTS                0x08    /* internal wimax */
 #define WW_RSTS                0x20    /* internal wwan */
 
+/* WLED and BLED type */
+#define TYPE_UNKNOWN   0
+#define TYPE_LED       1
+#define TYPE_RFKILL    2
+
 /* LED */
 #define METHOD_MLED            "MLED"
 #define METHOD_TLED            "TLED"
@@ -218,8 +236,9 @@ struct asus_led {
 /*
  * Same thing for rfkill
  */
-struct asus_pega_rfkill {
-       int control_id;         /* type of control. Maps to PEGA_* values */
+struct asus_rfkill {
+       /* type of control. Maps to PEGA_* values or *_RSTS  */
+       int control_id;
        struct rfkill *rfkill;
        struct asus_laptop *asus;
 };
@@ -240,6 +259,8 @@ struct asus_laptop {
        struct key_entry *keymap;
        struct input_polled_dev *pega_accel_poll;
 
+       struct asus_led wled;
+       struct asus_led bled;
        struct asus_led mled;
        struct asus_led tled;
        struct asus_led rled;
@@ -248,6 +269,8 @@ struct asus_laptop {
        struct asus_led kled;
        struct workqueue_struct *led_workqueue;
 
+       int wled_type;
+       int bled_type;
        int wireless_status;
        bool have_rsts;
        bool is_pega_lucid;
@@ -256,11 +279,11 @@ struct asus_laptop {
        int pega_acc_y;
        int pega_acc_z;
 
-       struct rfkill *gps_rfkill;
-
-       struct asus_pega_rfkill wlanrfk;
-       struct asus_pega_rfkill btrfk;
-       struct asus_pega_rfkill wwanrfk;
+       struct asus_rfkill wlan;
+       struct asus_rfkill bluetooth;
+       struct asus_rfkill wwan;
+       struct asus_rfkill wimax;
+       struct asus_rfkill gps;
 
        acpi_handle handle;     /* the handle of the hotk device */
        u32 ledd_status;        /* status of the LED display */
@@ -274,6 +297,7 @@ static const struct key_entry asus_keymap[] = {
        {KE_KEY, 0x02, { KEY_SCREENLOCK } },
        {KE_KEY, 0x05, { KEY_WLAN } },
        {KE_KEY, 0x08, { KEY_F13 } },
+       {KE_KEY, 0x09, { KEY_PROG2 } }, /* Dock */
        {KE_KEY, 0x17, { KEY_ZOOM } },
        {KE_KEY, 0x1f, { KEY_BATTERY } },
        /* End of Lenovo SL Specific keycodes */
@@ -299,6 +323,8 @@ static const struct key_entry asus_keymap[] = {
        {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
        {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
        {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
+       {KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
+       {KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
        {KE_KEY, 0x7E, { KEY_BLUETOOTH } },
        {KE_KEY, 0x7D, { KEY_BLUETOOTH } },
        {KE_KEY, 0x82, { KEY_CAMERA } },
@@ -601,6 +627,10 @@ static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
 
 static void asus_led_exit(struct asus_laptop *asus)
 {
+       if (!IS_ERR_OR_NULL(asus->wled.led.dev))
+               led_classdev_unregister(&asus->wled.led);
+       if (!IS_ERR_OR_NULL(asus->bled.led.dev))
+               led_classdev_unregister(&asus->bled.led);
        if (!IS_ERR_OR_NULL(asus->mled.led.dev))
                led_classdev_unregister(&asus->mled.led);
        if (!IS_ERR_OR_NULL(asus->tled.led.dev))
@@ -642,7 +672,7 @@ static int asus_led_register(struct asus_laptop *asus,
 
 static int asus_led_init(struct asus_laptop *asus)
 {
-       int r;
+       int r = 0;
 
        /*
         * The Pegatron Lucid has no physical leds, but all methods are
@@ -661,6 +691,16 @@ static int asus_led_init(struct asus_laptop *asus)
        if (!asus->led_workqueue)
                return -ENOMEM;
 
+       if (asus->wled_type == TYPE_LED)
+               r = asus_led_register(asus, &asus->wled, "asus::wlan",
+                                     METHOD_WLAN);
+       if (r)
+               goto error;
+       if (asus->bled_type == TYPE_LED)
+               r = asus_led_register(asus, &asus->bled, "asus::bluetooth",
+                                     METHOD_BLUETOOTH);
+       if (r)
+               goto error;
        r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
        if (r)
                goto error;
@@ -963,7 +1003,7 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
        return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
 }
 
-/*
+/*e
  * Bluetooth
  */
 static int asus_bluetooth_set(struct asus_laptop *asus, int status)
@@ -1228,7 +1268,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
        ret = asus_gps_switch(asus, !!value);
        if (ret)
                return ret;
-       rfkill_set_sw_state(asus->gps_rfkill, !value);
+       rfkill_set_sw_state(asus->gps.rfkill, !value);
        return rv;
 }
 
@@ -1246,90 +1286,139 @@ static const struct rfkill_ops asus_gps_rfkill_ops = {
        .set_block = asus_gps_rfkill_set,
 };
 
+static int asus_rfkill_set(void *data, bool blocked)
+{
+       struct asus_rfkill *rfk = data;
+       struct asus_laptop *asus = rfk->asus;
+
+       if (rfk->control_id == WL_RSTS)
+               return asus_wlan_set(asus, !blocked);
+       else if (rfk->control_id == BT_RSTS)
+               return asus_bluetooth_set(asus, !blocked);
+       else if (rfk->control_id == WM_RSTS)
+               return asus_wimax_set(asus, !blocked);
+       else if (rfk->control_id == WW_RSTS)
+               return asus_wwan_set(asus, !blocked);
+
+       return -EINVAL;
+}
+
+static const struct rfkill_ops asus_rfkill_ops = {
+       .set_block = asus_rfkill_set,
+};
+
+static void asus_rfkill_terminate(struct asus_rfkill *rfk)
+{
+       if (!rfk->rfkill)
+               return ;
+
+       rfkill_unregister(rfk->rfkill);
+       rfkill_destroy(rfk->rfkill);
+       rfk->rfkill = NULL;
+}
+
 static void asus_rfkill_exit(struct asus_laptop *asus)
 {
-       if (asus->gps_rfkill) {
-               rfkill_unregister(asus->gps_rfkill);
-               rfkill_destroy(asus->gps_rfkill);
-               asus->gps_rfkill = NULL;
-       }
+       asus_rfkill_terminate(&asus->wwan);
+       asus_rfkill_terminate(&asus->bluetooth);
+       asus_rfkill_terminate(&asus->wlan);
+       asus_rfkill_terminate(&asus->gps);
 }
 
-static int asus_rfkill_init(struct asus_laptop *asus)
+static int asus_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
+                            const char *name, int control_id, int type,
+                            const struct rfkill_ops *ops)
 {
        int result;
 
-       if (acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) ||
-           acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) ||
-           acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
-               return 0;
-
-       asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
-                                       RFKILL_TYPE_GPS,
-                                       &asus_gps_rfkill_ops, asus);
-       if (!asus->gps_rfkill)
+       rfk->control_id = control_id;
+       rfk->asus = asus;
+       rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
+                                  type, ops, rfk);
+       if (!rfk->rfkill)
                return -EINVAL;
 
-       result = rfkill_register(asus->gps_rfkill);
+       result = rfkill_register(rfk->rfkill);
        if (result) {
-               rfkill_destroy(asus->gps_rfkill);
-               asus->gps_rfkill = NULL;
+               rfkill_destroy(rfk->rfkill);
+               rfk->rfkill = NULL;
        }
 
        return result;
 }
 
-static int pega_rfkill_set(void *data, bool blocked)
+static int asus_rfkill_init(struct asus_laptop *asus)
 {
-       struct asus_pega_rfkill *pega_rfk = data;
+       int result = 0;
 
-       int ret = asus_pega_lucid_set(pega_rfk->asus, pega_rfk->control_id, !blocked);
-       pr_warn("Setting rfkill %d, to %d; returned %d\n", pega_rfk->control_id, !blocked, ret);
+       if (asus->is_pega_lucid)
+               return -ENODEV;
 
-       return ret;
-}
+       if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
+           !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
+           !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
+               result = asus_rfkill_setup(asus, &asus->gps, "asus-gps",
+                                          -1, RFKILL_TYPE_GPS,
+                                          &asus_gps_rfkill_ops);
+       if (result)
+               goto exit;
 
-static const struct rfkill_ops pega_rfkill_ops = {
-       .set_block = pega_rfkill_set,
-};
 
-static void pega_rfkill_terminate(struct asus_pega_rfkill *pega_rfk)
-{
-       pr_warn("Terminating %d\n", pega_rfk->control_id);
-       if (pega_rfk->rfkill) {
-               rfkill_unregister(pega_rfk->rfkill);
-               rfkill_destroy(pega_rfk->rfkill);
-               pega_rfk->rfkill = NULL;
-       }
-}
+       if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL) &&
+           asus->wled_type == TYPE_RFKILL)
+               result = asus_rfkill_setup(asus, &asus->wlan, "asus-wlan",
+                                          WL_RSTS, RFKILL_TYPE_WLAN,
+                                          &asus_rfkill_ops);
+       if (result)
+               goto exit;
 
-static void pega_rfkill_exit(struct asus_laptop *asus)
-{
-       pega_rfkill_terminate(&asus->wwanrfk);
-       pega_rfkill_terminate(&asus->btrfk);
-       pega_rfkill_terminate(&asus->wlanrfk);
+       if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL) &&
+           asus->bled_type == TYPE_RFKILL)
+               result = asus_rfkill_setup(asus, &asus->bluetooth,
+                                          "asus-bluetooth", BT_RSTS,
+                                          RFKILL_TYPE_BLUETOOTH,
+                                          &asus_rfkill_ops);
+       if (result)
+               goto exit;
+
+       if (!acpi_check_handle(asus->handle, METHOD_WWAN, NULL))
+               result = asus_rfkill_setup(asus, &asus->wwan, "asus-wwan",
+                                          WW_RSTS, RFKILL_TYPE_WWAN,
+                                          &asus_rfkill_ops);
+       if (result)
+               goto exit;
+
+       if (!acpi_check_handle(asus->handle, METHOD_WIMAX, NULL))
+               result = asus_rfkill_setup(asus, &asus->wimax, "asus-wimax",
+                                          WM_RSTS, RFKILL_TYPE_WIMAX,
+                                          &asus_rfkill_ops);
+       if (result)
+               goto exit;
+
+exit:
+       if (result)
+               asus_rfkill_exit(asus);
+
+       return result;
 }
 
-static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_pega_rfkill *pega_rfk,
-               const char *name, int controlid, int rfkill_type)
+static int pega_rfkill_set(void *data, bool blocked)
 {
-       int result;
+       struct asus_rfkill *rfk = data;
 
-       pr_warn("Setting up rfk %s, control %d, type %d\n", name, controlid, rfkill_type);
-       pega_rfk->control_id = controlid;
-       pega_rfk->asus = asus;
-       pega_rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
-                                       rfkill_type, &pega_rfkill_ops, pega_rfk);
-       if (!pega_rfk->rfkill)
-               return -EINVAL;
+       int ret = asus_pega_lucid_set(rfk->asus, rfk->control_id, !blocked);
+       return ret;
+}
 
-       result = rfkill_register(pega_rfk->rfkill);
-       if (result) {
-               rfkill_destroy(pega_rfk->rfkill);
-               pega_rfk->rfkill = NULL;
-       }
+static const struct rfkill_ops pega_rfkill_ops = {
+       .set_block = pega_rfkill_set,
+};
 
-       return result;
+static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
+                            const char *name, int controlid, int rfkill_type)
+{
+       return asus_rfkill_setup(asus, rfk, name, controlid, rfkill_type,
+                                &pega_rfkill_ops);
 }
 
 static int pega_rfkill_init(struct asus_laptop *asus)
@@ -1339,22 +1428,22 @@ static int pega_rfkill_init(struct asus_laptop *asus)
        if(!asus->is_pega_lucid)
                return -ENODEV;
 
-       ret = pega_rfkill_setup(asus, &asus->wlanrfk, "pega-wlan", PEGA_WLAN, RFKILL_TYPE_WLAN);
-       if(ret)
-               return ret;
-       ret = pega_rfkill_setup(asus, &asus->btrfk, "pega-bt", PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
+       ret = pega_rfkill_setup(asus, &asus->wlan, "pega-wlan",
+                               PEGA_WLAN, RFKILL_TYPE_WLAN);
        if(ret)
-               goto err_btrfk;
-       ret = pega_rfkill_setup(asus, &asus->wwanrfk, "pega-wwan", PEGA_WWAN, RFKILL_TYPE_WWAN);
+               goto exit;
+
+       ret = pega_rfkill_setup(asus, &asus->bluetooth, "pega-bt",
+                               PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
        if(ret)
-               goto err_wwanrfk;
+               goto exit;
 
-       pr_warn("Pega rfkill init succeeded\n");
-       return 0;
-err_wwanrfk:
-       pega_rfkill_terminate(&asus->btrfk);
-err_btrfk:
-       pega_rfkill_terminate(&asus->wlanrfk);
+       ret = pega_rfkill_setup(asus, &asus->wwan, "pega-wwan",
+                               PEGA_WWAN, RFKILL_TYPE_WWAN);
+
+exit:
+       if (ret)
+               asus_rfkill_exit(asus);
 
        return ret;
 }
@@ -1364,8 +1453,10 @@ err_btrfk:
  */
 static void asus_input_notify(struct asus_laptop *asus, int event)
 {
-       if (asus->inputdev)
-               sparse_keymap_report_event(asus->inputdev, event, 1, true);
+       if (!asus->inputdev)
+               return ;
+       if (!sparse_keymap_report_event(asus->inputdev, event, 1, true))
+               pr_info("Unknown key %x pressed\n", event);
 }
 
 static int asus_input_init(struct asus_laptop *asus)
@@ -1375,7 +1466,7 @@ static int asus_input_init(struct asus_laptop *asus)
 
        input = input_allocate_device();
        if (!input) {
-               pr_info("Unable to allocate input device\n");
+               pr_warn("Unable to allocate input device\n");
                return -ENOMEM;
        }
        input->name = "Asus Laptop extra buttons";
@@ -1390,7 +1481,7 @@ static int asus_input_init(struct asus_laptop *asus)
        }
        error = input_register_device(input);
        if (error) {
-               pr_info("Unable to register input device\n");
+               pr_warn("Unable to register input device\n");
                goto err_free_keymap;
        }
 
@@ -1688,7 +1779,16 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
        if (result)
                return result;
 
-       /* WLED and BLED are on by default */
+       if (!strcmp(bled_type, "led"))
+               asus->bled_type = TYPE_LED;
+       else if (!strcmp(bled_type, "rfkill"))
+               asus->bled_type = TYPE_RFKILL;
+
+       if (!strcmp(wled_type, "led"))
+               asus->wled_type = TYPE_LED;
+       else if (!strcmp(wled_type, "rfkill"))
+               asus->wled_type = TYPE_RFKILL;
+
        if (bluetooth_status >= 0)
                asus_bluetooth_set(asus, !!bluetooth_status);
 
@@ -1786,7 +1886,7 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
                goto fail_led;
 
        result = asus_rfkill_init(asus);
-       if (result)
+       if (result && result != -ENODEV)
                goto fail_rfkill;
 
        result = pega_accel_init(asus);
@@ -1828,7 +1928,6 @@ static int asus_acpi_remove(struct acpi_device *device, int type)
        asus_led_exit(asus);
        asus_input_exit(asus);
        pega_accel_exit(asus);
-       pega_rfkill_exit(asus);
        asus_platform_exit(asus);
 
        kfree(asus->name);
index b0859d4..99a30b5 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
+#include <linux/fb.h>
 
 #include "asus-wmi.h"
 
@@ -51,9 +52,14 @@ static uint wapf;
 module_param(wapf, uint, 0444);
 MODULE_PARM_DESC(wapf, "WAPF value");
 
+static struct quirk_entry quirk_asus_unknown = {
+};
+
 static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
 {
-       driver->wapf = wapf;
+       driver->quirks = &quirk_asus_unknown;
+       driver->quirks->wapf = wapf;
+       driver->panel_power = FB_BLANK_UNBLANK;
 }
 
 static const struct key_entry asus_nb_wmi_keymap[] = {
@@ -70,6 +76,8 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0x50, { KEY_EMAIL } },
        { KE_KEY, 0x51, { KEY_WWW } },
        { KE_KEY, 0x55, { KEY_CALC } },
+       { KE_IGNORE, 0x57, },  /* Battery mode */
+       { KE_IGNORE, 0x58, },  /* AC mode */
        { KE_KEY, 0x5C, { KEY_F15 } },  /* Power Gear key */
        { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
        { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
@@ -99,7 +107,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = {
        .keymap = asus_nb_wmi_keymap,
        .input_name = "Asus WMI hotkeys",
        .input_phys = ASUS_NB_WMI_FILE "/input0",
-       .quirks = asus_nb_wmi_quirks,
+       .detect_quirks = asus_nb_wmi_quirks,
 };
 
 
index 72d731c..77aadde 100644 (file)
@@ -411,7 +411,7 @@ static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
 
        if (retval >= 0) {
                if (level)
-                       *level = retval & 0x80 ? retval & 0x7F : 0;
+                       *level = retval & 0x7F;
                if (env)
                        *env = (retval >> 8) & 0x7F;
                retval = 0;
@@ -571,7 +571,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus)
                } else {
                        dev = pci_get_slot(bus, 0);
                        if (dev) {
-                               pci_remove_bus_device(dev);
+                               pci_stop_and_remove_bus_device(dev);
                                pci_dev_put(dev);
                        }
                }
@@ -784,7 +784,8 @@ static int asus_new_rfkill(struct asus_wmi *asus,
        arfkill->dev_id = dev_id;
        arfkill->asus = asus;
 
-       if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless)
+       if (dev_id == ASUS_WMI_DEVID_WLAN &&
+           asus->driver->quirks->hotplug_wireless)
                *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
                                       &asus_rfkill_wlan_ops, arfkill);
        else
@@ -895,7 +896,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
        if (result && result != -ENODEV)
                goto exit;
 
-       if (!asus->driver->hotplug_wireless)
+       if (!asus->driver->quirks->hotplug_wireless)
                goto exit;
 
        result = asus_setup_pci_hotplug(asus);
@@ -1075,7 +1076,12 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
  */
 static int read_backlight_power(struct asus_wmi *asus)
 {
-       int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT);
+       int ret;
+       if (asus->driver->quirks->store_backlight_power)
+               ret = !asus->driver->panel_power;
+       else
+               ret = asus_wmi_get_devstate_simple(asus,
+                                                  ASUS_WMI_DEVID_BACKLIGHT);
 
        if (ret < 0)
                return ret;
@@ -1116,26 +1122,51 @@ static int read_brightness(struct backlight_device *bd)
        return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
 }
 
-static int update_bl_status(struct backlight_device *bd)
+static u32 get_scalar_command(struct backlight_device *bd)
 {
        struct asus_wmi *asus = bl_get_data(bd);
-       u32 ctrl_param;
-       int power, err;
+       u32 ctrl_param = 0;
 
-       ctrl_param = bd->props.brightness;
+       if ((asus->driver->brightness < bd->props.brightness) ||
+           bd->props.brightness == bd->props.max_brightness)
+               ctrl_param = 0x00008001;
+       else if ((asus->driver->brightness > bd->props.brightness) ||
+                bd->props.brightness == 0)
+               ctrl_param = 0x00008000;
 
-       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
-                                   ctrl_param, NULL);
+       asus->driver->brightness = bd->props.brightness;
 
-       if (err < 0)
-               return err;
+       return ctrl_param;
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+       struct asus_wmi *asus = bl_get_data(bd);
+       u32 ctrl_param;
+       int power, err = 0;
 
        power = read_backlight_power(asus);
        if (power != -ENODEV && bd->props.power != power) {
                ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK);
                err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT,
                                            ctrl_param, NULL);
+               if (asus->driver->quirks->store_backlight_power)
+                       asus->driver->panel_power = bd->props.power;
+
+               /* When using scalar brightness, updating the brightness
+                * will mess with the backlight power */
+               if (asus->driver->quirks->scalar_panel_brightness)
+                       return err;
        }
+
+       if (asus->driver->quirks->scalar_panel_brightness)
+               ctrl_param = get_scalar_command(bd);
+       else
+               ctrl_param = bd->props.brightness;
+
+       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
+                                   ctrl_param, NULL);
+
        return err;
 }
 
@@ -1196,10 +1227,15 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
 
        asus->backlight_device = bd;
 
+       if (asus->driver->quirks->store_backlight_power)
+               asus->driver->panel_power = power;
+
        bd->props.brightness = read_brightness(bd);
        bd->props.power = power;
        backlight_update_status(bd);
 
+       asus->driver->brightness = bd->props.brightness;
+
        return 0;
 }
 
@@ -1441,9 +1477,9 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
 
        /* 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->wapf >= 0)
+       if (asus->driver->quirks->wapf >= 0)
                asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
-                                     asus->driver->wapf, NULL);
+                                     asus->driver->quirks->wapf, NULL);
 
        return asus_wmi_sysfs_init(asus->platform_device);
 }
@@ -1622,8 +1658,8 @@ static int asus_wmi_add(struct platform_device *pdev)
        wdrv->platform_device = pdev;
        platform_set_drvdata(asus->platform_device, asus);
 
-       if (wdrv->quirks)
-               wdrv->quirks(asus->driver);
+       if (wdrv->detect_quirks)
+               wdrv->detect_quirks(asus->driver);
 
        err = asus_wmi_platform_init(asus);
        if (err)
index 8147c10..d43b667 100644 (file)
@@ -35,9 +35,16 @@ struct module;
 struct key_entry;
 struct asus_wmi;
 
+struct quirk_entry {
+       bool hotplug_wireless;
+       bool scalar_panel_brightness;
+       bool store_backlight_power;
+       int wapf;
+};
+
 struct asus_wmi_driver {
-       bool                    hotplug_wireless;
-       int                     wapf;
+       int                     brightness;
+       int                     panel_power;
 
        const char              *name;
        struct module           *owner;
@@ -47,13 +54,14 @@ struct asus_wmi_driver {
        const struct key_entry  *keymap;
        const char              *input_name;
        const char              *input_phys;
+       struct quirk_entry      *quirks;
        /* Returns new code, value, and autorelease values in arguments.
         * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */
        void (*key_filter) (struct asus_wmi_driver *driver, int *code,
                            unsigned int *value, bool *autorelease);
 
        int (*probe) (struct platform_device *device);
-       void (*quirks) (struct asus_wmi_driver *driver);
+       void (*detect_quirks) (struct asus_wmi_driver *driver);
 
        struct platform_driver  platform_driver;
        struct platform_device *platform_device;
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
deleted file mode 100644 (file)
index 6f966d6..0000000
+++ /dev/null
@@ -1,1513 +0,0 @@
-/*
- *  asus_acpi.c - Asus Laptop ACPI Extras
- *
- *
- *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
- *
- *  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
- *
- *
- *  The development page for this driver is located at
- *  http://sourceforge.net/projects/acpi4asus/
- *
- *  Credits:
- *  Pontus Fuchs   - Helper functions, cleanup
- *  Johann Wiesner - Small compile fixes
- *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
- *  ï¿½ic Burghard  - LED display support for W1N
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/backlight.h>
-#include <acpi/acpi_drivers.h>
-#include <acpi/acpi_bus.h>
-#include <asm/uaccess.h>
-
-#define ASUS_ACPI_VERSION "0.30"
-
-#define PROC_ASUS       "asus" /* The directory */
-#define PROC_MLED       "mled"
-#define PROC_WLED       "wled"
-#define PROC_TLED       "tled"
-#define PROC_BT         "bluetooth"
-#define PROC_LEDD       "ledd"
-#define PROC_INFO       "info"
-#define PROC_LCD        "lcd"
-#define PROC_BRN        "brn"
-#define PROC_DISP       "disp"
-
-#define ACPI_HOTK_NAME          "Asus Laptop ACPI Extras Driver"
-#define ACPI_HOTK_CLASS         "hotkey"
-#define ACPI_HOTK_DEVICE_NAME   "Hotkey"
-
-/*
- * Some events we use, same for all Asus
- */
-#define BR_UP       0x10
-#define BR_DOWN     0x20
-
-/*
- * Flags for hotk status
- */
-#define MLED_ON     0x01       /* Mail LED */
-#define WLED_ON     0x02       /* Wireless LED */
-#define TLED_ON     0x04       /* Touchpad LED */
-#define BT_ON       0x08       /* Internal Bluetooth */
-
-MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
-MODULE_DESCRIPTION(ACPI_HOTK_NAME);
-MODULE_LICENSE("GPL");
-
-static uid_t asus_uid;
-static gid_t asus_gid;
-module_param(asus_uid, uint, 0);
-MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus");
-module_param(asus_gid, uint, 0);
-MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus");
-
-/* For each model, all features implemented,
- * those marked with R are relative to HOTK, A for absolute */
-struct model_data {
-       char *name;             /* name of the laptop________________A */
-       char *mt_mled;          /* method to handle mled_____________R */
-       char *mled_status;      /* node to handle mled reading_______A */
-       char *mt_wled;          /* method to handle wled_____________R */
-       char *wled_status;      /* node to handle wled reading_______A */
-       char *mt_tled;          /* method to handle tled_____________R */
-       char *tled_status;      /* node to handle tled reading_______A */
-       char *mt_ledd;          /* method to handle LED display______R */
-       char *mt_bt_switch;     /* method to switch Bluetooth on/off_R */
-       char *bt_status;        /* no model currently supports this__? */
-       char *mt_lcd_switch;    /* method to turn LCD on/off_________A */
-       char *lcd_status;       /* node to read LCD panel state______A */
-       char *brightness_up;    /* method to set brightness up_______A */
-       char *brightness_down;  /* method to set brightness down ____A */
-       char *brightness_set;   /* method to set absolute brightness_R */
-       char *brightness_get;   /* method to get absolute brightness_R */
-       char *brightness_status;/* node to get brightness____________A */
-       char *display_set;      /* method to set video output________R */
-       char *display_get;      /* method to get video output________R */
-};
-
-/*
- * This is the main structure, we can use it to store anything interesting
- * about the hotk device
- */
-struct asus_hotk {
-       struct acpi_device *device;     /* the device we are in */
-       acpi_handle handle;             /* the handle of the hotk device */
-       char status;                    /* status of the hotk, for LEDs */
-       u32 ledd_status;                /* status of the LED display */
-       struct model_data *methods;     /* methods available on the laptop */
-       u8 brightness;                  /* brightness level */
-       enum {
-               A1x = 0,        /* A1340D, A1300F */
-               A2x,            /* A2500H */
-               A4G,            /* A4700G */
-               D1x,            /* D1 */
-               L2D,            /* L2000D */
-               L3C,            /* L3800C */
-               L3D,            /* L3400D */
-               L3H,            /* L3H, L2000E, L5D */
-               L4R,            /* L4500R */
-               L5x,            /* L5800C */
-               L8L,            /* L8400L */
-               M1A,            /* M1300A */
-               M2E,            /* M2400E, L4400L */
-               M6N,            /* M6800N, W3400N */
-               M6R,            /* M6700R, A3000G */
-               P30,            /* Samsung P30 */
-               S1x,            /* S1300A, but also L1400B and M2400A (L84F) */
-               S2x,            /* S200 (J1 reported), Victor MP-XP7210 */
-               W1N,            /* W1000N */
-               W5A,            /* W5A */
-               W3V,            /* W3030V */
-               xxN,            /* M2400N, M3700N, M5200N, M6800N,
-                                                        S1300N, S5200N*/
-               A4S,            /* Z81sp */
-               F3Sa,           /* (Centrino) */
-               R1F,
-               END_MODEL
-       } model;                /* Models currently supported */
-       u16 event_count[128];   /* Count for each event TODO make this better */
-};
-
-/* Here we go */
-#define A1x_PREFIX "\\_SB.PCI0.ISA.EC0."
-#define L3C_PREFIX "\\_SB.PCI0.PX40.ECD0."
-#define M1A_PREFIX "\\_SB.PCI0.PX40.EC0."
-#define P30_PREFIX "\\_SB.PCI0.LPCB.EC0."
-#define S1x_PREFIX "\\_SB.PCI0.PX40."
-#define S2x_PREFIX A1x_PREFIX
-#define xxN_PREFIX "\\_SB.PCI0.SBRG.EC0."
-
-static struct model_data model_conf[END_MODEL] = {
-       /*
-        * TODO I have seen a SWBX and AIBX method on some models, like L1400B,
-        * it seems to be a kind of switch, but what for ?
-        */
-
-       {
-        .name = "A1x",
-        .mt_mled = "MLED",
-        .mled_status = "\\MAIL",
-        .mt_lcd_switch = A1x_PREFIX "_Q10",
-        .lcd_status = "\\BKLI",
-        .brightness_up = A1x_PREFIX "_Q0E",
-        .brightness_down = A1x_PREFIX "_Q0F"},
-
-       {
-        .name = "A2x",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .wled_status = "\\SG66",
-        .mt_lcd_switch = "\\Q10",
-        .lcd_status = "\\BAOF",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "A4G",
-        .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\ADVG"},
-
-       {
-        .name = "D1x",
-        .mt_mled = "MLED",
-        .mt_lcd_switch = "\\Q0D",
-        .lcd_status = "\\GP11",
-        .brightness_up = "\\Q0C",
-        .brightness_down = "\\Q0B",
-        .brightness_status = "\\BLVL",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "L2D",
-        .mt_mled = "MLED",
-        .mled_status = "\\SGP6",
-        .mt_wled = "WLED",
-        .wled_status = "\\RCP3",
-        .mt_lcd_switch = "\\Q10",
-        .lcd_status = "\\SGP0",
-        .brightness_up = "\\Q0E",
-        .brightness_down = "\\Q0F",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "L3C",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = L3C_PREFIX "_Q10",
-        .lcd_status = "\\GL32",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\_SB.PCI0.PCI1.VGAC.NMAP"},
-
-       {
-        .name = "L3D",
-        .mt_mled = "MLED",
-        .mled_status = "\\MALD",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = "\\Q10",
-        .lcd_status = "\\BKLG",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "L3H",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = "EHK",
-        .lcd_status = "\\_SB.PCI0.PM.PBC",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "L4R",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .wled_status = "\\_SB.PCI0.SBRG.SG13",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
-
-       {
-        .name = "L5x",
-        .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
-        .mt_tled = "TLED",
-        .mt_lcd_switch = "\\Q0D",
-        .lcd_status = "\\BAOF",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "L8L"
-/* No features, but at least support the hotkeys */
-        },
-
-       {
-        .name = "M1A",
-        .mt_mled = "MLED",
-        .mt_lcd_switch = M1A_PREFIX "Q10",
-        .lcd_status = "\\PNOF",
-        .brightness_up = M1A_PREFIX "Q0E",
-        .brightness_down = M1A_PREFIX "Q0F",
-        .brightness_status = "\\BRIT",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "M2E",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = "\\Q10",
-        .lcd_status = "\\GP06",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "M6N",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .wled_status = "\\_SB.PCI0.SBRG.SG13",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\_SB.BKLT",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\SSTE"},
-
-       {
-        .name = "M6R",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
-
-       {
-        .name = "P30",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = P30_PREFIX "_Q0E",
-        .lcd_status = "\\BKLT",
-        .brightness_up = P30_PREFIX "_Q68",
-        .brightness_down = P30_PREFIX "_Q69",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\DNXT"},
-
-       {
-        .name = "S1x",
-        .mt_mled = "MLED",
-        .mled_status = "\\EMLE",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = S1x_PREFIX "Q10",
-        .lcd_status = "\\PNOF",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV"},
-
-       {
-        .name = "S2x",
-        .mt_mled = "MLED",
-        .mled_status = "\\MAIL",
-        .mt_lcd_switch = S2x_PREFIX "_Q10",
-        .lcd_status = "\\BKLI",
-        .brightness_up = S2x_PREFIX "_Q0B",
-        .brightness_down = S2x_PREFIX "_Q0A"},
-
-       {
-        .name = "W1N",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_ledd = "SLCM",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\BKLT",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\ADVG"},
-
-       {
-        .name = "W5A",
-        .mt_bt_switch = "BLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\ADVG"},
-
-       {
-        .name = "W3V",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\BKLT",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "xxN",
-        .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\BKLT",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-       .display_get = "\\ADVG"},
-
-       {
-               .name              = "A4S",
-               .brightness_set    = "SPLV",
-               .brightness_get    = "GPLV",
-               .mt_bt_switch      = "BLED",
-               .mt_wled           = "WLED"
-       },
-
-       {
-               .name           = "F3Sa",
-               .mt_bt_switch   = "BLED",
-               .mt_wled        = "WLED",
-               .mt_mled        = "MLED",
-               .brightness_get = "GPLV",
-               .brightness_set = "SPLV",
-               .mt_lcd_switch  = "\\_SB.PCI0.SBRG.EC0._Q10",
-               .lcd_status     = "\\_SB.PCI0.SBRG.EC0.RPIN",
-               .display_get    = "\\ADVG",
-               .display_set    = "SDSP",
-       },
-       {
-               .name = "R1F",
-               .mt_bt_switch = "BLED",
-               .mt_mled = "MLED",
-               .mt_wled = "WLED",
-               .mt_lcd_switch = "\\Q10",
-               .lcd_status = "\\GP06",
-               .brightness_set = "SPLV",
-               .brightness_get = "GPLV",
-               .display_set = "SDSP",
-               .display_get = "\\INFB"
-       }
-};
-
-/* procdir we use */
-static struct proc_dir_entry *asus_proc_dir;
-
-static struct backlight_device *asus_backlight_device;
-
-/*
- * This header is made available to allow proper configuration given model,
- * revision number , ... this info cannot go in struct asus_hotk because it is
- * available before the hotk
- */
-static struct acpi_table_header *asus_info;
-
-/* The actual device the driver binds to */
-static struct asus_hotk *hotk;
-
-/*
- * The hotkey driver and autoloading declaration
- */
-static int asus_hotk_add(struct acpi_device *device);
-static int asus_hotk_remove(struct acpi_device *device, int type);
-static void asus_hotk_notify(struct acpi_device *device, u32 event);
-
-static const struct acpi_device_id asus_device_ids[] = {
-       {"ATK0100", 0},
-       {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, asus_device_ids);
-
-static struct acpi_driver asus_hotk_driver = {
-       .name = "asus_acpi",
-       .class = ACPI_HOTK_CLASS,
-       .owner = THIS_MODULE,
-       .ids = asus_device_ids,
-       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
-       .ops = {
-               .add = asus_hotk_add,
-               .remove = asus_hotk_remove,
-               .notify = asus_hotk_notify,
-               },
-};
-
-/*
- * This function evaluates an ACPI method, given an int as parameter, the
- * method is searched within the scope of the handle, can be NULL. The output
- * of the method is written is output, which can also be NULL
- *
- * returns 1 if write is successful, 0 else.
- */
-static int write_acpi_int(acpi_handle handle, const char *method, int val,
-                         struct acpi_buffer *output)
-{
-       struct acpi_object_list params; /* list of input parameters (int) */
-       union acpi_object in_obj;       /* the only param we use */
-       acpi_status status;
-
-       params.count = 1;
-       params.pointer = &in_obj;
-       in_obj.type = ACPI_TYPE_INTEGER;
-       in_obj.integer.value = val;
-
-       status = acpi_evaluate_object(handle, (char *)method, &params, output);
-       return (status == AE_OK);
-}
-
-static int read_acpi_int(acpi_handle handle, const char *method, int *val)
-{
-       struct acpi_buffer output;
-       union acpi_object out_obj;
-       acpi_status status;
-
-       output.length = sizeof(out_obj);
-       output.pointer = &out_obj;
-
-       status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
-       *val = out_obj.integer.value;
-       return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
-}
-
-static int asus_info_proc_show(struct seq_file *m, void *v)
-{
-       int temp;
-
-       seq_printf(m, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
-       seq_printf(m, "Model reference    : %s\n", hotk->methods->name);
-       /*
-        * The SFUN method probably allows the original driver to get the list
-        * of features supported by a given model. For now, 0x0100 or 0x0800
-        * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
-        * The significance of others is yet to be found.
-        */
-       if (read_acpi_int(hotk->handle, "SFUN", &temp))
-               seq_printf(m, "SFUN value         : 0x%04x\n", temp);
-       /*
-        * Another value for userspace: the ASYM method returns 0x02 for
-        * battery low and 0x04 for battery critical, its readings tend to be
-        * more accurate than those provided by _BST.
-        * Note: since not all the laptops provide this method, errors are
-        * silently ignored.
-        */
-       if (read_acpi_int(hotk->handle, "ASYM", &temp))
-               seq_printf(m, "ASYM value         : 0x%04x\n", temp);
-       if (asus_info) {
-               seq_printf(m, "DSDT length        : %d\n", asus_info->length);
-               seq_printf(m, "DSDT checksum      : %d\n", asus_info->checksum);
-               seq_printf(m, "DSDT revision      : %d\n", asus_info->revision);
-               seq_printf(m, "OEM id             : %.*s\n", ACPI_OEM_ID_SIZE, asus_info->oem_id);
-               seq_printf(m, "OEM table id       : %.*s\n", ACPI_OEM_TABLE_ID_SIZE, asus_info->oem_table_id);
-               seq_printf(m, "OEM revision       : 0x%x\n", asus_info->oem_revision);
-               seq_printf(m, "ASL comp vendor id : %.*s\n", ACPI_NAME_SIZE, asus_info->asl_compiler_id);
-               seq_printf(m, "ASL comp revision  : 0x%x\n", asus_info->asl_compiler_revision);
-       }
-
-       return 0;
-}
-
-static int asus_info_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, asus_info_proc_show, NULL);
-}
-
-static const struct file_operations asus_info_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = asus_info_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-/*
- * /proc handlers
- * We write our info in page, we begin at offset off and cannot write more
- * than count bytes. We set eof to 1 if we handle those 2 values. We return the
- * number of bytes written in page
- */
-
-/* Generic LED functions */
-static int read_led(const char *ledname, int ledmask)
-{
-       if (ledname) {
-               int led_status;
-
-               if (read_acpi_int(NULL, ledname, &led_status))
-                       return led_status;
-               else
-                       pr_warn("Error reading LED status\n");
-       }
-       return (hotk->status & ledmask) ? 1 : 0;
-}
-
-static int parse_arg(const char __user *buf, unsigned long count, int *val)
-{
-       char s[32];
-       if (!count)
-               return 0;
-       if (count > 31)
-               return -EINVAL;
-       if (copy_from_user(s, buf, count))
-               return -EFAULT;
-       s[count] = 0;
-       if (sscanf(s, "%i", val) != 1)
-               return -EINVAL;
-       return count;
-}
-
-/* FIXME: kill extraneous args so it can be called independently */
-static int
-write_led(const char __user *buffer, unsigned long count,
-         char *ledname, int ledmask, int invert)
-{
-       int rv, value;
-       int led_out = 0;
-
-       rv = parse_arg(buffer, count, &value);
-       if (rv > 0)
-               led_out = value ? 1 : 0;
-
-       hotk->status =
-           (led_out) ? (hotk->status | ledmask) : (hotk->status & ~ledmask);
-
-       if (invert)             /* invert target value */
-               led_out = !led_out;
-
-       if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
-               pr_warn("LED (%s) write failed\n", ledname);
-
-       return rv;
-}
-
-/*
- * Proc handlers for MLED
- */
-static int mled_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "%d\n", read_led(hotk->methods->mled_status, MLED_ON));
-       return 0;
-}
-
-static int mled_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, mled_proc_show, NULL);
-}
-
-static ssize_t mled_proc_write(struct file *file, const char __user *buffer,
-               size_t count, loff_t *pos)
-{
-       return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
-}
-
-static const struct file_operations mled_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = mled_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = mled_proc_write,
-};
-
-/*
- * Proc handlers for LED display
- */
-static int ledd_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "0x%08x\n", hotk->ledd_status);
-       return 0;
-}
-
-static int ledd_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, ledd_proc_show, NULL);
-}
-
-static ssize_t ledd_proc_write(struct file *file, const char __user *buffer,
-               size_t count, loff_t *pos)
-{
-       int rv, value;
-
-       rv = parse_arg(buffer, count, &value);
-       if (rv > 0) {
-               if (!write_acpi_int
-                   (hotk->handle, hotk->methods->mt_ledd, value, NULL))
-                       pr_warn("LED display write failed\n");
-               else
-                       hotk->ledd_status = (u32) value;
-       }
-       return rv;
-}
-
-static const struct file_operations ledd_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ledd_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = ledd_proc_write,
-};
-
-/*
- * Proc handlers for WLED
- */
-static int wled_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "%d\n", read_led(hotk->methods->wled_status, WLED_ON));
-       return 0;
-}
-
-static int wled_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, wled_proc_show, NULL);
-}
-
-static ssize_t wled_proc_write(struct file *file, const char __user *buffer,
-               size_t count, loff_t *pos)
-{
-       return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
-}
-
-static const struct file_operations wled_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = wled_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = wled_proc_write,
-};
-
-/*
- * Proc handlers for Bluetooth
- */
-static int bluetooth_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "%d\n", read_led(hotk->methods->bt_status, BT_ON));
-       return 0;
-}
-
-static int bluetooth_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, bluetooth_proc_show, NULL);
-}
-
-static ssize_t bluetooth_proc_write(struct file *file,
-               const char __user *buffer, size_t count, loff_t *pos)
-{
-       /* Note: mt_bt_switch controls both internal Bluetooth adapter's
-          presence and its LED */
-       return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
-}
-
-static const struct file_operations bluetooth_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = bluetooth_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = bluetooth_proc_write,
-};
-
-/*
- * Proc handlers for TLED
- */
-static int tled_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "%d\n", read_led(hotk->methods->tled_status, TLED_ON));
-       return 0;
-}
-
-static int tled_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, tled_proc_show, NULL);
-}
-
-static ssize_t tled_proc_write(struct file *file, const char __user *buffer,
-               size_t count, loff_t *pos)
-{
-       return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
-}
-
-static const struct file_operations tled_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = tled_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = tled_proc_write,
-};
-
-static int get_lcd_state(void)
-{
-       int lcd = 0;
-
-       if (hotk->model == L3H) {
-               /* L3H and the like have to be handled differently */
-               acpi_status status = 0;
-               struct acpi_object_list input;
-               union acpi_object mt_params[2];
-               struct acpi_buffer output;
-               union acpi_object out_obj;
-
-               input.count = 2;
-               input.pointer = mt_params;
-               /* Note: the following values are partly guessed up, but
-                  otherwise they seem to work */
-               mt_params[0].type = ACPI_TYPE_INTEGER;
-               mt_params[0].integer.value = 0x02;
-               mt_params[1].type = ACPI_TYPE_INTEGER;
-               mt_params[1].integer.value = 0x02;
-
-               output.length = sizeof(out_obj);
-               output.pointer = &out_obj;
-
-               status =
-                   acpi_evaluate_object(NULL, hotk->methods->lcd_status,
-                                        &input, &output);
-               if (status != AE_OK)
-                       return -1;
-               if (out_obj.type == ACPI_TYPE_INTEGER)
-                       /* That's what the AML code does */
-                       lcd = out_obj.integer.value >> 8;
-       } else if (hotk->model == F3Sa) {
-               unsigned long long tmp;
-               union acpi_object param;
-               struct acpi_object_list input;
-               acpi_status status;
-
-               /* Read pin 11 */
-               param.type = ACPI_TYPE_INTEGER;
-               param.integer.value = 0x11;
-               input.count = 1;
-               input.pointer = &param;
-
-               status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
-                                               &input, &tmp);
-               if (status != AE_OK)
-                       return -1;
-
-               lcd = tmp;
-       } else {
-               /* We don't have to check anything if we are here */
-               if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
-                       pr_warn("Error reading LCD status\n");
-
-               if (hotk->model == L2D)
-                       lcd = ~lcd;
-       }
-
-       return (lcd & 1);
-}
-
-static int set_lcd_state(int value)
-{
-       int lcd = 0;
-       acpi_status status = 0;
-
-       lcd = value ? 1 : 0;
-       if (lcd != get_lcd_state()) {
-               /* switch */
-               if (hotk->model != L3H) {
-                       status =
-                           acpi_evaluate_object(NULL,
-                                                hotk->methods->mt_lcd_switch,
-                                                NULL, NULL);
-               } else {
-                       /* L3H and the like must be handled differently */
-                       if (!write_acpi_int
-                           (hotk->handle, hotk->methods->mt_lcd_switch, 0x07,
-                            NULL))
-                               status = AE_ERROR;
-                       /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
-                          the exact behaviour is simulated here */
-               }
-               if (ACPI_FAILURE(status))
-                       pr_warn("Error switching LCD\n");
-       }
-       return 0;
-
-}
-
-static int lcd_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "%d\n", get_lcd_state());
-       return 0;
-}
-
-static int lcd_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, lcd_proc_show, NULL);
-}
-
-static ssize_t lcd_proc_write(struct file *file, const char __user *buffer,
-              size_t count, loff_t *pos)
-{
-       int rv, value;
-
-       rv = parse_arg(buffer, count, &value);
-       if (rv > 0)
-               set_lcd_state(value);
-       return rv;
-}
-
-static const struct file_operations lcd_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = lcd_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = lcd_proc_write,
-};
-
-static int read_brightness(struct backlight_device *bd)
-{
-       int value;
-
-       if (hotk->methods->brightness_get) {    /* SPLV/GPLV laptop */
-               if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get,
-                                  &value))
-                       pr_warn("Error reading brightness\n");
-       } else if (hotk->methods->brightness_status) {  /* For D1 for example */
-               if (!read_acpi_int(NULL, hotk->methods->brightness_status,
-                                  &value))
-                       pr_warn("Error reading brightness\n");
-       } else                  /* No GPLV method */
-               value = hotk->brightness;
-       return value;
-}
-
-/*
- * Change the brightness level
- */
-static int set_brightness(int value)
-{
-       acpi_status status = 0;
-       int ret = 0;
-
-       /* SPLV laptop */
-       if (hotk->methods->brightness_set) {
-               if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set,
-                                   value, NULL)) {
-                       pr_warn("Error changing brightness\n");
-                       ret = -EIO;
-               }
-               goto out;
-       }
-
-       /* No SPLV method if we are here, act as appropriate */
-       value -= read_brightness(NULL);
-       while (value != 0) {
-               status = acpi_evaluate_object(NULL, (value > 0) ?
-                                             hotk->methods->brightness_up :
-                                             hotk->methods->brightness_down,
-                                             NULL, NULL);
-               (value > 0) ? value-- : value++;
-               if (ACPI_FAILURE(status)) {
-                       pr_warn("Error changing brightness\n");
-                       ret = -EIO;
-               }
-       }
-out:
-       return ret;
-}
-
-static int set_brightness_status(struct backlight_device *bd)
-{
-       return set_brightness(bd->props.brightness);
-}
-
-static int brn_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "%d\n", read_brightness(NULL));
-       return 0;
-}
-
-static int brn_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, brn_proc_show, NULL);
-}
-
-static ssize_t brn_proc_write(struct file *file, const char __user *buffer,
-              size_t count, loff_t *pos)
-{
-       int rv, value;
-
-       rv = parse_arg(buffer, count, &value);
-       if (rv > 0) {
-               value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
-               /* 0 <= value <= 15 */
-               set_brightness(value);
-       }
-       return rv;
-}
-
-static const struct file_operations brn_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = brn_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = brn_proc_write,
-};
-
-static void set_display(int value)
-{
-       /* no sanity check needed for now */
-       if (!write_acpi_int(hotk->handle, hotk->methods->display_set,
-                           value, NULL))
-               pr_warn("Error setting display\n");
-       return;
-}
-
-/*
- * Now, *this* one could be more user-friendly, but so far, no-one has
- * complained. The significance of bits is the same as in proc_write_disp()
- */
-static int disp_proc_show(struct seq_file *m, void *v)
-{
-       int value = 0;
-
-       if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
-               pr_warn("Error reading display status\n");
-       value &= 0x07;  /* needed for some models, shouldn't hurt others */
-       seq_printf(m, "%d\n", value);
-       return 0;
-}
-
-static int disp_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, disp_proc_show, NULL);
-}
-
-/*
- * Experimental support for display switching. As of now: 1 should activate
- * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
- * (bitwise) of these will suffice. I never actually tested 3 displays hooked
- * up simultaneously, so be warned. See the acpi4asus README for more info.
- */
-static ssize_t disp_proc_write(struct file *file, const char __user *buffer,
-               size_t count, loff_t *pos)
-{
-       int rv, value;
-
-       rv = parse_arg(buffer, count, &value);
-       if (rv > 0)
-               set_display(value);
-       return rv;
-}
-
-static const struct file_operations disp_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = disp_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = disp_proc_write,
-};
-
-static int
-asus_proc_add(char *name, const struct file_operations *proc_fops, umode_t mode,
-                    struct acpi_device *device)
-{
-       struct proc_dir_entry *proc;
-
-       proc = proc_create_data(name, mode, acpi_device_dir(device),
-                               proc_fops, acpi_driver_data(device));
-       if (!proc) {
-               pr_warn("  Unable to create %s fs entry\n", name);
-               return -1;
-       }
-       proc->uid = asus_uid;
-       proc->gid = asus_gid;
-       return 0;
-}
-
-static int asus_hotk_add_fs(struct acpi_device *device)
-{
-       struct proc_dir_entry *proc;
-       umode_t mode;
-
-       if ((asus_uid == 0) && (asus_gid == 0)) {
-               mode = S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP;
-       } else {
-               mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
-               pr_warn("  asus_uid and asus_gid parameters are "
-                       "deprecated, use chown and chmod instead!\n");
-       }
-
-       acpi_device_dir(device) = asus_proc_dir;
-       if (!acpi_device_dir(device))
-               return -ENODEV;
-
-       proc = proc_create(PROC_INFO, mode, acpi_device_dir(device),
-                          &asus_info_proc_fops);
-       if (proc) {
-               proc->uid = asus_uid;
-               proc->gid = asus_gid;
-       } else {
-               pr_warn("  Unable to create " PROC_INFO " fs entry\n");
-       }
-
-       if (hotk->methods->mt_wled) {
-               asus_proc_add(PROC_WLED, &wled_proc_fops, mode, device);
-       }
-
-       if (hotk->methods->mt_ledd) {
-               asus_proc_add(PROC_LEDD, &ledd_proc_fops, mode, device);
-       }
-
-       if (hotk->methods->mt_mled) {
-               asus_proc_add(PROC_MLED, &mled_proc_fops, mode, device);
-       }
-
-       if (hotk->methods->mt_tled) {
-               asus_proc_add(PROC_TLED, &tled_proc_fops, mode, device);
-       }
-
-       if (hotk->methods->mt_bt_switch) {
-               asus_proc_add(PROC_BT, &bluetooth_proc_fops, mode, device);
-       }
-
-       /*
-        * We need both read node and write method as LCD switch is also
-        * accessible from the keyboard
-        */
-       if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
-               asus_proc_add(PROC_LCD, &lcd_proc_fops, mode, device);
-       }
-
-       if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
-           (hotk->methods->brightness_get && hotk->methods->brightness_set)) {
-               asus_proc_add(PROC_BRN, &brn_proc_fops, mode, device);
-       }
-
-       if (hotk->methods->display_set) {
-               asus_proc_add(PROC_DISP, &disp_proc_fops, mode, device);
-       }
-
-       return 0;
-}
-
-static int asus_hotk_remove_fs(struct acpi_device *device)
-{
-       if (acpi_device_dir(device)) {
-               remove_proc_entry(PROC_INFO, acpi_device_dir(device));
-               if (hotk->methods->mt_wled)
-                       remove_proc_entry(PROC_WLED, acpi_device_dir(device));
-               if (hotk->methods->mt_mled)
-                       remove_proc_entry(PROC_MLED, acpi_device_dir(device));
-               if (hotk->methods->mt_tled)
-                       remove_proc_entry(PROC_TLED, acpi_device_dir(device));
-               if (hotk->methods->mt_ledd)
-                       remove_proc_entry(PROC_LEDD, acpi_device_dir(device));
-               if (hotk->methods->mt_bt_switch)
-                       remove_proc_entry(PROC_BT, acpi_device_dir(device));
-               if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status)
-                       remove_proc_entry(PROC_LCD, acpi_device_dir(device));
-               if ((hotk->methods->brightness_up
-                    && hotk->methods->brightness_down)
-                   || (hotk->methods->brightness_get
-                       && hotk->methods->brightness_set))
-                       remove_proc_entry(PROC_BRN, acpi_device_dir(device));
-               if (hotk->methods->display_set)
-                       remove_proc_entry(PROC_DISP, acpi_device_dir(device));
-       }
-       return 0;
-}
-
-static void asus_hotk_notify(struct acpi_device *device, u32 event)
-{
-       /* TODO Find a better way to handle events count. */
-       if (!hotk)
-               return;
-
-       /*
-        * The BIOS *should* be sending us device events, but apparently
-        * Asus uses system events instead, so just ignore any device
-        * events we get.
-        */
-       if (event > ACPI_MAX_SYS_NOTIFY)
-               return;
-
-       if ((event & ~((u32) BR_UP)) < 16)
-               hotk->brightness = (event & ~((u32) BR_UP));
-       else if ((event & ~((u32) BR_DOWN)) < 16)
-               hotk->brightness = (event & ~((u32) BR_DOWN));
-
-       acpi_bus_generate_proc_event(hotk->device, event,
-                               hotk->event_count[event % 128]++);
-
-       return;
-}
-
-/*
- * Match the model string to the list of supported models. Return END_MODEL if
- * no match or model is NULL.
- */
-static int asus_model_match(char *model)
-{
-       if (model == NULL)
-               return END_MODEL;
-
-       if (strncmp(model, "L3D", 3) == 0)
-               return L3D;
-       else if (strncmp(model, "L2E", 3) == 0 ||
-                strncmp(model, "L3H", 3) == 0 || strncmp(model, "L5D", 3) == 0)
-               return L3H;
-       else if (strncmp(model, "L3", 2) == 0 || strncmp(model, "L2B", 3) == 0)
-               return L3C;
-       else if (strncmp(model, "L8L", 3) == 0)
-               return L8L;
-       else if (strncmp(model, "L4R", 3) == 0)
-               return L4R;
-       else if (strncmp(model, "M6N", 3) == 0 || strncmp(model, "W3N", 3) == 0)
-               return M6N;
-       else if (strncmp(model, "M6R", 3) == 0 || strncmp(model, "A3G", 3) == 0)
-               return M6R;
-       else if (strncmp(model, "M2N", 3) == 0 ||
-                strncmp(model, "M3N", 3) == 0 ||
-                strncmp(model, "M5N", 3) == 0 ||
-                strncmp(model, "S1N", 3) == 0 ||
-                strncmp(model, "S5N", 3) == 0)
-               return xxN;
-       else if (strncmp(model, "M1", 2) == 0)
-               return M1A;
-       else if (strncmp(model, "M2", 2) == 0 || strncmp(model, "L4E", 3) == 0)
-               return M2E;
-       else if (strncmp(model, "L2", 2) == 0)
-               return L2D;
-       else if (strncmp(model, "L8", 2) == 0)
-               return S1x;
-       else if (strncmp(model, "D1", 2) == 0)
-               return D1x;
-       else if (strncmp(model, "A1", 2) == 0)
-               return A1x;
-       else if (strncmp(model, "A2", 2) == 0)
-               return A2x;
-       else if (strncmp(model, "J1", 2) == 0)
-               return S2x;
-       else if (strncmp(model, "L5", 2) == 0)
-               return L5x;
-       else if (strncmp(model, "A4G", 3) == 0)
-               return A4G;
-       else if (strncmp(model, "W1N", 3) == 0)
-               return W1N;
-       else if (strncmp(model, "W3V", 3) == 0)
-               return W3V;
-       else if (strncmp(model, "W5A", 3) == 0)
-               return W5A;
-       else if (strncmp(model, "R1F", 3) == 0)
-               return R1F;
-       else if (strncmp(model, "A4S", 3) == 0)
-               return A4S;
-       else if (strncmp(model, "F3Sa", 4) == 0)
-               return F3Sa;
-       else
-               return END_MODEL;
-}
-
-/*
- * This function is used to initialize the hotk with right values. In this
- * method, we can make all the detection we want, and modify the hotk struct
- */
-static int asus_hotk_get_info(void)
-{
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       union acpi_object *model = NULL;
-       int bsts_result;
-       char *string = NULL;
-       acpi_status status;
-
-       /*
-        * Get DSDT headers early enough to allow for differentiating between
-        * models, but late enough to allow acpi_bus_register_driver() to fail
-        * before doing anything ACPI-specific. Should we encounter a machine,
-        * which needs special handling (i.e. its hotkey device has a different
-        * HID), this bit will be moved. A global variable asus_info contains
-        * the DSDT header.
-        */
-       status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
-       if (ACPI_FAILURE(status))
-               pr_warn("  Couldn't get the DSDT table header\n");
-
-       /* We have to write 0 on init this far for all ASUS models */
-       if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
-               pr_err("  Hotkey initialization failed\n");
-               return -ENODEV;
-       }
-
-       /* This needs to be called for some laptops to init properly */
-       if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))
-               pr_warn("  Error calling BSTS\n");
-       else if (bsts_result)
-               pr_notice("  BSTS called, 0x%02x returned\n", bsts_result);
-
-       /*
-        * Try to match the object returned by INIT to the specific model.
-        * Handle every possible object (or the lack of thereof) the DSDT
-        * writers might throw at us. When in trouble, we pass NULL to
-        * asus_model_match() and try something completely different.
-        */
-       if (buffer.pointer) {
-               model = buffer.pointer;
-               switch (model->type) {
-               case ACPI_TYPE_STRING:
-                       string = model->string.pointer;
-                       break;
-               case ACPI_TYPE_BUFFER:
-                       string = model->buffer.pointer;
-                       break;
-               default:
-                       kfree(model);
-                       model = NULL;
-                       break;
-               }
-       }
-       hotk->model = asus_model_match(string);
-       if (hotk->model == END_MODEL) { /* match failed */
-               if (asus_info &&
-                   strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
-                       hotk->model = P30;
-                       pr_notice("  Samsung P30 detected, supported\n");
-                       hotk->methods = &model_conf[hotk->model];
-                       kfree(model);
-                       return 0;
-               } else {
-                       hotk->model = M2E;
-                       pr_notice("  unsupported model %s, trying default values\n",
-                                 string);
-                       pr_notice("  send /proc/acpi/dsdt to the developers\n");
-                       kfree(model);
-                       return -ENODEV;
-               }
-       }
-       hotk->methods = &model_conf[hotk->model];
-       pr_notice("  %s model detected, supported\n", string);
-
-       /* Sort of per-model blacklist */
-       if (strncmp(string, "L2B", 3) == 0)
-               hotk->methods->lcd_status = NULL;
-       /* L2B is similar enough to L3C to use its settings, with this only
-          exception */
-       else if (strncmp(string, "A3G", 3) == 0)
-               hotk->methods->lcd_status = "\\BLFG";
-       /* A3G is like M6R */
-       else if (strncmp(string, "S5N", 3) == 0 ||
-                strncmp(string, "M5N", 3) == 0 ||
-                strncmp(string, "W3N", 3) == 0)
-               hotk->methods->mt_mled = NULL;
-       /* S5N, M5N and W3N have no MLED */
-       else if (strncmp(string, "L5D", 3) == 0)
-               hotk->methods->mt_wled = NULL;
-       /* L5D's WLED is not controlled by ACPI */
-       else if (strncmp(string, "M2N", 3) == 0 ||
-                strncmp(string, "W3V", 3) == 0 ||
-                strncmp(string, "S1N", 3) == 0)
-               hotk->methods->mt_wled = "WLED";
-       /* M2N, S1N and W3V have a usable WLED */
-       else if (asus_info) {
-               if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
-                       hotk->methods->mled_status = NULL;
-               /* S1300A reports L84F, but L1400B too, account for that */
-       }
-
-       kfree(model);
-
-       return 0;
-}
-
-static int asus_hotk_check(void)
-{
-       int result = 0;
-
-       result = acpi_bus_get_status(hotk->device);
-       if (result)
-               return result;
-
-       if (hotk->device->status.present) {
-               result = asus_hotk_get_info();
-       } else {
-               pr_err("  Hotkey device not present, aborting\n");
-               return -EINVAL;
-       }
-
-       return result;
-}
-
-static int asus_hotk_found;
-
-static int asus_hotk_add(struct acpi_device *device)
-{
-       acpi_status status = AE_OK;
-       int result;
-
-       pr_notice("Asus Laptop ACPI Extras version %s\n", ASUS_ACPI_VERSION);
-
-       hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
-       if (!hotk)
-               return -ENOMEM;
-
-       hotk->handle = device->handle;
-       strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
-       strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);
-       device->driver_data = hotk;
-       hotk->device = device;
-
-       result = asus_hotk_check();
-       if (result)
-               goto end;
-
-       result = asus_hotk_add_fs(device);
-       if (result)
-               goto end;
-
-       /* For laptops without GPLV: init the hotk->brightness value */
-       if ((!hotk->methods->brightness_get)
-           && (!hotk->methods->brightness_status)
-           && (hotk->methods->brightness_up && hotk->methods->brightness_down)) {
-               status =
-                   acpi_evaluate_object(NULL, hotk->methods->brightness_down,
-                                        NULL, NULL);
-               if (ACPI_FAILURE(status))
-                       pr_warn("  Error changing brightness\n");
-               else {
-                       status =
-                           acpi_evaluate_object(NULL,
-                                                hotk->methods->brightness_up,
-                                                NULL, NULL);
-                       if (ACPI_FAILURE(status))
-                               pr_warn("  Strange, error changing brightness\n");
-               }
-       }
-
-       asus_hotk_found = 1;
-
-       /* LED display is off by default */
-       hotk->ledd_status = 0xFFF;
-
-end:
-       if (result)
-               kfree(hotk);
-
-       return result;
-}
-
-static int asus_hotk_remove(struct acpi_device *device, int type)
-{
-       asus_hotk_remove_fs(device);
-
-       kfree(hotk);
-
-       return 0;
-}
-
-static const struct backlight_ops asus_backlight_data = {
-       .get_brightness = read_brightness,
-       .update_status  = set_brightness_status,
-};
-
-static void asus_acpi_exit(void)
-{
-       if (asus_backlight_device)
-               backlight_device_unregister(asus_backlight_device);
-
-       acpi_bus_unregister_driver(&asus_hotk_driver);
-       remove_proc_entry(PROC_ASUS, acpi_root_dir);
-
-       return;
-}
-
-static int __init asus_acpi_init(void)
-{
-       struct backlight_properties props;
-       int result;
-
-       result = acpi_bus_register_driver(&asus_hotk_driver);
-       if (result < 0)
-               return result;
-
-       asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
-       if (!asus_proc_dir) {
-               pr_err("Unable to create /proc entry\n");
-               acpi_bus_unregister_driver(&asus_hotk_driver);
-               return -ENODEV;
-       }
-
-       /*
-        * This is a bit of a kludge.  We only want this module loaded
-        * for ASUS systems, but there's currently no way to probe the
-        * ACPI namespace for ASUS HIDs.  So we just return failure if
-        * we didn't find one, which will cause the module to be
-        * unloaded.
-        */
-       if (!asus_hotk_found) {
-               acpi_bus_unregister_driver(&asus_hotk_driver);
-               remove_proc_entry(PROC_ASUS, acpi_root_dir);
-               return -ENODEV;
-       }
-
-       memset(&props, 0, sizeof(struct backlight_properties));
-       props.type = BACKLIGHT_PLATFORM;
-       props.max_brightness = 15;
-       asus_backlight_device = backlight_device_register("asus", NULL, NULL,
-                                                         &asus_backlight_data,
-                                                         &props);
-       if (IS_ERR(asus_backlight_device)) {
-               pr_err("Could not register asus backlight device\n");
-               asus_backlight_device = NULL;
-               asus_acpi_exit();
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-module_init(asus_acpi_init);
-module_exit(asus_acpi_exit);
index d967344..1887e2f 100644 (file)
@@ -882,6 +882,7 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(dmi, compal_dmi_table);
 
 static void initialize_power_supply_data(struct compal_data *data)
 {
@@ -1097,16 +1098,3 @@ MODULE_AUTHOR("Roald Frederickx (roald.frederickx@gmail.com)");
 MODULE_DESCRIPTION("Compal Laptop Support");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
-MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
-MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1012:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
-MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");
index d93e962..a05fc9c 100644 (file)
@@ -117,6 +117,7 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(dmi, dell_device_table);
 
 static struct dmi_system_id __devinitdata dell_blacklist[] = {
        /* Supported by compal-laptop */
@@ -184,6 +185,33 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
                },
                .driver_data = &quirk_dell_vostro_v130,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Vostro 3555",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Inspiron N311z",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "Dell Inspiron M5110",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"),
+               },
+               .driver_data = &quirk_dell_vostro_v130,
+       },
 };
 
 static struct calling_interface_buffer *buffer;
@@ -236,9 +264,7 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
 {
        switch (dm->type) {
        case 0xd4: /* Indexed IO */
-               break;
        case 0xd5: /* Protected Area Type 1 */
-               break;
        case 0xd6: /* Protected Area Type 2 */
                break;
        case 0xda: /* Calling interface */
@@ -615,6 +641,7 @@ static void touchpad_led_set(struct led_classdev *led_cdev,
 static struct led_classdev touchpad_led = {
        .name = "dell-laptop::touchpad",
        .brightness_set = touchpad_led_set,
+       .flags = LED_CORE_SUSPENDRESUME,
 };
 
 static int __devinit touchpad_led_init(struct device *dev)
@@ -794,6 +821,3 @@ module_exit(dell_exit);
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
 MODULE_DESCRIPTION("Dell laptop driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
-MODULE_ALIAS("dmi:*svnDellInc.:*:ct9:*");
-MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
index ea44abd..dab91b4 100644 (file)
@@ -646,7 +646,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
                } else {
                        dev = pci_get_slot(bus, 0);
                        if (dev) {
-                               pci_remove_bus_device(dev);
+                               pci_stop_and_remove_bus_device(dev);
                                pci_dev_put(dev);
                        }
                }
@@ -1251,6 +1251,14 @@ static void eeepc_input_exit(struct eeepc_laptop *eeepc)
 /*
  * ACPI driver
  */
+static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
+{
+       if (!eeepc->inputdev)
+               return ;
+       if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))
+               pr_info("Unknown key %x pressed\n", event);
+}
+
 static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
 {
        struct eeepc_laptop *eeepc = acpi_driver_data(device);
@@ -1287,12 +1295,11 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
                                * event will be desired value (or else ignored)
                                */
                        }
-                       sparse_keymap_report_event(eeepc->inputdev, event,
-                                                  1, true);
+                       eeepc_input_notify(eeepc, event);
                }
        } else {
                /* Everything else is a bona-fide keypress event */
-               sparse_keymap_report_event(eeepc->inputdev, event, 1, true);
+               eeepc_input_notify(eeepc, event);
        }
 }
 
index 9f6e643..6567613 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
 #include <linux/dmi.h>
+#include <linux/fb.h>
 #include <acpi/acpi_bus.h>
 
 #include "asus-wmi.h"
@@ -84,9 +85,81 @@ static const struct key_entry eeepc_wmi_keymap[] = {
        { KE_KEY, 0xed, { KEY_CAMERA_DOWN } },
        { KE_KEY, 0xee, { KEY_CAMERA_LEFT } },
        { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } },
+       { KE_KEY, 0xf3, { KEY_MENU } },
+       { KE_KEY, 0xf5, { KEY_HOMEPAGE } },
+       { KE_KEY, 0xf6, { KEY_ESC } },
        { KE_END, 0},
 };
 
+static struct quirk_entry quirk_asus_unknown = {
+};
+
+static struct quirk_entry quirk_asus_1000h = {
+       .hotplug_wireless = true,
+};
+
+static struct quirk_entry quirk_asus_et2012_type1 = {
+       .store_backlight_power = true,
+};
+
+static struct quirk_entry quirk_asus_et2012_type3 = {
+       .scalar_panel_brightness = true,
+       .store_backlight_power = true,
+};
+
+static struct quirk_entry *quirks;
+
+static void et2012_quirks(void)
+{
+       const struct dmi_device *dev = NULL;
+       char oemstring[30];
+
+       while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+               if (sscanf(dev->name, "AEMS%24c", oemstring) == 1) {
+                       if (oemstring[18] == '1')
+                               quirks = &quirk_asus_et2012_type1;
+                       else if (oemstring[18] == '3')
+                               quirks = &quirk_asus_et2012_type3;
+                       break;
+               }
+       }
+}
+
+static int dmi_matched(const struct dmi_system_id *dmi)
+{
+       char *model;
+
+       quirks = dmi->driver_data;
+
+       model = (char *)dmi->matches[1].substr;
+       if (unlikely(strncmp(model, "ET2012", 6) == 0))
+               et2012_quirks();
+
+       return 1;
+}
+
+static struct dmi_system_id asus_quirks[] = {
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK Computer INC. 1000H",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "1000H"),
+               },
+               .driver_data = &quirk_asus_1000h,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK Computer INC. ET2012E/I",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ET2012"),
+               },
+               .driver_data = &quirk_asus_unknown,
+       },
+       {},
+};
+
 static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
                                 unsigned int *value, bool *autorelease)
 {
@@ -141,33 +214,16 @@ static int eeepc_wmi_probe(struct platform_device *pdev)
        return 0;
 }
 
-static void eeepc_dmi_check(struct asus_wmi_driver *driver)
-{
-       const char *model;
-
-       model = dmi_get_system_info(DMI_PRODUCT_NAME);
-       if (!model)
-               return;
-
-       /*
-        * Whitelist for wlan hotplug
-        *
-        * Asus 1000H needs the current hotplug code to handle
-        * Fn+F2 correctly. We may add other Asus here later, but
-        * it seems that most of the laptops supported by asus-wmi
-        * don't need to be on this list
-        */
-       if (strcmp(model, "1000H") == 0) {
-               driver->hotplug_wireless = true;
-               pr_info("wlan hotplug enabled\n");
-       }
-}
-
 static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
 {
-       driver->hotplug_wireless = hotplug_wireless;
-       driver->wapf = -1;
-       eeepc_dmi_check(driver);
+       quirks = &quirk_asus_unknown;
+       quirks->hotplug_wireless = hotplug_wireless;
+
+       dmi_check_system(asus_quirks);
+
+       driver->quirks = quirks;
+       driver->quirks->wapf = -1;
+       driver->panel_power = FB_BLANK_UNBLANK;
 }
 
 static struct asus_wmi_driver asus_wmi_driver = {
@@ -179,7 +235,7 @@ static struct asus_wmi_driver asus_wmi_driver = {
        .input_phys = EEEPC_WMI_FILE "/input0",
        .key_filter = eeepc_wmi_key_filter,
        .probe = eeepc_wmi_probe,
-       .quirks = eeepc_wmi_quirks,
+       .detect_quirks = eeepc_wmi_quirks,
 };
 
 
index ba68d4e..7387f97 100644 (file)
@@ -375,7 +375,7 @@ static ssize_t hdaps_variance_show(struct device *dev,
 static ssize_t hdaps_temp1_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       u8 temp;
+       u8 uninitialized_var(temp);
        int ret;
 
        ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);
@@ -388,7 +388,7 @@ static ssize_t hdaps_temp1_show(struct device *dev,
 static ssize_t hdaps_temp2_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       u8 temp;
+       u8 uninitialized_var(temp);
        int ret;
 
        ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);
index 0903a88..0a3594c 100644 (file)
@@ -142,17 +142,7 @@ static struct platform_driver mfld_pb_driver = {
        .remove = __devexit_p(mfld_pb_remove),
 };
 
-static int __init mfld_pb_init(void)
-{
-       return platform_driver_register(&mfld_pb_driver);
-}
-module_init(mfld_pb_init);
-
-static void __exit mfld_pb_exit(void)
-{
-       platform_driver_unregister(&mfld_pb_driver);
-}
-module_exit(mfld_pb_exit);
+module_platform_driver(mfld_pb_driver);
 
 MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
 MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
index 2ee9766..5ae9cd9 100644 (file)
@@ -549,6 +549,7 @@ static int mid_thermal_remove(struct platform_device *pdev)
 
 static const struct platform_device_id therm_id_table[] = {
        { DRIVER_NAME, 1 },
+       { "msic_thermal", 1 },
        { }
 };
 
@@ -564,18 +565,7 @@ static struct platform_driver mid_thermal_driver = {
        .id_table = therm_id_table,
 };
 
-static int __init mid_thermal_module_init(void)
-{
-       return platform_driver_register(&mid_thermal_driver);
-}
-
-static void __exit mid_thermal_module_exit(void)
-{
-       platform_driver_unregister(&mid_thermal_driver);
-}
-
-module_init(mid_thermal_module_init);
-module_exit(mid_thermal_module_exit);
+module_platform_driver(mid_thermal_driver);
 
 MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
 MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
index 6ee0b5c..79a0c2f 100644 (file)
@@ -313,6 +313,7 @@ static struct dmi_system_id __initdata oaktrail_dmi_table[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(dmi, oaktrail_dmi_table);
 
 static int __init oaktrail_init(void)
 {
@@ -394,4 +395,3 @@ MODULE_AUTHOR("Yin Kangkai (kangkai.yin@intel.com)");
 MODULE_DESCRIPTION("Intel Oaktrail Platform ACPI Extras");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("dmi:*:svnIntelCorporation:pnOakTrailplatform:*");
index fd73ea8..e2a34b4 100644 (file)
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/backlight.h>
+#include <linux/leds.h>
 #include <linux/fb.h>
 #include <linux/dmi.h>
 #include <linux/platform_device.h>
 #include <linux/rfkill.h>
+#include <linux/acpi.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/ctype.h>
+#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
+#include <acpi/video.h>
+#endif
 
 /*
  * This driver is needed because a number of Samsung laptops do not hook
 #define SABI_IFACE_COMPLETE            0x04
 #define SABI_IFACE_DATA                        0x05
 
-/* Structure to get data back to the calling function */
-struct sabi_retval {
-       u8 retval[20];
+#define WL_STATUS_WLAN                 0x0
+#define WL_STATUS_BT                   0x2
+
+/* Structure get/set data using sabi */
+struct sabi_data {
+       union {
+               struct {
+                       u32 d0;
+                       u32 d1;
+                       u16 d2;
+                       u8  d3;
+               };
+               u8 data[11];
+       };
 };
 
 struct sabi_header_offsets {
@@ -60,8 +79,8 @@ struct sabi_commands {
         * Brightness is 0 - 8, as described above.
         * Value 0 is for the BIOS to use
         */
-       u8 get_brightness;
-       u8 set_brightness;
+       u16 get_brightness;
+       u16 set_brightness;
 
        /*
         * first byte:
@@ -72,40 +91,56 @@ struct sabi_commands {
         * 0x03 - 3G is on
         * TODO, verify 3G is correct, that doesn't seem right...
         */
-       u8 get_wireless_button;
-       u8 set_wireless_button;
+       u16 get_wireless_button;
+       u16 set_wireless_button;
 
        /* 0 is off, 1 is on */
-       u8 get_backlight;
-       u8 set_backlight;
+       u16 get_backlight;
+       u16 set_backlight;
 
        /*
         * 0x80 or 0x00 - no action
         * 0x81 - recovery key pressed
         */
-       u8 get_recovery_mode;
-       u8 set_recovery_mode;
+       u16 get_recovery_mode;
+       u16 set_recovery_mode;
 
        /*
         * on seclinux: 0 is low, 1 is high,
         * on swsmi: 0 is normal, 1 is silent, 2 is turbo
         */
-       u8 get_performance_level;
-       u8 set_performance_level;
+       u16 get_performance_level;
+       u16 set_performance_level;
+
+       /* 0x80 is off, 0x81 is on */
+       u16 get_battery_life_extender;
+       u16 set_battery_life_extender;
+
+       /* 0x80 is off, 0x81 is on */
+       u16 get_usb_charge;
+       u16 set_usb_charge;
+
+       /* the first byte is for bluetooth and the third one is for wlan */
+       u16 get_wireless_status;
+       u16 set_wireless_status;
+
+       /* 0x81 to read, (0x82 | level << 8) to set, 0xaabb to enable */
+       u16 kbd_backlight;
 
        /*
         * Tell the BIOS that Linux is running on this machine.
         * 81 is on, 80 is off
         */
-       u8 set_linux;
+       u16 set_linux;
 };
 
 struct sabi_performance_level {
        const char *name;
-       u8 value;
+       u16 value;
 };
 
 struct sabi_config {
+       int sabi_version;
        const char *test_string;
        u16 main_function;
        const struct sabi_header_offsets header_offsets;
@@ -117,6 +152,10 @@ struct sabi_config {
 
 static const struct sabi_config sabi_configs[] = {
        {
+               /* I don't know if it is really 2, but it it is
+                * less than 3 anyway */
+               .sabi_version = 2,
+
                .test_string = "SECLINUX",
 
                .main_function = 0x4c49,
@@ -146,6 +185,17 @@ static const struct sabi_config sabi_configs[] = {
                        .get_performance_level = 0x08,
                        .set_performance_level = 0x09,
 
+                       .get_battery_life_extender = 0xFFFF,
+                       .set_battery_life_extender = 0xFFFF,
+
+                       .get_usb_charge = 0xFFFF,
+                       .set_usb_charge = 0xFFFF,
+
+                       .get_wireless_status = 0xFFFF,
+                       .set_wireless_status = 0xFFFF,
+
+                       .kbd_backlight = 0xFFFF,
+
                        .set_linux = 0x0a,
                },
 
@@ -164,6 +214,8 @@ static const struct sabi_config sabi_configs[] = {
                .max_brightness = 8,
        },
        {
+               .sabi_version = 3,
+
                .test_string = "SwSmi@",
 
                .main_function = 0x5843,
@@ -193,6 +245,17 @@ static const struct sabi_config sabi_configs[] = {
                        .get_performance_level = 0x31,
                        .set_performance_level = 0x32,
 
+                       .get_battery_life_extender = 0x65,
+                       .set_battery_life_extender = 0x66,
+
+                       .get_usb_charge = 0x67,
+                       .set_usb_charge = 0x68,
+
+                       .get_wireless_status = 0x69,
+                       .set_wireless_status = 0x6a,
+
+                       .kbd_backlight = 0x78,
+
                        .set_linux = 0xff,
                },
 
@@ -217,16 +280,82 @@ static const struct sabi_config sabi_configs[] = {
        { },
 };
 
-static const struct sabi_config *sabi_config;
+/*
+ * samsung-laptop/    - debugfs root directory
+ *   f0000_segment    - dump f0000 segment
+ *   command          - current command
+ *   data             - current data
+ *   d0, d1, d2, d3   - data fields
+ *   call             - call SABI using command and data
+ *
+ * This allow to call arbitrary sabi commands wihout
+ * modifying the driver at all.
+ * For example, setting the keyboard backlight brightness to 5
+ *
+ *  echo 0x78 > command
+ *  echo 0x0582 > d0
+ *  echo 0 > d1
+ *  echo 0 > d2
+ *  echo 0 > d3
+ *  cat call
+ */
+
+struct samsung_laptop_debug {
+       struct dentry *root;
+       struct sabi_data data;
+       u16 command;
+
+       struct debugfs_blob_wrapper f0000_wrapper;
+       struct debugfs_blob_wrapper data_wrapper;
+       struct debugfs_blob_wrapper sdiag_wrapper;
+};
+
+struct samsung_laptop;
+
+struct samsung_rfkill {
+       struct samsung_laptop *samsung;
+       struct rfkill *rfkill;
+       enum rfkill_type type;
+};
+
+struct samsung_laptop {
+       const struct sabi_config *config;
+
+       void __iomem *sabi;
+       void __iomem *sabi_iface;
+       void __iomem *f0000_segment;
+
+       struct mutex sabi_mutex;
+
+       struct platform_device *platform_device;
+       struct backlight_device *backlight_device;
+
+       struct samsung_rfkill wlan;
+       struct samsung_rfkill bluetooth;
+
+       struct led_classdev kbd_led;
+       int kbd_led_wk;
+       struct workqueue_struct *led_workqueue;
+       struct work_struct kbd_led_work;
+
+       struct samsung_laptop_debug debug;
+       struct samsung_quirks *quirks;
+
+       bool handle_backlight;
+       bool has_stepping_quirk;
+
+       char sdiag[64];
+};
+
+struct samsung_quirks {
+       bool broken_acpi_video;
+};
+
+static struct samsung_quirks samsung_unknown = {};
 
-static void __iomem *sabi;
-static void __iomem *sabi_iface;
-static void __iomem *f0000_segment;
-static struct backlight_device *backlight_device;
-static struct mutex sabi_mutex;
-static struct platform_device *sdev;
-static struct rfkill *rfk;
-static bool has_stepping_quirk;
+static struct samsung_quirks samsung_broken_acpi_video = {
+       .broken_acpi_video = true,
+};
 
 static bool force;
 module_param(force, bool, 0);
@@ -237,176 +366,143 @@ static bool debug;
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
-static int sabi_get_command(u8 command, struct sabi_retval *sretval)
+static int sabi_command(struct samsung_laptop *samsung, u16 command,
+                       struct sabi_data *in,
+                       struct sabi_data *out)
 {
-       int retval = 0;
-       u16 port = readw(sabi + sabi_config->header_offsets.port);
+       const struct sabi_config *config = samsung->config;
+       int ret = 0;
+       u16 port = readw(samsung->sabi + config->header_offsets.port);
        u8 complete, iface_data;
 
-       mutex_lock(&sabi_mutex);
-
-       /* enable memory to be able to write to it */
-       outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
-
-       /* write out the command */
-       writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
-       writew(command, sabi_iface + SABI_IFACE_SUB);
-       writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
-       outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
-
-       /* write protect memory to make it safe */
-       outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+       mutex_lock(&samsung->sabi_mutex);
 
-       /* see if the command actually succeeded */
-       complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
-       iface_data = readb(sabi_iface + SABI_IFACE_DATA);
-       if (complete != 0xaa || iface_data == 0xff) {
-               pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
-                       command, complete, iface_data);
-               retval = -EINVAL;
-               goto exit;
+       if (debug) {
+               if (in)
+                       pr_info("SABI command:0x%04x "
+                               "data:{0x%08x, 0x%08x, 0x%04x, 0x%02x}",
+                               command, in->d0, in->d1, in->d2, in->d3);
+               else
+                       pr_info("SABI command:0x%04x", command);
        }
-       /*
-        * Save off the data into a structure so the caller use it.
-        * Right now we only want the first 4 bytes,
-        * There are commands that need more, but not for the ones we
-        * currently care about.
-        */
-       sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
-       sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
-       sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
-       sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
-
-exit:
-       mutex_unlock(&sabi_mutex);
-       return retval;
-
-}
-
-static int sabi_set_command(u8 command, u8 data)
-{
-       int retval = 0;
-       u16 port = readw(sabi + sabi_config->header_offsets.port);
-       u8 complete, iface_data;
-
-       mutex_lock(&sabi_mutex);
 
        /* enable memory to be able to write to it */
-       outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
+       outb(readb(samsung->sabi + config->header_offsets.en_mem), port);
 
        /* write out the command */
-       writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
-       writew(command, sabi_iface + SABI_IFACE_SUB);
-       writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
-       writeb(data, sabi_iface + SABI_IFACE_DATA);
-       outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
+       writew(config->main_function, samsung->sabi_iface + SABI_IFACE_MAIN);
+       writew(command, samsung->sabi_iface + SABI_IFACE_SUB);
+       writeb(0, samsung->sabi_iface + SABI_IFACE_COMPLETE);
+       if (in) {
+               writel(in->d0, samsung->sabi_iface + SABI_IFACE_DATA);
+               writel(in->d1, samsung->sabi_iface + SABI_IFACE_DATA + 4);
+               writew(in->d2, samsung->sabi_iface + SABI_IFACE_DATA + 8);
+               writeb(in->d3, samsung->sabi_iface + SABI_IFACE_DATA + 10);
+       }
+       outb(readb(samsung->sabi + config->header_offsets.iface_func), port);
 
        /* write protect memory to make it safe */
-       outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
+       outb(readb(samsung->sabi + config->header_offsets.re_mem), port);
 
        /* see if the command actually succeeded */
-       complete = readb(sabi_iface + SABI_IFACE_COMPLETE);
-       iface_data = readb(sabi_iface + SABI_IFACE_DATA);
+       complete = readb(samsung->sabi_iface + SABI_IFACE_COMPLETE);
+       iface_data = readb(samsung->sabi_iface + SABI_IFACE_DATA);
+
+       /* iface_data = 0xFF happens when a command is not known
+        * so we only add a warning in debug mode since we will
+        * probably issue some unknown command at startup to find
+        * out which features are supported */
+       if (complete != 0xaa || (iface_data == 0xff && debug))
+               pr_warn("SABI command 0x%04x failed with"
+                       " completion flag 0x%02x and interface data 0x%02x",
+                       command, complete, iface_data);
+
        if (complete != 0xaa || iface_data == 0xff) {
-               pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
-                      command, complete, iface_data);
-               retval = -EINVAL;
+               ret = -EINVAL;
+               goto exit;
        }
 
-       mutex_unlock(&sabi_mutex);
-       return retval;
-}
-
-static void test_backlight(void)
-{
-       struct sabi_retval sretval;
-
-       sabi_get_command(sabi_config->commands.get_backlight, &sretval);
-       printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
-
-       sabi_set_command(sabi_config->commands.set_backlight, 0);
-       printk(KERN_DEBUG "backlight should be off\n");
-
-       sabi_get_command(sabi_config->commands.get_backlight, &sretval);
-       printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
-
-       msleep(1000);
+       if (out) {
+               out->d0 = readl(samsung->sabi_iface + SABI_IFACE_DATA);
+               out->d1 = readl(samsung->sabi_iface + SABI_IFACE_DATA + 4);
+               out->d2 = readw(samsung->sabi_iface + SABI_IFACE_DATA + 2);
+               out->d3 = readb(samsung->sabi_iface + SABI_IFACE_DATA + 1);
+       }
 
-       sabi_set_command(sabi_config->commands.set_backlight, 1);
-       printk(KERN_DEBUG "backlight should be on\n");
+       if (debug && out) {
+               pr_info("SABI return data:{0x%08x, 0x%08x, 0x%04x, 0x%02x}",
+                       out->d0, out->d1, out->d2, out->d3);
+       }
 
-       sabi_get_command(sabi_config->commands.get_backlight, &sretval);
-       printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
+exit:
+       mutex_unlock(&samsung->sabi_mutex);
+       return ret;
 }
 
-static void test_wireless(void)
+/* simple wrappers usable with most commands */
+static int sabi_set_commandb(struct samsung_laptop *samsung,
+                            u16 command, u8 data)
 {
-       struct sabi_retval sretval;
+       struct sabi_data in = { { { .d0 = 0, .d1 = 0, .d2 = 0, .d3 = 0 } } };
 
-       sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
-       printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
-
-       sabi_set_command(sabi_config->commands.set_wireless_button, 0);
-       printk(KERN_DEBUG "wireless led should be off\n");
-
-       sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
-       printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
-
-       msleep(1000);
-
-       sabi_set_command(sabi_config->commands.set_wireless_button, 1);
-       printk(KERN_DEBUG "wireless led should be on\n");
-
-       sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
-       printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
+       in.data[0] = data;
+       return sabi_command(samsung, command, &in, NULL);
 }
 
-static u8 read_brightness(void)
+static int read_brightness(struct samsung_laptop *samsung)
 {
-       struct sabi_retval sretval;
+       const struct sabi_config *config = samsung->config;
+       const struct sabi_commands *commands = &samsung->config->commands;
+       struct sabi_data sretval;
        int user_brightness = 0;
        int retval;
 
-       retval = sabi_get_command(sabi_config->commands.get_brightness,
-                                 &sretval);
-       if (!retval) {
-               user_brightness = sretval.retval[0];
-               if (user_brightness > sabi_config->min_brightness)
-                       user_brightness -= sabi_config->min_brightness;
-               else
-                       user_brightness = 0;
-       }
+       retval = sabi_command(samsung, commands->get_brightness,
+                             NULL, &sretval);
+       if (retval)
+               return retval;
+
+       user_brightness = sretval.data[0];
+       if (user_brightness > config->min_brightness)
+               user_brightness -= config->min_brightness;
+       else
+               user_brightness = 0;
+
        return user_brightness;
 }
 
-static void set_brightness(u8 user_brightness)
+static void set_brightness(struct samsung_laptop *samsung, u8 user_brightness)
 {
-       u8 user_level = user_brightness + sabi_config->min_brightness;
+       const struct sabi_config *config = samsung->config;
+       const struct sabi_commands *commands = &samsung->config->commands;
+       u8 user_level = user_brightness + config->min_brightness;
 
-       if (has_stepping_quirk && user_level != 0) {
+       if (samsung->has_stepping_quirk && user_level != 0) {
                /*
                 * short circuit if the specified level is what's already set
                 * to prevent the screen from flickering needlessly
                 */
-               if (user_brightness == read_brightness())
+               if (user_brightness == read_brightness(samsung))
                        return;
 
-               sabi_set_command(sabi_config->commands.set_brightness, 0);
+               sabi_set_commandb(samsung, commands->set_brightness, 0);
        }
 
-       sabi_set_command(sabi_config->commands.set_brightness, user_level);
+       sabi_set_commandb(samsung, commands->set_brightness, user_level);
 }
 
 static int get_brightness(struct backlight_device *bd)
 {
-       return (int)read_brightness();
+       struct samsung_laptop *samsung = bl_get_data(bd);
+
+       return read_brightness(samsung);
 }
 
-static void check_for_stepping_quirk(void)
+static void check_for_stepping_quirk(struct samsung_laptop *samsung)
 {
-       u8 initial_level;
-       u8 check_level;
-       u8 orig_level = read_brightness();
+       int initial_level;
+       int check_level;
+       int orig_level = read_brightness(samsung);
 
        /*
         * Some laptops exhibit the strange behaviour of stepping toward
@@ -416,34 +512,38 @@ static void check_for_stepping_quirk(void)
         */
 
        if (orig_level == 0)
-               set_brightness(1);
+               set_brightness(samsung, 1);
 
-       initial_level = read_brightness();
+       initial_level = read_brightness(samsung);
 
        if (initial_level <= 2)
                check_level = initial_level + 2;
        else
                check_level = initial_level - 2;
 
-       has_stepping_quirk = false;
-       set_brightness(check_level);
+       samsung->has_stepping_quirk = false;
+       set_brightness(samsung, check_level);
 
-       if (read_brightness() != check_level) {
-               has_stepping_quirk = true;
+       if (read_brightness(samsung) != check_level) {
+               samsung->has_stepping_quirk = true;
                pr_info("enabled workaround for brightness stepping quirk\n");
        }
 
-       set_brightness(orig_level);
+       set_brightness(samsung, orig_level);
 }
 
 static int update_status(struct backlight_device *bd)
 {
-       set_brightness(bd->props.brightness);
+       struct samsung_laptop *samsung = bl_get_data(bd);
+       const struct sabi_commands *commands = &samsung->config->commands;
+
+       set_brightness(samsung, bd->props.brightness);
 
        if (bd->props.power == FB_BLANK_UNBLANK)
-               sabi_set_command(sabi_config->commands.set_backlight, 1);
+               sabi_set_commandb(samsung, commands->set_backlight, 1);
        else
-               sabi_set_command(sabi_config->commands.set_backlight, 0);
+               sabi_set_commandb(samsung, commands->set_backlight, 0);
+
        return 0;
 }
 
@@ -452,66 +552,101 @@ static const struct backlight_ops backlight_ops = {
        .update_status  = update_status,
 };
 
-static int rfkill_set(void *data, bool blocked)
+static int seclinux_rfkill_set(void *data, bool blocked)
 {
-       /* Do something with blocked...*/
-       /*
-        * blocked == false is on
-        * blocked == true is off
-        */
-       if (blocked)
-               sabi_set_command(sabi_config->commands.set_wireless_button, 0);
-       else
-               sabi_set_command(sabi_config->commands.set_wireless_button, 1);
+       struct samsung_rfkill *srfkill = data;
+       struct samsung_laptop *samsung = srfkill->samsung;
+       const struct sabi_commands *commands = &samsung->config->commands;
 
-       return 0;
+       return sabi_set_commandb(samsung, commands->set_wireless_button,
+                                !blocked);
 }
 
-static struct rfkill_ops rfkill_ops = {
-       .set_block = rfkill_set,
+static struct rfkill_ops seclinux_rfkill_ops = {
+       .set_block = seclinux_rfkill_set,
 };
 
-static int init_wireless(struct platform_device *sdev)
+static int swsmi_wireless_status(struct samsung_laptop *samsung,
+                                struct sabi_data *data)
 {
-       int retval;
+       const struct sabi_commands *commands = &samsung->config->commands;
 
-       rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN,
-                          &rfkill_ops, NULL);
-       if (!rfk)
-               return -ENOMEM;
-
-       retval = rfkill_register(rfk);
-       if (retval) {
-               rfkill_destroy(rfk);
-               return -ENODEV;
-       }
+       return sabi_command(samsung, commands->get_wireless_status,
+                           NULL, data);
+}
 
-       return 0;
+static int swsmi_rfkill_set(void *priv, bool blocked)
+{
+       struct samsung_rfkill *srfkill = priv;
+       struct samsung_laptop *samsung = srfkill->samsung;
+       const struct sabi_commands *commands = &samsung->config->commands;
+       struct sabi_data data;
+       int ret, i;
+
+       ret = swsmi_wireless_status(samsung, &data);
+       if (ret)
+               return ret;
+
+       /* Don't set the state for non-present devices */
+       for (i = 0; i < 4; i++)
+               if (data.data[i] == 0x02)
+                       data.data[1] = 0;
+
+       if (srfkill->type == RFKILL_TYPE_WLAN)
+               data.data[WL_STATUS_WLAN] = !blocked;
+       else if (srfkill->type == RFKILL_TYPE_BLUETOOTH)
+               data.data[WL_STATUS_BT] = !blocked;
+
+       return sabi_command(samsung, commands->set_wireless_status,
+                           &data, &data);
 }
 
-static void destroy_wireless(void)
+static void swsmi_rfkill_query(struct rfkill *rfkill, void *priv)
 {
-       rfkill_unregister(rfk);
-       rfkill_destroy(rfk);
+       struct samsung_rfkill *srfkill = priv;
+       struct samsung_laptop *samsung = srfkill->samsung;
+       struct sabi_data data;
+       int ret;
+
+       ret = swsmi_wireless_status(samsung, &data);
+       if (ret)
+               return ;
+
+       if (srfkill->type == RFKILL_TYPE_WLAN)
+               ret = data.data[WL_STATUS_WLAN];
+       else if (srfkill->type == RFKILL_TYPE_BLUETOOTH)
+               ret = data.data[WL_STATUS_BT];
+       else
+               return ;
+
+       rfkill_set_sw_state(rfkill, !ret);
 }
 
+static struct rfkill_ops swsmi_rfkill_ops = {
+       .set_block = swsmi_rfkill_set,
+       .query = swsmi_rfkill_query,
+};
+
 static ssize_t get_performance_level(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       struct sabi_retval sretval;
+       struct samsung_laptop *samsung = dev_get_drvdata(dev);
+       const struct sabi_config *config = samsung->config;
+       const struct sabi_commands *commands = &config->commands;
+       struct sabi_data sretval;
        int retval;
        int i;
 
        /* Read the state */
-       retval = sabi_get_command(sabi_config->commands.get_performance_level,
-                                 &sretval);
+       retval = sabi_command(samsung, commands->get_performance_level,
+                             NULL, &sretval);
        if (retval)
                return retval;
 
        /* The logic is backwards, yeah, lots of fun... */
-       for (i = 0; sabi_config->performance_levels[i].name; ++i) {
-               if (sretval.retval[0] == sabi_config->performance_levels[i].value)
-                       return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name);
+       for (i = 0; config->performance_levels[i].name; ++i) {
+               if (sretval.data[0] == config->performance_levels[i].value)
+                       return sprintf(buf, "%s\n", config->performance_levels[i].name);
        }
        return sprintf(buf, "%s\n", "unknown");
 }
@@ -520,280 +655,189 @@ static ssize_t set_performance_level(struct device *dev,
                                struct device_attribute *attr, const char *buf,
                                size_t count)
 {
-       if (count >= 1) {
-               int i;
-               for (i = 0; sabi_config->performance_levels[i].name; ++i) {
-                       const struct sabi_performance_level *level =
-                               &sabi_config->performance_levels[i];
-                       if (!strncasecmp(level->name, buf, strlen(level->name))) {
-                               sabi_set_command(sabi_config->commands.set_performance_level,
-                                                level->value);
-                               break;
-                       }
+       struct samsung_laptop *samsung = dev_get_drvdata(dev);
+       const struct sabi_config *config = samsung->config;
+       const struct sabi_commands *commands = &config->commands;
+       int i;
+
+       if (count < 1)
+               return count;
+
+       for (i = 0; config->performance_levels[i].name; ++i) {
+               const struct sabi_performance_level *level =
+                       &config->performance_levels[i];
+               if (!strncasecmp(level->name, buf, strlen(level->name))) {
+                       sabi_set_commandb(samsung,
+                                         commands->set_performance_level,
+                                         level->value);
+                       break;
                }
-               if (!sabi_config->performance_levels[i].name)
-                       return -EINVAL;
        }
+
+       if (!config->performance_levels[i].name)
+               return -EINVAL;
+
        return count;
 }
+
 static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
                   get_performance_level, set_performance_level);
 
-
-static int __init dmi_check_cb(const struct dmi_system_id *id)
+static int read_battery_life_extender(struct samsung_laptop *samsung)
 {
-       pr_info("found laptop model '%s'\n",
-               id->ident);
-       return 1;
-}
+       const struct sabi_commands *commands = &samsung->config->commands;
+       struct sabi_data data;
+       int retval;
 
-static struct dmi_system_id __initdata samsung_dmi_table[] = {
-       {
-               .ident = "N128",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N128"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N128"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N130",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N130"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N130"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N510",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N510"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N510"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "X125",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X125"),
-                       DMI_MATCH(DMI_BOARD_NAME, "X125"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "X120/X170",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"),
-                       DMI_MATCH(DMI_BOARD_NAME, "X120/X170"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "NC10",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
-                       DMI_MATCH(DMI_BOARD_NAME, "NC10"),
-               },
-               .callback = dmi_check_cb,
-       },
-               {
-               .ident = "NP-Q45",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
-                       DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"),
-               },
-               .callback = dmi_check_cb,
-               },
-       {
-               .ident = "X360",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
-                       DMI_MATCH(DMI_BOARD_NAME, "X360"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R410 Plus",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R410P"),
-                       DMI_MATCH(DMI_BOARD_NAME, "R460"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R518",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R518"),
-                       DMI_MATCH(DMI_BOARD_NAME, "R518"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R519/R719",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"),
-                       DMI_MATCH(DMI_BOARD_NAME, "R519/R719"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N150/N210/N220",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N220",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N220"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N220"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N150/N210/N220/N230",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N150P/N210P/N220P",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R700",
-               .matches = {
-                     DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                     DMI_MATCH(DMI_PRODUCT_NAME, "SR700"),
-                     DMI_MATCH(DMI_BOARD_NAME, "SR700"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R530/R730",
-               .matches = {
-                     DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                     DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
-                     DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "NF110/NF210/NF310",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
-                       DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "N145P/N250P/N260P",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
-                       DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R70/R71",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR,
-                                       "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
-                       DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "P460",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
-                       DMI_MATCH(DMI_BOARD_NAME, "P460"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "R528/R728",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R528/R728"),
-                       DMI_MATCH(DMI_BOARD_NAME, "R528/R728"),
-               },
-               .callback = dmi_check_cb,
-       },
-       {
-               .ident = "NC210/NC110",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
-                       DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
-               },
-               .callback = dmi_check_cb,
-       },
-               {
-               .ident = "X520",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X520"),
-                       DMI_MATCH(DMI_BOARD_NAME, "X520"),
-               },
-               .callback = dmi_check_cb,
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
+       if (commands->get_battery_life_extender == 0xFFFF)
+               return -ENODEV;
 
-static int find_signature(void __iomem *memcheck, const char *testStr)
-{
-       int i = 0;
-       int loca;
+       memset(&data, 0, sizeof(data));
+       data.data[0] = 0x80;
+       retval = sabi_command(samsung, commands->get_battery_life_extender,
+                             &data, &data);
 
-       for (loca = 0; loca < 0xffff; loca++) {
-               char temp = readb(memcheck + loca);
+       if (retval)
+               return retval;
 
-               if (temp == testStr[i]) {
-                       if (i == strlen(testStr)-1)
+       if (data.data[0] != 0 && data.data[0] != 1)
+               return -ENODEV;
+
+       return data.data[0];
+}
+
+static int write_battery_life_extender(struct samsung_laptop *samsung,
+                                      int enabled)
+{
+       const struct sabi_commands *commands = &samsung->config->commands;
+       struct sabi_data data;
+
+       memset(&data, 0, sizeof(data));
+       data.data[0] = 0x80 | enabled;
+       return sabi_command(samsung, commands->set_battery_life_extender,
+                           &data, NULL);
+}
+
+static ssize_t get_battery_life_extender(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct samsung_laptop *samsung = dev_get_drvdata(dev);
+       int ret;
+
+       ret = read_battery_life_extender(samsung);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n", ret);
+}
+
+static ssize_t set_battery_life_extender(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct samsung_laptop *samsung = dev_get_drvdata(dev);
+       int ret, value;
+
+       if (!count || sscanf(buf, "%i", &value) != 1)
+               return -EINVAL;
+
+       ret = write_battery_life_extender(samsung, !!value);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(battery_life_extender, S_IWUSR | S_IRUGO,
+                  get_battery_life_extender, set_battery_life_extender);
+
+static int read_usb_charge(struct samsung_laptop *samsung)
+{
+       const struct sabi_commands *commands = &samsung->config->commands;
+       struct sabi_data data;
+       int retval;
+
+       if (commands->get_usb_charge == 0xFFFF)
+               return -ENODEV;
+
+       memset(&data, 0, sizeof(data));
+       data.data[0] = 0x80;
+       retval = sabi_command(samsung, commands->get_usb_charge,
+                             &data, &data);
+
+       if (retval)
+               return retval;
+
+       if (data.data[0] != 0 && data.data[0] != 1)
+               return -ENODEV;
+
+       return data.data[0];
+}
+
+static int write_usb_charge(struct samsung_laptop *samsung,
+                           int enabled)
+{
+       const struct sabi_commands *commands = &samsung->config->commands;
+       struct sabi_data data;
+
+       memset(&data, 0, sizeof(data));
+       data.data[0] = 0x80 | enabled;
+       return sabi_command(samsung, commands->set_usb_charge,
+                           &data, NULL);
+}
+
+static ssize_t get_usb_charge(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       struct samsung_laptop *samsung = dev_get_drvdata(dev);
+       int ret;
+
+       ret = read_usb_charge(samsung);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n", ret);
+}
+
+static ssize_t set_usb_charge(struct device *dev,
+                             struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct samsung_laptop *samsung = dev_get_drvdata(dev);
+       int ret, value;
+
+       if (!count || sscanf(buf, "%i", &value) != 1)
+               return -EINVAL;
+
+       ret = write_usb_charge(samsung, !!value);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO,
+                  get_usb_charge, set_usb_charge);
+
+static struct attribute *platform_attributes[] = {
+       &dev_attr_performance_level.attr,
+       &dev_attr_battery_life_extender.attr,
+       &dev_attr_usb_charge.attr,
+       NULL
+};
+
+static int find_signature(void __iomem *memcheck, const char *testStr)
+{
+       int i = 0;
+       int loca;
+
+       for (loca = 0; loca < 0xffff; loca++) {
+               char temp = readb(memcheck + loca);
+
+               if (temp == testStr[i]) {
+                       if (i == strlen(testStr)-1)
                                break;
                        ++i;
                } else {
@@ -803,153 +847,772 @@ static int find_signature(void __iomem *memcheck, const char *testStr)
        return loca;
 }
 
-static int __init samsung_init(void)
+static void samsung_rfkill_exit(struct samsung_laptop *samsung)
 {
-       struct backlight_properties props;
-       struct sabi_retval sretval;
-       unsigned int ifaceP;
-       int i;
-       int loca;
+       if (samsung->wlan.rfkill) {
+               rfkill_unregister(samsung->wlan.rfkill);
+               rfkill_destroy(samsung->wlan.rfkill);
+               samsung->wlan.rfkill = NULL;
+       }
+       if (samsung->bluetooth.rfkill) {
+               rfkill_unregister(samsung->bluetooth.rfkill);
+               rfkill_destroy(samsung->bluetooth.rfkill);
+               samsung->bluetooth.rfkill = NULL;
+       }
+}
+
+static int samsung_new_rfkill(struct samsung_laptop *samsung,
+                             struct samsung_rfkill *arfkill,
+                             const char *name, enum rfkill_type type,
+                             const struct rfkill_ops *ops,
+                             int blocked)
+{
+       struct rfkill **rfkill = &arfkill->rfkill;
+       int ret;
+
+       arfkill->type = type;
+       arfkill->samsung = samsung;
+
+       *rfkill = rfkill_alloc(name, &samsung->platform_device->dev,
+                              type, ops, arfkill);
+
+       if (!*rfkill)
+               return -EINVAL;
+
+       if (blocked != -1)
+               rfkill_init_sw_state(*rfkill, blocked);
+
+       ret = rfkill_register(*rfkill);
+       if (ret) {
+               rfkill_destroy(*rfkill);
+               *rfkill = NULL;
+               return ret;
+       }
+       return 0;
+}
+
+static int __init samsung_rfkill_init_seclinux(struct samsung_laptop *samsung)
+{
+       return samsung_new_rfkill(samsung, &samsung->wlan, "samsung-wlan",
+                                 RFKILL_TYPE_WLAN, &seclinux_rfkill_ops, -1);
+}
+
+static int __init samsung_rfkill_init_swsmi(struct samsung_laptop *samsung)
+{
+       struct sabi_data data;
+       int ret;
+
+       ret = swsmi_wireless_status(samsung, &data);
+       if (ret) {
+               /* Some swsmi laptops use the old seclinux way to control
+                * wireless devices */
+               if (ret == -EINVAL)
+                       ret = samsung_rfkill_init_seclinux(samsung);
+               return ret;
+       }
+
+       /* 0x02 seems to mean that the device is no present/available */
+
+       if (data.data[WL_STATUS_WLAN] != 0x02)
+               ret = samsung_new_rfkill(samsung, &samsung->wlan,
+                                        "samsung-wlan",
+                                        RFKILL_TYPE_WLAN,
+                                        &swsmi_rfkill_ops,
+                                        !data.data[WL_STATUS_WLAN]);
+       if (ret)
+               goto exit;
+
+       if (data.data[WL_STATUS_BT] != 0x02)
+               ret = samsung_new_rfkill(samsung, &samsung->bluetooth,
+                                        "samsung-bluetooth",
+                                        RFKILL_TYPE_BLUETOOTH,
+                                        &swsmi_rfkill_ops,
+                                        !data.data[WL_STATUS_BT]);
+       if (ret)
+               goto exit;
+
+exit:
+       if (ret)
+               samsung_rfkill_exit(samsung);
+
+       return ret;
+}
+
+static int __init samsung_rfkill_init(struct samsung_laptop *samsung)
+{
+       if (samsung->config->sabi_version == 2)
+               return samsung_rfkill_init_seclinux(samsung);
+       if (samsung->config->sabi_version == 3)
+               return samsung_rfkill_init_swsmi(samsung);
+       return 0;
+}
+
+static int kbd_backlight_enable(struct samsung_laptop *samsung)
+{
+       const struct sabi_commands *commands = &samsung->config->commands;
+       struct sabi_data data;
        int retval;
 
-       mutex_init(&sabi_mutex);
+       if (commands->kbd_backlight == 0xFFFF)
+               return -ENODEV;
 
-       if (!force && !dmi_check_system(samsung_dmi_table))
+       memset(&data, 0, sizeof(data));
+       data.d0 = 0xaabb;
+       retval = sabi_command(samsung, commands->kbd_backlight,
+                             &data, &data);
+
+       if (retval)
+               return retval;
+
+       if (data.d0 != 0xccdd)
                return -ENODEV;
+       return 0;
+}
 
-       f0000_segment = ioremap_nocache(0xf0000, 0xffff);
-       if (!f0000_segment) {
-               pr_err("Can't map the segment at 0xf0000\n");
-               return -EINVAL;
+static int kbd_backlight_read(struct samsung_laptop *samsung)
+{
+       const struct sabi_commands *commands = &samsung->config->commands;
+       struct sabi_data data;
+       int retval;
+
+       memset(&data, 0, sizeof(data));
+       data.data[0] = 0x81;
+       retval = sabi_command(samsung, commands->kbd_backlight,
+                             &data, &data);
+
+       if (retval)
+               return retval;
+
+       return data.data[0];
+}
+
+static int kbd_backlight_write(struct samsung_laptop *samsung, int brightness)
+{
+       const struct sabi_commands *commands = &samsung->config->commands;
+       struct sabi_data data;
+
+       memset(&data, 0, sizeof(data));
+       data.d0 = 0x82 | ((brightness & 0xFF) << 8);
+       return sabi_command(samsung, commands->kbd_backlight,
+                           &data, NULL);
+}
+
+static void kbd_led_update(struct work_struct *work)
+{
+       struct samsung_laptop *samsung;
+
+       samsung = container_of(work, struct samsung_laptop, kbd_led_work);
+       kbd_backlight_write(samsung, samsung->kbd_led_wk);
+}
+
+static void kbd_led_set(struct led_classdev *led_cdev,
+                       enum led_brightness value)
+{
+       struct samsung_laptop *samsung;
+
+       samsung = container_of(led_cdev, struct samsung_laptop, kbd_led);
+
+       if (value > samsung->kbd_led.max_brightness)
+               value = samsung->kbd_led.max_brightness;
+       else if (value < 0)
+               value = 0;
+
+       samsung->kbd_led_wk = value;
+       queue_work(samsung->led_workqueue, &samsung->kbd_led_work);
+}
+
+static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
+{
+       struct samsung_laptop *samsung;
+
+       samsung = container_of(led_cdev, struct samsung_laptop, kbd_led);
+       return kbd_backlight_read(samsung);
+}
+
+static void samsung_leds_exit(struct samsung_laptop *samsung)
+{
+       if (!IS_ERR_OR_NULL(samsung->kbd_led.dev))
+               led_classdev_unregister(&samsung->kbd_led);
+       if (samsung->led_workqueue)
+               destroy_workqueue(samsung->led_workqueue);
+}
+
+static int __init samsung_leds_init(struct samsung_laptop *samsung)
+{
+       int ret = 0;
+
+       samsung->led_workqueue = create_singlethread_workqueue("led_workqueue");
+       if (!samsung->led_workqueue)
+               return -ENOMEM;
+
+       if (kbd_backlight_enable(samsung) >= 0) {
+               INIT_WORK(&samsung->kbd_led_work, kbd_led_update);
+
+               samsung->kbd_led.name = "samsung::kbd_backlight";
+               samsung->kbd_led.brightness_set = kbd_led_set;
+               samsung->kbd_led.brightness_get = kbd_led_get;
+               samsung->kbd_led.max_brightness = 8;
+
+               ret = led_classdev_register(&samsung->platform_device->dev,
+                                          &samsung->kbd_led);
+       }
+
+       if (ret)
+               samsung_leds_exit(samsung);
+
+       return ret;
+}
+
+static void samsung_backlight_exit(struct samsung_laptop *samsung)
+{
+       if (samsung->backlight_device) {
+               backlight_device_unregister(samsung->backlight_device);
+               samsung->backlight_device = NULL;
+       }
+}
+
+static int __init samsung_backlight_init(struct samsung_laptop *samsung)
+{
+       struct backlight_device *bd;
+       struct backlight_properties props;
+
+       if (!samsung->handle_backlight)
+               return 0;
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_PLATFORM;
+       props.max_brightness = samsung->config->max_brightness -
+               samsung->config->min_brightness;
+
+       bd = backlight_device_register("samsung",
+                                      &samsung->platform_device->dev,
+                                      samsung, &backlight_ops,
+                                      &props);
+       if (IS_ERR(bd))
+               return PTR_ERR(bd);
+
+       samsung->backlight_device = bd;
+       samsung->backlight_device->props.brightness = read_brightness(samsung);
+       samsung->backlight_device->props.power = FB_BLANK_UNBLANK;
+       backlight_update_status(samsung->backlight_device);
+
+       return 0;
+}
+
+static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
+                                      struct attribute *attr, int idx)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct samsung_laptop *samsung = platform_get_drvdata(pdev);
+       bool ok = true;
+
+       if (attr == &dev_attr_performance_level.attr)
+               ok = !!samsung->config->performance_levels[0].name;
+       if (attr == &dev_attr_battery_life_extender.attr)
+               ok = !!(read_battery_life_extender(samsung) >= 0);
+       if (attr == &dev_attr_usb_charge.attr)
+               ok = !!(read_usb_charge(samsung) >= 0);
+
+       return ok ? attr->mode : 0;
+}
+
+static struct attribute_group platform_attribute_group = {
+       .is_visible = samsung_sysfs_is_visible,
+       .attrs = platform_attributes
+};
+
+static void samsung_sysfs_exit(struct samsung_laptop *samsung)
+{
+       struct platform_device *device = samsung->platform_device;
+
+       sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
+}
+
+static int __init samsung_sysfs_init(struct samsung_laptop *samsung)
+{
+       struct platform_device *device = samsung->platform_device;
+
+       return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
+
+}
+
+static int show_call(struct seq_file *m, void *data)
+{
+       struct samsung_laptop *samsung = m->private;
+       struct sabi_data *sdata = &samsung->debug.data;
+       int ret;
+
+       seq_printf(m, "SABI 0x%04x {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n",
+                  samsung->debug.command,
+                  sdata->d0, sdata->d1, sdata->d2, sdata->d3);
+
+       ret = sabi_command(samsung, samsung->debug.command, sdata, sdata);
+
+       if (ret) {
+               seq_printf(m, "SABI command 0x%04x failed\n",
+                          samsung->debug.command);
+               return ret;
+       }
+
+       seq_printf(m, "SABI {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n",
+                  sdata->d0, sdata->d1, sdata->d2, sdata->d3);
+       return 0;
+}
+
+static int samsung_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_call, inode->i_private);
+}
+
+static const struct file_operations samsung_laptop_call_io_ops = {
+       .owner = THIS_MODULE,
+       .open = samsung_debugfs_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static void samsung_debugfs_exit(struct samsung_laptop *samsung)
+{
+       debugfs_remove_recursive(samsung->debug.root);
+}
+
+static int samsung_debugfs_init(struct samsung_laptop *samsung)
+{
+       struct dentry *dent;
+
+       samsung->debug.root = debugfs_create_dir("samsung-laptop", NULL);
+       if (!samsung->debug.root) {
+               pr_err("failed to create debugfs directory");
+               goto error_debugfs;
        }
 
+       samsung->debug.f0000_wrapper.data = samsung->f0000_segment;
+       samsung->debug.f0000_wrapper.size = 0xffff;
+
+       samsung->debug.data_wrapper.data = &samsung->debug.data;
+       samsung->debug.data_wrapper.size = sizeof(samsung->debug.data);
+
+       samsung->debug.sdiag_wrapper.data = samsung->sdiag;
+       samsung->debug.sdiag_wrapper.size = strlen(samsung->sdiag);
+
+       dent = debugfs_create_u16("command", S_IRUGO | S_IWUSR,
+                                 samsung->debug.root, &samsung->debug.command);
+       if (!dent)
+               goto error_debugfs;
+
+       dent = debugfs_create_u32("d0", S_IRUGO | S_IWUSR, samsung->debug.root,
+                                 &samsung->debug.data.d0);
+       if (!dent)
+               goto error_debugfs;
+
+       dent = debugfs_create_u32("d1", S_IRUGO | S_IWUSR, samsung->debug.root,
+                                 &samsung->debug.data.d1);
+       if (!dent)
+               goto error_debugfs;
+
+       dent = debugfs_create_u16("d2", S_IRUGO | S_IWUSR, samsung->debug.root,
+                                 &samsung->debug.data.d2);
+       if (!dent)
+               goto error_debugfs;
+
+       dent = debugfs_create_u8("d3", S_IRUGO | S_IWUSR, samsung->debug.root,
+                                &samsung->debug.data.d3);
+       if (!dent)
+               goto error_debugfs;
+
+       dent = debugfs_create_blob("data", S_IRUGO | S_IWUSR,
+                                  samsung->debug.root,
+                                  &samsung->debug.data_wrapper);
+       if (!dent)
+               goto error_debugfs;
+
+       dent = debugfs_create_blob("f0000_segment", S_IRUSR | S_IWUSR,
+                                  samsung->debug.root,
+                                  &samsung->debug.f0000_wrapper);
+       if (!dent)
+               goto error_debugfs;
+
+       dent = debugfs_create_file("call", S_IFREG | S_IRUGO,
+                                  samsung->debug.root, samsung,
+                                  &samsung_laptop_call_io_ops);
+       if (!dent)
+               goto error_debugfs;
+
+       dent = debugfs_create_blob("sdiag", S_IRUGO | S_IWUSR,
+                                  samsung->debug.root,
+                                  &samsung->debug.sdiag_wrapper);
+       if (!dent)
+               goto error_debugfs;
+
+       return 0;
+
+error_debugfs:
+       samsung_debugfs_exit(samsung);
+       return -ENOMEM;
+}
+
+static void samsung_sabi_exit(struct samsung_laptop *samsung)
+{
+       const struct sabi_config *config = samsung->config;
+
+       /* Turn off "Linux" mode in the BIOS */
+       if (config && config->commands.set_linux != 0xff)
+               sabi_set_commandb(samsung, config->commands.set_linux, 0x80);
+
+       if (samsung->sabi_iface) {
+               iounmap(samsung->sabi_iface);
+               samsung->sabi_iface = NULL;
+       }
+       if (samsung->f0000_segment) {
+               iounmap(samsung->f0000_segment);
+               samsung->f0000_segment = NULL;
+       }
+
+       samsung->config = NULL;
+}
+
+static __init void samsung_sabi_infos(struct samsung_laptop *samsung, int loca,
+                                     unsigned int ifaceP)
+{
+       const struct sabi_config *config = samsung->config;
+
+       printk(KERN_DEBUG "This computer supports SABI==%x\n",
+              loca + 0xf0000 - 6);
+
+       printk(KERN_DEBUG "SABI header:\n");
+       printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
+              readw(samsung->sabi + config->header_offsets.port));
+       printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
+              readb(samsung->sabi + config->header_offsets.iface_func));
+       printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
+              readb(samsung->sabi + config->header_offsets.en_mem));
+       printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
+              readb(samsung->sabi + config->header_offsets.re_mem));
+       printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
+              readw(samsung->sabi + config->header_offsets.data_offset));
+       printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
+              readw(samsung->sabi + config->header_offsets.data_segment));
+
+       printk(KERN_DEBUG " SABI pointer = 0x%08x\n", ifaceP);
+}
+
+static void __init samsung_sabi_diag(struct samsung_laptop *samsung)
+{
+       int loca = find_signature(samsung->f0000_segment, "SDiaG@");
+       int i;
+
+       if (loca == 0xffff)
+               return ;
+
+       /* Example:
+        * Ident: @SDiaG@686XX-N90X3A/966-SEC-07HL-S90X3A
+        *
+        * Product name: 90X3A
+        * BIOS Version: 07HL
+        */
+       loca += 1;
+       for (i = 0; loca < 0xffff && i < sizeof(samsung->sdiag) - 1; loca++) {
+               char temp = readb(samsung->f0000_segment + loca);
+
+               if (isalnum(temp) || temp == '/' || temp == '-')
+                       samsung->sdiag[i++] = temp;
+               else
+                       break ;
+       }
+
+       if (debug && samsung->sdiag[0])
+               pr_info("sdiag: %s", samsung->sdiag);
+}
+
+static int __init samsung_sabi_init(struct samsung_laptop *samsung)
+{
+       const struct sabi_config *config = NULL;
+       const struct sabi_commands *commands;
+       unsigned int ifaceP;
+       int ret = 0;
+       int i;
+       int loca;
+
+       samsung->f0000_segment = ioremap_nocache(0xf0000, 0xffff);
+       if (!samsung->f0000_segment) {
+               if (debug || force)
+                       pr_err("Can't map the segment at 0xf0000\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       samsung_sabi_diag(samsung);
+
        /* Try to find one of the signatures in memory to find the header */
        for (i = 0; sabi_configs[i].test_string != 0; ++i) {
-               sabi_config = &sabi_configs[i];
-               loca = find_signature(f0000_segment, sabi_config->test_string);
+               samsung->config = &sabi_configs[i];
+               loca = find_signature(samsung->f0000_segment,
+                                     samsung->config->test_string);
                if (loca != 0xffff)
                        break;
        }
 
        if (loca == 0xffff) {
-               pr_err("This computer does not support SABI\n");
-               goto error_no_signature;
+               if (debug || force)
+                       pr_err("This computer does not support SABI\n");
+               ret = -ENODEV;
+               goto exit;
        }
 
+       config = samsung->config;
+       commands = &config->commands;
+
        /* point to the SMI port Number */
        loca += 1;
-       sabi = (f0000_segment + loca);
-
-       if (debug) {
-               printk(KERN_DEBUG "This computer supports SABI==%x\n",
-                       loca + 0xf0000 - 6);
-               printk(KERN_DEBUG "SABI header:\n");
-               printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
-                       readw(sabi + sabi_config->header_offsets.port));
-               printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
-                       readb(sabi + sabi_config->header_offsets.iface_func));
-               printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
-                       readb(sabi + sabi_config->header_offsets.en_mem));
-               printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
-                       readb(sabi + sabi_config->header_offsets.re_mem));
-               printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
-                       readw(sabi + sabi_config->header_offsets.data_offset));
-               printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
-                       readw(sabi + sabi_config->header_offsets.data_segment));
-       }
+       samsung->sabi = (samsung->f0000_segment + loca);
 
        /* Get a pointer to the SABI Interface */
-       ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4;
-       ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff;
-       sabi_iface = ioremap_nocache(ifaceP, 16);
-       if (!sabi_iface) {
-               pr_err("Can't remap %x\n", ifaceP);
-               goto error_no_signature;
-       }
-       if (debug) {
-               printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
-               printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
+       ifaceP = (readw(samsung->sabi + config->header_offsets.data_segment) & 0x0ffff) << 4;
+       ifaceP += readw(samsung->sabi + config->header_offsets.data_offset) & 0x0ffff;
 
-               test_backlight();
-               test_wireless();
+       if (debug)
+               samsung_sabi_infos(samsung, loca, ifaceP);
 
-               retval = sabi_get_command(sabi_config->commands.get_brightness,
-                                         &sretval);
-               printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]);
+       samsung->sabi_iface = ioremap_nocache(ifaceP, 16);
+       if (!samsung->sabi_iface) {
+               pr_err("Can't remap %x\n", ifaceP);
+               ret = -EINVAL;
+               goto exit;
        }
 
        /* Turn on "Linux" mode in the BIOS */
-       if (sabi_config->commands.set_linux != 0xff) {
-               retval = sabi_set_command(sabi_config->commands.set_linux,
-                                         0x81);
+       if (commands->set_linux != 0xff) {
+               int retval = sabi_set_commandb(samsung,
+                                              commands->set_linux, 0x81);
                if (retval) {
                        pr_warn("Linux mode was not set!\n");
-                       goto error_no_platform;
+                       ret = -ENODEV;
+                       goto exit;
                }
        }
 
        /* Check for stepping quirk */
-       check_for_stepping_quirk();
+       if (samsung->handle_backlight)
+               check_for_stepping_quirk(samsung);
 
-       /* knock up a platform device to hang stuff off of */
-       sdev = platform_device_register_simple("samsung", -1, NULL, 0);
-       if (IS_ERR(sdev))
-               goto error_no_platform;
+       pr_info("detected SABI interface: %s\n",
+               samsung->config->test_string);
 
-       /* create a backlight device to talk to this one */
-       memset(&props, 0, sizeof(struct backlight_properties));
-       props.type = BACKLIGHT_PLATFORM;
-       props.max_brightness = sabi_config->max_brightness -
-                               sabi_config->min_brightness;
-       backlight_device = backlight_device_register("samsung", &sdev->dev,
-                                                    NULL, &backlight_ops,
-                                                    &props);
-       if (IS_ERR(backlight_device))
-               goto error_no_backlight;
-
-       backlight_device->props.brightness = read_brightness();
-       backlight_device->props.power = FB_BLANK_UNBLANK;
-       backlight_update_status(backlight_device);
-
-       retval = init_wireless(sdev);
-       if (retval)
-               goto error_no_rfk;
+exit:
+       if (ret)
+               samsung_sabi_exit(samsung);
 
-       retval = device_create_file(&sdev->dev, &dev_attr_performance_level);
-       if (retval)
-               goto error_file_create;
+       return ret;
+}
+
+static void samsung_platform_exit(struct samsung_laptop *samsung)
+{
+       if (samsung->platform_device) {
+               platform_device_unregister(samsung->platform_device);
+               samsung->platform_device = NULL;
+       }
+}
+
+static int __init samsung_platform_init(struct samsung_laptop *samsung)
+{
+       struct platform_device *pdev;
 
+       pdev = platform_device_register_simple("samsung", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       samsung->platform_device = pdev;
+       platform_set_drvdata(samsung->platform_device, samsung);
        return 0;
+}
 
-error_file_create:
-       destroy_wireless();
+static struct samsung_quirks *quirks;
 
-error_no_rfk:
-       backlight_device_unregister(backlight_device);
+static int __init samsung_dmi_matched(const struct dmi_system_id *d)
+{
+       quirks = d->driver_data;
+       return 0;
+}
 
-error_no_backlight:
-       platform_device_unregister(sdev);
+static struct dmi_system_id __initdata samsung_dmi_table[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                                       "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                                       "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                                       "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR,
+                                       "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
+               },
+       },
+       /* Specific DMI ids for laptop with quirks */
+       {
+        .callback = samsung_dmi_matched,
+        .ident = "N150P",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
+               DMI_MATCH(DMI_BOARD_NAME, "N150P"),
+               },
+        .driver_data = &samsung_broken_acpi_video,
+       },
+       {
+        .callback = samsung_dmi_matched,
+        .ident = "N145P/N250P/N260P",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
+               DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
+               },
+        .driver_data = &samsung_broken_acpi_video,
+       },
+       {
+        .callback = samsung_dmi_matched,
+        .ident = "N150/N210/N220",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+               DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+               },
+        .driver_data = &samsung_broken_acpi_video,
+       },
+       {
+        .callback = samsung_dmi_matched,
+        .ident = "NF110/NF210/NF310",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
+               DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
+               },
+        .driver_data = &samsung_broken_acpi_video,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
+
+static struct platform_device *samsung_platform_device;
+
+static int __init samsung_init(void)
+{
+       struct samsung_laptop *samsung;
+       int ret;
+
+       quirks = &samsung_unknown;
+       if (!force && !dmi_check_system(samsung_dmi_table))
+               return -ENODEV;
+
+       samsung = kzalloc(sizeof(*samsung), GFP_KERNEL);
+       if (!samsung)
+               return -ENOMEM;
+
+       mutex_init(&samsung->sabi_mutex);
+       samsung->handle_backlight = true;
+       samsung->quirks = quirks;
 
-error_no_platform:
-       iounmap(sabi_iface);
 
-error_no_signature:
-       iounmap(f0000_segment);
-       return -EINVAL;
+#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
+       /* 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;
+               }
+       }
+#endif
+
+       ret = samsung_platform_init(samsung);
+       if (ret)
+               goto error_platform;
+
+       ret = samsung_sabi_init(samsung);
+       if (ret)
+               goto error_sabi;
+
+#ifdef CONFIG_ACPI
+       /* Only log that if we are really on a sabi platform */
+       if (acpi_video_backlight_support() &&
+           !samsung->quirks->broken_acpi_video)
+               pr_info("Backlight controlled by ACPI video driver\n");
+#endif
+
+       ret = samsung_sysfs_init(samsung);
+       if (ret)
+               goto error_sysfs;
+
+       ret = samsung_backlight_init(samsung);
+       if (ret)
+               goto error_backlight;
+
+       ret = samsung_rfkill_init(samsung);
+       if (ret)
+               goto error_rfkill;
+
+       ret = samsung_leds_init(samsung);
+       if (ret)
+               goto error_leds;
+
+       ret = samsung_debugfs_init(samsung);
+       if (ret)
+               goto error_debugfs;
+
+       samsung_platform_device = samsung->platform_device;
+       return ret;
+
+error_debugfs:
+       samsung_leds_exit(samsung);
+error_leds:
+       samsung_rfkill_exit(samsung);
+error_rfkill:
+       samsung_backlight_exit(samsung);
+error_backlight:
+       samsung_sysfs_exit(samsung);
+error_sysfs:
+       samsung_sabi_exit(samsung);
+error_sabi:
+       samsung_platform_exit(samsung);
+error_platform:
+       kfree(samsung);
+       return ret;
 }
 
 static void __exit samsung_exit(void)
 {
-       /* Turn off "Linux" mode in the BIOS */
-       if (sabi_config->commands.set_linux != 0xff)
-               sabi_set_command(sabi_config->commands.set_linux, 0x80);
-
-       device_remove_file(&sdev->dev, &dev_attr_performance_level);
-       backlight_device_unregister(backlight_device);
-       destroy_wireless();
-       iounmap(sabi_iface);
-       iounmap(f0000_segment);
-       platform_device_unregister(sdev);
+       struct samsung_laptop *samsung;
+
+       samsung = platform_get_drvdata(samsung_platform_device);
+
+       samsung_debugfs_exit(samsung);
+       samsung_leds_exit(samsung);
+       samsung_rfkill_exit(samsung);
+       samsung_backlight_exit(samsung);
+       samsung_sysfs_exit(samsung);
+       samsung_sabi_exit(samsung);
+       samsung_platform_exit(samsung);
+
+       kfree(samsung);
+       samsung_platform_device = NULL;
 }
 
 module_init(samsung_init);
index c006dee..8a51795 100644 (file)
@@ -127,7 +127,7 @@ MODULE_PARM_DESC(minor,
                 "default is -1 (automatic)");
 #endif
 
-static int kbd_backlight;      /* = 1 */
+static int kbd_backlight = 1;
 module_param(kbd_backlight, int, 0444);
 MODULE_PARM_DESC(kbd_backlight,
                 "set this to 0 to disable keyboard backlight, "
@@ -347,6 +347,7 @@ static void sony_laptop_report_input_event(u8 event)
        struct input_dev *jog_dev = sony_laptop_input.jog_dev;
        struct input_dev *key_dev = sony_laptop_input.key_dev;
        struct sony_laptop_keypress kp = { NULL };
+       int scancode = -1;
 
        if (event == SONYPI_EVENT_FNKEY_RELEASED ||
                        event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
@@ -380,8 +381,8 @@ static void sony_laptop_report_input_event(u8 event)
                        dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
                        break;
                }
-               if (sony_laptop_input_index[event] != -1) {
-                       kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
+               if ((scancode = sony_laptop_input_index[event]) != -1) {
+                       kp.key = sony_laptop_input_keycode_map[scancode];
                        if (kp.key != KEY_UNKNOWN)
                                kp.dev = key_dev;
                }
@@ -389,9 +390,11 @@ static void sony_laptop_report_input_event(u8 event)
        }
 
        if (kp.dev) {
+               /* if we have a scancode we emit it so we can always
+                   remap the key */
+               if (scancode != -1)
+                       input_event(kp.dev, EV_MSC, MSC_SCAN, scancode);
                input_report_key(kp.dev, kp.key, 1);
-               /* we emit the scancode so we can always remap the key */
-               input_event(kp.dev, EV_MSC, MSC_SCAN, event);
                input_sync(kp.dev);
 
                /* schedule key release */
@@ -466,7 +469,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
        jog_dev->name = "Sony Vaio Jogdial";
        jog_dev->id.bustype = BUS_ISA;
        jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
-       key_dev->dev.parent = &acpi_device->dev;
+       jog_dev->dev.parent = &acpi_device->dev;
 
        input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
        input_set_capability(jog_dev, EV_REL, REL_WHEEL);
index ea0c607..d68c000 100644 (file)
@@ -8658,7 +8658,7 @@ static int __must_check __init get_thinkpad_model_data(
        }
 
        s = dmi_get_system_info(DMI_PRODUCT_VERSION);
-       if (s && !strnicmp(s, "ThinkPad", 8)) {
+       if (s && !(strnicmp(s, "ThinkPad", 8) && strnicmp(s, "Lenovo", 6))) {
                tp->model_str = kstrdup(s, GFP_KERNEL);
                if (!tp->model_str)
                        return -ENOMEM;
index dcdc1f4..ee79ce6 100644 (file)
@@ -52,6 +52,8 @@
 #include <linux/input/sparse-keymap.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/i8042.h>
 
 #include <asm/uaccess.h>
 
@@ -61,6 +63,11 @@ MODULE_AUTHOR("John Belmonte");
 MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
 MODULE_LICENSE("GPL");
 
+#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
+
+/* Scan code for Fn key on TOS1900 models */
+#define TOS1900_FN_SCAN                0x6e
+
 /* Toshiba ACPI method paths */
 #define METHOD_VIDEO_OUT       "\\_SB_.VALX.DSSX"
 
@@ -95,6 +102,8 @@ MODULE_LICENSE("GPL");
 #define HCI_WIRELESS                   0x0056
 
 /* field definitions */
+#define HCI_HOTKEY_DISABLE             0x0b
+#define HCI_HOTKEY_ENABLE              0x09
 #define HCI_LCD_BRIGHTNESS_BITS                3
 #define HCI_LCD_BRIGHTNESS_SHIFT       (16-HCI_LCD_BRIGHTNESS_BITS)
 #define HCI_LCD_BRIGHTNESS_LEVELS      (1 << HCI_LCD_BRIGHTNESS_BITS)
@@ -111,6 +120,7 @@ struct toshiba_acpi_dev {
        const char *method_hci;
        struct rfkill *bt_rfk;
        struct input_dev *hotkey_dev;
+       struct work_struct hotkey_work;
        struct backlight_device *backlight_dev;
        struct led_classdev led_dev;
 
@@ -118,14 +128,18 @@ struct toshiba_acpi_dev {
        int last_key_event;
        int key_event_valid;
 
-       int illumination_supported:1;
-       int video_supported:1;
-       int fan_supported:1;
-       int system_event_supported:1;
+       unsigned int illumination_supported:1;
+       unsigned int video_supported:1;
+       unsigned int fan_supported:1;
+       unsigned int system_event_supported:1;
+       unsigned int ntfy_supported:1;
+       unsigned int info_supported:1;
 
        struct mutex mutex;
 };
 
+static struct toshiba_acpi_dev *toshiba_acpi;
+
 static const struct acpi_device_id toshiba_device_ids[] = {
        {"TOS6200", 0},
        {"TOS6208", 0},
@@ -138,6 +152,8 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
        { KE_KEY, 0x101, { KEY_MUTE } },
        { KE_KEY, 0x102, { KEY_ZOOMOUT } },
        { KE_KEY, 0x103, { KEY_ZOOMIN } },
+       { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
+       { KE_KEY, 0x139, { KEY_ZOOMRESET } },
        { KE_KEY, 0x13b, { KEY_COFFEE } },
        { KE_KEY, 0x13c, { KEY_BATTERY } },
        { KE_KEY, 0x13d, { KEY_SLEEP } },
@@ -146,7 +162,7 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
        { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
        { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
        { KE_KEY, 0x142, { KEY_WLAN } },
-       { KE_KEY, 0x143, { KEY_PROG1 } },
+       { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
        { KE_KEY, 0x17f, { KEY_FN } },
        { KE_KEY, 0xb05, { KEY_PROG2 } },
        { KE_KEY, 0xb06, { KEY_WWW } },
@@ -156,6 +172,7 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
        { KE_KEY, 0xb32, { KEY_NEXTSONG } },
        { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
        { KE_KEY, 0xb5a, { KEY_MEDIA } },
+       { KE_IGNORE, 0x1430, { KEY_RESERVED } },
        { KE_END, 0 },
 };
 
@@ -847,10 +864,78 @@ static const struct backlight_ops toshiba_backlight_data = {
         .update_status  = set_lcd_status,
 };
 
+static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
+                                     struct serio *port)
+{
+       if (str & 0x20)
+               return false;
+
+       if (unlikely(data == 0xe0))
+               return false;
+
+       if ((data & 0x7f) == TOS1900_FN_SCAN) {
+               schedule_work(&toshiba_acpi->hotkey_work);
+               return true;
+       }
+
+       return false;
+}
+
+static void toshiba_acpi_hotkey_work(struct work_struct *work)
+{
+       acpi_handle ec_handle = ec_get_handle();
+       acpi_status status;
+
+       if (!ec_handle)
+               return;
+
+       status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
+       if (ACPI_FAILURE(status))
+               pr_err("ACPI NTFY method execution failed\n");
+}
+
+/*
+ * Returns hotkey scancode, or < 0 on failure.
+ */
+static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
+{
+       struct acpi_buffer buf;
+       union acpi_object out_obj;
+       acpi_status status;
+
+       buf.pointer = &out_obj;
+       buf.length = sizeof(out_obj);
+
+       status = acpi_evaluate_object(dev->acpi_dev->handle, "INFO",
+                                     NULL, &buf);
+       if (ACPI_FAILURE(status) || out_obj.type != ACPI_TYPE_INTEGER) {
+               pr_err("ACPI INFO method execution failed\n");
+               return -EIO;
+       }
+
+       return out_obj.integer.value;
+}
+
+static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
+                                      int scancode)
+{
+       if (scancode == 0x100)
+               return;
+
+       /* act on key press; ignore key release */
+       if (scancode & 0x80)
+               return;
+
+       if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
+               pr_info("Unknown key %x\n", scancode);
+}
+
 static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
 {
        acpi_status status;
+       acpi_handle ec_handle, handle;
        int error;
+       u32 hci_result;
 
        dev->hotkey_dev = input_allocate_device();
        if (!dev->hotkey_dev) {
@@ -866,21 +951,67 @@ static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
        if (error)
                goto err_free_dev;
 
+       /*
+        * For some machines the SCI responsible for providing hotkey
+        * notification doesn't fire. We can trigger the notification
+        * whenever the Fn key is pressed using the NTFY method, if
+        * supported, so if it's present set up an i8042 key filter
+        * for this purpose.
+        */
+       status = AE_ERROR;
+       ec_handle = ec_get_handle();
+       if (ec_handle)
+               status = acpi_get_handle(ec_handle, "NTFY", &handle);
+
+       if (ACPI_SUCCESS(status)) {
+               INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
+
+               error = i8042_install_filter(toshiba_acpi_i8042_filter);
+               if (error) {
+                       pr_err("Error installing key filter\n");
+                       goto err_free_keymap;
+               }
+
+               dev->ntfy_supported = 1;
+       }
+
+       /*
+        * Determine hotkey query interface. Prefer using the INFO
+        * method when it is available.
+        */
+       status = acpi_get_handle(dev->acpi_dev->handle, "INFO", &handle);
+       if (ACPI_SUCCESS(status)) {
+               dev->info_supported = 1;
+       } else {
+               hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
+               if (hci_result == HCI_SUCCESS)
+                       dev->system_event_supported = 1;
+       }
+
+       if (!dev->info_supported && !dev->system_event_supported) {
+               pr_warn("No hotkey query interface found\n");
+               goto err_remove_filter;
+       }
+
        status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL);
        if (ACPI_FAILURE(status)) {
                pr_info("Unable to enable hotkeys\n");
                error = -ENODEV;
-               goto err_free_keymap;
+               goto err_remove_filter;
        }
 
        error = input_register_device(dev->hotkey_dev);
        if (error) {
                pr_info("Unable to register input device\n");
-               goto err_free_keymap;
+               goto err_remove_filter;
        }
 
+       hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &hci_result);
        return 0;
 
+ err_remove_filter:
+       if (dev->ntfy_supported)
+               i8042_remove_filter(toshiba_acpi_i8042_filter);
  err_free_keymap:
        sparse_keymap_free(dev->hotkey_dev);
  err_free_dev:
@@ -895,6 +1026,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
 
        remove_toshiba_proc_entries(dev);
 
+       if (dev->ntfy_supported) {
+               i8042_remove_filter(toshiba_acpi_i8042_filter);
+               cancel_work_sync(&dev->hotkey_work);
+       }
+
        if (dev->hotkey_dev) {
                input_unregister_device(dev->hotkey_dev);
                sparse_keymap_free(dev->hotkey_dev);
@@ -911,6 +1047,9 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
        if (dev->illumination_supported)
                led_classdev_unregister(&dev->led_dev);
 
+       if (toshiba_acpi)
+               toshiba_acpi = NULL;
+
        kfree(dev);
 
        return 0;
@@ -936,12 +1075,14 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
 {
        struct toshiba_acpi_dev *dev;
        const char *hci_method;
-       u32 hci_result;
        u32 dummy;
        bool bt_present;
        int ret = 0;
        struct backlight_properties props;
 
+       if (toshiba_acpi)
+               return -EBUSY;
+
        pr_info("Toshiba Laptop ACPI Extras version %s\n",
               TOSHIBA_ACPI_VERSION);
 
@@ -963,11 +1104,6 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
 
        mutex_init(&dev->mutex);
 
-       /* enable event fifo */
-       hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
-       if (hci_result == HCI_SUCCESS)
-               dev->system_event_supported = 1;
-
        props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
        dev->backlight_dev = backlight_device_register("toshiba",
@@ -1024,6 +1160,8 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
 
        create_toshiba_proc_entries(dev);
 
+       toshiba_acpi = dev;
+
        return 0;
 
 error:
@@ -1036,40 +1174,64 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
        struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
        u32 hci_result, value;
        int retries = 3;
+       int scancode;
 
-       if (!dev->system_event_supported || event != 0x80)
+       if (event != 0x80)
                return;
 
-       do {
-               hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
-               switch (hci_result) {
-               case HCI_SUCCESS:
-                       if (value == 0x100)
-                               continue;
-                       /* act on key press; ignore key release */
-                       if (value & 0x80)
-                               continue;
-
-                       if (!sparse_keymap_report_event(dev->hotkey_dev,
-                                                       value, 1, true)) {
-                               pr_info("Unknown key %x\n",
-                                      value);
+       if (dev->info_supported) {
+               scancode = toshiba_acpi_query_hotkey(dev);
+               if (scancode < 0)
+                       pr_err("Failed to query hotkey event\n");
+               else if (scancode != 0)
+                       toshiba_acpi_report_hotkey(dev, scancode);
+       } else if (dev->system_event_supported) {
+               do {
+                       hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
+                       switch (hci_result) {
+                       case HCI_SUCCESS:
+                               toshiba_acpi_report_hotkey(dev, (int)value);
+                               break;
+                       case HCI_NOT_SUPPORTED:
+                               /*
+                                * This is a workaround for an unresolved
+                                * issue on some machines where system events
+                                * sporadically become disabled.
+                                */
+                               hci_write1(dev, HCI_SYSTEM_EVENT, 1,
+                                          &hci_result);
+                               pr_notice("Re-enabled hotkeys\n");
+                               /* fall through */
+                       default:
+                               retries--;
+                               break;
                        }
-                       break;
-               case HCI_NOT_SUPPORTED:
-                       /* This is a workaround for an unresolved issue on
-                        * some machines where system events sporadically
-                        * become disabled. */
-                       hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
-                       pr_notice("Re-enabled hotkeys\n");
-                       /* fall through */
-               default:
-                       retries--;
-                       break;
-               }
-       } while (retries && hci_result != HCI_EMPTY);
+               } while (retries && hci_result != HCI_EMPTY);
+       }
+}
+
+static int toshiba_acpi_suspend(struct acpi_device *acpi_dev,
+                               pm_message_t state)
+{
+       struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+       u32 result;
+
+       if (dev->hotkey_dev)
+               hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE, &result);
+
+       return 0;
 }
 
+static int toshiba_acpi_resume(struct acpi_device *acpi_dev)
+{
+       struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+       u32 result;
+
+       if (dev->hotkey_dev)
+               hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
+
+       return 0;
+}
 
 static struct acpi_driver toshiba_acpi_driver = {
        .name   = "Toshiba ACPI driver",
@@ -1080,6 +1242,8 @@ static struct acpi_driver toshiba_acpi_driver = {
                .add            = toshiba_acpi_add,
                .remove         = toshiba_acpi_remove,
                .notify         = toshiba_acpi_notify,
+               .suspend        = toshiba_acpi_suspend,
+               .resume         = toshiba_acpi_resume,
        },
 };
 
@@ -1087,6 +1251,14 @@ static int __init toshiba_acpi_init(void)
 {
        int ret;
 
+       /*
+        * Machines with this WMI guid aren't supported due to bugs in
+        * their AML. This check relies on wmi initializing before
+        * toshiba_acpi to guarantee guids have been identified.
+        */
+       if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
+               return -ENODEV;
+
        toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
        if (!toshiba_proc_dir) {
                pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
index e549eee..41781ed 100644 (file)
@@ -67,19 +67,8 @@ static struct platform_driver xo1_rfkill_driver = {
        .remove         = __devexit_p(xo1_rfkill_remove),
 };
 
-static int __init xo1_rfkill_init(void)
-{
-       return platform_driver_register(&xo1_rfkill_driver);
-}
-
-static void __exit xo1_rfkill_exit(void)
-{
-       platform_driver_unregister(&xo1_rfkill_driver);
-}
+module_platform_driver(xo1_rfkill_driver);
 
 MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:xo1-rfkill");
-
-module_init(xo1_rfkill_init);
-module_exit(xo1_rfkill_exit);
index 8a612de..3976301 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/device.h>
 #include <linux/power_supply.h>
 #include <linux/apm-emulation.h>
 
index 9b3f2bf..6dc01c2 100644 (file)
@@ -19,7 +19,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/module.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index 018de2b..cc439fd 100644 (file)
  *  You may use this code as per GPL version 2
  */
 
+struct device;
+struct device_type;
+struct power_supply;
+
 #ifdef CONFIG_SYSFS
 
 extern void power_supply_init_attrs(struct device_type *dev_type);
index da25eb9..995f966 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/power_supply.h>
 #include <linux/slab.h>
 
index b52b57c..4368e7d 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/ctype.h>
+#include <linux/device.h>
 #include <linux/power_supply.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
index a229de9..36db5a4 100644 (file)
@@ -258,14 +258,6 @@ config REGULATOR_DB8500_PRCMU
          This driver supports the voltage domain regulators controlled by the
          DB8500 PRCMU
 
-config REGULATOR_BQ24022
-       tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
-       help
-         This driver controls a TI bq24022 Charger attached via
-         GPIOs. The provided current regulator can enable/disable
-         charging select between 100 mA and 500 mA charging current
-         limit.
-
 config REGULATOR_TPS6105X
        tristate "TI TPS6105X Power regulators"
        depends on TPS6105X
index b5042c8..94b5274 100644 (file)
@@ -16,7 +16,6 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
 obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
 obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
 obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
-obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
 obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
 obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c
deleted file mode 100644 (file)
index 9fab6d1..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Support for TI bq24022 (bqTINY-II) Dual Input (USB/AC Adpater)
- * 1-Cell Li-Ion Charger connected via GPIOs.
- *
- * Copyright (c) 2008 Philipp Zabel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/regulator/bq24022.h>
-#include <linux/regulator/driver.h>
-
-
-static int bq24022_set_current_limit(struct regulator_dev *rdev,
-                                       int min_uA, int max_uA)
-{
-       struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
-
-       dev_dbg(rdev_get_dev(rdev), "setting current limit to %s mA\n",
-               max_uA >= 500000 ? "500" : "100");
-
-       /* REVISIT: maybe return error if min_uA != 0 ? */
-       gpio_set_value(pdata->gpio_iset2, max_uA >= 500000);
-       return 0;
-}
-
-static int bq24022_get_current_limit(struct regulator_dev *rdev)
-{
-       struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
-
-       return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000;
-}
-
-static int bq24022_enable(struct regulator_dev *rdev)
-{
-       struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
-
-       dev_dbg(rdev_get_dev(rdev), "enabling charger\n");
-
-       gpio_set_value(pdata->gpio_nce, 0);
-       return 0;
-}
-
-static int bq24022_disable(struct regulator_dev *rdev)
-{
-       struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
-
-       dev_dbg(rdev_get_dev(rdev), "disabling charger\n");
-
-       gpio_set_value(pdata->gpio_nce, 1);
-       return 0;
-}
-
-static int bq24022_is_enabled(struct regulator_dev *rdev)
-{
-       struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
-
-       return !gpio_get_value(pdata->gpio_nce);
-}
-
-static struct regulator_ops bq24022_ops = {
-       .set_current_limit = bq24022_set_current_limit,
-       .get_current_limit = bq24022_get_current_limit,
-       .enable            = bq24022_enable,
-       .disable           = bq24022_disable,
-       .is_enabled        = bq24022_is_enabled,
-};
-
-static struct regulator_desc bq24022_desc = {
-       .name  = "bq24022",
-       .ops   = &bq24022_ops,
-       .type  = REGULATOR_CURRENT,
-       .owner = THIS_MODULE,
-};
-
-static int __init bq24022_probe(struct platform_device *pdev)
-{
-       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
-       struct regulator_dev *bq24022;
-       int ret;
-
-       if (!pdata || !pdata->gpio_nce || !pdata->gpio_iset2)
-               return -EINVAL;
-
-       ret = gpio_request(pdata->gpio_nce, "ncharge_en");
-       if (ret) {
-               dev_dbg(&pdev->dev, "couldn't request nCE GPIO: %d\n",
-                       pdata->gpio_nce);
-               goto err_ce;
-       }
-       ret = gpio_request(pdata->gpio_iset2, "charge_mode");
-       if (ret) {
-               dev_dbg(&pdev->dev, "couldn't request ISET2 GPIO: %d\n",
-                       pdata->gpio_iset2);
-               goto err_iset2;
-       }
-       ret = gpio_direction_output(pdata->gpio_iset2, 0);
-       ret = gpio_direction_output(pdata->gpio_nce, 1);
-
-       bq24022 = regulator_register(&bq24022_desc, &pdev->dev,
-                                    pdata->init_data, pdata, NULL);
-       if (IS_ERR(bq24022)) {
-               dev_dbg(&pdev->dev, "couldn't register regulator\n");
-               ret = PTR_ERR(bq24022);
-               goto err_reg;
-       }
-       platform_set_drvdata(pdev, bq24022);
-       dev_dbg(&pdev->dev, "registered regulator\n");
-
-       return 0;
-err_reg:
-       gpio_free(pdata->gpio_iset2);
-err_iset2:
-       gpio_free(pdata->gpio_nce);
-err_ce:
-       return ret;
-}
-
-static int __devexit bq24022_remove(struct platform_device *pdev)
-{
-       struct bq24022_mach_info *pdata = pdev->dev.platform_data;
-       struct regulator_dev *bq24022 = platform_get_drvdata(pdev);
-
-       regulator_unregister(bq24022);
-       gpio_free(pdata->gpio_iset2);
-       gpio_free(pdata->gpio_nce);
-
-       return 0;
-}
-
-static struct platform_driver bq24022_driver = {
-       .driver = {
-               .name = "bq24022",
-       },
-       .remove = __devexit_p(bq24022_remove),
-};
-
-static int __init bq24022_init(void)
-{
-       return platform_driver_probe(&bq24022_driver, bq24022_probe);
-}
-
-static void __exit bq24022_exit(void)
-{
-       platform_driver_unregister(&bq24022_driver);
-}
-
-module_init(bq24022_init);
-module_exit(bq24022_exit);
-
-MODULE_AUTHOR("Philipp Zabel");
-MODULE_DESCRIPTION("TI bq24022 Li-Ion Charger driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
new file mode 100644 (file)
index 0000000..24d880e
--- /dev/null
@@ -0,0 +1,28 @@
+menu "Remoteproc drivers (EXPERIMENTAL)"
+
+# REMOTEPROC gets selected by whoever wants it
+config REMOTEPROC
+       tristate
+       depends on EXPERIMENTAL
+
+config OMAP_REMOTEPROC
+       tristate "OMAP remoteproc support"
+       depends on ARCH_OMAP4
+       depends on OMAP_IOMMU
+       select REMOTEPROC
+       select OMAP_MBOX_FWK
+       select RPMSG
+       help
+         Say y here to support OMAP's remote processors (dual M3
+         and DSP on OMAP4) via the remote processor framework.
+
+         Currently only supported on OMAP4.
+
+         Usually you want to say y here, in order to enable multimedia
+         use-cases to run on your platform (multimedia codecs are
+         offloaded to remote DSP processors using this framework).
+
+         It's safe to say n here if you're not interested in multimedia
+         offloading or just want a bare minimum kernel.
+
+endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
new file mode 100644 (file)
index 0000000..5445d9b
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Generic framework for controlling remote processors
+#
+
+obj-$(CONFIG_REMOTEPROC)               += remoteproc.o
+remoteproc-y                           := remoteproc_core.o
+remoteproc-y                           += remoteproc_debugfs.o
+remoteproc-y                           += remoteproc_virtio.o
+obj-$(CONFIG_OMAP_REMOTEPROC)          += omap_remoteproc.o
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
new file mode 100644 (file)
index 0000000..69425c4
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * OMAP Remote Processor driver
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ * Mark Grosen <mgrosen@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ * Hari Kanigeri <h-kanigeri2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/remoteproc.h>
+
+#include <plat/mailbox.h>
+#include <plat/remoteproc.h>
+
+#include "omap_remoteproc.h"
+#include "remoteproc_internal.h"
+
+/**
+ * struct omap_rproc - omap remote processor state
+ * @mbox: omap mailbox handle
+ * @nb: notifier block that will be invoked on inbound mailbox messages
+ * @rproc: rproc handle
+ */
+struct omap_rproc {
+       struct omap_mbox *mbox;
+       struct notifier_block nb;
+       struct rproc *rproc;
+};
+
+/**
+ * omap_rproc_mbox_callback() - inbound mailbox message handler
+ * @this: notifier block
+ * @index: unused
+ * @data: mailbox payload
+ *
+ * This handler is invoked by omap's mailbox driver whenever a mailbox
+ * message is received. Usually, the mailbox payload simply contains
+ * the index of the virtqueue that is kicked by the remote processor,
+ * and we let remoteproc core handle it.
+ *
+ * In addition to virtqueue indices, we also have some out-of-band values
+ * that indicates different events. Those values are deliberately very
+ * big so they don't coincide with virtqueue indices.
+ */
+static int omap_rproc_mbox_callback(struct notifier_block *this,
+                                       unsigned long index, void *data)
+{
+       mbox_msg_t msg = (mbox_msg_t) data;
+       struct omap_rproc *oproc = container_of(this, struct omap_rproc, nb);
+       struct device *dev = oproc->rproc->dev;
+       const char *name = oproc->rproc->name;
+
+       dev_dbg(dev, "mbox msg: 0x%x\n", msg);
+
+       switch (msg) {
+       case RP_MBOX_CRASH:
+               /* just log this for now. later, we'll also do recovery */
+               dev_err(dev, "omap rproc %s crashed\n", name);
+               break;
+       case RP_MBOX_ECHO_REPLY:
+               dev_info(dev, "received echo reply from %s\n", name);
+               break;
+       default:
+               /* msg contains the index of the triggered vring */
+               if (rproc_vq_interrupt(oproc->rproc, msg) == IRQ_NONE)
+                       dev_dbg(dev, "no message was found in vqid %d\n", msg);
+       }
+
+       return NOTIFY_DONE;
+}
+
+/* kick a virtqueue */
+static void omap_rproc_kick(struct rproc *rproc, int vqid)
+{
+       struct omap_rproc *oproc = rproc->priv;
+       int ret;
+
+       /* send the index of the triggered virtqueue in the mailbox payload */
+       ret = omap_mbox_msg_send(oproc->mbox, vqid);
+       if (ret)
+               dev_err(rproc->dev, "omap_mbox_msg_send failed: %d\n", ret);
+}
+
+/*
+ * Power up the remote processor.
+ *
+ * This function will be invoked only after the firmware for this rproc
+ * was loaded, parsed successfully, and all of its resource requirements
+ * were met.
+ */
+static int omap_rproc_start(struct rproc *rproc)
+{
+       struct omap_rproc *oproc = rproc->priv;
+       struct platform_device *pdev = to_platform_device(rproc->dev);
+       struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+       int ret;
+
+       oproc->nb.notifier_call = omap_rproc_mbox_callback;
+
+       /* every omap rproc is assigned a mailbox instance for messaging */
+       oproc->mbox = omap_mbox_get(pdata->mbox_name, &oproc->nb);
+       if (IS_ERR(oproc->mbox)) {
+               ret = PTR_ERR(oproc->mbox);
+               dev_err(rproc->dev, "omap_mbox_get failed: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * Ping the remote processor. this is only for sanity-sake;
+        * there is no functional effect whatsoever.
+        *
+        * Note that the reply will _not_ arrive immediately: this message
+        * will wait in the mailbox fifo until the remote processor is booted.
+        */
+       ret = omap_mbox_msg_send(oproc->mbox, RP_MBOX_ECHO_REQUEST);
+       if (ret) {
+               dev_err(rproc->dev, "omap_mbox_get failed: %d\n", ret);
+               goto put_mbox;
+       }
+
+       ret = pdata->device_enable(pdev);
+       if (ret) {
+               dev_err(rproc->dev, "omap_device_enable failed: %d\n", ret);
+               goto put_mbox;
+       }
+
+       return 0;
+
+put_mbox:
+       omap_mbox_put(oproc->mbox, &oproc->nb);
+       return ret;
+}
+
+/* power off the remote processor */
+static int omap_rproc_stop(struct rproc *rproc)
+{
+       struct platform_device *pdev = to_platform_device(rproc->dev);
+       struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+       struct omap_rproc *oproc = rproc->priv;
+       int ret;
+
+       ret = pdata->device_shutdown(pdev);
+       if (ret)
+               return ret;
+
+       omap_mbox_put(oproc->mbox, &oproc->nb);
+
+       return 0;
+}
+
+static struct rproc_ops omap_rproc_ops = {
+       .start          = omap_rproc_start,
+       .stop           = omap_rproc_stop,
+       .kick           = omap_rproc_kick,
+};
+
+static int __devinit omap_rproc_probe(struct platform_device *pdev)
+{
+       struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+       struct omap_rproc *oproc;
+       struct rproc *rproc;
+       int ret;
+
+       ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(pdev->dev.parent, "dma_set_coherent_mask: %d\n", ret);
+               return ret;
+       }
+
+       rproc = rproc_alloc(&pdev->dev, pdata->name, &omap_rproc_ops,
+                               pdata->firmware, sizeof(*oproc));
+       if (!rproc)
+               return -ENOMEM;
+
+       oproc = rproc->priv;
+       oproc->rproc = rproc;
+
+       platform_set_drvdata(pdev, rproc);
+
+       ret = rproc_register(rproc);
+       if (ret)
+               goto free_rproc;
+
+       return 0;
+
+free_rproc:
+       rproc_free(rproc);
+       return ret;
+}
+
+static int __devexit omap_rproc_remove(struct platform_device *pdev)
+{
+       struct rproc *rproc = platform_get_drvdata(pdev);
+
+       return rproc_unregister(rproc);
+}
+
+static struct platform_driver omap_rproc_driver = {
+       .probe = omap_rproc_probe,
+       .remove = __devexit_p(omap_rproc_remove),
+       .driver = {
+               .name = "omap-rproc",
+               .owner = THIS_MODULE,
+       },
+};
+
+module_platform_driver(omap_rproc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP Remote Processor control driver");
diff --git a/drivers/remoteproc/omap_remoteproc.h b/drivers/remoteproc/omap_remoteproc.h
new file mode 100644 (file)
index 0000000..f6d2036
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Remote processor messaging
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name Texas Instruments nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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 _OMAP_RPMSG_H
+#define _OMAP_RPMSG_H
+
+/*
+ * enum - Predefined Mailbox Messages
+ *
+ * @RP_MBOX_READY: informs the M3's that we're up and running. this is
+ * part of the init sequence sent that the M3 expects to see immediately
+ * after it is booted.
+ *
+ * @RP_MBOX_PENDING_MSG: informs the receiver that there is an inbound
+ * message waiting in its own receive-side vring. please note that currently
+ * this message is optional: alternatively, one can explicitly send the index
+ * of the triggered virtqueue itself. the preferred approach will be decided
+ * as we progress and experiment with those two different approaches.
+ *
+ * @RP_MBOX_CRASH: this message is sent if BIOS crashes
+ *
+ * @RP_MBOX_ECHO_REQUEST: a mailbox-level "ping" message.
+ *
+ * @RP_MBOX_ECHO_REPLY: a mailbox-level reply to a "ping"
+ *
+ * @RP_MBOX_ABORT_REQUEST: a "please crash" request, used for testing the
+ * recovery mechanism (to some extent).
+ */
+enum omap_rp_mbox_messages {
+       RP_MBOX_READY           = 0xFFFFFF00,
+       RP_MBOX_PENDING_MSG     = 0xFFFFFF01,
+       RP_MBOX_CRASH           = 0xFFFFFF02,
+       RP_MBOX_ECHO_REQUEST    = 0xFFFFFF03,
+       RP_MBOX_ECHO_REPLY      = 0xFFFFFF04,
+       RP_MBOX_ABORT_REQUEST   = 0xFFFFFF05,
+};
+
+#endif /* _OMAP_RPMSG_H */
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
new file mode 100644 (file)
index 0000000..ee15c68
--- /dev/null
@@ -0,0 +1,1586 @@
+/*
+ * Remote Processor Framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ * Mark Grosen <mgrosen@ti.com>
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ * Robert Tivy <rtivy@ti.com>
+ * Armando Uribe De Leon <x0095078@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/string.h>
+#include <linux/debugfs.h>
+#include <linux/remoteproc.h>
+#include <linux/iommu.h>
+#include <linux/klist.h>
+#include <linux/elf.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_ring.h>
+#include <asm/byteorder.h>
+
+#include "remoteproc_internal.h"
+
+static void klist_rproc_get(struct klist_node *n);
+static void klist_rproc_put(struct klist_node *n);
+
+/*
+ * klist of the available remote processors.
+ *
+ * We need this in order to support name-based lookups (needed by the
+ * rproc_get_by_name()).
+ *
+ * That said, we don't use rproc_get_by_name() at this point.
+ * The use cases that do require its existence should be
+ * scrutinized, and hopefully migrated to rproc_boot() using device-based
+ * binding.
+ *
+ * If/when this materializes, we could drop the klist (and the by_name
+ * API).
+ */
+static DEFINE_KLIST(rprocs, klist_rproc_get, klist_rproc_put);
+
+typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
+                               struct resource_table *table, int len);
+typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail);
+
+/*
+ * This is the IOMMU fault handler we register with the IOMMU API
+ * (when relevant; not all remote processors access memory through
+ * an IOMMU).
+ *
+ * IOMMU core will invoke this handler whenever the remote processor
+ * will try to access an unmapped device address.
+ *
+ * Currently this is mostly a stub, but it will be later used to trigger
+ * the recovery of the remote processor.
+ */
+static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev,
+               unsigned long iova, int flags)
+{
+       dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags);
+
+       /*
+        * Let the iommu core know we're not really handling this fault;
+        * we just plan to use this as a recovery trigger.
+        */
+       return -ENOSYS;
+}
+
+static int rproc_enable_iommu(struct rproc *rproc)
+{
+       struct iommu_domain *domain;
+       struct device *dev = rproc->dev;
+       int ret;
+
+       /*
+        * We currently use iommu_present() to decide if an IOMMU
+        * setup is needed.
+        *
+        * This works for simple cases, but will easily fail with
+        * platforms that do have an IOMMU, but not for this specific
+        * rproc.
+        *
+        * This will be easily solved by introducing hw capabilities
+        * that will be set by the remoteproc driver.
+        */
+       if (!iommu_present(dev->bus)) {
+               dev_dbg(dev, "iommu not found\n");
+               return 0;
+       }
+
+       domain = iommu_domain_alloc(dev->bus);
+       if (!domain) {
+               dev_err(dev, "can't alloc iommu domain\n");
+               return -ENOMEM;
+       }
+
+       iommu_set_fault_handler(domain, rproc_iommu_fault);
+
+       ret = iommu_attach_device(domain, dev);
+       if (ret) {
+               dev_err(dev, "can't attach iommu device: %d\n", ret);
+               goto free_domain;
+       }
+
+       rproc->domain = domain;
+
+       return 0;
+
+free_domain:
+       iommu_domain_free(domain);
+       return ret;
+}
+
+static void rproc_disable_iommu(struct rproc *rproc)
+{
+       struct iommu_domain *domain = rproc->domain;
+       struct device *dev = rproc->dev;
+
+       if (!domain)
+               return;
+
+       iommu_detach_device(domain, dev);
+       iommu_domain_free(domain);
+
+       return;
+}
+
+/*
+ * Some remote processors will ask us to allocate them physically contiguous
+ * memory regions (which we call "carveouts"), and map them to specific
+ * device addresses (which are hardcoded in the firmware).
+ *
+ * They may then ask us to copy objects into specific device addresses (e.g.
+ * code/data sections) or expose us certain symbols in other device address
+ * (e.g. their trace buffer).
+ *
+ * This function is an internal helper with which we can go over the allocated
+ * carveouts and translate specific device address to kernel virtual addresses
+ * so we can access the referenced memory.
+ *
+ * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too,
+ * but only on kernel direct mapped RAM memory. Instead, we're just using
+ * here the output of the DMA API, which should be more correct.
+ */
+static void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+       struct rproc_mem_entry *carveout;
+       void *ptr = NULL;
+
+       list_for_each_entry(carveout, &rproc->carveouts, node) {
+               int offset = da - carveout->da;
+
+               /* try next carveout if da is too small */
+               if (offset < 0)
+                       continue;
+
+               /* try next carveout if da is too large */
+               if (offset + len > carveout->len)
+                       continue;
+
+               ptr = carveout->va + offset;
+
+               break;
+       }
+
+       return ptr;
+}
+
+/**
+ * rproc_load_segments() - load firmware segments to memory
+ * @rproc: remote processor which will be booted using these fw segments
+ * @elf_data: the content of the ELF firmware image
+ * @len: firmware size (in bytes)
+ *
+ * This function loads the firmware segments to memory, where the remote
+ * processor expects them.
+ *
+ * Some remote processors will expect their code and data to be placed
+ * in specific device addresses, and can't have them dynamically assigned.
+ *
+ * We currently support only those kind of remote processors, and expect
+ * the program header's paddr member to contain those addresses. We then go
+ * through the physically contiguous "carveout" memory regions which we
+ * allocated (and mapped) earlier on behalf of the remote processor,
+ * and "translate" device address to kernel addresses, so we can copy the
+ * segments where they are expected.
+ *
+ * Currently we only support remote processors that required carveout
+ * allocations and got them mapped onto their iommus. Some processors
+ * might be different: they might not have iommus, and would prefer to
+ * directly allocate memory for every segment/resource. This is not yet
+ * supported, though.
+ */
+static int
+rproc_load_segments(struct rproc *rproc, const u8 *elf_data, size_t len)
+{
+       struct device *dev = rproc->dev;
+       struct elf32_hdr *ehdr;
+       struct elf32_phdr *phdr;
+       int i, ret = 0;
+
+       ehdr = (struct elf32_hdr *)elf_data;
+       phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+
+       /* go through the available ELF segments */
+       for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+               u32 da = phdr->p_paddr;
+               u32 memsz = phdr->p_memsz;
+               u32 filesz = phdr->p_filesz;
+               u32 offset = phdr->p_offset;
+               void *ptr;
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
+                                       phdr->p_type, da, memsz, filesz);
+
+               if (filesz > memsz) {
+                       dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+                                                       filesz, memsz);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (offset + filesz > len) {
+                       dev_err(dev, "truncated fw: need 0x%x avail 0x%x\n",
+                                       offset + filesz, len);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               /* grab the kernel address for this device address */
+               ptr = rproc_da_to_va(rproc, da, memsz);
+               if (!ptr) {
+                       dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               /* put the segment where the remote processor expects it */
+               if (phdr->p_filesz)
+                       memcpy(ptr, elf_data + phdr->p_offset, filesz);
+
+               /*
+                * Zero out remaining memory for this segment.
+                *
+                * This isn't strictly required since dma_alloc_coherent already
+                * did this for us. albeit harmless, we may consider removing
+                * this.
+                */
+               if (memsz > filesz)
+                       memset(ptr + filesz, 0, memsz - filesz);
+       }
+
+       return ret;
+}
+
+static int
+__rproc_handle_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i)
+{
+       struct rproc *rproc = rvdev->rproc;
+       struct device *dev = rproc->dev;
+       struct fw_rsc_vdev_vring *vring = &rsc->vring[i];
+       dma_addr_t dma;
+       void *va;
+       int ret, size, notifyid;
+
+       dev_dbg(dev, "vdev rsc: vring%d: da %x, qsz %d, align %d\n",
+                               i, vring->da, vring->num, vring->align);
+
+       /* make sure reserved bytes are zeroes */
+       if (vring->reserved) {
+               dev_err(dev, "vring rsc has non zero reserved bytes\n");
+               return -EINVAL;
+       }
+
+       /* verify queue size and vring alignment are sane */
+       if (!vring->num || !vring->align) {
+               dev_err(dev, "invalid qsz (%d) or alignment (%d)\n",
+                                               vring->num, vring->align);
+               return -EINVAL;
+       }
+
+       /* actual size of vring (in bytes) */
+       size = PAGE_ALIGN(vring_size(vring->num, vring->align));
+
+       if (!idr_pre_get(&rproc->notifyids, GFP_KERNEL)) {
+               dev_err(dev, "idr_pre_get failed\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * Allocate non-cacheable memory for the vring. In the future
+        * this call will also configure the IOMMU for us
+        */
+       va = dma_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+       if (!va) {
+               dev_err(dev, "dma_alloc_coherent failed\n");
+               return -EINVAL;
+       }
+
+       /* assign an rproc-wide unique index for this vring */
+       /* TODO: assign a notifyid for rvdev updates as well */
+       ret = idr_get_new(&rproc->notifyids, &rvdev->vring[i], &notifyid);
+       if (ret) {
+               dev_err(dev, "idr_get_new failed: %d\n", ret);
+               dma_free_coherent(dev, size, va, dma);
+               return ret;
+       }
+
+       /* let the rproc know the da and notifyid of this vring */
+       /* TODO: expose this to remote processor */
+       vring->da = dma;
+       vring->notifyid = notifyid;
+
+       dev_dbg(dev, "vring%d: va %p dma %x size %x idr %d\n", i, va,
+                                       dma, size, notifyid);
+
+       rvdev->vring[i].len = vring->num;
+       rvdev->vring[i].align = vring->align;
+       rvdev->vring[i].va = va;
+       rvdev->vring[i].dma = dma;
+       rvdev->vring[i].notifyid = notifyid;
+       rvdev->vring[i].rvdev = rvdev;
+
+       return 0;
+}
+
+static void __rproc_free_vrings(struct rproc_vdev *rvdev, int i)
+{
+       struct rproc *rproc = rvdev->rproc;
+
+       for (i--; i > 0; i--) {
+               struct rproc_vring *rvring = &rvdev->vring[i];
+               int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
+
+               dma_free_coherent(rproc->dev, size, rvring->va, rvring->dma);
+               idr_remove(&rproc->notifyids, rvring->notifyid);
+       }
+}
+
+/**
+ * rproc_handle_vdev() - handle a vdev fw resource
+ * @rproc: the remote processor
+ * @rsc: the vring resource descriptor
+ * @avail: size of available data (for sanity checking the image)
+ *
+ * This resource entry requests the host to statically register a virtio
+ * device (vdev), and setup everything needed to support it. It contains
+ * everything needed to make it possible: the virtio device id, virtio
+ * device features, vrings information, virtio config space, etc...
+ *
+ * Before registering the vdev, the vrings are allocated from non-cacheable
+ * physically contiguous memory. Currently we only support two vrings per
+ * remote processor (temporary limitation). We might also want to consider
+ * doing the vring allocation only later when ->find_vqs() is invoked, and
+ * then release them upon ->del_vqs().
+ *
+ * Note: @da is currently not really handled correctly: we dynamically
+ * allocate it using the DMA API, ignoring requested hard coded addresses,
+ * and we don't take care of any required IOMMU programming. This is all
+ * going to be taken care of when the generic iommu-based DMA API will be
+ * merged. Meanwhile, statically-addressed iommu-based firmware images should
+ * use RSC_DEVMEM resource entries to map their required @da to the physical
+ * address of their base CMA region (ouch, hacky!).
+ *
+ * Returns 0 on success, or an appropriate error code otherwise
+ */
+static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
+                                                               int avail)
+{
+       struct device *dev = rproc->dev;
+       struct rproc_vdev *rvdev;
+       int i, ret;
+
+       /* make sure resource isn't truncated */
+       if (sizeof(*rsc) + rsc->num_of_vrings * sizeof(struct fw_rsc_vdev_vring)
+                       + rsc->config_len > avail) {
+               dev_err(rproc->dev, "vdev rsc is truncated\n");
+               return -EINVAL;
+       }
+
+       /* make sure reserved bytes are zeroes */
+       if (rsc->reserved[0] || rsc->reserved[1]) {
+               dev_err(dev, "vdev rsc has non zero reserved bytes\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "vdev rsc: id %d, dfeatures %x, cfg len %d, %d vrings\n",
+               rsc->id, rsc->dfeatures, rsc->config_len, rsc->num_of_vrings);
+
+       /* we currently support only two vrings per rvdev */
+       if (rsc->num_of_vrings > ARRAY_SIZE(rvdev->vring)) {
+               dev_err(dev, "too many vrings: %d\n", rsc->num_of_vrings);
+               return -EINVAL;
+       }
+
+       rvdev = kzalloc(sizeof(struct rproc_vdev), GFP_KERNEL);
+       if (!rvdev)
+               return -ENOMEM;
+
+       rvdev->rproc = rproc;
+
+       /* allocate the vrings */
+       for (i = 0; i < rsc->num_of_vrings; i++) {
+               ret = __rproc_handle_vring(rvdev, rsc, i);
+               if (ret)
+                       goto free_vrings;
+       }
+
+       /* remember the device features */
+       rvdev->dfeatures = rsc->dfeatures;
+
+       list_add_tail(&rvdev->node, &rproc->rvdevs);
+
+       /* it is now safe to add the virtio device */
+       ret = rproc_add_virtio_dev(rvdev, rsc->id);
+       if (ret)
+               goto free_vrings;
+
+       return 0;
+
+free_vrings:
+       __rproc_free_vrings(rvdev, i);
+       kfree(rvdev);
+       return ret;
+}
+
+/**
+ * rproc_handle_trace() - handle a shared trace buffer resource
+ * @rproc: the remote processor
+ * @rsc: the trace resource descriptor
+ * @avail: size of available data (for sanity checking the image)
+ *
+ * In case the remote processor dumps trace logs into memory,
+ * export it via debugfs.
+ *
+ * Currently, the 'da' member of @rsc should contain the device address
+ * where the remote processor is dumping the traces. Later we could also
+ * support dynamically allocating this address using the generic
+ * DMA API (but currently there isn't a use case for that).
+ *
+ * Returns 0 on success, or an appropriate error code otherwise
+ */
+static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
+                                                               int avail)
+{
+       struct rproc_mem_entry *trace;
+       struct device *dev = rproc->dev;
+       void *ptr;
+       char name[15];
+
+       if (sizeof(*rsc) > avail) {
+               dev_err(rproc->dev, "trace rsc is truncated\n");
+               return -EINVAL;
+       }
+
+       /* make sure reserved bytes are zeroes */
+       if (rsc->reserved) {
+               dev_err(dev, "trace rsc has non zero reserved bytes\n");
+               return -EINVAL;
+       }
+
+       /* what's the kernel address of this resource ? */
+       ptr = rproc_da_to_va(rproc, rsc->da, rsc->len);
+       if (!ptr) {
+               dev_err(dev, "erroneous trace resource entry\n");
+               return -EINVAL;
+       }
+
+       trace = kzalloc(sizeof(*trace), GFP_KERNEL);
+       if (!trace) {
+               dev_err(dev, "kzalloc trace failed\n");
+               return -ENOMEM;
+       }
+
+       /* set the trace buffer dma properties */
+       trace->len = rsc->len;
+       trace->va = ptr;
+
+       /* make sure snprintf always null terminates, even if truncating */
+       snprintf(name, sizeof(name), "trace%d", rproc->num_traces);
+
+       /* create the debugfs entry */
+       trace->priv = rproc_create_trace_file(name, rproc, trace);
+       if (!trace->priv) {
+               trace->va = NULL;
+               kfree(trace);
+               return -EINVAL;
+       }
+
+       list_add_tail(&trace->node, &rproc->traces);
+
+       rproc->num_traces++;
+
+       dev_dbg(dev, "%s added: va %p, da 0x%x, len 0x%x\n", name, ptr,
+                                               rsc->da, rsc->len);
+
+       return 0;
+}
+
+/**
+ * rproc_handle_devmem() - handle devmem resource entry
+ * @rproc: remote processor handle
+ * @rsc: the devmem resource entry
+ * @avail: size of available data (for sanity checking the image)
+ *
+ * Remote processors commonly need to access certain on-chip peripherals.
+ *
+ * Some of these remote processors access memory via an iommu device,
+ * and might require us to configure their iommu before they can access
+ * the on-chip peripherals they need.
+ *
+ * This resource entry is a request to map such a peripheral device.
+ *
+ * These devmem entries will contain the physical address of the device in
+ * the 'pa' member. If a specific device address is expected, then 'da' will
+ * contain it (currently this is the only use case supported). 'len' will
+ * contain the size of the physical region we need to map.
+ *
+ * Currently we just "trust" those devmem entries to contain valid physical
+ * addresses, but this is going to change: we want the implementations to
+ * tell us ranges of physical addresses the firmware is allowed to request,
+ * and not allow firmwares to request access to physical addresses that
+ * are outside those ranges.
+ */
+static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
+                                                               int avail)
+{
+       struct rproc_mem_entry *mapping;
+       int ret;
+
+       /* no point in handling this resource without a valid iommu domain */
+       if (!rproc->domain)
+               return -EINVAL;
+
+       if (sizeof(*rsc) > avail) {
+               dev_err(rproc->dev, "devmem rsc is truncated\n");
+               return -EINVAL;
+       }
+
+       /* make sure reserved bytes are zeroes */
+       if (rsc->reserved) {
+               dev_err(rproc->dev, "devmem rsc has non zero reserved bytes\n");
+               return -EINVAL;
+       }
+
+       mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+       if (!mapping) {
+               dev_err(rproc->dev, "kzalloc mapping failed\n");
+               return -ENOMEM;
+       }
+
+       ret = iommu_map(rproc->domain, rsc->da, rsc->pa, rsc->len, rsc->flags);
+       if (ret) {
+               dev_err(rproc->dev, "failed to map devmem: %d\n", ret);
+               goto out;
+       }
+
+       /*
+        * We'll need this info later when we'll want to unmap everything
+        * (e.g. on shutdown).
+        *
+        * We can't trust the remote processor not to change the resource
+        * table, so we must maintain this info independently.
+        */
+       mapping->da = rsc->da;
+       mapping->len = rsc->len;
+       list_add_tail(&mapping->node, &rproc->mappings);
+
+       dev_dbg(rproc->dev, "mapped devmem pa 0x%x, da 0x%x, len 0x%x\n",
+                                       rsc->pa, rsc->da, rsc->len);
+
+       return 0;
+
+out:
+       kfree(mapping);
+       return ret;
+}
+
+/**
+ * rproc_handle_carveout() - handle phys contig memory allocation requests
+ * @rproc: rproc handle
+ * @rsc: the resource entry
+ * @avail: size of available data (for image validation)
+ *
+ * This function will handle firmware requests for allocation of physically
+ * contiguous memory regions.
+ *
+ * These request entries should come first in the firmware's resource table,
+ * as other firmware entries might request placing other data objects inside
+ * these memory regions (e.g. data/code segments, trace resource entries, ...).
+ *
+ * Allocating memory this way helps utilizing the reserved physical memory
+ * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries
+ * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB
+ * pressure is important; it may have a substantial impact on performance.
+ */
+static int rproc_handle_carveout(struct rproc *rproc,
+                               struct fw_rsc_carveout *rsc, int avail)
+{
+       struct rproc_mem_entry *carveout, *mapping;
+       struct device *dev = rproc->dev;
+       dma_addr_t dma;
+       void *va;
+       int ret;
+
+       if (sizeof(*rsc) > avail) {
+               dev_err(rproc->dev, "carveout rsc is truncated\n");
+               return -EINVAL;
+       }
+
+       /* make sure reserved bytes are zeroes */
+       if (rsc->reserved) {
+               dev_err(dev, "carveout rsc has non zero reserved bytes\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "carveout rsc: da %x, pa %x, len %x, flags %x\n",
+                       rsc->da, rsc->pa, rsc->len, rsc->flags);
+
+       mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+       if (!mapping) {
+               dev_err(dev, "kzalloc mapping failed\n");
+               return -ENOMEM;
+       }
+
+       carveout = kzalloc(sizeof(*carveout), GFP_KERNEL);
+       if (!carveout) {
+               dev_err(dev, "kzalloc carveout failed\n");
+               ret = -ENOMEM;
+               goto free_mapping;
+       }
+
+       va = dma_alloc_coherent(dev, rsc->len, &dma, GFP_KERNEL);
+       if (!va) {
+               dev_err(dev, "failed to dma alloc carveout: %d\n", rsc->len);
+               ret = -ENOMEM;
+               goto free_carv;
+       }
+
+       dev_dbg(dev, "carveout va %p, dma %x, len 0x%x\n", va, dma, rsc->len);
+
+       /*
+        * Ok, this is non-standard.
+        *
+        * Sometimes we can't rely on the generic iommu-based DMA API
+        * to dynamically allocate the device address and then set the IOMMU
+        * tables accordingly, because some remote processors might
+        * _require_ us to use hard coded device addresses that their
+        * firmware was compiled with.
+        *
+        * In this case, we must use the IOMMU API directly and map
+        * the memory to the device address as expected by the remote
+        * processor.
+        *
+        * Obviously such remote processor devices should not be configured
+        * to use the iommu-based DMA API: we expect 'dma' to contain the
+        * physical address in this case.
+        */
+       if (rproc->domain) {
+               ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len,
+                                                               rsc->flags);
+               if (ret) {
+                       dev_err(dev, "iommu_map failed: %d\n", ret);
+                       goto dma_free;
+               }
+
+               /*
+                * We'll need this info later when we'll want to unmap
+                * everything (e.g. on shutdown).
+                *
+                * We can't trust the remote processor not to change the
+                * resource table, so we must maintain this info independently.
+                */
+               mapping->da = rsc->da;
+               mapping->len = rsc->len;
+               list_add_tail(&mapping->node, &rproc->mappings);
+
+               dev_dbg(dev, "carveout mapped 0x%x to 0x%x\n", rsc->da, dma);
+
+               /*
+                * Some remote processors might need to know the pa
+                * even though they are behind an IOMMU. E.g., OMAP4's
+                * remote M3 processor needs this so it can control
+                * on-chip hardware accelerators that are not behind
+                * the IOMMU, and therefor must know the pa.
+                *
+                * Generally we don't want to expose physical addresses
+                * if we don't have to (remote processors are generally
+                * _not_ trusted), so we might want to do this only for
+                * remote processor that _must_ have this (e.g. OMAP4's
+                * dual M3 subsystem).
+                */
+               rsc->pa = dma;
+       }
+
+       carveout->va = va;
+       carveout->len = rsc->len;
+       carveout->dma = dma;
+       carveout->da = rsc->da;
+
+       list_add_tail(&carveout->node, &rproc->carveouts);
+
+       return 0;
+
+dma_free:
+       dma_free_coherent(dev, rsc->len, va, dma);
+free_carv:
+       kfree(carveout);
+free_mapping:
+       kfree(mapping);
+       return ret;
+}
+
+/*
+ * A lookup table for resource handlers. The indices are defined in
+ * enum fw_resource_type.
+ */
+static rproc_handle_resource_t rproc_handle_rsc[] = {
+       [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
+       [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
+       [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
+       [RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */
+};
+
+/* handle firmware resource entries before booting the remote processor */
+static int
+rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int len)
+{
+       struct device *dev = rproc->dev;
+       rproc_handle_resource_t handler;
+       int ret = 0, i;
+
+       for (i = 0; i < table->num; i++) {
+               int offset = table->offset[i];
+               struct fw_rsc_hdr *hdr = (void *)table + offset;
+               int avail = len - offset - sizeof(*hdr);
+               void *rsc = (void *)hdr + sizeof(*hdr);
+
+               /* make sure table isn't truncated */
+               if (avail < 0) {
+                       dev_err(dev, "rsc table is truncated\n");
+                       return -EINVAL;
+               }
+
+               dev_dbg(dev, "rsc: type %d\n", hdr->type);
+
+               if (hdr->type >= RSC_LAST) {
+                       dev_warn(dev, "unsupported resource %d\n", hdr->type);
+                       continue;
+               }
+
+               handler = rproc_handle_rsc[hdr->type];
+               if (!handler)
+                       continue;
+
+               ret = handler(rproc, rsc, avail);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+/* handle firmware resource entries while registering the remote processor */
+static int
+rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int len)
+{
+       struct device *dev = rproc->dev;
+       int ret = 0, i;
+
+       for (i = 0; i < table->num; i++) {
+               int offset = table->offset[i];
+               struct fw_rsc_hdr *hdr = (void *)table + offset;
+               int avail = len - offset - sizeof(*hdr);
+               struct fw_rsc_vdev *vrsc;
+
+               /* make sure table isn't truncated */
+               if (avail < 0) {
+                       dev_err(dev, "rsc table is truncated\n");
+                       return -EINVAL;
+               }
+
+               dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type);
+
+               if (hdr->type != RSC_VDEV)
+                       continue;
+
+               vrsc = (struct fw_rsc_vdev *)hdr->data;
+
+               ret = rproc_handle_vdev(rproc, vrsc, avail);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+/**
+ * rproc_find_rsc_table() - find the resource table
+ * @rproc: the rproc handle
+ * @elf_data: the content of the ELF firmware image
+ * @len: firmware size (in bytes)
+ * @tablesz: place holder for providing back the table size
+ *
+ * This function finds the resource table inside the remote processor's
+ * firmware. It is used both upon the registration of @rproc (in order
+ * to look for and register the supported virito devices), and when the
+ * @rproc is booted.
+ *
+ * Returns the pointer to the resource table if it is found, and write its
+ * size into @tablesz. If a valid table isn't found, NULL is returned
+ * (and @tablesz isn't set).
+ */
+static struct resource_table *
+rproc_find_rsc_table(struct rproc *rproc, const u8 *elf_data, size_t len,
+                                                       int *tablesz)
+{
+       struct elf32_hdr *ehdr;
+       struct elf32_shdr *shdr;
+       const char *name_table;
+       struct device *dev = rproc->dev;
+       struct resource_table *table = NULL;
+       int i;
+
+       ehdr = (struct elf32_hdr *)elf_data;
+       shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
+       name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
+
+       /* look for the resource table and handle it */
+       for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+               int size = shdr->sh_size;
+               int offset = shdr->sh_offset;
+
+               if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+                       continue;
+
+               table = (struct resource_table *)(elf_data + offset);
+
+               /* make sure we have the entire table */
+               if (offset + size > len) {
+                       dev_err(dev, "resource table truncated\n");
+                       return NULL;
+               }
+
+               /* make sure table has at least the header */
+               if (sizeof(struct resource_table) > size) {
+                       dev_err(dev, "header-less resource table\n");
+                       return NULL;
+               }
+
+               /* we don't support any version beyond the first */
+               if (table->ver != 1) {
+                       dev_err(dev, "unsupported fw ver: %d\n", table->ver);
+                       return NULL;
+               }
+
+               /* make sure reserved bytes are zeroes */
+               if (table->reserved[0] || table->reserved[1]) {
+                       dev_err(dev, "non zero reserved bytes\n");
+                       return NULL;
+               }
+
+               /* make sure the offsets array isn't truncated */
+               if (table->num * sizeof(table->offset[0]) +
+                               sizeof(struct resource_table) > size) {
+                       dev_err(dev, "resource table incomplete\n");
+                       return NULL;
+               }
+
+               *tablesz = shdr->sh_size;
+               break;
+       }
+
+       return table;
+}
+
+/**
+ * rproc_resource_cleanup() - clean up and free all acquired resources
+ * @rproc: rproc handle
+ *
+ * This function will free all resources acquired for @rproc, and it
+ * is called whenever @rproc either shuts down or fails to boot.
+ */
+static void rproc_resource_cleanup(struct rproc *rproc)
+{
+       struct rproc_mem_entry *entry, *tmp;
+       struct device *dev = rproc->dev;
+
+       /* clean up debugfs trace entries */
+       list_for_each_entry_safe(entry, tmp, &rproc->traces, node) {
+               rproc_remove_trace_file(entry->priv);
+               rproc->num_traces--;
+               list_del(&entry->node);
+               kfree(entry);
+       }
+
+       /* clean up carveout allocations */
+       list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
+               dma_free_coherent(dev, entry->len, entry->va, entry->dma);
+               list_del(&entry->node);
+               kfree(entry);
+       }
+
+       /* clean up iommu mapping entries */
+       list_for_each_entry_safe(entry, tmp, &rproc->mappings, node) {
+               size_t unmapped;
+
+               unmapped = iommu_unmap(rproc->domain, entry->da, entry->len);
+               if (unmapped != entry->len) {
+                       /* nothing much to do besides complaining */
+                       dev_err(dev, "failed to unmap %u/%u\n", entry->len,
+                                                               unmapped);
+               }
+
+               list_del(&entry->node);
+               kfree(entry);
+       }
+}
+
+/* make sure this fw image is sane */
+static int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
+{
+       const char *name = rproc->firmware;
+       struct device *dev = rproc->dev;
+       struct elf32_hdr *ehdr;
+       char class;
+
+       if (!fw) {
+               dev_err(dev, "failed to load %s\n", name);
+               return -EINVAL;
+       }
+
+       if (fw->size < sizeof(struct elf32_hdr)) {
+               dev_err(dev, "Image is too small\n");
+               return -EINVAL;
+       }
+
+       ehdr = (struct elf32_hdr *)fw->data;
+
+       /* We only support ELF32 at this point */
+       class = ehdr->e_ident[EI_CLASS];
+       if (class != ELFCLASS32) {
+               dev_err(dev, "Unsupported class: %d\n", class);
+               return -EINVAL;
+       }
+
+       /* We assume the firmware has the same endianess as the host */
+# ifdef __LITTLE_ENDIAN
+       if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+# else /* BIG ENDIAN */
+       if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
+# endif
+               dev_err(dev, "Unsupported firmware endianess\n");
+               return -EINVAL;
+       }
+
+       if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
+               dev_err(dev, "Image is too small\n");
+               return -EINVAL;
+       }
+
+       if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+               dev_err(dev, "Image is corrupted (bad magic)\n");
+               return -EINVAL;
+       }
+
+       if (ehdr->e_phnum == 0) {
+               dev_err(dev, "No loadable segments\n");
+               return -EINVAL;
+       }
+
+       if (ehdr->e_phoff > fw->size) {
+               dev_err(dev, "Firmware size is too small\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * take a firmware and boot a remote processor with it.
+ */
+static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
+{
+       struct device *dev = rproc->dev;
+       const char *name = rproc->firmware;
+       struct elf32_hdr *ehdr;
+       struct resource_table *table;
+       int ret, tablesz;
+
+       ret = rproc_fw_sanity_check(rproc, fw);
+       if (ret)
+               return ret;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+
+       dev_info(dev, "Booting fw image %s, size %d\n", name, fw->size);
+
+       /*
+        * if enabling an IOMMU isn't relevant for this rproc, this is
+        * just a nop
+        */
+       ret = rproc_enable_iommu(rproc);
+       if (ret) {
+               dev_err(dev, "can't enable iommu: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * The ELF entry point is the rproc's boot addr (though this is not
+        * a configurable property of all remote processors: some will always
+        * boot at a specific hardcoded address).
+        */
+       rproc->bootaddr = ehdr->e_entry;
+
+       /* look for the resource table */
+       table = rproc_find_rsc_table(rproc, fw->data, fw->size, &tablesz);
+       if (!table)
+               goto clean_up;
+
+       /* handle fw resources which are required to boot rproc */
+       ret = rproc_handle_boot_rsc(rproc, table, tablesz);
+       if (ret) {
+               dev_err(dev, "Failed to process resources: %d\n", ret);
+               goto clean_up;
+       }
+
+       /* load the ELF segments to memory */
+       ret = rproc_load_segments(rproc, fw->data, fw->size);
+       if (ret) {
+               dev_err(dev, "Failed to load program segments: %d\n", ret);
+               goto clean_up;
+       }
+
+       /* power up the remote processor */
+       ret = rproc->ops->start(rproc);
+       if (ret) {
+               dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret);
+               goto clean_up;
+       }
+
+       rproc->state = RPROC_RUNNING;
+
+       dev_info(dev, "remote processor %s is now up\n", rproc->name);
+
+       return 0;
+
+clean_up:
+       rproc_resource_cleanup(rproc);
+       rproc_disable_iommu(rproc);
+       return ret;
+}
+
+/*
+ * take a firmware and look for virtio devices to register.
+ *
+ * Note: this function is called asynchronously upon registration of the
+ * remote processor (so we must wait until it completes before we try
+ * to unregister the device. one other option is just to use kref here,
+ * that might be cleaner).
+ */
+static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
+{
+       struct rproc *rproc = context;
+       struct resource_table *table;
+       int ret, tablesz;
+
+       if (rproc_fw_sanity_check(rproc, fw) < 0)
+               goto out;
+
+       /* look for the resource table */
+       table = rproc_find_rsc_table(rproc, fw->data, fw->size, &tablesz);
+       if (!table)
+               goto out;
+
+       /* look for virtio devices and register them */
+       ret = rproc_handle_virtio_rsc(rproc, table, tablesz);
+       if (ret)
+               goto out;
+
+out:
+       if (fw)
+               release_firmware(fw);
+       /* allow rproc_unregister() contexts, if any, to proceed */
+       complete_all(&rproc->firmware_loading_complete);
+}
+
+/**
+ * rproc_boot() - boot a remote processor
+ * @rproc: handle of a remote processor
+ *
+ * Boot a remote processor (i.e. load its firmware, power it on, ...).
+ *
+ * If the remote processor is already powered on, this function immediately
+ * returns (successfully).
+ *
+ * Returns 0 on success, and an appropriate error value otherwise.
+ */
+int rproc_boot(struct rproc *rproc)
+{
+       const struct firmware *firmware_p;
+       struct device *dev;
+       int ret;
+
+       if (!rproc) {
+               pr_err("invalid rproc handle\n");
+               return -EINVAL;
+       }
+
+       dev = rproc->dev;
+
+       ret = mutex_lock_interruptible(&rproc->lock);
+       if (ret) {
+               dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret);
+               return ret;
+       }
+
+       /* loading a firmware is required */
+       if (!rproc->firmware) {
+               dev_err(dev, "%s: no firmware to load\n", __func__);
+               ret = -EINVAL;
+               goto unlock_mutex;
+       }
+
+       /* prevent underlying implementation from being removed */
+       if (!try_module_get(dev->driver->owner)) {
+               dev_err(dev, "%s: can't get owner\n", __func__);
+               ret = -EINVAL;
+               goto unlock_mutex;
+       }
+
+       /* skip the boot process if rproc is already powered up */
+       if (atomic_inc_return(&rproc->power) > 1) {
+               ret = 0;
+               goto unlock_mutex;
+       }
+
+       dev_info(dev, "powering up %s\n", rproc->name);
+
+       /* load firmware */
+       ret = request_firmware(&firmware_p, rproc->firmware, dev);
+       if (ret < 0) {
+               dev_err(dev, "request_firmware failed: %d\n", ret);
+               goto downref_rproc;
+       }
+
+       ret = rproc_fw_boot(rproc, firmware_p);
+
+       release_firmware(firmware_p);
+
+downref_rproc:
+       if (ret) {
+               module_put(dev->driver->owner);
+               atomic_dec(&rproc->power);
+       }
+unlock_mutex:
+       mutex_unlock(&rproc->lock);
+       return ret;
+}
+EXPORT_SYMBOL(rproc_boot);
+
+/**
+ * rproc_shutdown() - power off the remote processor
+ * @rproc: the remote processor
+ *
+ * Power off a remote processor (previously booted with rproc_boot()).
+ *
+ * In case @rproc is still being used by an additional user(s), then
+ * this function will just decrement the power refcount and exit,
+ * without really powering off the device.
+ *
+ * Every call to rproc_boot() must (eventually) be accompanied by a call
+ * to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
+ *
+ * Notes:
+ * - we're not decrementing the rproc's refcount, only the power refcount.
+ *   which means that the @rproc handle stays valid even after rproc_shutdown()
+ *   returns, and users can still use it with a subsequent rproc_boot(), if
+ *   needed.
+ * - don't call rproc_shutdown() to unroll rproc_get_by_name(), exactly
+ *   because rproc_shutdown() _does not_ decrement the refcount of @rproc.
+ *   To decrement the refcount of @rproc, use rproc_put() (but _only_ if
+ *   you acquired @rproc using rproc_get_by_name()).
+ */
+void rproc_shutdown(struct rproc *rproc)
+{
+       struct device *dev = rproc->dev;
+       int ret;
+
+       ret = mutex_lock_interruptible(&rproc->lock);
+       if (ret) {
+               dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret);
+               return;
+       }
+
+       /* if the remote proc is still needed, bail out */
+       if (!atomic_dec_and_test(&rproc->power))
+               goto out;
+
+       /* power off the remote processor */
+       ret = rproc->ops->stop(rproc);
+       if (ret) {
+               atomic_inc(&rproc->power);
+               dev_err(dev, "can't stop rproc: %d\n", ret);
+               goto out;
+       }
+
+       /* clean up all acquired resources */
+       rproc_resource_cleanup(rproc);
+
+       rproc_disable_iommu(rproc);
+
+       rproc->state = RPROC_OFFLINE;
+
+       dev_info(dev, "stopped remote processor %s\n", rproc->name);
+
+out:
+       mutex_unlock(&rproc->lock);
+       if (!ret)
+               module_put(dev->driver->owner);
+}
+EXPORT_SYMBOL(rproc_shutdown);
+
+/**
+ * rproc_release() - completely deletes the existence of a remote processor
+ * @kref: the rproc's kref
+ *
+ * This function should _never_ be called directly.
+ *
+ * The only reasonable location to use it is as an argument when kref_put'ing
+ * @rproc's refcount.
+ *
+ * This way it will be called when no one holds a valid pointer to this @rproc
+ * anymore (and obviously after it is removed from the rprocs klist).
+ *
+ * Note: this function is not static because rproc_vdev_release() needs it when
+ * it decrements @rproc's refcount.
+ */
+void rproc_release(struct kref *kref)
+{
+       struct rproc *rproc = container_of(kref, struct rproc, refcount);
+       struct rproc_vdev *rvdev, *rvtmp;
+
+       dev_info(rproc->dev, "removing %s\n", rproc->name);
+
+       rproc_delete_debug_dir(rproc);
+
+       /* clean up remote vdev entries */
+       list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node) {
+               __rproc_free_vrings(rvdev, RVDEV_NUM_VRINGS);
+               list_del(&rvdev->node);
+       }
+
+       /*
+        * At this point no one holds a reference to rproc anymore,
+        * so we can directly unroll rproc_alloc()
+        */
+       rproc_free(rproc);
+}
+
+/* will be called when an rproc is added to the rprocs klist */
+static void klist_rproc_get(struct klist_node *n)
+{
+       struct rproc *rproc = container_of(n, struct rproc, node);
+
+       kref_get(&rproc->refcount);
+}
+
+/* will be called when an rproc is removed from the rprocs klist */
+static void klist_rproc_put(struct klist_node *n)
+{
+       struct rproc *rproc = container_of(n, struct rproc, node);
+
+       kref_put(&rproc->refcount, rproc_release);
+}
+
+static struct rproc *next_rproc(struct klist_iter *i)
+{
+       struct klist_node *n;
+
+       n = klist_next(i);
+       if (!n)
+               return NULL;
+
+       return container_of(n, struct rproc, node);
+}
+
+/**
+ * rproc_get_by_name() - find a remote processor by name and boot it
+ * @name: name of the remote processor
+ *
+ * Finds an rproc handle using the remote processor's name, and then
+ * boot it. If it's already powered on, then just immediately return
+ * (successfully).
+ *
+ * Returns the rproc handle on success, and NULL on failure.
+ *
+ * This function increments the remote processor's refcount, so always
+ * use rproc_put() to decrement it back once rproc isn't needed anymore.
+ *
+ * Note: currently this function (and its counterpart rproc_put()) are not
+ * being used. We need to scrutinize the use cases
+ * that still need them, and see if we can migrate them to use the non
+ * name-based boot/shutdown interface.
+ */
+struct rproc *rproc_get_by_name(const char *name)
+{
+       struct rproc *rproc;
+       struct klist_iter i;
+       int ret;
+
+       /* find the remote processor, and upref its refcount */
+       klist_iter_init(&rprocs, &i);
+       while ((rproc = next_rproc(&i)) != NULL)
+               if (!strcmp(rproc->name, name)) {
+                       kref_get(&rproc->refcount);
+                       break;
+               }
+       klist_iter_exit(&i);
+
+       /* can't find this rproc ? */
+       if (!rproc) {
+               pr_err("can't find remote processor %s\n", name);
+               return NULL;
+       }
+
+       ret = rproc_boot(rproc);
+       if (ret < 0) {
+               kref_put(&rproc->refcount, rproc_release);
+               return NULL;
+       }
+
+       return rproc;
+}
+EXPORT_SYMBOL(rproc_get_by_name);
+
+/**
+ * rproc_put() - decrement the refcount of a remote processor, and shut it down
+ * @rproc: the remote processor
+ *
+ * This function tries to shutdown @rproc, and it then decrements its
+ * refcount.
+ *
+ * After this function returns, @rproc may _not_ be used anymore, and its
+ * handle should be considered invalid.
+ *
+ * This function should be called _iff_ the @rproc handle was grabbed by
+ * calling rproc_get_by_name().
+ */
+void rproc_put(struct rproc *rproc)
+{
+       /* try to power off the remote processor */
+       rproc_shutdown(rproc);
+
+       /* downref rproc's refcount */
+       kref_put(&rproc->refcount, rproc_release);
+}
+EXPORT_SYMBOL(rproc_put);
+
+/**
+ * rproc_register() - register a remote processor
+ * @rproc: the remote processor handle to register
+ *
+ * Registers @rproc with the remoteproc framework, after it has been
+ * allocated with rproc_alloc().
+ *
+ * This is called by the platform-specific rproc implementation, whenever
+ * a new remote processor device is probed.
+ *
+ * Returns 0 on success and an appropriate error code otherwise.
+ *
+ * Note: this function initiates an asynchronous firmware loading
+ * context, which will look for virtio devices supported by the rproc's
+ * firmware.
+ *
+ * If found, those virtio devices will be created and added, so as a result
+ * of registering this remote processor, additional virtio drivers might be
+ * probed.
+ */
+int rproc_register(struct rproc *rproc)
+{
+       struct device *dev = rproc->dev;
+       int ret = 0;
+
+       /* expose to rproc_get_by_name users */
+       klist_add_tail(&rproc->node, &rprocs);
+
+       dev_info(rproc->dev, "%s is available\n", rproc->name);
+
+       dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n");
+       dev_info(dev, "THE BINARY FORMAT IS NOT YET FINALIZED, and backward compatibility isn't yet guaranteed.\n");
+
+       /* create debugfs entries */
+       rproc_create_debug_dir(rproc);
+
+       /* rproc_unregister() calls must wait until async loader completes */
+       init_completion(&rproc->firmware_loading_complete);
+
+       /*
+        * We must retrieve early virtio configuration info from
+        * the firmware (e.g. whether to register a virtio device,
+        * what virtio features does it support, ...).
+        *
+        * We're initiating an asynchronous firmware loading, so we can
+        * be built-in kernel code, without hanging the boot process.
+        */
+       ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+                                       rproc->firmware, dev, GFP_KERNEL,
+                                       rproc, rproc_fw_config_virtio);
+       if (ret < 0) {
+               dev_err(dev, "request_firmware_nowait failed: %d\n", ret);
+               complete_all(&rproc->firmware_loading_complete);
+               klist_remove(&rproc->node);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(rproc_register);
+
+/**
+ * rproc_alloc() - allocate a remote processor handle
+ * @dev: the underlying device
+ * @name: name of this remote processor
+ * @ops: platform-specific handlers (mainly start/stop)
+ * @firmware: name of firmware file to load
+ * @len: length of private data needed by the rproc driver (in bytes)
+ *
+ * Allocates a new remote processor handle, but does not register
+ * it yet.
+ *
+ * This function should be used by rproc implementations during initialization
+ * of the remote processor.
+ *
+ * After creating an rproc handle using this function, and when ready,
+ * implementations should then call rproc_register() to complete
+ * the registration of the remote processor.
+ *
+ * On success the new rproc is returned, and on failure, NULL.
+ *
+ * Note: _never_ directly deallocate @rproc, even if it was not registered
+ * yet. Instead, if you just need to unroll rproc_alloc(), use rproc_free().
+ */
+struct rproc *rproc_alloc(struct device *dev, const char *name,
+                               const struct rproc_ops *ops,
+                               const char *firmware, int len)
+{
+       struct rproc *rproc;
+
+       if (!dev || !name || !ops)
+               return NULL;
+
+       rproc = kzalloc(sizeof(struct rproc) + len, GFP_KERNEL);
+       if (!rproc) {
+               dev_err(dev, "%s: kzalloc failed\n", __func__);
+               return NULL;
+       }
+
+       rproc->dev = dev;
+       rproc->name = name;
+       rproc->ops = ops;
+       rproc->firmware = firmware;
+       rproc->priv = &rproc[1];
+
+       atomic_set(&rproc->power, 0);
+
+       kref_init(&rproc->refcount);
+
+       mutex_init(&rproc->lock);
+
+       idr_init(&rproc->notifyids);
+
+       INIT_LIST_HEAD(&rproc->carveouts);
+       INIT_LIST_HEAD(&rproc->mappings);
+       INIT_LIST_HEAD(&rproc->traces);
+       INIT_LIST_HEAD(&rproc->rvdevs);
+
+       rproc->state = RPROC_OFFLINE;
+
+       return rproc;
+}
+EXPORT_SYMBOL(rproc_alloc);
+
+/**
+ * rproc_free() - free an rproc handle that was allocated by rproc_alloc
+ * @rproc: the remote processor handle
+ *
+ * This function should _only_ be used if @rproc was only allocated,
+ * but not registered yet.
+ *
+ * If @rproc was already successfully registered (by calling rproc_register()),
+ * then use rproc_unregister() instead.
+ */
+void rproc_free(struct rproc *rproc)
+{
+       idr_remove_all(&rproc->notifyids);
+       idr_destroy(&rproc->notifyids);
+
+       kfree(rproc);
+}
+EXPORT_SYMBOL(rproc_free);
+
+/**
+ * rproc_unregister() - unregister a remote processor
+ * @rproc: rproc handle to unregister
+ *
+ * Unregisters a remote processor, and decrements its refcount.
+ * If its refcount drops to zero, then @rproc will be freed. If not,
+ * it will be freed later once the last reference is dropped.
+ *
+ * This function should be called when the platform specific rproc
+ * implementation decides to remove the rproc device. it should
+ * _only_ be called if a previous invocation of rproc_register()
+ * has completed successfully.
+ *
+ * After rproc_unregister() returns, @rproc is _not_ valid anymore and
+ * it shouldn't be used. More specifically, don't call rproc_free()
+ * or try to directly free @rproc after rproc_unregister() returns;
+ * none of these are needed, and calling them is a bug.
+ *
+ * Returns 0 on success and -EINVAL if @rproc isn't valid.
+ */
+int rproc_unregister(struct rproc *rproc)
+{
+       struct rproc_vdev *rvdev;
+
+       if (!rproc)
+               return -EINVAL;
+
+       /* if rproc is just being registered, wait */
+       wait_for_completion(&rproc->firmware_loading_complete);
+
+       /* clean up remote vdev entries */
+       list_for_each_entry(rvdev, &rproc->rvdevs, node)
+               rproc_remove_virtio_dev(rvdev);
+
+       /* the rproc is downref'ed as soon as it's removed from the klist */
+       klist_del(&rproc->node);
+
+       /* the rproc will only be released after its refcount drops to zero */
+       kref_put(&rproc->refcount, rproc_release);
+
+       return 0;
+}
+EXPORT_SYMBOL(rproc_unregister);
+
+static int __init remoteproc_init(void)
+{
+       rproc_init_debugfs();
+       return 0;
+}
+module_init(remoteproc_init);
+
+static void __exit remoteproc_exit(void)
+{
+       rproc_exit_debugfs();
+}
+module_exit(remoteproc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Generic Remote Processor Framework");
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
new file mode 100644 (file)
index 0000000..70277a5
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Remote Processor Framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Mark Grosen <mgrosen@ti.com>
+ * Brian Swetland <swetland@google.com>
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ * Robert Tivy <rtivy@ti.com>
+ * Armando Uribe De Leon <x0095078@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/remoteproc.h>
+#include <linux/device.h>
+
+/* remoteproc debugfs parent dir */
+static struct dentry *rproc_dbg;
+
+/*
+ * Some remote processors may support dumping trace logs into a shared
+ * memory buffer. We expose this trace buffer using debugfs, so users
+ * can easily tell what's going on remotely.
+ *
+ * We will most probably improve the rproc tracing facilities later on,
+ * but this kind of lightweight and simple mechanism is always good to have,
+ * as it provides very early tracing with little to no dependencies at all.
+ */
+static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf,
+                                               size_t count, loff_t *ppos)
+{
+       struct rproc_mem_entry *trace = filp->private_data;
+       int len = strnlen(trace->va, trace->len);
+
+       return simple_read_from_buffer(userbuf, count, ppos, trace->va, len);
+}
+
+static int rproc_open_generic(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+
+       return 0;
+}
+
+static const struct file_operations trace_rproc_ops = {
+       .read = rproc_trace_read,
+       .open = rproc_open_generic,
+       .llseek = generic_file_llseek,
+};
+
+/*
+ * A state-to-string lookup table, for exposing a human readable state
+ * via debugfs. Always keep in sync with enum rproc_state
+ */
+static const char * const rproc_state_string[] = {
+       "offline",
+       "suspended",
+       "running",
+       "crashed",
+       "invalid",
+};
+
+/* expose the state of the remote processor via debugfs */
+static ssize_t rproc_state_read(struct file *filp, char __user *userbuf,
+                                               size_t count, loff_t *ppos)
+{
+       struct rproc *rproc = filp->private_data;
+       unsigned int state;
+       char buf[30];
+       int i;
+
+       state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
+
+       i = snprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state],
+                                                       rproc->state);
+
+       return simple_read_from_buffer(userbuf, count, ppos, buf, i);
+}
+
+static const struct file_operations rproc_state_ops = {
+       .read = rproc_state_read,
+       .open = rproc_open_generic,
+       .llseek = generic_file_llseek,
+};
+
+/* expose the name of the remote processor via debugfs */
+static ssize_t rproc_name_read(struct file *filp, char __user *userbuf,
+                                               size_t count, loff_t *ppos)
+{
+       struct rproc *rproc = filp->private_data;
+       /* need room for the name, a newline and a terminating null */
+       char buf[100];
+       int i;
+
+       i = snprintf(buf, sizeof(buf), "%.98s\n", rproc->name);
+
+       return simple_read_from_buffer(userbuf, count, ppos, buf, i);
+}
+
+static const struct file_operations rproc_name_ops = {
+       .read = rproc_name_read,
+       .open = rproc_open_generic,
+       .llseek = generic_file_llseek,
+};
+
+void rproc_remove_trace_file(struct dentry *tfile)
+{
+       debugfs_remove(tfile);
+}
+
+struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
+                                       struct rproc_mem_entry *trace)
+{
+       struct dentry *tfile;
+
+       tfile = debugfs_create_file(name, 0400, rproc->dbg_dir,
+                                               trace, &trace_rproc_ops);
+       if (!tfile) {
+               dev_err(rproc->dev, "failed to create debugfs trace entry\n");
+               return NULL;
+       }
+
+       return tfile;
+}
+
+void rproc_delete_debug_dir(struct rproc *rproc)
+{
+       if (!rproc->dbg_dir)
+               return;
+
+       debugfs_remove_recursive(rproc->dbg_dir);
+}
+
+void rproc_create_debug_dir(struct rproc *rproc)
+{
+       struct device *dev = rproc->dev;
+
+       if (!rproc_dbg)
+               return;
+
+       rproc->dbg_dir = debugfs_create_dir(dev_name(dev), rproc_dbg);
+       if (!rproc->dbg_dir)
+               return;
+
+       debugfs_create_file("name", 0400, rproc->dbg_dir,
+                                       rproc, &rproc_name_ops);
+       debugfs_create_file("state", 0400, rproc->dbg_dir,
+                                       rproc, &rproc_state_ops);
+}
+
+void __init rproc_init_debugfs(void)
+{
+       if (debugfs_initialized()) {
+               rproc_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
+               if (!rproc_dbg)
+                       pr_err("can't create debugfs dir\n");
+       }
+}
+
+void __exit rproc_exit_debugfs(void)
+{
+       if (rproc_dbg)
+               debugfs_remove(rproc_dbg);
+}
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
new file mode 100644 (file)
index 0000000..9f336d6
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Remote processor framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef REMOTEPROC_INTERNAL_H
+#define REMOTEPROC_INTERNAL_H
+
+#include <linux/irqreturn.h>
+
+struct rproc;
+
+/* from remoteproc_core.c */
+void rproc_release(struct kref *kref);
+irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id);
+
+/* from remoteproc_virtio.c */
+int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id);
+void rproc_remove_virtio_dev(struct rproc_vdev *rvdev);
+
+/* from remoteproc_debugfs.c */
+void rproc_remove_trace_file(struct dentry *tfile);
+struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
+                                       struct rproc_mem_entry *trace);
+void rproc_delete_debug_dir(struct rproc *rproc);
+void rproc_create_debug_dir(struct rproc *rproc);
+void rproc_init_debugfs(void);
+void rproc_exit_debugfs(void);
+
+#endif /* REMOTEPROC_INTERNAL_H */
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
new file mode 100644 (file)
index 0000000..ecf6121
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Remote processor messaging transport (OMAP platform-specific bits)
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/remoteproc.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_ring.h>
+#include <linux/err.h>
+#include <linux/kref.h>
+#include <linux/slab.h>
+
+#include "remoteproc_internal.h"
+
+/* kick the remote processor, and let it know which virtqueue to poke at */
+static void rproc_virtio_notify(struct virtqueue *vq)
+{
+       struct rproc_vring *rvring = vq->priv;
+       struct rproc *rproc = rvring->rvdev->rproc;
+       int notifyid = rvring->notifyid;
+
+       dev_dbg(rproc->dev, "kicking vq index: %d\n", notifyid);
+
+       rproc->ops->kick(rproc, notifyid);
+}
+
+/**
+ * rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted
+ * @rproc: handle to the remote processor
+ * @notifyid: index of the signalled virtqueue (unique per this @rproc)
+ *
+ * This function should be called by the platform-specific rproc driver,
+ * when the remote processor signals that a specific virtqueue has pending
+ * messages available.
+ *
+ * Returns IRQ_NONE if no message was found in the @notifyid virtqueue,
+ * and otherwise returns IRQ_HANDLED.
+ */
+irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int notifyid)
+{
+       struct rproc_vring *rvring;
+
+       dev_dbg(rproc->dev, "vq index %d is interrupted\n", notifyid);
+
+       rvring = idr_find(&rproc->notifyids, notifyid);
+       if (!rvring || !rvring->vq)
+               return IRQ_NONE;
+
+       return vring_interrupt(0, rvring->vq);
+}
+EXPORT_SYMBOL(rproc_vq_interrupt);
+
+static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
+                                   unsigned id,
+                                   void (*callback)(struct virtqueue *vq),
+                                   const char *name)
+{
+       struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+       struct rproc *rproc = vdev_to_rproc(vdev);
+       struct rproc_vring *rvring;
+       struct virtqueue *vq;
+       void *addr;
+       int len, size;
+
+       /* we're temporarily limited to two virtqueues per rvdev */
+       if (id >= ARRAY_SIZE(rvdev->vring))
+               return ERR_PTR(-EINVAL);
+
+       rvring = &rvdev->vring[id];
+
+       addr = rvring->va;
+       len = rvring->len;
+
+       /* zero vring */
+       size = vring_size(len, rvring->align);
+       memset(addr, 0, size);
+
+       dev_dbg(rproc->dev, "vring%d: va %p qsz %d notifyid %d\n",
+                                       id, addr, len, rvring->notifyid);
+
+       /*
+        * Create the new vq, and tell virtio we're not interested in
+        * the 'weak' smp barriers, since we're talking with a real device.
+        */
+       vq = vring_new_virtqueue(len, rvring->align, vdev, false, addr,
+                                       rproc_virtio_notify, callback, name);
+       if (!vq) {
+               dev_err(rproc->dev, "vring_new_virtqueue %s failed\n", name);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       rvring->vq = vq;
+       vq->priv = rvring;
+
+       return vq;
+}
+
+static void rproc_virtio_del_vqs(struct virtio_device *vdev)
+{
+       struct virtqueue *vq, *n;
+       struct rproc *rproc = vdev_to_rproc(vdev);
+       struct rproc_vring *rvring;
+
+       /* power down the remote processor before deleting vqs */
+       rproc_shutdown(rproc);
+
+       list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
+               rvring = vq->priv;
+               rvring->vq = NULL;
+               vring_del_virtqueue(vq);
+       }
+}
+
+static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+                      struct virtqueue *vqs[],
+                      vq_callback_t *callbacks[],
+                      const char *names[])
+{
+       struct rproc *rproc = vdev_to_rproc(vdev);
+       int i, ret;
+
+       for (i = 0; i < nvqs; ++i) {
+               vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
+               if (IS_ERR(vqs[i])) {
+                       ret = PTR_ERR(vqs[i]);
+                       goto error;
+               }
+       }
+
+       /* now that the vqs are all set, boot the remote processor */
+       ret = rproc_boot(rproc);
+       if (ret) {
+               dev_err(rproc->dev, "rproc_boot() failed %d\n", ret);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       rproc_virtio_del_vqs(vdev);
+       return ret;
+}
+
+/*
+ * We don't support yet real virtio status semantics.
+ *
+ * The plan is to provide this via the VDEV resource entry
+ * which is part of the firmware: this way the remote processor
+ * will be able to access the status values as set by us.
+ */
+static u8 rproc_virtio_get_status(struct virtio_device *vdev)
+{
+       return 0;
+}
+
+static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
+{
+       dev_dbg(&vdev->dev, "status: %d\n", status);
+}
+
+static void rproc_virtio_reset(struct virtio_device *vdev)
+{
+       dev_dbg(&vdev->dev, "reset !\n");
+}
+
+/* provide the vdev features as retrieved from the firmware */
+static u32 rproc_virtio_get_features(struct virtio_device *vdev)
+{
+       struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+
+       return rvdev->dfeatures;
+}
+
+static void rproc_virtio_finalize_features(struct virtio_device *vdev)
+{
+       struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+
+       /* Give virtio_ring a chance to accept features */
+       vring_transport_features(vdev);
+
+       /*
+        * Remember the finalized features of our vdev, and provide it
+        * to the remote processor once it is powered on.
+        *
+        * Similarly to the status field, we don't expose yet the negotiated
+        * features to the remote processors at this point. This will be
+        * fixed as part of a small resource table overhaul and then an
+        * extension of the virtio resource entries.
+        */
+       rvdev->gfeatures = vdev->features[0];
+}
+
+static struct virtio_config_ops rproc_virtio_config_ops = {
+       .get_features   = rproc_virtio_get_features,
+       .finalize_features = rproc_virtio_finalize_features,
+       .find_vqs       = rproc_virtio_find_vqs,
+       .del_vqs        = rproc_virtio_del_vqs,
+       .reset          = rproc_virtio_reset,
+       .set_status     = rproc_virtio_set_status,
+       .get_status     = rproc_virtio_get_status,
+};
+
+/*
+ * This function is called whenever vdev is released, and is responsible
+ * to decrement the remote processor's refcount taken when vdev was
+ * added.
+ *
+ * Never call this function directly; it will be called by the driver
+ * core when needed.
+ */
+static void rproc_vdev_release(struct device *dev)
+{
+       struct virtio_device *vdev = dev_to_virtio(dev);
+       struct rproc *rproc = vdev_to_rproc(vdev);
+
+       kref_put(&rproc->refcount, rproc_release);
+}
+
+/**
+ * rproc_add_virtio_dev() - register an rproc-induced virtio device
+ * @rvdev: the remote vdev
+ *
+ * This function registers a virtio device. This vdev's partent is
+ * the rproc device.
+ *
+ * Returns 0 on success or an appropriate error value otherwise.
+ */
+int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id)
+{
+       struct rproc *rproc = rvdev->rproc;
+       struct device *dev = rproc->dev;
+       struct virtio_device *vdev = &rvdev->vdev;
+       int ret;
+
+       vdev->id.device = id,
+       vdev->config = &rproc_virtio_config_ops,
+       vdev->dev.parent = dev;
+       vdev->dev.release = rproc_vdev_release;
+
+       /*
+        * We're indirectly making a non-temporary copy of the rproc pointer
+        * here, because drivers probed with this vdev will indirectly
+        * access the wrapping rproc.
+        *
+        * Therefore we must increment the rproc refcount here, and decrement
+        * it _only_ when the vdev is released.
+        */
+       kref_get(&rproc->refcount);
+
+       ret = register_virtio_device(vdev);
+       if (ret) {
+               kref_put(&rproc->refcount, rproc_release);
+               dev_err(dev, "failed to register vdev: %d\n", ret);
+               goto out;
+       }
+
+       dev_info(dev, "registered %s (type %d)\n", dev_name(&vdev->dev), id);
+
+out:
+       return ret;
+}
+
+/**
+ * rproc_remove_virtio_dev() - remove an rproc-induced virtio device
+ * @rvdev: the remote vdev
+ *
+ * This function unregisters an existing virtio device.
+ */
+void rproc_remove_virtio_dev(struct rproc_vdev *rvdev)
+{
+       unregister_virtio_device(&rvdev->vdev);
+}
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
new file mode 100644 (file)
index 0000000..32aead6
--- /dev/null
@@ -0,0 +1,10 @@
+menu "Rpmsg drivers (EXPERIMENTAL)"
+
+# RPMSG always gets selected by whoever wants it
+config RPMSG
+       tristate
+       select VIRTIO
+       select VIRTIO_RING
+       depends on EXPERIMENTAL
+
+endmenu
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
new file mode 100644 (file)
index 0000000..7617fcb
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_RPMSG)    += virtio_rpmsg_bus.o
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
new file mode 100644 (file)
index 0000000..75506ec
--- /dev/null
@@ -0,0 +1,1054 @@
+/*
+ * Virtio-based remote processor messaging bus
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/rpmsg.h>
+#include <linux/mutex.h>
+
+/**
+ * struct virtproc_info - virtual remote processor state
+ * @vdev:      the virtio device
+ * @rvq:       rx virtqueue
+ * @svq:       tx virtqueue
+ * @rbufs:     kernel address of rx buffers
+ * @sbufs:     kernel address of tx buffers
+ * @last_sbuf: index of last tx buffer used
+ * @bufs_dma:  dma base addr of the buffers
+ * @tx_lock:   protects svq, sbufs and sleepers, to allow concurrent senders.
+ *             sending a message might require waking up a dozing remote
+ *             processor, which involves sleeping, hence the mutex.
+ * @endpoints: idr of local endpoints, allows fast retrieval
+ * @endpoints_lock: lock of the endpoints set
+ * @sendq:     wait queue of sending contexts waiting for a tx buffers
+ * @sleepers:  number of senders that are waiting for a tx buffer
+ * @ns_ept:    the bus's name service endpoint
+ *
+ * This structure stores the rpmsg state of a given virtio remote processor
+ * device (there might be several virtio proc devices for each physical
+ * remote processor).
+ */
+struct virtproc_info {
+       struct virtio_device *vdev;
+       struct virtqueue *rvq, *svq;
+       void *rbufs, *sbufs;
+       int last_sbuf;
+       dma_addr_t bufs_dma;
+       struct mutex tx_lock;
+       struct idr endpoints;
+       struct mutex endpoints_lock;
+       wait_queue_head_t sendq;
+       atomic_t sleepers;
+       struct rpmsg_endpoint *ns_ept;
+};
+
+/**
+ * struct rpmsg_channel_info - internal channel info representation
+ * @name: name of service
+ * @src: local address
+ * @dst: destination address
+ */
+struct rpmsg_channel_info {
+       char name[RPMSG_NAME_SIZE];
+       u32 src;
+       u32 dst;
+};
+
+#define to_rpmsg_channel(d) container_of(d, struct rpmsg_channel, dev)
+#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
+
+/*
+ * We're allocating 512 buffers of 512 bytes for communications, and then
+ * using the first 256 buffers for RX, and the last 256 buffers for TX.
+ *
+ * Each buffer will have 16 bytes for the msg header and 496 bytes for
+ * the payload.
+ *
+ * This will require a total space of 256KB for the buffers.
+ *
+ * We might also want to add support for user-provided buffers in time.
+ * This will allow bigger buffer size flexibility, and can also be used
+ * to achieve zero-copy messaging.
+ *
+ * Note that these numbers are purely a decision of this driver - we
+ * can change this without changing anything in the firmware of the remote
+ * processor.
+ */
+#define RPMSG_NUM_BUFS         (512)
+#define RPMSG_BUF_SIZE         (512)
+#define RPMSG_TOTAL_BUF_SPACE  (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
+
+/*
+ * Local addresses are dynamically allocated on-demand.
+ * We do not dynamically assign addresses from the low 1024 range,
+ * in order to reserve that address range for predefined services.
+ */
+#define RPMSG_RESERVED_ADDRESSES       (1024)
+
+/* Address 53 is reserved for advertising remote services */
+#define RPMSG_NS_ADDR                  (53)
+
+/* sysfs show configuration fields */
+#define rpmsg_show_attr(field, path, format_string)                    \
+static ssize_t                                                         \
+field##_show(struct device *dev,                                       \
+                       struct device_attribute *attr, char *buf)       \
+{                                                                      \
+       struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);            \
+                                                                       \
+       return sprintf(buf, format_string, rpdev->path);                \
+}
+
+/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */
+rpmsg_show_attr(name, id.name, "%s\n");
+rpmsg_show_attr(src, src, "0x%x\n");
+rpmsg_show_attr(dst, dst, "0x%x\n");
+rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n");
+
+/*
+ * Unique (and free running) index for rpmsg devices.
+ *
+ * Yeah, we're not recycling those numbers (yet?). will be easy
+ * to change if/when we want to.
+ */
+static unsigned int rpmsg_dev_index;
+
+static ssize_t modalias_show(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+
+       return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name);
+}
+
+static struct device_attribute rpmsg_dev_attrs[] = {
+       __ATTR_RO(name),
+       __ATTR_RO(modalias),
+       __ATTR_RO(dst),
+       __ATTR_RO(src),
+       __ATTR_RO(announce),
+       __ATTR_NULL
+};
+
+/* rpmsg devices and drivers are matched using the service name */
+static inline int rpmsg_id_match(const struct rpmsg_channel *rpdev,
+                                 const struct rpmsg_device_id *id)
+{
+       return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0;
+}
+
+/* match rpmsg channel and rpmsg driver */
+static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
+{
+       struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+       struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
+       const struct rpmsg_device_id *ids = rpdrv->id_table;
+       unsigned int i;
+
+       for (i = 0; ids[i].name[0]; i++)
+               if (rpmsg_id_match(rpdev, &ids[i]))
+                       return 1;
+
+       return 0;
+}
+
+static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+
+       return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT,
+                                       rpdev->id.name);
+}
+
+/* for more info, see below documentation of rpmsg_create_ept() */
+static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
+               struct rpmsg_channel *rpdev, rpmsg_rx_cb_t cb,
+               void *priv, u32 addr)
+{
+       int err, tmpaddr, request;
+       struct rpmsg_endpoint *ept;
+       struct device *dev = rpdev ? &rpdev->dev : &vrp->vdev->dev;
+
+       if (!idr_pre_get(&vrp->endpoints, GFP_KERNEL))
+               return NULL;
+
+       ept = kzalloc(sizeof(*ept), GFP_KERNEL);
+       if (!ept) {
+               dev_err(dev, "failed to kzalloc a new ept\n");
+               return NULL;
+       }
+
+       ept->rpdev = rpdev;
+       ept->cb = cb;
+       ept->priv = priv;
+
+       /* do we need to allocate a local address ? */
+       request = addr == RPMSG_ADDR_ANY ? RPMSG_RESERVED_ADDRESSES : addr;
+
+       mutex_lock(&vrp->endpoints_lock);
+
+       /* bind the endpoint to an rpmsg address (and allocate one if needed) */
+       err = idr_get_new_above(&vrp->endpoints, ept, request, &tmpaddr);
+       if (err) {
+               dev_err(dev, "idr_get_new_above failed: %d\n", err);
+               goto free_ept;
+       }
+
+       /* make sure the user's address request is fulfilled, if relevant */
+       if (addr != RPMSG_ADDR_ANY && tmpaddr != addr) {
+               dev_err(dev, "address 0x%x already in use\n", addr);
+               goto rem_idr;
+       }
+
+       ept->addr = tmpaddr;
+
+       mutex_unlock(&vrp->endpoints_lock);
+
+       return ept;
+
+rem_idr:
+       idr_remove(&vrp->endpoints, request);
+free_ept:
+       mutex_unlock(&vrp->endpoints_lock);
+       kfree(ept);
+       return NULL;
+}
+
+/**
+ * rpmsg_create_ept() - create a new rpmsg_endpoint
+ * @rpdev: rpmsg channel device
+ * @cb: rx callback handler
+ * @priv: private data for the driver's use
+ * @addr: local rpmsg address to bind with @cb
+ *
+ * Every rpmsg address in the system is bound to an rx callback (so when
+ * inbound messages arrive, they are dispatched by the rpmsg bus using the
+ * appropriate callback handler) by means of an rpmsg_endpoint struct.
+ *
+ * This function allows drivers to create such an endpoint, and by that,
+ * bind a callback, and possibly some private data too, to an rpmsg address
+ * (either one that is known in advance, or one that will be dynamically
+ * assigned for them).
+ *
+ * Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint
+ * is already created for them when they are probed by the rpmsg bus
+ * (using the rx callback provided when they registered to the rpmsg bus).
+ *
+ * So things should just work for simple drivers: they already have an
+ * endpoint, their rx callback is bound to their rpmsg address, and when
+ * relevant inbound messages arrive (i.e. messages which their dst address
+ * equals to the src address of their rpmsg channel), the driver's handler
+ * is invoked to process it.
+ *
+ * That said, more complicated drivers might do need to allocate
+ * additional rpmsg addresses, and bind them to different rx callbacks.
+ * To accomplish that, those drivers need to call this function.
+ *
+ * Drivers should provide their @rpdev channel (so the new endpoint would belong
+ * to the same remote processor their channel belongs to), an rx callback
+ * function, an optional private data (which is provided back when the
+ * rx callback is invoked), and an address they want to bind with the
+ * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will
+ * dynamically assign them an available rpmsg address (drivers should have
+ * a very good reason why not to always use RPMSG_ADDR_ANY here).
+ *
+ * Returns a pointer to the endpoint on success, or NULL on error.
+ */
+struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rpdev,
+                               rpmsg_rx_cb_t cb, void *priv, u32 addr)
+{
+       return __rpmsg_create_ept(rpdev->vrp, rpdev, cb, priv, addr);
+}
+EXPORT_SYMBOL(rpmsg_create_ept);
+
+/**
+ * __rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
+ * @vrp: virtproc which owns this ept
+ * @ept: endpoing to destroy
+ *
+ * An internal function which destroy an ept without assuming it is
+ * bound to an rpmsg channel. This is needed for handling the internal
+ * name service endpoint, which isn't bound to an rpmsg channel.
+ * See also __rpmsg_create_ept().
+ */
+static void
+__rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
+{
+       mutex_lock(&vrp->endpoints_lock);
+       idr_remove(&vrp->endpoints, ept->addr);
+       mutex_unlock(&vrp->endpoints_lock);
+
+       kfree(ept);
+}
+
+/**
+ * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint
+ * @ept: endpoing to destroy
+ *
+ * Should be used by drivers to destroy an rpmsg endpoint previously
+ * created with rpmsg_create_ept().
+ */
+void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
+{
+       __rpmsg_destroy_ept(ept->rpdev->vrp, ept);
+}
+EXPORT_SYMBOL(rpmsg_destroy_ept);
+
+/*
+ * when an rpmsg driver is probed with a channel, we seamlessly create
+ * it an endpoint, binding its rx callback to a unique local rpmsg
+ * address.
+ *
+ * if we need to, we also announce about this channel to the remote
+ * processor (needed in case the driver is exposing an rpmsg service).
+ */
+static int rpmsg_dev_probe(struct device *dev)
+{
+       struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+       struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+       struct virtproc_info *vrp = rpdev->vrp;
+       struct rpmsg_endpoint *ept;
+       int err;
+
+       ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src);
+       if (!ept) {
+               dev_err(dev, "failed to create endpoint\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       rpdev->ept = ept;
+       rpdev->src = ept->addr;
+
+       err = rpdrv->probe(rpdev);
+       if (err) {
+               dev_err(dev, "%s: failed: %d\n", __func__, err);
+               rpmsg_destroy_ept(ept);
+               goto out;
+       }
+
+       /* need to tell remote processor's name service about this channel ? */
+       if (rpdev->announce &&
+                       virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
+               struct rpmsg_ns_msg nsm;
+
+               strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE);
+               nsm.addr = rpdev->src;
+               nsm.flags = RPMSG_NS_CREATE;
+
+               err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
+               if (err)
+                       dev_err(dev, "failed to announce service %d\n", err);
+       }
+
+out:
+       return err;
+}
+
+static int rpmsg_dev_remove(struct device *dev)
+{
+       struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+       struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+       struct virtproc_info *vrp = rpdev->vrp;
+       int err = 0;
+
+       /* tell remote processor's name service we're removing this channel */
+       if (rpdev->announce &&
+                       virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
+               struct rpmsg_ns_msg nsm;
+
+               strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE);
+               nsm.addr = rpdev->src;
+               nsm.flags = RPMSG_NS_DESTROY;
+
+               err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
+               if (err)
+                       dev_err(dev, "failed to announce service %d\n", err);
+       }
+
+       rpdrv->remove(rpdev);
+
+       rpmsg_destroy_ept(rpdev->ept);
+
+       return err;
+}
+
+static struct bus_type rpmsg_bus = {
+       .name           = "rpmsg",
+       .match          = rpmsg_dev_match,
+       .dev_attrs      = rpmsg_dev_attrs,
+       .uevent         = rpmsg_uevent,
+       .probe          = rpmsg_dev_probe,
+       .remove         = rpmsg_dev_remove,
+};
+
+/**
+ * register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus
+ * @rpdrv: pointer to a struct rpmsg_driver
+ *
+ * Returns 0 on success, and an appropriate error value on failure.
+ */
+int register_rpmsg_driver(struct rpmsg_driver *rpdrv)
+{
+       rpdrv->drv.bus = &rpmsg_bus;
+       return driver_register(&rpdrv->drv);
+}
+EXPORT_SYMBOL(register_rpmsg_driver);
+
+/**
+ * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg bus
+ * @rpdrv: pointer to a struct rpmsg_driver
+ *
+ * Returns 0 on success, and an appropriate error value on failure.
+ */
+void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv)
+{
+       driver_unregister(&rpdrv->drv);
+}
+EXPORT_SYMBOL(unregister_rpmsg_driver);
+
+static void rpmsg_release_device(struct device *dev)
+{
+       struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+
+       kfree(rpdev);
+}
+
+/*
+ * match an rpmsg channel with a channel info struct.
+ * this is used to make sure we're not creating rpmsg devices for channels
+ * that already exist.
+ */
+static int rpmsg_channel_match(struct device *dev, void *data)
+{
+       struct rpmsg_channel_info *chinfo = data;
+       struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+
+       if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src)
+               return 0;
+
+       if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst)
+               return 0;
+
+       if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE))
+               return 0;
+
+       /* found a match ! */
+       return 1;
+}
+
+/*
+ * create an rpmsg channel using its name and address info.
+ * this function will be used to create both static and dynamic
+ * channels.
+ */
+static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp,
+                               struct rpmsg_channel_info *chinfo)
+{
+       struct rpmsg_channel *rpdev;
+       struct device *tmp, *dev = &vrp->vdev->dev;
+       int ret;
+
+       /* make sure a similar channel doesn't already exist */
+       tmp = device_find_child(dev, chinfo, rpmsg_channel_match);
+       if (tmp) {
+               /* decrement the matched device's refcount back */
+               put_device(tmp);
+               dev_err(dev, "channel %s:%x:%x already exist\n",
+                               chinfo->name, chinfo->src, chinfo->dst);
+               return NULL;
+       }
+
+       rpdev = kzalloc(sizeof(struct rpmsg_channel), GFP_KERNEL);
+       if (!rpdev) {
+               pr_err("kzalloc failed\n");
+               return NULL;
+       }
+
+       rpdev->vrp = vrp;
+       rpdev->src = chinfo->src;
+       rpdev->dst = chinfo->dst;
+
+       /*
+        * rpmsg server channels has predefined local address (for now),
+        * and their existence needs to be announced remotely
+        */
+       rpdev->announce = rpdev->src != RPMSG_ADDR_ANY ? true : false;
+
+       strncpy(rpdev->id.name, chinfo->name, RPMSG_NAME_SIZE);
+
+       /* very simple device indexing plumbing which is enough for now */
+       dev_set_name(&rpdev->dev, "rpmsg%d", rpmsg_dev_index++);
+
+       rpdev->dev.parent = &vrp->vdev->dev;
+       rpdev->dev.bus = &rpmsg_bus;
+       rpdev->dev.release = rpmsg_release_device;
+
+       ret = device_register(&rpdev->dev);
+       if (ret) {
+               dev_err(dev, "device_register failed: %d\n", ret);
+               put_device(&rpdev->dev);
+               return NULL;
+       }
+
+       return rpdev;
+}
+
+/*
+ * find an existing channel using its name + address properties,
+ * and destroy it
+ */
+static int rpmsg_destroy_channel(struct virtproc_info *vrp,
+                                       struct rpmsg_channel_info *chinfo)
+{
+       struct virtio_device *vdev = vrp->vdev;
+       struct device *dev;
+
+       dev = device_find_child(&vdev->dev, chinfo, rpmsg_channel_match);
+       if (!dev)
+               return -EINVAL;
+
+       device_unregister(dev);
+
+       put_device(dev);
+
+       return 0;
+}
+
+/* super simple buffer "allocator" that is just enough for now */
+static void *get_a_tx_buf(struct virtproc_info *vrp)
+{
+       unsigned int len;
+       void *ret;
+
+       /* support multiple concurrent senders */
+       mutex_lock(&vrp->tx_lock);
+
+       /*
+        * either pick the next unused tx buffer
+        * (half of our buffers are used for sending messages)
+        */
+       if (vrp->last_sbuf < RPMSG_NUM_BUFS / 2)
+               ret = vrp->sbufs + RPMSG_BUF_SIZE * vrp->last_sbuf++;
+       /* or recycle a used one */
+       else
+               ret = virtqueue_get_buf(vrp->svq, &len);
+
+       mutex_unlock(&vrp->tx_lock);
+
+       return ret;
+}
+
+/**
+ * rpmsg_upref_sleepers() - enable "tx-complete" interrupts, if needed
+ * @vrp: virtual remote processor state
+ *
+ * This function is called before a sender is blocked, waiting for
+ * a tx buffer to become available.
+ *
+ * If we already have blocking senders, this function merely increases
+ * the "sleepers" reference count, and exits.
+ *
+ * Otherwise, if this is the first sender to block, we also enable
+ * virtio's tx callbacks, so we'd be immediately notified when a tx
+ * buffer is consumed (we rely on virtio's tx callback in order
+ * to wake up sleeping senders as soon as a tx buffer is used by the
+ * remote processor).
+ */
+static void rpmsg_upref_sleepers(struct virtproc_info *vrp)
+{
+       /* support multiple concurrent senders */
+       mutex_lock(&vrp->tx_lock);
+
+       /* are we the first sleeping context waiting for tx buffers ? */
+       if (atomic_inc_return(&vrp->sleepers) == 1)
+               /* enable "tx-complete" interrupts before dozing off */
+               virtqueue_enable_cb(vrp->svq);
+
+       mutex_unlock(&vrp->tx_lock);
+}
+
+/**
+ * rpmsg_downref_sleepers() - disable "tx-complete" interrupts, if needed
+ * @vrp: virtual remote processor state
+ *
+ * This function is called after a sender, that waited for a tx buffer
+ * to become available, is unblocked.
+ *
+ * If we still have blocking senders, this function merely decreases
+ * the "sleepers" reference count, and exits.
+ *
+ * Otherwise, if there are no more blocking senders, we also disable
+ * virtio's tx callbacks, to avoid the overhead incurred with handling
+ * those (now redundant) interrupts.
+ */
+static void rpmsg_downref_sleepers(struct virtproc_info *vrp)
+{
+       /* support multiple concurrent senders */
+       mutex_lock(&vrp->tx_lock);
+
+       /* are we the last sleeping context waiting for tx buffers ? */
+       if (atomic_dec_and_test(&vrp->sleepers))
+               /* disable "tx-complete" interrupts */
+               virtqueue_disable_cb(vrp->svq);
+
+       mutex_unlock(&vrp->tx_lock);
+}
+
+/**
+ * rpmsg_send_offchannel_raw() - send a message across to the remote processor
+ * @rpdev: the rpmsg channel
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ * @wait: indicates whether caller should block in case no TX buffers available
+ *
+ * This function is the base implementation for all of the rpmsg sending API.
+ *
+ * It will send @data of length @len to @dst, and say it's from @src. The
+ * message will be sent to the remote processor which the @rpdev channel
+ * belongs to.
+ *
+ * The message is sent using one of the TX buffers that are available for
+ * communication with this remote processor.
+ *
+ * If @wait is true, the caller will be blocked until either a TX buffer is
+ * available, or 15 seconds elapses (we don't want callers to
+ * sleep indefinitely due to misbehaving remote processors), and in that
+ * case -ERESTARTSYS is returned. The number '15' itself was picked
+ * arbitrarily; there's little point in asking drivers to provide a timeout
+ * value themselves.
+ *
+ * Otherwise, if @wait is false, and there are no TX buffers available,
+ * the function will immediately fail, and -ENOMEM will be returned.
+ *
+ * Normally drivers shouldn't use this function directly; instead, drivers
+ * should use the appropriate rpmsg_{try}send{to, _offchannel} API
+ * (see include/linux/rpmsg.h).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+                                       void *data, int len, bool wait)
+{
+       struct virtproc_info *vrp = rpdev->vrp;
+       struct device *dev = &rpdev->dev;
+       struct scatterlist sg;
+       struct rpmsg_hdr *msg;
+       int err;
+
+       /* bcasting isn't allowed */
+       if (src == RPMSG_ADDR_ANY || dst == RPMSG_ADDR_ANY) {
+               dev_err(dev, "invalid addr (src 0x%x, dst 0x%x)\n", src, dst);
+               return -EINVAL;
+       }
+
+       /*
+        * We currently use fixed-sized buffers, and therefore the payload
+        * length is limited.
+        *
+        * One of the possible improvements here is either to support
+        * user-provided buffers (and then we can also support zero-copy
+        * messaging), or to improve the buffer allocator, to support
+        * variable-length buffer sizes.
+        */
+       if (len > RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) {
+               dev_err(dev, "message is too big (%d)\n", len);
+               return -EMSGSIZE;
+       }
+
+       /* grab a buffer */
+       msg = get_a_tx_buf(vrp);
+       if (!msg && !wait)
+               return -ENOMEM;
+
+       /* no free buffer ? wait for one (but bail after 15 seconds) */
+       while (!msg) {
+               /* enable "tx-complete" interrupts, if not already enabled */
+               rpmsg_upref_sleepers(vrp);
+
+               /*
+                * sleep until a free buffer is available or 15 secs elapse.
+                * the timeout period is not configurable because there's
+                * little point in asking drivers to specify that.
+                * if later this happens to be required, it'd be easy to add.
+                */
+               err = wait_event_interruptible_timeout(vrp->sendq,
+                                       (msg = get_a_tx_buf(vrp)),
+                                       msecs_to_jiffies(15000));
+
+               /* disable "tx-complete" interrupts if we're the last sleeper */
+               rpmsg_downref_sleepers(vrp);
+
+               /* timeout ? */
+               if (!err) {
+                       dev_err(dev, "timeout waiting for a tx buffer\n");
+                       return -ERESTARTSYS;
+               }
+       }
+
+       msg->len = len;
+       msg->flags = 0;
+       msg->src = src;
+       msg->dst = dst;
+       msg->reserved = 0;
+       memcpy(msg->data, data, len);
+
+       dev_dbg(dev, "TX From 0x%x, To 0x%x, Len %d, Flags %d, Reserved %d\n",
+                                       msg->src, msg->dst, msg->len,
+                                       msg->flags, msg->reserved);
+       print_hex_dump(KERN_DEBUG, "rpmsg_virtio TX: ", DUMP_PREFIX_NONE, 16, 1,
+                                       msg, sizeof(*msg) + msg->len, true);
+
+       sg_init_one(&sg, msg, sizeof(*msg) + len);
+
+       mutex_lock(&vrp->tx_lock);
+
+       /* add message to the remote processor's virtqueue */
+       err = virtqueue_add_buf(vrp->svq, &sg, 1, 0, msg, GFP_KERNEL);
+       if (err < 0) {
+               /*
+                * need to reclaim the buffer here, otherwise it's lost
+                * (memory won't leak, but rpmsg won't use it again for TX).
+                * this will wait for a buffer management overhaul.
+                */
+               dev_err(dev, "virtqueue_add_buf failed: %d\n", err);
+               goto out;
+       }
+
+       /* tell the remote processor it has a pending message to read */
+       virtqueue_kick(vrp->svq);
+
+       err = 0;
+out:
+       mutex_unlock(&vrp->tx_lock);
+       return err;
+}
+EXPORT_SYMBOL(rpmsg_send_offchannel_raw);
+
+/* called when an rx buffer is used, and it's time to digest a message */
+static void rpmsg_recv_done(struct virtqueue *rvq)
+{
+       struct rpmsg_hdr *msg;
+       unsigned int len;
+       struct rpmsg_endpoint *ept;
+       struct scatterlist sg;
+       struct virtproc_info *vrp = rvq->vdev->priv;
+       struct device *dev = &rvq->vdev->dev;
+       int err;
+
+       msg = virtqueue_get_buf(rvq, &len);
+       if (!msg) {
+               dev_err(dev, "uhm, incoming signal, but no used buffer ?\n");
+               return;
+       }
+
+       dev_dbg(dev, "From: 0x%x, To: 0x%x, Len: %d, Flags: %d, Reserved: %d\n",
+                                       msg->src, msg->dst, msg->len,
+                                       msg->flags, msg->reserved);
+       print_hex_dump(KERN_DEBUG, "rpmsg_virtio RX: ", DUMP_PREFIX_NONE, 16, 1,
+                                       msg, sizeof(*msg) + msg->len, true);
+
+       /*
+        * We currently use fixed-sized buffers, so trivially sanitize
+        * the reported payload length.
+        */
+       if (len > RPMSG_BUF_SIZE ||
+               msg->len > (len - sizeof(struct rpmsg_hdr))) {
+               dev_warn(dev, "inbound msg too big: (%d, %d)\n", len, msg->len);
+               return;
+       }
+
+       /* use the dst addr to fetch the callback of the appropriate user */
+       mutex_lock(&vrp->endpoints_lock);
+       ept = idr_find(&vrp->endpoints, msg->dst);
+       mutex_unlock(&vrp->endpoints_lock);
+
+       if (ept && ept->cb)
+               ept->cb(ept->rpdev, msg->data, msg->len, ept->priv, msg->src);
+       else
+               dev_warn(dev, "msg received with no recepient\n");
+
+       /* publish the real size of the buffer */
+       sg_init_one(&sg, msg, RPMSG_BUF_SIZE);
+
+       /* add the buffer back to the remote processor's virtqueue */
+       err = virtqueue_add_buf(vrp->rvq, &sg, 0, 1, msg, GFP_KERNEL);
+       if (err < 0) {
+               dev_err(dev, "failed to add a virtqueue buffer: %d\n", err);
+               return;
+       }
+
+       /* tell the remote processor we added another available rx buffer */
+       virtqueue_kick(vrp->rvq);
+}
+
+/*
+ * This is invoked whenever the remote processor completed processing
+ * a TX msg we just sent it, and the buffer is put back to the used ring.
+ *
+ * Normally, though, we suppress this "tx complete" interrupt in order to
+ * avoid the incurred overhead.
+ */
+static void rpmsg_xmit_done(struct virtqueue *svq)
+{
+       struct virtproc_info *vrp = svq->vdev->priv;
+
+       dev_dbg(&svq->vdev->dev, "%s\n", __func__);
+
+       /* wake up potential senders that are waiting for a tx buffer */
+       wake_up_interruptible(&vrp->sendq);
+}
+
+/* invoked when a name service announcement arrives */
+static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
+                                                       void *priv, u32 src)
+{
+       struct rpmsg_ns_msg *msg = data;
+       struct rpmsg_channel *newch;
+       struct rpmsg_channel_info chinfo;
+       struct virtproc_info *vrp = priv;
+       struct device *dev = &vrp->vdev->dev;
+       int ret;
+
+       print_hex_dump(KERN_DEBUG, "NS announcement: ",
+                       DUMP_PREFIX_NONE, 16, 1,
+                       data, len, true);
+
+       if (len != sizeof(*msg)) {
+               dev_err(dev, "malformed ns msg (%d)\n", len);
+               return;
+       }
+
+       /*
+        * the name service ept does _not_ belong to a real rpmsg channel,
+        * and is handled by the rpmsg bus itself.
+        * for sanity reasons, make sure a valid rpdev has _not_ sneaked
+        * in somehow.
+        */
+       if (rpdev) {
+               dev_err(dev, "anomaly: ns ept has an rpdev handle\n");
+               return;
+       }
+
+       /* don't trust the remote processor for null terminating the name */
+       msg->name[RPMSG_NAME_SIZE - 1] = '\0';
+
+       dev_info(dev, "%sing channel %s addr 0x%x\n",
+                       msg->flags & RPMSG_NS_DESTROY ? "destroy" : "creat",
+                       msg->name, msg->addr);
+
+       strncpy(chinfo.name, msg->name, sizeof(chinfo.name));
+       chinfo.src = RPMSG_ADDR_ANY;
+       chinfo.dst = msg->addr;
+
+       if (msg->flags & RPMSG_NS_DESTROY) {
+               ret = rpmsg_destroy_channel(vrp, &chinfo);
+               if (ret)
+                       dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
+       } else {
+               newch = rpmsg_create_channel(vrp, &chinfo);
+               if (!newch)
+                       dev_err(dev, "rpmsg_create_channel failed\n");
+       }
+}
+
+static int rpmsg_probe(struct virtio_device *vdev)
+{
+       vq_callback_t *vq_cbs[] = { rpmsg_recv_done, rpmsg_xmit_done };
+       const char *names[] = { "input", "output" };
+       struct virtqueue *vqs[2];
+       struct virtproc_info *vrp;
+       void *bufs_va;
+       int err = 0, i;
+
+       vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
+       if (!vrp)
+               return -ENOMEM;
+
+       vrp->vdev = vdev;
+
+       idr_init(&vrp->endpoints);
+       mutex_init(&vrp->endpoints_lock);
+       mutex_init(&vrp->tx_lock);
+       init_waitqueue_head(&vrp->sendq);
+
+       /* We expect two virtqueues, rx and tx (and in this order) */
+       err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, names);
+       if (err)
+               goto free_vrp;
+
+       vrp->rvq = vqs[0];
+       vrp->svq = vqs[1];
+
+       /* allocate coherent memory for the buffers */
+       bufs_va = dma_alloc_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE,
+                               &vrp->bufs_dma, GFP_KERNEL);
+       if (!bufs_va)
+               goto vqs_del;
+
+       dev_dbg(&vdev->dev, "buffers: va %p, dma 0x%llx\n", bufs_va,
+                                       (unsigned long long)vrp->bufs_dma);
+
+       /* half of the buffers is dedicated for RX */
+       vrp->rbufs = bufs_va;
+
+       /* and half is dedicated for TX */
+       vrp->sbufs = bufs_va + RPMSG_TOTAL_BUF_SPACE / 2;
+
+       /* set up the receive buffers */
+       for (i = 0; i < RPMSG_NUM_BUFS / 2; i++) {
+               struct scatterlist sg;
+               void *cpu_addr = vrp->rbufs + i * RPMSG_BUF_SIZE;
+
+               sg_init_one(&sg, cpu_addr, RPMSG_BUF_SIZE);
+
+               err = virtqueue_add_buf(vrp->rvq, &sg, 0, 1, cpu_addr,
+                                                               GFP_KERNEL);
+               WARN_ON(err < 0); /* sanity check; this can't really happen */
+       }
+
+       /* suppress "tx-complete" interrupts */
+       virtqueue_disable_cb(vrp->svq);
+
+       vdev->priv = vrp;
+
+       /* if supported by the remote processor, enable the name service */
+       if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_NS)) {
+               /* a dedicated endpoint handles the name service msgs */
+               vrp->ns_ept = __rpmsg_create_ept(vrp, NULL, rpmsg_ns_cb,
+                                               vrp, RPMSG_NS_ADDR);
+               if (!vrp->ns_ept) {
+                       dev_err(&vdev->dev, "failed to create the ns ept\n");
+                       err = -ENOMEM;
+                       goto free_coherent;
+               }
+       }
+
+       /* tell the remote processor it can start sending messages */
+       virtqueue_kick(vrp->rvq);
+
+       dev_info(&vdev->dev, "rpmsg host is online\n");
+
+       return 0;
+
+free_coherent:
+       dma_free_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE, bufs_va,
+                                       vrp->bufs_dma);
+vqs_del:
+       vdev->config->del_vqs(vrp->vdev);
+free_vrp:
+       kfree(vrp);
+       return err;
+}
+
+static int rpmsg_remove_device(struct device *dev, void *data)
+{
+       device_unregister(dev);
+
+       return 0;
+}
+
+static void __devexit rpmsg_remove(struct virtio_device *vdev)
+{
+       struct virtproc_info *vrp = vdev->priv;
+       int ret;
+
+       vdev->config->reset(vdev);
+
+       ret = device_for_each_child(&vdev->dev, NULL, rpmsg_remove_device);
+       if (ret)
+               dev_warn(&vdev->dev, "can't remove rpmsg device: %d\n", ret);
+
+       if (vrp->ns_ept)
+               __rpmsg_destroy_ept(vrp, vrp->ns_ept);
+
+       idr_remove_all(&vrp->endpoints);
+       idr_destroy(&vrp->endpoints);
+
+       vdev->config->del_vqs(vrp->vdev);
+
+       dma_free_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE,
+                                       vrp->rbufs, vrp->bufs_dma);
+
+       kfree(vrp);
+}
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_RPMSG, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+static unsigned int features[] = {
+       VIRTIO_RPMSG_F_NS,
+};
+
+static struct virtio_driver virtio_ipc_driver = {
+       .feature_table  = features,
+       .feature_table_size = ARRAY_SIZE(features),
+       .driver.name    = KBUILD_MODNAME,
+       .driver.owner   = THIS_MODULE,
+       .id_table       = id_table,
+       .probe          = rpmsg_probe,
+       .remove         = __devexit_p(rpmsg_remove),
+};
+
+static int __init rpmsg_init(void)
+{
+       int ret;
+
+       ret = bus_register(&rpmsg_bus);
+       if (ret) {
+               pr_err("failed to register rpmsg bus: %d\n", ret);
+               return ret;
+       }
+
+       ret = register_virtio_driver(&virtio_ipc_driver);
+       if (ret) {
+               pr_err("failed to register virtio driver: %d\n", ret);
+               bus_unregister(&rpmsg_bus);
+       }
+
+       return ret;
+}
+module_init(rpmsg_init);
+
+static void __exit rpmsg_fini(void)
+{
+       unregister_virtio_driver(&virtio_ipc_driver);
+       bus_unregister(&rpmsg_bus);
+}
+module_exit(rpmsg_fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio-based remote processor messaging bus");
+MODULE_LICENSE("GPL v2");
index 3a125b8..8c8377d 100644 (file)
@@ -554,6 +554,13 @@ config RTC_DRV_DS1742
          This driver can also be built as a module. If so, the module
          will be called rtc-ds1742.
 
+config RTC_DRV_DA9052
+       tristate "Dialog DA9052/DA9053 RTC"
+       depends on PMIC_DA9052
+       help
+         Say y here to support the RTC driver for Dialog Semiconductor
+         DA9052-BC and DA9053-AA/Bx PMICs.
+
 config RTC_DRV_EFI
        tristate "EFI RTC"
        depends on IA64
@@ -748,7 +755,7 @@ config HAVE_S3C_RTC
 
 config RTC_DRV_S3C
        tristate "Samsung S3C series SoC RTC"
-       depends on ARCH_S3C2410 || ARCH_S3C64XX || HAVE_S3C_RTC
+       depends on ARCH_S3C64XX || HAVE_S3C_RTC
        help
          RTC (Realtime Clock) driver for the clock inbuilt into the
          Samsung S3C24XX series of SoCs. This can provide periodic
@@ -773,8 +780,8 @@ config RTC_DRV_EP93XX
          will be called rtc-ep93xx.
 
 config RTC_DRV_SA1100
-       tristate "SA11x0/PXA2xx"
-       depends on ARCH_SA1100 || ARCH_PXA
+       tristate "SA11x0/PXA2xx/PXA910"
+       depends on ARCH_SA1100 || ARCH_PXA || ARCH_MMP
        help
          If you say Y here you will get access to the real time clock
          built into your SA11x0 or PXA2xx CPU.
@@ -1070,4 +1077,14 @@ config RTC_DRV_PUV3
          This drive can also be built as a module. If so, the module
          will be called rtc-puv3.
 
+config RTC_DRV_LOONGSON1
+       tristate "loongson1 RTC support"
+       depends on MACH_LOONGSON1
+       help
+         This is a driver for the loongson1 on-chip Counter0 (Time-Of-Year
+         counter) to be used as a RTC.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-ls1x.
+
 endif # RTC_CLASS
index 6e69823..727ae77 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_RTC_DRV_BQ32K)   += rtc-bq32k.o
 obj-$(CONFIG_RTC_DRV_BQ4802)   += rtc-bq4802.o
 obj-$(CONFIG_RTC_DRV_CMOS)     += rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_COH901331)        += rtc-coh901331.o
+obj-$(CONFIG_RTC_DRV_DA9052)   += rtc-da9052.o
 obj-$(CONFIG_RTC_DRV_DAVINCI)  += rtc-davinci.o
 obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o
 obj-$(CONFIG_RTC_DRV_VRTC)     += rtc-mrst.o
@@ -53,6 +54,7 @@ obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
 obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
 obj-$(CONFIG_RTC_DRV_JZ4740)   += rtc-jz4740.o
 obj-$(CONFIG_RTC_DRV_LPC32XX)  += rtc-lpc32xx.o
+obj-$(CONFIG_RTC_DRV_LOONGSON1)        += rtc-ls1x.o
 obj-$(CONFIG_RTC_DRV_M41T80)   += rtc-m41t80.o
 obj-$(CONFIG_RTC_DRV_M41T93)   += rtc-m41t93.o
 obj-$(CONFIG_RTC_DRV_M41T94)   += rtc-m41t94.o
index f04761e..afee0e8 100644 (file)
@@ -376,6 +376,9 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
        INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
        schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
 #endif /* VRTC_CALIBRATION */
+
+       device_init_wakeup(&pdev->dev, 1);
+
        return 0;
 out_rtc:
        free_irq(info->irq, info);
@@ -401,10 +404,34 @@ static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_rtc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag |= 1 << PM8607_IRQ_RTC;
+       return 0;
+}
+static int pm860x_rtc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag &= ~(1 << PM8607_IRQ_RTC);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_rtc_pm_ops, pm860x_rtc_suspend, pm860x_rtc_resume);
+
 static struct platform_driver pm860x_rtc_driver = {
        .driver         = {
                .name   = "88pm860x-rtc",
                .owner  = THIS_MODULE,
+               .pm     = &pm860x_rtc_pm_ops,
        },
        .probe          = pm860x_rtc_probe,
        .remove         = __devexit_p(pm860x_rtc_remove),
index ee3c122..8318689 100644 (file)
@@ -57,6 +57,7 @@ struct sam9_rtc {
        void __iomem            *rtt;
        struct rtc_device       *rtcdev;
        u32                     imr;
+       void __iomem            *gpbr;
 };
 
 #define rtt_readl(rtc, field) \
@@ -65,9 +66,9 @@ struct sam9_rtc {
        __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
 
 #define gpbr_readl(rtc) \
-       at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR)
+       __raw_readl((rtc)->gpbr)
 #define gpbr_writel(rtc, val) \
-       at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val))
+       __raw_writel((val), (rtc)->gpbr)
 
 /*
  * Read current time and date in RTC
@@ -287,16 +288,19 @@ static const struct rtc_class_ops at91_rtc_ops = {
 /*
  * Initialize and install RTC driver
  */
-static int __init at91_rtc_probe(struct platform_device *pdev)
+static int __devinit at91_rtc_probe(struct platform_device *pdev)
 {
-       struct resource *r;
+       struct resource *r, *r_gpbr;
        struct sam9_rtc *rtc;
        int             ret;
        u32             mr;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r)
+       r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!r || !r_gpbr) {
+               dev_err(&pdev->dev, "need 2 ressources\n");
                return -ENODEV;
+       }
 
        rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
        if (!rtc)
@@ -314,6 +318,13 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
                goto fail;
        }
 
+       rtc->gpbr = ioremap(r_gpbr->start, resource_size(r_gpbr));
+       if (!rtc->gpbr) {
+               dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n");
+               ret = -ENOMEM;
+               goto fail_gpbr;
+       }
+
        mr = rtt_readl(rtc, MR);
 
        /* unless RTT is counting at 1 Hz, re-initialize it */
@@ -335,12 +346,12 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
 
        /* register irq handler after we know what name we'll use */
        ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
-                               IRQF_DISABLED | IRQF_SHARED,
+                               IRQF_SHARED,
                                dev_name(&rtc->rtcdev->dev), rtc);
        if (ret) {
                dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
                rtc_device_unregister(rtc->rtcdev);
-               goto fail;
+               goto fail_register;
        }
 
        /* NOTE:  sam9260 rev A silicon has a ROM bug which resets the
@@ -356,6 +367,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
        return 0;
 
 fail_register:
+       iounmap(rtc->gpbr);
+fail_gpbr:
        iounmap(rtc->rtt);
 fail:
        platform_set_drvdata(pdev, NULL);
@@ -366,7 +379,7 @@ fail:
 /*
  * Disable and remove the RTC driver
  */
-static int __exit at91_rtc_remove(struct platform_device *pdev)
+static int __devexit at91_rtc_remove(struct platform_device *pdev)
 {
        struct sam9_rtc *rtc = platform_get_drvdata(pdev);
        u32             mr = rtt_readl(rtc, MR);
@@ -377,6 +390,7 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
 
        rtc_device_unregister(rtc->rtcdev);
 
+       iounmap(rtc->gpbr);
        iounmap(rtc->rtt);
        platform_set_drvdata(pdev, NULL);
        kfree(rtc);
@@ -440,63 +454,20 @@ static int at91_rtc_resume(struct platform_device *pdev)
 #endif
 
 static struct platform_driver at91_rtc_driver = {
-       .driver.name    = "rtc-at91sam9",
-       .driver.owner   = THIS_MODULE,
-       .remove         = __exit_p(at91_rtc_remove),
+       .probe          = at91_rtc_probe,
+       .remove         = __devexit_p(at91_rtc_remove),
        .shutdown       = at91_rtc_shutdown,
        .suspend        = at91_rtc_suspend,
        .resume         = at91_rtc_resume,
+       .driver         = {
+               .name   = "rtc-at91sam9",
+               .owner  = THIS_MODULE,
+       },
 };
 
-/* Chips can have more than one RTT module, and they can be used for more
- * than just RTCs.  So we can't just register as "the" RTT driver.
- *
- * A normal approach in such cases is to create a library to allocate and
- * free the modules.  Here we just use bus_find_device() as like such a
- * library, binding directly ... no runtime "library" footprint is needed.
- */
-static int __init at91_rtc_match(struct device *dev, void *v)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       int ret;
-
-       /* continue searching if this isn't the RTT we need */
-       if (strcmp("at91_rtt", pdev->name) != 0
-                       || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT)
-               goto fail;
-
-       /* else we found it ... but fail unless we can bind to the RTC driver */
-       if (dev->driver) {
-               dev_dbg(dev, "busy, can't use as RTC!\n");
-               goto fail;
-       }
-       dev->driver = &at91_rtc_driver.driver;
-       if (device_attach(dev) == 0) {
-               dev_dbg(dev, "can't attach RTC!\n");
-               goto fail;
-       }
-       ret = at91_rtc_probe(pdev);
-       if (ret == 0)
-               return true;
-
-       dev_dbg(dev, "RTC probe err %d!\n", ret);
-fail:
-       return false;
-}
-
 static int __init at91_rtc_init(void)
 {
-       int status;
-       struct device *rtc;
-
-       status = platform_driver_register(&at91_rtc_driver);
-       if (status)
-               return status;
-       rtc = bus_find_device(&platform_bus_type, NULL,
-                       NULL, at91_rtc_match);
-       if (!rtc)
-               platform_driver_unregister(&at91_rtc_driver);
-       return rtc ? 0 : -ENODEV;
+       return platform_driver_register(&at91_rtc_driver);
 }
 module_init(at91_rtc_init);
 
index 408cc8f..f090159 100644 (file)
@@ -187,17 +187,7 @@ static struct i2c_driver bq32k_driver = {
        .id_table       = bq32k_id,
 };
 
-static __init int bq32k_init(void)
-{
-       return i2c_add_driver(&bq32k_driver);
-}
-module_init(bq32k_init);
-
-static __exit void bq32k_exit(void)
-{
-       i2c_del_driver(&bq32k_driver);
-}
-module_exit(bq32k_exit);
+module_i2c_driver(bq32k_driver);
 
 MODULE_AUTHOR("Semihalf, Piotr Ziecik <kosmo@semihalf.com>");
 MODULE_DESCRIPTION("TI BQ32000 I2C RTC driver");
index d7782aa..7d5f56e 100644 (file)
@@ -714,7 +714,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
                        rtc_cmos_int_handler = cmos_interrupt;
 
                retval = request_irq(rtc_irq, rtc_cmos_int_handler,
-                               IRQF_DISABLED, dev_name(&cmos_rtc.rtc->dev),
+                               0, dev_name(&cmos_rtc.rtc->dev),
                                cmos_rtc.rtc);
                if (retval < 0) {
                        dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
index 80f9c88..a5b8a0c 100644 (file)
@@ -199,7 +199,7 @@ static int __init coh901331_probe(struct platform_device *pdev)
        }
 
        rtap->irq = platform_get_irq(pdev, 0);
-       if (request_irq(rtap->irq, coh901331_interrupt, IRQF_DISABLED,
+       if (request_irq(rtap->irq, coh901331_interrupt, 0,
                        "RTC COH 901 331 Alarm", rtap)) {
                ret = -EIO;
                goto out_no_irq;
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c
new file mode 100644 (file)
index 0000000..da6ab52
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Real time clock driver for DA9052
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: Dajun Dajun Chen <dajun.chen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+#define rtc_err(da9052, fmt, ...) \
+               dev_err(da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__)
+
+struct da9052_rtc {
+       struct rtc_device *rtc;
+       struct da9052 *da9052;
+       int irq;
+};
+
+static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable)
+{
+       int ret;
+       if (enable) {
+               ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
+                                       DA9052_ALARM_Y_ALARM_ON,
+                                       DA9052_ALARM_Y_ALARM_ON);
+               if (ret != 0)
+                       rtc_err(da9052, "Failed to enable ALM: %d\n", ret);
+       } else {
+               ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
+                                       DA9052_ALARM_Y_ALARM_ON, 0);
+               if (ret != 0)
+                       rtc_err(da9052, "Write error: %d\n", ret);
+       }
+       return ret;
+}
+
+static irqreturn_t da9052_rtc_irq(int irq, void *data)
+{
+       struct da9052_rtc *rtc = data;
+       int ret;
+
+       ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_MI_REG);
+       if (ret < 0) {
+               rtc_err(rtc->da9052, "Read error: %d\n", ret);
+               return IRQ_NONE;
+       }
+
+       if (ret & DA9052_ALARMMI_ALARMTYPE) {
+               da9052_rtc_enable_alarm(rtc->da9052, 0);
+               rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+       } else
+               rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_PF);
+
+       return IRQ_HANDLED;
+}
+
+static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+       int ret;
+       uint8_t v[5];
+
+       ret = da9052_group_read(da9052, DA9052_ALARM_MI_REG, 5, v);
+       if (ret != 0) {
+               rtc_err(da9052, "Failed to group read ALM: %d\n", ret);
+               return ret;
+       }
+
+       rtc_tm->tm_year = (v[4] & DA9052_RTC_YEAR) + 100;
+       rtc_tm->tm_mon  = (v[3] & DA9052_RTC_MONTH) - 1;
+       rtc_tm->tm_mday = v[2] & DA9052_RTC_DAY;
+       rtc_tm->tm_hour = v[1] & DA9052_RTC_HOUR;
+       rtc_tm->tm_min  = v[0] & DA9052_RTC_MIN;
+
+       ret = rtc_valid_tm(rtc_tm);
+       if (ret != 0)
+               return ret;
+       return ret;
+}
+
+static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)
+{
+       int ret;
+       uint8_t v[3];
+
+       rtc_tm->tm_year -= 100;
+       rtc_tm->tm_mon += 1;
+
+       ret = da9052_reg_update(da9052, DA9052_ALARM_MI_REG,
+                               DA9052_RTC_MIN, rtc_tm->tm_min);
+       if (ret != 0) {
+               rtc_err(da9052, "Failed to write ALRM MIN: %d\n", ret);
+               return ret;
+       }
+
+       v[0] = rtc_tm->tm_hour;
+       v[1] = rtc_tm->tm_mday;
+       v[2] = rtc_tm->tm_mon;
+
+       ret = da9052_group_write(da9052, DA9052_ALARM_H_REG, 3, v);
+       if (ret < 0)
+               return ret;
+
+       ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
+                               DA9052_RTC_YEAR, rtc_tm->tm_year);
+       if (ret != 0)
+               rtc_err(da9052, "Failed to write ALRM YEAR: %d\n", ret);
+
+       return ret;
+}
+
+static int da9052_rtc_get_alarm_status(struct da9052 *da9052)
+{
+       int ret;
+
+       ret = da9052_reg_read(da9052, DA9052_ALARM_Y_REG);
+       if (ret < 0) {
+               rtc_err(da9052, "Failed to read ALM: %d\n", ret);
+               return ret;
+       }
+       ret &= DA9052_ALARM_Y_ALARM_ON;
+       return (ret > 0) ? 1 : 0;
+}
+
+static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+       struct da9052_rtc *rtc = dev_get_drvdata(dev);
+       uint8_t v[6];
+       int ret;
+
+       ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
+       if (ret < 0) {
+               rtc_err(rtc->da9052, "Failed to read RTC time : %d\n", ret);
+               return ret;
+       }
+
+       rtc_tm->tm_year = (v[5] & DA9052_RTC_YEAR) + 100;
+       rtc_tm->tm_mon  = (v[4] & DA9052_RTC_MONTH) - 1;
+       rtc_tm->tm_mday = v[3] & DA9052_RTC_DAY;
+       rtc_tm->tm_hour = v[2] & DA9052_RTC_HOUR;
+       rtc_tm->tm_min  = v[1] & DA9052_RTC_MIN;
+       rtc_tm->tm_sec  = v[0] & DA9052_RTC_SEC;
+
+       ret = rtc_valid_tm(rtc_tm);
+       if (ret != 0) {
+               rtc_err(rtc->da9052, "rtc_valid_tm failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct da9052_rtc *rtc;
+       uint8_t v[6];
+
+       rtc = dev_get_drvdata(dev);
+
+       v[0] = tm->tm_sec;
+       v[1] = tm->tm_min;
+       v[2] = tm->tm_hour;
+       v[3] = tm->tm_mday;
+       v[4] = tm->tm_mon + 1;
+       v[5] = tm->tm_year - 100;
+
+       return da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
+}
+
+static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       int ret;
+       struct rtc_time *tm = &alrm->time;
+       struct da9052_rtc *rtc = dev_get_drvdata(dev);
+
+       ret = da9052_read_alarm(rtc->da9052, tm);
+
+       if (ret)
+               return ret;
+
+       alrm->enabled = da9052_rtc_get_alarm_status(rtc->da9052);
+
+       return 0;
+}
+
+static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       int ret;
+       struct rtc_time *tm = &alrm->time;
+       struct da9052_rtc *rtc = dev_get_drvdata(dev);
+
+       ret = da9052_rtc_enable_alarm(rtc->da9052, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = da9052_set_alarm(rtc->da9052, tm);
+       if (ret)
+               return ret;
+
+       ret = da9052_rtc_enable_alarm(rtc->da9052, 1);
+
+       return ret;
+}
+
+static int da9052_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct da9052_rtc *rtc = dev_get_drvdata(dev);
+
+       return da9052_rtc_enable_alarm(rtc->da9052, enabled);
+}
+
+static const struct rtc_class_ops da9052_rtc_ops = {
+       .read_time      = da9052_rtc_read_time,
+       .set_time       = da9052_rtc_set_time,
+       .read_alarm     = da9052_rtc_read_alarm,
+       .set_alarm      = da9052_rtc_set_alarm,
+       .alarm_irq_enable = da9052_rtc_alarm_irq_enable,
+};
+
+static int __devinit da9052_rtc_probe(struct platform_device *pdev)
+{
+       struct da9052_rtc *rtc;
+       int ret;
+
+       rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9052_rtc), GFP_KERNEL);
+       if (!rtc)
+               return -ENOMEM;
+
+       rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
+       platform_set_drvdata(pdev, rtc);
+       rtc->irq = platform_get_irq_byname(pdev, "ALM");
+       ret = request_threaded_irq(rtc->irq, NULL, da9052_rtc_irq,
+                                  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                  "ALM", rtc);
+       if (ret != 0) {
+               rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
+               goto err_mem;
+       }
+
+       rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+                                      &da9052_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rtc)) {
+               ret = PTR_ERR(rtc->rtc);
+               goto err_free_irq;
+       }
+
+       return 0;
+
+err_free_irq:
+       free_irq(rtc->irq, rtc);
+err_mem:
+       devm_kfree(&pdev->dev, rtc);
+       return ret;
+}
+
+static int __devexit da9052_rtc_remove(struct platform_device *pdev)
+{
+       struct da9052_rtc *rtc = pdev->dev.platform_data;
+
+       rtc_device_unregister(rtc->rtc);
+       free_irq(rtc->irq, rtc);
+       platform_set_drvdata(pdev, NULL);
+       devm_kfree(&pdev->dev, rtc);
+
+       return 0;
+}
+
+static struct platform_driver da9052_rtc_driver = {
+       .probe  = da9052_rtc_probe,
+       .remove = __devexit_p(da9052_rtc_remove),
+       .driver = {
+               .name   = "da9052-rtc",
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(da9052_rtc_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-rtc");
index 755e1fe..14c2109 100644 (file)
@@ -542,7 +542,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
        rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL);
 
        ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt,
-                         IRQF_DISABLED, "davinci_rtc", davinci_rtc);
+                         0, "davinci_rtc", davinci_rtc);
        if (ret < 0) {
                dev_err(dev, "unable to register davinci RTC interrupt\n");
                goto fail4;
index 3a33b1f..686a865 100644 (file)
@@ -814,17 +814,7 @@ static struct spi_driver ds1305_driver = {
        /* REVISIT add suspend/resume */
 };
 
-static int __init ds1305_init(void)
-{
-       return spi_register_driver(&ds1305_driver);
-}
-module_init(ds1305_init);
-
-static void __exit ds1305_exit(void)
-{
-       spi_unregister_driver(&ds1305_driver);
-}
-module_exit(ds1305_exit);
+module_spi_driver(ds1305_driver);
 
 MODULE_DESCRIPTION("RTC driver for DS1305 and DS1306 chips");
 MODULE_LICENSE("GPL");
index 62b0763..cd188ab 100644 (file)
@@ -20,7 +20,8 @@
 
 
 
-/* We can't determine type by probing, but if we expect pre-Linux code
+/*
+ * We can't determine type by probing, but if we expect pre-Linux code
  * to have set the chip up as a clock (turning on the oscillator and
  * setting the date and time), Linux can ignore the non-clock features.
  * That's a natural job for a factory or repair bench.
@@ -36,7 +37,8 @@ enum ds_type {
        m41t00,
        mcp7941x,
        rx_8025,
-       // rs5c372 too?  different address...
+       last_ds_type /* always last */
+       /* rs5c372 too?  different address... */
 };
 
 
@@ -58,7 +60,8 @@ enum ds_type {
 #      define DS1337_BIT_CENTURY       0x80    /* in REG_MONTH */
 #define DS1307_REG_YEAR                0x06    /* 00-99 */
 
-/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
+/*
+ * Other registers (control, status, alarms, trickle charge, NVRAM, etc)
  * start at 7, and they differ a LOT. Only control and status matter for
  * basic RTC date and time functionality; be careful using them.
  */
@@ -102,6 +105,8 @@ enum ds_type {
 struct ds1307 {
        u8                      offset; /* register's offset */
        u8                      regs[11];
+       u16                     nvram_offset;
+       struct bin_attribute    *nvram;
        enum ds_type            type;
        unsigned long           flags;
 #define HAS_NVRAM      0               /* bit 0 == sysfs file active */
@@ -116,34 +121,35 @@ struct ds1307 {
 };
 
 struct chip_desc {
-       unsigned                nvram56:1;
        unsigned                alarm:1;
+       u16                     nvram_offset;
+       u16                     nvram_size;
 };
 
-static const struct chip_desc chips[] = {
-[ds_1307] = {
-       .nvram56        = 1,
-},
-[ds_1337] = {
-       .alarm          = 1,
-},
-[ds_1338] = {
-       .nvram56        = 1,
-},
-[ds_1339] = {
-       .alarm          = 1,
-},
-[ds_1340] = {
-},
-[ds_3231] = {
-       .alarm          = 1,
-},
-[m41t00] = {
-},
-[mcp7941x] = {
-},
-[rx_8025] = {
-}, };
+static const struct chip_desc chips[last_ds_type] = {
+       [ds_1307] = {
+               .nvram_offset   = 8,
+               .nvram_size     = 56,
+       },
+       [ds_1337] = {
+               .alarm          = 1,
+       },
+       [ds_1338] = {
+               .nvram_offset   = 8,
+               .nvram_size     = 56,
+       },
+       [ds_1339] = {
+               .alarm          = 1,
+       },
+       [ds_3231] = {
+               .alarm          = 1,
+       },
+       [mcp7941x] = {
+               /* this is battery backed SRAM */
+               .nvram_offset   = 0x20,
+               .nvram_size     = 0x40,
+       },
+};
 
 static const struct i2c_device_id ds1307_id[] = {
        { "ds1307", ds_1307 },
@@ -372,6 +378,11 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
                                | DS1340_BIT_CENTURY;
                break;
        case mcp7941x:
+               /*
+                * these bits were cleared when preparing the date/time
+                * values and need to be set again before writing the
+                * buffer out to the device.
+                */
                buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST;
                buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN;
                break;
@@ -417,7 +428,8 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
                        ds1307->regs[6], ds1307->regs[7],
                        ds1307->regs[8]);
 
-       /* report alarm time (ALARM1); assume 24 hour and day-of-month modes,
+       /*
+        * report alarm time (ALARM1); assume 24 hour and day-of-month modes,
         * and that all four fields are checked matches
         */
        t->time.tm_sec = bcd2bin(ds1307->regs[0] & 0x7f);
@@ -445,7 +457,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 
 static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
-       struct i2c_client       *client = to_i2c_client(dev);
+       struct i2c_client       *client = to_i2c_client(dev);
        struct ds1307           *ds1307 = i2c_get_clientdata(client);
        unsigned char           *buf = ds1307->regs;
        u8                      control, status;
@@ -541,8 +553,6 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
 
 /*----------------------------------------------------------------------*/
 
-#define NVRAM_SIZE     56
-
 static ssize_t
 ds1307_nvram_read(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr,
@@ -555,14 +565,15 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj,
        client = kobj_to_i2c_client(kobj);
        ds1307 = i2c_get_clientdata(client);
 
-       if (unlikely(off >= NVRAM_SIZE))
+       if (unlikely(off >= ds1307->nvram->size))
                return 0;
-       if ((off + count) > NVRAM_SIZE)
-               count = NVRAM_SIZE - off;
+       if ((off + count) > ds1307->nvram->size)
+               count = ds1307->nvram->size - off;
        if (unlikely(!count))
                return count;
 
-       result = ds1307->read_block_data(client, 8 + off, count, buf);
+       result = ds1307->read_block_data(client, ds1307->nvram_offset + off,
+                                                               count, buf);
        if (result < 0)
                dev_err(&client->dev, "%s error %d\n", "nvram read", result);
        return result;
@@ -580,14 +591,15 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
        client = kobj_to_i2c_client(kobj);
        ds1307 = i2c_get_clientdata(client);
 
-       if (unlikely(off >= NVRAM_SIZE))
+       if (unlikely(off >= ds1307->nvram->size))
                return -EFBIG;
-       if ((off + count) > NVRAM_SIZE)
-               count = NVRAM_SIZE - off;
+       if ((off + count) > ds1307->nvram->size)
+               count = ds1307->nvram->size - off;
        if (unlikely(!count))
                return count;
 
-       result = ds1307->write_block_data(client, 8 + off, count, buf);
+       result = ds1307->write_block_data(client, ds1307->nvram_offset + off,
+                                                               count, buf);
        if (result < 0) {
                dev_err(&client->dev, "%s error %d\n", "nvram write", result);
                return result;
@@ -595,21 +607,8 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
        return count;
 }
 
-static struct bin_attribute nvram = {
-       .attr = {
-               .name   = "nvram",
-               .mode   = S_IRUGO | S_IWUSR,
-       },
-
-       .read   = ds1307_nvram_read,
-       .write  = ds1307_nvram_write,
-       .size   = NVRAM_SIZE,
-};
-
 /*----------------------------------------------------------------------*/
 
-static struct i2c_driver ds1307_driver;
-
 static int __devinit ds1307_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
@@ -630,7 +629,8 @@ static int __devinit ds1307_probe(struct i2c_client *client,
            && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
                return -EIO;
 
-       if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
+       ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL);
+       if (!ds1307)
                return -ENOMEM;
 
        i2c_set_clientdata(client, ds1307);
@@ -652,11 +652,6 @@ static int __devinit ds1307_probe(struct i2c_client *client,
        case ds_1337:
        case ds_1339:
        case ds_3231:
-               /* has IRQ? */
-               if (ds1307->client->irq > 0 && chip->alarm) {
-                       INIT_WORK(&ds1307->work, ds1307_work);
-                       want_irq = true;
-               }
                /* get registers that the "rtc" read below won't read... */
                tmp = ds1307->read_block_data(ds1307->client,
                                DS1337_REG_CONTROL, 2, buf);
@@ -670,14 +665,19 @@ static int __devinit ds1307_probe(struct i2c_client *client,
                if (ds1307->regs[0] & DS1337_BIT_nEOSC)
                        ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
 
-               /* Using IRQ?  Disable the square wave and both alarms.
+               /*
+                * Using IRQ?  Disable the square wave and both alarms.
                 * For some variants, be sure alarms can trigger when we're
                 * running on Vbackup (BBSQI/BBSQW)
                 */
-               if (want_irq) {
+               if (ds1307->client->irq > 0 && chip->alarm) {
+                       INIT_WORK(&ds1307->work, ds1307_work);
+
                        ds1307->regs[0] |= DS1337_BIT_INTCN
                                        | bbsqi_bitpos[ds1307->type];
                        ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
+
+                       want_irq = true;
                }
 
                i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
@@ -772,7 +772,8 @@ read_rtc:
                goto exit_free;
        }
 
-       /* minimal sanity checking; some chips (like DS1340) don't
+       /*
+        * minimal sanity checking; some chips (like DS1340) don't
         * specify the extra bits as must-be-zero, but there are
         * still a few values that are clearly out-of-range.
         */
@@ -836,11 +837,7 @@ read_rtc:
                }
 
                break;
-       case rx_8025:
-       case ds_1337:
-       case ds_1339:
-       case ds_1388:
-       case ds_3231:
+       default:
                break;
        }
 
@@ -848,7 +845,8 @@ read_rtc:
        switch (ds1307->type) {
        case ds_1340:
        case m41t00:
-               /* NOTE: ignores century bits; fix before deploying
+               /*
+                * NOTE: ignores century bits; fix before deploying
                 * systems that will run through year 2100.
                 */
                break;
@@ -858,7 +856,8 @@ read_rtc:
                if (!(tmp & DS1307_BIT_12HR))
                        break;
 
-               /* Be sure we're in 24 hour mode.  Multi-master systems
+               /*
+                * Be sure we're in 24 hour mode.  Multi-master systems
                 * take note...
                 */
                tmp = bcd2bin(tmp & 0x1f);
@@ -894,16 +893,31 @@ read_rtc:
                dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
        }
 
-       if (chip->nvram56) {
-               err = sysfs_create_bin_file(&client->dev.kobj, &nvram);
-               if (err == 0) {
-                       set_bit(HAS_NVRAM, &ds1307->flags);
-                       dev_info(&client->dev, "56 bytes nvram\n");
+       if (chip->nvram_size) {
+               ds1307->nvram = kzalloc(sizeof(struct bin_attribute),
+                                                       GFP_KERNEL);
+               if (!ds1307->nvram) {
+                       err = -ENOMEM;
+                       goto exit_nvram;
+               }
+               ds1307->nvram->attr.name = "nvram";
+               ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
+               ds1307->nvram->read = ds1307_nvram_read,
+               ds1307->nvram->write = ds1307_nvram_write,
+               ds1307->nvram->size = chip->nvram_size;
+               ds1307->nvram_offset = chip->nvram_offset;
+               err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
+               if (err) {
+                       kfree(ds1307->nvram);
+                       goto exit_nvram;
                }
+               set_bit(HAS_NVRAM, &ds1307->flags);
+               dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size);
        }
 
        return 0;
 
+exit_nvram:
 exit_irq:
        rtc_device_unregister(ds1307->rtc);
 exit_free:
@@ -913,15 +927,17 @@ exit_free:
 
 static int __devexit ds1307_remove(struct i2c_client *client)
 {
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       struct ds1307 *ds1307 = i2c_get_clientdata(client);
 
        if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) {
                free_irq(client->irq, client);
                cancel_work_sync(&ds1307->work);
        }
 
-       if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
-               sysfs_remove_bin_file(&client->dev.kobj, &nvram);
+       if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) {
+               sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
+               kfree(ds1307->nvram);
+       }
 
        rtc_device_unregister(ds1307->rtc);
        kfree(ds1307);
@@ -938,17 +954,7 @@ static struct i2c_driver ds1307_driver = {
        .id_table       = ds1307_id,
 };
 
-static int __init ds1307_init(void)
-{
-       return i2c_add_driver(&ds1307_driver);
-}
-module_init(ds1307_init);
-
-static void __exit ds1307_exit(void)
-{
-       i2c_del_driver(&ds1307_driver);
-}
-module_exit(ds1307_exit);
+module_i2c_driver(ds1307_driver);
 
 MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips");
 MODULE_LICENSE("GPL");
index e6e71de..9663160 100644 (file)
@@ -446,18 +446,7 @@ static struct i2c_driver ds1374_driver = {
        .id_table = ds1374_id,
 };
 
-static int __init ds1374_init(void)
-{
-       return i2c_add_driver(&ds1374_driver);
-}
-
-static void __exit ds1374_exit(void)
-{
-       i2c_del_driver(&ds1374_driver);
-}
-
-module_init(ds1374_init);
-module_exit(ds1374_exit);
+module_i2c_driver(ds1374_driver);
 
 MODULE_AUTHOR("Scott Wood <scottwood@freescale.com>");
 MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC Driver");
index b038d2c..b0a99e1 100644 (file)
@@ -175,17 +175,7 @@ static struct spi_driver ds1390_driver = {
        .remove = __devexit_p(ds1390_remove),
 };
 
-static __init int ds1390_init(void)
-{
-       return spi_register_driver(&ds1390_driver);
-}
-module_init(ds1390_init);
-
-static __exit void ds1390_exit(void)
-{
-       spi_unregister_driver(&ds1390_driver);
-}
-module_exit(ds1390_exit);
+module_spi_driver(ds1390_driver);
 
 MODULE_DESCRIPTION("Dallas/Maxim DS1390/93/94 SPI RTC driver");
 MODULE_AUTHOR("Mark Jackson <mpfj@mimc.co.uk>");
index 761f36b..1f675f5 100644 (file)
@@ -532,7 +532,7 @@ ds1511_rtc_probe(struct platform_device *pdev)
        if (pdata->irq > 0) {
                rtc_read(RTC_CMD1);
                if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt,
-                       IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) {
+                       IRQF_SHARED, pdev->name, pdev) < 0) {
 
                        dev_warn(&pdev->dev, "interrupt not available.\n");
                        pdata->irq = 0;
index 6f0a1b5..6ccedbb 100644 (file)
@@ -320,7 +320,7 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev)
                writeb(0, ioaddr + RTC_INTERRUPTS);
                if (devm_request_irq(&pdev->dev, pdata->irq,
                                ds1553_rtc_interrupt,
-                               IRQF_DISABLED, pdev->name, pdev) < 0) {
+                               0, pdev->name, pdev) < 0) {
                        dev_warn(&pdev->dev, "interrupt not available.\n");
                        pdata->irq = 0;
                }
index a319402..7fa67d0 100644 (file)
@@ -202,20 +202,9 @@ static struct i2c_driver ds1672_driver = {
        .id_table = ds1672_id,
 };
 
-static int __init ds1672_init(void)
-{
-       return i2c_add_driver(&ds1672_driver);
-}
-
-static void __exit ds1672_exit(void)
-{
-       i2c_del_driver(&ds1672_driver);
-}
+module_i2c_driver(ds1672_driver);
 
 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(ds1672_init);
-module_exit(ds1672_exit);
index 27b7bf6..e194509 100644 (file)
@@ -473,18 +473,7 @@ static struct i2c_driver ds3232_driver = {
        .id_table = ds3232_id,
 };
 
-static int __init ds3232_init(void)
-{
-       return i2c_add_driver(&ds3232_driver);
-}
-
-static void __exit ds3232_exit(void)
-{
-       i2c_del_driver(&ds3232_driver);
-}
-
-module_init(ds3232_init);
-module_exit(ds3232_exit);
+module_i2c_driver(ds3232_driver);
 
 MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>");
 MODULE_DESCRIPTION("Maxim/Dallas DS3232 RTC Driver");
index bbd2622..fda7079 100644 (file)
@@ -173,17 +173,7 @@ static struct spi_driver ds3234_driver = {
        .remove = __devexit_p(ds3234_remove),
 };
 
-static __init int ds3234_init(void)
-{
-       return spi_register_driver(&ds3234_driver);
-}
-module_init(ds3234_init);
-
-static __exit void ds3234_exit(void)
-{
-       spi_unregister_driver(&ds3234_driver);
-}
-module_exit(ds3234_exit);
+module_spi_driver(ds3234_driver);
 
 MODULE_DESCRIPTION("DS3234 SPI RTC driver");
 MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
index 8414dea..0104ea7 100644 (file)
@@ -144,19 +144,8 @@ static struct i2c_driver em3027_driver = {
        .id_table = em3027_id,
 };
 
-static int __init em3027_init(void)
-{
-       return i2c_add_driver(&em3027_driver);
-}
-
-static void __exit em3027_exit(void)
-{
-       i2c_del_driver(&em3027_driver);
-}
+module_i2c_driver(em3027_driver);
 
 MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
 MODULE_DESCRIPTION("EM Microelectronic EM3027 RTC driver");
 MODULE_LICENSE("GPL");
-
-module_init(em3027_init);
-module_exit(em3027_exit);
index 4cf2e70..86b6ecc 100644 (file)
@@ -565,17 +565,7 @@ static struct i2c_driver fm3130_driver = {
        .id_table       = fm3130_id,
 };
 
-static int __init fm3130_init(void)
-{
-       return i2c_add_driver(&fm3130_driver);
-}
-module_init(fm3130_init);
-
-static void __exit fm3130_exit(void)
-{
-       i2c_del_driver(&fm3130_driver);
-}
-module_exit(fm3130_exit);
+module_i2c_driver(fm3130_driver);
 
 MODULE_DESCRIPTION("RTC driver for FM3130");
 MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
index 6186833..1850104 100644 (file)
@@ -309,18 +309,7 @@ static struct i2c_driver isl12022_driver = {
        .id_table       = isl12022_id,
 };
 
-static int __init isl12022_init(void)
-{
-       return i2c_add_driver(&isl12022_driver);
-}
-
-static void __exit isl12022_exit(void)
-{
-       i2c_del_driver(&isl12022_driver);
-}
-
-module_init(isl12022_init);
-module_exit(isl12022_exit);
+module_i2c_driver(isl12022_driver);
 
 MODULE_AUTHOR("roman.fietze@telemotive.de");
 MODULE_DESCRIPTION("ISL 12022 RTC driver");
index da8beb8..dd2aeee 100644 (file)
@@ -710,22 +710,9 @@ static struct i2c_driver isl1208_driver = {
        .id_table = isl1208_id,
 };
 
-static int __init
-isl1208_init(void)
-{
-       return i2c_add_driver(&isl1208_driver);
-}
-
-static void __exit
-isl1208_exit(void)
-{
-       i2c_del_driver(&isl1208_driver);
-}
+module_i2c_driver(isl1208_driver);
 
 MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
 MODULE_DESCRIPTION("Intersil ISL1208 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(isl1208_init);
-module_exit(isl1208_exit);
index ecc1713..63c7218 100644 (file)
@@ -287,7 +287,7 @@ static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev)
        if (rtc->irq >= 0) {
                if (devm_request_irq(&pdev->dev, rtc->irq,
                                     lpc32xx_rtc_alarm_interrupt,
-                                    IRQF_DISABLED, pdev->name, rtc) < 0) {
+                                    0, pdev->name, rtc) < 0) {
                        dev_warn(&pdev->dev, "Can't request interrupt.\n");
                        rtc->irq = -1;
                } else {
diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c
new file mode 100644 (file)
index 0000000..07e81c5
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2011 Zhao Zhang <zhzhl555@gmail.com>
+ *
+ * Derived from driver/rtc/rtc-au1xxx.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/module.h>
+#include <linux/kernel.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <asm/mach-loongson1/loongson1.h>
+
+#define LS1X_RTC_REG_OFFSET    (LS1X_RTC_BASE + 0x20)
+#define LS1X_RTC_REGS(x) \
+               ((void __iomem *)KSEG1ADDR(LS1X_RTC_REG_OFFSET + (x)))
+
+/*RTC programmable counters 0 and 1*/
+#define SYS_COUNTER_CNTRL              (LS1X_RTC_REGS(0x20))
+#define SYS_CNTRL_ERS                  (1 << 23)
+#define SYS_CNTRL_RTS                  (1 << 20)
+#define SYS_CNTRL_RM2                  (1 << 19)
+#define SYS_CNTRL_RM1                  (1 << 18)
+#define SYS_CNTRL_RM0                  (1 << 17)
+#define SYS_CNTRL_RS                   (1 << 16)
+#define SYS_CNTRL_BP                   (1 << 14)
+#define SYS_CNTRL_REN                  (1 << 13)
+#define SYS_CNTRL_BRT                  (1 << 12)
+#define SYS_CNTRL_TEN                  (1 << 11)
+#define SYS_CNTRL_BTT                  (1 << 10)
+#define SYS_CNTRL_E0                   (1 << 8)
+#define SYS_CNTRL_ETS                  (1 << 7)
+#define SYS_CNTRL_32S                  (1 << 5)
+#define SYS_CNTRL_TTS                  (1 << 4)
+#define SYS_CNTRL_TM2                  (1 << 3)
+#define SYS_CNTRL_TM1                  (1 << 2)
+#define SYS_CNTRL_TM0                  (1 << 1)
+#define SYS_CNTRL_TS                   (1 << 0)
+
+/* Programmable Counter 0 Registers */
+#define SYS_TOYTRIM            (LS1X_RTC_REGS(0))
+#define SYS_TOYWRITE0          (LS1X_RTC_REGS(4))
+#define SYS_TOYWRITE1          (LS1X_RTC_REGS(8))
+#define SYS_TOYREAD0           (LS1X_RTC_REGS(0xC))
+#define SYS_TOYREAD1           (LS1X_RTC_REGS(0x10))
+#define SYS_TOYMATCH0          (LS1X_RTC_REGS(0x14))
+#define SYS_TOYMATCH1          (LS1X_RTC_REGS(0x18))
+#define SYS_TOYMATCH2          (LS1X_RTC_REGS(0x1C))
+
+/* Programmable Counter 1 Registers */
+#define SYS_RTCTRIM            (LS1X_RTC_REGS(0x40))
+#define SYS_RTCWRITE0          (LS1X_RTC_REGS(0x44))
+#define SYS_RTCREAD0           (LS1X_RTC_REGS(0x48))
+#define SYS_RTCMATCH0          (LS1X_RTC_REGS(0x4C))
+#define SYS_RTCMATCH1          (LS1X_RTC_REGS(0x50))
+#define SYS_RTCMATCH2          (LS1X_RTC_REGS(0x54))
+
+#define LS1X_SEC_OFFSET                (4)
+#define LS1X_MIN_OFFSET                (10)
+#define LS1X_HOUR_OFFSET       (16)
+#define LS1X_DAY_OFFSET                (21)
+#define LS1X_MONTH_OFFSET      (26)
+
+
+#define LS1X_SEC_MASK          (0x3f)
+#define LS1X_MIN_MASK          (0x3f)
+#define LS1X_HOUR_MASK         (0x1f)
+#define LS1X_DAY_MASK          (0x1f)
+#define LS1X_MONTH_MASK                (0x3f)
+#define LS1X_YEAR_MASK         (0xffffffff)
+
+#define ls1x_get_sec(t)                (((t) >> LS1X_SEC_OFFSET) & LS1X_SEC_MASK)
+#define ls1x_get_min(t)                (((t) >> LS1X_MIN_OFFSET) & LS1X_MIN_MASK)
+#define ls1x_get_hour(t)       (((t) >> LS1X_HOUR_OFFSET) & LS1X_HOUR_MASK)
+#define ls1x_get_day(t)                (((t) >> LS1X_DAY_OFFSET) & LS1X_DAY_MASK)
+#define ls1x_get_month(t)      (((t) >> LS1X_MONTH_OFFSET) & LS1X_MONTH_MASK)
+
+#define RTC_CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S)
+
+static int ls1x_rtc_read_time(struct device *dev, struct rtc_time *rtm)
+{
+       unsigned long v, t;
+
+       v = readl(SYS_TOYREAD0);
+       t = readl(SYS_TOYREAD1);
+
+       memset(rtm, 0, sizeof(struct rtc_time));
+       t  = mktime((t & LS1X_YEAR_MASK), ls1x_get_month(v),
+                       ls1x_get_day(v), ls1x_get_hour(v),
+                       ls1x_get_min(v), ls1x_get_sec(v));
+       rtc_time_to_tm(t, rtm);
+
+       return rtc_valid_tm(rtm);
+}
+
+static int ls1x_rtc_set_time(struct device *dev, struct  rtc_time *rtm)
+{
+       unsigned long v, t, c;
+       int ret = -ETIMEDOUT;
+
+       v = ((rtm->tm_mon + 1)  << LS1X_MONTH_OFFSET)
+               | (rtm->tm_mday << LS1X_DAY_OFFSET)
+               | (rtm->tm_hour << LS1X_HOUR_OFFSET)
+               | (rtm->tm_min  << LS1X_MIN_OFFSET)
+               | (rtm->tm_sec  << LS1X_SEC_OFFSET);
+
+       writel(v, SYS_TOYWRITE0);
+       c = 0x10000;
+       /* add timeout check counter, for more safe */
+       while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c)
+               usleep_range(1000, 3000);
+
+       if (!c) {
+               dev_err(dev, "set time timeout!\n");
+               goto err;
+       }
+
+       t = rtm->tm_year + 1900;
+       writel(t, SYS_TOYWRITE1);
+       c = 0x10000;
+       while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c)
+               usleep_range(1000, 3000);
+
+       if (!c) {
+               dev_err(dev, "set time timeout!\n");
+               goto err;
+       }
+       return 0;
+err:
+       return ret;
+}
+
+static struct rtc_class_ops  ls1x_rtc_ops = {
+       .read_time      = ls1x_rtc_read_time,
+       .set_time       = ls1x_rtc_set_time,
+};
+
+static int __devinit ls1x_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtcdev;
+       unsigned long v;
+       int ret;
+
+       v = readl(SYS_COUNTER_CNTRL);
+       if (!(v & RTC_CNTR_OK)) {
+               dev_err(&pdev->dev, "rtc counters not working\n");
+               ret = -ENODEV;
+               goto err;
+       }
+       ret = -ETIMEDOUT;
+       /* set to 1 HZ if needed */
+       if (readl(SYS_TOYTRIM) != 32767) {
+               v = 0x100000;
+               while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) && --v)
+                       usleep_range(1000, 3000);
+
+               if (!v) {
+                       dev_err(&pdev->dev, "time out\n");
+                       goto err;
+               }
+               writel(32767, SYS_TOYTRIM);
+       }
+       /* this loop coundn't be endless */
+       while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS)
+               usleep_range(1000, 3000);
+
+       rtcdev = rtc_device_register("ls1x-rtc", &pdev->dev,
+                                       &ls1x_rtc_ops , THIS_MODULE);
+       if (IS_ERR(rtcdev)) {
+               ret = PTR_ERR(rtcdev);
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, rtcdev);
+       return 0;
+err:
+       return ret;
+}
+
+static int __devexit ls1x_rtc_remove(struct platform_device *pdev)
+{
+       struct rtc_device *rtcdev = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(rtcdev);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver  ls1x_rtc_driver = {
+       .driver         = {
+               .name   = "ls1x-rtc",
+               .owner  = THIS_MODULE,
+       },
+       .remove         = __devexit_p(ls1x_rtc_remove),
+       .probe          = ls1x_rtc_probe,
+};
+
+module_platform_driver(ls1x_rtc_driver);
+
+MODULE_AUTHOR("zhao zhang <zhzhl555@gmail.com>");
+MODULE_LICENSE("GPL");
index 64aedd8..4e0f84a 100644 (file)
@@ -900,20 +900,9 @@ static struct i2c_driver m41t80_driver = {
        .id_table = m41t80_id,
 };
 
-static int __init m41t80_rtc_init(void)
-{
-       return i2c_add_driver(&m41t80_driver);
-}
-
-static void __exit m41t80_rtc_exit(void)
-{
-       i2c_del_driver(&m41t80_driver);
-}
+module_i2c_driver(m41t80_driver);
 
 MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>");
 MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(m41t80_rtc_init);
-module_exit(m41t80_rtc_exit);
index ef71132..10f1c29 100644 (file)
@@ -206,17 +206,7 @@ static struct spi_driver m41t93_driver = {
        .remove = __devexit_p(m41t93_remove),
 };
 
-static __init int m41t93_init(void)
-{
-       return spi_register_driver(&m41t93_driver);
-}
-module_init(m41t93_init);
-
-static __exit void m41t93_exit(void)
-{
-       spi_unregister_driver(&m41t93_driver);
-}
-module_exit(m41t93_exit);
+module_spi_driver(m41t93_driver);
 
 MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
 MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC");
index 2a4721f..6e78193 100644 (file)
@@ -153,19 +153,7 @@ static struct spi_driver m41t94_driver = {
        .remove = __devexit_p(m41t94_remove),
 };
 
-static __init int m41t94_init(void)
-{
-       return spi_register_driver(&m41t94_driver);
-}
-
-module_init(m41t94_init);
-
-static __exit void m41t94_exit(void)
-{
-       spi_unregister_driver(&m41t94_driver);
-}
-
-module_exit(m41t94_exit);
+module_spi_driver(m41t94_driver);
 
 MODULE_AUTHOR("Kim B. Heino <Kim.Heino@bluegiga.com>");
 MODULE_DESCRIPTION("Driver for ST M41T94 SPI RTC");
index 486142c..a00e332 100644 (file)
@@ -261,20 +261,9 @@ static struct i2c_driver max6900_driver = {
        .id_table = max6900_id,
 };
 
-static int __init max6900_init(void)
-{
-       return i2c_add_driver(&max6900_driver);
-}
-
-static void __exit max6900_exit(void)
-{
-       i2c_del_driver(&max6900_driver);
-}
+module_i2c_driver(max6900_driver);
 
 MODULE_DESCRIPTION("Maxim MAX6900 RTC driver");
 MODULE_AUTHOR("Dale Farnsworth <dale@farnsworth.org>");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(max6900_init);
-module_exit(max6900_exit);
index 1f6b3cc..36c74d2 100644 (file)
@@ -160,17 +160,7 @@ static struct spi_driver max6902_driver = {
        .remove = __devexit_p(max6902_remove),
 };
 
-static __init int max6902_init(void)
-{
-       return spi_register_driver(&max6902_driver);
-}
-module_init(max6902_init);
-
-static __exit void max6902_exit(void)
-{
-       spi_unregister_driver(&max6902_driver);
-}
-module_exit(max6902_exit);
+module_spi_driver(max6902_driver);
 
 MODULE_DESCRIPTION ("max6902 spi RTC driver");
 MODULE_AUTHOR ("Raphael Assenat");
index 2d71943..1459055 100644 (file)
@@ -193,10 +193,17 @@ static int max8925_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        ret = max8925_reg_read(info->rtc, MAX8925_RTC_IRQ_MASK);
        if (ret < 0)
                goto out;
-       if ((ret & ALARM0_IRQ) == 0)
-               alrm->enabled = 1;
-       else
+       if (ret & ALARM0_IRQ) {
                alrm->enabled = 0;
+       } else {
+               ret = max8925_reg_read(info->rtc, MAX8925_ALARM0_CNTL);
+               if (ret < 0)
+                       goto out;
+               if (!ret)
+                       alrm->enabled = 0;
+               else
+                       alrm->enabled = 1;
+       }
        ret = max8925_reg_read(info->rtc, MAX8925_RTC_STATUS);
        if (ret < 0)
                goto out;
@@ -204,6 +211,7 @@ static int max8925_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
                alrm->pending = 1;
        else
                alrm->pending = 0;
+       return 0;
 out:
        return ret;
 }
@@ -220,8 +228,11 @@ static int max8925_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        ret = max8925_bulk_write(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf);
        if (ret < 0)
                goto out;
-       /* only enable alarm on year/month/day/hour/min/sec */
-       ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x77);
+       if (alrm->enabled)
+               /* only enable alarm on year/month/day/hour/min/sec */
+               ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x77);
+       else
+               ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x0);
        if (ret < 0)
                goto out;
 out:
index 9d3cacc..e954a75 100644 (file)
@@ -327,7 +327,7 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op)
        dev_set_drvdata(&op->dev, rtc);
 
        rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1);
-       err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED,
+       err = request_irq(rtc->irq, mpc5121_rtc_handler, 0,
                                                "mpc5121-rtc", &op->dev);
        if (err) {
                dev_err(&op->dev, "%s: could not request irq: %i\n",
@@ -337,7 +337,7 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op)
 
        rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0);
        err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd,
-                               IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev);
+                               0, "mpc5121-rtc_upd", &op->dev);
        if (err) {
                dev_err(&op->dev, "%s: could not request irq: %i\n",
                                                __func__, rtc->irq_periodic);
index 6cd6c72..f51719b 100644 (file)
@@ -366,7 +366,7 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq)
 
        if (rtc_irq) {
                retval = request_irq(rtc_irq, mrst_rtc_irq,
-                               IRQF_DISABLED, dev_name(&mrst_rtc.rtc->dev),
+                               0, dev_name(&mrst_rtc.rtc->dev),
                                mrst_rtc.rtc);
                if (retval < 0) {
                        dev_dbg(dev, "IRQ %d is already in use, err %d\n",
index 768e2ed..b2185f4 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/bcd.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 #include <linux/delay.h>
 #include <linux/gfp.h>
 #include <linux/module.h>
@@ -273,7 +274,7 @@ static int __devinit mv_rtc_probe(struct platform_device *pdev)
        if (pdata->irq >= 0) {
                writel(0, pdata->ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
                if (devm_request_irq(&pdev->dev, pdata->irq, mv_rtc_interrupt,
-                                    IRQF_DISABLED | IRQF_SHARED,
+                                    IRQF_SHARED,
                                     pdev->name, pdata) < 0) {
                        dev_warn(&pdev->dev, "interrupt not available.\n");
                        pdata->irq = -1;
@@ -294,11 +295,19 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id rtc_mv_of_match_table[] = {
+       { .compatible = "mrvl,orion-rtc", },
+       {}
+};
+#endif
+
 static struct platform_driver mv_rtc_driver = {
        .remove         = __exit_p(mv_rtc_remove),
        .driver         = {
                .name   = "rtc-mv",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(rtc_mv_of_match_table),
        },
 };
 
index 781068d..b790109 100644 (file)
@@ -269,7 +269,7 @@ static int __devinit nuc900_rtc_probe(struct platform_device *pdev)
 
        nuc900_rtc->irq_num = platform_get_irq(pdev, 0);
        if (request_irq(nuc900_rtc->irq_num, nuc900_rtc_interrupt,
-                               IRQF_DISABLED, "nuc900rtc", nuc900_rtc)) {
+                               0, "nuc900rtc", nuc900_rtc)) {
                dev_err(&pdev->dev, "NUC900 RTC request irq failed\n");
                err = -EBUSY;
                goto fail4;
index 7789002..0b614e3 100644 (file)
@@ -348,14 +348,14 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
                rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
 
        /* handle periodic and alarm irqs */
-       if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED,
+       if (request_irq(omap_rtc_timer, rtc_irq, 0,
                        dev_name(&rtc->dev), rtc)) {
                pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
                        pdev->name, omap_rtc_timer);
                goto fail1;
        }
        if ((omap_rtc_timer != omap_rtc_alarm) &&
-               (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED,
+               (request_irq(omap_rtc_alarm, rtc_irq, 0,
                        dev_name(&rtc->dev), rtc))) {
                pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
                        pdev->name, omap_rtc_alarm);
index b46c400..8361187 100644 (file)
@@ -346,20 +346,9 @@ static struct spi_driver pcf2123_driver = {
        .remove = __devexit_p(pcf2123_remove),
 };
 
-static int __init pcf2123_init(void)
-{
-       return spi_register_driver(&pcf2123_driver);
-}
-
-static void __exit pcf2123_exit(void)
-{
-       spi_unregister_driver(&pcf2123_driver);
-}
+module_spi_driver(pcf2123_driver);
 
 MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>");
 MODULE_DESCRIPTION("NXP PCF2123 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(pcf2123_init);
-module_exit(pcf2123_exit);
index 606fdfa..bc0677d 100644 (file)
@@ -252,20 +252,9 @@ static struct i2c_driver pcf8563_driver = {
        .id_table       = pcf8563_id,
 };
 
-static int __init pcf8563_init(void)
-{
-       return i2c_add_driver(&pcf8563_driver);
-}
-
-static void __exit pcf8563_exit(void)
-{
-       i2c_del_driver(&pcf8563_driver);
-}
+module_i2c_driver(pcf8563_driver);
 
 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(pcf8563_init);
-module_exit(pcf8563_exit);
index 2d201af..019ff35 100644 (file)
@@ -320,18 +320,7 @@ static struct i2c_driver pcf8583_driver = {
        .id_table       = pcf8583_id,
 };
 
-static __init int pcf8583_init(void)
-{
-       return i2c_add_driver(&pcf8583_driver);
-}
-
-static __exit void pcf8583_exit(void)
-{
-       i2c_del_driver(&pcf8583_driver);
-}
-
-module_init(pcf8583_init);
-module_exit(pcf8583_exit);
+module_i2c_driver(pcf8583_driver);
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("PCF8583 I2C RTC driver");
index 02111fe..22bacdb 100644 (file)
@@ -123,7 +123,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
 
        amba_set_drvdata(dev, rtc);
 
-       ret = request_irq(dev->irq[0], pl030_interrupt, IRQF_DISABLED,
+       ret = request_irq(dev->irq[0], pl030_interrupt, 0,
                          "rtc-pl030", rtc);
        if (ret)
                goto err_irq;
@@ -185,18 +185,7 @@ static struct amba_driver pl030_driver = {
        .id_table       = pl030_ids,
 };
 
-static int __init pl030_init(void)
-{
-       return amba_driver_register(&pl030_driver);
-}
-
-static void __exit pl030_exit(void)
-{
-       amba_driver_unregister(&pl030_driver);
-}
-
-module_init(pl030_init);
-module_exit(pl030_exit);
+module_amba_driver(pl030_driver);
 
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("ARM AMBA PL030 RTC Driver");
index a952c8d..692de73 100644 (file)
@@ -352,7 +352,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
        }
 
        if (request_irq(adev->irq[0], pl031_interrupt,
-                       IRQF_DISABLED, "rtc-pl031", ldata)) {
+                       0, "rtc-pl031", ldata)) {
                ret = -EIO;
                goto out_no_irq;
        }
@@ -431,18 +431,7 @@ static struct amba_driver pl031_driver = {
        .remove = pl031_remove,
 };
 
-static int __init pl031_init(void)
-{
-       return amba_driver_register(&pl031_driver);
-}
-
-static void __exit pl031_exit(void)
-{
-       amba_driver_unregister(&pl031_driver);
-}
-
-module_init(pl031_init);
-module_exit(pl031_exit);
+module_amba_driver(pl031_driver);
 
 MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
 MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
index 9f1d6bc..d00bd24 100644 (file)
@@ -520,7 +520,7 @@ static int pm8xxx_rtc_suspend(struct device *dev)
 }
 #endif
 
-SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume);
+static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume);
 
 static struct platform_driver pm8xxx_rtc_driver = {
        .probe          = pm8xxx_rtc_probe,
index fc9f499..0075c8f 100644 (file)
@@ -174,14 +174,14 @@ static int pxa_rtc_open(struct device *dev)
        struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
        int ret;
 
-       ret = request_irq(pxa_rtc->irq_1Hz, pxa_rtc_irq, IRQF_DISABLED,
+       ret = request_irq(pxa_rtc->irq_1Hz, pxa_rtc_irq, 0,
                          "rtc 1Hz", dev);
        if (ret < 0) {
                dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_1Hz,
                        ret);
                goto err_irq_1Hz;
        }
-       ret = request_irq(pxa_rtc->irq_Alrm, pxa_rtc_irq, IRQF_DISABLED,
+       ret = request_irq(pxa_rtc->irq_Alrm, pxa_rtc_irq, 0,
                          "rtc Alrm", dev);
        if (ret < 0) {
                dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_Alrm,
index 2853c2a..7f8e6c2 100644 (file)
@@ -159,17 +159,7 @@ static struct spi_driver r9701_driver = {
        .remove = __devexit_p(r9701_remove),
 };
 
-static __init int r9701_init(void)
-{
-       return spi_register_driver(&r9701_driver);
-}
-module_init(r9701_init);
-
-static __exit void r9701_exit(void)
-{
-       spi_unregister_driver(&r9701_driver);
-}
-module_exit(r9701_exit);
+module_spi_driver(r9701_driver);
 
 MODULE_DESCRIPTION("r9701 spi RTC driver");
 MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
index ce2ca85..77074cc 100644 (file)
@@ -235,18 +235,7 @@ static struct spi_driver rs5c348_driver = {
        .remove = __devexit_p(rs5c348_remove),
 };
 
-static __init int rs5c348_init(void)
-{
-       return spi_register_driver(&rs5c348_driver);
-}
-
-static __exit void rs5c348_exit(void)
-{
-       spi_unregister_driver(&rs5c348_driver);
-}
-
-module_init(rs5c348_init);
-module_exit(rs5c348_exit);
+module_spi_driver(rs5c348_driver);
 
 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
 MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver");
index d29f543..fb4842c 100644 (file)
@@ -689,18 +689,7 @@ static struct i2c_driver rs5c372_driver = {
        .id_table       = rs5c372_id,
 };
 
-static __init int rs5c372_init(void)
-{
-       return i2c_add_driver(&rs5c372_driver);
-}
-
-static __exit void rs5c372_exit(void)
-{
-       i2c_del_driver(&rs5c372_driver);
-}
-
-module_init(rs5c372_init);
-module_exit(rs5c372_exit);
+module_i2c_driver(rs5c372_driver);
 
 MODULE_AUTHOR(
                "Pavel Mironchik <pmironchik@optifacio.net>, "
index ea09ff2..0fbe57b 100644 (file)
@@ -436,18 +436,7 @@ static struct i2c_driver rv3029c2_driver = {
        .id_table = rv3029c2_id,
 };
 
-static int __init rv3029c2_init(void)
-{
-       return i2c_add_driver(&rv3029c2_driver);
-}
-
-static void __exit rv3029c2_exit(void)
-{
-       i2c_del_driver(&rv3029c2_driver);
-}
-
-module_init(rv3029c2_init);
-module_exit(rv3029c2_exit);
+module_i2c_driver(rv3029c2_driver);
 
 MODULE_AUTHOR("Gregory Hermant <gregory.hermant@calao-systems.com>");
 MODULE_DESCRIPTION("Micro Crystal RV3029C2 RTC driver");
index fde172f..0de902d 100644 (file)
@@ -644,19 +644,8 @@ static struct i2c_driver rx8025_driver = {
        .id_table       = rx8025_id,
 };
 
-static int __init rx8025_init(void)
-{
-       return i2c_add_driver(&rx8025_driver);
-}
-
-static void __exit rx8025_exit(void)
-{
-       i2c_del_driver(&rx8025_driver);
-}
+module_i2c_driver(rx8025_driver);
 
 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
 MODULE_DESCRIPTION("RX-8025 SA/NB RTC driver");
 MODULE_LICENSE("GPL");
-
-module_init(rx8025_init);
-module_exit(rx8025_exit);
index 600b890..d848251 100644 (file)
@@ -276,20 +276,9 @@ static struct i2c_driver rx8581_driver = {
        .id_table       = rx8581_id,
 };
 
-static int __init rx8581_init(void)
-{
-       return i2c_add_driver(&rx8581_driver);
-}
-
-static void __exit rx8581_exit(void)
-{
-       i2c_del_driver(&rx8581_driver);
-}
+module_i2c_driver(rx8581_driver);
 
 MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>");
 MODULE_DESCRIPTION("Epson RX-8581 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(rx8581_init);
-module_exit(rx8581_exit);
index f789e00..c9562ce 100644 (file)
@@ -304,19 +304,8 @@ static struct i2c_driver s35390a_driver = {
        .id_table       = s35390a_id,
 };
 
-static int __init s35390a_rtc_init(void)
-{
-       return i2c_add_driver(&s35390a_driver);
-}
-
-static void __exit s35390a_rtc_exit(void)
-{
-       i2c_del_driver(&s35390a_driver);
-}
+module_i2c_driver(s35390a_driver);
 
 MODULE_AUTHOR("Byron Bradley <byron.bbradley@gmail.com>");
 MODULE_DESCRIPTION("S35390A RTC driver");
 MODULE_LICENSE("GPL");
-
-module_init(s35390a_rtc_init);
-module_exit(s35390a_rtc_exit);
index aef40bd..9ccea13 100644 (file)
@@ -35,6 +35,8 @@
 
 enum s3c_cpu_type {
        TYPE_S3C2410,
+       TYPE_S3C2416,
+       TYPE_S3C2443,
        TYPE_S3C64XX,
 };
 
@@ -132,6 +134,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq)
        struct platform_device *pdev = to_platform_device(dev);
        struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
        unsigned int tmp = 0;
+       int val;
 
        if (!is_power_of_2(freq))
                return -EINVAL;
@@ -139,12 +142,22 @@ static int s3c_rtc_setfreq(struct device *dev, int freq)
        clk_enable(rtc_clk);
        spin_lock_irq(&s3c_rtc_pie_lock);
 
-       if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+       if (s3c_rtc_cpu_type != TYPE_S3C64XX) {
                tmp = readb(s3c_rtc_base + S3C2410_TICNT);
                tmp &= S3C2410_TICNT_ENABLE;
        }
 
-       tmp |= (rtc_dev->max_user_freq / freq)-1;
+       val = (rtc_dev->max_user_freq / freq) - 1;
+
+       if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) {
+               tmp |= S3C2443_TICNT_PART(val);
+               writel(S3C2443_TICNT1_PART(val), s3c_rtc_base + S3C2443_TICNT1);
+
+               if (s3c_rtc_cpu_type == TYPE_S3C2416)
+                       writel(S3C2416_TICNT2_PART(val), s3c_rtc_base + S3C2416_TICNT2);
+       } else {
+               tmp |= val;
+       }
 
        writel(tmp, s3c_rtc_base + S3C2410_TICNT);
        spin_unlock_irq(&s3c_rtc_pie_lock);
@@ -371,7 +384,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
                tmp &= ~S3C2410_RTCCON_RTCEN;
                writew(tmp, base + S3C2410_RTCCON);
 
-               if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+               if (s3c_rtc_cpu_type != TYPE_S3C64XX) {
                        tmp = readb(base + S3C2410_TICNT);
                        tmp &= ~S3C2410_TICNT_ENABLE;
                        writeb(tmp, base + S3C2410_TICNT);
@@ -428,12 +441,27 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)
        return 0;
 }
 
+static const struct of_device_id s3c_rtc_dt_match[];
+
+static inline int s3c_rtc_get_driver_data(struct platform_device *pdev)
+{
+#ifdef CONFIG_OF
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
+               return match->data;
+       }
+#endif
+       return platform_get_device_id(pdev)->driver_data;
+}
+
 static int __devinit s3c_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
        struct rtc_time rtc_tm;
        struct resource *res;
        int ret;
+       int tmp;
 
        pr_debug("%s: probe=%p\n", __func__, pdev);
 
@@ -508,13 +536,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
                goto err_nortc;
        }
 
-#ifdef CONFIG_OF
-       if (pdev->dev.of_node)
-               s3c_rtc_cpu_type = of_device_is_compatible(pdev->dev.of_node,
-                       "samsung,s3c6410-rtc") ? TYPE_S3C64XX : TYPE_S3C2410;
-       else
-#endif
-               s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
+       s3c_rtc_cpu_type = s3c_rtc_get_driver_data(pdev);
 
        /* Check RTC Time */
 
@@ -533,24 +555,30 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
                dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
        }
 
-       if (s3c_rtc_cpu_type == TYPE_S3C64XX)
+       if (s3c_rtc_cpu_type != TYPE_S3C2410)
                rtc->max_user_freq = 32768;
        else
                rtc->max_user_freq = 128;
 
+       if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) {
+               tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
+               tmp |= S3C2443_RTCCON_TICSEL;
+               writew(tmp, s3c_rtc_base + S3C2410_RTCCON);
+       }
+
        platform_set_drvdata(pdev, rtc);
 
        s3c_rtc_setfreq(&pdev->dev, 1);
 
        ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
-                         IRQF_DISABLED,  "s3c2410-rtc alarm", rtc);
+                         0,  "s3c2410-rtc alarm", rtc);
        if (ret) {
                dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
                goto err_alarm_irq;
        }
 
        ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
-                         IRQF_DISABLED,  "s3c2410-rtc tick", rtc);
+                         0,  "s3c2410-rtc tick", rtc);
        if (ret) {
                dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
                free_irq(s3c_rtc_alarmno, rtc);
@@ -638,8 +666,19 @@ static int s3c_rtc_resume(struct platform_device *pdev)
 
 #ifdef CONFIG_OF
 static const struct of_device_id s3c_rtc_dt_match[] = {
-       { .compatible = "samsung,s3c2410-rtc" },
-       { .compatible = "samsung,s3c6410-rtc" },
+       {
+               .compatible = "samsung,s3c2410-rtc"
+               .data = TYPE_S3C2410,
+       }, {
+               .compatible = "samsung,s3c2416-rtc"
+               .data = TYPE_S3C2416,
+       }, {
+               .compatible = "samsung,s3c2443-rtc"
+               .data = TYPE_S3C2443,
+       }, {
+               .compatible = "samsung,s3c6410-rtc"
+               .data = TYPE_S3C64XX,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
@@ -652,6 +691,12 @@ static struct platform_device_id s3c_rtc_driver_ids[] = {
                .name           = "s3c2410-rtc",
                .driver_data    = TYPE_S3C2410,
        }, {
+               .name           = "s3c2416-rtc",
+               .driver_data    = TYPE_S3C2416,
+       }, {
+               .name           = "s3c2443-rtc",
+               .driver_data    = TYPE_S3C2443,
+       }, {
                .name           = "s3c64xx-rtc",
                .driver_data    = TYPE_S3C64XX,
        },
index cb9a585..4940fa8 100644 (file)
 
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/clk.h>
 #include <linux/rtc.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/interrupt.h>
+#include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/of.h>
 #include <linux/pm.h>
 #include <linux/bitops.h>
 
 #include <mach/hardware.h>
-#include <asm/irq.h>
+#include <mach/irqs.h>
 
-#ifdef CONFIG_ARCH_PXA
+#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
 #include <mach/regs-rtc.h>
 #endif
 
 #define RTC_DEF_DIVIDER                (32768 - 1)
 #define RTC_DEF_TRIM           0
-
-static const unsigned long RTC_FREQ = 1024;
-static struct rtc_time rtc_alarm;
-static DEFINE_SPINLOCK(sa1100_rtc_lock);
-
-static inline int rtc_periodic_alarm(struct rtc_time *tm)
-{
-       return  (tm->tm_year == -1) ||
-               ((unsigned)tm->tm_mon >= 12) ||
-               ((unsigned)(tm->tm_mday - 1) >= 31) ||
-               ((unsigned)tm->tm_hour > 23) ||
-               ((unsigned)tm->tm_min > 59) ||
-               ((unsigned)tm->tm_sec > 59);
-}
-
-/*
- * 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 rtc_update_alarm(struct rtc_time *alrm)
-{
-       struct rtc_time alarm_tm, now_tm;
-       unsigned long now, time;
-       int ret;
-
-       do {
-               now = RCNR;
-               rtc_time_to_tm(now, &now_tm);
-               rtc_next_alarm_time(&alarm_tm, &now_tm, alrm);
-               ret = rtc_tm_to_time(&alarm_tm, &time);
-               if (ret != 0)
-                       break;
-
-               RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
-               RTAR = time;
-       } while (now != RCNR);
-
-       return ret;
-}
+#define RTC_FREQ               1024
+
+struct sa1100_rtc {
+       spinlock_t              lock;
+       int                     irq_1hz;
+       int                     irq_alarm;
+       struct rtc_device       *rtc;
+       struct clk              *clk;
+};
 
 static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
 {
-       struct platform_device *pdev = to_platform_device(dev_id);
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct sa1100_rtc *info = dev_get_drvdata(dev_id);
+       struct rtc_device *rtc = info->rtc;
        unsigned int rtsr;
        unsigned long events = 0;
 
-       spin_lock(&sa1100_rtc_lock);
+       spin_lock(&info->lock);
 
        rtsr = RTSR;
        /* clear interrupt sources */
@@ -146,30 +96,28 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
 
        rtc_update_irq(rtc, 1, events);
 
-       if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
-               rtc_update_alarm(&rtc_alarm);
-
-       spin_unlock(&sa1100_rtc_lock);
+       spin_unlock(&info->lock);
 
        return IRQ_HANDLED;
 }
 
 static int sa1100_rtc_open(struct device *dev)
 {
+       struct sa1100_rtc *info = dev_get_drvdata(dev);
+       struct rtc_device *rtc = info->rtc;
        int ret;
-       struct platform_device *plat_dev = to_platform_device(dev);
-       struct rtc_device *rtc = platform_get_drvdata(plat_dev);
 
-       ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED,
-               "rtc 1Hz", dev);
+       ret = clk_prepare_enable(info->clk);
+       if (ret)
+               goto fail_clk;
+       ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev);
        if (ret) {
-               dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz);
+               dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz);
                goto fail_ui;
        }
-       ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED,
-               "rtc Alrm", dev);
+       ret = request_irq(info->irq_alarm, sa1100_rtc_interrupt, 0, "rtc Alrm", dev);
        if (ret) {
-               dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm);
+               dev_err(dev, "IRQ %d already in use.\n", info->irq_alarm);
                goto fail_ai;
        }
        rtc->max_user_freq = RTC_FREQ;
@@ -178,29 +126,36 @@ static int sa1100_rtc_open(struct device *dev)
        return 0;
 
  fail_ai:
-       free_irq(IRQ_RTC1Hz, dev);
+       free_irq(info->irq_1hz, dev);
  fail_ui:
+       clk_disable_unprepare(info->clk);
+ fail_clk:
        return ret;
 }
 
 static void sa1100_rtc_release(struct device *dev)
 {
-       spin_lock_irq(&sa1100_rtc_lock);
+       struct sa1100_rtc *info = dev_get_drvdata(dev);
+
+       spin_lock_irq(&info->lock);
        RTSR = 0;
-       spin_unlock_irq(&sa1100_rtc_lock);
+       spin_unlock_irq(&info->lock);
 
-       free_irq(IRQ_RTCAlrm, dev);
-       free_irq(IRQ_RTC1Hz, dev);
+       free_irq(info->irq_alarm, dev);
+       free_irq(info->irq_1hz, dev);
+       clk_disable_unprepare(info->clk);
 }
 
 static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-       spin_lock_irq(&sa1100_rtc_lock);
+       struct sa1100_rtc *info = dev_get_drvdata(dev);
+
+       spin_lock_irq(&info->lock);
        if (enabled)
                RTSR |= RTSR_ALE;
        else
                RTSR &= ~RTSR_ALE;
-       spin_unlock_irq(&sa1100_rtc_lock);
+       spin_unlock_irq(&info->lock);
        return 0;
 }
 
@@ -225,7 +180,6 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        u32     rtsr;
 
-       memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
        rtsr = RTSR;
        alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0;
        alrm->pending = (rtsr & RTSR_AL) ? 1 : 0;
@@ -234,17 +188,22 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
 static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
+       struct sa1100_rtc *info = dev_get_drvdata(dev);
+       unsigned long time;
        int ret;
 
-       spin_lock_irq(&sa1100_rtc_lock);
-       ret = rtc_update_alarm(&alrm->time);
-       if (ret == 0) {
-               if (alrm->enabled)
-                       RTSR |= RTSR_ALE;
-               else
-                       RTSR &= ~RTSR_ALE;
-       }
-       spin_unlock_irq(&sa1100_rtc_lock);
+       spin_lock_irq(&info->lock);
+       ret = rtc_tm_to_time(&alrm->time, &time);
+       if (ret != 0)
+               goto out;
+       RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
+       RTAR = time;
+       if (alrm->enabled)
+               RTSR |= RTSR_ALE;
+       else
+               RTSR &= ~RTSR_ALE;
+out:
+       spin_unlock_irq(&info->lock);
 
        return ret;
 }
@@ -271,6 +230,27 @@ static const struct rtc_class_ops sa1100_rtc_ops = {
 static int sa1100_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
+       struct sa1100_rtc *info;
+       int irq_1hz, irq_alarm, ret = 0;
+
+       irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz");
+       irq_alarm = platform_get_irq_byname(pdev, "rtc alarm");
+       if (irq_1hz < 0 || irq_alarm < 0)
+               return -ENODEV;
+
+       info = kzalloc(sizeof(struct sa1100_rtc), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       info->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(info->clk)) {
+               dev_err(&pdev->dev, "failed to find rtc clock source\n");
+               ret = PTR_ERR(info->clk);
+               goto err_clk;
+       }
+       info->irq_1hz = irq_1hz;
+       info->irq_alarm = irq_alarm;
+       spin_lock_init(&info->lock);
+       platform_set_drvdata(pdev, info);
 
        /*
         * According to the manual we should be able to let RTTR be zero
@@ -292,10 +272,11 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
        rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
                THIS_MODULE);
 
-       if (IS_ERR(rtc))
-               return PTR_ERR(rtc);
-
-       platform_set_drvdata(pdev, rtc);
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               goto err_dev;
+       }
+       info->rtc = rtc;
 
        /* Fix for a nasty initialization problem the in SA11xx RTSR register.
         * See also the comments in sa1100_rtc_interrupt().
@@ -322,14 +303,24 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
        RTSR = RTSR_AL | RTSR_HZ;
 
        return 0;
+err_dev:
+       platform_set_drvdata(pdev, NULL);
+       clk_put(info->clk);
+err_clk:
+       kfree(info);
+       return ret;
 }
 
 static int sa1100_rtc_remove(struct platform_device *pdev)
 {
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       struct sa1100_rtc *info = platform_get_drvdata(pdev);
 
-       if (rtc)
-               rtc_device_unregister(rtc);
+       if (info) {
+               rtc_device_unregister(info->rtc);
+               clk_put(info->clk);
+               platform_set_drvdata(pdev, NULL);
+               kfree(info);
+       }
 
        return 0;
 }
@@ -337,15 +328,17 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int sa1100_rtc_suspend(struct device *dev)
 {
+       struct sa1100_rtc *info = dev_get_drvdata(dev);
        if (device_may_wakeup(dev))
-               enable_irq_wake(IRQ_RTCAlrm);
+               enable_irq_wake(info->irq_alarm);
        return 0;
 }
 
 static int sa1100_rtc_resume(struct device *dev)
 {
+       struct sa1100_rtc *info = dev_get_drvdata(dev);
        if (device_may_wakeup(dev))
-               disable_irq_wake(IRQ_RTCAlrm);
+               disable_irq_wake(info->irq_alarm);
        return 0;
 }
 
@@ -355,6 +348,13 @@ static const struct dev_pm_ops sa1100_rtc_pm_ops = {
 };
 #endif
 
+static struct of_device_id sa1100_rtc_dt_ids[] = {
+       { .compatible = "mrvl,sa1100-rtc", },
+       { .compatible = "mrvl,mmp-rtc", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids);
+
 static struct platform_driver sa1100_rtc_driver = {
        .probe          = sa1100_rtc_probe,
        .remove         = sa1100_rtc_remove,
@@ -363,6 +363,7 @@ static struct platform_driver sa1100_rtc_driver = {
 #ifdef CONFIG_PM
                .pm     = &sa1100_rtc_pm_ops,
 #endif
+               .of_match_table = sa1100_rtc_dt_ids,
        },
 };
 
index 6ac55fd..e55a763 100644 (file)
@@ -666,7 +666,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
        if (rtc->carry_irq <= 0) {
                /* register shared periodic/carry/alarm irq */
                ret = request_irq(rtc->periodic_irq, sh_rtc_shared,
-                                 IRQF_DISABLED, "sh-rtc", rtc);
+                                 0, "sh-rtc", rtc);
                if (unlikely(ret)) {
                        dev_err(&pdev->dev,
                                "request IRQ failed with %d, IRQ %d\n", ret,
@@ -676,7 +676,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
        } else {
                /* register periodic/carry/alarm irqs */
                ret = request_irq(rtc->periodic_irq, sh_rtc_periodic,
-                                 IRQF_DISABLED, "sh-rtc period", rtc);
+                                 0, "sh-rtc period", rtc);
                if (unlikely(ret)) {
                        dev_err(&pdev->dev,
                                "request period IRQ failed with %d, IRQ %d\n",
@@ -685,7 +685,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
                }
 
                ret = request_irq(rtc->carry_irq, sh_rtc_interrupt,
-                                 IRQF_DISABLED, "sh-rtc carry", rtc);
+                                 0, "sh-rtc carry", rtc);
                if (unlikely(ret)) {
                        dev_err(&pdev->dev,
                                "request carry IRQ failed with %d, IRQ %d\n",
@@ -695,7 +695,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
                }
 
                ret = request_irq(rtc->alarm_irq, sh_rtc_alarm,
-                                 IRQF_DISABLED, "sh-rtc alarm", rtc);
+                                 0, "sh-rtc alarm", rtc);
                if (unlikely(ret)) {
                        dev_err(&pdev->dev,
                                "request alarm IRQ failed with %d, IRQ %d\n",
index 19a28a6..e38da0d 100644 (file)
 #define STATUS_FAIL            (LOST_WR_TIME | LOST_WR_DATE)
 
 struct spear_rtc_config {
+       struct rtc_device *rtc;
        struct clk *clk;
        spinlock_t lock;
        void __iomem *ioaddr;
+       unsigned int irq_wake;
 };
 
 static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config)
@@ -149,8 +151,7 @@ static void rtc_wait_not_busy(struct spear_rtc_config *config)
 
 static irqreturn_t spear_rtc_irq(int irq, void *dev_id)
 {
-       struct rtc_device *rtc = (struct rtc_device *)dev_id;
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = dev_id;
        unsigned long flags, events = 0;
        unsigned int irq_data;
 
@@ -161,7 +162,7 @@ static irqreturn_t spear_rtc_irq(int irq, void *dev_id)
        if ((irq_data & RTC_INT_MASK)) {
                spear_rtc_clear_interrupt(config);
                events = RTC_IRQF | RTC_AF;
-               rtc_update_irq(rtc, 1, events);
+               rtc_update_irq(config->rtc, 1, events);
                return IRQ_HANDLED;
        } else
                return IRQ_NONE;
@@ -203,9 +204,7 @@ static void bcd2tm(struct rtc_time *tm)
  */
 static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = dev_get_drvdata(dev);
        unsigned int time, date;
 
        /* we don't report wday/yday/isdst ... */
@@ -234,9 +233,7 @@ static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)
  */
 static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = dev_get_drvdata(dev);
        unsigned int time, date, err = 0;
 
        if (tm2bcd(tm) < 0)
@@ -266,9 +263,7 @@ static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
  */
 static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = dev_get_drvdata(dev);
        unsigned int time, date;
 
        rtc_wait_not_busy(config);
@@ -298,9 +293,7 @@ static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
  */
 static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = dev_get_drvdata(dev);
        unsigned int time, date, err = 0;
 
        if (tm2bcd(&alm->time) < 0)
@@ -326,17 +319,42 @@ static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
        return 0;
 }
+
+static int spear_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct spear_rtc_config *config = dev_get_drvdata(dev);
+       int ret = 0;
+
+       spear_rtc_clear_interrupt(config);
+
+       switch (enabled) {
+       case 0:
+               /* alarm off */
+               spear_rtc_disable_interrupt(config);
+               break;
+       case 1:
+               /* alarm on */
+               spear_rtc_enable_interrupt(config);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
 static struct rtc_class_ops spear_rtc_ops = {
        .read_time = spear_rtc_read_time,
        .set_time = spear_rtc_set_time,
        .read_alarm = spear_rtc_read_alarm,
        .set_alarm = spear_rtc_set_alarm,
+       .alarm_irq_enable = spear_alarm_irq_enable,
 };
 
 static int __devinit spear_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
-       struct rtc_device *rtc;
        struct spear_rtc_config *config;
        unsigned int status = 0;
        int irq;
@@ -376,19 +394,17 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev)
        }
 
        spin_lock_init(&config->lock);
+       platform_set_drvdata(pdev, config);
 
-       rtc = rtc_device_register(pdev->name, &pdev->dev, &spear_rtc_ops,
-                       THIS_MODULE);
-       if (IS_ERR(rtc)) {
+       config->rtc = rtc_device_register(pdev->name, &pdev->dev,
+                       &spear_rtc_ops, THIS_MODULE);
+       if (IS_ERR(config->rtc)) {
                dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
-                               PTR_ERR(rtc));
-               status = PTR_ERR(rtc);
+                               PTR_ERR(config->rtc));
+               status = PTR_ERR(config->rtc);
                goto err_iounmap;
        }
 
-       platform_set_drvdata(pdev, rtc);
-       dev_set_drvdata(&rtc->dev, config);
-
        /* alarm irqs */
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
@@ -397,7 +413,7 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev)
                goto err_clear_platdata;
        }
 
-       status = request_irq(irq, spear_rtc_irq, 0, pdev->name, rtc);
+       status = request_irq(irq, spear_rtc_irq, 0, pdev->name, config);
        if (status) {
                dev_err(&pdev->dev, "Alarm interrupt IRQ%d already \
                                claimed\n", irq);
@@ -411,8 +427,7 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev)
 
 err_clear_platdata:
        platform_set_drvdata(pdev, NULL);
-       dev_set_drvdata(&rtc->dev, NULL);
-       rtc_device_unregister(rtc);
+       rtc_device_unregister(config->rtc);
 err_iounmap:
        iounmap(config->ioaddr);
 err_disable_clock:
@@ -429,8 +444,7 @@ err_release_region:
 
 static int __devexit spear_rtc_remove(struct platform_device *pdev)
 {
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = platform_get_drvdata(pdev);
        int irq;
        struct resource *res;
 
@@ -448,8 +462,7 @@ static int __devexit spear_rtc_remove(struct platform_device *pdev)
        if (res)
                release_mem_region(res->start, resource_size(res));
        platform_set_drvdata(pdev, NULL);
-       dev_set_drvdata(&rtc->dev, NULL);
-       rtc_device_unregister(rtc);
+       rtc_device_unregister(config->rtc);
 
        return 0;
 }
@@ -458,14 +471,14 @@ static int __devexit spear_rtc_remove(struct platform_device *pdev)
 
 static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = platform_get_drvdata(pdev);
        int irq;
 
        irq = platform_get_irq(pdev, 0);
-       if (device_may_wakeup(&pdev->dev))
-               enable_irq_wake(irq);
-       else {
+       if (device_may_wakeup(&pdev->dev)) {
+               if (!enable_irq_wake(irq))
+                       config->irq_wake = 1;
+       } else {
                spear_rtc_disable_interrupt(config);
                clk_disable(config->clk);
        }
@@ -475,15 +488,17 @@ static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 
 static int spear_rtc_resume(struct platform_device *pdev)
 {
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = platform_get_drvdata(pdev);
        int irq;
 
        irq = platform_get_irq(pdev, 0);
 
-       if (device_may_wakeup(&pdev->dev))
-               disable_irq_wake(irq);
-       else {
+       if (device_may_wakeup(&pdev->dev)) {
+               if (config->irq_wake) {
+                       disable_irq_wake(irq);
+                       config->irq_wake = 0;
+               }
+       } else {
                clk_enable(config->clk);
                spear_rtc_enable_interrupt(config);
        }
@@ -498,8 +513,7 @@ static int spear_rtc_resume(struct platform_device *pdev)
 
 static void spear_rtc_shutdown(struct platform_device *pdev)
 {
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-       struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+       struct spear_rtc_config *config = platform_get_drvdata(pdev);
 
        spear_rtc_disable_interrupt(config);
        clk_disable(config->clk);
index 7621116..279f5cf 100644 (file)
@@ -329,7 +329,7 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
                writeb(0, ioaddr + RTC_INTERRUPTS);
                if (devm_request_irq(&pdev->dev, pdata->irq,
                                stk17ta8_rtc_interrupt,
-                               IRQF_DISABLED | IRQF_SHARED,
+                               IRQF_SHARED,
                                pdev->name, pdev) < 0) {
                        dev_warn(&pdev->dev, "interrupt not available.\n");
                        pdata->irq = 0;
index d43b4f6..4c2c6df 100644 (file)
@@ -176,6 +176,10 @@ static int set_rtc_irq_bit(unsigned char bit)
        unsigned char val;
        int ret;
 
+       /* if the bit is set, return from here */
+       if (rtc_irq_bits & bit)
+               return 0;
+
        val = rtc_irq_bits | bit;
        val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
        ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
@@ -193,6 +197,10 @@ static int mask_rtc_irq_bit(unsigned char bit)
        unsigned char val;
        int ret;
 
+       /* if the bit is clear, return from here */
+       if (!(rtc_irq_bits & bit))
+               return 0;
+
        val = rtc_irq_bits & ~bit;
        ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
        if (ret == 0)
@@ -357,7 +365,7 @@ out:
 
 static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
 {
-       unsigned long events = 0;
+       unsigned long events;
        int ret = IRQ_NONE;
        int res;
        u8 rd_reg;
@@ -372,11 +380,11 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
         * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
         */
        if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
-               events |= RTC_IRQF | RTC_AF;
+               events = RTC_IRQF | RTC_AF;
        else
-               events |= RTC_IRQF | RTC_UF;
+               events = RTC_IRQF | RTC_PF;
 
-       res = twl_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M,
+       res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M,
                                   REG_RTC_STATUS_REG);
        if (res)
                goto out;
@@ -449,19 +457,11 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
                        REG_INT_MSK_STS_A);
        }
 
-       /* Check RTC module status, Enable if it is off */
-       ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
+       dev_info(&pdev->dev, "Enabling TWL-RTC\n");
+       ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG);
        if (ret < 0)
                goto out1;
 
-       if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
-               dev_info(&pdev->dev, "Enabling TWL-RTC.\n");
-               rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
-               ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
-               if (ret < 0)
-                       goto out1;
-       }
-
        /* init cached IRQ enable bits */
        ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
        if (ret < 0)
index aac0ffe..a12bfac 100644 (file)
@@ -266,7 +266,7 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
        spin_lock_init(&pdata->lock);
        tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);
        if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt,
-                            IRQF_DISABLED, pdev->name, &pdev->dev) < 0)
+                            0, pdev->name, &pdev->dev) < 0)
                return -EBUSY;
        rtc = rtc_device_register(pdev->name, &pdev->dev,
                                  &tx4939_rtc_ops, THIS_MODULE);
index fcbfdda..5f60a7c 100644 (file)
@@ -333,7 +333,7 @@ static int __devinit rtc_probe(struct platform_device *pdev)
                goto err_device_unregister;
        }
 
-       retval = request_irq(aie_irq, elapsedtime_interrupt, IRQF_DISABLED,
+       retval = request_irq(aie_irq, elapsedtime_interrupt, 0,
                             "elapsed_time", pdev);
        if (retval < 0)
                goto err_device_unregister;
@@ -342,7 +342,7 @@ static int __devinit rtc_probe(struct platform_device *pdev)
        if (pie_irq <= 0)
                goto err_free_irq;
 
-       retval = request_irq(pie_irq, rtclong1_interrupt, IRQF_DISABLED,
+       retval = request_irq(pie_irq, rtclong1_interrupt, 0,
                             "rtclong1", pdev);
        if (retval < 0)
                goto err_free_irq;
index 8c051d3..403b3d4 100644 (file)
@@ -623,15 +623,7 @@ static struct i2c_driver x1205_driver = {
        .id_table       = x1205_id,
 };
 
-static int __init x1205_init(void)
-{
-       return i2c_add_driver(&x1205_driver);
-}
-
-static void __exit x1205_exit(void)
-{
-       i2c_del_driver(&x1205_driver);
-}
+module_i2c_driver(x1205_driver);
 
 MODULE_AUTHOR(
        "Karen Spearel <kas111 at gmail dot com>, "
@@ -639,6 +631,3 @@ MODULE_AUTHOR(
 MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
-
-module_init(x1205_init);
-module_exit(x1205_exit);
index 2e58f47..231a1d8 100644 (file)
@@ -442,9 +442,8 @@ static int sclp_mem_notifier(struct notifier_block *nb,
        start = arg->start_pfn << PAGE_SHIFT;
        size = arg->nr_pages << PAGE_SHIFT;
        mutex_lock(&sclp_mem_mutex);
-       for (id = 0; id <= sclp_max_storage_id; id++)
-               if (!test_bit(id, sclp_storage_ids))
-                       sclp_attach_storage(id);
+       for_each_clear_bit(id, sclp_storage_ids, sclp_max_storage_id + 1)
+               sclp_attach_storage(id);
        switch (action) {
        case MEM_ONLINE:
        case MEM_GOING_OFFLINE:
index 2a0dfcb..35c685c 100644 (file)
@@ -1458,7 +1458,6 @@ int qdio_establish(struct qdio_initialize *init_data)
        }
 
        qdio_setup_ssqd_info(irq_ptr);
-       DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac);
 
        qdio_detect_hsicq(irq_ptr);
 
index 452989a..ecf12f0 100644 (file)
@@ -311,7 +311,8 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr)
 
        check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token);
        process_ac_flags(irq_ptr, qdioac);
-       DBF_EVENT("qdioac:%4x", qdioac);
+       DBF_EVENT("ac 1:%2x 2:%4x", qdioac, irq_ptr->ssqd_desc.qdioac2);
+       DBF_EVENT("3:%4x qib:%4x", irq_ptr->ssqd_desc.qdioac3, irq_ptr->qib.ac);
 }
 
 void qdio_release_memory(struct qdio_irq *irq_ptr)
index a750aa7..2a28b4a 100644 (file)
@@ -305,7 +305,7 @@ arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id)
        info->base = base;
 
        info->info.scsi.io_base         = base + 0x2000;
-       info->info.scsi.irq             = NO_IRQ;
+       info->info.scsi.irq             = 0;
        info->info.scsi.dma             = NO_DMA;
        info->info.scsi.io_shift        = 5;
        info->info.ifcfg.clockrate      = 24; /* MHz */
index e85c40b..6206a66 100644 (file)
@@ -2176,7 +2176,7 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
        fn = (void (*)(FAS216_Info *, struct scsi_cmnd *, unsigned int))SCpnt->host_scribble;
        fn(info, SCpnt, result);
 
-       if (info->scsi.irq != NO_IRQ) {
+       if (info->scsi.irq) {
                spin_lock_irqsave(&info->host_lock, flags);
                if (info->scsi.phase == PHASE_IDLE)
                        fas216_kick(info);
@@ -2276,7 +2276,7 @@ static int fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt,
         * We should only be using this if we don't have an interrupt.
         * Provide some "incentive" to use the queueing code.
         */
-       BUG_ON(info->scsi.irq != NO_IRQ);
+       BUG_ON(info->scsi.irq);
 
        info->internal_done = 0;
        fas216_queue_command_lck(SCpnt, fas216_internal_done);
index 84b7127..df2e1b3 100644 (file)
 #ifndef FAS216_H
 #define FAS216_H
 
-#ifndef NO_IRQ
-#define NO_IRQ 255
-#endif
-
 #include <scsi/scsi_eh.h>
 
 #include "queue.h"
index c12702b..dad9924 100644 (file)
@@ -47,6 +47,7 @@
 #define FCOE_KCQE_COMPLETION_STATUS_CTX_FREE_FAILURE   (0x4)
 #define FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR                  (0x5)
 #define FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION   (0x6)
+#define FCOE_KCQE_COMPLETION_STATUS_PARITY_ERROR       (0x81)
 
 /* CQE type */
 #define FCOE_PENDING_CQE_TYPE                  0
index 57515f1..495a841 100644 (file)
 #define ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED              (0x51)
 
 #define ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY                          (0x80)
+#define ISCSI_KCQE_COMPLETION_STATUS_PARITY_ERR                         (0x81)
 
 /* SQ/RQ/CQ DB structure sizes */
 #define ISCSI_SQ_DB_SIZE    (16)
index bdfa223..134a0ae 100644 (file)
@@ -4890,11 +4890,8 @@ static struct vio_driver ibmvfc_driver = {
        .probe = ibmvfc_probe,
        .remove = ibmvfc_remove,
        .get_desired_dma = ibmvfc_get_desired_dma,
-       .driver = {
-               .name = IBMVFC_NAME,
-               .owner = THIS_MODULE,
-               .pm = &ibmvfc_pm_ops,
-       }
+       .name = IBMVFC_NAME,
+       .pm = &ibmvfc_pm_ops,
 };
 
 static struct fc_function_template ibmvfc_transport_functions = {
index e984951..3a6c474 100644 (file)
@@ -2061,11 +2061,8 @@ static struct vio_driver ibmvscsi_driver = {
        .probe = ibmvscsi_probe,
        .remove = ibmvscsi_remove,
        .get_desired_dma = ibmvscsi_get_desired_dma,
-       .driver = {
-               .name = "ibmvscsi",
-               .owner = THIS_MODULE,
-               .pm = &ibmvscsi_pm_ops,
-       }
+       .name = "ibmvscsi",
+       .pm = &ibmvscsi_pm_ops,
 };
 
 static struct srp_function_template ibmvscsi_transport_functions = {
index 2256bab..aa7ed81 100644 (file)
@@ -918,10 +918,7 @@ static struct vio_driver ibmvstgt_driver = {
        .id_table = ibmvstgt_device_table,
        .probe = ibmvstgt_probe,
        .remove = ibmvstgt_remove,
-       .driver = {
-               .name = "ibmvscsis",
-               .owner = THIS_MODULE,
-       }
+       .name = "ibmvscsis",
 };
 
 static int get_system_info(void)
index 82fa6ce..5e69f46 100644 (file)
@@ -132,7 +132,7 @@ static int mpt2sas_remove_dead_ioc_func(void *arg)
                pdev = ioc->pdev;
                if ((pdev == NULL))
                        return -1;
-               pci_remove_bus_device(pdev);
+               pci_stop_and_remove_bus_device(pdev);
                return 0;
 }
 
index 92d314a..91b6d52 100644 (file)
@@ -26,7 +26,7 @@ static void sh_clk_mstp32_disable(struct clk *clk)
                  clk->mapped_reg);
 }
 
-static struct clk_ops sh_clk_mstp32_clk_ops = {
+static struct sh_clk_ops sh_clk_mstp32_clk_ops = {
        .enable         = sh_clk_mstp32_enable,
        .disable        = sh_clk_mstp32_disable,
        .recalc         = followparent_recalc,
@@ -150,7 +150,7 @@ static void sh_clk_div6_disable(struct clk *clk)
        iowrite32(value, clk->mapped_reg);
 }
 
-static struct clk_ops sh_clk_div6_clk_ops = {
+static struct sh_clk_ops sh_clk_div6_clk_ops = {
        .recalc         = sh_clk_div6_recalc,
        .round_rate     = sh_clk_div_round_rate,
        .set_rate       = sh_clk_div6_set_rate,
@@ -158,7 +158,7 @@ static struct clk_ops sh_clk_div6_clk_ops = {
        .disable        = sh_clk_div6_disable,
 };
 
-static struct clk_ops sh_clk_div6_reparent_clk_ops = {
+static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = {
        .recalc         = sh_clk_div6_recalc,
        .round_rate     = sh_clk_div_round_rate,
        .set_rate       = sh_clk_div6_set_rate,
@@ -200,7 +200,7 @@ static int __init sh_clk_init_parent(struct clk *clk)
 }
 
 static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
-                                          struct clk_ops *ops)
+                                          struct sh_clk_ops *ops)
 {
        struct clk *clkp;
        void *freq_table;
@@ -317,13 +317,13 @@ static void sh_clk_div4_disable(struct clk *clk)
        iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg);
 }
 
-static struct clk_ops sh_clk_div4_clk_ops = {
+static struct sh_clk_ops sh_clk_div4_clk_ops = {
        .recalc         = sh_clk_div4_recalc,
        .set_rate       = sh_clk_div4_set_rate,
        .round_rate     = sh_clk_div_round_rate,
 };
 
-static struct clk_ops sh_clk_div4_enable_clk_ops = {
+static struct sh_clk_ops sh_clk_div4_enable_clk_ops = {
        .recalc         = sh_clk_div4_recalc,
        .set_rate       = sh_clk_div4_set_rate,
        .round_rate     = sh_clk_div_round_rate,
@@ -331,7 +331,7 @@ static struct clk_ops sh_clk_div4_enable_clk_ops = {
        .disable        = sh_clk_div4_disable,
 };
 
-static struct clk_ops sh_clk_div4_reparent_clk_ops = {
+static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = {
        .recalc         = sh_clk_div4_recalc,
        .set_rate       = sh_clk_div4_set_rate,
        .round_rate     = sh_clk_div_round_rate,
@@ -341,7 +341,7 @@ static struct clk_ops sh_clk_div4_reparent_clk_ops = {
 };
 
 static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
-                       struct clk_div4_table *table, struct clk_ops *ops)
+                       struct clk_div4_table *table, struct sh_clk_ops *ops)
 {
        struct clk *clkp;
        void *freq_table;
index 0b06e36..3ed7483 100644 (file)
@@ -293,7 +293,7 @@ config SPI_RSPI
 
 config SPI_S3C24XX
        tristate "Samsung S3C24XX series SPI"
-       depends on ARCH_S3C2410 && EXPERIMENTAL
+       depends on ARCH_S3C24XX && EXPERIMENTAL
        select SPI_BITBANG
        help
          SPI driver for Samsung S3C24XX series ARM SoCs
index 13448c8..e496f79 100644 (file)
@@ -359,11 +359,6 @@ static int orion_spi_setup(struct spi_device *spi)
 
        orion_spi = spi_master_get_devdata(spi->master);
 
-       /* Fix ac timing if required.   */
-       if (orion_spi->spi_info->enable_clock_fix)
-               orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
-                                 (1 << 14));
-
        if ((spi->max_speed_hz == 0)
                        || (spi->max_speed_hz > orion_spi->max_speed))
                spi->max_speed_hz = orion_spi->max_speed;
index fc06453..8ee7d79 100644 (file)
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
+#include <linux/spi/s3c24xx.h>
 #include <linux/module.h>
 
 #include <plat/regs-spi.h>
-#include <mach/spi.h>
 
 #include <plat/fiq.h>
 #include <asm/fiq.h>
index c0ca709..02cc234 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
-#include <linux/module.h>
 
 #include "../iio.h"
 #include "../sysfs.h"
index 7e5caa3..4f4b7d6 100644 (file)
@@ -6,7 +6,7 @@ menuconfig STAGING_MEDIA
          don't have the "normal" Linux kernel quality level.
          Most of them don't follow properly the V4L, DVB and/or RC API's,
          so, they won't likely work fine with the existing applications.
-         That also means that, one fixed, their API's will change to match
+         That also means that, once fixed, their API's will change to match
          the existing ones.
 
           If you wish to work on these drivers, to help improve them, or
index aae0505..ea4f992 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 
-/* header file for Usb device driver*/
+/* header file for usb device driver*/
 #include "as102_drv.h"
 #include "as102_fw.h"
 #include "dvbdev.h"
index 957f0ed..b0e5a23 100644 (file)
@@ -76,7 +76,7 @@ struct as102_dev_t {
        struct as10x_bus_adapter_t bus_adap;
        struct list_head device_entry;
        struct kref kref;
-       unsigned long minor;
+       uint8_t elna_cfg;
 
        struct dvb_adapter dvb_adap;
        struct dvb_frontend dvb_fe;
index bdc5a38..5917657 100644 (file)
@@ -265,7 +265,7 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
 
        if (acquire) {
                if (elna_enable)
-                       as10x_cmd_set_context(&dev->bus_adap, 1010, 0xC0);
+                       as10x_cmd_set_context(&dev->bus_adap, CONTEXT_LNA, dev->elna_cfg);
 
                ret = as10x_cmd_turn_on(&dev->bus_adap);
        } else {
@@ -337,7 +337,7 @@ int as102_dvb_register_fe(struct as102_dev_t *as102_dev,
        strncpy(dvb_fe->ops.info.name, as102_dev->name,
                sizeof(dvb_fe->ops.info.name));
 
-       /* register dbvb frontend */
+       /* register dvb frontend */
        errno = dvb_register_frontend(dvb_adap, dvb_fe);
        if (errno == 0)
                dvb_fe->tuner_priv = as102_dev;
@@ -349,7 +349,7 @@ static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps,
                                         struct as10x_tps *as10x_tps)
 {
 
-       /* extract consteallation */
+       /* extract constellation */
        switch (as10x_tps->modulation) {
        case CONST_QPSK:
                fe_tps->modulation = QPSK;
index bd21f05..4bfc684 100644 (file)
@@ -29,7 +29,7 @@ struct as10x_fw_pkt_t {
        union {
                unsigned char request[2];
                unsigned char length[2];
-       } u;
+       } __packed u;
        struct as10x_raw_fw_pkt raw;
 } __packed;
 
index d775be0..0f6bfe7 100644 (file)
@@ -57,6 +57,17 @@ static const char * const as102_device_names[] = {
        NULL /* Terminating entry */
 };
 
+/* eLNA configuration: devices built on the reference design work best
+   with 0xA0, while custom designs seem to require 0xC0 */
+static uint8_t const as102_elna_cfg[] = {
+       0xA0,
+       0xC0,
+       0xC0,
+       0xA0,
+       0xA0,
+       0x00 /* Terminating entry */
+};
+
 struct usb_driver as102_usb_driver = {
        .name           = DRIVER_FULL_NAME,
        .probe          = as102_usb_probe,
@@ -270,6 +281,8 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
                }
 
                urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE);
+               urb->transfer_dma = dev->dma_addr + (i * AS102_USB_BUF_SIZE);
+               urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
                urb->transfer_buffer_length = AS102_USB_BUF_SIZE;
 
                dev->stream_urb[i] = urb;
@@ -369,8 +382,10 @@ static int as102_usb_probe(struct usb_interface *intf,
        /* Assign the user-friendly device name */
        for (i = 0; i < (sizeof(as102_usb_id_table) /
                         sizeof(struct usb_device_id)); i++) {
-               if (id == &as102_usb_id_table[i])
+               if (id == &as102_usb_id_table[i]) {
                        as102_dev->name = as102_device_names[i];
+                       as102_dev->elna_cfg = as102_elna_cfg[i];
+               }
        }
 
        if (as102_dev->name == NULL)
index 4ea249e..e21ec6c 100644 (file)
@@ -99,14 +99,14 @@ union as10x_turn_on {
        struct {
                /* request identifier */
                uint16_t proc_id;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
                uint16_t proc_id;
                /* error */
                uint8_t error;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_turn_off {
@@ -114,14 +114,14 @@ union as10x_turn_off {
        struct {
                /* request identifier */
                uint16_t proc_id;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
                uint16_t proc_id;
                /* error */
                uint8_t err;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_set_tune {
@@ -131,14 +131,14 @@ union as10x_set_tune {
                uint16_t proc_id;
                /* tune params */
                struct as10x_tune_args args;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
                uint16_t proc_id;
                /* response error */
                uint8_t error;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_get_tune_status {
@@ -146,7 +146,7 @@ union as10x_get_tune_status {
        struct {
                /* request identifier */
                uint16_t proc_id;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
@@ -155,7 +155,7 @@ union as10x_get_tune_status {
                uint8_t error;
                /* tune status */
                struct as10x_tune_status sts;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_get_tps {
@@ -163,7 +163,7 @@ union as10x_get_tps {
        struct {
                /* request identifier */
                uint16_t proc_id;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
@@ -172,7 +172,7 @@ union as10x_get_tps {
                uint8_t error;
                /* tps details */
                struct as10x_tps tps;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_common {
@@ -180,14 +180,14 @@ union as10x_common {
        struct {
                /* request identifier */
                uint16_t  proc_id;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
                uint16_t proc_id;
                /* response error */
                uint8_t error;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_add_pid_filter {
@@ -201,7 +201,7 @@ union as10x_add_pid_filter {
                uint8_t stream_type;
                /* PID index in filter table */
                uint8_t idx;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
@@ -210,7 +210,7 @@ union as10x_add_pid_filter {
                uint8_t error;
                /* Filter id */
                uint8_t filter_id;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_del_pid_filter {
@@ -220,14 +220,14 @@ union as10x_del_pid_filter {
                uint16_t  proc_id;
                /* PID to remove */
                uint16_t  pid;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
                uint16_t proc_id;
                /* response error */
                uint8_t error;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_start_streaming {
@@ -235,14 +235,14 @@ union as10x_start_streaming {
        struct {
                /* request identifier */
                uint16_t proc_id;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
                uint16_t proc_id;
                /* error */
                uint8_t error;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_stop_streaming {
@@ -250,14 +250,14 @@ union as10x_stop_streaming {
        struct {
                /* request identifier */
                uint16_t proc_id;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
                uint16_t proc_id;
                /* error */
                uint8_t error;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_get_demod_stats {
@@ -265,7 +265,7 @@ union as10x_get_demod_stats {
        struct {
                /* request identifier */
                uint16_t proc_id;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
@@ -274,7 +274,7 @@ union as10x_get_demod_stats {
                uint8_t error;
                /* demod stats */
                struct as10x_demod_stats stats;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_get_impulse_resp {
@@ -282,7 +282,7 @@ union as10x_get_impulse_resp {
        struct {
                /* request identifier */
                uint16_t proc_id;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
@@ -291,7 +291,7 @@ union as10x_get_impulse_resp {
                uint8_t error;
                /* impulse response ready */
                uint8_t is_ready;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_fw_context {
@@ -305,7 +305,7 @@ union as10x_fw_context {
                uint16_t tag;
                /* context request type */
                uint16_t type;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
@@ -316,7 +316,7 @@ union as10x_fw_context {
                uint16_t type;
                /* error */
                uint8_t error;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_set_register {
@@ -328,14 +328,14 @@ union as10x_set_register {
                struct as10x_register_addr reg_addr;
                /* register content */
                struct as10x_register_value reg_val;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
                uint16_t proc_id;
                /* error */
                uint8_t error;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_get_register {
@@ -345,7 +345,7 @@ union as10x_get_register {
                uint16_t proc_id;
                /* register description */
                struct as10x_register_addr reg_addr;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
@@ -354,7 +354,7 @@ union as10x_get_register {
                uint8_t error;
                /* register content */
                struct as10x_register_value reg_val;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_cfg_change_mode {
@@ -364,14 +364,14 @@ union as10x_cfg_change_mode {
                uint16_t proc_id;
                /* mode */
                uint8_t mode;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
                uint16_t proc_id;
                /* error */
                uint8_t error;
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 struct as10x_cmd_header_t {
@@ -394,7 +394,7 @@ union as10x_dump_memory {
                struct as10x_register_addr reg_addr;
                /* nb blocks to read */
                uint16_t num_blocks;
-       } req;
+       } __packed req;
        /* response */
        struct {
                /* response identifier */
@@ -408,8 +408,8 @@ union as10x_dump_memory {
                        uint8_t  data8[DUMP_BLOCK_SIZE];
                        uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)];
                        uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)];
-               } u;
-       } rsp;
+               } __packed u;
+       } __packed rsp;
 } __packed;
 
 union as10x_dumplog_memory {
@@ -418,7 +418,7 @@ union as10x_dumplog_memory {
                uint16_t proc_id;
                /* dump memory type request */
                uint8_t dump_req;
-       } req;
+       } __packed req;
        struct {
                /* request identifier */
                uint16_t proc_id;
@@ -428,7 +428,7 @@ union as10x_dumplog_memory {
                uint8_t dump_rsp;
                /* dump data */
                uint8_t data[DUMP_BLOCK_SIZE];
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 union as10x_raw_data {
@@ -437,14 +437,14 @@ union as10x_raw_data {
                uint16_t proc_id;
                uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
                             - 2 /* proc_id */];
-       } req;
+       } __packed req;
        /* response */
        struct {
                uint16_t proc_id;
                uint8_t error;
                uint8_t data[64 - sizeof(struct as10x_cmd_header_t)
                             - 2 /* proc_id */ - 1 /* rc */];
-       } rsp;
+       } __packed rsp;
 } __packed;
 
 struct as10x_cmd_t {
@@ -469,7 +469,7 @@ struct as10x_cmd_t {
                union as10x_dump_memory         dump_memory;
                union as10x_dumplog_memory      dumplog_memory;
                union as10x_raw_data            raw_data;
-       } body;
+       } __packed body;
 } __packed;
 
 struct as10x_token_cmd_t {
index fde8140..af26e05 100644 (file)
@@ -181,7 +181,7 @@ struct as10x_register_value {
                uint8_t  value8;   /* 8 bit value */
                uint16_t value16;  /* 16 bit value */
                uint32_t value32;  /* 32 bit value */
-       } u;
+       } __packed u;
 } __packed;
 
 struct as10x_register_addr {
index 3d439b7..d0fe34a 100644 (file)
@@ -2849,13 +2849,11 @@ static const struct v4l2_file_operations v4l2_fops = {
        .poll           = easycap_poll,
        .mmap           = easycap_mmap,
 };
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
+
 /*
- *  WHEN THE EasyCAP IS PHYSICALLY PLUGGED IN, THIS FUNCTION IS CALLED THREE
- *  TIMES, ONCE FOR EACH OF THE THREE INTERFACES.  BEWARE.
+ * When the device is plugged, this function is called three times,
+ * one for each interface.
  */
-/*---------------------------------------------------------------------------*/
 static int easycap_usb_probe(struct usb_interface *intf,
                            const struct usb_device_id *id)
 {
@@ -2884,7 +2882,6 @@ static int easycap_usb_probe(struct usb_interface *intf,
 
        usbdev = interface_to_usbdev(intf);
 
-/*---------------------------------------------------------------------------*/
        alt = usb_altnum_to_altsetting(intf, 0);
        if (!alt) {
                SAY("ERROR: usb_host_interface not found\n");
@@ -2896,11 +2893,8 @@ static int easycap_usb_probe(struct usb_interface *intf,
                SAY("ERROR: intf_descriptor is NULL\n");
                return -EFAULT;
        }
-/*---------------------------------------------------------------------------*/
-/*
- *  GET PROPERTIES OF PROBED INTERFACE
- */
-/*---------------------------------------------------------------------------*/
+
+       /* Get properties of probed interface */
        bInterfaceNumber = interface->bInterfaceNumber;
        bInterfaceClass = interface->bInterfaceClass;
        bInterfaceSubClass = interface->bInterfaceSubClass;
@@ -2912,28 +2906,23 @@ static int easycap_usb_probe(struct usb_interface *intf,
                (long int)(intf->cur_altsetting - intf->altsetting));
        JOT(4, "intf[%i]: bInterfaceClass=0x%02X bInterfaceSubClass=0x%02X\n",
                        bInterfaceNumber, bInterfaceClass, bInterfaceSubClass);
-/*---------------------------------------------------------------------------*/
-/*
- *  A NEW struct easycap IS ALWAYS ALLOCATED WHEN INTERFACE 0 IS PROBED.
- *  IT IS NOT POSSIBLE HERE TO FREE ANY EXISTING struct easycap.  THIS
- *  SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE EasyCAP WAS
- *  PHYSICALLY UNPLUGGED.
- *
- *  THE POINTER peasycap TO THE struct easycap IS REMEMBERED WHEN
- *  INTERFACES 1 AND 2 ARE PROBED.
-*/
-/*---------------------------------------------------------------------------*/
+
+       /*
+        * A new struct easycap is always allocated when interface 0 is probed.
+        * It is not possible here to free any existing struct easycap.
+        * This should have been done by easycap_delete() when the device was
+        * physically unplugged.
+        * The allocated struct easycap is saved for later usage when
+        * interfaces 1 and 2 are probed.
+        */
        if (0 == bInterfaceNumber) {
                peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
                if (!peasycap) {
                        SAY("ERROR: Could not allocate peasycap\n");
                        return -ENOMEM;
                }
-/*---------------------------------------------------------------------------*/
-/*
- *  PERFORM URGENT INTIALIZATIONS ...
-*/
-/*---------------------------------------------------------------------------*/
+
+               /* Perform urgent initializations */
                peasycap->minor = -1;
                kref_init(&peasycap->kref);
                JOM(8, "intf[%i]: after kref_init(..._video) "
@@ -2976,11 +2965,7 @@ static int easycap_usb_probe(struct usb_interface *intf,
 
                peasycap->allocation_video_struct = sizeof(struct easycap);
 
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND FURTHER INITIALIZE THE STRUCTURE
-*/
-/*---------------------------------------------------------------------------*/
+               /* and further initialize the structure */
                peasycap->pusb_device = usbdev;
                peasycap->pusb_interface = intf;
 
@@ -3002,11 +2987,7 @@ static int easycap_usb_probe(struct usb_interface *intf,
 
                peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
 
-/*---------------------------------------------------------------------------*/
-/*
- *  DYNAMICALLY FILL IN THE AVAILABLE FORMATS ...
- */
-/*---------------------------------------------------------------------------*/
+               /* Dynamically fill in the available formats */
                rc = easycap_video_fillin_formats();
                if (0 > rc) {
                        SAM("ERROR: fillin_formats() rc = %i\n", rc);
@@ -3014,10 +2995,8 @@ static int easycap_usb_probe(struct usb_interface *intf,
                }
                JOM(4, "%i formats available\n", rc);
 
-               /*  ... AND POPULATE easycap.inputset[] */
-
+               /* Populate easycap.inputset[] */
                inputset = peasycap->inputset;
-
                fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
                m = 0;
                mask = 0;
@@ -3030,7 +3009,6 @@ static int easycap_usb_probe(struct usb_interface *intf,
                                mask = easycap_standard[i].mask;
                        }
                }
-
                if (1 != m) {
                        SAM("ERROR: "
                            "inputset->standard_offset unpopulated, %i=m\n", m);
@@ -3089,14 +3067,13 @@ static int easycap_usb_probe(struct usb_interface *intf,
                JOM(4, "populated inputset[]\n");
                JOM(4, "finished initialization\n");
        } else {
-/*---------------------------------------------------------------------------*/
-/*
- *                                 FIXME
- *
- *  IDENTIFY THE APPROPRIATE POINTER peasycap FOR INTERFACES 1 AND 2.
- *  THE ADDRESS OF peasycap->pusb_device IS RELUCTANTLY USED FOR THIS PURPOSE.
- */
-/*---------------------------------------------------------------------------*/
+
+               /*
+                * FIXME: Identify the appropriate pointer
+                * peasycap for interfaces 1 and 2.
+                * The address of peasycap->pusb_device
+                * is reluctantly used for this purpose.
+                */
                for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
                        if (usbdev == easycapdc60_dongle[ndong].peasycap->
                                                                        pusb_device) {
@@ -3117,7 +3094,7 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        return -ENODEV;
                }
        }
-/*---------------------------------------------------------------------------*/
+
        if ((USB_CLASS_VIDEO == bInterfaceClass) ||
            (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
                if (-1 == peasycap->video_interface) {
@@ -3149,14 +3126,12 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        }
                }
        }
-/*---------------------------------------------------------------------------*/
-/*
- *  INVESTIGATE ALL ALTSETTINGS.
- *  DONE IN DETAIL BECAUSE USB DEVICE 05e1:0408 HAS DISPARATE INCARNATIONS.
- */
-/*---------------------------------------------------------------------------*/
-       isokalt = 0;
 
+       /*
+        * Investigate all altsettings. This is done in detail
+        * because USB device 05e1:0408 has disparate incarnations.
+        */
+       isokalt = 0;
        for (i = 0; i < intf->num_altsetting; i++) {
                alt = usb_altnum_to_altsetting(intf, i);
                if (!alt) {
@@ -3172,7 +3147,6 @@ static int easycap_usb_probe(struct usb_interface *intf,
                if (0 == interface->bNumEndpoints)
                        JOM(4, "intf[%i]alt[%i] has no endpoints\n",
                                                bInterfaceNumber, i);
-/*---------------------------------------------------------------------------*/
                for (j = 0; j < interface->bNumEndpoints; j++) {
                        ep = &alt->endpoint[j].desc;
                        if (!ep) {
@@ -3312,19 +3286,12 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        }
                }
        }
-/*---------------------------------------------------------------------------*/
-/*
- *  PERFORM INITIALIZATION OF THE PROBED INTERFACE
- */
-/*---------------------------------------------------------------------------*/
+
+       /* Perform initialization of the probed interface */
        JOM(4, "initialization begins for interface %i\n",
                interface->bInterfaceNumber);
        switch (bInterfaceNumber) {
-/*---------------------------------------------------------------------------*/
-/*
- *  INTERFACE 0 IS THE VIDEO INTERFACE
- */
-/*---------------------------------------------------------------------------*/
+       /* 0: Video interface */
        case 0: {
                if (!peasycap) {
                        SAM("MISTAKE: peasycap is NULL\n");
@@ -3337,11 +3304,8 @@ static int easycap_usb_probe(struct usb_interface *intf,
                peasycap->video_altsetting_on = okalt[isokalt - 1];
                JOM(4, "%i=video_altsetting_on <====\n",
                                        peasycap->video_altsetting_on);
-/*---------------------------------------------------------------------------*/
-/*
- *  DECIDE THE VIDEO STREAMING PARAMETERS
- */
-/*---------------------------------------------------------------------------*/
+
+               /* Decide video streaming parameters */
                peasycap->video_endpointnumber = okepn[isokalt - 1];
                JOM(4, "%i=video_endpointnumber\n", peasycap->video_endpointnumber);
                maxpacketsize = okmps[isokalt - 1];
@@ -3373,7 +3337,6 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        SAM("MISTAKE: peasycap->video_isoc_buffer_size too big\n");
                        return -EFAULT;
                }
-/*---------------------------------------------------------------------------*/
                if (-1 == peasycap->video_interface) {
                        SAM("MISTAKE:  video_interface is unset\n");
                        return -EFAULT;
@@ -3398,14 +3361,13 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        SAM("MISTAKE:  video_isoc_buffer_size is unset\n");
                        return -EFAULT;
                }
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE MEMORY FOR VIDEO BUFFERS.  LISTS MUST BE INITIALIZED FIRST.
- */
-/*---------------------------------------------------------------------------*/
+
+               /*
+                * Allocate memory for video buffers.
+                * Lists must be initialized first.
+                */
                INIT_LIST_HEAD(&(peasycap->urb_video_head));
                peasycap->purb_video_head = &(peasycap->urb_video_head);
-/*---------------------------------------------------------------------------*/
                JOM(4, "allocating %i frame buffers of size %li\n",
                                FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
                JOM(4, ".... each scattered over %li pages\n",
@@ -3436,7 +3398,6 @@ static int easycap_usb_probe(struct usb_interface *intf,
                peasycap->frame_read = 0;
                JOM(4, "allocation of frame buffers done:  %i pages\n", k *
                                                                        m);
-/*---------------------------------------------------------------------------*/
                JOM(4, "allocating %i field buffers of size %li\n",
                                FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
                JOM(4, ".... each scattered over %li pages\n",
@@ -3468,7 +3429,6 @@ static int easycap_usb_probe(struct usb_interface *intf,
                peasycap->field_read = 0;
                JOM(4, "allocation of field buffers done:  %i pages\n", k *
                                                                        m);
-/*---------------------------------------------------------------------------*/
                JOM(4, "allocating %i isoc video buffers of size %i\n",
                                                VIDEO_ISOC_BUFFER_MANY,
                                                peasycap->video_isoc_buffer_size);
@@ -3492,11 +3452,8 @@ static int easycap_usb_probe(struct usb_interface *intf,
                }
                JOM(4, "allocation of isoc video buffers done: %i pages\n",
                                                k * (0x01 << VIDEO_ISOC_ORDER));
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
- */
-/*---------------------------------------------------------------------------*/
+
+               /* Allocate and initialize multiple struct usb */
                JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
                JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
                                                peasycap->video_isoc_framesperdesc);
@@ -3515,7 +3472,6 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        }
 
                        peasycap->allocation_video_urb += 1;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
                        pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
                        if (!pdata_urb) {
                                SAM("ERROR: Could not allocate struct data_urb.\n");
@@ -3530,11 +3486,8 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        pdata_urb->length = 0;
                        list_add_tail(&(pdata_urb->list_head),
                                                        peasycap->purb_video_head);
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND INITIALIZE THEM
- */
-/*---------------------------------------------------------------------------*/
+
+                       /* Initialize allocated urbs */
                        if (!k) {
                                JOM(4, "initializing video urbs thus:\n");
                                JOM(4, "  purb->interval = 1;\n");
@@ -3582,20 +3535,16 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        }
                }
                JOM(4, "allocation of %i struct urb done.\n", k);
-/*--------------------------------------------------------------------------*/
-/*
- *  SAVE POINTER peasycap IN THIS INTERFACE.
- */
-/*--------------------------------------------------------------------------*/
+
+               /* Save pointer peasycap in this interface */
                usb_set_intfdata(intf, peasycap);
-/*---------------------------------------------------------------------------*/
-/*
- *  IT IS ESSENTIAL TO INITIALIZE THE HARDWARE BEFORE, RATHER THAN AFTER,
- *  THE DEVICE IS REGISTERED, BECAUSE SOME VERSIONS OF THE videodev MODULE
- *  CALL easycap_open() IMMEDIATELY AFTER REGISTRATION, CAUSING A CLASH.
- *  BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
+
+               /*
+                * It is essential to initialize the hardware before,
+                * rather than after, the device is registered,
+                * because some udev rules triggers easycap_open()
+                * immediately after registration, causing a clash.
+                */
                peasycap->ntsc = easycap_ntsc;
                JOM(8, "defaulting initially to %s\n",
                        easycap_ntsc ? "NTSC" : "PAL");
@@ -3604,27 +3553,20 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        SAM("ERROR: reset() rc = %i\n", rc);
                        return -EFAULT;
                }
-/*--------------------------------------------------------------------------*/
-/*
- *  THE VIDEO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
- */
-/*--------------------------------------------------------------------------*/
+
+               /* The video device can now be registered */
                if (v4l2_device_register(&intf->dev, &peasycap->v4l2_device)) {
                        SAM("v4l2_device_register() failed\n");
                        return -ENODEV;
                }
                JOM(4, "registered device instance: %s\n",
                        peasycap->v4l2_device.name);
-/*---------------------------------------------------------------------------*/
-/*
- *                                 FIXME
- *
- *
- *  THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
-*/
-/*---------------------------------------------------------------------------*/
+
+               /*
+                * FIXME: This is believed to be harmless,
+                * but may well be unnecessary or wrong.
+                */
                peasycap->video_device.v4l2_dev = NULL;
-/*---------------------------------------------------------------------------*/
 
 
                strcpy(&peasycap->video_device.name[0], "easycapdc60");
@@ -3648,28 +3590,19 @@ static int easycap_usb_probe(struct usb_interface *intf,
 
                break;
        }
-/*--------------------------------------------------------------------------*/
-/*
- *  INTERFACE 1 IS THE AUDIO CONTROL INTERFACE
- *  INTERFACE 2 IS THE AUDIO STREAMING INTERFACE
- */
-/*--------------------------------------------------------------------------*/
+       /* 1: Audio control */
        case 1: {
                if (!peasycap) {
                        SAM("MISTAKE: peasycap is NULL\n");
                        return -EFAULT;
                }
-/*--------------------------------------------------------------------------*/
-/*
- *  SAVE POINTER peasycap IN INTERFACE 1
- */
-/*--------------------------------------------------------------------------*/
+               /* Save pointer peasycap in this interface */
                usb_set_intfdata(intf, peasycap);
                JOM(4, "no initialization required for interface %i\n",
                                        interface->bInterfaceNumber);
                break;
        }
-/*--------------------------------------------------------------------------*/
+       /* 2: Audio streaming */
        case 2: {
                if (!peasycap) {
                        SAM("MISTAKE: peasycap is NULL\n");
@@ -3769,15 +3702,14 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        SAM("MISTAKE:  audio_isoc_buffer_size is unset\n");
                        return -EFAULT;
                }
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE MEMORY FOR AUDIO BUFFERS.  LISTS MUST BE INITIALIZED FIRST.
- */
-/*---------------------------------------------------------------------------*/
+
+               /*
+                * Allocate memory for audio buffers.
+                * Lists must be initialized first.
+                */
                INIT_LIST_HEAD(&(peasycap->urb_audio_head));
                peasycap->purb_audio_head = &(peasycap->urb_audio_head);
 
-/*---------------------------------------------------------------------------*/
                JOM(4, "allocating %i isoc audio buffers of size %i\n",
                        AUDIO_ISOC_BUFFER_MANY,
                        peasycap->audio_isoc_buffer_size);
@@ -3800,11 +3732,8 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        peasycap->audio_isoc_buffer[k].kount = k;
                }
                JOM(4, "allocation of isoc audio buffers done.\n");
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
- */
-/*---------------------------------------------------------------------------*/
+
+               /* Allocate and initialize urbs */
                JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
                JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
                                        peasycap->audio_isoc_framesperdesc);
@@ -3822,7 +3751,6 @@ static int easycap_usb_probe(struct usb_interface *intf,
                                return -ENOMEM;
                        }
                        peasycap->allocation_audio_urb += 1 ;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
                        pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
                        if (!pdata_urb) {
                                usb_free_urb(purb);
@@ -3837,11 +3765,7 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        pdata_urb->length = 0;
                        list_add_tail(&(pdata_urb->list_head),
                                                        peasycap->purb_audio_head);
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND INITIALIZE THEM
- */
-/*---------------------------------------------------------------------------*/
+
                        if (!k) {
                                JOM(4, "initializing audio urbs thus:\n");
                                JOM(4, "  purb->interval = 1;\n");
@@ -3889,17 +3813,11 @@ static int easycap_usb_probe(struct usb_interface *intf,
                        }
                }
                JOM(4, "allocation of %i struct urb done.\n", k);
-/*---------------------------------------------------------------------------*/
-/*
- *  SAVE POINTER peasycap IN THIS INTERFACE.
- */
-/*---------------------------------------------------------------------------*/
+
+               /* Save pointer peasycap in this interface */
                usb_set_intfdata(intf, peasycap);
-/*---------------------------------------------------------------------------*/
-/*
- *  THE AUDIO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
- */
-/*---------------------------------------------------------------------------*/
+
+               /* The audio device can now be registered */
                JOM(4, "initializing ALSA card\n");
 
                rc = easycap_alsa_probe(peasycap);
@@ -3915,11 +3833,7 @@ static int easycap_usb_probe(struct usb_interface *intf,
                peasycap->registered_audio++;
                break;
        }
-/*---------------------------------------------------------------------------*/
-/*
- *  INTERFACES OTHER THAN 0, 1 AND 2 ARE UNEXPECTED
- */
-/*---------------------------------------------------------------------------*/
+       /* Interfaces other than 0,1,2 are unexpected */
        default:
                JOM(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
                return -EINVAL;
index c8c96e2..3ef4cd8 100644 (file)
@@ -1049,15 +1049,15 @@ static int vidioc_s_parm(struct file *filp, void *priv,
        return 0;
 }
 
-/* VIDIOC_ENUMSTD on go7007 were used for enumberating the supported fps and
+/* VIDIOC_ENUMSTD on go7007 were used for enumerating the supported fps and
    its resolution, when the device is not connected to TV.
-   This were an API abuse, probably used by the lack of specific IOCTL's to
-   enumberate it, by the time the driver were written.
+   This is were an API abuse, probably used by the lack of specific IOCTL's to
+   enumerate it, by the time the driver was written.
 
    However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS
    and VIDIOC_ENUM_FRAMESIZES) were added for this purpose.
 
-   The two functions bellow implements the newer ioctls
+   The two functions below implement the newer ioctls
 */
 static int vidioc_enum_framesizes(struct file *filp, void *priv,
                                  struct v4l2_frmsizeenum *fsize)
index e7736a9..014d384 100644 (file)
@@ -192,6 +192,7 @@ static int write_reg_fp(struct i2c_client *client, u16 addr, u16 val)
 {
        struct go7007 *go = i2c_get_adapdata(client->adapter);
        struct go7007_usb *usb;
+       int rc;
        u8 *buf;
        struct s2250 *dec = i2c_get_clientdata(client);
 
@@ -216,12 +217,13 @@ static int write_reg_fp(struct i2c_client *client, u16 addr, u16 val)
                kfree(buf);
                return -EINTR;
        }
-       if (go7007_usb_vendor_request(go, 0x57, addr, val, buf, 16, 1) < 0) {
+       rc = go7007_usb_vendor_request(go, 0x57, addr, val, buf, 16, 1);
+       mutex_unlock(&usb->i2c_lock);
+       if (rc < 0) {
                kfree(buf);
-               return -EFAULT;
+               return rc;
        }
 
-       mutex_unlock(&usb->i2c_lock);
        if (buf[0] == 0) {
                unsigned int subaddr, val_read;
 
@@ -254,6 +256,7 @@ static int read_reg_fp(struct i2c_client *client, u16 addr, u16 *val)
 {
        struct go7007 *go = i2c_get_adapdata(client->adapter);
        struct go7007_usb *usb;
+       int rc;
        u8 *buf;
 
        if (go == NULL)
@@ -276,11 +279,12 @@ static int read_reg_fp(struct i2c_client *client, u16 addr, u16 *val)
                kfree(buf);
                return -EINTR;
        }
-       if (go7007_usb_vendor_request(go, 0x58, addr, 0, buf, 16, 1) < 0) {
+       rc = go7007_usb_vendor_request(go, 0x58, addr, 0, buf, 16, 1);
+       mutex_unlock(&usb->i2c_lock);
+       if (rc < 0) {
                kfree(buf);
-               return -EFAULT;
+               return rc;
        }
-       mutex_unlock(&usb->i2c_lock);
 
        *val = (buf[0] << 8) | buf[1];
        kfree(buf);
index 18a798c..3295ea6 100644 (file)
@@ -1281,7 +1281,7 @@ MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O"
 /*
  * some architectures (e.g. intel xscale) align the 8bit serial registers
  * on 32bit word boundaries.
- * See linux-kernel/serial/8250.c serial_in()/out()
+ * See linux-kernel/drivers/tty/serial/8250/8250.c serial_in()/out()
  */
 module_param(ioshift, int, S_IRUGO);
 MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)");
index 03dcac4..63352de 100644 (file)
@@ -5,4 +5,4 @@ config SOLO6X10
        select SND_PCM
        ---help---
          This driver supports the Softlogic based MPEG-4 and h.264 codec
-         codec cards.
+         cards.
index f974f64..d2fd842 100644 (file)
@@ -195,28 +195,28 @@ static int __devinit solo_pci_probe(struct pci_dev *pdev,
                        SOLO6010_SYS_CFG_OUTDIV(3);
        solo_reg_write(solo_dev, SOLO_SYS_CFG, reg);
 
-        if (solo_dev->flags & FLAGS_6110) {
-                u32 sys_clock_MHz = SOLO_CLOCK_MHZ;
-                u32 pll_DIVQ;
-                u32 pll_DIVF;
-
-                if (sys_clock_MHz < 125) {
-                        pll_DIVQ = 3;
-                        pll_DIVF = (sys_clock_MHz * 4) / 3;
-                } else {
-                        pll_DIVQ = 2;
-                        pll_DIVF = (sys_clock_MHz * 2) / 3;
-                }
-
-                solo_reg_write(solo_dev, SOLO6110_PLL_CONFIG,
+       if (solo_dev->flags & FLAGS_6110) {
+               u32 sys_clock_MHz = SOLO_CLOCK_MHZ;
+               u32 pll_DIVQ;
+               u32 pll_DIVF;
+
+               if (sys_clock_MHz < 125) {
+                       pll_DIVQ = 3;
+                       pll_DIVF = (sys_clock_MHz * 4) / 3;
+               } else {
+                       pll_DIVQ = 2;
+                       pll_DIVF = (sys_clock_MHz * 2) / 3;
+               }
+
+               solo_reg_write(solo_dev, SOLO6110_PLL_CONFIG,
                               SOLO6110_PLL_RANGE_5_10MHZ |
                               SOLO6110_PLL_DIVR(9) |
                               SOLO6110_PLL_DIVQ_EXP(pll_DIVQ) |
                               SOLO6110_PLL_DIVF(pll_DIVF) | SOLO6110_PLL_FSEN);
-               mdelay(1);      // PLL Locking time (1ms)
+               mdelay(1);      /* PLL Locking time (1ms) */
 
                solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 3 << 8); /* ? */
-        } else
+       } else
                solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 1 << 8); /* ? */
 
        solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1);
index a6910da..cf4c29d 100644 (file)
@@ -323,6 +323,7 @@ static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int t
        mutex_lock(&dev->device_lock);
 
        dev->wd_timeout = timeout;
+       wd_dev->timeout = timeout;
        mei_wd_set_start_timeout(dev, dev->wd_timeout);
 
        mutex_unlock(&dev->device_lock);
index e4ade55..4fe52f6 100644 (file)
@@ -4159,7 +4159,7 @@ void GPIOChangeRFWorkItemCallBack(struct work_struct *work)
                argv[0] = RadioPowerPath;
                argv[2] = NULL;
 
-               call_usermodehelper(RadioPowerPath, argv, envp, 1);
+               call_usermodehelper(RadioPowerPath, argv, envp, UMH_WAIT_PROC);
        }
 }
 
index a7fa9aa..f026b71 100644 (file)
@@ -208,7 +208,7 @@ static void dm_check_ac_dc_power(struct net_device *dev)
 
        if (priv->rtllib->state != RTLLIB_LINKED)
                return;
-       call_usermodehelper(ac_dc_check_script_path, argv, envp, 1);
+       call_usermodehelper(ac_dc_check_script_path, argv, envp, UMH_WAIT_PROC);
 
        return;
 };
@@ -2296,7 +2296,7 @@ void dm_CheckRfCtrlGPIO(void *data)
 
                argv[0] = RadioPowerPath;
                argv[2] = NULL;
-               call_usermodehelper(RadioPowerPath, argv, envp, 1);
+               call_usermodehelper(RadioPowerPath, argv, envp, UMH_WAIT_PROC);
        }
 }
 
index 176f469..e4c0335 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the RMI4 touchscreen driver.
 #
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o
-obj-$(CONFIG_MACH_U8500) += board-mop500-u8500uib-rmi4.o
+obj-$(CONFIG_MACH_MOP500) += board-mop500-u8500uib-rmi4.o
index d5f923b..f960279 100644 (file)
@@ -5927,7 +5927,8 @@ static void add_caps(IXJ *j)
        j->caplist[j->caps].cap = PHONE_VENDOR_QUICKNET;
        strcpy(j->caplist[j->caps].desc, "Quicknet Technologies, Inc. (www.quicknet.net)");
        j->caplist[j->caps].captype = vendor;
-       j->caplist[j->caps].handle = j->caps++;
+       j->caplist[j->caps].handle = j->caps;
+       j->caps++;
        j->caplist[j->caps].captype = device;
        switch (j->cardtype) {
        case QTI_PHONEJACK:
@@ -5947,11 +5948,13 @@ static void add_caps(IXJ *j)
                break;
        }
        j->caplist[j->caps].cap = j->cardtype;
-       j->caplist[j->caps].handle = j->caps++;
+       j->caplist[j->caps].handle = j->caps;
+       j->caps++;
        strcpy(j->caplist[j->caps].desc, "POTS");
        j->caplist[j->caps].captype = port;
        j->caplist[j->caps].cap = pots;
-       j->caplist[j->caps].handle = j->caps++;
+       j->caplist[j->caps].handle = j->caps;
+       j->caps++;
 
        /* add devices that can do speaker/mic */
        switch (j->cardtype) {
@@ -5962,7 +5965,8 @@ static void add_caps(IXJ *j)
                strcpy(j->caplist[j->caps].desc, "SPEAKER");
                j->caplist[j->caps].captype = port;
                j->caplist[j->caps].cap = speaker;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
         default:
                break;
        }
@@ -5973,7 +5977,8 @@ static void add_caps(IXJ *j)
                strcpy(j->caplist[j->caps].desc, "HANDSET");
                j->caplist[j->caps].captype = port;
                j->caplist[j->caps].cap = handset;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
                break;
         default:
                break;
@@ -5985,7 +5990,8 @@ static void add_caps(IXJ *j)
                strcpy(j->caplist[j->caps].desc, "PSTN");
                j->caplist[j->caps].captype = port;
                j->caplist[j->caps].cap = pstn;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
                break;
         default:
                break;
@@ -5995,50 +6001,59 @@ static void add_caps(IXJ *j)
        strcpy(j->caplist[j->caps].desc, "ULAW");
        j->caplist[j->caps].captype = codec;
        j->caplist[j->caps].cap = ULAW;
-       j->caplist[j->caps].handle = j->caps++;
+       j->caplist[j->caps].handle = j->caps;
+       j->caps++;
 
        strcpy(j->caplist[j->caps].desc, "LINEAR 16 bit");
        j->caplist[j->caps].captype = codec;
        j->caplist[j->caps].cap = LINEAR16;
-       j->caplist[j->caps].handle = j->caps++;
+       j->caplist[j->caps].handle = j->caps;
+       j->caps++;
 
        strcpy(j->caplist[j->caps].desc, "LINEAR 8 bit");
        j->caplist[j->caps].captype = codec;
        j->caplist[j->caps].cap = LINEAR8;
-       j->caplist[j->caps].handle = j->caps++;
+       j->caplist[j->caps].handle = j->caps;
+       j->caps++;
 
        strcpy(j->caplist[j->caps].desc, "Windows Sound System");
        j->caplist[j->caps].captype = codec;
        j->caplist[j->caps].cap = WSS;
-       j->caplist[j->caps].handle = j->caps++;
+       j->caplist[j->caps].handle = j->caps;
+       j->caps++;
 
        /* software ALAW codec, made from ULAW */
        strcpy(j->caplist[j->caps].desc, "ALAW");
        j->caplist[j->caps].captype = codec;
        j->caplist[j->caps].cap = ALAW;
-       j->caplist[j->caps].handle = j->caps++;
+       j->caplist[j->caps].handle = j->caps;
+       j->caps++;
 
        /* version 12 of the 8020 does the following codecs in a broken way */
        if (j->dsp.low != 0x20 || j->ver.low != 0x12) {
                strcpy(j->caplist[j->caps].desc, "G.723.1 6.3kbps");
                j->caplist[j->caps].captype = codec;
                j->caplist[j->caps].cap = G723_63;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
 
                strcpy(j->caplist[j->caps].desc, "G.723.1 5.3kbps");
                j->caplist[j->caps].captype = codec;
                j->caplist[j->caps].cap = G723_53;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
 
                strcpy(j->caplist[j->caps].desc, "TrueSpeech 4.8kbps");
                j->caplist[j->caps].captype = codec;
                j->caplist[j->caps].cap = TS48;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
 
                strcpy(j->caplist[j->caps].desc, "TrueSpeech 4.1kbps");
                j->caplist[j->caps].captype = codec;
                j->caplist[j->caps].cap = TS41;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
        }
 
        /* 8020 chips can do TS8.5 native, and 8021/8022 can load it */
@@ -6046,7 +6061,8 @@ static void add_caps(IXJ *j)
                strcpy(j->caplist[j->caps].desc, "TrueSpeech 8.5kbps");
                j->caplist[j->caps].captype = codec;
                j->caplist[j->caps].cap = TS85;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
        }
 
        /* 8021 chips can do G728 */
@@ -6054,7 +6070,8 @@ static void add_caps(IXJ *j)
                strcpy(j->caplist[j->caps].desc, "G.728 16kbps");
                j->caplist[j->caps].captype = codec;
                j->caplist[j->caps].cap = G728;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
        }
 
        /* 8021/8022 chips can do G729 if loaded */
@@ -6062,13 +6079,15 @@ static void add_caps(IXJ *j)
                strcpy(j->caplist[j->caps].desc, "G.729A 8kbps");
                j->caplist[j->caps].captype = codec;
                j->caplist[j->caps].cap = G729;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
        }
        if (j->dsp.low != 0x20 && j->flags.g729_loaded) {
                strcpy(j->caplist[j->caps].desc, "G.729B 8kbps");
                j->caplist[j->caps].captype = codec;
                j->caplist[j->caps].cap = G729B;
-               j->caplist[j->caps].handle = j->caps++;
+               j->caplist[j->caps].handle = j->caps;
+               j->caps++;
        }
 }
 
index b008773..5957c3a 100644 (file)
@@ -91,6 +91,7 @@
 #include "hcf.h"                // HCF and MSF common include file
 #include "hcfdef.h"             // HCF specific include file
 #include "mmd.h"                // MoreModularDriver common include file
+#include <linux/bug.h>
 #include <linux/kernel.h>
 
 #if ! defined offsetof
index 3a0d53d..ee30779 100644 (file)
@@ -310,11 +310,8 @@ static int __devexit hvc_vio_remove(struct vio_dev *vdev)
 static struct vio_driver hvc_vio_driver = {
        .id_table       = hvc_driver_table,
        .probe          = hvc_vio_probe,
-       .remove         = __devexit_p(hvc_vio_remove),
-       .driver         = {
-               .name   = hvc_driver_name,
-               .owner  = THIS_MODULE,
-       }
+       .remove         = hvc_vio_remove,
+       .name           = hvc_driver_name,
 };
 
 static int __init hvc_vio_init(void)
index d237591..3436436 100644 (file)
@@ -879,10 +879,7 @@ static struct vio_driver hvcs_vio_driver = {
        .id_table       = hvcs_driver_table,
        .probe          = hvcs_probe,
        .remove         = __devexit_p(hvcs_remove),
-       .driver         = {
-               .name   = hvcs_driver_name,
-               .owner  = THIS_MODULE,
-       }
+       .name           = hvcs_driver_name,
 };
 
 /* Only called from hvcs_get_pi please */
index 10605ec..f9a6be7 100644 (file)
@@ -1526,6 +1526,8 @@ void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
        atmel_pops.set_wake     = fns->set_wake;
 }
 
+struct platform_device *atmel_default_console_device;  /* the serial console device */
+
 #ifdef CONFIG_SERIAL_ATMEL_CONSOLE
 static void atmel_console_putchar(struct uart_port *port, int ch)
 {
index 0b7fed7..e7fecee 100644 (file)
@@ -1508,7 +1508,7 @@ static int serial_imx_probe(struct platform_device *pdev)
                ret = PTR_ERR(sport->clk);
                goto unmap;
        }
-       clk_enable(sport->clk);
+       clk_prepare_enable(sport->clk);
 
        sport->port.uartclk = clk_get_rate(sport->clk);
 
@@ -1531,8 +1531,8 @@ deinit:
        if (pdata && pdata->exit)
                pdata->exit(pdev);
 clkput:
+       clk_disable_unprepare(sport->clk);
        clk_put(sport->clk);
-       clk_disable(sport->clk);
 unmap:
        iounmap(sport->port.membase);
 free:
@@ -1552,11 +1552,10 @@ static int serial_imx_remove(struct platform_device *pdev)
 
        if (sport) {
                uart_remove_one_port(&imx_reg, &sport->port);
+               clk_disable_unprepare(sport->clk);
                clk_put(sport->clk);
        }
 
-       clk_disable(sport->clk);
-
        if (pdata && pdata->exit)
                pdata->exit(pdev);
 
index e2fd3d8..5847a4b 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/circ_buf.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -44,6 +45,8 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 
+#define PXA_NAME_LEN           8
+
 struct uart_pxa_port {
        struct uart_port        port;
        unsigned char           ier;
@@ -51,7 +54,7 @@ struct uart_pxa_port {
        unsigned char           mcr;
        unsigned int            lsr_break_flag;
        struct clk              *clk;
-       char                    *name;
+       char                    name[PXA_NAME_LEN];
 };
 
 static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
@@ -781,6 +784,31 @@ static const struct dev_pm_ops serial_pxa_pm_ops = {
 };
 #endif
 
+static struct of_device_id serial_pxa_dt_ids[] = {
+       { .compatible = "mrvl,pxa-uart", },
+       { .compatible = "mrvl,mmp-uart", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids);
+
+static int serial_pxa_probe_dt(struct platform_device *pdev,
+                              struct uart_pxa_port *sport)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int ret;
+
+       if (!np)
+               return 1;
+
+       ret = of_alias_get_id(np, "serial");
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+               return ret;
+       }
+       sport->port.line = ret;
+       return 0;
+}
+
 static int serial_pxa_probe(struct platform_device *dev)
 {
        struct uart_pxa_port *sport;
@@ -808,20 +836,16 @@ static int serial_pxa_probe(struct platform_device *dev)
        sport->port.irq = irqres->start;
        sport->port.fifosize = 64;
        sport->port.ops = &serial_pxa_pops;
-       sport->port.line = dev->id;
        sport->port.dev = &dev->dev;
        sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
        sport->port.uartclk = clk_get_rate(sport->clk);
 
-       switch (dev->id) {
-       case 0: sport->name = "FFUART"; break;
-       case 1: sport->name = "BTUART"; break;
-       case 2: sport->name = "STUART"; break;
-       case 3: sport->name = "HWUART"; break;
-       default:
-               sport->name = "???";
-               break;
-       }
+       ret = serial_pxa_probe_dt(dev, sport);
+       if (ret > 0)
+               sport->port.line = dev->id;
+       else if (ret < 0)
+               goto err_clk;
+       snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
 
        sport->port.membase = ioremap(mmres->start, resource_size(mmres));
        if (!sport->port.membase) {
@@ -829,7 +853,7 @@ static int serial_pxa_probe(struct platform_device *dev)
                goto err_clk;
        }
 
-       serial_pxa_ports[dev->id] = sport;
+       serial_pxa_ports[sport->port.line] = sport;
 
        uart_add_one_port(&serial_pxa_reg, &sport->port);
        platform_set_drvdata(dev, sport);
@@ -866,6 +890,7 @@ static struct platform_driver serial_pxa_driver = {
 #ifdef CONFIG_PM
                .pm     = &serial_pxa_pm_ops,
 #endif
+               .of_match_table = serial_pxa_dt_ids,
        },
 };
 
index ef7a21a..2ca5959 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 #include <asm/mach/serial_sa1100.h>
 
 /* We've been assigned a range on the "Low-density serial ports" major */
index 4e1b551..1c6de9f 100644 (file)
@@ -743,6 +743,7 @@ static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
                        spin_lock_irqsave(&port->sc_port.lock, flags);
                        port->sc_port.irq = SGI_UART_VECTOR;
                        port->sc_ops = &intr_ops;
+                       irq_set_handler(port->sc_port.irq, handle_level_irq);
 
                        /* turn on receive interrupts */
                        ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
index e4405e0..cbd8f5f 100644 (file)
@@ -16,7 +16,7 @@ config USB_ARCH_HAS_OHCI
        # ARM:
        default y if SA1111
        default y if ARCH_OMAP
-       default y if ARCH_S3C2410
+       default y if ARCH_S3C24XX
        default y if PXA27x
        default y if PXA3xx
        default y if ARCH_EP93XX
@@ -44,7 +44,7 @@ config USB_ARCH_HAS_EHCI
        default y if PPC_MPC512x
        default y if ARCH_IXP4XX
        default y if ARCH_W90X900
-       default y if ARCH_AT91SAM9G45
+       default y if ARCH_AT91
        default y if ARCH_MXC
        default y if ARCH_OMAP3
        default y if ARCH_CNS3XXX
index c14a397..2633f75 100644 (file)
@@ -137,7 +137,7 @@ choice
 
 config USB_AT91
        tristate "Atmel AT91 USB Device Port"
-       depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45
+       depends on ARCH_AT91
        help
           Many Atmel AT91 processors (such as the AT91RM2000) have a
           full speed USB Device Port with support for five configurable
@@ -150,7 +150,7 @@ config USB_AT91
 config USB_ATMEL_USBA
        tristate "Atmel USBA"
        select USB_GADGET_DUALSPEED
-       depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+       depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
        help
          USBA is the integrated high-speed USB Device controller on
          the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
@@ -284,7 +284,7 @@ config USB_IMX
 
 config USB_S3C2410
        tristate "S3C2410 USB Device Controller"
-       depends on ARCH_S3C2410
+       depends on ARCH_S3C24XX
        help
          Samsung's S3C2410 is an ARM-4 processor with an integrated
          full speed USB 1.1 device controller.  It has 4 configurable
@@ -299,7 +299,7 @@ config USB_S3C2410_DEBUG
 
 config USB_S3C_HSUDC
        tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller"
-       depends on ARCH_S3C2410
+       depends on ARCH_S3C24XX
        select USB_GADGET_DUALSPEED
        help
          Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC
index d03ab95..0c935d7 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include <asm/byteorder.h>
 #include <mach/hardware.h>
@@ -39,6 +41,7 @@
 #include <mach/board.h>
 #include <mach/cpu.h>
 #include <mach/at91sam9261_matrix.h>
+#include <mach/at91_matrix.h>
 
 #include "at91_udc.h"
 
@@ -909,9 +912,9 @@ static void pullup(struct at91_udc *udc, int is_on)
                } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
                        u32     usbpucr;
 
-                       usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+                       usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
                        usbpucr |= AT91_MATRIX_USBPUCR_PUON;
-                       at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
+                       at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
                }
        } else {
                stop_activity(udc);
@@ -927,9 +930,9 @@ static void pullup(struct at91_udc *udc, int is_on)
                } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
                        u32     usbpucr;
 
-                       usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+                       usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
                        usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
-                       at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
+                       at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
                }
                clk_off(udc);
        }
@@ -1705,7 +1708,27 @@ static void at91udc_shutdown(struct platform_device *dev)
        spin_unlock_irqrestore(&udc->lock, flags);
 }
 
-static int __init at91udc_probe(struct platform_device *pdev)
+static void __devinit at91udc_of_init(struct at91_udc *udc,
+                                    struct device_node *np)
+{
+       struct at91_udc_data *board = &udc->board;
+       u32 val;
+       enum of_gpio_flags flags;
+
+       if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
+               board->vbus_polled = 1;
+
+       board->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
+                                                 &flags);
+       board->vbus_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+
+       board->pullup_pin = of_get_named_gpio_flags(np, "atmel,pullup-gpio", 0,
+                                                 &flags);
+
+       board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+}
+
+static int __devinit at91udc_probe(struct platform_device *pdev)
 {
        struct device   *dev = &pdev->dev;
        struct at91_udc *udc;
@@ -1740,7 +1763,11 @@ static int __init at91udc_probe(struct platform_device *pdev)
        /* init software state */
        udc = &controller;
        udc->gadget.dev.parent = dev;
-       udc->board = *(struct at91_udc_data *) dev->platform_data;
+       if (pdev->dev.of_node)
+               at91udc_of_init(udc, pdev->dev.of_node);
+       else
+               memcpy(&udc->board, dev->platform_data,
+                      sizeof(struct at91_udc_data));
        udc->pdev = pdev;
        udc->enabled = 0;
        spin_lock_init(&udc->lock);
@@ -1969,6 +1996,15 @@ static int at91udc_resume(struct platform_device *pdev)
 #define        at91udc_resume  NULL
 #endif
 
+#if defined(CONFIG_OF)
+static const struct of_device_id at91_udc_dt_ids[] = {
+       { .compatible = "atmel,at91rm9200-udc" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);
+#endif
+
 static struct platform_driver at91_udc_driver = {
        .remove         = __exit_p(at91udc_remove),
        .shutdown       = at91udc_shutdown,
@@ -1977,6 +2013,7 @@ static struct platform_driver at91_udc_driver = {
        .driver         = {
                .name   = (char *) driver_name,
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(at91_udc_dt_ids),
        },
 };
 
index 5e10f65..9f98508 100644 (file)
@@ -332,12 +332,12 @@ static int vbus_is_present(struct usba_udc *udc)
 
 static void toggle_bias(int is_on)
 {
-       unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR);
+       unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
 
        if (is_on)
-               at91_sys_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
+               at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
        else
-               at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
+               at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
 }
 
 #else
index 7cdcb63..85a5ceb 100644 (file)
@@ -345,7 +345,7 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req)
                }
 
                skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
-                               skb->len <= 1, req->actual);
+                               skb->len <= 1, req->actual, req->actual);
                page = NULL;
 
                if (req->actual < req->length) { /* Last fragment */
index a5a3ef1..19f318a 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
 
 /* interface and function clocks */
 static struct clk *iclk, *fclk;
@@ -115,6 +116,8 @@ static const struct hc_driver ehci_atmel_hc_driver = {
        .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
+static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32);
+
 static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
 {
        struct usb_hcd *hcd;
@@ -137,6 +140,13 @@ static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
                goto fail_create_hcd;
        }
 
+       /* Right now device-tree probed devices don't get dma_mask set.
+        * Since shared usb code relies on it, set it here for now.
+        * Once we have dma capability bindings this can go away.
+        */
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &at91_ehci_dma_mask;
+
        hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
        if (!hcd) {
                retval = -ENOMEM;
@@ -225,9 +235,21 @@ static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ehci_dt_ids[] = {
+       { .compatible = "atmel,at91sam9g45-ehci" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
+#endif
+
 static struct platform_driver ehci_atmel_driver = {
        .probe          = ehci_atmel_drv_probe,
        .remove         = __devexit_p(ehci_atmel_drv_remove),
        .shutdown       = usb_hcd_platform_shutdown,
-       .driver.name    = "atmel-ehci",
+       .driver         = {
+               .name   = "atmel-ehci",
+               .of_match_table = of_match_ptr(atmel_ehci_dt_ids),
+       },
 };
index 77afabc..db8963f 100644 (file)
@@ -14,6 +14,8 @@
 
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/gpio.h>
@@ -448,10 +450,11 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
 
        /* From the GPIO notifying the over-current situation, find
         * out the corresponding port */
-       gpio = irq_to_gpio(irq);
        for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
-               if (pdata->overcurrent_pin[port] == gpio)
+               if (gpio_to_irq(pdata->overcurrent_pin[port]) == irq) {
+                       gpio = pdata->overcurrent_pin[port];
                        break;
+               }
        }
 
        if (port == ARRAY_SIZE(pdata->overcurrent_pin)) {
@@ -476,13 +479,109 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id at91_ohci_dt_ids[] = {
+       { .compatible = "atmel,at91rm9200-ohci" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids);
+
+static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32);
+
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int i, ret, gpio;
+       enum of_gpio_flags flags;
+       struct at91_usbh_data   *pdata;
+       u32 ports;
+
+       if (!np)
+               return 0;
+
+       /* Right now device-tree probed devices don't get dma_mask set.
+        * Since shared usb code relies on it, set it here for now.
+        * Once we have dma capability bindings this can go away.
+        */
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &at91_ohci_dma_mask;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       if (!of_property_read_u32(np, "num-ports", &ports))
+               pdata->ports = ports;
+
+       for (i = 0; i < 2; i++) {
+               gpio = of_get_named_gpio_flags(np, "atmel,vbus-gpio", i, &flags);
+               pdata->vbus_pin[i] = gpio;
+               if (!gpio_is_valid(gpio))
+                       continue;
+               pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW;
+               ret = gpio_request(gpio, "ohci_vbus");
+               if (ret) {
+                       dev_warn(&pdev->dev, "can't request vbus gpio %d", gpio);
+                       continue;
+               }
+               ret = gpio_direction_output(gpio, !(flags & OF_GPIO_ACTIVE_LOW) ^ 1);
+               if (ret)
+                       dev_warn(&pdev->dev, "can't put vbus gpio %d as output %d",
+                                !(flags & OF_GPIO_ACTIVE_LOW) ^ 1, gpio);
+       }
+
+       for (i = 0; i < 2; i++) {
+               gpio = of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags);
+               pdata->overcurrent_pin[i] = gpio;
+               if (!gpio_is_valid(gpio))
+                       continue;
+               ret = gpio_request(gpio, "ohci_overcurrent");
+               if (ret) {
+                       dev_err(&pdev->dev, "can't request overcurrent gpio %d", gpio);
+                       continue;
+               }
+
+               ret = gpio_direction_input(gpio);
+               if (ret) {
+                       dev_err(&pdev->dev, "can't configure overcurrent gpio %d as input", gpio);
+                       continue;
+               }
+
+               ret = request_irq(gpio_to_irq(gpio),
+                                 ohci_hcd_at91_overcurrent_irq,
+                                 IRQF_SHARED, "ohci_overcurrent", pdev);
+               if (ret) {
+                       gpio_free(gpio);
+                       dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n");
+               }
+       }
+
+       pdev->dev.platform_data = pdata;
+
+       return 0;
+}
+#else
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+       return 0;
+}
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
 {
-       struct at91_usbh_data   *pdata = pdev->dev.platform_data;
+       struct at91_usbh_data   *pdata;
        int                     i;
 
+       i = ohci_at91_of_init(pdev);
+
+       if (i)
+               return i;
+
+       pdata = pdev->dev.platform_data;
+
        if (pdata) {
                for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) {
                        if (!gpio_is_valid(pdata->vbus_pin[i]))
@@ -595,5 +694,6 @@ static struct platform_driver ohci_hcd_at91_driver = {
        .driver         = {
                .name   = "at91_ohci",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(at91_ohci_dt_ids),
        },
 };
index 788ff07..235171f 100644 (file)
@@ -999,7 +999,7 @@ MODULE_LICENSE ("GPL");
 #define SA1111_DRIVER          ohci_hcd_sa1111_driver
 #endif
 
-#if defined(CONFIG_ARCH_S3C2410) || defined(CONFIG_ARCH_S3C64XX)
+#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX)
 #include "ohci-s3c2410.c"
 #define PLATFORM_DRIVER                ohci_hcd_s3c2410_driver
 #endif
index 4bde4f9..e1004fb 100644 (file)
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <mach/assabet.h>
-#include <mach/badge4.h>
 #include <asm/hardware/sa1111.h>
 
 #ifndef CONFIG_SA1111
 #error "This file is SA-1111 bus glue.  CONFIG_SA1111 must be defined."
 #endif
 
-extern int usb_disabled(void);
+#define USB_STATUS     0x0118
+#define USB_RESET      0x011c
+#define USB_IRQTEST    0x0120
+
+#define USB_RESET_FORCEIFRESET (1 << 0)
+#define USB_RESET_FORCEHCRESET (1 << 1)
+#define USB_RESET_CLKGENRESET  (1 << 2)
+#define USB_RESET_SIMSCALEDOWN (1 << 3)
+#define USB_RESET_USBINTTEST   (1 << 4)
+#define USB_RESET_SLEEPSTBYEN  (1 << 5)
+#define USB_RESET_PWRSENSELOW  (1 << 6)
+#define USB_RESET_PWRCTRLLOW   (1 << 7)
+
+#define USB_STATUS_IRQHCIRMTWKUP  (1 <<  7)
+#define USB_STATUS_IRQHCIBUFFACC  (1 <<  8)
+#define USB_STATUS_NIRQHCIM       (1 <<  9)
+#define USB_STATUS_NHCIMFCLR      (1 << 10)
+#define USB_STATUS_USBPWRSENSE    (1 << 11)
 
-/*-------------------------------------------------------------------------*/
+#if 0
+static void dump_hci_status(struct usb_hcd *hcd, const char *label)
+{
+       unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
+
+       dbg("%s USB_STATUS = { %s%s%s%s%s}", label,
+            ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
+            ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
+            ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
+            ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
+            ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
+}
+#endif
 
-static void sa1111_start_hc(struct sa1111_dev *dev)
+static int ohci_sa1111_reset(struct usb_hcd *hcd)
 {
-       unsigned int usb_rst = 0;
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+       ohci_hcd_init(ohci);
+       return ohci_init(ohci);
+}
 
-       printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
-              __FILE__);
+static int __devinit ohci_sa1111_start(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+       int ret;
 
-#ifdef CONFIG_SA1100_BADGE4
-       if (machine_is_badge4()) {
-               badge4_set_5V(BADGE4_5V_USB, 1);
+       ret = ohci_run(ohci);
+       if (ret < 0) {
+               ohci_err(ohci, "can't start\n");
+               ohci_stop(hcd);
        }
+       return ret;
+}
+
+static const struct hc_driver ohci_sa1111_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "SA-1111 OHCI",
+       .hcd_priv_size =        sizeof(struct ohci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_USB11 | HCD_MEMORY,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset =                ohci_sa1111_reset,
+       .start =                ohci_sa1111_start,
+       .stop =                 ohci_stop,
+       .shutdown =             ohci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+#ifdef CONFIG_PM
+       .bus_suspend =          ohci_bus_suspend,
+       .bus_resume =           ohci_bus_resume,
 #endif
+       .start_port_reset =     ohci_start_port_reset,
+};
+
+static int sa1111_start_hc(struct sa1111_dev *dev)
+{
+       unsigned int usb_rst = 0;
+       int ret;
+
+       dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n");
 
        if (machine_is_xp860() ||
            machine_has_neponset() ||
@@ -51,220 +137,121 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
         * host controller in reset.
         */
        sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
-                     dev->mapbase + SA1111_USB_RESET);
+                     dev->mapbase + USB_RESET);
 
        /*
         * Now, carefully enable the USB clock, and take
         * the USB host controller out of reset.
         */
-       sa1111_enable_device(dev);
-       udelay(11);
-       sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
+       ret = sa1111_enable_device(dev);
+       if (ret == 0) {
+               udelay(11);
+               sa1111_writel(usb_rst, dev->mapbase + USB_RESET);
+       }
+
+       return ret;
 }
 
 static void sa1111_stop_hc(struct sa1111_dev *dev)
 {
        unsigned int usb_rst;
-       printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n",
-              __FILE__);
+
+       dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n");
 
        /*
         * Put the USB host controller into reset.
         */
-       usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
+       usb_rst = sa1111_readl(dev->mapbase + USB_RESET);
        sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
-                     dev->mapbase + SA1111_USB_RESET);
+                     dev->mapbase + USB_RESET);
 
        /*
         * Stop the USB clock.
         */
        sa1111_disable_device(dev);
-
-#ifdef CONFIG_SA1100_BADGE4
-       if (machine_is_badge4()) {
-               /* Disable power to the USB bus */
-               badge4_set_5V(BADGE4_5V_USB, 0);
-       }
-#endif
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-#if 0
-static void dump_hci_status(struct usb_hcd *hcd, const char *label)
-{
-       unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
-
-       dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
-            ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
-            ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
-            ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
-            ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
-            ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
 }
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
-
 
 /**
- * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs
- * Context: !in_interrupt()
+ * ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs
  *
  * Allocates basic resources for this USB host controller, and
- * then invokes the start() method for the HCD associated with it
- * through the hotplug entry's driver_data.
- *
- * Store this function in the HCD's struct pci_driver as probe().
+ * then invokes the start() method for the HCD associated with it.
  */
-int usb_hcd_sa1111_probe (const struct hc_driver *driver,
-                         struct sa1111_dev *dev)
+static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
 {
        struct usb_hcd *hcd;
-       int retval;
+       int ret;
 
-       hcd = usb_create_hcd (driver, &dev->dev, "sa1111");
+       if (usb_disabled())
+               return -ENODEV;
+
+       hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111");
        if (!hcd)
                return -ENOMEM;
+
        hcd->rsrc_start = dev->res.start;
        hcd->rsrc_len = resource_size(&dev->res);
 
        if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
                dbg("request_mem_region failed");
-               retval = -EBUSY;
+               ret = -EBUSY;
                goto err1;
        }
+
        hcd->regs = dev->mapbase;
 
-       sa1111_start_hc(dev);
-       ohci_hcd_init(hcd_to_ohci(hcd));
+       ret = sa1111_start_hc(dev);
+       if (ret)
+               goto err2;
 
-       retval = usb_add_hcd(hcd, dev->irq[1], 0);
-       if (retval == 0)
-               return retval;
+       ret = usb_add_hcd(hcd, dev->irq[1], 0);
+       if (ret == 0)
+               return ret;
 
        sa1111_stop_hc(dev);
+ err2:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  err1:
        usb_put_hcd(hcd);
-       return retval;
+       return ret;
 }
 
-
-/* may be called without controller electrically present */
-/* may be called with controller, bus, and devices active */
-
 /**
- * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
+ * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
  * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
- *
- * Reverses the effect of usb_hcd_sa1111_probe(), first invoking
- * the HCD's stop() method.  It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
  *
+ * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking
+ * the HCD's stop() method.
  */
-void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
+static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev)
 {
+       struct usb_hcd *hcd = sa1111_get_drvdata(dev);
+
        usb_remove_hcd(hcd);
        sa1111_stop_hc(dev);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
-}
-
-/*-------------------------------------------------------------------------*/
 
-static int __devinit
-ohci_sa1111_start (struct usb_hcd *hcd)
-{
-       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
-       int             ret;
-
-       if ((ret = ohci_init(ohci)) < 0)
-               return ret;
-
-       if ((ret = ohci_run (ohci)) < 0) {
-               err ("can't start %s", hcd->self.bus_name);
-               ohci_stop (hcd);
-               return ret;
-       }
        return 0;
 }
 
-/*-------------------------------------------------------------------------*/
-
-static const struct hc_driver ohci_sa1111_hc_driver = {
-       .description =          hcd_name,
-       .product_desc =         "SA-1111 OHCI",
-       .hcd_priv_size =        sizeof(struct ohci_hcd),
-
-       /*
-        * generic hardware linkage
-        */
-       .irq =                  ohci_irq,
-       .flags =                HCD_USB11 | HCD_MEMORY,
-
-       /*
-        * basic lifecycle operations
-        */
-       .start =                ohci_sa1111_start,
-       .stop =                 ohci_stop,
-
-       /*
-        * managing i/o requests and associated device resources
-        */
-       .urb_enqueue =          ohci_urb_enqueue,
-       .urb_dequeue =          ohci_urb_dequeue,
-       .endpoint_disable =     ohci_endpoint_disable,
-
-       /*
-        * scheduling support
-        */
-       .get_frame_number =     ohci_get_frame,
-
-       /*
-        * root hub support
-        */
-       .hub_status_data =      ohci_hub_status_data,
-       .hub_control =          ohci_hub_control,
-#ifdef CONFIG_PM
-       .bus_suspend =          ohci_bus_suspend,
-       .bus_resume =           ohci_bus_resume,
-#endif
-       .start_port_reset =     ohci_start_port_reset,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev)
-{
-       int ret;
-
-       if (usb_disabled())
-               return -ENODEV;
-
-       ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev);
-       return ret;
-}
-
-static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev)
+static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev)
 {
        struct usb_hcd *hcd = sa1111_get_drvdata(dev);
 
-       usb_hcd_sa1111_remove(hcd, dev);
-       return 0;
+       if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+               hcd->driver->shutdown(hcd);
+               sa1111_stop_hc(dev);
+       }
 }
 
 static struct sa1111_driver ohci_hcd_sa1111_driver = {
        .drv = {
                .name   = "sa1111-ohci",
+               .owner  = THIS_MODULE,
        },
        .devid          = SA1111_DEVID_USB,
-       .probe          = ohci_hcd_sa1111_drv_probe,
-       .remove         = ohci_hcd_sa1111_drv_remove,
+       .probe          = ohci_hcd_sa1111_probe,
+       .remove         = ohci_hcd_sa1111_remove,
+       .shutdown       = ohci_hcd_sa1111_shutdown,
 };
-
index 7732d69..11de5f1 100644 (file)
@@ -893,4 +893,5 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
                quirk_usb_handoff_xhci(pdev);
        pci_disable_device(pdev);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+                       PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
index 6815701..836cfa9 100644 (file)
@@ -903,8 +903,10 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
-       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
+         .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff),
+         .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) },
index e45e673..6e3e713 100644 (file)
@@ -334,10 +334,8 @@ int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *availab
 
 
        /* fill the not available vector from the available bm */
-       for (bit_index = 0; bit_index < UWB_NUM_MAS; bit_index++) {
-               if (!test_bit(bit_index, available->bm))
-                       ai->bm[bit_index] = UWB_RSV_MAS_NOT_AVAIL;
-       }
+       for_each_clear_bit(bit_index, available->bm, UWB_NUM_MAS)
+               ai->bm[bit_index] = UWB_RSV_MAS_NOT_AVAIL;
 
        if (ai->max_interval == 1) {
                get_row_descriptors(ai);
index 9dab1f5..f0da2c3 100644 (file)
@@ -588,7 +588,7 @@ static int vhost_net_release(struct inode *inode, struct file *f)
 
        vhost_net_stop(n, &tx_sock, &rx_sock);
        vhost_net_flush(n);
-       vhost_dev_cleanup(&n->dev);
+       vhost_dev_cleanup(&n->dev, false);
        if (tx_sock)
                fput(tx_sock->file);
        if (rx_sock)
index bdb2d64..947f00d 100644 (file)
@@ -222,6 +222,8 @@ static int vhost_worker(void *data)
                if (work) {
                        __set_current_state(TASK_RUNNING);
                        work->fn(work);
+                       if (need_resched())
+                               schedule();
                } else
                        schedule();
 
@@ -403,7 +405,7 @@ long vhost_dev_reset_owner(struct vhost_dev *dev)
        if (!memory)
                return -ENOMEM;
 
-       vhost_dev_cleanup(dev);
+       vhost_dev_cleanup(dev, true);
 
        memory->nregions = 0;
        RCU_INIT_POINTER(dev->memory, memory);
@@ -434,8 +436,8 @@ int vhost_zerocopy_signal_used(struct vhost_virtqueue *vq)
        return j;
 }
 
-/* Caller should have device mutex */
-void vhost_dev_cleanup(struct vhost_dev *dev)
+/* Caller should have device mutex if and only if locked is set */
+void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
 {
        int i;
 
@@ -472,7 +474,8 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
        dev->log_file = NULL;
        /* No one will access memory at this point */
        kfree(rcu_dereference_protected(dev->memory,
-                                       lockdep_is_held(&dev->mutex)));
+                                       locked ==
+                                               lockdep_is_held(&dev->mutex)));
        RCU_INIT_POINTER(dev->memory, NULL);
        WARN_ON(!list_empty(&dev->work_list));
        if (dev->worker) {
index a801e28..8dcf4cc 100644 (file)
@@ -163,7 +163,7 @@ struct vhost_dev {
 long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
 long vhost_dev_check_owner(struct vhost_dev *);
 long vhost_dev_reset_owner(struct vhost_dev *);
-void vhost_dev_cleanup(struct vhost_dev *);
+void vhost_dev_cleanup(struct vhost_dev *, bool locked);
 long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
 int vhost_vq_access_ok(struct vhost_virtqueue *vq);
 int vhost_log_access_ok(struct vhost_dev *);
index a8a897a..a290be5 100644 (file)
@@ -2061,7 +2061,7 @@ config FB_S3C_DEBUG_REGWRITE
 
 config FB_S3C2410
        tristate "S3C2410 LCD framebuffer support"
-       depends on FB && ARCH_S3C2410
+       depends on FB && ARCH_S3C24XX
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
index a1376dc..f49181c 100644 (file)
@@ -67,6 +67,28 @@ static inline int wled_idc(int port)
        return ret;
 }
 
+static int backlight_power_set(struct pm860x_chip *chip, int port,
+               int on)
+{
+       int ret = -EINVAL;
+
+       switch (port) {
+       case PM8606_BACKLIGHT1:
+               ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) :
+                       pm8606_osc_disable(chip, WLED1_DUTY);
+               break;
+       case PM8606_BACKLIGHT2:
+               ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) :
+                       pm8606_osc_disable(chip, WLED2_DUTY);
+               break;
+       case PM8606_BACKLIGHT3:
+               ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) :
+                       pm8606_osc_disable(chip, WLED3_DUTY);
+               break;
+       }
+       return ret;
+}
+
 static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
 {
        struct pm860x_backlight_data *data = bl_get_data(bl);
@@ -79,6 +101,9 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
        else
                value = brightness;
 
+       if (brightness)
+               backlight_power_set(chip, data->port, 1);
+
        ret = pm860x_reg_write(data->i2c, wled_a(data->port), value);
        if (ret < 0)
                goto out;
@@ -115,6 +140,9 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
        if (ret < 0)
                goto out;
 
+       if (brightness == 0)
+               backlight_power_set(chip, data->port, 0);
+
        dev_dbg(chip->dev, "set brightness %d\n", value);
        data->current_brightness = value;
        return 0;
@@ -170,7 +198,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        struct backlight_device *bl;
        struct resource *res;
        struct backlight_properties props;
-       unsigned char value;
        char name[MFD_NAME_SIZE];
        int ret;
 
@@ -187,7 +214,8 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       data = kzalloc(sizeof(struct pm860x_backlight_data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_backlight_data),
+                           GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
        strncpy(name, res->name, MFD_NAME_SIZE);
@@ -200,7 +228,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        data->port = pdata->flags;
        if (data->port < 0) {
                dev_err(&pdev->dev, "wrong platform data is assigned");
-               kfree(data);
                return -EINVAL;
        }
 
@@ -211,33 +238,12 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
                                        &pm860x_backlight_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
-               kfree(data);
                return PTR_ERR(bl);
        }
        bl->props.brightness = MAX_BRIGHTNESS;
 
        platform_set_drvdata(pdev, bl);
 
-       /* Enable reference VSYS */
-       ret = pm860x_reg_read(data->i2c, PM8606_VSYS);
-       if (ret < 0)
-               goto out;
-       if ((ret & PM8606_VSYS_EN) == 0) {
-               value = ret | PM8606_VSYS_EN;
-               ret = pm860x_reg_write(data->i2c, PM8606_VSYS, value);
-               if (ret < 0)
-                       goto out;
-       }
-       /* Enable reference OSC */
-       ret = pm860x_reg_read(data->i2c, PM8606_MISC);
-       if (ret < 0)
-               goto out;
-       if ((ret & PM8606_MISC_OSC_EN) == 0) {
-               value = ret | PM8606_MISC_OSC_EN;
-               ret = pm860x_reg_write(data->i2c, PM8606_MISC, value);
-               if (ret < 0)
-                       goto out;
-       }
        /* read current backlight */
        ret = pm860x_backlight_get_brightness(bl);
        if (ret < 0)
@@ -247,17 +253,14 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        return 0;
 out:
        backlight_device_unregister(bl);
-       kfree(data);
        return ret;
 }
 
 static int pm860x_backlight_remove(struct platform_device *pdev)
 {
        struct backlight_device *bl = platform_get_drvdata(pdev);
-       struct pm860x_backlight_data *data = bl_get_data(bl);
 
        backlight_device_unregister(bl);
-       kfree(data);
        return 0;
 }
 
index 681b369..7ed9991 100644 (file)
@@ -334,6 +334,27 @@ config BACKLIGHT_AAT2870
          If you have a AnalogicTech AAT2870 say Y to enable the
          backlight driver.
 
+config BACKLIGHT_LP855X
+       tristate "Backlight driver for TI LP855X"
+       depends on BACKLIGHT_CLASS_DEVICE && I2C
+       help
+         This supports TI LP8550, LP8551, LP8552, LP8553 and LP8556
+         backlight driver.
+
+config BACKLIGHT_OT200
+       tristate "Backlight driver for ot200 visualisation device"
+       depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535
+       help
+         To compile this driver as a module, choose M here: the module will be
+         called ot200_bl.
+
+config BACKLIGHT_PANDORA
+       tristate "Backlight driver for Pandora console"
+       depends on TWL4030_CORE
+       help
+         If you have a Pandora console, say Y to enable the
+         backlight driver.
+
 endif # BACKLIGHT_CLASS_DEVICE
 
 endif # BACKLIGHT_LCD_SUPPORT
index af5cf65..8071eb6 100644 (file)
@@ -22,7 +22,9 @@ obj-$(CONFIG_BACKLIGHT_GENERIC)       += generic_bl.o
 obj-$(CONFIG_BACKLIGHT_HP700)  += jornada720_bl.o
 obj-$(CONFIG_BACKLIGHT_HP680)  += hp680_bl.o
 obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
+obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_OMAP1)  += omap1_bl.o
+obj-$(CONFIG_BACKLIGHT_PANDORA)        += pandora_bl.o
 obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
 obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
 obj-$(CONFIG_BACKLIGHT_PWM)    += pwm_bl.o
@@ -38,4 +40,4 @@ obj-$(CONFIG_BACKLIGHT_ADP8870)       += adp8870_bl.o
 obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)       += pcf50633-backlight.o
 obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o
-
+obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o
index 331f1ef..7ff7522 100644 (file)
@@ -145,7 +145,9 @@ static int aat2870_bl_probe(struct platform_device *pdev)
                goto out;
        }
 
-       aat2870_bl = kzalloc(sizeof(struct aat2870_bl_driver_data), GFP_KERNEL);
+       aat2870_bl = devm_kzalloc(&pdev->dev,
+                                 sizeof(struct aat2870_bl_driver_data),
+                                 GFP_KERNEL);
        if (!aat2870_bl) {
                dev_err(&pdev->dev,
                        "Failed to allocate memory for aat2870 backlight\n");
@@ -162,7 +164,7 @@ static int aat2870_bl_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Failed allocate memory for backlight device\n");
                ret = PTR_ERR(bd);
-               goto out_kfree;
+               goto out;
        }
 
        aat2870_bl->pdev = pdev;
@@ -199,8 +201,6 @@ static int aat2870_bl_probe(struct platform_device *pdev)
 
 out_bl_dev_unregister:
        backlight_device_unregister(bd);
-out_kfree:
-       kfree(aat2870_bl);
 out:
        return ret;
 }
@@ -215,7 +215,6 @@ static int aat2870_bl_remove(struct platform_device *pdev)
        backlight_update_status(bd);
 
        backlight_device_unregister(bd);
-       kfree(aat2870_bl);
 
        return 0;
 }
index 2e630bf..4911ea7 100644 (file)
@@ -289,7 +289,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev)
        struct adp5520_bl *data;
        int ret = 0;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
 
@@ -298,7 +298,6 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev)
 
        if (data->pdata  == NULL) {
                dev_err(&pdev->dev, "missing platform data\n");
-               kfree(data);
                return -ENODEV;
        }
 
@@ -314,7 +313,6 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev)
                                       &adp5520_bl_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
-               kfree(data);
                return PTR_ERR(bl);
        }
 
@@ -326,7 +324,6 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev, "failed to register sysfs\n");
                backlight_device_unregister(bl);
-               kfree(data);
        }
 
        platform_set_drvdata(pdev, bl);
@@ -348,7 +345,6 @@ static int __devexit adp5520_bl_remove(struct platform_device *pdev)
                                &adp5520_bl_attr_group);
 
        backlight_device_unregister(bl);
-       kfree(data);
 
        return 0;
 }
index 378276c..550dbf0 100644 (file)
@@ -819,17 +819,7 @@ static struct i2c_driver adp8860_driver = {
        .id_table = adp8860_id,
 };
 
-static int __init adp8860_init(void)
-{
-       return i2c_add_driver(&adp8860_driver);
-}
-module_init(adp8860_init);
-
-static void __exit adp8860_exit(void)
-{
-       i2c_del_driver(&adp8860_driver);
-}
-module_exit(adp8860_exit);
+module_i2c_driver(adp8860_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
index 6735059..9be58c6 100644 (file)
@@ -991,17 +991,7 @@ static struct i2c_driver adp8870_driver = {
        .id_table = adp8870_id,
 };
 
-static int __init adp8870_init(void)
-{
-       return i2c_add_driver(&adp8870_driver);
-}
-module_init(adp8870_init);
-
-static void __exit adp8870_exit(void)
-{
-       i2c_del_driver(&adp8870_driver);
-}
-module_exit(adp8870_exit);
+module_i2c_driver(adp8870_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
index 7838a23..7bdadc7 100644 (file)
@@ -629,18 +629,7 @@ static struct spi_driver ams369fg06_driver = {
        .resume         = ams369fg06_resume,
 };
 
-static int __init ams369fg06_init(void)
-{
-       return spi_register_driver(&ams369fg06_driver);
-}
-
-static void __exit ams369fg06_exit(void)
-{
-       spi_unregister_driver(&ams369fg06_driver);
-}
-
-module_init(ams369fg06_init);
-module_exit(ams369fg06_exit);
+module_spi_driver(ams369fg06_driver);
 
 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
 MODULE_DESCRIPTION("ams369fg06 LCD Driver");
index be98d15..a523b25 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
+#include <linux/atomic.h>
 
 static struct backlight_device *apple_backlight_device;
 
@@ -221,14 +222,32 @@ static struct acpi_driver apple_bl_driver = {
        },
 };
 
+static atomic_t apple_bl_registered = ATOMIC_INIT(0);
+
+int apple_bl_register(void)
+{
+       if (atomic_xchg(&apple_bl_registered, 1) == 0)
+               return acpi_bus_register_driver(&apple_bl_driver);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apple_bl_register);
+
+void apple_bl_unregister(void)
+{
+       if (atomic_xchg(&apple_bl_registered, 0) == 1)
+               acpi_bus_unregister_driver(&apple_bl_driver);
+}
+EXPORT_SYMBOL_GPL(apple_bl_unregister);
+
 static int __init apple_bl_init(void)
 {
-       return acpi_bus_register_driver(&apple_bl_driver);
+       return apple_bl_register();
 }
 
 static void __exit apple_bl_exit(void)
 {
-       acpi_bus_unregister_driver(&apple_bl_driver);
+       apple_bl_unregister();
 }
 
 module_init(apple_bl_init);
index c6533ba..6dab13f 100644 (file)
@@ -629,17 +629,7 @@ static struct spi_driver corgi_lcd_driver = {
        .resume         = corgi_lcd_resume,
 };
 
-static int __init corgi_lcd_init(void)
-{
-       return spi_register_driver(&corgi_lcd_driver);
-}
-module_init(corgi_lcd_init);
-
-static void __exit corgi_lcd_exit(void)
-{
-       spi_unregister_driver(&corgi_lcd_driver);
-}
-module_exit(corgi_lcd_exit);
+module_spi_driver(corgi_lcd_driver);
 
 MODULE_DESCRIPTION("LCD and backlight driver for SHARP C7x0/Cxx00");
 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
index 6c8c540..22489eb 100644 (file)
@@ -212,7 +212,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
                              &gpio_bar);
        gpio_bar &= ~0x3F;
 
-       crp = kzalloc(sizeof(*crp), GFP_KERNEL);
+       crp = devm_kzalloc(&pdev->dev, sizeof(*crp), GFP_KERNEL);
        if (!crp) {
                lcd_device_unregister(ldp);
                backlight_device_unregister(bdp);
@@ -243,7 +243,6 @@ static int cr_backlight_remove(struct platform_device *pdev)
        backlight_device_unregister(crp->cr_backlight_device);
        lcd_device_unregister(crp->cr_lcd_device);
        pci_dev_put(lpc_dev);
-       kfree(crp);
 
        return 0;
 }
index abb4a06..30e1968 100644 (file)
@@ -110,7 +110,7 @@ static int da903x_backlight_probe(struct platform_device *pdev)
        struct backlight_properties props;
        int max_brightness;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
 
@@ -124,7 +124,6 @@ static int da903x_backlight_probe(struct platform_device *pdev)
        default:
                dev_err(&pdev->dev, "invalid backlight device ID(%d)\n",
                                pdev->id);
-               kfree(data);
                return -EINVAL;
        }
 
@@ -143,7 +142,6 @@ static int da903x_backlight_probe(struct platform_device *pdev)
                                       &da903x_backlight_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
-               kfree(data);
                return PTR_ERR(bl);
        }
 
@@ -157,10 +155,8 @@ static int da903x_backlight_probe(struct platform_device *pdev)
 static int da903x_backlight_remove(struct platform_device *pdev)
 {
        struct backlight_device *bl = platform_get_drvdata(pdev);
-       struct da903x_backlight_data *data = bl_get_data(bl);
 
        backlight_device_unregister(bl);
-       kfree(data);
        return 0;
 }
 
index b62b8b9..08214e1 100644 (file)
 #include <linux/fb.h>
 #include <linux/backlight.h>
 
-#include <mach/hardware.h>
-
-#define EP93XX_RASTER_REG(x)           (EP93XX_RASTER_BASE + (x))
-#define EP93XX_RASTER_BRIGHTNESS       EP93XX_RASTER_REG(0x20)
-
 #define EP93XX_MAX_COUNT               255
 #define EP93XX_MAX_BRIGHT              255
 #define EP93XX_DEF_BRIGHT              128
@@ -35,7 +30,7 @@ static int ep93xxbl_set(struct backlight_device *bl, int brightness)
 {
        struct ep93xxbl *ep93xxbl = bl_get_data(bl);
 
-       __raw_writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio);
+       writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio);
 
        ep93xxbl->brightness = brightness;
 
@@ -70,21 +65,29 @@ static int __init ep93xxbl_probe(struct platform_device *dev)
        struct ep93xxbl *ep93xxbl;
        struct backlight_device *bl;
        struct backlight_properties props;
+       struct resource *res;
 
        ep93xxbl = devm_kzalloc(&dev->dev, sizeof(*ep93xxbl), GFP_KERNEL);
        if (!ep93xxbl)
                return -ENOMEM;
 
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
+
        /*
-        * This register is located in the range already ioremap'ed by
-        * the framebuffer driver.  A MFD driver seems a bit of overkill
-        * to handle this so use the static I/O mapping; this address
-        * is already virtual.
+        * FIXME - We don't do a request_mem_region here because we are
+        * sharing the register space with the framebuffer driver (see
+        * drivers/video/ep93xx-fb.c) and doing so will cause the second
+        * loaded driver to return -EBUSY.
         *
         * NOTE: No locking is required; the framebuffer does not touch
         * this register.
         */
-       ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS;
+       ep93xxbl->mmio = devm_ioremap(&dev->dev, res->start,
+                                     resource_size(res));
+       if (!ep93xxbl->mmio)
+               return -ENXIO;
 
        memset(&props, 0, sizeof(struct backlight_properties));
        props.type = BACKLIGHT_RAW;
index 27d1d7a..6022b67 100644 (file)
@@ -274,18 +274,7 @@ static struct spi_driver l4f00242t03_driver = {
        .shutdown       = l4f00242t03_shutdown,
 };
 
-static __init int l4f00242t03_init(void)
-{
-       return spi_register_driver(&l4f00242t03_driver);
-}
-
-static __exit void l4f00242t03_exit(void)
-{
-       spi_unregister_driver(&l4f00242t03_driver);
-}
-
-module_init(l4f00242t03_init);
-module_exit(l4f00242t03_exit);
+module_spi_driver(l4f00242t03_driver);
 
 MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
 MODULE_DESCRIPTION("EPSON L4F00242T03 LCD");
index 78dafc0..efd352b 100644 (file)
@@ -856,18 +856,7 @@ static struct spi_driver ld9040_driver = {
        .resume         = ld9040_resume,
 };
 
-static int __init ld9040_init(void)
-{
-       return spi_register_driver(&ld9040_driver);
-}
-
-static void __exit ld9040_exit(void)
-{
-       spi_unregister_driver(&ld9040_driver);
-}
-
-module_init(ld9040_init);
-module_exit(ld9040_exit);
+module_spi_driver(ld9040_driver);
 
 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
 MODULE_DESCRIPTION("ld9040 LCD Driver");
index 4ec78cf..4161f9e 100644 (file)
@@ -226,18 +226,7 @@ static struct spi_driver lms283gf05_driver = {
        .remove         = __devexit_p(lms283gf05_remove),
 };
 
-static __init int lms283gf05_init(void)
-{
-       return spi_register_driver(&lms283gf05_driver);
-}
-
-static __exit void lms283gf05_exit(void)
-{
-       spi_unregister_driver(&lms283gf05_driver);
-}
-
-module_init(lms283gf05_init);
-module_exit(lms283gf05_exit);
+module_spi_driver(lms283gf05_driver);
 
 MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
 MODULE_DESCRIPTION("LCD283GF05 LCD");
diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
new file mode 100644 (file)
index 0000000..72a0e0c
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * TI LP855x Backlight Driver
+ *
+ *                     Copyright (C) 2011 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/lp855x.h>
+
+/* Registers */
+#define BRIGHTNESS_CTRL                (0x00)
+#define DEVICE_CTRL            (0x01)
+
+#define BUF_SIZE               20
+#define DEFAULT_BL_NAME                "lcd-backlight"
+#define MAX_BRIGHTNESS         255
+
+struct lp855x {
+       const char *chipname;
+       enum lp855x_chip_id chip_id;
+       struct i2c_client *client;
+       struct backlight_device *bl;
+       struct device *dev;
+       struct mutex xfer_lock;
+       struct lp855x_platform_data *pdata;
+};
+
+static int lp855x_read_byte(struct lp855x *lp, u8 reg, u8 *data)
+{
+       int ret;
+
+       mutex_lock(&lp->xfer_lock);
+       ret = i2c_smbus_read_byte_data(lp->client, reg);
+       if (ret < 0) {
+               mutex_unlock(&lp->xfer_lock);
+               dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
+               return ret;
+       }
+       mutex_unlock(&lp->xfer_lock);
+
+       *data = (u8)ret;
+       return 0;
+}
+
+static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data)
+{
+       int ret;
+
+       mutex_lock(&lp->xfer_lock);
+       ret = i2c_smbus_write_byte_data(lp->client, reg, data);
+       mutex_unlock(&lp->xfer_lock);
+
+       return ret;
+}
+
+static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr)
+{
+       u8 start, end;
+
+       switch (lp->chip_id) {
+       case LP8550:
+       case LP8551:
+       case LP8552:
+       case LP8553:
+               start = EEPROM_START;
+               end = EEPROM_END;
+               break;
+       case LP8556:
+               start = EPROM_START;
+               end = EPROM_END;
+               break;
+       default:
+               return false;
+       }
+
+       return (addr >= start && addr <= end);
+}
+
+static int lp855x_init_registers(struct lp855x *lp)
+{
+       u8 val, addr;
+       int i, ret;
+       struct lp855x_platform_data *pd = lp->pdata;
+
+       val = pd->initial_brightness;
+       ret = lp855x_write_byte(lp, BRIGHTNESS_CTRL, val);
+       if (ret)
+               return ret;
+
+       val = pd->device_control;
+       ret = lp855x_write_byte(lp, DEVICE_CTRL, val);
+       if (ret)
+               return ret;
+
+       if (pd->load_new_rom_data && pd->size_program) {
+               for (i = 0; i < pd->size_program; i++) {
+                       addr = pd->rom_data[i].addr;
+                       val = pd->rom_data[i].val;
+                       if (!lp855x_is_valid_rom_area(lp, addr))
+                               continue;
+
+                       ret = lp855x_write_byte(lp, addr, val);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return ret;
+}
+
+static int lp855x_bl_update_status(struct backlight_device *bl)
+{
+       struct lp855x *lp = bl_get_data(bl);
+       enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
+
+       if (bl->props.state & BL_CORE_SUSPENDED)
+               bl->props.brightness = 0;
+
+       if (mode == PWM_BASED) {
+               struct lp855x_pwm_data *pd = &lp->pdata->pwm_data;
+               int br = bl->props.brightness;
+               int max_br = bl->props.max_brightness;
+
+               if (pd->pwm_set_intensity)
+                       pd->pwm_set_intensity(br, max_br);
+
+       } else if (mode == REGISTER_BASED) {
+               u8 val = bl->props.brightness;
+               lp855x_write_byte(lp, BRIGHTNESS_CTRL, val);
+       }
+
+       return 0;
+}
+
+static int lp855x_bl_get_brightness(struct backlight_device *bl)
+{
+       struct lp855x *lp = bl_get_data(bl);
+       enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
+
+       if (mode == PWM_BASED) {
+               struct lp855x_pwm_data *pd = &lp->pdata->pwm_data;
+               int max_br = bl->props.max_brightness;
+
+               if (pd->pwm_get_intensity)
+                       bl->props.brightness = pd->pwm_get_intensity(max_br);
+
+       } else if (mode == REGISTER_BASED) {
+               u8 val = 0;
+
+               lp855x_read_byte(lp, BRIGHTNESS_CTRL, &val);
+               bl->props.brightness = val;
+       }
+
+       return bl->props.brightness;
+}
+
+static const struct backlight_ops lp855x_bl_ops = {
+       .options = BL_CORE_SUSPENDRESUME,
+       .update_status = lp855x_bl_update_status,
+       .get_brightness = lp855x_bl_get_brightness,
+};
+
+static int lp855x_backlight_register(struct lp855x *lp)
+{
+       struct backlight_device *bl;
+       struct backlight_properties props;
+       struct lp855x_platform_data *pdata = lp->pdata;
+       char *name = pdata->name ? : DEFAULT_BL_NAME;
+
+       props.type = BACKLIGHT_PLATFORM;
+       props.max_brightness = MAX_BRIGHTNESS;
+
+       if (pdata->initial_brightness > props.max_brightness)
+               pdata->initial_brightness = props.max_brightness;
+
+       props.brightness = pdata->initial_brightness;
+
+       bl = backlight_device_register(name, lp->dev, lp,
+                                      &lp855x_bl_ops, &props);
+       if (IS_ERR(bl))
+               return PTR_ERR(bl);
+
+       lp->bl = bl;
+
+       return 0;
+}
+
+static void lp855x_backlight_unregister(struct lp855x *lp)
+{
+       if (lp->bl)
+               backlight_device_unregister(lp->bl);
+}
+
+static ssize_t lp855x_get_chip_id(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct lp855x *lp = dev_get_drvdata(dev);
+       return scnprintf(buf, BUF_SIZE, "%s\n", lp->chipname);
+}
+
+static ssize_t lp855x_get_bl_ctl_mode(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct lp855x *lp = dev_get_drvdata(dev);
+       enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
+       char *strmode = NULL;
+
+       if (mode == PWM_BASED)
+               strmode = "pwm based";
+       else if (mode == REGISTER_BASED)
+               strmode = "register based";
+
+       return scnprintf(buf, BUF_SIZE, "%s\n", strmode);
+}
+
+static DEVICE_ATTR(chip_id, S_IRUGO, lp855x_get_chip_id, NULL);
+static DEVICE_ATTR(bl_ctl_mode, S_IRUGO, lp855x_get_bl_ctl_mode, NULL);
+
+static struct attribute *lp855x_attributes[] = {
+       &dev_attr_chip_id.attr,
+       &dev_attr_bl_ctl_mode.attr,
+       NULL,
+};
+
+static const struct attribute_group lp855x_attr_group = {
+       .attrs = lp855x_attributes,
+};
+
+static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
+{
+       struct lp855x *lp;
+       struct lp855x_platform_data *pdata = cl->dev.platform_data;
+       enum lp855x_brightness_ctrl_mode mode;
+       int ret;
+
+       if (!pdata) {
+               dev_err(&cl->dev, "no platform data supplied\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
+               return -EIO;
+
+       lp = devm_kzalloc(&cl->dev, sizeof(struct lp855x), GFP_KERNEL);
+       if (!lp)
+               return -ENOMEM;
+
+       mode = pdata->mode;
+       lp->client = cl;
+       lp->dev = &cl->dev;
+       lp->pdata = pdata;
+       lp->chipname = id->name;
+       lp->chip_id = id->driver_data;
+       i2c_set_clientdata(cl, lp);
+
+       mutex_init(&lp->xfer_lock);
+
+       ret = lp855x_init_registers(lp);
+       if (ret) {
+               dev_err(lp->dev, "i2c communication err: %d", ret);
+               if (mode == REGISTER_BASED)
+                       goto err_dev;
+       }
+
+       ret = lp855x_backlight_register(lp);
+       if (ret) {
+               dev_err(lp->dev,
+                       "failed to register backlight. err: %d\n", ret);
+               goto err_dev;
+       }
+
+       ret = sysfs_create_group(&lp->dev->kobj, &lp855x_attr_group);
+       if (ret) {
+               dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret);
+               goto err_sysfs;
+       }
+
+       backlight_update_status(lp->bl);
+       return 0;
+
+err_sysfs:
+       lp855x_backlight_unregister(lp);
+err_dev:
+       return ret;
+}
+
+static int __devexit lp855x_remove(struct i2c_client *cl)
+{
+       struct lp855x *lp = i2c_get_clientdata(cl);
+
+       lp->bl->props.brightness = 0;
+       backlight_update_status(lp->bl);
+       sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group);
+       lp855x_backlight_unregister(lp);
+
+       return 0;
+}
+
+static const struct i2c_device_id lp855x_ids[] = {
+       {"lp8550", LP8550},
+       {"lp8551", LP8551},
+       {"lp8552", LP8552},
+       {"lp8553", LP8553},
+       {"lp8556", LP8556},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lp855x_ids);
+
+static struct i2c_driver lp855x_driver = {
+       .driver = {
+                  .name = "lp855x",
+                  },
+       .probe = lp855x_probe,
+       .remove = __devexit_p(lp855x_remove),
+       .id_table = lp855x_ids,
+};
+
+module_i2c_driver(lp855x_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP855x Backlight driver");
+MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
+MODULE_LICENSE("GPL");
index cca43c0..333949f 100644 (file)
@@ -321,17 +321,7 @@ static struct spi_driver ltv350qv_driver = {
        .resume         = ltv350qv_resume,
 };
 
-static int __init ltv350qv_init(void)
-{
-       return spi_register_driver(&ltv350qv_driver);
-}
-
-static void __exit ltv350qv_exit(void)
-{
-       spi_unregister_driver(&ltv350qv_driver);
-}
-module_init(ltv350qv_init);
-module_exit(ltv350qv_exit);
+module_spi_driver(ltv350qv_driver);
 
 MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
 MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver");
index c915e3b..e833ac7 100644 (file)
@@ -129,7 +129,8 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       data = kzalloc(sizeof(struct max8925_backlight_data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(struct max8925_backlight_data),
+                           GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
        strncpy(name, res->name, MAX8925_NAME_SIZE);
@@ -143,7 +144,6 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
                                        &max8925_backlight_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
-               kfree(data);
                return PTR_ERR(bl);
        }
        bl->props.brightness = MAX_BRIGHTNESS;
@@ -165,17 +165,14 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
        return 0;
 out:
        backlight_device_unregister(bl);
-       kfree(data);
        return ret;
 }
 
 static int __devexit max8925_backlight_remove(struct platform_device *pdev)
 {
        struct backlight_device *bl = platform_get_drvdata(pdev);
-       struct max8925_backlight_data *data = bl_get_data(bl);
 
        backlight_device_unregister(bl);
-       kfree(data);
        return 0;
 }
 
index d8cde27..0175bfb 100644 (file)
@@ -141,7 +141,8 @@ static int omapbl_probe(struct platform_device *pdev)
        if (!pdata)
                return -ENXIO;
 
-       bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL);
+       bl = devm_kzalloc(&pdev->dev, sizeof(struct omap_backlight),
+                         GFP_KERNEL);
        if (unlikely(!bl))
                return -ENOMEM;
 
@@ -150,10 +151,8 @@ static int omapbl_probe(struct platform_device *pdev)
        props.max_brightness = OMAPBL_MAX_INTENSITY;
        dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops,
                                        &props);
-       if (IS_ERR(dev)) {
-               kfree(bl);
+       if (IS_ERR(dev))
                return PTR_ERR(dev);
-       }
 
        bl->powermode = FB_BLANK_POWERDOWN;
        bl->current_intensity = 0;
@@ -177,10 +176,8 @@ static int omapbl_probe(struct platform_device *pdev)
 static int omapbl_remove(struct platform_device *pdev)
 {
        struct backlight_device *dev = platform_get_drvdata(pdev);
-       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
 
        backlight_device_unregister(dev);
-       kfree(bl);
 
        return 0;
 }
diff --git a/drivers/video/backlight/ot200_bl.c b/drivers/video/backlight/ot200_bl.c
new file mode 100644 (file)
index 0000000..f519d55
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 Bachmann electronic GmbH
+ *     Christian Gmeiner <christian.gmeiner@gmail.com>
+ *
+ * Backlight driver for ot200 visualisation device from
+ * Bachmann electronic GmbH.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/gpio.h>
+#include <linux/cs5535.h>
+
+static struct cs5535_mfgpt_timer *pwm_timer;
+
+/* this array defines the mapping of brightness in % to pwm frequency */
+static const u8 dim_table[101] = {0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+                                 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+                                 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9,
+                                 10, 10, 11, 11, 12, 12, 13, 14, 15, 15, 16,
+                                 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28,
+                                 30, 31, 33, 35, 37, 39, 41, 43, 45, 47, 50,
+                                 53, 55, 58, 61, 65, 68, 72, 75, 79, 84, 88,
+                                 93, 97, 103, 108, 114, 120, 126, 133, 140,
+                                 147, 155, 163};
+
+struct ot200_backlight_data {
+       int current_brightness;
+};
+
+#define GPIO_DIMM      27
+#define SCALE          1
+#define CMP1MODE       0x2     /* compare on GE; output high on compare
+                                * greater than or equal */
+#define PWM_SETUP      (SCALE | CMP1MODE << 6 | MFGPT_SETUP_CNTEN)
+#define MAX_COMP2      163
+
+static int ot200_backlight_update_status(struct backlight_device *bl)
+{
+       struct ot200_backlight_data *data = bl_get_data(bl);
+       int brightness = bl->props.brightness;
+
+       if (bl->props.state & BL_CORE_FBBLANK)
+               brightness = 0;
+
+       /* enable or disable PWM timer */
+       if (brightness == 0)
+               cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, 0);
+       else if (data->current_brightness == 0) {
+               cs5535_mfgpt_write(pwm_timer, MFGPT_REG_COUNTER, 0);
+               cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP,
+                       MFGPT_SETUP_CNTEN);
+       }
+
+       /* apply new brightness value */
+       cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1,
+               MAX_COMP2 - dim_table[brightness]);
+       data->current_brightness = brightness;
+
+       return 0;
+}
+
+static int ot200_backlight_get_brightness(struct backlight_device *bl)
+{
+       struct ot200_backlight_data *data = bl_get_data(bl);
+       return data->current_brightness;
+}
+
+static const struct backlight_ops ot200_backlight_ops = {
+       .update_status  = ot200_backlight_update_status,
+       .get_brightness = ot200_backlight_get_brightness,
+};
+
+static int ot200_backlight_probe(struct platform_device *pdev)
+{
+       struct backlight_device *bl;
+       struct ot200_backlight_data *data;
+       struct backlight_properties props;
+       int retval = 0;
+
+       /* request gpio */
+       if (gpio_request(GPIO_DIMM, "ot200 backlight dimmer") < 0) {
+               dev_err(&pdev->dev, "failed to request GPIO %d\n", GPIO_DIMM);
+               return -ENODEV;
+       }
+
+       /* request timer */
+       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;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               retval = -ENOMEM;
+               goto error_kzalloc;
+       }
+
+       /* setup gpio */
+       cs5535_gpio_set(GPIO_DIMM, GPIO_OUTPUT_ENABLE);
+       cs5535_gpio_set(GPIO_DIMM, GPIO_OUTPUT_AUX1);
+
+       /* setup timer */
+       cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1, 0);
+       cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP2, MAX_COMP2);
+       cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, PWM_SETUP);
+
+       data->current_brightness = 100;
+       props.max_brightness = 100;
+       props.brightness = 100;
+       props.type = BACKLIGHT_RAW;
+
+       bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, data,
+                                       &ot200_backlight_ops, &props);
+       if (IS_ERR(bl)) {
+               dev_err(&pdev->dev, "failed to register backlight\n");
+               retval = PTR_ERR(bl);
+               goto error_backlight_device_register;
+       }
+
+       platform_set_drvdata(pdev, bl);
+
+       return 0;
+
+error_backlight_device_register:
+       kfree(data);
+error_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);
+
+       /* on module unload set brightness to 100% */
+       cs5535_mfgpt_write(pwm_timer, MFGPT_REG_COUNTER, 0);
+       cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
+       cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1,
+               MAX_COMP2 - dim_table[100]);
+
+       cs5535_mfgpt_free_timer(pwm_timer);
+       gpio_free(GPIO_DIMM);
+
+       kfree(data);
+       return 0;
+}
+
+static struct platform_driver ot200_backlight_driver = {
+       .driver         = {
+               .name   = "ot200-backlight",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ot200_backlight_probe,
+       .remove         = ot200_backlight_remove,
+};
+
+module_platform_driver(ot200_backlight_driver);
+
+MODULE_DESCRIPTION("backlight driver for ot200 visualisation device");
+MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ot200-backlight");
diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c
new file mode 100644 (file)
index 0000000..4ec3074
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Backlight driver for Pandora handheld.
+ * Pandora uses TWL4030 PWM0 -> TPS61161 combo for control backlight.
+ * Based on pwm_bl.c
+ *
+ * Copyright 2009,2012 Gražvydas Ignotas <notasas@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/i2c/twl.h>
+#include <linux/err.h>
+
+#define TWL_PWM0_ON            0x00
+#define TWL_PWM0_OFF           0x01
+
+#define TWL_INTBR_GPBR1                0x0c
+#define TWL_INTBR_PMBR1                0x0d
+
+#define TWL_PMBR1_PWM0_MUXMASK 0x0c
+#define TWL_PMBR1_PWM0         0x04
+#define PWM0_CLK_ENABLE                BIT(0)
+#define PWM0_ENABLE            BIT(2)
+
+/* range accepted by hardware */
+#define MIN_VALUE 9
+#define MAX_VALUE 63
+#define MAX_USER_VALUE (MAX_VALUE - MIN_VALUE)
+
+#define PANDORABL_WAS_OFF BL_CORE_DRIVER1
+
+static int pandora_backlight_update_status(struct backlight_device *bl)
+{
+       int brightness = bl->props.brightness;
+       u8 r;
+
+       if (bl->props.power != FB_BLANK_UNBLANK)
+               brightness = 0;
+       if (bl->props.state & BL_CORE_FBBLANK)
+               brightness = 0;
+       if (bl->props.state & BL_CORE_SUSPENDED)
+               brightness = 0;
+
+       if ((unsigned int)brightness > MAX_USER_VALUE)
+               brightness = MAX_USER_VALUE;
+
+       if (brightness == 0) {
+               if (bl->props.state & PANDORABL_WAS_OFF)
+                       goto done;
+
+               /* first disable PWM0 output, then clock */
+               twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1);
+               r &= ~PWM0_ENABLE;
+               twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
+               r &= ~PWM0_CLK_ENABLE;
+               twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
+
+               goto done;
+       }
+
+       if (bl->props.state & PANDORABL_WAS_OFF) {
+               /*
+                * set PWM duty cycle to max. TPS61161 seems to use this
+                * to calibrate it's PWM sensitivity when it starts.
+                */
+               twl_i2c_write_u8(TWL4030_MODULE_PWM0, MAX_VALUE,
+                                       TWL_PWM0_OFF);
+
+               /* first enable clock, then PWM0 out */
+               twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1);
+               r &= ~PWM0_ENABLE;
+               r |= PWM0_CLK_ENABLE;
+               twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
+               r |= PWM0_ENABLE;
+               twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);
+
+               /*
+                * TI made it very easy to enable digital control, so easy that
+                * it often triggers unintentionally and disabes PWM control,
+                * so wait until 1 wire mode detection window ends.
+                */
+               usleep_range(2000, 10000);
+       }
+
+       twl_i2c_write_u8(TWL4030_MODULE_PWM0, MIN_VALUE + brightness,
+                               TWL_PWM0_OFF);
+
+done:
+       if (brightness != 0)
+               bl->props.state &= ~PANDORABL_WAS_OFF;
+       else
+               bl->props.state |= PANDORABL_WAS_OFF;
+
+       return 0;
+}
+
+static int pandora_backlight_get_brightness(struct backlight_device *bl)
+{
+       return bl->props.brightness;
+}
+
+static const struct backlight_ops pandora_backlight_ops = {
+       .options        = BL_CORE_SUSPENDRESUME,
+       .update_status  = pandora_backlight_update_status,
+       .get_brightness = pandora_backlight_get_brightness,
+};
+
+static int pandora_backlight_probe(struct platform_device *pdev)
+{
+       struct backlight_properties props;
+       struct backlight_device *bl;
+       u8 r;
+
+       memset(&props, 0, sizeof(props));
+       props.max_brightness = MAX_USER_VALUE;
+       props.type = BACKLIGHT_RAW;
+       bl = backlight_device_register(pdev->name, &pdev->dev,
+                       NULL, &pandora_backlight_ops, &props);
+       if (IS_ERR(bl)) {
+               dev_err(&pdev->dev, "failed to register backlight\n");
+               return PTR_ERR(bl);
+       }
+
+       platform_set_drvdata(pdev, bl);
+
+       /* 64 cycle period, ON position 0 */
+       twl_i2c_write_u8(TWL4030_MODULE_PWM0, 0x80, TWL_PWM0_ON);
+
+       bl->props.state |= PANDORABL_WAS_OFF;
+       bl->props.brightness = MAX_USER_VALUE;
+       backlight_update_status(bl);
+
+       /* enable PWM function in pin mux */
+       twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_PMBR1);
+       r &= ~TWL_PMBR1_PWM0_MUXMASK;
+       r |= TWL_PMBR1_PWM0;
+       twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_PMBR1);
+
+       return 0;
+}
+
+static int pandora_backlight_remove(struct platform_device *pdev)
+{
+       struct backlight_device *bl = platform_get_drvdata(pdev);
+       backlight_device_unregister(bl);
+       return 0;
+}
+
+static struct platform_driver pandora_backlight_driver = {
+       .driver         = {
+               .name   = "pandora-backlight",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = pandora_backlight_probe,
+       .remove         = pandora_backlight_remove,
+};
+
+module_platform_driver(pandora_backlight_driver);
+
+MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
+MODULE_DESCRIPTION("Pandora Backlight Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pandora-backlight");
index 13e88b7..c65853c 100644 (file)
@@ -101,14 +101,13 @@ static const struct backlight_ops pcf50633_bl_ops = {
 
 static int __devinit pcf50633_bl_probe(struct platform_device *pdev)
 {
-       int ret;
        struct pcf50633_bl *pcf_bl;
        struct device *parent = pdev->dev.parent;
        struct pcf50633_platform_data *pcf50633_data = parent->platform_data;
        struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data;
        struct backlight_properties bl_props;
 
-       pcf_bl = kzalloc(sizeof(*pcf_bl), GFP_KERNEL);
+       pcf_bl = devm_kzalloc(&pdev->dev, sizeof(*pcf_bl), GFP_KERNEL);
        if (!pcf_bl)
                return -ENOMEM;
 
@@ -129,10 +128,8 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev)
        pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl,
                                                &pcf50633_bl_ops, &bl_props);
 
-       if (IS_ERR(pcf_bl->bl)) {
-               ret = PTR_ERR(pcf_bl->bl);
-               goto err_free;
-       }
+       if (IS_ERR(pcf_bl->bl))
+               return PTR_ERR(pcf_bl->bl);
 
        platform_set_drvdata(pdev, pcf_bl);
 
@@ -145,11 +142,6 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev)
        backlight_update_status(pcf_bl->bl);
 
        return 0;
-
-err_free:
-       kfree(pcf_bl);
-
-       return ret;
 }
 
 static int __devexit pcf50633_bl_remove(struct platform_device *pdev)
@@ -160,8 +152,6 @@ static int __devexit pcf50633_bl_remove(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, NULL);
 
-       kfree(pcf_bl);
-
        return 0;
 }
 
index f0bf491..b667234 100644 (file)
@@ -121,9 +121,9 @@ static int __devexit platform_lcd_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int platform_lcd_suspend(struct platform_device *pdev, pm_message_t st)
+static int platform_lcd_suspend(struct device *dev)
 {
-       struct platform_lcd *plcd = platform_get_drvdata(pdev);
+       struct platform_lcd *plcd = dev_get_drvdata(dev);
 
        plcd->suspended = 1;
        platform_lcd_set_power(plcd->lcd, plcd->power);
@@ -131,29 +131,30 @@ static int platform_lcd_suspend(struct platform_device *pdev, pm_message_t st)
        return 0;
 }
 
-static int platform_lcd_resume(struct platform_device *pdev)
+static int platform_lcd_resume(struct device *dev)
 {
-       struct platform_lcd *plcd = platform_get_drvdata(pdev);
+       struct platform_lcd *plcd = dev_get_drvdata(dev);
 
        plcd->suspended = 0;
        platform_lcd_set_power(plcd->lcd, plcd->power);
 
        return 0;
 }
-#else
-#define platform_lcd_suspend NULL
-#define platform_lcd_resume NULL
+
+static SIMPLE_DEV_PM_OPS(platform_lcd_pm_ops, platform_lcd_suspend,
+                       platform_lcd_resume);
 #endif
 
 static struct platform_driver platform_lcd_driver = {
        .driver         = {
                .name   = "platform-lcd",
                .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &platform_lcd_pm_ops,
+#endif
        },
        .probe          = platform_lcd_probe,
        .remove         = __devexit_p(platform_lcd_remove),
-       .suspend        = platform_lcd_suspend,
-       .resume         = platform_lcd_resume,
 };
 
 module_platform_driver(platform_lcd_driver);
index 7496d04..342b7d7 100644 (file)
@@ -102,7 +102,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
                        return ret;
        }
 
-       pb = kzalloc(sizeof(*pb), GFP_KERNEL);
+       pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
        if (!pb) {
                dev_err(&pdev->dev, "no memory for state\n");
                ret = -ENOMEM;
@@ -121,7 +121,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
        if (IS_ERR(pb->pwm)) {
                dev_err(&pdev->dev, "unable to request PWM for backlight\n");
                ret = PTR_ERR(pb->pwm);
-               goto err_pwm;
+               goto err_alloc;
        } else
                dev_dbg(&pdev->dev, "got pwm for backlight\n");
 
@@ -144,8 +144,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 
 err_bl:
        pwm_free(pb->pwm);
-err_pwm:
-       kfree(pb);
 err_alloc:
        if (data->exit)
                data->exit(&pdev->dev);
@@ -162,7 +160,6 @@ static int pwm_backlight_remove(struct platform_device *pdev)
        pwm_config(pb->pwm, 0, pb->period);
        pwm_disable(pb->pwm);
        pwm_free(pb->pwm);
-       kfree(pb);
        if (data->exit)
                data->exit(&pdev->dev);
        return 0;
index 516db70..e264f55 100644 (file)
@@ -909,18 +909,7 @@ static struct spi_driver s6e63m0_driver = {
        .resume         = s6e63m0_resume,
 };
 
-static int __init s6e63m0_init(void)
-{
-       return spi_register_driver(&s6e63m0_driver);
-}
-
-static void __exit s6e63m0_exit(void)
-{
-       spi_unregister_driver(&s6e63m0_driver);
-}
-
-module_init(s6e63m0_init);
-module_exit(s6e63m0_exit);
+module_spi_driver(s6e63m0_driver);
 
 MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
 MODULE_DESCRIPTION("S6E63M0 LCD Driver");
index 1997e12..2368b8e 100644 (file)
@@ -459,17 +459,7 @@ static struct spi_driver tdo24m_driver = {
        .resume         = tdo24m_resume,
 };
 
-static int __init tdo24m_init(void)
-{
-       return spi_register_driver(&tdo24m_driver);
-}
-module_init(tdo24m_init);
-
-static void __exit tdo24m_exit(void)
-{
-       spi_unregister_driver(&tdo24m_driver);
-}
-module_exit(tdo24m_exit);
+module_spi_driver(tdo24m_driver);
 
 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
 MODULE_DESCRIPTION("Driver for Toppoly TDO24M LCD Panel");
index 425a736..2b241ab 100644 (file)
@@ -181,18 +181,7 @@ static struct i2c_driver tosa_bl_driver = {
        .id_table       = tosa_bl_id,
 };
 
-static int __init tosa_bl_init(void)
-{
-       return i2c_add_driver(&tosa_bl_driver);
-}
-
-static void __exit tosa_bl_exit(void)
-{
-       i2c_del_driver(&tosa_bl_driver);
-}
-
-module_init(tosa_bl_init);
-module_exit(tosa_bl_exit);
+module_i2c_driver(tosa_bl_driver);
 
 MODULE_AUTHOR("Dmitry Baryshkov");
 MODULE_LICENSE("GPL v2");
index 772f601..a2161f6 100644 (file)
@@ -285,18 +285,7 @@ static struct spi_driver tosa_lcd_driver = {
        .resume         = tosa_lcd_resume,
 };
 
-static int __init tosa_lcd_init(void)
-{
-       return spi_register_driver(&tosa_lcd_driver);
-}
-
-static void __exit tosa_lcd_exit(void)
-{
-       spi_unregister_driver(&tosa_lcd_driver);
-}
-
-module_init(tosa_lcd_init);
-module_exit(tosa_lcd_exit);
+module_spi_driver(tosa_lcd_driver);
 
 MODULE_AUTHOR("Dmitry Baryshkov");
 MODULE_LICENSE("GPL v2");
index b49063c..b617fae 100644 (file)
@@ -262,20 +262,7 @@ static struct spi_driver vgg2432a4_driver = {
        .resume         = vgg2432a4_resume,
 };
 
-/* Device driver initialisation */
-
-static int __init vgg2432a4_init(void)
-{
-       return spi_register_driver(&vgg2432a4_driver);
-}
-
-static void __exit vgg2432a4_exit(void)
-{
-       spi_unregister_driver(&vgg2432a4_driver);
-}
-
-module_init(vgg2432a4_init);
-module_exit(vgg2432a4_exit);
+module_spi_driver(vgg2432a4_driver);
 
 MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
 MODULE_DESCRIPTION("VGG2432A4 LCD Driver");
index 4e915f5..5d365de 100644 (file)
@@ -186,7 +186,7 @@ static int wm831x_backlight_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
 
@@ -200,7 +200,6 @@ static int wm831x_backlight_probe(struct platform_device *pdev)
                                       &wm831x_backlight_ops, &props);
        if (IS_ERR(bl)) {
                dev_err(&pdev->dev, "failed to register backlight\n");
-               kfree(data);
                return PTR_ERR(bl);
        }
 
@@ -211,7 +210,6 @@ static int wm831x_backlight_probe(struct platform_device *pdev)
        /* Disable the DCDC if it was started so we can bootstrap */
        wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, WM831X_DC4_ENA, 0);
 
-
        backlight_update_status(bl);
 
        return 0;
@@ -220,10 +218,8 @@ static int wm831x_backlight_probe(struct platform_device *pdev)
 static int wm831x_backlight_remove(struct platform_device *pdev)
 {
        struct backlight_device *bl = platform_get_drvdata(pdev);
-       struct wm831x_backlight_data *data = bl_get_data(bl);
 
        backlight_device_unregister(bl);
-       kfree(data);
        return 0;
 }
 
index 2e830ec..f8babbe 100644 (file)
@@ -519,12 +519,15 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev)
                goto failed;
        }
 
-       res = request_mem_region(res->start, resource_size(res), pdev->name);
-       if (!res) {
-               err = -EBUSY;
-               goto failed;
-       }
-
+       /*
+        * FIXME - We don't do a request_mem_region here because we are
+        * sharing the register space with the backlight driver (see
+        * drivers/video/backlight/ep93xx_bl.c) and doing so will cause
+        * the second loaded driver to return -EBUSY.
+        *
+        * NOTE: No locking is required; the backlight does not touch
+        * any of the framebuffer registers.
+        */
        fbi->res = res;
        fbi->mmio_base = ioremap(res->start, resource_size(res));
        if (!fbi->mmio_base) {
@@ -586,8 +589,6 @@ failed:
                clk_put(fbi->clk);
        if (fbi->mmio_base)
                iounmap(fbi->mmio_base);
-       if (fbi->res)
-               release_mem_region(fbi->res->start, resource_size(fbi->res));
        ep93xxfb_dealloc_videomem(info);
        if (&info->cmap)
                fb_dealloc_cmap(&info->cmap);
@@ -608,7 +609,6 @@ static int __devexit ep93xxfb_remove(struct platform_device *pdev)
        clk_disable(fbi->clk);
        clk_put(fbi->clk);
        iounmap(fbi->mmio_base);
-       release_mem_region(fbi->res->start, resource_size(fbi->res));
        ep93xxfb_dealloc_videomem(info);
        fb_dealloc_cmap(&info->cmap);
 
index 0fdd6f6..d3a3113 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/lcd.h>
+#include <linux/gpio.h>
 
 #include <plat/board-ams-delta.h>
 #include <mach/hardware.h>
@@ -98,29 +99,41 @@ static struct lcd_ops ams_delta_lcd_ops = {
 
 /* omapfb panel section */
 
+static const struct gpio _gpios[] = {
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_LCD_VBLEN,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "lcd_vblen",
+       },
+       {
+               .gpio   = AMS_DELTA_GPIO_PIN_LCD_NDISP,
+               .flags  = GPIOF_OUT_INIT_LOW,
+               .label  = "lcd_ndisp",
+       },
+};
+
 static int ams_delta_panel_init(struct lcd_panel *panel,
                struct omapfb_device *fbdev)
 {
-       return 0;
+       return gpio_request_array(_gpios, ARRAY_SIZE(_gpios));
 }
 
 static void ams_delta_panel_cleanup(struct lcd_panel *panel)
 {
+       gpio_free_array(_gpios, ARRAY_SIZE(_gpios));
 }
 
 static int ams_delta_panel_enable(struct lcd_panel *panel)
 {
-       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP,
-                       AMS_DELTA_LATCH2_LCD_NDISP);
-       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN,
-                       AMS_DELTA_LATCH2_LCD_VBLEN);
+       gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_NDISP, 1);
+       gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_VBLEN, 1);
        return 0;
 }
 
 static void ams_delta_panel_disable(struct lcd_panel *panel)
 {
-       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN, 0);
-       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP, 0);
+       gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_VBLEN, 0);
+       gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_NDISP, 0);
 }
 
 static unsigned long ams_delta_panel_get_caps(struct lcd_panel *panel)
index bddd64b..ee30937 100644 (file)
@@ -3318,11 +3318,6 @@ static void _omap_dispc_initial_config(void)
        if (dss_has_feature(FEAT_FUNCGATED))
                REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
 
-       /* L3 firewall setting: enable access to OCM RAM */
-       /* XXX this should be somewhere in plat-omap */
-       if (cpu_is_omap24xx())
-               __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
-
        _dispc_setup_color_conv_coef();
 
        dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
index 4a6b5ee..bd2d5e1 100644 (file)
 #include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
+
+#include <plat/cpu.h>
 #include <plat/clock.h>
+
 #include "dss.h"
 #include "dss_features.h"
 
index 98d55d0..b632584 100644 (file)
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/cpufreq.h>
+#include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/mutex.h>
 #include <linux/io.h>
 
+#include <video/sa1100fb.h>
+
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
-#include <mach/assabet.h>
 #include <mach/shannon.h>
 
 /*
- * debugging?
- */
-#define DEBUG 0
-/*
  * Complain if VAR is out of range.
  */
 #define DEBUG_VAR 1
 
-#undef ASSABET_PAL_VIDEO
-
 #include "sa1100fb.h"
 
-extern void (*sa1100fb_backlight_power)(int on);
-extern void (*sa1100fb_lcd_power)(int on);
-
-static struct sa1100fb_rgb rgb_4 = {
+static const struct sa1100fb_rgb rgb_4 = {
        .red    = { .offset = 0,  .length = 4, },
        .green  = { .offset = 0,  .length = 4, },
        .blue   = { .offset = 0,  .length = 4, },
        .transp = { .offset = 0,  .length = 0, },
 };
 
-static struct sa1100fb_rgb rgb_8 = {
+static const struct sa1100fb_rgb rgb_8 = {
        .red    = { .offset = 0,  .length = 8, },
        .green  = { .offset = 0,  .length = 8, },
        .blue   = { .offset = 0,  .length = 8, },
        .transp = { .offset = 0,  .length = 0, },
 };
 
-static struct sa1100fb_rgb def_rgb_16 = {
+static const struct sa1100fb_rgb def_rgb_16 = {
        .red    = { .offset = 11, .length = 5, },
        .green  = { .offset = 5,  .length = 6, },
        .blue   = { .offset = 0,  .length = 5, },
        .transp = { .offset = 0,  .length = 0, },
 };
 
-#ifdef CONFIG_SA1100_ASSABET
-#ifndef ASSABET_PAL_VIDEO
-/*
- * The assabet uses a sharp LQ039Q2DS54 LCD module.  It is actually
- * takes an RGB666 signal, but we provide it with an RGB565 signal
- * instead (def_rgb_16).
- */
-static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
-       .pixclock       = 171521,       .bpp            = 16,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 5,            .vsync_len      = 1,
-       .left_margin    = 61,           .upper_margin   = 3,
-       .right_margin   = 9,            .lower_margin   = 0,
-
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-#else
-static struct sa1100fb_mach_info pal_info __initdata = {
-       .pixclock       = 67797,        .bpp            = 16,
-       .xres           = 640,          .yres           = 512,
-
-       .hsync_len      = 64,           .vsync_len      = 6,
-       .left_margin    = 125,          .upper_margin   = 70,
-       .right_margin   = 115,          .lower_margin   = 36,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-#endif
-
-#ifdef CONFIG_SA1100_H3600
-static struct sa1100fb_mach_info h3600_info __initdata = {
-       .pixclock       = 174757,       .bpp            = 16,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 3,            .vsync_len      = 3,
-       .left_margin    = 12,           .upper_margin   = 10,
-       .right_margin   = 17,           .lower_margin   = 1,
-
-       .cmap_static    = 1,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-
-static struct sa1100fb_rgb h3600_rgb_16 = {
-       .red    = { .offset = 12, .length = 4, },
-       .green  = { .offset = 7,  .length = 4, },
-       .blue   = { .offset = 1,  .length = 4, },
-       .transp = { .offset = 0,  .length = 0, },
-};
-#endif
-
-#ifdef CONFIG_SA1100_H3100
-static struct sa1100fb_mach_info h3100_info __initdata = {
-       .pixclock       = 406977,       .bpp            = 4,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 26,           .vsync_len      = 41,
-       .left_margin    = 4,            .upper_margin   = 0,
-       .right_margin   = 4,            .lower_margin   = 0,
-
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-       .cmap_greyscale = 1,
-       .cmap_inverse   = 1,
-
-       .lccr0          = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-#endif
-
-#ifdef CONFIG_SA1100_COLLIE
-static struct sa1100fb_mach_info collie_info __initdata = {
-       .pixclock       = 171521,       .bpp            = 16,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 5,            .vsync_len      = 1,
-       .left_margin    = 11,           .upper_margin   = 2,
-       .right_margin   = 30,           .lower_margin   = 0,
-
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
-};
-#endif
-
-#ifdef LART_GREY_LCD
-static struct sa1100fb_mach_info lart_grey_info __initdata = {
-       .pixclock       = 150000,       .bpp            = 4,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 1,            .vsync_len      = 1,
-       .left_margin    = 4,            .upper_margin   = 0,
-       .right_margin   = 2,            .lower_margin   = 0,
-
-       .cmap_greyscale = 1,
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-       .lccr0          = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-#ifdef LART_COLOR_LCD
-static struct sa1100fb_mach_info lart_color_info __initdata = {
-       .pixclock       = 150000,       .bpp            = 16,
-       .xres           = 320,          .yres           = 240,
-
-       .hsync_len      = 2,            .vsync_len      = 3,
-       .left_margin    = 69,           .upper_margin   = 14,
-       .right_margin   = 8,            .lower_margin   = 4,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-#ifdef LART_VIDEO_OUT
-static struct sa1100fb_mach_info lart_video_info __initdata = {
-       .pixclock       = 39721,        .bpp            = 16,
-       .xres           = 640,          .yres           = 480,
-
-       .hsync_len      = 95,           .vsync_len      = 2,
-       .left_margin    = 40,           .upper_margin   = 32,
-       .right_margin   = 24,           .lower_margin   = 11,
-
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
-};
-#endif
-
-#ifdef LART_KIT01_LCD
-static struct sa1100fb_mach_info lart_kit01_info __initdata = {
-       .pixclock       = 63291,        .bpp            = 16,
-       .xres           = 640,          .yres           = 480,
-
-       .hsync_len      = 64,           .vsync_len      = 3,
-       .left_margin    = 122,          .upper_margin   = 45,
-       .right_margin   = 10,           .lower_margin   = 10,
-
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3          = LCCR3_OutEnH | LCCR3_PixFlEdg
-};
-#endif
-
-#ifdef CONFIG_SA1100_SHANNON
-static struct sa1100fb_mach_info shannon_info __initdata = {
-       .pixclock       = 152500,       .bpp            = 8,
-       .xres           = 640,          .yres           = 480,
-
-       .hsync_len      = 4,            .vsync_len      = 3,
-       .left_margin    = 2,            .upper_margin   = 0,
-       .right_margin   = 1,            .lower_margin   = 0,
-
-       .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-       .lccr0          = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
-       .lccr3          = LCCR3_ACBsDiv(512),
-};
-#endif
-
 
 
-static struct sa1100fb_mach_info * __init
-sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
-{
-       struct sa1100fb_mach_info *inf = NULL;
-
-       /*
-        *            R        G       B       T
-        * default  {11,5}, { 5,6}, { 0,5}, { 0,0}
-        * h3600    {12,4}, { 7,4}, { 1,4}, { 0,0}
-        * freebird { 8,4}, { 4,4}, { 0,4}, {12,4}
-        */
-#ifdef CONFIG_SA1100_ASSABET
-       if (machine_is_assabet()) {
-#ifndef ASSABET_PAL_VIDEO
-               inf = &lq039q2ds54_info;
-#else
-               inf = &pal_info;
-#endif
-       }
-#endif
-#ifdef CONFIG_SA1100_H3100
-       if (machine_is_h3100()) {
-               inf = &h3100_info;
-       }
-#endif
-#ifdef CONFIG_SA1100_H3600
-       if (machine_is_h3600()) {
-               inf = &h3600_info;
-               fbi->rgb[RGB_16] = &h3600_rgb_16;
-       }
-#endif
-#ifdef CONFIG_SA1100_COLLIE
-       if (machine_is_collie()) {
-               inf = &collie_info;
-       }
-#endif
-#ifdef CONFIG_SA1100_LART
-       if (machine_is_lart()) {
-#ifdef LART_GREY_LCD
-               inf = &lart_grey_info;
-#endif
-#ifdef LART_COLOR_LCD
-               inf = &lart_color_info;
-#endif
-#ifdef LART_VIDEO_OUT
-               inf = &lart_video_info;
-#endif
-#ifdef LART_KIT01_LCD
-               inf = &lart_kit01_info;
-#endif
-       }
-#endif
-#ifdef CONFIG_SA1100_SHANNON
-       if (machine_is_shannon()) {
-               inf = &shannon_info;
-       }
-#endif
-       return inf;
-}
-
 static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
 static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
 
@@ -533,7 +299,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
         * is what you poke into the framebuffer to produce the
         * colour you requested.
         */
-       if (fbi->cmap_inverse) {
+       if (fbi->inf->cmap_inverse) {
                red   = 0xffff - red;
                green = 0xffff - green;
                blue  = 0xffff - blue;
@@ -607,14 +373,14 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                var->xres = MIN_XRES;
        if (var->yres < MIN_YRES)
                var->yres = MIN_YRES;
-       if (var->xres > fbi->max_xres)
-               var->xres = fbi->max_xres;
-       if (var->yres > fbi->max_yres)
-               var->yres = fbi->max_yres;
+       if (var->xres > fbi->inf->xres)
+               var->xres = fbi->inf->xres;
+       if (var->yres > fbi->inf->yres)
+               var->yres = fbi->inf->yres;
        var->xres_virtual = max(var->xres_virtual, var->xres);
        var->yres_virtual = max(var->yres_virtual, var->yres);
 
-       DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
+       dev_dbg(fbi->dev, "var->bits_per_pixel=%d\n", var->bits_per_pixel);
        switch (var->bits_per_pixel) {
        case 4:
                rgbidx = RGB_4;
@@ -638,16 +404,16 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        var->blue   = fbi->rgb[rgbidx]->blue;
        var->transp = fbi->rgb[rgbidx]->transp;
 
-       DPRINTK("RGBT length = %d:%d:%d:%d\n",
+       dev_dbg(fbi->dev, "RGBT length = %d:%d:%d:%d\n",
                var->red.length, var->green.length, var->blue.length,
                var->transp.length);
 
-       DPRINTK("RGBT offset = %d:%d:%d:%d\n",
+       dev_dbg(fbi->dev, "RGBT offset = %d:%d:%d:%d\n",
                var->red.offset, var->green.offset, var->blue.offset,
                var->transp.offset);
 
 #ifdef CONFIG_CPU_FREQ
-       printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
+       dev_dbg(fbi->dev, "dma period = %d ps, clock = %d kHz\n",
                sa1100fb_display_dma_period(var),
                cpufreq_get(smp_processor_id()));
 #endif
@@ -655,22 +421,10 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        return 0;
 }
 
-static inline void sa1100fb_set_truecolor(u_int is_true_color)
+static void sa1100fb_set_visual(struct sa1100fb_info *fbi, u32 visual)
 {
-       if (machine_is_assabet()) {
-#if 1          // phase 4 or newer Assabet's
-               if (is_true_color)
-                       ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
-               else
-                       ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
-#else
-               // older Assabet's
-               if (is_true_color)
-                       ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
-               else
-                       ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
-#endif
-       }
+       if (fbi->inf->set_visual)
+               fbi->inf->set_visual(visual);
 }
 
 /*
@@ -683,11 +437,11 @@ static int sa1100fb_set_par(struct fb_info *info)
        struct fb_var_screeninfo *var = &info->var;
        unsigned long palette_mem_size;
 
-       DPRINTK("set_par\n");
+       dev_dbg(fbi->dev, "set_par\n");
 
        if (var->bits_per_pixel == 16)
                fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-       else if (!fbi->cmap_static)
+       else if (!fbi->inf->cmap_static)
                fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
        else {
                /*
@@ -704,7 +458,7 @@ static int sa1100fb_set_par(struct fb_info *info)
 
        palette_mem_size = fbi->palette_size * sizeof(u16);
 
-       DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+       dev_dbg(fbi->dev, "palette_mem_size = 0x%08lx\n", palette_mem_size);
 
        fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
        fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
@@ -712,7 +466,7 @@ static int sa1100fb_set_par(struct fb_info *info)
        /*
         * Set (any) board control register to handle new color depth
         */
-       sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
+       sa1100fb_set_visual(fbi, fbi->fb.fix.visual);
        sa1100fb_activate_var(var, fbi);
 
        return 0;
@@ -728,7 +482,7 @@ sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        /*
         * Make sure the user isn't doing something stupid.
         */
-       if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static))
+       if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->inf->cmap_static))
                return -EINVAL;
 
        return gen_set_cmap(cmap, kspc, con, info);
@@ -775,7 +529,7 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
        struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
        int i;
 
-       DPRINTK("sa1100fb_blank: blank=%d\n", blank);
+       dev_dbg(fbi->dev, "sa1100fb_blank: blank=%d\n", blank);
 
        switch (blank) {
        case FB_BLANK_POWERDOWN:
@@ -863,43 +617,43 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
        u_int half_screen_size, yres, pcd;
        u_long flags;
 
-       DPRINTK("Configuring SA1100 LCD\n");
+       dev_dbg(fbi->dev, "Configuring SA1100 LCD\n");
 
-       DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
+       dev_dbg(fbi->dev, "var: xres=%d hslen=%d lm=%d rm=%d\n",
                var->xres, var->hsync_len,
                var->left_margin, var->right_margin);
-       DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
+       dev_dbg(fbi->dev, "var: yres=%d vslen=%d um=%d bm=%d\n",
                var->yres, var->vsync_len,
                var->upper_margin, var->lower_margin);
 
 #if DEBUG_VAR
        if (var->xres < 16        || var->xres > 1024)
-               printk(KERN_ERR "%s: invalid xres %d\n",
+               dev_err(fbi->dev, "%s: invalid xres %d\n",
                        fbi->fb.fix.id, var->xres);
        if (var->hsync_len < 1    || var->hsync_len > 64)
-               printk(KERN_ERR "%s: invalid hsync_len %d\n",
+               dev_err(fbi->dev, "%s: invalid hsync_len %d\n",
                        fbi->fb.fix.id, var->hsync_len);
        if (var->left_margin < 1  || var->left_margin > 255)
-               printk(KERN_ERR "%s: invalid left_margin %d\n",
+               dev_err(fbi->dev, "%s: invalid left_margin %d\n",
                        fbi->fb.fix.id, var->left_margin);
        if (var->right_margin < 1 || var->right_margin > 255)
-               printk(KERN_ERR "%s: invalid right_margin %d\n",
+               dev_err(fbi->dev, "%s: invalid right_margin %d\n",
                        fbi->fb.fix.id, var->right_margin);
        if (var->yres < 1         || var->yres > 1024)
-               printk(KERN_ERR "%s: invalid yres %d\n",
+               dev_err(fbi->dev, "%s: invalid yres %d\n",
                        fbi->fb.fix.id, var->yres);
        if (var->vsync_len < 1    || var->vsync_len > 64)
-               printk(KERN_ERR "%s: invalid vsync_len %d\n",
+               dev_err(fbi->dev, "%s: invalid vsync_len %d\n",
                        fbi->fb.fix.id, var->vsync_len);
        if (var->upper_margin < 0 || var->upper_margin > 255)
-               printk(KERN_ERR "%s: invalid upper_margin %d\n",
+               dev_err(fbi->dev, "%s: invalid upper_margin %d\n",
                        fbi->fb.fix.id, var->upper_margin);
        if (var->lower_margin < 0 || var->lower_margin > 255)
-               printk(KERN_ERR "%s: invalid lower_margin %d\n",
+               dev_err(fbi->dev, "%s: invalid lower_margin %d\n",
                        fbi->fb.fix.id, var->lower_margin);
 #endif
 
-       new_regs.lccr0 = fbi->lccr0 |
+       new_regs.lccr0 = fbi->inf->lccr0 |
                LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
                LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
 
@@ -914,7 +668,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
         * the YRES parameter.
         */
        yres = var->yres;
-       if (fbi->lccr0 & LCCR0_Dual)
+       if (fbi->inf->lccr0 & LCCR0_Dual)
                yres /= 2;
 
        new_regs.lccr2 =
@@ -924,14 +678,14 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
                LCCR2_EndFrmDel(var->lower_margin);
 
        pcd = get_pcd(var->pixclock, cpufreq_get(0));
-       new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 |
+       new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |
                (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
                (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
 
-       DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0);
-       DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1);
-       DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2);
-       DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3);
+       dev_dbg(fbi->dev, "nlccr0 = 0x%08lx\n", new_regs.lccr0);
+       dev_dbg(fbi->dev, "nlccr1 = 0x%08lx\n", new_regs.lccr1);
+       dev_dbg(fbi->dev, "nlccr2 = 0x%08lx\n", new_regs.lccr2);
+       dev_dbg(fbi->dev, "nlccr3 = 0x%08lx\n", new_regs.lccr3);
 
        half_screen_size = var->bits_per_pixel;
        half_screen_size = half_screen_size * var->xres * var->yres / 16;
@@ -951,9 +705,12 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
         * Only update the registers if the controller is enabled
         * and something has changed.
         */
-       if ((LCCR0 != fbi->reg_lccr0)       || (LCCR1 != fbi->reg_lccr1) ||
-           (LCCR2 != fbi->reg_lccr2)       || (LCCR3 != fbi->reg_lccr3) ||
-           (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2))
+       if (readl_relaxed(fbi->base + LCCR0) != fbi->reg_lccr0 ||
+           readl_relaxed(fbi->base + LCCR1) != fbi->reg_lccr1 ||
+           readl_relaxed(fbi->base + LCCR2) != fbi->reg_lccr2 ||
+           readl_relaxed(fbi->base + LCCR3) != fbi->reg_lccr3 ||
+           readl_relaxed(fbi->base + DBAR1) != fbi->dbar1 ||
+           readl_relaxed(fbi->base + DBAR2) != fbi->dbar2)
                sa1100fb_schedule_work(fbi, C_REENABLE);
 
        return 0;
@@ -967,18 +724,18 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
  */
 static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
 {
-       DPRINTK("backlight o%s\n", on ? "n" : "ff");
+       dev_dbg(fbi->dev, "backlight o%s\n", on ? "n" : "ff");
 
-       if (sa1100fb_backlight_power)
-               sa1100fb_backlight_power(on);
+       if (fbi->inf->backlight_power)
+               fbi->inf->backlight_power(on);
 }
 
 static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
 {
-       DPRINTK("LCD power o%s\n", on ? "n" : "ff");
+       dev_dbg(fbi->dev, "LCD power o%s\n", on ? "n" : "ff");
 
-       if (sa1100fb_lcd_power)
-               sa1100fb_lcd_power(on);
+       if (fbi->inf->lcd_power)
+               fbi->inf->lcd_power(on);
 }
 
 static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
@@ -1008,14 +765,25 @@ static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
        }
 
        if (mask) {
+               unsigned long flags;
+
+               /*
+                * SA-1100 requires the GPIO direction register set
+                * appropriately for the alternate function.  Hence
+                * we set it here via bitmask rather than excessive
+                * fiddling via the GPIO subsystem - and even then
+                * we'll still have to deal with GAFR.
+                */
+               local_irq_save(flags);
                GPDR |= mask;
                GAFR |= mask;
+               local_irq_restore(flags);
        }
 }
 
 static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
 {
-       DPRINTK("Enabling LCD controller\n");
+       dev_dbg(fbi->dev, "Enabling LCD controller\n");
 
        /*
         * Make sure the mode bits are present in the first palette entry
@@ -1024,43 +792,46 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
        fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
 
        /* Sequence from 11.7.10 */
-       LCCR3 = fbi->reg_lccr3;
-       LCCR2 = fbi->reg_lccr2;
-       LCCR1 = fbi->reg_lccr1;
-       LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
-       DBAR1 = fbi->dbar1;
-       DBAR2 = fbi->dbar2;
-       LCCR0 |= LCCR0_LEN;
-
-       if (machine_is_shannon()) {
-               GPDR |= SHANNON_GPIO_DISP_EN;
-               GPSR |= SHANNON_GPIO_DISP_EN;
-       }
-
-       DPRINTK("DBAR1 = 0x%08x\n", DBAR1);
-       DPRINTK("DBAR2 = 0x%08x\n", DBAR2);
-       DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
-       DPRINTK("LCCR1 = 0x%08x\n", LCCR1);
-       DPRINTK("LCCR2 = 0x%08x\n", LCCR2);
-       DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
+       writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3);
+       writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2);
+       writel_relaxed(fbi->reg_lccr1, fbi->base + LCCR1);
+       writel_relaxed(fbi->reg_lccr0 & ~LCCR0_LEN, fbi->base + LCCR0);
+       writel_relaxed(fbi->dbar1, fbi->base + DBAR1);
+       writel_relaxed(fbi->dbar2, fbi->base + DBAR2);
+       writel_relaxed(fbi->reg_lccr0 | LCCR0_LEN, fbi->base + LCCR0);
+
+       if (machine_is_shannon())
+               gpio_set_value(SHANNON_GPIO_DISP_EN, 1);
+
+       dev_dbg(fbi->dev, "DBAR1: 0x%08x\n", readl_relaxed(fbi->base + DBAR1));
+       dev_dbg(fbi->dev, "DBAR2: 0x%08x\n", readl_relaxed(fbi->base + DBAR2));
+       dev_dbg(fbi->dev, "LCCR0: 0x%08x\n", readl_relaxed(fbi->base + LCCR0));
+       dev_dbg(fbi->dev, "LCCR1: 0x%08x\n", readl_relaxed(fbi->base + LCCR1));
+       dev_dbg(fbi->dev, "LCCR2: 0x%08x\n", readl_relaxed(fbi->base + LCCR2));
+       dev_dbg(fbi->dev, "LCCR3: 0x%08x\n", readl_relaxed(fbi->base + LCCR3));
 }
 
 static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 {
        DECLARE_WAITQUEUE(wait, current);
+       u32 lccr0;
 
-       DPRINTK("Disabling LCD controller\n");
+       dev_dbg(fbi->dev, "Disabling LCD controller\n");
 
-       if (machine_is_shannon()) {
-               GPCR |= SHANNON_GPIO_DISP_EN;
-       }       
+       if (machine_is_shannon())
+               gpio_set_value(SHANNON_GPIO_DISP_EN, 0);
 
        set_current_state(TASK_UNINTERRUPTIBLE);
        add_wait_queue(&fbi->ctrlr_wait, &wait);
 
-       LCSR = 0xffffffff;      /* Clear LCD Status Register */
-       LCCR0 &= ~LCCR0_LDM;    /* Enable LCD Disable Done Interrupt */
-       LCCR0 &= ~LCCR0_LEN;    /* Disable LCD Controller */
+       /* Clear LCD Status Register */
+       writel_relaxed(~0, fbi->base + LCSR);
+
+       lccr0 = readl_relaxed(fbi->base + LCCR0);
+       lccr0 &= ~LCCR0_LDM;    /* Enable LCD Disable Done Interrupt */
+       writel_relaxed(lccr0, fbi->base + LCCR0);
+       lccr0 &= ~LCCR0_LEN;    /* Disable LCD Controller */
+       writel_relaxed(lccr0, fbi->base + LCCR0);
 
        schedule_timeout(20 * HZ / 1000);
        remove_wait_queue(&fbi->ctrlr_wait, &wait);
@@ -1072,14 +843,15 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
 {
        struct sa1100fb_info *fbi = dev_id;
-       unsigned int lcsr = LCSR;
+       unsigned int lcsr = readl_relaxed(fbi->base + LCSR);
 
        if (lcsr & LCSR_LDD) {
-               LCCR0 |= LCCR0_LDM;
+               u32 lccr0 = readl_relaxed(fbi->base + LCCR0) | LCCR0_LDM;
+               writel_relaxed(lccr0, fbi->base + LCCR0);
                wake_up(&fbi->ctrlr_wait);
        }
 
-       LCSR = lcsr;
+       writel_relaxed(lcsr, fbi->base + LCSR);
        return IRQ_HANDLED;
 }
 
@@ -1268,7 +1040,7 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
        switch (val) {
        case CPUFREQ_ADJUST:
        case CPUFREQ_INCOMPATIBLE:
-               printk(KERN_DEBUG "min dma period: %d ps, "
+               dev_dbg(fbi->dev, "min dma period: %d ps, "
                        "new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
                        policy->max);
                /* todo: fill in min/max values */
@@ -1318,7 +1090,7 @@ static int sa1100fb_resume(struct platform_device *dev)
  *      cache.  Once this area is remapped, all virtual memory
  *      access to the video memory should occur at the new region.
  */
-static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
+static int __devinit sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
 {
        /*
         * We reserve one page for the palette, plus the size
@@ -1344,7 +1116,7 @@ static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
 }
 
 /* Fake monspecs to fill in fbinfo structure */
-static struct fb_monspecs monspecs __initdata = {
+static struct fb_monspecs monspecs __devinitdata = {
        .hfmin  = 30000,
        .hfmax  = 70000,
        .vfmin  = 50,
@@ -1352,10 +1124,11 @@ static struct fb_monspecs monspecs __initdata = {
 };
 
 
-static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
+static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev)
 {
-       struct sa1100fb_mach_info *inf;
+       struct sa1100fb_mach_info *inf = dev->platform_data;
        struct sa1100fb_info *fbi;
+       unsigned i;
 
        fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
                      GFP_KERNEL);
@@ -1390,8 +1163,6 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
        fbi->rgb[RGB_8]         = &rgb_8;
        fbi->rgb[RGB_16]        = &def_rgb_16;
 
-       inf = sa1100fb_get_machine_info(fbi);
-
        /*
         * People just don't seem to get this.  We don't support
         * anything but correct entries now, so panic if someone
@@ -1402,13 +1173,10 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
                panic("sa1100fb error: invalid LCCR3 fields set or zero "
                        "pixclock.");
 
-       fbi->max_xres                   = inf->xres;
        fbi->fb.var.xres                = inf->xres;
        fbi->fb.var.xres_virtual        = inf->xres;
-       fbi->max_yres                   = inf->yres;
        fbi->fb.var.yres                = inf->yres;
        fbi->fb.var.yres_virtual        = inf->yres;
-       fbi->max_bpp                    = inf->bpp;
        fbi->fb.var.bits_per_pixel      = inf->bpp;
        fbi->fb.var.pixclock            = inf->pixclock;
        fbi->fb.var.hsync_len           = inf->hsync_len;
@@ -1419,14 +1187,16 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
        fbi->fb.var.lower_margin        = inf->lower_margin;
        fbi->fb.var.sync                = inf->sync;
        fbi->fb.var.grayscale           = inf->cmap_greyscale;
-       fbi->cmap_inverse               = inf->cmap_inverse;
-       fbi->cmap_static                = inf->cmap_static;
-       fbi->lccr0                      = inf->lccr0;
-       fbi->lccr3                      = inf->lccr3;
        fbi->state                      = C_STARTUP;
        fbi->task_state                 = (u_char)-1;
-       fbi->fb.fix.smem_len            = fbi->max_xres * fbi->max_yres *
-                                         fbi->max_bpp / 8;
+       fbi->fb.fix.smem_len            = inf->xres * inf->yres *
+                                         inf->bpp / 8;
+       fbi->inf                        = inf;
+
+       /* Copy the RGB bitfield overrides */
+       for (i = 0; i < NR_RGB; i++)
+               if (inf->rgb[i])
+                       fbi->rgb[i] = inf->rgb[i];
 
        init_waitqueue_head(&fbi->ctrlr_wait);
        INIT_WORK(&fbi->task, sa1100fb_task);
@@ -1438,13 +1208,20 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
 static int __devinit sa1100fb_probe(struct platform_device *pdev)
 {
        struct sa1100fb_info *fbi;
+       struct resource *res;
        int ret, irq;
 
+       if (!pdev->dev.platform_data) {
+               dev_err(&pdev->dev, "no platform LCD data\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
+       if (irq < 0 || !res)
                return -EINVAL;
 
-       if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
+       if (!request_mem_region(res->start, resource_size(res), "LCD"))
                return -EBUSY;
 
        fbi = sa1100fb_init_fbinfo(&pdev->dev);
@@ -1452,6 +1229,10 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
        if (!fbi)
                goto failed;
 
+       fbi->base = ioremap(res->start, resource_size(res));
+       if (!fbi->base)
+               goto failed;
+
        /* Initialize video memory */
        ret = sa1100fb_map_video_memory(fbi);
        if (ret)
@@ -1459,14 +1240,16 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
 
        ret = request_irq(irq, sa1100fb_handle_irq, 0, "LCD", fbi);
        if (ret) {
-               printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
+               dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
                goto failed;
        }
 
-#ifdef ASSABET_PAL_VIDEO
-       if (machine_is_assabet())
-               ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
-#endif
+       if (machine_is_shannon()) {
+               ret = gpio_request_one(SHANNON_GPIO_DISP_EN,
+                       GPIOF_OUT_INIT_LOW, "display enable");
+               if (ret)
+                       goto err_free_irq;
+       }
 
        /*
         * This makes sure that our colour bitfield
@@ -1478,7 +1261,7 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
 
        ret = register_framebuffer(&fbi->fb);
        if (ret < 0)
-               goto err_free_irq;
+               goto err_reg_fb;
 
 #ifdef CONFIG_CPU_FREQ
        fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
@@ -1490,12 +1273,17 @@ static int __devinit sa1100fb_probe(struct platform_device *pdev)
        /* This driver cannot be unloaded at the moment */
        return 0;
 
+ err_reg_fb:
+       if (machine_is_shannon())
+               gpio_free(SHANNON_GPIO_DISP_EN);
  err_free_irq:
        free_irq(irq, fbi);
  failed:
+       if (fbi)
+               iounmap(fbi->base);
        platform_set_drvdata(pdev, NULL);
        kfree(fbi);
-       release_mem_region(0xb0100000, 0x10000);
+       release_mem_region(res->start, resource_size(res));
        return ret;
 }
 
@@ -1505,6 +1293,7 @@ static struct platform_driver sa1100fb_driver = {
        .resume         = sa1100fb_resume,
        .driver         = {
                .name   = "sa11x0-fb",
+               .owner  = THIS_MODULE,
        },
 };
 
index 1c3b459..fc5d429 100644 (file)
  * for more details.
  */
 
-/*
- * These are the bitfields for each
- * display depth that we support.
- */
-struct sa1100fb_rgb {
-       struct fb_bitfield      red;
-       struct fb_bitfield      green;
-       struct fb_bitfield      blue;
-       struct fb_bitfield      transp;
-};
-
-/*
- * This structure describes the machine which we are running on.
- */
-struct sa1100fb_mach_info {
-       u_long          pixclock;
-
-       u_short         xres;
-       u_short         yres;
-
-       u_char          bpp;
-       u_char          hsync_len;
-       u_char          left_margin;
-       u_char          right_margin;
-
-       u_char          vsync_len;
-       u_char          upper_margin;
-       u_char          lower_margin;
-       u_char          sync;
-
-       u_int           cmap_greyscale:1,
-                       cmap_inverse:1,
-                       cmap_static:1,
-                       unused:29;
-
-       u_int           lccr0;
-       u_int           lccr3;
-};
+#define LCCR0           0x0000          /* LCD Control Reg. 0 */
+#define LCSR            0x0004          /* LCD Status Reg. */
+#define DBAR1           0x0010          /* LCD DMA Base Address Reg. channel 1 */
+#define DCAR1           0x0014          /* LCD DMA Current Address Reg. channel 1 */
+#define DBAR2           0x0018          /* LCD DMA Base Address Reg.  channel 2 */
+#define DCAR2           0x001C          /* LCD DMA Current Address Reg. channel 2 */
+#define LCCR1           0x0020          /* LCD Control Reg. 1 */
+#define LCCR2           0x0024          /* LCD Control Reg. 2 */
+#define LCCR3           0x0028          /* LCD Control Reg. 3 */
 
 /* Shadows for LCD controller registers */
 struct sa1100fb_lcd_reg {
@@ -57,19 +28,11 @@ struct sa1100fb_lcd_reg {
        unsigned long lccr3;
 };
 
-#define RGB_4  (0)
-#define RGB_8  (1)
-#define RGB_16 (2)
-#define NR_RGB 3
-
 struct sa1100fb_info {
        struct fb_info          fb;
        struct device           *dev;
-       struct sa1100fb_rgb     *rgb[NR_RGB];
-
-       u_int                   max_bpp;
-       u_int                   max_xres;
-       u_int                   max_yres;
+       const struct sa1100fb_rgb *rgb[NR_RGB];
+       void __iomem            *base;
 
        /*
         * These are the addresses we mapped
@@ -88,12 +51,6 @@ struct sa1100fb_info {
        dma_addr_t              dbar1;
        dma_addr_t              dbar2;
 
-       u_int                   lccr0;
-       u_int                   lccr3;
-       u_int                   cmap_inverse:1,
-                               cmap_static:1,
-                               unused:30;
-
        u_int                   reg_lccr0;
        u_int                   reg_lccr1;
        u_int                   reg_lccr2;
@@ -109,6 +66,8 @@ struct sa1100fb_info {
        struct notifier_block   freq_transition;
        struct notifier_block   freq_policy;
 #endif
+
+       const struct sa1100fb_mach_info *inf;
 };
 
 #define TO_INF(ptr,member)     container_of(ptr,struct sa1100fb_info,member)
@@ -130,15 +89,6 @@ struct sa1100fb_info {
 #define SA1100_NAME    "SA1100"
 
 /*
- *  Debug macros 
- */
-#if DEBUG
-#  define DPRINTK(fmt, args...)        printk("%s: " fmt, __func__ , ## args)
-#else
-#  define DPRINTK(fmt, args...)
-#endif
-
-/*
  * Minimum X and Y resolutions
  */
 #define MIN_XRES       64
index 9db3de3..260cca7 100644 (file)
@@ -121,7 +121,7 @@ static int uvesafb_helper_start(void)
                NULL,
        };
 
-       return call_usermodehelper(v86d_path, argv, envp, 1);
+       return call_usermodehelper(v86d_path, argv, envp, UMH_WAIT_PROC);
 }
 
 /*
index 7e9e8f4..3709624 100644 (file)
@@ -55,6 +55,7 @@ comment "Watchdog Device Drivers"
 
 config SOFT_WATCHDOG
        tristate "Software watchdog"
+       select WATCHDOG_CORE
        help
          A software monitoring watchdog. This will fail to reboot your system
          from some situations that the hardware watchdog will recover
@@ -74,6 +75,7 @@ config WM831X_WATCHDOG
 config WM8350_WATCHDOG
        tristate "WM8350 watchdog"
        depends on MFD_WM8350
+       select WATCHDOG_CORE
        help
          Support for the watchdog in the WM8350 AudioPlus PMIC.  When
          the watchdog triggers the system will be reset.
@@ -170,7 +172,7 @@ config HAVE_S3C2410_WATCHDOG
 
 config S3C2410_WATCHDOG
        tristate "S3C2410 Watchdog"
-       depends on ARCH_S3C2410 || HAVE_S3C2410_WATCHDOG
+       depends on HAVE_S3C2410_WATCHDOG
        select WATCHDOG_CORE
        help
          Watchdog timer block in the Samsung SoCs. This will reboot
@@ -217,6 +219,7 @@ config MPCORE_WATCHDOG
 config EP93XX_WATCHDOG
        tristate "EP93xx Watchdog"
        depends on ARCH_EP93XX
+       select WATCHDOG_CORE
        help
          Say Y here if to include support for the watchdog timer
          embedded in the Cirrus Logic EP93xx family of devices.
@@ -234,6 +237,7 @@ config OMAP_WATCHDOG
 config PNX4008_WATCHDOG
        tristate "PNX4008 and LPC32XX Watchdog"
        depends on ARCH_PNX4008 || ARCH_LPC32XX
+       select WATCHDOG_CORE
        help
          Say Y here if to include support for the watchdog timer
          in the PNX4008 or LPC32XX processor.
@@ -283,6 +287,7 @@ config COH901327_WATCHDOG
        bool "ST-Ericsson COH 901 327 watchdog"
        depends on ARCH_U300
        default y if MACH_U300
+       select WATCHDOG_CORE
        help
          Say Y here to include Watchdog timer support for the
          watchdog embedded into the ST-Ericsson U300 series platforms.
@@ -328,6 +333,7 @@ config TS72XX_WATCHDOG
 config MAX63XX_WATCHDOG
        tristate "Max63xx watchdog"
        depends on ARM && HAS_IOMEM
+       select WATCHDOG_CORE
        help
          Support for memory mapped max63{69,70,71,72,73,74} watchdog timer.
 
@@ -955,6 +961,7 @@ config INDYDOG
 config JZ4740_WDT
        tristate "Ingenic jz4740 SoC hardware watchdog"
        depends on MACH_JZ4740
+       select WATCHDOG_CORE
        help
          Hardware driver for the built-in watchdog timer on Ingenic jz4740 SoCs.
 
@@ -996,6 +1003,7 @@ config AR7_WDT
 config TXX9_WDT
        tristate "Toshiba TXx9 Watchdog Timer"
        depends on CPU_TX39XX || CPU_TX49XX
+       select WATCHDOG_CORE
        help
          Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
 
index b6a2b58..4397881 100644 (file)
@@ -52,6 +52,8 @@
  *     Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 /* Includes */
 #include <linux/module.h>              /* For module specific items */
 #include <linux/moduleparam.h>         /* For new moduleparam's */
@@ -70,7 +72,6 @@
 
 /* Module information */
 #define DRV_NAME "acquirewdt"
-#define PFX DRV_NAME ": "
 #define WATCHDOG_NAME "Acquire WDT"
 /* There is no way to see what the correct time-out period is */
 #define WATCHDOG_HEARTBEAT 0
@@ -92,8 +93,8 @@ static int wdt_start = 0x443;
 module_param(wdt_start, int, 0);
 MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -208,8 +209,7 @@ static int acq_close(struct inode *inode, struct file *file)
        if (expect_close == 42) {
                acq_stop();
        } else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                acq_keepalive();
        }
        clear_bit(0, &acq_is_open);
@@ -246,27 +246,24 @@ static int __devinit acq_probe(struct platform_device *dev)
 
        if (wdt_stop != wdt_start) {
                if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
-                       printk(KERN_ERR PFX
-                           "I/O address 0x%04x already in use\n", wdt_stop);
+                       pr_err("I/O address 0x%04x already in use\n", wdt_stop);
                        ret = -EIO;
                        goto out;
                }
        }
 
        if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       wdt_start);
+               pr_err("I/O address 0x%04x already in use\n", wdt_start);
                ret = -EIO;
                goto unreg_stop;
        }
        ret = misc_register(&acq_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto unreg_regions;
        }
-       printk(KERN_INFO PFX "initialized. (nowayout=%d)\n", nowayout);
+       pr_info("initialized. (nowayout=%d)\n", nowayout);
 
        return 0;
 unreg_regions:
@@ -308,8 +305,7 @@ static int __init acq_init(void)
 {
        int err;
 
-       printk(KERN_INFO
-             "WDT driver for Acquire single board computer initialising.\n");
+       pr_info("WDT driver for Acquire single board computer initialising\n");
 
        err = platform_driver_register(&acquirewdt_driver);
        if (err)
@@ -332,7 +328,7 @@ static void __exit acq_exit(void)
 {
        platform_device_unregister(acq_platform_device);
        platform_driver_unregister(&acquirewdt_driver);
-       printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+       pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(acq_init);
index 6112bef..64ae9e9 100644 (file)
@@ -28,6 +28,8 @@
  *         add wdt_start and wdt_stop as parameters.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -42,7 +44,6 @@
 
 
 #define DRV_NAME "advantechwdt"
-#define PFX DRV_NAME ": "
 #define WATCHDOG_NAME "Advantech WDT"
 #define WATCHDOG_TIMEOUT 60            /* 60 sec default timeout */
 
@@ -76,8 +77,8 @@ MODULE_PARM_DESC(timeout,
        "Watchdog timeout in seconds. 1<= timeout <=63, default="
                __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -206,8 +207,7 @@ static int advwdt_close(struct inode *inode, struct file *file)
        if (adv_expect_close == 42) {
                advwdt_disable();
        } else {
-               printk(KERN_CRIT PFX
-                               "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                advwdt_ping();
        }
        clear_bit(0, &advwdt_is_open);
@@ -244,18 +244,15 @@ static int __devinit advwdt_probe(struct platform_device *dev)
 
        if (wdt_stop != wdt_start) {
                if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
-                       printk(KERN_ERR PFX
-                               "I/O address 0x%04x already in use\n",
-                                                               wdt_stop);
+                       pr_err("I/O address 0x%04x already in use\n",
+                              wdt_stop);
                        ret = -EIO;
                        goto out;
                }
        }
 
        if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
-               printk(KERN_ERR PFX
-                               "I/O address 0x%04x already in use\n",
-                                                               wdt_start);
+               pr_err("I/O address 0x%04x already in use\n", wdt_start);
                ret = -EIO;
                goto unreg_stop;
        }
@@ -264,18 +261,16 @@ static int __devinit advwdt_probe(struct platform_device *dev)
         * if not reset to the default */
        if (advwdt_set_heartbeat(timeout)) {
                advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
-               printk(KERN_INFO PFX
-                       "timeout value must be 1<=x<=63, using %d\n", timeout);
+               pr_info("timeout value must be 1<=x<=63, using %d\n", timeout);
        }
 
        ret = misc_register(&advwdt_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto unreg_regions;
        }
-       printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+       pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
                timeout, nowayout);
 out:
        return ret;
@@ -317,8 +312,7 @@ static int __init advwdt_init(void)
 {
        int err;
 
-       printk(KERN_INFO
-            "WDT driver for Advantech single board computer initialising.\n");
+       pr_info("WDT driver for Advantech single board computer initialising\n");
 
        err = platform_driver_register(&advwdt_driver);
        if (err)
@@ -342,7 +336,7 @@ static void __exit advwdt_exit(void)
 {
        platform_device_unregister(advwdt_platform_device);
        platform_driver_unregister(&advwdt_driver);
-       printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+       pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(advwdt_init);
index f16dcbd..41b8493 100644 (file)
@@ -7,6 +7,8 @@
  *     2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -22,7 +24,6 @@
 #include <linux/io.h>
 
 #define WATCHDOG_NAME "ALi_M1535"
-#define PFX WATCHDOG_NAME ": "
 #define WATCHDOG_TIMEOUT 60    /* 60 sec default timeout */
 
 /* internal variables */
@@ -39,8 +40,8 @@ MODULE_PARM_DESC(timeout,
                "Watchdog timeout in seconds. (0 < timeout < 18000, default="
                                __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -268,8 +269,7 @@ static int ali_release(struct inode *inode, struct file *file)
        if (ali_expect_release == 42)
                ali_stop();
        else {
-               printk(KERN_CRIT PFX
-                               "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                ali_keepalive();
        }
        clear_bit(0, &ali_is_open);
@@ -399,9 +399,8 @@ static int __init watchdog_init(void)
           if not reset to the default */
        if (timeout < 1 || timeout >= 18000) {
                timeout = WATCHDOG_TIMEOUT;
-               printk(KERN_INFO PFX
-                    "timeout value must be 0 < timeout < 18000, using %d\n",
-                                                       timeout);
+               pr_info("timeout value must be 0 < timeout < 18000, using %d\n",
+                       timeout);
        }
 
        /* Calculate the watchdog's timeout */
@@ -409,20 +408,18 @@ static int __init watchdog_init(void)
 
        ret = register_reboot_notifier(&ali_notifier);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                goto out;
        }
 
        ret = misc_register(&ali_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                               WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto unreg_reboot;
        }
 
-       printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+       pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
                timeout, nowayout);
 
 out:
index 4868418..5eee550 100644 (file)
@@ -19,6 +19,8 @@
  *                  -- Mike Waychison <michael.waychison@sun.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -35,9 +37,6 @@
 #include <linux/uaccess.h>
 
 
-#define OUR_NAME "alim7101_wdt"
-#define PFX OUR_NAME ": "
-
 #define WDT_ENABLE 0x9C
 #define WDT_DISABLE 0x8C
 
@@ -78,8 +77,8 @@ static unsigned long wdt_is_open;
 static char wdt_expect_close;
 static struct pci_dev *alim7101_pmu;
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -111,8 +110,7 @@ static void wdt_timer_ping(unsigned long data)
                                        ALI_7101_GPIO_O, tmp & ~0x20);
                }
        } else {
-               printk(KERN_WARNING PFX
-                       "Heartbeat lost! Will not ping the watchdog\n");
+               pr_warn("Heartbeat lost! Will not ping the watchdog\n");
        }
        /* Re-set the timer interval */
        mod_timer(&timer, jiffies + WDT_INTERVAL);
@@ -161,7 +159,7 @@ static void wdt_startup(void)
        /* Start the timer */
        mod_timer(&timer, jiffies + WDT_INTERVAL);
 
-       printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+       pr_info("Watchdog timer is now enabled\n");
 }
 
 static void wdt_turnoff(void)
@@ -169,7 +167,7 @@ static void wdt_turnoff(void)
        /* Stop the timer */
        del_timer_sync(&timer);
        wdt_change(WDT_DISABLE);
-       printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+       pr_info("Watchdog timer is now disabled...\n");
 }
 
 static void wdt_keepalive(void)
@@ -225,8 +223,7 @@ static int fop_close(struct inode *inode, struct file *file)
                wdt_turnoff();
        else {
                /* wim: shouldn't there be a: del_timer(&timer); */
-               printk(KERN_CRIT PFX
-                 "device file closed unexpectedly. Will not stop the WDT!\n");
+               pr_crit("device file closed unexpectedly. Will not stop the WDT!\n");
        }
        clear_bit(0, &wdt_is_open);
        wdt_expect_close = 0;
@@ -321,8 +318,7 @@ static int wdt_notify_sys(struct notifier_block *this,
                 * watchdog on reboot with no heartbeat
                 */
                wdt_change(WDT_ENABLE);
-               printk(KERN_INFO PFX "Watchdog timer is now enabled "
-                       "with no heartbeat - should reboot in ~1 second.\n");
+               pr_info("Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second\n");
        }
        return NOTIFY_DONE;
 }
@@ -351,12 +347,11 @@ static int __init alim7101_wdt_init(void)
        struct pci_dev *ali1543_south;
        char tmp;
 
-       printk(KERN_INFO PFX "Steve Hill <steve@navaho.co.uk>.\n");
+       pr_info("Steve Hill <steve@navaho.co.uk>\n");
        alim7101_pmu = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
                NULL);
        if (!alim7101_pmu) {
-               printk(KERN_INFO PFX
-                       "ALi M7101 PMU not present - WDT not set\n");
+               pr_info("ALi M7101 PMU not present - WDT not set\n");
                return -EBUSY;
        }
 
@@ -366,56 +361,46 @@ static int __init alim7101_wdt_init(void)
        ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
                NULL);
        if (!ali1543_south) {
-               printk(KERN_INFO PFX
-                       "ALi 1543 South-Bridge not present - WDT not set\n");
+               pr_info("ALi 1543 South-Bridge not present - WDT not set\n");
                goto err_out;
        }
        pci_read_config_byte(ali1543_south, 0x5e, &tmp);
        pci_dev_put(ali1543_south);
        if ((tmp & 0x1e) == 0x00) {
                if (!use_gpio) {
-                       printk(KERN_INFO PFX
-                               "Detected old alim7101 revision 'a1d'.  "
-                               "If this is a cobalt board, set the 'use_gpio' "
-                               "module parameter.\n");
+                       pr_info("Detected old alim7101 revision 'a1d'.  If this is a cobalt board, set the 'use_gpio' module parameter.\n");
                        goto err_out;
                }
                nowayout = 1;
        } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
-               printk(KERN_INFO PFX
-                       "ALi 1543 South-Bridge does not have the correct "
-                       "revision number (???1001?) - WDT not set\n");
+               pr_info("ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
                goto err_out;
        }
 
        if (timeout < 1 || timeout > 3600) {
                /* arbitrary upper limit */
                timeout = WATCHDOG_TIMEOUT;
-               printk(KERN_INFO PFX
-                       "timeout value must be 1 <= x <= 3600, using %d\n",
-                                                               timeout);
+               pr_info("timeout value must be 1 <= x <= 3600, using %d\n",
+                       timeout);
        }
 
        rc = register_reboot_notifier(&wdt_notifier);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", rc);
+               pr_err("cannot register reboot notifier (err=%d)\n", rc);
                goto err_out;
        }
 
        rc = misc_register(&wdt_miscdev);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                       wdt_miscdev.minor, rc);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      wdt_miscdev.minor, rc);
                goto err_out_reboot;
        }
 
        if (nowayout)
                __module_get(THIS_MODULE);
 
-       printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. "
-                                       "timeout=%d sec (nowayout=%d)\n",
+       pr_info("WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n",
                timeout, nowayout);
        return 0;
 
index 502773a..639ae9a 100644 (file)
@@ -23,6 +23,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/errno.h>
@@ -39,7 +41,6 @@
 #include <asm/addrspace.h>
 #include <asm/mach-ar7/ar7.h>
 
-#define DRVNAME "ar7_wdt"
 #define LONGNAME "TI AR7 Watchdog Timer"
 
 MODULE_AUTHOR("Nicolas Thill <nico@openwrt.org>");
@@ -51,8 +52,8 @@ static int margin = 60;
 module_param(margin, int, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
 #define READ_REG(x) readl((void __iomem *)&(x))
@@ -93,7 +94,7 @@ static void ar7_wdt_kick(u32 value)
                        return;
                }
        }
-       printk(KERN_ERR DRVNAME ": failed to unlock WDT kick reg\n");
+       pr_err("failed to unlock WDT kick reg\n");
 }
 
 static void ar7_wdt_prescale(u32 value)
@@ -106,7 +107,7 @@ static void ar7_wdt_prescale(u32 value)
                        return;
                }
        }
-       printk(KERN_ERR DRVNAME ": failed to unlock WDT prescale reg\n");
+       pr_err("failed to unlock WDT prescale reg\n");
 }
 
 static void ar7_wdt_change(u32 value)
@@ -119,7 +120,7 @@ static void ar7_wdt_change(u32 value)
                        return;
                }
        }
-       printk(KERN_ERR DRVNAME ": failed to unlock WDT change reg\n");
+       pr_err("failed to unlock WDT change reg\n");
 }
 
 static void ar7_wdt_disable(u32 value)
@@ -135,7 +136,7 @@ static void ar7_wdt_disable(u32 value)
                        }
                }
        }
-       printk(KERN_ERR DRVNAME ": failed to unlock WDT disable reg\n");
+       pr_err("failed to unlock WDT disable reg\n");
 }
 
 static void ar7_wdt_update_margin(int new_margin)
@@ -151,21 +152,20 @@ static void ar7_wdt_update_margin(int new_margin)
                change = 0xffff;
        ar7_wdt_change(change);
        margin = change * prescale_value / vbus_rate;
-       printk(KERN_INFO DRVNAME
-              ": timer margin %d seconds (prescale %d, change %d, freq %d)\n",
-              margin, prescale_value, change, vbus_rate);
+       pr_info("timer margin %d seconds (prescale %d, change %d, freq %d)\n",
+               margin, prescale_value, change, vbus_rate);
 }
 
 static void ar7_wdt_enable_wdt(void)
 {
-       printk(KERN_DEBUG DRVNAME ": enabling watchdog timer\n");
+       pr_debug("enabling watchdog timer\n");
        ar7_wdt_disable(1);
        ar7_wdt_kick(1);
 }
 
 static void ar7_wdt_disable_wdt(void)
 {
-       printk(KERN_DEBUG DRVNAME ": disabling watchdog timer\n");
+       pr_debug("disabling watchdog timer\n");
        ar7_wdt_disable(0);
 }
 
@@ -183,9 +183,7 @@ static int ar7_wdt_open(struct inode *inode, struct file *file)
 static int ar7_wdt_release(struct inode *inode, struct file *file)
 {
        if (!expect_close)
-               printk(KERN_WARNING DRVNAME
-               ": watchdog device closed unexpectedly,"
-               "will not disable the watchdog timer\n");
+               pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n");
        else if (!nowayout)
                ar7_wdt_disable_wdt();
        clear_bit(0, &wdt_is_open);
@@ -283,28 +281,28 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
        ar7_regs_wdt =
                platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
        if (!ar7_regs_wdt) {
-               printk(KERN_ERR DRVNAME ": could not get registers resource\n");
+               pr_err("could not get registers resource\n");
                rc = -ENODEV;
                goto out;
        }
 
        if (!request_mem_region(ar7_regs_wdt->start,
                                resource_size(ar7_regs_wdt), LONGNAME)) {
-               printk(KERN_WARNING DRVNAME ": watchdog I/O region busy\n");
+               pr_warn("watchdog I/O region busy\n");
                rc = -EBUSY;
                goto out;
        }
 
        ar7_wdt = ioremap(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
        if (!ar7_wdt) {
-               printk(KERN_ERR DRVNAME ": could not ioremap registers\n");
+               pr_err("could not ioremap registers\n");
                rc = -ENXIO;
                goto out_mem_region;
        }
 
        vbus_clk = clk_get(NULL, "vbus");
        if (IS_ERR(vbus_clk)) {
-               printk(KERN_ERR DRVNAME ": could not get vbus clock\n");
+               pr_err("could not get vbus clock\n");
                rc = PTR_ERR(vbus_clk);
                goto out_mem_region;
        }
@@ -315,7 +313,7 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
 
        rc = misc_register(&ar7_wdt_miscdev);
        if (rc) {
-               printk(KERN_ERR DRVNAME ": unable to register misc device\n");
+               pr_err("unable to register misc device\n");
                goto out_alloc;
        }
        goto out;
index 4ca5d40..2896430 100644 (file)
@@ -45,8 +45,8 @@ MODULE_PARM_DESC(timeout,
                "Timeout value. Limited to be 1 or 2 seconds. (default="
                __MODULE_STRING(TIMEOUT_DEFAULT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
index b3046dc..7ef99a1 100644 (file)
@@ -9,6 +9,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #define WDT_MAX_TIME           256     /* seconds */
 
 static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 module_param(wdt_time, int, 0);
 MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
                                __MODULE_STRING(WDT_DEFAULT_TIME) ")");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -51,7 +53,7 @@ static unsigned long at91wdt_busy;
  */
 static inline void at91_wdt_stop(void)
 {
-       at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN);
+       at91_st_write(AT91_ST_WDMR, AT91_ST_EXTEN);
 }
 
 /*
@@ -59,9 +61,9 @@ static inline void at91_wdt_stop(void)
  */
 static inline void at91_wdt_start(void)
 {
-       at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN |
+       at91_st_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN |
                                (((65536 * wdt_time) >> 8) & AT91_ST_WDV));
-       at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+       at91_st_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
 /*
@@ -69,7 +71,7 @@ static inline void at91_wdt_start(void)
  */
 static inline void at91_wdt_reload(void)
 {
-       at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
+       at91_st_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
 /* ......................................................................... */
@@ -209,8 +211,8 @@ static int __devinit at91wdt_probe(struct platform_device *pdev)
        if (res)
                return res;
 
-       printk(KERN_INFO "AT91 Watchdog Timer enabled (%d seconds%s)\n",
-                               wdt_time, nowayout ? ", nowayout" : "");
+       pr_info("AT91 Watchdog Timer enabled (%d seconds%s)\n",
+               wdt_time, nowayout ? ", nowayout" : "");
        return 0;
 }
 
@@ -268,8 +270,8 @@ static int __init at91_wdt_init(void)
           if not reset to the default */
        if (at91_wdt_settimeout(wdt_time)) {
                at91_wdt_settimeout(WDT_DEFAULT_TIME);
-               pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256"
-                                               ", using %d\n", wdt_time);
+               pr_info("wdt_time value must be 1 <= wdt_time <= 256, using %d\n",
+                       wdt_time);
        }
 
        return platform_driver_register(&at91wdt_driver);
index 0056256..05e1be8 100644 (file)
@@ -15,6 +15,8 @@
  * bootloader doesn't write to this register.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -60,8 +62,8 @@ module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
        "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
        "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -96,7 +98,7 @@ static void at91_ping(unsigned long data)
                at91_wdt_reset();
                mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
        } else
-               printk(KERN_CRIT DRV_NAME": I will reset your machine !\n");
+               pr_crit("I will reset your machine !\n");
 }
 
 /*
@@ -140,7 +142,7 @@ static int at91_wdt_settimeout(unsigned int timeout)
        /* Check if disabled */
        mr = wdt_read(AT91_WDT_MR);
        if (mr & AT91_WDT_WDDIS) {
-               printk(KERN_ERR DRV_NAME": sorry, watchdog is disabled\n");
+               pr_err("sorry, watchdog is disabled\n");
                return -EIO;
        }
 
@@ -283,7 +285,7 @@ static int __init at91wdt_probe(struct platform_device *pdev)
        setup_timer(&at91wdt_private.timer, at91_ping, 0);
        mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
 
-       printk(KERN_INFO DRV_NAME " enabled (heartbeat=%d sec, nowayout=%d)\n",
+       pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n",
                heartbeat, nowayout);
 
        return 0;
index 9db8083..1f9371f 100644 (file)
@@ -17,6 +17,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -45,8 +47,8 @@
 #define WDOG_CTRL_ACTION_NMI   2       /* NMI */
 #define WDOG_CTRL_ACTION_FCR   3       /* full chip reset */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
                           "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -114,8 +116,7 @@ static int ath79_wdt_release(struct inode *inode, struct file *file)
        if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags))
                ath79_wdt_disable();
        else {
-               pr_crit(DRIVER_NAME ": device closed unexpectedly, "
-                       "watchdog timer will not stop!\n");
+               pr_crit("device closed unexpectedly, watchdog timer will not stop!\n");
                ath79_wdt_keepalive();
        }
 
index 5c5f4b1..bc0e91e 100644 (file)
@@ -10,6 +10,8 @@
  *  2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #define WDT_MAX_TIME           255     /* seconds */
 
 static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 module_param(wdt_time, int, 0);
 MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
                                __MODULE_STRING(WDT_DEFAULT_TIME) ")");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -91,7 +93,7 @@ static void bcm47xx_timer_tick(unsigned long unused)
                bcm47xx_wdt_hw_start();
                mod_timer(&wdt_timer, jiffies + HZ);
        } else {
-               printk(KERN_CRIT DRV_NAME "Watchdog will fire soon!!!\n");
+               pr_crit("Watchdog will fire soon!!!\n");
        }
 }
 
@@ -140,8 +142,7 @@ static int bcm47xx_wdt_release(struct inode *inode, struct file *file)
        if (expect_release == 42) {
                bcm47xx_wdt_stop();
        } else {
-               printk(KERN_CRIT DRV_NAME
-                       ": Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                bcm47xx_wdt_start();
        }
 
@@ -270,8 +271,7 @@ static int __init bcm47xx_wdt_init(void)
 
        if (bcm47xx_wdt_settimeout(wdt_time)) {
                bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME);
-               printk(KERN_INFO DRV_NAME ": "
-                       "wdt_time value must be 0 < wdt_time < %d, using %d\n",
+               pr_info("wdt_time value must be 0 < wdt_time < %d, using %d\n",
                        (WDT_MAX_TIME + 1), wdt_time);
        }
 
@@ -285,8 +285,8 @@ static int __init bcm47xx_wdt_init(void)
                return ret;
        }
 
-       printk(KERN_INFO "BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
-                               wdt_time, nowayout ? ", nowayout" : "");
+       pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
+               wdt_time, nowayout ? ", nowayout" : "");
        return 0;
 }
 
index 8dc7de6..8379dc3 100644 (file)
@@ -10,6 +10,8 @@
  *  2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -50,8 +52,8 @@ static struct {
 static int expect_close;
 
 static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -82,7 +84,7 @@ static void bcm63xx_timer_tick(unsigned long unused)
                bcm63xx_wdt_hw_start();
                mod_timer(&bcm63xx_wdt_device.timer, jiffies + HZ);
        } else
-               printk(KERN_CRIT PFX ": watchdog will restart system\n");
+               pr_crit("watchdog will restart system\n");
 }
 
 static void bcm63xx_wdt_pet(void)
@@ -126,8 +128,7 @@ static int bcm63xx_wdt_release(struct inode *inode, struct file *file)
        if (expect_close == 42)
                bcm63xx_wdt_pause();
        else {
-               printk(KERN_CRIT PFX
-                       ": Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                bcm63xx_wdt_start();
        }
        clear_bit(0, &bcm63xx_wdt_device.inuse);
index b9fa9b7..38bc383 100644 (file)
@@ -11,6 +11,8 @@
  * Licensed under the GPL-2 or later.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #define stamp(fmt, args...) \
        pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
 #define stampit() stamp("here i am")
-#define pr_devinit(fmt, args...) \
-       ({ static const __devinitconst char __fmt[] = fmt; \
-       printk(__fmt, ## args); })
-#define pr_init(fmt, args...) \
-       ({ static const __initconst char __fmt[] = fmt; \
-       printk(__fmt, ## args); })
 
 #define WATCHDOG_NAME "bfin-wdt"
-#define PFX WATCHDOG_NAME ": "
 
 /* The BF561 has two watchdogs (one per core), but since Linux
  * only runs on core A, we'll just work with that one.
@@ -54,7 +49,7 @@
 #define WATCHDOG_TIMEOUT 20
 
 static unsigned int timeout = WATCHDOG_TIMEOUT;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static const struct watchdog_info bfin_wdt_info;
 static unsigned long open_check;
 static char expect_close;
@@ -126,7 +121,7 @@ static int bfin_wdt_set_timeout(unsigned long t)
        stamp("maxtimeout=%us newtimeout=%lus (cnt=%#x)", max_t, t, cnt);
 
        if (t > max_t) {
-               printk(KERN_WARNING PFX "timeout value is too large\n");
+               pr_warn("timeout value is too large\n");
                return -EINVAL;
        }
 
@@ -182,8 +177,7 @@ static int bfin_wdt_release(struct inode *inode, struct file *file)
        if (expect_close == 42)
                bfin_wdt_stop();
        else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                bfin_wdt_keepalive();
        }
        expect_close = 0;
@@ -368,14 +362,13 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev)
 
        ret = misc_register(&bfin_wdt_miscdev);
        if (ret) {
-               pr_devinit(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                               WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                return ret;
        }
 
-       pr_devinit(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
-              timeout, nowayout);
+       pr_info("initialized: timeout=%d sec (nowayout=%d)\n",
+               timeout, nowayout);
 
        return 0;
 }
@@ -439,14 +432,14 @@ static int __init bfin_wdt_init(void)
         */
        ret = platform_driver_register(&bfin_wdt_driver);
        if (ret) {
-               pr_init(KERN_ERR PFX "unable to register driver\n");
+               pr_err("unable to register driver\n");
                return ret;
        }
 
        bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME,
                                                                -1, NULL, 0);
        if (IS_ERR(bfin_wdt_device)) {
-               pr_init(KERN_ERR PFX "unable to register device\n");
+               pr_err("unable to register device\n");
                platform_driver_unregister(&bfin_wdt_driver);
                return PTR_ERR(bfin_wdt_device);
        }
@@ -479,7 +472,7 @@ MODULE_PARM_DESC(timeout,
        "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default="
                __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
index 3a76e19..ce0ab44 100644 (file)
@@ -12,6 +12,8 @@
  * option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/smp.h>
@@ -224,8 +226,8 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
        if (booke_wdt_enabled == 0) {
                booke_wdt_enabled = 1;
                on_each_cpu(__booke_wdt_enable, NULL, 0);
-               pr_debug("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
-                       period_to_sec(booke_wdt_period));
+               pr_debug("watchdog enabled (timeout = %llu sec)\n",
+                        period_to_sec(booke_wdt_period));
        }
        spin_unlock(&booke_wdt_lock);
 
@@ -242,7 +244,7 @@ static int booke_wdt_release(struct inode *inode, struct file *file)
         */
        on_each_cpu(__booke_wdt_disable, NULL, 0);
        booke_wdt_enabled = 0;
-       pr_debug("booke_wdt: watchdog disabled\n");
+       pr_debug("watchdog disabled\n");
 #endif
 
        clear_bit(0, &wdt_is_active);
@@ -274,19 +276,19 @@ static int __init booke_wdt_init(void)
 {
        int ret = 0;
 
-       pr_info("booke_wdt: powerpc book-e watchdog driver loaded\n");
+       pr_info("powerpc book-e watchdog driver loaded\n");
        ident.firmware_version = cur_cpu_spec->pvr_value;
 
        ret = misc_register(&booke_wdt_miscdev);
        if (ret) {
-               pr_err("booke_wdt: cannot register device (minor=%u, ret=%i)\n",
+               pr_err("cannot register device (minor=%u, ret=%i)\n",
                       WATCHDOG_MINOR, ret);
                return ret;
        }
 
        spin_lock(&booke_wdt_lock);
        if (booke_wdt_enabled == 1) {
-               pr_info("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
+               pr_info("watchdog enabled (timeout = %llu sec)\n",
                        period_to_sec(booke_wdt_period));
                on_each_cpu(__booke_wdt_enable, NULL, 0);
        }
index 5b89f7d..6876430 100644 (file)
@@ -8,17 +8,15 @@
  */
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/interrupt.h>
 #include <linux/pm.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/bitops.h>
-#include <linux/uaccess.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/err.h>
 
 #define DRV_NAME "WDOG COH 901 327"
 
 #define U300_WDOG_IFR_WILL_BARK_IRQ_FORCE_ENABLE                       0x0001U
 
 /* Default timeout in seconds = 1 minute */
-static int margin = 60;
+static unsigned int margin = 60;
 static resource_size_t phybase;
 static resource_size_t physize;
 static int irq;
 static void __iomem *virtbase;
-static unsigned long coh901327_users;
-static unsigned long boot_status;
 static struct device *parent;
 
 /*
@@ -155,34 +151,35 @@ static void coh901327_disable(void)
                        __func__, val);
 }
 
-static void coh901327_start(void)
+static int coh901327_start(struct watchdog_device *wdt_dev)
 {
-       coh901327_enable(margin * 100);
+       coh901327_enable(wdt_dev->timeout * 100);
+       return 0;
+}
+
+static int coh901327_stop(struct watchdog_device *wdt_dev)
+{
+       coh901327_disable();
+       return 0;
 }
 
-static void coh901327_keepalive(void)
+static int coh901327_ping(struct watchdog_device *wdd)
 {
        clk_enable(clk);
        /* Feed the watchdog */
        writew(U300_WDOG_FR_FEED_RESTART_TIMER,
               virtbase + U300_WDOG_FR);
        clk_disable(clk);
+       return 0;
 }
 
-static int coh901327_settimeout(int time)
+static int coh901327_settimeout(struct watchdog_device *wdt_dev,
+                               unsigned int time)
 {
-       /*
-        * Max margin is 327 since the 10ms
-        * timeout register is max
-        * 0x7FFF = 327670ms ~= 327s.
-        */
-       if (time <= 0 || time > 327)
-               return -EINVAL;
-
-       margin = time;
+       wdt_dev->timeout = time;
        clk_enable(clk);
        /* Set new timeout value */
-       writew(margin * 100, virtbase + U300_WDOG_TR);
+       writew(time * 100, virtbase + U300_WDOG_TR);
        /* Feed the dog */
        writew(U300_WDOG_FR_FEED_RESTART_TIMER,
               virtbase + U300_WDOG_FR);
@@ -190,6 +187,23 @@ static int coh901327_settimeout(int time)
        return 0;
 }
 
+static unsigned int coh901327_gettimeleft(struct watchdog_device *wdt_dev)
+{
+       u16 val;
+
+       clk_enable(clk);
+       /* Read repeatedly until the value is stable! */
+       val = readw(virtbase + U300_WDOG_CR);
+       while (val & U300_WDOG_CR_VALID_IND)
+               val = readw(virtbase + U300_WDOG_CR);
+       val &= U300_WDOG_CR_COUNT_VALUE_MASK;
+       clk_disable(clk);
+       if (val != 0)
+               val /= 100;
+
+       return val;
+}
+
 /*
  * This interrupt occurs 10 ms before the watchdog WILL bark.
  */
@@ -218,130 +232,35 @@ static irqreturn_t coh901327_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-/*
- * Allow only one user (daemon) to open the watchdog
- */
-static int coh901327_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(1, &coh901327_users))
-               return -EBUSY;
-       coh901327_start();
-       return nonseekable_open(inode, file);
-}
-
-static int coh901327_release(struct inode *inode, struct file *file)
-{
-       clear_bit(1, &coh901327_users);
-       coh901327_disable();
-       return 0;
-}
-
-static ssize_t coh901327_write(struct file *file, const char __user *data,
-                              size_t len, loff_t *ppos)
-{
-       if (len)
-               coh901327_keepalive();
-       return len;
-}
-
-static long coh901327_ioctl(struct file *file, unsigned int cmd,
-                           unsigned long arg)
-{
-       int ret = -ENOTTY;
-       u16 val;
-       int time;
-       int new_options;
-       union {
-               struct watchdog_info __user *ident;
-               int __user *i;
-       } uarg;
-       static const struct watchdog_info ident = {
-               .options                = WDIOF_CARDRESET |
-                                         WDIOF_SETTIMEOUT |
-                                         WDIOF_KEEPALIVEPING,
-               .identity               = "COH 901 327 Watchdog",
-               .firmware_version       = 1,
-       };
-       uarg.i = (int __user *)arg;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user(uarg.ident, &ident,
-                                  sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-               ret = put_user(0, uarg.i);
-               break;
-
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(boot_status, uarg.i);
-               break;
-
-       case WDIOC_SETOPTIONS:
-               ret = get_user(new_options, uarg.i);
-               if (ret)
-                       break;
-               if (new_options & WDIOS_DISABLECARD)
-                       coh901327_disable();
-               if (new_options & WDIOS_ENABLECARD)
-                       coh901327_start();
-               ret = 0;
-               break;
-
-       case WDIOC_KEEPALIVE:
-               coh901327_keepalive();
-               ret = 0;
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               ret = get_user(time, uarg.i);
-               if (ret)
-                       break;
-
-               ret = coh901327_settimeout(time);
-               if (ret)
-                       break;
-               /* Then fall through to return set value */
-
-       case WDIOC_GETTIMEOUT:
-               ret = put_user(margin, uarg.i);
-               break;
-
-       case WDIOC_GETTIMELEFT:
-               clk_enable(clk);
-               /* Read repeatedly until the value is stable! */
-               val = readw(virtbase + U300_WDOG_CR);
-               while (val & U300_WDOG_CR_VALID_IND)
-                       val = readw(virtbase + U300_WDOG_CR);
-               val &= U300_WDOG_CR_COUNT_VALUE_MASK;
-               clk_disable(clk);
-               if (val != 0)
-                       val /= 100;
-               ret = put_user(val, uarg.i);
-               break;
-       }
-       return ret;
-}
+static const struct watchdog_info coh901327_ident = {
+       .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity = DRV_NAME,
+};
 
-static const struct file_operations coh901327_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = coh901327_write,
-       .unlocked_ioctl = coh901327_ioctl,
-       .open           = coh901327_open,
-       .release        = coh901327_release,
+static struct watchdog_ops coh901327_ops = {
+       .owner = THIS_MODULE,
+       .start = coh901327_start,
+       .stop = coh901327_stop,
+       .ping = coh901327_ping,
+       .set_timeout = coh901327_settimeout,
+       .get_timeleft = coh901327_gettimeleft,
 };
 
-static struct miscdevice coh901327_miscdev = {
-       .minor          = WATCHDOG_MINOR,
-       .name           = "watchdog",
-       .fops           = &coh901327_fops,
+static struct watchdog_device coh901327_wdt = {
+       .info = &coh901327_ident,
+       .ops = &coh901327_ops,
+       /*
+        * Max timeout is 327 since the 10ms
+        * timeout register is max
+        * 0x7FFF = 327670ms ~= 327s.
+        */
+       .min_timeout = 0,
+       .max_timeout = 327,
 };
 
 static int __exit coh901327_remove(struct platform_device *pdev)
 {
-       misc_deregister(&coh901327_miscdev);
+       watchdog_unregister_device(&coh901327_wdt);
        coh901327_disable();
        free_irq(irq, pdev);
        clk_put(clk);
@@ -350,7 +269,6 @@ static int __exit coh901327_remove(struct platform_device *pdev)
        return 0;
 }
 
-
 static int __init coh901327_probe(struct platform_device *pdev)
 {
        int ret;
@@ -393,7 +311,7 @@ static int __init coh901327_probe(struct platform_device *pdev)
        case U300_WDOG_SR_STATUS_TIMED_OUT:
                dev_info(&pdev->dev,
                        "watchdog timed out since last chip reset!\n");
-               boot_status = WDIOF_CARDRESET;
+               coh901327_wdt.bootstatus |= WDIOF_CARDRESET;
                /* Status will be cleared below */
                break;
        case U300_WDOG_SR_STATUS_NORMAL:
@@ -435,7 +353,11 @@ static int __init coh901327_probe(struct platform_device *pdev)
 
        clk_disable(clk);
 
-       ret = misc_register(&coh901327_miscdev);
+       if (margin < 1 || margin > 327)
+               margin = 60;
+       coh901327_wdt.timeout = margin;
+
+       ret = watchdog_register_device(&coh901327_wdt);
        if (ret == 0)
                dev_info(&pdev->dev,
                         "initialized. timer margin=%d sec\n", margin);
@@ -543,8 +465,8 @@ module_exit(coh901327_exit);
 MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
 MODULE_DESCRIPTION("COH 901 327 Watchdog");
 
-module_param(margin, int, 0);
+module_param(margin, uint, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
 
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:coh901327-watchdog");
index 251c863..7e88839 100644 (file)
@@ -19,6 +19,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -71,7 +73,7 @@ static struct {
 static void cpu5wdt_trigger(unsigned long unused)
 {
        if (verbose > 2)
-               printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks);
+               pr_debug("trigger at %i ticks\n", ticks);
 
        if (cpu5wdt_device.running)
                ticks--;
@@ -96,7 +98,7 @@ static void cpu5wdt_reset(void)
        ticks = cpu5wdt_device.default_ticks;
 
        if (verbose)
-               printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks);
+               pr_debug("reset (%i ticks)\n", (int) ticks);
 
 }
 
@@ -129,7 +131,7 @@ static int cpu5wdt_stop(void)
        ticks = cpu5wdt_device.default_ticks;
        spin_unlock_irqrestore(&cpu5wdt_lock, flags);
        if (verbose)
-               printk(KERN_CRIT PFX "stop not possible\n");
+               pr_crit("stop not possible\n");
        return -EIO;
 }
 
@@ -219,8 +221,7 @@ static int __devinit cpu5wdt_init(void)
        int err;
 
        if (verbose)
-               printk(KERN_DEBUG PFX
-                               "port=0x%x, verbose=%i\n", port, verbose);
+               pr_debug("port=0x%x, verbose=%i\n", port, verbose);
 
        init_completion(&cpu5wdt_device.stop);
        cpu5wdt_device.queue = 0;
@@ -228,7 +229,7 @@ static int __devinit cpu5wdt_init(void)
        cpu5wdt_device.default_ticks = ticks;
 
        if (!request_region(port, CPU5WDT_EXTENT, PFX)) {
-               printk(KERN_ERR PFX "request_region failed\n");
+               pr_err("request_region failed\n");
                err = -EBUSY;
                goto no_port;
        }
@@ -237,16 +238,16 @@ static int __devinit cpu5wdt_init(void)
        val = inb(port + CPU5WDT_STATUS_REG);
        val = (val >> 2) & 1;
        if (!val)
-               printk(KERN_INFO PFX "sorry, was my fault\n");
+               pr_info("sorry, was my fault\n");
 
        err = misc_register(&cpu5wdt_misc);
        if (err < 0) {
-               printk(KERN_ERR PFX "misc_register failed\n");
+               pr_err("misc_register failed\n");
                goto no_misc;
        }
 
 
-       printk(KERN_INFO PFX "init success\n");
+       pr_info("init success\n");
        return 0;
 
 no_misc:
index 1b793df..95b1b95 100644 (file)
@@ -14,6 +14,8 @@
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -35,7 +37,6 @@
 #include <asm/watchdog.h>
 
 #define DRIVER_NAME    "cpwd"
-#define PFX            DRIVER_NAME ": "
 
 #define WD_OBPNAME     "watchdog"
 #define WD_BADMODEL    "SUNW,501-5336"
@@ -385,8 +386,7 @@ static int cpwd_open(struct inode *inode, struct file *f)
        if (!p->initialized) {
                if (request_irq(p->irq, &cpwd_interrupt,
                                IRQF_SHARED, DRIVER_NAME, p)) {
-                       printk(KERN_ERR PFX "Cannot register IRQ %d\n",
-                               p->irq);
+                       pr_err("Cannot register IRQ %d\n", p->irq);
                        mutex_unlock(&cpwd_mutex);
                        return -EBUSY;
                }
@@ -542,7 +542,7 @@ static int __devinit cpwd_probe(struct platform_device *op)
        p = kzalloc(sizeof(*p), GFP_KERNEL);
        err = -ENOMEM;
        if (!p) {
-               printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n");
+               pr_err("Unable to allocate struct cpwd\n");
                goto out;
        }
 
@@ -553,14 +553,14 @@ static int __devinit cpwd_probe(struct platform_device *op)
        p->regs = of_ioremap(&op->resource[0], 0,
                             4 * WD_TIMER_REGSZ, DRIVER_NAME);
        if (!p->regs) {
-               printk(KERN_ERR PFX "Unable to map registers.\n");
+               pr_err("Unable to map registers\n");
                goto out_free;
        }
 
        options = of_find_node_by_path("/options");
        err = -ENODEV;
        if (!options) {
-               printk(KERN_ERR PFX "Unable to find /options node.\n");
+               pr_err("Unable to find /options node\n");
                goto out_iounmap;
        }
 
@@ -605,8 +605,8 @@ static int __devinit cpwd_probe(struct platform_device *op)
 
                err = misc_register(&p->devs[i].misc);
                if (err) {
-                       printk(KERN_ERR "Could not register misc device for "
-                              "dev %d\n", i);
+                       pr_err("Could not register misc device for dev %d\n",
+                              i);
                        goto out_unregister;
                }
        }
@@ -617,8 +617,8 @@ static int __devinit cpwd_probe(struct platform_device *op)
                cpwd_timer.data         = (unsigned long) p;
                cpwd_timer.expires      = WD_BTIMEOUT;
 
-               printk(KERN_INFO PFX "PLD defect workaround enabled for "
-                      "model " WD_BADMODEL ".\n");
+               pr_info("PLD defect workaround enabled for model %s\n",
+                       WD_BADMODEL);
        }
 
        dev_set_drvdata(&op->dev, p);
index 63d7b58..06de121 100644 (file)
@@ -16,7 +16,8 @@
  * If we receive an expected close for the watchdog then we keep the timer
  * running, otherwise the timer is stopped and the watchdog will expire.
  */
-#define pr_fmt(fmt) "dw_wdt: " fmt
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/bitops.h>
 #include <linux/clk.h>
@@ -45,8 +46,8 @@
 /* The maximum TOP (timeout period) value that can be set in the watchdog. */
 #define DW_WDT_MAX_TOP         15
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
                 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
index 726b7df..7705003 100644 (file)
@@ -8,6 +8,9 @@
  * Authors: Ray Lehtiniemi <rayl@mail.com>,
  *     Alessandro Zummo <a.zummo@towertech.it>
  *
+ * Copyright (c) 2012 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *     Convert to a platform device and use the watchdog framework API
+ *
  * 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.
  *     - Add a few missing ioctls
  */
 
+#include <linux/platform_device.h>
 #include <linux/module.h>
-#include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/timer.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
-#include <mach/hardware.h>
 
-#define WDT_VERSION    "0.3"
-#define PFX            "ep93xx_wdt: "
+#define WDT_VERSION    "0.4"
 
 /* default timeout (secs) */
 #define WDT_TIMEOUT 30
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-static int timeout = WDT_TIMEOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
+static unsigned int timeout = WDT_TIMEOUT;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+       "Watchdog timeout in seconds. (1<=timeout<=3600, default="
+                               __MODULE_STRING(WDT_TIMEOUT) ")");
+
+static void __iomem *mmio_base;
 static struct timer_list timer;
 static unsigned long next_heartbeat;
-static unsigned long wdt_status;
-static unsigned long boot_status;
-
-#define WDT_IN_USE             0
-#define WDT_OK_TO_CLOSE                1
 
-#define EP93XX_WDT_REG(x)      (EP93XX_WATCHDOG_BASE + (x))
-#define EP93XX_WDT_WATCHDOG    EP93XX_WDT_REG(0x00)
-#define EP93XX_WDT_WDSTATUS    EP93XX_WDT_REG(0x04)
+#define EP93XX_WATCHDOG                0x00
+#define EP93XX_WDSTATUS                0x04
 
-/* reset the wdt every ~200ms */
+/* reset the wdt every ~200ms - the heartbeat of the device is 0.250 seconds*/
 #define WDT_INTERVAL (HZ/5)
 
-static void wdt_enable(void)
+static void ep93xx_wdt_timer_ping(unsigned long data)
 {
-       __raw_writew(0xaaaa, EP93XX_WDT_WATCHDOG);
-}
-
-static void wdt_disable(void)
-{
-       __raw_writew(0xaa55, EP93XX_WDT_WATCHDOG);
-}
+       if (time_before(jiffies, next_heartbeat))
+               writel(0x5555, mmio_base + EP93XX_WATCHDOG);
 
-static inline void wdt_ping(void)
-{
-       __raw_writew(0x5555, EP93XX_WDT_WATCHDOG);
+       /* Re-set the timer interval */
+       mod_timer(&timer, jiffies + WDT_INTERVAL);
 }
 
-static void wdt_startup(void)
+static int ep93xx_wdt_start(struct watchdog_device *wdd)
 {
        next_heartbeat = jiffies + (timeout * HZ);
 
-       wdt_enable();
+       writel(0xaaaa, mmio_base + EP93XX_WATCHDOG);
        mod_timer(&timer, jiffies + WDT_INTERVAL);
+
+       return 0;
 }
 
-static void wdt_shutdown(void)
+static int ep93xx_wdt_stop(struct watchdog_device *wdd)
 {
        del_timer_sync(&timer);
-       wdt_disable();
+       writel(0xaa55, mmio_base + EP93XX_WATCHDOG);
+
+       return 0;
 }
 
-static void wdt_keepalive(void)
+static int ep93xx_wdt_keepalive(struct watchdog_device *wdd)
 {
        /* user land ping */
        next_heartbeat = jiffies + (timeout * HZ);
-}
-
-static int ep93xx_wdt_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-               return -EBUSY;
-
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-       wdt_startup();
-
-       return nonseekable_open(inode, file);
-}
-
-static ssize_t
-ep93xx_wdt_write(struct file *file, const char __user *data, size_t len,
-                loff_t *ppos)
-{
-       if (len) {
-               if (!nowayout) {
-                       size_t i;
-
-                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-                       for (i = 0; i != len; i++) {
-                               char c;
-
-                               if (get_user(c, data + i))
-                                       return -EFAULT;
-
-                               if (c == 'V')
-                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
-                               else
-                                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-                       }
-               }
-               wdt_keepalive();
-       }
 
-       return len;
+       return 0;
 }
 
-static const struct watchdog_info ident = {
-       .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE,
-       .identity = "EP93xx Watchdog",
+static const struct watchdog_info ep93xx_wdt_ident = {
+       .options        = WDIOF_CARDRESET |
+                         WDIOF_MAGICCLOSE |
+                         WDIOF_KEEPALIVEPING,
+       .identity       = "EP93xx Watchdog",
 };
 
-static long ep93xx_wdt_ioctl(struct file *file,
-                                       unsigned int cmd, unsigned long arg)
-{
-       int ret = -ENOTTY;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
-                               sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-               ret = put_user(0, (int __user *)arg);
-               break;
-
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(boot_status, (int __user *)arg);
-               break;
-
-       case WDIOC_KEEPALIVE:
-               wdt_keepalive();
-               ret = 0;
-               break;
-
-       case WDIOC_GETTIMEOUT:
-               /* actually, it is 0.250 seconds.... */
-               ret = put_user(1, (int __user *)arg);
-               break;
-       }
-       return ret;
-}
-
-static int ep93xx_wdt_release(struct inode *inode, struct file *file)
-{
-       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-               wdt_shutdown();
-       else
-               printk(KERN_CRIT PFX
-                       "Device closed unexpectedly - timer will not stop\n");
-
-       clear_bit(WDT_IN_USE, &wdt_status);
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-       return 0;
-}
-
-static const struct file_operations ep93xx_wdt_fops = {
+static struct watchdog_ops ep93xx_wdt_ops = {
        .owner          = THIS_MODULE,
-       .write          = ep93xx_wdt_write,
-       .unlocked_ioctl = ep93xx_wdt_ioctl,
-       .open           = ep93xx_wdt_open,
-       .release        = ep93xx_wdt_release,
-       .llseek         = no_llseek,
+       .start          = ep93xx_wdt_start,
+       .stop           = ep93xx_wdt_stop,
+       .ping           = ep93xx_wdt_keepalive,
 };
 
-static struct miscdevice ep93xx_wdt_miscdev = {
-       .minor          = WATCHDOG_MINOR,
-       .name           = "watchdog",
-       .fops           = &ep93xx_wdt_fops,
+static struct watchdog_device ep93xx_wdt_wdd = {
+       .info           = &ep93xx_wdt_ident,
+       .ops            = &ep93xx_wdt_ops,
 };
 
-static void ep93xx_timer_ping(unsigned long data)
-{
-       if (time_before(jiffies, next_heartbeat))
-               wdt_ping();
-
-       /* Re-set the timer interval */
-       mod_timer(&timer, jiffies + WDT_INTERVAL);
-}
-
-static int __init ep93xx_wdt_init(void)
+static int __devinit ep93xx_wdt_probe(struct platform_device *pdev)
 {
+       struct resource *res;
+       unsigned long val;
        int err;
 
-       err = misc_register(&ep93xx_wdt_miscdev);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENXIO;
 
-       boot_status = __raw_readl(EP93XX_WDT_WATCHDOG) & 0x01 ? 1 : 0;
+       if (!devm_request_mem_region(&pdev->dev, res->start,
+                                    resource_size(res), pdev->name))
+               return -EBUSY;
 
-       printk(KERN_INFO PFX "EP93XX watchdog, driver version "
-               WDT_VERSION "%s\n",
-               (__raw_readl(EP93XX_WDT_WATCHDOG) & 0x08)
-               ? " (nCS1 disable detected)" : "");
+       mmio_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!mmio_base)
+               return -ENXIO;
 
        if (timeout < 1 || timeout > 3600) {
                timeout = WDT_TIMEOUT;
-               printk(KERN_INFO PFX
+               dev_warn(&pdev->dev,
                        "timeout value must be 1<=x<=3600, using %d\n",
                        timeout);
        }
 
-       setup_timer(&timer, ep93xx_timer_ping, 1);
-       return err;
+       val = readl(mmio_base + EP93XX_WATCHDOG);
+       ep93xx_wdt_wdd.bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0;
+       ep93xx_wdt_wdd.timeout = timeout;
+
+       watchdog_set_nowayout(&ep93xx_wdt_wdd, nowayout);
+
+       setup_timer(&timer, ep93xx_wdt_timer_ping, 1);
+
+       err = watchdog_register_device(&ep93xx_wdt_wdd);
+       if (err)
+               return err;
+
+       dev_info(&pdev->dev,
+               "EP93XX watchdog, driver version " WDT_VERSION "%s\n",
+               (val & 0x08) ? " (nCS1 disable detected)" : "");
+
+       return 0;
 }
 
-static void __exit ep93xx_wdt_exit(void)
+static int __devexit ep93xx_wdt_remove(struct platform_device *pdev)
 {
-       wdt_shutdown();
-       misc_deregister(&ep93xx_wdt_miscdev);
+       watchdog_unregister_device(&ep93xx_wdt_wdd);
+       return 0;
 }
 
-module_init(ep93xx_wdt_init);
-module_exit(ep93xx_wdt_exit);
-
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+static struct platform_driver ep93xx_wdt_driver = {
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "ep93xx-wdt",
+       },
+       .probe          = ep93xx_wdt_probe,
+       .remove         = __devexit_p(ep93xx_wdt_remove),
+};
 
-module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout,
-       "Watchdog timeout in seconds. (1<=timeout<=3600, default="
-                               __MODULE_STRING(WDT_TIMEOUT) ")");
+module_platform_driver(ep93xx_wdt_driver);
 
 MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>,"
-               "Alessandro Zummo <a.zummo@towertech.it>");
+               "Alessandro Zummo <a.zummo@towertech.it>,"
+               "H Hartley Sweeten <hsweeten@visionengravers.com>");
 MODULE_DESCRIPTION("EP93xx Watchdog");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(WDT_VERSION);
index f507fe7..cd31b8a 100644 (file)
@@ -45,6 +45,8 @@
  *     of the on-board SUPER I/O device SMSC FDC 37B782.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -75,8 +77,8 @@ static char *ev = "int";
 
 #define WDT_TIMEOUT            60                /* 1 minute */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -143,11 +145,11 @@ static void eurwdt_activate_timer(void)
 
        /* Setting interrupt line */
        if (irq == 2 || irq > 15 || irq < 0) {
-               printk(KERN_ERR ": invalid irq number\n");
+               pr_err("invalid irq number\n");
                irq = 0;        /* if invalid we disable interrupt */
        }
        if (irq == 0)
-               printk(KERN_INFO ": interrupt disabled\n");
+               pr_info("interrupt disabled\n");
 
        eurwdt_write_reg(WDT_TIMER_CFG, irq << 4);
 
@@ -162,12 +164,12 @@ static void eurwdt_activate_timer(void)
 
 static irqreturn_t eurwdt_interrupt(int irq, void *dev_id)
 {
-       printk(KERN_CRIT "timeout WDT timeout\n");
+       pr_crit("timeout WDT timeout\n");
 
 #ifdef ONLY_TESTING
-       printk(KERN_CRIT "Would Reboot.\n");
+       pr_crit("Would Reboot\n");
 #else
-       printk(KERN_CRIT "Initiating system reboot.\n");
+       pr_crit("Initiating system reboot\n");
        emergency_restart();
 #endif
        return IRQ_HANDLED;
@@ -334,8 +336,7 @@ static int eurwdt_release(struct inode *inode, struct file *file)
        if (eur_expect_close == 42)
                eurwdt_disable_timer();
        else {
-               printk(KERN_CRIT
-                       "eurwdt: Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                eurwdt_ping();
        }
        clear_bit(0, &eurwdt_is_open);
@@ -428,35 +429,32 @@ static int __init eurwdt_init(void)
 
        ret = request_irq(irq, eurwdt_interrupt, 0, "eurwdt", NULL);
        if (ret) {
-               printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
+               pr_err("IRQ %d is not free\n", irq);
                goto out;
        }
 
        if (!request_region(io, 2, "eurwdt")) {
-               printk(KERN_ERR "eurwdt: IO %X is not free.\n", io);
+               pr_err("IO %X is not free\n", io);
                ret = -EBUSY;
                goto outirq;
        }
 
        ret = register_reboot_notifier(&eurwdt_notifier);
        if (ret) {
-               printk(KERN_ERR
-                   "eurwdt: can't register reboot notifier (err=%d)\n", ret);
+               pr_err("can't register reboot notifier (err=%d)\n", ret);
                goto outreg;
        }
 
        ret = misc_register(&eurwdt_miscdev);
        if (ret) {
-               printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
-               WATCHDOG_MINOR);
+               pr_err("can't misc_register on minor=%d\n", WATCHDOG_MINOR);
                goto outreboot;
        }
 
        eurwdt_unlock_chip();
 
        ret = 0;
-       printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)"
-               " - timeout event: %s\n",
+       pr_info("Eurotech WDT driver 0.01 at %X (Interrupt %d) - timeout event: %s\n",
                io, irq, (!strcmp("int", ev) ? "int" : "reboot"));
 
 out:
index e45ca2b..c65b0a5 100644 (file)
@@ -19,6 +19,8 @@
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/err.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -189,8 +191,7 @@ static inline int superio_enter(int base)
 {
        /* Don't step on other drivers' I/O space by accident */
        if (!request_muxed_region(base, 2, DRVNAME)) {
-               printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
-                               (int)base);
+               pr_err("I/O address 0x%04x already in use\n", (int)base);
                return -EBUSY;
        }
 
@@ -217,7 +218,7 @@ static int watchdog_set_timeout(int timeout)
 {
        if (timeout <= 0
         || timeout >  max_timeout) {
-               printk(KERN_ERR DRVNAME ": watchdog timeout out of range\n");
+               pr_err("watchdog timeout out of range\n");
                return -EINVAL;
        }
 
@@ -252,7 +253,7 @@ static int watchdog_set_pulse_width(unsigned int pw)
        } else if (pw <= 5000) {
                watchdog.pulse_val = 3;
        } else {
-               printk(KERN_ERR DRVNAME ": pulse width out of range\n");
+               pr_err("pulse width out of range\n");
                err = -EINVAL;
                goto exit_unlock;
        }
@@ -309,8 +310,7 @@ static int f71862fg_pin_configure(unsigned short ioaddr)
                if (ioaddr)
                        superio_set_bit(ioaddr, SIO_REG_MFUNCT1, 1);
        } else {
-               printk(KERN_ERR DRVNAME ": Invalid argument f71862fg_pin=%d\n",
-                               f71862fg_pin);
+               pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin);
                return -EINVAL;
        }
        return 0;
@@ -487,8 +487,7 @@ static int watchdog_release(struct inode *inode, struct file *file)
 
        if (!watchdog.expect_close) {
                watchdog_keepalive();
-               printk(KERN_CRIT DRVNAME
-                       ": Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
        } else if (!nowayout) {
                watchdog_stop();
        }
@@ -672,25 +671,22 @@ static int __init watchdog_init(int sioaddr)
 
        err = misc_register(&watchdog_miscdev);
        if (err) {
-               printk(KERN_ERR DRVNAME
-                       ": cannot register miscdev on minor=%d\n",
-                               watchdog_miscdev.minor);
+               pr_err("cannot register miscdev on minor=%d\n",
+                      watchdog_miscdev.minor);
                goto exit_reboot;
        }
 
        if (start_withtimeout) {
                if (start_withtimeout <= 0
                 || start_withtimeout >  max_timeout) {
-                       printk(KERN_ERR DRVNAME
-                               ": starting timeout out of range\n");
+                       pr_err("starting timeout out of range\n");
                        err = -EINVAL;
                        goto exit_miscdev;
                }
 
                err = watchdog_start();
                if (err) {
-                       printk(KERN_ERR DRVNAME
-                               ": cannot start watchdog timer\n");
+                       pr_err("cannot start watchdog timer\n");
                        goto exit_miscdev;
                }
 
@@ -720,8 +716,7 @@ static int __init watchdog_init(int sioaddr)
                if (nowayout)
                        __module_get(THIS_MODULE);
 
-               printk(KERN_INFO DRVNAME
-                       ": watchdog started with initial timeout of %u sec\n",
+               pr_info("watchdog started with initial timeout of %u sec\n",
                        start_withtimeout);
        }
 
@@ -746,7 +741,7 @@ static int __init f71808e_find(int sioaddr)
 
        devid = superio_inw(sioaddr, SIO_REG_MANID);
        if (devid != SIO_FINTEK_ID) {
-               pr_debug(DRVNAME ": Not a Fintek device\n");
+               pr_debug("Not a Fintek device\n");
                err = -ENODEV;
                goto exit;
        }
@@ -774,13 +769,13 @@ static int __init f71808e_find(int sioaddr)
                err = -ENODEV;
                goto exit;
        default:
-               printk(KERN_INFO DRVNAME ": Unrecognized Fintek device: %04x\n",
-                      (unsigned int)devid);
+               pr_info("Unrecognized Fintek device: %04x\n",
+                       (unsigned int)devid);
                err = -ENODEV;
                goto exit;
        }
 
-       printk(KERN_INFO DRVNAME ": Found %s watchdog chip, revision %d\n",
+       pr_info("Found %s watchdog chip, revision %d\n",
                f71808e_names[watchdog.type],
                (int)superio_inb(sioaddr, SIO_REG_DEVREV));
 exit:
@@ -808,8 +803,7 @@ static int __init f71808e_init(void)
 static void __exit f71808e_exit(void)
 {
        if (watchdog_is_running()) {
-               printk(KERN_WARNING DRVNAME
-                       ": Watchdog timer still running, stopping it\n");
+               pr_warn("Watchdog timer still running, stopping it\n");
                watchdog_stop();
        }
        misc_deregister(&watchdog_miscdev);
index b146082..17f4cae 100644 (file)
@@ -24,6 +24,8 @@
  * capabilities) a kernel-based watchdog.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/compiler.h>
 #include <linux/init.h>
@@ -68,8 +70,8 @@ static unsigned int bus_clk;
 static char expect_close;
 static DEFINE_SPINLOCK(gef_wdt_spinlock);
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -110,7 +112,7 @@ static void gef_wdt_handler_enable(void)
        if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_FALSE,
                                   GEF_WDC_ENABLE_SHIFT)) {
                gef_wdt_service();
-               printk(KERN_NOTICE "gef_wdt: watchdog activated\n");
+               pr_notice("watchdog activated\n");
        }
 }
 
@@ -118,7 +120,7 @@ static void gef_wdt_handler_disable(void)
 {
        if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE,
                                   GEF_WDC_ENABLE_SHIFT))
-               printk(KERN_NOTICE "gef_wdt: watchdog deactivated\n");
+               pr_notice("watchdog deactivated\n");
 }
 
 static void gef_wdt_set_timeout(unsigned int timeout)
@@ -234,8 +236,7 @@ static int gef_wdt_release(struct inode *inode, struct file *file)
        if (expect_close == 42)
                gef_wdt_handler_disable();
        else {
-               printk(KERN_CRIT
-                      "gef_wdt: unexpected close, not stopping timer!\n");
+               pr_crit("unexpected close, not stopping timer!\n");
                gef_wdt_service();
        }
        expect_close = 0;
@@ -313,7 +314,7 @@ static struct platform_driver gef_wdt_driver = {
 
 static int __init gef_wdt_init(void)
 {
-       printk(KERN_INFO "GE watchdog driver\n");
+       pr_info("GE watchdog driver\n");
        return platform_driver_register(&gef_wdt_driver);
 }
 
index 9b49b12..dc563b6 100644 (file)
@@ -9,6 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -39,8 +40,8 @@ MODULE_PARM_DESC(timeout,
        "Watchdog timeout in seconds. 1<= timeout <=131, default="
                                __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -100,7 +101,7 @@ static int geodewdt_release(struct inode *inode, struct file *file)
                geodewdt_disable();
                module_put(THIS_MODULE);
        } else {
-               printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n");
+               pr_crit("Unexpected close - watchdog is not stopping\n");
                geodewdt_ping();
 
                set_bit(WDT_FLAGS_ORPHAN, &wdt_flags);
@@ -220,7 +221,7 @@ static int __devinit geodewdt_probe(struct platform_device *dev)
 
        wdt_timer = cs5535_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING);
        if (!wdt_timer) {
-               printk(KERN_ERR "geodewdt:  No timers were available\n");
+               pr_err("No timers were available\n");
                return -ENODEV;
        }
 
index 3c166d3..cbc7cee 100644 (file)
@@ -13,6 +13,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -45,7 +47,7 @@
 
 static unsigned int soft_margin = DEFAULT_MARGIN;      /* in seconds */
 static unsigned int reload;                    /* the computed soft_margin */
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static char expect_release;
 static unsigned long hpwdt_is_open;
 
@@ -235,8 +237,7 @@ static int __devinit cru_detect(unsigned long map_entry,
        asminline_call(&cmn_regs, bios32_entrypoint);
 
        if (cmn_regs.u1.ral != 0) {
-               printk(KERN_WARNING
-                       "hpwdt: Call succeeded but with an error: 0x%x\n",
+               pr_warn("Call succeeded but with an error: 0x%x\n",
                        cmn_regs.u1.ral);
        } else {
                physical_bios_base = cmn_regs.u2.rebx;
@@ -256,14 +257,10 @@ static int __devinit cru_detect(unsigned long map_entry,
                        }
                }
 
-               printk(KERN_DEBUG "hpwdt: CRU Base Address:   0x%lx\n",
-                       physical_bios_base);
-               printk(KERN_DEBUG "hpwdt: CRU Offset Address: 0x%lx\n",
-                       physical_bios_offset);
-               printk(KERN_DEBUG "hpwdt: CRU Length:         0x%lx\n",
-                       cru_length);
-               printk(KERN_DEBUG "hpwdt: CRU Mapped Address: %p\n",
-                       &cru_rom_addr);
+               pr_debug("CRU Base Address:   0x%lx\n", physical_bios_base);
+               pr_debug("CRU Offset Address: 0x%lx\n", physical_bios_offset);
+               pr_debug("CRU Length:         0x%lx\n", cru_length);
+               pr_debug("CRU Mapped Address: %p\n", &cru_rom_addr);
        }
        iounmap(bios32_map);
        return retval;
@@ -458,16 +455,13 @@ static void hpwdt_ping(void)
 static int hpwdt_change_timer(int new_margin)
 {
        if (new_margin < 1 || new_margin > HPWDT_MAX_TIMER) {
-               printk(KERN_WARNING
-                       "hpwdt: New value passed in is invalid: %d seconds.\n",
+               pr_warn("New value passed in is invalid: %d seconds\n",
                        new_margin);
                return -EINVAL;
        }
 
        soft_margin = new_margin;
-       printk(KERN_DEBUG
-               "hpwdt: New timer passed in is %d seconds.\n",
-               new_margin);
+       pr_debug("New timer passed in is %d seconds\n", new_margin);
        reload = SECS_TO_TICKS(soft_margin);
 
        return 0;
@@ -535,8 +529,7 @@ static int hpwdt_release(struct inode *inode, struct file *file)
        if (expect_release == 42) {
                hpwdt_stop();
        } else {
-               printk(KERN_CRIT
-                       "hpwdt: Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                hpwdt_ping();
        }
 
@@ -881,7 +874,7 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 module_param(soft_margin, int, 0);
 MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
index db45091..738032a 100644 (file)
@@ -27,6 +27,8 @@
  *      Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -44,7 +46,6 @@
 #define ESB_VERSION "0.05"
 #define ESB_MODULE_NAME "i6300ESB timer"
 #define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
-#define PFX ESB_MODULE_NAME ": "
 
 /* PCI configuration registers */
 #define ESB_CONFIG_REG  0x60            /* Config register                   */
@@ -94,8 +95,8 @@ MODULE_PARM_DESC(heartbeat,
                "Watchdog heartbeat in seconds. (1<heartbeat<2046, default="
                                __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -213,8 +214,7 @@ static int esb_release(struct inode *inode, struct file *file)
        if (esb_expect_close == 42)
                esb_timer_stop();
        else {
-               printk(KERN_CRIT PFX
-                               "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                esb_timer_keepalive();
        }
        clear_bit(0, &timer_alive);
@@ -347,19 +347,19 @@ MODULE_DEVICE_TABLE(pci, esb_pci_tbl);
 static unsigned char __devinit esb_getdevice(struct pci_dev *pdev)
 {
        if (pci_enable_device(pdev)) {
-               printk(KERN_ERR PFX "failed to enable device\n");
+               pr_err("failed to enable device\n");
                goto err_devput;
        }
 
        if (pci_request_region(pdev, 0, ESB_MODULE_NAME)) {
-               printk(KERN_ERR PFX "failed to request region\n");
+               pr_err("failed to request region\n");
                goto err_disable;
        }
 
        BASEADDR = pci_ioremap_bar(pdev, 0);
        if (BASEADDR == NULL) {
                /* Something's wrong here, BASEADDR has to be set */
-               printk(KERN_ERR PFX "failed to get BASEADDR\n");
+               pr_err("failed to get BASEADDR\n");
                goto err_release;
        }
 
@@ -397,7 +397,7 @@ static void __devinit esb_initdevice(void)
        /* Check that the WDT isn't already locked */
        pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
        if (val1 & ESB_WDT_LOCK)
-               printk(KERN_WARNING PFX "nowayout already set\n");
+               pr_warn("nowayout already set\n");
 
        /* Set the timer to watchdog mode and disable it for now */
        pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
@@ -423,11 +423,11 @@ static int __devinit esb_probe(struct pci_dev *pdev,
 
        cards_found++;
        if (cards_found == 1)
-               printk(KERN_INFO PFX "Intel 6300ESB WatchDog Timer Driver v%s\n",
+               pr_info("Intel 6300ESB WatchDog Timer Driver v%s\n",
                        ESB_VERSION);
 
        if (cards_found > 1) {
-               printk(KERN_ERR PFX "This driver only supports 1 device\n");
+               pr_err("This driver only supports 1 device\n");
                return -ENODEV;
        }
 
@@ -439,9 +439,8 @@ static int __devinit esb_probe(struct pci_dev *pdev,
           if not reset to the default */
        if (heartbeat < 0x1 || heartbeat > 2 * 0x03ff) {
                heartbeat = WATCHDOG_HEARTBEAT;
-               printk(KERN_INFO PFX
-                       "heartbeat value must be 1<heartbeat<2046, using %d\n",
-                                                               heartbeat);
+               pr_info("heartbeat value must be 1<heartbeat<2046, using %d\n",
+                       heartbeat);
        }
 
        /* Initialize the watchdog and make sure it does not run */
@@ -450,14 +449,12 @@ static int __devinit esb_probe(struct pci_dev *pdev,
        /* Register the watchdog so that userspace has access to it */
        ret = misc_register(&esb_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto err_unmap;
        }
-       printk(KERN_INFO PFX
-               "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
-                                               BASEADDR, heartbeat, nowayout);
+       pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
+               BASEADDR, heartbeat, nowayout);
        return 0;
 
 err_unmap:
@@ -503,7 +500,7 @@ static int __init watchdog_init(void)
 static void __exit watchdog_cleanup(void)
 {
        pci_unregister_driver(&esb_driver);
-       printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+       pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(watchdog_init);
index 481d1ad..2721d29 100644 (file)
  *     Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 /* Module and version information */
 #define DRV_NAME       "iTCO_vendor_support"
 #define DRV_VERSION    "1.04"
-#define PFX            DRV_NAME ": "
 
 /* Includes */
 #include <linux/module.h>              /* For module specific items */
@@ -355,13 +356,13 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
 
 static int __init iTCO_vendor_init_module(void)
 {
-       printk(KERN_INFO PFX "vendor-support=%d\n", vendorsupport);
+       pr_info("vendor-support=%d\n", vendorsupport);
        return 0;
 }
 
 static void __exit iTCO_vendor_exit_module(void)
 {
-       printk(KERN_INFO PFX "Module Unloaded\n");
+       pr_info("Module Unloaded\n");
 }
 
 module_init(iTCO_vendor_init_module);
index bdf401b..9fecb95 100644 (file)
  *     Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 /* Module and version information */
 #define DRV_NAME       "iTCO_wdt"
 #define DRV_VERSION    "1.07"
-#define PFX            DRV_NAME ": "
 
 /* Includes */
 #include <linux/module.h>              /* For module specific items */
@@ -413,8 +414,8 @@ MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
        "5..76 (TCO v1) or 3..614 (TCO v2), default="
                                __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -489,8 +490,7 @@ static int iTCO_wdt_start(void)
        /* disable chipset's NO_REBOOT bit */
        if (iTCO_wdt_unset_NO_REBOOT_bit()) {
                spin_unlock(&iTCO_wdt_private.io_lock);
-               printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, "
-                                       "reboot disabled by hardware/BIOS\n");
+               pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n");
                return -EIO;
        }
 
@@ -661,8 +661,7 @@ static int iTCO_wdt_release(struct inode *inode, struct file *file)
        if (expect_release == 42) {
                iTCO_wdt_stop();
        } else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                iTCO_wdt_keepalive();
        }
        clear_bit(0, &is_active);
@@ -804,8 +803,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
        base_address &= 0x0000ff80;
        if (base_address == 0x00000000) {
                /* Something's wrong here, ACPIBASE has to be set */
-               printk(KERN_ERR PFX "failed to get TCOBASE address, "
-                                       "device disabled by hardware/BIOS\n");
+               pr_err("failed to get TCOBASE address, device disabled by hardware/BIOS\n");
                return -ENODEV;
        }
        iTCO_wdt_private.iTCO_version =
@@ -820,8 +818,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
        if (iTCO_wdt_private.iTCO_version == 2) {
                pci_read_config_dword(pdev, 0xf0, &base_address);
                if ((base_address & 1) == 0) {
-                       printk(KERN_ERR PFX "RCBA is disabled by hardware"
-                                               "/BIOS, device disabled\n");
+                       pr_err("RCBA is disabled by hardware/BIOS, device disabled\n");
                        ret = -ENODEV;
                        goto out;
                }
@@ -831,8 +828,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
 
        /* Check chipset's NO_REBOOT bit */
        if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
-               printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, "
-                                       "device disabled by hardware/BIOS\n");
+               pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n");
                ret = -ENODEV;  /* Cannot reset NO_REBOOT bit */
                goto out_unmap;
        }
@@ -842,9 +838,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
 
        /* The TCO logic uses the TCO_EN bit in the SMI_EN register */
        if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
-               printk(KERN_ERR PFX
-                       "I/O address 0x%04lx already in use, "
-                                               "device disabled\n", SMI_EN);
+               pr_err("I/O address 0x%04lx already in use, device disabled\n",
+                      SMI_EN);
                ret = -EIO;
                goto out_unmap;
        }
@@ -858,17 +853,16 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
        /* The TCO I/O registers reside in a 32-byte range pointed to
           by the TCOBASE value */
        if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
-               printk(KERN_ERR PFX "I/O address 0x%04lx already in use "
-                                               "device disabled\n", TCOBASE);
+               pr_err("I/O address 0x%04lx already in use, device disabled\n",
+                      TCOBASE);
                ret = -EIO;
                goto unreg_smi_en;
        }
 
-       printk(KERN_INFO PFX
-               "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
-                       iTCO_chipset_info[ent->driver_data].name,
-                       iTCO_chipset_info[ent->driver_data].iTCO_version,
-                       TCOBASE);
+       pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
+               iTCO_chipset_info[ent->driver_data].name,
+               iTCO_chipset_info[ent->driver_data].iTCO_version,
+               TCOBASE);
 
        /* Clear out the (probably old) status */
        outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
@@ -882,20 +876,18 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
           if not reset to the default */
        if (iTCO_wdt_set_heartbeat(heartbeat)) {
                iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
-               printk(KERN_INFO PFX
-                       "timeout value out of range, using %d\n", heartbeat);
+               pr_info("timeout value out of range, using %d\n", heartbeat);
        }
 
        ret = misc_register(&iTCO_wdt_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto unreg_region;
        }
 
-       printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
-                                                       heartbeat, nowayout);
+       pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
+               heartbeat, nowayout);
 
        return 0;
 
@@ -947,7 +939,7 @@ static int __devinit iTCO_wdt_probe(struct platform_device *dev)
        }
 
        if (!found)
-               printk(KERN_INFO PFX "No device detected.\n");
+               pr_info("No device detected\n");
 
        return ret;
 }
@@ -979,8 +971,7 @@ static int __init iTCO_wdt_init_module(void)
 {
        int err;
 
-       printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",
-               DRV_VERSION);
+       pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION);
 
        err = platform_driver_register(&iTCO_wdt_driver);
        if (err)
@@ -1004,7 +995,7 @@ static void __exit iTCO_wdt_cleanup_module(void)
 {
        platform_device_unregister(iTCO_wdt_platform_device);
        platform_driver_unregister(&iTCO_wdt_driver);
-       printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+       pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(iTCO_wdt_init_module);
index 9402c0b..184c0bf 100644 (file)
@@ -31,6 +31,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
@@ -52,7 +54,6 @@ static char expect_close;
 
 /* Module information */
 #define DRV_NAME "ib700wdt"
-#define PFX DRV_NAME ": "
 
 /*
  *
@@ -101,8 +102,8 @@ MODULE_PARM_DESC(timeout,
        "Watchdog timeout in seconds. 0<= timeout <=30, default="
                __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -245,8 +246,7 @@ static int ibwdt_close(struct inode *inode, struct file *file)
        if (expect_close == 42) {
                ibwdt_disable();
        } else {
-               printk(KERN_CRIT PFX
-                    "WDT device closed unexpectedly.  WDT will not stop!\n");
+               pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
                ibwdt_ping();
        }
        clear_bit(0, &ibwdt_is_open);
@@ -283,16 +283,14 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
 
 #if WDT_START != WDT_STOP
        if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
-               printk(KERN_ERR PFX "STOP method I/O %X is not available.\n",
-                                                               WDT_STOP);
+               pr_err("STOP method I/O %X is not available\n", WDT_STOP);
                res = -EIO;
                goto out_nostopreg;
        }
 #endif
 
        if (!request_region(WDT_START, 1, "IB700 WDT")) {
-               printk(KERN_ERR PFX "START method I/O %X is not available.\n",
-                                                               WDT_START);
+               pr_err("START method I/O %X is not available\n", WDT_START);
                res = -EIO;
                goto out_nostartreg;
        }
@@ -301,13 +299,12 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
         * if not reset to the default */
        if (ibwdt_set_heartbeat(timeout)) {
                ibwdt_set_heartbeat(WATCHDOG_TIMEOUT);
-               printk(KERN_INFO PFX
-                       "timeout value must be 0<=x<=30, using %d\n", timeout);
+               pr_info("timeout value must be 0<=x<=30, using %d\n", timeout);
        }
 
        res = misc_register(&ibwdt_miscdev);
        if (res) {
-               printk(KERN_ERR PFX "failed to register misc device\n");
+               pr_err("failed to register misc device\n");
                goto out_nomisc;
        }
        return 0;
@@ -352,8 +349,7 @@ static int __init ibwdt_init(void)
 {
        int err;
 
-       printk(KERN_INFO PFX
-               "WDT driver for IB700 single board computer initialising.\n");
+       pr_info("WDT driver for IB700 single board computer initialising\n");
 
        err = platform_driver_register(&ibwdt_driver);
        if (err)
@@ -377,7 +373,7 @@ static void __exit ibwdt_exit(void)
 {
        platform_device_unregister(ibwdt_platform_device);
        platform_driver_unregister(&ibwdt_driver);
-       printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+       pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(ibwdt_init);
index c7481ad..bc3fb8f 100644 (file)
@@ -10,6 +10,8 @@
  * of the GNU Public License, incorporated herein by reference.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -31,8 +33,6 @@ enum {
        ASMTYPE_SPRUCE,
 };
 
-#define PFX "ibmasr: "
-
 #define TOPAZ_ASR_REG_OFFSET   4
 #define TOPAZ_ASR_TOGGLE       0x40
 #define TOPAZ_ASR_DISABLE      0x80
@@ -60,7 +60,7 @@ enum {
 #define SPRUCE_ASR_TOGGLE_MASK 0x02    /* bit 0: 0, then 1, then 0 */
 
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 static unsigned long asr_is_open;
 static char asr_expect_close;
@@ -234,12 +234,11 @@ static int __init asr_get_base_address(void)
        }
 
        if (!request_region(asr_base, asr_length, "ibmasr")) {
-               printk(KERN_ERR PFX "address %#x already in use\n",
-                       asr_base);
+               pr_err("address %#x already in use\n", asr_base);
                return -EBUSY;
        }
 
-       printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base);
+       pr_info("found %sASR @ addr %#x\n", type, asr_base);
 
        return 0;
 }
@@ -332,8 +331,7 @@ static int asr_release(struct inode *inode, struct file *file)
        if (asr_expect_close == 42)
                asr_disable();
        else {
-               printk(KERN_CRIT PFX
-                               "unexpected close, not stopping watchdog!\n");
+               pr_crit("unexpected close, not stopping watchdog!\n");
                asr_toggle();
        }
        clear_bit(0, &asr_is_open);
@@ -393,7 +391,7 @@ static int __init ibmasr_init(void)
        rc = misc_register(&asr_miscdev);
        if (rc < 0) {
                release_region(asr_base, asr_length);
-               printk(KERN_ERR PFX "failed to register misc device\n");
+               pr_err("failed to register misc device\n");
                return rc;
        }
 
@@ -413,7 +411,7 @@ static void __exit ibmasr_exit(void)
 module_init(ibmasr_init);
 module_exit(ibmasr_exit);
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
index c44c333..7a2b734 100644 (file)
@@ -46,6 +46,9 @@
 #define IMX2_WDT_SEQ1          0x5555          /* -> service sequence 1 */
 #define IMX2_WDT_SEQ2          0xAAAA          /* -> service sequence 2 */
 
+#define IMX2_WDT_WRSR          0x04            /* Reset Status Register */
+#define IMX2_WDT_WRSR_TOUT     (1 << 1)        /* -> Reset due to Timeout */
+
 #define IMX2_WDT_MAX_TIME      128
 #define IMX2_WDT_DEFAULT_TIME  60              /* in seconds */
 
@@ -65,8 +68,8 @@ static struct {
 
 static struct miscdevice imx2_wdt_miscdev;
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -175,6 +178,7 @@ static long imx2_wdt_ioctl(struct file *file, unsigned int cmd,
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
        int new_value;
+       u16 val;
 
        switch (cmd) {
        case WDIOC_GETSUPPORT:
@@ -182,9 +186,13 @@ static long imx2_wdt_ioctl(struct file *file, unsigned int cmd,
                        sizeof(struct watchdog_info)) ? -EFAULT : 0;
 
        case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
                return put_user(0, p);
 
+       case WDIOC_GETBOOTSTATUS:
+               val = __raw_readw(imx2_wdt.base + IMX2_WDT_WRSR);
+               new_value = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
+               return put_user(new_value, p);
+
        case WDIOC_KEEPALIVE:
                imx2_wdt_ping();
                return 0;
index 1475e09..6d90f7a 100644 (file)
@@ -12,6 +12,8 @@
  *     based on softdog.c by Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/uaccess.h>
 #include <asm/sgi/mc.h>
 
-#define PFX "indydog: "
 static unsigned long indydog_alive;
 static DEFINE_SPINLOCK(indydog_lock);
 
 #define WATCHDOG_TIMEOUT 30            /* 30 sec default timeout */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -60,7 +61,7 @@ static void indydog_stop(void)
        sgimc->cpuctrl0 = mc_ctrl0;
        spin_unlock(&indydog_lock);
 
-       printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+       pr_info("Stopped watchdog timer\n");
 }
 
 static void indydog_ping(void)
@@ -83,7 +84,7 @@ static int indydog_open(struct inode *inode, struct file *file)
        indydog_start();
        indydog_ping();
 
-       printk(KERN_INFO "Started watchdog timer.\n");
+       pr_info("Started watchdog timer\n");
 
        return nonseekable_open(inode, file);
 }
@@ -178,30 +179,25 @@ static struct notifier_block indydog_notifier = {
        .notifier_call = indydog_notify_sys,
 };
 
-static char banner[] __initdata =
-       KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
-
 static int __init watchdog_init(void)
 {
        int ret;
 
        ret = register_reboot_notifier(&indydog_notifier);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                return ret;
        }
 
        ret = misc_register(&indydog_miscdev);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                unregister_reboot_notifier(&indydog_notifier);
                return ret;
        }
 
-       printk(banner);
+       pr_info("Hardware Watchdog Timer for SGI IP22: 0.3\n");
 
        return 0;
 }
index 1abdc04..9dda2d0 100644 (file)
@@ -22,6 +22,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -96,15 +98,14 @@ static struct intel_scu_watchdog_dev watchdog_device;
 static void watchdog_fire(void)
 {
        if (force_boot) {
-               printk(KERN_CRIT PFX "Initiating system reboot.\n");
+               pr_crit("Initiating system reboot\n");
                emergency_restart();
-               printk(KERN_CRIT PFX "Reboot didn't ?????\n");
+               pr_crit("Reboot didn't ?????\n");
        }
 
        else {
-               printk(KERN_CRIT PFX "Immediate Reboot Disabled\n");
-               printk(KERN_CRIT PFX
-                       "System will reset when watchdog timer times out!\n");
+               pr_crit("Immediate Reboot Disabled\n");
+               pr_crit("System will reset when watchdog timer times out!\n");
        }
 }
 
@@ -112,8 +113,8 @@ static int check_timer_margin(int new_margin)
 {
        if ((new_margin < MIN_TIME_CYCLE) ||
            (new_margin > MAX_TIME - timer_set)) {
-               pr_debug("Watchdog timer: value of new_margin %d is out of the range %d to %d\n",
-                         new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
+               pr_debug("value of new_margin %d is out of the range %d to %d\n",
+                        new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
                return -EINVAL;
        }
        return 0;
@@ -156,14 +157,14 @@ static irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id)
        int int_status;
        int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
 
-       pr_debug("Watchdog timer: irq, int_status: %x\n", int_status);
+       pr_debug("irq, int_status: %x\n", int_status);
 
        if (int_status != 0)
                return IRQ_NONE;
 
        /* has the timer been started? If not, then this is spurious */
        if (watchdog_device.timer_started == 0) {
-               pr_debug("Watchdog timer: spurious interrupt received\n");
+               pr_debug("spurious interrupt received\n");
                return IRQ_HANDLED;
        }
 
@@ -220,16 +221,15 @@ static int intel_scu_set_heartbeat(u32 t)
                (watchdog_device.timer_set - timer_margin)
                * watchdog_device.timer_tbl_ptr->freq_hz;
 
-       pr_debug("Watchdog timer: set_heartbeat: timer freq is %d\n",
-               watchdog_device.timer_tbl_ptr->freq_hz);
-       pr_debug("Watchdog timer: set_heartbeat: timer_set is %x (hex)\n",
-               watchdog_device.timer_set);
-       pr_debug("Watchdog timer: set_hearbeat: timer_margin is %x (hex)\n",
-               timer_margin);
-       pr_debug("Watchdog timer: set_heartbeat: threshold is %x (hex)\n",
-               watchdog_device.threshold);
-       pr_debug("Watchdog timer: set_heartbeat: soft_threshold is %x (hex)\n",
-               watchdog_device.soft_threshold);
+       pr_debug("set_heartbeat: timer freq is %d\n",
+                watchdog_device.timer_tbl_ptr->freq_hz);
+       pr_debug("set_heartbeat: timer_set is %x (hex)\n",
+                watchdog_device.timer_set);
+       pr_debug("set_hearbeat: timer_margin is %x (hex)\n", timer_margin);
+       pr_debug("set_heartbeat: threshold is %x (hex)\n",
+                watchdog_device.threshold);
+       pr_debug("set_heartbeat: soft_threshold is %x (hex)\n",
+                watchdog_device.soft_threshold);
 
        /* Adjust thresholds by FREQ_ADJUSTMENT factor, to make the */
        /* watchdog timing come out right. */
@@ -264,7 +264,7 @@ static int intel_scu_set_heartbeat(u32 t)
 
                if (MAX_RETRY < retry_count++) {
                        /* Unable to set timer value */
-                       pr_err("Watchdog timer: Unable to set timer\n");
+                       pr_err("Unable to set timer\n");
                        return -ENODEV;
                }
 
@@ -321,18 +321,17 @@ static int intel_scu_release(struct inode *inode, struct file *file)
         */
 
        if (!test_and_clear_bit(0, &watchdog_device.driver_open)) {
-               pr_debug("Watchdog timer: intel_scu_release, without open\n");
+               pr_debug("intel_scu_release, without open\n");
                return -ENOTTY;
        }
 
        if (!watchdog_device.timer_started) {
                /* Just close, since timer has not been started */
-               pr_debug("Watchdog timer: closed, without starting timer\n");
+               pr_debug("closed, without starting timer\n");
                return 0;
        }
 
-       printk(KERN_CRIT PFX
-              "Unexpected close of /dev/watchdog!\n");
+       pr_crit("Unexpected close of /dev/watchdog!\n");
 
        /* Since the timer was started, prevent future reopens */
        watchdog_device.driver_closed = 1;
@@ -454,9 +453,8 @@ static int __init intel_scu_watchdog_init(void)
        /* Check value of timer_set boot parameter */
        if ((timer_set < MIN_TIME_CYCLE) ||
            (timer_set > MAX_TIME - MIN_TIME_CYCLE)) {
-               pr_err("Watchdog timer: value of timer_set %x (hex) "
-                 "is out of range from %x to %x (hex)\n",
-                 timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
+               pr_err("value of timer_set %x (hex) is out of range from %x to %x (hex)\n",
+                      timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
                return -EINVAL;
        }
 
@@ -467,19 +465,18 @@ static int __init intel_scu_watchdog_init(void)
        watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
 
        if (watchdog_device.timer_tbl_ptr == NULL) {
-               pr_debug("Watchdog timer - Intel SCU watchdog: timer is not available\n");
+               pr_debug("timer is not available\n");
                return -ENODEV;
        }
        /* make sure the timer exists */
        if (watchdog_device.timer_tbl_ptr->phys_addr == 0) {
-               pr_debug("Watchdog timer - Intel SCU watchdog - timer %d does not have valid physical memory\n",
-                                                               sfi_mtimer_num);
+               pr_debug("timer %d does not have valid physical memory\n",
+                        sfi_mtimer_num);
                return -ENODEV;
        }
 
        if (watchdog_device.timer_tbl_ptr->irq == 0) {
-               pr_debug("Watchdog timer: timer %d invalid irq\n",
-                                                       sfi_mtimer_num);
+               pr_debug("timer %d invalid irq\n", sfi_mtimer_num);
                return -ENODEV;
        }
 
@@ -487,7 +484,7 @@ static int __init intel_scu_watchdog_init(void)
                        20);
 
        if (tmp_addr == NULL) {
-               pr_debug("Watchdog timer: timer unable to ioremap\n");
+               pr_debug("timer unable to ioremap\n");
                return -ENOMEM;
        }
 
@@ -512,7 +509,7 @@ static int __init intel_scu_watchdog_init(void)
 
        ret = register_reboot_notifier(&watchdog_device.intel_scu_notifier);
        if (ret) {
-               pr_err("Watchdog timer: cannot register notifier %d)\n", ret);
+               pr_err("cannot register notifier %d)\n", ret);
                goto register_reboot_error;
        }
 
@@ -522,8 +519,8 @@ static int __init intel_scu_watchdog_init(void)
 
        ret = misc_register(&watchdog_device.miscdev);
        if (ret) {
-               pr_err("Watchdog timer: cannot register miscdev %d err =%d\n",
-                                                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev %d err =%d\n",
+                      WATCHDOG_MINOR, ret);
                goto misc_register_error;
        }
 
@@ -532,7 +529,7 @@ static int __init intel_scu_watchdog_init(void)
                IRQF_SHARED, "watchdog",
                &watchdog_device.timer_load_count_addr);
        if (ret) {
-               pr_err("Watchdog timer: error requesting irq %d\n", ret);
+               pr_err("error requesting irq %d\n", ret);
                goto request_irq_error;
        }
        /* Make sure timer is disabled before returning */
index d2b074a..f3ac608 100644 (file)
@@ -25,7 +25,6 @@
 #ifndef __INTEL_SCU_WATCHDOG_H
 #define __INTEL_SCU_WATCHDOG_H
 
-#define PFX "Intel_SCU: "
 #define WDT_VER "0.3"
 
 /* minimum time between interrupts */
index 82fa7a9..d964faf 100644 (file)
@@ -24,6 +24,8 @@
  *     Dan Williams <dan.j.williams@intel.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
@@ -34,7 +36,7 @@
 #include <linux/uaccess.h>
 #include <mach/hardware.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned long wdt_status;
 static unsigned long boot_status;
 static DEFINE_SPINLOCK(wdt_lock);
@@ -85,7 +87,7 @@ static int wdt_disable(void)
                write_wdtcr(IOP_WDTCR_DIS);
                clear_bit(WDT_ENABLED, &wdt_status);
                spin_unlock(&wdt_lock);
-               printk(KERN_INFO "WATCHDOG: Disabled\n");
+               pr_info("Disabled\n");
                return 0;
        } else
                return 1;
@@ -197,8 +199,8 @@ static int iop_wdt_release(struct inode *inode, struct file *file)
         */
        if (state != 0) {
                wdt_enable();
-               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-                      "reset in %lu seconds\n", iop_watchdog_timeout());
+               pr_crit("Device closed unexpectedly - reset in %lu seconds\n",
+                       iop_watchdog_timeout());
        }
 
        clear_bit(WDT_IN_USE, &wdt_status);
@@ -238,8 +240,7 @@ static int __init iop_wdt_init(void)
           with an open */
        ret = misc_register(&iop_wdt_miscdev);
        if (ret == 0)
-               printk(KERN_INFO "iop watchdog timer: timeout %lu sec\n",
-                      iop_watchdog_timeout());
+               pr_info("timeout %lu sec\n", iop_watchdog_timeout());
 
        return ret;
 }
@@ -252,7 +253,7 @@ static void __exit iop_wdt_exit(void)
 module_init(iop_wdt_init);
 module_exit(iop_wdt_exit);
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
index 8d2d850..f4cce6d 100644 (file)
@@ -20,6 +20,8 @@
  *     software is provided AS-IS with no warranties.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -33,6 +35,7 @@
 #include <linux/io.h>
 #include <linux/ioport.h>
 
+#define DEBUG
 #define NAME "it8712f_wdt"
 
 MODULE_AUTHOR("Jorge Boncompte - DTI2 <jorge@dti2.net>");
@@ -45,8 +48,8 @@ static int margin = 60;               /* in seconds */
 module_param(margin, int, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
 static unsigned long wdt_open;
@@ -158,10 +161,10 @@ static void it8712f_wdt_update_margin(void)
         */
        if (units <= max_units) {
                config |= WDT_UNIT_SEC; /* else UNIT is MINUTES */
-               printk(KERN_INFO NAME ": timer margin %d seconds\n", units);
+               pr_info("timer margin %d seconds\n", units);
        } else {
                units /= 60;
-               printk(KERN_INFO NAME ": timer margin %d minutes\n", units);
+               pr_info("timer margin %d minutes\n", units);
        }
        superio_outb(config, WDT_CONFIG);
 
@@ -184,7 +187,7 @@ static int it8712f_wdt_enable(void)
        if (ret)
                return ret;
 
-       printk(KERN_DEBUG NAME ": enabling watchdog timer\n");
+       pr_debug("enabling watchdog timer\n");
        superio_select(LDN_GPIO);
 
        superio_outb(wdt_control_reg, WDT_CONTROL);
@@ -204,7 +207,7 @@ static int it8712f_wdt_disable(void)
        if (ret)
                return ret;
 
-       printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+       pr_debug("disabling watchdog timer\n");
        superio_select(LDN_GPIO);
 
        superio_outb(0, WDT_CONFIG);
@@ -331,12 +334,10 @@ static int it8712f_wdt_open(struct inode *inode, struct file *file)
 static int it8712f_wdt_release(struct inode *inode, struct file *file)
 {
        if (expect_close != 42) {
-               printk(KERN_WARNING NAME
-                       ": watchdog device closed unexpectedly, will not"
-                       " disable the watchdog timer\n");
+               pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n");
        } else if (!nowayout) {
                if (it8712f_wdt_disable())
-                       printk(KERN_WARNING NAME "Watchdog disable failed\n");
+                       pr_warn("Watchdog disable failed\n");
        }
        expect_close = 0;
        clear_bit(0, &wdt_open);
@@ -374,13 +375,13 @@ static int __init it8712f_wdt_find(unsigned short *address)
        superio_select(LDN_GAME);
        superio_outb(1, ACT_REG);
        if (!(superio_inb(ACT_REG) & 0x01)) {
-               printk(KERN_ERR NAME ": Device not activated, skipping\n");
+               pr_err("Device not activated, skipping\n");
                goto exit;
        }
 
        *address = superio_inw(BASE_REG);
        if (*address == 0) {
-               printk(KERN_ERR NAME ": Base address not set, skipping\n");
+               pr_err("Base address not set, skipping\n");
                goto exit;
        }
 
@@ -394,8 +395,7 @@ static int __init it8712f_wdt_find(unsigned short *address)
        if (margin > (max_units * 60))
                margin = (max_units * 60);
 
-       printk(KERN_INFO NAME ": Found IT%04xF chip revision %d - "
-               "using DogFood address 0x%x\n",
+       pr_info("Found IT%04xF chip revision %d - using DogFood address 0x%x\n",
                chip_type, revision, *address);
 
 exit:
@@ -411,27 +411,26 @@ static int __init it8712f_wdt_init(void)
                return -ENODEV;
 
        if (!request_region(address, 1, "IT8712F Watchdog")) {
-               printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
+               pr_warn("watchdog I/O region busy\n");
                return -EBUSY;
        }
 
        err = it8712f_wdt_disable();
        if (err) {
-               printk(KERN_ERR NAME ": unable to disable watchdog timer.\n");
+               pr_err("unable to disable watchdog timer\n");
                goto out;
        }
 
        err = register_reboot_notifier(&it8712f_wdt_notifier);
        if (err) {
-               printk(KERN_ERR NAME ": unable to register reboot notifier\n");
+               pr_err("unable to register reboot notifier\n");
                goto out;
        }
 
        err = misc_register(&it8712f_wdt_miscdev);
        if (err) {
-               printk(KERN_ERR NAME
-                       ": cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, err);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, err);
                goto reboot_out;
        }
 
index d761c41..8a741bc 100644 (file)
@@ -29,6 +29,8 @@
  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -46,7 +48,6 @@
 
 #define WATCHDOG_VERSION       "1.14"
 #define WATCHDOG_NAME          "IT87 WDT"
-#define PFX                    WATCHDOG_NAME ": "
 #define DRIVER_VERSION         WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
 #define WD_MAGIC               'V'
 
@@ -141,7 +142,7 @@ static      int nogameport = DEFAULT_NOGAMEPORT;
 static int exclusive  = DEFAULT_EXCLUSIVE;
 static int timeout    = DEFAULT_TIMEOUT;
 static int testmode   = DEFAULT_TESTMODE;
-static int nowayout   = DEFAULT_NOWAYOUT;
+static bool nowayout   = DEFAULT_NOWAYOUT;
 
 module_param(nogameport, int, 0);
 MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
@@ -155,7 +156,7 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="
 module_param(testmode, int, 0);
 MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
                __MODULE_STRING(DEFAULT_TESTMODE));
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
                __MODULE_STRING(WATCHDOG_NOWAYOUT));
 
@@ -427,8 +428,7 @@ static int wdt_release(struct inode *inode, struct file *file)
                        clear_bit(WDTS_TIMER_RUN, &wdt_status);
                } else {
                        wdt_keepalive();
-                       printk(KERN_CRIT PFX
-                              "unexpected close, not stopping watchdog!\n");
+                       pr_crit("unexpected close, not stopping watchdog!\n");
                }
        }
        clear_bit(WDTS_DEV_OPEN, &wdt_status);
@@ -620,16 +620,14 @@ static int __init it87_wdt_init(void)
                try_gameport = 0;
                break;
        case IT8705_ID:
-               printk(KERN_ERR PFX
-                      "Unsupported Chip found, Chip %04x Revision %02x\n",
+               pr_err("Unsupported Chip found, Chip %04x Revision %02x\n",
                       chip_type, chip_rev);
                return -ENODEV;
        case NO_DEV_ID:
-               printk(KERN_ERR PFX "no device\n");
+               pr_err("no device\n");
                return -ENODEV;
        default:
-               printk(KERN_ERR PFX
-                      "Unknown Chip found, Chip %04x Revision %04x\n",
+               pr_err("Unknown Chip found, Chip %04x Revision %04x\n",
                       chip_type, chip_rev);
                return -ENODEV;
        }
@@ -662,13 +660,11 @@ static int __init it87_wdt_init(void)
        if (!test_bit(WDTS_USE_GP, &wdt_status)) {
                if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
                        if (gp_rreq_fail)
-                               printk(KERN_ERR PFX
-                                       "I/O Address 0x%04x and 0x%04x"
-                                       " already in use\n", base, CIR_BASE);
+                               pr_err("I/O Address 0x%04x and 0x%04x already in use\n",
+                                      base, CIR_BASE);
                        else
-                               printk(KERN_ERR PFX
-                                       "I/O Address 0x%04x already in use\n",
-                                       CIR_BASE);
+                               pr_err("I/O Address 0x%04x already in use\n",
+                                      CIR_BASE);
                        rc = -EIO;
                        goto err_out;
                }
@@ -687,9 +683,8 @@ static int __init it87_wdt_init(void)
 
        if (timeout < 1 || timeout > max_units * 60) {
                timeout = DEFAULT_TIMEOUT;
-               printk(KERN_WARNING PFX
-                      "Timeout value out of range, use default %d sec\n",
-                      DEFAULT_TIMEOUT);
+               pr_warn("Timeout value out of range, use default %d sec\n",
+                       DEFAULT_TIMEOUT);
        }
 
        if (timeout > max_units)
@@ -697,16 +692,14 @@ static int __init it87_wdt_init(void)
 
        rc = register_reboot_notifier(&wdt_notifier);
        if (rc) {
-               printk(KERN_ERR PFX
-                      "Cannot register reboot notifier (err=%d)\n", rc);
+               pr_err("Cannot register reboot notifier (err=%d)\n", rc);
                goto err_out_region;
        }
 
        rc = misc_register(&wdt_miscdev);
        if (rc) {
-               printk(KERN_ERR PFX
-                      "Cannot register miscdev on minor=%d (err=%d)\n",
-                       wdt_miscdev.minor, rc);
+               pr_err("Cannot register miscdev on minor=%d (err=%d)\n",
+                      wdt_miscdev.minor, rc);
                goto err_out_reboot;
        }
 
@@ -721,9 +714,8 @@ static int __init it87_wdt_init(void)
                outb(0x09, CIR_IER(base));
        }
 
-       printk(KERN_INFO PFX "Chip IT%04x revision %d initialized. "
-               "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d "
-               "nogameport=%d)\n", chip_type, chip_rev, timeout,
+       pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d)\n",
+               chip_type, chip_rev, timeout,
                nowayout, testmode, exclusive, nogameport);
 
        superio_exit();
index 084f71a..3f047a5 100644 (file)
@@ -16,6 +16,8 @@
  * warranty of any kind, whether express or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -29,7 +31,7 @@
 #include <linux/uaccess.h>
 #include <mach/hardware.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned int heartbeat = 60;    /* (secs) Default is 1 minute */
 static unsigned long wdt_status;
 static DEFINE_SPINLOCK(wdt_lock);
@@ -158,8 +160,7 @@ static int ixp2000_wdt_release(struct inode *inode, struct file *file)
        if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
                wdt_disable();
        else
-               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-                                       "timer will not stop\n");
+               pr_crit("Device closed unexpectedly - timer will not stop\n");
        clear_bit(WDT_IN_USE, &wdt_status);
        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 
@@ -185,7 +186,7 @@ static struct miscdevice ixp2000_wdt_miscdev = {
 static int __init ixp2000_wdt_init(void)
 {
        if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
-               printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n");
+               pr_info("Unable to use IXP2000 watchdog due to IXP2800 erratum #25\n");
                return -EIO;
        }
        wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
@@ -206,7 +207,7 @@ MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
 module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_LICENSE("GPL");
index 4fc2e9a..5580b4f 100644 (file)
@@ -13,6 +13,8 @@
  * warranty of any kind, whether express or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -25,7 +27,7 @@
 #include <linux/uaccess.h>
 #include <mach/hardware.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = 60;     /* (secs) Default is 1 minute */
 static unsigned long wdt_status;
 static unsigned long boot_status;
@@ -147,8 +149,7 @@ static int ixp4xx_wdt_release(struct inode *inode, struct file *file)
        if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
                wdt_disable();
        else
-               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-                                       "timer will not stop\n");
+               pr_crit("Device closed unexpectedly - timer will not stop\n");
        clear_bit(WDT_IN_USE, &wdt_status);
        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 
@@ -176,8 +177,7 @@ static int __init ixp4xx_wdt_init(void)
        int ret;
 
        if (!(read_cpuid_id() & 0xf) && !cpu_is_ixp46x()) {
-               printk(KERN_ERR "IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected"
-                       " - watchdog disabled\n");
+               pr_err("Rev. A0 IXP42x CPU detected - watchdog disabled\n");
 
                return -ENODEV;
        }
@@ -185,8 +185,7 @@ static int __init ixp4xx_wdt_init(void)
                        WDIOF_CARDRESET : 0;
        ret = misc_register(&ixp4xx_wdt_miscdev);
        if (ret == 0)
-               printk(KERN_INFO "IXP4xx Watchdog Timer: heartbeat %d sec\n",
-                       heartbeat);
+               pr_info("timer heartbeat %d sec\n", heartbeat);
        return ret;
 }
 
@@ -205,7 +204,7 @@ MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog");
 module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_LICENSE("GPL");
index 17ef300..978615e 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
-#include <linux/bitops.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/device.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
+#include <linux/err.h>
 
 #include <asm/mach-jz4740/timer.h>
 
@@ -41,9 +38,6 @@
 #define JZ_WDT_CLOCK_RTC  0x2
 #define JZ_WDT_CLOCK_EXT  0x4
 
-#define WDT_IN_USE        0
-#define WDT_OK_TO_CLOSE   1
-
 #define JZ_WDT_CLOCK_DIV_SHIFT   3
 
 #define JZ_WDT_CLOCK_DIV_1    (0 << JZ_WDT_CLOCK_DIV_SHIFT)
 #define DEFAULT_HEARTBEAT 5
 #define MAX_HEARTBEAT     2048
 
-static struct {
-       void __iomem *base;
-       struct resource *mem;
-       struct clk *rtc_clk;
-       unsigned long status;
-} jz4740_wdt;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+                "Watchdog cannot be stopped once started (default="
+                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-static int heartbeat = DEFAULT_HEARTBEAT;
+static unsigned int heartbeat = DEFAULT_HEARTBEAT;
+module_param(heartbeat, uint, 0);
+MODULE_PARM_DESC(heartbeat,
+               "Watchdog heartbeat period in seconds from 1 to "
+               __MODULE_STRING(MAX_HEARTBEAT) ", default "
+               __MODULE_STRING(DEFAULT_HEARTBEAT));
 
+struct jz4740_wdt_drvdata {
+       struct watchdog_device wdt;
+       void __iomem *base;
+       struct clk *rtc_clk;
+};
 
-static void jz4740_wdt_service(void)
+static int jz4740_wdt_ping(struct watchdog_device *wdt_dev)
 {
-       writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
+       struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
+
+       writew(0x0, drvdata->base + JZ_REG_WDT_TIMER_COUNTER);
+       return 0;
 }
 
-static void jz4740_wdt_set_heartbeat(int new_heartbeat)
+static int jz4740_wdt_set_timeout(struct watchdog_device *wdt_dev,
+                                   unsigned int new_timeout)
 {
+       struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
        unsigned int rtc_clk_rate;
        unsigned int timeout_value;
        unsigned short clock_div = JZ_WDT_CLOCK_DIV_1;
 
-       heartbeat = new_heartbeat;
-
-       rtc_clk_rate = clk_get_rate(jz4740_wdt.rtc_clk);
+       rtc_clk_rate = clk_get_rate(drvdata->rtc_clk);
 
-       timeout_value = rtc_clk_rate * heartbeat;
+       timeout_value = rtc_clk_rate * new_timeout;
        while (timeout_value > 0xffff) {
                if (clock_div == JZ_WDT_CLOCK_DIV_1024) {
                        /* Requested timeout too high;
@@ -93,199 +99,115 @@ static void jz4740_wdt_set_heartbeat(int new_heartbeat)
                clock_div += (1 << JZ_WDT_CLOCK_DIV_SHIFT);
        }
 
-       writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
-       writew(clock_div, jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
+       writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
+       writew(clock_div, drvdata->base + JZ_REG_WDT_TIMER_CONTROL);
 
-       writew((u16)timeout_value, jz4740_wdt.base + JZ_REG_WDT_TIMER_DATA);
-       writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
+       writew((u16)timeout_value, drvdata->base + JZ_REG_WDT_TIMER_DATA);
+       writew(0x0, drvdata->base + JZ_REG_WDT_TIMER_COUNTER);
        writew(clock_div | JZ_WDT_CLOCK_RTC,
-               jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
+               drvdata->base + JZ_REG_WDT_TIMER_CONTROL);
 
-       writeb(0x1, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
-}
+       writeb(0x1, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
 
-static void jz4740_wdt_enable(void)
-{
-       jz4740_timer_enable_watchdog();
-       jz4740_wdt_set_heartbeat(heartbeat);
-}
-
-static void jz4740_wdt_disable(void)
-{
-       jz4740_timer_disable_watchdog();
-       writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
+       wdt_dev->timeout = new_timeout;
+       return 0;
 }
 
-static int jz4740_wdt_open(struct inode *inode, struct file *file)
+static int jz4740_wdt_start(struct watchdog_device *wdt_dev)
 {
-       if (test_and_set_bit(WDT_IN_USE, &jz4740_wdt.status))
-               return -EBUSY;
-
-       jz4740_wdt_enable();
+       jz4740_timer_enable_watchdog();
+       jz4740_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
 
-       return nonseekable_open(inode, file);
+       return 0;
 }
 
-static ssize_t jz4740_wdt_write(struct file *file, const char *data,
-               size_t len, loff_t *ppos)
+static int jz4740_wdt_stop(struct watchdog_device *wdt_dev)
 {
-       if (len) {
-               size_t i;
-
-               clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
-               for (i = 0; i != len; i++) {
-                       char c;
+       struct jz4740_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
 
-                       if (get_user(c, data + i))
-                               return -EFAULT;
-
-                       if (c == 'V')
-                               set_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
-               }
-               jz4740_wdt_service();
-       }
+       jz4740_timer_disable_watchdog();
+       writeb(0x0, drvdata->base + JZ_REG_WDT_COUNTER_ENABLE);
 
-       return len;
+       return 0;
 }
 
-static const struct watchdog_info ident = {
-       .options = WDIOF_KEEPALIVEPING,
+static const struct watchdog_info jz4740_wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
        .identity = "jz4740 Watchdog",
 };
 
-static long jz4740_wdt_ioctl(struct file *file,
-                                       unsigned int cmd, unsigned long arg)
-{
-       int ret = -ENOTTY;
-       int heartbeat_seconds;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user((struct watchdog_info *)arg, &ident,
-                               sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(0, (int *)arg);
-               break;
-
-       case WDIOC_KEEPALIVE:
-               jz4740_wdt_service();
-               return 0;
-
-       case WDIOC_SETTIMEOUT:
-               if (get_user(heartbeat_seconds, (int __user *)arg))
-                       return -EFAULT;
-
-               jz4740_wdt_set_heartbeat(heartbeat_seconds);
-               return 0;
-
-       case WDIOC_GETTIMEOUT:
-               return put_user(heartbeat, (int *)arg);
-
-       default:
-               break;
-       }
-
-       return ret;
-}
-
-static int jz4740_wdt_release(struct inode *inode, struct file *file)
-{
-       jz4740_wdt_service();
-
-       if (test_and_clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status))
-               jz4740_wdt_disable();
-
-       clear_bit(WDT_IN_USE, &jz4740_wdt.status);
-       return 0;
-}
-
-static const struct file_operations jz4740_wdt_fops = {
+static const struct watchdog_ops jz4740_wdt_ops = {
        .owner = THIS_MODULE,
-       .llseek = no_llseek,
-       .write = jz4740_wdt_write,
-       .unlocked_ioctl = jz4740_wdt_ioctl,
-       .open = jz4740_wdt_open,
-       .release = jz4740_wdt_release,
-};
-
-static struct miscdevice jz4740_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &jz4740_wdt_fops,
+       .start = jz4740_wdt_start,
+       .stop = jz4740_wdt_stop,
+       .ping = jz4740_wdt_ping,
+       .set_timeout = jz4740_wdt_set_timeout,
 };
 
 static int __devinit jz4740_wdt_probe(struct platform_device *pdev)
 {
-       int ret = 0, size;
-       struct resource *res;
-       struct device *dev = &pdev->dev;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(dev, "failed to get memory region resource\n");
-               return -ENXIO;
+       struct jz4740_wdt_drvdata *drvdata;
+       struct watchdog_device *jz4740_wdt;
+       struct resource *res;
+       int ret;
+
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(struct jz4740_wdt_drvdata),
+                              GFP_KERNEL);
+       if (!drvdata) {
+               dev_err(&pdev->dev, "Unable to alloacate watchdog device\n");
+               return -ENOMEM;
        }
 
-       size = resource_size(res);
-       jz4740_wdt.mem = request_mem_region(res->start, size, pdev->name);
-       if (jz4740_wdt.mem == NULL) {
-               dev_err(dev, "failed to get memory region\n");
-               return -EBUSY;
-       }
+       if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+               heartbeat = DEFAULT_HEARTBEAT;
 
-       jz4740_wdt.base = ioremap_nocache(res->start, size);
-       if (jz4740_wdt.base == NULL) {
-               dev_err(dev, "failed to map memory region\n");
+       jz4740_wdt = &drvdata->wdt;
+       jz4740_wdt->info = &jz4740_wdt_info;
+       jz4740_wdt->ops = &jz4740_wdt_ops;
+       jz4740_wdt->timeout = heartbeat;
+       jz4740_wdt->min_timeout = 1;
+       jz4740_wdt->max_timeout = MAX_HEARTBEAT;
+       watchdog_set_nowayout(jz4740_wdt, nowayout);
+       watchdog_set_drvdata(jz4740_wdt, drvdata);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       drvdata->base = devm_request_and_ioremap(&pdev->dev, res);
+       if (drvdata->base == NULL) {
                ret = -EBUSY;
-               goto err_release_region;
+               goto err_out;
        }
 
-       jz4740_wdt.rtc_clk = clk_get(NULL, "rtc");
-       if (IS_ERR(jz4740_wdt.rtc_clk)) {
-               dev_err(dev, "cannot find RTC clock\n");
-               ret = PTR_ERR(jz4740_wdt.rtc_clk);
-               goto err_iounmap;
+       drvdata->rtc_clk = clk_get(NULL, "rtc");
+       if (IS_ERR(drvdata->rtc_clk)) {
+               dev_err(&pdev->dev, "cannot find RTC clock\n");
+               ret = PTR_ERR(drvdata->rtc_clk);
+               goto err_out;
        }
 
-       ret = misc_register(&jz4740_wdt_miscdev);
-       if (ret < 0) {
-               dev_err(dev, "cannot register misc device\n");
+       ret = watchdog_register_device(&drvdata->wdt);
+       if (ret < 0)
                goto err_disable_clk;
-       }
 
+       platform_set_drvdata(pdev, drvdata);
        return 0;
 
 err_disable_clk:
-       clk_put(jz4740_wdt.rtc_clk);
-err_iounmap:
-       iounmap(jz4740_wdt.base);
-err_release_region:
-       release_mem_region(jz4740_wdt.mem->start,
-                       resource_size(jz4740_wdt.mem));
+       clk_put(drvdata->rtc_clk);
+err_out:
        return ret;
 }
 
-
 static int __devexit jz4740_wdt_remove(struct platform_device *pdev)
 {
-       jz4740_wdt_disable();
-       misc_deregister(&jz4740_wdt_miscdev);
-       clk_put(jz4740_wdt.rtc_clk);
+       struct jz4740_wdt_drvdata *drvdata = platform_get_drvdata(pdev);
 
-       iounmap(jz4740_wdt.base);
-       jz4740_wdt.base = NULL;
-
-       release_mem_region(jz4740_wdt.mem->start,
-                               resource_size(jz4740_wdt.mem));
-       jz4740_wdt.mem = NULL;
+       jz4740_wdt_stop(&drvdata->wdt);
+       watchdog_unregister_device(&drvdata->wdt);
+       clk_put(drvdata->rtc_clk);
 
        return 0;
 }
 
-
 static struct platform_driver jz4740_wdt_driver = {
        .probe = jz4740_wdt_probe,
        .remove = __devexit_p(jz4740_wdt_remove),
@@ -299,13 +221,6 @@ module_platform_driver(jz4740_wdt_driver);
 
 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
 MODULE_DESCRIPTION("jz4740 Watchdog Driver");
-
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat,
-               "Watchdog heartbeat period in seconds from 1 to "
-               __MODULE_STRING(MAX_HEARTBEAT) ", default "
-               __MODULE_STRING(DEFAULT_HEARTBEAT));
-
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS("platform:jz4740-wdt");
index 51757a5..59e75d9 100644 (file)
@@ -8,6 +8,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #define WDT_MAX_TIME           171     /* seconds */
 
 static int wdt_time = WDT_DEFAULT_TIME;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 module_param(wdt_time, int, 0);
 MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
                                        __MODULE_STRING(WDT_DEFAULT_TIME) ")");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 #endif
@@ -233,8 +235,8 @@ static int __devinit ks8695wdt_probe(struct platform_device *pdev)
        if (res)
                return res;
 
-       printk(KERN_INFO "KS8695 Watchdog Timer enabled (%d seconds%s)\n",
-                               wdt_time, nowayout ? ", nowayout" : "");
+       pr_info("KS8695 Watchdog Timer enabled (%d seconds%s)\n",
+               wdt_time, nowayout ? ", nowayout" : "");
        return 0;
 }
 
index d3a63be..a9593a3 100644 (file)
@@ -7,6 +7,8 @@
  *  Based on EP93xx wdt driver
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
@@ -38,7 +40,7 @@
 #define LTQ_WDT_DIVIDER                0x40000
 #define LTQ_MAX_TIMEOUT                ((1 << 16) - 1) /* the reload field is 16 bit */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 static void __iomem *ltq_wdt_membase;
 static unsigned long ltq_io_region_clk_rate;
@@ -160,7 +162,7 @@ ltq_wdt_release(struct inode *inode, struct file *file)
        if (ltq_wdt_ok_to_close)
                ltq_wdt_disable();
        else
-               pr_err("ltq_wdt: watchdog closed without warning\n");
+               pr_err("watchdog closed without warning\n");
        ltq_wdt_ok_to_close = 0;
        clear_bit(0, &ltq_wdt_in_use);
 
@@ -249,7 +251,7 @@ exit_ltq_wdt(void)
 module_init(init_ltq_wdt);
 module_exit(exit_ltq_wdt);
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
index 4d43286..663cad8 100644 (file)
@@ -16,6 +16,8 @@
  * warranty of any kind, whether express or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -32,7 +34,7 @@
 #include <asm/m54xxsim.h>
 #include <asm/m54xxgpt.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned int heartbeat = 30;    /* (secs) Default is 0.5 minute */
 static unsigned long wdt_status;
 
@@ -166,8 +168,7 @@ static int m54xx_wdt_release(struct inode *inode, struct file *file)
        if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
                wdt_disable();
        else {
-               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-                                       "timer will not stop\n");
+               pr_crit("Device closed unexpectedly - timer will not stop\n");
                wdt_keepalive();
        }
        clear_bit(WDT_IN_USE, &wdt_status);
@@ -196,11 +197,10 @@ static int __init m54xx_wdt_init(void)
 {
        if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4,
                                                "Coldfire M54xx Watchdog")) {
-               printk(KERN_WARNING
-                               "Coldfire M54xx Watchdog : I/O region busy\n");
+               pr_warn("I/O region busy\n");
                return -EBUSY;
        }
-       printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
+       pr_info("driver is loaded\n");
 
        return misc_register(&m54xx_wdt_miscdev);
 }
@@ -220,7 +220,7 @@ MODULE_DESCRIPTION("Coldfire M54xx Watchdog");
 module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_LICENSE("GPL");
index b536111..bf84f78 100644 (file)
@@ -28,6 +28,8 @@
  *      Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -92,8 +94,8 @@ MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -140,10 +142,10 @@ static unsigned long next_heartbeat;
 #define ZF_CTIMEOUT 0xffff
 
 #ifndef ZF_DEBUG
-#      define dprintk(format, args...)
+#define dprintk(format, args...)
 #else
-#      define dprintk(format, args...) printk(KERN_DEBUG PFX \
-                               ":%s:%d: " format, __func__, __LINE__ , ## args)
+#define dprintk(format, args...)                                       \
+       pr_debug(":%s:%d: " format, __func__, __LINE__ , ## args)
 #endif
 
 
@@ -202,7 +204,7 @@ static void zf_timer_off(void)
        zf_set_control(ctrl_reg);
        spin_unlock_irqrestore(&zf_port_lock, flags);
 
-       printk(KERN_INFO PFX ": Watchdog timer is now disabled\n");
+       pr_info("Watchdog timer is now disabled\n");
 }
 
 
@@ -232,7 +234,7 @@ static void zf_timer_on(void)
        zf_set_control(ctrl_reg);
        spin_unlock_irqrestore(&zf_port_lock, flags);
 
-       printk(KERN_INFO PFX ": Watchdog timer is now enabled\n");
+       pr_info("Watchdog timer is now enabled\n");
 }
 
 
@@ -262,7 +264,7 @@ static void zf_ping(unsigned long data)
 
                mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
        } else
-               printk(KERN_CRIT PFX ": I will reset your machine\n");
+               pr_crit("I will reset your machine\n");
 }
 
 static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
@@ -341,8 +343,7 @@ static int zf_close(struct inode *inode, struct file *file)
                zf_timer_off();
        else {
                del_timer(&zf_timer);
-               printk(KERN_ERR PFX ": device file closed unexpectedly. "
-                                               "Will not stop the WDT!\n");
+               pr_err("device file closed unexpectedly. Will not stop the WDT!\n");
        }
        clear_bit(0, &zf_is_open);
        zf_expect_close = 0;
@@ -389,19 +390,18 @@ static void __init zf_show_action(int act)
 {
        static const char * const str[] = { "RESET", "SMI", "NMI", "SCI" };
 
-       printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]);
+       pr_info("Watchdog using action = %s\n", str[act]);
 }
 
 static int __init zf_init(void)
 {
        int ret;
 
-       printk(KERN_INFO PFX
-               ": MachZ ZF-Logic Watchdog driver initializing.\n");
+       pr_info("MachZ ZF-Logic Watchdog driver initializing\n");
 
        ret = zf_get_ZFL_version();
        if (!ret || ret == 0xffff) {
-               printk(KERN_WARNING PFX ": no ZF-Logic found\n");
+               pr_warn("no ZF-Logic found\n");
                return -ENODEV;
        }
 
@@ -413,23 +413,20 @@ static int __init zf_init(void)
        zf_show_action(action);
 
        if (!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")) {
-               printk(KERN_ERR "cannot reserve I/O ports at %d\n",
-                                                       ZF_IOBASE);
+               pr_err("cannot reserve I/O ports at %d\n", ZF_IOBASE);
                ret = -EBUSY;
                goto no_region;
        }
 
        ret = register_reboot_notifier(&zf_notifier);
        if (ret) {
-               printk(KERN_ERR "can't register reboot notifier (err=%d)\n",
-                                                                       ret);
+               pr_err("can't register reboot notifier (err=%d)\n", ret);
                goto no_reboot;
        }
 
        ret = misc_register(&zf_miscdev);
        if (ret) {
-               printk(KERN_ERR "can't misc_register on minor=%d\n",
-                                                       WATCHDOG_MINOR);
+               pr_err("can't misc_register on minor=%d\n", WATCHDOG_MINOR);
                goto no_misc;
        }
 
index af63ecf..8f4a74e 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
-#include <linux/device.h>
 #include <linux/slab.h>
 
 #define DEFAULT_HEARTBEAT 60
 #define MAX_HEARTBEAT     60
 
-static int heartbeat = DEFAULT_HEARTBEAT;
-static int nowayout  = WATCHDOG_NOWAYOUT;
+static unsigned int heartbeat = DEFAULT_HEARTBEAT;
+static bool nowayout  = WATCHDOG_NOWAYOUT;
 
 /*
  * Memory mapping: a single byte, 3 first lower bits to select bit 3
@@ -45,15 +42,8 @@ static int nowayout  = WATCHDOG_NOWAYOUT;
 
 static DEFINE_SPINLOCK(io_lock);
 
-static unsigned long wdt_status;
-#define WDT_IN_USE     0
-#define WDT_RUNNING    1
-#define WDT_OK_TO_CLOSE 2
-
 static int nodelay;
-static struct resource *wdt_mem;
 static void __iomem    *wdt_base;
-static struct platform_device *max63xx_pdev;
 
 /*
  * The timeout values used are actually the absolute minimum the chip
@@ -117,7 +107,7 @@ max63xx_select_timeout(struct max63xx_timeout *table, int value)
        return NULL;
 }
 
-static void max63xx_wdt_ping(void)
+static int max63xx_wdt_ping(struct watchdog_device *wdd)
 {
        u8 val;
 
@@ -129,15 +119,14 @@ static void max63xx_wdt_ping(void)
        __raw_writeb(val & ~MAX6369_WDI, wdt_base);
 
        spin_unlock(&io_lock);
+       return 0;
 }
 
-static void max63xx_wdt_enable(struct max63xx_timeout *entry)
+static int max63xx_wdt_start(struct watchdog_device *wdd)
 {
+       struct max63xx_timeout *entry = watchdog_get_drvdata(wdd);
        u8 val;
 
-       if (test_and_set_bit(WDT_RUNNING, &wdt_status))
-               return;
-
        spin_lock(&io_lock);
 
        val = __raw_readb(wdt_base);
@@ -149,10 +138,11 @@ static void max63xx_wdt_enable(struct max63xx_timeout *entry)
 
        /* check for a edge triggered startup */
        if (entry->tdelay == 0)
-               max63xx_wdt_ping();
+               max63xx_wdt_ping(wdd);
+       return 0;
 }
 
-static void max63xx_wdt_disable(void)
+static int max63xx_wdt_stop(struct watchdog_device *wdd)
 {
        u8 val;
 
@@ -164,113 +154,29 @@ static void max63xx_wdt_disable(void)
        __raw_writeb(val, wdt_base);
 
        spin_unlock(&io_lock);
-
-       clear_bit(WDT_RUNNING, &wdt_status);
-}
-
-static int max63xx_wdt_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-               return -EBUSY;
-
-       max63xx_wdt_enable(current_timeout);
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-       return nonseekable_open(inode, file);
-}
-
-static ssize_t max63xx_wdt_write(struct file *file, const char *data,
-                                size_t len, loff_t *ppos)
-{
-       if (len) {
-               if (!nowayout) {
-                       size_t i;
-
-                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-                       for (i = 0; i != len; i++) {
-                               char c;
-
-                               if (get_user(c, data + i))
-                                       return -EFAULT;
-
-                               if (c == 'V')
-                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
-                       }
-               }
-
-               max63xx_wdt_ping();
-       }
-
-       return len;
+       return 0;
 }
 
-static const struct watchdog_info ident = {
-       .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+static const struct watchdog_info max63xx_wdt_info = {
+       .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
        .identity = "max63xx Watchdog",
 };
 
-static long max63xx_wdt_ioctl(struct file *file, unsigned int cmd,
-                             unsigned long arg)
-{
-       int ret = -ENOTTY;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user((struct watchdog_info *)arg, &ident,
-                                  sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(0, (int *)arg);
-               break;
-
-       case WDIOC_KEEPALIVE:
-               max63xx_wdt_ping();
-               ret = 0;
-               break;
-
-       case WDIOC_GETTIMEOUT:
-               ret = put_user(heartbeat, (int *)arg);
-               break;
-       }
-       return ret;
-}
-
-static int max63xx_wdt_release(struct inode *inode, struct file *file)
-{
-       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-               max63xx_wdt_disable();
-       else
-               dev_crit(&max63xx_pdev->dev,
-                        "device closed unexpectedly - timer will not stop\n");
-
-       clear_bit(WDT_IN_USE, &wdt_status);
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-       return 0;
-}
-
-static const struct file_operations max63xx_wdt_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = max63xx_wdt_write,
-       .unlocked_ioctl = max63xx_wdt_ioctl,
-       .open           = max63xx_wdt_open,
-       .release        = max63xx_wdt_release,
+static const struct watchdog_ops max63xx_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = max63xx_wdt_start,
+       .stop = max63xx_wdt_stop,
+       .ping = max63xx_wdt_ping,
 };
 
-static struct miscdevice max63xx_wdt_miscdev = {
-       .minor  = WATCHDOG_MINOR,
-       .name   = "watchdog",
-       .fops   = &max63xx_wdt_fops,
+static struct watchdog_device max63xx_wdt_dev = {
+       .info = &max63xx_wdt_info,
+       .ops = &max63xx_wdt_ops,
 };
 
 static int __devinit max63xx_wdt_probe(struct platform_device *pdev)
 {
-       int ret = 0;
-       int size;
-       struct device *dev = &pdev->dev;
+       struct resource *wdt_mem;
        struct max63xx_timeout *table;
 
        table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
@@ -278,68 +184,34 @@ static int __devinit max63xx_wdt_probe(struct platform_device *pdev)
        if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
                heartbeat = DEFAULT_HEARTBEAT;
 
-       dev_info(dev, "requesting %ds heartbeat\n", heartbeat);
+       dev_info(&pdev->dev, "requesting %ds heartbeat\n", heartbeat);
        current_timeout = max63xx_select_timeout(table, heartbeat);
 
        if (!current_timeout) {
-               dev_err(dev, "unable to satisfy heartbeat request\n");
+               dev_err(&pdev->dev, "unable to satisfy heartbeat request\n");
                return -EINVAL;
        }
 
-       dev_info(dev, "using %ds heartbeat with %ds initial delay\n",
+       dev_info(&pdev->dev, "using %ds heartbeat with %ds initial delay\n",
                 current_timeout->twd, current_timeout->tdelay);
 
        heartbeat = current_timeout->twd;
 
-       max63xx_pdev = pdev;
-
        wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (wdt_mem == NULL) {
-               dev_err(dev, "failed to get memory region resource\n");
-               return -ENOENT;
-       }
+       wdt_base = devm_request_and_ioremap(&pdev->dev, wdt_mem);
+       if (!wdt_base)
+               return -ENOMEM;
 
-       size = resource_size(wdt_mem);
-       if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
-               dev_err(dev, "failed to get memory region\n");
-               return -ENOENT;
-       }
-
-       wdt_base = ioremap(wdt_mem->start, size);
-       if (!wdt_base) {
-               dev_err(dev, "failed to map memory region\n");
-               ret = -ENOMEM;
-               goto out_request;
-       }
+       max63xx_wdt_dev.timeout = heartbeat;
+       watchdog_set_nowayout(&max63xx_wdt_dev, nowayout);
+       watchdog_set_drvdata(&max63xx_wdt_dev, current_timeout);
 
-       ret = misc_register(&max63xx_wdt_miscdev);
-       if (ret < 0) {
-               dev_err(dev, "cannot register misc device\n");
-               goto out_unmap;
-       }
-
-       return 0;
-
-out_unmap:
-       iounmap(wdt_base);
-out_request:
-       release_mem_region(wdt_mem->start, size);
-       wdt_mem = NULL;
-
-       return ret;
+       return watchdog_register_device(&max63xx_wdt_dev);
 }
 
 static int __devexit max63xx_wdt_remove(struct platform_device *pdev)
 {
-       misc_deregister(&max63xx_wdt_miscdev);
-       if (wdt_mem) {
-               release_mem_region(wdt_mem->start, resource_size(wdt_mem));
-               wdt_mem = NULL;
-       }
-
-       if (wdt_base)
-               iounmap(wdt_base);
-
+       watchdog_unregister_device(&max63xx_wdt_dev);
        return 0;
 }
 
@@ -375,7 +247,7 @@ MODULE_PARM_DESC(heartbeat,
                 __MODULE_STRING(MAX_HEARTBEAT) ", default "
                 __MODULE_STRING(DEFAULT_HEARTBEAT));
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
index bc820d1..37e4b52 100644 (file)
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define VERSION "0.6"
 #define WATCHDOG_NAME "mixcomwd"
-#define PFX WATCHDOG_NAME ": "
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -107,8 +108,8 @@ static int mixcomwd_timer_alive;
 static DEFINE_TIMER(mixcomwd_timer, mixcomwd_timerfun, 0, 0);
 static char expect_close;
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -156,15 +157,13 @@ static int mixcomwd_release(struct inode *inode, struct file *file)
 {
        if (expect_close == 42) {
                if (mixcomwd_timer_alive) {
-                       printk(KERN_ERR PFX
-                               "release called while internal timer alive");
+                       pr_err("release called while internal timer alive\n");
                        return -EBUSY;
                }
                mixcomwd_timer_alive = 1;
                mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
        } else
-               printk(KERN_CRIT PFX
-                   "WDT device closed unexpectedly.  WDT will not stop!\n");
+               pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
 
        clear_bit(0, &mixcomwd_opened);
        expect_close = 0;
@@ -274,22 +273,19 @@ static int __init mixcomwd_init(void)
        }
 
        if (!found) {
-               printk(KERN_ERR PFX
-                       "No card detected, or port not available.\n");
+               pr_err("No card detected, or port not available\n");
                return -ENODEV;
        }
 
        ret = misc_register(&mixcomwd_miscdev);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto error_misc_register_watchdog;
        }
 
-       printk(KERN_INFO
-               "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
-                                       VERSION, watchdog_port);
+       pr_info("MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
+               VERSION, watchdog_port);
 
        return 0;
 
@@ -303,8 +299,7 @@ static void __exit mixcomwd_exit(void)
 {
        if (!nowayout) {
                if (mixcomwd_timer_alive) {
-                       printk(KERN_WARNING PFX "I quit now, hardware will"
-                              " probably reboot!\n");
+                       pr_warn("I quit now, hardware will probably reboot!\n");
                        del_timer_sync(&mixcomwd_timer);
                        mixcomwd_timer_alive = 0;
                }
index 20feb4d..40f7bf1 100644 (file)
@@ -17,6 +17,8 @@
  * option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -60,8 +62,8 @@ module_param(reset, bool, 0);
 MODULE_PARM_DESC(reset,
        "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
                 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -96,7 +98,7 @@ static void mpc8xxx_wdt_timer_ping(unsigned long arg)
 
 static void mpc8xxx_wdt_pr_warn(const char *msg)
 {
-       pr_crit("mpc8xxx_wdt: %s, expect the %s soon!\n", msg,
+       pr_crit("%s, expect the %s soon!\n", msg,
                reset ? "reset" : "machine check exception");
 }
 
@@ -209,7 +211,7 @@ static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev)
 
        enabled = in_be32(&wd_base->swcrr) & SWCRR_SWEN;
        if (!enabled && wdt_type->hw_enabled) {
-               pr_info("mpc8xxx_wdt: could not be enabled in software\n");
+               pr_info("could not be enabled in software\n");
                ret = -ENOSYS;
                goto err_unmap;
        }
@@ -226,9 +228,8 @@ static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev)
                goto err_unmap;
 #endif
 
-       pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d "
-               "(%d seconds)\n", reset ? "reset" : "interrupt", timeout,
-               timeout_sec);
+       pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n",
+               reset ? "reset" : "interrupt", timeout, timeout_sec);
 
        /*
         * If the watchdog was previously enabled or we're running on
@@ -303,7 +304,7 @@ static int mpc8xxx_wdt_init_late(void)
        ret = misc_register(&mpc8xxx_wdt_miscdev);
        if (ret) {
                pr_err("cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, ret);
+                      WATCHDOG_MINOR, ret);
                return ret;
        }
        return 0;
index 82ccd36..7c741dc 100644 (file)
@@ -19,6 +19,9 @@
  *     (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -44,7 +47,7 @@ struct mpcore_wdt {
        char            expect_close;
 };
 
-static struct platform_device *mpcore_wdt_dev;
+static struct platform_device *mpcore_wdt_pdev;
 static DEFINE_SPINLOCK(wdt_lock);
 
 #define TIMER_MARGIN   60
@@ -54,8 +57,8 @@ MODULE_PARM_DESC(mpcore_margin,
        "MPcore timer margin in seconds. (0 < mpcore_margin < 65536, default="
                                __MODULE_STRING(TIMER_MARGIN) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -148,7 +151,7 @@ static int mpcore_wdt_set_heartbeat(int t)
  */
 static int mpcore_wdt_open(struct inode *inode, struct file *file)
 {
-       struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_dev);
+       struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_pdev);
 
        if (test_and_set_bit(0, &wdt->timer_alive))
                return -EBUSY;
@@ -298,9 +301,9 @@ static long mpcore_wdt_ioctl(struct file *file, unsigned int cmd,
  *     System shutdown handler.  Turn off the watchdog if we're
  *     restarting or halting the system.
  */
-static void mpcore_wdt_shutdown(struct platform_device *dev)
+static void mpcore_wdt_shutdown(struct platform_device *pdev)
 {
-       struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+       struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
 
        if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT)
                mpcore_wdt_stop(wdt);
@@ -324,99 +327,79 @@ static struct miscdevice mpcore_wdt_miscdev = {
        .fops           = &mpcore_wdt_fops,
 };
 
-static int __devinit mpcore_wdt_probe(struct platform_device *dev)
+static int __devinit mpcore_wdt_probe(struct platform_device *pdev)
 {
        struct mpcore_wdt *wdt;
        struct resource *res;
        int ret;
 
        /* We only accept one device, and it must have an id of -1 */
-       if (dev->id != -1)
+       if (pdev->id != -1)
                return -ENODEV;
 
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENODEV;
-               goto err_out;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
 
-       wdt = kzalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
-       if (!wdt) {
-               ret = -ENOMEM;
-               goto err_out;
+       wdt = devm_kzalloc(&pdev->dev, sizeof(struct mpcore_wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       wdt->dev = &pdev->dev;
+       wdt->irq = platform_get_irq(pdev, 0);
+       if (wdt->irq >= 0) {
+               ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0,
+                               "mpcore_wdt", wdt);
+               if (ret) {
+                       dev_printk(KERN_ERR, wdt->dev,
+                                       "cannot register IRQ%d for watchdog\n",
+                                       wdt->irq);
+                       return ret;
+               }
        }
 
-       wdt->dev = &dev->dev;
-       wdt->irq = platform_get_irq(dev, 0);
-       if (wdt->irq < 0) {
-               ret = -ENXIO;
-               goto err_free;
-       }
-       wdt->base = ioremap(res->start, resource_size(res));
-       if (!wdt->base) {
-               ret = -ENOMEM;
-               goto err_free;
-       }
+       wdt->base = devm_ioremap(wdt->dev, res->start, resource_size(res));
+       if (!wdt->base)
+               return -ENOMEM;
 
-       mpcore_wdt_miscdev.parent = &dev->dev;
+       mpcore_wdt_miscdev.parent = &pdev->dev;
        ret = misc_register(&mpcore_wdt_miscdev);
        if (ret) {
                dev_printk(KERN_ERR, wdt->dev,
                        "cannot register miscdev on minor=%d (err=%d)\n",
                                                        WATCHDOG_MINOR, ret);
-               goto err_misc;
-       }
-
-       ret = request_irq(wdt->irq, mpcore_wdt_fire, 0, "mpcore_wdt", wdt);
-       if (ret) {
-               dev_printk(KERN_ERR, wdt->dev,
-                       "cannot register IRQ%d for watchdog\n", wdt->irq);
-               goto err_irq;
+               return ret;
        }
 
        mpcore_wdt_stop(wdt);
-       platform_set_drvdata(dev, wdt);
-       mpcore_wdt_dev = dev;
+       platform_set_drvdata(pdev, wdt);
+       mpcore_wdt_pdev = pdev;
 
        return 0;
-
-err_irq:
-       misc_deregister(&mpcore_wdt_miscdev);
-err_misc:
-       iounmap(wdt->base);
-err_free:
-       kfree(wdt);
-err_out:
-       return ret;
 }
 
-static int __devexit mpcore_wdt_remove(struct platform_device *dev)
+static int __devexit mpcore_wdt_remove(struct platform_device *pdev)
 {
-       struct mpcore_wdt *wdt = platform_get_drvdata(dev);
-
-       platform_set_drvdata(dev, NULL);
+       platform_set_drvdata(pdev, NULL);
 
        misc_deregister(&mpcore_wdt_miscdev);
 
-       mpcore_wdt_dev = NULL;
+       mpcore_wdt_pdev = NULL;
 
-       free_irq(wdt->irq, wdt);
-       iounmap(wdt->base);
-       kfree(wdt);
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int mpcore_wdt_suspend(struct platform_device *dev, pm_message_t msg)
+static int mpcore_wdt_suspend(struct platform_device *pdev, pm_message_t msg)
 {
-       struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+       struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
        mpcore_wdt_stop(wdt);           /* Turn the WDT off */
        return 0;
 }
 
-static int mpcore_wdt_resume(struct platform_device *dev)
+static int mpcore_wdt_resume(struct platform_device *pdev)
 {
-       struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+       struct mpcore_wdt *wdt = platform_get_drvdata(pdev);
        /* re-activate timer */
        if (test_bit(0, &wdt->timer_alive))
                mpcore_wdt_start(wdt);
@@ -442,9 +425,6 @@ static struct platform_driver mpcore_wdt_driver = {
        },
 };
 
-static char banner[] __initdata = KERN_INFO "MPcore Watchdog Timer: 0.1. "
-               "mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n";
-
 static int __init mpcore_wdt_init(void)
 {
        /*
@@ -453,11 +433,12 @@ static int __init mpcore_wdt_init(void)
         */
        if (mpcore_wdt_set_heartbeat(mpcore_margin)) {
                mpcore_wdt_set_heartbeat(TIMER_MARGIN);
-               printk(KERN_INFO "mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n",
+               pr_info("mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n",
                        TIMER_MARGIN);
        }
 
-       printk(banner, mpcore_noboot, mpcore_margin, nowayout);
+       pr_info("MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n",
+               mpcore_noboot, mpcore_margin, nowayout);
 
        return platform_driver_register(&mpcore_wdt_driver);
 }
index 97f8a48..c53d025 100644 (file)
@@ -15,6 +15,8 @@
  * or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -58,8 +60,8 @@ static unsigned int bus_clk;
 static char expect_close;
 static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -100,7 +102,7 @@ static void mv64x60_wdt_handler_enable(void)
        if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE,
                                   MV64x60_WDC_ENABLE_SHIFT)) {
                mv64x60_wdt_service();
-               printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
+               pr_notice("watchdog activated\n");
        }
 }
 
@@ -108,7 +110,7 @@ static void mv64x60_wdt_handler_disable(void)
 {
        if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
                                   MV64x60_WDC_ENABLE_SHIFT))
-               printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
+               pr_notice("watchdog deactivated\n");
 }
 
 static void mv64x60_wdt_set_timeout(unsigned int timeout)
@@ -139,8 +141,7 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file)
        if (expect_close == 42)
                mv64x60_wdt_handler_disable();
        else {
-               printk(KERN_CRIT
-                      "mv64x60_wdt: unexpected close, not stopping timer!\n");
+               pr_crit("unexpected close, not stopping timer!\n");
                mv64x60_wdt_service();
        }
        expect_close = 0;
@@ -308,7 +309,7 @@ static struct platform_driver mv64x60_wdt_driver = {
 
 static int __init mv64x60_wdt_init(void)
 {
-       printk(KERN_INFO "MV64x60 watchdog driver\n");
+       pr_info("MV64x60 watchdog driver\n");
 
        return platform_driver_register(&mv64x60_wdt_driver);
 }
index 529085b..ea4c744 100644 (file)
@@ -55,8 +55,8 @@ module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
        "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
        "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
index 809f41c..6bbb9ef 100644 (file)
@@ -21,6 +21,8 @@
  *     Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -41,7 +43,6 @@
 #define TCO_VERSION "0.01"
 #define TCO_MODULE_NAME "NV_TCO"
 #define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
-#define PFX TCO_MODULE_NAME ": "
 
 /* internal variables */
 static unsigned int tcobase;
@@ -60,8 +61,8 @@ module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, "
                            "default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
                " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -169,8 +170,7 @@ static int nv_tco_release(struct inode *inode, struct file *file)
        if (tco_expect_close == 42) {
                tco_timer_stop();
        } else {
-               printk(KERN_CRIT PFX "Unexpected close, not stopping "
-                      "watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                tco_timer_keepalive();
        }
        clear_bit(0, &timer_alive);
@@ -323,15 +323,14 @@ static unsigned char __devinit nv_tco_getdevice(void)
        val &= 0xffff;
        if (val == 0x0001 || val == 0x0000) {
                /* Something is wrong here, bar isn't setup */
-               printk(KERN_ERR PFX "failed to get tcobase address\n");
+               pr_err("failed to get tcobase address\n");
                return 0;
        }
        val &= 0xff00;
        tcobase = val + 0x40;
 
        if (!request_region(tcobase, 0x10, "NV TCO")) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                      tcobase);
+               pr_err("I/O address 0x%04x already in use\n", tcobase);
                return 0;
        }
 
@@ -347,7 +346,7 @@ static unsigned char __devinit nv_tco_getdevice(void)
 
        /* Disable SMI caused by TCO */
        if (!request_region(MCP51_SMI_EN(tcobase), 4, "NV TCO")) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+               pr_err("I/O address 0x%04x already in use\n",
                       MCP51_SMI_EN(tcobase));
                goto out;
        }
@@ -357,7 +356,7 @@ static unsigned char __devinit nv_tco_getdevice(void)
        val = inl(MCP51_SMI_EN(tcobase));
        release_region(MCP51_SMI_EN(tcobase), 4);
        if (val & MCP51_SMI_EN_TCO) {
-               printk(KERN_ERR PFX "Could not disable SMI caused by TCO\n");
+               pr_err("Could not disable SMI caused by TCO\n");
                goto out;
        }
 
@@ -367,8 +366,7 @@ static unsigned char __devinit nv_tco_getdevice(void)
        pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
        pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
        if (!(val & MCP51_SMBUS_SETUP_B_TCO_REBOOT)) {
-               printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot "
-                      "disabled by hardware\n");
+               pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
                goto out;
        }
 
@@ -387,8 +385,8 @@ static int __devinit nv_tco_init(struct platform_device *dev)
                return -ENODEV;
 
        /* Check to see if last reboot was due to watchdog timeout */
-       printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n",
-              inl(TCO_STS(tcobase)) & TCO_STS_TCO2TO_STS ? "" : "not ");
+       pr_info("Watchdog reboot %sdetected\n",
+               inl(TCO_STS(tcobase)) & TCO_STS_TCO2TO_STS ? "" : "not ");
 
        /* Clear out the old status */
        outl(TCO_STS_RESET, TCO_STS(tcobase));
@@ -400,14 +398,14 @@ static int __devinit nv_tco_init(struct platform_device *dev)
        if (tco_timer_set_heartbeat(heartbeat)) {
                heartbeat = WATCHDOG_HEARTBEAT;
                tco_timer_set_heartbeat(heartbeat);
-               printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, "
-                      "using %d\n", heartbeat);
+               pr_info("heartbeat value must be 2<heartbeat<39, using %d\n",
+                       heartbeat);
        }
 
        ret = misc_register(&nv_tco_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
-                      "(err=%d)\n", WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto unreg_region;
        }
 
@@ -415,8 +413,8 @@ static int __devinit nv_tco_init(struct platform_device *dev)
 
        tco_timer_stop();
 
-       printk(KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec "
-              "(nowayout=%d)\n", tcobase, heartbeat, nowayout);
+       pr_info("initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n",
+               tcobase, heartbeat, nowayout);
 
        return 0;
 
@@ -439,8 +437,7 @@ static void __devexit nv_tco_cleanup(void)
        pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
        pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
        if (val & MCP51_SMBUS_SETUP_B_TCO_REBOOT) {
-               printk(KERN_CRIT PFX "Couldn't unset REBOOT bit.  Machine may "
-                      "soon reset\n");
+               pr_crit("Couldn't unset REBOOT bit.  Machine may soon reset\n");
        }
 
        /* Deregister */
@@ -483,8 +480,7 @@ static int __init nv_tco_init_module(void)
 {
        int err;
 
-       printk(KERN_INFO PFX "NV TCO WatchDog Timer Driver v%s\n",
-              TCO_VERSION);
+       pr_info("NV TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
 
        err = platform_driver_register(&nv_tco_driver);
        if (err)
@@ -508,7 +504,7 @@ static void __exit nv_tco_cleanup_module(void)
 {
        platform_device_unregister(nv_tco_platform_device);
        platform_driver_unregister(&nv_tco_driver);
-       printk(KERN_INFO PFX "NV TCO Watchdog Module Unloaded.\n");
+       pr_info("NV TCO Watchdog Module Unloaded\n");
 }
 
 module_init(nv_tco_init_module);
index 7c0d863..4612088 100644 (file)
@@ -52,6 +52,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/miscdevice.h>
 #include <linux/interrupt.h>
 #include <linux/watchdog.h>
@@ -95,8 +97,8 @@ MODULE_PARM_DESC(heartbeat,
        "Watchdog heartbeat in seconds. (0 < heartbeat, default="
                                __MODULE_STRING(WD_TIMO) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, S_IRUGO);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, S_IRUGO);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -201,7 +203,7 @@ static void __init octeon_wdt_build_stage1(void)
        uasm_resolve_relocs(relocs, labels);
 
        len = (int)(p - nmi_stage1_insns);
-       pr_debug("Synthesized NMI stage 1 handler (%d instructions).\n", len);
+       pr_debug("Synthesized NMI stage 1 handler (%d instructions)\n", len);
 
        pr_debug("\t.set push\n");
        pr_debug("\t.set noreorder\n");
@@ -627,7 +629,7 @@ static int octeon_wdt_release(struct inode *inode, struct file *file)
                do_coundown = 0;
                octeon_wdt_ping();
        } else {
-               pr_crit("octeon_wdt: WDT device closed unexpectedly.  WDT will not stop!\n");
+               pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
        }
        clear_bit(0, &octeon_wdt_is_open);
        expect_close = 0;
@@ -684,12 +686,12 @@ static int __init octeon_wdt_init(void)
 
        octeon_wdt_calc_parameters(heartbeat);
 
-       pr_info("octeon_wdt: Initial granularity %d Sec.\n", timeout_sec);
+       pr_info("Initial granularity %d Sec\n", timeout_sec);
 
        ret = misc_register(&octeon_wdt_miscdev);
        if (ret) {
-               pr_err("octeon_wdt: cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto out;
        }
 
index f359ab8..55d2f66 100644 (file)
@@ -19,6 +19,8 @@
 *                know the wdt reset interval
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -99,7 +101,7 @@ static void xwdt_stop(void)
        iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
 
        spin_unlock(&spinlock);
-       printk(KERN_INFO PFX "Stopped!\n");
+       pr_info("Stopped!\n");
 }
 
 static void xwdt_keepalive(void)
@@ -165,7 +167,7 @@ static int xwdt_open(struct inode *inode, struct file *file)
                __module_get(THIS_MODULE);
 
        xwdt_start();
-       printk(KERN_INFO PFX "Started...\n");
+       pr_info("Started...\n");
 
        return nonseekable_open(inode, file);
 }
@@ -175,8 +177,7 @@ static int xwdt_release(struct inode *inode, struct file *file)
        if (expect_close == 42) {
                xwdt_stop();
        } else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                xwdt_keepalive();
        }
 
@@ -300,22 +301,20 @@ static int __devinit xwdt_probe(struct platform_device *pdev)
                                        "clock-frequency", NULL);
 
        if (pfreq == NULL) {
-               printk(KERN_WARNING PFX
-                       "The watchdog clock frequency cannot be obtained!\n");
+               pr_warn("The watchdog clock frequency cannot be obtained!\n");
                no_timeout = 1;
        }
 
        rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res);
        if (rc) {
-               printk(KERN_WARNING PFX "invalid address!\n");
+               pr_warn("invalid address!\n");
                return rc;
        }
 
        tmptr = (u32 *)of_get_property(pdev->dev.of_node,
                                        "xlnx,wdt-interval", NULL);
        if (tmptr == NULL) {
-               printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-interval\""
-                                       " not found in device tree!\n");
+               pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n");
                no_timeout = 1;
        } else {
                xdev.wdt_interval = *tmptr;
@@ -324,8 +323,7 @@ static int __devinit xwdt_probe(struct platform_device *pdev)
        tmptr = (u32 *)of_get_property(pdev->dev.of_node,
                                        "xlnx,wdt-enable-once", NULL);
        if (tmptr == NULL) {
-               printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-enable-once\""
-                                       " not found in device tree!\n");
+               pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n");
                xdev.nowayout = WATCHDOG_NOWAYOUT;
        }
 
@@ -339,20 +337,20 @@ static int __devinit xwdt_probe(struct platform_device *pdev)
        if (!request_mem_region(xdev.res.start,
                        xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) {
                rc = -ENXIO;
-               printk(KERN_ERR PFX "memory request failure!\n");
+               pr_err("memory request failure!\n");
                goto err_out;
        }
 
        xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1);
        if (xdev.base == NULL) {
                rc = -ENOMEM;
-               printk(KERN_ERR PFX "ioremap failure!\n");
+               pr_err("ioremap failure!\n");
                goto release_mem;
        }
 
        rc = xwdt_selftest();
        if (rc == XWT_TIMER_FAILED) {
-               printk(KERN_ERR PFX "SelfTest routine error!\n");
+               pr_err("SelfTest routine error!\n");
                goto unmap_io;
        }
 
@@ -360,20 +358,17 @@ static int __devinit xwdt_probe(struct platform_device *pdev)
 
        rc = misc_register(&xwdt_miscdev);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                               xwdt_miscdev.minor, rc);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      xwdt_miscdev.minor, rc);
                goto unmap_io;
        }
 
        if (no_timeout)
-               printk(KERN_INFO PFX
-                       "driver loaded (timeout=? sec, nowayout=%d)\n",
-                                                   xdev.nowayout);
+               pr_info("driver loaded (timeout=? sec, nowayout=%d)\n",
+                       xdev.nowayout);
        else
-               printk(KERN_INFO PFX
-                       "driver loaded (timeout=%d sec, nowayout=%d)\n",
-                                       timeout, xdev.nowayout);
+               pr_info("driver loaded (timeout=%d sec, nowayout=%d)\n",
+                       timeout, xdev.nowayout);
 
        expect_close = 0;
        clear_bit(0, &driver_open);
index d19ff51..8285d65 100644 (file)
@@ -26,6 +26,8 @@
  *     Use the driver model and standard identifiers; handle bigger timeouts.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -183,7 +185,7 @@ static int omap_wdt_release(struct inode *inode, struct file *file)
 
        pm_runtime_put_sync(wdev->dev);
 #else
-       printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
+       pr_crit("Unexpected close, not stopping!\n");
 #endif
        wdev->omap_wdt_users = 0;
 
index 4ad78f8..788aa15 100644 (file)
@@ -10,6 +10,8 @@
  * warranty of any kind, whether express or implied.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 /*
  * Watchdog timer block registers.
  */
-#define TIMER_CTRL             (TIMER_VIRT_BASE + 0x0000)
+#define TIMER_CTRL             0x0000
 #define  WDT_EN                        0x0010
-#define WDT_VAL                        (TIMER_VIRT_BASE + 0x0024)
+#define WDT_VAL                        0x0024
 
 #define WDT_MAX_CYCLE_COUNT    0xffffffff
 #define WDT_IN_USE             0
 #define WDT_OK_TO_CLOSE                1
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = -1;             /* module parameter (seconds) */
 static unsigned int wdt_max_duration;  /* (seconds) */
 static unsigned int wdt_tclk;
+static void __iomem *wdt_reg;
 static unsigned long wdt_status;
 static DEFINE_SPINLOCK(wdt_lock);
 
@@ -48,7 +51,7 @@ static void orion_wdt_ping(void)
        spin_lock(&wdt_lock);
 
        /* Reload watchdog duration */
-       writel(wdt_tclk * heartbeat, WDT_VAL);
+       writel(wdt_tclk * heartbeat, wdt_reg + WDT_VAL);
 
        spin_unlock(&wdt_lock);
 }
@@ -60,7 +63,7 @@ static void orion_wdt_enable(void)
        spin_lock(&wdt_lock);
 
        /* Set watchdog duration */
-       writel(wdt_tclk * heartbeat, WDT_VAL);
+       writel(wdt_tclk * heartbeat, wdt_reg + WDT_VAL);
 
        /* Clear watchdog timer interrupt */
        reg = readl(BRIDGE_CAUSE);
@@ -68,9 +71,9 @@ static void orion_wdt_enable(void)
        writel(reg, BRIDGE_CAUSE);
 
        /* Enable watchdog timer */
-       reg = readl(TIMER_CTRL);
+       reg = readl(wdt_reg + TIMER_CTRL);
        reg |= WDT_EN;
-       writel(reg, TIMER_CTRL);
+       writel(reg, wdt_reg + TIMER_CTRL);
 
        /* Enable reset on watchdog */
        reg = readl(RSTOUTn_MASK);
@@ -92,9 +95,9 @@ static void orion_wdt_disable(void)
        writel(reg, RSTOUTn_MASK);
 
        /* Disable watchdog timer */
-       reg = readl(TIMER_CTRL);
+       reg = readl(wdt_reg + TIMER_CTRL);
        reg &= ~WDT_EN;
-       writel(reg, TIMER_CTRL);
+       writel(reg, wdt_reg + TIMER_CTRL);
 
        spin_unlock(&wdt_lock);
 }
@@ -102,7 +105,7 @@ static void orion_wdt_disable(void)
 static int orion_wdt_get_timeleft(int *time_left)
 {
        spin_lock(&wdt_lock);
-       *time_left = readl(WDT_VAL) / wdt_tclk;
+       *time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk;
        spin_unlock(&wdt_lock);
        return 0;
 }
@@ -209,8 +212,7 @@ static int orion_wdt_release(struct inode *inode, struct file *file)
        if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
                orion_wdt_disable();
        else
-               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-                                       "timer will not stop\n");
+               pr_crit("Device closed unexpectedly - timer will not stop\n");
        clear_bit(WDT_IN_USE, &wdt_status);
        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 
@@ -236,15 +238,20 @@ static struct miscdevice orion_wdt_miscdev = {
 static int __devinit orion_wdt_probe(struct platform_device *pdev)
 {
        struct orion_wdt_platform_data *pdata = pdev->dev.platform_data;
+       struct resource *res;
        int ret;
 
        if (pdata) {
                wdt_tclk = pdata->tclk;
        } else {
-               printk(KERN_ERR "Orion Watchdog misses platform data\n");
+               pr_err("misses platform data\n");
                return -ENODEV;
        }
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       wdt_reg = ioremap(res->start, resource_size(res));
+
        if (orion_wdt_miscdev.parent)
                return -EBUSY;
        orion_wdt_miscdev.parent = &pdev->dev;
@@ -257,8 +264,8 @@ static int __devinit orion_wdt_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       printk(KERN_INFO "Orion Watchdog Timer: Initial timeout %d sec%s\n",
-                               heartbeat, nowayout ? ", nowayout" : "");
+       pr_info("Initial timeout %d sec%s\n",
+               heartbeat, nowayout ? ", nowayout" : "");
        return 0;
 }
 
@@ -302,7 +309,7 @@ MODULE_DESCRIPTION("Orion Processor Watchdog");
 module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
index 669e562..5afb89b 100644 (file)
@@ -18,6 +18,8 @@
  *      Release 1.1
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
@@ -41,7 +43,6 @@
 
 #define VERSION             "1.1"
 #define MODNAME             "pc87413 WDT"
-#define PFX                 MODNAME ": "
 #define DPFX                MODNAME " - DEBUG: "
 
 #define WDT_INDEX_IO_PORT   (io+0)     /* I/O port base (index register) */
@@ -64,7 +65,7 @@ static char expect_close;             /* is the close expected? */
 
 static DEFINE_SPINLOCK(io_lock);       /* to guard us from io races */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 /* -- Low level function ----------------------------------------*/
 
@@ -86,7 +87,7 @@ static inline void pc87413_select_wdt_out(void)
        outb_p(cr_data, WDT_DATA_IO_PORT);
 
 #ifdef DEBUG
-       printk(KERN_INFO DPFX
+       pr_info(DPFX
                "Select multiple pin,pin55,as WDT output: Bit7 to 1: %d\n",
                                                                cr_data);
 #endif
@@ -110,7 +111,7 @@ static inline void pc87413_enable_swc(void)
        outb_p(cr_data, WDT_DATA_IO_PORT);      /* Index0x30_bit0P1 */
 
 #ifdef DEBUG
-       printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n");
+       pr_info(DPFX "pc87413 - Enable SWC functions\n");
 #endif
 }
 
@@ -131,7 +132,7 @@ static void pc87413_get_swc_base_addr(void)
 
        swc_base_addr = (addr_h << 8) + addr_l;
 #ifdef DEBUG
-       printk(KERN_INFO DPFX
+       pr_info(DPFX
                "Read SWC I/O Base Address: low %d, high %d, res %d\n",
                                                addr_l, addr_h, swc_base_addr);
 #endif
@@ -144,7 +145,7 @@ static inline void pc87413_swc_bank3(void)
        /* Step 4: Select Bank3 of SWC */
        outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);
 #ifdef DEBUG
-       printk(KERN_INFO DPFX "Select Bank3 of SWC\n");
+       pr_info(DPFX "Select Bank3 of SWC\n");
 #endif
 }
 
@@ -155,7 +156,7 @@ static inline void pc87413_programm_wdto(char pc87413_time)
        /* Step 5: Programm WDTO, Twd. */
        outb_p(pc87413_time, swc_base_addr + WDTO);
 #ifdef DEBUG
-       printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time);
+       pr_info(DPFX "Set WDTO to %d minutes\n", pc87413_time);
 #endif
 }
 
@@ -166,7 +167,7 @@ static inline void pc87413_enable_wden(void)
        /* Step 6: Enable WDEN */
        outb_p(inb(swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);
 #ifdef DEBUG
-       printk(KERN_INFO DPFX "Enable WDEN\n");
+       pr_info(DPFX "Enable WDEN\n");
 #endif
 }
 
@@ -176,7 +177,7 @@ static inline void pc87413_enable_sw_wd_tren(void)
        /* Enable SW_WD_TREN */
        outb_p(inb(swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);
 #ifdef DEBUG
-       printk(KERN_INFO DPFX "Enable SW_WD_TREN\n");
+       pr_info(DPFX "Enable SW_WD_TREN\n");
 #endif
 }
 
@@ -187,7 +188,7 @@ static inline void pc87413_disable_sw_wd_tren(void)
        /* Disable SW_WD_TREN */
        outb_p(inb(swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);
 #ifdef DEBUG
-       printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n");
+       pr_info(DPFX "pc87413 - Disable SW_WD_TREN\n");
 #endif
 }
 
@@ -198,7 +199,7 @@ static inline void pc87413_enable_sw_wd_trg(void)
        /* Enable SW_WD_TRG */
        outb_p(inb(swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);
 #ifdef DEBUG
-       printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n");
+       pr_info(DPFX "pc87413 - Enable SW_WD_TRG\n");
 #endif
 }
 
@@ -209,7 +210,7 @@ static inline void pc87413_disable_sw_wd_trg(void)
        /* Disable SW_WD_TRG */
        outb_p(inb(swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);
 #ifdef DEBUG
-       printk(KERN_INFO DPFX "Disable SW_WD_TRG\n");
+       pr_info(DPFX "Disable SW_WD_TRG\n");
 #endif
 }
 
@@ -283,8 +284,7 @@ static int pc87413_open(struct inode *inode, struct file *file)
        /* Reload and activate timer */
        pc87413_refresh();
 
-       printk(KERN_INFO MODNAME
-               "Watchdog enabled. Timeout set to %d minute(s).\n", timeout);
+       pr_info("Watchdog enabled. Timeout set to %d minute(s).\n", timeout);
 
        return nonseekable_open(inode, file);
 }
@@ -307,11 +307,9 @@ static int pc87413_release(struct inode *inode, struct file *file)
 
        if (expect_close == 42) {
                pc87413_disable();
-               printk(KERN_INFO MODNAME
-                               "Watchdog disabled, sleeping again...\n");
+               pr_info("Watchdog disabled, sleeping again...\n");
        } else {
-               printk(KERN_CRIT MODNAME
-                               "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                pc87413_refresh();
        }
        clear_bit(0, &timer_enabled);
@@ -427,7 +425,7 @@ static long pc87413_ioctl(struct file *file, unsigned int cmd,
        case WDIOC_KEEPALIVE:
                pc87413_refresh();
 #ifdef DEBUG
-               printk(KERN_INFO DPFX "keepalive\n");
+               pr_info(DPFX "keepalive\n");
 #endif
                return 0;
        case WDIOC_SETTIMEOUT:
@@ -507,7 +505,7 @@ static int __init pc87413_init(void)
 {
        int ret;
 
-       printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n",
+       pr_info("Version " VERSION " at io 0x%X\n",
                                                        WDT_INDEX_IO_PORT);
 
        if (!request_muxed_region(io, 2, MODNAME))
@@ -515,26 +513,23 @@ static int __init pc87413_init(void)
 
        ret = register_reboot_notifier(&pc87413_notifier);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
        }
 
        ret = misc_register(&pc87413_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto reboot_unreg;
        }
-       printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
+       pr_info("initialized. timeout=%d min\n", timeout);
 
        pc87413_select_wdt_out();
        pc87413_enable_swc();
        pc87413_get_swc_base_addr();
 
        if (!request_region(swc_base_addr, 0x20, MODNAME)) {
-               printk(KERN_ERR PFX
-                       "cannot request SWC region at 0x%x\n", swc_base_addr);
+               pr_err("cannot request SWC region at 0x%x\n", swc_base_addr);
                ret = -EBUSY;
                goto misc_unreg;
        }
@@ -567,14 +562,14 @@ static void __exit pc87413_exit(void)
        /* Stop the timer before we leave */
        if (!nowayout) {
                pc87413_disable();
-               printk(KERN_INFO MODNAME "Watchdog disabled.\n");
+               pr_info("Watchdog disabled\n");
        }
 
        misc_deregister(&pc87413_miscdev);
        unregister_reboot_notifier(&pc87413_notifier);
        release_region(swc_base_addr, 0x20);
 
-       printk(KERN_INFO MODNAME " watchdog component driver removed.\n");
+       pr_info("watchdog component driver removed\n");
 }
 
 module_init(pc87413_init);
@@ -596,7 +591,7 @@ MODULE_PARM_DESC(timeout,
                "Watchdog timeout in minutes (default="
                                __MODULE_STRING(DEFAULT_TIMEOUT) ").");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
index 06f7922..75694cf 100644 (file)
@@ -51,6 +51,8 @@
  *     http://www.pcwatchdog.com/
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>      /* For module specific items */
 #include <linux/moduleparam.h> /* For new moduleparam's */
 #include <linux/types.h>       /* For standard types (like size_t) */
@@ -75,7 +77,6 @@
 #define WATCHDOG_DATE "18 Feb 2007"
 #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
 #define WATCHDOG_NAME "pcwd"
-#define PFX WATCHDOG_NAME ": "
 #define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION "\n"
 
 /*
@@ -203,8 +204,8 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. "
        "(2 <= heartbeat <= 7200 or 0=delay-time from dip-switches, default="
                                __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -220,8 +221,7 @@ static int send_isa_command(int cmd)
        int port0, last_port0;  /* Double read for stabilising */
 
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "sending following data cmd=0x%02x\n",
-                       cmd);
+               pr_debug("sending following data cmd=0x%02x\n", cmd);
 
        /* The WCMD bit must be 1 and the command is only 4 bits in size */
        control_status = (cmd & 0x0F) | WD_WCMD;
@@ -240,9 +240,8 @@ static int send_isa_command(int cmd)
        }
 
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "received following data for "
-                       "cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n",
-                       cmd, port0, last_port0);
+               pr_debug("received following data for cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n",
+                        cmd, port0, last_port0);
 
        return port0;
 }
@@ -271,8 +270,7 @@ static int set_command_mode(void)
        pcwd_private.command_mode = found;
 
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "command_mode=%d\n",
-                               pcwd_private.command_mode);
+               pr_debug("command_mode=%d\n", pcwd_private.command_mode);
 
        return found;
 }
@@ -288,8 +286,7 @@ static void unset_command_mode(void)
        pcwd_private.command_mode = 0;
 
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "command_mode=%d\n",
-                               pcwd_private.command_mode);
+               pr_debug("command_mode=%d\n", pcwd_private.command_mode);
 }
 
 static inline void pcwd_check_temperature_support(void)
@@ -336,17 +333,14 @@ static void pcwd_show_card_info(void)
 
        /* Get some extra info from the hardware (in command/debug/diag mode) */
        if (pcwd_private.revision == PCWD_REVISION_A)
-               printk(KERN_INFO PFX
-                       "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n",
-                                                       pcwd_private.io_addr);
+               pr_info("ISA-PC Watchdog (REV.A) detected at port 0x%04x\n",
+                       pcwd_private.io_addr);
        else if (pcwd_private.revision == PCWD_REVISION_C) {
                pcwd_get_firmware();
-               printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port "
-                       "0x%04x (Firmware version: %s)\n",
+               pr_info("ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
                        pcwd_private.io_addr, pcwd_private.fw_ver_str);
                option_switches = pcwd_get_option_switches();
-               printk(KERN_INFO PFX "Option switches (0x%02x): "
-                       "Temperature Reset Enable=%s, Power On Delay=%s\n",
+               pr_info("Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
                        option_switches,
                        ((option_switches & 0x10) ? "ON" : "OFF"),
                        ((option_switches & 0x08) ? "ON" : "OFF"));
@@ -359,22 +353,18 @@ static void pcwd_show_card_info(void)
        }
 
        if (pcwd_private.supports_temp)
-               printk(KERN_INFO PFX "Temperature Option Detected\n");
+               pr_info("Temperature Option Detected\n");
 
        if (pcwd_private.boot_status & WDIOF_CARDRESET)
-               printk(KERN_INFO PFX
-                       "Previous reboot was caused by the card\n");
+               pr_info("Previous reboot was caused by the card\n");
 
        if (pcwd_private.boot_status & WDIOF_OVERHEAT) {
-               printk(KERN_EMERG PFX
-                       "Card senses a CPU Overheat. Panicking!\n");
-               printk(KERN_EMERG PFX
-                       "CPU Overheat\n");
+               pr_emerg("Card senses a CPU Overheat. Panicking!\n");
+               pr_emerg("CPU Overheat\n");
        }
 
        if (pcwd_private.boot_status == 0)
-               printk(KERN_INFO PFX
-                       "No previous trip detected - Cold boot or reset\n");
+               pr_info("No previous trip detected - Cold boot or reset\n");
 }
 
 static void pcwd_timer_ping(unsigned long data)
@@ -404,8 +394,7 @@ static void pcwd_timer_ping(unsigned long data)
 
                spin_unlock(&pcwd_private.io_lock);
        } else {
-               printk(KERN_WARNING PFX
-                       "Heartbeat lost! Will not ping the watchdog\n");
+               pr_warn("Heartbeat lost! Will not ping the watchdog\n");
        }
 }
 
@@ -426,13 +415,13 @@ static int pcwd_start(void)
                stat_reg = inb_p(pcwd_private.io_addr + 2);
                spin_unlock(&pcwd_private.io_lock);
                if (stat_reg & WD_WDIS) {
-                       printk(KERN_INFO PFX "Could not start watchdog\n");
+                       pr_info("Could not start watchdog\n");
                        return -EIO;
                }
        }
 
        if (debug >= VERBOSE)
-               printk(KERN_DEBUG PFX "Watchdog started\n");
+               pr_debug("Watchdog started\n");
 
        return 0;
 }
@@ -454,13 +443,13 @@ static int pcwd_stop(void)
                stat_reg = inb_p(pcwd_private.io_addr + 2);
                spin_unlock(&pcwd_private.io_lock);
                if ((stat_reg & WD_WDIS) == 0) {
-                       printk(KERN_INFO PFX "Could not stop watchdog\n");
+                       pr_info("Could not stop watchdog\n");
                        return -EIO;
                }
        }
 
        if (debug >= VERBOSE)
-               printk(KERN_DEBUG PFX "Watchdog stopped\n");
+               pr_debug("Watchdog stopped\n");
 
        return 0;
 }
@@ -471,7 +460,7 @@ static int pcwd_keepalive(void)
        pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
 
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
+               pr_debug("Watchdog keepalive signal send\n");
 
        return 0;
 }
@@ -484,8 +473,7 @@ static int pcwd_set_heartbeat(int t)
        heartbeat = t;
 
        if (debug >= VERBOSE)
-               printk(KERN_DEBUG PFX "New heartbeat: %d\n",
-                      heartbeat);
+               pr_debug("New heartbeat: %d\n", heartbeat);
 
        return 0;
 }
@@ -518,8 +506,7 @@ static int pcwd_get_status(int *status)
                if (control_status & WD_T110) {
                        *status |= WDIOF_OVERHEAT;
                        if (temp_panic) {
-                               printk(KERN_INFO PFX
-                                       "Temperature overheat trip!\n");
+                               pr_info("Temperature overheat trip!\n");
                                kernel_power_off();
                        }
                }
@@ -530,8 +517,7 @@ static int pcwd_get_status(int *status)
                if (control_status & WD_REVC_TTRP) {
                        *status |= WDIOF_OVERHEAT;
                        if (temp_panic) {
-                               printk(KERN_INFO PFX
-                                       "Temperature overheat trip!\n");
+                               pr_info("Temperature overheat trip!\n");
                                kernel_power_off();
                        }
                }
@@ -548,16 +534,14 @@ static int pcwd_clear_status(void)
                spin_lock(&pcwd_private.io_lock);
 
                if (debug >= VERBOSE)
-                       printk(KERN_INFO PFX
-                                       "clearing watchdog trip status\n");
+                       pr_info("clearing watchdog trip status\n");
 
                control_status = inb_p(pcwd_private.io_addr + 1);
 
                if (debug >= DEBUG) {
-                       printk(KERN_DEBUG PFX "status was: 0x%02x\n",
-                               control_status);
-                       printk(KERN_DEBUG PFX "sending: 0x%02x\n",
-                               (control_status & WD_REVC_R2DS));
+                       pr_debug("status was: 0x%02x\n", control_status);
+                       pr_debug("sending: 0x%02x\n",
+                                (control_status & WD_REVC_R2DS));
                }
 
                /* clear reset status & Keep Relay 2 disable state as it is */
@@ -588,8 +572,7 @@ static int pcwd_get_temperature(int *temperature)
        spin_unlock(&pcwd_private.io_lock);
 
        if (debug >= DEBUG) {
-               printk(KERN_DEBUG PFX "temperature is: %d F\n",
-                       *temperature);
+               pr_debug("temperature is: %d F\n", *temperature);
        }
 
        return 0;
@@ -720,8 +703,7 @@ static int pcwd_close(struct inode *inode, struct file *file)
        if (expect_close == 42)
                pcwd_stop();
        else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                pcwd_keepalive();
        }
        expect_close = 0;
@@ -828,11 +810,10 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id)
        int retval;
 
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n",
-                       id);
+               pr_debug("pcwd_isa_match id=%d\n", id);
 
        if (!request_region(base_addr, 4, "PCWD")) {
-               printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
+               pr_info("Port 0x%04x unavailable\n", base_addr);
                return 0;
        }
 
@@ -870,21 +851,20 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
        int ret;
 
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "pcwd_isa_probe id=%d\n",
-                       id);
+               pr_debug("pcwd_isa_probe id=%d\n", id);
 
        cards_found++;
        if (cards_found == 1)
-               printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n",
+               pr_info("v%s Ken Hollis (kenji@bitgate.com)\n",
                                                        WATCHDOG_VERSION);
 
        if (cards_found > 1) {
-               printk(KERN_ERR PFX "This driver only supports 1 device\n");
+               pr_err("This driver only supports 1 device\n");
                return -ENODEV;
        }
 
        if (pcwd_ioports[id] == 0x0000) {
-               printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+               pr_err("No I/O-Address for card detected\n");
                return -ENODEV;
        }
        pcwd_private.io_addr = pcwd_ioports[id];
@@ -896,8 +876,8 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
 
        if (!request_region(pcwd_private.io_addr,
                (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       pcwd_private.io_addr);
+               pr_err("I/O address 0x%04x already in use\n",
+                      pcwd_private.io_addr);
                ret = -EIO;
                goto error_request_region;
        }
@@ -932,30 +912,27 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
           if not reset to the default */
        if (pcwd_set_heartbeat(heartbeat)) {
                pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
-               printk(KERN_INFO PFX
-                 "heartbeat value must be 2 <= heartbeat <= 7200, using %d\n",
-                                                       WATCHDOG_HEARTBEAT);
+               pr_info("heartbeat value must be 2 <= heartbeat <= 7200, using %d\n",
+                       WATCHDOG_HEARTBEAT);
        }
 
        if (pcwd_private.supports_temp) {
                ret = misc_register(&temp_miscdev);
                if (ret) {
-                       printk(KERN_ERR PFX
-                           "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       TEMP_MINOR, ret);
+                       pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                              TEMP_MINOR, ret);
                        goto error_misc_register_temp;
                }
        }
 
        ret = misc_register(&pcwd_miscdev);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto error_misc_register_watchdog;
        }
 
-       printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+       pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
                heartbeat, nowayout);
 
        return 0;
@@ -975,8 +952,7 @@ error_request_region:
 static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
 {
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "pcwd_isa_remove id=%d\n",
-                       id);
+               pr_debug("pcwd_isa_remove id=%d\n", id);
 
        if (!pcwd_private.io_addr)
                return 1;
@@ -1000,8 +976,7 @@ static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
 static void pcwd_isa_shutdown(struct device *dev, unsigned int id)
 {
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "pcwd_isa_shutdown id=%d\n",
-                       id);
+               pr_debug("pcwd_isa_shutdown id=%d\n", id);
 
        pcwd_stop();
 }
@@ -1025,7 +1000,7 @@ static int __init pcwd_init_module(void)
 static void __exit pcwd_cleanup_module(void)
 {
        isa_unregister_driver(&pcwd_isa_driver);
-       printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+       pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(pcwd_init_module);
index b8d14f8..c891399 100644 (file)
@@ -32,6 +32,8 @@
  *     Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>      /* For module specific items */
 #include <linux/moduleparam.h> /* For new moduleparam's */
 #include <linux/types.h>       /* For standard types (like size_t) */
@@ -54,8 +56,7 @@
 #define WATCHDOG_VERSION "1.03"
 #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
 #define WATCHDOG_NAME "pcwd_pci"
-#define PFX WATCHDOG_NAME ": "
-#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION "\n"
+#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION
 
 /* Stuff for the PCI ID's  */
 #ifndef PCI_VENDOR_ID_QUICKLOGIC
@@ -145,8 +146,8 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. "
        "(0<heartbeat<65536 or 0=delay-time from dip-switches, default="
                                __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                                        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -159,8 +160,8 @@ static int send_command(int cmd, int *msb, int *lsb)
        int got_response, count;
 
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "sending following data "
-               "cmd=0x%02x msb=0x%02x lsb=0x%02x\n", cmd, *msb, *lsb);
+               pr_debug("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x\n",
+                        cmd, *msb, *lsb);
 
        spin_lock(&pcipcwd_private.io_lock);
        /* If a command requires data it should be written first.
@@ -185,12 +186,10 @@ static int send_command(int cmd, int *msb, int *lsb)
 
        if (debug >= DEBUG) {
                if (got_response) {
-                       printk(KERN_DEBUG PFX
-                               "time to process command was: %d ms\n",
-                               count);
+                       pr_debug("time to process command was: %d ms\n",
+                                count);
                } else {
-                       printk(KERN_DEBUG PFX
-                               "card did not respond on command!\n");
+                       pr_debug("card did not respond on command!\n");
                }
        }
 
@@ -203,9 +202,8 @@ static int send_command(int cmd, int *msb, int *lsb)
                inb_p(pcipcwd_private.io_addr + 6);
 
                if (debug >= DEBUG)
-                       printk(KERN_DEBUG PFX "received following data for "
-                               "cmd=0x%02x: msb=0x%02x lsb=0x%02x\n",
-                               cmd, *msb, *lsb);
+                       pr_debug("received following data for cmd=0x%02x: msb=0x%02x lsb=0x%02x\n",
+                                cmd, *msb, *lsb);
        }
 
        spin_unlock(&pcipcwd_private.io_lock);
@@ -243,27 +241,23 @@ static void pcipcwd_show_card_info(void)
        /* Get switch settings */
        option_switches = pcipcwd_get_option_switches();
 
-       printk(KERN_INFO PFX "Found card at port "
-               "0x%04x (Firmware: %s) %s temp option\n",
+       pr_info("Found card at port 0x%04x (Firmware: %s) %s temp option\n",
                (int) pcipcwd_private.io_addr, fw_ver_str,
                (pcipcwd_private.supports_temp ? "with" : "without"));
 
-       printk(KERN_INFO PFX "Option switches (0x%02x): "
-               "Temperature Reset Enable=%s, Power On Delay=%s\n",
+       pr_info("Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
                option_switches,
                ((option_switches & 0x10) ? "ON" : "OFF"),
                ((option_switches & 0x08) ? "ON" : "OFF"));
 
        if (pcipcwd_private.boot_status & WDIOF_CARDRESET)
-               printk(KERN_INFO PFX
-                       "Previous reset was caused by the Watchdog card\n");
+               pr_info("Previous reset was caused by the Watchdog card\n");
 
        if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)
-               printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");
+               pr_info("Card sensed a CPU Overheat\n");
 
        if (pcipcwd_private.boot_status == 0)
-               printk(KERN_INFO PFX
-                       "No previous trip detected - Cold boot or reset\n");
+               pr_info("No previous trip detected - Cold boot or reset\n");
 }
 
 static int pcipcwd_start(void)
@@ -278,12 +272,12 @@ static int pcipcwd_start(void)
        spin_unlock(&pcipcwd_private.io_lock);
 
        if (stat_reg & WD_PCI_WDIS) {
-               printk(KERN_ERR PFX "Card timer not enabled\n");
+               pr_err("Card timer not enabled\n");
                return -1;
        }
 
        if (debug >= VERBOSE)
-               printk(KERN_DEBUG PFX "Watchdog started\n");
+               pr_debug("Watchdog started\n");
 
        return 0;
 }
@@ -303,13 +297,12 @@ static int pcipcwd_stop(void)
        spin_unlock(&pcipcwd_private.io_lock);
 
        if (!(stat_reg & WD_PCI_WDIS)) {
-               printk(KERN_ERR PFX
-                       "Card did not acknowledge disable attempt\n");
+               pr_err("Card did not acknowledge disable attempt\n");
                return -1;
        }
 
        if (debug >= VERBOSE)
-               printk(KERN_DEBUG PFX "Watchdog stopped\n");
+               pr_debug("Watchdog stopped\n");
 
        return 0;
 }
@@ -322,7 +315,7 @@ static int pcipcwd_keepalive(void)
        spin_unlock(&pcipcwd_private.io_lock);
 
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
+               pr_debug("Watchdog keepalive signal send\n");
 
        return 0;
 }
@@ -340,8 +333,7 @@ static int pcipcwd_set_heartbeat(int t)
 
        heartbeat = t;
        if (debug >= VERBOSE)
-               printk(KERN_DEBUG PFX "New heartbeat: %d\n",
-                      heartbeat);
+               pr_debug("New heartbeat: %d\n", heartbeat);
 
        return 0;
 }
@@ -357,12 +349,11 @@ static int pcipcwd_get_status(int *status)
        if (control_status & WD_PCI_TTRP) {
                *status |= WDIOF_OVERHEAT;
                if (temp_panic)
-                       panic(PFX "Temperature overheat trip!\n");
+                       panic(KBUILD_MODNAME ": Temperature overheat trip!\n");
        }
 
        if (debug >= DEBUG)
-               printk(KERN_DEBUG PFX "Control Status #1: 0x%02x\n",
-                      control_status);
+               pr_debug("Control Status #1: 0x%02x\n", control_status);
 
        return 0;
 }
@@ -374,14 +365,14 @@ static int pcipcwd_clear_status(void)
        int reset_counter;
 
        if (debug >= VERBOSE)
-               printk(KERN_INFO PFX "clearing watchdog trip status & LED\n");
+               pr_info("clearing watchdog trip status & LED\n");
 
        control_status = inb_p(pcipcwd_private.io_addr + 1);
 
        if (debug >= DEBUG) {
-               printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status);
-               printk(KERN_DEBUG PFX "sending: 0x%02x\n",
-                      (control_status & WD_PCI_R2DS) | WD_PCI_WTRP);
+               pr_debug("status was: 0x%02x\n", control_status);
+               pr_debug("sending: 0x%02x\n",
+                        (control_status & WD_PCI_R2DS) | WD_PCI_WTRP);
        }
 
        /* clear trip status & LED and keep mode of relay 2 */
@@ -394,8 +385,7 @@ static int pcipcwd_clear_status(void)
        send_command(CMD_GET_CLEAR_RESET_COUNT, &msb, &reset_counter);
 
        if (debug >= DEBUG) {
-               printk(KERN_DEBUG PFX "reset count was: 0x%02x\n",
-                      reset_counter);
+               pr_debug("reset count was: 0x%02x\n", reset_counter);
        }
 
        return 0;
@@ -418,8 +408,7 @@ static int pcipcwd_get_temperature(int *temperature)
        *temperature = (*temperature * 9 / 5) + 32;
 
        if (debug >= DEBUG) {
-               printk(KERN_DEBUG PFX "temperature is: %d F\n",
-                      *temperature);
+               pr_debug("temperature is: %d F\n", *temperature);
        }
 
        return 0;
@@ -437,8 +426,7 @@ static int pcipcwd_get_timeleft(int *time_left)
        *time_left = (msb << 8) + lsb;
 
        if (debug >= VERBOSE)
-               printk(KERN_DEBUG PFX "Time left before next reboot: %d\n",
-                      *time_left);
+               pr_debug("Time left before next reboot: %d\n", *time_left);
 
        return 0;
 }
@@ -583,8 +571,7 @@ static int pcipcwd_open(struct inode *inode, struct file *file)
        /* /dev/watchdog can only be opened once */
        if (test_and_set_bit(0, &is_active)) {
                if (debug >= VERBOSE)
-                       printk(KERN_ERR PFX
-                               "Attempt to open already opened device.\n");
+                       pr_err("Attempt to open already opened device\n");
                return -EBUSY;
        }
 
@@ -602,8 +589,7 @@ static int pcipcwd_release(struct inode *inode, struct file *file)
        if (expect_release == 42) {
                pcipcwd_stop();
        } else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                pcipcwd_keepalive();
        }
        expect_release = 0;
@@ -703,20 +689,20 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
 
        cards_found++;
        if (cards_found == 1)
-               printk(KERN_INFO PFX DRIVER_VERSION);
+               pr_info("%s\n", DRIVER_VERSION);
 
        if (cards_found > 1) {
-               printk(KERN_ERR PFX "This driver only supports 1 device\n");
+               pr_err("This driver only supports 1 device\n");
                return -ENODEV;
        }
 
        if (pci_enable_device(pdev)) {
-               printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
+               pr_err("Not possible to enable PCI Device\n");
                return -ENODEV;
        }
 
        if (pci_resource_start(pdev, 0) == 0x0000) {
-               printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+               pr_err("No I/O-Address for card detected\n");
                ret = -ENODEV;
                goto err_out_disable_device;
        }
@@ -725,8 +711,8 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
        pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
 
        if (pci_request_regions(pdev, WATCHDOG_NAME)) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       (int) pcipcwd_private.io_addr);
+               pr_err("I/O address 0x%04x already in use\n",
+                      (int) pcipcwd_private.io_addr);
                ret = -EIO;
                goto err_out_disable_device;
        }
@@ -755,36 +741,33 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
         * if not reset to the default */
        if (pcipcwd_set_heartbeat(heartbeat)) {
                pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
-               printk(KERN_INFO PFX
-                       "heartbeat value must be 0<heartbeat<65536, using %d\n",
+               pr_info("heartbeat value must be 0<heartbeat<65536, using %d\n",
                        WATCHDOG_HEARTBEAT);
        }
 
        ret = register_reboot_notifier(&pcipcwd_notifier);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                goto err_out_release_region;
        }
 
        if (pcipcwd_private.supports_temp) {
                ret = misc_register(&pcipcwd_temp_miscdev);
                if (ret != 0) {
-                       printk(KERN_ERR PFX "cannot register miscdev on "
-                               "minor=%d (err=%d)\n", TEMP_MINOR, ret);
+                       pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                              TEMP_MINOR, ret);
                        goto err_out_unregister_reboot;
                }
        }
 
        ret = misc_register(&pcipcwd_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto err_out_misc_deregister;
        }
 
-       printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+       pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
                heartbeat, nowayout);
 
        return 0;
@@ -842,7 +825,7 @@ static void __exit pcipcwd_cleanup_module(void)
 {
        pci_unregister_driver(&pcipcwd_driver);
 
-       printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+       pr_info("Watchdog Module Unloaded\n");
 }
 
 module_init(pcipcwd_init_module);
index d8de1dd..7b14d18 100644 (file)
@@ -24,6 +24,8 @@
  *     http://www.berkprod.com/ or http://www.pcwatchdog.com/
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>      /* For module specific items */
 #include <linux/moduleparam.h> /* For new moduleparam's */
 #include <linux/types.h>       /* For standard types (like size_t) */
 #include <linux/hid.h>         /* For HID_REQ_SET_REPORT & HID_DT_REPORT */
 #include <linux/uaccess.h>     /* For copy_to_user/put_user/... */
 
-
 #ifdef CONFIG_USB_DEBUG
-       static int debug = 1;
+static int debug = 1;
 #else
-       static int debug;
+static int debug;
 #endif
 
 /* Use our own dbg macro */
+
 #undef dbg
-#define dbg(format, arg...) \
-       do { if (debug) printk(KERN_DEBUG PFX format "\n" , ## arg); } while (0)
+#ifndef DEBUG
+#define DEBUG
+#endif
+#define dbg(format, ...)                               \
+do {                                                   \
+       if (debug)                                      \
+               pr_debug(format "\n", ##__VA_ARGS__);   \
+} while (0)
 
 /* Module and Version Information */
 #define DRIVER_VERSION "1.02"
@@ -60,7 +68,6 @@
 #define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
 #define DRIVER_LICENSE "GPL"
 #define DRIVER_NAME "pcwd_usb"
-#define PFX DRIVER_NAME ": "
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -80,8 +87,8 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. "
        "(0<heartbeat<65536 or 0=delay-time from dip-switches, default="
                                __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -220,8 +227,8 @@ static void usb_pcwd_intr_done(struct urb *urb)
 resubmit:
        retval = usb_submit_urb(urb, GFP_ATOMIC);
        if (retval)
-               printk(KERN_ERR PFX "can't resubmit intr, "
-                       "usb_submit_urb failed with result %d\n", retval);
+               pr_err("can't resubmit intr, usb_submit_urb failed with result %d\n",
+                      retval);
 }
 
 static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd,
@@ -284,8 +291,7 @@ static int usb_pcwd_start(struct usb_pcwd_private *usb_pcwd)
                                                                &msb, &lsb);
 
        if ((retval == 0) || (lsb == 0)) {
-               printk(KERN_ERR PFX
-                               "Card did not acknowledge enable attempt\n");
+               pr_err("Card did not acknowledge enable attempt\n");
                return -1;
        }
 
@@ -303,8 +309,7 @@ static int usb_pcwd_stop(struct usb_pcwd_private *usb_pcwd)
                                                                &msb, &lsb);
 
        if ((retval == 0) || (lsb != 0)) {
-               printk(KERN_ERR PFX
-                       "Card did not acknowledge disable attempt\n");
+               pr_err("Card did not acknowledge disable attempt\n");
                return -1;
        }
 
@@ -506,8 +511,7 @@ static int usb_pcwd_release(struct inode *inode, struct file *file)
        if (expect_release == 42) {
                usb_pcwd_stop(usb_pcwd_device);
        } else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                usb_pcwd_keepalive(usb_pcwd_device);
        }
        expect_release = 0;
@@ -627,7 +631,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
 
        cards_found++;
        if (cards_found > 1) {
-               printk(KERN_ERR PFX "This driver only supports 1 device\n");
+               pr_err("This driver only supports 1 device\n");
                return -ENODEV;
        }
 
@@ -636,8 +640,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
 
        /* check out that we have a HID device */
        if (!(iface_desc->desc.bInterfaceClass == USB_CLASS_HID)) {
-               printk(KERN_ERR PFX
-                       "The device isn't a Human Interface Device\n");
+               pr_err("The device isn't a Human Interface Device\n");
                return -ENODEV;
        }
 
@@ -646,7 +649,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
 
        if (!usb_endpoint_is_int_in(endpoint)) {
                /* we didn't find a Interrupt endpoint with direction IN */
-               printk(KERN_ERR PFX "Couldn't find an INTR & IN endpoint\n");
+               pr_err("Couldn't find an INTR & IN endpoint\n");
                return -ENODEV;
        }
 
@@ -657,7 +660,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
        /* allocate memory for our device and initialize it */
        usb_pcwd = kzalloc(sizeof(struct usb_pcwd_private), GFP_KERNEL);
        if (usb_pcwd == NULL) {
-               printk(KERN_ERR PFX "Out of memory\n");
+               pr_err("Out of memory\n");
                goto error;
        }
 
@@ -674,14 +677,14 @@ static int usb_pcwd_probe(struct usb_interface *interface,
        usb_pcwd->intr_buffer = usb_alloc_coherent(udev, usb_pcwd->intr_size,
                                        GFP_ATOMIC, &usb_pcwd->intr_dma);
        if (!usb_pcwd->intr_buffer) {
-               printk(KERN_ERR PFX "Out of memory\n");
+               pr_err("Out of memory\n");
                goto error;
        }
 
        /* allocate the urb's */
        usb_pcwd->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!usb_pcwd->intr_urb) {
-               printk(KERN_ERR PFX "Out of memory\n");
+               pr_err("Out of memory\n");
                goto error;
        }
 
@@ -694,7 +697,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
 
        /* register our interrupt URB with the USB system */
        if (usb_submit_urb(usb_pcwd->intr_urb, GFP_KERNEL)) {
-               printk(KERN_ERR PFX "Problem registering interrupt URB\n");
+               pr_err("Problem registering interrupt URB\n");
                retval = -EIO; /* failure */
                goto error;
        }
@@ -713,15 +716,13 @@ static int usb_pcwd_probe(struct usb_interface *interface,
        else
                sprintf(fw_ver_str, "<card no answer>");
 
-       printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n",
-               fw_ver_str);
+       pr_info("Found card (Firmware: %s) with temp option\n", fw_ver_str);
 
        /* Get switch settings */
        usb_pcwd_send_command(usb_pcwd, CMD_GET_DIP_SWITCH_SETTINGS, &dummy,
                                                        &option_switches);
 
-       printk(KERN_INFO PFX "Option switches (0x%02x): "
-               "Temperature Reset Enable=%s, Power On Delay=%s\n",
+       pr_info("Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
                option_switches,
                ((option_switches & 0x10) ? "ON" : "OFF"),
                ((option_switches & 0x08) ? "ON" : "OFF"));
@@ -734,39 +735,34 @@ static int usb_pcwd_probe(struct usb_interface *interface,
         * if not reset to the default */
        if (usb_pcwd_set_heartbeat(usb_pcwd, heartbeat)) {
                usb_pcwd_set_heartbeat(usb_pcwd, WATCHDOG_HEARTBEAT);
-               printk(KERN_INFO PFX
-                       "heartbeat value must be 0<heartbeat<65536, using %d\n",
+               pr_info("heartbeat value must be 0<heartbeat<65536, using %d\n",
                        WATCHDOG_HEARTBEAT);
        }
 
        retval = register_reboot_notifier(&usb_pcwd_notifier);
        if (retval != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n",
-                       retval);
+               pr_err("cannot register reboot notifier (err=%d)\n", retval);
                goto error;
        }
 
        retval = misc_register(&usb_pcwd_temperature_miscdev);
        if (retval != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                       TEMP_MINOR, retval);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      TEMP_MINOR, retval);
                goto err_out_unregister_reboot;
        }
 
        retval = misc_register(&usb_pcwd_miscdev);
        if (retval != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, retval);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, retval);
                goto err_out_misc_deregister;
        }
 
        /* we can register the device now, as it is ready */
        usb_set_intfdata(interface, usb_pcwd);
 
-       printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+       pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
                heartbeat, nowayout);
 
        return 0;
@@ -824,7 +820,7 @@ static void usb_pcwd_disconnect(struct usb_interface *interface)
 
        mutex_unlock(&disconnect_mutex);
 
-       printk(KERN_INFO PFX "USB PC Watchdog disconnected\n");
+       pr_info("USB PC Watchdog disconnected\n");
 }
 
 module_usb_driver(usb_pcwd_driver);
index 2d22e99..7d3d471 100644 (file)
@@ -5,6 +5,8 @@
  *   Sean MacLennan <smaclennan@pikatech.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/module.h>
@@ -23,7 +25,6 @@
 #include <linux/of_platform.h>
 
 #define DRV_NAME "PIKA-WDT"
-#define PFX DRV_NAME ": "
 
 /* Hardware timeout in seconds */
 #define WDT_HW_TIMEOUT 2
@@ -38,8 +39,8 @@ module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
        "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
        "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -90,7 +91,7 @@ static void pikawdt_ping(unsigned long data)
                pikawdt_reset();
                mod_timer(&pikawdt_private.timer, jiffies + WDT_TIMEOUT);
        } else
-               printk(KERN_CRIT PFX "I will reset your machine !\n");
+               pr_crit("I will reset your machine !\n");
 }
 
 
@@ -228,14 +229,14 @@ static int __init pikawdt_init(void)
 
        np = of_find_compatible_node(NULL, NULL, "pika,fpga");
        if (np == NULL) {
-               printk(KERN_ERR PFX "Unable to find fpga.\n");
+               pr_err("Unable to find fpga\n");
                return -ENOENT;
        }
 
        pikawdt_private.fpga = of_iomap(np, 0);
        of_node_put(np);
        if (pikawdt_private.fpga == NULL) {
-               printk(KERN_ERR PFX "Unable to map fpga.\n");
+               pr_err("Unable to map fpga\n");
                return -ENOMEM;
        }
 
@@ -244,7 +245,7 @@ static int __init pikawdt_init(void)
        /* POST information is in the sd area. */
        np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd");
        if (np == NULL) {
-               printk(KERN_ERR PFX "Unable to find fpga-sd.\n");
+               pr_err("Unable to find fpga-sd\n");
                ret = -ENOENT;
                goto out;
        }
@@ -252,7 +253,7 @@ static int __init pikawdt_init(void)
        fpga = of_iomap(np, 0);
        of_node_put(np);
        if (fpga == NULL) {
-               printk(KERN_ERR PFX "Unable to map fpga-sd.\n");
+               pr_err("Unable to map fpga-sd\n");
                ret = -ENOMEM;
                goto out;
        }
@@ -271,12 +272,12 @@ static int __init pikawdt_init(void)
 
        ret = misc_register(&pikawdt_miscdev);
        if (ret) {
-               printk(KERN_ERR PFX "Unable to register miscdev.\n");
+               pr_err("Unable to register miscdev\n");
                goto out;
        }
 
-       printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
-                                                       heartbeat, nowayout);
+       pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
+               heartbeat, nowayout);
        return 0;
 
 out:
index dfae030..6b8432f 100644 (file)
@@ -8,33 +8,32 @@
  * Based on sa1100 driver,
  * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
  *
- * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
+ * 2005-2006 (c) MontaVista Software, Inc.
+ *
+ * (C) 2012 Wolfram Sang, Pengutronix
+ *
+ * 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.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/spinlock.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/err.h>
 #include <mach/hardware.h>
 
-#define MODULE_NAME "PNX4008-WDT: "
-
 /* WatchDog Timer - Chapter 23 Page 207 */
 
 #define DEFAULT_HEARTBEAT 19
 
 #define WDOG_COUNTER_RATE 13000000     /*the counter clock is 13 MHz fixed */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-static int heartbeat = DEFAULT_HEARTBEAT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+static unsigned int heartbeat = DEFAULT_HEARTBEAT;
 
 static DEFINE_SPINLOCK(io_lock);
-static unsigned long wdt_status;
-#define WDT_IN_USE        0
-#define WDT_OK_TO_CLOSE   1
-#define WDT_REGION_INITED 2
-#define WDT_DEVICE_INITED 3
-
-static unsigned long boot_status;
-
-static struct resource *wdt_mem;
 static void __iomem    *wdt_base;
 struct clk             *wdt_clk;
 
-static void wdt_enable(void)
+static int pnx4008_wdt_start(struct watchdog_device *wdd)
 {
        spin_lock(&io_lock);
 
        /* stop counter, initiate counter reset */
-       __raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
+       writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
        /*wait for reset to complete. 100% guarantee event */
-       while (__raw_readl(WDTIM_COUNTER(wdt_base)))
+       while (readl(WDTIM_COUNTER(wdt_base)))
                cpu_relax();
        /* internal and external reset, stop after that */
-       __raw_writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0,
-               WDTIM_MCTRL(wdt_base));
+       writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0, WDTIM_MCTRL(wdt_base));
        /* configure match output */
-       __raw_writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
+       writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
        /* clear interrupt, just in case */
-       __raw_writel(MATCH_INT, WDTIM_INT(wdt_base));
+       writel(MATCH_INT, WDTIM_INT(wdt_base));
        /* the longest pulse period 65541/(13*10^6) seconds ~ 5 ms. */
-       __raw_writel(0xFFFF, WDTIM_PULSE(wdt_base));
-       __raw_writel(heartbeat * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
+       writel(0xFFFF, WDTIM_PULSE(wdt_base));
+       writel(wdd->timeout * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
        /*enable counter, stop when debugger active */
-       __raw_writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
+       writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
 
        spin_unlock(&io_lock);
+       return 0;
 }
 
-static void wdt_disable(void)
+static int pnx4008_wdt_stop(struct watchdog_device *wdd)
 {
        spin_lock(&io_lock);
 
-       __raw_writel(0, WDTIM_CTRL(wdt_base));  /*stop counter */
+       writel(0, WDTIM_CTRL(wdt_base));        /*stop counter */
 
        spin_unlock(&io_lock);
+       return 0;
 }
 
-static int pnx4008_wdt_open(struct inode *inode, struct file *file)
-{
-       int ret;
-
-       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-               return -EBUSY;
-
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-       ret = clk_enable(wdt_clk);
-       if (ret) {
-               clear_bit(WDT_IN_USE, &wdt_status);
-               return ret;
-       }
-
-       wdt_enable();
-
-       return nonseekable_open(inode, file);
-}
-
-static ssize_t pnx4008_wdt_write(struct file *file, const char *data,
-                                       size_t len, loff_t *ppos)
+static int pnx4008_wdt_set_timeout(struct watchdog_device *wdd,
+                                   unsigned int new_timeout)
 {
-       if (len) {
-               if (!nowayout) {
-                       size_t i;
-
-                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-                       for (i = 0; i != len; i++) {
-                               char c;
-
-                               if (get_user(c, data + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
-                       }
-               }
-               wdt_enable();
-       }
-
-       return len;
+       wdd->timeout = new_timeout;
+       return 0;
 }
 
-static const struct watchdog_info ident = {
+static const struct watchdog_info pnx4008_wdt_ident = {
        .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
            WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
        .identity = "PNX4008 Watchdog",
 };
 
-static long pnx4008_wdt_ioctl(struct file *file, unsigned int cmd,
-                               unsigned long arg)
-{
-       int ret = -ENOTTY;
-       int time;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user((struct watchdog_info *)arg, &ident,
-                                  sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-               ret = put_user(0, (int *)arg);
-               break;
-
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(boot_status, (int *)arg);
-               break;
-
-       case WDIOC_KEEPALIVE:
-               wdt_enable();
-               ret = 0;
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               ret = get_user(time, (int *)arg);
-               if (ret)
-                       break;
-
-               if (time <= 0 || time > MAX_HEARTBEAT) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               heartbeat = time;
-               wdt_enable();
-               /* Fall through */
-
-       case WDIOC_GETTIMEOUT:
-               ret = put_user(heartbeat, (int *)arg);
-               break;
-       }
-       return ret;
-}
-
-static int pnx4008_wdt_release(struct inode *inode, struct file *file)
-{
-       if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-               printk(KERN_WARNING "WATCHDOG: Device closed unexpectedly\n");
-
-       wdt_disable();
-       clk_disable(wdt_clk);
-       clear_bit(WDT_IN_USE, &wdt_status);
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-       return 0;
-}
-
-static const struct file_operations pnx4008_wdt_fops = {
+static const struct watchdog_ops pnx4008_wdt_ops = {
        .owner = THIS_MODULE,
-       .llseek = no_llseek,
-       .write = pnx4008_wdt_write,
-       .unlocked_ioctl = pnx4008_wdt_ioctl,
-       .open = pnx4008_wdt_open,
-       .release = pnx4008_wdt_release,
+       .start = pnx4008_wdt_start,
+       .stop = pnx4008_wdt_stop,
+       .set_timeout = pnx4008_wdt_set_timeout,
 };
 
-static struct miscdevice pnx4008_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &pnx4008_wdt_fops,
+static struct watchdog_device pnx4008_wdd = {
+       .info = &pnx4008_wdt_ident,
+       .ops = &pnx4008_wdt_ops,
+       .min_timeout = 1,
+       .max_timeout = MAX_HEARTBEAT,
 };
 
 static int __devinit pnx4008_wdt_probe(struct platform_device *pdev)
 {
-       int ret = 0, size;
+       struct resource *r;
+       int ret = 0;
 
        if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
                heartbeat = DEFAULT_HEARTBEAT;
 
-       printk(KERN_INFO MODULE_NAME
-               "PNX4008 Watchdog Timer: heartbeat %d sec\n", heartbeat);
-
-       wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (wdt_mem == NULL) {
-               printk(KERN_INFO MODULE_NAME
-                       "failed to get memory region resource\n");
-               return -ENOENT;
-       }
-
-       size = resource_size(wdt_mem);
-
-       if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
-               printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
-               return -ENOENT;
-       }
-       wdt_base = (void __iomem *)IO_ADDRESS(wdt_mem->start);
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       wdt_base = devm_request_and_ioremap(&pdev->dev, r);
+       if (!wdt_base)
+               return -EADDRINUSE;
 
        wdt_clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(wdt_clk)) {
-               ret = PTR_ERR(wdt_clk);
-               release_mem_region(wdt_mem->start, size);
-               wdt_mem = NULL;
-               goto out;
-       }
+       if (IS_ERR(wdt_clk))
+               return PTR_ERR(wdt_clk);
 
        ret = clk_enable(wdt_clk);
-       if (ret) {
-               release_mem_region(wdt_mem->start, size);
-               wdt_mem = NULL;
-               clk_put(wdt_clk);
+       if (ret)
                goto out;
-       }
 
-       ret = misc_register(&pnx4008_wdt_miscdev);
+       pnx4008_wdd.timeout = heartbeat;
+       pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
+                       WDIOF_CARDRESET : 0;
+       watchdog_set_nowayout(&pnx4008_wdd, nowayout);
+
+       pnx4008_wdt_stop(&pnx4008_wdd); /* disable for now */
+
+       ret = watchdog_register_device(&pnx4008_wdd);
        if (ret < 0) {
-               printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
-               release_mem_region(wdt_mem->start, size);
-               wdt_mem = NULL;
-               clk_disable(wdt_clk);
-               clk_put(wdt_clk);
-       } else {
-               boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
-                   WDIOF_CARDRESET : 0;
-               wdt_disable();          /*disable for now */
-               clk_disable(wdt_clk);
-               set_bit(WDT_DEVICE_INITED, &wdt_status);
+               dev_err(&pdev->dev, "cannot register watchdog device\n");
+               goto disable_clk;
        }
 
+       dev_info(&pdev->dev, "PNX4008 Watchdog Timer: heartbeat %d sec\n",
+                       heartbeat);
+
+       return 0;
+
+disable_clk:
+       clk_disable(wdt_clk);
 out:
+       clk_put(wdt_clk);
        return ret;
 }
 
 static int __devexit pnx4008_wdt_remove(struct platform_device *pdev)
 {
-       misc_deregister(&pnx4008_wdt_miscdev);
+       watchdog_unregister_device(&pnx4008_wdd);
 
        clk_disable(wdt_clk);
        clk_put(wdt_clk);
 
-       if (wdt_mem) {
-               release_mem_region(wdt_mem->start, resource_size(wdt_mem));
-               wdt_mem = NULL;
-       }
        return 0;
 }
 
@@ -337,15 +213,16 @@ static struct platform_driver platform_wdt_driver = {
 module_platform_driver(platform_wdt_driver);
 
 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
 MODULE_DESCRIPTION("PNX4008 Watchdog Driver");
 
-module_param(heartbeat, int, 0);
+module_param(heartbeat, uint, 0);
 MODULE_PARM_DESC(heartbeat,
                 "Watchdog heartbeat period in seconds from 1 to "
                 __MODULE_STRING(MAX_HEARTBEAT) ", default "
                 __MODULE_STRING(DEFAULT_HEARTBEAT));
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                 "Set to 1 to keep watchdog running after device release");
 
index a7b5ad2..1b62a7d 100644 (file)
@@ -17,6 +17,8 @@
  * based on softdog.c by Alan Cox <alan@redhat.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -30,7 +32,6 @@
 #include <linux/init.h>
 #include <asm/mach-pnx833x/pnx833x.h>
 
-#define PFX "pnx833x: "
 #define WATCHDOG_TIMEOUT 30            /* 30 sec Maximum timeout */
 #define WATCHDOG_COUNT_FREQUENCY 68000000U /* Watchdog counts at 68MHZ. */
 #define        PNX_WATCHDOG_TIMEOUT    (WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY)
@@ -54,8 +55,8 @@ module_param(pnx833x_wdt_timeout, int, 0);
 MODULE_PARM_DESC(timeout, "Watchdog timeout in Mhz. (68Mhz clock), default="
                        __MODULE_STRING(PNX_TIMEOUT_VALUE) "(30 seconds).");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                                        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -76,7 +77,7 @@ static void pnx833x_wdt_start(void)
        PNX833X_REG(PNX833X_CONFIG +
                                PNX833X_CONFIG_CPU_COUNTERS_CONTROL) |= 0x1;
 
-       printk(KERN_INFO PFX "Started watchdog timer.\n");
+       pr_info("Started watchdog timer\n");
 }
 
 static void pnx833x_wdt_stop(void)
@@ -87,7 +88,7 @@ static void pnx833x_wdt_stop(void)
        PNX833X_REG(PNX833X_CONFIG +
                        PNX833X_CONFIG_CPU_COUNTERS_CONTROL) &= 0xFFFFFFFE;
 
-       printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+       pr_info("Stopped watchdog timer\n");
 }
 
 static void pnx833x_wdt_ping(void)
@@ -113,7 +114,7 @@ static int pnx833x_wdt_open(struct inode *inode, struct file *file)
 
        pnx833x_wdt_ping();
 
-       printk(KERN_INFO "Started watchdog timer.\n");
+       pr_info("Started watchdog timer\n");
 
        return nonseekable_open(inode, file);
 }
@@ -232,9 +233,6 @@ static struct notifier_block pnx833x_wdt_notifier = {
        .notifier_call = pnx833x_wdt_notify_sys,
 };
 
-static char banner[] __initdata =
-       KERN_INFO PFX "Hardware Watchdog Timer for PNX833x: Version 0.1\n";
-
 static int __init watchdog_init(void)
 {
        int ret, cause;
@@ -243,27 +241,25 @@ static int __init watchdog_init(void)
        cause = PNX833X_REG(PNX833X_RESET);
        /*If bit 31 is set then watchdog was cause of reset.*/
        if (cause & 0x80000000) {
-               printk(KERN_INFO PFX "The system was previously reset due to "
-                       "the watchdog firing - please investigate...\n");
+               pr_info("The system was previously reset due to the watchdog firing - please investigate...\n");
        }
 
        ret = register_reboot_notifier(&pnx833x_wdt_notifier);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                return ret;
        }
 
        ret = misc_register(&pnx833x_wdt_miscdev);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                unregister_reboot_notifier(&pnx833x_wdt_notifier);
                return ret;
        }
 
-       printk(banner);
+       pr_info("Hardware Watchdog Timer for PNX833x: Version 0.1\n");
+
        if (start_enabled)
                pnx833x_wdt_start();
 
index bf7bc8a..547353a 100644 (file)
@@ -17,6 +17,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>              /* For module specific items */
 #include <linux/moduleparam.h>         /* For new moduleparam's */
 #include <linux/types.h>               /* For standard types (like size_t) */
@@ -33,8 +35,6 @@
 
 #include <asm/mach-rc32434/integ.h>    /* For the Watchdog registers */
 
-#define PFX KBUILD_MODNAME ": "
-
 #define VERSION "1.0"
 
 static struct {
@@ -64,8 +64,8 @@ module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout, "Watchdog timeout value, in seconds (default="
                __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -78,8 +78,7 @@ static int rc32434_wdt_set(int new_timeout)
        int max_to = WTCOMP2SEC((u32)-1);
 
        if (new_timeout < 0 || new_timeout > max_to) {
-               printk(KERN_ERR PFX "timeout value must be between 0 and %d",
-                       max_to);
+               pr_err("timeout value must be between 0 and %d\n", max_to);
                return -EINVAL;
        }
        timeout = new_timeout;
@@ -119,7 +118,7 @@ static void rc32434_wdt_start(void)
        SET_BITS(wdt_reg->wtc, or, nand);
 
        spin_unlock(&rc32434_wdt_device.io_lock);
-       printk(KERN_INFO PFX "Started watchdog timer.\n");
+       pr_info("Started watchdog timer\n");
 }
 
 static void rc32434_wdt_stop(void)
@@ -130,7 +129,7 @@ static void rc32434_wdt_stop(void)
        SET_BITS(wdt_reg->wtc, 0, 1 << RC32434_WTC_EN);
 
        spin_unlock(&rc32434_wdt_device.io_lock);
-       printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+       pr_info("Stopped watchdog timer\n");
 }
 
 static void rc32434_wdt_ping(void)
@@ -160,8 +159,7 @@ static int rc32434_wdt_release(struct inode *inode, struct file *file)
                rc32434_wdt_stop();
                module_put(THIS_MODULE);
        } else {
-               printk(KERN_CRIT PFX
-                       "device closed unexpectedly. WDT will not stop!\n");
+               pr_crit("device closed unexpectedly. WDT will not stop!\n");
                rc32434_wdt_ping();
        }
        clear_bit(0, &rc32434_wdt_device.inuse);
@@ -262,9 +260,6 @@ static struct miscdevice rc32434_wdt_miscdev = {
        .fops   = &rc32434_wdt_fops,
 };
 
-static char banner[] __devinitdata = KERN_INFO PFX
-               "Watchdog Timer version " VERSION ", timer margin: %d sec\n";
-
 static int __devinit rc32434_wdt_probe(struct platform_device *pdev)
 {
        int ret;
@@ -272,13 +267,13 @@ static int __devinit rc32434_wdt_probe(struct platform_device *pdev)
 
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb532_wdt_res");
        if (!r) {
-               printk(KERN_ERR PFX "failed to retrieve resources\n");
+               pr_err("failed to retrieve resources\n");
                return -ENODEV;
        }
 
        wdt_reg = ioremap_nocache(r->start, resource_size(r));
        if (!wdt_reg) {
-               printk(KERN_ERR PFX "failed to remap I/O resources\n");
+               pr_err("failed to remap I/O resources\n");
                return -ENXIO;
        }
 
@@ -291,18 +286,18 @@ static int __devinit rc32434_wdt_probe(struct platform_device *pdev)
         * if not reset to the default */
        if (rc32434_wdt_set(timeout)) {
                rc32434_wdt_set(WATCHDOG_TIMEOUT);
-               printk(KERN_INFO PFX
-                       "timeout value must be between 0 and %d\n",
+               pr_info("timeout value must be between 0 and %d\n",
                        WTCOMP2SEC((u32)-1));
        }
 
        ret = misc_register(&rc32434_wdt_miscdev);
        if (ret < 0) {
-               printk(KERN_ERR PFX "failed to register watchdog device\n");
+               pr_err("failed to register watchdog device\n");
                goto unmap;
        }
 
-       printk(banner, timeout);
+       pr_info("Watchdog Timer version " VERSION ", timer margin: %d sec\n",
+               timeout);
 
        return 0;
 
index c7e17ce..49e1b1c 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -189,7 +191,7 @@ static int __devinit riowd_probe(struct platform_device *op)
 
        p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
        if (!p->regs) {
-               printk(KERN_ERR PFX "Cannot map registers.\n");
+               pr_err("Cannot map registers\n");
                goto out_free;
        }
        /* Make miscdev useable right away */
@@ -197,12 +199,12 @@ static int __devinit riowd_probe(struct platform_device *op)
 
        err = misc_register(&riowd_miscdev);
        if (err) {
-               printk(KERN_ERR PFX "Cannot register watchdog misc device.\n");
+               pr_err("Cannot register watchdog misc device\n");
                goto out_iounmap;
        }
 
-       printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
-              "regs at %p\n", riowd_timeout, p->regs);
+       pr_info("Hardware watchdog [%i minutes], regs at %p\n",
+               riowd_timeout, p->regs);
 
        dev_set_drvdata(&op->dev, p);
        return 0;
index 404172f..04e5a6d 100644 (file)
@@ -23,6 +23,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 
 #include <plat/regs-watchdog.h>
 
-#define PFX "s3c2410-wdt: "
-
 #define CONFIG_S3C2410_WATCHDOG_ATBOOT         (0)
 #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME   (15)
 
-static int nowayout    = WATCHDOG_NOWAYOUT;
+static bool nowayout   = WATCHDOG_NOWAYOUT;
 static int tmr_margin  = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
 static int tmr_atboot  = CONFIG_S3C2410_WATCHDOG_ATBOOT;
 static int soft_noboot;
@@ -59,7 +59,7 @@ static int debug;
 
 module_param(tmr_margin,  int, 0);
 module_param(tmr_atboot,  int, 0);
-module_param(nowayout,    int, 0);
+module_param(nowayout,   bool, 0);
 module_param(soft_noboot, int, 0);
 module_param(debug,      int, 0);
 
@@ -84,10 +84,11 @@ static DEFINE_SPINLOCK(wdt_lock);
 
 /* watchdog control routines */
 
-#define DBG(msg...) do { \
-       if (debug) \
-               printk(KERN_INFO msg); \
-       } while (0)
+#define DBG(fmt, ...)                                  \
+do {                                                   \
+       if (debug)                                      \
+               pr_info(fmt, ##__VA_ARGS__);            \
+} while (0)
 
 /* functions */
 
@@ -200,6 +201,8 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
        writel(count, wdt_base + S3C2410_WTDAT);
        writel(wtcon, wdt_base + S3C2410_WTCON);
 
+       wdd->timeout = timeout;
+
        return 0;
 }
 
@@ -354,7 +357,7 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
 
        ret = s3c2410wdt_cpufreq_register();
        if (ret < 0) {
-               printk(KERN_ERR PFX "failed to register cpufreq\n");
+               pr_err("failed to register cpufreq\n");
                goto err_clk;
        }
 
@@ -483,8 +486,8 @@ static int s3c2410wdt_resume(struct platform_device *dev)
        writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
        writel(wtcon_save, wdt_base + S3C2410_WTCON);
 
-       printk(KERN_INFO PFX "watchdog %sabled\n",
-              (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
+       pr_info("watchdog %sabled\n",
+               (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
 
        return 0;
 }
@@ -518,12 +521,10 @@ static struct platform_driver s3c2410wdt_driver = {
 };
 
 
-static char banner[] __initdata =
-       KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
-
 static int __init watchdog_init(void)
 {
-       printk(banner);
+       pr_info("S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n");
+
        return platform_driver_register(&s3c2410wdt_driver);
 }
 
index 0162454..d54e04d 100644 (file)
@@ -17,6 +17,9 @@
  *
  *     27/11/2000 Initial release
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -66,7 +69,7 @@ static int sa1100dog_open(struct inode *inode, struct file *file)
  */
 static int sa1100dog_release(struct inode *inode, struct file *file)
 {
-       printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n");
+       pr_crit("Device closed - timer will not stop\n");
        clear_bit(1, &sa1100wdt_users);
        return 0;
 }
@@ -169,9 +172,8 @@ static int __init sa1100dog_init(void)
 
        ret = misc_register(&sa1100dog_miscdev);
        if (ret == 0)
-               printk(KERN_INFO
-                       "SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
-                                               margin);
+               pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
+                       margin);
        return ret;
 }
 
index b01a30e..25c7a3f 100644 (file)
@@ -43,6 +43,9 @@
  *     version 1 or 2 as published by the Free Software Foundation.
  *
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
@@ -125,9 +128,8 @@ static int sbwdog_release(struct inode *inode, struct file *file)
                __raw_writeb(0, user_dog);
                module_put(THIS_MODULE);
        } else {
-               printk(KERN_CRIT
-                       "%s: Unexpected close, not stopping watchdog!\n",
-                                               ident.identity);
+               pr_crit("%s: Unexpected close, not stopping watchdog!\n",
+                       ident.identity);
                sbwdog_pet(user_dog);
        }
        clear_bit(0, &sbwdog_gate);
@@ -269,7 +271,7 @@ irqreturn_t sbwdog_interrupt(int irq, void *addr)
         * if it's the second watchdog timer, it's for those users
         */
        if (wd_cfg_reg == user_dog)
-               printk(KERN_CRIT "%s in danger of initiating system reset "
+               pr_crit("%s in danger of initiating system reset "
                        "in %ld.%01ld seconds\n",
                        ident.identity,
                        wd_init / 1000000, (wd_init / 100000) % 10);
@@ -290,9 +292,8 @@ static int __init sbwdog_init(void)
         */
        ret = register_reboot_notifier(&sbwdog_notifier);
        if (ret) {
-               printk(KERN_ERR
-                       "%s: cannot register reboot notifier (err=%d)\n",
-                                               ident.identity, ret);
+               pr_err("%s: cannot register reboot notifier (err=%d)\n",
+                      ident.identity, ret);
                return ret;
        }
 
@@ -303,16 +304,16 @@ static int __init sbwdog_init(void)
        ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED,
                ident.identity, (void *)user_dog);
        if (ret) {
-               printk(KERN_ERR "%s: failed to request irq 1 - %d\n",
-                                               ident.identity, ret);
+               pr_err("%s: failed to request irq 1 - %d\n",
+                      ident.identity, ret);
                goto out;
        }
 
        ret = misc_register(&sbwdog_miscdev);
        if (ret == 0) {
-               printk(KERN_INFO "%s: timeout is %ld.%ld secs\n",
-                               ident.identity,
-                               timeout / 1000000, (timeout / 100000) % 10);
+               pr_info("%s: timeout is %ld.%ld secs\n",
+                       ident.identity,
+                       timeout / 1000000, (timeout / 100000) % 10);
                return 0;
        }
        free_irq(1, (void *)user_dog);
@@ -353,8 +354,7 @@ void platform_wd_setup(void)
        ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED,
                "Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0));
        if (ret) {
-               printk(KERN_CRIT
-                 "Watchdog IRQ zero(0) failed to be requested - %d\n", ret);
+               pr_crit("Watchdog IRQ zero(0) failed to be requested - %d\n", ret);
        }
 }
 
index 4b53756..63632ec 100644 (file)
@@ -48,6 +48,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -104,8 +106,8 @@ MODULE_PARM_DESC(timeout,
        "Watchdog timeout in seconds. (1<=timeout<=3600, default="
                                __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -131,8 +133,7 @@ static void wdt_timer_ping(unsigned long data)
                /* Re-set the timer interval */
                mod_timer(&timer, jiffies + WDT_INTERVAL);
        } else
-               printk(KERN_WARNING PFX
-                       "Heartbeat lost! Will not ping the watchdog\n");
+               pr_warn("Heartbeat lost! Will not ping the watchdog\n");
 }
 
 /*
@@ -145,7 +146,7 @@ static void wdt_startup(void)
 
        /* Start the timer */
        mod_timer(&timer, jiffies + WDT_INTERVAL);
-       printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+       pr_info("Watchdog timer is now enabled\n");
 }
 
 static void wdt_turnoff(void)
@@ -153,7 +154,7 @@ static void wdt_turnoff(void)
        /* Stop the timer */
        del_timer(&timer);
        inb_p(wdt_stop);
-       printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+       pr_info("Watchdog timer is now disabled...\n");
 }
 
 static void wdt_keepalive(void)
@@ -216,8 +217,7 @@ static int fop_close(struct inode *inode, struct file *file)
                wdt_turnoff();
        else {
                del_timer(&timer);
-               printk(KERN_CRIT PFX
-                 "device file closed unexpectedly. Will not stop the WDT!\n");
+               pr_crit("device file closed unexpectedly. Will not stop the WDT!\n");
        }
        clear_bit(0, &wdt_is_open);
        wdt_expect_close = 0;
@@ -334,14 +334,12 @@ static int __init sbc60xxwdt_init(void)
 
        if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
                timeout = WATCHDOG_TIMEOUT;
-               printk(KERN_INFO PFX
-                       "timeout value must be 1 <= x <= 3600, using %d\n",
-                                                               timeout);
+               pr_info("timeout value must be 1 <= x <= 3600, using %d\n",
+                       timeout);
        }
 
        if (!request_region(wdt_start, 1, "SBC 60XX WDT")) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       wdt_start);
+               pr_err("I/O address 0x%04x already in use\n", wdt_start);
                rc = -EIO;
                goto err_out;
        }
@@ -349,9 +347,7 @@ static int __init sbc60xxwdt_init(void)
        /* We cannot reserve 0x45 - the kernel already has! */
        if (wdt_stop != 0x45 && wdt_stop != wdt_start) {
                if (!request_region(wdt_stop, 1, "SBC 60XX WDT")) {
-                       printk(KERN_ERR PFX
-                               "I/O address 0x%04x already in use\n",
-                                                       wdt_stop);
+                       pr_err("I/O address 0x%04x already in use\n", wdt_stop);
                        rc = -EIO;
                        goto err_out_region1;
                }
@@ -359,21 +355,18 @@ static int __init sbc60xxwdt_init(void)
 
        rc = register_reboot_notifier(&wdt_notifier);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", rc);
+               pr_err("cannot register reboot notifier (err=%d)\n", rc);
                goto err_out_region2;
        }
 
        rc = misc_register(&wdt_miscdev);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                               wdt_miscdev.minor, rc);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      wdt_miscdev.minor, rc);
                goto err_out_reboot;
        }
-       printk(KERN_INFO PFX
-               "WDT driver for 60XX single board computer initialised. "
-               "timeout=%d sec (nowayout=%d)\n", timeout, nowayout);
+       pr_info("WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
+               timeout, nowayout);
 
        return 0;
 
index 80f39a3..719edc8 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -31,8 +33,6 @@
 #include <linux/uaccess.h>
 #include <linux/atomic.h>
 
-#define SBC7240_PREFIX "sbc7240_wdt: "
-
 #define SBC7240_ENABLE_PORT            0x443
 #define SBC7240_DISABLE_PORT           0x043
 #define SBC7240_SET_TIMEOUT_PORT       SBC7240_ENABLE_PORT
@@ -46,8 +46,8 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<="
                 __MODULE_STRING(SBC7240_MAX_TIMEOUT) ", default="
                 __MODULE_STRING(SBC7240_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog when closing device file");
 
 #define SBC7240_OPEN_STATUS_BIT                0
@@ -64,8 +64,7 @@ static void wdt_disable(void)
        /* disable the watchdog */
        if (test_and_clear_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) {
                inb_p(SBC7240_DISABLE_PORT);
-               printk(KERN_INFO SBC7240_PREFIX
-                      "Watchdog timer is now disabled.\n");
+               pr_info("Watchdog timer is now disabled\n");
        }
 }
 
@@ -74,23 +73,20 @@ static void wdt_enable(void)
        /* enable the watchdog */
        if (!test_and_set_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) {
                inb_p(SBC7240_ENABLE_PORT);
-               printk(KERN_INFO SBC7240_PREFIX
-                      "Watchdog timer is now enabled.\n");
+               pr_info("Watchdog timer is now enabled\n");
        }
 }
 
 static int wdt_set_timeout(int t)
 {
        if (t < 1 || t > SBC7240_MAX_TIMEOUT) {
-               printk(KERN_ERR SBC7240_PREFIX
-                      "timeout value must be 1<=x<=%d\n",
-                      SBC7240_MAX_TIMEOUT);
+               pr_err("timeout value must be 1<=x<=%d\n", SBC7240_MAX_TIMEOUT);
                return -1;
        }
        /* set the timeout */
        outb_p((unsigned)t, SBC7240_SET_TIMEOUT_PORT);
        timeout = t;
-       printk(KERN_INFO SBC7240_PREFIX "timeout set to %d seconds\n", t);
+       pr_info("timeout set to %d seconds\n", t);
        return 0;
 }
 
@@ -149,8 +145,7 @@ static int fop_close(struct inode *inode, struct file *file)
            || !nowayout) {
                wdt_disable();
        } else {
-               printk(KERN_CRIT SBC7240_PREFIX
-                      "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                wdt_keepalive();
        }
 
@@ -251,7 +246,7 @@ static struct notifier_block wdt_notifier = {
 
 static void __exit sbc7240_wdt_unload(void)
 {
-       printk(KERN_INFO SBC7240_PREFIX "Removing watchdog\n");
+       pr_info("Removing watchdog\n");
        misc_deregister(&wdt_miscdev);
 
        unregister_reboot_notifier(&wdt_notifier);
@@ -263,8 +258,7 @@ static int __init sbc7240_wdt_init(void)
        int rc = -EBUSY;
 
        if (!request_region(SBC7240_ENABLE_PORT, 1, "SBC7240 WDT")) {
-               printk(KERN_ERR SBC7240_PREFIX
-                      "I/O address 0x%04x already in use\n",
+               pr_err("I/O address 0x%04x already in use\n",
                       SBC7240_ENABLE_PORT);
                rc = -EIO;
                goto err_out;
@@ -276,31 +270,27 @@ static int __init sbc7240_wdt_init(void)
 
        if (timeout < 1 || timeout > SBC7240_MAX_TIMEOUT) {
                timeout = SBC7240_TIMEOUT;
-               printk(KERN_INFO SBC7240_PREFIX
-                      "timeout value must be 1<=x<=%d, using %d\n",
-                      SBC7240_MAX_TIMEOUT, timeout);
+               pr_info("timeout value must be 1<=x<=%d, using %d\n",
+                       SBC7240_MAX_TIMEOUT, timeout);
        }
        wdt_set_timeout(timeout);
        wdt_disable();
 
        rc = register_reboot_notifier(&wdt_notifier);
        if (rc) {
-               printk(KERN_ERR SBC7240_PREFIX
-                      "cannot register reboot notifier (err=%d)\n", rc);
+               pr_err("cannot register reboot notifier (err=%d)\n", rc);
                goto err_out_region;
        }
 
        rc = misc_register(&wdt_miscdev);
        if (rc) {
-               printk(KERN_ERR SBC7240_PREFIX
-                      "cannot register miscdev on minor=%d (err=%d)\n",
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
                       wdt_miscdev.minor, rc);
                goto err_out_reboot_notifier;
        }
 
-       printk(KERN_INFO SBC7240_PREFIX
-              "Watchdog driver for SBC7240 initialised (nowayout=%d)\n",
-              nowayout);
+       pr_info("Watchdog driver for SBC7240 initialised (nowayout=%d)\n",
+               nowayout);
 
        return 0;
 
index 7c242bc..d4781e0 100644 (file)
@@ -36,6 +36,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
@@ -55,8 +57,6 @@
 static unsigned long sbc8360_is_open;
 static char expect_close;
 
-#define PFX "sbc8360: "
-
 /*
  *
  * Watchdog Timer Configuration
@@ -196,11 +196,11 @@ static int wd_times[64][2] = {
 static int timeout = 27;
 static int wd_margin = 0xB;
 static int wd_multiplier = 2;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                 "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -279,8 +279,7 @@ static int sbc8360_close(struct inode *inode, struct file *file)
        if (expect_close == 42)
                sbc8360_stop();
        else
-               printk(KERN_CRIT PFX "SBC8360 device closed unexpectedly.  "
-                                               "SBC8360 will not stop!\n");
+               pr_crit("SBC8360 device closed unexpectedly.  SBC8360 will not stop!\n");
 
        clear_bit(0, &sbc8360_is_open);
        expect_close = 0;
@@ -333,20 +332,19 @@ static int __init sbc8360_init(void)
        unsigned long int mseconds = 60000;
 
        if (timeout < 0 || timeout > 63) {
-               printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
+               pr_err("Invalid timeout index (must be 0-63)\n");
                res = -EINVAL;
                goto out;
        }
 
        if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
-               printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
+               pr_err("ENABLE method I/O %X is not available\n",
                       SBC8360_ENABLE);
                res = -EIO;
                goto out;
        }
        if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
-               printk(KERN_ERR PFX
-                      "BASETIME method I/O %X is not available.\n",
+               pr_err("BASETIME method I/O %X is not available\n",
                       SBC8360_BASETIME);
                res = -EIO;
                goto out_nobasetimereg;
@@ -354,13 +352,13 @@ static int __init sbc8360_init(void)
 
        res = register_reboot_notifier(&sbc8360_notifier);
        if (res) {
-               printk(KERN_ERR PFX "Failed to register reboot notifier.\n");
+               pr_err("Failed to register reboot notifier\n");
                goto out_noreboot;
        }
 
        res = misc_register(&sbc8360_miscdev);
        if (res) {
-               printk(KERN_ERR PFX "failed to register misc device\n");
+               pr_err("failed to register misc device\n");
                goto out_nomisc;
        }
 
@@ -377,7 +375,7 @@ static int __init sbc8360_init(void)
                mseconds = (wd_margin + 1) * 100000;
 
        /* My kingdom for the ability to print "0.5 seconds" in the kernel! */
-       printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds);
+       pr_info("Timeout set at %ld ms\n", mseconds);
 
        return 0;
 
index eaca366..0c3e9f6 100644 (file)
@@ -13,6 +13,8 @@
  *     based on softdog.c by Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-#define PFX "epx_c3: "
 static int epx_c3_alive;
 
 #define WATCHDOG_TIMEOUT 1             /* 1 sec default timeout */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                                        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -51,7 +52,7 @@ static void epx_c3_stop(void)
 
        outb(0, EPXC3_WATCHDOG_CTL_REG);
 
-       printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+       pr_info("Stopped watchdog timer\n");
 }
 
 static void epx_c3_pet(void)
@@ -75,7 +76,7 @@ static int epx_c3_open(struct inode *inode, struct file *file)
        epx_c3_pet();
 
        epx_c3_alive = 1;
-       printk(KERN_INFO "Started watchdog timer.\n");
+       pr_info("Started watchdog timer\n");
 
        return nonseekable_open(inode, file);
 }
@@ -173,9 +174,6 @@ static struct notifier_block epx_c3_notifier = {
        .notifier_call = epx_c3_notify_sys,
 };
 
-static const char banner[] __initconst = KERN_INFO PFX
-       "Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n";
-
 static int __init watchdog_init(void)
 {
        int ret;
@@ -185,20 +183,19 @@ static int __init watchdog_init(void)
 
        ret = register_reboot_notifier(&epx_c3_notifier);
        if (ret) {
-               printk(KERN_ERR PFX "cannot register reboot notifier "
-                       "(err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                goto out;
        }
 
        ret = misc_register(&epx_c3_miscdev);
        if (ret) {
-               printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
-                       "(err=%d)\n", WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                unregister_reboot_notifier(&epx_c3_notifier);
                goto out;
        }
 
-       printk(banner);
+       pr_info("Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n");
 
        return 0;
 
index 07d59b3..90d5527 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/uaccess.h>
 
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned int margin = 60;       /* (secs) Default is 1 minute */
 static unsigned long wdt_status;
 static DEFINE_MUTEX(wdt_lock);
@@ -170,8 +170,7 @@ static int fitpc2_wdt_release(struct inode *inode, struct file *file)
                wdt_disable();
                pr_info("Device disabled\n");
        } else {
-               pr_warning("Device closed unexpectedly -"
-                       " timer will not stop\n");
+               pr_warn("Device closed unexpectedly - timer will not stop\n");
                wdt_enable();
        }
 
@@ -221,8 +220,8 @@ static int __init fitpc2_wdt_init(void)
        }
 
        if (margin < 31 || margin > 255) {
-               pr_err("margin must be in range 31 - 255"
-                      " seconds, you tried to set %d\n", margin);
+               pr_err("margin must be in range 31 - 255 seconds, you tried to set %d\n",
+                      margin);
                err = -EINVAL;
                goto err_margin;
        }
@@ -230,7 +229,7 @@ static int __init fitpc2_wdt_init(void)
        err = misc_register(&fitpc2_wdt_miscdev);
        if (err) {
                pr_err("cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, err);
+                      WATCHDOG_MINOR, err);
                goto err_margin;
        }
 
@@ -260,7 +259,7 @@ MODULE_DESCRIPTION("SBC-FITPC2 Watchdog");
 module_param(margin, int, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
 MODULE_LICENSE("GPL");
index c01daca..3fb83b0 100644 (file)
@@ -31,6 +31,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/miscdevice.h>
@@ -48,7 +50,6 @@
 
 #define SC1200_MODULE_VER      "build 20020303"
 #define SC1200_MODULE_NAME     "sc1200wdt"
-#define PFX                    SC1200_MODULE_NAME ": "
 
 #define        MAX_TIMEOUT     255     /* 255 minutes */
 #define PMIR           (io)    /* Power Management Index Register */
@@ -71,7 +72,6 @@
 #define UART2_IRQ      0x04    /* Serial1 */
 /* 5 -7 are reserved */
 
-static char banner[] __initdata = PFX SC1200_MODULE_VER;
 static int timeout = 1;
 static int io = -1;
 static int io_len = 2;         /* for non plug and play */
@@ -93,8 +93,8 @@ MODULE_PARM_DESC(io, "io port");
 module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -176,7 +176,7 @@ static int sc1200wdt_open(struct inode *inode, struct file *file)
                timeout = MAX_TIMEOUT;
 
        sc1200wdt_start();
-       printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
+       pr_info("Watchdog enabled, timeout = %d min(s)", timeout);
 
        return nonseekable_open(inode, file);
 }
@@ -254,11 +254,10 @@ static int sc1200wdt_release(struct inode *inode, struct file *file)
 {
        if (expect_close == 42) {
                sc1200wdt_stop();
-               printk(KERN_INFO PFX "Watchdog disabled\n");
+               pr_info("Watchdog disabled\n");
        } else {
                sc1200wdt_write_data(WDTO, timeout);
-               printk(KERN_CRIT PFX
-                       "Unexpected close!, timeout = %d min(s)\n", timeout);
+               pr_crit("Unexpected close!, timeout = %d min(s)\n", timeout);
        }
        clear_bit(0, &open_flag);
        expect_close = 0;
@@ -361,12 +360,11 @@ static int scl200wdt_pnp_probe(struct pnp_dev *dev,
        io_len = pnp_port_len(wdt_dev, 0);
 
        if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
-               printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
+               pr_err("Unable to register IO port %#x\n", io);
                return -EBUSY;
        }
 
-       printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n",
-                                                               io, io_len);
+       pr_info("PnP device found at io port %#x/%d\n", io, io_len);
        return 0;
 }
 
@@ -392,7 +390,7 @@ static int __init sc1200wdt_init(void)
 {
        int ret;
 
-       printk(KERN_INFO "%s\n", banner);
+       pr_info("%s\n", SC1200_MODULE_VER);
 
 #if defined CONFIG_PNP
        if (isapnp) {
@@ -403,7 +401,7 @@ static int __init sc1200wdt_init(void)
 #endif
 
        if (io == -1) {
-               printk(KERN_ERR PFX "io parameter must be specified\n");
+               pr_err("io parameter must be specified\n");
                ret = -EINVAL;
                goto out_pnp;
        }
@@ -416,7 +414,7 @@ static int __init sc1200wdt_init(void)
 #endif
 
        if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
-               printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
+               pr_err("Unable to register IO port %#x\n", io);
                ret = -EBUSY;
                goto out_pnp;
        }
@@ -427,16 +425,14 @@ static int __init sc1200wdt_init(void)
 
        ret = register_reboot_notifier(&sc1200wdt_notifier);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "Unable to register reboot notifier err = %d\n", ret);
+               pr_err("Unable to register reboot notifier err = %d\n", ret);
                goto out_io;
        }
 
        ret = misc_register(&sc1200wdt_miscdev);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "Unable to register miscdev on minor %d\n",
-                                                       WATCHDOG_MINOR);
+               pr_err("Unable to register miscdev on minor %d\n",
+                      WATCHDOG_MINOR);
                goto out_rbt;
        }
 
index c794803..707e027 100644 (file)
@@ -52,6 +52,8 @@
  *  This driver uses memory mapped IO, and spinlock.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -68,9 +70,6 @@
 #include <linux/uaccess.h>
 
 
-#define OUR_NAME "sc520_wdt"
-#define PFX OUR_NAME ": "
-
 /*
  * The AMD Elan SC520 timeout value is 492us times a power of 2 (0-7)
  *
@@ -97,8 +96,8 @@ MODULE_PARM_DESC(timeout,
        "Watchdog timeout in seconds. (1 <= timeout <= 3600, default="
                                __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -150,8 +149,7 @@ static void wdt_timer_ping(unsigned long data)
                /* Re-set the timer interval */
                mod_timer(&timer, jiffies + WDT_INTERVAL);
        } else
-               printk(KERN_WARNING PFX
-                       "Heartbeat lost! Will not ping the watchdog\n");
+               pr_warn("Heartbeat lost! Will not ping the watchdog\n");
 }
 
 /*
@@ -186,7 +184,7 @@ static int wdt_startup(void)
        /* Start the watchdog */
        wdt_config(WDT_ENB | WDT_WRST_ENB | WDT_EXP_SEL_04);
 
-       printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+       pr_info("Watchdog timer is now enabled\n");
        return 0;
 }
 
@@ -198,7 +196,7 @@ static int wdt_turnoff(void)
        /* Stop the watchdog */
        wdt_config(0);
 
-       printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+       pr_info("Watchdog timer is now disabled...\n");
        return 0;
 }
 
@@ -269,8 +267,7 @@ static int fop_close(struct inode *inode, struct file *file)
        if (wdt_expect_close == 42)
                wdt_turnoff();
        else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                wdt_keepalive();
        }
        clear_bit(0, &wdt_is_open);
@@ -392,36 +389,32 @@ static int __init sc520_wdt_init(void)
           if not reset to the default */
        if (wdt_set_heartbeat(timeout)) {
                wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-               printk(KERN_INFO PFX
-                   "timeout value must be 1 <= timeout <= 3600, using %d\n",
-                                                       WATCHDOG_TIMEOUT);
+               pr_info("timeout value must be 1 <= timeout <= 3600, using %d\n",
+                       WATCHDOG_TIMEOUT);
        }
 
        wdtmrctl = ioremap(MMCR_BASE + OFFS_WDTMRCTL, 2);
        if (!wdtmrctl) {
-               printk(KERN_ERR PFX "Unable to remap memory\n");
+               pr_err("Unable to remap memory\n");
                rc = -ENOMEM;
                goto err_out_region2;
        }
 
        rc = register_reboot_notifier(&wdt_notifier);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", rc);
+               pr_err("cannot register reboot notifier (err=%d)\n", rc);
                goto err_out_ioremap;
        }
 
        rc = misc_register(&wdt_miscdev);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, rc);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, rc);
                goto err_out_notifier;
        }
 
-       printk(KERN_INFO PFX
-          "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
-                                                       timeout, nowayout);
+       pr_info("WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
+               timeout, nowayout);
 
        return 0;
 
index 029467e..bd86f32 100644 (file)
@@ -18,6 +18,8 @@
  *     Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 /* Includes */
 #include <linux/module.h>              /* For module specific items */
 #include <linux/moduleparam.h>         /* For new moduleparam's */
@@ -37,7 +39,6 @@
 
 /* Module and version information */
 #define DRV_NAME       "sch311x_wdt"
-#define PFX            DRV_NAME ": "
 
 /* Runtime registers */
 #define RESGEN                 0x1d
@@ -79,8 +80,8 @@ MODULE_PARM_DESC(timeout,
        "Watchdog timeout in seconds. 1<= timeout <=15300, default="
                __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -323,8 +324,7 @@ static int sch311x_wdt_close(struct inode *inode, struct file *file)
        if (sch311x_wdt_expect_close == 42) {
                sch311x_wdt_stop();
        } else {
-               printk(KERN_CRIT PFX
-                               "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                sch311x_wdt_keepalive();
        }
        clear_bit(0, &sch311x_wdt_is_open);
@@ -504,20 +504,19 @@ static int __init sch311x_detect(int sio_config_port, unsigned short *addr)
 
        /* Check if Logical Device Register is currently active */
        if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
-               printk(KERN_INFO PFX "Seems that LDN 0x0a is not active...\n");
+               pr_info("Seems that LDN 0x0a is not active...\n");
 
        /* Get the base address of the runtime registers */
        base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) |
                           sch311x_sio_inb(sio_config_port, 0x61);
        if (!base_addr) {
-               printk(KERN_ERR PFX "Base address not set.\n");
+               pr_err("Base address not set\n");
                err = -ENODEV;
                goto exit;
        }
        *addr = base_addr;
 
-       printk(KERN_INFO PFX "Found an SMSC SCH311%d chip at 0x%04x\n",
-               dev_id, base_addr);
+       pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr);
 
 exit:
        sch311x_sio_exit(sio_config_port);
index e67b76c..8ae7c28 100644 (file)
@@ -17,6 +17,8 @@
    of any nature resulting due to the use of this software. This
    software is provided AS-IS with no warranties. */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -30,7 +32,7 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-#define NAME "scx200_wdt"
+#define DEBUG
 
 MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
 MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
@@ -41,8 +43,8 @@ static int margin = 60;               /* in seconds */
 module_param(margin, int, 0);
 MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
 static u16 wdto_restart;
@@ -66,14 +68,13 @@ static void scx200_wdt_ping(void)
 
 static void scx200_wdt_update_margin(void)
 {
-       printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
+       pr_info("timer margin %d seconds\n", margin);
        wdto_restart = margin * W_SCALE;
 }
 
 static void scx200_wdt_enable(void)
 {
-       printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n",
-              wdto_restart);
+       pr_debug("enabling watchdog timer, wdto_restart = %d\n", wdto_restart);
 
        spin_lock(&scx_lock);
        outw(0, scx200_cb_base + SCx200_WDT_WDTO);
@@ -86,7 +87,7 @@ static void scx200_wdt_enable(void)
 
 static void scx200_wdt_disable(void)
 {
-       printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+       pr_debug("disabling watchdog timer\n");
 
        spin_lock(&scx_lock);
        outw(0, scx200_cb_base + SCx200_WDT_WDTO);
@@ -108,9 +109,7 @@ static int scx200_wdt_open(struct inode *inode, struct file *file)
 static int scx200_wdt_release(struct inode *inode, struct file *file)
 {
        if (expect_close != 42)
-               printk(KERN_WARNING NAME
-                       ": watchdog device closed unexpectedly, "
-                       "will not disable the watchdog timer\n");
+               pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n");
        else if (!nowayout)
                scx200_wdt_disable();
        expect_close = 0;
@@ -219,7 +218,7 @@ static int __init scx200_wdt_init(void)
 {
        int r;
 
-       printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
+       pr_debug("NatSemi SCx200 Watchdog Driver\n");
 
        /* check that we have found the configuration block */
        if (!scx200_cb_present())
@@ -228,7 +227,7 @@ static int __init scx200_wdt_init(void)
        if (!request_region(scx200_cb_base + SCx200_WDT_OFFSET,
                            SCx200_WDT_SIZE,
                            "NatSemi SCx200 Watchdog")) {
-               printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
+               pr_warn("watchdog I/O region busy\n");
                return -EBUSY;
        }
 
@@ -237,7 +236,7 @@ static int __init scx200_wdt_init(void)
 
        r = register_reboot_notifier(&scx200_wdt_notifier);
        if (r) {
-               printk(KERN_ERR NAME ": unable to register reboot notifier");
+               pr_err("unable to register reboot notifier\n");
                release_region(scx200_cb_base + SCx200_WDT_OFFSET,
                                SCx200_WDT_SIZE);
                return r;
index a267dc0..93958a7 100644 (file)
@@ -17,6 +17,9 @@
  *     Added expect close support, made emulated timeout runtime changeable
  *     general cleanups, add some ioctls
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
@@ -72,7 +75,7 @@ static DEFINE_SPINLOCK(shwdt_lock);
 
 #define WATCHDOG_HEARTBEAT 30                  /* 30 sec default heartbeat */
 static int heartbeat = WATCHDOG_HEARTBEAT;     /* in seconds */
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 static unsigned long next_heartbeat;
 
 struct sh_wdt {
@@ -440,20 +443,20 @@ static int __init sh_wdt_init(void)
                     clock_division_ratio > 0x7)) {
                clock_division_ratio = WTCSR_CKS_4096;
 
-               pr_info("%s: divisor must be 0x5<=x<=0x7, using %d\n",
-                        DRV_NAME, clock_division_ratio);
+               pr_info("divisor must be 0x5<=x<=0x7, using %d\n",
+                       clock_division_ratio);
        }
 
        rc = sh_wdt_set_heartbeat(heartbeat);
        if (unlikely(rc)) {
                heartbeat = WATCHDOG_HEARTBEAT;
 
-               pr_info("%s: heartbeat value must be 1<=x<=3600, using %d\n",
-                       DRV_NAME, heartbeat);
+               pr_info("heartbeat value must be 1<=x<=3600, using %d\n",
+                       heartbeat);
        }
 
-       pr_info("%s: configured with heartbeat=%d sec (nowayout=%d)\n",
-               DRV_NAME, heartbeat, nowayout);
+       pr_info("configured with heartbeat=%d sec (nowayout=%d)\n",
+               heartbeat, nowayout);
 
        return platform_driver_register(&sh_wdt_driver);
 }
@@ -481,7 +484,7 @@ MODULE_PARM_DESC(heartbeat,
        "Watchdog heartbeat in seconds. (1 <= heartbeat <= 3600, default="
                                __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
index 16365d0..6d665f9 100644 (file)
@@ -43,6 +43,8 @@
  *   Documentation/watchdog/wdt.txt
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -69,7 +71,6 @@
 #define UNIT_SECOND     0
 #define UNIT_MINUTE     1
 
-#define MODNAME                "smsc37b787_wdt: "
 #define VERSION                "1.1"
 
 #define IOPORT         0x3F0
@@ -84,7 +85,7 @@ static char expect_close;       /* is the close expected? */
 
 static DEFINE_SPINLOCK(io_lock);/* to guard the watchdog from io races */
 
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 /* -- Low level function ----------------------------------------*/
 
@@ -362,8 +363,7 @@ static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
        /* Reload and activate timer */
        wb_smsc_wdt_enable();
 
-       printk(KERN_INFO MODNAME
-               "Watchdog enabled. Timeout set to %d %s.\n",
+       pr_info("Watchdog enabled. Timeout set to %d %s\n",
                timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
 
        return nonseekable_open(inode, file);
@@ -377,11 +377,9 @@ static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
 
        if (expect_close == 42) {
                wb_smsc_wdt_disable();
-               printk(KERN_INFO MODNAME
-                               "Watchdog disabled, sleeping again...\n");
+               pr_info("Watchdog disabled, sleeping again...\n");
        } else {
-               printk(KERN_CRIT MODNAME
-                               "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                wb_smsc_wdt_reset_timer();
        }
 
@@ -533,12 +531,11 @@ static int __init wb_smsc_wdt_init(void)
 {
        int ret;
 
-       printk(KERN_INFO "SMsC 37B787 watchdog component driver "
-                                       VERSION " initialising...\n");
+       pr_info("SMsC 37B787 watchdog component driver "
+               VERSION " initialising...\n");
 
        if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
-               printk(KERN_ERR MODNAME "Unable to register IO port %#x\n",
-                                                               IOPORT);
+               pr_err("Unable to register IO port %#x\n", IOPORT);
                ret = -EBUSY;
                goto out_pnp;
        }
@@ -552,25 +549,22 @@ static int __init wb_smsc_wdt_init(void)
 
        ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
        if (ret) {
-               printk(KERN_ERR MODNAME
-                       "Unable to register reboot notifier err = %d\n", ret);
+               pr_err("Unable to register reboot notifier err = %d\n", ret);
                goto out_io;
        }
 
        ret = misc_register(&wb_smsc_wdt_miscdev);
        if (ret) {
-               printk(KERN_ERR MODNAME
-                       "Unable to register miscdev on minor %d\n",
-                                                       WATCHDOG_MINOR);
+               pr_err("Unable to register miscdev on minor %d\n",
+                      WATCHDOG_MINOR);
                goto out_rbt;
        }
 
        /* output info */
-       printk(KERN_INFO MODNAME "Timeout set to %d %s.\n",
+       pr_info("Timeout set to %d %s\n",
                timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
-       printk(KERN_INFO MODNAME
-               "Watchdog initialized and sleeping (nowayout=%d)...\n",
-                                                               nowayout);
+       pr_info("Watchdog initialized and sleeping (nowayout=%d)...\n",
+               nowayout);
 out_clean:
        return ret;
 
@@ -591,14 +585,14 @@ static void __exit wb_smsc_wdt_exit(void)
        /* Stop the timer before we leave */
        if (!nowayout) {
                wb_smsc_wdt_shutdown();
-               printk(KERN_INFO MODNAME "Watchdog disabled.\n");
+               pr_info("Watchdog disabled\n");
        }
 
        misc_deregister(&wb_smsc_wdt_miscdev);
        unregister_reboot_notifier(&wb_smsc_wdt_notifier);
        release_region(IOPORT, IOPORT_SIZE);
 
-       printk(KERN_INFO "SMsC 37B787 watchdog component driver removed.\n");
+       pr_info("SMsC 37B787 watchdog component driver removed\n");
 }
 
 module_init(wb_smsc_wdt_init);
@@ -620,7 +614,7 @@ MODULE_PARM_DESC(unit,
 module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
index bf16ffb..fe83beb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     SoftDog 0.07:   A Software Watchdog Device
+ *     SoftDog:        A Software Watchdog Device
  *
  *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  *                                                     All Rights Reserved.
  *     Added Matt Domsch's nowayout module option.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
-#include <linux/fs.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
-#include <linux/uaccess.h>
 #include <linux/kernel.h>
 
-#define PFX "SoftDog: "
-
 #define TIMER_MARGIN   60              /* Default is 60 seconds */
-static int soft_margin = TIMER_MARGIN; /* in seconds */
-module_param(soft_margin, int, 0);
+static unsigned int soft_margin = TIMER_MARGIN;        /* in seconds */
+module_param(soft_margin, uint, 0);
 MODULE_PARM_DESC(soft_margin,
        "Watchdog soft_margin in seconds. (0 < soft_margin < 65536, default="
                                        __MODULE_STRING(TIMER_MARGIN) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-#ifdef ONLY_TESTING
-static int soft_noboot = 1;
-#else
 static int soft_noboot = 0;
-#endif  /* ONLY_TESTING */
-
 module_param(soft_noboot, int, 0);
 MODULE_PARM_DESC(soft_noboot,
-       "Softdog action, set to 1 to ignore reboots, 0 to reboot "
-                                       "(default depends on ONLY_TESTING)");
+       "Softdog action, set to 1 to ignore reboots, 0 to reboot (default=0)");
 
 static int soft_panic;
 module_param(soft_panic, int, 0);
@@ -89,9 +81,6 @@ static void watchdog_fire(unsigned long);
 
 static struct timer_list watchdog_ticktock =
                TIMER_INITIALIZER(watchdog_fire, 0, 0);
-static unsigned long driver_open, orphan_timer;
-static char expect_close;
-
 
 /*
  *     If the timer expires..
@@ -99,18 +88,15 @@ static char expect_close;
 
 static void watchdog_fire(unsigned long data)
 {
-       if (test_and_clear_bit(0, &orphan_timer))
-               module_put(THIS_MODULE);
-
        if (soft_noboot)
-               printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
+               pr_crit("Triggered - Reboot ignored\n");
        else if (soft_panic) {
-               printk(KERN_CRIT PFX "Initiating panic.\n");
-               panic("Software Watchdog Timer expired.");
+               pr_crit("Initiating panic\n");
+               panic("Software Watchdog Timer expired");
        } else {
-               printk(KERN_CRIT PFX "Initiating system reboot.\n");
+               pr_crit("Initiating system reboot\n");
                emergency_restart();
-               printk(KERN_CRIT PFX "Reboot didn't ?????\n");
+               pr_crit("Reboot didn't ?????\n");
        }
 }
 
@@ -118,127 +104,24 @@ static void watchdog_fire(unsigned long data)
  *     Softdog operations
  */
 
-static int softdog_keepalive(void)
+static int softdog_ping(struct watchdog_device *w)
 {
-       mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
+       mod_timer(&watchdog_ticktock, jiffies+(w->timeout*HZ));
        return 0;
 }
 
-static int softdog_stop(void)
+static int softdog_stop(struct watchdog_device *w)
 {
        del_timer(&watchdog_ticktock);
        return 0;
 }
 
-static int softdog_set_heartbeat(int t)
-{
-       if ((t < 0x0001) || (t > 0xFFFF))
-               return -EINVAL;
-
-       soft_margin = t;
-       return 0;
-}
-
-/*
- *     /dev/watchdog handling
- */
-
-static int softdog_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(0, &driver_open))
-               return -EBUSY;
-       if (!test_and_clear_bit(0, &orphan_timer))
-               __module_get(THIS_MODULE);
-       /*
-        *      Activate timer
-        */
-       softdog_keepalive();
-       return nonseekable_open(inode, file);
-}
-
-static int softdog_release(struct inode *inode, struct file *file)
+static int softdog_set_timeout(struct watchdog_device *w, unsigned int t)
 {
-       /*
-        *      Shut off the timer.
-        *      Lock it in if it's a module and we set nowayout
-        */
-       if (expect_close == 42) {
-               softdog_stop();
-               module_put(THIS_MODULE);
-       } else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
-               set_bit(0, &orphan_timer);
-               softdog_keepalive();
-       }
-       clear_bit(0, &driver_open);
-       expect_close = 0;
+       w->timeout = t;
        return 0;
 }
 
-static ssize_t softdog_write(struct file *file, const char __user *data,
-                                               size_t len, loff_t *ppos)
-{
-       /*
-        *      Refresh the timer.
-        */
-       if (len) {
-               if (!nowayout) {
-                       size_t i;
-
-                       /* In case it was set long ago */
-                       expect_close = 0;
-
-                       for (i = 0; i != len; i++) {
-                               char c;
-
-                               if (get_user(c, data + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       expect_close = 42;
-                       }
-               }
-               softdog_keepalive();
-       }
-       return len;
-}
-
-static long softdog_ioctl(struct file *file, unsigned int cmd,
-                                                       unsigned long arg)
-{
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       int new_margin;
-       static const struct watchdog_info ident = {
-               .options =              WDIOF_SETTIMEOUT |
-                                       WDIOF_KEEPALIVEPING |
-                                       WDIOF_MAGICCLOSE,
-               .firmware_version =     0,
-               .identity =             "Software Watchdog",
-       };
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               return put_user(0, p);
-       case WDIOC_KEEPALIVE:
-               softdog_keepalive();
-               return 0;
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_margin, p))
-                       return -EFAULT;
-               if (softdog_set_heartbeat(new_margin))
-                       return -EINVAL;
-               softdog_keepalive();
-               /* Fall */
-       case WDIOC_GETTIMEOUT:
-               return put_user(soft_margin, p);
-       default:
-               return -ENOTTY;
-       }
-}
-
 /*
  *     Notifier for system down
  */
@@ -248,7 +131,7 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
 {
        if (code == SYS_DOWN || code == SYS_HALT)
                /* Turn the WDT off */
-               softdog_stop();
+               softdog_stop(NULL);
        return NOTIFY_DONE;
 }
 
@@ -256,28 +139,29 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
  *     Kernel Interfaces
  */
 
-static const struct file_operations softdog_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = softdog_write,
-       .unlocked_ioctl = softdog_ioctl,
-       .open           = softdog_open,
-       .release        = softdog_release,
+static struct notifier_block softdog_notifier = {
+       .notifier_call  = softdog_notify_sys,
 };
 
-static struct miscdevice softdog_miscdev = {
-       .minor          = WATCHDOG_MINOR,
-       .name           = "watchdog",
-       .fops           = &softdog_fops,
+static struct watchdog_info softdog_info = {
+       .identity = "Software Watchdog",
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 };
 
-static struct notifier_block softdog_notifier = {
-       .notifier_call  = softdog_notify_sys,
+static struct watchdog_ops softdog_ops = {
+       .owner = THIS_MODULE,
+       .start = softdog_ping,
+       .stop = softdog_stop,
+       .ping = softdog_ping,
+       .set_timeout = softdog_set_timeout,
 };
 
-static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 "
-       "initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d "
-       "(nowayout= %d)\n";
+static struct watchdog_device softdog_dev = {
+       .info = &softdog_info,
+       .ops = &softdog_ops,
+       .min_timeout = 1,
+       .max_timeout = 0xFFFF
+};
 
 static int __init watchdog_init(void)
 {
@@ -285,37 +169,36 @@ static int __init watchdog_init(void)
 
        /* Check that the soft_margin value is within it's range;
           if not reset to the default */
-       if (softdog_set_heartbeat(soft_margin)) {
-               softdog_set_heartbeat(TIMER_MARGIN);
-               printk(KERN_INFO PFX
-                   "soft_margin must be 0 < soft_margin < 65536, using %d\n",
+       if (soft_margin < 1 || soft_margin > 65535) {
+               pr_info("soft_margin must be 0 < soft_margin < 65536, using %d\n",
                        TIMER_MARGIN);
+               return -EINVAL;
        }
+       softdog_dev.timeout = soft_margin;
+
+       watchdog_set_nowayout(&softdog_dev, nowayout);
 
        ret = register_reboot_notifier(&softdog_notifier);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                return ret;
        }
 
-       ret = misc_register(&softdog_miscdev);
+       ret = watchdog_register_device(&softdog_dev);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                               WATCHDOG_MINOR, ret);
                unregister_reboot_notifier(&softdog_notifier);
                return ret;
        }
 
-       printk(banner, soft_noboot, soft_margin, soft_panic, nowayout);
+       pr_info("Software Watchdog Timer: 0.08 initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d (nowayout=%d)\n",
+               soft_noboot, soft_margin, soft_panic, nowayout);
 
        return 0;
 }
 
 static void __exit watchdog_exit(void)
 {
-       misc_deregister(&softdog_miscdev);
+       watchdog_unregister_device(&softdog_dev);
        unregister_reboot_notifier(&softdog_notifier);
 }
 
index 87e0527..59108e4 100644 (file)
@@ -20,6 +20,8 @@
  *     Includes, defines, variables, module parameters, ...
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -39,7 +41,6 @@
 #define TCO_VERSION "0.01"
 #define TCO_MODULE_NAME "SP5100 TCO timer"
 #define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
-#define PFX TCO_MODULE_NAME ": "
 
 /* internal variables */
 static u32 tcobase_phys;
@@ -61,8 +62,8 @@ module_param(heartbeat, int, 0);
 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
                 __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
                " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -143,8 +144,7 @@ static int sp5100_tco_release(struct inode *inode, struct file *file)
        if (tco_expect_close == 42) {
                tco_timer_stop();
        } else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                tco_timer_keepalive();
        }
        clear_bit(0, &timer_alive);
@@ -290,8 +290,7 @@ static unsigned char __devinit sp5100_tco_setupdevice(void)
        /* Request the IO ports used by this driver */
        pm_iobase = SP5100_IO_PM_INDEX_REG;
        if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       pm_iobase);
+               pr_err("I/O address 0x%04x already in use\n", pm_iobase);
                goto exit;
        }
 
@@ -308,15 +307,14 @@ static unsigned char __devinit sp5100_tco_setupdevice(void)
 
        if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
                                                                "SP5100 TCO")) {
-               printk(KERN_ERR PFX "mmio address 0x%04x already in use\n",
-                       val);
+               pr_err("mmio address 0x%04x already in use\n", val);
                goto unreg_region;
        }
        tcobase_phys = val;
 
        tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
        if (tcobase == 0) {
-               printk(KERN_ERR PFX "failed to get tcobase address\n");
+               pr_err("failed to get tcobase address\n");
                goto unreg_mem_region;
        }
 
@@ -375,9 +373,9 @@ static int __devinit sp5100_tco_init(struct platform_device *dev)
                return -ENODEV;
 
        /* Check to see if last reboot was due to watchdog timeout */
-       printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n",
-              readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ?
-                     "" : "not ");
+       pr_info("Watchdog reboot %sdetected\n",
+               readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ?
+               "" : "not ");
 
        /* Clear out the old status */
        val = readl(SP5100_WDT_CONTROL(tcobase));
@@ -395,16 +393,14 @@ static int __devinit sp5100_tco_init(struct platform_device *dev)
 
        ret = misc_register(&sp5100_tco_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX "cannot register miscdev on minor="
-                      "%d (err=%d)\n",
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
                       WATCHDOG_MINOR, ret);
                goto exit;
        }
 
        clear_bit(0, &timer_alive);
 
-       printk(KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec"
-               " (nowayout=%d)\n",
+       pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
                tcobase, heartbeat, nowayout);
 
        return 0;
@@ -455,8 +451,7 @@ static int __init sp5100_tco_init_module(void)
 {
        int err;
 
-       printk(KERN_INFO PFX "SP5100 TCO WatchDog Timer Driver v%s\n",
-              TCO_VERSION);
+       pr_info("SP5100 TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
 
        err = platform_driver_register(&sp5100_tco_driver);
        if (err)
@@ -480,7 +475,7 @@ static void __exit sp5100_tco_cleanup_module(void)
 {
        platform_device_unregister(sp5100_tco_platform_device);
        platform_driver_unregister(&sp5100_tco_driver);
-       printk(KERN_INFO PFX "SP5100 TCO Watchdog Module Unloaded.\n");
+       pr_info("SP5100 TCO Watchdog Module Unloaded\n");
 }
 
 module_init(sp5100_tco_init_module);
index eef1524..bbb170e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
 /**
  * struct sp805_wdt: sp805 wdt device structure
- *
- * lock: spin lock protecting dev structure and io access
- * base: base address of wdt
- * clk: clock structure of wdt
- * dev: amba device structure of wdt
- * status: current status of wdt
- * load_val: load value to be set for current timeout
- * timeout: current programmed timeout
+ * @lock: spin lock protecting dev structure and io access
+ * @base: base address of wdt
+ * @clk: clock structure of wdt
+ * @adev: amba device structure of wdt
+ * @status: current status of wdt
+ * @load_val: load value to be set for current timeout
+ * @timeout: current programmed timeout
  */
 struct sp805_wdt {
        spinlock_t                      lock;
@@ -78,7 +78,7 @@ struct sp805_wdt {
 
 /* local variables */
 static struct sp805_wdt *wdt;
-static int nowayout = WATCHDOG_NOWAYOUT;
+static bool nowayout = WATCHDOG_NOWAYOUT;
 
 /* This routine finds load value that will reset system in required timout */
 static void wdt_setload(unsigned int timeout)
@@ -113,10 +113,10 @@ static u32 wdt_timeleft(void)
        rate = clk_get_rate(wdt->clk);
 
        spin_lock(&wdt->lock);
-       load = readl(wdt->base + WDTVALUE);
+       load = readl_relaxed(wdt->base + WDTVALUE);
 
        /*If the interrupt is inactive then time left is WDTValue + WDTLoad. */
-       if (!(readl(wdt->base + WDTRIS) & INT_MASK))
+       if (!(readl_relaxed(wdt->base + WDTRIS) & INT_MASK))
                load += wdt->load_val + 1;
        spin_unlock(&wdt->lock);
 
@@ -128,14 +128,14 @@ static void wdt_enable(void)
 {
        spin_lock(&wdt->lock);
 
-       writel(UNLOCK, wdt->base + WDTLOCK);
-       writel(wdt->load_val, wdt->base + WDTLOAD);
-       writel(INT_MASK, wdt->base + WDTINTCLR);
-       writel(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
-       writel(LOCK, wdt->base + WDTLOCK);
+       writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
+       writel_relaxed(wdt->load_val, wdt->base + WDTLOAD);
+       writel_relaxed(INT_MASK, wdt->base + WDTINTCLR);
+       writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
+       writel_relaxed(LOCK, wdt->base + WDTLOCK);
 
        /* Flush posted writes. */
-       readl(wdt->base + WDTLOCK);
+       readl_relaxed(wdt->base + WDTLOCK);
        spin_unlock(&wdt->lock);
 }
 
@@ -144,12 +144,12 @@ static void wdt_disable(void)
 {
        spin_lock(&wdt->lock);
 
-       writel(UNLOCK, wdt->base + WDTLOCK);
-       writel(0, wdt->base + WDTCONTROL);
-       writel(LOCK, wdt->base + WDTLOCK);
+       writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
+       writel_relaxed(0, wdt->base + WDTCONTROL);
+       writel_relaxed(LOCK, wdt->base + WDTLOCK);
 
        /* Flush posted writes. */
-       readl(wdt->base + WDTLOCK);
+       readl_relaxed(wdt->base + WDTLOCK);
        spin_unlock(&wdt->lock);
 }
 
@@ -285,32 +285,33 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
 {
        int ret = 0;
 
-       if (!request_mem_region(adev->res.start, resource_size(&adev->res),
-                               "sp805_wdt")) {
+       if (!devm_request_mem_region(&adev->dev, adev->res.start,
+                               resource_size(&adev->res), "sp805_wdt")) {
                dev_warn(&adev->dev, "Failed to get memory region resource\n");
                ret = -ENOENT;
                goto err;
        }
 
-       wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt) {
                dev_warn(&adev->dev, "Kzalloc failed\n");
                ret = -ENOMEM;
-               goto err_kzalloc;
+               goto err;
+       }
+
+       wdt->base = devm_ioremap(&adev->dev, adev->res.start,
+                       resource_size(&adev->res));
+       if (!wdt->base) {
+               ret = -ENOMEM;
+               dev_warn(&adev->dev, "ioremap fail\n");
+               goto err;
        }
 
        wdt->clk = clk_get(&adev->dev, NULL);
        if (IS_ERR(wdt->clk)) {
                dev_warn(&adev->dev, "Clock not found\n");
                ret = PTR_ERR(wdt->clk);
-               goto err_clk_get;
-       }
-
-       wdt->base = ioremap(adev->res.start, resource_size(&adev->res));
-       if (!wdt->base) {
-               ret = -ENOMEM;
-               dev_warn(&adev->dev, "ioremap fail\n");
-               goto err_ioremap;
+               goto err;
        }
 
        wdt->adev = adev;
@@ -327,14 +328,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
        return 0;
 
 err_misc_register:
-       iounmap(wdt->base);
-err_ioremap:
        clk_put(wdt->clk);
-err_clk_get:
-       kfree(wdt);
-       wdt = NULL;
-err_kzalloc:
-       release_mem_region(adev->res.start, resource_size(&adev->res));
 err:
        dev_err(&adev->dev, "Probe Failed!!!\n");
        return ret;
@@ -343,14 +337,42 @@ err:
 static int __devexit sp805_wdt_remove(struct amba_device *adev)
 {
        misc_deregister(&sp805_wdt_miscdev);
-       iounmap(wdt->base);
        clk_put(wdt->clk);
-       kfree(wdt);
-       release_mem_region(adev->res.start, resource_size(&adev->res));
 
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int sp805_wdt_suspend(struct device *dev)
+{
+       if (test_bit(WDT_BUSY, &wdt->status)) {
+               wdt_disable();
+               clk_disable(wdt->clk);
+       }
+
+       return 0;
+}
+
+static int sp805_wdt_resume(struct device *dev)
+{
+       int ret = 0;
+
+       if (test_bit(WDT_BUSY, &wdt->status)) {
+               ret = clk_enable(wdt->clk);
+               if (ret) {
+                       dev_err(dev, "clock enable fail");
+                       return ret;
+               }
+               wdt_enable();
+       }
+
+       return ret;
+}
+#endif /* CONFIG_PM */
+
+static SIMPLE_DEV_PM_OPS(sp805_wdt_dev_pm_ops, sp805_wdt_suspend,
+               sp805_wdt_resume);
+
 static struct amba_id sp805_wdt_ids[] = {
        {
                .id     = 0x00141805,
@@ -364,25 +386,16 @@ MODULE_DEVICE_TABLE(amba, sp805_wdt_ids);
 static struct amba_driver sp805_wdt_driver = {
        .drv = {
                .name   = MODULE_NAME,
+               .pm     = &sp805_wdt_dev_pm_ops,
        },
        .id_table       = sp805_wdt_ids,
        .probe          = sp805_wdt_probe,
        .remove = __devexit_p(sp805_wdt_remove),
 };
 
-static int __init sp805_wdt_init(void)
-{
-       return amba_driver_register(&sp805_wdt_driver);
-}
-module_init(sp805_wdt_init);
-
-static void __exit sp805_wdt_exit(void)
-{
-       amba_driver_unregister(&sp805_wdt_driver);
-}
-module_exit(sp805_wdt_exit);
+module_amba_driver(sp805_wdt_driver);
 
-module_param(nowayout, int, 0);
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Set to 1 to keep watchdog running after device release");
 
index e37d811..21d96b9 100644 (file)
@@ -6,6 +6,9 @@
  * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
  * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
@@ -32,7 +35,7 @@
 
 static DEFINE_SPINLOCK(stmp3xxx_wdt_io_lock);
 static unsigned long wdt_status;
-static const int nowayout = WATCHDOG_NOWAYOUT;
+static const bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = DEFAULT_HEARTBEAT;
 static unsigned long boot_status;
 
@@ -221,8 +224,7 @@ static int __devinit stmp3xxx_wdt_probe(struct platform_device *pdev)
                return ret;
        }
 
-       printk(KERN_INFO "stmp3xxx watchdog: initialized, heartbeat %d sec\n",
-               heartbeat);
+       pr_info("initialized, heartbeat %d sec\n", heartbeat);
 
        return ret;
 }
index 1490293..8df050d 100644 (file)
@@ -34,8 +34,8 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. "
                          __MODULE_STRING(TS72XX_WDT_DEFAULT_TIMEOUT)
                          ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
 /**
index 0764c62..249f113 100644 (file)
@@ -42,8 +42,8 @@ struct twl4030_wdt {
        unsigned long           state;
 };
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
        "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
index 9e9ed7b..98e1637 100644 (file)
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
-#include <linux/fs.h>
 #include <linux/init.h>
-#include <linux/uaccess.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <asm/txx9tmr.h>
 
+#define WD_TIMER_CCD   7               /* 1/256 */
+#define WD_TIMER_CLK   (clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))
+#define WD_MAX_TIMEOUT ((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)
 #define TIMER_MARGIN   60              /* Default is 60 seconds */
 
-static int timeout = TIMER_MARGIN;     /* in seconds */
-module_param(timeout, int, 0);
+static unsigned int timeout = TIMER_MARGIN;    /* in seconds */
+module_param(timeout, uint, 0);
 MODULE_PARM_DESC(timeout,
        "Watchdog timeout in seconds. "
        "(0<timeout<((2^" __MODULE_STRING(TXX9_TIMER_BITS) ")/(IMCLK/256)), "
        "default=" __MODULE_STRING(TIMER_MARGIN) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started "
        "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-#define WD_TIMER_CCD   7       /* 1/256 */
-#define WD_TIMER_CLK   (clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))
-#define WD_MAX_TIMEOUT ((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)
-
-static unsigned long txx9wdt_alive;
-static int expect_close;
 static struct txx9_tmr_reg __iomem *txx9wdt_reg;
 static struct clk *txx9_imclk;
 static DEFINE_SPINLOCK(txx9_lock);
 
-static void txx9wdt_ping(void)
+static int txx9wdt_ping(struct watchdog_device *wdt_dev)
 {
        spin_lock(&txx9_lock);
        __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
        spin_unlock(&txx9_lock);
+       return 0;
 }
 
-static void txx9wdt_start(void)
+static int txx9wdt_start(struct watchdog_device *wdt_dev)
 {
        spin_lock(&txx9_lock);
-       __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra);
+       __raw_writel(WD_TIMER_CLK * wdt_dev->timeout, &txx9wdt_reg->cpra);
        __raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr);
        __raw_writel(0, &txx9wdt_reg->tisr);    /* clear pending interrupt */
        __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
                     &txx9wdt_reg->tcr);
        __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
        spin_unlock(&txx9_lock);
+       return 0;
 }
 
-static void txx9wdt_stop(void)
+static int txx9wdt_stop(struct watchdog_device *wdt_dev)
 {
        spin_lock(&txx9_lock);
        __raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr);
        __raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE,
                     &txx9wdt_reg->tcr);
        spin_unlock(&txx9_lock);
-}
-
-static int txx9wdt_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(0, &txx9wdt_alive))
-               return -EBUSY;
-
-       if (__raw_readl(&txx9wdt_reg->tcr) & TXx9_TMTCR_TCE) {
-               clear_bit(0, &txx9wdt_alive);
-               return -EBUSY;
-       }
-
-       if (nowayout)
-               __module_get(THIS_MODULE);
-
-       txx9wdt_start();
-       return nonseekable_open(inode, file);
-}
-
-static int txx9wdt_release(struct inode *inode, struct file *file)
-{
-       if (expect_close)
-               txx9wdt_stop();
-       else {
-               printk(KERN_CRIT "txx9wdt: "
-                      "Unexpected close, not stopping watchdog!\n");
-               txx9wdt_ping();
-       }
-       clear_bit(0, &txx9wdt_alive);
-       expect_close = 0;
        return 0;
 }
 
-static ssize_t txx9wdt_write(struct file *file, const char __user *data,
-                            size_t len, loff_t *ppos)
+static int txx9wdt_set_timeout(struct watchdog_device *wdt_dev,
+                              unsigned int new_timeout)
 {
-       if (len) {
-               if (!nowayout) {
-                       size_t i;
-
-                       expect_close = 0;
-                       for (i = 0; i != len; i++) {
-                               char c;
-                               if (get_user(c, data + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       expect_close = 1;
-                       }
-               }
-               txx9wdt_ping();
-       }
-       return len;
+       wdt_dev->timeout = new_timeout;
+       txx9wdt_stop(wdt_dev);
+       txx9wdt_start(wdt_dev);
+       return 0;
 }
 
-static long txx9wdt_ioctl(struct file *file, unsigned int cmd,
-                                                       unsigned long arg)
-{
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       int new_timeout;
-       static const struct watchdog_info ident = {
-               .options =              WDIOF_SETTIMEOUT |
-                                       WDIOF_KEEPALIVEPING |
-                                       WDIOF_MAGICCLOSE,
-               .firmware_version =     0,
-               .identity =             "Hardware Watchdog for TXx9",
-       };
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               return put_user(0, p);
-       case WDIOC_KEEPALIVE:
-               txx9wdt_ping();
-               return 0;
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_timeout, p))
-                       return -EFAULT;
-               if (new_timeout < 1 || new_timeout > WD_MAX_TIMEOUT)
-                       return -EINVAL;
-               timeout = new_timeout;
-               txx9wdt_stop();
-               txx9wdt_start();
-               /* Fall */
-       case WDIOC_GETTIMEOUT:
-               return put_user(timeout, p);
-       default:
-               return -ENOTTY;
-       }
-}
+static const struct watchdog_info txx9wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+       .identity = "Hardware Watchdog for TXx9",
+};
 
-static const struct file_operations txx9wdt_fops = {
-       .owner          =       THIS_MODULE,
-       .llseek         =       no_llseek,
-       .write          =       txx9wdt_write,
-       .unlocked_ioctl =       txx9wdt_ioctl,
-       .open           =       txx9wdt_open,
-       .release        =       txx9wdt_release,
+static const struct watchdog_ops txx9wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = txx9wdt_start,
+       .stop = txx9wdt_stop,
+       .ping = txx9wdt_ping,
+       .set_timeout = txx9wdt_set_timeout,
 };
 
-static struct miscdevice txx9wdt_miscdev = {
-       .minor  =       WATCHDOG_MINOR,
-       .name   =       "watchdog",
-       .fops   =       &txx9wdt_fops,
+static struct watchdog_device txx9wdt = {
+       .info = &txx9wdt_info,
+       .ops = &txx9wdt_ops,
 };
 
 static int __init txx9wdt_probe(struct platform_device *dev)
@@ -199,27 +121,27 @@ static int __init txx9wdt_probe(struct platform_device *dev)
        }
 
        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res)
-               goto exit_busy;
-       if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
-                                    "txx9wdt"))
-               goto exit_busy;
-       txx9wdt_reg = devm_ioremap(&dev->dev, res->start, resource_size(res));
-       if (!txx9wdt_reg)
-               goto exit_busy;
-
-       ret = misc_register(&txx9wdt_miscdev);
-       if (ret) {
+       txx9wdt_reg = devm_request_and_ioremap(&dev->dev, res);
+       if (!txx9wdt_reg) {
+               ret = -EBUSY;
                goto exit;
        }
 
-       printk(KERN_INFO "Hardware Watchdog Timer for TXx9: "
-              "timeout=%d sec (max %ld) (nowayout= %d)\n",
-              timeout, WD_MAX_TIMEOUT, nowayout);
+       if (timeout < 1 || timeout > WD_MAX_TIMEOUT)
+               timeout = TIMER_MARGIN;
+       txx9wdt.timeout = timeout;
+       txx9wdt.min_timeout = 1;
+       txx9wdt.max_timeout = WD_MAX_TIMEOUT;
+       watchdog_set_nowayout(&txx9wdt, nowayout);
+
+       ret = watchdog_register_device(&txx9wdt);
+       if (ret)
+               goto exit;
+
+       pr_info("Hardware Watchdog Timer: timeout=%d sec (max %ld) (nowayout= %d)\n",
+               timeout, WD_MAX_TIMEOUT, nowayout);
 
        return 0;
-exit_busy:
-       ret = -EBUSY;
 exit:
        if (txx9_imclk) {
                clk_disable(txx9_imclk);
@@ -230,7 +152,7 @@ exit:
 
 static int __exit txx9wdt_remove(struct platform_device *dev)
 {
-       misc_deregister(&txx9wdt_miscdev);
+       watchdog_unregister_device(&txx9wdt);
        clk_disable(txx9_imclk);
        clk_put(txx9_imclk);
        return 0;
@@ -238,7 +160,7 @@ static int __exit txx9wdt_remove(struct platform_device *dev)
 
 static void txx9wdt_shutdown(struct platform_device *dev)
 {
-       txx9wdt_stop();
+       txx9wdt_stop(&txx9wdt);
 }
 
 static struct platform_driver txx9wdt_driver = {
index 8f07dd4..465e082 100644 (file)
@@ -10,6 +10,9 @@
  * Caveat: PnP must be enabled in BIOS to allow full access to watchdog
  * control registers. If not, the watchdog must be configured in BIOS manually.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/jiffies.h>
@@ -55,8 +58,8 @@ module_param(timeout, int, 0);
 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, between 1 and 1023 "
        "(default = " __MODULE_STRING(WDT_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
        "(default = " __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
@@ -98,7 +101,7 @@ static void wdt_timer_tick(unsigned long data)
 static int wdt_ping(struct watchdog_device *wdd)
 {
        /* calculate when the next userspace timeout will be */
-       next_heartbeat = jiffies + timeout * HZ;
+       next_heartbeat = jiffies + wdd->timeout * HZ;
        return 0;
 }
 
@@ -106,7 +109,7 @@ static int wdt_start(struct watchdog_device *wdd)
 {
        unsigned int ctl = readl(wdt_mem);
 
-       writel(timeout, wdt_mem + VIA_WDT_COUNT);
+       writel(wdd->timeout, wdt_mem + VIA_WDT_COUNT);
        writel(ctl | VIA_WDT_RUNNING | VIA_WDT_TRIGGER, wdt_mem);
        wdt_ping(wdd);
        mod_timer(&timer, jiffies + WDT_HEARTBEAT);
@@ -125,7 +128,7 @@ static int wdt_set_timeout(struct watchdog_device *wdd,
                           unsigned int new_timeout)
 {
        writel(new_timeout, wdt_mem + VIA_WDT_COUNT);
-       timeout = new_timeout;
+       wdd->timeout = new_timeout;
        return 0;
 }
 
index 1283d06..92f1326 100644 (file)
@@ -26,6 +26,8 @@
  *     (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -42,7 +44,6 @@
 
 
 #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
-#define PFX WATCHDOG_NAME ": "
 #define WATCHDOG_TIMEOUT 60            /* 60 sec default timeout */
 
 static unsigned long wdt_is_open;
@@ -60,8 +61,8 @@ MODULE_PARM_DESC(timeout,
                "Watchdog timeout in seconds. 1 <= timeout <= 255, default="
                                __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -118,9 +119,8 @@ static void w83627hf_init(void)
        outb_p(0xF6, WDT_EFER); /* Select CRF6 */
        t = inb_p(WDT_EFDR);      /* read CRF6 */
        if (t != 0) {
-               printk(KERN_INFO PFX
-                    "Watchdog already running. Resetting timeout to %d sec\n",
-                                                               timeout);
+               pr_info("Watchdog already running. Resetting timeout to %d sec\n",
+                       timeout);
                outb_p(timeout, WDT_EFDR);    /* Write back to CRF6 */
        }
 
@@ -289,8 +289,7 @@ static int wdt_close(struct inode *inode, struct file *file)
        if (expect_close == 42)
                wdt_disable();
        else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                wdt_ping();
        }
        expect_close = 0;
@@ -343,18 +342,16 @@ static int __init wdt_init(void)
 {
        int ret;
 
-       printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising.\n");
+       pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n");
 
        if (wdt_set_heartbeat(timeout)) {
                wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-               printk(KERN_INFO PFX
-                    "timeout value must be 1 <= timeout <= 255, using %d\n",
-                               WATCHDOG_TIMEOUT);
+               pr_info("timeout value must be 1 <= timeout <= 255, using %d\n",
+                       WATCHDOG_TIMEOUT);
        }
 
        if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       wdt_io);
+               pr_err("I/O address 0x%04x already in use\n", wdt_io);
                ret = -EIO;
                goto out;
        }
@@ -363,22 +360,19 @@ static int __init wdt_init(void)
 
        ret = register_reboot_notifier(&wdt_notifier);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                goto unreg_regions;
        }
 
        ret = misc_register(&wdt_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto unreg_reboot;
        }
 
-       printk(KERN_INFO PFX
-                       "initialized. timeout=%d sec (nowayout=%d)\n",
-                                                       timeout, nowayout);
+       pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
+               timeout, nowayout);
 
 out:
        return ret;
index e5cb768..cd9f3c1 100644 (file)
@@ -25,6 +25,8 @@
  *     "AS-IS" and at no charge.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -41,7 +43,6 @@
 
 
 #define WATCHDOG_NAME "w83697hf/hg WDT"
-#define PFX WATCHDOG_NAME ": "
 #define WATCHDOG_TIMEOUT 60            /* 60 sec default timeout */
 #define WATCHDOG_EARLY_DISABLE 1       /* Disable until userland kicks in */
 
@@ -61,8 +62,8 @@ MODULE_PARM_DESC(timeout,
        "Watchdog timeout in seconds. 1<= timeout <=255 (default="
                                __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -308,8 +309,7 @@ static int wdt_close(struct inode *inode, struct file *file)
        if (expect_close == 42)
                wdt_disable();
        else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                wdt_ping();
        }
        expect_close = 0;
@@ -361,24 +361,21 @@ static struct notifier_block wdt_notifier = {
 static int w83697hf_check_wdt(void)
 {
        if (!request_region(wdt_io, 2, WATCHDOG_NAME)) {
-               printk(KERN_ERR PFX
-                       "I/O address 0x%x already in use\n", wdt_io);
+               pr_err("I/O address 0x%x already in use\n", wdt_io);
                return -EIO;
        }
 
-       printk(KERN_DEBUG PFX
-                       "Looking for watchdog at address 0x%x\n", wdt_io);
+       pr_debug("Looking for watchdog at address 0x%x\n", wdt_io);
        w83697hf_unlock();
        if (w83697hf_get_reg(0x20) == 0x60) {
-               printk(KERN_INFO PFX
-                       "watchdog found at address 0x%x\n", wdt_io);
+               pr_info("watchdog found at address 0x%x\n", wdt_io);
                w83697hf_lock();
                return 0;
        }
        /* Reprotect in case it was a compatible device */
        w83697hf_lock();
 
-       printk(KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io);
+       pr_info("watchdog not found at address 0x%x\n", wdt_io);
        release_region(wdt_io, 2);
        return -EIO;
 }
@@ -389,7 +386,7 @@ static int __init wdt_init(void)
 {
        int ret, i, found = 0;
 
-       printk(KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n");
+       pr_info("WDT driver for W83697HF/HG initializing\n");
 
        if (wdt_io == 0) {
                /* we will autodetect the W83697HF/HG watchdog */
@@ -404,7 +401,7 @@ static int __init wdt_init(void)
        }
 
        if (!found) {
-               printk(KERN_ERR PFX "No W83697HF/HG could be found\n");
+               pr_err("No W83697HF/HG could be found\n");
                ret = -EIO;
                goto out;
        }
@@ -412,34 +409,30 @@ static int __init wdt_init(void)
        w83697hf_init();
        if (early_disable) {
                if (wdt_running())
-                       printk(KERN_WARNING PFX "Stopping previously enabled "
-                                       "watchdog until userland kicks in\n");
+                       pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
                wdt_disable();
        }
 
        if (wdt_set_heartbeat(timeout)) {
                wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-               printk(KERN_INFO PFX
-                    "timeout value must be 1 <= timeout <= 255, using %d\n",
-                                                       WATCHDOG_TIMEOUT);
+               pr_info("timeout value must be 1 <= timeout <= 255, using %d\n",
+                       WATCHDOG_TIMEOUT);
        }
 
        ret = register_reboot_notifier(&wdt_notifier);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                goto unreg_regions;
        }
 
        ret = misc_register(&wdt_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                               WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto unreg_reboot;
        }
 
-       printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+       pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
                timeout, nowayout);
 
 out:
index 24a46ff..274be0b 100644 (file)
@@ -30,6 +30,8 @@
  *     (c) Copyright 1995    Alan Cox <alan@redhat.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -46,7 +48,6 @@
 
 
 #define WATCHDOG_NAME "w83697ug/uf WDT"
-#define PFX WATCHDOG_NAME ": "
 #define WATCHDOG_TIMEOUT 60            /* 60 sec default timeout */
 
 static unsigned long wdt_is_open;
@@ -63,8 +64,8 @@ MODULE_PARM_DESC(timeout,
        "Watchdog timeout in seconds. 1<= timeout <=255 (default="
                                __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -90,8 +91,8 @@ static int w83697ug_select_wd_register(void)
        version = inb(WDT_EFDR);
 
        if (version == 0x68) {  /* W83697UG             */
-               printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
-                       "W83697UG/UF found at 0x%04x\n", version, wdt_io);
+               pr_info("Watchdog chip version 0x%02x = W83697UG/UF found at 0x%04x\n",
+                       version, wdt_io);
 
                outb_p(0x2b, WDT_EFER);
                c = inb_p(WDT_EFDR);    /* select WDT0 */
@@ -100,7 +101,7 @@ static int w83697ug_select_wd_register(void)
                outb_p(c, WDT_EFDR);    /* set pin118 to WDT0 */
 
        } else {
-               printk(KERN_ERR PFX "No W83697UG/UF could be found\n");
+               pr_err("No W83697UG/UF could be found\n");
                return -ENODEV;
        }
 
@@ -130,8 +131,8 @@ static int w83697ug_init(void)
        outb_p(0xF6, WDT_EFER); /* Select CRF6 */
        t = inb_p(WDT_EFDR);    /* read CRF6 */
        if (t != 0) {
-               printk(KERN_INFO PFX "Watchdog already running."
-                       " Resetting timeout to %d sec\n", timeout);
+               pr_info("Watchdog already running. Resetting timeout to %d sec\n",
+                       timeout);
                outb_p(timeout, WDT_EFDR);    /* Write back to CRF6 */
        }
        outb_p(0xF5, WDT_EFER); /* Select CRF5 */
@@ -285,8 +286,7 @@ static int wdt_close(struct inode *inode, struct file *file)
        if (expect_close == 42)
                wdt_disable();
        else {
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
                wdt_ping();
        }
        expect_close = 0;
@@ -339,18 +339,16 @@ static int __init wdt_init(void)
 {
        int ret;
 
-       printk(KERN_INFO "WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising.\n");
+       pr_info("WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising\n");
 
        if (wdt_set_heartbeat(timeout)) {
                wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-               printk(KERN_INFO PFX
-                       "timeout value must be 1<=timeout<=255, using %d\n",
+               pr_info("timeout value must be 1<=timeout<=255, using %d\n",
                        WATCHDOG_TIMEOUT);
        }
 
        if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       wdt_io);
+               pr_err("I/O address 0x%04x already in use\n", wdt_io);
                ret = -EIO;
                goto out;
        }
@@ -361,20 +359,18 @@ static int __init wdt_init(void)
 
        ret = register_reboot_notifier(&wdt_notifier);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                goto unreg_regions;
        }
 
        ret = misc_register(&wdt_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto unreg_reboot;
        }
 
-       printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+       pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
                timeout, nowayout);
 
 out:
index 5f3b945..7874ae0 100644 (file)
@@ -42,6 +42,8 @@
  *  daemon always getting scheduled within that time frame.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -58,7 +60,6 @@
 #include <linux/uaccess.h>
 
 #define OUR_NAME "w83877f_wdt"
-#define PFX OUR_NAME ": "
 
 #define ENABLE_W83877F_PORT 0x3F0
 #define ENABLE_W83877F 0x87
@@ -90,8 +91,8 @@ MODULE_PARM_DESC(timeout,
                                __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -125,8 +126,7 @@ static void wdt_timer_ping(unsigned long data)
                spin_unlock(&wdt_spinlock);
 
        } else
-               printk(KERN_WARNING PFX
-                       "Heartbeat lost! Will not ping the watchdog\n");
+               pr_warn("Heartbeat lost! Will not ping the watchdog\n");
 }
 
 /*
@@ -164,7 +164,7 @@ static void wdt_startup(void)
 
        wdt_change(WDT_ENABLE);
 
-       printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+       pr_info("Watchdog timer is now enabled\n");
 }
 
 static void wdt_turnoff(void)
@@ -174,7 +174,7 @@ static void wdt_turnoff(void)
 
        wdt_change(WDT_DISABLE);
 
-       printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+       pr_info("Watchdog timer is now disabled...\n");
 }
 
 static void wdt_keepalive(void)
@@ -233,8 +233,7 @@ static int fop_close(struct inode *inode, struct file *file)
                wdt_turnoff();
        else {
                del_timer(&timer);
-               printk(KERN_CRIT PFX
-                 "device file closed unexpectedly. Will not stop the WDT!\n");
+               pr_crit("device file closed unexpectedly. Will not stop the WDT!\n");
        }
        clear_bit(0, &wdt_is_open);
        wdt_expect_close = 0;
@@ -356,42 +355,37 @@ static int __init w83877f_wdt_init(void)
 
        if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
                timeout = WATCHDOG_TIMEOUT;
-               printk(KERN_INFO PFX
-                       "timeout value must be 1 <= x <= 3600, using %d\n",
-                                                       timeout);
+               pr_info("timeout value must be 1 <= x <= 3600, using %d\n",
+                       timeout);
        }
 
        if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       ENABLE_W83877F_PORT);
+               pr_err("I/O address 0x%04x already in use\n",
+                      ENABLE_W83877F_PORT);
                rc = -EIO;
                goto err_out;
        }
 
        if (!request_region(WDT_PING, 1, "W8387FF WDT")) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       WDT_PING);
+               pr_err("I/O address 0x%04x already in use\n", WDT_PING);
                rc = -EIO;
                goto err_out_region1;
        }
 
        rc = register_reboot_notifier(&wdt_notifier);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", rc);
+               pr_err("cannot register reboot notifier (err=%d)\n", rc);
                goto err_out_region2;
        }
 
        rc = misc_register(&wdt_miscdev);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       wdt_miscdev.minor, rc);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      wdt_miscdev.minor, rc);
                goto err_out_reboot;
        }
 
-       printk(KERN_INFO PFX
-         "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
+       pr_info("WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
                timeout, nowayout);
 
        return 0;
index 7f4330e..5d2c902 100644 (file)
@@ -15,6 +15,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -32,8 +34,6 @@
 
 #define WATCHDOG_VERSION  "1.00"
 #define WATCHDOG_NAME     "W83977F WDT"
-#define PFX WATCHDOG_NAME ": "
-#define DRIVER_VERSION    WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
 
 #define IO_INDEX_PORT     0x3F0
 #define IO_DATA_PORT      (IO_INDEX_PORT+1)
@@ -58,8 +58,8 @@ MODULE_PARM_DESC(timeout,
 module_param(testmode, int, 0);
 MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -130,7 +130,7 @@ static int wdt_start(void)
 
        spin_unlock_irqrestore(&spinlock, flags);
 
-       printk(KERN_INFO PFX "activated.\n");
+       pr_info("activated\n");
 
        return 0;
 }
@@ -184,7 +184,7 @@ static int wdt_stop(void)
 
        spin_unlock_irqrestore(&spinlock, flags);
 
-       printk(KERN_INFO PFX "shutdown.\n");
+       pr_info("shutdown\n");
 
        return 0;
 }
@@ -312,8 +312,7 @@ static int wdt_release(struct inode *inode, struct file *file)
                clear_bit(0, &timer_alive);
        } else {
                wdt_keepalive();
-               printk(KERN_CRIT PFX
-                       "unexpected close, not stopping watchdog!\n");
+               pr_crit("unexpected close, not stopping watchdog!\n");
        }
        expect_close = 0;
        return 0;
@@ -470,7 +469,7 @@ static int __init w83977f_wdt_init(void)
 {
        int rc;
 
-       printk(KERN_INFO PFX DRIVER_VERSION);
+       pr_info("driver v%s\n", WATCHDOG_VERSION);
 
        /*
         * Check that the timeout value is within it's range;
@@ -478,36 +477,31 @@ static int __init w83977f_wdt_init(void)
         */
        if (wdt_set_timeout(timeout)) {
                wdt_set_timeout(DEFAULT_TIMEOUT);
-               printk(KERN_INFO PFX
-                   "timeout value must be 15 <= timeout <= 7635, using %d\n",
-                                                       DEFAULT_TIMEOUT);
+               pr_info("timeout value must be 15 <= timeout <= 7635, using %d\n",
+                       DEFAULT_TIMEOUT);
        }
 
        if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       IO_INDEX_PORT);
+               pr_err("I/O address 0x%04x already in use\n", IO_INDEX_PORT);
                rc = -EIO;
                goto err_out;
        }
 
        rc = register_reboot_notifier(&wdt_notifier);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", rc);
+               pr_err("cannot register reboot notifier (err=%d)\n", rc);
                goto err_out_region;
        }
 
        rc = misc_register(&wdt_miscdev);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                               wdt_miscdev.minor, rc);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      wdt_miscdev.minor, rc);
                goto err_out_reboot;
        }
 
-       printk(KERN_INFO PFX
-               "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
-                                       timeout, nowayout, testmode);
+       pr_info("initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
+               timeout, nowayout, testmode);
 
        return 0;
 
index c3c3188..25aba6e 100644 (file)
@@ -26,6 +26,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/miscdevice.h>
@@ -65,8 +67,8 @@ MODULE_PARM_DESC(timeout,
                "Watchdog timeout in seconds. 1 <= timeout <= 255, default="
                                __MODULE_STRING(WD_TIMO) ".");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -203,8 +205,7 @@ static int wafwdt_close(struct inode *inode, struct file *file)
        if (expect_close == 42)
                wafwdt_stop();
        else {
-               printk(KERN_CRIT PFX
-                   "WDT device closed unexpectedly.  WDT will not stop!\n");
+               pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
                wafwdt_ping();
        }
        clear_bit(0, &wafwdt_is_open);
@@ -256,49 +257,42 @@ static int __init wafwdt_init(void)
 {
        int ret;
 
-       printk(KERN_INFO
-         "WDT driver for Wafer 5823 single board computer initialising.\n");
+       pr_info("WDT driver for Wafer 5823 single board computer initialising\n");
 
        if (timeout < 1 || timeout > 255) {
                timeout = WD_TIMO;
-               printk(KERN_INFO PFX
-                       "timeout value must be 1 <= x <= 255, using %d\n",
-                                                               timeout);
+               pr_info("timeout value must be 1 <= x <= 255, using %d\n",
+                       timeout);
        }
 
        if (wdt_stop != wdt_start) {
                if (!request_region(wdt_stop, 1, "Wafer 5823 WDT")) {
-                       printk(KERN_ERR PFX
-                               "I/O address 0x%04x already in use\n",
-                                                               wdt_stop);
+                       pr_err("I/O address 0x%04x already in use\n", wdt_stop);
                        ret = -EIO;
                        goto error;
                }
        }
 
        if (!request_region(wdt_start, 1, "Wafer 5823 WDT")) {
-               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       wdt_start);
+               pr_err("I/O address 0x%04x already in use\n", wdt_start);
                ret = -EIO;
                goto error2;
        }
 
        ret = register_reboot_notifier(&wafwdt_notifier);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                goto error3;
        }
 
        ret = misc_register(&wafwdt_miscdev);
        if (ret != 0) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                               WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto error4;
        }
 
-       printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+       pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
                timeout, nowayout);
 
        return ret;
index cfa1a15..14d768b 100644 (file)
@@ -77,7 +77,7 @@ int watchdog_register_device(struct watchdog_device *wdd)
        /* We only support 1 watchdog device via the /dev/watchdog interface */
        ret = watchdog_dev_register(wdd);
        if (ret) {
-               pr_err("error registering /dev/watchdog (err=%d).\n", ret);
+               pr_err("error registering /dev/watchdog (err=%d)\n", ret);
                return ret;
        }
 
@@ -101,7 +101,7 @@ void watchdog_unregister_device(struct watchdog_device *wdd)
 
        ret = watchdog_dev_unregister(wdd);
        if (ret)
-               pr_err("error unregistering /dev/watchdog (err=%d).\n", ret);
+               pr_err("error unregistering /dev/watchdog (err=%d)\n", ret);
 }
 EXPORT_SYMBOL_GPL(watchdog_unregister_device);
 
index 1199da0..8558da9 100644 (file)
@@ -226,7 +226,6 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
                err = wdd->ops->set_timeout(wdd, val);
                if (err < 0)
                        return err;
-               wdd->timeout = val;
                /* If the watchdog is active then we send a keepalive ping
                 * to make sure that the watchdog keep's running (and if
                 * possible that it takes the new timeout) */
@@ -237,6 +236,11 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
                if (wdd->timeout == 0)
                        return -EOPNOTSUPP;
                return put_user(wdd->timeout, p);
+       case WDIOC_GETTIMELEFT:
+               if (!wdd->ops->get_timeleft)
+                       return -EOPNOTSUPP;
+
+               return put_user(wdd->ops->get_timeleft(wdd), p);
        default:
                return -ENOTTY;
        }
@@ -347,7 +351,7 @@ int watchdog_dev_register(struct watchdog_device *watchdog)
 
        /* Only one device can register for /dev/watchdog */
        if (test_and_set_bit(0, &watchdog_dev_busy)) {
-               pr_err("only one watchdog can use /dev/watchdog.\n");
+               pr_err("only one watchdog can use /dev/watchdog\n");
                return -EBUSY;
        }
 
@@ -355,8 +359,8 @@ int watchdog_dev_register(struct watchdog_device *watchdog)
 
        err = misc_register(&watchdog_miscdev);
        if (err != 0) {
-               pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
-                       watchdog->info->identity, WATCHDOG_MINOR, err);
+               pr_err("%s: cannot register miscdev on minor=%d (err=%d)\n",
+                      watchdog->info->identity, WATCHDOG_MINOR, err);
                goto out;
        }
 
@@ -383,8 +387,8 @@ int watchdog_dev_unregister(struct watchdog_device *watchdog)
 
        /* We can only unregister the watchdog device that was registered */
        if (watchdog != wdd) {
-               pr_err("%s: watchdog was not registered as /dev/watchdog.\n",
-                       watchdog->info->identity);
+               pr_err("%s: watchdog was not registered as /dev/watchdog\n",
+                      watchdog->info->identity);
                return -ENODEV;
        }
 
index 94ec22b..0a77655 100644 (file)
@@ -26,6 +26,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -49,7 +51,7 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS_MISCDEV(TEMP_MINOR);
 
-static int wdrtas_nowayout = WATCHDOG_NOWAYOUT;
+static bool wdrtas_nowayout = WATCHDOG_NOWAYOUT;
 static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
 static char wdrtas_expect_close;
 
@@ -93,8 +95,8 @@ static int wdrtas_set_interval(int interval)
        result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
                           WDRTAS_SURVEILLANCE_IND, 0, interval);
        if (result < 0 && print_msg) {
-               printk(KERN_ERR "wdrtas: setting the watchdog to %i "
-                      "timeout failed: %li\n", interval, result);
+               pr_err("setting the watchdog to %i timeout failed: %li\n",
+                      interval, result);
                print_msg--;
        }
 
@@ -128,8 +130,8 @@ static int wdrtas_get_interval(int fallback_value)
        spin_unlock(&rtas_data_buf_lock);
 
        if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) {
-               printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog "
-                      "timeout (%li). Continuing\n", result);
+               pr_warn("could not get sp_spi watchdog timeout (%li). Continuing\n",
+                       result);
                return fallback_value;
        }
 
@@ -170,18 +172,18 @@ static void wdrtas_log_scanned_event(void)
        int i;
 
        for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16)
-               printk(KERN_INFO "wdrtas: dumping event (line %i/%i), data = "
-                      "%02x %02x %02x %02x  %02x %02x %02x %02x   "
-                      "%02x %02x %02x %02x  %02x %02x %02x %02x\n",
-                      (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
-                      wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
-                      wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
-                      wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
-                      wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
-                      wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
-                      wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
-                      wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
-                      wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
+               pr_info("dumping event (line %i/%i), data = "
+                       "%02x %02x %02x %02x  %02x %02x %02x %02x   "
+                       "%02x %02x %02x %02x  %02x %02x %02x %02x\n",
+                       (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
+                       wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
+                       wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
+                       wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
+                       wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
+                       wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
+                       wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
+                       wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
+                       wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
 }
 
 /**
@@ -201,8 +203,7 @@ static void wdrtas_timer_keepalive(void)
                                   (void *)__pa(wdrtas_logbuffer),
                                   WDRTAS_LOGBUFFER_LEN);
                if (result < 0)
-                       printk(KERN_ERR "wdrtas: event-scan failed: %li\n",
-                              result);
+                       pr_err("event-scan failed: %li\n", result);
                if (result == 0)
                        wdrtas_log_scanned_event();
        } while (result == 0);
@@ -224,8 +225,7 @@ static int wdrtas_get_temperature(void)
        result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
 
        if (result < 0)
-               printk(KERN_WARNING "wdrtas: reading the thermal sensor "
-                      "failed: %i\n", result);
+               pr_warn("reading the thermal sensor failed: %i\n", result);
        else
                temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
 
@@ -419,8 +419,7 @@ static int wdrtas_close(struct inode *inode, struct file *file)
        if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
                wdrtas_timer_stop();
        else {
-               printk(KERN_WARNING "wdrtas: got unexpected close. Watchdog "
-                      "not stopped.\n");
+               pr_warn("got unexpected close. Watchdog not stopped.\n");
                wdrtas_timer_keepalive();
        }
 
@@ -552,30 +551,24 @@ static int wdrtas_get_tokens(void)
 {
        wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
        if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
-               printk(KERN_WARNING "wdrtas: couldn't get token for "
-                      "get-sensor-state. Trying to continue without "
-                      "temperature support.\n");
+               pr_warn("couldn't get token for get-sensor-state. Trying to continue without temperature support.\n");
        }
 
        wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter");
        if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) {
-               printk(KERN_WARNING "wdrtas: couldn't get token for "
-                      "ibm,get-system-parameter. Trying to continue with "
-                      "a default timeout value of %i seconds.\n",
-                      WDRTAS_DEFAULT_INTERVAL);
+               pr_warn("couldn't get token for ibm,get-system-parameter. Trying to continue with a default timeout value of %i seconds.\n",
+                       WDRTAS_DEFAULT_INTERVAL);
        }
 
        wdrtas_token_set_indicator = rtas_token("set-indicator");
        if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) {
-               printk(KERN_ERR "wdrtas: couldn't get token for "
-                      "set-indicator. Terminating watchdog code.\n");
+               pr_err("couldn't get token for set-indicator. Terminating watchdog code.\n");
                return -EIO;
        }
 
        wdrtas_token_event_scan = rtas_token("event-scan");
        if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) {
-               printk(KERN_ERR "wdrtas: couldn't get token for event-scan. "
-                      "Terminating watchdog code.\n");
+               pr_err("couldn't get token for event-scan. Terminating watchdog code.\n");
                return -EIO;
        }
 
@@ -609,17 +602,14 @@ static int wdrtas_register_devs(void)
 
        result = misc_register(&wdrtas_miscdev);
        if (result) {
-               printk(KERN_ERR "wdrtas: couldn't register watchdog misc "
-                      "device. Terminating watchdog code.\n");
+               pr_err("couldn't register watchdog misc device. Terminating watchdog code.\n");
                return result;
        }
 
        if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) {
                result = misc_register(&wdrtas_tempdev);
                if (result) {
-                       printk(KERN_WARNING "wdrtas: couldn't register "
-                              "watchdog temperature misc device. Continuing "
-                              "without temperature support.\n");
+                       pr_warn("couldn't register watchdog temperature misc device. Continuing without temperature support.\n");
                        wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE;
                }
        }
@@ -643,8 +633,7 @@ static int __init wdrtas_init(void)
                return -ENODEV;
 
        if (register_reboot_notifier(&wdrtas_notifier)) {
-               printk(KERN_ERR "wdrtas: could not register reboot notifier. "
-                      "Terminating watchdog code.\n");
+               pr_err("could not register reboot notifier. Terminating watchdog code.\n");
                wdrtas_unregister_devs();
                return -ENODEV;
        }
index f3026cd..ee4333c 100644 (file)
@@ -32,6 +32,8 @@
  *             Matt Domsch     :       Added nowayout module option
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -64,8 +66,8 @@ MODULE_PARM_DESC(heartbeat,
        "Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default="
                                __MODULE_STRING(WD_TIMO) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
        "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -251,11 +253,11 @@ static int wdt_get_temperature(void)
 static void wdt_decode_501(int status)
 {
        if (!(status & WDC_SR_TGOOD))
-               printk(KERN_CRIT "Overheat alarm.(%d)\n", inb_p(WDT_RT));
+               pr_crit("Overheat alarm (%d)\n", inb_p(WDT_RT));
        if (!(status & WDC_SR_PSUOVER))
-               printk(KERN_CRIT "PSU over voltage.\n");
+               pr_crit("PSU over voltage\n");
        if (!(status & WDC_SR_PSUUNDR))
-               printk(KERN_CRIT "PSU under voltage.\n");
+               pr_crit("PSU under voltage\n");
 }
 
 /**
@@ -279,25 +281,25 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
        spin_lock(&wdt_lock);
        status = inb_p(WDT_SR);
 
-       printk(KERN_CRIT "WDT status %d\n", status);
+       pr_crit("WDT status %d\n", status);
 
        if (type == 501) {
                wdt_decode_501(status);
                if (tachometer) {
                        if (!(status & WDC_SR_FANGOOD))
-                               printk(KERN_CRIT "Possible fan fault.\n");
+                               pr_crit("Possible fan fault\n");
                }
        }
        if (!(status & WDC_SR_WCCR)) {
 #ifdef SOFTWARE_REBOOT
 #ifdef ONLY_TESTING
-               printk(KERN_CRIT "Would Reboot.\n");
+               pr_crit("Would Reboot\n");
 #else
-               printk(KERN_CRIT "Initiating system reboot.\n");
+               pr_crit("Initiating system reboot\n");
                emergency_restart();
 #endif
 #else
-               printk(KERN_CRIT "Reset in 5ms.\n");
+               pr_crit("Reset in 5ms\n");
 #endif
        }
        spin_unlock(&wdt_lock);
@@ -440,8 +442,7 @@ static int wdt_release(struct inode *inode, struct file *file)
                wdt_stop();
                clear_bit(0, &wdt_is_open);
        } else {
-               printk(KERN_CRIT
-                "wdt: WDT device closed unexpectedly.  WDT will not stop!\n");
+               pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
                wdt_ping();
        }
        expect_close = 0;
@@ -592,7 +593,7 @@ static int __init wdt_init(void)
        int ret;
 
        if (type != 500 && type != 501) {
-               printk(KERN_ERR "wdt: unknown card type '%d'.\n", type);
+               pr_err("unknown card type '%d'\n", type);
                return -ENODEV;
        }
 
@@ -600,53 +601,49 @@ static int __init wdt_init(void)
           if not reset to the default */
        if (wdt_set_heartbeat(heartbeat)) {
                wdt_set_heartbeat(WD_TIMO);
-               printk(KERN_INFO "wdt: heartbeat value must be "
-                       "0 < heartbeat < 65536, using %d\n", WD_TIMO);
+               pr_info("heartbeat value must be 0 < heartbeat < 65536, using %d\n",
+                       WD_TIMO);
        }
 
        if (!request_region(io, 8, "wdt501p")) {
-               printk(KERN_ERR
-                       "wdt: I/O address 0x%04x already in use\n", io);
+               pr_err("I/O address 0x%04x already in use\n", io);
                ret = -EBUSY;
                goto out;
        }
 
        ret = request_irq(irq, wdt_interrupt, 0, "wdt501p", NULL);
        if (ret) {
-               printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq);
+               pr_err("IRQ %d is not free\n", irq);
                goto outreg;
        }
 
        ret = register_reboot_notifier(&wdt_notifier);
        if (ret) {
-               printk(KERN_ERR
-                     "wdt: cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                goto outirq;
        }
 
        if (type == 501) {
                ret = misc_register(&temp_miscdev);
                if (ret) {
-                       printk(KERN_ERR "wdt: cannot register miscdev "
-                               "on minor=%d (err=%d)\n", TEMP_MINOR, ret);
+                       pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                              TEMP_MINOR, ret);
                        goto outrbt;
                }
        }
 
        ret = misc_register(&wdt_miscdev);
        if (ret) {
-               printk(KERN_ERR
-                       "wdt: cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto outmisc;
        }
 
-       printk(KERN_INFO "WDT500/501-P driver 0.10 "
-               "at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
+       pr_info("WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
                io, irq, heartbeat, nowayout);
        if (type == 501)
-               printk(KERN_INFO "wdt: Fan Tachometer is %s\n",
-                               (tachometer ? "Enabled" : "Disabled"));
+               pr_info("Fan Tachometer is %s\n",
+                       tachometer ? "Enabled" : "Disabled");
        return 0;
 
 outmisc:
index 658a36d..5eec740 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -50,7 +52,7 @@ static unsigned long timer_alive;
  */
 static void watchdog_fire(int irq, void *dev_id)
 {
-       printk(KERN_CRIT "Watchdog: Would Reboot.\n");
+       pr_crit("Would Reboot\n");
        *CSR_TIMER4_CNTL = 0;
        *CSR_TIMER4_CLR = 0;
 }
@@ -206,13 +208,11 @@ static int __init footbridge_watchdog_init(void)
        if (retval < 0)
                return retval;
 
-       printk(KERN_INFO
-               "Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
-                                                               soft_margin);
+       pr_info("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
+               soft_margin);
 
        if (machine_is_cats())
-               printk(KERN_WARNING
-                 "Warning: Watchdog reset may not work on this machine.\n");
+               pr_warn("Warning: Watchdog reset may not work on this machine\n");
        return 0;
 }
 
index 855bb0f..65a4023 100644 (file)
@@ -23,6 +23,8 @@
  *                                 Netwinders only
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -41,8 +43,6 @@
 
 #define WATCHDOG_VERSION  "0.04"
 #define WATCHDOG_NAME     "Wdt977"
-#define PFX WATCHDOG_NAME ": "
-#define DRIVER_VERSION    WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
 
 #define IO_INDEX_PORT  0x370           /* on some systems it can be 0x3F0 */
 #define IO_DATA_PORT   (IO_INDEX_PORT + 1)
@@ -67,8 +67,8 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (60..15300, default="
 module_param(testmode, int, 0);
 MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -118,7 +118,7 @@ static int wdt977_start(void)
        outb_p(LOCK_DATA, IO_INDEX_PORT);
 
        spin_unlock_irqrestore(&spinlock, flags);
-       printk(KERN_INFO PFX "activated.\n");
+       pr_info("activated\n");
 
        return 0;
 }
@@ -163,7 +163,7 @@ static int wdt977_stop(void)
        outb_p(LOCK_DATA, IO_INDEX_PORT);
 
        spin_unlock_irqrestore(&spinlock, flags);
-       printk(KERN_INFO PFX "shutdown.\n");
+       pr_info("shutdown\n");
 
        return 0;
 }
@@ -287,8 +287,7 @@ static int wdt977_release(struct inode *inode, struct file *file)
                clear_bit(0, &timer_alive);
        } else {
                wdt977_keepalive();
-               printk(KERN_CRIT PFX
-                       "Unexpected close, not stopping watchdog!\n");
+               pr_crit("Unexpected close, not stopping watchdog!\n");
        }
        expect_close = 0;
        return 0;
@@ -445,15 +444,14 @@ static int __init wd977_init(void)
 {
        int rc;
 
-       printk(KERN_INFO PFX DRIVER_VERSION);
+       pr_info("driver v%s\n", WATCHDOG_VERSION);
 
        /* Check that the timeout value is within its range;
           if not reset to the default */
        if (wdt977_set_timeout(timeout)) {
                wdt977_set_timeout(DEFAULT_TIMEOUT);
-               printk(KERN_INFO PFX
-                     "timeout value must be 60 < timeout < 15300, using %d\n",
-                                                       DEFAULT_TIMEOUT);
+               pr_info("timeout value must be 60 < timeout < 15300, using %d\n",
+                       DEFAULT_TIMEOUT);
        }
 
        /* on Netwinder the IOports are already reserved by
@@ -461,9 +459,8 @@ static int __init wd977_init(void)
         */
        if (!machine_is_netwinder()) {
                if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
-                       printk(KERN_ERR PFX
-                               "I/O address 0x%04x already in use\n",
-                                                               IO_INDEX_PORT);
+                       pr_err("I/O address 0x%04x already in use\n",
+                              IO_INDEX_PORT);
                        rc = -EIO;
                        goto err_out;
                }
@@ -471,22 +468,19 @@ static int __init wd977_init(void)
 
        rc = register_reboot_notifier(&wdt977_notifier);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", rc);
+               pr_err("cannot register reboot notifier (err=%d)\n", rc);
                goto err_out_region;
        }
 
        rc = misc_register(&wdt977_miscdev);
        if (rc) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                               wdt977_miscdev.minor, rc);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      wdt977_miscdev.minor, rc);
                goto err_out_reboot;
        }
 
-       printk(KERN_INFO PFX
-               "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
-                                               timeout, nowayout, testmode);
+       pr_info("initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
+               timeout, nowayout, testmode);
 
        return 0;
 
index fae2567..1c888c7 100644 (file)
@@ -37,6 +37,8 @@
  *             Matt Domsch     :       nowayout module option
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -57,8 +59,6 @@
 #define WDT_IS_PCI
 #include "wd501p.h"
 
-#define PFX "wdt_pci: "
-
 /* We can only use 1 card due to the /dev/watchdog restriction */
 static int dev_count;
 
@@ -79,8 +79,8 @@ MODULE_PARM_DESC(heartbeat,
                "Watchdog heartbeat in seconds. (0<heartbeat<65536, default="
                                __MODULE_STRING(WD_TIMO) ")");
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -311,33 +311,32 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
        status = inb(WDT_SR);
        udelay(8);
 
-       printk(KERN_CRIT PFX "status %d\n", status);
+       pr_crit("status %d\n", status);
 
        if (type == 501) {
                if (!(status & WDC_SR_TGOOD)) {
-                       printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",
-                                                               inb(WDT_RT));
+                       pr_crit("Overheat alarm (%d)\n", inb(WDT_RT));
                        udelay(8);
                }
                if (!(status & WDC_SR_PSUOVER))
-                       printk(KERN_CRIT PFX "PSU over voltage.\n");
+                       pr_crit("PSU over voltage\n");
                if (!(status & WDC_SR_PSUUNDR))
-                       printk(KERN_CRIT PFX "PSU under voltage.\n");
+                       pr_crit("PSU under voltage\n");
                if (tachometer) {
                        if (!(status & WDC_SR_FANGOOD))
-                               printk(KERN_CRIT PFX "Possible fan fault.\n");
+                               pr_crit("Possible fan fault\n");
                }
        }
        if (!(status & WDC_SR_WCCR)) {
 #ifdef SOFTWARE_REBOOT
 #ifdef ONLY_TESTING
-               printk(KERN_CRIT PFX "Would Reboot.\n");
+               pr_crit("Would Reboot\n");
 #else
-               printk(KERN_CRIT PFX "Initiating system reboot.\n");
+               pr_crit("Initiating system reboot\n");
                emergency_restart(NULL);
 #endif
 #else
-               printk(KERN_CRIT PFX "Reset in 5ms.\n");
+               pr_crit("Reset in 5ms\n");
 #endif
        }
        spin_unlock(&wdtpci_lock);
@@ -483,7 +482,7 @@ static int wdtpci_release(struct inode *inode, struct file *file)
        if (expect_close == 42) {
                wdtpci_stop();
        } else {
-               printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
+               pr_crit("Unexpected close, not stopping timer!\n");
                wdtpci_ping();
        }
        expect_close = 0;
@@ -613,29 +612,29 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
 
        dev_count++;
        if (dev_count > 1) {
-               printk(KERN_ERR PFX "This driver only supports one device\n");
+               pr_err("This driver only supports one device\n");
                return -ENODEV;
        }
 
        if (type != 500 && type != 501) {
-               printk(KERN_ERR PFX "unknown card type '%d'.\n", type);
+               pr_err("unknown card type '%d'\n", type);
                return -ENODEV;
        }
 
        if (pci_enable_device(dev)) {
-               printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
+               pr_err("Not possible to enable PCI Device\n");
                return -ENODEV;
        }
 
        if (pci_resource_start(dev, 2) == 0x0000) {
-               printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+               pr_err("No I/O-Address for card detected\n");
                ret = -ENODEV;
                goto out_pci;
        }
 
        if (pci_request_region(dev, 2, "wdt_pci")) {
-               printk(KERN_ERR PFX "I/O address 0x%llx already in use\n",
-                       (unsigned long long)pci_resource_start(dev, 2));
+               pr_err("I/O address 0x%llx already in use\n",
+                      (unsigned long long)pci_resource_start(dev, 2));
                goto out_pci;
        }
 
@@ -644,53 +643,48 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
 
        if (request_irq(irq, wdtpci_interrupt, IRQF_SHARED,
                         "wdt_pci", &wdtpci_miscdev)) {
-               printk(KERN_ERR PFX "IRQ %d is not free\n", irq);
+               pr_err("IRQ %d is not free\n", irq);
                goto out_reg;
        }
 
-       printk(KERN_INFO
-        "PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%llx (Interrupt %d)\n",
-                                       (unsigned long long)io, irq);
+       pr_info("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%llx (Interrupt %d)\n",
+               (unsigned long long)io, irq);
 
        /* Check that the heartbeat value is within its range;
           if not reset to the default */
        if (wdtpci_set_heartbeat(heartbeat)) {
                wdtpci_set_heartbeat(WD_TIMO);
-               printk(KERN_INFO PFX
-                 "heartbeat value must be 0 < heartbeat < 65536, using %d\n",
-                                                               WD_TIMO);
+               pr_info("heartbeat value must be 0 < heartbeat < 65536, using %d\n",
+                       WD_TIMO);
        }
 
        ret = register_reboot_notifier(&wdtpci_notifier);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "cannot register reboot notifier (err=%d)\n", ret);
+               pr_err("cannot register reboot notifier (err=%d)\n", ret);
                goto out_irq;
        }
 
        if (type == 501) {
                ret = misc_register(&temp_miscdev);
                if (ret) {
-                       printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       TEMP_MINOR, ret);
+                       pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                              TEMP_MINOR, ret);
                        goto out_rbt;
                }
        }
 
        ret = misc_register(&wdtpci_miscdev);
        if (ret) {
-               printk(KERN_ERR PFX
-                       "cannot register miscdev on minor=%d (err=%d)\n",
-                                               WATCHDOG_MINOR, ret);
+               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
+                      WATCHDOG_MINOR, ret);
                goto out_misc;
        }
 
-       printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+       pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
                heartbeat, nowayout);
        if (type == 501)
-               printk(KERN_INFO "wdt: Fan Tachometer is %s\n",
-                               (tachometer ? "Enabled" : "Disabled"));
+               pr_info("Fan Tachometer is %s\n",
+                       tachometer ? "Enabled" : "Disabled");
 
        ret = 0;
 out:
index 263c883..b1815c5 100644 (file)
@@ -22,8 +22,8 @@
 #include <linux/mfd/wm831x/pdata.h>
 #include <linux/mfd/wm831x/watchdog.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                 "Watchdog cannot be stopped once started (default="
                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
@@ -163,6 +163,8 @@ static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev,
                        ret);
        }
 
+       wdt_dev->timeout = timeout;
+
        return ret;
 }
 
index 5d7113c..3c76693 100644 (file)
@@ -8,63 +8,65 @@
  * as published by the Free Software Foundation
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 #include <linux/uaccess.h>
 #include <linux/mfd/wm8350/core.h>
 
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
                 "Watchdog cannot be stopped once started (default="
                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-static unsigned long wm8350_wdt_users;
-static struct miscdevice wm8350_wdt_miscdev;
-static int wm8350_wdt_expect_close;
 static DEFINE_MUTEX(wdt_mutex);
 
 static struct {
-       int time;  /* Seconds */
-       u16 val;   /* To be set in WM8350_SYSTEM_CONTROL_2 */
+       unsigned int time;  /* Seconds */
+       u16 val;            /* To be set in WM8350_SYSTEM_CONTROL_2 */
 } wm8350_wdt_cfgs[] = {
        { 1, 0x02 },
        { 2, 0x04 },
        { 4, 0x05 },
 };
 
-static struct wm8350 *get_wm8350(void)
-{
-       return dev_get_drvdata(wm8350_wdt_miscdev.parent);
-}
-
-static int wm8350_wdt_set_timeout(struct wm8350 *wm8350, u16 value)
+static int wm8350_wdt_set_timeout(struct watchdog_device *wdt_dev,
+                                 unsigned int timeout)
 {
-       int ret;
+       struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
+       int ret, i;
        u16 reg;
 
+       for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
+               if (wm8350_wdt_cfgs[i].time == timeout)
+                       break;
+       if (i == ARRAY_SIZE(wm8350_wdt_cfgs))
+               return -EINVAL;
+
        mutex_lock(&wdt_mutex);
        wm8350_reg_unlock(wm8350);
 
        reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
        reg &= ~WM8350_WDOG_TO_MASK;
-       reg |= value;
+       reg |= wm8350_wdt_cfgs[i].val;
        ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);
 
        wm8350_reg_lock(wm8350);
        mutex_unlock(&wdt_mutex);
 
+       wdt_dev->timeout = timeout;
        return ret;
 }
 
-static int wm8350_wdt_start(struct wm8350 *wm8350)
+static int wm8350_wdt_start(struct watchdog_device *wdt_dev)
 {
+       struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
        int ret;
        u16 reg;
 
@@ -82,8 +84,9 @@ static int wm8350_wdt_start(struct wm8350 *wm8350)
        return ret;
 }
 
-static int wm8350_wdt_stop(struct wm8350 *wm8350)
+static int wm8350_wdt_stop(struct watchdog_device *wdt_dev)
 {
+       struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
        int ret;
        u16 reg;
 
@@ -100,8 +103,9 @@ static int wm8350_wdt_stop(struct wm8350 *wm8350)
        return ret;
 }
 
-static int wm8350_wdt_kick(struct wm8350 *wm8350)
+static int wm8350_wdt_ping(struct watchdog_device *wdt_dev)
 {
+       struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
        int ret;
        u16 reg;
 
@@ -115,168 +119,25 @@ static int wm8350_wdt_kick(struct wm8350 *wm8350)
        return ret;
 }
 
-static int wm8350_wdt_open(struct inode *inode, struct file *file)
-{
-       struct wm8350 *wm8350 = get_wm8350();
-       int ret;
-
-       if (!wm8350)
-               return -ENODEV;
-
-       if (test_and_set_bit(0, &wm8350_wdt_users))
-               return -EBUSY;
-
-       ret = wm8350_wdt_start(wm8350);
-       if (ret != 0)
-               return ret;
-
-       return nonseekable_open(inode, file);
-}
-
-static int wm8350_wdt_release(struct inode *inode, struct file *file)
-{
-       struct wm8350 *wm8350 = get_wm8350();
-
-       if (wm8350_wdt_expect_close)
-               wm8350_wdt_stop(wm8350);
-       else {
-               dev_warn(wm8350->dev, "Watchdog device closed uncleanly\n");
-               wm8350_wdt_kick(wm8350);
-       }
-
-       clear_bit(0, &wm8350_wdt_users);
-
-       return 0;
-}
-
-static ssize_t wm8350_wdt_write(struct file *file,
-                               const char __user *data, size_t count,
-                               loff_t *ppos)
-{
-       struct wm8350 *wm8350 = get_wm8350();
-       size_t i;
-
-       if (count) {
-               wm8350_wdt_kick(wm8350);
-
-               if (!nowayout) {
-                       /* In case it was set long ago */
-                       wm8350_wdt_expect_close = 0;
-
-                       /* scan to see whether or not we got the magic
-                          character */
-                       for (i = 0; i != count; i++) {
-                               char c;
-                               if (get_user(c, data + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       wm8350_wdt_expect_close = 42;
-                       }
-               }
-       }
-       return count;
-}
-
-static const struct watchdog_info ident = {
+static const struct watchdog_info wm8350_wdt_info = {
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
        .identity = "WM8350 Watchdog",
 };
 
-static long wm8350_wdt_ioctl(struct file *file, unsigned int cmd,
-                            unsigned long arg)
-{
-       struct wm8350 *wm8350 = get_wm8350();
-       int ret = -ENOTTY, time, i;
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       u16 reg;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(0, p);
-               break;
-
-       case WDIOC_SETOPTIONS:
-       {
-               int options;
-
-               if (get_user(options, p))
-                       return -EFAULT;
-
-               ret = -EINVAL;
-
-               /* Setting both simultaneously means at least one must fail */
-               if (options == WDIOS_DISABLECARD)
-                       ret = wm8350_wdt_stop(wm8350);
-
-               if (options == WDIOS_ENABLECARD)
-                       ret = wm8350_wdt_start(wm8350);
-               break;
-       }
-
-       case WDIOC_KEEPALIVE:
-               ret = wm8350_wdt_kick(wm8350);
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               ret = get_user(time, p);
-               if (ret)
-                       break;
-
-               if (time == 0) {
-                       if (nowayout)
-                               ret = -EINVAL;
-                       else
-                               wm8350_wdt_stop(wm8350);
-                       break;
-               }
-
-               for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
-                       if (wm8350_wdt_cfgs[i].time == time)
-                               break;
-               if (i == ARRAY_SIZE(wm8350_wdt_cfgs))
-                       ret = -EINVAL;
-               else
-                       ret = wm8350_wdt_set_timeout(wm8350,
-                                                    wm8350_wdt_cfgs[i].val);
-               break;
-
-       case WDIOC_GETTIMEOUT:
-               reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
-               reg &= WM8350_WDOG_TO_MASK;
-               for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
-                       if (wm8350_wdt_cfgs[i].val == reg)
-                               break;
-               if (i == ARRAY_SIZE(wm8350_wdt_cfgs)) {
-                       dev_warn(wm8350->dev,
-                                "Unknown watchdog configuration: %x\n", reg);
-                       ret = -EINVAL;
-               } else
-                       ret = put_user(wm8350_wdt_cfgs[i].time, p);
-
-       }
-
-       return ret;
-}
-
-static const struct file_operations wm8350_wdt_fops = {
+static const struct watchdog_ops wm8350_wdt_ops = {
        .owner = THIS_MODULE,
-       .llseek = no_llseek,
-       .write = wm8350_wdt_write,
-       .unlocked_ioctl = wm8350_wdt_ioctl,
-       .open = wm8350_wdt_open,
-       .release = wm8350_wdt_release,
+       .start = wm8350_wdt_start,
+       .stop = wm8350_wdt_stop,
+       .ping = wm8350_wdt_ping,
+       .set_timeout = wm8350_wdt_set_timeout,
 };
 
-static struct miscdevice wm8350_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &wm8350_wdt_fops,
+static struct watchdog_device wm8350_wdt = {
+       .info = &wm8350_wdt_info,
+       .ops = &wm8350_wdt_ops,
+       .timeout = 4,
+       .min_timeout = 1,
+       .max_timeout = 4,
 };
 
 static int __devinit wm8350_wdt_probe(struct platform_device *pdev)
@@ -288,18 +149,18 @@ static int __devinit wm8350_wdt_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       /* Default to 4s timeout */
-       wm8350_wdt_set_timeout(wm8350, 0x05);
+       watchdog_set_nowayout(&wm8350_wdt, nowayout);
+       watchdog_set_drvdata(&wm8350_wdt, wm8350);
 
-       wm8350_wdt_miscdev.parent = &pdev->dev;
+       /* Default to 4s timeout */
+       wm8350_wdt_set_timeout(&wm8350_wdt, 4);
 
-       return misc_register(&wm8350_wdt_miscdev);
+       return watchdog_register_device(&wm8350_wdt);
 }
 
 static int __devexit wm8350_wdt_remove(struct platform_device *pdev)
 {
-       misc_deregister(&wm8350_wdt_miscdev);
-
+       watchdog_unregister_device(&wm8350_wdt);
        return 0;
 }
 
index 49bd9d3..e4a25b5 100644 (file)
@@ -9,9 +9,10 @@
  *     2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DRV_NAME       "wdt"
 #define DRV_VERSION    "0.01"
-#define PFX            DRV_NAME ": "
 
 #include <linux/bug.h>
 #include <linux/errno.h>
@@ -131,16 +132,17 @@ static int xen_wdt_open(struct inode *inode, struct file *file)
 
 static int xen_wdt_release(struct inode *inode, struct file *file)
 {
+       int err = 0;
+
        if (expect_release)
-               xen_wdt_stop();
+               err = xen_wdt_stop();
        else {
-               printk(KERN_CRIT PFX
-                      "unexpected close, not stopping watchdog!\n");
+               pr_crit("unexpected close, not stopping watchdog!\n");
                xen_wdt_kick();
        }
-       is_active = false;
+       is_active = err;
        expect_release = false;
-       return 0;
+       return err;
 }
 
 static ssize_t xen_wdt_write(struct file *file, const char __user *data,
@@ -251,30 +253,27 @@ static int __devinit xen_wdt_probe(struct platform_device *dev)
        case -EINVAL:
                if (!timeout) {
                        timeout = WATCHDOG_TIMEOUT;
-                       printk(KERN_INFO PFX
-                              "timeout value invalid, using %d\n", timeout);
+                       pr_info("timeout value invalid, using %d\n", timeout);
                }
 
                ret = misc_register(&xen_wdt_miscdev);
                if (ret) {
-                       printk(KERN_ERR PFX
-                              "cannot register miscdev on minor=%d (%d)\n",
+                       pr_err("cannot register miscdev on minor=%d (%d)\n",
                               WATCHDOG_MINOR, ret);
                        break;
                }
 
-               printk(KERN_INFO PFX
-                      "initialized (timeout=%ds, nowayout=%d)\n",
-                      timeout, nowayout);
+               pr_info("initialized (timeout=%ds, nowayout=%d)\n",
+                       timeout, nowayout);
                break;
 
        case -ENOSYS:
-               printk(KERN_INFO PFX "not supported\n");
+               pr_info("not supported\n");
                ret = -ENODEV;
                break;
 
        default:
-               printk(KERN_INFO PFX "bogus return value %d\n", ret);
+               pr_info("bogus return value %d\n", ret);
                break;
        }
 
@@ -299,11 +298,18 @@ static void xen_wdt_shutdown(struct platform_device *dev)
 
 static int xen_wdt_suspend(struct platform_device *dev, pm_message_t state)
 {
-       return xen_wdt_stop();
+       typeof(wdt.id) id = wdt.id;
+       int rc = xen_wdt_stop();
+
+       wdt.id = id;
+       return rc;
 }
 
 static int xen_wdt_resume(struct platform_device *dev)
 {
+       if (!wdt.id)
+               return 0;
+       wdt.id = 0;
        return xen_wdt_start();
 }
 
@@ -326,7 +332,7 @@ static int __init xen_wdt_init_module(void)
        if (!xen_domain())
                return -ENODEV;
 
-       printk(KERN_INFO PFX "Xen WatchDog Timer Driver v%s\n", DRV_VERSION);
+       pr_info("Xen WatchDog Timer Driver v%s\n", DRV_VERSION);
 
        err = platform_driver_register(&xen_wdt_driver);
        if (err)
@@ -346,7 +352,7 @@ static void __exit xen_wdt_cleanup_module(void)
 {
        platform_device_unregister(platform_device);
        platform_driver_unregister(&xen_wdt_driver);
-       printk(KERN_INFO PFX "module unloaded\n");
+       pr_info("module unloaded\n");
 }
 
 module_init(xen_wdt_init_module);
index 648bcd4..9424313 100644 (file)
@@ -180,9 +180,8 @@ config XEN_PRIVCMD
 
 config XEN_ACPI_PROCESSOR
        tristate "Xen ACPI processor"
-       depends on XEN && X86 && ACPI_PROCESSOR
-       default y if (X86_ACPI_CPUFREQ = y || X86_POWERNOW_K8 = y)
-       default m if (X86_ACPI_CPUFREQ = m || X86_POWERNOW_K8 = m)
+       depends on XEN && X86 && ACPI_PROCESSOR && CPU_FREQ
+       default m
        help
           This ACPI processor uploads Power Management information to the Xen hypervisor.
 
index e5e5812..4b33acd 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/idle.h>
 #include <asm/io_apic.h>
 #include <asm/sync_bitops.h>
+#include <asm/xen/page.h>
 #include <asm/xen/pci.h>
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
@@ -109,6 +110,8 @@ struct irq_info {
 #define PIRQ_SHAREABLE (1 << 1)
 
 static int *evtchn_to_irq;
+static unsigned long *pirq_eoi_map;
+static bool (*pirq_needs_eoi)(unsigned irq);
 
 static DEFINE_PER_CPU(unsigned long [NR_EVENT_CHANNELS/BITS_PER_LONG],
                      cpu_evtchn_mask);
@@ -269,10 +272,14 @@ static unsigned int cpu_from_evtchn(unsigned int evtchn)
        return ret;
 }
 
-static bool pirq_needs_eoi(unsigned irq)
+static bool pirq_check_eoi_map(unsigned irq)
 {
-       struct irq_info *info = info_for_irq(irq);
+       return test_bit(irq, pirq_eoi_map);
+}
 
+static bool pirq_needs_eoi_flag(unsigned irq)
+{
+       struct irq_info *info = info_for_irq(irq);
        BUG_ON(info->type != IRQT_PIRQ);
 
        return info->u.pirq.flags & PIRQ_NEEDS_EOI;
@@ -1768,7 +1775,7 @@ void xen_callback_vector(void) {}
 
 void __init xen_init_IRQ(void)
 {
-       int i;
+       int i, rc;
 
        evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq),
                                    GFP_KERNEL);
@@ -1782,6 +1789,8 @@ void __init xen_init_IRQ(void)
        for (i = 0; i < NR_EVENT_CHANNELS; i++)
                mask_evtchn(i);
 
+       pirq_needs_eoi = pirq_needs_eoi_flag;
+
        if (xen_hvm_domain()) {
                xen_callback_vector();
                native_init_IRQ();
@@ -1789,8 +1798,19 @@ void __init xen_init_IRQ(void)
                 * __acpi_register_gsi can point at the right function */
                pci_xen_hvm_init();
        } else {
+               struct physdev_pirq_eoi_gmfn eoi_gmfn;
+
                irq_ctx_init(smp_processor_id());
                if (xen_initial_domain())
                        pci_xen_initial_domain();
+
+               pirq_eoi_map = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
+               eoi_gmfn.gmfn = virt_to_mfn(pirq_eoi_map);
+               rc = HYPERVISOR_physdev_op(PHYSDEVOP_pirq_eoi_gmfn_v2, &eoi_gmfn);
+               if (rc != 0) {
+                       free_page((unsigned long) pirq_eoi_map);
+                       pirq_eoi_map = NULL;
+               } else
+                       pirq_needs_eoi = pirq_check_eoi_map;
        }
 }
index 319dd0a..2389e58 100644 (file)
@@ -186,11 +186,6 @@ static struct pci_driver platform_driver = {
 
 static int __init platform_pci_module_init(void)
 {
-       /* no unplug has been done, IGNORE hasn't been specified: just
-        * return now */
-       if (!xen_platform_pci_unplug)
-               return -ENODEV;
-
        return pci_register_driver(&platform_driver);
 }
 
index 17d9e37..dcb7952 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/pagemap.h>
-#include <linux/module.h>
 #include <linux/cleancache.h>
 
 /* temporary ifdef until include/linux/frontswap.h is upstream */
@@ -128,15 +127,13 @@ static int xen_tmem_flush_object(u32 pool_id, struct tmem_oid oid)
        return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, oid, 0, 0, 0, 0, 0);
 }
 
-int tmem_enabled __read_mostly;
-EXPORT_SYMBOL(tmem_enabled);
+bool __read_mostly tmem_enabled = false;
 
 static int __init enable_tmem(char *s)
 {
-       tmem_enabled = 1;
+       tmem_enabled = true;
        return 1;
 }
-
 __setup("tmem", enable_tmem);
 
 #ifdef CONFIG_CLEANCACHE
@@ -229,17 +226,16 @@ static int tmem_cleancache_init_shared_fs(char *uuid, size_t pagesize)
        return xen_tmem_new_pool(shared_uuid, TMEM_POOL_SHARED, pagesize);
 }
 
-static int use_cleancache = 1;
+static bool __initdata use_cleancache = true;
 
 static int __init no_cleancache(char *s)
 {
-       use_cleancache = 0;
+       use_cleancache = false;
        return 1;
 }
-
 __setup("nocleancache", no_cleancache);
 
-static struct cleancache_ops tmem_cleancache_ops = {
+static struct cleancache_ops __initdata tmem_cleancache_ops = {
        .put_page = tmem_cleancache_put_page,
        .get_page = tmem_cleancache_get_page,
        .invalidate_page = tmem_cleancache_flush_page,
@@ -356,17 +352,16 @@ static void tmem_frontswap_init(unsigned ignored)
                    xen_tmem_new_pool(private, TMEM_POOL_PERSIST, PAGE_SIZE);
 }
 
-static int __initdata use_frontswap = 1;
+static bool __initdata use_frontswap = true;
 
 static int __init no_frontswap(char *s)
 {
-       use_frontswap = 0;
+       use_frontswap = false;
        return 1;
 }
-
 __setup("nofrontswap", no_frontswap);
 
-static struct frontswap_ops tmem_frontswap_ops = {
+static struct frontswap_ops __initdata tmem_frontswap_ops = {
        .put_page = tmem_frontswap_put_page,
        .get_page = tmem_frontswap_get_page,
        .invalidate_page = tmem_frontswap_flush_page,
index 5c2be96..174b565 100644 (file)
@@ -501,11 +501,11 @@ static int __init xen_acpi_processor_init(void)
 
                perf = per_cpu_ptr(acpi_perf_data, i);
                rc = acpi_processor_register_performance(perf, i);
-               if (WARN_ON(rc))
+               if (rc)
                        goto err_out;
        }
        rc = acpi_processor_notify_smm(THIS_MODULE);
-       if (WARN_ON(rc))
+       if (rc)
                goto err_unregister;
 
        for_each_possible_cpu(i) {
index 10b7d3c..8c92a9b 100644 (file)
@@ -259,7 +259,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
        if (v9fs_proto_dotl(v9ses)) {
                res = p9_client_statfs(fid, &rs);
                if (res == 0) {
-                       buf->f_type = V9FS_MAGIC;
+                       buf->f_type = rs.type;
                        buf->f_bsize = rs.bsize;
                        buf->f_blocks = rs.blocks;
                        buf->f_bfree = rs.bfree;
index c7acaf3..4f71627 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -13,7 +13,7 @@
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/aio_abi.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/syscalls.h>
 #include <linux/backing-dev.h>
 #include <linux/uio.h>
index 95053ad..73f69a6 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -5,7 +5,7 @@
  *  changes by Thomas Schoebel-Theuer
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/string.h>
index 22e9a78..37268c5 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 #include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/stat.h>
 #include <linux/time.h>
 #include <linux/namei.h>
index 1827653..7d7ff20 100644 (file)
@@ -1094,6 +1094,29 @@ out:
  */
 
 /*
+ * The purpose of always_dump_vma() is to make sure that special kernel mappings
+ * that are useful for post-mortem analysis are included in every core dump.
+ * In that way we ensure that the core dump is fully interpretable later
+ * without matching up the same kernel and hardware config to see what PC values
+ * meant. These special mappings include - vDSO, vsyscall, and other
+ * architecture specific mappings
+ */
+static bool always_dump_vma(struct vm_area_struct *vma)
+{
+       /* Any vsyscall mappings? */
+       if (vma == get_gate_vma(vma->vm_mm))
+               return true;
+       /*
+        * arch_vma_name() returns non-NULL for special architecture mappings,
+        * such as vDSO sections.
+        */
+       if (arch_vma_name(vma))
+               return true;
+
+       return false;
+}
+
+/*
  * Decide what to dump of a segment, part, all or none.
  */
 static unsigned long vma_dump_size(struct vm_area_struct *vma,
@@ -1101,10 +1124,13 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
 {
 #define FILTER(type)   (mm_flags & (1UL << MMF_DUMP_##type))
 
-       /* The vma can be set up to tell us the answer directly.  */
-       if (vma->vm_flags & VM_ALWAYSDUMP)
+       /* always dump the vdso and vsyscall sections */
+       if (always_dump_vma(vma))
                goto whole;
 
+       if (vma->vm_flags & VM_NODUMP)
+               return 0;
+
        /* Hugetlb memory check */
        if (vma->vm_flags & VM_HUGETLB) {
                if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED))
index 4e4017c..024d20e 100644 (file)
@@ -15,7 +15,7 @@
  *     JAN/99 -- coded full program relocation (gerg@snapgear.com)
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
index 1ffb603..613aa06 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/magic.h>
 #include <linux/binfmts.h>
 #include <linux/slab.h>
 #include <linux/ctype.h>
@@ -699,7 +700,7 @@ static int bm_fill_super(struct super_block * sb, void * data, int silent)
                [3] = {"register", &bm_register_operations, S_IWUSR},
                /* last one */ {""}
        };
-       int err = simple_fill_super(sb, 0x42494e4d, bm_files);
+       int err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files);
        if (!err)
                sb->s_op = &s_ops;
        return err;
index b980ecd..e453924 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -22,7 +22,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
 #include <scsi/sg.h>           /* for struct sg_iovec */
index a9ff300..e08f6a2 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/blkdev.h>
 #include <linux/module.h>
 #include <linux/blkpg.h>
+#include <linux/magic.h>
 #include <linux/buffer_head.h>
 #include <linux/swap.h>
 #include <linux/pagevec.h>
@@ -506,7 +507,7 @@ static const struct super_operations bdev_sops = {
 static struct dentry *bd_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
-       return mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, 0x62646576);
+       return mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, BDEVFS_MAGIC);
 }
 
 static struct file_system_type bd_type = {
index 1a30db7..70e2017 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/file.h>
 #include <linux/quotaops.h>
 #include <linux/highmem.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/writeback.h>
 #include <linux/hash.h>
 #include <linux/suspend.h>
index 2c48937..9fff9f3 100644 (file)
@@ -677,18 +677,19 @@ static int fill_inode(struct inode *inode,
        case S_IFLNK:
                inode->i_op = &ceph_symlink_iops;
                if (!ci->i_symlink) {
-                       int symlen = iinfo->symlink_len;
+                       u32 symlen = iinfo->symlink_len;
                        char *sym;
 
-                       BUG_ON(symlen != inode->i_size);
                        spin_unlock(&ci->i_ceph_lock);
 
+                       err = -EINVAL;
+                       if (WARN_ON(symlen != inode->i_size))
+                               goto out;
+
                        err = -ENOMEM;
-                       sym = kmalloc(symlen+1, GFP_NOFS);
+                       sym = kstrndup(iinfo->symlink, symlen, GFP_NOFS);
                        if (!sym)
                                goto out;
-                       memcpy(sym, iinfo->symlink, symlen);
-                       sym[symlen] = 0;
 
                        spin_lock(&ci->i_ceph_lock);
                        if (!ci->i_symlink)
index 866e8d7..89971e1 100644 (file)
@@ -402,7 +402,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
 
        spin_lock_init(&s->s_gen_ttl_lock);
        s->s_cap_gen = 0;
-       s->s_cap_ttl = 0;
+       s->s_cap_ttl = jiffies - 1;
 
        spin_lock_init(&s->s_cap_lock);
        s->s_renew_requested = 0;
@@ -1083,8 +1083,7 @@ static void renewed_caps(struct ceph_mds_client *mdsc,
        int wake = 0;
 
        spin_lock(&session->s_cap_lock);
-       was_stale = is_renew && (session->s_cap_ttl == 0 ||
-                                time_after_eq(jiffies, session->s_cap_ttl));
+       was_stale = is_renew && time_after_eq(jiffies, session->s_cap_ttl);
 
        session->s_cap_ttl = session->s_renew_requested +
                mdsc->mdsmap->m_session_timeout*HZ;
@@ -2332,7 +2331,7 @@ static void handle_session(struct ceph_mds_session *session,
                        session->s_mds);
                spin_lock(&session->s_gen_ttl_lock);
                session->s_cap_gen++;
-               session->s_cap_ttl = 0;
+               session->s_cap_ttl = jiffies - 1;
                spin_unlock(&session->s_gen_ttl_lock);
                send_renew_caps(mdsc, session);
                break;
index a559c80..f04c096 100644 (file)
@@ -331,7 +331,7 @@ static int build_snap_context(struct ceph_snap_realm *realm)
 
        /* alloc new snap context */
        err = -ENOMEM;
-       if (num > ULONG_MAX / sizeof(u64) - sizeof(*snapc))
+       if (num > (ULONG_MAX - sizeof(*snapc)) / sizeof(u64))
                goto fail;
        snapc = kzalloc(sizeof(*snapc) + num*sizeof(u64), GFP_NOFS);
        if (!snapc)
index 256f852..1e67dd7 100644 (file)
@@ -130,10 +130,12 @@ enum {
        Opt_nodirstat,
        Opt_rbytes,
        Opt_norbytes,
+       Opt_asyncreaddir,
        Opt_noasyncreaddir,
        Opt_dcache,
        Opt_nodcache,
        Opt_ino32,
+       Opt_noino32,
 };
 
 static match_table_t fsopt_tokens = {
@@ -153,10 +155,12 @@ static match_table_t fsopt_tokens = {
        {Opt_nodirstat, "nodirstat"},
        {Opt_rbytes, "rbytes"},
        {Opt_norbytes, "norbytes"},
+       {Opt_asyncreaddir, "asyncreaddir"},
        {Opt_noasyncreaddir, "noasyncreaddir"},
        {Opt_dcache, "dcache"},
        {Opt_nodcache, "nodcache"},
        {Opt_ino32, "ino32"},
+       {Opt_noino32, "noino32"},
        {-1, NULL}
 };
 
@@ -232,6 +236,9 @@ static int parse_fsopt_token(char *c, void *private)
        case Opt_norbytes:
                fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES;
                break;
+       case Opt_asyncreaddir:
+               fsopt->flags &= ~CEPH_MOUNT_OPT_NOASYNCREADDIR;
+               break;
        case Opt_noasyncreaddir:
                fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
                break;
@@ -244,6 +251,9 @@ static int parse_fsopt_token(char *c, void *private)
        case Opt_ino32:
                fsopt->flags |= CEPH_MOUNT_OPT_INO32;
                break;
+       case Opt_noino32:
+               fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
+               break;
        default:
                BUG_ON(token);
        }
@@ -334,10 +344,12 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
        *path += 2;
        dout("server path '%s'\n", *path);
 
-       err = ceph_parse_options(popt, options, dev_name, dev_name_end,
+       *popt = ceph_parse_options(options, dev_name, dev_name_end,
                                 parse_fsopt_token, (void *)fsopt);
-       if (err)
+       if (IS_ERR(*popt)) {
+               err = PTR_ERR(*popt);
                goto out;
+       }
 
        /* success */
        *pfsopt = fsopt;
@@ -926,6 +938,7 @@ static int __init init_ceph(void)
        if (ret)
                goto out;
 
+       ceph_xattr_init();
        ret = register_filesystem(&ceph_fs_type);
        if (ret)
                goto out_icache;
@@ -935,6 +948,7 @@ static int __init init_ceph(void)
        return 0;
 
 out_icache:
+       ceph_xattr_exit();
        destroy_caches();
 out:
        return ret;
@@ -944,6 +958,7 @@ static void __exit exit_ceph(void)
 {
        dout("exit_ceph\n");
        unregister_filesystem(&ceph_fs_type);
+       ceph_xattr_exit();
        destroy_caches();
 }
 
index 1421f3d..fc35036 100644 (file)
@@ -367,7 +367,7 @@ static inline u32 ceph_ino_to_ino32(__u64 vino)
        u32 ino = vino & 0xffffffff;
        ino ^= vino >> 32;
        if (!ino)
-               ino = 1;
+               ino = 2;
        return ino;
 }
 
@@ -733,6 +733,8 @@ extern ssize_t ceph_listxattr(struct dentry *, char *, size_t);
 extern int ceph_removexattr(struct dentry *, const char *);
 extern void __ceph_build_xattrs_blob(struct ceph_inode_info *ci);
 extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci);
+extern void __init ceph_xattr_init(void);
+extern void ceph_xattr_exit(void);
 
 /* caps.c */
 extern const char *ceph_cap_string(int c);
index a76f697..35b8633 100644 (file)
@@ -8,9 +8,12 @@
 #include <linux/xattr.h>
 #include <linux/slab.h>
 
+#define XATTR_CEPH_PREFIX "ceph."
+#define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1)
+
 static bool ceph_is_valid_xattr(const char *name)
 {
-       return !strncmp(name, "ceph.", 5) ||
+       return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) ||
               !strncmp(name, XATTR_SECURITY_PREFIX,
                        XATTR_SECURITY_PREFIX_LEN) ||
               !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
@@ -21,79 +24,91 @@ static bool ceph_is_valid_xattr(const char *name)
  * These define virtual xattrs exposing the recursive directory
  * statistics and layout metadata.
  */
-struct ceph_vxattr_cb {
-       bool readonly;
+struct ceph_vxattr {
        char *name;
+       size_t name_size;       /* strlen(name) + 1 (for '\0') */
        size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
                              size_t size);
+       bool readonly;
 };
 
 /* directories */
 
-static size_t ceph_vxattrcb_entries(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val,
                                        size_t size)
 {
        return snprintf(val, size, "%lld", ci->i_files + ci->i_subdirs);
 }
 
-static size_t ceph_vxattrcb_files(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_files(struct ceph_inode_info *ci, char *val,
                                      size_t size)
 {
        return snprintf(val, size, "%lld", ci->i_files);
 }
 
-static size_t ceph_vxattrcb_subdirs(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_subdirs(struct ceph_inode_info *ci, char *val,
                                        size_t size)
 {
        return snprintf(val, size, "%lld", ci->i_subdirs);
 }
 
-static size_t ceph_vxattrcb_rentries(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_rentries(struct ceph_inode_info *ci, char *val,
                                         size_t size)
 {
        return snprintf(val, size, "%lld", ci->i_rfiles + ci->i_rsubdirs);
 }
 
-static size_t ceph_vxattrcb_rfiles(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_rfiles(struct ceph_inode_info *ci, char *val,
                                       size_t size)
 {
        return snprintf(val, size, "%lld", ci->i_rfiles);
 }
 
-static size_t ceph_vxattrcb_rsubdirs(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val,
                                         size_t size)
 {
        return snprintf(val, size, "%lld", ci->i_rsubdirs);
 }
 
-static size_t ceph_vxattrcb_rbytes(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val,
                                       size_t size)
 {
        return snprintf(val, size, "%lld", ci->i_rbytes);
 }
 
-static size_t ceph_vxattrcb_rctime(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_dir_rctime(struct ceph_inode_info *ci, char *val,
                                       size_t size)
 {
-       return snprintf(val, size, "%ld.%ld", (long)ci->i_rctime.tv_sec,
+       return snprintf(val, size, "%ld.09%ld", (long)ci->i_rctime.tv_sec,
                        (long)ci->i_rctime.tv_nsec);
 }
 
-static struct ceph_vxattr_cb ceph_dir_vxattrs[] = {
-       { true, "ceph.dir.entries", ceph_vxattrcb_entries},
-       { true, "ceph.dir.files", ceph_vxattrcb_files},
-       { true, "ceph.dir.subdirs", ceph_vxattrcb_subdirs},
-       { true, "ceph.dir.rentries", ceph_vxattrcb_rentries},
-       { true, "ceph.dir.rfiles", ceph_vxattrcb_rfiles},
-       { true, "ceph.dir.rsubdirs", ceph_vxattrcb_rsubdirs},
-       { true, "ceph.dir.rbytes", ceph_vxattrcb_rbytes},
-       { true, "ceph.dir.rctime", ceph_vxattrcb_rctime},
-       { true, NULL, NULL }
+#define CEPH_XATTR_NAME(_type, _name)  XATTR_CEPH_PREFIX #_type "." #_name
+
+#define XATTR_NAME_CEPH(_type, _name) \
+               { \
+                       .name = CEPH_XATTR_NAME(_type, _name), \
+                       .name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \
+                       .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \
+                       .readonly = true, \
+               }
+
+static struct ceph_vxattr ceph_dir_vxattrs[] = {
+       XATTR_NAME_CEPH(dir, entries),
+       XATTR_NAME_CEPH(dir, files),
+       XATTR_NAME_CEPH(dir, subdirs),
+       XATTR_NAME_CEPH(dir, rentries),
+       XATTR_NAME_CEPH(dir, rfiles),
+       XATTR_NAME_CEPH(dir, rsubdirs),
+       XATTR_NAME_CEPH(dir, rbytes),
+       XATTR_NAME_CEPH(dir, rctime),
+       { 0 }   /* Required table terminator */
 };
+static size_t ceph_dir_vxattrs_name_size;      /* total size of all names */
 
 /* files */
 
-static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
+static size_t ceph_vxattrcb_file_layout(struct ceph_inode_info *ci, char *val,
                                   size_t size)
 {
        int ret;
@@ -103,21 +118,32 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
                (unsigned long long)ceph_file_layout_su(ci->i_layout),
                (unsigned long long)ceph_file_layout_stripe_count(ci->i_layout),
                (unsigned long long)ceph_file_layout_object_size(ci->i_layout));
-       if (ceph_file_layout_pg_preferred(ci->i_layout))
-               ret += snprintf(val + ret, size, "preferred_osd=%lld\n",
+
+       if (ceph_file_layout_pg_preferred(ci->i_layout) >= 0) {
+               val += ret;
+               size -= ret;
+               ret += snprintf(val, size, "preferred_osd=%lld\n",
                            (unsigned long long)ceph_file_layout_pg_preferred(
                                    ci->i_layout));
+       }
+
        return ret;
 }
 
-static struct ceph_vxattr_cb ceph_file_vxattrs[] = {
-       { true, "ceph.file.layout", ceph_vxattrcb_layout},
+static struct ceph_vxattr ceph_file_vxattrs[] = {
+       XATTR_NAME_CEPH(file, layout),
        /* The following extended attribute name is deprecated */
-       { true, "ceph.layout", ceph_vxattrcb_layout},
-       { true, NULL, NULL }
+       {
+               .name = XATTR_CEPH_PREFIX "layout",
+               .name_size = sizeof (XATTR_CEPH_PREFIX "layout"),
+               .getxattr_cb = ceph_vxattrcb_file_layout,
+               .readonly = true,
+       },
+       { 0 }   /* Required table terminator */
 };
+static size_t ceph_file_vxattrs_name_size;     /* total size of all names */
 
-static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode)
+static struct ceph_vxattr *ceph_inode_vxattrs(struct inode *inode)
 {
        if (S_ISDIR(inode->i_mode))
                return ceph_dir_vxattrs;
@@ -126,14 +152,59 @@ static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode)
        return NULL;
 }
 
-static struct ceph_vxattr_cb *ceph_match_vxattr(struct ceph_vxattr_cb *vxattr,
+static size_t ceph_vxattrs_name_size(struct ceph_vxattr *vxattrs)
+{
+       if (vxattrs == ceph_dir_vxattrs)
+               return ceph_dir_vxattrs_name_size;
+       if (vxattrs == ceph_file_vxattrs)
+               return ceph_file_vxattrs_name_size;
+       BUG();
+
+       return 0;
+}
+
+/*
+ * Compute the aggregate size (including terminating '\0') of all
+ * virtual extended attribute names in the given vxattr table.
+ */
+static size_t __init vxattrs_name_size(struct ceph_vxattr *vxattrs)
+{
+       struct ceph_vxattr *vxattr;
+       size_t size = 0;
+
+       for (vxattr = vxattrs; vxattr->name; vxattr++)
+               size += vxattr->name_size;
+
+       return size;
+}
+
+/* Routines called at initialization and exit time */
+
+void __init ceph_xattr_init(void)
+{
+       ceph_dir_vxattrs_name_size = vxattrs_name_size(ceph_dir_vxattrs);
+       ceph_file_vxattrs_name_size = vxattrs_name_size(ceph_file_vxattrs);
+}
+
+void ceph_xattr_exit(void)
+{
+       ceph_dir_vxattrs_name_size = 0;
+       ceph_file_vxattrs_name_size = 0;
+}
+
+static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode,
                                                const char *name)
 {
-       do {
-               if (strcmp(vxattr->name, name) == 0)
-                       return vxattr;
-               vxattr++;
-       } while (vxattr->name);
+       struct ceph_vxattr *vxattr = ceph_inode_vxattrs(inode);
+
+       if (vxattr) {
+               while (vxattr->name) {
+                       if (!strcmp(vxattr->name, name))
+                               return vxattr;
+                       vxattr++;
+               }
+       }
+
        return NULL;
 }
 
@@ -502,17 +573,15 @@ ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value,
 {
        struct inode *inode = dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
        int err;
        struct ceph_inode_xattr *xattr;
-       struct ceph_vxattr_cb *vxattr = NULL;
+       struct ceph_vxattr *vxattr = NULL;
 
        if (!ceph_is_valid_xattr(name))
                return -ENODATA;
 
        /* let's see if a virtual xattr was requested */
-       if (vxattrs)
-               vxattr = ceph_match_vxattr(vxattrs, name);
+       vxattr = ceph_match_vxattr(inode, name);
 
        spin_lock(&ci->i_ceph_lock);
        dout("getxattr %p ver=%lld index_ver=%lld\n", inode,
@@ -568,7 +637,7 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
 {
        struct inode *inode = dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+       struct ceph_vxattr *vxattrs = ceph_inode_vxattrs(inode);
        u32 vir_namelen = 0;
        u32 namelen;
        int err;
@@ -596,11 +665,12 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
                goto out;
 
 list_xattr:
-       vir_namelen = 0;
-       /* include virtual dir xattrs */
-       if (vxattrs)
-               for (i = 0; vxattrs[i].name; i++)
-                       vir_namelen += strlen(vxattrs[i].name) + 1;
+       /*
+        * Start with virtual dir xattr names (if any) (including
+        * terminating '\0' characters for each).
+        */
+       vir_namelen = ceph_vxattrs_name_size(vxattrs);
+
        /* adding 1 byte per each variable due to the null termination */
        namelen = vir_namelen + ci->i_xattrs.names_size + ci->i_xattrs.count;
        err = -ERANGE;
@@ -698,17 +768,17 @@ int ceph_setxattr(struct dentry *dentry, const char *name,
                  const void *value, size_t size, int flags)
 {
        struct inode *inode = dentry->d_inode;
+       struct ceph_vxattr *vxattr;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
+       int issued;
        int err;
+       int dirty;
        int name_len = strlen(name);
        int val_len = size;
        char *newname = NULL;
        char *newval = NULL;
        struct ceph_inode_xattr *xattr = NULL;
-       int issued;
        int required_blob_size;
-       int dirty;
 
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return -EROFS;
@@ -716,12 +786,9 @@ int ceph_setxattr(struct dentry *dentry, const char *name,
        if (!ceph_is_valid_xattr(name))
                return -EOPNOTSUPP;
 
-       if (vxattrs) {
-               struct ceph_vxattr_cb *vxattr =
-                       ceph_match_vxattr(vxattrs, name);
-               if (vxattr && vxattr->readonly)
-                       return -EOPNOTSUPP;
-       }
+       vxattr = ceph_match_vxattr(inode, name);
+       if (vxattr && vxattr->readonly)
+               return -EOPNOTSUPP;
 
        /* preallocate memory for xattr name, value, index node */
        err = -ENOMEM;
@@ -730,11 +797,9 @@ int ceph_setxattr(struct dentry *dentry, const char *name,
                goto out;
 
        if (val_len) {
-               newval = kmalloc(val_len + 1, GFP_NOFS);
+               newval = kmemdup(value, val_len, GFP_NOFS);
                if (!newval)
                        goto out;
-               memcpy(newval, value, val_len);
-               newval[val_len] = '\0';
        }
 
        xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS);
@@ -744,6 +809,7 @@ int ceph_setxattr(struct dentry *dentry, const char *name,
        spin_lock(&ci->i_ceph_lock);
 retry:
        issued = __ceph_caps_issued(ci, NULL);
+       dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued));
        if (!(issued & CEPH_CAP_XATTR_EXCL))
                goto do_sync;
        __build_xattrs(inode);
@@ -752,7 +818,7 @@ retry:
 
        if (!ci->i_xattrs.prealloc_blob ||
            required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
-               struct ceph_buffer *blob = NULL;
+               struct ceph_buffer *blob;
 
                spin_unlock(&ci->i_ceph_lock);
                dout(" preaallocating new blob size=%d\n", required_blob_size);
@@ -766,12 +832,13 @@ retry:
                goto retry;
        }
 
-       dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued));
        err = __set_xattr(ci, newname, name_len, newval,
                          val_len, 1, 1, 1, &xattr);
+
        dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
        ci->i_xattrs.dirty = true;
        inode->i_ctime = CURRENT_TIME;
+
        spin_unlock(&ci->i_ceph_lock);
        if (dirty)
                __mark_inode_dirty(inode, dirty);
@@ -816,8 +883,8 @@ static int ceph_send_removexattr(struct dentry *dentry, const char *name)
 int ceph_removexattr(struct dentry *dentry, const char *name)
 {
        struct inode *inode = dentry->d_inode;
+       struct ceph_vxattr *vxattr;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
        int issued;
        int err;
        int required_blob_size;
@@ -829,22 +896,19 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
        if (!ceph_is_valid_xattr(name))
                return -EOPNOTSUPP;
 
-       if (vxattrs) {
-               struct ceph_vxattr_cb *vxattr =
-                       ceph_match_vxattr(vxattrs, name);
-               if (vxattr && vxattr->readonly)
-                       return -EOPNOTSUPP;
-       }
+       vxattr = ceph_match_vxattr(inode, name);
+       if (vxattr && vxattr->readonly)
+               return -EOPNOTSUPP;
 
        err = -ENOMEM;
        spin_lock(&ci->i_ceph_lock);
-       __build_xattrs(inode);
 retry:
        issued = __ceph_caps_issued(ci, NULL);
        dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued));
 
        if (!(issued & CEPH_CAP_XATTR_EXCL))
                goto do_sync;
+       __build_xattrs(inode);
 
        required_blob_size = __get_required_blob_size(ci, 0, 0);
 
@@ -865,10 +929,10 @@ retry:
        }
 
        err = __remove_xattr_by_name(ceph_inode(inode), name);
+
        dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
        ci->i_xattrs.dirty = true;
        inode->i_ctime = CURRENT_TIME;
-
        spin_unlock(&ci->i_ceph_lock);
        if (dirty)
                __mark_inode_dirty(inode, dirty);
index 895da1d..b7d782b 100644 (file)
@@ -753,10 +753,6 @@ module loading or during the runtime by using the interface
 
 i.e. echo "value" > /sys/module/cifs/parameters/<param>
 
-1. echo_retries - The number of echo attempts before giving up and
-                 reconnecting to the server. The default is 5. The value 0
-                 means never reconnect.
-
-2. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
+1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
                    [Y/y/1]. To disable use any of [N/n/0].
 
index 24b3dfc..573b899 100644 (file)
@@ -171,8 +171,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                        seq_printf(m, "TCP status: %d\n\tLocal Users To "
                                   "Server: %d SecMode: 0x%x Req On Wire: %d",
                                   server->tcpStatus, server->srv_count,
-                                  server->sec_mode,
-                                  atomic_read(&server->inFlight));
+                                  server->sec_mode, in_flight(server));
 
 #ifdef CONFIG_CIFS_STATS2
                        seq_printf(m, " In Send: %d In MaxReq Wait: %d",
index 418fc42..eee522c 100644 (file)
@@ -76,12 +76,7 @@ MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
 unsigned int cifs_max_pending = CIFS_MAX_REQ;
 module_param(cifs_max_pending, int, 0444);
 MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
-                                  "Default: 50 Range: 2 to 256");
-unsigned short echo_retries = 5;
-module_param(echo_retries, ushort, 0644);
-MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
-                              "reconnecting server. Default: 5. 0 means "
-                              "never reconnect.");
+                                  "Default: 32767 Range: 2 to 32767.");
 module_param(enable_oplocks, bool, 0644);
 MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
                                 "y/Y/1");
@@ -1111,9 +1106,9 @@ init_cifs(void)
        if (cifs_max_pending < 2) {
                cifs_max_pending = 2;
                cFYI(1, "cifs_max_pending set to min of 2");
-       } else if (cifs_max_pending > 256) {
-               cifs_max_pending = 256;
-               cFYI(1, "cifs_max_pending set to max of 256");
+       } else if (cifs_max_pending > CIFS_MAX_REQ) {
+               cifs_max_pending = CIFS_MAX_REQ;
+               cFYI(1, "cifs_max_pending set to max of %u", CIFS_MAX_REQ);
        }
 
        rc = cifs_fscache_register();
@@ -1175,11 +1170,8 @@ static void __exit
 exit_cifs(void)
 {
        cFYI(DBG2, "exit_cifs");
-       cifs_proc_clean();
-       cifs_fscache_unregister();
-#ifdef CONFIG_CIFS_DFS_UPCALL
+       unregister_filesystem(&cifs_fs_type);
        cifs_dfs_release_automount_timer();
-#endif
 #ifdef CONFIG_CIFS_ACL
        cifs_destroy_idmaptrees();
        exit_cifs_idmap();
@@ -1187,10 +1179,11 @@ exit_cifs(void)
 #ifdef CONFIG_CIFS_UPCALL
        unregister_key_type(&cifs_spnego_key_type);
 #endif
-       unregister_filesystem(&cifs_fs_type);
-       cifs_destroy_inodecache();
-       cifs_destroy_mids();
        cifs_destroy_request_bufs();
+       cifs_destroy_mids();
+       cifs_destroy_inodecache();
+       cifs_fscache_unregister();
+       cifs_proc_clean();
 }
 
 MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
index 76e7d8b..339ebe3 100644 (file)
 
 /*
  * MAX_REQ is the maximum number of requests that WE will send
- * on one socket concurrently. It also matches the most common
- * value of max multiplex returned by servers.  We may
- * eventually want to use the negotiated value (in case
- * future servers can handle more) when we are more confident that
- * we will not have problems oveloading the socket with pending
- * write data.
+ * on one socket concurrently.
  */
-#define CIFS_MAX_REQ 50
+#define CIFS_MAX_REQ 32767
 
 #define RFC1001_NAME_LEN 15
 #define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
@@ -255,7 +250,9 @@ struct TCP_Server_Info {
        bool noblocksnd;                /* use blocking sendmsg */
        bool noautotune;                /* do not autotune send buf sizes */
        bool tcp_nodelay;
-       atomic_t inFlight;  /* number of requests on the wire to server */
+       int credits;  /* send no more requests at once */
+       unsigned int in_flight;  /* number of requests on the wire to server */
+       spinlock_t req_lock;  /* protect the two values above */
        struct mutex srv_mutex;
        struct task_struct *tsk;
        char server_GUID[16];
@@ -263,6 +260,7 @@ struct TCP_Server_Info {
        bool session_estab; /* mark when very first sess is established */
        u16 dialect; /* dialect index that server chose */
        enum securityEnum secType;
+       bool oplocks:1; /* enable oplocks */
        unsigned int maxReq;    /* Clients should submit no more */
        /* than maxReq distinct unanswered SMBs to the server when using  */
        /* multiplexed reads or writes */
@@ -307,6 +305,36 @@ struct TCP_Server_Info {
 #endif
 };
 
+static inline unsigned int
+in_flight(struct TCP_Server_Info *server)
+{
+       unsigned int num;
+       spin_lock(&server->req_lock);
+       num = server->in_flight;
+       spin_unlock(&server->req_lock);
+       return num;
+}
+
+static inline int*
+get_credits_field(struct TCP_Server_Info *server)
+{
+       /*
+        * This will change to switch statement when we reserve slots for echos
+        * and oplock breaks.
+        */
+       return &server->credits;
+}
+
+static inline bool
+has_credits(struct TCP_Server_Info *server, int *credits)
+{
+       int num;
+       spin_lock(&server->req_lock);
+       num = *credits;
+       spin_unlock(&server->req_lock);
+       return num > 0;
+}
+
 /*
  * Macros to allow the TCP_Server_Info->net field and related code to drop out
  * when CONFIG_NET_NS isn't set.
@@ -1010,9 +1038,6 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
 GLOBAL_EXTERN unsigned int cifs_min_small;  /* min size of small buf pool */
 GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
 
-/* reconnect after this many failed echo attempts */
-GLOBAL_EXTERN unsigned short echo_retries;
-
 #ifdef CONFIG_CIFS_ACL
 GLOBAL_EXTERN struct rb_root uidtree;
 GLOBAL_EXTERN struct rb_root gidtree;
index 6f4e243..503e73d 100644 (file)
@@ -88,6 +88,9 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
                        struct smb_hdr *in_buf ,
                        struct smb_hdr *out_buf,
                        int *bytes_returned);
+extern void cifs_add_credits(struct TCP_Server_Info *server,
+                            const unsigned int add);
+extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
 extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
 extern bool is_valid_oplock_break(struct smb_hdr *smb,
                                  struct TCP_Server_Info *);
@@ -168,7 +171,13 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data,
                                            const char *devname);
 extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
 extern void cifs_umount(struct cifs_sb_info *);
+
+#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
 extern void cifs_dfs_release_automount_timer(void);
+#else /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
+#define cifs_dfs_release_automount_timer()     do { } while (0)
+#endif /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
+
 void cifs_proc_init(void);
 void cifs_proc_clean(void);
 
index 8b7794c..70aac35 100644 (file)
@@ -458,7 +458,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
                        goto neg_err_exit;
                }
                server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
-               server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+               server->maxReq = min_t(unsigned int,
+                                      le16_to_cpu(rsp->MaxMpxCount),
+                                      cifs_max_pending);
+               cifs_set_credits(server, server->maxReq);
                server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
                server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
                /* even though we do not use raw we might as well set this
@@ -564,7 +567,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
 
        /* one byte, so no need to convert this or EncryptionKeyLen from
           little endian */
-       server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+       server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
+                              cifs_max_pending);
+       cifs_set_credits(server, server->maxReq);
        /* probably no need to store and check maxvcs */
        server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
        server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
@@ -716,8 +721,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
        struct TCP_Server_Info *server = mid->callback_data;
 
        DeleteMidQEntry(mid);
-       atomic_dec(&server->inFlight);
-       wake_up(&server->request_q);
+       cifs_add_credits(server, 1);
 }
 
 int
@@ -1669,8 +1673,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
 
        queue_work(system_nrt_wq, &rdata->work);
        DeleteMidQEntry(mid);
-       atomic_dec(&server->inFlight);
-       wake_up(&server->request_q);
+       cifs_add_credits(server, 1);
 }
 
 /* cifs_async_readv - send an async write, and set up mid to handle result */
@@ -2110,8 +2113,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
 
        queue_work(system_nrt_wq, &wdata->work);
        DeleteMidQEntry(mid);
-       atomic_dec(&tcon->ses->server->inFlight);
-       wake_up(&tcon->ses->server->request_q);
+       cifs_add_credits(tcon->ses->server, 1);
 }
 
 /* cifs_async_writev - send an async write, and set up mid to handle result */
index 602f77c..5560e1d 100644 (file)
@@ -373,12 +373,22 @@ allocate_buffers(struct TCP_Server_Info *server)
 static bool
 server_unresponsive(struct TCP_Server_Info *server)
 {
-       if (echo_retries > 0 && server->tcpStatus == CifsGood &&
-           time_after(jiffies, server->lstrp +
-                               (echo_retries * SMB_ECHO_INTERVAL))) {
+       /*
+        * We need to wait 2 echo intervals to make sure we handle such
+        * situations right:
+        * 1s  client sends a normal SMB request
+        * 2s  client gets a response
+        * 30s echo workqueue job pops, and decides we got a response recently
+        *     and don't need to send another
+        * ...
+        * 65s kernel_recvmsg times out, and we see that we haven't gotten
+        *     a response in >60s.
+        */
+       if (server->tcpStatus == CifsGood &&
+           time_after(jiffies, server->lstrp + 2 * SMB_ECHO_INTERVAL)) {
                cERROR(1, "Server %s has not responded in %d seconds. "
                          "Reconnecting...", server->hostname,
-                         (echo_retries * SMB_ECHO_INTERVAL / HZ));
+                         (2 * SMB_ECHO_INTERVAL) / HZ);
                cifs_reconnect(server);
                wake_up(&server->response_q);
                return true;
@@ -642,19 +652,11 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
        spin_unlock(&GlobalMid_Lock);
        wake_up_all(&server->response_q);
 
-       /*
-        * Check if we have blocked requests that need to free. Note that
-        * cifs_max_pending is normally 50, but can be set at module install
-        * time to as little as two.
-        */
-       spin_lock(&GlobalMid_Lock);
-       if (atomic_read(&server->inFlight) >= cifs_max_pending)
-               atomic_set(&server->inFlight, cifs_max_pending - 1);
-       /*
-        * We do not want to set the max_pending too low or we could end up
-        * with the counter going negative.
-        */
-       spin_unlock(&GlobalMid_Lock);
+       /* check if we have blocked requests that need to free */
+       spin_lock(&server->req_lock);
+       if (server->credits <= 0)
+               server->credits = 1;
+       spin_unlock(&server->req_lock);
        /*
         * Although there should not be any requests blocked on this queue it
         * can not hurt to be paranoid and try to wake up requests that may
@@ -1909,7 +1911,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
        tcp_ses->noblocksnd = volume_info->noblocksnd;
        tcp_ses->noautotune = volume_info->noautotune;
        tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
-       atomic_set(&tcp_ses->inFlight, 0);
+       tcp_ses->in_flight = 0;
+       tcp_ses->credits = 1;
        init_waitqueue_head(&tcp_ses->response_q);
        init_waitqueue_head(&tcp_ses->request_q);
        INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
@@ -3371,7 +3374,7 @@ cifs_ra_pages(struct cifs_sb_info *cifs_sb)
 int
 cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
 {
-       int rc = 0;
+       int rc;
        int xid;
        struct cifs_ses *pSesInfo;
        struct cifs_tcon *tcon;
@@ -3398,6 +3401,7 @@ try_mount_again:
                FreeXid(xid);
        }
 #endif
+       rc = 0;
        tcon = NULL;
        pSesInfo = NULL;
        srvTcp = NULL;
@@ -3759,9 +3763,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
        if (server->maxBuf != 0)
                return 0;
 
+       cifs_set_credits(server, 1);
        rc = CIFSSMBNegotiate(xid, ses);
        if (rc == -EAGAIN) {
                /* retry only once on 1st time connection */
+               cifs_set_credits(server, 1);
                rc = CIFSSMBNegotiate(xid, ses);
                if (rc == -EAGAIN)
                        rc = -EHOSTDOWN;
index bc7e244..d172c8e 100644 (file)
@@ -171,7 +171,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
        }
        tcon = tlink_tcon(tlink);
 
-       if (enable_oplocks)
+       if (tcon->ses->server->oplocks)
                oplock = REQ_OPLOCK;
 
        if (nd)
@@ -492,7 +492,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 {
        int xid;
        int rc = 0; /* to get around spurious gcc warning, set to zero here */
-       __u32 oplock = enable_oplocks ? REQ_OPLOCK : 0;
+       __u32 oplock;
        __u16 fileHandle = 0;
        bool posix_open = false;
        struct cifs_sb_info *cifs_sb;
@@ -518,6 +518,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
        }
        pTcon = tlink_tcon(tlink);
 
+       oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
+
        /*
         * Don't allow the separator character in a path component.
         * The VFS will not allow "/", but "\" is allowed by posix.
index 5e64748..159fcc5 100644 (file)
@@ -380,7 +380,7 @@ int cifs_open(struct inode *inode, struct file *file)
        cFYI(1, "inode = 0x%p file flags are 0x%x for %s",
                 inode, file->f_flags, full_path);
 
-       if (enable_oplocks)
+       if (tcon->ses->server->oplocks)
                oplock = REQ_OPLOCK;
        else
                oplock = 0;
@@ -505,7 +505,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
        cFYI(1, "inode = 0x%p file flags 0x%x for %s",
                 inode, pCifsFile->f_flags, full_path);
 
-       if (enable_oplocks)
+       if (tcon->ses->server->oplocks)
                oplock = REQ_OPLOCK;
        else
                oplock = 0;
@@ -960,9 +960,9 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
        INIT_LIST_HEAD(&locks_to_send);
 
        /*
-        * Allocating count locks is enough because no locks can be added to
-        * the list while we are holding cinode->lock_mutex that protects
-        * locking operations of this inode.
+        * Allocating count locks is enough because no FL_POSIX locks can be
+        * added to the list while we are holding cinode->lock_mutex that
+        * protects locking operations of this inode.
         */
        for (; i < count; i++) {
                lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL);
@@ -973,18 +973,20 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
                list_add_tail(&lck->llist, &locks_to_send);
        }
 
-       i = 0;
        el = locks_to_send.next;
        lock_flocks();
        cifs_for_each_lock(cfile->dentry->d_inode, before) {
+               flock = *before;
+               if ((flock->fl_flags & FL_POSIX) == 0)
+                       continue;
                if (el == &locks_to_send) {
-                       /* something is really wrong */
+                       /*
+                        * The list ended. We don't have enough allocated
+                        * structures - something is really wrong.
+                        */
                        cERROR(1, "Can't push all brlocks!");
                        break;
                }
-               flock = *before;
-               if ((flock->fl_flags & FL_POSIX) == 0)
-                       continue;
                length = 1 + flock->fl_end - flock->fl_start;
                if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK)
                        type = CIFS_RDLCK;
@@ -996,7 +998,6 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
                lck->length = length;
                lck->type = type;
                lck->offset = flock->fl_start;
-               i++;
                el = el->next;
        }
        unlock_flocks();
index 703ef5c..c273c12 100644 (file)
@@ -690,3 +690,22 @@ backup_cred(struct cifs_sb_info *cifs_sb)
 
        return false;
 }
+
+void
+cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add)
+{
+       spin_lock(&server->req_lock);
+       server->credits += add;
+       server->in_flight--;
+       spin_unlock(&server->req_lock);
+       wake_up(&server->request_q);
+}
+
+void
+cifs_set_credits(struct TCP_Server_Info *server, const int val)
+{
+       spin_lock(&server->req_lock);
+       server->credits = val;
+       server->oplocks = val > 1 ? enable_oplocks : false;
+       spin_unlock(&server->req_lock);
+}
index 0cc9584..310918b 100644 (file)
@@ -254,44 +254,60 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
        return smb_sendv(server, &iov, 1);
 }
 
-static int wait_for_free_request(struct TCP_Server_Info *server,
-                                const int long_op)
+static int
+wait_for_free_credits(struct TCP_Server_Info *server, const int optype,
+                     int *credits)
 {
-       if (long_op == CIFS_ASYNC_OP) {
+       int rc;
+
+       spin_lock(&server->req_lock);
+       if (optype == CIFS_ASYNC_OP) {
                /* oplock breaks must not be held up */
-               atomic_inc(&server->inFlight);
+               server->in_flight++;
+               *credits -= 1;
+               spin_unlock(&server->req_lock);
                return 0;
        }
 
-       spin_lock(&GlobalMid_Lock);
        while (1) {
-               if (atomic_read(&server->inFlight) >= cifs_max_pending) {
-                       spin_unlock(&GlobalMid_Lock);
+               if (*credits <= 0) {
+                       spin_unlock(&server->req_lock);
                        cifs_num_waiters_inc(server);
-                       wait_event(server->request_q,
-                                  atomic_read(&server->inFlight)
-                                    < cifs_max_pending);
+                       rc = wait_event_killable(server->request_q,
+                                                has_credits(server, credits));
                        cifs_num_waiters_dec(server);
-                       spin_lock(&GlobalMid_Lock);
+                       if (rc)
+                               return rc;
+                       spin_lock(&server->req_lock);
                } else {
                        if (server->tcpStatus == CifsExiting) {
-                               spin_unlock(&GlobalMid_Lock);
+                               spin_unlock(&server->req_lock);
                                return -ENOENT;
                        }
 
-                       /* can not count locking commands against total
-                          as they are allowed to block on server */
+                       /*
+                        * Can not count locking commands against total
+                        * as they are allowed to block on server.
+                        */
 
                        /* update # of requests on the wire to server */
-                       if (long_op != CIFS_BLOCKING_OP)
-                               atomic_inc(&server->inFlight);
-                       spin_unlock(&GlobalMid_Lock);
+                       if (optype != CIFS_BLOCKING_OP) {
+                               *credits -= 1;
+                               server->in_flight++;
+                       }
+                       spin_unlock(&server->req_lock);
                        break;
                }
        }
        return 0;
 }
 
+static int
+wait_for_free_request(struct TCP_Server_Info *server, const int optype)
+{
+       return wait_for_free_credits(server, optype, get_credits_field(server));
+}
+
 static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
                        struct mid_q_entry **ppmidQ)
 {
@@ -359,7 +375,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
        mid = AllocMidQEntry(hdr, server);
        if (mid == NULL) {
                mutex_unlock(&server->srv_mutex);
-               atomic_dec(&server->inFlight);
+               cifs_add_credits(server, 1);
                wake_up(&server->request_q);
                return -ENOMEM;
        }
@@ -392,7 +408,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
        return rc;
 out_err:
        delete_mid(mid);
-       atomic_dec(&server->inFlight);
+       cifs_add_credits(server, 1);
        wake_up(&server->request_q);
        return rc;
 }
@@ -564,8 +580,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
                mutex_unlock(&ses->server->srv_mutex);
                cifs_small_buf_release(in_buf);
                /* Update # of requests on wire to server */
-               atomic_dec(&ses->server->inFlight);
-               wake_up(&ses->server->request_q);
+               cifs_add_credits(ses->server, 1);
                return rc;
        }
        rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
@@ -601,8 +616,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
                        midQ->callback = DeleteMidQEntry;
                        spin_unlock(&GlobalMid_Lock);
                        cifs_small_buf_release(in_buf);
-                       atomic_dec(&ses->server->inFlight);
-                       wake_up(&ses->server->request_q);
+                       cifs_add_credits(ses->server, 1);
                        return rc;
                }
                spin_unlock(&GlobalMid_Lock);
@@ -612,8 +626,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 
        rc = cifs_sync_mid_result(midQ, ses->server);
        if (rc != 0) {
-               atomic_dec(&ses->server->inFlight);
-               wake_up(&ses->server->request_q);
+               cifs_add_credits(ses->server, 1);
                return rc;
        }
 
@@ -637,8 +650,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
                midQ->resp_buf = NULL;
 out:
        delete_mid(midQ);
-       atomic_dec(&ses->server->inFlight);
-       wake_up(&ses->server->request_q);
+       cifs_add_credits(ses->server, 1);
 
        return rc;
 }
@@ -688,8 +700,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
        if (rc) {
                mutex_unlock(&ses->server->srv_mutex);
                /* Update # of requests on wire to server */
-               atomic_dec(&ses->server->inFlight);
-               wake_up(&ses->server->request_q);
+               cifs_add_credits(ses->server, 1);
                return rc;
        }
 
@@ -721,8 +732,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
                        /* no longer considered to be "in-flight" */
                        midQ->callback = DeleteMidQEntry;
                        spin_unlock(&GlobalMid_Lock);
-                       atomic_dec(&ses->server->inFlight);
-                       wake_up(&ses->server->request_q);
+                       cifs_add_credits(ses->server, 1);
                        return rc;
                }
                spin_unlock(&GlobalMid_Lock);
@@ -730,8 +740,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 
        rc = cifs_sync_mid_result(midQ, ses->server);
        if (rc != 0) {
-               atomic_dec(&ses->server->inFlight);
-               wake_up(&ses->server->request_q);
+               cifs_add_credits(ses->server, 1);
                return rc;
        }
 
@@ -747,8 +756,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
        rc = cifs_check_receive(midQ, ses->server, 0);
 out:
        delete_mid(midQ);
-       atomic_dec(&ses->server->inFlight);
-       wake_up(&ses->server->request_q);
+       cifs_add_credits(ses->server, 1);
 
        return rc;
 }
index 07880ba..14483a7 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/nfs4_mount.h>
 #include <linux/syscalls.h>
 #include <linux/ctype.h>
-#include <linux/module.h>
 #include <linux/dirent.h>
 #include <linux/fsnotify.h>
 #include <linux/highuid.h>
index 10d8cd9..debdfe0 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/elevator.h>
 #include <linux/rtc.h>
 #include <linux/pci.h>
-#include <linux/module.h>
 #include <linux/serial.h>
 #include <linux/if_tun.h>
 #include <linux/ctype.h>
index 2b55bd0..b60ddc4 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/cache.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mount.h>
 #include <linux/file.h>
 #include <asm/uaccess.h>
@@ -2404,6 +2404,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
                        if (d_ancestor(alias, dentry)) {
                                /* Check for loops */
                                actual = ERR_PTR(-ELOOP);
+                               spin_unlock(&inode->i_lock);
                        } else if (IS_ROOT(alias)) {
                                /* Is this an anonymous mountpoint that we
                                 * could splice into our tree? */
@@ -2413,7 +2414,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
                                goto found;
                        } else {
                                /* Nope, but we must(!) avoid directory
-                                * aliasing */
+                                * aliasing. This drops inode->i_lock */
                                actual = __d_unalias(inode, dentry, alias);
                        }
                        write_sequnlock(&rename_lock);
index dda0dc7..17c7799 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 #include <linux/syscalls.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/mount.h>
index d9a5917..dba15fe 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/spinlock.h>
 #include <linux/anon_inodes.h>
 #include <linux/syscalls.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kref.h>
 #include <linux/eventfd.h>
 
index 2a7dcd6..739b098 100644 (file)
@@ -426,6 +426,31 @@ out_unlock:
        return error;
 }
 
+/*
+ * As described in commit 0ccf831cb lockdep: annotate epoll
+ * the use of wait queues used by epoll is done in a very controlled
+ * manner. Wake ups can nest inside each other, but are never done
+ * with the same locking. For example:
+ *
+ *   dfd = socket(...);
+ *   efd1 = epoll_create();
+ *   efd2 = epoll_create();
+ *   epoll_ctl(efd1, EPOLL_CTL_ADD, dfd, ...);
+ *   epoll_ctl(efd2, EPOLL_CTL_ADD, efd1, ...);
+ *
+ * When a packet arrives to the device underneath "dfd", the net code will
+ * issue a wake_up() on its poll wake list. Epoll (efd1) has installed a
+ * callback wakeup entry on that queue, and the wake_up() performed by the
+ * "dfd" net code will end up in ep_poll_callback(). At this point epoll
+ * (efd1) notices that it may have some event ready, so it needs to wake up
+ * the waiters on its poll wait list (efd2). So it calls ep_poll_safewake()
+ * that ends up in another wake_up(), after having checked about the
+ * recursion constraints. That are, no more than EP_MAX_POLLWAKE_NESTS, to
+ * avoid stack blasting.
+ *
+ * When CONFIG_DEBUG_LOCK_ALLOC is enabled, make sure lockdep can handle
+ * this special case of epoll.
+ */
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static inline void ep_wake_up_nested(wait_queue_head_t *wqueue,
                                     unsigned long events, int subclass)
@@ -698,9 +723,12 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
                               void *priv)
 {
        struct epitem *epi, *tmp;
+       poll_table pt;
 
+       init_poll_funcptr(&pt, NULL);
        list_for_each_entry_safe(epi, tmp, head, rdllink) {
-               if (epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
+               pt._key = epi->event.events;
+               if (epi->ffd.file->f_op->poll(epi->ffd.file, &pt) &
                    epi->event.events)
                        return POLLIN | POLLRDNORM;
                else {
@@ -1048,13 +1076,11 @@ static int reverse_path_check_proc(void *priv, void *cookie, int call_nests)
  */
 static int reverse_path_check(void)
 {
-       int length = 0;
        int error = 0;
        struct file *current_file;
 
        /* let's call this for all tfiles */
        list_for_each_entry(current_file, &tfile_check_list, f_tfile_llink) {
-               length++;
                path_count_init();
                error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
                                        reverse_path_check_proc, current_file,
@@ -1096,6 +1122,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
        /* Initialize the poll table using the queue callback */
        epq.epi = epi;
        init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);
+       epq.pt._key = event->events;
 
        /*
         * Attach the item to the poll hooks and get current event bits.
@@ -1190,6 +1217,9 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
 {
        int pwake = 0;
        unsigned int revents;
+       poll_table pt;
+
+       init_poll_funcptr(&pt, NULL);
 
        /*
         * Set the new event interest mask before calling f_op->poll();
@@ -1197,13 +1227,14 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
         * f_op->poll() call and the new event set registering.
         */
        epi->event.events = event->events;
+       pt._key = event->events;
        epi->event.data = event->data; /* protected by mtx */
 
        /*
         * Get current event bits. We can safely use the file* here because
         * its usage count has been increased by the caller of this function.
         */
-       revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
+       revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt);
 
        /*
         * If the item is "hot" and it is not registered inside the ready
@@ -1238,6 +1269,9 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
        unsigned int revents;
        struct epitem *epi;
        struct epoll_event __user *uevent;
+       poll_table pt;
+
+       init_poll_funcptr(&pt, NULL);
 
        /*
         * We can loop without lock because we are passed a task private list.
@@ -1250,7 +1284,8 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
 
                list_del_init(&epi->rdllink);
 
-               revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL) &
+               pt._key = epi->event.events;
+               revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt) &
                        epi->event.events;
 
                /*
index a203892..1e036b7 100644 (file)
@@ -1743,8 +1743,11 @@ allocated:
 
        *errp = 0;
        brelse(bitmap_bh);
-       dquot_free_block(inode, *count-num);
-       *count = num;
+
+       if (num < *count) {
+               dquot_free_block(inode, *count-num);
+               *count = num;
+       }
 
        trace_ext3_allocate_blocks(inode, goal, num,
                                   (unsigned long long)ret_block);
@@ -1970,7 +1973,7 @@ static ext3_grpblk_t ext3_trim_all_free(struct super_block *sb,
        sbi = EXT3_SB(sb);
 
         /* Walk through the whole group */
-       while (start < max) {
+       while (start <= max) {
                start = bitmap_search_next_usable_block(start, bitmap_bh, max);
                if (start < 0)
                        break;
@@ -1980,7 +1983,7 @@ static ext3_grpblk_t ext3_trim_all_free(struct super_block *sb,
                 * Allocate contiguous free extents by setting bits in the
                 * block bitmap
                 */
-               while (next < max
+               while (next <= max
                        && claim_block(sb_bgl_lock(sbi, group),
                                        next, bitmap_bh)) {
                        next++;
@@ -2091,73 +2094,74 @@ err_out:
  */
 int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range)
 {
-       ext3_grpblk_t last_block, first_block, free_blocks;
-       unsigned long first_group, last_group;
-       unsigned long group, ngroups;
+       ext3_grpblk_t last_block, first_block;
+       unsigned long group, first_group, last_group;
        struct ext3_group_desc *gdp;
        struct ext3_super_block *es = EXT3_SB(sb)->s_es;
-       uint64_t start, len, minlen, trimmed;
+       uint64_t start, minlen, end, trimmed = 0;
+       ext3_fsblk_t first_data_blk =
+                       le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block);
        ext3_fsblk_t max_blks = le32_to_cpu(es->s_blocks_count);
        int ret = 0;
 
-       start = (range->start >> sb->s_blocksize_bits) +
-               le32_to_cpu(es->s_first_data_block);
-       len = range->len >> sb->s_blocksize_bits;
+       start = range->start >> sb->s_blocksize_bits;
+       end = start + (range->len >> sb->s_blocksize_bits) - 1;
        minlen = range->minlen >> sb->s_blocksize_bits;
-       trimmed = 0;
 
-       if (unlikely(minlen > EXT3_BLOCKS_PER_GROUP(sb)))
+       if (unlikely(minlen > EXT3_BLOCKS_PER_GROUP(sb)) ||
+           unlikely(start >= max_blks))
                return -EINVAL;
-       if (start >= max_blks)
-               return -EINVAL;
-       if (start + len > max_blks)
-               len = max_blks - start;
+       if (end >= max_blks)
+               end = max_blks - 1;
+       if (end <= first_data_blk)
+               goto out;
+       if (start < first_data_blk)
+               start = first_data_blk;
 
-       ngroups = EXT3_SB(sb)->s_groups_count;
        smp_rmb();
 
        /* Determine first and last group to examine based on start and len */
        ext3_get_group_no_and_offset(sb, (ext3_fsblk_t) start,
                                     &first_group, &first_block);
-       ext3_get_group_no_and_offset(sb, (ext3_fsblk_t) (start + len),
+       ext3_get_group_no_and_offset(sb, (ext3_fsblk_t) end,
                                     &last_group, &last_block);
-       last_group = (last_group > ngroups - 1) ? ngroups - 1 : last_group;
-       last_block = EXT3_BLOCKS_PER_GROUP(sb);
 
-       if (first_group > last_group)
-               return -EINVAL;
+       /* end now represents the last block to discard in this group */
+       end = EXT3_BLOCKS_PER_GROUP(sb) - 1;
 
        for (group = first_group; group <= last_group; group++) {
                gdp = ext3_get_group_desc(sb, group, NULL);
                if (!gdp)
                        break;
 
-               free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
-               if (free_blocks < minlen)
-                       continue;
-
                /*
                 * For all the groups except the last one, last block will
-                * always be EXT3_BLOCKS_PER_GROUP(sb), so we only need to
-                * change it for the last group in which case first_block +
-                * len < EXT3_BLOCKS_PER_GROUP(sb).
+                * always be EXT3_BLOCKS_PER_GROUP(sb)-1, so we only need to
+                * change it for the last group, note that last_block is
+                * already computed earlier by ext3_get_group_no_and_offset()
                 */
-               if (first_block + len < EXT3_BLOCKS_PER_GROUP(sb))
-                       last_block = first_block + len;
-               len -= last_block - first_block;
+               if (group == last_group)
+                       end = last_block;
 
-               ret = ext3_trim_all_free(sb, group, first_block,
-                                       last_block, minlen);
-               if (ret < 0)
-                       break;
+               if (le16_to_cpu(gdp->bg_free_blocks_count) >= minlen) {
+                       ret = ext3_trim_all_free(sb, group, first_block,
+                                                end, minlen);
+                       if (ret < 0)
+                               break;
+                       trimmed += ret;
+               }
 
-               trimmed += ret;
+               /*
+                * For every group except the first one, we are sure
+                * that the first block to discard will be block #0.
+                */
                first_block = 0;
        }
 
-       if (ret >= 0)
+       if (ret > 0)
                ret = 0;
-       range->len = trimmed * sb->s_blocksize;
 
+out:
+       range->len = trimmed * sb->s_blocksize;
        return ret;
 }
index 2d0afec..6d34186 100644 (file)
@@ -756,6 +756,7 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode,
        struct ext3_block_alloc_info *block_i;
        ext3_fsblk_t current_block;
        struct ext3_inode_info *ei = EXT3_I(inode);
+       struct timespec now;
 
        block_i = ei->i_block_alloc_info;
        /*
@@ -795,9 +796,11 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode,
        }
 
        /* We are done with atomic stuff, now do the rest of housekeeping */
-
-       inode->i_ctime = CURRENT_TIME_SEC;
-       ext3_mark_inode_dirty(handle, inode);
+       now = CURRENT_TIME_SEC;
+       if (!timespec_equal(&inode->i_ctime, &now) || !where->bh) {
+               inode->i_ctime = now;
+               ext3_mark_inode_dirty(handle, inode);
+       }
        /* ext3_mark_inode_dirty already updated i_sync_tid */
        atomic_set(&ei->i_datasync_tid, handle->h_transaction->t_tid);
 
index f9e2cd8..4bbd07a 100644 (file)
@@ -336,10 +336,10 @@ err_out:
  * Return buffer_head on success or NULL in case of failure.
  */
 struct buffer_head *
-ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
+ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
 {
        struct ext4_group_desc *desc;
-       struct buffer_head *bh = NULL;
+       struct buffer_head *bh;
        ext4_fsblk_t bitmap_blk;
 
        desc = ext4_get_group_desc(sb, block_group, NULL);
@@ -348,9 +348,9 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
        bitmap_blk = ext4_block_bitmap(sb, desc);
        bh = sb_getblk(sb, bitmap_blk);
        if (unlikely(!bh)) {
-               ext4_error(sb, "Cannot read block bitmap - "
-                           "block_group = %u, block_bitmap = %llu",
-                           block_group, bitmap_blk);
+               ext4_error(sb, "Cannot get buffer for block bitmap - "
+                          "block_group = %u, block_bitmap = %llu",
+                          block_group, bitmap_blk);
                return NULL;
        }
 
@@ -382,25 +382,50 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
                return bh;
        }
        /*
-        * submit the buffer_head for read. We can
-        * safely mark the bitmap as uptodate now.
-        * We do it here so the bitmap uptodate bit
-        * get set with buffer lock held.
+        * submit the buffer_head for reading
         */
+       set_buffer_new(bh);
        trace_ext4_read_block_bitmap_load(sb, block_group);
-       set_bitmap_uptodate(bh);
-       if (bh_submit_read(bh) < 0) {
-               put_bh(bh);
+       bh->b_end_io = ext4_end_bitmap_read;
+       get_bh(bh);
+       submit_bh(READ, bh);
+       return bh;
+}
+
+/* Returns 0 on success, 1 on error */
+int ext4_wait_block_bitmap(struct super_block *sb, ext4_group_t block_group,
+                          struct buffer_head *bh)
+{
+       struct ext4_group_desc *desc;
+
+       if (!buffer_new(bh))
+               return 0;
+       desc = ext4_get_group_desc(sb, block_group, NULL);
+       if (!desc)
+               return 1;
+       wait_on_buffer(bh);
+       if (!buffer_uptodate(bh)) {
                ext4_error(sb, "Cannot read block bitmap - "
-                           "block_group = %u, block_bitmap = %llu",
-                           block_group, bitmap_blk);
-               return NULL;
+                          "block_group = %u, block_bitmap = %llu",
+                          block_group, (unsigned long long) bh->b_blocknr);
+               return 1;
        }
+       clear_buffer_new(bh);
+       /* Panic or remount fs read-only if block bitmap is invalid */
        ext4_valid_block_bitmap(sb, desc, block_group, bh);
-       /*
-        * file system mounted not to panic on error,
-        * continue with corrupt bitmap
-        */
+       return 0;
+}
+
+struct buffer_head *
+ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
+{
+       struct buffer_head *bh;
+
+       bh = ext4_read_block_bitmap_nowait(sb, block_group);
+       if (ext4_wait_block_bitmap(sb, block_group, bh)) {
+               put_bh(bh);
+               return NULL;
+       }
        return bh;
 }
 
index 164c560..ad56866 100644 (file)
@@ -91,17 +91,17 @@ int __ext4_check_dir_entry(const char *function, unsigned int line,
                return 0;
 
        if (filp)
-               ext4_error_file(filp, function, line, bh ? bh->b_blocknr : 0,
+               ext4_error_file(filp, function, line, bh->b_blocknr,
                                "bad entry in directory: %s - offset=%u(%u), "
                                "inode=%u, rec_len=%d, name_len=%d",
-                               error_msg, (unsigned) (offset%bh->b_size),
+                               error_msg, (unsigned) (offset % bh->b_size),
                                offset, le32_to_cpu(de->inode),
                                rlen, de->name_len);
        else
-               ext4_error_inode(dir, function, line, bh ? bh->b_blocknr : 0,
+               ext4_error_inode(dir, function, line, bh->b_blocknr,
                                "bad entry in directory: %s - offset=%u(%u), "
                                "inode=%u, rec_len=%d, name_len=%d",
-                               error_msg, (unsigned) (offset%bh->b_size),
+                               error_msg, (unsigned) (offset % bh->b_size),
                                offset, le32_to_cpu(de->inode),
                                rlen, de->name_len);
 
@@ -425,8 +425,9 @@ static int call_filldir(struct file *filp, void *dirent,
        sb = inode->i_sb;
 
        if (!fname) {
-               printk(KERN_ERR "EXT4-fs: call_filldir: called with "
-                      "null fname?!?\n");
+               ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: "
+                        "called with null fname?!?", __func__, __LINE__,
+                        inode->i_ino, current->comm);
                return 0;
        }
        curr_pos = hash2pos(fname->hash, fname->minor_hash);
index 513004f..ded731a 100644 (file)
@@ -53,7 +53,7 @@
                printk(KERN_DEBUG f, ## a);                             \
        } while (0)
 #else
-#define ext4_debug(f, a...)    do {} while (0)
+#define ext4_debug(fmt, ...)   no_printk(fmt, ##__VA_ARGS__)
 #endif
 
 #define EXT4_ERROR_INODE(inode, fmt, a...) \
@@ -184,6 +184,8 @@ struct mpage_da_data {
 #define        EXT4_IO_END_UNWRITTEN   0x0001
 #define EXT4_IO_END_ERROR      0x0002
 #define EXT4_IO_END_QUEUED     0x0004
+#define EXT4_IO_END_DIRECT     0x0008
+#define EXT4_IO_END_IN_FSYNC   0x0010
 
 struct ext4_io_page {
        struct page     *p_page;
@@ -192,18 +194,25 @@ struct ext4_io_page {
 
 #define MAX_IO_PAGES 128
 
+/*
+ * For converting uninitialized extents on a work queue.
+ *
+ * 'page' is only used from the writepage() path; 'pages' is only used for
+ * buffered writes; they are used to keep page references until conversion
+ * takes place.  For AIO/DIO, neither field is filled in.
+ */
 typedef struct ext4_io_end {
        struct list_head        list;           /* per-file finished IO list */
        struct inode            *inode;         /* file being written to */
        unsigned int            flag;           /* unwritten or not */
-       struct page             *page;          /* page struct for buffer write */
+       struct page             *page;          /* for writepage() path */
        loff_t                  offset;         /* offset in the file */
        ssize_t                 size;           /* size of the extent */
        struct work_struct      work;           /* data work queue */
        struct kiocb            *iocb;          /* iocb struct for AIO */
        int                     result;         /* error value for AIO */
-       int                     num_io_pages;
-       struct ext4_io_page     *pages[MAX_IO_PAGES];
+       int                     num_io_pages;   /* for writepages() */
+       struct ext4_io_page     *pages[MAX_IO_PAGES]; /* for writepages() */
 } ext4_io_end_t;
 
 struct ext4_io_submit {
@@ -923,6 +932,7 @@ struct ext4_inode_info {
 #define EXT4_MOUNT_ERRORS_CONT         0x00010 /* Continue on errors */
 #define EXT4_MOUNT_ERRORS_RO           0x00020 /* Remount fs ro on errors */
 #define EXT4_MOUNT_ERRORS_PANIC                0x00040 /* Panic on errors */
+#define EXT4_MOUNT_ERRORS_MASK         0x00070
 #define EXT4_MOUNT_MINIX_DF            0x00080 /* Mimics the Minix statfs */
 #define EXT4_MOUNT_NOLOAD              0x00100 /* Don't use existing journal*/
 #define EXT4_MOUNT_DATA_FLAGS          0x00C00 /* Mode for data writes: */
@@ -941,7 +951,6 @@ struct ext4_inode_info {
 #define EXT4_MOUNT_DIOREAD_NOLOCK      0x400000 /* Enable support for dio read nolocking */
 #define EXT4_MOUNT_JOURNAL_CHECKSUM    0x800000 /* Journal checksums */
 #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT        0x1000000 /* Journal Async Commit */
-#define EXT4_MOUNT_I_VERSION            0x2000000 /* i_version support */
 #define EXT4_MOUNT_MBLK_IO_SUBMIT      0x4000000 /* multi-block io submits */
 #define EXT4_MOUNT_DELALLOC            0x8000000 /* Delalloc support */
 #define EXT4_MOUNT_DATA_ERR_ABORT      0x10000000 /* Abort on file data write */
@@ -1142,6 +1151,7 @@ struct ext4_sb_info {
        unsigned int s_mount_opt;
        unsigned int s_mount_opt2;
        unsigned int s_mount_flags;
+       unsigned int s_def_mount_opt;
        ext4_fsblk_t s_sb_block;
        uid_t s_resuid;
        gid_t s_resgid;
@@ -1420,8 +1430,9 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
 #define EXT4_FEATURE_INCOMPAT_FLEX_BG          0x0200
 #define EXT4_FEATURE_INCOMPAT_EA_INODE         0x0400 /* EA in inode */
 #define EXT4_FEATURE_INCOMPAT_DIRDATA          0x1000 /* data in dirent */
-#define EXT4_FEATURE_INCOMPAT_INLINEDATA       0x2000 /* data in inode */
+#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */
 #define EXT4_FEATURE_INCOMPAT_LARGEDIR         0x4000 /* >2GB or 3-lvl htree */
+#define EXT4_FEATURE_INCOMPAT_INLINEDATA       0x8000 /* data in inode */
 
 #define EXT2_FEATURE_COMPAT_SUPP       EXT4_FEATURE_COMPAT_EXT_ATTR
 #define EXT2_FEATURE_INCOMPAT_SUPP     (EXT4_FEATURE_INCOMPAT_FILETYPE| \
@@ -1794,8 +1805,14 @@ extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
                                                    ext4_group_t block_group,
                                                    struct buffer_head ** bh);
 extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
-struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
-                                     ext4_group_t block_group);
+
+extern struct buffer_head *ext4_read_block_bitmap_nowait(struct super_block *sb,
+                                               ext4_group_t block_group);
+extern int ext4_wait_block_bitmap(struct super_block *sb,
+                                 ext4_group_t block_group,
+                                 struct buffer_head *bh);
+extern struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
+                                                 ext4_group_t block_group);
 extern void ext4_init_block_bitmap(struct super_block *sb,
                                   struct buffer_head *bh,
                                   ext4_group_t group,
@@ -1841,6 +1858,7 @@ extern void ext4_check_inodes_bitmap(struct super_block *);
 extern void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
 extern int ext4_init_inode_table(struct super_block *sb,
                                 ext4_group_t group, int barrier);
+extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate);
 
 /* mballoc.c */
 extern long ext4_mb_stats;
index a52db3a..0f58b86 100644 (file)
@@ -47,9 +47,9 @@
  */
 #define EXT_DEBUG__
 #ifdef EXT_DEBUG
-#define ext_debug(a...)                printk(a)
+#define ext_debug(fmt, ...)    printk(fmt, ##__VA_ARGS__)
 #else
-#define ext_debug(a...)
+#define ext_debug(fmt, ...)    no_printk(fmt, ##__VA_ARGS__)
 #endif
 
 /*
index 5802fa1..83b20fc 100644 (file)
 #define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb))
 #define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb))
 
+/**
+ *   struct ext4_journal_cb_entry - Base structure for callback information.
+ *
+ *   This struct is a 'seed' structure for a using with your own callback
+ *   structs. If you are using callbacks you must allocate one of these
+ *   or another struct of your own definition which has this struct
+ *   as it's first element and pass it to ext4_journal_callback_add().
+ */
+struct ext4_journal_cb_entry {
+       /* list information for other callbacks attached to the same handle */
+       struct list_head jce_list;
+
+       /*  Function to call with this callback structure */
+       void (*jce_func)(struct super_block *sb,
+                        struct ext4_journal_cb_entry *jce, int error);
+
+       /* user data goes here */
+};
+
+/**
+ * ext4_journal_callback_add: add a function to call after transaction commit
+ * @handle: active journal transaction handle to register callback on
+ * @func: callback function to call after the transaction has committed:
+ *        @sb: superblock of current filesystem for transaction
+ *        @jce: returned journal callback data
+ *        @rc: journal state at commit (0 = transaction committed properly)
+ * @jce: journal callback data (internal and function private data struct)
+ *
+ * The registered function will be called in the context of the journal thread
+ * after the transaction for which the handle was created has completed.
+ *
+ * No locks are held when the callback function is called, so it is safe to
+ * call blocking functions from within the callback, but the callback should
+ * not block or run for too long, or the filesystem will be blocked waiting for
+ * the next transaction to commit. No journaling functions can be used, or
+ * there is a risk of deadlock.
+ *
+ * There is no guaranteed calling order of multiple registered callbacks on
+ * the same transaction.
+ */
+static inline void ext4_journal_callback_add(handle_t *handle,
+                       void (*func)(struct super_block *sb,
+                                    struct ext4_journal_cb_entry *jce,
+                                    int rc),
+                       struct ext4_journal_cb_entry *jce)
+{
+       struct ext4_sb_info *sbi =
+                       EXT4_SB(handle->h_transaction->t_journal->j_private);
+
+       /* Add the jce to transaction's private list */
+       jce->jce_func = func;
+       spin_lock(&sbi->s_md_lock);
+       list_add_tail(&jce->jce_list, &handle->h_transaction->t_private_list);
+       spin_unlock(&sbi->s_md_lock);
+}
+
+/**
+ * ext4_journal_callback_del: delete a registered callback
+ * @handle: active journal transaction handle on which callback was registered
+ * @jce: registered journal callback entry to unregister
+ */
+static inline void ext4_journal_callback_del(handle_t *handle,
+                                            struct ext4_journal_cb_entry *jce)
+{
+       struct ext4_sb_info *sbi =
+                       EXT4_SB(handle->h_transaction->t_journal->j_private);
+
+       spin_lock(&sbi->s_md_lock);
+       list_del_init(&jce->jce_list);
+       spin_unlock(&sbi->s_md_lock);
+}
+
 int
 ext4_mark_iloc_dirty(handle_t *handle,
                     struct inode *inode,
@@ -261,43 +333,45 @@ static inline void ext4_update_inode_fsync_trans(handle_t *handle,
 /* super.c */
 int ext4_force_commit(struct super_block *sb);
 
-static inline int ext4_should_journal_data(struct inode *inode)
+/*
+ * Ext4 inode journal modes
+ */
+#define EXT4_INODE_JOURNAL_DATA_MODE   0x01 /* journal data mode */
+#define EXT4_INODE_ORDERED_DATA_MODE   0x02 /* ordered data mode */
+#define EXT4_INODE_WRITEBACK_DATA_MODE 0x04 /* writeback data mode */
+
+static inline int ext4_inode_journal_mode(struct inode *inode)
 {
        if (EXT4_JOURNAL(inode) == NULL)
-               return 0;
-       if (!S_ISREG(inode->i_mode))
-               return 1;
-       if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
-               return 1;
-       if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
-               return 1;
-       return 0;
+               return EXT4_INODE_WRITEBACK_DATA_MODE;  /* writeback */
+       /* We do not support data journalling with delayed allocation */
+       if (!S_ISREG(inode->i_mode) ||
+           test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
+               return EXT4_INODE_JOURNAL_DATA_MODE;    /* journal data */
+       if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) &&
+           !test_opt(inode->i_sb, DELALLOC))
+               return EXT4_INODE_JOURNAL_DATA_MODE;    /* journal data */
+       if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
+               return EXT4_INODE_ORDERED_DATA_MODE;    /* ordered */
+       if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
+               return EXT4_INODE_WRITEBACK_DATA_MODE;  /* writeback */
+       else
+               BUG();
+}
+
+static inline int ext4_should_journal_data(struct inode *inode)
+{
+       return ext4_inode_journal_mode(inode) & EXT4_INODE_JOURNAL_DATA_MODE;
 }
 
 static inline int ext4_should_order_data(struct inode *inode)
 {
-       if (EXT4_JOURNAL(inode) == NULL)
-               return 0;
-       if (!S_ISREG(inode->i_mode))
-               return 0;
-       if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
-               return 0;
-       if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
-               return 1;
-       return 0;
+       return ext4_inode_journal_mode(inode) & EXT4_INODE_ORDERED_DATA_MODE;
 }
 
 static inline int ext4_should_writeback_data(struct inode *inode)
 {
-       if (EXT4_JOURNAL(inode) == NULL)
-               return 1;
-       if (!S_ISREG(inode->i_mode))
-               return 0;
-       if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
-               return 0;
-       if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
-               return 1;
-       return 0;
+       return ext4_inode_journal_mode(inode) & EXT4_INODE_WRITEBACK_DATA_MODE;
 }
 
 /*
index 74f23c2..1421938 100644 (file)
 
 #include <trace/events/ext4.h>
 
+/*
+ * used by extent splitting.
+ */
+#define EXT4_EXT_MAY_ZEROOUT   0x1  /* safe to zeroout if split fails \
+                                       due to ENOSPC */
+#define EXT4_EXT_MARK_UNINIT1  0x2  /* mark first half uninitialized */
+#define EXT4_EXT_MARK_UNINIT2  0x4  /* mark second half uninitialized */
+
 static int ext4_split_extent(handle_t *handle,
                                struct inode *inode,
                                struct ext4_ext_path *path,
@@ -51,6 +59,13 @@ static int ext4_split_extent(handle_t *handle,
                                int split_flag,
                                int flags);
 
+static int ext4_split_extent_at(handle_t *handle,
+                            struct inode *inode,
+                            struct ext4_ext_path *path,
+                            ext4_lblk_t split,
+                            int split_flag,
+                            int flags);
+
 static int ext4_ext_truncate_extend_restart(handle_t *handle,
                                            struct inode *inode,
                                            int needed)
@@ -300,6 +315,8 @@ static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
        ext4_fsblk_t block = ext4_ext_pblock(ext);
        int len = ext4_ext_get_actual_len(ext);
 
+       if (len == 0)
+               return 0;
        return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
 }
 
@@ -2308,7 +2325,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
        struct ext4_extent *ex;
 
        /* the header must be checked already in ext4_ext_remove_space() */
-       ext_debug("truncate since %u in leaf\n", start);
+       ext_debug("truncate since %u in leaf to %u\n", start, end);
        if (!path[depth].p_hdr)
                path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
        eh = path[depth].p_hdr;
@@ -2343,14 +2360,17 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
                ext_debug("  border %u:%u\n", a, b);
 
                /* If this extent is beyond the end of the hole, skip it */
-               if (end <= ex_ee_block) {
+               if (end < ex_ee_block) {
                        ex--;
                        ex_ee_block = le32_to_cpu(ex->ee_block);
                        ex_ee_len = ext4_ext_get_actual_len(ex);
                        continue;
                } else if (b != ex_ee_block + ex_ee_len - 1) {
-                       EXT4_ERROR_INODE(inode,"  bad truncate %u:%u\n",
-                                        start, end);
+                       EXT4_ERROR_INODE(inode,
+                                        "can not handle truncate %u:%u "
+                                        "on extent %u:%u",
+                                        start, end, ex_ee_block,
+                                        ex_ee_block + ex_ee_len - 1);
                        err = -EIO;
                        goto out;
                } else if (a != ex_ee_block) {
@@ -2482,7 +2502,8 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path)
        return 1;
 }
 
-static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
+static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
+                                ext4_lblk_t end)
 {
        struct super_block *sb = inode->i_sb;
        int depth = ext_depth(inode);
@@ -2491,7 +2512,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
        handle_t *handle;
        int i, err;
 
-       ext_debug("truncate since %u\n", start);
+       ext_debug("truncate since %u to %u\n", start, end);
 
        /* probably first extent we're gonna free will be last in block */
        handle = ext4_journal_start(inode, depth + 1);
@@ -2504,6 +2525,61 @@ again:
        trace_ext4_ext_remove_space(inode, start, depth);
 
        /*
+        * Check if we are removing extents inside the extent tree. If that
+        * is the case, we are going to punch a hole inside the extent tree
+        * so we have to check whether we need to split the extent covering
+        * the last block to remove so we can easily remove the part of it
+        * in ext4_ext_rm_leaf().
+        */
+       if (end < EXT_MAX_BLOCKS - 1) {
+               struct ext4_extent *ex;
+               ext4_lblk_t ee_block;
+
+               /* find extent for this block */
+               path = ext4_ext_find_extent(inode, end, NULL);
+               if (IS_ERR(path)) {
+                       ext4_journal_stop(handle);
+                       return PTR_ERR(path);
+               }
+               depth = ext_depth(inode);
+               ex = path[depth].p_ext;
+               if (!ex)
+                       goto cont;
+
+               ee_block = le32_to_cpu(ex->ee_block);
+
+               /*
+                * See if the last block is inside the extent, if so split
+                * the extent at 'end' block so we can easily remove the
+                * tail of the first part of the split extent in
+                * ext4_ext_rm_leaf().
+                */
+               if (end >= ee_block &&
+                   end < ee_block + ext4_ext_get_actual_len(ex) - 1) {
+                       int split_flag = 0;
+
+                       if (ext4_ext_is_uninitialized(ex))
+                               split_flag = EXT4_EXT_MARK_UNINIT1 |
+                                            EXT4_EXT_MARK_UNINIT2;
+
+                       /*
+                        * Split the extent in two so that 'end' is the last
+                        * block in the first new extent
+                        */
+                       err = ext4_split_extent_at(handle, inode, path,
+                                               end + 1, split_flag,
+                                               EXT4_GET_BLOCKS_PRE_IO |
+                                               EXT4_GET_BLOCKS_PUNCH_OUT_EXT);
+
+                       if (err < 0)
+                               goto out;
+               }
+               ext4_ext_drop_refs(path);
+               kfree(path);
+       }
+cont:
+
+       /*
         * We start scanning from right side, freeing all the blocks
         * after i_size and walking into the tree depth-wise.
         */
@@ -2515,6 +2591,7 @@ again:
        }
        path[0].p_depth = depth;
        path[0].p_hdr = ext_inode_hdr(inode);
+
        if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
                err = -EIO;
                goto out;
@@ -2526,7 +2603,7 @@ again:
                        /* this is leaf block */
                        err = ext4_ext_rm_leaf(handle, inode, path,
                                               &partial_cluster, start,
-                                              EXT_MAX_BLOCKS - 1);
+                                              end);
                        /* root level has p_bh == NULL, brelse() eats this */
                        brelse(path[i].p_bh);
                        path[i].p_bh = NULL;
@@ -2651,17 +2728,17 @@ void ext4_ext_init(struct super_block *sb)
 
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
 #if defined(AGGRESSIVE_TEST) || defined(CHECK_BINSEARCH) || defined(EXTENTS_STATS)
-               printk(KERN_INFO "EXT4-fs: file extents enabled");
+               printk(KERN_INFO "EXT4-fs: file extents enabled"
 #ifdef AGGRESSIVE_TEST
-               printk(", aggressive tests");
+                      ", aggressive tests"
 #endif
 #ifdef CHECK_BINSEARCH
-               printk(", check binsearch");
+                      ", check binsearch"
 #endif
 #ifdef EXTENTS_STATS
-               printk(", stats");
+                      ", stats"
 #endif
-               printk("\n");
+                      "\n");
 #endif
 #ifdef EXTENTS_STATS
                spin_lock_init(&EXT4_SB(sb)->s_ext_stats_lock);
@@ -2709,14 +2786,6 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
 }
 
 /*
- * used by extent splitting.
- */
-#define EXT4_EXT_MAY_ZEROOUT   0x1  /* safe to zeroout if split fails \
-                                       due to ENOSPC */
-#define EXT4_EXT_MARK_UNINIT1  0x2  /* mark first half uninitialized */
-#define EXT4_EXT_MARK_UNINIT2  0x4  /* mark second half uninitialized */
-
-/*
  * ext4_split_extent_at() splits an extent at given block.
  *
  * @handle: the journal handle
@@ -3224,11 +3293,13 @@ static int check_eofblocks_fl(handle_t *handle, struct inode *inode,
        depth = ext_depth(inode);
        eh = path[depth].p_hdr;
 
-       if (unlikely(!eh->eh_entries)) {
-               EXT4_ERROR_INODE(inode, "eh->eh_entries == 0 and "
-                                "EOFBLOCKS_FL set");
-               return -EIO;
-       }
+       /*
+        * We're going to remove EOFBLOCKS_FL entirely in future so we
+        * do not care for this case anymore. Simply remove the flag
+        * if there are no extents.
+        */
+       if (unlikely(!eh->eh_entries))
+               goto out;
        last_ex = EXT_LAST_EXTENT(eh);
        /*
         * We should clear the EOFBLOCKS_FL flag if we are writing the
@@ -3252,6 +3323,7 @@ static int check_eofblocks_fl(handle_t *handle, struct inode *inode,
        for (i = depth-1; i >= 0; i--)
                if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr))
                        return 0;
+out:
        ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
        return ext4_mark_inode_dirty(handle, inode);
 }
@@ -3710,8 +3782,6 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
        int free_on_err = 0, err = 0, depth, ret;
        unsigned int allocated = 0, offset = 0;
        unsigned int allocated_clusters = 0;
-       unsigned int punched_out = 0;
-       unsigned int result = 0;
        struct ext4_allocation_request ar;
        ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
        ext4_lblk_t cluster_offset;
@@ -3721,8 +3791,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
        trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
 
        /* check in cache */
-       if (!(flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) &&
-               ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
+       if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
                if (!newex.ee_start_lo && !newex.ee_start_hi) {
                        if ((sbi->s_cluster_ratio > 1) &&
                            ext4_find_delalloc_cluster(inode, map->m_lblk, 0))
@@ -3790,113 +3859,25 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
 
                /* if found extent covers block, simply return it */
                if (in_range(map->m_lblk, ee_block, ee_len)) {
-                       struct ext4_map_blocks punch_map;
-                       ext4_fsblk_t partial_cluster = 0;
-
                        newblock = map->m_lblk - ee_block + ee_start;
                        /* number of remaining blocks in the extent */
                        allocated = ee_len - (map->m_lblk - ee_block);
                        ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk,
                                  ee_block, ee_len, newblock);
 
-                       if ((flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) == 0) {
-                               /*
-                                * Do not put uninitialized extent
-                                * in the cache
-                                */
-                               if (!ext4_ext_is_uninitialized(ex)) {
-                                       ext4_ext_put_in_cache(inode, ee_block,
-                                               ee_len, ee_start);
-                                       goto out;
-                               }
-                               ret = ext4_ext_handle_uninitialized_extents(
-                                       handle, inode, map, path, flags,
-                                       allocated, newblock);
-                               return ret;
-                       }
-
-                       /*
-                        * Punch out the map length, but only to the
-                        * end of the extent
-                        */
-                       punched_out = allocated < map->m_len ?
-                               allocated : map->m_len;
-
                        /*
-                        * Sense extents need to be converted to
-                        * uninitialized, they must fit in an
-                        * uninitialized extent
+                        * Do not put uninitialized extent
+                        * in the cache
                         */
-                       if (punched_out > EXT_UNINIT_MAX_LEN)
-                               punched_out = EXT_UNINIT_MAX_LEN;
-
-                       punch_map.m_lblk = map->m_lblk;
-                       punch_map.m_pblk = newblock;
-                       punch_map.m_len = punched_out;
-                       punch_map.m_flags = 0;
-
-                       /* Check to see if the extent needs to be split */
-                       if (punch_map.m_len != ee_len ||
-                               punch_map.m_lblk != ee_block) {
-
-                               ret = ext4_split_extent(handle, inode,
-                               path, &punch_map, 0,
-                               EXT4_GET_BLOCKS_PUNCH_OUT_EXT |
-                               EXT4_GET_BLOCKS_PRE_IO);
-
-                               if (ret < 0) {
-                                       err = ret;
-                                       goto out2;
-                               }
-                               /*
-                                * find extent for the block at
-                                * the start of the hole
-                                */
-                               ext4_ext_drop_refs(path);
-                               kfree(path);
-
-                               path = ext4_ext_find_extent(inode,
-                               map->m_lblk, NULL);
-                               if (IS_ERR(path)) {
-                                       err = PTR_ERR(path);
-                                       path = NULL;
-                                       goto out2;
-                               }
-
-                               depth = ext_depth(inode);
-                               ex = path[depth].p_ext;
-                               ee_len = ext4_ext_get_actual_len(ex);
-                               ee_block = le32_to_cpu(ex->ee_block);
-                               ee_start = ext4_ext_pblock(ex);
-
-                       }
-
-                       ext4_ext_mark_uninitialized(ex);
-
-                       ext4_ext_invalidate_cache(inode);
-
-                       err = ext4_ext_rm_leaf(handle, inode, path,
-                                              &partial_cluster, map->m_lblk,
-                                              map->m_lblk + punched_out);
-
-                       if (!err && path->p_hdr->eh_entries == 0) {
-                               /*
-                                * Punch hole freed all of this sub tree,
-                                * so we need to correct eh_depth
-                                */
-                               err = ext4_ext_get_access(handle, inode, path);
-                               if (err == 0) {
-                                       ext_inode_hdr(inode)->eh_depth = 0;
-                                       ext_inode_hdr(inode)->eh_max =
-                                       cpu_to_le16(ext4_ext_space_root(
-                                               inode, 0));
-
-                                       err = ext4_ext_dirty(
-                                               handle, inode, path);
-                               }
+                       if (!ext4_ext_is_uninitialized(ex)) {
+                               ext4_ext_put_in_cache(inode, ee_block,
+                                       ee_len, ee_start);
+                               goto out;
                        }
-
-                       goto out2;
+                       ret = ext4_ext_handle_uninitialized_extents(
+                               handle, inode, map, path, flags,
+                               allocated, newblock);
+                       return ret;
                }
        }
 
@@ -4165,13 +4146,11 @@ out2:
                ext4_ext_drop_refs(path);
                kfree(path);
        }
-       result = (flags & EXT4_GET_BLOCKS_PUNCH_OUT_EXT) ?
-                       punched_out : allocated;
 
        trace_ext4_ext_map_blocks_exit(inode, map->m_lblk,
-               newblock, map->m_len, err ? err : result);
+               newblock, map->m_len, err ? err : allocated);
 
-       return err ? err : result;
+       return err ? err : allocated;
 }
 
 void ext4_ext_truncate(struct inode *inode)
@@ -4228,7 +4207,7 @@ void ext4_ext_truncate(struct inode *inode)
 
        last_block = (inode->i_size + sb->s_blocksize - 1)
                        >> EXT4_BLOCK_SIZE_BITS(sb);
-       err = ext4_ext_remove_space(inode, last_block);
+       err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1);
 
        /* In a multi-transaction truncate, we only make the final
         * transaction synchronous.
@@ -4436,10 +4415,11 @@ int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
                                      EXT4_GET_BLOCKS_IO_CONVERT_EXT);
                if (ret <= 0) {
                        WARN_ON(ret <= 0);
-                       printk(KERN_ERR "%s: ext4_ext_map_blocks "
-                                   "returned error inode#%lu, block=%u, "
-                                   "max_blocks=%u", __func__,
-                                   inode->i_ino, map.m_lblk, map.m_len);
+                       ext4_msg(inode->i_sb, KERN_ERR,
+                                "%s:%d: inode #%lu: block %u: len %u: "
+                                "ext4_ext_map_blocks returned %d",
+                                __func__, __LINE__, inode->i_ino, map.m_lblk,
+                                map.m_len, ret);
                }
                ext4_mark_inode_dirty(handle, inode);
                ret2 = ext4_journal_stop(handle);
@@ -4705,14 +4685,12 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length)
 {
        struct inode *inode = file->f_path.dentry->d_inode;
        struct super_block *sb = inode->i_sb;
-       struct ext4_ext_cache cache_ex;
-       ext4_lblk_t first_block, last_block, num_blocks, iblock, max_blocks;
+       ext4_lblk_t first_block, stop_block;
        struct address_space *mapping = inode->i_mapping;
-       struct ext4_map_blocks map;
        handle_t *handle;
        loff_t first_page, last_page, page_len;
        loff_t first_page_offset, last_page_offset;
-       int ret, credits, blocks_released, err = 0;
+       int credits, err = 0;
 
        /* No need to punch hole beyond i_size */
        if (offset >= inode->i_size)
@@ -4728,10 +4706,6 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length)
                   offset;
        }
 
-       first_block = (offset + sb->s_blocksize - 1) >>
-               EXT4_BLOCK_SIZE_BITS(sb);
-       last_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);
-
        first_page = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
        last_page = (offset + length) >> PAGE_CACHE_SHIFT;
 
@@ -4810,7 +4784,6 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length)
                }
        }
 
-
        /*
         * If i_size is contained in the last page, we need to
         * unmap and zero the partial page after i_size
@@ -4830,73 +4803,22 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length)
                }
        }
 
+       first_block = (offset + sb->s_blocksize - 1) >>
+               EXT4_BLOCK_SIZE_BITS(sb);
+       stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);
+
        /* If there are no blocks to remove, return now */
-       if (first_block >= last_block)
+       if (first_block >= stop_block)
                goto out;
 
        down_write(&EXT4_I(inode)->i_data_sem);
        ext4_ext_invalidate_cache(inode);
        ext4_discard_preallocations(inode);
 
-       /*
-        * Loop over all the blocks and identify blocks
-        * that need to be punched out
-        */
-       iblock = first_block;
-       blocks_released = 0;
-       while (iblock < last_block) {
-               max_blocks = last_block - iblock;
-               num_blocks = 1;
-               memset(&map, 0, sizeof(map));
-               map.m_lblk = iblock;
-               map.m_len = max_blocks;
-               ret = ext4_ext_map_blocks(handle, inode, &map,
-                       EXT4_GET_BLOCKS_PUNCH_OUT_EXT);
-
-               if (ret > 0) {
-                       blocks_released += ret;
-                       num_blocks = ret;
-               } else if (ret == 0) {
-                       /*
-                        * If map blocks could not find the block,
-                        * then it is in a hole.  If the hole was
-                        * not already cached, then map blocks should
-                        * put it in the cache.  So we can get the hole
-                        * out of the cache
-                        */
-                       memset(&cache_ex, 0, sizeof(cache_ex));
-                       if ((ext4_ext_check_cache(inode, iblock, &cache_ex)) &&
-                               !cache_ex.ec_start) {
-
-                               /* The hole is cached */
-                               num_blocks = cache_ex.ec_block +
-                               cache_ex.ec_len - iblock;
-
-                       } else {
-                               /* The block could not be identified */
-                               err = -EIO;
-                               break;
-                       }
-               } else {
-                       /* Map blocks error */
-                       err = ret;
-                       break;
-               }
-
-               if (num_blocks == 0) {
-                       /* This condition should never happen */
-                       ext_debug("Block lookup failed");
-                       err = -EIO;
-                       break;
-               }
-
-               iblock += num_blocks;
-       }
+       err = ext4_ext_remove_space(inode, first_block, stop_block - 1);
 
-       if (blocks_released > 0) {
-               ext4_ext_invalidate_cache(inode);
-               ext4_discard_preallocations(inode);
-       }
+       ext4_ext_invalidate_cache(inode);
+       ext4_discard_preallocations(inode);
 
        if (IS_SYNC(inode))
                ext4_handle_sync(handle);
index 00a2cb7..bb6c7d8 100644 (file)
@@ -89,6 +89,7 @@ int ext4_flush_completed_IO(struct inode *inode)
                io = list_entry(ei->i_completed_io_list.next,
                                ext4_io_end_t, list);
                list_del_init(&io->list);
+               io->flag |= EXT4_IO_END_IN_FSYNC;
                /*
                 * Calling ext4_end_io_nolock() to convert completed
                 * IO to written.
@@ -108,6 +109,7 @@ int ext4_flush_completed_IO(struct inode *inode)
                if (ret < 0)
                        ret2 = ret;
                spin_lock_irqsave(&ei->i_completed_io_lock, flags);
+               io->flag &= ~EXT4_IO_END_IN_FSYNC;
        }
        spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
        return (ret2 < 0) ? ret2 : 0;
index 25d8c97..409c2ee 100644 (file)
@@ -92,6 +92,16 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
        return EXT4_INODES_PER_GROUP(sb);
 }
 
+void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
+{
+       if (uptodate) {
+               set_buffer_uptodate(bh);
+               set_bitmap_uptodate(bh);
+       }
+       unlock_buffer(bh);
+       put_bh(bh);
+}
+
 /*
  * Read the inode allocation bitmap for a given block_group, reading
  * into the specified slot in the superblock's bitmap cache.
@@ -147,18 +157,18 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
                return bh;
        }
        /*
-        * submit the buffer_head for read. We can
-        * safely mark the bitmap as uptodate now.
-        * We do it here so the bitmap uptodate bit
-        * get set with buffer lock held.
+        * submit the buffer_head for reading
         */
        trace_ext4_load_inode_bitmap(sb, block_group);
-       set_bitmap_uptodate(bh);
-       if (bh_submit_read(bh) < 0) {
+       bh->b_end_io = ext4_end_bitmap_read;
+       get_bh(bh);
+       submit_bh(READ, bh);
+       wait_on_buffer(bh);
+       if (!buffer_uptodate(bh)) {
                put_bh(bh);
                ext4_error(sb, "Cannot read inode bitmap - "
-                           "block_group = %u, inode_bitmap = %llu",
-                           block_group, bitmap_blk);
+                          "block_group = %u, inode_bitmap = %llu",
+                          block_group, bitmap_blk);
                return NULL;
        }
        return bh;
@@ -194,19 +204,20 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
        struct ext4_sb_info *sbi;
        int fatal = 0, err, count, cleared;
 
-       if (atomic_read(&inode->i_count) > 1) {
-               printk(KERN_ERR "ext4_free_inode: inode has count=%d\n",
-                      atomic_read(&inode->i_count));
+       if (!sb) {
+               printk(KERN_ERR "EXT4-fs: %s:%d: inode on "
+                      "nonexistent device\n", __func__, __LINE__);
                return;
        }
-       if (inode->i_nlink) {
-               printk(KERN_ERR "ext4_free_inode: inode has nlink=%d\n",
-                      inode->i_nlink);
+       if (atomic_read(&inode->i_count) > 1) {
+               ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: count=%d",
+                        __func__, __LINE__, inode->i_ino,
+                        atomic_read(&inode->i_count));
                return;
        }
-       if (!sb) {
-               printk(KERN_ERR "ext4_free_inode: inode on "
-                      "nonexistent device\n");
+       if (inode->i_nlink) {
+               ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: nlink=%d\n",
+                        __func__, __LINE__, inode->i_ino, inode->i_nlink);
                return;
        }
        sbi = EXT4_SB(sb);
@@ -593,94 +604,6 @@ static int find_group_other(struct super_block *sb, struct inode *parent,
 }
 
 /*
- * claim the inode from the inode bitmap. If the group
- * is uninit we need to take the groups's ext4_group_lock
- * and clear the uninit flag. The inode bitmap update
- * and group desc uninit flag clear should be done
- * after holding ext4_group_lock so that ext4_read_inode_bitmap
- * doesn't race with the ext4_claim_inode
- */
-static int ext4_claim_inode(struct super_block *sb,
-                       struct buffer_head *inode_bitmap_bh,
-                       unsigned long ino, ext4_group_t group, umode_t mode)
-{
-       int free = 0, retval = 0, count;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct ext4_group_info *grp = ext4_get_group_info(sb, group);
-       struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
-
-       /*
-        * We have to be sure that new inode allocation does not race with
-        * inode table initialization, because otherwise we may end up
-        * allocating and writing new inode right before sb_issue_zeroout
-        * takes place and overwriting our new inode with zeroes. So we
-        * take alloc_sem to prevent it.
-        */
-       down_read(&grp->alloc_sem);
-       ext4_lock_group(sb, group);
-       if (ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data)) {
-               /* not a free inode */
-               retval = 1;
-               goto err_ret;
-       }
-       ino++;
-       if ((group == 0 && ino < EXT4_FIRST_INO(sb)) ||
-                       ino > EXT4_INODES_PER_GROUP(sb)) {
-               ext4_unlock_group(sb, group);
-               up_read(&grp->alloc_sem);
-               ext4_error(sb, "reserved inode or inode > inodes count - "
-                          "block_group = %u, inode=%lu", group,
-                          ino + group * EXT4_INODES_PER_GROUP(sb));
-               return 1;
-       }
-       /* If we didn't allocate from within the initialized part of the inode
-        * table then we need to initialize up to this inode. */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-
-               if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
-                       gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
-                       /* When marking the block group with
-                        * ~EXT4_BG_INODE_UNINIT we don't want to depend
-                        * on the value of bg_itable_unused even though
-                        * mke2fs could have initialized the same for us.
-                        * Instead we calculated the value below
-                        */
-
-                       free = 0;
-               } else {
-                       free = EXT4_INODES_PER_GROUP(sb) -
-                               ext4_itable_unused_count(sb, gdp);
-               }
-
-               /*
-                * Check the relative inode number against the last used
-                * relative inode number in this group. if it is greater
-                * we need to  update the bg_itable_unused count
-                *
-                */
-               if (ino > free)
-                       ext4_itable_unused_set(sb, gdp,
-                                       (EXT4_INODES_PER_GROUP(sb) - ino));
-       }
-       count = ext4_free_inodes_count(sb, gdp) - 1;
-       ext4_free_inodes_set(sb, gdp, count);
-       if (S_ISDIR(mode)) {
-               count = ext4_used_dirs_count(sb, gdp) + 1;
-               ext4_used_dirs_set(sb, gdp, count);
-               if (sbi->s_log_groups_per_flex) {
-                       ext4_group_t f = ext4_flex_group(sbi, group);
-
-                       atomic_inc(&sbi->s_flex_groups[f].used_dirs);
-               }
-       }
-       gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
-err_ret:
-       ext4_unlock_group(sb, group);
-       up_read(&grp->alloc_sem);
-       return retval;
-}
-
-/*
  * There are two policies for allocating an inode.  If the new inode is
  * a directory, then a forward search is made for a block group with both
  * free space and a low directory-to-inode ratio; if that fails, then of
@@ -741,6 +664,11 @@ got_group:
        if (ret2 == -1)
                goto out;
 
+       /*
+        * Normally we will only go through one pass of this loop,
+        * unless we get unlucky and it turns out the group we selected
+        * had its last inode grabbed by someone else.
+        */
        for (i = 0; i < ngroups; i++, ino = 0) {
                err = -EIO;
 
@@ -757,51 +685,24 @@ repeat_in_this_group:
                ino = ext4_find_next_zero_bit((unsigned long *)
                                              inode_bitmap_bh->b_data,
                                              EXT4_INODES_PER_GROUP(sb), ino);
-
-               if (ino < EXT4_INODES_PER_GROUP(sb)) {
-
-                       BUFFER_TRACE(inode_bitmap_bh, "get_write_access");
-                       err = ext4_journal_get_write_access(handle,
-                                                           inode_bitmap_bh);
-                       if (err)
-                               goto fail;
-
-                       BUFFER_TRACE(group_desc_bh, "get_write_access");
-                       err = ext4_journal_get_write_access(handle,
-                                                               group_desc_bh);
-                       if (err)
-                               goto fail;
-                       if (!ext4_claim_inode(sb, inode_bitmap_bh,
-                                               ino, group, mode)) {
-                               /* we won it */
-                               BUFFER_TRACE(inode_bitmap_bh,
-                                       "call ext4_handle_dirty_metadata");
-                               err = ext4_handle_dirty_metadata(handle,
-                                                                NULL,
-                                                       inode_bitmap_bh);
-                               if (err)
-                                       goto fail;
-                               /* zero bit is inode number 1*/
-                               ino++;
-                               goto got;
-                       }
-                       /* we lost it */
-                       ext4_handle_release_buffer(handle, inode_bitmap_bh);
-                       ext4_handle_release_buffer(handle, group_desc_bh);
-
-                       if (++ino < EXT4_INODES_PER_GROUP(sb))
-                               goto repeat_in_this_group;
+               if (ino >= EXT4_INODES_PER_GROUP(sb)) {
+                       if (++group == ngroups)
+                               group = 0;
+                       continue;
                }
-
-               /*
-                * This case is possible in concurrent environment.  It is very
-                * rare.  We cannot repeat the find_group_xxx() call because
-                * that will simply return the same blockgroup, because the
-                * group descriptor metadata has not yet been updated.
-                * So we just go onto the next blockgroup.
-                */
-               if (++group == ngroups)
-                       group = 0;
+               if (group == 0 && (ino+1) < EXT4_FIRST_INO(sb)) {
+                       ext4_error(sb, "reserved inode found cleared - "
+                                  "inode=%lu", ino + 1);
+                       continue;
+               }
+               ext4_lock_group(sb, group);
+               ret2 = ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data);
+               ext4_unlock_group(sb, group);
+               ino++;          /* the inode bitmap is zero-based */
+               if (!ret2)
+                       goto got; /* we grabbed the inode! */
+               if (ino < EXT4_INODES_PER_GROUP(sb))
+                       goto repeat_in_this_group;
        }
        err = -ENOSPC;
        goto out;
@@ -838,6 +739,59 @@ got:
                if (err)
                        goto fail;
        }
+
+       BUFFER_TRACE(inode_bitmap_bh, "get_write_access");
+       err = ext4_journal_get_write_access(handle, inode_bitmap_bh);
+       if (err)
+               goto fail;
+
+       BUFFER_TRACE(group_desc_bh, "get_write_access");
+       err = ext4_journal_get_write_access(handle, group_desc_bh);
+       if (err)
+               goto fail;
+
+       /* Update the relevant bg descriptor fields */
+       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+               int free;
+               struct ext4_group_info *grp = ext4_get_group_info(sb, group);
+
+               down_read(&grp->alloc_sem); /* protect vs itable lazyinit */
+               ext4_lock_group(sb, group); /* while we modify the bg desc */
+               free = EXT4_INODES_PER_GROUP(sb) -
+                       ext4_itable_unused_count(sb, gdp);
+               if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
+                       gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
+                       free = 0;
+               }
+               /*
+                * Check the relative inode number against the last used
+                * relative inode number in this group. if it is greater
+                * we need to update the bg_itable_unused count
+                */
+               if (ino > free)
+                       ext4_itable_unused_set(sb, gdp,
+                                       (EXT4_INODES_PER_GROUP(sb) - ino));
+               up_read(&grp->alloc_sem);
+       }
+       ext4_free_inodes_set(sb, gdp, ext4_free_inodes_count(sb, gdp) - 1);
+       if (S_ISDIR(mode)) {
+               ext4_used_dirs_set(sb, gdp, ext4_used_dirs_count(sb, gdp) + 1);
+               if (sbi->s_log_groups_per_flex) {
+                       ext4_group_t f = ext4_flex_group(sbi, group);
+
+                       atomic_inc(&sbi->s_flex_groups[f].used_dirs);
+               }
+       }
+       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+               gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
+               ext4_unlock_group(sb, group);
+       }
+
+       BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata");
+       err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh);
+       if (err)
+               goto fail;
+
        BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata");
        err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh);
        if (err)
@@ -1101,7 +1055,7 @@ unsigned long ext4_count_dirs(struct super_block * sb)
  * where it is called from on active part of filesystem is ext4lazyinit
  * thread, so we do not need any special locks, however we have to prevent
  * inode allocation from the current group, so we take alloc_sem lock, to
- * block ext4_claim_inode until we are finished.
+ * block ext4_new_inode() until we are finished.
  */
 int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
                                 int barrier)
@@ -1149,9 +1103,9 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
                            sbi->s_inodes_per_block);
 
        if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) {
-               ext4_error(sb, "Something is wrong with group %u\n"
-                          "Used itable blocks: %d"
-                          "itable unused count: %u\n",
+               ext4_error(sb, "Something is wrong with group %u: "
+                          "used itable blocks: %d; "
+                          "itable unused count: %u",
                           group, used_blks,
                           ext4_itable_unused_count(sb, gdp));
                ret = 1;
index feaa82f..c77b0bd 100644 (file)
@@ -272,7 +272,7 @@ void ext4_da_update_reserve_space(struct inode *inode,
        trace_ext4_da_update_reserve_space(inode, used, quota_claim);
        if (unlikely(used > ei->i_reserved_data_blocks)) {
                ext4_msg(inode->i_sb, KERN_NOTICE, "%s: ino %lu, used %d "
-                        "with only %d reserved data blocks\n",
+                        "with only %d reserved data blocks",
                         __func__, inode->i_ino, used,
                         ei->i_reserved_data_blocks);
                WARN_ON(1);
@@ -1165,7 +1165,7 @@ static void ext4_da_release_space(struct inode *inode, int to_free)
                 */
                ext4_msg(inode->i_sb, KERN_NOTICE, "ext4_da_release_space: "
                         "ino %lu, to_free %d with only %d reserved "
-                        "data blocks\n", inode->i_ino, to_free,
+                        "data blocks", inode->i_ino, to_free,
                         ei->i_reserved_data_blocks);
                WARN_ON(1);
                to_free = ei->i_reserved_data_blocks;
@@ -1428,20 +1428,22 @@ static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd)
 static void ext4_print_free_blocks(struct inode *inode)
 {
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-       printk(KERN_CRIT "Total free blocks count %lld\n",
+       struct super_block *sb = inode->i_sb;
+
+       ext4_msg(sb, KERN_CRIT, "Total free blocks count %lld",
               EXT4_C2B(EXT4_SB(inode->i_sb),
                        ext4_count_free_clusters(inode->i_sb)));
-       printk(KERN_CRIT "Free/Dirty block details\n");
-       printk(KERN_CRIT "free_blocks=%lld\n",
+       ext4_msg(sb, KERN_CRIT, "Free/Dirty block details");
+       ext4_msg(sb, KERN_CRIT, "free_blocks=%lld",
               (long long) EXT4_C2B(EXT4_SB(inode->i_sb),
                percpu_counter_sum(&sbi->s_freeclusters_counter)));
-       printk(KERN_CRIT "dirty_blocks=%lld\n",
+       ext4_msg(sb, KERN_CRIT, "dirty_blocks=%lld",
               (long long) EXT4_C2B(EXT4_SB(inode->i_sb),
                percpu_counter_sum(&sbi->s_dirtyclusters_counter)));
-       printk(KERN_CRIT "Block reservation details\n");
-       printk(KERN_CRIT "i_reserved_data_blocks=%u\n",
-              EXT4_I(inode)->i_reserved_data_blocks);
-       printk(KERN_CRIT "i_reserved_meta_blocks=%u\n",
+       ext4_msg(sb, KERN_CRIT, "Block reservation details");
+       ext4_msg(sb, KERN_CRIT, "i_reserved_data_blocks=%u",
+                EXT4_I(inode)->i_reserved_data_blocks);
+       ext4_msg(sb, KERN_CRIT, "i_reserved_meta_blocks=%u",
               EXT4_I(inode)->i_reserved_meta_blocks);
        return;
 }
@@ -2482,13 +2484,14 @@ static int ext4_da_write_end(struct file *file,
        int write_mode = (int)(unsigned long)fsdata;
 
        if (write_mode == FALL_BACK_TO_NONDELALLOC) {
-               if (ext4_should_order_data(inode)) {
+               switch (ext4_inode_journal_mode(inode)) {
+               case EXT4_INODE_ORDERED_DATA_MODE:
                        return ext4_ordered_write_end(file, mapping, pos,
                                        len, copied, page, fsdata);
-               } else if (ext4_should_writeback_data(inode)) {
+               case EXT4_INODE_WRITEBACK_DATA_MODE:
                        return ext4_writeback_write_end(file, mapping, pos,
                                        len, copied, page, fsdata);
-               } else {
+               default:
                        BUG();
                }
        }
@@ -2763,7 +2766,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
                goto out;
 
        ext_debug("ext4_end_io_dio(): io_end 0x%p "
-                 "for inode %lu, iocb 0x%p, offset %llu, size %llu\n",
+                 "for inode %lu, iocb 0x%p, offset %llu, size %zd\n",
                  iocb->private, io_end->inode->i_ino, iocb, offset,
                  size);
 
@@ -2795,9 +2798,6 @@ out:
 
        /* queue the work to convert unwritten extents to written */
        queue_work(wq, &io_end->work);
-
-       /* XXX: probably should move into the real I/O completion handler */
-       inode_dio_done(inode);
 }
 
 static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate)
@@ -2811,8 +2811,9 @@ static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate)
                goto out;
 
        if (!(io_end->inode->i_sb->s_flags & MS_ACTIVE)) {
-               printk("sb umounted, discard end_io request for inode %lu\n",
-                       io_end->inode->i_ino);
+               ext4_msg(io_end->inode->i_sb, KERN_INFO,
+                        "sb umounted, discard end_io request for inode %lu",
+                        io_end->inode->i_ino);
                ext4_free_io_end(io_end);
                goto out;
        }
@@ -2921,9 +2922,12 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
                iocb->private = NULL;
                EXT4_I(inode)->cur_aio_dio = NULL;
                if (!is_sync_kiocb(iocb)) {
-                       iocb->private = ext4_init_io_end(inode, GFP_NOFS);
-                       if (!iocb->private)
+                       ext4_io_end_t *io_end =
+                               ext4_init_io_end(inode, GFP_NOFS);
+                       if (!io_end)
                                return -ENOMEM;
+                       io_end->flag |= EXT4_IO_END_DIRECT;
+                       iocb->private = io_end;
                        /*
                         * we save the io structure for current async
                         * direct IO, so that later ext4_map_blocks()
@@ -2940,7 +2944,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
                                         ext4_get_block_write,
                                         ext4_end_io_dio,
                                         NULL,
-                                        DIO_LOCKING | DIO_SKIP_HOLES);
+                                        DIO_LOCKING);
                if (iocb->private)
                        EXT4_I(inode)->cur_aio_dio = NULL;
                /*
@@ -3086,18 +3090,25 @@ static const struct address_space_operations ext4_da_aops = {
 
 void ext4_set_aops(struct inode *inode)
 {
-       if (ext4_should_order_data(inode) &&
-               test_opt(inode->i_sb, DELALLOC))
-               inode->i_mapping->a_ops = &ext4_da_aops;
-       else if (ext4_should_order_data(inode))
-               inode->i_mapping->a_ops = &ext4_ordered_aops;
-       else if (ext4_should_writeback_data(inode) &&
-                test_opt(inode->i_sb, DELALLOC))
-               inode->i_mapping->a_ops = &ext4_da_aops;
-       else if (ext4_should_writeback_data(inode))
-               inode->i_mapping->a_ops = &ext4_writeback_aops;
-       else
+       switch (ext4_inode_journal_mode(inode)) {
+       case EXT4_INODE_ORDERED_DATA_MODE:
+               if (test_opt(inode->i_sb, DELALLOC))
+                       inode->i_mapping->a_ops = &ext4_da_aops;
+               else
+                       inode->i_mapping->a_ops = &ext4_ordered_aops;
+               break;
+       case EXT4_INODE_WRITEBACK_DATA_MODE:
+               if (test_opt(inode->i_sb, DELALLOC))
+                       inode->i_mapping->a_ops = &ext4_da_aops;
+               else
+                       inode->i_mapping->a_ops = &ext4_writeback_aops;
+               break;
+       case EXT4_INODE_JOURNAL_DATA_MODE:
                inode->i_mapping->a_ops = &ext4_journalled_aops;
+               break;
+       default:
+               BUG();
+       }
 }
 
 
@@ -3329,16 +3340,16 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
 {
        struct inode *inode = file->f_path.dentry->d_inode;
        if (!S_ISREG(inode->i_mode))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
                /* TODO: Add support for non extent hole punching */
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
 
        if (EXT4_SB(inode->i_sb)->s_cluster_ratio > 1) {
                /* TODO: Add support for bigalloc file systems */
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
 
        return ext4_ext_punch_hole(file, offset, length);
@@ -3924,10 +3935,8 @@ static int ext4_do_update_inode(handle_t *handle,
                        ext4_update_dynamic_rev(sb);
                        EXT4_SET_RO_COMPAT_FEATURE(sb,
                                        EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
-                       sb->s_dirt = 1;
                        ext4_handle_sync(handle);
-                       err = ext4_handle_dirty_metadata(handle, NULL,
-                                       EXT4_SB(sb)->s_sbh);
+                       err = ext4_handle_dirty_super(handle, sb);
                }
        }
        raw_inode->i_generation = cpu_to_le32(inode->i_generation);
@@ -4152,11 +4161,9 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
        }
 
        if (attr->ia_valid & ATTR_SIZE) {
-               if (attr->ia_size != i_size_read(inode)) {
+               if (attr->ia_size != i_size_read(inode))
                        truncate_setsize(inode, attr->ia_size);
-                       ext4_truncate(inode);
-               } else if (ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS))
-                       ext4_truncate(inode);
+               ext4_truncate(inode);
        }
 
        if (!rc) {
@@ -4314,7 +4321,7 @@ int ext4_mark_iloc_dirty(handle_t *handle,
 {
        int err = 0;
 
-       if (test_opt(inode->i_sb, I_VERSION))
+       if (IS_I_VERSION(inode))
                inode_inc_iversion(inode);
 
        /* the do_update_inode consumes one bh->b_count */
index cb990b2..99ab428 100644 (file)
@@ -21,6 +21,7 @@
  * mballoc.c contains the multiblocks allocation routines
  */
 
+#include "ext4_jbd2.h"
 #include "mballoc.h"
 #include <linux/debugfs.h>
 #include <linux/slab.h>
  */
 static struct kmem_cache *ext4_pspace_cachep;
 static struct kmem_cache *ext4_ac_cachep;
-static struct kmem_cache *ext4_free_ext_cachep;
+static struct kmem_cache *ext4_free_data_cachep;
 
 /* We create slab caches for groupinfo data structures based on the
  * superblock block size.  There will be one per mounted filesystem for
@@ -357,7 +358,8 @@ static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                                        ext4_group_t group);
 static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
                                                ext4_group_t group);
-static void release_blocks_on_commit(journal_t *journal, transaction_t *txn);
+static void ext4_free_data_callback(struct super_block *sb,
+                               struct ext4_journal_cb_entry *jce, int rc);
 
 static inline void *mb_correct_addr_and_bit(int *bit, void *addr)
 {
@@ -425,7 +427,7 @@ static void *mb_find_buddy(struct ext4_buddy *e4b, int order, int *max)
 {
        char *bb;
 
-       BUG_ON(EXT4_MB_BITMAP(e4b) == EXT4_MB_BUDDY(e4b));
+       BUG_ON(e4b->bd_bitmap == e4b->bd_buddy);
        BUG_ON(max == NULL);
 
        if (order > e4b->bd_blkbits + 1) {
@@ -436,10 +438,10 @@ static void *mb_find_buddy(struct ext4_buddy *e4b, int order, int *max)
        /* at order 0 we see each particular block */
        if (order == 0) {
                *max = 1 << (e4b->bd_blkbits + 3);
-               return EXT4_MB_BITMAP(e4b);
+               return e4b->bd_bitmap;
        }
 
-       bb = EXT4_MB_BUDDY(e4b) + EXT4_SB(e4b->bd_sb)->s_mb_offsets[order];
+       bb = e4b->bd_buddy + EXT4_SB(e4b->bd_sb)->s_mb_offsets[order];
        *max = EXT4_SB(e4b->bd_sb)->s_mb_maxs[order];
 
        return bb;
@@ -588,7 +590,7 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file,
                        for (j = 0; j < (1 << order); j++) {
                                k = (i * (1 << order)) + j;
                                MB_CHECK_ASSERT(
-                                       !mb_test_bit(k, EXT4_MB_BITMAP(e4b)));
+                                       !mb_test_bit(k, e4b->bd_bitmap));
                        }
                        count++;
                }
@@ -782,7 +784,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
        int groups_per_page;
        int err = 0;
        int i;
-       ext4_group_t first_group;
+       ext4_group_t first_group, group;
        int first_block;
        struct super_block *sb;
        struct buffer_head *bhs;
@@ -806,24 +808,23 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
 
        /* allocate buffer_heads to read bitmaps */
        if (groups_per_page > 1) {
-               err = -ENOMEM;
                i = sizeof(struct buffer_head *) * groups_per_page;
                bh = kzalloc(i, GFP_NOFS);
-               if (bh == NULL)
+               if (bh == NULL) {
+                       err = -ENOMEM;
                        goto out;
+               }
        } else
                bh = &bhs;
 
        first_group = page->index * blocks_per_page / 2;
 
        /* read all groups the page covers into the cache */
-       for (i = 0; i < groups_per_page; i++) {
-               struct ext4_group_desc *desc;
-
-               if (first_group + i >= ngroups)
+       for (i = 0, group = first_group; i < groups_per_page; i++, group++) {
+               if (group >= ngroups)
                        break;
 
-               grinfo = ext4_get_group_info(sb, first_group + i);
+               grinfo = ext4_get_group_info(sb, group);
                /*
                 * If page is uptodate then we came here after online resize
                 * which added some new uninitialized group info structs, so
@@ -834,69 +835,21 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
                        bh[i] = NULL;
                        continue;
                }
-
-               err = -EIO;
-               desc = ext4_get_group_desc(sb, first_group + i, NULL);
-               if (desc == NULL)
-                       goto out;
-
-               err = -ENOMEM;
-               bh[i] = sb_getblk(sb, ext4_block_bitmap(sb, desc));
-               if (bh[i] == NULL)
+               if (!(bh[i] = ext4_read_block_bitmap_nowait(sb, group))) {
+                       err = -ENOMEM;
                        goto out;
-
-               if (bitmap_uptodate(bh[i]))
-                       continue;
-
-               lock_buffer(bh[i]);
-               if (bitmap_uptodate(bh[i])) {
-                       unlock_buffer(bh[i]);
-                       continue;
-               }
-               ext4_lock_group(sb, first_group + i);
-               if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
-                       ext4_init_block_bitmap(sb, bh[i],
-                                               first_group + i, desc);
-                       set_bitmap_uptodate(bh[i]);
-                       set_buffer_uptodate(bh[i]);
-                       ext4_unlock_group(sb, first_group + i);
-                       unlock_buffer(bh[i]);
-                       continue;
                }
-               ext4_unlock_group(sb, first_group + i);
-               if (buffer_uptodate(bh[i])) {
-                       /*
-                        * if not uninit if bh is uptodate,
-                        * bitmap is also uptodate
-                        */
-                       set_bitmap_uptodate(bh[i]);
-                       unlock_buffer(bh[i]);
-                       continue;
-               }
-               get_bh(bh[i]);
-               /*
-                * submit the buffer_head for read. We can
-                * safely mark the bitmap as uptodate now.
-                * We do it here so the bitmap uptodate bit
-                * get set with buffer lock held.
-                */
-               set_bitmap_uptodate(bh[i]);
-               bh[i]->b_end_io = end_buffer_read_sync;
-               submit_bh(READ, bh[i]);
-               mb_debug(1, "read bitmap for group %u\n", first_group + i);
+               mb_debug(1, "read bitmap for group %u\n", group);
        }
 
        /* wait for I/O completion */
-       for (i = 0; i < groups_per_page; i++)
-               if (bh[i])
-                       wait_on_buffer(bh[i]);
-
-       err = -EIO;
-       for (i = 0; i < groups_per_page; i++)
-               if (bh[i] && !buffer_uptodate(bh[i]))
+       for (i = 0, group = first_group; i < groups_per_page; i++, group++) {
+               if (bh[i] && ext4_wait_block_bitmap(sb, group, bh[i])) {
+                       err = -EIO;
                        goto out;
+               }
+       }
 
-       err = 0;
        first_block = page->index * blocks_per_page;
        for (i = 0; i < blocks_per_page; i++) {
                int group;
@@ -1250,10 +1203,10 @@ static int mb_find_order_for_block(struct ext4_buddy *e4b, int block)
        int order = 1;
        void *bb;
 
-       BUG_ON(EXT4_MB_BITMAP(e4b) == EXT4_MB_BUDDY(e4b));
+       BUG_ON(e4b->bd_bitmap == e4b->bd_buddy);
        BUG_ON(block >= (1 << (e4b->bd_blkbits + 3)));
 
-       bb = EXT4_MB_BUDDY(e4b);
+       bb = e4b->bd_buddy;
        while (order <= e4b->bd_blkbits + 1) {
                block = block >> 1;
                if (!mb_test_bit(block, bb)) {
@@ -1323,9 +1276,9 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
 
        /* let's maintain fragments counter */
        if (first != 0)
-               block = !mb_test_bit(first - 1, EXT4_MB_BITMAP(e4b));
+               block = !mb_test_bit(first - 1, e4b->bd_bitmap);
        if (first + count < EXT4_SB(sb)->s_mb_maxs[0])
-               max = !mb_test_bit(first + count, EXT4_MB_BITMAP(e4b));
+               max = !mb_test_bit(first + count, e4b->bd_bitmap);
        if (block && max)
                e4b->bd_info->bb_fragments--;
        else if (!block && !max)
@@ -1336,7 +1289,7 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
                block = first++;
                order = 0;
 
-               if (!mb_test_bit(block, EXT4_MB_BITMAP(e4b))) {
+               if (!mb_test_bit(block, e4b->bd_bitmap)) {
                        ext4_fsblk_t blocknr;
 
                        blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
@@ -1347,7 +1300,7 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
                                              "freeing already freed block "
                                              "(bit %u)", block);
                }
-               mb_clear_bit(block, EXT4_MB_BITMAP(e4b));
+               mb_clear_bit(block, e4b->bd_bitmap);
                e4b->bd_info->bb_counters[order]++;
 
                /* start of the buddy */
@@ -1429,7 +1382,7 @@ static int mb_find_extent(struct ext4_buddy *e4b, int order, int block,
                        break;
 
                next = (block + 1) * (1 << order);
-               if (mb_test_bit(next, EXT4_MB_BITMAP(e4b)))
+               if (mb_test_bit(next, e4b->bd_bitmap))
                        break;
 
                order = mb_find_order_for_block(e4b, next);
@@ -1466,9 +1419,9 @@ static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex)
 
        /* let's maintain fragments counter */
        if (start != 0)
-               mlen = !mb_test_bit(start - 1, EXT4_MB_BITMAP(e4b));
+               mlen = !mb_test_bit(start - 1, e4b->bd_bitmap);
        if (start + len < EXT4_SB(e4b->bd_sb)->s_mb_maxs[0])
-               max = !mb_test_bit(start + len, EXT4_MB_BITMAP(e4b));
+               max = !mb_test_bit(start + len, e4b->bd_bitmap);
        if (mlen && max)
                e4b->bd_info->bb_fragments++;
        else if (!mlen && !max)
@@ -1511,7 +1464,7 @@ static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex)
        }
        mb_set_largest_free_order(e4b->bd_sb, e4b->bd_info);
 
-       ext4_set_bits(EXT4_MB_BITMAP(e4b), ex->fe_start, len0);
+       ext4_set_bits(e4b->bd_bitmap, ex->fe_start, len0);
        mb_check_buddy(e4b);
 
        return ret;
@@ -1810,7 +1763,7 @@ void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
                                        struct ext4_buddy *e4b)
 {
        struct super_block *sb = ac->ac_sb;
-       void *bitmap = EXT4_MB_BITMAP(e4b);
+       void *bitmap = e4b->bd_bitmap;
        struct ext4_free_extent ex;
        int i;
        int free;
@@ -1870,7 +1823,7 @@ void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
 {
        struct super_block *sb = ac->ac_sb;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       void *bitmap = EXT4_MB_BITMAP(e4b);
+       void *bitmap = e4b->bd_bitmap;
        struct ext4_free_extent ex;
        ext4_fsblk_t first_group_block;
        ext4_fsblk_t a;
@@ -2224,7 +2177,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
                        EXT4_DESC_PER_BLOCK_BITS(sb);
                meta_group_info = kmalloc(metalen, GFP_KERNEL);
                if (meta_group_info == NULL) {
-                       ext4_msg(sb, KERN_ERR, "EXT4-fs: can't allocate mem "
+                       ext4_msg(sb, KERN_ERR, "can't allocate mem "
                                 "for a buddy group");
                        goto exit_meta_group_info;
                }
@@ -2238,7 +2191,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
 
        meta_group_info[i] = kmem_cache_alloc(cachep, GFP_KERNEL);
        if (meta_group_info[i] == NULL) {
-               ext4_msg(sb, KERN_ERR, "EXT4-fs: can't allocate buddy mem");
+               ext4_msg(sb, KERN_ERR, "can't allocate buddy mem");
                goto exit_group_info;
        }
        memset(meta_group_info[i], 0, kmem_cache_size(cachep));
@@ -2522,9 +2475,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
                proc_create_data("mb_groups", S_IRUGO, sbi->s_proc,
                                 &ext4_mb_seq_groups_fops, sb);
 
-       if (sbi->s_journal)
-               sbi->s_journal->j_commit_callback = release_blocks_on_commit;
-
        return 0;
 
 out_free_locality_groups:
@@ -2637,58 +2587,55 @@ static inline int ext4_issue_discard(struct super_block *sb,
  * This function is called by the jbd2 layer once the commit has finished,
  * so we know we can free the blocks that were released with that commit.
  */
-static void release_blocks_on_commit(journal_t *journal, transaction_t *txn)
+static void ext4_free_data_callback(struct super_block *sb,
+                                   struct ext4_journal_cb_entry *jce,
+                                   int rc)
 {
-       struct super_block *sb = journal->j_private;
+       struct ext4_free_data *entry = (struct ext4_free_data *)jce;
        struct ext4_buddy e4b;
        struct ext4_group_info *db;
        int err, count = 0, count2 = 0;
-       struct ext4_free_data *entry;
-       struct list_head *l, *ltmp;
 
-       list_for_each_safe(l, ltmp, &txn->t_private_list) {
-               entry = list_entry(l, struct ext4_free_data, list);
+       mb_debug(1, "gonna free %u blocks in group %u (0x%p):",
+                entry->efd_count, entry->efd_group, entry);
 
-               mb_debug(1, "gonna free %u blocks in group %u (0x%p):",
-                        entry->count, entry->group, entry);
+       if (test_opt(sb, DISCARD))
+               ext4_issue_discard(sb, entry->efd_group,
+                                  entry->efd_start_cluster, entry->efd_count);
 
-               if (test_opt(sb, DISCARD))
-                       ext4_issue_discard(sb, entry->group,
-                                          entry->start_cluster, entry->count);
+       err = ext4_mb_load_buddy(sb, entry->efd_group, &e4b);
+       /* we expect to find existing buddy because it's pinned */
+       BUG_ON(err != 0);
 
-               err = ext4_mb_load_buddy(sb, entry->group, &e4b);
-               /* we expect to find existing buddy because it's pinned */
-               BUG_ON(err != 0);
 
-               db = e4b.bd_info;
-               /* there are blocks to put in buddy to make them really free */
-               count += entry->count;
-               count2++;
-               ext4_lock_group(sb, entry->group);
-               /* Take it out of per group rb tree */
-               rb_erase(&entry->node, &(db->bb_free_root));
-               mb_free_blocks(NULL, &e4b, entry->start_cluster, entry->count);
+       db = e4b.bd_info;
+       /* there are blocks to put in buddy to make them really free */
+       count += entry->efd_count;
+       count2++;
+       ext4_lock_group(sb, entry->efd_group);
+       /* Take it out of per group rb tree */
+       rb_erase(&entry->efd_node, &(db->bb_free_root));
+       mb_free_blocks(NULL, &e4b, entry->efd_start_cluster, entry->efd_count);
 
-               /*
-                * Clear the trimmed flag for the group so that the next
-                * ext4_trim_fs can trim it.
-                * If the volume is mounted with -o discard, online discard
-                * is supported and the free blocks will be trimmed online.
-                */
-               if (!test_opt(sb, DISCARD))
-                       EXT4_MB_GRP_CLEAR_TRIMMED(db);
+       /*
+        * Clear the trimmed flag for the group so that the next
+        * ext4_trim_fs can trim it.
+        * If the volume is mounted with -o discard, online discard
+        * is supported and the free blocks will be trimmed online.
+        */
+       if (!test_opt(sb, DISCARD))
+               EXT4_MB_GRP_CLEAR_TRIMMED(db);
 
-               if (!db->bb_free_root.rb_node) {
-                       /* No more items in the per group rb tree
-                        * balance refcounts from ext4_mb_free_metadata()
-                        */
-                       page_cache_release(e4b.bd_buddy_page);
-                       page_cache_release(e4b.bd_bitmap_page);
-               }
-               ext4_unlock_group(sb, entry->group);
-               kmem_cache_free(ext4_free_ext_cachep, entry);
-               ext4_mb_unload_buddy(&e4b);
+       if (!db->bb_free_root.rb_node) {
+               /* No more items in the per group rb tree
+                * balance refcounts from ext4_mb_free_metadata()
+                */
+               page_cache_release(e4b.bd_buddy_page);
+               page_cache_release(e4b.bd_bitmap_page);
        }
+       ext4_unlock_group(sb, entry->efd_group);
+       kmem_cache_free(ext4_free_data_cachep, entry);
+       ext4_mb_unload_buddy(&e4b);
 
        mb_debug(1, "freed %u blocks in %u structures\n", count, count2);
 }
@@ -2741,9 +2688,9 @@ int __init ext4_init_mballoc(void)
                return -ENOMEM;
        }
 
-       ext4_free_ext_cachep = KMEM_CACHE(ext4_free_data,
-                                         SLAB_RECLAIM_ACCOUNT);
-       if (ext4_free_ext_cachep == NULL) {
+       ext4_free_data_cachep = KMEM_CACHE(ext4_free_data,
+                                          SLAB_RECLAIM_ACCOUNT);
+       if (ext4_free_data_cachep == NULL) {
                kmem_cache_destroy(ext4_pspace_cachep);
                kmem_cache_destroy(ext4_ac_cachep);
                return -ENOMEM;
@@ -2761,7 +2708,7 @@ void ext4_exit_mballoc(void)
        rcu_barrier();
        kmem_cache_destroy(ext4_pspace_cachep);
        kmem_cache_destroy(ext4_ac_cachep);
-       kmem_cache_destroy(ext4_free_ext_cachep);
+       kmem_cache_destroy(ext4_free_data_cachep);
        ext4_groupinfo_destroy_slabs();
        ext4_remove_debugfs_entry();
 }
@@ -2815,7 +2762,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
        len = EXT4_C2B(sbi, ac->ac_b_ex.fe_len);
        if (!ext4_data_block_valid(sbi, block, len)) {
                ext4_error(sb, "Allocating blocks %llu-%llu which overlap "
-                          "fs metadata\n", block, block+len);
+                          "fs metadata", block, block+len);
                /* File system mounted not to panic on error
                 * Fix the bitmap and repeat the block allocation
                 * We leak some of the blocks here.
@@ -2911,7 +2858,8 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
        struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
        int bsbits, max;
        ext4_lblk_t end;
-       loff_t size, orig_size, start_off;
+       loff_t size, start_off;
+       loff_t orig_size __maybe_unused;
        ext4_lblk_t start;
        struct ext4_inode_info *ei = EXT4_I(ac->ac_inode);
        struct ext4_prealloc_space *pa;
@@ -3321,8 +3269,8 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
        n = rb_first(&(grp->bb_free_root));
 
        while (n) {
-               entry = rb_entry(n, struct ext4_free_data, node);
-               ext4_set_bits(bitmap, entry->start_cluster, entry->count);
+               entry = rb_entry(n, struct ext4_free_data, efd_node);
+               ext4_set_bits(bitmap, entry->efd_start_cluster, entry->efd_count);
                n = rb_next(n);
        }
        return;
@@ -3916,11 +3864,11 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
            (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED))
                return;
 
-       ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: Can't allocate:"
+       ext4_msg(ac->ac_sb, KERN_ERR, "Can't allocate:"
                        " Allocation context details:");
-       ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: status %d flags %d",
+       ext4_msg(ac->ac_sb, KERN_ERR, "status %d flags %d",
                        ac->ac_status, ac->ac_flags);
-       ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: orig %lu/%lu/%lu@%lu, "
+       ext4_msg(ac->ac_sb, KERN_ERR, "orig %lu/%lu/%lu@%lu, "
                        "goal %lu/%lu/%lu@%lu, "
                        "best %lu/%lu/%lu@%lu cr %d",
                        (unsigned long)ac->ac_o_ex.fe_group,
@@ -3936,9 +3884,9 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
                        (unsigned long)ac->ac_b_ex.fe_len,
                        (unsigned long)ac->ac_b_ex.fe_logical,
                        (int)ac->ac_criteria);
-       ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: %lu scanned, %d found",
+       ext4_msg(ac->ac_sb, KERN_ERR, "%lu scanned, %d found",
                 ac->ac_ex_scanned, ac->ac_found);
-       ext4_msg(ac->ac_sb, KERN_ERR, "EXT4-fs: groups: ");
+       ext4_msg(ac->ac_sb, KERN_ERR, "groups: ");
        ngroups = ext4_get_groups_count(sb);
        for (i = 0; i < ngroups; i++) {
                struct ext4_group_info *grp = ext4_get_group_info(sb, i);
@@ -4428,9 +4376,9 @@ out:
 static int can_merge(struct ext4_free_data *entry1,
                        struct ext4_free_data *entry2)
 {
-       if ((entry1->t_tid == entry2->t_tid) &&
-           (entry1->group == entry2->group) &&
-           ((entry1->start_cluster + entry1->count) == entry2->start_cluster))
+       if ((entry1->efd_tid == entry2->efd_tid) &&
+           (entry1->efd_group == entry2->efd_group) &&
+           ((entry1->efd_start_cluster + entry1->efd_count) == entry2->efd_start_cluster))
                return 1;
        return 0;
 }
@@ -4452,8 +4400,8 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
        BUG_ON(e4b->bd_bitmap_page == NULL);
        BUG_ON(e4b->bd_buddy_page == NULL);
 
-       new_node = &new_entry->node;
-       cluster = new_entry->start_cluster;
+       new_node = &new_entry->efd_node;
+       cluster = new_entry->efd_start_cluster;
 
        if (!*n) {
                /* first free block exent. We need to
@@ -4466,10 +4414,10 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
        }
        while (*n) {
                parent = *n;
-               entry = rb_entry(parent, struct ext4_free_data, node);
-               if (cluster < entry->start_cluster)
+               entry = rb_entry(parent, struct ext4_free_data, efd_node);
+               if (cluster < entry->efd_start_cluster)
                        n = &(*n)->rb_left;
-               else if (cluster >= (entry->start_cluster + entry->count))
+               else if (cluster >= (entry->efd_start_cluster + entry->efd_count))
                        n = &(*n)->rb_right;
                else {
                        ext4_grp_locked_error(sb, group, 0,
@@ -4486,34 +4434,29 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
        /* Now try to see the extent can be merged to left and right */
        node = rb_prev(new_node);
        if (node) {
-               entry = rb_entry(node, struct ext4_free_data, node);
+               entry = rb_entry(node, struct ext4_free_data, efd_node);
                if (can_merge(entry, new_entry)) {
-                       new_entry->start_cluster = entry->start_cluster;
-                       new_entry->count += entry->count;
+                       new_entry->efd_start_cluster = entry->efd_start_cluster;
+                       new_entry->efd_count += entry->efd_count;
                        rb_erase(node, &(db->bb_free_root));
-                       spin_lock(&sbi->s_md_lock);
-                       list_del(&entry->list);
-                       spin_unlock(&sbi->s_md_lock);
-                       kmem_cache_free(ext4_free_ext_cachep, entry);
+                       ext4_journal_callback_del(handle, &entry->efd_jce);
+                       kmem_cache_free(ext4_free_data_cachep, entry);
                }
        }
 
        node = rb_next(new_node);
        if (node) {
-               entry = rb_entry(node, struct ext4_free_data, node);
+               entry = rb_entry(node, struct ext4_free_data, efd_node);
                if (can_merge(new_entry, entry)) {
-                       new_entry->count += entry->count;
+                       new_entry->efd_count += entry->efd_count;
                        rb_erase(node, &(db->bb_free_root));
-                       spin_lock(&sbi->s_md_lock);
-                       list_del(&entry->list);
-                       spin_unlock(&sbi->s_md_lock);
-                       kmem_cache_free(ext4_free_ext_cachep, entry);
+                       ext4_journal_callback_del(handle, &entry->efd_jce);
+                       kmem_cache_free(ext4_free_data_cachep, entry);
                }
        }
        /* Add the extent to transaction's private list */
-       spin_lock(&sbi->s_md_lock);
-       list_add(&new_entry->list, &handle->h_transaction->t_private_list);
-       spin_unlock(&sbi->s_md_lock);
+       ext4_journal_callback_add(handle, ext4_free_data_callback,
+                                 &new_entry->efd_jce);
        return 0;
 }
 
@@ -4691,15 +4634,15 @@ do_more:
                 * blocks being freed are metadata. these blocks shouldn't
                 * be used until this transaction is committed
                 */
-               new_entry = kmem_cache_alloc(ext4_free_ext_cachep, GFP_NOFS);
+               new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS);
                if (!new_entry) {
                        err = -ENOMEM;
                        goto error_return;
                }
-               new_entry->start_cluster = bit;
-               new_entry->group  = block_group;
-               new_entry->count = count_clusters;
-               new_entry->t_tid = handle->h_transaction->t_tid;
+               new_entry->efd_start_cluster = bit;
+               new_entry->efd_group = block_group;
+               new_entry->efd_count = count_clusters;
+               new_entry->efd_tid = handle->h_transaction->t_tid;
 
                ext4_lock_group(sb, block_group);
                mb_clear_bits(bitmap_bh->b_data, bit, count_clusters);
@@ -4971,11 +4914,11 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
        start = (e4b.bd_info->bb_first_free > start) ?
                e4b.bd_info->bb_first_free : start;
 
-       while (start < max) {
-               start = mb_find_next_zero_bit(bitmap, max, start);
-               if (start >= max)
+       while (start <= max) {
+               start = mb_find_next_zero_bit(bitmap, max + 1, start);
+               if (start > max)
                        break;
-               next = mb_find_next_bit(bitmap, max, start);
+               next = mb_find_next_bit(bitmap, max + 1, start);
 
                if ((next - start) >= minblocks) {
                        ext4_trim_extent(sb, start,
@@ -5027,37 +4970,36 @@ out:
 int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
 {
        struct ext4_group_info *grp;
-       ext4_group_t first_group, last_group;
-       ext4_group_t group, ngroups = ext4_get_groups_count(sb);
+       ext4_group_t group, first_group, last_group;
        ext4_grpblk_t cnt = 0, first_cluster, last_cluster;
-       uint64_t start, len, minlen, trimmed = 0;
+       uint64_t start, end, minlen, trimmed = 0;
        ext4_fsblk_t first_data_blk =
                        le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
+       ext4_fsblk_t max_blks = ext4_blocks_count(EXT4_SB(sb)->s_es);
        int ret = 0;
 
        start = range->start >> sb->s_blocksize_bits;
-       len = range->len >> sb->s_blocksize_bits;
+       end = start + (range->len >> sb->s_blocksize_bits) - 1;
        minlen = range->minlen >> sb->s_blocksize_bits;
 
-       if (unlikely(minlen > EXT4_CLUSTERS_PER_GROUP(sb)))
+       if (unlikely(minlen > EXT4_CLUSTERS_PER_GROUP(sb)) ||
+           unlikely(start >= max_blks))
                return -EINVAL;
-       if (start + len <= first_data_blk)
+       if (end >= max_blks)
+               end = max_blks - 1;
+       if (end <= first_data_blk)
                goto out;
-       if (start < first_data_blk) {
-               len -= first_data_blk - start;
+       if (start < first_data_blk)
                start = first_data_blk;
-       }
 
-       /* Determine first and last group to examine based on start and len */
+       /* Determine first and last group to examine based on start and end */
        ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) start,
                                     &first_group, &first_cluster);
-       ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) (start + len),
+       ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) end,
                                     &last_group, &last_cluster);
-       last_group = (last_group > ngroups - 1) ? ngroups - 1 : last_group;
-       last_cluster = EXT4_CLUSTERS_PER_GROUP(sb);
 
-       if (first_group > last_group)
-               return -EINVAL;
+       /* end now represents the last cluster to discard in this group */
+       end = EXT4_CLUSTERS_PER_GROUP(sb) - 1;
 
        for (group = first_group; group <= last_group; group++) {
                grp = ext4_get_group_info(sb, group);
@@ -5069,31 +5011,35 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
                }
 
                /*
-                * For all the groups except the last one, last block will
-                * always be EXT4_BLOCKS_PER_GROUP(sb), so we only need to
-                * change it for the last group in which case start +
-                * len < EXT4_BLOCKS_PER_GROUP(sb).
+                * For all the groups except the last one, last cluster will
+                * always be EXT4_CLUSTERS_PER_GROUP(sb)-1, so we only need to
+                * change it for the last group, note that last_cluster is
+                * already computed earlier by ext4_get_group_no_and_offset()
                 */
-               if (first_cluster + len < EXT4_CLUSTERS_PER_GROUP(sb))
-                       last_cluster = first_cluster + len;
-               len -= last_cluster - first_cluster;
+               if (group == last_group)
+                       end = last_cluster;
 
                if (grp->bb_free >= minlen) {
                        cnt = ext4_trim_all_free(sb, group, first_cluster,
-                                               last_cluster, minlen);
+                                               end, minlen);
                        if (cnt < 0) {
                                ret = cnt;
                                break;
                        }
+                       trimmed += cnt;
                }
-               trimmed += cnt;
+
+               /*
+                * For every group except the first one, we are sure
+                * that the first cluster to discard will be cluster #0.
+                */
                first_cluster = 0;
        }
-       range->len = trimmed * sb->s_blocksize;
 
        if (!ret)
                atomic_set(&EXT4_SB(sb)->s_last_trim_minblks, minlen);
 
 out:
+       range->len = trimmed * sb->s_blocksize;
        return ret;
 }
index 47705f3..c070618 100644 (file)
@@ -96,21 +96,23 @@ extern u8 mb_enable_debug;
 
 
 struct ext4_free_data {
-       /* this links the free block information from group_info */
-       struct rb_node node;
+       /* MUST be the first member */
+       struct ext4_journal_cb_entry    efd_jce;
+
+       /* ext4_free_data private data starts from here */
 
-       /* this links the free block information from ext4_sb_info */
-       struct list_head list;
+       /* this links the free block information from group_info */
+       struct rb_node                  efd_node;
 
        /* group which free block extent belongs */
-       ext4_group_t group;
+       ext4_group_t                    efd_group;
 
        /* free block extent */
-       ext4_grpblk_t start_cluster;
-       ext4_grpblk_t count;
+       ext4_grpblk_t                   efd_start_cluster;
+       ext4_grpblk_t                   efd_count;
 
        /* transaction which freed this extent */
-       tid_t   t_tid;
+       tid_t                           efd_tid;
 };
 
 struct ext4_prealloc_space {
@@ -210,8 +212,6 @@ struct ext4_buddy {
        __u16 bd_blkbits;
        ext4_group_t bd_group;
 };
-#define EXT4_MB_BITMAP(e4b)    ((e4b)->bd_bitmap)
-#define EXT4_MB_BUDDY(e4b)     ((e4b)->bd_buddy)
 
 static inline ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb,
                                        struct ext4_free_extent *fex)
index e7d6bb0..f39f80f 100644 (file)
@@ -471,7 +471,7 @@ int ext4_ext_migrate(struct inode *inode)
        tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode,
                                   S_IFREG, NULL, goal, owner);
        if (IS_ERR(tmp_inode)) {
-               retval = PTR_ERR(inode);
+               retval = PTR_ERR(tmp_inode);
                ext4_journal_stop(handle);
                return retval;
        }
index 7ea4ba4..ed6548d 100644 (file)
@@ -257,8 +257,8 @@ int ext4_multi_mount_protect(struct super_block *sb,
         * If check_interval in MMP block is larger, use that instead of
         * update_interval from the superblock.
         */
-       if (mmp->mmp_check_interval > mmp_check_interval)
-               mmp_check_interval = mmp->mmp_check_interval;
+       if (le16_to_cpu(mmp->mmp_check_interval) > mmp_check_interval)
+               mmp_check_interval = le16_to_cpu(mmp->mmp_check_interval);
 
        seq = le32_to_cpu(mmp->mmp_seq);
        if (seq == EXT4_MMP_SEQ_CLEAN)
index 2043f48..349d7b3 100644 (file)
@@ -468,7 +468,7 @@ fail2:
 fail:
        if (*err == ERR_BAD_DX_DIR)
                ext4_warning(dir->i_sb,
-                            "Corrupt dir inode %ld, running e2fsck is "
+                            "Corrupt dir inode %lu, running e2fsck is "
                             "recommended.", dir->i_ino);
        return NULL;
 }
index 4758518..74cd1f7 100644 (file)
@@ -60,7 +60,6 @@ void ext4_ioend_wait(struct inode *inode)
 static void put_io_page(struct ext4_io_page *io_page)
 {
        if (atomic_dec_and_test(&io_page->p_count)) {
-               end_page_writeback(io_page->p_page);
                put_page(io_page->p_page);
                kmem_cache_free(io_page_cachep, io_page);
        }
@@ -110,6 +109,8 @@ int ext4_end_io_nolock(ext4_io_end_t *io)
        if (io->iocb)
                aio_complete(io->iocb, io->result, 0);
 
+       if (io->flag & EXT4_IO_END_DIRECT)
+               inode_dio_done(inode);
        /* Wake up anyone waiting on unwritten extent conversion */
        if (atomic_dec_and_test(&EXT4_I(inode)->i_aiodio_unwritten))
                wake_up_all(ext4_ioend_wq(io->inode));
@@ -127,12 +128,18 @@ static void ext4_end_io_work(struct work_struct *work)
        unsigned long           flags;
 
        spin_lock_irqsave(&ei->i_completed_io_lock, flags);
+       if (io->flag & EXT4_IO_END_IN_FSYNC)
+               goto requeue;
        if (list_empty(&io->list)) {
                spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
                goto free;
        }
 
        if (!mutex_trylock(&inode->i_mutex)) {
+               bool was_queued;
+requeue:
+               was_queued = !!(io->flag & EXT4_IO_END_QUEUED);
+               io->flag |= EXT4_IO_END_QUEUED;
                spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
                /*
                 * Requeue the work instead of waiting so that the work
@@ -145,9 +152,8 @@ static void ext4_end_io_work(struct work_struct *work)
                 * yield the cpu if it sees an end_io request that has already
                 * been requeued.
                 */
-               if (io->flag & EXT4_IO_END_QUEUED)
+               if (was_queued)
                        yield();
-               io->flag |= EXT4_IO_END_QUEUED;
                return;
        }
        list_del_init(&io->list);
@@ -227,9 +233,9 @@ static void ext4_end_bio(struct bio *bio, int error)
                        } while (bh != head);
                }
 
-               put_io_page(io_end->pages[i]);
+               if (atomic_read(&io_end->pages[i]->p_count) == 1)
+                       end_page_writeback(io_end->pages[i]->p_page);
        }
-       io_end->num_io_pages = 0;
        inode = io_end->inode;
 
        if (error) {
@@ -421,6 +427,8 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
         * PageWriteback bit from the page to prevent the system from
         * wedging later on.
         */
+       if (atomic_read(&io_page->p_count) == 1)
+               end_page_writeback(page);
        put_io_page(io_page);
        return ret;
 }
index f9d948f..59fa0be 100644 (file)
@@ -1163,8 +1163,11 @@ static void ext4_update_super(struct super_block *sb,
        do_div(reserved_blocks, 100);
 
        ext4_blocks_count_set(es, ext4_blocks_count(es) + blocks_count);
+       ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + free_blocks);
        le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb) *
                     flex_gd->count);
+       le32_add_cpu(&es->s_free_inodes_count, EXT4_INODES_PER_GROUP(sb) *
+                    flex_gd->count);
 
        /*
         * We need to protect s_groups_count against other CPUs seeing
@@ -1465,6 +1468,7 @@ static int ext4_group_extend_no_check(struct super_block *sb,
        }
 
        ext4_blocks_count_set(es, o_blocks_count + add);
+       ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + add);
        ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
                   o_blocks_count + add);
        /* We add the blocks to the bitmap and set the group need init bit */
@@ -1512,16 +1516,17 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
        o_blocks_count = ext4_blocks_count(es);
 
        if (test_opt(sb, DEBUG))
-               printk(KERN_DEBUG "EXT4-fs: extending last group from %llu to %llu blocks\n",
-                      o_blocks_count, n_blocks_count);
+               ext4_msg(sb, KERN_DEBUG,
+                        "extending last group from %llu to %llu blocks",
+                        o_blocks_count, n_blocks_count);
 
        if (n_blocks_count == 0 || n_blocks_count == o_blocks_count)
                return 0;
 
        if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
-               printk(KERN_ERR "EXT4-fs: filesystem on %s:"
-                       " too large to resize to %llu blocks safely\n",
-                       sb->s_id, n_blocks_count);
+               ext4_msg(sb, KERN_ERR,
+                        "filesystem too large to resize to %llu blocks safely",
+                        n_blocks_count);
                if (sizeof(sector_t) < 8)
                        ext4_warning(sb, "CONFIG_LBDAF not enabled");
                return -EINVAL;
@@ -1582,7 +1587,7 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
        ext4_fsblk_t o_blocks_count;
        ext4_group_t o_group;
        ext4_group_t n_group;
-       ext4_grpblk_t offset;
+       ext4_grpblk_t offset, add;
        unsigned long n_desc_blocks;
        unsigned long o_desc_blocks;
        unsigned long desc_blocks;
@@ -1591,8 +1596,8 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
        o_blocks_count = ext4_blocks_count(es);
 
        if (test_opt(sb, DEBUG))
-               printk(KERN_DEBUG "EXT4-fs: resizing filesystem from %llu "
-                      "upto %llu blocks\n", o_blocks_count, n_blocks_count);
+               ext4_msg(sb, KERN_DEBUG, "resizing filesystem from %llu "
+                      "to %llu blocks", o_blocks_count, n_blocks_count);
 
        if (n_blocks_count < o_blocks_count) {
                /* On-line shrinking not supported */
@@ -1605,7 +1610,7 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
                return 0;
 
        ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &offset);
-       ext4_get_group_no_and_offset(sb, o_blocks_count, &o_group, &offset);
+       ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset);
 
        n_desc_blocks = (n_group + EXT4_DESC_PER_BLOCK(sb)) /
                        EXT4_DESC_PER_BLOCK(sb);
@@ -1634,10 +1639,12 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
        }
        brelse(bh);
 
-       if (offset != 0) {
-               /* extend the last group */
-               ext4_grpblk_t add;
-               add = EXT4_BLOCKS_PER_GROUP(sb) - offset;
+       /* extend the last group */
+       if (n_group == o_group)
+               add = n_blocks_count - o_blocks_count;
+       else
+               add = EXT4_BLOCKS_PER_GROUP(sb) - (offset + 1);
+       if (add > 0) {
                err = ext4_group_extend_no_check(sb, o_blocks_count, add);
                if (err)
                        goto out;
@@ -1674,7 +1681,7 @@ out:
 
        iput(resize_inode);
        if (test_opt(sb, DEBUG))
-               printk(KERN_DEBUG "EXT4-fs: resized filesystem from %llu "
-                      "upto %llu blocks\n", o_blocks_count, n_blocks_count);
+               ext4_msg(sb, KERN_DEBUG, "resized filesystem from %llu "
+                      "upto %llu blocks", o_blocks_count, n_blocks_count);
        return err;
 }
index 9339009..ceebaf8 100644 (file)
@@ -62,6 +62,7 @@ static struct ext4_features *ext4_feat;
 
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
                             unsigned long journal_devnum);
+static int ext4_show_options(struct seq_file *seq, struct dentry *root);
 static int ext4_commit_super(struct super_block *sb, int sync);
 static void ext4_mark_recovery_complete(struct super_block *sb,
                                        struct ext4_super_block *es);
@@ -375,7 +376,7 @@ void ext4_journal_abort_handle(const char *caller, unsigned int line,
        if (is_handle_aborted(handle))
                return;
 
-       printk(KERN_ERR "%s:%d: aborting transaction: %s in %s\n",
+       printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
               caller, line, errstr, err_fn);
 
        jbd2_journal_abort_handle(handle);
@@ -431,6 +432,22 @@ static int block_device_ejected(struct super_block *sb)
        return bdi->dev == NULL;
 }
 
+static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
+{
+       struct super_block              *sb = journal->j_private;
+       struct ext4_sb_info             *sbi = EXT4_SB(sb);
+       int                             error = is_journal_aborted(journal);
+       struct ext4_journal_cb_entry    *jce, *tmp;
+
+       spin_lock(&sbi->s_md_lock);
+       list_for_each_entry_safe(jce, tmp, &txn->t_private_list, jce_list) {
+               list_del_init(&jce->jce_list);
+               spin_unlock(&sbi->s_md_lock);
+               jce->jce_func(sb, jce, error);
+               spin_lock(&sbi->s_md_lock);
+       }
+       spin_unlock(&sbi->s_md_lock);
+}
 
 /* Deal with the reporting of failure conditions on a filesystem such as
  * inconsistencies detected or read IO failures.
@@ -498,11 +515,16 @@ void ext4_error_inode(struct inode *inode, const char *function,
        va_start(args, fmt);
        vaf.fmt = fmt;
        vaf.va = &args;
-       printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: inode #%lu: ",
-              inode->i_sb->s_id, function, line, inode->i_ino);
        if (block)
-               printk(KERN_CONT "block %llu: ", block);
-       printk(KERN_CONT "comm %s: %pV\n", current->comm, &vaf);
+               printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: "
+                      "inode #%lu: block %llu: comm %s: %pV\n",
+                      inode->i_sb->s_id, function, line, inode->i_ino,
+                      block, current->comm, &vaf);
+       else
+               printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: "
+                      "inode #%lu: comm %s: %pV\n",
+                      inode->i_sb->s_id, function, line, inode->i_ino,
+                      current->comm, &vaf);
        va_end(args);
 
        ext4_handle_error(inode->i_sb);
@@ -524,15 +546,21 @@ void ext4_error_file(struct file *file, const char *function,
        path = d_path(&(file->f_path), pathname, sizeof(pathname));
        if (IS_ERR(path))
                path = "(unknown)";
-       printk(KERN_CRIT
-              "EXT4-fs error (device %s): %s:%d: inode #%lu: ",
-              inode->i_sb->s_id, function, line, inode->i_ino);
-       if (block)
-               printk(KERN_CONT "block %llu: ", block);
        va_start(args, fmt);
        vaf.fmt = fmt;
        vaf.va = &args;
-       printk(KERN_CONT "comm %s: path %s: %pV\n", current->comm, path, &vaf);
+       if (block)
+               printk(KERN_CRIT
+                      "EXT4-fs error (device %s): %s:%d: inode #%lu: "
+                      "block %llu: comm %s: path %s: %pV\n",
+                      inode->i_sb->s_id, function, line, inode->i_ino,
+                      block, current->comm, path, &vaf);
+       else
+               printk(KERN_CRIT
+                      "EXT4-fs error (device %s): %s:%d: inode #%lu: "
+                      "comm %s: path %s: %pV\n",
+                      inode->i_sb->s_id, function, line, inode->i_ino,
+                      current->comm, path, &vaf);
        va_end(args);
 
        ext4_handle_error(inode->i_sb);
@@ -808,9 +836,6 @@ static void ext4_put_super(struct super_block *sb)
        destroy_workqueue(sbi->dio_unwritten_wq);
 
        lock_super(sb);
-       if (sb->s_dirt)
-               ext4_commit_super(sb, 1);
-
        if (sbi->s_journal) {
                err = jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
@@ -827,9 +852,12 @@ static void ext4_put_super(struct super_block *sb)
        if (!(sb->s_flags & MS_RDONLY)) {
                EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
-               ext4_commit_super(sb, 1);
        }
+       if (sb->s_dirt || !(sb->s_flags & MS_RDONLY))
+               ext4_commit_super(sb, 1);
+
        if (sbi->s_proc) {
+               remove_proc_entry("options", sbi->s_proc);
                remove_proc_entry(sb->s_id, ext4_proc_root);
        }
        kobject_del(&sbi->s_kobj);
@@ -990,180 +1018,6 @@ void ext4_clear_inode(struct inode *inode)
        }
 }
 
-static inline void ext4_show_quota_options(struct seq_file *seq,
-                                          struct super_block *sb)
-{
-#if defined(CONFIG_QUOTA)
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-
-       if (sbi->s_jquota_fmt) {
-               char *fmtname = "";
-
-               switch (sbi->s_jquota_fmt) {
-               case QFMT_VFS_OLD:
-                       fmtname = "vfsold";
-                       break;
-               case QFMT_VFS_V0:
-                       fmtname = "vfsv0";
-                       break;
-               case QFMT_VFS_V1:
-                       fmtname = "vfsv1";
-                       break;
-               }
-               seq_printf(seq, ",jqfmt=%s", fmtname);
-       }
-
-       if (sbi->s_qf_names[USRQUOTA])
-               seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
-
-       if (sbi->s_qf_names[GRPQUOTA])
-               seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
-
-       if (test_opt(sb, USRQUOTA))
-               seq_puts(seq, ",usrquota");
-
-       if (test_opt(sb, GRPQUOTA))
-               seq_puts(seq, ",grpquota");
-#endif
-}
-
-/*
- * Show an option if
- *  - it's set to a non-default value OR
- *  - if the per-sb default is different from the global default
- */
-static int ext4_show_options(struct seq_file *seq, struct dentry *root)
-{
-       int def_errors;
-       unsigned long def_mount_opts;
-       struct super_block *sb = root->d_sb;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct ext4_super_block *es = sbi->s_es;
-
-       def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
-       def_errors     = le16_to_cpu(es->s_errors);
-
-       if (sbi->s_sb_block != 1)
-               seq_printf(seq, ",sb=%llu", sbi->s_sb_block);
-       if (test_opt(sb, MINIX_DF))
-               seq_puts(seq, ",minixdf");
-       if (test_opt(sb, GRPID) && !(def_mount_opts & EXT4_DEFM_BSDGROUPS))
-               seq_puts(seq, ",grpid");
-       if (!test_opt(sb, GRPID) && (def_mount_opts & EXT4_DEFM_BSDGROUPS))
-               seq_puts(seq, ",nogrpid");
-       if (sbi->s_resuid != EXT4_DEF_RESUID ||
-           le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) {
-               seq_printf(seq, ",resuid=%u", sbi->s_resuid);
-       }
-       if (sbi->s_resgid != EXT4_DEF_RESGID ||
-           le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) {
-               seq_printf(seq, ",resgid=%u", sbi->s_resgid);
-       }
-       if (test_opt(sb, ERRORS_RO)) {
-               if (def_errors == EXT4_ERRORS_PANIC ||
-                   def_errors == EXT4_ERRORS_CONTINUE) {
-                       seq_puts(seq, ",errors=remount-ro");
-               }
-       }
-       if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE)
-               seq_puts(seq, ",errors=continue");
-       if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC)
-               seq_puts(seq, ",errors=panic");
-       if (test_opt(sb, NO_UID32) && !(def_mount_opts & EXT4_DEFM_UID16))
-               seq_puts(seq, ",nouid32");
-       if (test_opt(sb, DEBUG) && !(def_mount_opts & EXT4_DEFM_DEBUG))
-               seq_puts(seq, ",debug");
-#ifdef CONFIG_EXT4_FS_XATTR
-       if (test_opt(sb, XATTR_USER))
-               seq_puts(seq, ",user_xattr");
-       if (!test_opt(sb, XATTR_USER))
-               seq_puts(seq, ",nouser_xattr");
-#endif
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
-       if (test_opt(sb, POSIX_ACL) && !(def_mount_opts & EXT4_DEFM_ACL))
-               seq_puts(seq, ",acl");
-       if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL))
-               seq_puts(seq, ",noacl");
-#endif
-       if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
-               seq_printf(seq, ",commit=%u",
-                          (unsigned) (sbi->s_commit_interval / HZ));
-       }
-       if (sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME) {
-               seq_printf(seq, ",min_batch_time=%u",
-                          (unsigned) sbi->s_min_batch_time);
-       }
-       if (sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME) {
-               seq_printf(seq, ",max_batch_time=%u",
-                          (unsigned) sbi->s_max_batch_time);
-       }
-
-       /*
-        * We're changing the default of barrier mount option, so
-        * let's always display its mount state so it's clear what its
-        * status is.
-        */
-       seq_puts(seq, ",barrier=");
-       seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0");
-       if (test_opt(sb, JOURNAL_ASYNC_COMMIT))
-               seq_puts(seq, ",journal_async_commit");
-       else if (test_opt(sb, JOURNAL_CHECKSUM))
-               seq_puts(seq, ",journal_checksum");
-       if (test_opt(sb, I_VERSION))
-               seq_puts(seq, ",i_version");
-       if (!test_opt(sb, DELALLOC) &&
-           !(def_mount_opts & EXT4_DEFM_NODELALLOC))
-               seq_puts(seq, ",nodelalloc");
-
-       if (!test_opt(sb, MBLK_IO_SUBMIT))
-               seq_puts(seq, ",nomblk_io_submit");
-       if (sbi->s_stripe)
-               seq_printf(seq, ",stripe=%lu", sbi->s_stripe);
-       /*
-        * journal mode get enabled in different ways
-        * So just print the value even if we didn't specify it
-        */
-       if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
-               seq_puts(seq, ",data=journal");
-       else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
-               seq_puts(seq, ",data=ordered");
-       else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
-               seq_puts(seq, ",data=writeback");
-
-       if (sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS)
-               seq_printf(seq, ",inode_readahead_blks=%u",
-                          sbi->s_inode_readahead_blks);
-
-       if (test_opt(sb, DATA_ERR_ABORT))
-               seq_puts(seq, ",data_err=abort");
-
-       if (test_opt(sb, NO_AUTO_DA_ALLOC))
-               seq_puts(seq, ",noauto_da_alloc");
-
-       if (test_opt(sb, DISCARD) && !(def_mount_opts & EXT4_DEFM_DISCARD))
-               seq_puts(seq, ",discard");
-
-       if (test_opt(sb, NOLOAD))
-               seq_puts(seq, ",norecovery");
-
-       if (test_opt(sb, DIOREAD_NOLOCK))
-               seq_puts(seq, ",dioread_nolock");
-
-       if (test_opt(sb, BLOCK_VALIDITY) &&
-           !(def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY))
-               seq_puts(seq, ",block_validity");
-
-       if (!test_opt(sb, INIT_INODE_TABLE))
-               seq_puts(seq, ",noinit_itable");
-       else if (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)
-               seq_printf(seq, ",init_itable=%u",
-                          (unsigned) sbi->s_li_wait_mult);
-
-       ext4_show_quota_options(seq, sb);
-
-       return 0;
-}
-
 static struct inode *ext4_nfs_get_inode(struct super_block *sb,
                                        u64 ino, u32 generation)
 {
@@ -1316,18 +1170,17 @@ static const struct export_operations ext4_export_ops = {
 enum {
        Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
        Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
-       Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov,
+       Opt_nouid32, Opt_debug, Opt_removed,
        Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
-       Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload, Opt_nobh, Opt_bh,
+       Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload,
        Opt_commit, Opt_min_batch_time, Opt_max_batch_time,
-       Opt_journal_update, Opt_journal_dev,
-       Opt_journal_checksum, Opt_journal_async_commit,
+       Opt_journal_dev, Opt_journal_checksum, Opt_journal_async_commit,
        Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
        Opt_data_err_abort, Opt_data_err_ignore,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
-       Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err,
-       Opt_resize, Opt_usrquota, Opt_grpquota, Opt_i_version,
+       Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
+       Opt_usrquota, Opt_grpquota, Opt_i_version,
        Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
        Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
        Opt_inode_readahead_blks, Opt_journal_ioprio,
@@ -1350,20 +1203,19 @@ static const match_table_t tokens = {
        {Opt_err_ro, "errors=remount-ro"},
        {Opt_nouid32, "nouid32"},
        {Opt_debug, "debug"},
-       {Opt_oldalloc, "oldalloc"},
-       {Opt_orlov, "orlov"},
+       {Opt_removed, "oldalloc"},
+       {Opt_removed, "orlov"},
        {Opt_user_xattr, "user_xattr"},
        {Opt_nouser_xattr, "nouser_xattr"},
        {Opt_acl, "acl"},
        {Opt_noacl, "noacl"},
-       {Opt_noload, "noload"},
        {Opt_noload, "norecovery"},
-       {Opt_nobh, "nobh"},
-       {Opt_bh, "bh"},
+       {Opt_noload, "noload"},
+       {Opt_removed, "nobh"},
+       {Opt_removed, "bh"},
        {Opt_commit, "commit=%u"},
        {Opt_min_batch_time, "min_batch_time=%u"},
        {Opt_max_batch_time, "max_batch_time=%u"},
-       {Opt_journal_update, "journal=update"},
        {Opt_journal_dev, "journal_dev=%u"},
        {Opt_journal_checksum, "journal_checksum"},
        {Opt_journal_async_commit, "journal_async_commit"},
@@ -1389,7 +1241,6 @@ static const match_table_t tokens = {
        {Opt_nobarrier, "nobarrier"},
        {Opt_i_version, "i_version"},
        {Opt_stripe, "stripe=%u"},
-       {Opt_resize, "resize"},
        {Opt_delalloc, "delalloc"},
        {Opt_nodelalloc, "nodelalloc"},
        {Opt_mblk_io_submit, "mblk_io_submit"},
@@ -1408,6 +1259,11 @@ static const match_table_t tokens = {
        {Opt_init_itable, "init_itable=%u"},
        {Opt_init_itable, "init_itable"},
        {Opt_noinit_itable, "noinit_itable"},
+       {Opt_removed, "check=none"},    /* mount option from ext2/3 */
+       {Opt_removed, "nocheck"},       /* mount option from ext2/3 */
+       {Opt_removed, "reservation"},   /* mount option from ext2/3 */
+       {Opt_removed, "noreservation"}, /* mount option from ext2/3 */
+       {Opt_removed, "journal=%u"},    /* mount option from ext2/3 */
        {Opt_err, NULL},
 };
 
@@ -1496,420 +1352,273 @@ static int clear_qf_name(struct super_block *sb, int qtype)
 }
 #endif
 
-static int parse_options(char *options, struct super_block *sb,
-                        unsigned long *journal_devnum,
-                        unsigned int *journal_ioprio,
-                        ext4_fsblk_t *n_blocks_count, int is_remount)
-{
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       char *p;
-       substring_t args[MAX_OPT_ARGS];
-       int data_opt = 0;
-       int option;
+#define MOPT_SET       0x0001
+#define MOPT_CLEAR     0x0002
+#define MOPT_NOSUPPORT 0x0004
+#define MOPT_EXPLICIT  0x0008
+#define MOPT_CLEAR_ERR 0x0010
+#define MOPT_GTE0      0x0020
 #ifdef CONFIG_QUOTA
-       int qfmt;
+#define MOPT_Q         0
+#define MOPT_QFMT      0x0040
+#else
+#define MOPT_Q         MOPT_NOSUPPORT
+#define MOPT_QFMT      MOPT_NOSUPPORT
 #endif
-
-       if (!options)
-               return 1;
-
-       while ((p = strsep(&options, ",")) != NULL) {
-               int token;
-               if (!*p)
-                       continue;
-
-               /*
-                * Initialize args struct so we know whether arg was
-                * found; some options take optional arguments.
-                */
-               args[0].to = args[0].from = NULL;
-               token = match_token(p, tokens, args);
-               switch (token) {
-               case Opt_bsd_df:
-                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-                       clear_opt(sb, MINIX_DF);
-                       break;
-               case Opt_minix_df:
-                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-                       set_opt(sb, MINIX_DF);
-
-                       break;
-               case Opt_grpid:
-                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-                       set_opt(sb, GRPID);
-
-                       break;
-               case Opt_nogrpid:
-                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-                       clear_opt(sb, GRPID);
-
-                       break;
-               case Opt_resuid:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       sbi->s_resuid = option;
-                       break;
-               case Opt_resgid:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       sbi->s_resgid = option;
-                       break;
-               case Opt_sb:
-                       /* handled by get_sb_block() instead of here */
-                       /* *sb_block = match_int(&args[0]); */
-                       break;
-               case Opt_err_panic:
-                       clear_opt(sb, ERRORS_CONT);
-                       clear_opt(sb, ERRORS_RO);
-                       set_opt(sb, ERRORS_PANIC);
-                       break;
-               case Opt_err_ro:
-                       clear_opt(sb, ERRORS_CONT);
-                       clear_opt(sb, ERRORS_PANIC);
-                       set_opt(sb, ERRORS_RO);
-                       break;
-               case Opt_err_cont:
-                       clear_opt(sb, ERRORS_RO);
-                       clear_opt(sb, ERRORS_PANIC);
-                       set_opt(sb, ERRORS_CONT);
-                       break;
-               case Opt_nouid32:
-                       set_opt(sb, NO_UID32);
-                       break;
-               case Opt_debug:
-                       set_opt(sb, DEBUG);
-                       break;
-               case Opt_oldalloc:
-                       ext4_msg(sb, KERN_WARNING,
-                                "Ignoring deprecated oldalloc option");
-                       break;
-               case Opt_orlov:
-                       ext4_msg(sb, KERN_WARNING,
-                                "Ignoring deprecated orlov option");
-                       break;
+#define MOPT_DATAJ     0x0080
+
+static const struct mount_opts {
+       int     token;
+       int     mount_opt;
+       int     flags;
+} ext4_mount_opts[] = {
+       {Opt_minix_df, EXT4_MOUNT_MINIX_DF, MOPT_SET},
+       {Opt_bsd_df, EXT4_MOUNT_MINIX_DF, MOPT_CLEAR},
+       {Opt_grpid, EXT4_MOUNT_GRPID, MOPT_SET},
+       {Opt_nogrpid, EXT4_MOUNT_GRPID, MOPT_CLEAR},
+       {Opt_mblk_io_submit, EXT4_MOUNT_MBLK_IO_SUBMIT, MOPT_SET},
+       {Opt_nomblk_io_submit, EXT4_MOUNT_MBLK_IO_SUBMIT, MOPT_CLEAR},
+       {Opt_block_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_SET},
+       {Opt_noblock_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_CLEAR},
+       {Opt_dioread_nolock, EXT4_MOUNT_DIOREAD_NOLOCK, MOPT_SET},
+       {Opt_dioread_lock, EXT4_MOUNT_DIOREAD_NOLOCK, MOPT_CLEAR},
+       {Opt_discard, EXT4_MOUNT_DISCARD, MOPT_SET},
+       {Opt_nodiscard, EXT4_MOUNT_DISCARD, MOPT_CLEAR},
+       {Opt_delalloc, EXT4_MOUNT_DELALLOC, MOPT_SET | MOPT_EXPLICIT},
+       {Opt_nodelalloc, EXT4_MOUNT_DELALLOC, MOPT_CLEAR | MOPT_EXPLICIT},
+       {Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM, MOPT_SET},
+       {Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT |
+                                   EXT4_MOUNT_JOURNAL_CHECKSUM), MOPT_SET},
+       {Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_SET},
+       {Opt_err_panic, EXT4_MOUNT_ERRORS_PANIC, MOPT_SET | MOPT_CLEAR_ERR},
+       {Opt_err_ro, EXT4_MOUNT_ERRORS_RO, MOPT_SET | MOPT_CLEAR_ERR},
+       {Opt_err_cont, EXT4_MOUNT_ERRORS_CONT, MOPT_SET | MOPT_CLEAR_ERR},
+       {Opt_data_err_abort, EXT4_MOUNT_DATA_ERR_ABORT, MOPT_SET},
+       {Opt_data_err_ignore, EXT4_MOUNT_DATA_ERR_ABORT, MOPT_CLEAR},
+       {Opt_barrier, EXT4_MOUNT_BARRIER, MOPT_SET},
+       {Opt_nobarrier, EXT4_MOUNT_BARRIER, MOPT_CLEAR},
+       {Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET},
+       {Opt_auto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_CLEAR},
+       {Opt_noinit_itable, EXT4_MOUNT_INIT_INODE_TABLE, MOPT_CLEAR},
+       {Opt_commit, 0, MOPT_GTE0},
+       {Opt_max_batch_time, 0, MOPT_GTE0},
+       {Opt_min_batch_time, 0, MOPT_GTE0},
+       {Opt_inode_readahead_blks, 0, MOPT_GTE0},
+       {Opt_init_itable, 0, MOPT_GTE0},
+       {Opt_stripe, 0, MOPT_GTE0},
+       {Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_DATAJ},
+       {Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_DATAJ},
+       {Opt_data_writeback, EXT4_MOUNT_WRITEBACK_DATA, MOPT_DATAJ},
 #ifdef CONFIG_EXT4_FS_XATTR
-               case Opt_user_xattr:
-                       set_opt(sb, XATTR_USER);
-                       break;
-               case Opt_nouser_xattr:
-                       clear_opt(sb, XATTR_USER);
-                       break;
+       {Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET},
+       {Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR},
 #else
-               case Opt_user_xattr:
-               case Opt_nouser_xattr:
-                       ext4_msg(sb, KERN_ERR, "(no)user_xattr options not supported");
-                       break;
+       {Opt_user_xattr, 0, MOPT_NOSUPPORT},
+       {Opt_nouser_xattr, 0, MOPT_NOSUPPORT},
 #endif
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
-               case Opt_acl:
-                       set_opt(sb, POSIX_ACL);
-                       break;
-               case Opt_noacl:
-                       clear_opt(sb, POSIX_ACL);
-                       break;
+       {Opt_acl, EXT4_MOUNT_POSIX_ACL, MOPT_SET},
+       {Opt_noacl, EXT4_MOUNT_POSIX_ACL, MOPT_CLEAR},
 #else
-               case Opt_acl:
-               case Opt_noacl:
-                       ext4_msg(sb, KERN_ERR, "(no)acl options not supported");
-                       break;
+       {Opt_acl, 0, MOPT_NOSUPPORT},
+       {Opt_noacl, 0, MOPT_NOSUPPORT},
 #endif
-               case Opt_journal_update:
-                       /* @@@ FIXME */
-                       /* Eventually we will want to be able to create
-                          a journal file here.  For now, only allow the
-                          user to specify an existing inode to be the
-                          journal file. */
-                       if (is_remount) {
-                               ext4_msg(sb, KERN_ERR,
-                                        "Cannot specify journal on remount");
-                               return 0;
-                       }
-                       set_opt(sb, UPDATE_JOURNAL);
-                       break;
-               case Opt_journal_dev:
-                       if (is_remount) {
+       {Opt_nouid32, EXT4_MOUNT_NO_UID32, MOPT_SET},
+       {Opt_debug, EXT4_MOUNT_DEBUG, MOPT_SET},
+       {Opt_quota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, MOPT_SET | MOPT_Q},
+       {Opt_usrquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA,
+                                                       MOPT_SET | MOPT_Q},
+       {Opt_grpquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_GRPQUOTA,
+                                                       MOPT_SET | MOPT_Q},
+       {Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA |
+                      EXT4_MOUNT_GRPQUOTA), MOPT_CLEAR | MOPT_Q},
+       {Opt_usrjquota, 0, MOPT_Q},
+       {Opt_grpjquota, 0, MOPT_Q},
+       {Opt_offusrjquota, 0, MOPT_Q},
+       {Opt_offgrpjquota, 0, MOPT_Q},
+       {Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT},
+       {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},
+       {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
+       {Opt_err, 0, 0}
+};
+
+static int handle_mount_opt(struct super_block *sb, char *opt, int token,
+                           substring_t *args, unsigned long *journal_devnum,
+                           unsigned int *journal_ioprio, int is_remount)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       const struct mount_opts *m;
+       int arg = 0;
+
+       if (args->from && match_int(args, &arg))
+               return -1;
+       switch (token) {
+       case Opt_noacl:
+       case Opt_nouser_xattr:
+               ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5");
+               break;
+       case Opt_sb:
+               return 1;       /* handled by get_sb_block() */
+       case Opt_removed:
+               ext4_msg(sb, KERN_WARNING,
+                        "Ignoring removed %s option", opt);
+               return 1;
+       case Opt_resuid:
+               sbi->s_resuid = arg;
+               return 1;
+       case Opt_resgid:
+               sbi->s_resgid = arg;
+               return 1;
+       case Opt_abort:
+               sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
+               return 1;
+       case Opt_i_version:
+               sb->s_flags |= MS_I_VERSION;
+               return 1;
+       case Opt_journal_dev:
+               if (is_remount) {
+                       ext4_msg(sb, KERN_ERR,
+                                "Cannot specify journal on remount");
+                       return -1;
+               }
+               *journal_devnum = arg;
+               return 1;
+       case Opt_journal_ioprio:
+               if (arg < 0 || arg > 7)
+                       return -1;
+               *journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg);
+               return 1;
+       }
+
+       for (m = ext4_mount_opts; m->token != Opt_err; m++) {
+               if (token != m->token)
+                       continue;
+               if (args->from && (m->flags & MOPT_GTE0) && (arg < 0))
+                       return -1;
+               if (m->flags & MOPT_EXPLICIT)
+                       set_opt2(sb, EXPLICIT_DELALLOC);
+               if (m->flags & MOPT_CLEAR_ERR)
+                       clear_opt(sb, ERRORS_MASK);
+               if (token == Opt_noquota && sb_any_quota_loaded(sb)) {
+                       ext4_msg(sb, KERN_ERR, "Cannot change quota "
+                                "options when quota turned on");
+                       return -1;
+               }
+
+               if (m->flags & MOPT_NOSUPPORT) {
+                       ext4_msg(sb, KERN_ERR, "%s option not supported", opt);
+               } else if (token == Opt_commit) {
+                       if (arg == 0)
+                               arg = JBD2_DEFAULT_MAX_COMMIT_AGE;
+                       sbi->s_commit_interval = HZ * arg;
+               } else if (token == Opt_max_batch_time) {
+                       if (arg == 0)
+                               arg = EXT4_DEF_MAX_BATCH_TIME;
+                       sbi->s_max_batch_time = arg;
+               } else if (token == Opt_min_batch_time) {
+                       sbi->s_min_batch_time = arg;
+               } else if (token == Opt_inode_readahead_blks) {
+                       if (arg > (1 << 30))
+                               return -1;
+                       if (arg && !is_power_of_2(arg)) {
                                ext4_msg(sb, KERN_ERR,
-                                       "Cannot specify journal on remount");
-                               return 0;
+                                        "EXT4-fs: inode_readahead_blks"
+                                        " must be a power of 2");
+                               return -1;
                        }
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       *journal_devnum = option;
-                       break;
-               case Opt_journal_checksum:
-                       set_opt(sb, JOURNAL_CHECKSUM);
-                       break;
-               case Opt_journal_async_commit:
-                       set_opt(sb, JOURNAL_ASYNC_COMMIT);
-                       set_opt(sb, JOURNAL_CHECKSUM);
-                       break;
-               case Opt_noload:
-                       set_opt(sb, NOLOAD);
-                       break;
-               case Opt_commit:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0)
-                               return 0;
-                       if (option == 0)
-                               option = JBD2_DEFAULT_MAX_COMMIT_AGE;
-                       sbi->s_commit_interval = HZ * option;
-                       break;
-               case Opt_max_batch_time:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0)
-                               return 0;
-                       if (option == 0)
-                               option = EXT4_DEF_MAX_BATCH_TIME;
-                       sbi->s_max_batch_time = option;
-                       break;
-               case Opt_min_batch_time:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0)
-                               return 0;
-                       sbi->s_min_batch_time = option;
-                       break;
-               case Opt_data_journal:
-                       data_opt = EXT4_MOUNT_JOURNAL_DATA;
-                       goto datacheck;
-               case Opt_data_ordered:
-                       data_opt = EXT4_MOUNT_ORDERED_DATA;
-                       goto datacheck;
-               case Opt_data_writeback:
-                       data_opt = EXT4_MOUNT_WRITEBACK_DATA;
-               datacheck:
+                       sbi->s_inode_readahead_blks = arg;
+               } else if (token == Opt_init_itable) {
+                       set_opt(sb, INIT_INODE_TABLE);
+                       if (!args->from)
+                               arg = EXT4_DEF_LI_WAIT_MULT;
+                       sbi->s_li_wait_mult = arg;
+               } else if (token == Opt_stripe) {
+                       sbi->s_stripe = arg;
+               } else if (m->flags & MOPT_DATAJ) {
                        if (is_remount) {
                                if (!sbi->s_journal)
                                        ext4_msg(sb, KERN_WARNING, "Remounting file system with no journal so ignoring journalled data option");
-                               else if (test_opt(sb, DATA_FLAGS) != data_opt) {
+                               else if (test_opt(sb, DATA_FLAGS) !=
+                                        m->mount_opt) {
                                        ext4_msg(sb, KERN_ERR,
-                                               "Cannot change data mode on remount");
-                                       return 0;
+                                        "Cannot change data mode on remount");
+                                       return -1;
                                }
                        } else {
                                clear_opt(sb, DATA_FLAGS);
-                               sbi->s_mount_opt |= data_opt;
+                               sbi->s_mount_opt |= m->mount_opt;
                        }
-                       break;
-               case Opt_data_err_abort:
-                       set_opt(sb, DATA_ERR_ABORT);
-                       break;
-               case Opt_data_err_ignore:
-                       clear_opt(sb, DATA_ERR_ABORT);
-                       break;
 #ifdef CONFIG_QUOTA
-               case Opt_usrjquota:
+               } else if (token == Opt_usrjquota) {
                        if (!set_qf_name(sb, USRQUOTA, &args[0]))
-                               return 0;
-                       break;
-               case Opt_grpjquota:
+                               return -1;
+               } else if (token == Opt_grpjquota) {
                        if (!set_qf_name(sb, GRPQUOTA, &args[0]))
-                               return 0;
-                       break;
-               case Opt_offusrjquota:
+                               return -1;
+               } else if (token == Opt_offusrjquota) {
                        if (!clear_qf_name(sb, USRQUOTA))
-                               return 0;
-                       break;
-               case Opt_offgrpjquota:
+                               return -1;
+               } else if (token == Opt_offgrpjquota) {
                        if (!clear_qf_name(sb, GRPQUOTA))
-                               return 0;
-                       break;
-
-               case Opt_jqfmt_vfsold:
-                       qfmt = QFMT_VFS_OLD;
-                       goto set_qf_format;
-               case Opt_jqfmt_vfsv0:
-                       qfmt = QFMT_VFS_V0;
-                       goto set_qf_format;
-               case Opt_jqfmt_vfsv1:
-                       qfmt = QFMT_VFS_V1;
-set_qf_format:
+                               return -1;
+               } else if (m->flags & MOPT_QFMT) {
                        if (sb_any_quota_loaded(sb) &&
-                           sbi->s_jquota_fmt != qfmt) {
-                               ext4_msg(sb, KERN_ERR, "Cannot change "
-                                       "journaled quota options when "
-                                       "quota turned on");
-                               return 0;
-                       }
-                       sbi->s_jquota_fmt = qfmt;
-                       break;
-               case Opt_quota:
-               case Opt_usrquota:
-                       set_opt(sb, QUOTA);
-                       set_opt(sb, USRQUOTA);
-                       break;
-               case Opt_grpquota:
-                       set_opt(sb, QUOTA);
-                       set_opt(sb, GRPQUOTA);
-                       break;
-               case Opt_noquota:
-                       if (sb_any_quota_loaded(sb)) {
-                               ext4_msg(sb, KERN_ERR, "Cannot change quota "
-                                       "options when quota turned on");
-                               return 0;
+                           sbi->s_jquota_fmt != m->mount_opt) {
+                               ext4_msg(sb, KERN_ERR, "Cannot "
+                                        "change journaled quota options "
+                                        "when quota turned on");
+                               return -1;
                        }
-                       clear_opt(sb, QUOTA);
-                       clear_opt(sb, USRQUOTA);
-                       clear_opt(sb, GRPQUOTA);
-                       break;
-#else
-               case Opt_quota:
-               case Opt_usrquota:
-               case Opt_grpquota:
-                       ext4_msg(sb, KERN_ERR,
-                               "quota options not supported");
-                       break;
-               case Opt_usrjquota:
-               case Opt_grpjquota:
-               case Opt_offusrjquota:
-               case Opt_offgrpjquota:
-               case Opt_jqfmt_vfsold:
-               case Opt_jqfmt_vfsv0:
-               case Opt_jqfmt_vfsv1:
-                       ext4_msg(sb, KERN_ERR,
-                               "journaled quota options not supported");
-                       break;
-               case Opt_noquota:
-                       break;
+                       sbi->s_jquota_fmt = m->mount_opt;
 #endif
-               case Opt_abort:
-                       sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
-                       break;
-               case Opt_nobarrier:
-                       clear_opt(sb, BARRIER);
-                       break;
-               case Opt_barrier:
-                       if (args[0].from) {
-                               if (match_int(&args[0], &option))
-                                       return 0;
-                       } else
-                               option = 1;     /* No argument, default to 1 */
-                       if (option)
-                               set_opt(sb, BARRIER);
-                       else
-                               clear_opt(sb, BARRIER);
-                       break;
-               case Opt_ignore:
-                       break;
-               case Opt_resize:
-                       if (!is_remount) {
-                               ext4_msg(sb, KERN_ERR,
-                                       "resize option only available "
-                                       "for remount");
-                               return 0;
-                       }
-                       if (match_int(&args[0], &option) != 0)
-                               return 0;
-                       *n_blocks_count = option;
-                       break;
-               case Opt_nobh:
-                       ext4_msg(sb, KERN_WARNING,
-                                "Ignoring deprecated nobh option");
-                       break;
-               case Opt_bh:
-                       ext4_msg(sb, KERN_WARNING,
-                                "Ignoring deprecated bh option");
-                       break;
-               case Opt_i_version:
-                       set_opt(sb, I_VERSION);
-                       sb->s_flags |= MS_I_VERSION;
-                       break;
-               case Opt_nodelalloc:
-                       clear_opt(sb, DELALLOC);
-                       clear_opt2(sb, EXPLICIT_DELALLOC);
-                       break;
-               case Opt_mblk_io_submit:
-                       set_opt(sb, MBLK_IO_SUBMIT);
-                       break;
-               case Opt_nomblk_io_submit:
-                       clear_opt(sb, MBLK_IO_SUBMIT);
-                       break;
-               case Opt_stripe:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0)
-                               return 0;
-                       sbi->s_stripe = option;
-                       break;
-               case Opt_delalloc:
-                       set_opt(sb, DELALLOC);
-                       set_opt2(sb, EXPLICIT_DELALLOC);
-                       break;
-               case Opt_block_validity:
-                       set_opt(sb, BLOCK_VALIDITY);
-                       break;
-               case Opt_noblock_validity:
-                       clear_opt(sb, BLOCK_VALIDITY);
-                       break;
-               case Opt_inode_readahead_blks:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0 || option > (1 << 30))
-                               return 0;
-                       if (option && !is_power_of_2(option)) {
-                               ext4_msg(sb, KERN_ERR,
-                                        "EXT4-fs: inode_readahead_blks"
-                                        " must be a power of 2");
-                               return 0;
+               } else {
+                       if (!args->from)
+                               arg = 1;
+                       if (m->flags & MOPT_CLEAR)
+                               arg = !arg;
+                       else if (unlikely(!(m->flags & MOPT_SET))) {
+                               ext4_msg(sb, KERN_WARNING,
+                                        "buggy handling of option %s", opt);
+                               WARN_ON(1);
+                               return -1;
                        }
-                       sbi->s_inode_readahead_blks = option;
-                       break;
-               case Opt_journal_ioprio:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0 || option > 7)
-                               break;
-                       *journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE,
-                                                           option);
-                       break;
-               case Opt_noauto_da_alloc:
-                       set_opt(sb, NO_AUTO_DA_ALLOC);
-                       break;
-               case Opt_auto_da_alloc:
-                       if (args[0].from) {
-                               if (match_int(&args[0], &option))
-                                       return 0;
-                       } else
-                               option = 1;     /* No argument, default to 1 */
-                       if (option)
-                               clear_opt(sb, NO_AUTO_DA_ALLOC);
+                       if (arg != 0)
+                               sbi->s_mount_opt |= m->mount_opt;
                        else
-                               set_opt(sb,NO_AUTO_DA_ALLOC);
-                       break;
-               case Opt_discard:
-                       set_opt(sb, DISCARD);
-                       break;
-               case Opt_nodiscard:
-                       clear_opt(sb, DISCARD);
-                       break;
-               case Opt_dioread_nolock:
-                       set_opt(sb, DIOREAD_NOLOCK);
-                       break;
-               case Opt_dioread_lock:
-                       clear_opt(sb, DIOREAD_NOLOCK);
-                       break;
-               case Opt_init_itable:
-                       set_opt(sb, INIT_INODE_TABLE);
-                       if (args[0].from) {
-                               if (match_int(&args[0], &option))
-                                       return 0;
-                       } else
-                               option = EXT4_DEF_LI_WAIT_MULT;
-                       if (option < 0)
-                               return 0;
-                       sbi->s_li_wait_mult = option;
-                       break;
-               case Opt_noinit_itable:
-                       clear_opt(sb, INIT_INODE_TABLE);
-                       break;
-               default:
-                       ext4_msg(sb, KERN_ERR,
-                              "Unrecognized mount option \"%s\" "
-                              "or missing value", p);
-                       return 0;
+                               sbi->s_mount_opt &= ~m->mount_opt;
                }
+               return 1;
+       }
+       ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" "
+                "or missing value", opt);
+       return -1;
+}
+
+static int parse_options(char *options, struct super_block *sb,
+                        unsigned long *journal_devnum,
+                        unsigned int *journal_ioprio,
+                        int is_remount)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int token;
+
+       if (!options)
+               return 1;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               if (!*p)
+                       continue;
+               /*
+                * Initialize args struct so we know whether arg was
+                * found; some options take optional arguments.
+                */
+               args[0].to = args[0].from = 0;
+               token = match_token(p, tokens, args);
+               if (handle_mount_opt(sb, p, token, args, journal_devnum,
+                                    journal_ioprio, is_remount) < 0)
+                       return 0;
        }
 #ifdef CONFIG_QUOTA
        if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
@@ -1942,6 +1651,160 @@ set_qf_format:
        return 1;
 }
 
+static inline void ext4_show_quota_options(struct seq_file *seq,
+                                          struct super_block *sb)
+{
+#if defined(CONFIG_QUOTA)
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+       if (sbi->s_jquota_fmt) {
+               char *fmtname = "";
+
+               switch (sbi->s_jquota_fmt) {
+               case QFMT_VFS_OLD:
+                       fmtname = "vfsold";
+                       break;
+               case QFMT_VFS_V0:
+                       fmtname = "vfsv0";
+                       break;
+               case QFMT_VFS_V1:
+                       fmtname = "vfsv1";
+                       break;
+               }
+               seq_printf(seq, ",jqfmt=%s", fmtname);
+       }
+
+       if (sbi->s_qf_names[USRQUOTA])
+               seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
+
+       if (sbi->s_qf_names[GRPQUOTA])
+               seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
+
+       if (test_opt(sb, USRQUOTA))
+               seq_puts(seq, ",usrquota");
+
+       if (test_opt(sb, GRPQUOTA))
+               seq_puts(seq, ",grpquota");
+#endif
+}
+
+static const char *token2str(int token)
+{
+       static const struct match_token *t;
+
+       for (t = tokens; t->token != Opt_err; t++)
+               if (t->token == token && !strchr(t->pattern, '='))
+                       break;
+       return t->pattern;
+}
+
+/*
+ * Show an option if
+ *  - it's set to a non-default value OR
+ *  - if the per-sb default is different from the global default
+ */
+static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
+                             int nodefs)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_super_block *es = sbi->s_es;
+       int def_errors, def_mount_opt = nodefs ? 0 : sbi->s_def_mount_opt;
+       const struct mount_opts *m;
+       char sep = nodefs ? '\n' : ',';
+
+#define SEQ_OPTS_PUTS(str) seq_printf(seq, "%c" str, sep)
+#define SEQ_OPTS_PRINT(str, arg) seq_printf(seq, "%c" str, sep, arg)
+
+       if (sbi->s_sb_block != 1)
+               SEQ_OPTS_PRINT("sb=%llu", sbi->s_sb_block);
+
+       for (m = ext4_mount_opts; m->token != Opt_err; m++) {
+               int want_set = m->flags & MOPT_SET;
+               if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) ||
+                   (m->flags & MOPT_CLEAR_ERR))
+                       continue;
+               if (!(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt)))
+                       continue; /* skip if same as the default */
+               if ((want_set &&
+                    (sbi->s_mount_opt & m->mount_opt) != m->mount_opt) ||
+                   (!want_set && (sbi->s_mount_opt & m->mount_opt)))
+                       continue; /* select Opt_noFoo vs Opt_Foo */
+               SEQ_OPTS_PRINT("%s", token2str(m->token));
+       }
+
+       if (nodefs || sbi->s_resuid != EXT4_DEF_RESUID ||
+           le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID)
+               SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid);
+       if (nodefs || sbi->s_resgid != EXT4_DEF_RESGID ||
+           le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID)
+               SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid);
+       def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors);
+       if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO)
+               SEQ_OPTS_PUTS("errors=remount-ro");
+       if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE)
+               SEQ_OPTS_PUTS("errors=continue");
+       if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC)
+               SEQ_OPTS_PUTS("errors=panic");
+       if (nodefs || sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ)
+               SEQ_OPTS_PRINT("commit=%lu", sbi->s_commit_interval / HZ);
+       if (nodefs || sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME)
+               SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time);
+       if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME)
+               SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time);
+       if (sb->s_flags & MS_I_VERSION)
+               SEQ_OPTS_PUTS("i_version");
+       if (nodefs || sbi->s_stripe)
+               SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe);
+       if (EXT4_MOUNT_DATA_FLAGS & (sbi->s_mount_opt ^ def_mount_opt)) {
+               if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
+                       SEQ_OPTS_PUTS("data=journal");
+               else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
+                       SEQ_OPTS_PUTS("data=ordered");
+               else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
+                       SEQ_OPTS_PUTS("data=writeback");
+       }
+       if (nodefs ||
+           sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS)
+               SEQ_OPTS_PRINT("inode_readahead_blks=%u",
+                              sbi->s_inode_readahead_blks);
+
+       if (nodefs || (test_opt(sb, INIT_INODE_TABLE) &&
+                      (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)))
+               SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult);
+
+       ext4_show_quota_options(seq, sb);
+       return 0;
+}
+
+static int ext4_show_options(struct seq_file *seq, struct dentry *root)
+{
+       return _ext4_show_options(seq, root->d_sb, 0);
+}
+
+static int options_seq_show(struct seq_file *seq, void *offset)
+{
+       struct super_block *sb = seq->private;
+       int rc;
+
+       seq_puts(seq, (sb->s_flags & MS_RDONLY) ? "ro" : "rw");
+       rc = _ext4_show_options(seq, sb, 1);
+       seq_puts(seq, "\n");
+       return rc;
+}
+
+static int options_open_fs(struct inode *inode, struct file *file)
+{
+       return single_open(file, options_seq_show, PDE(inode)->data);
+}
+
+static const struct file_operations ext4_seq_options_fops = {
+       .owner = THIS_MODULE,
+       .open = options_open_fs,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
                            int read_only)
 {
@@ -2945,7 +2808,7 @@ static int ext4_run_lazyinit_thread(void)
                ext4_clear_request_list();
                kfree(ext4_li_info);
                ext4_li_info = NULL;
-               printk(KERN_CRIT "EXT4: error %d creating inode table "
+               printk(KERN_CRIT "EXT4-fs: error %d creating inode table "
                                 "initialization thread\n",
                                 err);
                return err;
@@ -3183,11 +3046,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        set_opt(sb, INIT_INODE_TABLE);
        if (def_mount_opts & EXT4_DEFM_DEBUG)
                set_opt(sb, DEBUG);
-       if (def_mount_opts & EXT4_DEFM_BSDGROUPS) {
-               ext4_msg(sb, KERN_WARNING, deprecated_msg, "bsdgroups",
-                       "2.6.38");
+       if (def_mount_opts & EXT4_DEFM_BSDGROUPS)
                set_opt(sb, GRPID);
-       }
        if (def_mount_opts & EXT4_DEFM_UID16)
                set_opt(sb, NO_UID32);
        /* xattr user namespace & acls are now defaulted on */
@@ -3240,13 +3100,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
 
        if (!parse_options((char *) sbi->s_es->s_mount_opts, sb,
-                          &journal_devnum, &journal_ioprio, NULL, 0)) {
+                          &journal_devnum, &journal_ioprio, 0)) {
                ext4_msg(sb, KERN_WARNING,
                         "failed to parse options in superblock: %s",
                         sbi->s_es->s_mount_opts);
        }
+       sbi->s_def_mount_opt = sbi->s_mount_opt;
        if (!parse_options((char *) data, sb, &journal_devnum,
-                          &journal_ioprio, NULL, 0))
+                          &journal_ioprio, 0))
                goto failed_mount;
 
        if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
@@ -3416,7 +3277,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 #else
                es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
 #endif
-               sb->s_dirt = 1;
        }
 
        /* Handle clustersize */
@@ -3540,6 +3400,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        if (ext4_proc_root)
                sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
 
+       if (sbi->s_proc)
+               proc_create_data("options", S_IRUGO, sbi->s_proc,
+                                &ext4_seq_options_fops, sb);
+
        bgl_lock_init(sbi->s_blockgroup_lock);
 
        for (i = 0; i < db_count; i++) {
@@ -3694,6 +3558,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
        set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 
+       sbi->s_journal->j_commit_callback = ext4_journal_commit_callback;
+
        /*
         * The journal may have updated the bg summary counts, so we
         * need to update the global counters.
@@ -3861,6 +3727,7 @@ failed_mount2:
        ext4_kvfree(sbi->s_group_desc);
 failed_mount:
        if (sbi->s_proc) {
+               remove_proc_entry("options", sbi->s_proc);
                remove_proc_entry(sb->s_id, ext4_proc_root);
        }
 #ifdef CONFIG_QUOTA
@@ -4090,15 +3957,6 @@ static int ext4_load_journal(struct super_block *sb,
        if (!(journal->j_flags & JBD2_BARRIER))
                ext4_msg(sb, KERN_INFO, "barriers disabled");
 
-       if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) {
-               err = jbd2_journal_update_format(journal);
-               if (err)  {
-                       ext4_msg(sb, KERN_ERR, "error updating journal");
-                       jbd2_journal_destroy(journal);
-                       return err;
-               }
-       }
-
        if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
                err = jbd2_journal_wipe(journal, !really_read_only);
        if (!err) {
@@ -4385,7 +4243,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 {
        struct ext4_super_block *es;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       ext4_fsblk_t n_blocks_count = 0;
        unsigned long old_sb_flags;
        struct ext4_mount_options old_opts;
        int enable_quota = 0;
@@ -4418,8 +4275,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        /*
         * Allow the "check" option to be passed as a remount option.
         */
-       if (!parse_options(data, sb, NULL, &journal_ioprio,
-                          &n_blocks_count, 1)) {
+       if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) {
                err = -EINVAL;
                goto restore_opts;
        }
@@ -4437,8 +4293,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
        }
 
-       if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
-               n_blocks_count > ext4_blocks_count(es)) {
+       if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
                if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) {
                        err = -EROFS;
                        goto restore_opts;
@@ -4513,8 +4368,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                        if (sbi->s_journal)
                                ext4_clear_journal_err(sb, es);
                        sbi->s_mount_state = le16_to_cpu(es->s_state);
-                       if ((err = ext4_group_extend(sb, es, n_blocks_count)))
-                               goto restore_opts;
                        if (!ext4_setup_super(sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
                        if (EXT4_HAS_INCOMPAT_FEATURE(sb,
index 93a00d8..e88748e 100644 (file)
@@ -82,8 +82,8 @@
                printk("\n"); \
        } while (0)
 #else
-# define ea_idebug(f...)
-# define ea_bdebug(f...)
+# define ea_idebug(inode, fmt, ...)    no_printk(fmt, ##__VA_ARGS__)
+# define ea_bdebug(bh, fmt, ...)       no_printk(fmt, ##__VA_ARGS__)
 #endif
 
 static void ext4_xattr_cache_insert(struct buffer_head *);
@@ -158,13 +158,10 @@ ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end)
 static inline int
 ext4_xattr_check_block(struct buffer_head *bh)
 {
-       int error;
-
        if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
            BHDR(bh)->h_blocks != cpu_to_le32(1))
                return -EIO;
-       error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size);
-       return error;
+       return ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size);
 }
 
 static inline int
@@ -220,7 +217,8 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
        error = -ENODATA;
        if (!EXT4_I(inode)->i_file_acl)
                goto cleanup;
-       ea_idebug(inode, "reading block %u", EXT4_I(inode)->i_file_acl);
+       ea_idebug(inode, "reading block %llu",
+                 (unsigned long long)EXT4_I(inode)->i_file_acl);
        bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
        if (!bh)
                goto cleanup;
@@ -363,7 +361,8 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
        error = 0;
        if (!EXT4_I(inode)->i_file_acl)
                goto cleanup;
-       ea_idebug(inode, "reading block %u", EXT4_I(inode)->i_file_acl);
+       ea_idebug(inode, "reading block %llu",
+                 (unsigned long long)EXT4_I(inode)->i_file_acl);
        bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
        error = -EIO;
        if (!bh)
@@ -487,18 +486,19 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
                ext4_free_blocks(handle, inode, bh, 0, 1,
                                 EXT4_FREE_BLOCKS_METADATA |
                                 EXT4_FREE_BLOCKS_FORGET);
+               unlock_buffer(bh);
        } else {
                le32_add_cpu(&BHDR(bh)->h_refcount, -1);
+               if (ce)
+                       mb_cache_entry_release(ce);
+               unlock_buffer(bh);
                error = ext4_handle_dirty_metadata(handle, inode, bh);
                if (IS_SYNC(inode))
                        ext4_handle_sync(handle);
                dquot_free_block(inode, 1);
                ea_bdebug(bh, "refcount now=%d; releasing",
                          le32_to_cpu(BHDR(bh)->h_refcount));
-               if (ce)
-                       mb_cache_entry_release(ce);
        }
-       unlock_buffer(bh);
 out:
        ext4_std_error(inode->i_sb, error);
        return;
@@ -834,7 +834,8 @@ inserted:
                        if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
                                BUG_ON(block > EXT4_MAX_BLOCK_FILE_PHYS);
 
-                       ea_idebug(inode, "creating block %d", block);
+                       ea_idebug(inode, "creating block %llu",
+                                 (unsigned long long)block);
 
                        new_bh = sb_getblk(sb, block);
                        if (!new_bh) {
index a81eb23..98ae804 100644 (file)
@@ -521,57 +521,46 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
 
                op = &outname[*outlen * sizeof(wchar_t)];
        } else {
-               if (nls) {
-                       for (i = 0, ip = name, op = outname, *outlen = 0;
-                            i < len && *outlen <= FAT_LFN_LEN;
-                            *outlen += 1)
-                       {
-                               if (escape && (*ip == ':')) {
-                                       if (i > len - 5)
-                                               return -EINVAL;
-                                       ec = 0;
-                                       for (k = 1; k < 5; k++) {
-                                               nc = ip[k];
-                                               ec <<= 4;
-                                               if (nc >= '0' && nc <= '9') {
-                                                       ec |= nc - '0';
-                                                       continue;
-                                               }
-                                               if (nc >= 'a' && nc <= 'f') {
-                                                       ec |= nc - ('a' - 10);
-                                                       continue;
-                                               }
-                                               if (nc >= 'A' && nc <= 'F') {
-                                                       ec |= nc - ('A' - 10);
-                                                       continue;
-                                               }
-                                               return -EINVAL;
+               for (i = 0, ip = name, op = outname, *outlen = 0;
+                        i < len && *outlen < FAT_LFN_LEN;
+                        *outlen += 1) {
+                       if (escape && (*ip == ':')) {
+                               if (i > len - 5)
+                                       return -EINVAL;
+                               ec = 0;
+                               for (k = 1; k < 5; k++) {
+                                       nc = ip[k];
+                                       ec <<= 4;
+                                       if (nc >= '0' && nc <= '9') {
+                                               ec |= nc - '0';
+                                               continue;
                                        }
-                                       *op++ = ec & 0xFF;
-                                       *op++ = ec >> 8;
-                                       ip += 5;
-                                       i += 5;
-                               } else {
-                                       if ((charlen = nls->char2uni(ip, len - i, (wchar_t *)op)) < 0)
-                                               return -EINVAL;
-                                       ip += charlen;
-                                       i += charlen;
-                                       op += 2;
+                                       if (nc >= 'a' && nc <= 'f') {
+                                               ec |= nc - ('a' - 10);
+                                               continue;
+                                       }
+                                       if (nc >= 'A' && nc <= 'F') {
+                                               ec |= nc - ('A' - 10);
+                                               continue;
+                                       }
+                                       return -EINVAL;
                                }
+                               *op++ = ec & 0xFF;
+                               *op++ = ec >> 8;
+                               ip += 5;
+                               i += 5;
+                       } else {
+                               charlen = nls->char2uni(ip, len - i,
+                                                                       (wchar_t *)op);
+                               if (charlen < 0)
+                                       return -EINVAL;
+                               ip += charlen;
+                               i += charlen;
+                               op += 2;
                        }
-                       if (i < len)
-                               return -ENAMETOOLONG;
-               } else {
-                       for (i = 0, ip = name, op = outname, *outlen = 0;
-                            i < len && *outlen <= FAT_LFN_LEN;
-                            i++, *outlen += 1)
-                       {
-                               *op++ = *ip++;
-                               *op++ = 0;
-                       }
-                       if (i < len)
-                               return -ENAMETOOLONG;
                }
+               if (i < len)
+                       return -ENAMETOOLONG;
        }
 
        *longlen = *outlen;
index 4c6992d..3c426de 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -6,7 +6,7 @@
  *  Manage the dynamic fd arrays in the process files_struct.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/mmzone.h>
index 77b535a..539f36c 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
@@ -256,7 +256,8 @@ static bool inode_dirtied_after(struct inode *inode, unsigned long t)
 }
 
 /*
- * Move expired dirty inodes from @delaying_queue to @dispatch_queue.
+ * Move expired (dirtied after work->older_than_this) dirty inodes from
+ * @delaying_queue to @dispatch_queue.
  */
 static int move_expired_inodes(struct list_head *delaying_queue,
                               struct list_head *dispatch_queue,
@@ -1148,23 +1149,6 @@ out_unlock_inode:
 }
 EXPORT_SYMBOL(__mark_inode_dirty);
 
-/*
- * Write out a superblock's list of dirty inodes.  A wait will be performed
- * upon no inodes, all inodes or the final one, depending upon sync_mode.
- *
- * If older_than_this is non-NULL, then only write out inodes which
- * had their first dirtying at a time earlier than *older_than_this.
- *
- * If `bdi' is non-zero then we're being asked to writeback a specific queue.
- * This function assumes that the blockdev superblock's inodes are backed by
- * a variety of queues, so all inodes are searched.  For other superblocks,
- * assume that all inodes are backed by the same queue.
- *
- * The inodes to be written are parked on bdi->b_io.  They are moved back onto
- * bdi->b_dirty as they are selected for writing.  This way, none can be missed
- * on the writer throttling path, and we get decent balancing between many
- * throttled threads: we don't want them all piling up on inode_sync_wait.
- */
 static void wait_sb_inodes(struct super_block *sb)
 {
        struct inode *inode, *old_inode = NULL;
@@ -1364,8 +1348,6 @@ int write_inode_now(struct inode *inode, int sync)
        ret = writeback_single_inode(inode, wb, &wbc);
        spin_unlock(&inode->i_lock);
        spin_unlock(&wb->list_lock);
-       if (sync)
-               inode_sync_wait(inode);
        return ret;
 }
 EXPORT_SYMBOL(write_inode_now);
index 6324c42..e159e68 100644 (file)
@@ -1,4 +1,4 @@
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/path.h>
index 3cbfa93..1fe7313 100644 (file)
@@ -67,7 +67,8 @@ extern int access_file(char *path, int r, int w, int x);
 extern int open_file(char *path, int r, int w, int append);
 extern void *open_dir(char *path, int *err_out);
 extern char *read_dir(void *stream, unsigned long long *pos,
-                     unsigned long long *ino_out, int *len_out);
+                     unsigned long long *ino_out, int *len_out,
+                     unsigned int *type_out);
 extern void close_file(void *stream);
 extern int replace_file(int oldfd, int fd);
 extern void close_dir(void *stream);
index 588d458..07c516b 100644 (file)
@@ -283,6 +283,7 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
        char *name;
        unsigned long long next, ino;
        int error, len;
+       unsigned int type;
 
        name = dentry_name(file->f_path.dentry);
        if (name == NULL)
@@ -292,9 +293,9 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
        if (dir == NULL)
                return -error;
        next = file->f_pos;
-       while ((name = read_dir(dir, &next, &ino, &len)) != NULL) {
+       while ((name = read_dir(dir, &next, &ino, &len, &type)) != NULL) {
                error = (*filldir)(ent, name, len, file->f_pos,
-                                  ino, DT_UNKNOWN);
+                                  ino, type);
                if (error) break;
                file->f_pos = next;
        }
index dd7bc38..a74ad0d 100644 (file)
@@ -98,7 +98,8 @@ void *open_dir(char *path, int *err_out)
 }
 
 char *read_dir(void *stream, unsigned long long *pos,
-              unsigned long long *ino_out, int *len_out)
+              unsigned long long *ino_out, int *len_out,
+              unsigned int *type_out)
 {
        DIR *dir = stream;
        struct dirent *ent;
@@ -109,6 +110,7 @@ char *read_dir(void *stream, unsigned long long *pos,
                return NULL;
        *len_out = strlen(ent->d_name);
        *ino_out = ent->d_ino;
+       *type_out = ent->d_type;
        *pos = telldir(dir);
        return ent->d_name;
 }
index 066836e..29167be 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/security.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/uaccess.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>
index d49d202..c78841e 100644 (file)
@@ -88,14 +88,13 @@ static inline void __buffer_relink_io(struct journal_head *jh)
  * whole transaction.
  *
  * Requires j_list_lock
- * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
  */
 static int __try_to_free_cp_buf(struct journal_head *jh)
 {
        int ret = 0;
        struct buffer_head *bh = jh2bh(jh);
 
-       if (jh->b_jlist == BJ_None && !buffer_locked(bh) &&
+       if (jh->b_transaction == NULL && !buffer_locked(bh) &&
            !buffer_dirty(bh) && !buffer_write_io_error(bh)) {
                /*
                 * Get our reference so that bh cannot be freed before
@@ -104,11 +103,8 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
                get_bh(bh);
                JBUFFER_TRACE(jh, "remove from checkpoint list");
                ret = __jbd2_journal_remove_checkpoint(jh) + 1;
-               jbd_unlock_bh_state(bh);
                BUFFER_TRACE(bh, "release");
                __brelse(bh);
-       } else {
-               jbd_unlock_bh_state(bh);
        }
        return ret;
 }
@@ -180,21 +176,6 @@ void __jbd2_log_wait_for_space(journal_t *journal)
 }
 
 /*
- * We were unable to perform jbd_trylock_bh_state() inside j_list_lock.
- * The caller must restart a list walk.  Wait for someone else to run
- * jbd_unlock_bh_state().
- */
-static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh)
-       __releases(journal->j_list_lock)
-{
-       get_bh(bh);
-       spin_unlock(&journal->j_list_lock);
-       jbd_lock_bh_state(bh);
-       jbd_unlock_bh_state(bh);
-       put_bh(bh);
-}
-
-/*
  * Clean up transaction's list of buffers submitted for io.
  * We wait for any pending IO to complete and remove any clean
  * buffers. Note that we take the buffers in the opposite ordering
@@ -222,15 +203,9 @@ restart:
        while (!released && transaction->t_checkpoint_io_list) {
                jh = transaction->t_checkpoint_io_list;
                bh = jh2bh(jh);
-               if (!jbd_trylock_bh_state(bh)) {
-                       jbd_sync_bh(journal, bh);
-                       spin_lock(&journal->j_list_lock);
-                       goto restart;
-               }
                get_bh(bh);
                if (buffer_locked(bh)) {
                        spin_unlock(&journal->j_list_lock);
-                       jbd_unlock_bh_state(bh);
                        wait_on_buffer(bh);
                        /* the journal_head may have gone by now */
                        BUFFER_TRACE(bh, "brelse");
@@ -246,7 +221,6 @@ restart:
                 * it has been written out and so we can drop it from the list
                 */
                released = __jbd2_journal_remove_checkpoint(jh);
-               jbd_unlock_bh_state(bh);
                __brelse(bh);
        }
 
@@ -266,7 +240,6 @@ __flush_batch(journal_t *journal, int *batch_count)
 
        for (i = 0; i < *batch_count; i++) {
                struct buffer_head *bh = journal->j_chkpt_bhs[i];
-               clear_buffer_jwrite(bh);
                BUFFER_TRACE(bh, "brelse");
                __brelse(bh);
        }
@@ -281,7 +254,6 @@ __flush_batch(journal_t *journal, int *batch_count)
  * be written out.
  *
  * Called with j_list_lock held and drops it if 1 is returned
- * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
  */
 static int __process_buffer(journal_t *journal, struct journal_head *jh,
                            int *batch_count, transaction_t *transaction)
@@ -292,7 +264,6 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
        if (buffer_locked(bh)) {
                get_bh(bh);
                spin_unlock(&journal->j_list_lock);
-               jbd_unlock_bh_state(bh);
                wait_on_buffer(bh);
                /* the journal_head may have gone by now */
                BUFFER_TRACE(bh, "brelse");
@@ -304,7 +275,6 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
 
                transaction->t_chp_stats.cs_forced_to_close++;
                spin_unlock(&journal->j_list_lock);
-               jbd_unlock_bh_state(bh);
                if (unlikely(journal->j_flags & JBD2_UNMOUNT))
                        /*
                         * The journal thread is dead; so starting and
@@ -323,11 +293,9 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
                if (unlikely(buffer_write_io_error(bh)))
                        ret = -EIO;
                get_bh(bh);
-               J_ASSERT_JH(jh, !buffer_jbddirty(bh));
                BUFFER_TRACE(bh, "remove from checkpoint");
                __jbd2_journal_remove_checkpoint(jh);
                spin_unlock(&journal->j_list_lock);
-               jbd_unlock_bh_state(bh);
                __brelse(bh);
        } else {
                /*
@@ -340,10 +308,8 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
                BUFFER_TRACE(bh, "queue");
                get_bh(bh);
                J_ASSERT_BH(bh, !buffer_jwrite(bh));
-               set_buffer_jwrite(bh);
                journal->j_chkpt_bhs[*batch_count] = bh;
                __buffer_relink_io(jh);
-               jbd_unlock_bh_state(bh);
                transaction->t_chp_stats.cs_written++;
                (*batch_count)++;
                if (*batch_count == JBD2_NR_BATCH) {
@@ -407,15 +373,7 @@ restart:
                int retry = 0, err;
 
                while (!retry && transaction->t_checkpoint_list) {
-                       struct buffer_head *bh;
-
                        jh = transaction->t_checkpoint_list;
-                       bh = jh2bh(jh);
-                       if (!jbd_trylock_bh_state(bh)) {
-                               jbd_sync_bh(journal, bh);
-                               retry = 1;
-                               break;
-                       }
                        retry = __process_buffer(journal, jh, &batch_count,
                                                 transaction);
                        if (retry < 0 && !result)
@@ -478,79 +436,28 @@ out:
 
 int jbd2_cleanup_journal_tail(journal_t *journal)
 {
-       transaction_t * transaction;
        tid_t           first_tid;
-       unsigned long   blocknr, freed;
+       unsigned long   blocknr;
 
        if (is_journal_aborted(journal))
                return 1;
 
-       /* OK, work out the oldest transaction remaining in the log, and
-        * the log block it starts at.
-        *
-        * If the log is now empty, we need to work out which is the
-        * next transaction ID we will write, and where it will
-        * start. */
-
-       write_lock(&journal->j_state_lock);
-       spin_lock(&journal->j_list_lock);
-       transaction = journal->j_checkpoint_transactions;
-       if (transaction) {
-               first_tid = transaction->t_tid;
-               blocknr = transaction->t_log_start;
-       } else if ((transaction = journal->j_committing_transaction) != NULL) {
-               first_tid = transaction->t_tid;
-               blocknr = transaction->t_log_start;
-       } else if ((transaction = journal->j_running_transaction) != NULL) {
-               first_tid = transaction->t_tid;
-               blocknr = journal->j_head;
-       } else {
-               first_tid = journal->j_transaction_sequence;
-               blocknr = journal->j_head;
-       }
-       spin_unlock(&journal->j_list_lock);
-       J_ASSERT(blocknr != 0);
-
-       /* If the oldest pinned transaction is at the tail of the log
-           already then there's not much we can do right now. */
-       if (journal->j_tail_sequence == first_tid) {
-               write_unlock(&journal->j_state_lock);
+       if (!jbd2_journal_get_log_tail(journal, &first_tid, &blocknr))
                return 1;
-       }
-
-       /* OK, update the superblock to recover the freed space.
-        * Physical blocks come first: have we wrapped beyond the end of
-        * the log?  */
-       freed = blocknr - journal->j_tail;
-       if (blocknr < journal->j_tail)
-               freed = freed + journal->j_last - journal->j_first;
-
-       trace_jbd2_cleanup_journal_tail(journal, first_tid, blocknr, freed);
-       jbd_debug(1,
-                 "Cleaning journal tail from %d to %d (offset %lu), "
-                 "freeing %lu\n",
-                 journal->j_tail_sequence, first_tid, blocknr, freed);
-
-       journal->j_free += freed;
-       journal->j_tail_sequence = first_tid;
-       journal->j_tail = blocknr;
-       write_unlock(&journal->j_state_lock);
+       J_ASSERT(blocknr != 0);
 
        /*
-        * If there is an external journal, we need to make sure that
-        * any data blocks that were recently written out --- perhaps
-        * by jbd2_log_do_checkpoint() --- are flushed out before we
-        * drop the transactions from the external journal.  It's
-        * unlikely this will be necessary, especially with a
-        * appropriately sized journal, but we need this to guarantee
-        * correctness.  Fortunately jbd2_cleanup_journal_tail()
-        * doesn't get called all that often.
+        * We need to make sure that any blocks that were recently written out
+        * --- perhaps by jbd2_log_do_checkpoint() --- are flushed out before
+        * we drop the transactions from the journal. It's unlikely this will
+        * be necessary, especially with an appropriately sized journal, but we
+        * need this to guarantee correctness.  Fortunately
+        * jbd2_cleanup_journal_tail() doesn't get called all that often.
         */
-       if ((journal->j_fs_dev != journal->j_dev) &&
-           (journal->j_flags & JBD2_BARRIER))
+       if (journal->j_flags & JBD2_BARRIER)
                blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL);
-       if (!(journal->j_flags & JBD2_ABORT))
-               jbd2_journal_update_superblock(journal, 1);
+
+       __jbd2_update_log_tail(journal, first_tid, blocknr);
        return 0;
 }
 
@@ -582,15 +489,12 @@ static int journal_clean_one_cp_list(struct journal_head *jh, int *released)
        do {
                jh = next_jh;
                next_jh = jh->b_cpnext;
-               /* Use trylock because of the ranking */
-               if (jbd_trylock_bh_state(jh2bh(jh))) {
-                       ret = __try_to_free_cp_buf(jh);
-                       if (ret) {
-                               freed++;
-                               if (ret == 2) {
-                                       *released = 1;
-                                       return freed;
-                               }
+               ret = __try_to_free_cp_buf(jh);
+               if (ret) {
+                       freed++;
+                       if (ret == 2) {
+                               *released = 1;
+                               return freed;
                        }
                }
                /*
@@ -673,9 +577,7 @@ out:
  * The function can free jh and bh.
  *
  * This function is called with j_list_lock held.
- * This function is called with jbd_lock_bh_state(jh2bh(jh))
  */
-
 int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
 {
        struct transaction_chp_stats_s *stats;
@@ -722,7 +624,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
                                    transaction->t_tid, stats);
 
        __jbd2_journal_drop_transaction(journal, transaction);
-       kfree(transaction);
+       jbd2_journal_free_transaction(transaction);
 
        /* Just in case anybody was waiting for more transactions to be
            checkpointed... */
@@ -797,5 +699,7 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
        J_ASSERT(journal->j_committing_transaction != transaction);
        J_ASSERT(journal->j_running_transaction != transaction);
 
+       trace_jbd2_drop_transaction(journal, transaction);
+
        jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);
 }
index 29853de..806525a 100644 (file)
@@ -330,6 +330,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        struct buffer_head *cbh = NULL; /* For transactional checksums */
        __u32 crc32_sum = ~0;
        struct blk_plug plug;
+       /* Tail of the journal */
+       unsigned long first_block;
+       tid_t first_tid;
+       int update_tail;
 
        /*
         * First job: lock down the current transaction and wait for
@@ -339,7 +343,18 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        /* Do we need to erase the effects of a prior jbd2_journal_flush? */
        if (journal->j_flags & JBD2_FLUSHED) {
                jbd_debug(3, "super block updated\n");
-               jbd2_journal_update_superblock(journal, 1);
+               mutex_lock(&journal->j_checkpoint_mutex);
+               /*
+                * We hold j_checkpoint_mutex so tail cannot change under us.
+                * We don't need any special data guarantees for writing sb
+                * since journal is empty and it is ok for write to be
+                * flushed only with transaction commit.
+                */
+               jbd2_journal_update_sb_log_tail(journal,
+                                               journal->j_tail_sequence,
+                                               journal->j_tail,
+                                               WRITE_SYNC);
+               mutex_unlock(&journal->j_checkpoint_mutex);
        } else {
                jbd_debug(3, "superblock not updated\n");
        }
@@ -676,10 +691,30 @@ start_journal_io:
                err = 0;
        }
 
+       /*
+        * Get current oldest transaction in the log before we issue flush
+        * to the filesystem device. After the flush we can be sure that
+        * blocks of all older transactions are checkpointed to persistent
+        * storage and we will be safe to update journal start in the
+        * superblock with the numbers we get here.
+        */
+       update_tail =
+               jbd2_journal_get_log_tail(journal, &first_tid, &first_block);
+
        write_lock(&journal->j_state_lock);
+       if (update_tail) {
+               long freed = first_block - journal->j_tail;
+
+               if (first_block < journal->j_tail)
+                       freed += journal->j_last - journal->j_first;
+               /* Update tail only if we free significant amount of space */
+               if (freed < journal->j_maxlen / 4)
+                       update_tail = 0;
+       }
        J_ASSERT(commit_transaction->t_state == T_COMMIT);
        commit_transaction->t_state = T_COMMIT_DFLUSH;
        write_unlock(&journal->j_state_lock);
+
        /* 
         * If the journal is not located on the file system device,
         * then we must flush the file system device before we issue
@@ -830,6 +865,14 @@ wait_for_iobuf:
        if (err)
                jbd2_journal_abort(journal, err);
 
+       /*
+        * Now disk caches for filesystem device are flushed so we are safe to
+        * erase checkpointed transactions from the log by updating journal
+        * superblock.
+        */
+       if (update_tail)
+               jbd2_update_log_tail(journal, first_tid, first_block);
+
        /* End of a transaction!  Finally, we can do checkpoint
            processing: any buffers committed as a result of this
            transaction can be removed from any checkpoint list it was on
@@ -1047,7 +1090,7 @@ restart_loop:
        jbd_debug(1, "JBD2: commit %d complete, head %d\n",
                  journal->j_commit_sequence, journal->j_tail_sequence);
        if (to_free)
-               kfree(commit_transaction);
+               jbd2_journal_free_transaction(commit_transaction);
 
        wake_up(&journal->j_wait_done_commit);
 }
index c6d2274..1afb701 100644 (file)
@@ -70,7 +70,6 @@ EXPORT_SYMBOL(jbd2_journal_revoke);
 
 EXPORT_SYMBOL(jbd2_journal_init_dev);
 EXPORT_SYMBOL(jbd2_journal_init_inode);
-EXPORT_SYMBOL(jbd2_journal_update_format);
 EXPORT_SYMBOL(jbd2_journal_check_used_features);
 EXPORT_SYMBOL(jbd2_journal_check_available_features);
 EXPORT_SYMBOL(jbd2_journal_set_features);
@@ -95,7 +94,6 @@ EXPORT_SYMBOL(jbd2_journal_release_jbd_inode);
 EXPORT_SYMBOL(jbd2_journal_begin_ordered_truncate);
 EXPORT_SYMBOL(jbd2_inode_cache);
 
-static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
 static void __journal_abort_soft (journal_t *journal, int errno);
 static int jbd2_journal_create_slab(size_t slab_size);
 
@@ -745,6 +743,98 @@ struct journal_head *jbd2_journal_get_descriptor_buffer(journal_t *journal)
        return jbd2_journal_add_journal_head(bh);
 }
 
+/*
+ * Return tid of the oldest transaction in the journal and block in the journal
+ * where the transaction starts.
+ *
+ * If the journal is now empty, return which will be the next transaction ID
+ * we will write and where will that transaction start.
+ *
+ * The return value is 0 if journal tail cannot be pushed any further, 1 if
+ * it can.
+ */
+int jbd2_journal_get_log_tail(journal_t *journal, tid_t *tid,
+                             unsigned long *block)
+{
+       transaction_t *transaction;
+       int ret;
+
+       read_lock(&journal->j_state_lock);
+       spin_lock(&journal->j_list_lock);
+       transaction = journal->j_checkpoint_transactions;
+       if (transaction) {
+               *tid = transaction->t_tid;
+               *block = transaction->t_log_start;
+       } else if ((transaction = journal->j_committing_transaction) != NULL) {
+               *tid = transaction->t_tid;
+               *block = transaction->t_log_start;
+       } else if ((transaction = journal->j_running_transaction) != NULL) {
+               *tid = transaction->t_tid;
+               *block = journal->j_head;
+       } else {
+               *tid = journal->j_transaction_sequence;
+               *block = journal->j_head;
+       }
+       ret = tid_gt(*tid, journal->j_tail_sequence);
+       spin_unlock(&journal->j_list_lock);
+       read_unlock(&journal->j_state_lock);
+
+       return ret;
+}
+
+/*
+ * Update information in journal structure and in on disk journal superblock
+ * about log tail. This function does not check whether information passed in
+ * really pushes log tail further. It's responsibility of the caller to make
+ * sure provided log tail information is valid (e.g. by holding
+ * j_checkpoint_mutex all the time between computing log tail and calling this
+ * function as is the case with jbd2_cleanup_journal_tail()).
+ *
+ * Requires j_checkpoint_mutex
+ */
+void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block)
+{
+       unsigned long freed;
+
+       BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
+
+       /*
+        * We cannot afford for write to remain in drive's caches since as
+        * soon as we update j_tail, next transaction can start reusing journal
+        * space and if we lose sb update during power failure we'd replay
+        * old transaction with possibly newly overwritten data.
+        */
+       jbd2_journal_update_sb_log_tail(journal, tid, block, WRITE_FUA);
+       write_lock(&journal->j_state_lock);
+       freed = block - journal->j_tail;
+       if (block < journal->j_tail)
+               freed += journal->j_last - journal->j_first;
+
+       trace_jbd2_update_log_tail(journal, tid, block, freed);
+       jbd_debug(1,
+                 "Cleaning journal tail from %d to %d (offset %lu), "
+                 "freeing %lu\n",
+                 journal->j_tail_sequence, tid, block, freed);
+
+       journal->j_free += freed;
+       journal->j_tail_sequence = tid;
+       journal->j_tail = block;
+       write_unlock(&journal->j_state_lock);
+}
+
+/*
+ * This is a variaon of __jbd2_update_log_tail which checks for validity of
+ * provided log tail and locks j_checkpoint_mutex. So it is safe against races
+ * with other threads updating log tail.
+ */
+void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block)
+{
+       mutex_lock(&journal->j_checkpoint_mutex);
+       if (tid_gt(tid, journal->j_tail_sequence))
+               __jbd2_update_log_tail(journal, tid, block);
+       mutex_unlock(&journal->j_checkpoint_mutex);
+}
+
 struct jbd2_stats_proc_session {
        journal_t *journal;
        struct transaction_stats_s *stats;
@@ -1113,40 +1203,45 @@ static int journal_reset(journal_t *journal)
 
        journal->j_max_transaction_buffers = journal->j_maxlen / 4;
 
-       /* Add the dynamic fields and write it to disk. */
-       jbd2_journal_update_superblock(journal, 1);
-       return jbd2_journal_start_thread(journal);
-}
-
-/**
- * void jbd2_journal_update_superblock() - Update journal sb on disk.
- * @journal: The journal to update.
- * @wait: Set to '0' if you don't want to wait for IO completion.
- *
- * Update a journal's dynamic superblock fields and write it to disk,
- * optionally waiting for the IO to complete.
- */
-void jbd2_journal_update_superblock(journal_t *journal, int wait)
-{
-       journal_superblock_t *sb = journal->j_superblock;
-       struct buffer_head *bh = journal->j_sb_buffer;
-
        /*
         * As a special case, if the on-disk copy is already marked as needing
-        * no recovery (s_start == 0) and there are no outstanding transactions
-        * in the filesystem, then we can safely defer the superblock update
-        * until the next commit by setting JBD2_FLUSHED.  This avoids
+        * no recovery (s_start == 0), then we can safely defer the superblock
+        * update until the next commit by setting JBD2_FLUSHED.  This avoids
         * attempting a write to a potential-readonly device.
         */
-       if (sb->s_start == 0 && journal->j_tail_sequence ==
-                               journal->j_transaction_sequence) {
+       if (sb->s_start == 0) {
                jbd_debug(1, "JBD2: Skipping superblock update on recovered sb "
                        "(start %ld, seq %d, errno %d)\n",
                        journal->j_tail, journal->j_tail_sequence,
                        journal->j_errno);
-               goto out;
+               journal->j_flags |= JBD2_FLUSHED;
+       } else {
+               /* Lock here to make assertions happy... */
+               mutex_lock(&journal->j_checkpoint_mutex);
+               /*
+                * Update log tail information. We use WRITE_FUA since new
+                * transaction will start reusing journal space and so we
+                * must make sure information about current log tail is on
+                * disk before that.
+                */
+               jbd2_journal_update_sb_log_tail(journal,
+                                               journal->j_tail_sequence,
+                                               journal->j_tail,
+                                               WRITE_FUA);
+               mutex_unlock(&journal->j_checkpoint_mutex);
        }
+       return jbd2_journal_start_thread(journal);
+}
 
+static void jbd2_write_superblock(journal_t *journal, int write_op)
+{
+       struct buffer_head *bh = journal->j_sb_buffer;
+       int ret;
+
+       trace_jbd2_write_superblock(journal, write_op);
+       if (!(journal->j_flags & JBD2_BARRIER))
+               write_op &= ~(REQ_FUA | REQ_FLUSH);
+       lock_buffer(bh);
        if (buffer_write_io_error(bh)) {
                /*
                 * Oh, dear.  A previous attempt to write the journal
@@ -1162,48 +1257,106 @@ void jbd2_journal_update_superblock(journal_t *journal, int wait)
                clear_buffer_write_io_error(bh);
                set_buffer_uptodate(bh);
        }
+       get_bh(bh);
+       bh->b_end_io = end_buffer_write_sync;
+       ret = submit_bh(write_op, bh);
+       wait_on_buffer(bh);
+       if (buffer_write_io_error(bh)) {
+               clear_buffer_write_io_error(bh);
+               set_buffer_uptodate(bh);
+               ret = -EIO;
+       }
+       if (ret) {
+               printk(KERN_ERR "JBD2: Error %d detected when updating "
+                      "journal superblock for %s.\n", ret,
+                      journal->j_devname);
+       }
+}
+
+/**
+ * jbd2_journal_update_sb_log_tail() - Update log tail in journal sb on disk.
+ * @journal: The journal to update.
+ * @tail_tid: TID of the new transaction at the tail of the log
+ * @tail_block: The first block of the transaction at the tail of the log
+ * @write_op: With which operation should we write the journal sb
+ *
+ * Update a journal's superblock information about log tail and write it to
+ * disk, waiting for the IO to complete.
+ */
+void jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid,
+                                    unsigned long tail_block, int write_op)
+{
+       journal_superblock_t *sb = journal->j_superblock;
+
+       BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
+       jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n",
+                 tail_block, tail_tid);
+
+       sb->s_sequence = cpu_to_be32(tail_tid);
+       sb->s_start    = cpu_to_be32(tail_block);
+
+       jbd2_write_superblock(journal, write_op);
+
+       /* Log is no longer empty */
+       write_lock(&journal->j_state_lock);
+       WARN_ON(!sb->s_sequence);
+       journal->j_flags &= ~JBD2_FLUSHED;
+       write_unlock(&journal->j_state_lock);
+}
+
+/**
+ * jbd2_mark_journal_empty() - Mark on disk journal as empty.
+ * @journal: The journal to update.
+ *
+ * Update a journal's dynamic superblock fields to show that journal is empty.
+ * Write updated superblock to disk waiting for IO to complete.
+ */
+static void jbd2_mark_journal_empty(journal_t *journal)
+{
+       journal_superblock_t *sb = journal->j_superblock;
 
+       BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
        read_lock(&journal->j_state_lock);
-       jbd_debug(1, "JBD2: updating superblock (start %ld, seq %d, errno %d)\n",
-                 journal->j_tail, journal->j_tail_sequence, journal->j_errno);
+       jbd_debug(1, "JBD2: Marking journal as empty (seq %d)\n",
+                 journal->j_tail_sequence);
 
        sb->s_sequence = cpu_to_be32(journal->j_tail_sequence);
-       sb->s_start    = cpu_to_be32(journal->j_tail);
-       sb->s_errno    = cpu_to_be32(journal->j_errno);
+       sb->s_start    = cpu_to_be32(0);
        read_unlock(&journal->j_state_lock);
 
-       BUFFER_TRACE(bh, "marking dirty");
-       mark_buffer_dirty(bh);
-       if (wait) {
-               sync_dirty_buffer(bh);
-               if (buffer_write_io_error(bh)) {
-                       printk(KERN_ERR "JBD2: I/O error detected "
-                              "when updating journal superblock for %s.\n",
-                              journal->j_devname);
-                       clear_buffer_write_io_error(bh);
-                       set_buffer_uptodate(bh);
-               }
-       } else
-               write_dirty_buffer(bh, WRITE);
-
-out:
-       /* If we have just flushed the log (by marking s_start==0), then
-        * any future commit will have to be careful to update the
-        * superblock again to re-record the true start of the log. */
+       jbd2_write_superblock(journal, WRITE_FUA);
 
+       /* Log is no longer empty */
        write_lock(&journal->j_state_lock);
-       if (sb->s_start)
-               journal->j_flags &= ~JBD2_FLUSHED;
-       else
-               journal->j_flags |= JBD2_FLUSHED;
+       journal->j_flags |= JBD2_FLUSHED;
        write_unlock(&journal->j_state_lock);
 }
 
+
+/**
+ * jbd2_journal_update_sb_errno() - Update error in the journal.
+ * @journal: The journal to update.
+ *
+ * Update a journal's errno.  Write updated superblock to disk waiting for IO
+ * to complete.
+ */
+static void jbd2_journal_update_sb_errno(journal_t *journal)
+{
+       journal_superblock_t *sb = journal->j_superblock;
+
+       read_lock(&journal->j_state_lock);
+       jbd_debug(1, "JBD2: updating superblock error (errno %d)\n",
+                 journal->j_errno);
+       sb->s_errno    = cpu_to_be32(journal->j_errno);
+       read_unlock(&journal->j_state_lock);
+
+       jbd2_write_superblock(journal, WRITE_SYNC);
+}
+
 /*
  * Read the superblock for a given journal, performing initial
  * validation of the format.
  */
-
 static int journal_get_superblock(journal_t *journal)
 {
        struct buffer_head *bh;
@@ -1397,14 +1550,11 @@ int jbd2_journal_destroy(journal_t *journal)
 
        if (journal->j_sb_buffer) {
                if (!is_journal_aborted(journal)) {
-                       /* We can now mark the journal as empty. */
-                       journal->j_tail = 0;
-                       journal->j_tail_sequence =
-                               ++journal->j_transaction_sequence;
-                       jbd2_journal_update_superblock(journal, 1);
-               } else {
+                       mutex_lock(&journal->j_checkpoint_mutex);
+                       jbd2_mark_journal_empty(journal);
+                       mutex_unlock(&journal->j_checkpoint_mutex);
+               } else
                        err = -EIO;
-               }
                brelse(journal->j_sb_buffer);
        }
 
@@ -1551,61 +1701,6 @@ void jbd2_journal_clear_features(journal_t *journal, unsigned long compat,
 EXPORT_SYMBOL(jbd2_journal_clear_features);
 
 /**
- * int jbd2_journal_update_format () - Update on-disk journal structure.
- * @journal: Journal to act on.
- *
- * Given an initialised but unloaded journal struct, poke about in the
- * on-disk structure to update it to the most recent supported version.
- */
-int jbd2_journal_update_format (journal_t *journal)
-{
-       journal_superblock_t *sb;
-       int err;
-
-       err = journal_get_superblock(journal);
-       if (err)
-               return err;
-
-       sb = journal->j_superblock;
-
-       switch (be32_to_cpu(sb->s_header.h_blocktype)) {
-       case JBD2_SUPERBLOCK_V2:
-               return 0;
-       case JBD2_SUPERBLOCK_V1:
-               return journal_convert_superblock_v1(journal, sb);
-       default:
-               break;
-       }
-       return -EINVAL;
-}
-
-static int journal_convert_superblock_v1(journal_t *journal,
-                                        journal_superblock_t *sb)
-{
-       int offset, blocksize;
-       struct buffer_head *bh;
-
-       printk(KERN_WARNING
-               "JBD2: Converting superblock from version 1 to 2.\n");
-
-       /* Pre-initialise new fields to zero */
-       offset = ((char *) &(sb->s_feature_compat)) - ((char *) sb);
-       blocksize = be32_to_cpu(sb->s_blocksize);
-       memset(&sb->s_feature_compat, 0, blocksize-offset);
-
-       sb->s_nr_users = cpu_to_be32(1);
-       sb->s_header.h_blocktype = cpu_to_be32(JBD2_SUPERBLOCK_V2);
-       journal->j_format_version = 2;
-
-       bh = journal->j_sb_buffer;
-       BUFFER_TRACE(bh, "marking dirty");
-       mark_buffer_dirty(bh);
-       sync_dirty_buffer(bh);
-       return 0;
-}
-
-
-/**
  * int jbd2_journal_flush () - Flush journal
  * @journal: Journal to act on.
  *
@@ -1618,7 +1713,6 @@ int jbd2_journal_flush(journal_t *journal)
 {
        int err = 0;
        transaction_t *transaction = NULL;
-       unsigned long old_tail;
 
        write_lock(&journal->j_state_lock);
 
@@ -1653,6 +1747,7 @@ int jbd2_journal_flush(journal_t *journal)
        if (is_journal_aborted(journal))
                return -EIO;
 
+       mutex_lock(&journal->j_checkpoint_mutex);
        jbd2_cleanup_journal_tail(journal);
 
        /* Finally, mark the journal as really needing no recovery.
@@ -1660,14 +1755,9 @@ int jbd2_journal_flush(journal_t *journal)
         * the magic code for a fully-recovered superblock.  Any future
         * commits of data to the journal will restore the current
         * s_start value. */
+       jbd2_mark_journal_empty(journal);
+       mutex_unlock(&journal->j_checkpoint_mutex);
        write_lock(&journal->j_state_lock);
-       old_tail = journal->j_tail;
-       journal->j_tail = 0;
-       write_unlock(&journal->j_state_lock);
-       jbd2_journal_update_superblock(journal, 1);
-       write_lock(&journal->j_state_lock);
-       journal->j_tail = old_tail;
-
        J_ASSERT(!journal->j_running_transaction);
        J_ASSERT(!journal->j_committing_transaction);
        J_ASSERT(!journal->j_checkpoint_transactions);
@@ -1707,8 +1797,12 @@ int jbd2_journal_wipe(journal_t *journal, int write)
                write ? "Clearing" : "Ignoring");
 
        err = jbd2_journal_skip_recovery(journal);
-       if (write)
-               jbd2_journal_update_superblock(journal, 1);
+       if (write) {
+               /* Lock to make assertions happy... */
+               mutex_lock(&journal->j_checkpoint_mutex);
+               jbd2_mark_journal_empty(journal);
+               mutex_unlock(&journal->j_checkpoint_mutex);
+       }
 
  no_recovery:
        return err;
@@ -1758,7 +1852,7 @@ static void __journal_abort_soft (journal_t *journal, int errno)
        __jbd2_journal_abort_hard(journal);
 
        if (errno)
-               jbd2_journal_update_superblock(journal, 1);
+               jbd2_journal_update_sb_errno(journal);
 }
 
 /**
@@ -2016,7 +2110,7 @@ static struct kmem_cache *jbd2_journal_head_cache;
 static atomic_t nr_journal_heads = ATOMIC_INIT(0);
 #endif
 
-static int journal_init_jbd2_journal_head_cache(void)
+static int jbd2_journal_init_journal_head_cache(void)
 {
        int retval;
 
@@ -2034,7 +2128,7 @@ static int journal_init_jbd2_journal_head_cache(void)
        return retval;
 }
 
-static void jbd2_journal_destroy_jbd2_journal_head_cache(void)
+static void jbd2_journal_destroy_journal_head_cache(void)
 {
        if (jbd2_journal_head_cache) {
                kmem_cache_destroy(jbd2_journal_head_cache);
@@ -2322,7 +2416,7 @@ static void __exit jbd2_remove_jbd_stats_proc_entry(void)
 
 struct kmem_cache *jbd2_handle_cache, *jbd2_inode_cache;
 
-static int __init journal_init_handle_cache(void)
+static int __init jbd2_journal_init_handle_cache(void)
 {
        jbd2_handle_cache = KMEM_CACHE(jbd2_journal_handle, SLAB_TEMPORARY);
        if (jbd2_handle_cache == NULL) {
@@ -2357,17 +2451,20 @@ static int __init journal_init_caches(void)
 
        ret = jbd2_journal_init_revoke_caches();
        if (ret == 0)
-               ret = journal_init_jbd2_journal_head_cache();
+               ret = jbd2_journal_init_journal_head_cache();
+       if (ret == 0)
+               ret = jbd2_journal_init_handle_cache();
        if (ret == 0)
-               ret = journal_init_handle_cache();
+               ret = jbd2_journal_init_transaction_cache();
        return ret;
 }
 
 static void jbd2_journal_destroy_caches(void)
 {
        jbd2_journal_destroy_revoke_caches();
-       jbd2_journal_destroy_jbd2_journal_head_cache();
+       jbd2_journal_destroy_journal_head_cache();
        jbd2_journal_destroy_handle_cache();
+       jbd2_journal_destroy_transaction_cache();
        jbd2_journal_destroy_slabs();
 }
 
index da6d7ba..c1a0335 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/jbd2.h>
 #include <linux/errno.h>
 #include <linux/crc32.h>
+#include <linux/blkdev.h>
 #endif
 
 /*
@@ -265,7 +266,9 @@ int jbd2_journal_recover(journal_t *journal)
        err2 = sync_blockdev(journal->j_fs_dev);
        if (!err)
                err = err2;
-
+       /* Make sure all replayed data is on permanent storage */
+       if (journal->j_flags & JBD2_BARRIER)
+               blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL);
        return err;
 }
 
index 30b2867..6973705 100644 (file)
@@ -208,17 +208,13 @@ int __init jbd2_journal_init_revoke_caches(void)
        J_ASSERT(!jbd2_revoke_record_cache);
        J_ASSERT(!jbd2_revoke_table_cache);
 
-       jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record",
-                                          sizeof(struct jbd2_revoke_record_s),
-                                          0,
-                                          SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY,
-                                          NULL);
+       jbd2_revoke_record_cache = KMEM_CACHE(jbd2_revoke_record_s,
+                                       SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY);
        if (!jbd2_revoke_record_cache)
                goto record_cache_failure;
 
-       jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table",
-                                          sizeof(struct jbd2_revoke_table_s),
-                                          0, SLAB_TEMPORARY, NULL);
+       jbd2_revoke_table_cache = KMEM_CACHE(jbd2_revoke_table_s,
+                                            SLAB_TEMPORARY);
        if (!jbd2_revoke_table_cache)
                goto table_cache_failure;
        return 0;
index e5aba56..ddcd354 100644 (file)
 static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh);
 static void __jbd2_journal_unfile_buffer(struct journal_head *jh);
 
+static struct kmem_cache *transaction_cache;
+int __init jbd2_journal_init_transaction_cache(void)
+{
+       J_ASSERT(!transaction_cache);
+       transaction_cache = kmem_cache_create("jbd2_transaction_s",
+                                       sizeof(transaction_t),
+                                       0,
+                                       SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY,
+                                       NULL);
+       if (transaction_cache)
+               return 0;
+       return -ENOMEM;
+}
+
+void jbd2_journal_destroy_transaction_cache(void)
+{
+       if (transaction_cache) {
+               kmem_cache_destroy(transaction_cache);
+               transaction_cache = NULL;
+       }
+}
+
+void jbd2_journal_free_transaction(transaction_t *transaction)
+{
+       if (unlikely(ZERO_OR_NULL_PTR(transaction)))
+               return;
+       kmem_cache_free(transaction_cache, transaction);
+}
+
 /*
  * jbd2_get_transaction: obtain a new transaction_t object.
  *
@@ -133,7 +162,8 @@ static int start_this_handle(journal_t *journal, handle_t *handle,
 
 alloc_transaction:
        if (!journal->j_running_transaction) {
-               new_transaction = kzalloc(sizeof(*new_transaction), gfp_mask);
+               new_transaction = kmem_cache_alloc(transaction_cache,
+                                                  gfp_mask | __GFP_ZERO);
                if (!new_transaction) {
                        /*
                         * If __GFP_FS is not present, then we may be
@@ -162,7 +192,7 @@ repeat:
        if (is_journal_aborted(journal) ||
            (journal->j_errno != 0 && !(journal->j_flags & JBD2_ACK_ERR))) {
                read_unlock(&journal->j_state_lock);
-               kfree(new_transaction);
+               jbd2_journal_free_transaction(new_transaction);
                return -EROFS;
        }
 
@@ -284,7 +314,7 @@ repeat:
        read_unlock(&journal->j_state_lock);
 
        lock_map_acquire(&handle->h_lockdep_map);
-       kfree(new_transaction);
+       jbd2_journal_free_transaction(new_transaction);
        return 0;
 }
 
@@ -1549,9 +1579,9 @@ __blist_del_buffer(struct journal_head **list, struct journal_head *jh)
  * of these pointers, it could go bad.  Generally the caller needs to re-read
  * the pointer from the transaction_t.
  *
- * Called under j_list_lock.  The journal may not be locked.
+ * Called under j_list_lock.
  */
-void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
+static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
 {
        struct journal_head **list = NULL;
        transaction_t *transaction;
@@ -1646,10 +1676,8 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
        spin_lock(&journal->j_list_lock);
        if (jh->b_cp_transaction != NULL && jh->b_transaction == NULL) {
                /* written-back checkpointed metadata buffer */
-               if (jh->b_jlist == BJ_None) {
-                       JBUFFER_TRACE(jh, "remove from checkpoint list");
-                       __jbd2_journal_remove_checkpoint(jh);
-               }
+               JBUFFER_TRACE(jh, "remove from checkpoint list");
+               __jbd2_journal_remove_checkpoint(jh);
        }
        spin_unlock(&journal->j_list_lock);
 out:
@@ -1949,6 +1977,8 @@ zap_buffer_unlocked:
        clear_buffer_mapped(bh);
        clear_buffer_req(bh);
        clear_buffer_new(bh);
+       clear_buffer_delay(bh);
+       clear_buffer_unwritten(bh);
        bh->b_bdev = NULL;
        return may_free;
 }
index 722e0d5..4a0d1f0 100644 (file)
@@ -3,7 +3,7 @@
  *     Library for filesystems writers.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/mount.h>
index f848b52..3ddcbb1 100644 (file)
@@ -598,7 +598,7 @@ static struct rpc_procinfo  nlm4_procedures[] = {
        PROC(GRANTED_RES,       res,            norep),
 };
 
-struct rpc_version     nlm_version4 = {
+const struct rpc_version nlm_version4 = {
        .number         = 4,
        .nrprocs        = ARRAY_SIZE(nlm4_procedures),
        .procs          = nlm4_procedures,
index 8d4ea83..ba1dc2e 100644 (file)
@@ -62,7 +62,8 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
 
        host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
                                   nlm_init->protocol, nlm_version,
-                                  nlm_init->hostname, nlm_init->noresvport);
+                                  nlm_init->hostname, nlm_init->noresvport,
+                                  nlm_init->net);
        if (host == NULL) {
                lockd_down();
                return ERR_PTR(-ENOLCK);
index 180ac34..3d35e3e 100644 (file)
@@ -596,19 +596,19 @@ static struct rpc_procinfo        nlm_procedures[] = {
        PROC(GRANTED_RES,       res,            norep),
 };
 
-static struct rpc_version      nlm_version1 = {
+static const struct rpc_version        nlm_version1 = {
                .number         = 1,
                .nrprocs        = ARRAY_SIZE(nlm_procedures),
                .procs          = nlm_procedures,
 };
 
-static struct rpc_version      nlm_version3 = {
+static const struct rpc_version        nlm_version3 = {
                .number         = 3,
                .nrprocs        = ARRAY_SIZE(nlm_procedures),
                .procs          = nlm_procedures,
 };
 
-static struct rpc_version      *nlm_versions[] = {
+static const struct rpc_version        *nlm_versions[] = {
        [1] = &nlm_version1,
        [3] = &nlm_version3,
 #ifdef CONFIG_LOCKD_V4
@@ -618,7 +618,7 @@ static struct rpc_version   *nlm_versions[] = {
 
 static struct rpc_stat         nlm_rpc_stats;
 
-struct rpc_program             nlm_program = {
+const struct rpc_program       nlm_program = {
                .name           = "lockd",
                .number         = NLM_PROGRAM,
                .nrvers         = ARRAY_SIZE(nlm_versions),
index 6f29836..eb75ca7 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/lockd/lockd.h>
 #include <linux/mutex.h>
 
+#include <linux/sunrpc/svc_xprt.h>
+
 #include <net/ipv6.h>
 
 #define NLMDBG_FACILITY                NLMDBG_HOSTCACHE
@@ -54,6 +56,7 @@ struct nlm_lookup_host_info {
        const char              *hostname;      /* remote's hostname */
        const size_t            hostname_len;   /* it's length */
        const int               noresvport;     /* use non-priv port */
+       struct net              *net;           /* network namespace to bind */
 };
 
 /*
@@ -155,6 +158,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
        INIT_LIST_HEAD(&host->h_reclaim);
        host->h_nsmhandle  = nsm;
        host->h_addrbuf    = nsm->sm_addrbuf;
+       host->net          = ni->net;
 
 out:
        return host;
@@ -206,7 +210,8 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
                                     const unsigned short protocol,
                                     const u32 version,
                                     const char *hostname,
-                                    int noresvport)
+                                    int noresvport,
+                                    struct net *net)
 {
        struct nlm_lookup_host_info ni = {
                .server         = 0,
@@ -217,6 +222,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
                .hostname       = hostname,
                .hostname_len   = strlen(hostname),
                .noresvport     = noresvport,
+               .net            = net,
        };
        struct hlist_head *chain;
        struct hlist_node *pos;
@@ -231,6 +237,8 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
 
        chain = &nlm_client_hosts[nlm_hash_address(sap)];
        hlist_for_each_entry(host, pos, chain, h_hash) {
+               if (host->net != net)
+                       continue;
                if (!rpc_cmp_addr(nlm_addr(host), sap))
                        continue;
 
@@ -318,6 +326,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 nlm_lookup_host_info ni = {
                .server         = 1,
                .sap            = svc_addr(rqstp),
@@ -326,6 +335,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
                .version        = rqstp->rq_vers,
                .hostname       = hostname,
                .hostname_len   = hostname_len,
+               .net            = net,
        };
 
        dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
@@ -339,6 +349,8 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 
        chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
        hlist_for_each_entry(host, pos, chain, h_hash) {
+               if (host->net != net)
+                       continue;
                if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
                        continue;
 
@@ -431,7 +443,7 @@ nlm_bind_host(struct nlm_host *host)
                        .to_retries     = 5U,
                };
                struct rpc_create_args args = {
-                       .net            = &init_net,
+                       .net            = host->net,
                        .protocol       = host->h_proto,
                        .address        = nlm_addr(host),
                        .addrsize       = host->h_addrlen,
@@ -553,12 +565,8 @@ void nlm_host_rebooted(const struct nlm_reboot *info)
        nsm_release(nsm);
 }
 
-/*
- * Shut down the hosts module.
- * Note that this routine is called only at server shutdown time.
- */
 void
-nlm_shutdown_hosts(void)
+nlm_shutdown_hosts_net(struct net *net)
 {
        struct hlist_head *chain;
        struct hlist_node *pos;
@@ -570,6 +578,8 @@ nlm_shutdown_hosts(void)
        /* First, make all hosts eligible for gc */
        dprintk("lockd: nuking all hosts...\n");
        for_each_host(host, pos, chain, nlm_server_hosts) {
+               if (net && host->net != net)
+                       continue;
                host->h_expires = jiffies - 1;
                if (host->h_rpcclnt) {
                        rpc_shutdown_client(host->h_rpcclnt);
@@ -580,15 +590,29 @@ nlm_shutdown_hosts(void)
        /* Then, perform a garbage collection pass */
        nlm_gc_hosts();
        mutex_unlock(&nlm_host_mutex);
+}
+
+/*
+ * Shut down the hosts module.
+ * Note that this routine is called only at server shutdown time.
+ */
+void
+nlm_shutdown_hosts(void)
+{
+       struct hlist_head *chain;
+       struct hlist_node *pos;
+       struct nlm_host *host;
+
+       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)\n",
+                       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->h_inuse, host->h_expires, host->net);
                }
        }
 }
index 65ba36b..7ef14b3 100644 (file)
@@ -47,7 +47,7 @@ struct nsm_res {
        u32                     state;
 };
 
-static struct rpc_program      nsm_program;
+static const struct rpc_program        nsm_program;
 static                         LIST_HEAD(nsm_handles);
 static                         DEFINE_SPINLOCK(nsm_lock);
 
@@ -62,14 +62,14 @@ static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
        return (struct sockaddr *)&nsm->sm_addr;
 }
 
-static struct rpc_clnt *nsm_create(void)
+static struct rpc_clnt *nsm_create(struct net *net)
 {
        struct sockaddr_in sin = {
                .sin_family             = AF_INET,
                .sin_addr.s_addr        = htonl(INADDR_LOOPBACK),
        };
        struct rpc_create_args args = {
-               .net                    = &init_net,
+               .net                    = net,
                .protocol               = XPRT_TRANSPORT_UDP,
                .address                = (struct sockaddr *)&sin,
                .addrsize               = sizeof(sin),
@@ -83,7 +83,8 @@ static struct rpc_clnt *nsm_create(void)
        return rpc_create(&args);
 }
 
-static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
+static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
+                        struct net *net)
 {
        struct rpc_clnt *clnt;
        int             status;
@@ -99,7 +100,7 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
                .rpc_resp       = res,
        };
 
-       clnt = nsm_create();
+       clnt = nsm_create(net);
        if (IS_ERR(clnt)) {
                status = PTR_ERR(clnt);
                dprintk("lockd: failed to create NSM upcall transport, "
@@ -149,7 +150,7 @@ int nsm_monitor(const struct nlm_host *host)
         */
        nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
 
-       status = nsm_mon_unmon(nsm, NSMPROC_MON, &res);
+       status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host->net);
        if (unlikely(res.status != 0))
                status = -EIO;
        if (unlikely(status < 0)) {
@@ -183,7 +184,7 @@ void nsm_unmonitor(const struct nlm_host *host)
         && nsm->sm_monitored && !nsm->sm_sticky) {
                dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
 
-               status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res);
+               status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host->net);
                if (res.status != 0)
                        status = -EIO;
                if (status < 0)
@@ -534,19 +535,19 @@ static struct rpc_procinfo        nsm_procedures[] = {
        },
 };
 
-static struct rpc_version      nsm_version1 = {
+static const struct rpc_version nsm_version1 = {
                .number         = 1,
                .nrprocs        = ARRAY_SIZE(nsm_procedures),
                .procs          = nsm_procedures
 };
 
-static struct rpc_version *    nsm_version[] = {
+static const struct rpc_version *nsm_version[] = {
        [1] = &nsm_version1,
 };
 
 static struct rpc_stat         nsm_stats;
 
-static struct rpc_program      nsm_program = {
+static const struct rpc_program nsm_program = {
                .name           = "statd",
                .number         = NSM_PROGRAM,
                .nrvers         = ARRAY_SIZE(nsm_version),
diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h
new file mode 100644 (file)
index 0000000..ce227e0
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __LOCKD_NETNS_H__
+#define __LOCKD_NETNS_H__
+
+#include <net/netns/generic.h>
+
+struct lockd_net {
+       unsigned int nlmsvc_users;
+};
+
+extern int lockd_net_id;
+
+#endif
index c061b9a..2774e10 100644 (file)
@@ -35,6 +35,8 @@
 #include <linux/lockd/lockd.h>
 #include <linux/nfs.h>
 
+#include "netns.h"
+
 #define NLMDBG_FACILITY                NLMDBG_SVC
 #define LOCKD_BUFSIZE          (1024 + NLMSVC_XDRSIZE)
 #define ALLOWED_SIGS           (sigmask(SIGKILL))
@@ -50,6 +52,8 @@ static struct task_struct     *nlmsvc_task;
 static struct svc_rqst         *nlmsvc_rqst;
 unsigned long                  nlmsvc_timeout;
 
+int lockd_net_id;
+
 /*
  * These can be set at insmod time (useful for NFS as root filesystem),
  * and also changed through the sysctl interface.  -- Jamie Lokier, Aug 2003
@@ -189,27 +193,29 @@ lockd(void *vrqstp)
 }
 
 static int create_lockd_listener(struct svc_serv *serv, const char *name,
-                                const int family, const unsigned short port)
+                                struct net *net, const int family,
+                                const unsigned short port)
 {
        struct svc_xprt *xprt;
 
-       xprt = svc_find_xprt(serv, name, family, 0);
+       xprt = svc_find_xprt(serv, name, net, family, 0);
        if (xprt == NULL)
-               return svc_create_xprt(serv, name, &init_net, family, port,
+               return svc_create_xprt(serv, name, net, family, port,
                                                SVC_SOCK_DEFAULTS);
        svc_xprt_put(xprt);
        return 0;
 }
 
-static int create_lockd_family(struct svc_serv *serv, const int family)
+static int create_lockd_family(struct svc_serv *serv, struct net *net,
+                              const int family)
 {
        int err;
 
-       err = create_lockd_listener(serv, "udp", family, nlm_udpport);
+       err = create_lockd_listener(serv, "udp", net, family, nlm_udpport);
        if (err < 0)
                return err;
 
-       return create_lockd_listener(serv, "tcp", family, nlm_tcpport);
+       return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport);
 }
 
 /*
@@ -222,16 +228,16 @@ static int create_lockd_family(struct svc_serv *serv, const int family)
  * Returns zero if all listeners are available; otherwise a
  * negative errno value is returned.
  */
-static int make_socks(struct svc_serv *serv)
+static int make_socks(struct svc_serv *serv, struct net *net)
 {
        static int warned;
        int err;
 
-       err = create_lockd_family(serv, PF_INET);
+       err = create_lockd_family(serv, net, PF_INET);
        if (err < 0)
                goto out_err;
 
-       err = create_lockd_family(serv, PF_INET6);
+       err = create_lockd_family(serv, net, PF_INET6);
        if (err < 0 && err != -EAFNOSUPPORT)
                goto out_err;
 
@@ -245,6 +251,47 @@ out_err:
        return err;
 }
 
+static int lockd_up_net(struct net *net)
+{
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
+       struct svc_serv *serv = nlmsvc_rqst->rq_server;
+       int error;
+
+       if (ln->nlmsvc_users)
+               return 0;
+
+       error = svc_rpcb_setup(serv, net);
+       if (error)
+               goto err_rpcb;
+
+       error = make_socks(serv, net);
+       if (error < 0)
+               goto err_socks;
+       return 0;
+
+err_socks:
+       svc_rpcb_cleanup(serv, net);
+err_rpcb:
+       return error;
+}
+
+static void lockd_down_net(struct net *net)
+{
+       struct lockd_net *ln = net_generic(net, lockd_net_id);
+       struct svc_serv *serv = nlmsvc_rqst->rq_server;
+
+       if (ln->nlmsvc_users) {
+               if (--ln->nlmsvc_users == 0) {
+                       nlm_shutdown_hosts_net(net);
+                       svc_shutdown_net(serv, net);
+               }
+       } else {
+               printk(KERN_ERR "lockd_down_net: no users! task=%p, net=%p\n",
+                               nlmsvc_task, net);
+               BUG();
+       }
+}
+
 /*
  * Bring up the lockd process if it's not already up.
  */
@@ -252,13 +299,16 @@ int lockd_up(void)
 {
        struct svc_serv *serv;
        int             error = 0;
+       struct net *net = current->nsproxy->net_ns;
 
        mutex_lock(&nlmsvc_mutex);
        /*
         * Check whether we're already up and running.
         */
-       if (nlmsvc_rqst)
+       if (nlmsvc_rqst) {
+               error = lockd_up_net(net);
                goto out;
+       }
 
        /*
         * Sanity check: if there's no pid,
@@ -275,7 +325,7 @@ int lockd_up(void)
                goto out;
        }
 
-       error = make_socks(serv);
+       error = make_socks(serv, net);
        if (error < 0)
                goto destroy_and_out;
 
@@ -313,8 +363,12 @@ int lockd_up(void)
 destroy_and_out:
        svc_destroy(serv);
 out:
-       if (!error)
+       if (!error) {
+               struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+               ln->nlmsvc_users++;
                nlmsvc_users++;
+       }
        mutex_unlock(&nlmsvc_mutex);
        return error;
 }
@@ -328,8 +382,10 @@ lockd_down(void)
 {
        mutex_lock(&nlmsvc_mutex);
        if (nlmsvc_users) {
-               if (--nlmsvc_users)
+               if (--nlmsvc_users) {
+                       lockd_down_net(current->nsproxy->net_ns);
                        goto out;
+               }
        } else {
                printk(KERN_ERR "lockd_down: no users! task=%p\n",
                        nlmsvc_task);
@@ -497,24 +553,55 @@ module_param_call(nlm_tcpport, param_set_port, param_get_int,
 module_param(nsm_use_hostnames, bool, 0644);
 module_param(nlm_max_connections, uint, 0644);
 
+static int lockd_init_net(struct net *net)
+{
+       return 0;
+}
+
+static void lockd_exit_net(struct net *net)
+{
+}
+
+static struct pernet_operations lockd_net_ops = {
+       .init = lockd_init_net,
+       .exit = lockd_exit_net,
+       .id = &lockd_net_id,
+       .size = sizeof(struct lockd_net),
+};
+
+
 /*
  * Initialising and terminating the module.
  */
 
 static int __init init_nlm(void)
 {
+       int err;
+
 #ifdef CONFIG_SYSCTL
+       err = -ENOMEM;
        nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root);
-       return nlm_sysctl_table ? 0 : -ENOMEM;
-#else
+       if (nlm_sysctl_table == NULL)
+               goto err_sysctl;
+#endif
+       err = register_pernet_subsys(&lockd_net_ops);
+       if (err)
+               goto err_pernet;
        return 0;
+
+err_pernet:
+#ifdef CONFIG_SYSCTL
+       unregister_sysctl_table(nlm_sysctl_table);
 #endif
+err_sysctl:
+       return err;
 }
 
 static void __exit exit_nlm(void)
 {
        /* FIXME: delete all NLM clients */
        nlm_shutdown_hosts();
+       unregister_pernet_subsys(&lockd_net_ops);
 #ifdef CONFIG_SYSCTL
        unregister_sysctl_table(nlm_sysctl_table);
 #endif
index f0179c3..e46353f 100644 (file)
@@ -46,7 +46,6 @@ static void   nlmsvc_remove_block(struct nlm_block *block);
 static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
 static void nlmsvc_freegrantargs(struct nlm_rqst *call);
 static const struct rpc_call_ops nlmsvc_grant_ops;
-static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie);
 
 /*
  * The list of blocked locks to retry
@@ -54,6 +53,35 @@ static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie);
 static LIST_HEAD(nlm_blocked);
 static DEFINE_SPINLOCK(nlm_blocked_lock);
 
+#ifdef LOCKD_DEBUG
+static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
+{
+       /*
+        * We can get away with a static buffer because we're only
+        * called with BKL held.
+        */
+       static char buf[2*NLM_MAXCOOKIELEN+1];
+       unsigned int i, len = sizeof(buf);
+       char *p = buf;
+
+       len--;  /* allow for trailing \0 */
+       if (len < 3)
+               return "???";
+       for (i = 0 ; i < cookie->len ; i++) {
+               if (len < 2) {
+                       strcpy(p-3, "...");
+                       break;
+               }
+               sprintf(p, "%02x", cookie->data[i]);
+               p += 2;
+               len -= 2;
+       }
+       *p = '\0';
+
+       return buf;
+}
+#endif
+
 /*
  * Insert a blocked lock into the global list
  */
@@ -935,32 +963,3 @@ nlmsvc_retry_blocked(void)
 
        return timeout;
 }
-
-#ifdef RPC_DEBUG
-static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
-{
-       /*
-        * We can get away with a static buffer because we're only
-        * called with BKL held.
-        */
-       static char buf[2*NLM_MAXCOOKIELEN+1];
-       unsigned int i, len = sizeof(buf);
-       char *p = buf;
-
-       len--;  /* allow for trailing \0 */
-       if (len < 3)
-               return "???";
-       for (i = 0 ; i < cookie->len ; i++) {
-               if (len < 2) {
-                       strcpy(p-3, "...");
-                       break;
-               }
-               sprintf(p, "%02x", cookie->data[i]);
-               p += 2;
-               len -= 2;
-       }
-       *p = '\0';
-
-       return buf;
-}
-#endif
index 643e9f5..0face1c 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mm.h>
 #include <linux/kdev_t.h>
 #include <linux/gfp.h>
index 73ec863..e615ff3 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
index dbcd821..2a0e6c5 100644 (file)
@@ -64,6 +64,7 @@ config NFS_V4
        bool "NFS client support for NFS version 4"
        depends on NFS_FS
        select SUNRPC_GSS
+       select KEYS
        help
          This option enables support for version 4 of the NFS protocol
          (RFC 3530) in the kernel's NFS client.
@@ -98,6 +99,18 @@ config PNFS_OBJLAYOUT
        depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
        default m
 
+config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
+       string "NFSv4.1 Implementation ID Domain"
+       depends on NFS_V4_1
+       default "kernel.org"
+       help
+         This option defines the domain portion of the implementation ID that
+         may be sent in the NFS exchange_id operation.  The value must be in
+         the format of a DNS domain name and should be set to the DNS domain
+         name of the distribution.
+         If the NFS client is unchanged from the upstream kernel, this
+         option should be set to the default "kernel.org".
+
 config ROOT_NFS
        bool "Root file system on NFS"
        depends on NFS_FS=y && IP_PNP
@@ -130,16 +143,10 @@ config NFS_USE_KERNEL_DNS
        bool
        depends on NFS_V4 && !NFS_USE_LEGACY_DNS
        select DNS_RESOLVER
-       select KEYS
        default y
 
-config NFS_USE_NEW_IDMAPPER
-       bool "Use the new idmapper upcall routine"
-       depends on NFS_V4 && KEYS
-       help
-         Say Y here if you want NFS to use the new idmapper upcall functions.
-         You will need /sbin/request-key (usually provided by the keyutils
-         package).  For details, read
-         <file:Documentation/filesystems/nfs/idmapper.txt>.
-
-         If you are unsure, say N.
+config NFS_DEBUG
+       bool
+       depends on NFS_FS && SUNRPC_DEBUG
+       select CRC32
+       default y
index 48cfac3..9c94297 100644 (file)
@@ -46,9 +46,6 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Andy Adamson <andros@citi.umich.edu>");
 MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver");
 
-struct dentry *bl_device_pipe;
-wait_queue_head_t bl_wq;
-
 static void print_page(struct page *page)
 {
        dprintk("PRINTPAGE page %p\n", page);
@@ -236,12 +233,11 @@ bl_read_pagelist(struct nfs_read_data *rdata)
        sector_t isect, extent_length = 0;
        struct parallel_io *par;
        loff_t f_offset = rdata->args.offset;
-       size_t count = rdata->args.count;
        struct page **pages = rdata->args.pages;
        int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT;
 
-       dprintk("%s enter nr_pages %u offset %lld count %Zd\n", __func__,
-              rdata->npages, f_offset, count);
+       dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__,
+              rdata->npages, f_offset, (unsigned int)rdata->args.count);
 
        par = alloc_parallel(rdata);
        if (!par)
@@ -1025,10 +1021,128 @@ static const struct rpc_pipe_ops bl_upcall_ops = {
        .destroy_msg    = bl_pipe_destroy_msg,
 };
 
+static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb,
+                                           struct rpc_pipe *pipe)
+{
+       struct dentry *dir, *dentry;
+
+       dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME);
+       if (dir == NULL)
+               return ERR_PTR(-ENOENT);
+       dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe);
+       dput(dir);
+       return dentry;
+}
+
+static void nfs4blocklayout_unregister_sb(struct super_block *sb,
+                                         struct rpc_pipe *pipe)
+{
+       if (pipe->dentry)
+               rpc_unlink(pipe->dentry);
+}
+
+static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
+                          void *ptr)
+{
+       struct super_block *sb = ptr;
+       struct net *net = sb->s_fs_info;
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+       struct dentry *dentry;
+       int ret = 0;
+
+       if (!try_module_get(THIS_MODULE))
+               return 0;
+
+       if (nn->bl_device_pipe == NULL) {
+               module_put(THIS_MODULE);
+               return 0;
+       }
+
+       switch (event) {
+       case RPC_PIPEFS_MOUNT:
+               dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe);
+               if (IS_ERR(dentry)) {
+                       ret = PTR_ERR(dentry);
+                       break;
+               }
+               nn->bl_device_pipe->dentry = dentry;
+               break;
+       case RPC_PIPEFS_UMOUNT:
+               if (nn->bl_device_pipe->dentry)
+                       nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe);
+               break;
+       default:
+               ret = -ENOTSUPP;
+               break;
+       }
+       module_put(THIS_MODULE);
+       return ret;
+}
+
+static struct notifier_block nfs4blocklayout_block = {
+       .notifier_call = rpc_pipefs_event,
+};
+
+static struct dentry *nfs4blocklayout_register_net(struct net *net,
+                                                  struct rpc_pipe *pipe)
+{
+       struct super_block *pipefs_sb;
+       struct dentry *dentry;
+
+       pipefs_sb = rpc_get_sb_net(net);
+       if (!pipefs_sb)
+               return NULL;
+       dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe);
+       rpc_put_sb_net(net);
+       return dentry;
+}
+
+static void nfs4blocklayout_unregister_net(struct net *net,
+                                          struct rpc_pipe *pipe)
+{
+       struct super_block *pipefs_sb;
+
+       pipefs_sb = rpc_get_sb_net(net);
+       if (pipefs_sb) {
+               nfs4blocklayout_unregister_sb(pipefs_sb, pipe);
+               rpc_put_sb_net(net);
+       }
+}
+
+static int nfs4blocklayout_net_init(struct net *net)
+{
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+       struct dentry *dentry;
+
+       init_waitqueue_head(&nn->bl_wq);
+       nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
+       if (IS_ERR(nn->bl_device_pipe))
+               return PTR_ERR(nn->bl_device_pipe);
+       dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe);
+       if (IS_ERR(dentry)) {
+               rpc_destroy_pipe_data(nn->bl_device_pipe);
+               return PTR_ERR(dentry);
+       }
+       nn->bl_device_pipe->dentry = dentry;
+       return 0;
+}
+
+static void nfs4blocklayout_net_exit(struct net *net)
+{
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+       nfs4blocklayout_unregister_net(net, nn->bl_device_pipe);
+       rpc_destroy_pipe_data(nn->bl_device_pipe);
+       nn->bl_device_pipe = NULL;
+}
+
+static struct pernet_operations nfs4blocklayout_net_ops = {
+       .init = nfs4blocklayout_net_init,
+       .exit = nfs4blocklayout_net_exit,
+};
+
 static int __init nfs4blocklayout_init(void)
 {
-       struct vfsmount *mnt;
-       struct path path;
        int ret;
 
        dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__);
@@ -1037,32 +1151,17 @@ static int __init nfs4blocklayout_init(void)
        if (ret)
                goto out;
 
-       init_waitqueue_head(&bl_wq);
-
-       mnt = rpc_get_mount();
-       if (IS_ERR(mnt)) {
-               ret = PTR_ERR(mnt);
+       ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block);
+       if (ret)
                goto out_remove;
-       }
-
-       ret = vfs_path_lookup(mnt->mnt_root,
-                             mnt,
-                             NFS_PIPE_DIRNAME, 0, &path);
+       ret = register_pernet_subsys(&nfs4blocklayout_net_ops);
        if (ret)
-               goto out_putrpc;
-
-       bl_device_pipe = rpc_mkpipe(path.dentry, "blocklayout", NULL,
-                                   &bl_upcall_ops, 0);
-       path_put(&path);
-       if (IS_ERR(bl_device_pipe)) {
-               ret = PTR_ERR(bl_device_pipe);
-               goto out_putrpc;
-       }
+               goto out_notifier;
 out:
        return ret;
 
-out_putrpc:
-       rpc_put_mount();
+out_notifier:
+       rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
 out_remove:
        pnfs_unregister_layoutdriver(&blocklayout_type);
        return ret;
@@ -1073,9 +1172,9 @@ static void __exit nfs4blocklayout_exit(void)
        dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n",
               __func__);
 
+       rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
+       unregister_pernet_subsys(&nfs4blocklayout_net_ops);
        pnfs_unregister_layoutdriver(&blocklayout_type);
-       rpc_unlink(bl_device_pipe);
-       rpc_put_mount();
 }
 
 MODULE_ALIAS("nfs-layouttype4-3");
index e31a2df..0335069 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/sunrpc/rpc_pipe_fs.h>
 
 #include "../pnfs.h"
+#include "../netns.h"
 
 #define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT)
 #define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
@@ -50,6 +51,7 @@ struct pnfs_block_dev {
        struct list_head                bm_node;
        struct nfs4_deviceid            bm_mdevid;    /* associated devid */
        struct block_device             *bm_mdev;     /* meta device itself */
+       struct net                      *net;
 };
 
 enum exstate4 {
@@ -151,9 +153,9 @@ BLK_LSEG2EXT(struct pnfs_layout_segment *lseg)
        return BLK_LO2EXT(lseg->pls_layout);
 }
 
-struct bl_dev_msg {
-       int32_t status;
-       uint32_t major, minor;
+struct bl_pipe_msg {
+       struct rpc_pipe_msg msg;
+       wait_queue_head_t *bl_wq;
 };
 
 struct bl_msg_hdr {
@@ -161,9 +163,6 @@ struct bl_msg_hdr {
        u16 totallen; /* length of entire message, including hdr itself */
 };
 
-extern struct dentry *bl_device_pipe;
-extern wait_queue_head_t bl_wq;
-
 #define BL_DEVICE_UMOUNT               0x0 /* Umount--delete devices */
 #define BL_DEVICE_MOUNT                0x1 /* Mount--create devices*/
 #define BL_DEVICE_REQUEST_INIT         0x0 /* Start request */
index d08ba91..a5c88a5 100644 (file)
@@ -46,7 +46,7 @@ static int decode_sector_number(__be32 **rp, sector_t *sp)
 
        *rp = xdr_decode_hyper(*rp, &s);
        if (s & 0x1ff) {
-               printk(KERN_WARNING "%s: sector not aligned\n", __func__);
+               printk(KERN_WARNING "NFS: %s: sector not aligned\n", __func__);
                return -1;
        }
        *sp = s >> SECTOR_SHIFT;
@@ -79,27 +79,30 @@ int nfs4_blkdev_put(struct block_device *bdev)
        return blkdev_put(bdev, FMODE_READ);
 }
 
-static struct bl_dev_msg bl_mount_reply;
-
 ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
                         size_t mlen)
 {
+       struct nfs_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
+                                        nfs_net_id);
+
        if (mlen != sizeof (struct bl_dev_msg))
                return -EINVAL;
 
-       if (copy_from_user(&bl_mount_reply, src, mlen) != 0)
+       if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0)
                return -EFAULT;
 
-       wake_up(&bl_wq);
+       wake_up(&nn->bl_wq);
 
        return mlen;
 }
 
 void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 {
+       struct bl_pipe_msg *bl_pipe_msg = container_of(msg, struct bl_pipe_msg, msg);
+
        if (msg->errno >= 0)
                return;
-       wake_up(&bl_wq);
+       wake_up(bl_pipe_msg->bl_wq);
 }
 
 /*
@@ -111,29 +114,33 @@ nfs4_blk_decode_device(struct nfs_server *server,
 {
        struct pnfs_block_dev *rv;
        struct block_device *bd = NULL;
-       struct rpc_pipe_msg msg;
+       struct bl_pipe_msg bl_pipe_msg;
+       struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
        struct bl_msg_hdr bl_msg = {
                .type = BL_DEVICE_MOUNT,
                .totallen = dev->mincount,
        };
        uint8_t *dataptr;
        DECLARE_WAITQUEUE(wq, current);
-       struct bl_dev_msg *reply = &bl_mount_reply;
        int offset, len, i, rc;
+       struct net *net = server->nfs_client->net;
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+       struct bl_dev_msg *reply = &nn->bl_mount_reply;
 
        dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
        dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data,
                dev->mincount);
 
-       memset(&msg, 0, sizeof(msg));
-       msg.data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS);
-       if (!msg.data) {
+       bl_pipe_msg.bl_wq = &nn->bl_wq;
+       memset(msg, 0, sizeof(*msg));
+       msg->data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS);
+       if (!msg->data) {
                rv = ERR_PTR(-ENOMEM);
                goto out;
        }
 
-       memcpy(msg.data, &bl_msg, sizeof(bl_msg));
-       dataptr = (uint8_t *) msg.data;
+       memcpy(msg->data, &bl_msg, sizeof(bl_msg));
+       dataptr = (uint8_t *) msg->data;
        len = dev->mincount;
        offset = sizeof(bl_msg);
        for (i = 0; len > 0; i++) {
@@ -142,13 +149,13 @@ nfs4_blk_decode_device(struct nfs_server *server,
                len -= PAGE_CACHE_SIZE;
                offset += PAGE_CACHE_SIZE;
        }
-       msg.len = sizeof(bl_msg) + dev->mincount;
+       msg->len = sizeof(bl_msg) + dev->mincount;
 
        dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
-       add_wait_queue(&bl_wq, &wq);
-       rc = rpc_queue_upcall(bl_device_pipe->d_inode, &msg);
+       add_wait_queue(&nn->bl_wq, &wq);
+       rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
        if (rc < 0) {
-               remove_wait_queue(&bl_wq, &wq);
+               remove_wait_queue(&nn->bl_wq, &wq);
                rv = ERR_PTR(rc);
                goto out;
        }
@@ -156,7 +163,7 @@ nfs4_blk_decode_device(struct nfs_server *server,
        set_current_state(TASK_UNINTERRUPTIBLE);
        schedule();
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&bl_wq, &wq);
+       remove_wait_queue(&nn->bl_wq, &wq);
 
        if (reply->status != BL_DEVICE_REQUEST_PROC) {
                dprintk("%s failed to open device: %d\n",
@@ -181,13 +188,14 @@ nfs4_blk_decode_device(struct nfs_server *server,
 
        rv->bm_mdev = bd;
        memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid));
+       rv->net = net;
        dprintk("%s Created device %s with bd_block_size %u\n",
                __func__,
                bd->bd_disk->disk_name,
                bd->bd_block_size);
 
 out:
-       kfree(msg.data);
+       kfree(msg->data);
        return rv;
 }
 
index d055c75..737d839 100644 (file)
 
 #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
 
-static void dev_remove(dev_t dev)
+static void dev_remove(struct net *net, dev_t dev)
 {
-       struct rpc_pipe_msg msg;
+       struct bl_pipe_msg bl_pipe_msg;
+       struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
        struct bl_dev_msg bl_umount_request;
        struct bl_msg_hdr bl_msg = {
                .type = BL_DEVICE_UMOUNT,
@@ -48,36 +49,38 @@ static void dev_remove(dev_t dev)
        };
        uint8_t *dataptr;
        DECLARE_WAITQUEUE(wq, current);
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
 
        dprintk("Entering %s\n", __func__);
 
-       memset(&msg, 0, sizeof(msg));
-       msg.data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
-       if (!msg.data)
+       bl_pipe_msg.bl_wq = &nn->bl_wq;
+       memset(msg, 0, sizeof(*msg));
+       msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
+       if (!msg->data)
                goto out;
 
        memset(&bl_umount_request, 0, sizeof(bl_umount_request));
        bl_umount_request.major = MAJOR(dev);
        bl_umount_request.minor = MINOR(dev);
 
-       memcpy(msg.data, &bl_msg, sizeof(bl_msg));
-       dataptr = (uint8_t *) msg.data;
+       memcpy(msg->data, &bl_msg, sizeof(bl_msg));
+       dataptr = (uint8_t *) msg->data;
        memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
-       msg.len = sizeof(bl_msg) + bl_msg.totallen;
+       msg->len = sizeof(bl_msg) + bl_msg.totallen;
 
-       add_wait_queue(&bl_wq, &wq);
-       if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) {
-               remove_wait_queue(&bl_wq, &wq);
+       add_wait_queue(&nn->bl_wq, &wq);
+       if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) {
+               remove_wait_queue(&nn->bl_wq, &wq);
                goto out;
        }
 
        set_current_state(TASK_UNINTERRUPTIBLE);
        schedule();
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&bl_wq, &wq);
+       remove_wait_queue(&nn->bl_wq, &wq);
 
 out:
-       kfree(msg.data);
+       kfree(msg->data);
 }
 
 /*
@@ -90,10 +93,10 @@ static void nfs4_blk_metadev_release(struct pnfs_block_dev *bdev)
        dprintk("%s Releasing\n", __func__);
        rv = nfs4_blkdev_put(bdev->bm_mdev);
        if (rv)
-               printk(KERN_ERR "%s nfs4_blkdev_put returns %d\n",
+               printk(KERN_ERR "NFS: %s nfs4_blkdev_put returns %d\n",
                                __func__, rv);
 
-       dev_remove(bdev->bm_mdev->bd_dev);
+       dev_remove(bdev->net, bdev->bm_mdev->bd_dev);
 }
 
 void bl_free_block_dev(struct pnfs_block_dev *bdev)
index 1abac09..1f9a603 100644 (file)
@@ -147,7 +147,7 @@ static int _preload_range(struct pnfs_inval_markings *marks,
        count = (int)(end - start) / (int)tree->mtt_step_size;
 
        /* Pre-malloc what memory we might need */
-       storage = kmalloc(sizeof(*storage) * count, GFP_NOFS);
+       storage = kcalloc(count, sizeof(*storage), GFP_NOFS);
        if (!storage)
                return -ENOMEM;
        for (i = 0; i < count; i++) {
index c98b439..dded263 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/sunrpc/cache.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
+#include <net/net_namespace.h>
 
 #include "cache_lib.h"
 
@@ -111,30 +112,54 @@ int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq)
        return 0;
 }
 
-int nfs_cache_register(struct cache_detail *cd)
+int nfs_cache_register_sb(struct super_block *sb, struct cache_detail *cd)
 {
-       struct vfsmount *mnt;
-       struct path path;
        int ret;
+       struct dentry *dir;
 
-       mnt = rpc_get_mount();
-       if (IS_ERR(mnt))
-               return PTR_ERR(mnt);
-       ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &path);
-       if (ret)
-               goto err;
-       ret = sunrpc_cache_register_pipefs(path.dentry, cd->name, 0600, cd);
-       path_put(&path);
-       if (!ret)
-               return ret;
-err:
-       rpc_put_mount();
+       dir = rpc_d_lookup_sb(sb, "cache");
+       BUG_ON(dir == NULL);
+       ret = sunrpc_cache_register_pipefs(dir, cd->name, 0600, cd);
+       dput(dir);
        return ret;
 }
 
-void nfs_cache_unregister(struct cache_detail *cd)
+int nfs_cache_register_net(struct net *net, struct cache_detail *cd)
 {
-       sunrpc_cache_unregister_pipefs(cd);
-       rpc_put_mount();
+       struct super_block *pipefs_sb;
+       int ret = 0;
+
+       pipefs_sb = rpc_get_sb_net(net);
+       if (pipefs_sb) {
+               ret = nfs_cache_register_sb(pipefs_sb, cd);
+               rpc_put_sb_net(net);
+       }
+       return ret;
+}
+
+void nfs_cache_unregister_sb(struct super_block *sb, struct cache_detail *cd)
+{
+       if (cd->u.pipefs.dir)
+               sunrpc_cache_unregister_pipefs(cd);
+}
+
+void nfs_cache_unregister_net(struct net *net, struct cache_detail *cd)
+{
+       struct super_block *pipefs_sb;
+
+       pipefs_sb = rpc_get_sb_net(net);
+       if (pipefs_sb) {
+               nfs_cache_unregister_sb(pipefs_sb, cd);
+               rpc_put_sb_net(net);
+       }
+}
+
+void nfs_cache_init(struct cache_detail *cd)
+{
+       sunrpc_init_cache_detail(cd);
 }
 
+void nfs_cache_destroy(struct cache_detail *cd)
+{
+       sunrpc_destroy_cache_detail(cd);
+}
index 7cf6caf..317db95 100644 (file)
@@ -23,5 +23,11 @@ extern struct nfs_cache_defer_req *nfs_cache_defer_req_alloc(void);
 extern void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq);
 extern int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq);
 
-extern int nfs_cache_register(struct cache_detail *cd);
-extern void nfs_cache_unregister(struct cache_detail *cd);
+extern void nfs_cache_init(struct cache_detail *cd);
+extern void nfs_cache_destroy(struct cache_detail *cd);
+extern int nfs_cache_register_net(struct net *net, struct cache_detail *cd);
+extern void nfs_cache_unregister_net(struct net *net, struct cache_detail *cd);
+extern int nfs_cache_register_sb(struct super_block *sb,
+                                struct cache_detail *cd);
+extern void nfs_cache_unregister_sb(struct super_block *sb,
+                                   struct cache_detail *cd);
index 516f337..eb95f50 100644 (file)
@@ -85,7 +85,7 @@ nfs4_callback_svc(void *vrqstp)
                }
                if (err < 0) {
                        if (err != preverr) {
-                               printk(KERN_WARNING "%s: unexpected error "
+                               printk(KERN_WARNING "NFS: %s: unexpected error "
                                        "from svc_recv (%d)\n", __func__, err);
                                preverr = err;
                        }
@@ -101,12 +101,12 @@ nfs4_callback_svc(void *vrqstp)
 /*
  * Prepare to bring up the NFSv4 callback service
  */
-struct svc_rqst *
-nfs4_callback_up(struct svc_serv *serv)
+static struct svc_rqst *
+nfs4_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
 {
        int ret;
 
-       ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET,
+       ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET,
                                nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
        if (ret <= 0)
                goto out_err;
@@ -114,7 +114,7 @@ nfs4_callback_up(struct svc_serv *serv)
        dprintk("NFS: Callback listener port = %u (af %u)\n",
                        nfs_callback_tcpport, PF_INET);
 
-       ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6,
+       ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET6,
                                nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
        if (ret > 0) {
                nfs_callback_tcpport6 = ret;
@@ -172,7 +172,7 @@ nfs41_callback_svc(void *vrqstp)
 /*
  * Bring up the NFSv4.1 callback service
  */
-struct svc_rqst *
+static struct svc_rqst *
 nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
 {
        struct svc_rqst *rqstp;
@@ -183,7 +183,7 @@ nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt)
         * fore channel connection.
         * Returns the input port (0) and sets the svc_serv bc_xprt on success
         */
-       ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0,
+       ret = svc_create_xprt(serv, "tcp-bc", xprt->xprt_net, PF_INET, 0,
                              SVC_SOCK_ANONYMOUS);
        if (ret < 0) {
                rqstp = ERR_PTR(ret);
@@ -269,7 +269,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
                                        serv, xprt, &rqstp, &callback_svc);
        if (!minorversion_setup) {
                /* v4.0 callback setup */
-               rqstp = nfs4_callback_up(serv);
+               rqstp = nfs4_callback_up(serv, xprt);
                callback_svc = nfs4_callback_svc;
        }
 
@@ -332,7 +332,6 @@ void nfs_callback_down(int minorversion)
 int
 check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
 {
-       struct rpc_clnt *r = clp->cl_rpcclient;
        char *p = svc_gss_principal(rqstp);
 
        if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
@@ -353,7 +352,7 @@ check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
        if (memcmp(p, "nfs@", 4) != 0)
                return 0;
        p += 4;
-       if (strcmp(p, r->cl_server) != 0)
+       if (strcmp(p, clp->cl_hostname) != 0)
                return 0;
        return 1;
 }
index c89d3b9..a5527c9 100644 (file)
@@ -38,7 +38,8 @@ enum nfs4_callback_opnum {
 struct cb_process_state {
        __be32                  drc_status;
        struct nfs_client       *clp;
-       int                     slotid;
+       u32                     slotid;
+       struct net              *net;
 };
 
 struct cb_compound_hdr_arg {
index 54cea8a..1b5d809 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/slab.h>
+#include <linux/rcupdate.h>
 #include "nfs4_fs.h"
 #include "callback.h"
 #include "delegation.h"
@@ -33,7 +34,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
        res->bitmap[0] = res->bitmap[1] = 0;
        res->status = htonl(NFS4ERR_BADHANDLE);
 
-       dprintk("NFS: GETATTR callback request from %s\n",
+       dprintk_rcu("NFS: GETATTR callback request from %s\n",
                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 
        inode = nfs_delegation_find_inode(cps->clp, &args->fh);
@@ -73,7 +74,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
        if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
                goto out;
 
-       dprintk("NFS: RECALL callback request from %s\n",
+       dprintk_rcu("NFS: RECALL callback request from %s\n",
                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 
        res = htonl(NFS4ERR_BADHANDLE);
@@ -86,8 +87,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
                res = 0;
                break;
        case -ENOENT:
-               if (res != 0)
-                       res = htonl(NFS4ERR_BAD_STATEID);
+               res = htonl(NFS4ERR_BAD_STATEID);
                break;
        default:
                res = htonl(NFS4ERR_RESOURCE);
@@ -98,52 +98,64 @@ out:
        return res;
 }
 
-int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
-{
-       if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
-                                        sizeof(delegation->stateid.data)) != 0)
-               return 0;
-       return 1;
-}
-
 #if defined(CONFIG_NFS_V4_1)
 
-static u32 initiate_file_draining(struct nfs_client *clp,
-                                 struct cb_layoutrecallargs *args)
+/*
+ * Lookup a layout by filehandle.
+ *
+ * Note: gets a refcount on the layout hdr and on its respective inode.
+ * Caller must put the layout hdr and the inode.
+ *
+ * TODO: keep track of all layouts (and delegations) in a hash table
+ * hashed by filehandle.
+ */
+static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh)
 {
        struct nfs_server *server;
-       struct pnfs_layout_hdr *lo;
        struct inode *ino;
-       bool found = false;
-       u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
-       LIST_HEAD(free_me_list);
+       struct pnfs_layout_hdr *lo;
 
-       spin_lock(&clp->cl_lock);
-       rcu_read_lock();
        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
                list_for_each_entry(lo, &server->layouts, plh_layouts) {
-                       if (nfs_compare_fh(&args->cbl_fh,
-                                          &NFS_I(lo->plh_inode)->fh))
+                       if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh))
                                continue;
                        ino = igrab(lo->plh_inode);
                        if (!ino)
                                continue;
-                       found = true;
-                       /* Without this, layout can be freed as soon
-                        * as we release cl_lock.
-                        */
                        get_layout_hdr(lo);
-                       break;
+                       return lo;
                }
-               if (found)
-                       break;
        }
+
+       return NULL;
+}
+
+static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh)
+{
+       struct pnfs_layout_hdr *lo;
+
+       spin_lock(&clp->cl_lock);
+       rcu_read_lock();
+       lo = get_layout_by_fh_locked(clp, fh);
        rcu_read_unlock();
        spin_unlock(&clp->cl_lock);
 
-       if (!found)
+       return lo;
+}
+
+static u32 initiate_file_draining(struct nfs_client *clp,
+                                 struct cb_layoutrecallargs *args)
+{
+       struct inode *ino;
+       struct pnfs_layout_hdr *lo;
+       u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
+       LIST_HEAD(free_me_list);
+
+       lo = get_layout_by_fh(clp, &args->cbl_fh);
+       if (!lo)
                return NFS4ERR_NOMATCHING_LAYOUT;
 
+       ino = lo->plh_inode;
        spin_lock(&ino->i_lock);
        if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
            mark_matching_lsegs_invalid(lo, &free_me_list,
@@ -213,17 +225,13 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
 static u32 do_callback_layoutrecall(struct nfs_client *clp,
                                    struct cb_layoutrecallargs *args)
 {
-       u32 res = NFS4ERR_DELAY;
+       u32 res;
 
        dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type);
-       if (test_and_set_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state))
-               goto out;
        if (args->cbl_recall_type == RETURN_FILE)
                res = initiate_file_draining(clp, args);
        else
                res = initiate_bulk_draining(clp, args);
-       clear_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state);
-out:
        dprintk("%s returning %i\n", __func__, res);
        return res;
 
@@ -303,21 +311,6 @@ out:
        return res;
 }
 
-int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
-{
-       if (delegation == NULL)
-               return 0;
-
-       if (stateid->stateid.seqid != 0)
-               return 0;
-       if (memcmp(&delegation->stateid.stateid.other,
-                  &stateid->stateid.other,
-                  NFS4_STATEID_OTHER_SIZE))
-               return 0;
-
-       return 1;
-}
-
 /*
  * Validate the sequenceID sent by the server.
  * Return success if the sequenceID is one more than what we last saw on
@@ -441,7 +434,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
        int i;
        __be32 status = htonl(NFS4ERR_BADSESSION);
 
-       clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
+       clp = nfs4_find_client_sessionid(cps->net, args->csa_addr, &args->csa_sessionid);
        if (clp == NULL)
                goto out;
 
@@ -517,7 +510,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy,
        if (!cps->clp) /* set in cb_sequence */
                goto out;
 
-       dprintk("NFS: RECALL_ANY callback request from %s\n",
+       dprintk_rcu("NFS: RECALL_ANY callback request from %s\n",
                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 
        status = cpu_to_be32(NFS4ERR_INVAL);
@@ -552,7 +545,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
        if (!cps->clp) /* set in cb_sequence */
                goto out;
 
-       dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
+       dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
                args->crsa_target_max_slots);
 
index d50b274..95bfc24 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
+#include <linux/ratelimit.h>
+#include <linux/printk.h>
 #include <linux/slab.h>
 #include <linux/sunrpc/bc_xprt.h>
 #include "nfs4_fs.h"
@@ -73,7 +75,7 @@ static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)
 
        p = xdr_inline_decode(xdr, nbytes);
        if (unlikely(p == NULL))
-               printk(KERN_WARNING "NFSv4 callback reply buffer overflowed!\n");
+               printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n");
        return p;
 }
 
@@ -138,10 +140,10 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
 {
        __be32 *p;
 
-       p = read_buf(xdr, 16);
+       p = read_buf(xdr, NFS4_STATEID_SIZE);
        if (unlikely(p == NULL))
                return htonl(NFS4ERR_RESOURCE);
-       memcpy(stateid->data, p, 16);
+       memcpy(stateid, p, NFS4_STATEID_SIZE);
        return 0;
 }
 
@@ -155,7 +157,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
                return status;
        /* We do not like overly long tags! */
        if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) {
-               printk("NFSv4 CALLBACK %s: client sent tag of length %u\n",
+               printk("NFS: NFSv4 CALLBACK %s: client sent tag of length %u\n",
                                __func__, hdr->taglen);
                return htonl(NFS4ERR_RESOURCE);
        }
@@ -167,7 +169,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
        if (hdr->minorversion <= 1) {
                hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */
        } else {
-               printk(KERN_WARNING "%s: NFSv4 server callback with "
+               pr_warn_ratelimited("NFS: %s: NFSv4 server callback with "
                        "illegal minor version %u!\n",
                        __func__, hdr->minorversion);
                return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
@@ -759,14 +761,14 @@ static void nfs4_callback_free_slot(struct nfs4_session *session)
         * Let the state manager know callback processing done.
         * A single slot, so highest used slotid is either 0 or -1
         */
-       tbl->highest_used_slotid = -1;
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
        nfs4_check_drain_bc_complete(session);
        spin_unlock(&tbl->slot_tbl_lock);
 }
 
 static void nfs4_cb_free_slot(struct cb_process_state *cps)
 {
-       if (cps->slotid != -1)
+       if (cps->slotid != NFS4_NO_SLOT)
                nfs4_callback_free_slot(cps->clp->cl_session);
 }
 
@@ -860,7 +862,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
        struct cb_process_state cps = {
                .drc_status = 0,
                .clp = NULL,
-               .slotid = -1,
+               .slotid = NFS4_NO_SLOT,
+               .net = rqstp->rq_xprt->xpt_net,
        };
        unsigned int nops = 0;
 
@@ -876,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(hdr_arg.cb_ident);
+               cps.clp = nfs4_find_client_ident(rqstp->rq_xprt->xpt_net, hdr_arg.cb_ident);
                if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
                        return rpc_drop_reply;
        }
index ad5565a..da7b5e4 100644 (file)
@@ -40,6 +40,8 @@
 #include <net/ipv6.h>
 #include <linux/nfs_xdr.h>
 #include <linux/sunrpc/bc_xprt.h>
+#include <linux/nsproxy.h>
+#include <linux/pid_namespace.h>
 
 
 #include "nfs4_fs.h"
 #include "internal.h"
 #include "fscache.h"
 #include "pnfs.h"
+#include "netns.h"
 
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
 
-static DEFINE_SPINLOCK(nfs_client_lock);
-static LIST_HEAD(nfs_client_list);
-static LIST_HEAD(nfs_volume_list);
 static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
 #ifdef CONFIG_NFS_V4
-static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */
 
 /*
  * Get a unique NFSv4.0 callback identifier which will be used
@@ -66,15 +65,16 @@ static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */
 static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
 {
        int ret = 0;
+       struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
 
        if (clp->rpc_ops->version != 4 || minorversion != 0)
                return ret;
 retry:
-       if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL))
+       if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL))
                return -ENOMEM;
-       spin_lock(&nfs_client_lock);
-       ret = idr_get_new(&cb_ident_idr, clp, &clp->cl_cb_ident);
-       spin_unlock(&nfs_client_lock);
+       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;
@@ -89,7 +89,7 @@ static bool nfs4_disable_idmapping = true;
 /*
  * RPC cruft for NFS
  */
-static struct rpc_version *nfs_version[5] = {
+static const struct rpc_version *nfs_version[5] = {
        [2]                     = &nfs_version2,
 #ifdef CONFIG_NFS_V3
        [3]                     = &nfs_version3,
@@ -99,7 +99,7 @@ static struct rpc_version *nfs_version[5] = {
 #endif
 };
 
-struct rpc_program nfs_program = {
+const struct rpc_program nfs_program = {
        .name                   = "nfs",
        .number                 = NFS_PROGRAM,
        .nrvers                 = ARRAY_SIZE(nfs_version),
@@ -115,11 +115,11 @@ struct rpc_stat nfs_rpcstat = {
 
 #ifdef CONFIG_NFS_V3_ACL
 static struct rpc_stat         nfsacl_rpcstat = { &nfsacl_program };
-static struct rpc_version *    nfsacl_version[] = {
+static const struct rpc_version *nfsacl_version[] = {
        [3]                     = &nfsacl_version3,
 };
 
-struct rpc_program             nfsacl_program = {
+const struct rpc_program nfsacl_program = {
        .name                   = "nfsacl",
        .number                 = NFS_ACL_PROGRAM,
        .nrvers                 = ARRAY_SIZE(nfsacl_version),
@@ -135,6 +135,7 @@ struct nfs_client_initdata {
        const struct nfs_rpc_ops *rpc_ops;
        int proto;
        u32 minorversion;
+       struct net *net;
 };
 
 /*
@@ -171,6 +172,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
        clp->cl_rpcclient = ERR_PTR(-EINVAL);
 
        clp->cl_proto = cl_init->proto;
+       clp->net = get_net(cl_init->net);
 
 #ifdef CONFIG_NFS_V4
        err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
@@ -202,8 +204,11 @@ error_0:
 #ifdef CONFIG_NFS_V4_1
 static void nfs4_shutdown_session(struct nfs_client *clp)
 {
-       if (nfs4_has_session(clp))
+       if (nfs4_has_session(clp)) {
+               nfs4_deviceid_purge_client(clp);
                nfs4_destroy_session(clp->cl_session);
+       }
+
 }
 #else /* CONFIG_NFS_V4_1 */
 static void nfs4_shutdown_session(struct nfs_client *clp)
@@ -233,16 +238,20 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
 }
 
 /* idr_remove_all is not needed as all id's are removed by nfs_put_client */
-void nfs_cleanup_cb_ident_idr(void)
+void nfs_cleanup_cb_ident_idr(struct net *net)
 {
-       idr_destroy(&cb_ident_idr);
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+       idr_destroy(&nn->cb_ident_idr);
 }
 
 /* nfs_client_lock held */
 static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
 {
+       struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
+
        if (clp->cl_cb_ident)
-               idr_remove(&cb_ident_idr, clp->cl_cb_ident);
+               idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);
 }
 
 static void pnfs_init_server(struct nfs_server *server)
@@ -260,7 +269,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
 {
 }
 
-void nfs_cleanup_cb_ident_idr(void)
+void nfs_cleanup_cb_ident_idr(struct net *net)
 {
 }
 
@@ -292,10 +301,10 @@ static void nfs_free_client(struct nfs_client *clp)
        if (clp->cl_machine_cred != NULL)
                put_rpccred(clp->cl_machine_cred);
 
-       nfs4_deviceid_purge_client(clp);
-
+       put_net(clp->net);
        kfree(clp->cl_hostname);
        kfree(clp->server_scope);
+       kfree(clp->impl_id);
        kfree(clp);
 
        dprintk("<-- nfs_free_client()\n");
@@ -306,15 +315,18 @@ static void nfs_free_client(struct nfs_client *clp)
  */
 void nfs_put_client(struct nfs_client *clp)
 {
+       struct nfs_net *nn;
+
        if (!clp)
                return;
 
        dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));
+       nn = net_generic(clp->net, nfs_net_id);
 
-       if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) {
+       if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) {
                list_del(&clp->cl_share_link);
                nfs_cb_idr_remove_locked(clp);
-               spin_unlock(&nfs_client_lock);
+               spin_unlock(&nn->nfs_client_lock);
 
                BUG_ON(!list_empty(&clp->cl_superblocks));
 
@@ -392,6 +404,7 @@ static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,
                (sin1->sin_port == sin2->sin_port);
 }
 
+#if defined(CONFIG_NFS_V4_1)
 /*
  * Test if two socket addresses represent the same actual socket,
  * by comparing (only) relevant fields, excluding the port number.
@@ -410,6 +423,7 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
        }
        return 0;
 }
+#endif /* CONFIG_NFS_V4_1 */
 
 /*
  * Test if two socket addresses represent the same actual socket,
@@ -430,10 +444,10 @@ 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 */
-bool
-nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp,
-                    u32 minorversion)
+static bool nfs4_cb_match_client(const struct sockaddr *addr,
+               struct nfs_client *clp, u32 minorversion)
 {
        struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
 
@@ -453,6 +467,7 @@ nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp,
 
        return true;
 }
+#endif /* CONFIG_NFS_V4_1 */
 
 /*
  * Find an nfs_client on the list that matches the initialisation data
@@ -462,8 +477,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
 {
        struct nfs_client *clp;
        const struct sockaddr *sap = data->addr;
+       struct nfs_net *nn = net_generic(data->net, nfs_net_id);
 
-       list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
+       list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
                const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
                /* Don't match clients that failed to initialise properly */
                if (clp->cl_cons_state < 0)
@@ -501,13 +517,14 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
 {
        struct nfs_client *clp, *new = NULL;
        int error;
+       struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
 
        dprintk("--> nfs_get_client(%s,v%u)\n",
                cl_init->hostname ?: "", cl_init->rpc_ops->version);
 
        /* see if the client already exists */
        do {
-               spin_lock(&nfs_client_lock);
+               spin_lock(&nn->nfs_client_lock);
 
                clp = nfs_match_client(cl_init);
                if (clp)
@@ -515,7 +532,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
                if (new)
                        goto install_client;
 
-               spin_unlock(&nfs_client_lock);
+               spin_unlock(&nn->nfs_client_lock);
 
                new = nfs_alloc_client(cl_init);
        } while (!IS_ERR(new));
@@ -526,8 +543,8 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
        /* install a new client and return with it unready */
 install_client:
        clp = new;
-       list_add(&clp->cl_share_link, &nfs_client_list);
-       spin_unlock(&nfs_client_lock);
+       list_add(&clp->cl_share_link, &nn->nfs_client_list);
+       spin_unlock(&nn->nfs_client_lock);
 
        error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr,
                                              authflavour, noresvport);
@@ -542,7 +559,7 @@ install_client:
         * - make sure it's ready before returning
         */
 found_client:
-       spin_unlock(&nfs_client_lock);
+       spin_unlock(&nn->nfs_client_lock);
 
        if (new)
                nfs_free_client(new);
@@ -642,7 +659,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
 {
        struct rpc_clnt         *clnt = NULL;
        struct rpc_create_args args = {
-               .net            = &init_net,
+               .net            = clp->net,
                .protocol       = clp->cl_proto,
                .address        = (struct sockaddr *)&clp->cl_addr,
                .addrsize       = clp->cl_addrlen,
@@ -696,6 +713,7 @@ static int nfs_start_lockd(struct nfs_server *server)
                .nfs_version    = clp->rpc_ops->version,
                .noresvport     = server->flags & NFS_MOUNT_NORESVPORT ?
                                        1 : 0,
+               .net            = clp->net,
        };
 
        if (nlm_init.nfs_version > 3)
@@ -831,6 +849,7 @@ static int nfs_init_server(struct nfs_server *server,
                .addrlen = data->nfs_server.addrlen,
                .rpc_ops = &nfs_v2_clientops,
                .proto = data->nfs_server.protocol,
+               .net = data->net,
        };
        struct rpc_timeout timeparms;
        struct nfs_client *clp;
@@ -1029,25 +1048,30 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve
 static void nfs_server_insert_lists(struct nfs_server *server)
 {
        struct nfs_client *clp = server->nfs_client;
+       struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
 
-       spin_lock(&nfs_client_lock);
+       spin_lock(&nn->nfs_client_lock);
        list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
-       list_add_tail(&server->master_link, &nfs_volume_list);
+       list_add_tail(&server->master_link, &nn->nfs_volume_list);
        clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
-       spin_unlock(&nfs_client_lock);
+       spin_unlock(&nn->nfs_client_lock);
 
 }
 
 static void nfs_server_remove_lists(struct nfs_server *server)
 {
        struct nfs_client *clp = server->nfs_client;
+       struct nfs_net *nn;
 
-       spin_lock(&nfs_client_lock);
+       if (clp == NULL)
+               return;
+       nn = net_generic(clp->net, nfs_net_id);
+       spin_lock(&nn->nfs_client_lock);
        list_del_rcu(&server->client_link);
-       if (clp && list_empty(&clp->cl_superblocks))
+       if (list_empty(&clp->cl_superblocks))
                set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
        list_del(&server->master_link);
-       spin_unlock(&nfs_client_lock);
+       spin_unlock(&nn->nfs_client_lock);
 
        synchronize_rcu();
 }
@@ -1086,6 +1110,8 @@ static struct nfs_server *nfs_alloc_server(void)
                return NULL;
        }
 
+       ida_init(&server->openowner_id);
+       ida_init(&server->lockowner_id);
        pnfs_init_server(server);
 
        return server;
@@ -1111,6 +1137,8 @@ void nfs_free_server(struct nfs_server *server)
 
        nfs_put_client(server->nfs_client);
 
+       ida_destroy(&server->lockowner_id);
+       ida_destroy(&server->openowner_id);
        nfs_free_iostats(server->io_stats);
        bdi_destroy(&server->backing_dev_info);
        kfree(server);
@@ -1189,45 +1217,19 @@ error:
 /*
  * NFSv4.0 callback thread helper
  *
- * Find a client by IP address, protocol version, and minorversion
- *
- * Called from the pg_authenticate method. The callback identifier
- * is not used as it has not been decoded.
- *
- * Returns NULL if no such client
- */
-struct nfs_client *
-nfs4_find_client_no_ident(const struct sockaddr *addr)
-{
-       struct nfs_client *clp;
-
-       spin_lock(&nfs_client_lock);
-       list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
-               if (nfs4_cb_match_client(addr, clp, 0) == false)
-                       continue;
-               atomic_inc(&clp->cl_count);
-               spin_unlock(&nfs_client_lock);
-               return clp;
-       }
-       spin_unlock(&nfs_client_lock);
-       return NULL;
-}
-
-/*
- * NFSv4.0 callback thread helper
- *
  * Find a client by callback identifier
  */
 struct nfs_client *
-nfs4_find_client_ident(int cb_ident)
+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(&nfs_client_lock);
-       clp = idr_find(&cb_ident_idr, cb_ident);
+       spin_lock(&nn->nfs_client_lock);
+       clp = idr_find(&nn->cb_ident_idr, cb_ident);
        if (clp)
                atomic_inc(&clp->cl_count);
-       spin_unlock(&nfs_client_lock);
+       spin_unlock(&nn->nfs_client_lock);
        return clp;
 }
 
@@ -1240,13 +1242,14 @@ nfs4_find_client_ident(int cb_ident)
  * Returns NULL if no such client
  */
 struct nfs_client *
-nfs4_find_client_sessionid(const struct sockaddr *addr,
+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(&nfs_client_lock);
-       list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
+       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;
 
@@ -1259,17 +1262,17 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
                        continue;
 
                atomic_inc(&clp->cl_count);
-               spin_unlock(&nfs_client_lock);
+               spin_unlock(&nn->nfs_client_lock);
                return clp;
        }
-       spin_unlock(&nfs_client_lock);
+       spin_unlock(&nn->nfs_client_lock);
        return NULL;
 }
 
 #else /* CONFIG_NFS_V4_1 */
 
 struct nfs_client *
-nfs4_find_client_sessionid(const struct sockaddr *addr,
+nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
                           struct nfs4_sessionid *sid)
 {
        return NULL;
@@ -1284,16 +1287,18 @@ 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(
-                                               clp->cl_rpcclient->cl_xprt,
+                       error = xprt_setup_backchannel(xprt,
                                                NFS41_BC_MIN_CALLBACKS);
                        if (error < 0)
                                return error;
                }
 
-               error = nfs_callback_up(clp->cl_mvops->minor_version,
-                                       clp->cl_rpcclient->cl_xprt);
+               error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
                if (error < 0) {
                        dprintk("%s: failed to start callback. Error = %d\n",
                                __func__, error);
@@ -1344,6 +1349,7 @@ int nfs4_init_client(struct nfs_client *clp,
                     rpc_authflavor_t authflavour,
                     int noresvport)
 {
+       char buf[INET6_ADDRSTRLEN + 1];
        int error;
 
        if (clp->cl_cons_state == NFS_CS_READY) {
@@ -1359,6 +1365,20 @@ int nfs4_init_client(struct nfs_client *clp,
                                      1, noresvport);
        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);
@@ -1393,7 +1413,7 @@ static int nfs4_set_client(struct nfs_server *server,
                const char *ip_addr,
                rpc_authflavor_t authflavour,
                int proto, const struct rpc_timeout *timeparms,
-               u32 minorversion)
+               u32 minorversion, struct net *net)
 {
        struct nfs_client_initdata cl_init = {
                .hostname = hostname,
@@ -1402,6 +1422,7 @@ static int nfs4_set_client(struct nfs_server *server,
                .rpc_ops = &nfs_v4_clientops,
                .proto = proto,
                .minorversion = minorversion,
+               .net = net,
        };
        struct nfs_client *clp;
        int error;
@@ -1453,6 +1474,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
                .rpc_ops = &nfs_v4_clientops,
                .proto = ds_proto,
                .minorversion = mds_clp->cl_minorversion,
+               .net = mds_clp->net,
        };
        struct rpc_timeout ds_timeout = {
                .to_initval = 15 * HZ,
@@ -1580,7 +1602,8 @@ static int nfs4_init_server(struct nfs_server *server,
                        data->auth_flavors[0],
                        data->nfs_server.protocol,
                        &timeparms,
-                       data->minorversion);
+                       data->minorversion,
+                       data->net);
        if (error < 0)
                goto error;
 
@@ -1675,9 +1698,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
                                data->addrlen,
                                parent_client->cl_ipaddr,
                                data->authflavor,
-                               parent_server->client->cl_xprt->prot,
+                               rpc_protocol(parent_server->client),
                                parent_server->client->cl_timeout,
-                               parent_client->cl_mvops->minor_version);
+                               parent_client->cl_mvops->minor_version,
+                               parent_client->net);
        if (error < 0)
                goto error;
 
@@ -1770,6 +1794,18 @@ out_free_server:
        return ERR_PTR(error);
 }
 
+void nfs_clients_init(struct net *net)
+{
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+
+       INIT_LIST_HEAD(&nn->nfs_client_list);
+       INIT_LIST_HEAD(&nn->nfs_volume_list);
+#ifdef CONFIG_NFS_V4
+       idr_init(&nn->cb_ident_idr);
+#endif
+       spin_lock_init(&nn->nfs_client_lock);
+}
+
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry *proc_fs_nfs;
 
@@ -1823,13 +1859,15 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
 {
        struct seq_file *m;
        int ret;
+       struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
+       struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
 
        ret = seq_open(file, &nfs_server_list_ops);
        if (ret < 0)
                return ret;
 
        m = file->private_data;
-       m->private = PDE(inode)->data;
+       m->private = net;
 
        return 0;
 }
@@ -1839,9 +1877,11 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
  */
 static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
 {
+       struct nfs_net *nn = net_generic(m->private, nfs_net_id);
+
        /* lock the list against modification */
-       spin_lock(&nfs_client_lock);
-       return seq_list_start_head(&nfs_client_list, *_pos);
+       spin_lock(&nn->nfs_client_lock);
+       return seq_list_start_head(&nn->nfs_client_list, *_pos);
 }
 
 /*
@@ -1849,7 +1889,9 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
  */
 static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
 {
-       return seq_list_next(v, &nfs_client_list, pos);
+       struct nfs_net *nn = net_generic(p->private, nfs_net_id);
+
+       return seq_list_next(v, &nn->nfs_client_list, pos);
 }
 
 /*
@@ -1857,7 +1899,9 @@ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
  */
 static void nfs_server_list_stop(struct seq_file *p, void *v)
 {
-       spin_unlock(&nfs_client_lock);
+       struct nfs_net *nn = net_generic(p->private, nfs_net_id);
+
+       spin_unlock(&nn->nfs_client_lock);
 }
 
 /*
@@ -1866,9 +1910,10 @@ static void nfs_server_list_stop(struct seq_file *p, void *v)
 static int nfs_server_list_show(struct seq_file *m, void *v)
 {
        struct nfs_client *clp;
+       struct nfs_net *nn = net_generic(m->private, nfs_net_id);
 
        /* display header on line 1 */
-       if (v == &nfs_client_list) {
+       if (v == &nn->nfs_client_list) {
                seq_puts(m, "NV SERVER   PORT USE HOSTNAME\n");
                return 0;
        }
@@ -1880,12 +1925,14 @@ static int nfs_server_list_show(struct seq_file *m, void *v)
        if (clp->cl_cons_state != NFS_CS_READY)
                return 0;
 
+       rcu_read_lock();
        seq_printf(m, "v%u %s %s %3d %s\n",
                   clp->rpc_ops->version,
                   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
                   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
                   atomic_read(&clp->cl_count),
                   clp->cl_hostname);
+       rcu_read_unlock();
 
        return 0;
 }
@@ -1897,13 +1944,15 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)
 {
        struct seq_file *m;
        int ret;
+       struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
+       struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
 
        ret = seq_open(file, &nfs_volume_list_ops);
        if (ret < 0)
                return ret;
 
        m = file->private_data;
-       m->private = PDE(inode)->data;
+       m->private = net;
 
        return 0;
 }
@@ -1913,9 +1962,11 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)
  */
 static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
 {
+       struct nfs_net *nn = net_generic(m->private, nfs_net_id);
+
        /* lock the list against modification */
-       spin_lock(&nfs_client_lock);
-       return seq_list_start_head(&nfs_volume_list, *_pos);
+       spin_lock(&nn->nfs_client_lock);
+       return seq_list_start_head(&nn->nfs_volume_list, *_pos);
 }
 
 /*
@@ -1923,7 +1974,9 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
  */
 static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
 {
-       return seq_list_next(v, &nfs_volume_list, pos);
+       struct nfs_net *nn = net_generic(p->private, nfs_net_id);
+
+       return seq_list_next(v, &nn->nfs_volume_list, pos);
 }
 
 /*
@@ -1931,7 +1984,9 @@ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
  */
 static void nfs_volume_list_stop(struct seq_file *p, void *v)
 {
-       spin_unlock(&nfs_client_lock);
+       struct nfs_net *nn = net_generic(p->private, nfs_net_id);
+
+       spin_unlock(&nn->nfs_client_lock);
 }
 
 /*
@@ -1942,9 +1997,10 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
        struct nfs_server *server;
        struct nfs_client *clp;
        char dev[8], fsid[17];
+       struct nfs_net *nn = net_generic(m->private, nfs_net_id);
 
        /* display header on line 1 */
-       if (v == &nfs_volume_list) {
+       if (v == &nn->nfs_volume_list) {
                seq_puts(m, "NV SERVER   PORT DEV     FSID              FSC\n");
                return 0;
        }
@@ -1959,6 +2015,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
                 (unsigned long long) server->fsid.major,
                 (unsigned long long) server->fsid.minor);
 
+       rcu_read_lock();
        seq_printf(m, "v%u %s %s %-7s %-17s %s\n",
                   clp->rpc_ops->version,
                   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
@@ -1966,6 +2023,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
                   dev,
                   fsid,
                   nfs_server_fscache_state(server));
+       rcu_read_unlock();
 
        return 0;
 }
index 7f26540..89af1d2 100644 (file)
@@ -105,7 +105,7 @@ again:
                        continue;
                if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
                        continue;
-               if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0)
+               if (!nfs4_stateid_match(&state->stateid, stateid))
                        continue;
                get_nfs_open_context(ctx);
                spin_unlock(&inode->i_lock);
@@ -139,8 +139,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
        if (delegation != NULL) {
                spin_lock(&delegation->lock);
                if (delegation->inode != NULL) {
-                       memcpy(delegation->stateid.data, res->delegation.data,
-                              sizeof(delegation->stateid.data));
+                       nfs4_stateid_copy(&delegation->stateid, &res->delegation);
                        delegation->type = res->delegation_type;
                        delegation->maxsize = res->maxsize;
                        oldcred = delegation->cred;
@@ -236,8 +235,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
        delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
        if (delegation == NULL)
                return -ENOMEM;
-       memcpy(delegation->stateid.data, res->delegation.data,
-                       sizeof(delegation->stateid.data));
+       nfs4_stateid_copy(&delegation->stateid, &res->delegation);
        delegation->type = res->delegation_type;
        delegation->maxsize = res->maxsize;
        delegation->change_attr = inode->i_version;
@@ -250,19 +248,22 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
        old_delegation = rcu_dereference_protected(nfsi->delegation,
                                        lockdep_is_held(&clp->cl_lock));
        if (old_delegation != NULL) {
-               if (memcmp(&delegation->stateid, &old_delegation->stateid,
-                                       sizeof(old_delegation->stateid)) == 0 &&
+               if (nfs4_stateid_match(&delegation->stateid,
+                                       &old_delegation->stateid) &&
                                delegation->type == old_delegation->type) {
                        goto out;
                }
                /*
                 * Deal with broken servers that hand out two
                 * delegations for the same file.
+                * Allow for upgrades to a WRITE delegation, but
+                * nothing else.
                 */
                dfprintk(FILE, "%s: server %s handed out "
                                "a duplicate delegation!\n",
                                __func__, clp->cl_hostname);
-               if (delegation->type <= old_delegation->type) {
+               if (delegation->type == old_delegation->type ||
+                   !(delegation->type & FMODE_WRITE)) {
                        freeme = delegation;
                        delegation = NULL;
                        goto out;
@@ -455,17 +456,24 @@ static void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp,
        rcu_read_unlock();
 }
 
-static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
-{
-       nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
-}
-
 static void nfs_delegation_run_state_manager(struct nfs_client *clp)
 {
        if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
                nfs4_schedule_state_manager(clp);
 }
 
+void nfs_remove_bad_delegation(struct inode *inode)
+{
+       struct nfs_delegation *delegation;
+
+       delegation = nfs_detach_delegation(NFS_I(inode), NFS_SERVER(inode));
+       if (delegation) {
+               nfs_inode_find_state_and_recover(inode, &delegation->stateid);
+               nfs_free_delegation(delegation);
+       }
+}
+EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
+
 /**
  * nfs_expire_all_delegation_types
  * @clp: client to process
@@ -488,18 +496,6 @@ void nfs_expire_all_delegations(struct nfs_client *clp)
        nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
 }
 
-/**
- * nfs_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
- * @clp: client to process
- *
- */
-void nfs_handle_cb_pathdown(struct nfs_client *clp)
-{
-       if (clp == NULL)
-               return;
-       nfs_client_mark_return_all_delegations(clp);
-}
-
 static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
 {
        struct nfs_delegation *delegation;
@@ -531,7 +527,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
 /**
  * nfs_async_inode_return_delegation - asynchronously return a delegation
  * @inode: inode to process
- * @stateid: state ID information from CB_RECALL arguments
+ * @stateid: state ID information
  *
  * Returns zero on success, or a negative errno value.
  */
@@ -545,7 +541,7 @@ int nfs_async_inode_return_delegation(struct inode *inode,
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(inode)->delegation);
 
-       if (!clp->cl_mvops->validate_stateid(delegation, stateid)) {
+       if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
                rcu_read_unlock();
                return -ENOENT;
        }
@@ -684,21 +680,25 @@ int nfs_delegations_present(struct nfs_client *clp)
  * nfs4_copy_delegation_stateid - Copy inode's state ID information
  * @dst: stateid data structure to fill in
  * @inode: inode to check
+ * @flags: delegation type requirement
  *
- * Returns one and fills in "dst->data" * if inode had a delegation,
- * otherwise zero is returned.
+ * Returns "true" and fills in "dst->data" * if inode had a delegation,
+ * otherwise "false" is returned.
  */
-int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
+bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
+               fmode_t flags)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct nfs_delegation *delegation;
-       int ret = 0;
+       bool ret;
 
+       flags &= FMODE_READ|FMODE_WRITE;
        rcu_read_lock();
        delegation = rcu_dereference(nfsi->delegation);
-       if (delegation != NULL) {
-               memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
-               ret = 1;
+       ret = (delegation != NULL && (delegation->type & flags) == flags);
+       if (ret) {
+               nfs4_stateid_copy(dst, &delegation->stateid);
+               nfs_mark_delegation_referenced(delegation);
        }
        rcu_read_unlock();
        return ret;
index d9322e4..cd6a7a8 100644 (file)
@@ -42,9 +42,9 @@ void nfs_super_return_all_delegations(struct super_block *sb);
 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);
-void nfs_handle_cb_pathdown(struct nfs_client *clp);
 int nfs_client_return_marked_delegations(struct nfs_client *clp);
 int nfs_delegations_present(struct nfs_client *clp);
+void nfs_remove_bad_delegation(struct inode *inode);
 
 void nfs_delegation_mark_reclaim(struct nfs_client *clp);
 void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
@@ -53,7 +53,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
 int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync);
 int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid);
 int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
-int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
+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);
index 32aa691..4aaf031 100644 (file)
@@ -207,7 +207,7 @@ struct nfs_cache_array_entry {
 };
 
 struct nfs_cache_array {
-       unsigned int size;
+       int size;
        int eof_index;
        u64 last_cookie;
        struct nfs_cache_array_entry array[0];
@@ -1429,6 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
        }
 
        open_flags = nd->intent.open.flags;
+       attr.ia_valid = 0;
 
        ctx = create_nfs_open_context(dentry, open_flags);
        res = ERR_CAST(ctx);
@@ -1437,11 +1438,14 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
 
        if (nd->flags & LOOKUP_CREATE) {
                attr.ia_mode = nd->intent.open.create_mode;
-               attr.ia_valid = ATTR_MODE;
+               attr.ia_valid |= ATTR_MODE;
                attr.ia_mode &= ~current_umask();
-       } else {
+       } else
                open_flags &= ~(O_EXCL | O_CREAT);
-               attr.ia_valid = 0;
+
+       if (open_flags & O_TRUNC) {
+               attr.ia_valid |= ATTR_SIZE;
+               attr.ia_size = 0;
        }
 
        /* Open the file on the server */
@@ -1495,6 +1499,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
        struct inode *inode;
        struct inode *dir;
        struct nfs_open_context *ctx;
+       struct iattr attr;
        int openflags, ret = 0;
 
        if (nd->flags & LOOKUP_RCU)
@@ -1523,19 +1528,27 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
        /* We cannot do exclusive creation on a positive dentry */
        if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
                goto no_open_dput;
-       /* We can't create new files, or truncate existing ones here */
-       openflags &= ~(O_CREAT|O_EXCL|O_TRUNC);
+       /* We can't create new files here */
+       openflags &= ~(O_CREAT|O_EXCL);
 
        ctx = create_nfs_open_context(dentry, openflags);
        ret = PTR_ERR(ctx);
        if (IS_ERR(ctx))
                goto out;
+
+       attr.ia_valid = 0;
+       if (openflags & O_TRUNC) {
+               attr.ia_valid |= ATTR_SIZE;
+               attr.ia_size = 0;
+               nfs_wb_all(inode);
+       }
+
        /*
         * Note: we're not holding inode->i_mutex and so may be racing with
         * operations that change the directory. We therefore save the
         * change attribute *before* we do the RPC call.
         */
-       inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL);
+       inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
        if (IS_ERR(inode)) {
                ret = PTR_ERR(inode);
                switch (ret) {
index ea5be12..481be7f 100644 (file)
@@ -264,9 +264,7 @@ static void nfs_direct_read_release(void *calldata)
 }
 
 static const struct rpc_call_ops nfs_read_direct_ops = {
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs_read_prepare,
-#endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs_direct_read_result,
        .rpc_release = nfs_direct_read_release,
 };
@@ -553,9 +551,7 @@ static void nfs_direct_commit_release(void *calldata)
 }
 
 static const struct rpc_call_ops nfs_commit_direct_ops = {
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs_write_prepare,
-#endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs_direct_commit_result,
        .rpc_release = nfs_direct_commit_release,
 };
@@ -695,9 +691,7 @@ out_unlock:
 }
 
 static const struct rpc_call_ops nfs_write_direct_ops = {
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs_write_prepare,
-#endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs_direct_write_result,
        .rpc_release = nfs_direct_write_release,
 };
index a6e711a..b3924b8 100644 (file)
@@ -10,8 +10,9 @@
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/dns_resolver.h>
+#include "dns_resolve.h"
 
-ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
+ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
                struct sockaddr *sa, size_t salen)
 {
        ssize_t ret;
@@ -20,7 +21,7 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
 
        ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL);
        if (ip_len > 0)
-               ret = rpc_pton(ip_addr, ip_len, sa, salen);
+               ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
        else
                ret = -ESRCH;
        kfree(ip_addr);
@@ -40,15 +41,15 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/cache.h>
 #include <linux/sunrpc/svcauth.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
 
 #include "dns_resolve.h"
 #include "cache_lib.h"
+#include "netns.h"
 
 #define NFS_DNS_HASHBITS 4
 #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)
 
-static struct cache_head *nfs_dns_table[NFS_DNS_HASHTBL_SIZE];
-
 struct nfs_dns_ent {
        struct cache_head h;
 
@@ -224,7 +225,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
        len = qword_get(&buf, buf1, sizeof(buf1));
        if (len <= 0)
                goto out;
-       key.addrlen = rpc_pton(buf1, len,
+       key.addrlen = rpc_pton(cd->net, buf1, len,
                        (struct sockaddr *)&key.addr,
                        sizeof(key.addr));
 
@@ -259,21 +260,6 @@ out:
        return ret;
 }
 
-static struct cache_detail nfs_dns_resolve = {
-       .owner = THIS_MODULE,
-       .hash_size = NFS_DNS_HASHTBL_SIZE,
-       .hash_table = nfs_dns_table,
-       .name = "dns_resolve",
-       .cache_put = nfs_dns_ent_put,
-       .cache_upcall = nfs_dns_upcall,
-       .cache_parse = nfs_dns_parse,
-       .cache_show = nfs_dns_show,
-       .match = nfs_dns_match,
-       .init = nfs_dns_ent_init,
-       .update = nfs_dns_ent_update,
-       .alloc = nfs_dns_ent_alloc,
-};
-
 static int do_cache_lookup(struct cache_detail *cd,
                struct nfs_dns_ent *key,
                struct nfs_dns_ent **item,
@@ -336,8 +322,8 @@ out:
        return ret;
 }
 
-ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
-               struct sockaddr *sa, size_t salen)
+ssize_t nfs_dns_resolve_name(struct net *net, char *name,
+               size_t namelen, struct sockaddr *sa, size_t salen)
 {
        struct nfs_dns_ent key = {
                .hostname = name,
@@ -345,28 +331,118 @@ ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
        };
        struct nfs_dns_ent *item = NULL;
        ssize_t ret;
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
 
-       ret = do_cache_lookup_wait(&nfs_dns_resolve, &key, &item);
+       ret = do_cache_lookup_wait(nn->nfs_dns_resolve, &key, &item);
        if (ret == 0) {
                if (salen >= item->addrlen) {
                        memcpy(sa, &item->addr, item->addrlen);
                        ret = item->addrlen;
                } else
                        ret = -EOVERFLOW;
-               cache_put(&item->h, &nfs_dns_resolve);
+               cache_put(&item->h, nn->nfs_dns_resolve);
        } else if (ret == -ENOENT)
                ret = -ESRCH;
        return ret;
 }
 
+int nfs_dns_resolver_cache_init(struct net *net)
+{
+       int err = -ENOMEM;
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+       struct cache_detail *cd;
+       struct cache_head **tbl;
+
+       cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL);
+       if (cd == NULL)
+               goto err_cd;
+
+       tbl = kzalloc(NFS_DNS_HASHTBL_SIZE * sizeof(struct cache_head *),
+                       GFP_KERNEL);
+       if (tbl == NULL)
+               goto err_tbl;
+
+       cd->owner = THIS_MODULE,
+       cd->hash_size = NFS_DNS_HASHTBL_SIZE,
+       cd->hash_table = tbl,
+       cd->name = "dns_resolve",
+       cd->cache_put = nfs_dns_ent_put,
+       cd->cache_upcall = nfs_dns_upcall,
+       cd->cache_parse = nfs_dns_parse,
+       cd->cache_show = nfs_dns_show,
+       cd->match = nfs_dns_match,
+       cd->init = nfs_dns_ent_init,
+       cd->update = nfs_dns_ent_update,
+       cd->alloc = nfs_dns_ent_alloc,
+
+       nfs_cache_init(cd);
+       err = nfs_cache_register_net(net, cd);
+       if (err)
+               goto err_reg;
+       nn->nfs_dns_resolve = cd;
+       return 0;
+
+err_reg:
+       nfs_cache_destroy(cd);
+       kfree(cd->hash_table);
+err_tbl:
+       kfree(cd);
+err_cd:
+       return err;
+}
+
+void nfs_dns_resolver_cache_destroy(struct net *net)
+{
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+       struct cache_detail *cd = nn->nfs_dns_resolve;
+
+       nfs_cache_unregister_net(net, cd);
+       nfs_cache_destroy(cd);
+       kfree(cd->hash_table);
+       kfree(cd);
+}
+
+static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
+                          void *ptr)
+{
+       struct super_block *sb = ptr;
+       struct net *net = sb->s_fs_info;
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+       struct cache_detail *cd = nn->nfs_dns_resolve;
+       int ret = 0;
+
+       if (cd == NULL)
+               return 0;
+
+       if (!try_module_get(THIS_MODULE))
+               return 0;
+
+       switch (event) {
+       case RPC_PIPEFS_MOUNT:
+               ret = nfs_cache_register_sb(sb, cd);
+               break;
+       case RPC_PIPEFS_UMOUNT:
+               nfs_cache_unregister_sb(sb, cd);
+               break;
+       default:
+               ret = -ENOTSUPP;
+               break;
+       }
+       module_put(THIS_MODULE);
+       return ret;
+}
+
+static struct notifier_block nfs_dns_resolver_block = {
+       .notifier_call  = rpc_pipefs_event,
+};
+
 int nfs_dns_resolver_init(void)
 {
-       return nfs_cache_register(&nfs_dns_resolve);
+       return rpc_pipefs_notifier_register(&nfs_dns_resolver_block);
 }
 
 void nfs_dns_resolver_destroy(void)
 {
-       nfs_cache_unregister(&nfs_dns_resolve);
+       rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block);
 }
-
 #endif
index 199bb55..2e4f596 100644 (file)
@@ -15,12 +15,22 @@ static inline int nfs_dns_resolver_init(void)
 
 static inline void nfs_dns_resolver_destroy(void)
 {}
+
+static inline int nfs_dns_resolver_cache_init(struct net *net)
+{
+       return 0;
+}
+
+static inline void nfs_dns_resolver_cache_destroy(struct net *net)
+{}
 #else
 extern int nfs_dns_resolver_init(void);
 extern void nfs_dns_resolver_destroy(void);
+extern int nfs_dns_resolver_cache_init(struct net *net);
+extern void nfs_dns_resolver_cache_destroy(struct net *net);
 #endif
 
-extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
-               struct sockaddr *sa, size_t salen);
+extern ssize_t nfs_dns_resolve_name(struct net *net, char *name,
+               size_t namelen, struct sockaddr *sa, size_t salen);
 
 #endif
index a77a1f2..aa9b709 100644 (file)
@@ -529,6 +529,8 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        if (mapping != dentry->d_inode->i_mapping)
                goto out_unlock;
 
+       wait_on_page_writeback(page);
+
        pagelen = nfs_page_length(page);
        if (pagelen == 0)
                goto out_unlock;
index 419119c..ae65c16 100644 (file)
@@ -327,7 +327,7 @@ void nfs_fscache_reset_inode_cookie(struct inode *inode)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct nfs_server *nfss = NFS_SERVER(inode);
-       struct fscache_cookie *old = nfsi->fscache;
+       NFS_IFDEBUG(struct fscache_cookie *old = nfsi->fscache);
 
        nfs_fscache_inode_lock(inode);
        if (nfsi->fscache) {
index a1bbf77..b7f348b 100644 (file)
  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
+#include <linux/parser.h>
+#include <linux/fs.h>
 #include <linux/nfs_idmap.h>
+#include <net/net_namespace.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_fs_sb.h>
+#include <linux/key.h>
+#include <linux/keyctl.h>
+#include <linux/key-type.h>
+#include <keys/user-type.h>
+#include <linux/module.h>
+
+#include "internal.h"
+#include "netns.h"
+
+#define NFS_UINT_MAXLEN 11
+
+/* Default cache timeout is 10 minutes */
+unsigned int nfs_idmap_cache_timeout = 600;
+static const struct cred *id_resolver_cache;
+static struct key_type key_type_id_resolver_legacy;
+
 
 /**
  * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
@@ -142,24 +160,7 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
        return snprintf(buf, buflen, "%u", id);
 }
 
-#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
-
-#include <linux/cred.h>
-#include <linux/sunrpc/sched.h>
-#include <linux/nfs4.h>
-#include <linux/nfs_fs_sb.h>
-#include <linux/keyctl.h>
-#include <linux/key-type.h>
-#include <linux/rcupdate.h>
-#include <linux/err.h>
-
-#include <keys/user-type.h>
-
-#define NFS_UINT_MAXLEN 11
-
-const struct cred *id_resolver_cache;
-
-struct key_type key_type_id_resolver = {
+static struct key_type key_type_id_resolver = {
        .name           = "id_resolver",
        .instantiate    = user_instantiate,
        .match          = user_match,
@@ -169,13 +170,14 @@ struct key_type key_type_id_resolver = {
        .read           = user_read,
 };
 
-int nfs_idmap_init(void)
+static int nfs_idmap_init_keyring(void)
 {
        struct cred *cred;
        struct key *keyring;
        int ret = 0;
 
-       printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name);
+       printk(KERN_NOTICE "NFS: Registering the %s key type\n",
+               key_type_id_resolver.name);
 
        cred = prepare_kernel_cred(NULL);
        if (!cred)
@@ -211,7 +213,7 @@ failed_put_cred:
        return ret;
 }
 
-void nfs_idmap_quit(void)
+static void nfs_idmap_quit_keyring(void)
 {
        key_revoke(id_resolver_cache->thread_keyring);
        unregister_key_type(&key_type_id_resolver);
@@ -246,8 +248,10 @@ static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen,
        return desclen;
 }
 
-static ssize_t nfs_idmap_request_key(const char *name, size_t namelen,
-               const char *type, void *data, size_t data_size)
+static ssize_t nfs_idmap_request_key(struct key_type *key_type,
+                                    const char *name, size_t namelen,
+                                    const char *type, void *data,
+                                    size_t data_size, struct idmap *idmap)
 {
        const struct cred *saved_cred;
        struct key *rkey;
@@ -260,8 +264,12 @@ static ssize_t nfs_idmap_request_key(const char *name, size_t namelen,
                goto out;
 
        saved_cred = override_creds(id_resolver_cache);
-       rkey = request_key(&key_type_id_resolver, desc, "");
+       if (idmap)
+               rkey = request_key_with_auxdata(key_type, desc, "", 0, idmap);
+       else
+               rkey = request_key(&key_type_id_resolver, desc, "");
        revert_creds(saved_cred);
+
        kfree(desc);
        if (IS_ERR(rkey)) {
                ret = PTR_ERR(rkey);
@@ -294,31 +302,46 @@ out:
        return ret;
 }
 
+static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
+                                const char *type, void *data,
+                                size_t data_size, struct idmap *idmap)
+{
+       ssize_t ret = nfs_idmap_request_key(&key_type_id_resolver,
+                                           name, namelen, type, data,
+                                           data_size, NULL);
+       if (ret < 0) {
+               ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
+                                           name, namelen, type, data,
+                                           data_size, idmap);
+       }
+       return ret;
+}
 
 /* ID -> Name */
-static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen)
+static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf,
+                                    size_t buflen, struct idmap *idmap)
 {
        char id_str[NFS_UINT_MAXLEN];
        int id_len;
        ssize_t ret;
 
        id_len = snprintf(id_str, sizeof(id_str), "%u", id);
-       ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen);
+       ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap);
        if (ret < 0)
                return -EINVAL;
        return ret;
 }
 
 /* Name -> ID */
-static int nfs_idmap_lookup_id(const char *name, size_t namelen,
-                               const char *type, __u32 *id)
+static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type,
+                              __u32 *id, struct idmap *idmap)
 {
        char id_str[NFS_UINT_MAXLEN];
        long id_long;
        ssize_t data_size;
        int ret = 0;
 
-       data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN);
+       data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap);
        if (data_size <= 0) {
                ret = -EINVAL;
        } else {
@@ -328,114 +351,103 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen,
        return ret;
 }
 
-int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
-{
-       if (nfs_map_string_to_numeric(name, namelen, uid))
-               return 0;
-       return nfs_idmap_lookup_id(name, namelen, "uid", uid);
-}
-
-int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
-{
-       if (nfs_map_string_to_numeric(name, namelen, gid))
-               return 0;
-       return nfs_idmap_lookup_id(name, namelen, "gid", gid);
-}
-
-int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
-{
-       int ret = -EINVAL;
-
-       if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
-               ret = nfs_idmap_lookup_name(uid, "user", buf, buflen);
-       if (ret < 0)
-               ret = nfs_map_numeric_to_string(uid, buf, buflen);
-       return ret;
-}
-int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
-{
-       int ret = -EINVAL;
+/* idmap classic begins here */
+module_param(nfs_idmap_cache_timeout, int, 0644);
 
-       if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
-               ret = nfs_idmap_lookup_name(gid, "group", buf, buflen);
-       if (ret < 0)
-               ret = nfs_map_numeric_to_string(gid, buf, buflen);
-       return ret;
-}
-
-#else  /* CONFIG_NFS_USE_NEW_IDMAPPER not defined */
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/sched.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/workqueue.h>
-#include <linux/sunrpc/rpc_pipe_fs.h>
-
-#include <linux/nfs_fs.h>
-
-#include "nfs4_fs.h"
-
-#define IDMAP_HASH_SZ          128
-
-/* Default cache timeout is 10 minutes */
-unsigned int nfs_idmap_cache_timeout = 600 * HZ;
-
-static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
-{
-       char *endp;
-       int num = simple_strtol(val, &endp, 0);
-       int jif = num * HZ;
-       if (endp == val || *endp || num < 0 || jif < num)
-               return -EINVAL;
-       *((int *)kp->arg) = jif;
-       return 0;
-}
-
-module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
-                &nfs_idmap_cache_timeout, 0644);
-
-struct idmap_hashent {
-       unsigned long           ih_expires;
-       __u32                   ih_id;
-       size_t                  ih_namelen;
-       char                    ih_name[IDMAP_NAMESZ];
+struct idmap {
+       struct rpc_pipe         *idmap_pipe;
+       struct key_construction *idmap_key_cons;
 };
 
-struct idmap_hashtable {
-       __u8                    h_type;
-       struct idmap_hashent    h_entries[IDMAP_HASH_SZ];
+enum {
+       Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err
 };
 
-struct idmap {
-       struct dentry           *idmap_dentry;
-       wait_queue_head_t       idmap_wq;
-       struct idmap_msg        idmap_im;
-       struct mutex            idmap_lock;     /* Serializes upcalls */
-       struct mutex            idmap_im_lock;  /* Protects the hashtable */
-       struct idmap_hashtable  idmap_user_hash;
-       struct idmap_hashtable  idmap_group_hash;
+static const match_table_t nfs_idmap_tokens = {
+       { Opt_find_uid, "uid:%s" },
+       { Opt_find_gid, "gid:%s" },
+       { Opt_find_user, "user:%s" },
+       { Opt_find_group, "group:%s" },
+       { Opt_find_err, NULL }
 };
 
+static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
 static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
                                   size_t);
 static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
 
-static unsigned int fnvhash32(const void *, size_t);
-
 static const struct rpc_pipe_ops idmap_upcall_ops = {
        .upcall         = rpc_pipe_generic_upcall,
        .downcall       = idmap_pipe_downcall,
        .destroy_msg    = idmap_pipe_destroy_msg,
 };
 
+static struct key_type key_type_id_resolver_legacy = {
+       .name           = "id_resolver",
+       .instantiate    = user_instantiate,
+       .match          = user_match,
+       .revoke         = user_revoke,
+       .destroy        = user_destroy,
+       .describe       = user_describe,
+       .read           = user_read,
+       .request_key    = nfs_idmap_legacy_upcall,
+};
+
+static void __nfs_idmap_unregister(struct rpc_pipe *pipe)
+{
+       if (pipe->dentry)
+               rpc_unlink(pipe->dentry);
+}
+
+static int __nfs_idmap_register(struct dentry *dir,
+                                    struct idmap *idmap,
+                                    struct rpc_pipe *pipe)
+{
+       struct dentry *dentry;
+
+       dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+       pipe->dentry = dentry;
+       return 0;
+}
+
+static void nfs_idmap_unregister(struct nfs_client *clp,
+                                     struct rpc_pipe *pipe)
+{
+       struct net *net = clp->net;
+       struct super_block *pipefs_sb;
+
+       pipefs_sb = rpc_get_sb_net(net);
+       if (pipefs_sb) {
+               __nfs_idmap_unregister(pipe);
+               rpc_put_sb_net(net);
+       }
+}
+
+static int nfs_idmap_register(struct nfs_client *clp,
+                                  struct idmap *idmap,
+                                  struct rpc_pipe *pipe)
+{
+       struct net *net = clp->net;
+       struct super_block *pipefs_sb;
+       int err = 0;
+
+       pipefs_sb = rpc_get_sb_net(net);
+       if (pipefs_sb) {
+               if (clp->cl_rpcclient->cl_dentry)
+                       err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
+                                                  idmap, pipe);
+               rpc_put_sb_net(net);
+       }
+       return err;
+}
+
 int
 nfs_idmap_new(struct nfs_client *clp)
 {
        struct idmap *idmap;
+       struct rpc_pipe *pipe;
        int error;
 
        BUG_ON(clp->cl_idmap != NULL);
@@ -444,19 +456,19 @@ nfs_idmap_new(struct nfs_client *clp)
        if (idmap == NULL)
                return -ENOMEM;
 
-       idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry,
-                       "idmap", idmap, &idmap_upcall_ops, 0);
-       if (IS_ERR(idmap->idmap_dentry)) {
-               error = PTR_ERR(idmap->idmap_dentry);
+       pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0);
+       if (IS_ERR(pipe)) {
+               error = PTR_ERR(pipe);
                kfree(idmap);
                return error;
        }
-
-       mutex_init(&idmap->idmap_lock);
-       mutex_init(&idmap->idmap_im_lock);
-       init_waitqueue_head(&idmap->idmap_wq);
-       idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER;
-       idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
+       error = nfs_idmap_register(clp, idmap, pipe);
+       if (error) {
+               rpc_destroy_pipe_data(pipe);
+               kfree(idmap);
+               return error;
+       }
+       idmap->idmap_pipe = pipe;
 
        clp->cl_idmap = idmap;
        return 0;
@@ -469,211 +481,220 @@ nfs_idmap_delete(struct nfs_client *clp)
 
        if (!idmap)
                return;
-       rpc_unlink(idmap->idmap_dentry);
+       nfs_idmap_unregister(clp, idmap->idmap_pipe);
+       rpc_destroy_pipe_data(idmap->idmap_pipe);
        clp->cl_idmap = NULL;
        kfree(idmap);
 }
 
-/*
- * Helper routines for manipulating the hashtable
- */
-static inline struct idmap_hashent *
-idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len)
-{
-       return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ];
-}
-
-static struct idmap_hashent *
-idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
+static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event,
+                             struct super_block *sb)
 {
-       struct idmap_hashent *he = idmap_name_hash(h, name, len);
+       int err = 0;
 
-       if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0)
-               return NULL;
-       if (time_after(jiffies, he->ih_expires))
-               return NULL;
-       return he;
+       switch (event) {
+       case RPC_PIPEFS_MOUNT:
+               BUG_ON(clp->cl_rpcclient->cl_dentry == NULL);
+               err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
+                                               clp->cl_idmap,
+                                               clp->cl_idmap->idmap_pipe);
+               break;
+       case RPC_PIPEFS_UMOUNT:
+               if (clp->cl_idmap->idmap_pipe) {
+                       struct dentry *parent;
+
+                       parent = clp->cl_idmap->idmap_pipe->dentry->d_parent;
+                       __nfs_idmap_unregister(clp->cl_idmap->idmap_pipe);
+                       /*
+                        * Note: This is a dirty hack. SUNRPC hook has been
+                        * called already but simple_rmdir() call for the
+                        * directory returned with error because of idmap pipe
+                        * inside. Thus now we have to remove this directory
+                        * here.
+                        */
+                       if (rpc_rmdir(parent))
+                               printk(KERN_ERR "NFS: %s: failed to remove "
+                                       "clnt dir!\n", __func__);
+               }
+               break;
+       default:
+               printk(KERN_ERR "NFS: %s: unknown event: %ld\n", __func__,
+                       event);
+               return -ENOTSUPP;
+       }
+       return err;
+}
+
+static struct nfs_client *nfs_get_client_for_event(struct net *net, int event)
+{
+       struct nfs_net *nn = net_generic(net, nfs_net_id);
+       struct dentry *cl_dentry;
+       struct nfs_client *clp;
+
+       spin_lock(&nn->nfs_client_lock);
+       list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
+               if (clp->rpc_ops != &nfs_v4_clientops)
+                       continue;
+               cl_dentry = clp->cl_idmap->idmap_pipe->dentry;
+               if (((event == RPC_PIPEFS_MOUNT) && cl_dentry) ||
+                   ((event == RPC_PIPEFS_UMOUNT) && !cl_dentry))
+                       continue;
+               atomic_inc(&clp->cl_count);
+               spin_unlock(&nn->nfs_client_lock);
+               return clp;
+       }
+       spin_unlock(&nn->nfs_client_lock);
+       return NULL;
 }
 
-static inline struct idmap_hashent *
-idmap_id_hash(struct idmap_hashtable* h, __u32 id)
+static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
+                           void *ptr)
 {
-       return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ];
-}
+       struct super_block *sb = ptr;
+       struct nfs_client *clp;
+       int error = 0;
 
-static struct idmap_hashent *
-idmap_lookup_id(struct idmap_hashtable *h, __u32 id)
-{
-       struct idmap_hashent *he = idmap_id_hash(h, id);
-       if (he->ih_id != id || he->ih_namelen == 0)
-               return NULL;
-       if (time_after(jiffies, he->ih_expires))
-               return NULL;
-       return he;
+       while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) {
+               error = __rpc_pipefs_event(clp, event, sb);
+               nfs_put_client(clp);
+               if (error)
+                       break;
+       }
+       return error;
 }
 
-/*
- * Routines for allocating new entries in the hashtable.
- * For now, we just have 1 entry per bucket, so it's all
- * pretty trivial.
- */
-static inline struct idmap_hashent *
-idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len)
-{
-       return idmap_name_hash(h, name, len);
-}
+#define PIPEFS_NFS_PRIO                1
+
+static struct notifier_block nfs_idmap_block = {
+       .notifier_call  = rpc_pipefs_event,
+       .priority       = SUNRPC_PIPEFS_NFS_PRIO,
+};
 
-static inline struct idmap_hashent *
-idmap_alloc_id(struct idmap_hashtable *h, __u32 id)
+int nfs_idmap_init(void)
 {
-       return idmap_id_hash(h, id);
+       int ret;
+       ret = nfs_idmap_init_keyring();
+       if (ret != 0)
+               goto out;
+       ret = rpc_pipefs_notifier_register(&nfs_idmap_block);
+       if (ret != 0)
+               nfs_idmap_quit_keyring();
+out:
+       return ret;
 }
 
-static void
-idmap_update_entry(struct idmap_hashent *he, const char *name,
-               size_t namelen, __u32 id)
+void nfs_idmap_quit(void)
 {
-       he->ih_id = id;
-       memcpy(he->ih_name, name, namelen);
-       he->ih_name[namelen] = '\0';
-       he->ih_namelen = namelen;
-       he->ih_expires = jiffies + nfs_idmap_cache_timeout;
+       rpc_pipefs_notifier_unregister(&nfs_idmap_block);
+       nfs_idmap_quit_keyring();
 }
 
-/*
- * Name -> ID
- */
-static int
-nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
-               const char *name, size_t namelen, __u32 *id)
+static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
+                                    struct rpc_pipe_msg *msg)
 {
-       struct rpc_pipe_msg msg;
-       struct idmap_msg *im;
-       struct idmap_hashent *he;
-       DECLARE_WAITQUEUE(wq, current);
-       int ret = -EIO;
-
-       im = &idmap->idmap_im;
-
-       /*
-        * String sanity checks
-        * Note that the userland daemon expects NUL terminated strings
-        */
-       for (;;) {
-               if (namelen == 0)
-                       return -EINVAL;
-               if (name[namelen-1] != '\0')
-                       break;
-               namelen--;
-       }
-       if (namelen >= IDMAP_NAMESZ)
-               return -EINVAL;
+       substring_t substr;
+       int token, ret;
 
-       mutex_lock(&idmap->idmap_lock);
-       mutex_lock(&idmap->idmap_im_lock);
-
-       he = idmap_lookup_name(h, name, namelen);
-       if (he != NULL) {
-               *id = he->ih_id;
-               ret = 0;
-               goto out;
-       }
+       memset(im,  0, sizeof(*im));
+       memset(msg, 0, sizeof(*msg));
 
-       memset(im, 0, sizeof(*im));
-       memcpy(im->im_name, name, namelen);
+       im->im_type = IDMAP_TYPE_GROUP;
+       token = match_token(desc, nfs_idmap_tokens, &substr);
 
-       im->im_type = h->h_type;
-       im->im_conv = IDMAP_CONV_NAMETOID;
+       switch (token) {
+       case Opt_find_uid:
+               im->im_type = IDMAP_TYPE_USER;
+       case Opt_find_gid:
+               im->im_conv = IDMAP_CONV_NAMETOID;
+               ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ);
+               break;
 
-       memset(&msg, 0, sizeof(msg));
-       msg.data = im;
-       msg.len = sizeof(*im);
+       case Opt_find_user:
+               im->im_type = IDMAP_TYPE_USER;
+       case Opt_find_group:
+               im->im_conv = IDMAP_CONV_IDTONAME;
+               ret = match_int(&substr, &im->im_id);
+               break;
 
-       add_wait_queue(&idmap->idmap_wq, &wq);
-       if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
-               remove_wait_queue(&idmap->idmap_wq, &wq);
+       default:
+               ret = -EINVAL;
                goto out;
        }
 
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       mutex_unlock(&idmap->idmap_im_lock);
-       schedule();
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&idmap->idmap_wq, &wq);
-       mutex_lock(&idmap->idmap_im_lock);
+       msg->data = im;
+       msg->len  = sizeof(struct idmap_msg);
 
-       if (im->im_status & IDMAP_STATUS_SUCCESS) {
-               *id = im->im_id;
-               ret = 0;
-       }
-
- out:
-       memset(im, 0, sizeof(*im));
-       mutex_unlock(&idmap->idmap_im_lock);
-       mutex_unlock(&idmap->idmap_lock);
+out:
        return ret;
 }
 
-/*
- * ID -> Name
- */
-static int
-nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
-               __u32 id, char *name)
+static int nfs_idmap_legacy_upcall(struct key_construction *cons,
+                                  const char *op,
+                                  void *aux)
 {
-       struct rpc_pipe_msg msg;
+       struct rpc_pipe_msg *msg;
        struct idmap_msg *im;
-       struct idmap_hashent *he;
-       DECLARE_WAITQUEUE(wq, current);
-       int ret = -EIO;
-       unsigned int len;
-
-       im = &idmap->idmap_im;
+       struct idmap *idmap = (struct idmap *)aux;
+       struct key *key = cons->key;
+       int ret;
 
-       mutex_lock(&idmap->idmap_lock);
-       mutex_lock(&idmap->idmap_im_lock);
+       /* msg and im are freed in idmap_pipe_destroy_msg */
+       msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+       if (IS_ERR(msg)) {
+               ret = PTR_ERR(msg);
+               goto out0;
+       }
 
-       he = idmap_lookup_id(h, id);
-       if (he) {
-               memcpy(name, he->ih_name, he->ih_namelen);
-               ret = he->ih_namelen;
-               goto out;
+       im = kmalloc(sizeof(*im), GFP_KERNEL);
+       if (IS_ERR(im)) {
+               ret = PTR_ERR(im);
+               goto out1;
        }
 
-       memset(im, 0, sizeof(*im));
-       im->im_type = h->h_type;
-       im->im_conv = IDMAP_CONV_IDTONAME;
-       im->im_id = id;
+       ret = nfs_idmap_prepare_message(key->description, im, msg);
+       if (ret < 0)
+               goto out2;
 
-       memset(&msg, 0, sizeof(msg));
-       msg.data = im;
-       msg.len = sizeof(*im);
+       idmap->idmap_key_cons = cons;
 
-       add_wait_queue(&idmap->idmap_wq, &wq);
+       ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
+       if (ret < 0)
+               goto out2;
 
-       if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
-               remove_wait_queue(&idmap->idmap_wq, &wq);
-               goto out;
-       }
+       return ret;
+
+out2:
+       kfree(im);
+out1:
+       kfree(msg);
+out0:
+       key_revoke(cons->key);
+       key_revoke(cons->authkey);
+       return ret;
+}
+
+static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data)
+{
+       return key_instantiate_and_link(key, data, strlen(data) + 1,
+                                       id_resolver_cache->thread_keyring,
+                                       authkey);
+}
 
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       mutex_unlock(&idmap->idmap_im_lock);
-       schedule();
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&idmap->idmap_wq, &wq);
-       mutex_lock(&idmap->idmap_im_lock);
-
-       if (im->im_status & IDMAP_STATUS_SUCCESS) {
-               if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0)
-                       goto out;
-               memcpy(name, im->im_name, len);
-               ret = len;
+static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey)
+{
+       char id_str[NFS_UINT_MAXLEN];
+       int ret = -EINVAL;
+
+       switch (im->im_conv) {
+       case IDMAP_CONV_NAMETOID:
+               sprintf(id_str, "%d", im->im_id);
+               ret = nfs_idmap_instantiate(key, authkey, id_str);
+               break;
+       case IDMAP_CONV_IDTONAME:
+               ret = nfs_idmap_instantiate(key, authkey, im->im_name);
+               break;
        }
 
- out:
-       memset(im, 0, sizeof(*im));
-       mutex_unlock(&idmap->idmap_im_lock);
-       mutex_unlock(&idmap->idmap_lock);
        return ret;
 }
 
@@ -682,115 +703,51 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 {
        struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
        struct idmap *idmap = (struct idmap *)rpci->private;
-       struct idmap_msg im_in, *im = &idmap->idmap_im;
-       struct idmap_hashtable *h;
-       struct idmap_hashent *he = NULL;
+       struct key_construction *cons = idmap->idmap_key_cons;
+       struct idmap_msg im;
        size_t namelen_in;
        int ret;
 
-       if (mlen != sizeof(im_in))
-               return -ENOSPC;
-
-       if (copy_from_user(&im_in, src, mlen) != 0)
-               return -EFAULT;
-
-       mutex_lock(&idmap->idmap_im_lock);
-
-       ret = mlen;
-       im->im_status = im_in.im_status;
-       /* If we got an error, terminate now, and wake up pending upcalls */
-       if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) {
-               wake_up(&idmap->idmap_wq);
+       if (mlen != sizeof(im)) {
+               ret = -ENOSPC;
                goto out;
        }
 
-       /* Sanity checking of strings */
-       ret = -EINVAL;
-       namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ);
-       if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ)
+       if (copy_from_user(&im, src, mlen) != 0) {
+               ret = -EFAULT;
                goto out;
+       }
 
-       switch (im_in.im_type) {
-               case IDMAP_TYPE_USER:
-                       h = &idmap->idmap_user_hash;
-                       break;
-               case IDMAP_TYPE_GROUP:
-                       h = &idmap->idmap_group_hash;
-                       break;
-               default:
-                       goto out;
+       if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
+               ret = mlen;
+               complete_request_key(idmap->idmap_key_cons, -ENOKEY);
+               goto out_incomplete;
        }
 
-       switch (im_in.im_conv) {
-       case IDMAP_CONV_IDTONAME:
-               /* Did we match the current upcall? */
-               if (im->im_conv == IDMAP_CONV_IDTONAME
-                               && im->im_type == im_in.im_type
-                               && im->im_id == im_in.im_id) {
-                       /* Yes: copy string, including the terminating '\0'  */
-                       memcpy(im->im_name, im_in.im_name, namelen_in);
-                       im->im_name[namelen_in] = '\0';
-                       wake_up(&idmap->idmap_wq);
-               }
-               he = idmap_alloc_id(h, im_in.im_id);
-               break;
-       case IDMAP_CONV_NAMETOID:
-               /* Did we match the current upcall? */
-               if (im->im_conv == IDMAP_CONV_NAMETOID
-                               && im->im_type == im_in.im_type
-                               && strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in
-                               && memcmp(im->im_name, im_in.im_name, namelen_in) == 0) {
-                       im->im_id = im_in.im_id;
-                       wake_up(&idmap->idmap_wq);
-               }
-               he = idmap_alloc_name(h, im_in.im_name, namelen_in);
-               break;
-       default:
+       namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
+       if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) {
+               ret = -EINVAL;
                goto out;
        }
 
-       /* If the entry is valid, also copy it to the cache */
-       if (he != NULL)
-               idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id);
-       ret = mlen;
+       ret = nfs_idmap_read_message(&im, cons->key, cons->authkey);
+       if (ret >= 0) {
+               key_set_timeout(cons->key, nfs_idmap_cache_timeout);
+               ret = mlen;
+       }
+
 out:
-       mutex_unlock(&idmap->idmap_im_lock);
+       complete_request_key(idmap->idmap_key_cons, ret);
+out_incomplete:
        return ret;
 }
 
 static void
 idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 {
-       struct idmap_msg *im = msg->data;
-       struct idmap *idmap = container_of(im, struct idmap, idmap_im); 
-
-       if (msg->errno >= 0)
-               return;
-       mutex_lock(&idmap->idmap_im_lock);
-       im->im_status = IDMAP_STATUS_LOOKUPFAIL;
-       wake_up(&idmap->idmap_wq);
-       mutex_unlock(&idmap->idmap_im_lock);
-}
-
-/* 
- * Fowler/Noll/Vo hash
- *    http://www.isthe.com/chongo/tech/comp/fnv/
- */
-
-#define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
-#define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
-
-static unsigned int fnvhash32(const void *buf, size_t buflen)
-{
-       const unsigned char *p, *end = (const unsigned char *)buf + buflen;
-       unsigned int hash = FNV_1_32;
-
-       for (p = buf; p < end; p++) {
-               hash *= FNV_P_32;
-               hash ^= (unsigned int)*p;
-       }
-
-       return hash;
+       /* Free memory allocated in nfs_idmap_legacy_upcall() */
+       kfree(msg->data);
+       kfree(msg);
 }
 
 int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
@@ -799,16 +756,16 @@ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_
 
        if (nfs_map_string_to_numeric(name, namelen, uid))
                return 0;
-       return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
+       return nfs_idmap_lookup_id(name, namelen, "uid", uid, idmap);
 }
 
-int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
+int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
 {
        struct idmap *idmap = server->nfs_client->cl_idmap;
 
-       if (nfs_map_string_to_numeric(name, namelen, uid))
+       if (nfs_map_string_to_numeric(name, namelen, gid))
                return 0;
-       return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
+       return nfs_idmap_lookup_id(name, namelen, "gid", gid, idmap);
 }
 
 int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
@@ -817,21 +774,19 @@ int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, s
        int ret = -EINVAL;
 
        if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
-               ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
+               ret = nfs_idmap_lookup_name(uid, "user", buf, buflen, idmap);
        if (ret < 0)
                ret = nfs_map_numeric_to_string(uid, buf, buflen);
        return ret;
 }
-int nfs_map_gid_to_group(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
+int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
 {
        struct idmap *idmap = server->nfs_client->cl_idmap;
        int ret = -EINVAL;
 
        if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
-               ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
+               ret = nfs_idmap_lookup_name(gid, "group", buf, buflen, idmap);
        if (ret < 0)
-               ret = nfs_map_numeric_to_string(uid, buf, buflen);
+               ret = nfs_map_numeric_to_string(gid, buf, buflen);
        return ret;
 }
-
-#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
index c2ce819..e8bbfa5 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/compat.h>
 #include <linux/freezer.h>
+#include <linux/crc32.h>
 
 #include <asm/uaccess.h>
 
@@ -50,6 +51,7 @@
 #include "fscache.h"
 #include "dns_resolve.h"
 #include "pnfs.h"
+#include "netns.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
@@ -387,9 +389,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                unlock_new_inode(inode);
        } else
                nfs_refresh_inode(inode, fattr);
-       dprintk("NFS: nfs_fhget(%s/%Ld ct=%d)\n",
+       dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
                inode->i_sb->s_id,
                (long long)NFS_FILEID(inode),
+               nfs_display_fhandle_hash(fh),
                atomic_read(&inode->i_count));
 
 out:
@@ -400,7 +403,7 @@ out_no_inode:
        goto out;
 }
 
-#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE)
+#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE|ATTR_OPEN)
 
 int
 nfs_setattr(struct dentry *dentry, struct iattr *attr)
@@ -422,7 +425,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
 
        /* Optimization: if the end result is no change, don't RPC */
        attr->ia_valid &= NFS_VALID_ATTRS;
-       if ((attr->ia_valid & ~ATTR_FILE) == 0)
+       if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
                return 0;
 
        /* Write all dirty data */
@@ -1043,6 +1046,67 @@ struct nfs_fh *nfs_alloc_fhandle(void)
        return fh;
 }
 
+#ifdef NFS_DEBUG
+/*
+ * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle
+ *                             in the same way that wireshark does
+ *
+ * @fh: file handle
+ *
+ * For debugging only.
+ */
+u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh)
+{
+       /* wireshark uses 32-bit AUTODIN crc and does a bitwise
+        * not on the result */
+       return ~crc32(0xFFFFFFFF, &fh->data[0], fh->size);
+}
+
+/*
+ * _nfs_display_fhandle - display an NFS file handle on the console
+ *
+ * @fh: file handle to display
+ * @caption: display caption
+ *
+ * For debugging only.
+ */
+void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption)
+{
+       unsigned short i;
+
+       if (fh == NULL || fh->size == 0) {
+               printk(KERN_DEFAULT "%s at %p is empty\n", caption, fh);
+               return;
+       }
+
+       printk(KERN_DEFAULT "%s at %p is %u bytes, crc: 0x%08x:\n",
+              caption, fh, fh->size, _nfs_display_fhandle_hash(fh));
+       for (i = 0; i < fh->size; i += 16) {
+               __be32 *pos = (__be32 *)&fh->data[i];
+
+               switch ((fh->size - i - 1) >> 2) {
+               case 0:
+                       printk(KERN_DEFAULT " %08x\n",
+                               be32_to_cpup(pos));
+                       break;
+               case 1:
+                       printk(KERN_DEFAULT " %08x %08x\n",
+                               be32_to_cpup(pos), be32_to_cpup(pos + 1));
+                       break;
+               case 2:
+                       printk(KERN_DEFAULT " %08x %08x %08x\n",
+                               be32_to_cpup(pos), be32_to_cpup(pos + 1),
+                               be32_to_cpup(pos + 2));
+                       break;
+               default:
+                       printk(KERN_DEFAULT " %08x %08x %08x %08x\n",
+                               be32_to_cpup(pos), be32_to_cpup(pos + 1),
+                               be32_to_cpup(pos + 2), be32_to_cpup(pos + 3));
+               }
+       }
+}
+#endif
+
 /**
  * nfs_inode_attrs_need_update - check if the inode attributes need updating
  * @inode - pointer to inode
@@ -1210,8 +1274,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        unsigned long now = jiffies;
        unsigned long save_cache_validity;
 
-       dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
+       dfprintk(VFS, "NFS: %s(%s/%ld fh_crc=0x%08x ct=%d info=0x%x)\n",
                        __func__, inode->i_sb->s_id, inode->i_ino,
+                       nfs_display_fhandle_hash(NFS_FH(inode)),
                        atomic_read(&inode->i_count), fattr->valid);
 
        if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
@@ -1405,7 +1470,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        /*
         * Big trouble! The inode has become a different object.
         */
-       printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
+       printk(KERN_DEBUG "NFS: %s: inode %ld mode changed, %07o to %07o\n",
                        __func__, inode->i_ino, inode->i_mode, fattr->mode);
  out_err:
        /*
@@ -1494,7 +1559,7 @@ static void init_once(void *foo)
        INIT_LIST_HEAD(&nfsi->open_files);
        INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
        INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
-       INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
+       INIT_LIST_HEAD(&nfsi->commit_list);
        nfsi->npages = 0;
        nfsi->ncommit = 0;
        atomic_set(&nfsi->silly_count, 1);
@@ -1551,6 +1616,28 @@ static void nfsiod_stop(void)
        destroy_workqueue(wq);
 }
 
+int nfs_net_id;
+EXPORT_SYMBOL_GPL(nfs_net_id);
+
+static int nfs_net_init(struct net *net)
+{
+       nfs_clients_init(net);
+       return nfs_dns_resolver_cache_init(net);
+}
+
+static void nfs_net_exit(struct net *net)
+{
+       nfs_dns_resolver_cache_destroy(net);
+       nfs_cleanup_cb_ident_idr(net);
+}
+
+static struct pernet_operations nfs_net_ops = {
+       .init = nfs_net_init,
+       .exit = nfs_net_exit,
+       .id   = &nfs_net_id,
+       .size = sizeof(struct nfs_net),
+};
+
 /*
  * Initialize NFS
  */
@@ -1560,10 +1647,14 @@ static int __init init_nfs_fs(void)
 
        err = nfs_idmap_init();
        if (err < 0)
-               goto out9;
+               goto out10;
 
        err = nfs_dns_resolver_init();
        if (err < 0)
+               goto out9;
+
+       err = register_pernet_subsys(&nfs_net_ops);
+       if (err < 0)
                goto out8;
 
        err = nfs_fscache_register();
@@ -1599,14 +1690,14 @@ static int __init init_nfs_fs(void)
                goto out0;
 
 #ifdef CONFIG_PROC_FS
-       rpc_proc_register(&nfs_rpcstat);
+       rpc_proc_register(&init_net, &nfs_rpcstat);
 #endif
        if ((err = register_nfs_fs()) != 0)
                goto out;
        return 0;
 out:
 #ifdef CONFIG_PROC_FS
-       rpc_proc_unregister("nfs");
+       rpc_proc_unregister(&init_net, "nfs");
 #endif
        nfs_destroy_directcache();
 out0:
@@ -1624,10 +1715,12 @@ out5:
 out6:
        nfs_fscache_unregister();
 out7:
-       nfs_dns_resolver_destroy();
+       unregister_pernet_subsys(&nfs_net_ops);
 out8:
-       nfs_idmap_quit();
+       nfs_dns_resolver_destroy();
 out9:
+       nfs_idmap_quit();
+out10:
        return err;
 }
 
@@ -1639,12 +1732,12 @@ static void __exit exit_nfs_fs(void)
        nfs_destroy_inodecache();
        nfs_destroy_nfspagecache();
        nfs_fscache_unregister();
+       unregister_pernet_subsys(&nfs_net_ops);
        nfs_dns_resolver_destroy();
        nfs_idmap_quit();
 #ifdef CONFIG_PROC_FS
-       rpc_proc_unregister("nfs");
+       rpc_proc_unregister(&init_net, "nfs");
 #endif
-       nfs_cleanup_cb_ident_idr();
        unregister_nfs_fs();
        nfs_fs_proc_exit();
        nfsiod_stop();
index 8102db9..2476dc6 100644 (file)
@@ -123,6 +123,7 @@ struct nfs_parsed_mount_data {
        } nfs_server;
 
        struct security_mnt_opts lsm_opts;
+       struct net              *net;
 };
 
 /* mount_clnt.c */
@@ -137,20 +138,22 @@ struct nfs_mount_request {
        int                     noresvport;
        unsigned int            *auth_flav_len;
        rpc_authflavor_t        *auth_flavs;
+       struct net              *net;
 };
 
 extern int nfs_mount(struct nfs_mount_request *info);
 extern void nfs_umount(const struct nfs_mount_request *info);
 
 /* client.c */
-extern struct rpc_program nfs_program;
+extern const struct rpc_program nfs_program;
+extern void nfs_clients_init(struct net *net);
 
-extern void nfs_cleanup_cb_ident_idr(void);
+extern void nfs_cleanup_cb_ident_idr(struct net *);
 extern void nfs_put_client(struct nfs_client *);
-extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *);
-extern struct nfs_client *nfs4_find_client_ident(int);
+extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
 extern struct nfs_client *
-nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *);
+nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
+                               struct nfs4_sessionid *);
 extern struct nfs_server *nfs_create_server(
                                        const struct nfs_parsed_mount_data *,
                                        struct nfs_fh *);
@@ -329,6 +332,8 @@ void nfs_retry_commit(struct list_head *page_list,
 void nfs_commit_clear_lock(struct nfs_inode *nfsi);
 void nfs_commitdata_release(void *data);
 void nfs_commit_release_pages(struct nfs_write_data *data);
+void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head);
+void nfs_request_remove_commit_list(struct nfs_page *req);
 
 #ifdef CONFIG_MIGRATION
 extern int nfs_migrate_page(struct address_space *,
index d4c2d6b..8e65c7f 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/nfs_fs.h>
 #include "internal.h"
 
-#ifdef RPC_DEBUG
+#ifdef NFS_DEBUG
 # define NFSDBG_FACILITY       NFSDBG_MOUNT
 #endif
 
@@ -67,7 +67,7 @@ enum {
        MOUNTPROC3_EXPORT       = 5,
 };
 
-static struct rpc_program      mnt_program;
+static const struct rpc_program mnt_program;
 
 /*
  * Defined by OpenGroup XNFS Version 3W, chapter 8
@@ -153,7 +153,7 @@ int nfs_mount(struct nfs_mount_request *info)
                .rpc_resp       = &result,
        };
        struct rpc_create_args args = {
-               .net            = &init_net,
+               .net            = info->net,
                .protocol       = info->protocol,
                .address        = info->sap,
                .addrsize       = info->salen,
@@ -225,7 +225,7 @@ void nfs_umount(const struct nfs_mount_request *info)
                .to_retries = 2,
        };
        struct rpc_create_args args = {
-               .net            = &init_net,
+               .net            = info->net,
                .protocol       = IPPROTO_UDP,
                .address        = info->sap,
                .addrsize       = info->salen,
@@ -488,19 +488,19 @@ static struct rpc_procinfo mnt3_procedures[] = {
 };
 
 
-static struct rpc_version mnt_version1 = {
+static const struct rpc_version mnt_version1 = {
        .number         = 1,
        .nrprocs        = ARRAY_SIZE(mnt_procedures),
        .procs          = mnt_procedures,
 };
 
-static struct rpc_version mnt_version3 = {
+static const struct rpc_version mnt_version3 = {
        .number         = 3,
        .nrprocs        = ARRAY_SIZE(mnt3_procedures),
        .procs          = mnt3_procedures,
 };
 
-static struct rpc_version *mnt_version[] = {
+static const struct rpc_version *mnt_version[] = {
        NULL,
        &mnt_version1,
        NULL,
@@ -509,7 +509,7 @@ static struct rpc_version *mnt_version[] = {
 
 static struct rpc_stat mnt_stats;
 
-static struct rpc_program mnt_program = {
+static const struct rpc_program mnt_program = {
        .name           = "mount",
        .number         = NFS_MNT_PROGRAM,
        .nrvers         = ARRAY_SIZE(mnt_version),
index 8102391..1807866 100644 (file)
@@ -276,7 +276,10 @@ out:
        nfs_free_fattr(fattr);
        nfs_free_fhandle(fh);
 out_nofree:
-       dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt);
+       if (IS_ERR(mnt))
+               dprintk("<-- %s(): error %ld\n", __func__, PTR_ERR(mnt));
+       else
+               dprintk("<-- %s() = %p\n", __func__, mnt);
        return mnt;
 }
 
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h
new file mode 100644 (file)
index 0000000..aa14ec3
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __NFS_NETNS_H__
+#define __NFS_NETNS_H__
+
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
+struct bl_dev_msg {
+       int32_t status;
+       uint32_t major, minor;
+};
+
+struct nfs_net {
+       struct cache_detail *nfs_dns_resolve;
+       struct rpc_pipe *bl_device_pipe;
+       struct bl_dev_msg bl_mount_reply;
+       wait_queue_head_t bl_wq;
+       struct list_head nfs_client_list;
+       struct list_head nfs_volume_list;
+#ifdef CONFIG_NFS_V4
+       struct idr cb_ident_idr; /* Protected by nfs_client_lock */
+#endif
+       spinlock_t nfs_client_lock;
+};
+
+extern int nfs_net_id;
+
+#endif
index 792cb13..1f56000 100644 (file)
@@ -1150,7 +1150,7 @@ struct rpc_procinfo       nfs_procedures[] = {
        PROC(STATFS,    fhandle,        statfsres,      0),
 };
 
-struct rpc_version             nfs_version2 = {
+const struct rpc_version nfs_version2 = {
        .number                 = 2,
        .nrprocs                = ARRAY_SIZE(nfs_procedures),
        .procs                  = nfs_procedures
index 7ef2397..e4498dc 100644 (file)
@@ -192,7 +192,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
                .pages = pages,
        };
        struct nfs3_getaclres res = {
-               0
+               NULL,
        };
        struct rpc_message msg = {
                .rpc_argp       = &args,
index 9194395..5242eae 100644 (file)
@@ -428,6 +428,11 @@ nfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
        msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
 }
 
+static void nfs3_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
+{
+       rpc_call_start(task);
+}
+
 static int
 nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
@@ -445,6 +450,11 @@ nfs3_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
        msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME];
 }
 
+static void nfs3_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
+{
+       rpc_call_start(task);
+}
+
 static int
 nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
                      struct inode *new_dir)
@@ -814,6 +824,11 @@ static void nfs3_proc_read_setup(struct nfs_read_data *data, struct rpc_message
        msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ];
 }
 
+static void nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+{
+       rpc_call_start(task);
+}
+
 static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
 {
        if (nfs3_async_handle_jukebox(task, data->inode))
@@ -828,6 +843,11 @@ static void nfs3_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
        msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE];
 }
 
+static void nfs3_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+{
+       rpc_call_start(task);
+}
+
 static int nfs3_commit_done(struct rpc_task *task, struct nfs_write_data *data)
 {
        if (nfs3_async_handle_jukebox(task, data->inode))
@@ -864,9 +884,11 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
        .create         = nfs3_proc_create,
        .remove         = nfs3_proc_remove,
        .unlink_setup   = nfs3_proc_unlink_setup,
+       .unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare,
        .unlink_done    = nfs3_proc_unlink_done,
        .rename         = nfs3_proc_rename,
        .rename_setup   = nfs3_proc_rename_setup,
+       .rename_rpc_prepare = nfs3_proc_rename_rpc_prepare,
        .rename_done    = nfs3_proc_rename_done,
        .link           = nfs3_proc_link,
        .symlink        = nfs3_proc_symlink,
@@ -879,8 +901,10 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
        .pathconf       = nfs3_proc_pathconf,
        .decode_dirent  = nfs3_decode_dirent,
        .read_setup     = nfs3_proc_read_setup,
+       .read_rpc_prepare = nfs3_proc_read_rpc_prepare,
        .read_done      = nfs3_read_done,
        .write_setup    = nfs3_proc_write_setup,
+       .write_rpc_prepare = nfs3_proc_write_rpc_prepare,
        .write_done     = nfs3_write_done,
        .commit_setup   = nfs3_proc_commit_setup,
        .commit_done    = nfs3_commit_done,
index 183c6b1..a77cc9a 100644 (file)
@@ -2461,7 +2461,7 @@ struct rpc_procinfo       nfs3_procedures[] = {
        PROC(COMMIT,            commit,         commit,         5),
 };
 
-struct rpc_version             nfs_version3 = {
+const struct rpc_version nfs_version3 = {
        .number                 = 3,
        .nrprocs                = ARRAY_SIZE(nfs3_procedures),
        .procs                  = nfs3_procedures
@@ -2489,7 +2489,7 @@ static struct rpc_procinfo        nfs3_acl_procedures[] = {
        },
 };
 
-struct rpc_version             nfsacl_version3 = {
+const struct rpc_version nfsacl_version3 = {
        .number                 = 3,
        .nrprocs                = sizeof(nfs3_acl_procedures)/
                                  sizeof(nfs3_acl_procedures[0]),
index 4d7d0ae..97ecc86 100644 (file)
@@ -20,7 +20,6 @@ enum nfs4_client_state {
        NFS4CLNT_RECLAIM_REBOOT,
        NFS4CLNT_RECLAIM_NOGRACE,
        NFS4CLNT_DELEGRETURN,
-       NFS4CLNT_LAYOUTRECALL,
        NFS4CLNT_SESSION_RESET,
        NFS4CLNT_RECALL_SLOT,
        NFS4CLNT_LEASE_CONFIRM,
@@ -44,7 +43,7 @@ struct nfs4_minor_version_ops {
                        struct nfs4_sequence_args *args,
                        struct nfs4_sequence_res *res,
                        int cache_reply);
-       int     (*validate_stateid)(struct nfs_delegation *,
+       bool    (*match_stateid)(const nfs4_stateid *,
                        const nfs4_stateid *);
        int     (*find_root_sec)(struct nfs_server *, struct nfs_fh *,
                        struct nfs_fsinfo *);
@@ -53,26 +52,25 @@ struct nfs4_minor_version_ops {
        const struct nfs4_state_maintenance_ops *state_renewal_ops;
 };
 
-/*
- * struct rpc_sequence ensures that RPC calls are sent in the exact
- * order that they appear on the list.
- */
-struct rpc_sequence {
-       struct rpc_wait_queue   wait;   /* RPC call delay queue */
-       spinlock_t lock;                /* Protects the list */
-       struct list_head list;          /* Defines sequence of RPC calls */
+struct nfs_unique_id {
+       struct rb_node rb_node;
+       __u64 id;
 };
 
 #define NFS_SEQID_CONFIRMED 1
 struct nfs_seqid_counter {
-       struct rpc_sequence *sequence;
+       int owner_id;
        int flags;
        u32 counter;
+       spinlock_t lock;                /* Protects the list */
+       struct list_head list;          /* Defines sequence of RPC calls */
+       struct rpc_wait_queue   wait;   /* RPC call delay queue */
 };
 
 struct nfs_seqid {
        struct nfs_seqid_counter *sequence;
        struct list_head list;
+       struct rpc_task *task;
 };
 
 static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status)
@@ -81,18 +79,12 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status
                seqid->flags |= NFS_SEQID_CONFIRMED;
 }
 
-struct nfs_unique_id {
-       struct rb_node rb_node;
-       __u64 id;
-};
-
 /*
  * NFS4 state_owners and lock_owners are simply labels for ordered
  * sequences of RPC calls. Their sole purpose is to provide once-only
  * semantics by allowing the server to identify replayed requests.
  */
 struct nfs4_state_owner {
-       struct nfs_unique_id so_owner_id;
        struct nfs_server    *so_server;
        struct list_head     so_lru;
        unsigned long        so_expires;
@@ -105,7 +97,6 @@ struct nfs4_state_owner {
        unsigned long        so_flags;
        struct list_head     so_states;
        struct nfs_seqid_counter so_seqid;
-       struct rpc_sequence  so_sequence;
 };
 
 enum {
@@ -146,8 +137,6 @@ struct nfs4_lock_state {
 #define NFS_LOCK_INITIALIZED 1
        int                     ls_flags;
        struct nfs_seqid_counter        ls_seqid;
-       struct rpc_sequence     ls_sequence;
-       struct nfs_unique_id    ls_id;
        nfs4_stateid            ls_stateid;
        atomic_t                ls_count;
        struct nfs4_lock_owner  ls_owner;
@@ -193,6 +182,7 @@ struct nfs4_exception {
        long timeout;
        int retry;
        struct nfs4_state *state;
+       struct inode *inode;
 };
 
 struct nfs4_state_recovery_ops {
@@ -224,7 +214,7 @@ extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, boo
 extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
 extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
                struct nfs4_fs_locations *fs_locations, struct page *page);
-extern void nfs4_release_lockowner(const struct nfs4_lock_state *);
+extern int nfs4_release_lockowner(struct nfs4_lock_state *);
 extern const struct xattr_handler *nfs4_xattr_handlers[];
 
 #if defined(CONFIG_NFS_V4_1)
@@ -233,12 +223,13 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
        return server->nfs_client->cl_session;
 }
 
+extern bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy);
 extern int nfs4_setup_sequence(const struct nfs_server *server,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
-               int cache_reply, struct rpc_task *task);
+               struct rpc_task *task);
 extern int nfs41_setup_sequence(struct nfs4_session *session,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
-               int cache_reply, struct rpc_task *task);
+               struct rpc_task *task);
 extern void nfs4_destroy_session(struct nfs4_session *session);
 extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
 extern int nfs4_proc_create_session(struct nfs_client *);
@@ -269,7 +260,7 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
 
 static inline int nfs4_setup_sequence(const struct nfs_server *server,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
-               int cache_reply, struct rpc_task *task)
+               struct rpc_task *task)
 {
        return 0;
 }
@@ -319,7 +310,7 @@ static inline void nfs4_schedule_session_recovery(struct nfs4_session *session)
 }
 #endif /* CONFIG_NFS_V4_1 */
 
-extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
+extern struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *, gfp_t);
 extern void nfs4_put_state_owner(struct nfs4_state_owner *);
 extern void nfs4_purge_state_owners(struct nfs_server *);
 extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
@@ -327,6 +318,8 @@ extern void nfs4_put_open_state(struct nfs4_state *);
 extern void nfs4_close_state(struct nfs4_state *, fmode_t);
 extern void nfs4_close_sync(struct nfs4_state *, fmode_t);
 extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
+extern void nfs_inode_find_state_and_recover(struct inode *inode,
+               const nfs4_stateid *stateid);
 extern void nfs4_schedule_lease_recovery(struct nfs_client *);
 extern void nfs4_schedule_state_manager(struct nfs_client *);
 extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
@@ -337,7 +330,8 @@ extern void nfs41_handle_server_scope(struct nfs_client *,
                                      struct server_scope **);
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
 extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
-extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t);
+extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *,
+               fmode_t, fl_owner_t, pid_t);
 
 extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
 extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
@@ -346,6 +340,8 @@ extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid);
 extern void nfs_release_seqid(struct nfs_seqid *seqid);
 extern void nfs_free_seqid(struct nfs_seqid *seqid);
 
+extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp);
+
 extern const nfs4_stateid zero_stateid;
 
 /* nfs4xdr.c */
@@ -357,6 +353,16 @@ struct nfs4_mount_data;
 extern struct svc_version nfs4_callback_version1;
 extern struct svc_version nfs4_callback_version4;
 
+static inline void nfs4_stateid_copy(nfs4_stateid *dst, const nfs4_stateid *src)
+{
+       memcpy(dst, src, sizeof(*dst));
+}
+
+static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_stateid *src)
+{
+       return memcmp(dst, src, sizeof(*dst)) == 0;
+}
+
 #else
 
 #define nfs4_close_state(a, b) do { } while (0)
index 71ec086..634c0bc 100644 (file)
 #include <linux/nfs_page.h>
 #include <linux/module.h>
 
+#include <linux/sunrpc/metrics.h>
+
 #include "internal.h"
+#include "delegation.h"
 #include "nfs4filelayout.h"
 
 #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
@@ -84,12 +87,27 @@ static int filelayout_async_handle_error(struct rpc_task *task,
                                         struct nfs_client *clp,
                                         int *reset)
 {
+       struct nfs_server *mds_server = NFS_SERVER(state->inode);
+       struct nfs_client *mds_client = mds_server->nfs_client;
+
        if (task->tk_status >= 0)
                return 0;
-
        *reset = 0;
 
        switch (task->tk_status) {
+       /* MDS state errors */
+       case -NFS4ERR_DELEG_REVOKED:
+       case -NFS4ERR_ADMIN_REVOKED:
+       case -NFS4ERR_BAD_STATEID:
+               nfs_remove_bad_delegation(state->inode);
+       case -NFS4ERR_OPENMODE:
+               nfs4_schedule_stateid_recovery(mds_server, state);
+               goto wait_on_recovery;
+       case -NFS4ERR_EXPIRED:
+               nfs4_schedule_stateid_recovery(mds_server, state);
+               nfs4_schedule_lease_recovery(mds_client);
+               goto wait_on_recovery;
+       /* DS session errors */
        case -NFS4ERR_BADSESSION:
        case -NFS4ERR_BADSLOT:
        case -NFS4ERR_BAD_HIGH_SLOT:
@@ -115,8 +133,14 @@ static int filelayout_async_handle_error(struct rpc_task *task,
                *reset = 1;
                break;
        }
+out:
        task->tk_status = 0;
        return -EAGAIN;
+wait_on_recovery:
+       rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL);
+       if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0)
+               rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task);
+       goto out;
 }
 
 /* NFS_PROTO call done callback routines */
@@ -173,7 +197,7 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
 
        if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
                                &rdata->args.seq_args, &rdata->res.seq_res,
-                               0, task))
+                               task))
                return;
 
        rpc_call_start(task);
@@ -189,10 +213,18 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data)
        rdata->mds_ops->rpc_call_done(task, data);
 }
 
+static void filelayout_read_count_stats(struct rpc_task *task, void *data)
+{
+       struct nfs_read_data *rdata = (struct nfs_read_data *)data;
+
+       rpc_count_iostats(task, NFS_SERVER(rdata->inode)->client->cl_metrics);
+}
+
 static void filelayout_read_release(void *data)
 {
        struct nfs_read_data *rdata = (struct nfs_read_data *)data;
 
+       put_lseg(rdata->lseg);
        rdata->mds_ops->rpc_release(data);
 }
 
@@ -254,7 +286,7 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
 
        if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
                                &wdata->args.seq_args, &wdata->res.seq_res,
-                               0, task))
+                               task))
                return;
 
        rpc_call_start(task);
@@ -268,10 +300,18 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data)
        wdata->mds_ops->rpc_call_done(task, data);
 }
 
+static void filelayout_write_count_stats(struct rpc_task *task, void *data)
+{
+       struct nfs_write_data *wdata = (struct nfs_write_data *)data;
+
+       rpc_count_iostats(task, NFS_SERVER(wdata->inode)->client->cl_metrics);
+}
+
 static void filelayout_write_release(void *data)
 {
        struct nfs_write_data *wdata = (struct nfs_write_data *)data;
 
+       put_lseg(wdata->lseg);
        wdata->mds_ops->rpc_release(data);
 }
 
@@ -282,24 +322,28 @@ static void filelayout_commit_release(void *data)
        nfs_commit_release_pages(wdata);
        if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding))
                nfs_commit_clear_lock(NFS_I(wdata->inode));
+       put_lseg(wdata->lseg);
        nfs_commitdata_release(wdata);
 }
 
-struct rpc_call_ops filelayout_read_call_ops = {
+static const struct rpc_call_ops filelayout_read_call_ops = {
        .rpc_call_prepare = filelayout_read_prepare,
        .rpc_call_done = filelayout_read_call_done,
+       .rpc_count_stats = filelayout_read_count_stats,
        .rpc_release = filelayout_read_release,
 };
 
-struct rpc_call_ops filelayout_write_call_ops = {
+static const struct rpc_call_ops filelayout_write_call_ops = {
        .rpc_call_prepare = filelayout_write_prepare,
        .rpc_call_done = filelayout_write_call_done,
+       .rpc_count_stats = filelayout_write_count_stats,
        .rpc_release = filelayout_write_release,
 };
 
-struct rpc_call_ops filelayout_commit_call_ops = {
+static const struct rpc_call_ops filelayout_commit_call_ops = {
        .rpc_call_prepare = filelayout_write_prepare,
        .rpc_call_done = filelayout_write_call_done,
+       .rpc_count_stats = filelayout_write_count_stats,
        .rpc_release = filelayout_commit_release,
 };
 
@@ -367,7 +411,8 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
        idx = nfs4_fl_calc_ds_index(lseg, j);
        ds = nfs4_fl_prepare_ds(lseg, idx);
        if (!ds) {
-               printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__);
+               printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n",
+                       __func__);
                set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
                set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
                return PNFS_NOT_ATTEMPTED;
@@ -575,7 +620,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo,
                        goto out_err_free;
                fl->fh_array[i]->size = be32_to_cpup(p++);
                if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
-                       printk(KERN_ERR "Too big fh %d received %d\n",
+                       printk(KERN_ERR "NFS: Too big fh %d received %d\n",
                               i, fl->fh_array[i]->size);
                        goto out_err_free;
                }
@@ -640,14 +685,16 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
                int size = (fl->stripe_type == STRIPE_SPARSE) ?
                        fl->dsaddr->ds_num : fl->dsaddr->stripe_count;
 
-               fl->commit_buckets = kcalloc(size, sizeof(struct list_head), gfp_flags);
+               fl->commit_buckets = kcalloc(size, sizeof(struct nfs4_fl_commit_bucket), gfp_flags);
                if (!fl->commit_buckets) {
                        filelayout_free_lseg(&fl->generic_hdr);
                        return NULL;
                }
                fl->number_of_buckets = size;
-               for (i = 0; i < size; i++)
-                       INIT_LIST_HEAD(&fl->commit_buckets[i]);
+               for (i = 0; i < size; i++) {
+                       INIT_LIST_HEAD(&fl->commit_buckets[i].written);
+                       INIT_LIST_HEAD(&fl->commit_buckets[i].committing);
+               }
        }
        return &fl->generic_hdr;
 }
@@ -679,7 +726,7 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
        return (p_stripe == r_stripe);
 }
 
-void
+static void
 filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
                        struct nfs_page *req)
 {
@@ -696,7 +743,7 @@ filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
                nfs_pageio_reset_read_mds(pgio);
 }
 
-void
+static void
 filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
                         struct nfs_page *req)
 {
@@ -725,11 +772,6 @@ static const struct nfs_pageio_ops filelayout_pg_write_ops = {
        .pg_doio = pnfs_generic_pg_writepages,
 };
 
-static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg)
-{
-       return !FILELAYOUT_LSEG(lseg)->commit_through_mds;
-}
-
 static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
 {
        if (fl->stripe_type == STRIPE_SPARSE)
@@ -738,13 +780,49 @@ static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
                return j;
 }
 
-struct list_head *filelayout_choose_commit_list(struct nfs_page *req)
+/* The generic layer is about to remove the req from the commit list.
+ * If this will make the bucket empty, it will need to put the lseg reference.
+ */
+static void
+filelayout_clear_request_commit(struct nfs_page *req)
+{
+       struct pnfs_layout_segment *freeme = NULL;
+       struct inode *inode = req->wb_context->dentry->d_inode;
+
+       spin_lock(&inode->i_lock);
+       if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
+               goto out;
+       if (list_is_singular(&req->wb_list)) {
+               struct inode *inode = req->wb_context->dentry->d_inode;
+               struct pnfs_layout_segment *lseg;
+
+               /* From here we can find the bucket, but for the moment,
+                * since there is only one relevant lseg...
+                */
+               list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
+                       if (lseg->pls_range.iomode == IOMODE_RW) {
+                               freeme = lseg;
+                               break;
+                       }
+               }
+       }
+out:
+       nfs_request_remove_commit_list(req);
+       spin_unlock(&inode->i_lock);
+       put_lseg(freeme);
+}
+
+static struct list_head *
+filelayout_choose_commit_list(struct nfs_page *req,
+                             struct pnfs_layout_segment *lseg)
 {
-       struct pnfs_layout_segment *lseg = req->wb_commit_lseg;
        struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
        u32 i, j;
        struct list_head *list;
 
+       if (fl->commit_through_mds)
+               return &NFS_I(req->wb_context->dentry->d_inode)->commit_list;
+
        /* Note that we are calling nfs4_fl_calc_j_index on each page
         * that ends up being committed to a data server.  An attractive
         * alternative is to add a field to nfs_write_data and nfs_page
@@ -754,14 +832,30 @@ struct list_head *filelayout_choose_commit_list(struct nfs_page *req)
        j = nfs4_fl_calc_j_index(lseg,
                                 (loff_t)req->wb_index << PAGE_CACHE_SHIFT);
        i = select_bucket_index(fl, j);
-       list = &fl->commit_buckets[i];
+       list = &fl->commit_buckets[i].written;
        if (list_empty(list)) {
-               /* Non-empty buckets hold a reference on the lseg */
+               /* Non-empty buckets hold a reference on the lseg.  That ref
+                * is normally transferred to the COMMIT call and released
+                * there.  It could also be released if the last req is pulled
+                * off due to a rewrite, in which case it will be done in
+                * filelayout_remove_commit_req
+                */
                get_lseg(lseg);
        }
+       set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
        return list;
 }
 
+static void
+filelayout_mark_request_commit(struct nfs_page *req,
+               struct pnfs_layout_segment *lseg)
+{
+       struct list_head *list;
+
+       list = filelayout_choose_commit_list(req, lseg);
+       nfs_request_add_commit_list(req, list);
+}
+
 static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
 {
        struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
@@ -797,11 +891,12 @@ static int filelayout_initiate_commit(struct nfs_write_data *data, int how)
        idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
        ds = nfs4_fl_prepare_ds(lseg, idx);
        if (!ds) {
-               printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__);
+               printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n",
+                       __func__);
                set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
                set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
                prepare_to_resend_writes(data);
-               data->mds_ops->rpc_release(data);
+               filelayout_commit_release(data);
                return -EAGAIN;
        }
        dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how);
@@ -817,24 +912,87 @@ static int filelayout_initiate_commit(struct nfs_write_data *data, int how)
 /*
  * This is only useful while we are using whole file layouts.
  */
-static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
+static struct pnfs_layout_segment *
+find_only_write_lseg_locked(struct inode *inode)
 {
-       struct pnfs_layout_segment *lseg, *rv = NULL;
+       struct pnfs_layout_segment *lseg;
 
-       spin_lock(&inode->i_lock);
        list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
                if (lseg->pls_range.iomode == IOMODE_RW)
-                       rv = get_lseg(lseg);
+                       return lseg;
+       return NULL;
+}
+
+static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
+{
+       struct pnfs_layout_segment *rv;
+
+       spin_lock(&inode->i_lock);
+       rv = find_only_write_lseg_locked(inode);
+       if (rv)
+               get_lseg(rv);
        spin_unlock(&inode->i_lock);
        return rv;
 }
 
-static int alloc_ds_commits(struct inode *inode, struct list_head *list)
+static int
+filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max,
+               spinlock_t *lock)
+{
+       struct list_head *src = &bucket->written;
+       struct list_head *dst = &bucket->committing;
+       struct nfs_page *req, *tmp;
+       int ret = 0;
+
+       list_for_each_entry_safe(req, tmp, src, wb_list) {
+               if (!nfs_lock_request(req))
+                       continue;
+               if (cond_resched_lock(lock))
+                       list_safe_reset_next(req, tmp, wb_list);
+               nfs_request_remove_commit_list(req);
+               clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);
+               nfs_list_add_request(req, dst);
+               ret++;
+               if (ret == max)
+                       break;
+       }
+       return ret;
+}
+
+/* Move reqs from written to committing lists, returning count of number moved.
+ * Note called with i_lock held.
+ */
+static int filelayout_scan_commit_lists(struct inode *inode, int max,
+               spinlock_t *lock)
+{
+       struct pnfs_layout_segment *lseg;
+       struct nfs4_filelayout_segment *fl;
+       int i, rv = 0, cnt;
+
+       lseg = find_only_write_lseg_locked(inode);
+       if (!lseg)
+               goto out_done;
+       fl = FILELAYOUT_LSEG(lseg);
+       if (fl->commit_through_mds)
+               goto out_done;
+       for (i = 0; i < fl->number_of_buckets && max != 0; i++) {
+               cnt = filelayout_scan_ds_commit_list(&fl->commit_buckets[i],
+                               max, lock);
+               max -= cnt;
+               rv += cnt;
+       }
+out_done:
+       return rv;
+}
+
+static unsigned int
+alloc_ds_commits(struct inode *inode, struct list_head *list)
 {
        struct pnfs_layout_segment *lseg;
        struct nfs4_filelayout_segment *fl;
        struct nfs_write_data *data;
        int i, j;
+       unsigned int nreq = 0;
 
        /* Won't need this when non-whole file layout segments are supported
         * instead we will use a pnfs_layout_hdr structure */
@@ -843,28 +1001,27 @@ static int alloc_ds_commits(struct inode *inode, struct list_head *list)
                return 0;
        fl = FILELAYOUT_LSEG(lseg);
        for (i = 0; i < fl->number_of_buckets; i++) {
-               if (list_empty(&fl->commit_buckets[i]))
+               if (list_empty(&fl->commit_buckets[i].committing))
                        continue;
                data = nfs_commitdata_alloc();
                if (!data)
-                       goto out_bad;
+                       break;
                data->ds_commit_index = i;
                data->lseg = lseg;
                list_add(&data->pages, list);
+               nreq++;
        }
-       put_lseg(lseg);
-       return 0;
 
-out_bad:
+       /* Clean up on error */
        for (j = i; j < fl->number_of_buckets; j++) {
-               if (list_empty(&fl->commit_buckets[i]))
+               if (list_empty(&fl->commit_buckets[i].committing))
                        continue;
-               nfs_retry_commit(&fl->commit_buckets[i], lseg);
+               nfs_retry_commit(&fl->commit_buckets[i].committing, lseg);
                put_lseg(lseg);  /* associated with emptying bucket */
        }
        put_lseg(lseg);
        /* Caller will clean up entries put on list */
-       return -ENOMEM;
+       return nreq;
 }
 
 /* This follows nfs_commit_list pretty closely */
@@ -874,40 +1031,40 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
 {
        struct nfs_write_data   *data, *tmp;
        LIST_HEAD(list);
+       unsigned int nreq = 0;
 
        if (!list_empty(mds_pages)) {
                data = nfs_commitdata_alloc();
-               if (!data)
-                       goto out_bad;
-               data->lseg = NULL;
-               list_add(&data->pages, &list);
+               if (data != NULL) {
+                       data->lseg = NULL;
+                       list_add(&data->pages, &list);
+                       nreq++;
+               } else
+                       nfs_retry_commit(mds_pages, NULL);
        }
 
-       if (alloc_ds_commits(inode, &list))
-               goto out_bad;
+       nreq += alloc_ds_commits(inode, &list);
+
+       if (nreq == 0) {
+               nfs_commit_clear_lock(NFS_I(inode));
+               goto out;
+       }
+
+       atomic_add(nreq, &NFS_I(inode)->commits_outstanding);
 
        list_for_each_entry_safe(data, tmp, &list, pages) {
                list_del_init(&data->pages);
-               atomic_inc(&NFS_I(inode)->commits_outstanding);
                if (!data->lseg) {
                        nfs_init_commit(data, mds_pages, NULL);
                        nfs_initiate_commit(data, NFS_CLIENT(inode),
                                            data->mds_ops, how);
                } else {
-                       nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index], data->lseg);
+                       nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index].committing, data->lseg);
                        filelayout_initiate_commit(data, how);
                }
        }
-       return 0;
- out_bad:
-       list_for_each_entry_safe(data, tmp, &list, pages) {
-               nfs_retry_commit(&data->pages, data->lseg);
-               list_del_init(&data->pages);
-               nfs_commit_free(data);
-       }
-       nfs_retry_commit(mds_pages, NULL);
-       nfs_commit_clear_lock(NFS_I(inode));
-       return -ENOMEM;
+out:
+       return PNFS_ATTEMPTED;
 }
 
 static void
@@ -924,8 +1081,9 @@ static struct pnfs_layoutdriver_type filelayout_type = {
        .free_lseg              = filelayout_free_lseg,
        .pg_read_ops            = &filelayout_pg_read_ops,
        .pg_write_ops           = &filelayout_pg_write_ops,
-       .mark_pnfs_commit       = filelayout_mark_pnfs_commit,
-       .choose_commit_list     = filelayout_choose_commit_list,
+       .mark_request_commit    = filelayout_mark_request_commit,
+       .clear_request_commit   = filelayout_clear_request_commit,
+       .scan_commit_lists      = filelayout_scan_commit_lists,
        .commit_pagelist        = filelayout_commit_pagelist,
        .read_pagelist          = filelayout_read_pagelist,
        .write_pagelist         = filelayout_write_pagelist,
index 2e42284..21190bb 100644 (file)
@@ -74,6 +74,11 @@ struct nfs4_file_layout_dsaddr {
        struct nfs4_pnfs_ds             *ds_list[1];
 };
 
+struct nfs4_fl_commit_bucket {
+       struct list_head written;
+       struct list_head committing;
+};
+
 struct nfs4_filelayout_segment {
        struct pnfs_layout_segment generic_hdr;
        u32 stripe_type;
@@ -84,7 +89,7 @@ struct nfs4_filelayout_segment {
        struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */
        unsigned int num_fh;
        struct nfs_fh **fh_array;
-       struct list_head *commit_buckets; /* Sort commits to ds */
+       struct nfs4_fl_commit_bucket *commit_buckets; /* Sort commits to ds */
        int number_of_buckets;
 };
 
index 8ae9190..a866bbd 100644 (file)
@@ -45,7 +45,7 @@
  *   - incremented when a device id maps a data server already in the cache.
  *   - decremented when deviceid is removed from the cache.
  */
-DEFINE_SPINLOCK(nfs4_ds_cache_lock);
+static DEFINE_SPINLOCK(nfs4_ds_cache_lock);
 static LIST_HEAD(nfs4_data_server_cache);
 
 /* Debug routines */
@@ -108,58 +108,40 @@ same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
        return false;
 }
 
-/*
- * Lookup DS by addresses.  The first matching address returns true.
- * nfs4_ds_cache_lock is held
- */
-static struct nfs4_pnfs_ds *
-_data_server_lookup_locked(struct list_head *dsaddrs)
+static bool
+_same_data_server_addrs_locked(const struct list_head *dsaddrs1,
+                              const struct list_head *dsaddrs2)
 {
-       struct nfs4_pnfs_ds *ds;
        struct nfs4_pnfs_ds_addr *da1, *da2;
 
-       list_for_each_entry(da1, dsaddrs, da_node) {
-               list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) {
-                       list_for_each_entry(da2, &ds->ds_addrs, da_node) {
-                               if (same_sockaddr(
-                                       (struct sockaddr *)&da1->da_addr,
-                                       (struct sockaddr *)&da2->da_addr))
-                                       return ds;
-                       }
-               }
+       /* step through both lists, comparing as we go */
+       for (da1 = list_first_entry(dsaddrs1, typeof(*da1), da_node),
+            da2 = list_first_entry(dsaddrs2, typeof(*da2), da_node);
+            da1 != NULL && da2 != NULL;
+            da1 = list_entry(da1->da_node.next, typeof(*da1), da_node),
+            da2 = list_entry(da2->da_node.next, typeof(*da2), da_node)) {
+               if (!same_sockaddr((struct sockaddr *)&da1->da_addr,
+                                  (struct sockaddr *)&da2->da_addr))
+                       return false;
        }
-       return NULL;
+       if (da1 == NULL && da2 == NULL)
+               return true;
+
+       return false;
 }
 
 /*
- * Compare two lists of addresses.
+ * Lookup DS by addresses.  nfs4_ds_cache_lock is held
  */
-static bool
-_data_server_match_all_addrs_locked(struct list_head *dsaddrs1,
-                                   struct list_head *dsaddrs2)
+static struct nfs4_pnfs_ds *
+_data_server_lookup_locked(const struct list_head *dsaddrs)
 {
-       struct nfs4_pnfs_ds_addr *da1, *da2;
-       size_t count1 = 0,
-              count2 = 0;
-
-       list_for_each_entry(da1, dsaddrs1, da_node)
-               count1++;
-
-       list_for_each_entry(da2, dsaddrs2, da_node) {
-               bool found = false;
-               count2++;
-               list_for_each_entry(da1, dsaddrs1, da_node) {
-                       if (same_sockaddr((struct sockaddr *)&da1->da_addr,
-                               (struct sockaddr *)&da2->da_addr)) {
-                               found = true;
-                               break;
-                       }
-               }
-               if (!found)
-                       return false;
-       }
+       struct nfs4_pnfs_ds *ds;
 
-       return (count1 == count2);
+       list_for_each_entry(ds, &nfs4_data_server_cache, ds_node)
+               if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
+                       return ds;
+       return NULL;
 }
 
 /*
@@ -356,11 +338,6 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
                dprintk("%s add new data server %s\n", __func__,
                        ds->ds_remotestr);
        } else {
-               if (!_data_server_match_all_addrs_locked(&tmp_ds->ds_addrs,
-                                                        dsaddrs)) {
-                       dprintk("%s:  multipath address mismatch: %s != %s",
-                               __func__, tmp_ds->ds_remotestr, remotestr);
-               }
                kfree(remotestr);
                kfree(ds);
                atomic_inc(&tmp_ds->ds_count);
@@ -378,7 +355,7 @@ out:
  * Currently only supports ipv4, ipv6 and one multi-path address.
  */
 static struct nfs4_pnfs_ds_addr *
-decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags)
+decode_ds_addr(struct net *net, struct xdr_stream *streamp, gfp_t gfp_flags)
 {
        struct nfs4_pnfs_ds_addr *da = NULL;
        char *buf, *portstr;
@@ -457,7 +434,7 @@ decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags)
 
        INIT_LIST_HEAD(&da->da_node);
 
-       if (!rpc_pton(buf, portstr-buf, (struct sockaddr *)&da->da_addr,
+       if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr,
                      sizeof(da->da_addr))) {
                dprintk("%s: error parsing address %s\n", __func__, buf);
                goto out_free_da;
@@ -554,7 +531,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
        cnt = be32_to_cpup(p);
        dprintk("%s stripe count  %d\n", __func__, cnt);
        if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
-               printk(KERN_WARNING "%s: stripe count %d greater than "
+               printk(KERN_WARNING "NFS: %s: stripe count %d greater than "
                       "supported maximum %d\n", __func__,
                        cnt, NFS4_PNFS_MAX_STRIPE_CNT);
                goto out_err_free_scratch;
@@ -585,7 +562,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
        num = be32_to_cpup(p);
        dprintk("%s ds_num %u\n", __func__, num);
        if (num > NFS4_PNFS_MAX_MULTI_CNT) {
-               printk(KERN_WARNING "%s: multipath count %d greater than "
+               printk(KERN_WARNING "NFS: %s: multipath count %d greater than "
                        "supported maximum %d\n", __func__,
                        num, NFS4_PNFS_MAX_MULTI_CNT);
                goto out_err_free_stripe_indices;
@@ -593,7 +570,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
 
        /* validate stripe indices are all < num */
        if (max_stripe_index >= num) {
-               printk(KERN_WARNING "%s: stripe index %u >= num ds %u\n",
+               printk(KERN_WARNING "NFS: %s: stripe index %u >= num ds %u\n",
                        __func__, max_stripe_index, num);
                goto out_err_free_stripe_indices;
        }
@@ -625,7 +602,8 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
 
                mp_count = be32_to_cpup(p); /* multipath count */
                for (j = 0; j < mp_count; j++) {
-                       da = decode_ds_addr(&stream, gfp_flags);
+                       da = decode_ds_addr(NFS_SERVER(ino)->nfs_client->net,
+                                           &stream, gfp_flags);
                        if (da)
                                list_add_tail(&da->da_node, &dsaddrs);
                }
@@ -686,7 +664,7 @@ decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_fl
 
        new = decode_device(inode, dev, gfp_flags);
        if (!new) {
-               printk(KERN_WARNING "%s: Could not decode or add device\n",
+               printk(KERN_WARNING "NFS: %s: Could not decode or add device\n",
                        __func__);
                return NULL;
        }
@@ -835,7 +813,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
        struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
 
        if (ds == NULL) {
-               printk(KERN_ERR "%s: No data server for offset index %d\n",
+               printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
                        __func__, ds_idx);
                return NULL;
        }
index bb80c49..9c8eca3 100644 (file)
@@ -94,13 +94,14 @@ static int nfs4_validate_fspath(struct dentry *dentry,
 }
 
 static size_t nfs_parse_server_name(char *string, size_t len,
-               struct sockaddr *sa, size_t salen)
+               struct sockaddr *sa, size_t salen, struct nfs_server *server)
 {
+       struct net *net = rpc_net_ns(server->client);
        ssize_t ret;
 
-       ret = rpc_pton(string, len, sa, salen);
+       ret = rpc_pton(net, string, len, sa, salen);
        if (ret == 0) {
-               ret = nfs_dns_resolve_name(string, len, sa, salen);
+               ret = nfs_dns_resolve_name(net, string, len, sa, salen);
                if (ret < 0)
                        ret = 0;
        }
@@ -137,7 +138,8 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
                        continue;
 
                mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
-                               mountdata->addr, addr_bufsize);
+                               mountdata->addr, addr_bufsize,
+                               NFS_SB(mountdata->sb));
                if (mountdata->addrlen == 0)
                        continue;
 
index caf92d0..e809d23 100644 (file)
 
 #define NFS4_MAX_LOOP_ON_RECOVER (10)
 
+static unsigned short max_session_slots = NFS4_DEF_SLOT_TABLE_SIZE;
+
 struct nfs4_opendata;
 static int _nfs4_proc_open(struct nfs4_opendata *data);
 static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
 static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
 static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
+static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
 static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
 static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
                            struct nfs_fattr *fattr, struct iattr *sattr,
                            struct nfs4_state *state);
 #ifdef CONFIG_NFS_V4_1
-static int nfs41_test_stateid(struct nfs_server *, struct nfs4_state *);
-static int nfs41_free_stateid(struct nfs_server *, struct nfs4_state *);
+static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *);
+static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *);
 #endif
 /* Prevent leaks of NFSv4 errors into userland */
 static int nfs4_map_errors(int err)
@@ -259,15 +262,28 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
 {
        struct nfs_client *clp = server->nfs_client;
        struct nfs4_state *state = exception->state;
+       struct inode *inode = exception->inode;
        int ret = errorcode;
 
        exception->retry = 0;
        switch(errorcode) {
                case 0:
                        return 0;
+               case -NFS4ERR_OPENMODE:
+                       if (nfs_have_delegation(inode, FMODE_READ)) {
+                               nfs_inode_return_delegation(inode);
+                               exception->retry = 1;
+                               return 0;
+                       }
+                       if (state == NULL)
+                               break;
+                       nfs4_schedule_stateid_recovery(server, state);
+                       goto wait_on_recovery;
+               case -NFS4ERR_DELEG_REVOKED:
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_BAD_STATEID:
-               case -NFS4ERR_OPENMODE:
+                       if (state != NULL)
+                               nfs_remove_bad_delegation(state->inode);
                        if (state == NULL)
                                break;
                        nfs4_schedule_stateid_recovery(server, state);
@@ -360,16 +376,14 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
  * When updating highest_used_slotid there may be "holes" in the bitmap
  * so we need to scan down from highest_used_slotid to 0 looking for the now
  * highest slotid in use.
- * If none found, highest_used_slotid is set to -1.
+ * If none found, highest_used_slotid is set to NFS4_NO_SLOT.
  *
  * Must be called while holding tbl->slot_tbl_lock
  */
 static void
-nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
+nfs4_free_slot(struct nfs4_slot_table *tbl, u32 slotid)
 {
-       int slotid = free_slotid;
-
-       BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE);
+       BUG_ON(slotid >= NFS4_MAX_SLOT_TABLE);
        /* clear used bit in bitmap */
        __clear_bit(slotid, tbl->used_slots);
 
@@ -379,10 +393,16 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
                if (slotid < tbl->max_slots)
                        tbl->highest_used_slotid = slotid;
                else
-                       tbl->highest_used_slotid = -1;
+                       tbl->highest_used_slotid = NFS4_NO_SLOT;
        }
-       dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__,
-               free_slotid, tbl->highest_used_slotid);
+       dprintk("%s: slotid %u highest_used_slotid %d\n", __func__,
+               slotid, tbl->highest_used_slotid);
+}
+
+bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy)
+{
+       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
+       return true;
 }
 
 /*
@@ -390,16 +410,13 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
  */
 static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)
 {
-       struct rpc_task *task;
-
        if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
-               task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq);
-               if (task)
-                       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
+               rpc_wake_up_first(&ses->fc_slot_table.slot_tbl_waitq,
+                               nfs4_set_task_privileged, NULL);
                return;
        }
 
-       if (ses->fc_slot_table.highest_used_slotid != -1)
+       if (ses->fc_slot_table.highest_used_slotid != NFS4_NO_SLOT)
                return;
 
        dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__);
@@ -412,7 +429,7 @@ static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)
 void nfs4_check_drain_bc_complete(struct nfs4_session *ses)
 {
        if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) ||
-           ses->bc_slot_table.highest_used_slotid != -1)
+           ses->bc_slot_table.highest_used_slotid != NFS4_NO_SLOT)
                return;
        dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__);
        complete(&ses->bc_slot_table.complete);
@@ -507,25 +524,25 @@ static int nfs4_sequence_done(struct rpc_task *task,
  * nfs4_find_slot looks for an unset bit in the used_slots bitmap.
  * If found, we mark the slot as used, update the highest_used_slotid,
  * and respectively set up the sequence operation args.
- * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise.
+ * The slot number is returned if found, or NFS4_NO_SLOT otherwise.
  *
  * Note: must be called with under the slot_tbl_lock.
  */
-static u8
+static u32
 nfs4_find_slot(struct nfs4_slot_table *tbl)
 {
-       int slotid;
-       u8 ret_id = NFS4_MAX_SLOT_TABLE;
-       BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE);
+       u32 slotid;
+       u32 ret_id = NFS4_NO_SLOT;
 
-       dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d\n",
+       dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n",
                __func__, tbl->used_slots[0], tbl->highest_used_slotid,
                tbl->max_slots);
        slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots);
        if (slotid >= tbl->max_slots)
                goto out;
        __set_bit(slotid, tbl->used_slots);
-       if (slotid > tbl->highest_used_slotid)
+       if (slotid > tbl->highest_used_slotid ||
+                       tbl->highest_used_slotid == NFS4_NO_SLOT)
                tbl->highest_used_slotid = slotid;
        ret_id = slotid;
 out:
@@ -534,15 +551,25 @@ out:
        return ret_id;
 }
 
+static void nfs41_init_sequence(struct nfs4_sequence_args *args,
+               struct nfs4_sequence_res *res, int cache_reply)
+{
+       args->sa_session = NULL;
+       args->sa_cache_this = 0;
+       if (cache_reply)
+               args->sa_cache_this = 1;
+       res->sr_session = NULL;
+       res->sr_slot = NULL;
+}
+
 int nfs41_setup_sequence(struct nfs4_session *session,
                                struct nfs4_sequence_args *args,
                                struct nfs4_sequence_res *res,
-                               int cache_reply,
                                struct rpc_task *task)
 {
        struct nfs4_slot *slot;
        struct nfs4_slot_table *tbl;
-       u8 slotid;
+       u32 slotid;
 
        dprintk("--> %s\n", __func__);
        /* slot already allocated? */
@@ -570,7 +597,7 @@ int nfs41_setup_sequence(struct nfs4_session *session,
        }
 
        slotid = nfs4_find_slot(tbl);
-       if (slotid == NFS4_MAX_SLOT_TABLE) {
+       if (slotid == NFS4_NO_SLOT) {
                rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
                spin_unlock(&tbl->slot_tbl_lock);
                dprintk("<-- %s: no free slots\n", __func__);
@@ -582,7 +609,6 @@ int nfs41_setup_sequence(struct nfs4_session *session,
        slot = tbl->slots + slotid;
        args->sa_session = session;
        args->sa_slotid = slotid;
-       args->sa_cache_this = cache_reply;
 
        dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr);
 
@@ -602,24 +628,19 @@ EXPORT_SYMBOL_GPL(nfs41_setup_sequence);
 int nfs4_setup_sequence(const struct nfs_server *server,
                        struct nfs4_sequence_args *args,
                        struct nfs4_sequence_res *res,
-                       int cache_reply,
                        struct rpc_task *task)
 {
        struct nfs4_session *session = nfs4_get_session(server);
        int ret = 0;
 
-       if (session == NULL) {
-               args->sa_session = NULL;
-               res->sr_session = NULL;
+       if (session == NULL)
                goto out;
-       }
 
        dprintk("--> %s clp %p session %p sr_slot %td\n",
                __func__, session->clp, session, res->sr_slot ?
                        res->sr_slot - session->fc_slot_table.slots : -1);
 
-       ret = nfs41_setup_sequence(session, args, res, cache_reply,
-                                  task);
+       ret = nfs41_setup_sequence(session, args, res, task);
 out:
        dprintk("<-- %s status=%d\n", __func__, ret);
        return ret;
@@ -629,7 +650,6 @@ struct nfs41_call_sync_data {
        const struct nfs_server *seq_server;
        struct nfs4_sequence_args *seq_args;
        struct nfs4_sequence_res *seq_res;
-       int cache_reply;
 };
 
 static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
@@ -639,7 +659,7 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
        dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
 
        if (nfs4_setup_sequence(data->seq_server, data->seq_args,
-                               data->seq_res, data->cache_reply, task))
+                               data->seq_res, task))
                return;
        rpc_call_start(task);
 }
@@ -657,12 +677,12 @@ static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
        nfs41_sequence_done(task, data->seq_res);
 }
 
-struct rpc_call_ops nfs41_call_sync_ops = {
+static const struct rpc_call_ops nfs41_call_sync_ops = {
        .rpc_call_prepare = nfs41_call_sync_prepare,
        .rpc_call_done = nfs41_call_sync_done,
 };
 
-struct rpc_call_ops nfs41_call_priv_sync_ops = {
+static const struct rpc_call_ops nfs41_call_priv_sync_ops = {
        .rpc_call_prepare = nfs41_call_priv_sync_prepare,
        .rpc_call_done = nfs41_call_sync_done,
 };
@@ -672,7 +692,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                                   struct rpc_message *msg,
                                   struct nfs4_sequence_args *args,
                                   struct nfs4_sequence_res *res,
-                                  int cache_reply,
                                   int privileged)
 {
        int ret;
@@ -681,7 +700,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                .seq_server = server,
                .seq_args = args,
                .seq_res = res,
-               .cache_reply = cache_reply,
        };
        struct rpc_task_setup task_setup = {
                .rpc_client = clnt,
@@ -690,7 +708,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                .callback_data = &data
        };
 
-       res->sr_slot = NULL;
        if (privileged)
                task_setup.callback_ops = &nfs41_call_priv_sync_ops;
        task = rpc_run_task(&task_setup);
@@ -710,10 +727,17 @@ int _nfs4_call_sync_session(struct rpc_clnt *clnt,
                            struct nfs4_sequence_res *res,
                            int cache_reply)
 {
-       return nfs4_call_sync_sequence(clnt, server, msg, args, res, cache_reply, 0);
+       nfs41_init_sequence(args, res, cache_reply);
+       return nfs4_call_sync_sequence(clnt, server, msg, args, res, 0);
 }
 
 #else
+static inline
+void nfs41_init_sequence(struct nfs4_sequence_args *args,
+               struct nfs4_sequence_res *res, int cache_reply)
+{
+}
+
 static int nfs4_sequence_done(struct rpc_task *task,
                               struct nfs4_sequence_res *res)
 {
@@ -728,7 +752,7 @@ int _nfs4_call_sync(struct rpc_clnt *clnt,
                    struct nfs4_sequence_res *res,
                    int cache_reply)
 {
-       args->sa_session = res->sr_session = NULL;
+       nfs41_init_sequence(args, res, cache_reply);
        return rpc_call_sync(clnt, msg, 0);
 }
 
@@ -815,20 +839,22 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        p->o_arg.open_flags = flags;
        p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
        p->o_arg.clientid = server->nfs_client->cl_clientid;
-       p->o_arg.id = sp->so_owner_id.id;
+       p->o_arg.id = sp->so_seqid.owner_id;
        p->o_arg.name = &dentry->d_name;
        p->o_arg.server = server;
        p->o_arg.bitmask = server->attr_bitmask;
        p->o_arg.dir_bitmask = server->cache_consistency_bitmask;
        p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
-       if (flags & O_CREAT) {
-               u32 *s;
+       if (attrs != NULL && attrs->ia_valid != 0) {
+               __be32 verf[2];
 
                p->o_arg.u.attrs = &p->attrs;
                memcpy(&p->attrs, attrs, sizeof(p->attrs));
-               s = (u32 *) p->o_arg.u.verifier.data;
-               s[0] = jiffies;
-               s[1] = current->pid;
+
+               verf[0] = jiffies;
+               verf[1] = current->pid;
+               memcpy(p->o_arg.u.verifier.data, verf,
+                               sizeof(p->o_arg.u.verifier.data));
        }
        p->c_arg.fh = &p->o_res.fh;
        p->c_arg.stateid = &p->o_res.stateid;
@@ -878,7 +904,7 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode
 {
        int ret = 0;
 
-       if (open_mode & O_EXCL)
+       if (open_mode & (O_EXCL|O_TRUNC))
                goto out;
        switch (mode & (FMODE_READ|FMODE_WRITE)) {
                case FMODE_READ:
@@ -927,8 +953,8 @@ static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
 static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
 {
        if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
-               memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data));
-       memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data));
+               nfs4_stateid_copy(&state->stateid, stateid);
+       nfs4_stateid_copy(&state->open_stateid, stateid);
        switch (fmode) {
                case FMODE_READ:
                        set_bit(NFS_O_RDONLY_STATE, &state->flags);
@@ -956,7 +982,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
         */
        write_seqlock(&state->seqlock);
        if (deleg_stateid != NULL) {
-               memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data));
+               nfs4_stateid_copy(&state->stateid, deleg_stateid);
                set_bit(NFS_DELEGATED_STATE, &state->flags);
        }
        if (open_stateid != NULL)
@@ -987,7 +1013,7 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat
 
        if (delegation == NULL)
                delegation = &deleg_cur->stateid;
-       else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0)
+       else if (!nfs4_stateid_match(&deleg_cur->stateid, delegation))
                goto no_delegation_unlock;
 
        nfs_mark_delegation_referenced(deleg_cur);
@@ -1026,7 +1052,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
        struct nfs4_state *state = opendata->state;
        struct nfs_inode *nfsi = NFS_I(state->inode);
        struct nfs_delegation *delegation;
-       int open_mode = opendata->o_arg.open_flags & O_EXCL;
+       int open_mode = opendata->o_arg.open_flags & (O_EXCL|O_TRUNC);
        fmode_t fmode = opendata->o_arg.fmode;
        nfs4_stateid stateid;
        int ret = -EAGAIN;
@@ -1048,7 +1074,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
                        break;
                }
                /* Save the delegation */
-               memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data));
+               nfs4_stateid_copy(&stateid, &delegation->stateid);
                rcu_read_unlock();
                ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
                if (ret != 0)
@@ -1090,6 +1116,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
        if (state == NULL)
                goto err_put_inode;
        if (data->o_res.delegation_type != 0) {
+               struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
                int delegation_flags = 0;
 
                rcu_read_lock();
@@ -1101,7 +1128,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
                        pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
                                        "returning a delegation for "
                                        "OPEN(CLAIM_DELEGATE_CUR)\n",
-                                       NFS_CLIENT(inode)->cl_server);
+                                       clp->cl_hostname);
                } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
                        nfs_inode_set_delegation(state->inode,
                                        data->owner->so_cred,
@@ -1210,10 +1237,10 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
         * Check if we need to update the current stateid.
         */
        if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&
-           memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) {
+           !nfs4_stateid_match(&state->stateid, &state->open_stateid)) {
                write_seqlock(&state->seqlock);
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
-                       memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data));
+                       nfs4_stateid_copy(&state->stateid, &state->open_stateid);
                write_sequnlock(&state->seqlock);
        }
        return 0;
@@ -1282,8 +1309,7 @@ static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs
        if (IS_ERR(opendata))
                return PTR_ERR(opendata);
        opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
-       memcpy(opendata->o_arg.u.delegation.data, stateid->data,
-                       sizeof(opendata->o_arg.u.delegation.data));
+       nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
        ret = nfs4_open_recover(opendata, state);
        nfs4_opendata_put(opendata);
        return ret;
@@ -1319,8 +1345,11 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
                                 * The show must go on: exit, but mark the
                                 * stateid as needing recovery.
                                 */
+                       case -NFS4ERR_DELEG_REVOKED:
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_BAD_STATEID:
+                               nfs_inode_find_state_and_recover(state->inode,
+                                               stateid);
                                nfs4_schedule_stateid_recovery(server, state);
                        case -EKEYEXPIRED:
                                /*
@@ -1345,8 +1374,7 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
 
        data->rpc_status = task->tk_status;
        if (data->rpc_status == 0) {
-               memcpy(data->o_res.stateid.data, data->c_res.stateid.data,
-                               sizeof(data->o_res.stateid.data));
+               nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);
                nfs_confirm_seqid(&data->owner->so_seqid, 0);
                renew_lease(data->o_res.server, data->timestamp);
                data->rpc_done = 1;
@@ -1440,7 +1468,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
                rcu_read_unlock();
        }
        /* Update sequence id. */
-       data->o_arg.id = sp->so_owner_id.id;
+       data->o_arg.id = sp->so_seqid.owner_id;
        data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
        if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
                task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
@@ -1449,7 +1477,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
        data->timestamp = jiffies;
        if (nfs4_setup_sequence(data->o_arg.server,
                                &data->o_arg.seq_args,
-                               &data->o_res.seq_res, 1, task))
+                               &data->o_res.seq_res, task))
                return;
        rpc_call_start(task);
        return;
@@ -1551,6 +1579,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
        };
        int status;
 
+       nfs41_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
        kref_get(&data->kref);
        data->rpc_done = 0;
        data->rpc_status = 0;
@@ -1712,15 +1741,32 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
 }
 
 #if defined(CONFIG_NFS_V4_1)
-static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
+static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *stateid, unsigned int flags)
 {
-       int status;
+       int status = NFS_OK;
        struct nfs_server *server = NFS_SERVER(state->inode);
 
-       status = nfs41_test_stateid(server, state);
-       if (status == NFS_OK)
-               return 0;
-       nfs41_free_stateid(server, state);
+       if (state->flags & flags) {
+               status = nfs41_test_stateid(server, stateid);
+               if (status != NFS_OK) {
+                       nfs41_free_stateid(server, stateid);
+                       state->flags &= ~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);
+
+       if ((deleg_status == NFS_OK) && (open_status == NFS_OK))
+               return NFS_OK;
        return nfs4_open_expired(sp, state);
 }
 #endif
@@ -1754,7 +1800,8 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode
 
        /* Protect against reboot recovery conflicts */
        status = -ENOMEM;
-       if (!(sp = nfs4_get_state_owner(server, cred))) {
+       sp = nfs4_get_state_owner(server, cred, GFP_KERNEL);
+       if (sp == NULL) {
                dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
                goto out_err;
        }
@@ -1829,7 +1876,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry,
                 * the user though...
                 */
                if (status == -NFS4ERR_BAD_SEQID) {
-                       printk(KERN_WARNING "NFS: v4 server %s "
+                       pr_warn_ratelimited("NFS: v4 server %s "
                                        " returned a bad sequence-id error!\n",
                                        NFS_SERVER(dir)->nfs_client->cl_hostname);
                        exception.retry = 1;
@@ -1882,12 +1929,14 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 
        nfs_fattr_init(fattr);
 
-       if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {
+       if (state != NULL) {
+               nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
+                               current->files, current->tgid);
+       } else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
+                               FMODE_WRITE)) {
                /* Use that stateid */
-       } else if (state != NULL) {
-               nfs4_copy_stateid(&arg.stateid, state, current->files, current->tgid);
        } else
-               memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
+               nfs4_stateid_copy(&arg.stateid, &zero_stateid);
 
        status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
        if (status == 0 && state != NULL)
@@ -1900,7 +1949,10 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
                           struct nfs4_state *state)
 {
        struct nfs_server *server = NFS_SERVER(inode);
-       struct nfs4_exception exception = { };
+       struct nfs4_exception exception = {
+               .state = state,
+               .inode = inode,
+       };
        int err;
        do {
                err = nfs4_handle_exception(server,
@@ -1954,6 +2006,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
        struct nfs4_state *state = calldata->state;
        struct nfs_server *server = NFS_SERVER(calldata->inode);
 
+       dprintk("%s: begin!\n", __func__);
        if (!nfs4_sequence_done(task, &calldata->res.seq_res))
                return;
         /* hmm. we are done with the inode, and in the process of freeing
@@ -1981,6 +2034,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
        }
        nfs_release_seqid(calldata->arg.seqid);
        nfs_refresh_inode(calldata->inode, calldata->res.fattr);
+       dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);
 }
 
 static void nfs4_close_prepare(struct rpc_task *task, void *data)
@@ -1989,6 +2043,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        struct nfs4_state *state = calldata->state;
        int call_close = 0;
 
+       dprintk("%s: begin!\n", __func__);
        if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
                return;
 
@@ -2013,7 +2068,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        if (!call_close) {
                /* Note: exit _without_ calling nfs4_close_done */
                task->tk_action = NULL;
-               return;
+               goto out;
        }
 
        if (calldata->arg.fmode == 0) {
@@ -2022,17 +2077,20 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                    pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) {
                        rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq,
                                     task, NULL);
-                       return;
+                       goto out;
                }
        }
 
        nfs_fattr_init(calldata->res.fattr);
        calldata->timestamp = jiffies;
        if (nfs4_setup_sequence(NFS_SERVER(calldata->inode),
-                               &calldata->arg.seq_args, &calldata->res.seq_res,
-                               1, task))
-               return;
+                               &calldata->arg.seq_args,
+                               &calldata->res.seq_res,
+                               task))
+               goto out;
        rpc_call_start(task);
+out:
+       dprintk("%s: done!\n", __func__);
 }
 
 static const struct rpc_call_ops nfs4_close_ops = {
@@ -2074,6 +2132,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
        calldata = kzalloc(sizeof(*calldata), gfp_mask);
        if (calldata == NULL)
                goto out;
+       nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);
        calldata->inode = state->inode;
        calldata->state = state;
        calldata->arg.fh = NFS_FH(state->inode);
@@ -2182,6 +2241,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
                server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
                server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
                server->acl_bitmask = res.acl_bitmask;
+               server->fh_expire_type = res.fh_expire_type;
        }
 
        return status;
@@ -2303,7 +2363,6 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
        return nfs4_map_errors(status);
 }
 
-static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
 /*
  * Get locations and (maybe) other attributes of a referral.
  * Note that we'll actually follow the referral later when
@@ -2420,6 +2479,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
                }
        }
 
+       /* Deal with open(O_TRUNC) */
+       if (sattr->ia_valid & ATTR_OPEN)
+               sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+
        status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
        if (status == 0)
                nfs_setattr_update_inode(inode, sattr);
@@ -2494,7 +2557,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs4_accessargs args = {
                .fh = NFS_FH(inode),
-               .bitmask = server->attr_bitmask,
+               .bitmask = server->cache_consistency_bitmask,
        };
        struct nfs4_accessres res = {
                .server = server,
@@ -2712,8 +2775,18 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 
        args->bitmask = server->cache_consistency_bitmask;
        res->server = server;
-       res->seq_res.sr_slot = NULL;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
+       nfs41_init_sequence(&args->seq_args, &res->seq_res, 1);
+}
+
+static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
+{
+       if (nfs4_setup_sequence(NFS_SERVER(data->dir),
+                               &data->args.seq_args,
+                               &data->res.seq_res,
+                               task))
+               return;
+       rpc_call_start(task);
 }
 
 static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
@@ -2738,6 +2811,17 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
        arg->bitmask = server->attr_bitmask;
        res->server = server;
+       nfs41_init_sequence(&arg->seq_args, &res->seq_res, 1);
+}
+
+static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
+{
+       if (nfs4_setup_sequence(NFS_SERVER(data->old_dir),
+                               &data->args.seq_args,
+                               &data->res.seq_res,
+                               task))
+               return;
+       rpc_call_start(task);
 }
 
 static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
@@ -3232,6 +3316,17 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message
        data->timestamp   = jiffies;
        data->read_done_cb = nfs4_read_done_cb;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
+       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
+}
+
+static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+{
+       if (nfs4_setup_sequence(NFS_SERVER(data->inode),
+                               &data->args.seq_args,
+                               &data->res.seq_res,
+                               task))
+               return;
+       rpc_call_start(task);
 }
 
 /* Reset the the nfs_read_data to send the read to the MDS. */
@@ -3305,6 +3400,17 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
        data->timestamp   = jiffies;
 
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
+       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+}
+
+static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+{
+       if (nfs4_setup_sequence(NFS_SERVER(data->inode),
+                               &data->args.seq_args,
+                               &data->res.seq_res,
+                               task))
+               return;
+       rpc_call_start(task);
 }
 
 static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data)
@@ -3339,6 +3445,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa
                data->write_done_cb = nfs4_commit_done_cb;
        data->res.server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
+       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
 }
 
 struct nfs4_renewdata {
@@ -3714,8 +3821,11 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
        if (task->tk_status >= 0)
                return 0;
        switch(task->tk_status) {
+               case -NFS4ERR_DELEG_REVOKED:
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_BAD_STATEID:
+                       if (state != NULL)
+                               nfs_remove_bad_delegation(state->inode);
                case -NFS4ERR_OPENMODE:
                        if (state == NULL)
                                break;
@@ -3764,6 +3874,16 @@ wait_on_recovery:
        return -EAGAIN;
 }
 
+static void nfs4_construct_boot_verifier(struct nfs_client *clp,
+                                        nfs4_verifier *bootverf)
+{
+       __be32 verf[2];
+
+       verf[0] = htonl((u32)clp->cl_boot_time.tv_sec);
+       verf[1] = htonl((u32)clp->cl_boot_time.tv_nsec);
+       memcpy(bootverf->data, verf, sizeof(bootverf->data));
+}
+
 int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                unsigned short port, struct rpc_cred *cred,
                struct nfs4_setclientid_res *res)
@@ -3780,15 +3900,13 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                .rpc_resp = res,
                .rpc_cred = cred,
        };
-       __be32 *p;
        int loop = 0;
        int status;
 
-       p = (__be32*)sc_verifier.data;
-       *p++ = htonl((u32)clp->cl_boot_time.tv_sec);
-       *p = htonl((u32)clp->cl_boot_time.tv_nsec);
+       nfs4_construct_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,
@@ -3805,6 +3923,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                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)
@@ -3891,7 +4010,7 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
 
        if (nfs4_setup_sequence(d_data->res.server,
                                &d_data->args.seq_args,
-                               &d_data->res.seq_res, 1, task))
+                               &d_data->res.seq_res, task))
                return;
        rpc_call_start(task);
 }
@@ -3925,11 +4044,12 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        data = kzalloc(sizeof(*data), GFP_NOFS);
        if (data == NULL)
                return -ENOMEM;
+       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
        data->args.fhandle = &data->fh;
        data->args.stateid = &data->stateid;
        data->args.bitmask = server->attr_bitmask;
        nfs_copy_fh(&data->fh, NFS_FH(inode));
-       memcpy(&data->stateid, stateid, sizeof(data->stateid));
+       nfs4_stateid_copy(&data->stateid, stateid);
        data->res.fattr = &data->fattr;
        data->res.server = server;
        nfs_fattr_init(data->res.fattr);
@@ -4016,7 +4136,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
        if (status != 0)
                goto out;
        lsp = request->fl_u.nfs4_fl.owner;
-       arg.lock_owner.id = lsp->ls_id.id;
+       arg.lock_owner.id = lsp->ls_seqid.owner_id;
        arg.lock_owner.s_dev = server->s_dev;
        status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
        switch (status) {
@@ -4112,9 +4232,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
                return;
        switch (task->tk_status) {
                case 0:
-                       memcpy(calldata->lsp->ls_stateid.data,
-                                       calldata->res.stateid.data,
-                                       sizeof(calldata->lsp->ls_stateid.data));
+                       nfs4_stateid_copy(&calldata->lsp->ls_stateid,
+                                       &calldata->res.stateid);
                        renew_lease(calldata->server, calldata->timestamp);
                        break;
                case -NFS4ERR_BAD_STATEID:
@@ -4142,7 +4261,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
        calldata->timestamp = jiffies;
        if (nfs4_setup_sequence(calldata->server,
                                &calldata->arg.seq_args,
-                               &calldata->res.seq_res, 1, task))
+                               &calldata->res.seq_res, task))
                return;
        rpc_call_start(task);
 }
@@ -4182,6 +4301,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
                return ERR_PTR(-ENOMEM);
        }
 
+       nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
        msg.rpc_argp = &data->arg;
        msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
@@ -4261,7 +4381,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
                goto out_free_seqid;
        p->arg.lock_stateid = &lsp->ls_stateid;
        p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
-       p->arg.lock_owner.id = lsp->ls_id.id;
+       p->arg.lock_owner.id = lsp->ls_seqid.owner_id;
        p->arg.lock_owner.s_dev = server->s_dev;
        p->res.lock_seqid = p->arg.lock_seqid;
        p->lsp = lsp;
@@ -4297,7 +4417,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
        data->timestamp = jiffies;
        if (nfs4_setup_sequence(data->server,
                                &data->arg.seq_args,
-                               &data->res.seq_res, 1, task))
+                               &data->res.seq_res, task))
                return;
        rpc_call_start(task);
        dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
@@ -4326,8 +4446,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
                        goto out;
        }
        if (data->rpc_status == 0) {
-               memcpy(data->lsp->ls_stateid.data, data->res.stateid.data,
-                                       sizeof(data->lsp->ls_stateid.data));
+               nfs4_stateid_copy(&data->lsp->ls_stateid, &data->res.stateid);
                data->lsp->ls_flags |= NFS_LOCK_INITIALIZED;
                renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
        }
@@ -4415,6 +4534,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                        data->arg.reclaim = NFS_LOCK_RECLAIM;
                task_setup_data.callback_ops = &nfs4_recover_lock_ops;
        }
+       nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
        msg.rpc_argp = &data->arg;
        msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
@@ -4479,15 +4599,34 @@ out:
 }
 
 #if defined(CONFIG_NFS_V4_1)
-static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
+static int nfs41_check_expired_locks(struct nfs4_state *state)
 {
-       int status;
+       int status, ret = NFS_OK;
+       struct nfs4_lock_state *lsp;
        struct nfs_server *server = NFS_SERVER(state->inode);
 
-       status = nfs41_test_stateid(server, state);
+       list_for_each_entry(lsp, &state->lock_states, ls_locks) {
+               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);
+                               lsp->ls_flags &= ~NFS_LOCK_INITIALIZED;
+                               ret = status;
+                       }
+               }
+       };
+
+       return ret;
+}
+
+static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
+{
+       int status = NFS_OK;
+
+       if (test_bit(LK_STATE_IN_USE, &state->flags))
+               status = nfs41_check_expired_locks(state);
        if (status == NFS_OK)
-               return 0;
-       nfs41_free_stateid(server, state);
+               return status;
        return nfs4_lock_expired(state, request);
 }
 #endif
@@ -4523,7 +4662,8 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
        /* Note: we always want to sleep here! */
        request->fl_flags = fl_flags | FL_SLEEP;
        if (do_vfs_lock(request->fl_file, request) < 0)
-               printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__);
+               printk(KERN_WARNING "NFS: %s: VFS is out of sync with lock "
+                       "manager!\n", __func__);
 out_unlock:
        up_read(&nfsi->rwsem);
 out:
@@ -4533,7 +4673,9 @@ out:
 
 static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
-       struct nfs4_exception exception = { };
+       struct nfs4_exception exception = {
+               .state = state,
+       };
        int err;
 
        do {
@@ -4603,8 +4745,8 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
                switch (err) {
                        default:
-                               printk(KERN_ERR "%s: unhandled error %d.\n",
-                                               __func__, err);
+                               printk(KERN_ERR "NFS: %s: unhandled error "
+                                       "%d.\n", __func__, err);
                        case 0:
                        case -ESTALE:
                                goto out;
@@ -4626,6 +4768,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                                 * The show must go on: exit, but mark the
                                 * stateid as needing recovery.
                                 */
+                       case -NFS4ERR_DELEG_REVOKED:
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_BAD_STATEID:
                        case -NFS4ERR_OPENMODE:
@@ -4655,33 +4798,44 @@ out:
        return err;
 }
 
+struct nfs_release_lockowner_data {
+       struct nfs4_lock_state *lsp;
+       struct nfs_server *server;
+       struct nfs_release_lockowner_args args;
+};
+
 static void nfs4_release_lockowner_release(void *calldata)
 {
+       struct nfs_release_lockowner_data *data = calldata;
+       nfs4_free_lock_state(data->server, data->lsp);
        kfree(calldata);
 }
 
-const struct rpc_call_ops nfs4_release_lockowner_ops = {
+static const struct rpc_call_ops nfs4_release_lockowner_ops = {
        .rpc_release = nfs4_release_lockowner_release,
 };
 
-void nfs4_release_lockowner(const struct nfs4_lock_state *lsp)
+int nfs4_release_lockowner(struct nfs4_lock_state *lsp)
 {
        struct nfs_server *server = lsp->ls_state->owner->so_server;
-       struct nfs_release_lockowner_args *args;
+       struct nfs_release_lockowner_data *data;
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
        };
 
        if (server->nfs_client->cl_mvops->minor_version != 0)
-               return;
-       args = kmalloc(sizeof(*args), GFP_NOFS);
-       if (!args)
-               return;
-       args->lock_owner.clientid = server->nfs_client->cl_clientid;
-       args->lock_owner.id = lsp->ls_id.id;
-       args->lock_owner.s_dev = server->s_dev;
-       msg.rpc_argp = args;
-       rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args);
+               return -EINVAL;
+       data = kmalloc(sizeof(*data), GFP_NOFS);
+       if (!data)
+               return -ENOMEM;
+       data->lsp = lsp;
+       data->server = server;
+       data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
+       data->args.lock_owner.id = lsp->ls_seqid.owner_id;
+       data->args.lock_owner.s_dev = server->s_dev;
+       msg.rpc_argp = &data->args;
+       rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
+       return 0;
 }
 
 #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
@@ -4727,11 +4881,11 @@ static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
        if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) ||
               (fattr->valid & NFS_ATTR_FATTR_FILEID)) &&
              (fattr->valid & NFS_ATTR_FATTR_FSID) &&
-             (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)))
+             (fattr->valid & NFS_ATTR_FATTR_V4_LOCATIONS)))
                return;
 
        fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
-               NFS_ATTR_FATTR_NLINK;
+               NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_V4_REFERRAL;
        fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
        fattr->nlink = 2;
 }
@@ -4798,7 +4952,8 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct
        return status;
 }
 
-int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors)
+static int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
+               struct nfs4_secinfo_flavors *flavors)
 {
        struct nfs4_exception exception = { };
        int err;
@@ -4852,6 +5007,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
 {
        nfs4_verifier verifier;
        struct nfs41_exchange_id_args args = {
+               .verifier = &verifier,
                .client = clp,
                .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER,
        };
@@ -4865,15 +5021,11 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
                .rpc_resp = &res,
                .rpc_cred = cred,
        };
-       __be32 *p;
 
        dprintk("--> %s\n", __func__);
        BUG_ON(clp == NULL);
 
-       p = (u32 *)verifier.data;
-       *p++ = htonl((u32)clp->cl_boot_time.tv_sec);
-       *p = htonl((u32)clp->cl_boot_time.tv_nsec);
-       args.verifier = &verifier;
+       nfs4_construct_boot_verifier(clp, &verifier);
 
        args.id_len = scnprintf(args.id, sizeof(args.id),
                                "%s/%s.%s/%u",
@@ -4888,11 +5040,24 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
                goto out;
        }
 
+       res.impl_id = kzalloc(sizeof(struct nfs41_impl_id), GFP_KERNEL);
+       if (unlikely(!res.impl_id)) {
+               status = -ENOMEM;
+               goto out_server_scope;
+       }
+
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        if (!status)
                status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
 
        if (!status) {
+               /* use the most recent implementation id */
+               kfree(clp->impl_id);
+               clp->impl_id = res.impl_id;
+       } else
+               kfree(res.impl_id);
+
+       if (!status) {
                if (clp->server_scope &&
                    !nfs41_same_server_scope(clp->server_scope,
                                             res.server_scope)) {
@@ -4908,8 +5073,16 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
                        goto out;
                }
        }
+
+out_server_scope:
        kfree(res.server_scope);
 out:
+       if (clp->impl_id)
+               dprintk("%s: Server Implementation ID: "
+                       "domain: %s, name: %s, date: %llu,%u\n",
+                       __func__, clp->impl_id->domain, clp->impl_id->name,
+                       clp->impl_id->date.seconds,
+                       clp->impl_id->date.nseconds);
        dprintk("<-- %s status= %d\n", __func__, status);
        return status;
 }
@@ -4933,7 +5106,7 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task,
           since we're invoked within one */
        ret = nfs41_setup_sequence(data->clp->cl_session,
                                   &data->args->la_seq_args,
-                                  &data->res->lr_seq_res, 0, task);
+                                  &data->res->lr_seq_res, task);
 
        BUG_ON(ret == -EAGAIN);
        rpc_call_start(task);
@@ -4966,7 +5139,7 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
        dprintk("<-- %s\n", __func__);
 }
 
-struct rpc_call_ops nfs4_get_lease_time_ops = {
+static const struct rpc_call_ops nfs4_get_lease_time_ops = {
        .rpc_call_prepare = nfs4_get_lease_time_prepare,
        .rpc_call_done = nfs4_get_lease_time_done,
 };
@@ -4997,6 +5170,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
        };
        int status;
 
+       nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
        dprintk("--> %s\n", __func__);
        task = rpc_run_task(&task_setup);
 
@@ -5113,13 +5287,13 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
                return NULL;
 
        tbl = &session->fc_slot_table;
-       tbl->highest_used_slotid = -1;
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
        spin_lock_init(&tbl->slot_tbl_lock);
        rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
        init_completion(&tbl->complete);
 
        tbl = &session->bc_slot_table;
-       tbl->highest_used_slotid = -1;
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
        spin_lock_init(&tbl->slot_tbl_lock);
        rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
        init_completion(&tbl->complete);
@@ -5132,11 +5306,16 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
 
 void nfs4_destroy_session(struct nfs4_session *session)
 {
+       struct rpc_xprt *xprt;
+
        nfs4_proc_destroy_session(session);
+
+       rcu_read_lock();
+       xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt);
+       rcu_read_unlock();
        dprintk("%s Destroy backchannel for xprt %p\n",
-               __func__, session->clp->cl_rpcclient->cl_xprt);
-       xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt,
-                               NFS41_BC_MIN_CALLBACKS);
+               __func__, xprt);
+       xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
        nfs4_destroy_slot_tables(session);
        kfree(session);
 }
@@ -5164,7 +5343,7 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
        args->fc_attrs.max_rqst_sz = mxrqst_sz;
        args->fc_attrs.max_resp_sz = mxresp_sz;
        args->fc_attrs.max_ops = NFS4_MAX_OPS;
-       args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs;
+       args->fc_attrs.max_reqs = max_session_slots;
 
        dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u "
                "max_ops=%u max_reqs=%u\n",
@@ -5204,6 +5383,8 @@ static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args
                return -EINVAL;
        if (rcvd->max_reqs == 0)
                return -EINVAL;
+       if (rcvd->max_reqs > NFS4_MAX_SLOT_TABLE)
+               rcvd->max_reqs = NFS4_MAX_SLOT_TABLE;
        return 0;
 }
 
@@ -5219,9 +5400,9 @@ static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args
        if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
                return -EINVAL;
        /* These would render the backchannel useless: */
-       if (rcvd->max_ops  == 0)
+       if (rcvd->max_ops != sent->max_ops)
                return -EINVAL;
-       if (rcvd->max_reqs == 0)
+       if (rcvd->max_reqs != sent->max_reqs)
                return -EINVAL;
        return 0;
 }
@@ -5324,7 +5505,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session)
 
        if (status)
                printk(KERN_WARNING
-                       "Got error %d from the server on DESTROY_SESSION. "
+                       "NFS: Got error %d from the server on DESTROY_SESSION. "
                        "Session has been destroyed regardless...\n", status);
 
        dprintk("<-- nfs4_proc_destroy_session\n");
@@ -5447,7 +5628,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
        args = task->tk_msg.rpc_argp;
        res = task->tk_msg.rpc_resp;
 
-       if (nfs41_setup_sequence(clp->cl_session, args, res, 0, task))
+       if (nfs41_setup_sequence(clp->cl_session, args, res, task))
                return;
        rpc_call_start(task);
 }
@@ -5479,6 +5660,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_
                nfs_put_client(clp);
                return ERR_PTR(-ENOMEM);
        }
+       nfs41_init_sequence(&calldata->args, &calldata->res, 0);
        msg.rpc_argp = &calldata->args;
        msg.rpc_resp = &calldata->res;
        calldata->clp = clp;
@@ -5540,7 +5722,7 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
        rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
        if (nfs41_setup_sequence(calldata->clp->cl_session,
                                &calldata->arg.seq_args,
-                               &calldata->res.seq_res, 0, task))
+                               &calldata->res.seq_res, task))
                return;
 
        rpc_call_start(task);
@@ -5619,6 +5801,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
        calldata->clp = clp;
        calldata->arg.one_fs = 0;
 
+       nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
        msg.rpc_argp = &calldata->arg;
        msg.rpc_resp = &calldata->res;
        task_setup_data.callback_data = calldata;
@@ -5650,7 +5833,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
         * to be no way to prevent it completely.
         */
        if (nfs4_setup_sequence(server, &lgp->args.seq_args,
-                               &lgp->res.seq_res, 0, task))
+                               &lgp->res.seq_res, task))
                return;
        if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
                                          NFS_I(lgp->args.inode)->layout,
@@ -5725,6 +5908,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
 
        lgp->res.layoutp = &lgp->args.layout;
        lgp->res.seq_res.sr_slot = NULL;
+       nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -5745,7 +5929,7 @@ nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
 
        dprintk("--> %s\n", __func__);
        if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args,
-                               &lrp->res.seq_res, 0, task))
+                               &lrp->res.seq_res, task))
                return;
        rpc_call_start(task);
 }
@@ -5811,6 +5995,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
        int status;
 
        dprintk("--> %s\n", __func__);
+       nfs41_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -5911,7 +6096,7 @@ static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)
        struct nfs_server *server = NFS_SERVER(data->args.inode);
 
        if (nfs4_setup_sequence(server, &data->args.seq_args,
-                               &data->res.seq_res, 1, task))
+                               &data->res.seq_res, task))
                return;
        rpc_call_start(task);
 }
@@ -5998,6 +6183,7 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
                data->args.lastbytewritten,
                data->args.inode->i_ino);
 
+       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -6091,11 +6277,12 @@ out_freepage:
 out:
        return err;
 }
-static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state)
+
+static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
        int status;
        struct nfs41_test_stateid_args args = {
-               .stateid = &state->stateid,
+               .stateid = stateid,
        };
        struct nfs41_test_stateid_res res;
        struct rpc_message msg = {
@@ -6103,28 +6290,31 @@ static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *sta
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       args.seq_args.sa_session = res.seq_res.sr_session = NULL;
-       status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1);
+
+       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;
 }
 
-static int nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state)
+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, state),
+                               _nfs41_test_stateid(server, stateid),
                                &exception);
        } while (exception.retry);
        return err;
 }
 
-static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *state)
+static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 {
-       int status;
        struct nfs41_free_stateid_args args = {
-               .stateid = &state->stateid,
+               .stateid = stateid,
        };
        struct nfs41_free_stateid_res res;
        struct rpc_message msg = {
@@ -6133,25 +6323,46 @@ static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *stat
                .rpc_resp = &res,
        };
 
-       args.seq_args.sa_session = res.seq_res.sr_session = NULL;
-       status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1);
-       return status;
+       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);
 }
 
-static int nfs41_free_stateid(struct nfs_server *server, struct nfs4_state *state)
+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, state),
+                               _nfs4_free_stateid(server, stateid),
                                &exception);
        } while (exception.retry);
        return err;
 }
+
+static bool nfs41_match_stateid(const nfs4_stateid *s1,
+               const nfs4_stateid *s2)
+{
+       if (memcmp(s1->other, s2->other, sizeof(s1->other)) != 0)
+               return false;
+
+       if (s1->seqid == s2->seqid)
+               return true;
+       if (s1->seqid == 0 || s2->seqid == 0)
+               return true;
+
+       return false;
+}
+
 #endif /* CONFIG_NFS_V4_1 */
 
-struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
+static bool nfs4_match_stateid(const nfs4_stateid *s1,
+               const nfs4_stateid *s2)
+{
+       return nfs4_stateid_match(s1, s2);
+}
+
+
+static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
        .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
        .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
        .recover_open   = nfs4_open_reclaim,
@@ -6161,7 +6372,7 @@ struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
 };
 
 #if defined(CONFIG_NFS_V4_1)
-struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
+static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
        .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
        .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
        .recover_open   = nfs4_open_reclaim,
@@ -6172,7 +6383,7 @@ struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
 };
 #endif /* CONFIG_NFS_V4_1 */
 
-struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
+static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
        .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
        .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
        .recover_open   = nfs4_open_expired,
@@ -6182,7 +6393,7 @@ struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
 };
 
 #if defined(CONFIG_NFS_V4_1)
-struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
+static const struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
        .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
        .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
        .recover_open   = nfs41_open_expired,
@@ -6192,14 +6403,14 @@ struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
 };
 #endif /* CONFIG_NFS_V4_1 */
 
-struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
+static const struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
        .sched_state_renewal = nfs4_proc_async_renew,
        .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked,
        .renew_lease = nfs4_proc_renew,
 };
 
 #if defined(CONFIG_NFS_V4_1)
-struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
+static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
        .sched_state_renewal = nfs41_proc_async_sequence,
        .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked,
        .renew_lease = nfs4_proc_sequence,
@@ -6209,7 +6420,7 @@ struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
 static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
        .minor_version = 0,
        .call_sync = _nfs4_call_sync,
-       .validate_stateid = nfs4_validate_delegation_stateid,
+       .match_stateid = nfs4_match_stateid,
        .find_root_sec = nfs4_find_root_sec,
        .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
@@ -6220,7 +6431,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
 static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
        .minor_version = 1,
        .call_sync = _nfs4_call_sync_session,
-       .validate_stateid = nfs41_validate_delegation_stateid,
+       .match_stateid = nfs41_match_stateid,
        .find_root_sec = nfs41_find_root_sec,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
@@ -6260,9 +6471,11 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .create         = nfs4_proc_create,
        .remove         = nfs4_proc_remove,
        .unlink_setup   = nfs4_proc_unlink_setup,
+       .unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare,
        .unlink_done    = nfs4_proc_unlink_done,
        .rename         = nfs4_proc_rename,
        .rename_setup   = nfs4_proc_rename_setup,
+       .rename_rpc_prepare = nfs4_proc_rename_rpc_prepare,
        .rename_done    = nfs4_proc_rename_done,
        .link           = nfs4_proc_link,
        .symlink        = nfs4_proc_symlink,
@@ -6276,8 +6489,10 @@ 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_rpc_prepare = nfs4_proc_read_rpc_prepare,
        .read_done      = nfs4_read_done,
        .write_setup    = nfs4_proc_write_setup,
+       .write_rpc_prepare = nfs4_proc_write_rpc_prepare,
        .write_done     = nfs4_write_done,
        .commit_setup   = nfs4_proc_commit_setup,
        .commit_done    = nfs4_commit_done,
@@ -6301,6 +6516,10 @@ const struct xattr_handler *nfs4_xattr_handlers[] = {
        NULL
 };
 
+module_param(max_session_slots, ushort, 0644);
+MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 "
+               "requests the client will negotiate");
+
 /*
  * Local variables:
  *  c-basic-offset: 8
index 4539203..0f43414 100644 (file)
@@ -146,6 +146,11 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
        struct rpc_cred *cred = NULL;
        struct nfs_server *server;
 
+       /* Use machine credentials if available */
+       cred = nfs4_get_machine_cred_locked(clp);
+       if (cred != NULL)
+               goto out;
+
        rcu_read_lock();
        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
                cred = nfs4_get_renew_cred_server_locked(server);
@@ -153,6 +158,8 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
                        break;
        }
        rcu_read_unlock();
+
+out:
        return cred;
 }
 
@@ -190,30 +197,29 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp)
 static void nfs4_end_drain_session(struct nfs_client *clp)
 {
        struct nfs4_session *ses = clp->cl_session;
+       struct nfs4_slot_table *tbl;
        int max_slots;
 
        if (ses == NULL)
                return;
+       tbl = &ses->fc_slot_table;
        if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
-               spin_lock(&ses->fc_slot_table.slot_tbl_lock);
-               max_slots = ses->fc_slot_table.max_slots;
+               spin_lock(&tbl->slot_tbl_lock);
+               max_slots = tbl->max_slots;
                while (max_slots--) {
-                       struct rpc_task *task;
-
-                       task = rpc_wake_up_next(&ses->fc_slot_table.
-                                               slot_tbl_waitq);
-                       if (!task)
+                       if (rpc_wake_up_first(&tbl->slot_tbl_waitq,
+                                               nfs4_set_task_privileged,
+                                               NULL) == NULL)
                                break;
-                       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
                }
-               spin_unlock(&ses->fc_slot_table.slot_tbl_lock);
+               spin_unlock(&tbl->slot_tbl_lock);
        }
 }
 
 static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
 {
        spin_lock(&tbl->slot_tbl_lock);
-       if (tbl->highest_used_slotid != -1) {
+       if (tbl->highest_used_slotid != NFS4_NO_SLOT) {
                INIT_COMPLETION(tbl->complete);
                spin_unlock(&tbl->slot_tbl_lock);
                return wait_for_completion_interruptible(&tbl->complete);
@@ -317,62 +323,6 @@ out:
        return cred;
 }
 
-static void nfs_alloc_unique_id_locked(struct rb_root *root,
-                                      struct nfs_unique_id *new,
-                                      __u64 minval, int maxbits)
-{
-       struct rb_node **p, *parent;
-       struct nfs_unique_id *pos;
-       __u64 mask = ~0ULL;
-
-       if (maxbits < 64)
-               mask = (1ULL << maxbits) - 1ULL;
-
-       /* Ensure distribution is more or less flat */
-       get_random_bytes(&new->id, sizeof(new->id));
-       new->id &= mask;
-       if (new->id < minval)
-               new->id += minval;
-retry:
-       p = &root->rb_node;
-       parent = NULL;
-
-       while (*p != NULL) {
-               parent = *p;
-               pos = rb_entry(parent, struct nfs_unique_id, rb_node);
-
-               if (new->id < pos->id)
-                       p = &(*p)->rb_left;
-               else if (new->id > pos->id)
-                       p = &(*p)->rb_right;
-               else
-                       goto id_exists;
-       }
-       rb_link_node(&new->rb_node, parent, p);
-       rb_insert_color(&new->rb_node, root);
-       return;
-id_exists:
-       for (;;) {
-               new->id++;
-               if (new->id < minval || (new->id & mask) != new->id) {
-                       new->id = minval;
-                       break;
-               }
-               parent = rb_next(parent);
-               if (parent == NULL)
-                       break;
-               pos = rb_entry(parent, struct nfs_unique_id, rb_node);
-               if (new->id < pos->id)
-                       break;
-       }
-       goto retry;
-}
-
-static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id)
-{
-       rb_erase(&id->rb_node, root);
-}
-
 static struct nfs4_state_owner *
 nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred)
 {
@@ -405,6 +355,7 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
        struct rb_node **p = &server->state_owners.rb_node,
                       *parent = NULL;
        struct nfs4_state_owner *sp;
+       int err;
 
        while (*p != NULL) {
                parent = *p;
@@ -421,8 +372,9 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
                        return sp;
                }
        }
-       nfs_alloc_unique_id_locked(&server->openowner_id,
-                                       &new->so_owner_id, 1, 64);
+       err = ida_get_new(&server->openowner_id, &new->so_seqid.owner_id);
+       if (err)
+               return ERR_PTR(err);
        rb_link_node(&new->so_server_node, parent, p);
        rb_insert_color(&new->so_server_node, &server->state_owners);
        return new;
@@ -435,7 +387,23 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
 
        if (!RB_EMPTY_NODE(&sp->so_server_node))
                rb_erase(&sp->so_server_node, &server->state_owners);
-       nfs_free_unique_id(&server->openowner_id, &sp->so_owner_id);
+       ida_remove(&server->openowner_id, sp->so_seqid.owner_id);
+}
+
+static void
+nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
+{
+       sc->flags = 0;
+       sc->counter = 0;
+       spin_lock_init(&sc->lock);
+       INIT_LIST_HEAD(&sc->list);
+       rpc_init_wait_queue(&sc->wait, "Seqid_waitqueue");
+}
+
+static void
+nfs4_destroy_seqid_counter(struct nfs_seqid_counter *sc)
+{
+       rpc_destroy_wait_queue(&sc->wait);
 }
 
 /*
@@ -444,19 +412,20 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
  *
  */
 static struct nfs4_state_owner *
-nfs4_alloc_state_owner(void)
+nfs4_alloc_state_owner(struct nfs_server *server,
+               struct rpc_cred *cred,
+               gfp_t gfp_flags)
 {
        struct nfs4_state_owner *sp;
 
-       sp = kzalloc(sizeof(*sp),GFP_NOFS);
+       sp = kzalloc(sizeof(*sp), gfp_flags);
        if (!sp)
                return NULL;
+       sp->so_server = server;
+       sp->so_cred = get_rpccred(cred);
        spin_lock_init(&sp->so_lock);
        INIT_LIST_HEAD(&sp->so_states);
-       rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue");
-       sp->so_seqid.sequence = &sp->so_sequence;
-       spin_lock_init(&sp->so_sequence.lock);
-       INIT_LIST_HEAD(&sp->so_sequence.list);
+       nfs4_init_seqid_counter(&sp->so_seqid);
        atomic_set(&sp->so_count, 1);
        INIT_LIST_HEAD(&sp->so_lru);
        return sp;
@@ -478,7 +447,7 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp)
 
 static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
 {
-       rpc_destroy_wait_queue(&sp->so_sequence.wait);
+       nfs4_destroy_seqid_counter(&sp->so_seqid);
        put_rpccred(sp->so_cred);
        kfree(sp);
 }
@@ -516,7 +485,8 @@ static void nfs4_gc_state_owners(struct nfs_server *server)
  * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL.
  */
 struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
-                                             struct rpc_cred *cred)
+                                             struct rpc_cred *cred,
+                                             gfp_t gfp_flags)
 {
        struct nfs_client *clp = server->nfs_client;
        struct nfs4_state_owner *sp, *new;
@@ -526,20 +496,18 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
        spin_unlock(&clp->cl_lock);
        if (sp != NULL)
                goto out;
-       new = nfs4_alloc_state_owner();
+       new = nfs4_alloc_state_owner(server, cred, gfp_flags);
        if (new == NULL)
                goto out;
-       new->so_server = server;
-       new->so_cred = cred;
-       spin_lock(&clp->cl_lock);
-       sp = nfs4_insert_state_owner_locked(new);
-       spin_unlock(&clp->cl_lock);
-       if (sp == new)
-               get_rpccred(cred);
-       else {
-               rpc_destroy_wait_queue(&new->so_sequence.wait);
-               kfree(new);
-       }
+       do {
+               if (ida_pre_get(&server->openowner_id, gfp_flags) == 0)
+                       break;
+               spin_lock(&clp->cl_lock);
+               sp = nfs4_insert_state_owner_locked(new);
+               spin_unlock(&clp->cl_lock);
+       } while (sp == ERR_PTR(-EAGAIN));
+       if (sp != new)
+               nfs4_free_state_owner(new);
 out:
        nfs4_gc_state_owners(server);
        return sp;
@@ -795,15 +763,11 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
 {
        struct nfs4_lock_state *lsp;
        struct nfs_server *server = state->owner->so_server;
-       struct nfs_client *clp = server->nfs_client;
 
        lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
        if (lsp == NULL)
                return NULL;
-       rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue");
-       spin_lock_init(&lsp->ls_sequence.lock);
-       INIT_LIST_HEAD(&lsp->ls_sequence.list);
-       lsp->ls_seqid.sequence = &lsp->ls_sequence;
+       nfs4_init_seqid_counter(&lsp->ls_seqid);
        atomic_set(&lsp->ls_count, 1);
        lsp->ls_state = state;
        lsp->ls_owner.lo_type = type;
@@ -815,25 +779,22 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
                lsp->ls_owner.lo_u.posix_owner = fl_owner;
                break;
        default:
-               kfree(lsp);
-               return NULL;
+               goto out_free;
        }
-       spin_lock(&clp->cl_lock);
-       nfs_alloc_unique_id_locked(&server->lockowner_id, &lsp->ls_id, 1, 64);
-       spin_unlock(&clp->cl_lock);
+       lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS);
+       if (lsp->ls_seqid.owner_id < 0)
+               goto out_free;
        INIT_LIST_HEAD(&lsp->ls_locks);
        return lsp;
+out_free:
+       kfree(lsp);
+       return NULL;
 }
 
-static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
+void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
 {
-       struct nfs_server *server = lsp->ls_state->owner->so_server;
-       struct nfs_client *clp = server->nfs_client;
-
-       spin_lock(&clp->cl_lock);
-       nfs_free_unique_id(&server->lockowner_id, &lsp->ls_id);
-       spin_unlock(&clp->cl_lock);
-       rpc_destroy_wait_queue(&lsp->ls_sequence.wait);
+       ida_simple_remove(&server->lockowner_id, lsp->ls_seqid.owner_id);
+       nfs4_destroy_seqid_counter(&lsp->ls_seqid);
        kfree(lsp);
 }
 
@@ -865,7 +826,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
        }
        spin_unlock(&state->state_lock);
        if (new != NULL)
-               nfs4_free_lock_state(new);
+               nfs4_free_lock_state(state->owner->so_server, new);
        return lsp;
 }
 
@@ -886,9 +847,11 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
        if (list_empty(&state->lock_states))
                clear_bit(LK_STATE_IN_USE, &state->flags);
        spin_unlock(&state->state_lock);
-       if (lsp->ls_flags & NFS_LOCK_INITIALIZED)
-               nfs4_release_lockowner(lsp);
-       nfs4_free_lock_state(lsp);
+       if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
+               if (nfs4_release_lockowner(lsp) == 0)
+                       return;
+       }
+       nfs4_free_lock_state(lsp->ls_state->owner->so_server, lsp);
 }
 
 static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
@@ -918,7 +881,8 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
        if (fl->fl_flags & FL_POSIX)
                lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE);
        else if (fl->fl_flags & FL_FLOCK)
-               lsp = nfs4_get_lock_state(state, 0, fl->fl_pid, NFS4_FLOCK_LOCK_TYPE);
+               lsp = nfs4_get_lock_state(state, NULL, fl->fl_pid,
+                               NFS4_FLOCK_LOCK_TYPE);
        else
                return -EINVAL;
        if (lsp == NULL)
@@ -928,28 +892,49 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
        return 0;
 }
 
-/*
- * Byte-range lock aware utility to initialize the stateid of read/write
- * requests.
- */
-void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid)
+static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
+               fl_owner_t fl_owner, pid_t fl_pid)
 {
        struct nfs4_lock_state *lsp;
-       int seq;
+       bool ret = false;
 
-       do {
-               seq = read_seqbegin(&state->seqlock);
-               memcpy(dst, &state->stateid, sizeof(*dst));
-       } while (read_seqretry(&state->seqlock, seq));
        if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
-               return;
+               goto out;
 
        spin_lock(&state->state_lock);
        lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
-       if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
-               memcpy(dst, &lsp->ls_stateid, sizeof(*dst));
+       if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) {
+               nfs4_stateid_copy(dst, &lsp->ls_stateid);
+               ret = true;
+       }
        spin_unlock(&state->state_lock);
        nfs4_put_lock_state(lsp);
+out:
+       return ret;
+}
+
+static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
+{
+       int seq;
+
+       do {
+               seq = read_seqbegin(&state->seqlock);
+               nfs4_stateid_copy(dst, &state->stateid);
+       } while (read_seqretry(&state->seqlock, seq));
+}
+
+/*
+ * Byte-range lock aware utility to initialize the stateid of read/write
+ * requests.
+ */
+void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
+               fmode_t fmode, fl_owner_t fl_owner, pid_t fl_pid)
+{
+       if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
+               return;
+       if (nfs4_copy_lock_stateid(dst, state, fl_owner, fl_pid))
+               return;
+       nfs4_copy_open_stateid(dst, state);
 }
 
 struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
@@ -960,20 +945,28 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_m
        if (new != NULL) {
                new->sequence = counter;
                INIT_LIST_HEAD(&new->list);
+               new->task = NULL;
        }
        return new;
 }
 
 void nfs_release_seqid(struct nfs_seqid *seqid)
 {
-       if (!list_empty(&seqid->list)) {
-               struct rpc_sequence *sequence = seqid->sequence->sequence;
+       struct nfs_seqid_counter *sequence;
 
-               spin_lock(&sequence->lock);
-               list_del_init(&seqid->list);
-               spin_unlock(&sequence->lock);
-               rpc_wake_up(&sequence->wait);
+       if (list_empty(&seqid->list))
+               return;
+       sequence = seqid->sequence;
+       spin_lock(&sequence->lock);
+       list_del_init(&seqid->list);
+       if (!list_empty(&sequence->list)) {
+               struct nfs_seqid *next;
+
+               next = list_first_entry(&sequence->list,
+                               struct nfs_seqid, list);
+               rpc_wake_up_queued_task(&sequence->wait, next->task);
        }
+       spin_unlock(&sequence->lock);
 }
 
 void nfs_free_seqid(struct nfs_seqid *seqid)
@@ -989,14 +982,14 @@ void nfs_free_seqid(struct nfs_seqid *seqid)
  */
 static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
 {
-       BUG_ON(list_first_entry(&seqid->sequence->sequence->list, struct nfs_seqid, list) != seqid);
+       BUG_ON(list_first_entry(&seqid->sequence->list, struct nfs_seqid, list) != seqid);
        switch (status) {
                case 0:
                        break;
                case -NFS4ERR_BAD_SEQID:
                        if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
                                return;
-                       printk(KERN_WARNING "NFS: v4 server returned a bad"
+                       pr_warn_ratelimited("NFS: v4 server returned a bad"
                                        " sequence-id error on an"
                                        " unconfirmed sequence %p!\n",
                                        seqid->sequence);
@@ -1040,10 +1033,11 @@ void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
 
 int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
 {
-       struct rpc_sequence *sequence = seqid->sequence->sequence;
+       struct nfs_seqid_counter *sequence = seqid->sequence;
        int status = 0;
 
        spin_lock(&sequence->lock);
+       seqid->task = task;
        if (list_empty(&seqid->list))
                list_add_tail(&seqid->list, &sequence->list);
        if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid)
@@ -1072,19 +1066,28 @@ static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
 void nfs4_schedule_state_manager(struct nfs_client *clp)
 {
        struct task_struct *task;
+       char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
 
        if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
                return;
        __module_get(THIS_MODULE);
        atomic_inc(&clp->cl_count);
-       task = kthread_run(nfs4_run_state_manager, clp, "%s-manager",
-                               rpc_peeraddr2str(clp->cl_rpcclient,
-                                                       RPC_DISPLAY_ADDR));
-       if (!IS_ERR(task))
-               return;
-       nfs4_clear_state_manager_bit(clp);
-       nfs_put_client(clp);
-       module_put(THIS_MODULE);
+
+       /* The rcu_read_lock() is not strictly necessary, as the state
+        * manager is the only thread that ever changes the rpc_xprt
+        * after it's initialized.  At this point, we're single threaded. */
+       rcu_read_lock();
+       snprintf(buf, sizeof(buf), "%s-manager",
+                       rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
+       rcu_read_unlock();
+       task = kthread_run(nfs4_run_state_manager, clp, buf);
+       if (IS_ERR(task)) {
+               printk(KERN_ERR "%s: kthread_run: %ld\n",
+                       __func__, PTR_ERR(task));
+               nfs4_clear_state_manager_bit(clp);
+               nfs_put_client(clp);
+               module_put(THIS_MODULE);
+       }
 }
 
 /*
@@ -1098,10 +1101,25 @@ void nfs4_schedule_lease_recovery(struct nfs_client *clp)
                set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
        nfs4_schedule_state_manager(clp);
 }
+EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery);
+
+/*
+ * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
+ * @clp: client to process
+ *
+ * Set the NFS4CLNT_LEASE_EXPIRED state in order to force a
+ * resend of the SETCLIENTID and hence re-establish the
+ * callback channel. Then return all existing delegations.
+ */
+static void nfs40_handle_cb_pathdown(struct nfs_client *clp)
+{
+       set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+       nfs_expire_all_delegations(clp);
+}
 
 void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
 {
-       nfs_handle_cb_pathdown(clp);
+       nfs40_handle_cb_pathdown(clp);
        nfs4_schedule_state_manager(clp);
 }
 
@@ -1132,11 +1150,37 @@ void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4
 {
        struct nfs_client *clp = server->nfs_client;
 
-       if (test_and_clear_bit(NFS_DELEGATED_STATE, &state->flags))
-               nfs_async_inode_return_delegation(state->inode, &state->stateid);
        nfs4_state_mark_reclaim_nograce(clp, state);
        nfs4_schedule_state_manager(clp);
 }
+EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
+
+void nfs_inode_find_state_and_recover(struct inode *inode,
+               const nfs4_stateid *stateid)
+{
+       struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct nfs_open_context *ctx;
+       struct nfs4_state *state;
+       bool found = false;
+
+       spin_lock(&inode->i_lock);
+       list_for_each_entry(ctx, &nfsi->open_files, list) {
+               state = ctx->state;
+               if (state == NULL)
+                       continue;
+               if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
+                       continue;
+               if (!nfs4_stateid_match(&state->stateid, stateid))
+                       continue;
+               nfs4_state_mark_reclaim_nograce(clp, state);
+               found = true;
+       }
+       spin_unlock(&inode->i_lock);
+       if (found)
+               nfs4_schedule_state_manager(clp);
+}
+
 
 static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
 {
@@ -1175,8 +1219,8 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
                        case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                                goto out;
                        default:
-                               printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
-                                               __func__, status);
+                               printk(KERN_ERR "NFS: %s: unhandled error %d. "
+                                       "Zeroing state\n", __func__, status);
                        case -ENOMEM:
                        case -NFS4ERR_DENIED:
                        case -NFS4ERR_RECLAIM_BAD:
@@ -1222,8 +1266,9 @@ restart:
                                spin_lock(&state->state_lock);
                                list_for_each_entry(lock, &state->lock_states, ls_locks) {
                                        if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
-                                               printk("%s: Lock reclaim failed!\n",
-                                                       __func__);
+                                               pr_warn_ratelimited("NFS: "
+                                                       "%s: Lock reclaim "
+                                                       "failed!\n", __func__);
                                }
                                spin_unlock(&state->state_lock);
                                nfs4_put_open_state(state);
@@ -1232,8 +1277,8 @@ restart:
                }
                switch (status) {
                        default:
-                               printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
-                                               __func__, status);
+                               printk(KERN_ERR "NFS: %s: unhandled error %d. "
+                                       "Zeroing state\n", __func__, status);
                        case -ENOENT:
                        case -ENOMEM:
                        case -ESTALE:
@@ -1241,8 +1286,8 @@ restart:
                                 * Open state on this file cannot be recovered
                                 * All we can do is revert to using the zero stateid.
                                 */
-                               memset(state->stateid.data, 0,
-                                       sizeof(state->stateid.data));
+                               memset(&state->stateid, 0,
+                                       sizeof(state->stateid));
                                /* Mark the file as being 'closed' */
                                state->state = 0;
                                break;
@@ -1420,7 +1465,7 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
                case 0:
                        break;
                case -NFS4ERR_CB_PATH_DOWN:
-                       nfs_handle_cb_pathdown(clp);
+                       nfs40_handle_cb_pathdown(clp);
                        break;
                case -NFS4ERR_NO_GRACE:
                        nfs4_state_end_reclaim_reboot(clp);
@@ -1801,7 +1846,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
        } while (atomic_read(&clp->cl_count) > 1);
        return;
 out_error:
-       printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
+       pr_warn_ratelimited("NFS: state manager failed on NFSv4 server %s"
                        " with error %d\n", clp->cl_hostname, -status);
        nfs4_end_drain_session(clp);
        nfs4_clear_state_manager_bit(clp);
index 33bd8d0..c74fdb1 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
 #include <linux/kdev_t.h>
+#include <linux/module.h>
+#include <linux/utsname.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/gss_api.h>
@@ -271,7 +273,12 @@ static int nfs4_stat_to_errno(int);
                                1 /* flags */ + \
                                1 /* spa_how */ + \
                                0 /* SP4_NONE (for now) */ + \
-                               1 /* zero implemetation id array */)
+                               1 /* implementation id array of size 1 */ + \
+                               1 /* nii_domain */ + \
+                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+                               1 /* nii_name */ + \
+                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+                               3 /* nii_date */)
 #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
                                2 /* eir_clientid */ + \
                                1 /* eir_sequenceid */ + \
@@ -284,7 +291,11 @@ static int nfs4_stat_to_errno(int);
                                /* eir_server_scope<> */ \
                                XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
                                1 /* eir_server_impl_id array length */ + \
-                               0 /* ignored eir_server_impl_id contents */)
+                               1 /* nii_domain */ + \
+                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+                               1 /* nii_name */ + \
+                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+                               3 /* nii_date */)
 #define encode_channel_attrs_maxsz  (6 + 1 /* ca_rdma_ird.len (0) */)
 #define decode_channel_attrs_maxsz  (6 + \
                                     1 /* ca_rdma_ird.len */ + \
@@ -838,6 +849,12 @@ const u32 nfs41_maxread_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
                                    XDR_UNIT);
 #endif /* CONFIG_NFS_V4_1 */
 
+static unsigned short send_implementation_id = 1;
+
+module_param(send_implementation_id, ushort, 0644);
+MODULE_PARM_DESC(send_implementation_id,
+               "Send implementation ID with NFSv4.1 exchange_id");
+
 static const umode_t nfs_type2fmt[] = {
        [NF4BAD] = 0,
        [NF4REG] = S_IFREG,
@@ -868,15 +885,44 @@ static __be32 *reserve_space(struct xdr_stream *xdr, size_t nbytes)
        return p;
 }
 
+static void encode_opaque_fixed(struct xdr_stream *xdr, const void *buf, size_t len)
+{
+       __be32 *p;
+
+       p = xdr_reserve_space(xdr, len);
+       xdr_encode_opaque_fixed(p, buf, len);
+}
+
 static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
 {
        __be32 *p;
 
-       p = xdr_reserve_space(xdr, 4 + len);
-       BUG_ON(p == NULL);
+       p = reserve_space(xdr, 4 + len);
        xdr_encode_opaque(p, str, len);
 }
 
+static void encode_uint32(struct xdr_stream *xdr, u32 n)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 4);
+       *p = cpu_to_be32(n);
+}
+
+static void encode_uint64(struct xdr_stream *xdr, u64 n)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 8);
+       xdr_encode_hyper(p, n);
+}
+
+static void encode_nfs4_seqid(struct xdr_stream *xdr,
+               const struct nfs_seqid *seqid)
+{
+       encode_uint32(xdr, seqid->sequence->counter);
+}
+
 static void encode_compound_hdr(struct xdr_stream *xdr,
                                struct rpc_rqst *req,
                                struct compound_hdr *hdr)
@@ -889,28 +935,37 @@ static void encode_compound_hdr(struct xdr_stream *xdr,
         * but this is not required as a MUST for the server to do so. */
        hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen;
 
-       dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
        BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
-       p = reserve_space(xdr, 4 + hdr->taglen + 8);
-       p = xdr_encode_opaque(p, hdr->tag, hdr->taglen);
+       encode_string(xdr, hdr->taglen, hdr->tag);
+       p = reserve_space(xdr, 8);
        *p++ = cpu_to_be32(hdr->minorversion);
        hdr->nops_p = p;
        *p = cpu_to_be32(hdr->nops);
 }
 
+static void encode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 op,
+               uint32_t replen,
+               struct compound_hdr *hdr)
+{
+       encode_uint32(xdr, op);
+       hdr->nops++;
+       hdr->replen += replen;
+}
+
 static void encode_nops(struct compound_hdr *hdr)
 {
        BUG_ON(hdr->nops > NFS4_MAX_OPS);
        *hdr->nops_p = htonl(hdr->nops);
 }
 
-static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
+static void encode_nfs4_stateid(struct xdr_stream *xdr, const nfs4_stateid *stateid)
 {
-       __be32 *p;
+       encode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE);
+}
 
-       p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
-       BUG_ON(p == NULL);
-       xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
+static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
+{
+       encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE);
 }
 
 static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
@@ -1023,7 +1078,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
         * Now we backfill the bitmap and the attribute buffer length.
         */
        if (len != ((char *)p - (char *)q) + 4) {
-               printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
+               printk(KERN_ERR "NFS: Attr length error, %u != %Zu\n",
                                len, ((char *)p - (char *)q) + 4);
                BUG();
        }
@@ -1037,46 +1092,33 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 
 static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(OP_ACCESS);
-       *p = cpu_to_be32(access);
-       hdr->nops++;
-       hdr->replen += decode_access_maxsz;
+       encode_op_hdr(xdr, OP_ACCESS, decode_access_maxsz, hdr);
+       encode_uint32(xdr, access);
 }
 
 static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8+NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_CLOSE);
-       *p++ = cpu_to_be32(arg->seqid->sequence->counter);
-       xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_close_maxsz;
+       encode_op_hdr(xdr, OP_CLOSE, decode_close_maxsz, hdr);
+       encode_nfs4_seqid(xdr, arg->seqid);
+       encode_nfs4_stateid(xdr, arg->stateid);
 }
 
 static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 16);
-       *p++ = cpu_to_be32(OP_COMMIT);
+       encode_op_hdr(xdr, OP_COMMIT, decode_commit_maxsz, hdr);
+       p = reserve_space(xdr, 12);
        p = xdr_encode_hyper(p, args->offset);
        *p = cpu_to_be32(args->count);
-       hdr->nops++;
-       hdr->replen += decode_commit_maxsz;
 }
 
 static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(OP_CREATE);
-       *p = cpu_to_be32(create->ftype);
+       encode_op_hdr(xdr, OP_CREATE, decode_create_maxsz, hdr);
+       encode_uint32(xdr, create->ftype);
 
        switch (create->ftype) {
        case NF4LNK:
@@ -1096,9 +1138,6 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
        }
 
        encode_string(xdr, create->name->len, create->name->name);
-       hdr->nops++;
-       hdr->replen += decode_create_maxsz;
-
        encode_attrs(xdr, create->attrs, create->server);
 }
 
@@ -1106,25 +1145,21 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 12);
-       *p++ = cpu_to_be32(OP_GETATTR);
+       encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
+       p = reserve_space(xdr, 8);
        *p++ = cpu_to_be32(1);
        *p = cpu_to_be32(bitmap);
-       hdr->nops++;
-       hdr->replen += decode_getattr_maxsz;
 }
 
 static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 16);
-       *p++ = cpu_to_be32(OP_GETATTR);
+       encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
+       p = reserve_space(xdr, 12);
        *p++ = cpu_to_be32(2);
        *p++ = cpu_to_be32(bm0);
        *p = cpu_to_be32(bm1);
-       hdr->nops++;
-       hdr->replen += decode_getattr_maxsz;
 }
 
 static void
@@ -1134,8 +1169,7 @@ encode_getattr_three(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_GETATTR);
+       encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
        if (bm2) {
                p = reserve_space(xdr, 16);
                *p++ = cpu_to_be32(3);
@@ -1152,8 +1186,6 @@ encode_getattr_three(struct xdr_stream *xdr,
                *p++ = cpu_to_be32(1);
                *p = cpu_to_be32(bm0);
        }
-       hdr->nops++;
-       hdr->replen += decode_getattr_maxsz;
 }
 
 static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
@@ -1179,23 +1211,13 @@ static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, stru
 
 static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_GETFH);
-       hdr->nops++;
-       hdr->replen += decode_getfh_maxsz;
+       encode_op_hdr(xdr, OP_GETFH, decode_getfh_maxsz, hdr);
 }
 
 static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + name->len);
-       *p++ = cpu_to_be32(OP_LINK);
-       xdr_encode_opaque(p, name->name, name->len);
-       hdr->nops++;
-       hdr->replen += decode_link_maxsz;
+       encode_op_hdr(xdr, OP_LINK, decode_link_maxsz, hdr);
+       encode_string(xdr, name->len, name->name);
 }
 
 static inline int nfs4_lock_type(struct file_lock *fl, int block)
@@ -1232,79 +1254,60 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 32);
-       *p++ = cpu_to_be32(OP_LOCK);
+       encode_op_hdr(xdr, OP_LOCK, decode_lock_maxsz, hdr);
+       p = reserve_space(xdr, 28);
        *p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block));
        *p++ = cpu_to_be32(args->reclaim);
        p = xdr_encode_hyper(p, args->fl->fl_start);
        p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
        *p = cpu_to_be32(args->new_lock_owner);
        if (args->new_lock_owner){
-               p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
-               *p++ = cpu_to_be32(args->open_seqid->sequence->counter);
-               p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE);
-               *p++ = cpu_to_be32(args->lock_seqid->sequence->counter);
+               encode_nfs4_seqid(xdr, args->open_seqid);
+               encode_nfs4_stateid(xdr, args->open_stateid);
+               encode_nfs4_seqid(xdr, args->lock_seqid);
                encode_lockowner(xdr, &args->lock_owner);
        }
        else {
-               p = reserve_space(xdr, NFS4_STATEID_SIZE+4);
-               p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE);
-               *p = cpu_to_be32(args->lock_seqid->sequence->counter);
+               encode_nfs4_stateid(xdr, args->lock_stateid);
+               encode_nfs4_seqid(xdr, args->lock_seqid);
        }
-       hdr->nops++;
-       hdr->replen += decode_lock_maxsz;
 }
 
 static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 24);
-       *p++ = cpu_to_be32(OP_LOCKT);
+       encode_op_hdr(xdr, OP_LOCKT, decode_lockt_maxsz, hdr);
+       p = reserve_space(xdr, 20);
        *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
        p = xdr_encode_hyper(p, args->fl->fl_start);
        p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
        encode_lockowner(xdr, &args->lock_owner);
-       hdr->nops++;
-       hdr->replen += decode_lockt_maxsz;
 }
 
 static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16);
-       *p++ = cpu_to_be32(OP_LOCKU);
-       *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
-       *p++ = cpu_to_be32(args->seqid->sequence->counter);
-       p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
+       encode_op_hdr(xdr, OP_LOCKU, decode_locku_maxsz, hdr);
+       encode_uint32(xdr, nfs4_lock_type(args->fl, 0));
+       encode_nfs4_seqid(xdr, args->seqid);
+       encode_nfs4_stateid(xdr, args->stateid);
+       p = reserve_space(xdr, 16);
        p = xdr_encode_hyper(p, args->fl->fl_start);
        xdr_encode_hyper(p, nfs4_lock_length(args->fl));
-       hdr->nops++;
-       hdr->replen += decode_locku_maxsz;
 }
 
 static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_RELEASE_LOCKOWNER);
+       encode_op_hdr(xdr, OP_RELEASE_LOCKOWNER, decode_release_lockowner_maxsz, hdr);
        encode_lockowner(xdr, lowner);
-       hdr->nops++;
-       hdr->replen += decode_release_lockowner_maxsz;
 }
 
 static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-       int len = name->len;
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + len);
-       *p++ = cpu_to_be32(OP_LOOKUP);
-       xdr_encode_opaque(p, name->name, len);
-       hdr->nops++;
-       hdr->replen += decode_lookup_maxsz;
+       encode_op_hdr(xdr, OP_LOOKUP, decode_lookup_maxsz, hdr);
+       encode_string(xdr, name->len, name->name);
 }
 
 static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
@@ -1335,9 +1338,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
  * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
  * owner 4 = 32
  */
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(OP_OPEN);
-       *p = cpu_to_be32(arg->seqid->sequence->counter);
+       encode_nfs4_seqid(xdr, arg->seqid);
        encode_share_access(xdr, arg->fmode);
        p = reserve_space(xdr, 32);
        p = xdr_encode_hyper(p, arg->clientid);
@@ -1437,14 +1438,15 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
-       xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
+       p = reserve_space(xdr, 4);
+       *p = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
+       encode_nfs4_stateid(xdr, stateid);
        encode_string(xdr, name->len, name->name);
 }
 
 static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
 {
+       encode_op_hdr(xdr, OP_OPEN, decode_open_maxsz, hdr);
        encode_openhdr(xdr, arg);
        encode_opentype(xdr, arg);
        switch (arg->claim) {
@@ -1460,88 +1462,64 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg,
        default:
                BUG();
        }
-       hdr->nops++;
-       hdr->replen += decode_open_maxsz;
 }
 
 static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
-       *p++ = cpu_to_be32(OP_OPEN_CONFIRM);
-       p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
-       *p = cpu_to_be32(arg->seqid->sequence->counter);
-       hdr->nops++;
-       hdr->replen += decode_open_confirm_maxsz;
+       encode_op_hdr(xdr, OP_OPEN_CONFIRM, decode_open_confirm_maxsz, hdr);
+       encode_nfs4_stateid(xdr, arg->stateid);
+       encode_nfs4_seqid(xdr, arg->seqid);
 }
 
 static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
-       *p++ = cpu_to_be32(OP_OPEN_DOWNGRADE);
-       p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
-       *p = cpu_to_be32(arg->seqid->sequence->counter);
+       encode_op_hdr(xdr, OP_OPEN_DOWNGRADE, decode_open_downgrade_maxsz, hdr);
+       encode_nfs4_stateid(xdr, arg->stateid);
+       encode_nfs4_seqid(xdr, arg->seqid);
        encode_share_access(xdr, arg->fmode);
-       hdr->nops++;
-       hdr->replen += decode_open_downgrade_maxsz;
 }
 
 static void
 encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
 {
-       int len = fh->size;
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + len);
-       *p++ = cpu_to_be32(OP_PUTFH);
-       xdr_encode_opaque(p, fh->data, len);
-       hdr->nops++;
-       hdr->replen += decode_putfh_maxsz;
+       encode_op_hdr(xdr, OP_PUTFH, decode_putfh_maxsz, hdr);
+       encode_string(xdr, fh->size, fh->data);
 }
 
 static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_PUTROOTFH);
-       hdr->nops++;
-       hdr->replen += decode_putrootfh_maxsz;
+       encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr);
 }
 
-static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx, int zero_seqid)
+static void encode_open_stateid(struct xdr_stream *xdr,
+               const struct nfs_open_context *ctx,
+               const struct nfs_lock_context *l_ctx,
+               fmode_t fmode,
+               int zero_seqid)
 {
        nfs4_stateid stateid;
-       __be32 *p;
 
-       p = reserve_space(xdr, NFS4_STATEID_SIZE);
        if (ctx->state != NULL) {
-               nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner, l_ctx->pid);
+               nfs4_select_rw_stateid(&stateid, ctx->state,
+                               fmode, l_ctx->lockowner, l_ctx->pid);
                if (zero_seqid)
-                       stateid.stateid.seqid = 0;
-               xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
+                       stateid.seqid = 0;
+               encode_nfs4_stateid(xdr, &stateid);
        } else
-               xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
+               encode_nfs4_stateid(xdr, &zero_stateid);
 }
 
 static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_READ);
-
-       encode_stateid(xdr, args->context, args->lock_context,
-                      hdr->minorversion);
+       encode_op_hdr(xdr, OP_READ, decode_read_maxsz, hdr);
+       encode_open_stateid(xdr, args->context, args->lock_context,
+                       FMODE_READ, hdr->minorversion);
 
        p = reserve_space(xdr, 12);
        p = xdr_encode_hyper(p, args->offset);
        *p = cpu_to_be32(args->count);
-       hdr->nops++;
-       hdr->replen += decode_read_maxsz;
 }
 
 static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
@@ -1551,7 +1529,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
                FATTR4_WORD1_MOUNTED_ON_FILEID,
        };
        uint32_t dircount = readdir->count >> 1;
-       __be32 *p;
+       __be32 *p, verf[2];
 
        if (readdir->plus) {
                attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
@@ -1566,80 +1544,54 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
        if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
                attrs[0] |= FATTR4_WORD0_FILEID;
 
-       p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
-       *p++ = cpu_to_be32(OP_READDIR);
-       p = xdr_encode_hyper(p, readdir->cookie);
-       p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
+       encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr);
+       encode_uint64(xdr, readdir->cookie);
+       encode_nfs4_verifier(xdr, &readdir->verifier);
+       p = reserve_space(xdr, 20);
        *p++ = cpu_to_be32(dircount);
        *p++ = cpu_to_be32(readdir->count);
        *p++ = cpu_to_be32(2);
 
        *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
        *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
-       hdr->nops++;
-       hdr->replen += decode_readdir_maxsz;
+       memcpy(verf, readdir->verifier.data, sizeof(verf));
        dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
                        __func__,
                        (unsigned long long)readdir->cookie,
-                       ((u32 *)readdir->verifier.data)[0],
-                       ((u32 *)readdir->verifier.data)[1],
+                       verf[0], verf[1],
                        attrs[0] & readdir->bitmask[0],
                        attrs[1] & readdir->bitmask[1]);
 }
 
 static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_READLINK);
-       hdr->nops++;
-       hdr->replen += decode_readlink_maxsz;
+       encode_op_hdr(xdr, OP_READLINK, decode_readlink_maxsz, hdr);
 }
 
 static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + name->len);
-       *p++ = cpu_to_be32(OP_REMOVE);
-       xdr_encode_opaque(p, name->name, name->len);
-       hdr->nops++;
-       hdr->replen += decode_remove_maxsz;
+       encode_op_hdr(xdr, OP_REMOVE, decode_remove_maxsz, hdr);
+       encode_string(xdr, name->len, name->name);
 }
 
 static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_RENAME);
+       encode_op_hdr(xdr, OP_RENAME, decode_rename_maxsz, hdr);
        encode_string(xdr, oldname->len, oldname->name);
        encode_string(xdr, newname->len, newname->name);
-       hdr->nops++;
-       hdr->replen += decode_rename_maxsz;
 }
 
-static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr)
+static void encode_renew(struct xdr_stream *xdr, clientid4 clid,
+                        struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 12);
-       *p++ = cpu_to_be32(OP_RENEW);
-       xdr_encode_hyper(p, client_stateid->cl_clientid);
-       hdr->nops++;
-       hdr->replen += decode_renew_maxsz;
+       encode_op_hdr(xdr, OP_RENEW, decode_renew_maxsz, hdr);
+       encode_uint64(xdr, clid);
 }
 
 static void
 encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_RESTOREFH);
-       hdr->nops++;
-       hdr->replen += decode_restorefh_maxsz;
+       encode_op_hdr(xdr, OP_RESTOREFH, decode_restorefh_maxsz, hdr);
 }
 
 static void
@@ -1647,9 +1599,8 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_SETATTR);
-       xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
+       encode_op_hdr(xdr, OP_SETATTR, decode_setacl_maxsz, hdr);
+       encode_nfs4_stateid(xdr, &zero_stateid);
        p = reserve_space(xdr, 2*4);
        *p++ = cpu_to_be32(1);
        *p = cpu_to_be32(FATTR4_WORD0_ACL);
@@ -1657,30 +1608,18 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
        p = reserve_space(xdr, 4);
        *p = cpu_to_be32(arg->acl_len);
        xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
-       hdr->nops++;
-       hdr->replen += decode_setacl_maxsz;
 }
 
 static void
 encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_SAVEFH);
-       hdr->nops++;
-       hdr->replen += decode_savefh_maxsz;
+       encode_op_hdr(xdr, OP_SAVEFH, decode_savefh_maxsz, hdr);
 }
 
 static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_SETATTR);
-       xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_setattr_maxsz;
+       encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
+       encode_nfs4_stateid(xdr, &arg->stateid);
        encode_attrs(xdr, arg->iap, server);
 }
 
@@ -1688,9 +1627,8 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE);
-       *p++ = cpu_to_be32(OP_SETCLIENTID);
-       xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
+       encode_op_hdr(xdr, OP_SETCLIENTID, decode_setclientid_maxsz, hdr);
+       encode_nfs4_verifier(xdr, setclientid->sc_verifier);
 
        encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
        p = reserve_space(xdr, 4);
@@ -1699,31 +1637,23 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie
        encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
        p = reserve_space(xdr, 4);
        *p = cpu_to_be32(setclientid->sc_cb_ident);
-       hdr->nops++;
-       hdr->replen += decode_setclientid_maxsz;
 }
 
 static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE);
-       *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
-       p = xdr_encode_hyper(p, arg->clientid);
-       xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_setclientid_confirm_maxsz;
+       encode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM,
+                       decode_setclientid_confirm_maxsz, hdr);
+       encode_uint64(xdr, arg->clientid);
+       encode_nfs4_verifier(xdr, &arg->confirm);
 }
 
 static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_WRITE);
-
-       encode_stateid(xdr, args->context, args->lock_context,
-                      hdr->minorversion);
+       encode_op_hdr(xdr, OP_WRITE, decode_write_maxsz, hdr);
+       encode_open_stateid(xdr, args->context, args->lock_context,
+                       FMODE_WRITE, hdr->minorversion);
 
        p = reserve_space(xdr, 16);
        p = xdr_encode_hyper(p, args->offset);
@@ -1731,32 +1661,18 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg
        *p = cpu_to_be32(args->count);
 
        xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
-       hdr->nops++;
-       hdr->replen += decode_write_maxsz;
 }
 
 static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-
-       *p++ = cpu_to_be32(OP_DELEGRETURN);
-       xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_delegreturn_maxsz;
+       encode_op_hdr(xdr, OP_DELEGRETURN, decode_delegreturn_maxsz, hdr);
+       encode_nfs4_stateid(xdr, stateid);
 }
 
 static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-       int len = name->len;
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + len);
-       *p++ = cpu_to_be32(OP_SECINFO);
-       xdr_encode_opaque(p, name->name, len);
-       hdr->nops++;
-       hdr->replen += decode_secinfo_maxsz;
+       encode_op_hdr(xdr, OP_SECINFO, decode_secinfo_maxsz, hdr);
+       encode_string(xdr, name->len, name->name);
 }
 
 #if defined(CONFIG_NFS_V4_1)
@@ -1766,19 +1682,39 @@ static void encode_exchange_id(struct xdr_stream *xdr,
                               struct compound_hdr *hdr)
 {
        __be32 *p;
+       char impl_name[NFS4_OPAQUE_LIMIT];
+       int len = 0;
 
-       p = reserve_space(xdr, 4 + sizeof(args->verifier->data));
-       *p++ = cpu_to_be32(OP_EXCHANGE_ID);
-       xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data));
+       encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr);
+       encode_nfs4_verifier(xdr, args->verifier);
 
        encode_string(xdr, args->id_len, args->id);
 
        p = reserve_space(xdr, 12);
        *p++ = cpu_to_be32(args->flags);
        *p++ = cpu_to_be32(0);  /* zero length state_protect4_a */
-       *p = cpu_to_be32(0);    /* zero length implementation id array */
-       hdr->nops++;
-       hdr->replen += decode_exchange_id_maxsz;
+
+       if (send_implementation_id &&
+           sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 &&
+           sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN)
+               <= NFS4_OPAQUE_LIMIT + 1)
+               len = snprintf(impl_name, sizeof(impl_name), "%s %s %s %s",
+                              utsname()->sysname, utsname()->release,
+                              utsname()->version, utsname()->machine);
+
+       if (len > 0) {
+               *p = cpu_to_be32(1);    /* implementation id array length=1 */
+
+               encode_string(xdr,
+                       sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) - 1,
+                       CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN);
+               encode_string(xdr, len, impl_name);
+               /* just send zeros for nii_date - the date is in nii_name */
+               p = reserve_space(xdr, 12);
+               p = xdr_encode_hyper(p, 0);
+               *p = cpu_to_be32(0);
+       } else
+               *p = cpu_to_be32(0);    /* implementation id array length=0 */
 }
 
 static void encode_create_session(struct xdr_stream *xdr,
@@ -1801,8 +1737,8 @@ static void encode_create_session(struct xdr_stream *xdr,
        len = scnprintf(machine_name, sizeof(machine_name), "%s",
                        clp->cl_ipaddr);
 
-       p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12);
-       *p++ = cpu_to_be32(OP_CREATE_SESSION);
+       encode_op_hdr(xdr, OP_CREATE_SESSION, decode_create_session_maxsz, hdr);
+       p = reserve_space(xdr, 16 + 2*28 + 20 + len + 12);
        p = xdr_encode_hyper(p, clp->cl_clientid);
        *p++ = cpu_to_be32(clp->cl_seqid);                      /*Sequence id */
        *p++ = cpu_to_be32(args->flags);                        /*flags */
@@ -1835,33 +1771,22 @@ static void encode_create_session(struct xdr_stream *xdr,
        *p++ = cpu_to_be32(0);                          /* UID */
        *p++ = cpu_to_be32(0);                          /* GID */
        *p = cpu_to_be32(0);                            /* No more gids */
-       hdr->nops++;
-       hdr->replen += decode_create_session_maxsz;
 }
 
 static void encode_destroy_session(struct xdr_stream *xdr,
                                   struct nfs4_session *session,
                                   struct compound_hdr *hdr)
 {
-       __be32 *p;
-       p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN);
-       *p++ = cpu_to_be32(OP_DESTROY_SESSION);
-       xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
-       hdr->nops++;
-       hdr->replen += decode_destroy_session_maxsz;
+       encode_op_hdr(xdr, OP_DESTROY_SESSION, decode_destroy_session_maxsz, hdr);
+       encode_opaque_fixed(xdr, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
 }
 
 static void encode_reclaim_complete(struct xdr_stream *xdr,
                                    struct nfs41_reclaim_complete_args *args,
                                    struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(OP_RECLAIM_COMPLETE);
-       *p++ = cpu_to_be32(args->one_fs);
-       hdr->nops++;
-       hdr->replen += decode_reclaim_complete_maxsz;
+       encode_op_hdr(xdr, OP_RECLAIM_COMPLETE, decode_reclaim_complete_maxsz, hdr);
+       encode_uint32(xdr, args->one_fs);
 }
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -1883,8 +1808,7 @@ static void encode_sequence(struct xdr_stream *xdr,
        WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE);
        slot = tp->slots + args->sa_slotid;
 
-       p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16);
-       *p++ = cpu_to_be32(OP_SEQUENCE);
+       encode_op_hdr(xdr, OP_SEQUENCE, decode_sequence_maxsz, hdr);
 
        /*
         * Sessionid + seqid + slotid + max slotid + cache_this
@@ -1898,13 +1822,12 @@ static void encode_sequence(struct xdr_stream *xdr,
                ((u32 *)session->sess_id.data)[3],
                slot->seq_nr, args->sa_slotid,
                tp->highest_used_slotid, args->sa_cache_this);
+       p = reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 16);
        p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
        *p++ = cpu_to_be32(slot->seq_nr);
        *p++ = cpu_to_be32(args->sa_slotid);
        *p++ = cpu_to_be32(tp->highest_used_slotid);
        *p = cpu_to_be32(args->sa_cache_this);
-       hdr->nops++;
-       hdr->replen += decode_sequence_maxsz;
 #endif /* CONFIG_NFS_V4_1 */
 }
 
@@ -1919,14 +1842,12 @@ encode_getdevicelist(struct xdr_stream *xdr,
                .data = "dummmmmy",
        };
 
-       p = reserve_space(xdr, 20);
-       *p++ = cpu_to_be32(OP_GETDEVICELIST);
+       encode_op_hdr(xdr, OP_GETDEVICELIST, decode_getdevicelist_maxsz, hdr);
+       p = reserve_space(xdr, 16);
        *p++ = cpu_to_be32(args->layoutclass);
        *p++ = cpu_to_be32(NFS4_PNFS_GETDEVLIST_MAXNUM);
        xdr_encode_hyper(p, 0ULL);                          /* cookie */
        encode_nfs4_verifier(xdr, &dummy);
-       hdr->nops++;
-       hdr->replen += decode_getdevicelist_maxsz;
 }
 
 static void
@@ -1936,15 +1857,13 @@ encode_getdeviceinfo(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 16 + NFS4_DEVICEID4_SIZE);
-       *p++ = cpu_to_be32(OP_GETDEVICEINFO);
+       encode_op_hdr(xdr, OP_GETDEVICEINFO, decode_getdeviceinfo_maxsz, hdr);
+       p = reserve_space(xdr, 12 + NFS4_DEVICEID4_SIZE);
        p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data,
                                    NFS4_DEVICEID4_SIZE);
        *p++ = cpu_to_be32(args->pdev->layout_type);
        *p++ = cpu_to_be32(args->pdev->pglen);          /* gdia_maxcount */
        *p++ = cpu_to_be32(0);                          /* bitmap length 0 */
-       hdr->nops++;
-       hdr->replen += decode_getdeviceinfo_maxsz;
 }
 
 static void
@@ -1954,16 +1873,16 @@ encode_layoutget(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_LAYOUTGET);
+       encode_op_hdr(xdr, OP_LAYOUTGET, decode_layoutget_maxsz, hdr);
+       p = reserve_space(xdr, 36);
        *p++ = cpu_to_be32(0);     /* Signal layout available */
        *p++ = cpu_to_be32(args->type);
        *p++ = cpu_to_be32(args->range.iomode);
        p = xdr_encode_hyper(p, args->range.offset);
        p = xdr_encode_hyper(p, args->range.length);
        p = xdr_encode_hyper(p, args->minlength);
-       p = xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
-       *p = cpu_to_be32(args->maxcount);
+       encode_nfs4_stateid(xdr, &args->stateid);
+       encode_uint32(xdr, args->maxcount);
 
        dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n",
                __func__,
@@ -1972,8 +1891,6 @@ encode_layoutget(struct xdr_stream *xdr,
                (unsigned long)args->range.offset,
                (unsigned long)args->range.length,
                args->maxcount);
-       hdr->nops++;
-       hdr->replen += decode_layoutget_maxsz;
 }
 
 static int
@@ -1987,13 +1904,14 @@ encode_layoutcommit(struct xdr_stream *xdr,
        dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten,
                NFS_SERVER(args->inode)->pnfs_curr_ld->id);
 
-       p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_LAYOUTCOMMIT);
+       encode_op_hdr(xdr, OP_LAYOUTCOMMIT, decode_layoutcommit_maxsz, hdr);
+       p = reserve_space(xdr, 20);
        /* Only whole file layouts */
        p = xdr_encode_hyper(p, 0); /* offset */
        p = xdr_encode_hyper(p, args->lastbytewritten + 1);     /* length */
-       *p++ = cpu_to_be32(0); /* reclaim */
-       p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE);
+       *p = cpu_to_be32(0); /* reclaim */
+       encode_nfs4_stateid(xdr, &args->stateid);
+       p = reserve_space(xdr, 20);
        *p++ = cpu_to_be32(1); /* newoffset = TRUE */
        p = xdr_encode_hyper(p, args->lastbytewritten);
        *p++ = cpu_to_be32(0); /* Never send time_modify_changed */
@@ -2002,13 +1920,9 @@ encode_layoutcommit(struct xdr_stream *xdr,
        if (NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit)
                NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit(
                        NFS_I(inode)->layout, xdr, args);
-       else {
-               p = reserve_space(xdr, 4);
-               *p = cpu_to_be32(0); /* no layout-type payload */
-       }
+       else
+               encode_uint32(xdr, 0); /* no layout-type payload */
 
-       hdr->nops++;
-       hdr->replen += decode_layoutcommit_maxsz;
        return 0;
 }
 
@@ -2019,27 +1933,23 @@ encode_layoutreturn(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 20);
-       *p++ = cpu_to_be32(OP_LAYOUTRETURN);
+       encode_op_hdr(xdr, OP_LAYOUTRETURN, decode_layoutreturn_maxsz, hdr);
+       p = reserve_space(xdr, 16);
        *p++ = cpu_to_be32(0);          /* reclaim. always 0 for now */
        *p++ = cpu_to_be32(args->layout_type);
        *p++ = cpu_to_be32(IOMODE_ANY);
        *p = cpu_to_be32(RETURN_FILE);
-       p = reserve_space(xdr, 16 + NFS4_STATEID_SIZE);
+       p = reserve_space(xdr, 16);
        p = xdr_encode_hyper(p, 0);
        p = xdr_encode_hyper(p, NFS4_MAX_UINT64);
        spin_lock(&args->inode->i_lock);
-       xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
+       encode_nfs4_stateid(xdr, &args->stateid);
        spin_unlock(&args->inode->i_lock);
        if (NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn) {
                NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn(
                        NFS_I(args->inode)->layout, xdr, args);
-       } else {
-               p = reserve_space(xdr, 4);
-               *p = cpu_to_be32(0);
-       }
-       hdr->nops++;
-       hdr->replen += decode_layoutreturn_maxsz;
+       } else
+               encode_uint32(xdr, 0);
 }
 
 static int
@@ -2047,12 +1957,8 @@ encode_secinfo_no_name(struct xdr_stream *xdr,
                       const struct nfs41_secinfo_no_name_args *args,
                       struct compound_hdr *hdr)
 {
-       __be32 *p;
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(OP_SECINFO_NO_NAME);
-       *p++ = cpu_to_be32(args->style);
-       hdr->nops++;
-       hdr->replen += decode_secinfo_no_name_maxsz;
+       encode_op_hdr(xdr, OP_SECINFO_NO_NAME, decode_secinfo_no_name_maxsz, hdr);
+       encode_uint32(xdr, args->style);
        return 0;
 }
 
@@ -2060,26 +1966,17 @@ static void encode_test_stateid(struct xdr_stream *xdr,
                                struct nfs41_test_stateid_args *args,
                                struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_TEST_STATEID);
-       *p++ = cpu_to_be32(1);
-       xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_test_stateid_maxsz;
+       encode_op_hdr(xdr, OP_TEST_STATEID, decode_test_stateid_maxsz, hdr);
+       encode_uint32(xdr, 1);
+       encode_nfs4_stateid(xdr, args->stateid);
 }
 
 static void encode_free_stateid(struct xdr_stream *xdr,
                                struct nfs41_free_stateid_args *args,
                                struct compound_hdr *hdr)
 {
-       __be32 *p;
-       p = reserve_space(xdr, 4 + NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_FREE_STATEID);
-       xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_free_stateid_maxsz;
+       encode_op_hdr(xdr, OP_FREE_STATEID, decode_free_stateid_maxsz, hdr);
+       encode_nfs4_stateid(xdr, args->stateid);
 }
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -2633,6 +2530,7 @@ static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fhandle, &hdr);
        encode_getattr_one(xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
+                          FATTR4_WORD0_FH_EXPIRE_TYPE|
                           FATTR4_WORD0_LINK_SUPPORT|
                           FATTR4_WORD0_SYMLINK_SUPPORT|
                           FATTR4_WORD0_ACLSUPPORT, &hdr);
@@ -2650,7 +2548,7 @@ static void nfs4_xdr_enc_renew(struct rpc_rqst *req, struct xdr_stream *xdr,
        };
 
        encode_compound_hdr(xdr, req, &hdr);
-       encode_renew(xdr, clp, &hdr);
+       encode_renew(xdr, clp->cl_clientid, &hdr);
        encode_nops(&hdr);
 }
 
@@ -3180,6 +3078,28 @@ out_overflow:
        return -EIO;
 }
 
+static int decode_attr_fh_expire_type(struct xdr_stream *xdr,
+                                     uint32_t *bitmap, uint32_t *type)
+{
+       __be32 *p;
+
+       *type = 0;
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_FH_EXPIRE_TYPE - 1U)))
+               return -EIO;
+       if (likely(bitmap[0] & FATTR4_WORD0_FH_EXPIRE_TYPE)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       goto out_overflow;
+               *type = be32_to_cpup(p);
+               bitmap[0] &= ~FATTR4_WORD0_FH_EXPIRE_TYPE;
+       }
+       dprintk("%s: expire type=0x%x\n", __func__, *type);
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
 static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
 {
        __be32 *p;
@@ -3513,16 +3433,17 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
        n = be32_to_cpup(p);
        if (n == 0)
                goto root_path;
-       dprintk("path ");
+       dprintk("pathname4: ");
        path->ncomponents = 0;
        while (path->ncomponents < n) {
                struct nfs4_string *component = &path->components[path->ncomponents];
                status = decode_opaque_inline(xdr, &component->len, &component->data);
                if (unlikely(status != 0))
                        goto out_eio;
-               if (path->ncomponents != n)
-                       dprintk("/");
-               dprintk("%s", component->data);
+               ifdebug (XDR)
+                       pr_cont("%s%.*s ",
+                               (path->ncomponents != n ? "/ " : ""),
+                               component->len, component->data);
                if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
                        path->ncomponents++;
                else {
@@ -3531,14 +3452,13 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
                }
        }
 out:
-       dprintk("\n");
        return status;
 root_path:
 /* a root pathname is sent as a zero component4 */
        path->ncomponents = 1;
        path->components[0].len=0;
        path->components[0].data=NULL;
-       dprintk("path /\n");
+       dprintk("pathname4: /\n");
        goto out;
 out_eio:
        dprintk(" status %d", status);
@@ -3560,7 +3480,11 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
        status = 0;
        if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
                goto out;
-       dprintk("%s: fsroot ", __func__);
+       status = -EIO;
+       /* Ignore borken servers that return unrequested attrs */
+       if (unlikely(res == NULL))
+               goto out;
+       dprintk("%s: fsroot:\n", __func__);
        status = decode_pathname(xdr, &res->fs_path);
        if (unlikely(status != 0))
                goto out;
@@ -3581,7 +3505,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
                m = be32_to_cpup(p);
 
                loc->nservers = 0;
-               dprintk("%s: servers ", __func__);
+               dprintk("%s: servers:\n", __func__);
                while (loc->nservers < m) {
                        struct nfs4_string *server = &loc->servers[loc->nservers];
                        status = decode_opaque_inline(xdr, &server->len, &server->data);
@@ -3613,7 +3537,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
                        res->nlocations++;
        }
        if (res->nlocations != 0)
-               status = NFS_ATTR_FATTR_V4_REFERRAL;
+               status = NFS_ATTR_FATTR_V4_LOCATIONS;
 out:
        dprintk("%s: fs_locations done, error = %d\n", __func__, status);
        return status;
@@ -4157,7 +4081,7 @@ static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
 
 static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
 {
-       return decode_opaque_fixed(xdr, stateid->data, NFS4_STATEID_SIZE);
+       return decode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE);
 }
 
 static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
@@ -4174,7 +4098,7 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
 
 static int decode_verifier(struct xdr_stream *xdr, void *verifier)
 {
-       return decode_opaque_fixed(xdr, verifier, 8);
+       return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE);
 }
 
 static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
@@ -4224,6 +4148,9 @@ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_re
                goto xdr_error;
        if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
                goto xdr_error;
+       if ((status = decode_attr_fh_expire_type(xdr, bitmap,
+                                                &res->fh_expire_type)) != 0)
+               goto xdr_error;
        if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
                goto xdr_error;
        if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
@@ -4294,6 +4221,7 @@ xdr_error:
 
 static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                struct nfs_fattr *fattr, struct nfs_fh *fh,
+               struct nfs4_fs_locations *fs_loc,
                const struct nfs_server *server)
 {
        int status;
@@ -4341,9 +4269,7 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                goto xdr_error;
        fattr->valid |= status;
 
-       status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
-                                               struct nfs4_fs_locations,
-                                               fattr));
+       status = decode_attr_fs_locations(xdr, bitmap, fs_loc);
        if (status < 0)
                goto xdr_error;
        fattr->valid |= status;
@@ -4407,7 +4333,8 @@ xdr_error:
 }
 
 static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
-               struct nfs_fh *fh, const struct nfs_server *server)
+               struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc,
+               const struct nfs_server *server)
 {
        __be32 *savep;
        uint32_t attrlen,
@@ -4426,7 +4353,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
        if (status < 0)
                goto xdr_error;
 
-       status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server);
+       status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, server);
        if (status < 0)
                goto xdr_error;
 
@@ -4439,7 +4366,7 @@ xdr_error:
 static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
                const struct nfs_server *server)
 {
-       return decode_getfattr_generic(xdr, fattr, NULL, server);
+       return decode_getfattr_generic(xdr, fattr, NULL, NULL, server);
 }
 
 /*
@@ -4463,8 +4390,8 @@ static int decode_first_pnfs_layout_type(struct xdr_stream *xdr,
                return 0;
        }
        if (num > 1)
-               printk(KERN_INFO "%s: Warning: Multiple pNFS layout drivers "
-                       "per filesystem not supported\n", __func__);
+               printk(KERN_INFO "NFS: %s: Warning: Multiple pNFS layout "
+                       "drivers per filesystem not supported\n", __func__);
 
        /* Decode and set first layout type, move xdr->p past unused types */
        p = xdr_inline_decode(xdr, num * 4);
@@ -4863,17 +4790,16 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
        size_t          hdrlen;
        u32             recvd, pglen = rcvbuf->page_len;
        int             status;
+       __be32          verf[2];
 
        status = decode_op_hdr(xdr, OP_READDIR);
        if (!status)
                status = decode_verifier(xdr, readdir->verifier.data);
        if (unlikely(status))
                return status;
+       memcpy(verf, readdir->verifier.data, sizeof(verf));
        dprintk("%s: verifier = %08x:%08x\n",
-                       __func__,
-                       ((u32 *)readdir->verifier.data)[0],
-                       ((u32 *)readdir->verifier.data)[1]);
-
+                       __func__, verf[0], verf[1]);
 
        hdrlen = (char *) xdr->p - (char *) iov->iov_base;
        recvd = rcvbuf->len - hdrlen;
@@ -5120,7 +5046,7 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
                goto out_overflow;
        res->count = be32_to_cpup(p++);
        res->verf->committed = be32_to_cpup(p++);
-       memcpy(res->verf->verifier, p, 8);
+       memcpy(res->verf->verifier, p, NFS4_VERIFIER_SIZE);
        return 0;
 out_overflow:
        print_overflow_msg(__func__, xdr);
@@ -5214,6 +5140,7 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        char *dummy_str;
        int status;
        struct nfs_client *clp = res->client;
+       uint32_t impl_id_count;
 
        status = decode_op_hdr(xdr, OP_EXCHANGE_ID);
        if (status)
@@ -5255,11 +5182,38 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        memcpy(res->server_scope->server_scope, dummy_str, dummy);
        res->server_scope->server_scope_sz = dummy;
 
-       /* Throw away Implementation id array */
-       status = decode_opaque_inline(xdr, &dummy, &dummy_str);
-       if (unlikely(status))
-               return status;
+       /* Implementation Id */
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       impl_id_count = be32_to_cpup(p++);
+
+       if (impl_id_count) {
+               /* nii_domain */
+               status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+               if (unlikely(status))
+                       return status;
+               if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+                       return -EIO;
+               memcpy(res->impl_id->domain, dummy_str, dummy);
 
+               /* nii_name */
+               status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+               if (unlikely(status))
+                       return status;
+               if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+                       return -EIO;
+               memcpy(res->impl_id->name, dummy_str, dummy);
+
+               /* nii_date */
+               p = xdr_inline_decode(xdr, 12);
+               if (unlikely(!p))
+                       goto out_overflow;
+               p = xdr_decode_hyper(p, &res->impl_id->date.seconds);
+               res->impl_id->date.nseconds = be32_to_cpup(p);
+
+               /* if there's more than one entry, ignore the rest */
+       }
        return 0;
 out_overflow:
        print_overflow_msg(__func__, xdr);
@@ -5285,8 +5239,8 @@ static int decode_chan_attrs(struct xdr_stream *xdr,
        attrs->max_reqs = be32_to_cpup(p++);
        nr_attrs = be32_to_cpup(p);
        if (unlikely(nr_attrs > 1)) {
-               printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n",
-                       __func__, nr_attrs);
+               printk(KERN_WARNING "NFS: %s: Invalid rdma channel attrs "
+                       "count %u\n", __func__, nr_attrs);
                return -EINVAL;
        }
        if (nr_attrs == 1) {
@@ -5436,14 +5390,14 @@ static int decode_getdevicelist(struct xdr_stream *xdr,
        p += 2;
 
        /* Read verifier */
-       p = xdr_decode_opaque_fixed(p, verftemp.verifier, 8);
+       p = xdr_decode_opaque_fixed(p, verftemp.verifier, NFS4_VERIFIER_SIZE);
 
        res->num_devs = be32_to_cpup(p);
 
        dprintk("%s: num_dev %d\n", __func__, res->num_devs);
 
        if (res->num_devs > NFS4_PNFS_GETDEVLIST_MAXNUM) {
-               printk(KERN_ERR "%s too many result dev_num %u\n",
+               printk(KERN_ERR "NFS: %s too many result dev_num %u\n",
                                __func__, res->num_devs);
                return -EIO;
        }
@@ -5537,11 +5491,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
        status = decode_op_hdr(xdr, OP_LAYOUTGET);
        if (status)
                return status;
-       p = xdr_inline_decode(xdr, 8 + NFS4_STATEID_SIZE);
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       res->return_on_close = be32_to_cpup(p);
+       decode_stateid(xdr, &res->stateid);
+       p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
                goto out_overflow;
-       res->return_on_close = be32_to_cpup(p++);
-       p = xdr_decode_opaque_fixed(p, res->stateid.data, NFS4_STATEID_SIZE);
        layout_count = be32_to_cpup(p);
        if (!layout_count) {
                dprintk("%s: server responded with empty layout array\n",
@@ -5666,7 +5623,8 @@ static int decode_test_stateid(struct xdr_stream *xdr,
        if (unlikely(!p))
                goto out_overflow;
        res->status = be32_to_cpup(p++);
-       return res->status;
+
+       return status;
 out_overflow:
        print_overflow_msg(__func__, xdr);
 out:
@@ -6583,8 +6541,9 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
        if (status)
                goto out;
        xdr_enter_page(xdr, PAGE_SIZE);
-       status = decode_getfattr(xdr, &res->fs_locations->fattr,
-                                res->fs_locations->server);
+       status = decode_getfattr_generic(xdr, &res->fs_locations->fattr,
+                                        NULL, res->fs_locations,
+                                        res->fs_locations->server);
 out:
        return status;
 }
@@ -6964,7 +6923,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                goto out_overflow;
 
        if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
-                                       entry->server) < 0)
+                                 NULL, entry->server) < 0)
                goto out_overflow;
        if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
                entry->ino = entry->fattr->mounted_on_fileid;
@@ -7112,7 +7071,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
 #endif /* CONFIG_NFS_V4_1 */
 };
 
-struct rpc_version             nfs_version4 = {
+const struct rpc_version nfs_version4 = {
        .number                 = 4,
        .nrprocs                = ARRAY_SIZE(nfs4_procedures),
        .procs                  = nfs4_procedures
index c4744e1..cd3c910 100644 (file)
@@ -104,7 +104,7 @@ static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = "";
 /* server:export path string passed to super.c */
 static char nfs_root_device[NFS_MAXPATHLEN + 1] __initdata = "";
 
-#ifdef RPC_DEBUG
+#ifdef NFS_DEBUG
 /*
  * When the "nfsrootdebug" kernel command line option is specified,
  * enable debugging messages for NFSROOT.
index 55d0128..4bff4a3 100644 (file)
@@ -137,6 +137,7 @@ static int objio_devices_lookup(struct pnfs_layout_hdr *pnfslay,
        struct objio_dev_ent *ode;
        struct osd_dev *od;
        struct osd_dev_info odi;
+       bool retry_flag = true;
        int err;
 
        ode = _dev_list_find(NFS_SERVER(pnfslay->plh_inode), d_id);
@@ -171,10 +172,18 @@ static int objio_devices_lookup(struct pnfs_layout_hdr *pnfslay,
                goto out;
        }
 
+retry_lookup:
        od = osduld_info_lookup(&odi);
        if (unlikely(IS_ERR(od))) {
                err = PTR_ERR(od);
                dprintk("%s: osduld_info_lookup => %d\n", __func__, err);
+               if (err == -ENODEV && retry_flag) {
+                       err = objlayout_autologin(deviceaddr);
+                       if (likely(!err)) {
+                               retry_flag = false;
+                               goto retry_lookup;
+                       }
+               }
                goto out;
        }
 
@@ -205,25 +214,36 @@ static void copy_single_comp(struct ore_components *oc, unsigned c,
 int __alloc_objio_seg(unsigned numdevs, gfp_t gfp_flags,
                       struct objio_segment **pseg)
 {
-       struct __alloc_objio_segment {
-               struct objio_segment olseg;
-               struct ore_dev *ods[numdevs];
-               struct ore_comp comps[numdevs];
-       } *aolseg;
-
-       aolseg = kzalloc(sizeof(*aolseg), gfp_flags);
-       if (unlikely(!aolseg)) {
+/*     This is the in memory structure of the objio_segment
+ *
+ *     struct __alloc_objio_segment {
+ *             struct objio_segment olseg;
+ *             struct ore_dev *ods[numdevs];
+ *             struct ore_comp comps[numdevs];
+ *     } *aolseg;
+ *     NOTE: The code as above compiles and runs perfectly. It is elegant,
+ *     type safe and compact. At some Past time Linus has decided he does not
+ *     like variable length arrays, For the sake of this principal we uglify
+ *     the code as below.
+ */
+       struct objio_segment *lseg;
+       size_t lseg_size = sizeof(*lseg) +
+                       numdevs * sizeof(lseg->oc.ods[0]) +
+                       numdevs * sizeof(*lseg->oc.comps);
+
+       lseg = kzalloc(lseg_size, gfp_flags);
+       if (unlikely(!lseg)) {
                dprintk("%s: Faild allocation numdevs=%d size=%zd\n", __func__,
-                       numdevs, sizeof(*aolseg));
+                       numdevs, lseg_size);
                return -ENOMEM;
        }
 
-       aolseg->olseg.oc.numdevs = numdevs;
-       aolseg->olseg.oc.single_comp = EC_MULTPLE_COMPS;
-       aolseg->olseg.oc.comps = aolseg->comps;
-       aolseg->olseg.oc.ods = aolseg->ods;
+       lseg->oc.numdevs = numdevs;
+       lseg->oc.single_comp = EC_MULTPLE_COMPS;
+       lseg->oc.ods = (void *)(lseg + 1);
+       lseg->oc.comps = (void *)(lseg->oc.ods + numdevs);
 
-       *pseg = &aolseg->olseg;
+       *pseg = lseg;
        return 0;
 }
 
@@ -582,10 +602,10 @@ objlayout_init(void)
 
        if (ret)
                printk(KERN_INFO
-                       "%s: Registering OSD pNFS Layout Driver failed: error=%d\n",
+                       "NFS: %s: Registering OSD pNFS Layout Driver failed: error=%d\n",
                        __func__, ret);
        else
-               printk(KERN_INFO "%s: Registered OSD pNFS Layout Driver\n",
+               printk(KERN_INFO "NFS: %s: Registered OSD pNFS Layout Driver\n",
                        __func__);
        return ret;
 }
@@ -594,7 +614,7 @@ static void __exit
 objlayout_exit(void)
 {
        pnfs_unregister_layoutdriver(&objlayout_type);
-       printk(KERN_INFO "%s: Unregistered OSD pNFS Layout Driver\n",
+       printk(KERN_INFO "NFS: %s: Unregistered OSD pNFS Layout Driver\n",
               __func__);
 }
 
index b3c2903..8d45f1c 100644 (file)
@@ -37,6 +37,9 @@
  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <linux/kmod.h>
+#include <linux/moduleparam.h>
+#include <linux/ratelimit.h>
 #include <scsi/osd_initiator.h>
 #include "objlayout.h"
 
@@ -156,7 +159,7 @@ last_byte_offset(u64 start, u64 len)
        return end > start ? end - 1 : NFS4_MAX_UINT64;
 }
 
-void _fix_verify_io_params(struct pnfs_layout_segment *lseg,
+static void _fix_verify_io_params(struct pnfs_layout_segment *lseg,
                           struct page ***p_pages, unsigned *p_pgbase,
                           u64 offset, unsigned long count)
 {
@@ -490,9 +493,9 @@ encode_accumulated_error(struct objlayout *objlay, __be32 *p)
                        if (!ioerr->oer_errno)
                                continue;
 
-                       printk(KERN_ERR "%s: err[%d]: errno=%d is_write=%d "
-                               "dev(%llx:%llx) par=0x%llx obj=0x%llx "
-                               "offset=0x%llx length=0x%llx\n",
+                       printk(KERN_ERR "NFS: %s: err[%d]: errno=%d "
+                               "is_write=%d dev(%llx:%llx) par=0x%llx "
+                               "obj=0x%llx offset=0x%llx length=0x%llx\n",
                                __func__, i, ioerr->oer_errno,
                                ioerr->oer_iswrite,
                                _DEVID_LO(&ioerr->oer_component.oid_device_id),
@@ -651,3 +654,134 @@ void objlayout_put_deviceinfo(struct pnfs_osd_deviceaddr *deviceaddr)
        __free_page(odi->page);
        kfree(odi);
 }
+
+enum {
+       OBJLAYOUT_MAX_URI_LEN = 256, OBJLAYOUT_MAX_OSDNAME_LEN = 64,
+       OBJLAYOUT_MAX_SYSID_HEX_LEN = OSD_SYSTEMID_LEN * 2 + 1,
+       OSD_LOGIN_UPCALL_PATHLEN  = 256
+};
+
+static char osd_login_prog[OSD_LOGIN_UPCALL_PATHLEN] = "/sbin/osd_login";
+
+module_param_string(osd_login_prog, osd_login_prog, sizeof(osd_login_prog),
+                   0600);
+MODULE_PARM_DESC(osd_login_prog, "Path to the osd_login upcall program");
+
+struct __auto_login {
+       char uri[OBJLAYOUT_MAX_URI_LEN];
+       char osdname[OBJLAYOUT_MAX_OSDNAME_LEN];
+       char systemid_hex[OBJLAYOUT_MAX_SYSID_HEX_LEN];
+};
+
+static int __objlayout_upcall(struct __auto_login *login)
+{
+       static char *envp[] = { "HOME=/",
+               "TERM=linux",
+               "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+               NULL
+       };
+       char *argv[8];
+       int ret;
+
+       if (unlikely(!osd_login_prog[0])) {
+               dprintk("%s: osd_login_prog is disabled\n", __func__);
+               return -EACCES;
+       }
+
+       dprintk("%s uri: %s\n", __func__, login->uri);
+       dprintk("%s osdname %s\n", __func__, login->osdname);
+       dprintk("%s systemid_hex %s\n", __func__, login->systemid_hex);
+
+       argv[0] = (char *)osd_login_prog;
+       argv[1] = "-u";
+       argv[2] = login->uri;
+       argv[3] = "-o";
+       argv[4] = login->osdname;
+       argv[5] = "-s";
+       argv[6] = login->systemid_hex;
+       argv[7] = NULL;
+
+       ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+       /*
+        * Disable the upcall mechanism if we're getting an ENOENT or
+        * EACCES error. The admin can re-enable it on the fly by using
+        * sysfs to set the objlayoutdriver.osd_login_prog module parameter once
+        * the problem has been fixed.
+        */
+       if (ret == -ENOENT || ret == -EACCES) {
+               printk(KERN_ERR "PNFS-OBJ: %s was not found please set "
+                       "objlayoutdriver.osd_login_prog kernel parameter!\n",
+                       osd_login_prog);
+               osd_login_prog[0] = '\0';
+       }
+       dprintk("%s %s return value: %d\n", __func__, osd_login_prog, ret);
+
+       return ret;
+}
+
+/* Assume dest is all zeros */
+static void __copy_nfsS_and_zero_terminate(struct nfs4_string s,
+                                          char *dest, int max_len,
+                                          const char *var_name)
+{
+       if (!s.len)
+               return;
+
+       if (s.len >= max_len) {
+               pr_warn_ratelimited(
+                       "objlayout_autologin: %s: s.len(%d) >= max_len(%d)",
+                       var_name, s.len, max_len);
+               s.len = max_len - 1; /* space for null terminator */
+       }
+
+       memcpy(dest, s.data, s.len);
+}
+
+/* Assume sysid is all zeros */
+static void _sysid_2_hex(struct nfs4_string s,
+                 char sysid[OBJLAYOUT_MAX_SYSID_HEX_LEN])
+{
+       int i;
+       char *cur;
+
+       if (!s.len)
+               return;
+
+       if (s.len != OSD_SYSTEMID_LEN) {
+               pr_warn_ratelimited(
+                   "objlayout_autologin: systemid_len(%d) != OSD_SYSTEMID_LEN",
+                   s.len);
+               if (s.len > OSD_SYSTEMID_LEN)
+                       s.len = OSD_SYSTEMID_LEN;
+       }
+
+       cur = sysid;
+       for (i = 0; i < s.len; i++)
+               cur = hex_byte_pack(cur, s.data[i]);
+}
+
+int objlayout_autologin(struct pnfs_osd_deviceaddr *deviceaddr)
+{
+       int rc;
+       struct __auto_login login;
+
+       if (!deviceaddr->oda_targetaddr.ota_netaddr.r_addr.len)
+               return -ENODEV;
+
+       memset(&login, 0, sizeof(login));
+       __copy_nfsS_and_zero_terminate(
+               deviceaddr->oda_targetaddr.ota_netaddr.r_addr,
+               login.uri, sizeof(login.uri), "URI");
+
+       __copy_nfsS_and_zero_terminate(
+               deviceaddr->oda_osdname,
+               login.osdname, sizeof(login.osdname), "OSDNAME");
+
+       _sysid_2_hex(deviceaddr->oda_systemid, login.systemid_hex);
+
+       rc = __objlayout_upcall(&login);
+       if (rc > 0) /* script returns positive values */
+               rc = -ENODEV;
+
+       return rc;
+}
index 8ec3472..880ba08 100644 (file)
@@ -184,4 +184,6 @@ extern void objlayout_encode_layoutreturn(
        struct xdr_stream *,
        const struct nfs4_layoutreturn_args *);
 
+extern int objlayout_autologin(struct pnfs_osd_deviceaddr *deviceaddr);
+
 #endif /* _OBJLAYOUT_H */
index 5668f7c..d21fcea 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/file.h>
 #include <linux/sched.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
 #include <linux/nfs3.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_page.h>
@@ -106,36 +107,6 @@ void nfs_unlock_request(struct nfs_page *req)
        nfs_release_request(req);
 }
 
-/**
- * nfs_set_page_tag_locked - Tag a request as locked
- * @req:
- */
-int nfs_set_page_tag_locked(struct nfs_page *req)
-{
-       if (!nfs_lock_request_dontget(req))
-               return 0;
-       if (test_bit(PG_MAPPED, &req->wb_flags))
-               radix_tree_tag_set(&NFS_I(req->wb_context->dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
-       return 1;
-}
-
-/**
- * nfs_clear_page_tag_locked - Clear request tag and wake up sleepers
- */
-void nfs_clear_page_tag_locked(struct nfs_page *req)
-{
-       if (test_bit(PG_MAPPED, &req->wb_flags)) {
-               struct inode *inode = req->wb_context->dentry->d_inode;
-               struct nfs_inode *nfsi = NFS_I(inode);
-
-               spin_lock(&inode->i_lock);
-               radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
-               nfs_unlock_request(req);
-               spin_unlock(&inode->i_lock);
-       } else
-               nfs_unlock_request(req);
-}
-
 /*
  * nfs_clear_request - Free up all resources allocated to the request
  * @req:
@@ -425,67 +396,6 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
        }
 }
 
-#define NFS_SCAN_MAXENTRIES 16
-/**
- * nfs_scan_list - Scan a list for matching requests
- * @nfsi: NFS inode
- * @dst: Destination list
- * @idx_start: lower bound of page->index to scan
- * @npages: idx_start + npages sets the upper bound to scan.
- * @tag: tag to scan for
- *
- * Moves elements from one of the inode request lists.
- * If the number of requests is set to 0, the entire address_space
- * starting at index idx_start, is scanned.
- * The requests are *not* checked to ensure that they form a contiguous set.
- * You must be holding the inode's i_lock when calling this function
- */
-int nfs_scan_list(struct nfs_inode *nfsi,
-               struct list_head *dst, pgoff_t idx_start,
-               unsigned int npages, int tag)
-{
-       struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
-       struct nfs_page *req;
-       pgoff_t idx_end;
-       int found, i;
-       int res;
-       struct list_head *list;
-
-       res = 0;
-       if (npages == 0)
-               idx_end = ~0;
-       else
-               idx_end = idx_start + npages - 1;
-
-       for (;;) {
-               found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree,
-                               (void **)&pgvec[0], idx_start,
-                               NFS_SCAN_MAXENTRIES, tag);
-               if (found <= 0)
-                       break;
-               for (i = 0; i < found; i++) {
-                       req = pgvec[i];
-                       if (req->wb_index > idx_end)
-                               goto out;
-                       idx_start = req->wb_index + 1;
-                       if (nfs_set_page_tag_locked(req)) {
-                               kref_get(&req->wb_kref);
-                               radix_tree_tag_clear(&nfsi->nfs_page_tree,
-                                               req->wb_index, tag);
-                               list = pnfs_choose_commit_list(req, dst);
-                               nfs_list_add_request(req, list);
-                               res++;
-                               if (res == INT_MAX)
-                                       goto out;
-                       }
-               }
-               /* for latency reduction */
-               cond_resched_lock(&nfsi->vfs_inode.i_lock);
-       }
-out:
-       return res;
-}
-
 int __init nfs_init_nfspagecache(void)
 {
        nfs_page_cachep = kmem_cache_create("nfs_page",
index 17149a4..b5d4515 100644 (file)
@@ -101,8 +101,8 @@ set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
                goto out_no_driver;
        if (!(server->nfs_client->cl_exchange_flags &
                 (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
-               printk(KERN_ERR "%s: id %u cl_exchange_flags 0x%x\n", __func__,
-                      id, server->nfs_client->cl_exchange_flags);
+               printk(KERN_ERR "NFS: %s: id %u cl_exchange_flags 0x%x\n",
+                       __func__, id, server->nfs_client->cl_exchange_flags);
                goto out_no_driver;
        }
        ld_type = find_pnfs_driver(id);
@@ -122,8 +122,8 @@ set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
        server->pnfs_curr_ld = ld_type;
        if (ld_type->set_layoutdriver
            && ld_type->set_layoutdriver(server, mntfh)) {
-               printk(KERN_ERR "%s: Error initializing pNFS layout driver %u.\n",
-                               __func__, id);
+               printk(KERN_ERR "NFS: %s: Error initializing pNFS layout "
+                       "driver %u.\n", __func__, id);
                module_put(ld_type->owner);
                goto out_no_driver;
        }
@@ -143,11 +143,11 @@ pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
        struct pnfs_layoutdriver_type *tmp;
 
        if (ld_type->id == 0) {
-               printk(KERN_ERR "%s id 0 is reserved\n", __func__);
+               printk(KERN_ERR "NFS: %s id 0 is reserved\n", __func__);
                return status;
        }
        if (!ld_type->alloc_lseg || !ld_type->free_lseg) {
-               printk(KERN_ERR "%s Layout driver must provide "
+               printk(KERN_ERR "NFS: %s Layout driver must provide "
                       "alloc_lseg and free_lseg.\n", __func__);
                return status;
        }
@@ -160,7 +160,7 @@ pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
                dprintk("%s Registering id:%u name:%s\n", __func__, ld_type->id,
                        ld_type->name);
        } else {
-               printk(KERN_ERR "%s Module with id %d already loaded!\n",
+               printk(KERN_ERR "NFS: %s Module with id %d already loaded!\n",
                        __func__, ld_type->id);
        }
        spin_unlock(&pnfs_spinlock);
@@ -496,12 +496,12 @@ pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new,
 {
        u32 oldseq, newseq;
 
-       oldseq = be32_to_cpu(lo->plh_stateid.stateid.seqid);
-       newseq = be32_to_cpu(new->stateid.seqid);
+       oldseq = be32_to_cpu(lo->plh_stateid.seqid);
+       newseq = be32_to_cpu(new->seqid);
        if ((int)(newseq - oldseq) > 0) {
-               memcpy(&lo->plh_stateid, &new->stateid, sizeof(new->stateid));
+               nfs4_stateid_copy(&lo->plh_stateid, new);
                if (update_barrier) {
-                       u32 new_barrier = be32_to_cpu(new->stateid.seqid);
+                       u32 new_barrier = be32_to_cpu(new->seqid);
 
                        if ((int)(new_barrier - lo->plh_barrier))
                                lo->plh_barrier = new_barrier;
@@ -525,7 +525,7 @@ pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid,
                        int lget)
 {
        if ((stateid) &&
-           (int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0)
+           (int)(lo->plh_barrier - be32_to_cpu(stateid->seqid)) >= 0)
                return true;
        return lo->plh_block_lgets ||
                test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) ||
@@ -549,11 +549,10 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
 
                do {
                        seq = read_seqbegin(&open_state->seqlock);
-                       memcpy(dst->data, open_state->stateid.data,
-                              sizeof(open_state->stateid.data));
+                       nfs4_stateid_copy(dst, &open_state->stateid);
                } while (read_seqretry(&open_state->seqlock, seq));
        } else
-               memcpy(dst->data, lo->plh_stateid.data, sizeof(lo->plh_stateid.data));
+               nfs4_stateid_copy(dst, &lo->plh_stateid);
        spin_unlock(&lo->plh_inode->i_lock);
        dprintk("<-- %s\n", __func__);
        return status;
@@ -590,7 +589,7 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
        max_pages = max_resp_sz >> PAGE_SHIFT;
 
-       pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags);
+       pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
        if (!pages)
                goto out_err_free;
 
@@ -760,7 +759,7 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier)
                }
        if (!found) {
                struct pnfs_layout_hdr *lo = nfsi->layout;
-               u32 current_seqid = be32_to_cpu(lo->plh_stateid.stateid.seqid);
+               u32 current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
 
                /* Since close does not return a layout stateid for use as
                 * a barrier, we choose the worst-case barrier.
@@ -966,8 +965,7 @@ pnfs_update_layout(struct inode *ino,
        }
 
        /* Do we even need to bother with this? */
-       if (test_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state) ||
-           test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
+       if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
                dprintk("%s matches recall, use MDS\n", __func__);
                goto out_unlock;
        }
@@ -1032,7 +1030,6 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
        struct nfs4_layoutget_res *res = &lgp->res;
        struct pnfs_layout_segment *lseg;
        struct inode *ino = lo->plh_inode;
-       struct nfs_client *clp = NFS_SERVER(ino)->nfs_client;
        int status = 0;
 
        /* Inject layout blob into I/O device driver */
@@ -1048,8 +1045,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
        }
 
        spin_lock(&ino->i_lock);
-       if (test_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state) ||
-           test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
+       if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
                dprintk("%s forget reply due to recall\n", __func__);
                goto out_forget_reply;
        }
@@ -1214,6 +1210,7 @@ void pnfs_ld_write_done(struct nfs_write_data *data)
                }
                data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages);
        }
+       put_lseg(data->lseg);
        data->mds_ops->rpc_release(data);
 }
 EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
@@ -1227,6 +1224,7 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
                nfs_list_add_request(data->req, &desc->pg_list);
        nfs_pageio_reset_write_mds(desc);
        desc->pg_recoalesce = 1;
+       put_lseg(data->lseg);
        nfs_writedata_release(data);
 }
 
@@ -1327,6 +1325,7 @@ void pnfs_ld_read_done(struct nfs_read_data *data)
                data->mds_ops->rpc_call_done(&data->task, data);
        } else
                pnfs_ld_handle_read_error(data);
+       put_lseg(data->lseg);
        data->mds_ops->rpc_release(data);
 }
 EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
@@ -1530,8 +1529,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
        end_pos = nfsi->layout->plh_lwb;
        nfsi->layout->plh_lwb = 0;
 
-       memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data,
-               sizeof(nfsi->layout->plh_stateid.data));
+       nfs4_stateid_copy(&data->args.stateid, &nfsi->layout->plh_stateid);
        spin_unlock(&inode->i_lock);
 
        data->args.inode = inode;
index 53d593a..442ebf6 100644 (file)
@@ -94,11 +94,10 @@ struct pnfs_layoutdriver_type {
        const struct nfs_pageio_ops *pg_read_ops;
        const struct nfs_pageio_ops *pg_write_ops;
 
-       /* Returns true if layoutdriver wants to divert this request to
-        * driver's commit routine.
-        */
-       bool (*mark_pnfs_commit)(struct pnfs_layout_segment *lseg);
-       struct list_head * (*choose_commit_list) (struct nfs_page *req);
+       void (*mark_request_commit) (struct nfs_page *req,
+                                       struct pnfs_layout_segment *lseg);
+       void (*clear_request_commit) (struct nfs_page *req);
+       int (*scan_commit_lists) (struct inode *inode, int max, spinlock_t *lock);
        int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how);
 
        /*
@@ -229,7 +228,6 @@ struct nfs4_deviceid_node {
        atomic_t                        ref;
 };
 
-void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id);
 struct nfs4_deviceid_node *nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
 void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
 void nfs4_init_deviceid_node(struct nfs4_deviceid_node *,
@@ -262,20 +260,6 @@ static inline int pnfs_enabled_sb(struct nfs_server *nfss)
        return nfss->pnfs_curr_ld != NULL;
 }
 
-static inline void
-pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
-{
-       if (lseg) {
-               struct pnfs_layoutdriver_type *ld;
-
-               ld = NFS_SERVER(req->wb_page->mapping->host)->pnfs_curr_ld;
-               if (ld->mark_pnfs_commit && ld->mark_pnfs_commit(lseg)) {
-                       set_bit(PG_PNFS_COMMIT, &req->wb_flags);
-                       req->wb_commit_lseg = get_lseg(lseg);
-               }
-       }
-}
-
 static inline int
 pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
 {
@@ -284,27 +268,42 @@ pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
        return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how);
 }
 
-static inline struct list_head *
-pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
+static inline bool
+pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 {
-       struct list_head *rv;
+       struct inode *inode = req->wb_context->dentry->d_inode;
+       struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
 
-       if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) {
-               struct inode *inode = req->wb_commit_lseg->pls_layout->plh_inode;
+       if (lseg == NULL || ld->mark_request_commit == NULL)
+               return false;
+       ld->mark_request_commit(req, lseg);
+       return true;
+}
 
-               set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags);
-               rv = NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list(req);
-               /* matched by ref taken when PG_PNFS_COMMIT is set */
-               put_lseg(req->wb_commit_lseg);
-       } else
-               rv = mds;
-       return rv;
+static inline bool
+pnfs_clear_request_commit(struct nfs_page *req)
+{
+       struct inode *inode = req->wb_context->dentry->d_inode;
+       struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
+
+       if (ld == NULL || ld->clear_request_commit == NULL)
+               return false;
+       ld->clear_request_commit(req);
+       return true;
 }
 
-static inline void pnfs_clear_request_commit(struct nfs_page *req)
+static inline int
+pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock)
 {
-       if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags))
-               put_lseg(req->wb_commit_lseg);
+       struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
+       int ret;
+
+       if (ld == NULL || ld->scan_commit_lists == NULL)
+               return 0;
+       ret = ld->scan_commit_lists(inode, max, lock);
+       if (ret != 0)
+               set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags);
+       return ret;
 }
 
 /* Should the pNFS client commit and return the layout upon a setattr */
@@ -328,6 +327,13 @@ static inline int pnfs_return_layout(struct inode *ino)
        return 0;
 }
 
+#ifdef NFS_DEBUG
+void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id);
+#else
+static inline void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id)
+{
+}
+#endif /* NFS_DEBUG */
 #else  /* CONFIG_NFS_V4_1 */
 
 static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
@@ -400,35 +406,35 @@ static inline bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, st
        return false;
 }
 
-static inline void
-pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
-{
-}
-
 static inline int
 pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
 {
        return PNFS_NOT_ATTEMPTED;
 }
 
-static inline struct list_head *
-pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
+static inline bool
+pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 {
-       return mds;
+       return false;
 }
 
-static inline void pnfs_clear_request_commit(struct nfs_page *req)
+static inline bool
+pnfs_clear_request_commit(struct nfs_page *req)
 {
+       return false;
 }
 
-static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync)
+static inline int
+pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock)
 {
        return 0;
 }
 
-static inline void nfs4_deviceid_purge_client(struct nfs_client *ncl)
+static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 {
+       return 0;
 }
+
 #endif /* CONFIG_NFS_V4_1 */
 
 #endif /* FS_NFS_PNFS_H */
index 4f359d2..73f701f 100644 (file)
@@ -43,6 +43,7 @@
 static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];
 static DEFINE_SPINLOCK(nfs4_deviceid_lock);
 
+#ifdef NFS_DEBUG
 void
 nfs4_print_deviceid(const struct nfs4_deviceid *id)
 {
@@ -52,6 +53,7 @@ nfs4_print_deviceid(const struct nfs4_deviceid *id)
                p[0], p[1], p[2], p[3]);
 }
 EXPORT_SYMBOL_GPL(nfs4_print_deviceid);
+#endif
 
 static inline u32
 nfs4_deviceid_hash(const struct nfs4_deviceid *id)
@@ -92,7 +94,7 @@ _lookup_deviceid(const struct pnfs_layoutdriver_type *ld,
  * @clp nfs_client associated with deviceid
  * @id deviceid to look up
  */
-struct nfs4_deviceid_node *
+static struct nfs4_deviceid_node *
 _find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
                   const struct nfs_client *clp, const struct nfs4_deviceid *id,
                   long hash)
index 0c67258..b63b6f4 100644 (file)
@@ -358,6 +358,11 @@ nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
        msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE];
 }
 
+static void nfs_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
+{
+       rpc_call_start(task);
+}
+
 static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
        if (nfs_async_handle_expired_key(task))
@@ -372,6 +377,11 @@ nfs_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
        msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME];
 }
 
+static void nfs_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
+{
+       rpc_call_start(task);
+}
+
 static int
 nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
                     struct inode *new_dir)
@@ -651,6 +661,11 @@ static void nfs_proc_read_setup(struct nfs_read_data *data, struct rpc_message *
        msg->rpc_proc = &nfs_procedures[NFSPROC_READ];
 }
 
+static void nfs_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+{
+       rpc_call_start(task);
+}
+
 static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
 {
        if (nfs_async_handle_expired_key(task))
@@ -668,6 +683,11 @@ static void nfs_proc_write_setup(struct nfs_write_data *data, struct rpc_message
        msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE];
 }
 
+static void nfs_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+{
+       rpc_call_start(task);
+}
+
 static void
 nfs_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg)
 {
@@ -721,9 +741,11 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
        .create         = nfs_proc_create,
        .remove         = nfs_proc_remove,
        .unlink_setup   = nfs_proc_unlink_setup,
+       .unlink_rpc_prepare = nfs_proc_unlink_rpc_prepare,
        .unlink_done    = nfs_proc_unlink_done,
        .rename         = nfs_proc_rename,
        .rename_setup   = nfs_proc_rename_setup,
+       .rename_rpc_prepare = nfs_proc_rename_rpc_prepare,
        .rename_done    = nfs_proc_rename_done,
        .link           = nfs_proc_link,
        .symlink        = nfs_proc_symlink,
@@ -736,8 +758,10 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
        .pathconf       = nfs_proc_pathconf,
        .decode_dirent  = nfs2_decode_dirent,
        .read_setup     = nfs_proc_read_setup,
+       .read_rpc_prepare = nfs_proc_read_rpc_prepare,
        .read_done      = nfs_read_done,
        .write_setup    = nfs_proc_write_setup,
+       .write_rpc_prepare = nfs_proc_write_rpc_prepare,
        .write_done     = nfs_write_done,
        .commit_setup   = nfs_proc_commit_setup,
        .lock           = nfs_proc_lock,
index b83e89b..9a0e8ef 100644 (file)
@@ -65,7 +65,6 @@ void nfs_readdata_free(struct nfs_read_data *p)
 
 void nfs_readdata_release(struct nfs_read_data *rdata)
 {
-       put_lseg(rdata->lseg);
        put_nfs_open_context(rdata->args.context);
        nfs_readdata_free(rdata);
 }
@@ -464,23 +463,14 @@ static void nfs_readpage_release_partial(void *calldata)
        nfs_readdata_release(calldata);
 }
 
-#if defined(CONFIG_NFS_V4_1)
 void nfs_read_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs_read_data *data = calldata;
-
-       if (nfs4_setup_sequence(NFS_SERVER(data->inode),
-                               &data->args.seq_args, &data->res.seq_res,
-                               0, task))
-               return;
-       rpc_call_start(task);
+       NFS_PROTO(data->inode)->read_rpc_prepare(task, data);
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 static const struct rpc_call_ops nfs_read_partial_ops = {
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs_read_prepare,
-#endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs_readpage_result_partial,
        .rpc_release = nfs_readpage_release_partial,
 };
@@ -544,9 +534,7 @@ static void nfs_readpage_release_full(void *calldata)
 }
 
 static const struct rpc_call_ops nfs_read_full_ops = {
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs_read_prepare,
-#endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs_readpage_result_full,
        .rpc_release = nfs_readpage_release_full,
 };
index e3f6b23..37412f7 100644 (file)
@@ -52,6 +52,8 @@
 #include <linux/nfs_xdr.h>
 #include <linux/magic.h>
 #include <linux/parser.h>
+#include <linux/nsproxy.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 
@@ -78,7 +80,6 @@ enum {
        Opt_cto, Opt_nocto,
        Opt_ac, Opt_noac,
        Opt_lock, Opt_nolock,
-       Opt_v2, Opt_v3, Opt_v4,
        Opt_udp, Opt_tcp, Opt_rdma,
        Opt_acl, Opt_noacl,
        Opt_rdirplus, Opt_nordirplus,
@@ -96,10 +97,10 @@ enum {
        Opt_namelen,
        Opt_mountport,
        Opt_mountvers,
-       Opt_nfsvers,
        Opt_minorversion,
 
        /* Mount options that take string arguments */
+       Opt_nfsvers,
        Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
        Opt_addr, Opt_mountaddr, Opt_clientaddr,
        Opt_lookupcache,
@@ -131,9 +132,6 @@ static const match_table_t nfs_mount_option_tokens = {
        { Opt_noac, "noac" },
        { Opt_lock, "lock" },
        { Opt_nolock, "nolock" },
-       { Opt_v2, "v2" },
-       { Opt_v3, "v3" },
-       { Opt_v4, "v4" },
        { Opt_udp, "udp" },
        { Opt_tcp, "tcp" },
        { Opt_rdma, "rdma" },
@@ -162,9 +160,10 @@ static const match_table_t nfs_mount_option_tokens = {
        { Opt_namelen, "namlen=%s" },
        { Opt_mountport, "mountport=%s" },
        { Opt_mountvers, "mountvers=%s" },
+       { Opt_minorversion, "minorversion=%s" },
+
        { Opt_nfsvers, "nfsvers=%s" },
        { Opt_nfsvers, "vers=%s" },
-       { Opt_minorversion, "minorversion=%s" },
 
        { Opt_sec, "sec=%s" },
        { Opt_proto, "proto=%s" },
@@ -178,6 +177,9 @@ static const match_table_t nfs_mount_option_tokens = {
        { Opt_fscache_uniq, "fsc=%s" },
        { Opt_local_lock, "local_lock=%s" },
 
+       /* The following needs to be listed after all other options */
+       { Opt_nfsvers, "v%s" },
+
        { Opt_err, NULL }
 };
 
@@ -258,6 +260,22 @@ static match_table_t nfs_local_lock_tokens = {
        { Opt_local_lock_err, NULL }
 };
 
+enum {
+       Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
+       Opt_vers_4_1,
+
+       Opt_vers_err
+};
+
+static match_table_t nfs_vers_tokens = {
+       { Opt_vers_2, "2" },
+       { Opt_vers_3, "3" },
+       { Opt_vers_4, "4" },
+       { Opt_vers_4_0, "4.0" },
+       { Opt_vers_4_1, "4.1" },
+
+       { Opt_vers_err, NULL }
+};
 
 static void nfs_umount_begin(struct super_block *);
 static int  nfs_statfs(struct dentry *, struct kstatfs *);
@@ -619,7 +637,6 @@ static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
        struct nfs_client *clp = nfss->nfs_client;
 
        seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
-       seq_printf(m, ",minorversion=%u", clp->cl_minorversion);
 }
 #else
 static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
@@ -628,6 +645,15 @@ static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
 }
 #endif
 
+static void nfs_show_nfs_version(struct seq_file *m,
+               unsigned int version,
+               unsigned int minorversion)
+{
+       seq_printf(m, ",vers=%u", version);
+       if (version == 4)
+               seq_printf(m, ".%u", minorversion);
+}
+
 /*
  * Describe the mount options in force on this server representation
  */
@@ -655,7 +681,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
        u32 version = clp->rpc_ops->version;
        int local_flock, local_fcntl;
 
-       seq_printf(m, ",vers=%u", version);
+       nfs_show_nfs_version(m, version, clp->cl_minorversion);
        seq_printf(m, ",rsize=%u", nfss->rsize);
        seq_printf(m, ",wsize=%u", nfss->wsize);
        if (nfss->bsize != 0)
@@ -675,8 +701,10 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                else
                        seq_puts(m, nfs_infop->nostr);
        }
+       rcu_read_lock();
        seq_printf(m, ",proto=%s",
                   rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID));
+       rcu_read_unlock();
        if (version == 4) {
                if (nfss->port != NFS_PORT)
                        seq_printf(m, ",port=%u", nfss->port);
@@ -725,9 +753,11 @@ static int nfs_show_options(struct seq_file *m, struct dentry *root)
 
        nfs_show_mount_options(m, nfss, 0);
 
+       rcu_read_lock();
        seq_printf(m, ",addr=%s",
                        rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient,
                                                        RPC_DISPLAY_ADDR));
+       rcu_read_unlock();
 
        return 0;
 }
@@ -744,7 +774,6 @@ static void show_sessions(struct seq_file *m, struct nfs_server *server) {}
 #endif
 #endif
 
-#ifdef CONFIG_NFS_V4
 #ifdef CONFIG_NFS_V4_1
 static void show_pnfs(struct seq_file *m, struct nfs_server *server)
 {
@@ -754,9 +783,26 @@ static void show_pnfs(struct seq_file *m, struct nfs_server *server)
        else
                seq_printf(m, "not configured");
 }
+
+static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss)
+{
+       if (nfss->nfs_client && nfss->nfs_client->impl_id) {
+               struct nfs41_impl_id *impl_id = nfss->nfs_client->impl_id;
+               seq_printf(m, "\n\timpl_id:\tname='%s',domain='%s',"
+                          "date='%llu,%u'",
+                          impl_id->name, impl_id->domain,
+                          impl_id->date.seconds, impl_id->date.nseconds);
+       }
+}
 #else
-static void show_pnfs(struct seq_file *m, struct nfs_server *server) {}
+#ifdef CONFIG_NFS_V4
+static void show_pnfs(struct seq_file *m, struct nfs_server *server)
+{
+}
 #endif
+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)
@@ -805,6 +851,8 @@ static int nfs_show_stats(struct seq_file *m, struct dentry *root)
 
        seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
 
+       show_implementation_id(m, nfss);
+
        seq_printf(m, "\n\tcaps:\t");
        seq_printf(m, "caps=0x%x", nfss->caps);
        seq_printf(m, ",wtmult=%u", nfss->wtmult);
@@ -907,6 +955,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int ve
                data->auth_flavor_len   = 1;
                data->version           = version;
                data->minorversion      = 0;
+               data->net               = current->nsproxy->net_ns;
                security_init_mnt_opts(&data->lsm_opts);
        }
        return data;
@@ -1051,6 +1100,40 @@ static int nfs_parse_security_flavors(char *value,
        return 1;
 }
 
+static int nfs_parse_version_string(char *string,
+               struct nfs_parsed_mount_data *mnt,
+               substring_t *args)
+{
+       mnt->flags &= ~NFS_MOUNT_VER3;
+       switch (match_token(string, nfs_vers_tokens, args)) {
+       case Opt_vers_2:
+               mnt->version = 2;
+               break;
+       case Opt_vers_3:
+               mnt->flags |= NFS_MOUNT_VER3;
+               mnt->version = 3;
+               break;
+       case Opt_vers_4:
+               /* Backward compatibility option. In future,
+                * the mount program should always supply
+                * a NFSv4 minor version number.
+                */
+               mnt->version = 4;
+               break;
+       case Opt_vers_4_0:
+               mnt->version = 4;
+               mnt->minorversion = 0;
+               break;
+       case Opt_vers_4_1:
+               mnt->version = 4;
+               mnt->minorversion = 1;
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
 static int nfs_get_option_str(substring_t args[], char **option)
 {
        kfree(*option);
@@ -1156,18 +1239,6 @@ static int nfs_parse_mount_options(char *raw,
                        mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
                                       NFS_MOUNT_LOCAL_FCNTL);
                        break;
-               case Opt_v2:
-                       mnt->flags &= ~NFS_MOUNT_VER3;
-                       mnt->version = 2;
-                       break;
-               case Opt_v3:
-                       mnt->flags |= NFS_MOUNT_VER3;
-                       mnt->version = 3;
-                       break;
-               case Opt_v4:
-                       mnt->flags &= ~NFS_MOUNT_VER3;
-                       mnt->version = 4;
-                       break;
                case Opt_udp:
                        mnt->flags &= ~NFS_MOUNT_TCP;
                        mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
@@ -1294,26 +1365,6 @@ static int nfs_parse_mount_options(char *raw,
                                goto out_invalid_value;
                        mnt->mount_server.version = option;
                        break;
-               case Opt_nfsvers:
-                       if (nfs_get_option_ul(args, &option))
-                               goto out_invalid_value;
-                       switch (option) {
-                       case NFS2_VERSION:
-                               mnt->flags &= ~NFS_MOUNT_VER3;
-                               mnt->version = 2;
-                               break;
-                       case NFS3_VERSION:
-                               mnt->flags |= NFS_MOUNT_VER3;
-                               mnt->version = 3;
-                               break;
-                       case NFS4_VERSION:
-                               mnt->flags &= ~NFS_MOUNT_VER3;
-                               mnt->version = 4;
-                               break;
-                       default:
-                               goto out_invalid_value;
-                       }
-                       break;
                case Opt_minorversion:
                        if (nfs_get_option_ul(args, &option))
                                goto out_invalid_value;
@@ -1325,6 +1376,15 @@ static int nfs_parse_mount_options(char *raw,
                /*
                 * options that take text values
                 */
+               case Opt_nfsvers:
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = nfs_parse_version_string(string, mnt, args);
+                       kfree(string);
+                       if (!rc)
+                               goto out_invalid_value;
+                       break;
                case Opt_sec:
                        string = match_strdup(args);
                        if (string == NULL)
@@ -1404,7 +1464,7 @@ static int nfs_parse_mount_options(char *raw,
                        if (string == NULL)
                                goto out_nomem;
                        mnt->nfs_server.addrlen =
-                               rpc_pton(string, strlen(string),
+                               rpc_pton(mnt->net, string, strlen(string),
                                        (struct sockaddr *)
                                        &mnt->nfs_server.address,
                                        sizeof(mnt->nfs_server.address));
@@ -1426,7 +1486,7 @@ static int nfs_parse_mount_options(char *raw,
                        if (string == NULL)
                                goto out_nomem;
                        mnt->mount_server.addrlen =
-                               rpc_pton(string, strlen(string),
+                               rpc_pton(mnt->net, string, strlen(string),
                                        (struct sockaddr *)
                                        &mnt->mount_server.address,
                                        sizeof(mnt->mount_server.address));
@@ -1515,6 +1575,9 @@ static int nfs_parse_mount_options(char *raw,
        if (!sloppy && invalid_option)
                return 0;
 
+       if (mnt->minorversion && mnt->version != 4)
+               goto out_minorversion_mismatch;
+
        /*
         * verify that any proto=/mountproto= options match the address
         * familiies in the addr=/mountaddr= options.
@@ -1548,6 +1611,10 @@ out_invalid_address:
 out_invalid_value:
        printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
        return 0;
+out_minorversion_mismatch:
+       printk(KERN_INFO "NFS: mount option vers=%u does not support "
+                        "minorversion=%u\n", mnt->version, mnt->minorversion);
+       return 0;
 out_nomem:
        printk(KERN_INFO "NFS: not enough memory to parse option\n");
        return 0;
@@ -1621,6 +1688,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
                .noresvport     = args->flags & NFS_MOUNT_NORESVPORT,
                .auth_flav_len  = &server_authlist_len,
                .auth_flavs     = server_authlist,
+               .net            = args->net,
        };
        int status;
 
@@ -2046,7 +2114,7 @@ static inline void nfs_initialise_sb(struct super_block *sb)
 
        /* We probably want something more informative here */
        snprintf(sb->s_id, sizeof(sb->s_id),
-                "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
+                "%u:%u", MAJOR(sb->s_dev), MINOR(sb->s_dev));
 
        if (sb->s_blocksize == 0)
                sb->s_blocksize = nfs_block_bits(server->wsize,
@@ -2498,12 +2566,6 @@ static int nfs4_validate_text_mount_data(void *options,
                return -EINVAL;
        }
 
-       if (args->client_address == NULL) {
-               dfprintk(MOUNT,
-                        "NFS4: mount program didn't pass callback address\n");
-               return -EINVAL;
-       }
-
        return nfs_parse_devname(dev_name,
                                   &args->nfs_server.hostname,
                                   NFS4_MAXNAMLEN,
@@ -2662,8 +2724,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
        if (!s->s_root) {
                /* initial superblock/root creation */
                nfs4_fill_super(s);
-               nfs_fscache_get_super_cookie(
-                       s, data ? data->fscache_uniq : NULL, NULL);
+               nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL);
        }
 
        mntroot = nfs4_get_root(s, mntfh, dev_name);
index 978aaeb..ad4d2e7 100644 (file)
@@ -32,7 +32,6 @@ static ctl_table nfs_cb_sysctls[] = {
                .extra1 = (int *)&nfs_set_port_min,
                .extra2 = (int *)&nfs_set_port_max,
        },
-#ifndef CONFIG_NFS_USE_NEW_IDMAPPER
        {
                .procname = "idmap_cache_timeout",
                .data = &nfs_idmap_cache_timeout,
@@ -40,7 +39,6 @@ static ctl_table nfs_cb_sysctls[] = {
                .mode = 0644,
                .proc_handler = proc_dointvec_jiffies,
        },
-#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
 #endif
        {
                .procname       = "nfs_mountpoint_timeout",
index 4f9319a..3210a03 100644 (file)
 #include "iostat.h"
 #include "delegation.h"
 
-struct nfs_unlinkdata {
-       struct hlist_node list;
-       struct nfs_removeargs args;
-       struct nfs_removeres res;
-       struct inode *dir;
-       struct rpc_cred *cred;
-       struct nfs_fattr dir_attr;
-};
-
 /**
  * nfs_free_unlinkdata - release data from a sillydelete operation.
  * @data: pointer to unlink structure.
@@ -107,25 +98,16 @@ static void nfs_async_unlink_release(void *calldata)
        nfs_sb_deactive(sb);
 }
 
-#if defined(CONFIG_NFS_V4_1)
-void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
+static void nfs_unlink_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs_unlinkdata *data = calldata;
-       struct nfs_server *server = NFS_SERVER(data->dir);
-
-       if (nfs4_setup_sequence(server, &data->args.seq_args,
-                               &data->res.seq_res, 1, task))
-               return;
-       rpc_call_start(task);
+       NFS_PROTO(data->dir)->unlink_rpc_prepare(task, data);
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 static const struct rpc_call_ops nfs_unlink_ops = {
        .rpc_call_done = nfs_async_unlink_done,
        .rpc_release = nfs_async_unlink_release,
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs_unlink_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 };
 
 static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data)
@@ -341,18 +323,6 @@ nfs_cancel_async_unlink(struct dentry *dentry)
        spin_unlock(&dentry->d_lock);
 }
 
-struct nfs_renamedata {
-       struct nfs_renameargs   args;
-       struct nfs_renameres    res;
-       struct rpc_cred         *cred;
-       struct inode            *old_dir;
-       struct dentry           *old_dentry;
-       struct nfs_fattr        old_fattr;
-       struct inode            *new_dir;
-       struct dentry           *new_dentry;
-       struct nfs_fattr        new_fattr;
-};
-
 /**
  * nfs_async_rename_done - Sillyrename post-processing
  * @task: rpc_task of the sillyrename
@@ -403,25 +373,16 @@ static void nfs_async_rename_release(void *calldata)
        kfree(data);
 }
 
-#if defined(CONFIG_NFS_V4_1)
 static void nfs_rename_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs_renamedata *data = calldata;
-       struct nfs_server *server = NFS_SERVER(data->old_dir);
-
-       if (nfs4_setup_sequence(server, &data->args.seq_args,
-                               &data->res.seq_res, 1, task))
-               return;
-       rpc_call_start(task);
+       NFS_PROTO(data->old_dir)->rename_rpc_prepare(task, data);
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 static const struct rpc_call_ops nfs_rename_ops = {
        .rpc_call_done = nfs_async_rename_done,
        .rpc_release = nfs_async_rename_release,
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs_rename_prepare,
-#endif /* CONFIG_NFS_V4_1 */
 };
 
 /**
index 834f0fe..2c68818 100644 (file)
@@ -100,7 +100,6 @@ void nfs_writedata_free(struct nfs_write_data *p)
 
 void nfs_writedata_release(struct nfs_write_data *wdata)
 {
-       put_lseg(wdata->lseg);
        put_nfs_open_context(wdata->args.context);
        nfs_writedata_free(wdata);
 }
@@ -236,10 +235,10 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblo
                req = nfs_page_find_request_locked(page);
                if (req == NULL)
                        break;
-               if (nfs_set_page_tag_locked(req))
+               if (nfs_lock_request_dontget(req))
                        break;
                /* Note: If we hold the page lock, as is the case in nfs_writepage,
-                *       then the call to nfs_set_page_tag_locked() will always
+                *       then the call to nfs_lock_request_dontget() will always
                 *       succeed provided that someone hasn't already marked the
                 *       request as dirty (in which case we don't care).
                 */
@@ -375,21 +374,14 @@ out_err:
 /*
  * Insert a write request into an inode
  */
-static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
+static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
-       int error;
-
-       error = radix_tree_preload(GFP_NOFS);
-       if (error != 0)
-               goto out;
 
        /* Lock the request! */
        nfs_lock_request_dontget(req);
 
        spin_lock(&inode->i_lock);
-       error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
-       BUG_ON(error);
        if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE))
                inode->i_version++;
        set_bit(PG_MAPPED, &req->wb_flags);
@@ -397,12 +389,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
        set_page_private(req->wb_page, (unsigned long)req);
        nfsi->npages++;
        kref_get(&req->wb_kref);
-       radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
-                               NFS_PAGE_TAG_LOCKED);
        spin_unlock(&inode->i_lock);
-       radix_tree_preload_end();
-out:
-       return error;
 }
 
 /*
@@ -419,7 +406,6 @@ static void nfs_inode_remove_request(struct nfs_page *req)
        set_page_private(req->wb_page, 0);
        ClearPagePrivate(req->wb_page);
        clear_bit(PG_MAPPED, &req->wb_flags);
-       radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
        nfsi->npages--;
        spin_unlock(&inode->i_lock);
        nfs_release_request(req);
@@ -432,39 +418,90 @@ nfs_mark_request_dirty(struct nfs_page *req)
 }
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-/*
- * Add a request to the inode's commit list.
+/**
+ * nfs_request_add_commit_list - add request to a commit list
+ * @req: pointer to a struct nfs_page
+ * @head: commit list head
+ *
+ * This sets the PG_CLEAN bit, updates the inode global count of
+ * number of outstanding requests requiring a commit as well as
+ * the MM page stats.
+ *
+ * The caller must _not_ hold the inode->i_lock, but must be
+ * holding the nfs_page lock.
  */
-static void
-nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
+void
+nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head)
 {
        struct inode *inode = req->wb_context->dentry->d_inode;
-       struct nfs_inode *nfsi = NFS_I(inode);
 
-       spin_lock(&inode->i_lock);
        set_bit(PG_CLEAN, &(req)->wb_flags);
-       radix_tree_tag_set(&nfsi->nfs_page_tree,
-                       req->wb_index,
-                       NFS_PAGE_TAG_COMMIT);
-       nfsi->ncommit++;
+       spin_lock(&inode->i_lock);
+       nfs_list_add_request(req, head);
+       NFS_I(inode)->ncommit++;
        spin_unlock(&inode->i_lock);
-       pnfs_mark_request_commit(req, lseg);
        inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
        inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE);
        __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
 }
+EXPORT_SYMBOL_GPL(nfs_request_add_commit_list);
 
-static int
+/**
+ * nfs_request_remove_commit_list - Remove request from a commit list
+ * @req: pointer to a nfs_page
+ *
+ * This clears the PG_CLEAN bit, and updates the inode global count of
+ * number of outstanding requests requiring a commit
+ * It does not update the MM page stats.
+ *
+ * The caller _must_ hold the inode->i_lock and the nfs_page lock.
+ */
+void
+nfs_request_remove_commit_list(struct nfs_page *req)
+{
+       struct inode *inode = req->wb_context->dentry->d_inode;
+
+       if (!test_and_clear_bit(PG_CLEAN, &(req)->wb_flags))
+               return;
+       nfs_list_remove_request(req);
+       NFS_I(inode)->ncommit--;
+}
+EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list);
+
+
+/*
+ * Add a request to the inode's commit list.
+ */
+static void
+nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
+{
+       struct inode *inode = req->wb_context->dentry->d_inode;
+
+       if (pnfs_mark_request_commit(req, lseg))
+               return;
+       nfs_request_add_commit_list(req, &NFS_I(inode)->commit_list);
+}
+
+static void
+nfs_clear_page_commit(struct page *page)
+{
+       dec_zone_page_state(page, NR_UNSTABLE_NFS);
+       dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
+}
+
+static void
 nfs_clear_request_commit(struct nfs_page *req)
 {
-       struct page *page = req->wb_page;
+       if (test_bit(PG_CLEAN, &req->wb_flags)) {
+               struct inode *inode = req->wb_context->dentry->d_inode;
 
-       if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) {
-               dec_zone_page_state(page, NR_UNSTABLE_NFS);
-               dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
-               return 1;
+               if (!pnfs_clear_request_commit(req)) {
+                       spin_lock(&inode->i_lock);
+                       nfs_request_remove_commit_list(req);
+                       spin_unlock(&inode->i_lock);
+               }
+               nfs_clear_page_commit(req->wb_page);
        }
-       return 0;
 }
 
 static inline
@@ -491,15 +528,14 @@ int nfs_reschedule_unstable_write(struct nfs_page *req,
        return 0;
 }
 #else
-static inline void
+static void
 nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
 {
 }
 
-static inline int
+static void
 nfs_clear_request_commit(struct nfs_page *req)
 {
-       return 0;
 }
 
 static inline
@@ -520,46 +556,65 @@ int nfs_reschedule_unstable_write(struct nfs_page *req,
 static int
 nfs_need_commit(struct nfs_inode *nfsi)
 {
-       return radix_tree_tagged(&nfsi->nfs_page_tree, NFS_PAGE_TAG_COMMIT);
+       return nfsi->ncommit > 0;
+}
+
+/* i_lock held by caller */
+static int
+nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max,
+               spinlock_t *lock)
+{
+       struct nfs_page *req, *tmp;
+       int ret = 0;
+
+       list_for_each_entry_safe(req, tmp, src, wb_list) {
+               if (!nfs_lock_request(req))
+                       continue;
+               if (cond_resched_lock(lock))
+                       list_safe_reset_next(req, tmp, wb_list);
+               nfs_request_remove_commit_list(req);
+               nfs_list_add_request(req, dst);
+               ret++;
+               if (ret == max)
+                       break;
+       }
+       return ret;
 }
 
 /*
  * nfs_scan_commit - Scan an inode for commit requests
  * @inode: NFS inode to scan
  * @dst: destination list
- * @idx_start: lower bound of page->index to scan.
- * @npages: idx_start + npages sets the upper bound to scan.
  *
  * Moves requests from the inode's 'commit' request list.
  * The requests are *not* checked to ensure that they form a contiguous set.
  */
 static int
-nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
+nfs_scan_commit(struct inode *inode, struct list_head *dst)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
-       int ret;
-
-       if (!nfs_need_commit(nfsi))
-               return 0;
+       int ret = 0;
 
        spin_lock(&inode->i_lock);
-       ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT);
-       if (ret > 0)
-               nfsi->ncommit -= ret;
-       spin_unlock(&inode->i_lock);
-
-       if (nfs_need_commit(NFS_I(inode)))
-               __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+       if (nfsi->ncommit > 0) {
+               const int max = INT_MAX;
 
+               ret = nfs_scan_commit_list(&nfsi->commit_list, dst, max,
+                               &inode->i_lock);
+               ret += pnfs_scan_commit_lists(inode, max - ret,
+                               &inode->i_lock);
+       }
+       spin_unlock(&inode->i_lock);
        return ret;
 }
+
 #else
 static inline int nfs_need_commit(struct nfs_inode *nfsi)
 {
        return 0;
 }
 
-static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
+static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst)
 {
        return 0;
 }
@@ -604,7 +659,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
                    || end < req->wb_offset)
                        goto out_flushme;
 
-               if (nfs_set_page_tag_locked(req))
+               if (nfs_lock_request_dontget(req))
                        break;
 
                /* The request is locked, so wait and then retry */
@@ -616,13 +671,6 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
                spin_lock(&inode->i_lock);
        }
 
-       if (nfs_clear_request_commit(req) &&
-           radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
-                                req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) {
-               NFS_I(inode)->ncommit--;
-               pnfs_clear_request_commit(req);
-       }
-
        /* Okay, the request matches. Update the region */
        if (offset < req->wb_offset) {
                req->wb_offset = offset;
@@ -634,6 +682,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
                req->wb_bytes = rqend - req->wb_offset;
 out_unlock:
        spin_unlock(&inode->i_lock);
+       nfs_clear_request_commit(req);
        return req;
 out_flushme:
        spin_unlock(&inode->i_lock);
@@ -655,7 +704,6 @@ static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,
 {
        struct inode *inode = page->mapping->host;
        struct nfs_page *req;
-       int error;
 
        req = nfs_try_to_update_request(inode, page, offset, bytes);
        if (req != NULL)
@@ -663,11 +711,7 @@ static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,
        req = nfs_create_request(ctx, inode, page, offset, bytes);
        if (IS_ERR(req))
                goto out;
-       error = nfs_inode_add_request(inode, req);
-       if (error != 0) {
-               nfs_release_request(req);
-               req = ERR_PTR(error);
-       }
+       nfs_inode_add_request(inode, req);
 out:
        return req;
 }
@@ -684,7 +728,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
        nfs_grow_file(page, offset, count);
        nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
        nfs_mark_request_dirty(req);
-       nfs_clear_page_tag_locked(req);
+       nfs_unlock_request(req);
        return 0;
 }
 
@@ -777,7 +821,7 @@ static void nfs_writepage_release(struct nfs_page *req,
 
        if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data))
                nfs_inode_remove_request(req);
-       nfs_clear_page_tag_locked(req);
+       nfs_unlock_request(req);
        nfs_end_page_writeback(page);
 }
 
@@ -925,7 +969,7 @@ static void nfs_redirty_request(struct nfs_page *req)
        struct page *page = req->wb_page;
 
        nfs_mark_request_dirty(req);
-       nfs_clear_page_tag_locked(req);
+       nfs_unlock_request(req);
        nfs_end_page_writeback(page);
 }
 
@@ -1128,23 +1172,14 @@ out:
        nfs_writedata_release(calldata);
 }
 
-#if defined(CONFIG_NFS_V4_1)
 void nfs_write_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs_write_data *data = calldata;
-
-       if (nfs4_setup_sequence(NFS_SERVER(data->inode),
-                               &data->args.seq_args,
-                               &data->res.seq_res, 1, task))
-               return;
-       rpc_call_start(task);
+       NFS_PROTO(data->inode)->write_rpc_prepare(task, data);
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 static const struct rpc_call_ops nfs_write_partial_ops = {
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs_write_prepare,
-#endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs_writeback_done_partial,
        .rpc_release = nfs_writeback_release_partial,
 };
@@ -1199,16 +1234,14 @@ static void nfs_writeback_release_full(void *calldata)
 remove_request:
                nfs_inode_remove_request(req);
        next:
-               nfs_clear_page_tag_locked(req);
+               nfs_unlock_request(req);
                nfs_end_page_writeback(page);
        }
        nfs_writedata_release(calldata);
 }
 
 static const struct rpc_call_ops nfs_write_full_ops = {
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs_write_prepare,
-#endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs_writeback_done_full,
        .rpc_release = nfs_writeback_release_full,
 };
@@ -1325,7 +1358,6 @@ void nfs_commitdata_release(void *data)
 {
        struct nfs_write_data *wdata = data;
 
-       put_lseg(wdata->lseg);
        put_nfs_open_context(wdata->args.context);
        nfs_commit_free(wdata);
 }
@@ -1411,7 +1443,7 @@ void nfs_retry_commit(struct list_head *page_list,
                dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
                dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
                             BDI_RECLAIMABLE);
-               nfs_clear_page_tag_locked(req);
+               nfs_unlock_request(req);
        }
 }
 EXPORT_SYMBOL_GPL(nfs_retry_commit);
@@ -1460,7 +1492,7 @@ void nfs_commit_release_pages(struct nfs_write_data *data)
        while (!list_empty(&data->pages)) {
                req = nfs_list_entry(data->pages.next);
                nfs_list_remove_request(req);
-               nfs_clear_request_commit(req);
+               nfs_clear_page_commit(req->wb_page);
 
                dprintk("NFS:       commit (%s/%lld %d@%lld)",
                        req->wb_context->dentry->d_sb->s_id,
@@ -1486,7 +1518,7 @@ void nfs_commit_release_pages(struct nfs_write_data *data)
                dprintk(" mismatch\n");
                nfs_mark_request_dirty(req);
        next:
-               nfs_clear_page_tag_locked(req);
+               nfs_unlock_request(req);
        }
 }
 EXPORT_SYMBOL_GPL(nfs_commit_release_pages);
@@ -1501,9 +1533,7 @@ static void nfs_commit_release(void *calldata)
 }
 
 static const struct rpc_call_ops nfs_commit_ops = {
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs_write_prepare,
-#endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs_commit_done,
        .rpc_release = nfs_commit_release,
 };
@@ -1517,7 +1547,7 @@ int nfs_commit_inode(struct inode *inode, int how)
        res = nfs_commit_set_lock(NFS_I(inode), may_wait);
        if (res <= 0)
                goto out_mark_dirty;
-       res = nfs_scan_commit(inode, &head, 0, 0);
+       res = nfs_scan_commit(inode, &head);
        if (res) {
                int error;
 
@@ -1635,6 +1665,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
                if (req == NULL)
                        break;
                if (nfs_lock_request_dontget(req)) {
+                       nfs_clear_request_commit(req);
                        nfs_inode_remove_request(req);
                        /*
                         * In case nfs_inode_remove_request has marked the
index 6f3ebb4..0e262f3 100644 (file)
@@ -605,24 +605,24 @@ static struct rpc_version nfs_cb_version4 = {
        .procs                  = nfs4_cb_procedures
 };
 
-static struct rpc_version *nfs_cb_version[] = {
+static const struct rpc_version *nfs_cb_version[] = {
        &nfs_cb_version4,
 };
 
-static struct rpc_program cb_program;
+static const struct rpc_program cb_program;
 
 static struct rpc_stat cb_stats = {
        .program                = &cb_program
 };
 
 #define NFS4_CALLBACK 0x40000000
-static struct rpc_program cb_program = {
+static const struct rpc_program cb_program = {
        .name                   = "nfs4_cb",
        .number                 = NFS4_CALLBACK,
        .nrvers                 = ARRAY_SIZE(nfs_cb_version),
        .version                = nfs_cb_version,
        .stats                  = &cb_stats,
-       .pipe_dir_name          = "/nfsd4_cb",
+       .pipe_dir_name          = "nfsd4_cb",
 };
 
 static int max_cb_time(void)
index e8c98f0..c5cddd6 100644 (file)
@@ -1308,7 +1308,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r
        else
                goto out_err;
 
-       conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
+       conn->cb_addrlen = rpc_uaddr2sockaddr(&init_net, se->se_callback_addr_val,
                                            se->se_callback_addr_len,
                                            (struct sockaddr *)&conn->cb_addr,
                                            sizeof(conn->cb_addr));
index 748eda9..64c24af 100644 (file)
@@ -223,7 +223,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
        if (qword_get(&buf, fo_path, size) < 0)
                return -EINVAL;
 
-       if (rpc_pton(fo_path, size, sap, salen) == 0)
+       if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0)
                return -EINVAL;
 
        return nlmsvc_unlock_all_by_ip(sap);
@@ -722,7 +722,7 @@ static ssize_t __write_ports_addxprt(char *buf)
        nfsd_serv->sv_nrthreads--;
        return 0;
 out_close:
-       xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
+       xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port);
        if (xprt != NULL) {
                svc_close_xprt(xprt);
                svc_xprt_put(xprt);
@@ -748,7 +748,7 @@ static ssize_t __write_ports_delxprt(char *buf)
        if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
                return -EINVAL;
 
-       xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
+       xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port);
        if (xprt == NULL)
                return -ENOTCONN;
 
index eda7d7e..fce472f 100644 (file)
@@ -251,13 +251,13 @@ static void nfsd_shutdown(void)
        nfsd_up = false;
 }
 
-static void nfsd_last_thread(struct svc_serv *serv)
+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);
+       svc_rpcb_cleanup(serv, net);
 
        printk(KERN_WARNING "nfsd: last server has exited, flushing export "
                            "cache\n");
index a2e2402..6d4521f 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/sunrpc/stats.h>
 #include <linux/nfsd/stats.h>
+#include <net/net_namespace.h>
 
 #include "nfsd.h"
 
@@ -94,11 +95,11 @@ static const struct file_operations nfsd_proc_fops = {
 void
 nfsd_stat_init(void)
 {
-       svc_proc_register(&nfsd_svcstats, &nfsd_proc_fops);
+       svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_fops);
 }
 
 void
 nfsd_stat_shutdown(void)
 {
-       svc_proc_unregister("nfsd");
+       svc_proc_unregister(&init_net, "nfsd");
 }
index ee18815..c887b13 100644 (file)
@@ -447,7 +447,7 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
        return event;
 }
 
-__init int fsnotify_notification_init(void)
+static __init int fsnotify_notification_init(void)
 {
        fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC);
        fsnotify_event_holder_cachep = KMEM_CACHE(fsnotify_event_holder, SLAB_PANIC);
@@ -461,4 +461,3 @@ __init int fsnotify_notification_init(void)
        return 0;
 }
 subsys_initcall(fsnotify_notification_init);
-
index fe0502f..25feaa3 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -13,6 +13,7 @@
 #include <linux/fs.h>
 #include <linux/log2.h>
 #include <linux/mount.h>
+#include <linux/magic.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/uio.h>
 #include <linux/highmem.h>
index cea4623..5e325a4 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/posix_acl.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 #include <linux/errno.h>
 
index c602b8d..fbb53c2 100644 (file)
@@ -462,59 +462,56 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
        /* convert nsec -> ticks */
        start_time = nsec_to_clock_t(start_time);
 
-       seq_printf(m, "%d (%s) %c %d %d %d %d %d %u %lu \
-%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld %lu %lu %lu\n",
-               pid_nr_ns(pid, ns),
-               tcomm,
-               state,
-               ppid,
-               pgid,
-               sid,
-               tty_nr,
-               tty_pgrp,
-               task->flags,
-               min_flt,
-               cmin_flt,
-               maj_flt,
-               cmaj_flt,
-               cputime_to_clock_t(utime),
-               cputime_to_clock_t(stime),
-               cputime_to_clock_t(cutime),
-               cputime_to_clock_t(cstime),
-               priority,
-               nice,
-               num_threads,
-               start_time,
-               vsize,
-               mm ? get_mm_rss(mm) : 0,
-               rsslim,
-               mm ? (permitted ? mm->start_code : 1) : 0,
-               mm ? (permitted ? mm->end_code : 1) : 0,
-               (permitted && mm) ? mm->start_stack : 0,
-               esp,
-               eip,
-               /* The signal information here is obsolete.
-                * It must be decimal for Linux 2.0 compatibility.
-                * Use /proc/#/status for real-time signals.
-                */
-               task->pending.signal.sig[0] & 0x7fffffffUL,
-               task->blocked.sig[0] & 0x7fffffffUL,
-               sigign      .sig[0] & 0x7fffffffUL,
-               sigcatch    .sig[0] & 0x7fffffffUL,
-               wchan,
-               0UL,
-               0UL,
-               task->exit_signal,
-               task_cpu(task),
-               task->rt_priority,
-               task->policy,
-               (unsigned long long)delayacct_blkio_ticks(task),
-               cputime_to_clock_t(gtime),
-               cputime_to_clock_t(cgtime),
-               (mm && permitted) ? mm->start_data : 0,
-               (mm && permitted) ? mm->end_data : 0,
-               (mm && permitted) ? mm->start_brk : 0);
+       seq_printf(m, "%d (%s) %c", pid_nr_ns(pid, ns), tcomm, state);
+       seq_put_decimal_ll(m, ' ', ppid);
+       seq_put_decimal_ll(m, ' ', pgid);
+       seq_put_decimal_ll(m, ' ', sid);
+       seq_put_decimal_ll(m, ' ', tty_nr);
+       seq_put_decimal_ll(m, ' ', tty_pgrp);
+       seq_put_decimal_ull(m, ' ', task->flags);
+       seq_put_decimal_ull(m, ' ', min_flt);
+       seq_put_decimal_ull(m, ' ', cmin_flt);
+       seq_put_decimal_ull(m, ' ', maj_flt);
+       seq_put_decimal_ull(m, ' ', cmaj_flt);
+       seq_put_decimal_ull(m, ' ', cputime_to_clock_t(utime));
+       seq_put_decimal_ull(m, ' ', cputime_to_clock_t(stime));
+       seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cutime));
+       seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cstime));
+       seq_put_decimal_ll(m, ' ', priority);
+       seq_put_decimal_ll(m, ' ', nice);
+       seq_put_decimal_ll(m, ' ', num_threads);
+       seq_put_decimal_ull(m, ' ', 0);
+       seq_put_decimal_ull(m, ' ', start_time);
+       seq_put_decimal_ull(m, ' ', vsize);
+       seq_put_decimal_ll(m, ' ', mm ? get_mm_rss(mm) : 0);
+       seq_put_decimal_ull(m, ' ', rsslim);
+       seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->start_code : 1) : 0);
+       seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->end_code : 1) : 0);
+       seq_put_decimal_ull(m, ' ', (permitted && mm) ? mm->start_stack : 0);
+       seq_put_decimal_ull(m, ' ', esp);
+       seq_put_decimal_ull(m, ' ', eip);
+       /* The signal information here is obsolete.
+        * It must be decimal for Linux 2.0 compatibility.
+        * Use /proc/#/status for real-time signals.
+        */
+       seq_put_decimal_ull(m, ' ', task->pending.signal.sig[0] & 0x7fffffffUL);
+       seq_put_decimal_ull(m, ' ', task->blocked.sig[0] & 0x7fffffffUL);
+       seq_put_decimal_ull(m, ' ', sigign.sig[0] & 0x7fffffffUL);
+       seq_put_decimal_ull(m, ' ', sigcatch.sig[0] & 0x7fffffffUL);
+       seq_put_decimal_ull(m, ' ', wchan);
+       seq_put_decimal_ull(m, ' ', 0);
+       seq_put_decimal_ull(m, ' ', 0);
+       seq_put_decimal_ll(m, ' ', task->exit_signal);
+       seq_put_decimal_ll(m, ' ', task_cpu(task));
+       seq_put_decimal_ull(m, ' ', task->rt_priority);
+       seq_put_decimal_ull(m, ' ', task->policy);
+       seq_put_decimal_ull(m, ' ', delayacct_blkio_ticks(task));
+       seq_put_decimal_ull(m, ' ', cputime_to_clock_t(gtime));
+       seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cgtime));
+       seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->start_data : 0);
+       seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->end_data : 0);
+       seq_put_decimal_ull(m, ' ', (mm && permitted) ? mm->start_brk : 0);
+       seq_putc(m, '\n');
        if (mm)
                mmput(mm);
        return 0;
@@ -542,8 +539,20 @@ int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns,
                size = task_statm(mm, &shared, &text, &data, &resident);
                mmput(mm);
        }
-       seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
-                       size, resident, shared, text, data);
+       /*
+        * For quick read, open code by putting numbers directly
+        * expected format is
+        * seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
+        *               size, resident, shared, text, data);
+        */
+       seq_put_decimal_ull(m, 0, size);
+       seq_put_decimal_ull(m, ' ', resident);
+       seq_put_decimal_ull(m, ' ', shared);
+       seq_put_decimal_ull(m, ' ', text);
+       seq_put_decimal_ull(m, ' ', 0);
+       seq_put_decimal_ull(m, ' ', text);
+       seq_put_decimal_ull(m, ' ', 0);
+       seq_putc(m, '\n');
 
        return 0;
 }
index c44efe1..5f79bb8 100644 (file)
  */
 
 #include <linux/proc_fs.h>
+struct  ctl_table_header;
 
 extern struct proc_dir_entry proc_root;
 #ifdef CONFIG_PROC_SYSCTL
 extern int proc_sys_init(void);
+extern void sysctl_head_put(struct ctl_table_header *head);
 #else
 static inline void proc_sys_init(void) { }
+static inline void sysctl_head_put(struct ctl_table_header *head) { }
 #endif
 #ifdef CONFIG_NET
 extern int proc_net_init(void);
index e5e69af..86c67ee 100644 (file)
@@ -157,7 +157,8 @@ static int kcore_update_ram(void)
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
 /* calculate vmemmap's address from given system ram pfn and register it */
-int get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
+static int
+get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
 {
        unsigned long pfn = __pa(ent->addr) >> PAGE_SHIFT;
        unsigned long nr_pages = ent->size >> PAGE_SHIFT;
@@ -189,7 +190,8 @@ int get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
 
 }
 #else
-int get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
+static int
+get_sparsemem_vmemmap_info(struct kcore_list *ent, struct list_head *head)
 {
        return 1;
 }
index 27da860..3551f1f 100644 (file)
@@ -53,7 +53,7 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
        ei->ns_ops    = ns_ops;
        ei->ns        = ns;
 
-       dentry->d_op = &pid_dentry_operations;
+       d_set_d_op(dentry, &pid_dentry_operations);
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, NULL))
index 67bbf6e..21d836f 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/sched.h>
 #include <linux/namei.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include "internal.h"
 
 static const struct dentry_operations proc_sys_dentry_operations;
@@ -26,6 +27,371 @@ void proc_sys_poll_notify(struct ctl_table_poll *poll)
        wake_up_interruptible(&poll->wait);
 }
 
+static struct ctl_table root_table[] = {
+       {
+               .procname = "",
+               .mode = S_IFDIR|S_IRUGO|S_IXUGO,
+       },
+       { }
+};
+static struct ctl_table_root sysctl_table_root = {
+       .default_set.dir.header = {
+               {{.count = 1,
+                 .nreg = 1,
+                 .ctl_table = root_table }},
+               .ctl_table_arg = root_table,
+               .root = &sysctl_table_root,
+               .set = &sysctl_table_root.default_set,
+       },
+};
+
+static DEFINE_SPINLOCK(sysctl_lock);
+
+static void drop_sysctl_table(struct ctl_table_header *header);
+static int sysctl_follow_link(struct ctl_table_header **phead,
+       struct ctl_table **pentry, struct nsproxy *namespaces);
+static int insert_links(struct ctl_table_header *head);
+static void put_links(struct ctl_table_header *header);
+
+static void sysctl_print_dir(struct ctl_dir *dir)
+{
+       if (dir->header.parent)
+               sysctl_print_dir(dir->header.parent);
+       printk(KERN_CONT "%s/", dir->header.ctl_table[0].procname);
+}
+
+static int namecmp(const char *name1, int len1, const char *name2, int len2)
+{
+       int minlen;
+       int cmp;
+
+       minlen = len1;
+       if (minlen > len2)
+               minlen = len2;
+
+       cmp = memcmp(name1, name2, minlen);
+       if (cmp == 0)
+               cmp = len1 - len2;
+       return cmp;
+}
+
+/* Called under sysctl_lock */
+static struct ctl_table *find_entry(struct ctl_table_header **phead,
+       struct ctl_dir *dir, const char *name, int namelen)
+{
+       struct ctl_table_header *head;
+       struct ctl_table *entry;
+       struct rb_node *node = dir->root.rb_node;
+
+       while (node)
+       {
+               struct ctl_node *ctl_node;
+               const char *procname;
+               int cmp;
+
+               ctl_node = rb_entry(node, struct ctl_node, node);
+               head = ctl_node->header;
+               entry = &head->ctl_table[ctl_node - head->node];
+               procname = entry->procname;
+
+               cmp = namecmp(name, namelen, procname, strlen(procname));
+               if (cmp < 0)
+                       node = node->rb_left;
+               else if (cmp > 0)
+                       node = node->rb_right;
+               else {
+                       *phead = head;
+                       return entry;
+               }
+       }
+       return NULL;
+}
+
+static int insert_entry(struct ctl_table_header *head, struct ctl_table *entry)
+{
+       struct rb_node *node = &head->node[entry - head->ctl_table].node;
+       struct rb_node **p = &head->parent->root.rb_node;
+       struct rb_node *parent = NULL;
+       const char *name = entry->procname;
+       int namelen = strlen(name);
+
+       while (*p) {
+               struct ctl_table_header *parent_head;
+               struct ctl_table *parent_entry;
+               struct ctl_node *parent_node;
+               const char *parent_name;
+               int cmp;
+
+               parent = *p;
+               parent_node = rb_entry(parent, struct ctl_node, node);
+               parent_head = parent_node->header;
+               parent_entry = &parent_head->ctl_table[parent_node - parent_head->node];
+               parent_name = parent_entry->procname;
+
+               cmp = namecmp(name, namelen, parent_name, strlen(parent_name));
+               if (cmp < 0)
+                       p = &(*p)->rb_left;
+               else if (cmp > 0)
+                       p = &(*p)->rb_right;
+               else {
+                       printk(KERN_ERR "sysctl duplicate entry: ");
+                       sysctl_print_dir(head->parent);
+                       printk(KERN_CONT "/%s\n", entry->procname);
+                       return -EEXIST;
+               }
+       }
+
+       rb_link_node(node, parent, p);
+       return 0;
+}
+
+static void erase_entry(struct ctl_table_header *head, struct ctl_table *entry)
+{
+       struct rb_node *node = &head->node[entry - head->ctl_table].node;
+
+       rb_erase(node, &head->parent->root);
+}
+
+static void init_header(struct ctl_table_header *head,
+       struct ctl_table_root *root, struct ctl_table_set *set,
+       struct ctl_node *node, struct ctl_table *table)
+{
+       head->ctl_table = table;
+       head->ctl_table_arg = table;
+       head->used = 0;
+       head->count = 1;
+       head->nreg = 1;
+       head->unregistering = NULL;
+       head->root = root;
+       head->set = set;
+       head->parent = NULL;
+       head->node = node;
+       if (node) {
+               struct ctl_table *entry;
+               for (entry = table; entry->procname; entry++, node++) {
+                       rb_init_node(&node->node);
+                       node->header = head;
+               }
+       }
+}
+
+static void erase_header(struct ctl_table_header *head)
+{
+       struct ctl_table *entry;
+       for (entry = head->ctl_table; entry->procname; entry++)
+               erase_entry(head, entry);
+}
+
+static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header)
+{
+       struct ctl_table *entry;
+       int err;
+
+       dir->header.nreg++;
+       header->parent = dir;
+       err = insert_links(header);
+       if (err)
+               goto fail_links;
+       for (entry = header->ctl_table; entry->procname; entry++) {
+               err = insert_entry(header, entry);
+               if (err)
+                       goto fail;
+       }
+       return 0;
+fail:
+       erase_header(header);
+       put_links(header);
+fail_links:
+       header->parent = NULL;
+       drop_sysctl_table(&dir->header);
+       return err;
+}
+
+/* called under sysctl_lock */
+static int use_table(struct ctl_table_header *p)
+{
+       if (unlikely(p->unregistering))
+               return 0;
+       p->used++;
+       return 1;
+}
+
+/* called under sysctl_lock */
+static void unuse_table(struct ctl_table_header *p)
+{
+       if (!--p->used)
+               if (unlikely(p->unregistering))
+                       complete(p->unregistering);
+}
+
+/* called under sysctl_lock, will reacquire if has to wait */
+static void start_unregistering(struct ctl_table_header *p)
+{
+       /*
+        * if p->used is 0, nobody will ever touch that entry again;
+        * we'll eliminate all paths to it before dropping sysctl_lock
+        */
+       if (unlikely(p->used)) {
+               struct completion wait;
+               init_completion(&wait);
+               p->unregistering = &wait;
+               spin_unlock(&sysctl_lock);
+               wait_for_completion(&wait);
+               spin_lock(&sysctl_lock);
+       } else {
+               /* anything non-NULL; we'll never dereference it */
+               p->unregistering = ERR_PTR(-EINVAL);
+       }
+       /*
+        * do not remove from the list until nobody holds it; walking the
+        * list in do_sysctl() relies on that.
+        */
+       erase_header(p);
+}
+
+static void sysctl_head_get(struct ctl_table_header *head)
+{
+       spin_lock(&sysctl_lock);
+       head->count++;
+       spin_unlock(&sysctl_lock);
+}
+
+void sysctl_head_put(struct ctl_table_header *head)
+{
+       spin_lock(&sysctl_lock);
+       if (!--head->count)
+               kfree_rcu(head, rcu);
+       spin_unlock(&sysctl_lock);
+}
+
+static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
+{
+       if (!head)
+               BUG();
+       spin_lock(&sysctl_lock);
+       if (!use_table(head))
+               head = ERR_PTR(-ENOENT);
+       spin_unlock(&sysctl_lock);
+       return head;
+}
+
+static void sysctl_head_finish(struct ctl_table_header *head)
+{
+       if (!head)
+               return;
+       spin_lock(&sysctl_lock);
+       unuse_table(head);
+       spin_unlock(&sysctl_lock);
+}
+
+static struct ctl_table_set *
+lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces)
+{
+       struct ctl_table_set *set = &root->default_set;
+       if (root->lookup)
+               set = root->lookup(root, namespaces);
+       return set;
+}
+
+static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
+                                     struct ctl_dir *dir,
+                                     const char *name, int namelen)
+{
+       struct ctl_table_header *head;
+       struct ctl_table *entry;
+
+       spin_lock(&sysctl_lock);
+       entry = find_entry(&head, dir, name, namelen);
+       if (entry && use_table(head))
+               *phead = head;
+       else
+               entry = NULL;
+       spin_unlock(&sysctl_lock);
+       return entry;
+}
+
+static struct ctl_node *first_usable_entry(struct rb_node *node)
+{
+       struct ctl_node *ctl_node;
+
+       for (;node; node = rb_next(node)) {
+               ctl_node = rb_entry(node, struct ctl_node, node);
+               if (use_table(ctl_node->header))
+                       return ctl_node;
+       }
+       return NULL;
+}
+
+static void first_entry(struct ctl_dir *dir,
+       struct ctl_table_header **phead, struct ctl_table **pentry)
+{
+       struct ctl_table_header *head = NULL;
+       struct ctl_table *entry = NULL;
+       struct ctl_node *ctl_node;
+
+       spin_lock(&sysctl_lock);
+       ctl_node = first_usable_entry(rb_first(&dir->root));
+       spin_unlock(&sysctl_lock);
+       if (ctl_node) {
+               head = ctl_node->header;
+               entry = &head->ctl_table[ctl_node - head->node];
+       }
+       *phead = head;
+       *pentry = entry;
+}
+
+static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
+{
+       struct ctl_table_header *head = *phead;
+       struct ctl_table *entry = *pentry;
+       struct ctl_node *ctl_node = &head->node[entry - head->ctl_table];
+
+       spin_lock(&sysctl_lock);
+       unuse_table(head);
+
+       ctl_node = first_usable_entry(rb_next(&ctl_node->node));
+       spin_unlock(&sysctl_lock);
+       head = NULL;
+       if (ctl_node) {
+               head = ctl_node->header;
+               entry = &head->ctl_table[ctl_node - head->node];
+       }
+       *phead = head;
+       *pentry = entry;
+}
+
+void register_sysctl_root(struct ctl_table_root *root)
+{
+}
+
+/*
+ * sysctl_perm does NOT grant the superuser all rights automatically, because
+ * some sysctl variables are readonly even to root.
+ */
+
+static int test_perm(int mode, int op)
+{
+       if (!current_euid())
+               mode >>= 6;
+       else if (in_egroup_p(0))
+               mode >>= 3;
+       if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
+               return 0;
+       return -EACCES;
+}
+
+static int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
+{
+       int mode;
+
+       if (root->permissions)
+               mode = root->permissions(root, current->nsproxy, table);
+       else
+               mode = table->mode;
+
+       return test_perm(mode, op);
+}
+
 static struct inode *proc_sys_make_inode(struct super_block *sb,
                struct ctl_table_header *head, struct ctl_table *table)
 {
@@ -45,13 +411,12 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
 
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode->i_mode = table->mode;
-       if (!table->child) {
+       if (!S_ISDIR(table->mode)) {
                inode->i_mode |= S_IFREG;
                inode->i_op = &proc_sys_inode_operations;
                inode->i_fop = &proc_sys_file_operations;
        } else {
                inode->i_mode |= S_IFDIR;
-               clear_nlink(inode);
                inode->i_op = &proc_sys_dir_operations;
                inode->i_fop = &proc_sys_dir_file_operations;
        }
@@ -59,70 +424,42 @@ out:
        return inode;
 }
 
-static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name)
-{
-       int len;
-       for ( ; p->procname; p++) {
-
-               if (!p->procname)
-                       continue;
-
-               len = strlen(p->procname);
-               if (len != name->len)
-                       continue;
-
-               if (memcmp(p->procname, name->name, len) != 0)
-                       continue;
-
-               /* I have a match */
-               return p;
-       }
-       return NULL;
-}
-
 static struct ctl_table_header *grab_header(struct inode *inode)
 {
-       if (PROC_I(inode)->sysctl)
-               return sysctl_head_grab(PROC_I(inode)->sysctl);
-       else
-               return sysctl_head_next(NULL);
+       struct ctl_table_header *head = PROC_I(inode)->sysctl;
+       if (!head)
+               head = &sysctl_table_root.default_set.dir.header;
+       return sysctl_head_grab(head);
 }
 
 static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
                                        struct nameidata *nd)
 {
        struct ctl_table_header *head = grab_header(dir);
-       struct ctl_table *table = PROC_I(dir)->sysctl_entry;
        struct ctl_table_header *h = NULL;
        struct qstr *name = &dentry->d_name;
        struct ctl_table *p;
        struct inode *inode;
        struct dentry *err = ERR_PTR(-ENOENT);
+       struct ctl_dir *ctl_dir;
+       int ret;
 
        if (IS_ERR(head))
                return ERR_CAST(head);
 
-       if (table && !table->child) {
-               WARN_ON(1);
-               goto out;
-       }
-
-       table = table ? table->child : head->ctl_table;
-
-       p = find_in_table(table, name);
-       if (!p) {
-               for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
-                       if (h->attached_to != table)
-                               continue;
-                       p = find_in_table(h->attached_by, name);
-                       if (p)
-                               break;
-               }
-       }
+       ctl_dir = container_of(head, struct ctl_dir, header);
 
+       p = lookup_entry(&h, ctl_dir, name->name, name->len);
        if (!p)
                goto out;
 
+       if (S_ISLNK(p->mode)) {
+               ret = sysctl_follow_link(&h, &p, current->nsproxy);
+               err = ERR_PTR(ret);
+               if (ret)
+                       goto out;
+       }
+
        err = ERR_PTR(-ENOMEM);
        inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
        if (h)
@@ -190,20 +527,32 @@ static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
 
 static int proc_sys_open(struct inode *inode, struct file *filp)
 {
+       struct ctl_table_header *head = grab_header(inode);
        struct ctl_table *table = PROC_I(inode)->sysctl_entry;
 
+       /* sysctl was unregistered */
+       if (IS_ERR(head))
+               return PTR_ERR(head);
+
        if (table->poll)
                filp->private_data = proc_sys_poll_event(table->poll);
 
+       sysctl_head_finish(head);
+
        return 0;
 }
 
 static unsigned int proc_sys_poll(struct file *filp, poll_table *wait)
 {
        struct inode *inode = filp->f_path.dentry->d_inode;
+       struct ctl_table_header *head = grab_header(inode);
        struct ctl_table *table = PROC_I(inode)->sysctl_entry;
-       unsigned long event = (unsigned long)filp->private_data;
        unsigned int ret = DEFAULT_POLLMASK;
+       unsigned long event;
+
+       /* sysctl was unregistered */
+       if (IS_ERR(head))
+               return POLLERR | POLLHUP;
 
        if (!table->proc_handler)
                goto out;
@@ -211,6 +560,7 @@ static unsigned int proc_sys_poll(struct file *filp, poll_table *wait)
        if (!table->poll)
                goto out;
 
+       event = (unsigned long)filp->private_data;
        poll_wait(filp, &table->poll->wait, wait);
 
        if (event != atomic_read(&table->poll->event)) {
@@ -219,6 +569,8 @@ static unsigned int proc_sys_poll(struct file *filp, poll_table *wait)
        }
 
 out:
+       sysctl_head_finish(head);
+
        return ret;
 }
 
@@ -260,28 +612,45 @@ static int proc_sys_fill_cache(struct file *filp, void *dirent,
        return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
 }
 
+static int proc_sys_link_fill_cache(struct file *filp, void *dirent,
+                                   filldir_t filldir,
+                                   struct ctl_table_header *head,
+                                   struct ctl_table *table)
+{
+       int err, ret = 0;
+       head = sysctl_head_grab(head);
+
+       if (S_ISLNK(table->mode)) {
+               /* It is not an error if we can not follow the link ignore it */
+               err = sysctl_follow_link(&head, &table, current->nsproxy);
+               if (err)
+                       goto out;
+       }
+
+       ret = proc_sys_fill_cache(filp, dirent, filldir, head, table);
+out:
+       sysctl_head_finish(head);
+       return ret;
+}
+
 static int scan(struct ctl_table_header *head, ctl_table *table,
                unsigned long *pos, struct file *file,
                void *dirent, filldir_t filldir)
 {
+       int res;
 
-       for (; table->procname; table++, (*pos)++) {
-               int res;
-
-               /* Can't do anything without a proc name */
-               if (!table->procname)
-                       continue;
-
-               if (*pos < file->f_pos)
-                       continue;
+       if ((*pos)++ < file->f_pos)
+               return 0;
 
+       if (unlikely(S_ISLNK(table->mode)))
+               res = proc_sys_link_fill_cache(file, dirent, filldir, head, table);
+       else
                res = proc_sys_fill_cache(file, dirent, filldir, head, table);
-               if (res)
-                       return res;
 
-               file->f_pos = *pos + 1;
-       }
-       return 0;
+       if (res == 0)
+               file->f_pos = *pos;
+
+       return res;
 }
 
 static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
@@ -289,20 +658,16 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        struct ctl_table_header *head = grab_header(inode);
-       struct ctl_table *table = PROC_I(inode)->sysctl_entry;
        struct ctl_table_header *h = NULL;
+       struct ctl_table *entry;
+       struct ctl_dir *ctl_dir;
        unsigned long pos;
        int ret = -EINVAL;
 
        if (IS_ERR(head))
                return PTR_ERR(head);
 
-       if (table && !table->child) {
-               WARN_ON(1);
-               goto out;
-       }
-
-       table = table ? table->child : head->ctl_table;
+       ctl_dir = container_of(head, struct ctl_dir, header);
 
        ret = 0;
        /* Avoid a switch here: arm builds fail with missing __cmpdi2 */
@@ -320,14 +685,8 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
        }
        pos = 2;
 
-       ret = scan(head, table, &pos, filp, dirent, filldir);
-       if (ret)
-               goto out;
-
-       for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
-               if (h->attached_to != table)
-                       continue;
-               ret = scan(h, h->attached_by, &pos, filp, dirent, filldir);
+       for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) {
+               ret = scan(h, entry, &pos, filp, dirent, filldir);
                if (ret) {
                        sysctl_head_finish(h);
                        break;
@@ -447,6 +806,21 @@ static int proc_sys_delete(const struct dentry *dentry)
        return !!PROC_I(dentry->d_inode)->sysctl->unregistering;
 }
 
+static int sysctl_is_seen(struct ctl_table_header *p)
+{
+       struct ctl_table_set *set = p->set;
+       int res;
+       spin_lock(&sysctl_lock);
+       if (p->unregistering)
+               res = 0;
+       else if (!set->is_seen)
+               res = 1;
+       else
+               res = set->is_seen(set);
+       spin_unlock(&sysctl_lock);
+       return res;
+}
+
 static int proc_sys_compare(const struct dentry *parent,
                const struct inode *pinode,
                const struct dentry *dentry, const struct inode *inode,
@@ -472,6 +846,753 @@ static const struct dentry_operations proc_sys_dentry_operations = {
        .d_compare      = proc_sys_compare,
 };
 
+static struct ctl_dir *find_subdir(struct ctl_dir *dir,
+                                  const char *name, int namelen)
+{
+       struct ctl_table_header *head;
+       struct ctl_table *entry;
+
+       entry = find_entry(&head, dir, name, namelen);
+       if (!entry)
+               return ERR_PTR(-ENOENT);
+       if (!S_ISDIR(entry->mode))
+               return ERR_PTR(-ENOTDIR);
+       return container_of(head, struct ctl_dir, header);
+}
+
+static struct ctl_dir *new_dir(struct ctl_table_set *set,
+                              const char *name, int namelen)
+{
+       struct ctl_table *table;
+       struct ctl_dir *new;
+       struct ctl_node *node;
+       char *new_name;
+
+       new = kzalloc(sizeof(*new) + sizeof(struct ctl_node) +
+                     sizeof(struct ctl_table)*2 +  namelen + 1,
+                     GFP_KERNEL);
+       if (!new)
+               return NULL;
+
+       node = (struct ctl_node *)(new + 1);
+       table = (struct ctl_table *)(node + 1);
+       new_name = (char *)(table + 2);
+       memcpy(new_name, name, namelen);
+       new_name[namelen] = '\0';
+       table[0].procname = new_name;
+       table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO;
+       init_header(&new->header, set->dir.header.root, set, node, table);
+
+       return new;
+}
+
+/**
+ * get_subdir - find or create a subdir with the specified name.
+ * @dir:  Directory to create the subdirectory in
+ * @name: The name of the subdirectory to find or create
+ * @namelen: The length of name
+ *
+ * Takes a directory with an elevated reference count so we know that
+ * if we drop the lock the directory will not go away.  Upon success
+ * the reference is moved from @dir to the returned subdirectory.
+ * Upon error an error code is returned and the reference on @dir is
+ * simply dropped.
+ */
+static struct ctl_dir *get_subdir(struct ctl_dir *dir,
+                                 const char *name, int namelen)
+{
+       struct ctl_table_set *set = dir->header.set;
+       struct ctl_dir *subdir, *new = NULL;
+       int err;
+
+       spin_lock(&sysctl_lock);
+       subdir = find_subdir(dir, name, namelen);
+       if (!IS_ERR(subdir))
+               goto found;
+       if (PTR_ERR(subdir) != -ENOENT)
+               goto failed;
+
+       spin_unlock(&sysctl_lock);
+       new = new_dir(set, name, namelen);
+       spin_lock(&sysctl_lock);
+       subdir = ERR_PTR(-ENOMEM);
+       if (!new)
+               goto failed;
+
+       /* Was the subdir added while we dropped the lock? */
+       subdir = find_subdir(dir, name, namelen);
+       if (!IS_ERR(subdir))
+               goto found;
+       if (PTR_ERR(subdir) != -ENOENT)
+               goto failed;
+
+       /* Nope.  Use the our freshly made directory entry. */
+       err = insert_header(dir, &new->header);
+       subdir = ERR_PTR(err);
+       if (err)
+               goto failed;
+       subdir = new;
+found:
+       subdir->header.nreg++;
+failed:
+       if (unlikely(IS_ERR(subdir))) {
+               printk(KERN_ERR "sysctl could not get directory: ");
+               sysctl_print_dir(dir);
+               printk(KERN_CONT "/%*.*s %ld\n",
+                       namelen, namelen, name, PTR_ERR(subdir));
+       }
+       drop_sysctl_table(&dir->header);
+       if (new)
+               drop_sysctl_table(&new->header);
+       spin_unlock(&sysctl_lock);
+       return subdir;
+}
+
+static struct ctl_dir *xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
+{
+       struct ctl_dir *parent;
+       const char *procname;
+       if (!dir->header.parent)
+               return &set->dir;
+       parent = xlate_dir(set, dir->header.parent);
+       if (IS_ERR(parent))
+               return parent;
+       procname = dir->header.ctl_table[0].procname;
+       return find_subdir(parent, procname, strlen(procname));
+}
+
+static int sysctl_follow_link(struct ctl_table_header **phead,
+       struct ctl_table **pentry, struct nsproxy *namespaces)
+{
+       struct ctl_table_header *head;
+       struct ctl_table_root *root;
+       struct ctl_table_set *set;
+       struct ctl_table *entry;
+       struct ctl_dir *dir;
+       int ret;
+
+       ret = 0;
+       spin_lock(&sysctl_lock);
+       root = (*pentry)->data;
+       set = lookup_header_set(root, namespaces);
+       dir = xlate_dir(set, (*phead)->parent);
+       if (IS_ERR(dir))
+               ret = PTR_ERR(dir);
+       else {
+               const char *procname = (*pentry)->procname;
+               head = NULL;
+               entry = find_entry(&head, dir, procname, strlen(procname));
+               ret = -ENOENT;
+               if (entry && use_table(head)) {
+                       unuse_table(*phead);
+                       *phead = head;
+                       *pentry = entry;
+                       ret = 0;
+               }
+       }
+
+       spin_unlock(&sysctl_lock);
+       return ret;
+}
+
+static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       printk(KERN_ERR "sysctl table check failed: %s/%s %pV\n",
+               path, table->procname, &vaf);
+
+       va_end(args);
+       return -EINVAL;
+}
+
+static int sysctl_check_table(const char *path, struct ctl_table *table)
+{
+       int err = 0;
+       for (; table->procname; table++) {
+               if (table->child)
+                       err = sysctl_err(path, table, "Not a file");
+
+               if ((table->proc_handler == proc_dostring) ||
+                   (table->proc_handler == proc_dointvec) ||
+                   (table->proc_handler == proc_dointvec_minmax) ||
+                   (table->proc_handler == proc_dointvec_jiffies) ||
+                   (table->proc_handler == proc_dointvec_userhz_jiffies) ||
+                   (table->proc_handler == proc_dointvec_ms_jiffies) ||
+                   (table->proc_handler == proc_doulongvec_minmax) ||
+                   (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
+                       if (!table->data)
+                               err = sysctl_err(path, table, "No data");
+                       if (!table->maxlen)
+                               err = sysctl_err(path, table, "No maxlen");
+               }
+               if (!table->proc_handler)
+                       err = sysctl_err(path, table, "No proc_handler");
+
+               if ((table->mode & (S_IRUGO|S_IWUGO)) != table->mode)
+                       err = sysctl_err(path, table, "bogus .mode 0%o",
+                               table->mode);
+       }
+       return err;
+}
+
+static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table *table,
+       struct ctl_table_root *link_root)
+{
+       struct ctl_table *link_table, *entry, *link;
+       struct ctl_table_header *links;
+       struct ctl_node *node;
+       char *link_name;
+       int nr_entries, name_bytes;
+
+       name_bytes = 0;
+       nr_entries = 0;
+       for (entry = table; entry->procname; entry++) {
+               nr_entries++;
+               name_bytes += strlen(entry->procname) + 1;
+       }
+
+       links = kzalloc(sizeof(struct ctl_table_header) +
+                       sizeof(struct ctl_node)*nr_entries +
+                       sizeof(struct ctl_table)*(nr_entries + 1) +
+                       name_bytes,
+                       GFP_KERNEL);
+
+       if (!links)
+               return NULL;
+
+       node = (struct ctl_node *)(links + 1);
+       link_table = (struct ctl_table *)(node + nr_entries);
+       link_name = (char *)&link_table[nr_entries + 1];
+
+       for (link = link_table, entry = table; entry->procname; link++, entry++) {
+               int len = strlen(entry->procname) + 1;
+               memcpy(link_name, entry->procname, len);
+               link->procname = link_name;
+               link->mode = S_IFLNK|S_IRWXUGO;
+               link->data = link_root;
+               link_name += len;
+       }
+       init_header(links, dir->header.root, dir->header.set, node, link_table);
+       links->nreg = nr_entries;
+
+       return links;
+}
+
+static bool get_links(struct ctl_dir *dir,
+       struct ctl_table *table, struct ctl_table_root *link_root)
+{
+       struct ctl_table_header *head;
+       struct ctl_table *entry, *link;
+
+       /* Are there links available for every entry in table? */
+       for (entry = table; entry->procname; entry++) {
+               const char *procname = entry->procname;
+               link = find_entry(&head, dir, procname, strlen(procname));
+               if (!link)
+                       return false;
+               if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
+                       continue;
+               if (S_ISLNK(link->mode) && (link->data == link_root))
+                       continue;
+               return false;
+       }
+
+       /* The checks passed.  Increase the registration count on the links */
+       for (entry = table; entry->procname; entry++) {
+               const char *procname = entry->procname;
+               link = find_entry(&head, dir, procname, strlen(procname));
+               head->nreg++;
+       }
+       return true;
+}
+
+static int insert_links(struct ctl_table_header *head)
+{
+       struct ctl_table_set *root_set = &sysctl_table_root.default_set;
+       struct ctl_dir *core_parent = NULL;
+       struct ctl_table_header *links;
+       int err;
+
+       if (head->set == root_set)
+               return 0;
+
+       core_parent = xlate_dir(root_set, head->parent);
+       if (IS_ERR(core_parent))
+               return 0;
+
+       if (get_links(core_parent, head->ctl_table, head->root))
+               return 0;
+
+       core_parent->header.nreg++;
+       spin_unlock(&sysctl_lock);
+
+       links = new_links(core_parent, head->ctl_table, head->root);
+
+       spin_lock(&sysctl_lock);
+       err = -ENOMEM;
+       if (!links)
+               goto out;
+
+       err = 0;
+       if (get_links(core_parent, head->ctl_table, head->root)) {
+               kfree(links);
+               goto out;
+       }
+
+       err = insert_header(core_parent, links);
+       if (err)
+               kfree(links);
+out:
+       drop_sysctl_table(&core_parent->header);
+       return err;
+}
+
+/**
+ * __register_sysctl_table - register a leaf sysctl table
+ * @set: Sysctl tree to register on
+ * @path: The path to the directory the sysctl table is in.
+ * @table: the top-level table structure
+ *
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * The members of the &struct ctl_table structure are used as follows:
+ *
+ * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
+ *            enter a sysctl file
+ *
+ * data - a pointer to data for use by proc_handler
+ *
+ * maxlen - the maximum size in bytes of the data
+ *
+ * mode - the file permissions for the /proc/sys file
+ *
+ * child - must be %NULL.
+ *
+ * proc_handler - the text handler routine (described below)
+ *
+ * extra1, extra2 - extra pointers usable by the proc handler routines
+ *
+ * Leaf nodes in the sysctl tree will be represented by a single file
+ * under /proc; non-leaf nodes will be represented by directories.
+ *
+ * There must be a proc_handler routine for any terminal nodes.
+ * Several default handlers are available to cover common cases -
+ *
+ * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
+ * proc_dointvec_userhz_jiffies(), proc_dointvec_minmax(),
+ * proc_doulongvec_ms_jiffies_minmax(), proc_doulongvec_minmax()
+ *
+ * It is the handler's job to read the input buffer from user memory
+ * and process it. The handler should return 0 on success.
+ *
+ * This routine returns %NULL on a failure to register, and a pointer
+ * to the table header on success.
+ */
+struct ctl_table_header *__register_sysctl_table(
+       struct ctl_table_set *set,
+       const char *path, struct ctl_table *table)
+{
+       struct ctl_table_root *root = set->dir.header.root;
+       struct ctl_table_header *header;
+       const char *name, *nextname;
+       struct ctl_dir *dir;
+       struct ctl_table *entry;
+       struct ctl_node *node;
+       int nr_entries = 0;
+
+       for (entry = table; entry->procname; entry++)
+               nr_entries++;
+
+       header = kzalloc(sizeof(struct ctl_table_header) +
+                        sizeof(struct ctl_node)*nr_entries, GFP_KERNEL);
+       if (!header)
+               return NULL;
+
+       node = (struct ctl_node *)(header + 1);
+       init_header(header, root, set, node, table);
+       if (sysctl_check_table(path, table))
+               goto fail;
+
+       spin_lock(&sysctl_lock);
+       dir = &set->dir;
+       /* Reference moved down the diretory tree get_subdir */
+       dir->header.nreg++;
+       spin_unlock(&sysctl_lock);
+
+       /* Find the directory for the ctl_table */
+       for (name = path; name; name = nextname) {
+               int namelen;
+               nextname = strchr(name, '/');
+               if (nextname) {
+                       namelen = nextname - name;
+                       nextname++;
+               } else {
+                       namelen = strlen(name);
+               }
+               if (namelen == 0)
+                       continue;
+
+               dir = get_subdir(dir, name, namelen);
+               if (IS_ERR(dir))
+                       goto fail;
+       }
+
+       spin_lock(&sysctl_lock);
+       if (insert_header(dir, header))
+               goto fail_put_dir_locked;
+
+       drop_sysctl_table(&dir->header);
+       spin_unlock(&sysctl_lock);
+
+       return header;
+
+fail_put_dir_locked:
+       drop_sysctl_table(&dir->header);
+       spin_unlock(&sysctl_lock);
+fail:
+       kfree(header);
+       dump_stack();
+       return NULL;
+}
+
+/**
+ * register_sysctl - register a sysctl table
+ * @path: The path to the directory the sysctl table is in.
+ * @table: the table structure
+ *
+ * Register a sysctl table. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * See __register_sysctl_table for more details.
+ */
+struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
+{
+       return __register_sysctl_table(&sysctl_table_root.default_set,
+                                       path, table);
+}
+EXPORT_SYMBOL(register_sysctl);
+
+static char *append_path(const char *path, char *pos, const char *name)
+{
+       int namelen;
+       namelen = strlen(name);
+       if (((pos - path) + namelen + 2) >= PATH_MAX)
+               return NULL;
+       memcpy(pos, name, namelen);
+       pos[namelen] = '/';
+       pos[namelen + 1] = '\0';
+       pos += namelen + 1;
+       return pos;
+}
+
+static int count_subheaders(struct ctl_table *table)
+{
+       int has_files = 0;
+       int nr_subheaders = 0;
+       struct ctl_table *entry;
+
+       /* special case: no directory and empty directory */
+       if (!table || !table->procname)
+               return 1;
+
+       for (entry = table; entry->procname; entry++) {
+               if (entry->child)
+                       nr_subheaders += count_subheaders(entry->child);
+               else
+                       has_files = 1;
+       }
+       return nr_subheaders + has_files;
+}
+
+static int register_leaf_sysctl_tables(const char *path, char *pos,
+       struct ctl_table_header ***subheader, struct ctl_table_set *set,
+       struct ctl_table *table)
+{
+       struct ctl_table *ctl_table_arg = NULL;
+       struct ctl_table *entry, *files;
+       int nr_files = 0;
+       int nr_dirs = 0;
+       int err = -ENOMEM;
+
+       for (entry = table; entry->procname; entry++) {
+               if (entry->child)
+                       nr_dirs++;
+               else
+                       nr_files++;
+       }
+
+       files = table;
+       /* If there are mixed files and directories we need a new table */
+       if (nr_dirs && nr_files) {
+               struct ctl_table *new;
+               files = kzalloc(sizeof(struct ctl_table) * (nr_files + 1),
+                               GFP_KERNEL);
+               if (!files)
+                       goto out;
+
+               ctl_table_arg = files;
+               for (new = files, entry = table; entry->procname; entry++) {
+                       if (entry->child)
+                               continue;
+                       *new = *entry;
+                       new++;
+               }
+       }
+
+       /* Register everything except a directory full of subdirectories */
+       if (nr_files || !nr_dirs) {
+               struct ctl_table_header *header;
+               header = __register_sysctl_table(set, path, files);
+               if (!header) {
+                       kfree(ctl_table_arg);
+                       goto out;
+               }
+
+               /* Remember if we need to free the file table */
+               header->ctl_table_arg = ctl_table_arg;
+               **subheader = header;
+               (*subheader)++;
+       }
+
+       /* Recurse into the subdirectories. */
+       for (entry = table; entry->procname; entry++) {
+               char *child_pos;
+
+               if (!entry->child)
+                       continue;
+
+               err = -ENAMETOOLONG;
+               child_pos = append_path(path, pos, entry->procname);
+               if (!child_pos)
+                       goto out;
+
+               err = register_leaf_sysctl_tables(path, child_pos, subheader,
+                                                 set, entry->child);
+               pos[0] = '\0';
+               if (err)
+                       goto out;
+       }
+       err = 0;
+out:
+       /* On failure our caller will unregister all registered subheaders */
+       return err;
+}
+
+/**
+ * __register_sysctl_paths - register a sysctl table hierarchy
+ * @set: Sysctl tree to register on
+ * @path: The path to the directory the sysctl table is in.
+ * @table: the top-level table structure
+ *
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * See __register_sysctl_table for more details.
+ */
+struct ctl_table_header *__register_sysctl_paths(
+       struct ctl_table_set *set,
+       const struct ctl_path *path, struct ctl_table *table)
+{
+       struct ctl_table *ctl_table_arg = table;
+       int nr_subheaders = count_subheaders(table);
+       struct ctl_table_header *header = NULL, **subheaders, **subheader;
+       const struct ctl_path *component;
+       char *new_path, *pos;
+
+       pos = new_path = kmalloc(PATH_MAX, GFP_KERNEL);
+       if (!new_path)
+               return NULL;
+
+       pos[0] = '\0';
+       for (component = path; component->procname; component++) {
+               pos = append_path(new_path, pos, component->procname);
+               if (!pos)
+                       goto out;
+       }
+       while (table->procname && table->child && !table[1].procname) {
+               pos = append_path(new_path, pos, table->procname);
+               if (!pos)
+                       goto out;
+               table = table->child;
+       }
+       if (nr_subheaders == 1) {
+               header = __register_sysctl_table(set, new_path, table);
+               if (header)
+                       header->ctl_table_arg = ctl_table_arg;
+       } else {
+               header = kzalloc(sizeof(*header) +
+                                sizeof(*subheaders)*nr_subheaders, GFP_KERNEL);
+               if (!header)
+                       goto out;
+
+               subheaders = (struct ctl_table_header **) (header + 1);
+               subheader = subheaders;
+               header->ctl_table_arg = ctl_table_arg;
+
+               if (register_leaf_sysctl_tables(new_path, pos, &subheader,
+                                               set, table))
+                       goto err_register_leaves;
+       }
+
+out:
+       kfree(new_path);
+       return header;
+
+err_register_leaves:
+       while (subheader > subheaders) {
+               struct ctl_table_header *subh = *(--subheader);
+               struct ctl_table *table = subh->ctl_table_arg;
+               unregister_sysctl_table(subh);
+               kfree(table);
+       }
+       kfree(header);
+       header = NULL;
+       goto out;
+}
+
+/**
+ * register_sysctl_table_path - register a sysctl table hierarchy
+ * @path: The path to the directory the sysctl table is in.
+ * @table: the top-level table structure
+ *
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * See __register_sysctl_paths for more details.
+ */
+struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
+                                               struct ctl_table *table)
+{
+       return __register_sysctl_paths(&sysctl_table_root.default_set,
+                                       path, table);
+}
+EXPORT_SYMBOL(register_sysctl_paths);
+
+/**
+ * register_sysctl_table - register a sysctl table hierarchy
+ * @table: the top-level table structure
+ *
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * See register_sysctl_paths for more details.
+ */
+struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
+{
+       static const struct ctl_path null_path[] = { {} };
+
+       return register_sysctl_paths(null_path, table);
+}
+EXPORT_SYMBOL(register_sysctl_table);
+
+static void put_links(struct ctl_table_header *header)
+{
+       struct ctl_table_set *root_set = &sysctl_table_root.default_set;
+       struct ctl_table_root *root = header->root;
+       struct ctl_dir *parent = header->parent;
+       struct ctl_dir *core_parent;
+       struct ctl_table *entry;
+
+       if (header->set == root_set)
+               return;
+
+       core_parent = xlate_dir(root_set, parent);
+       if (IS_ERR(core_parent))
+               return;
+
+       for (entry = header->ctl_table; entry->procname; entry++) {
+               struct ctl_table_header *link_head;
+               struct ctl_table *link;
+               const char *name = entry->procname;
+
+               link = find_entry(&link_head, core_parent, name, strlen(name));
+               if (link &&
+                   ((S_ISDIR(link->mode) && S_ISDIR(entry->mode)) ||
+                    (S_ISLNK(link->mode) && (link->data == root)))) {
+                       drop_sysctl_table(link_head);
+               }
+               else {
+                       printk(KERN_ERR "sysctl link missing during unregister: ");
+                       sysctl_print_dir(parent);
+                       printk(KERN_CONT "/%s\n", name);
+               }
+       }
+}
+
+static void drop_sysctl_table(struct ctl_table_header *header)
+{
+       struct ctl_dir *parent = header->parent;
+
+       if (--header->nreg)
+               return;
+
+       put_links(header);
+       start_unregistering(header);
+       if (!--header->count)
+               kfree_rcu(header, rcu);
+
+       if (parent)
+               drop_sysctl_table(&parent->header);
+}
+
+/**
+ * unregister_sysctl_table - unregister a sysctl table hierarchy
+ * @header: the header returned from register_sysctl_table
+ *
+ * Unregisters the sysctl table and all children. proc entries may not
+ * actually be removed until they are no longer used by anyone.
+ */
+void unregister_sysctl_table(struct ctl_table_header * header)
+{
+       int nr_subheaders;
+       might_sleep();
+
+       if (header == NULL)
+               return;
+
+       nr_subheaders = count_subheaders(header->ctl_table_arg);
+       if (unlikely(nr_subheaders > 1)) {
+               struct ctl_table_header **subheaders;
+               int i;
+
+               subheaders = (struct ctl_table_header **)(header + 1);
+               for (i = nr_subheaders -1; i >= 0; i--) {
+                       struct ctl_table_header *subh = subheaders[i];
+                       struct ctl_table *table = subh->ctl_table_arg;
+                       unregister_sysctl_table(subh);
+                       kfree(table);
+               }
+               kfree(header);
+               return;
+       }
+
+       spin_lock(&sysctl_lock);
+       drop_sysctl_table(header);
+       spin_unlock(&sysctl_lock);
+}
+EXPORT_SYMBOL(unregister_sysctl_table);
+
+void setup_sysctl_set(struct ctl_table_set *set,
+       struct ctl_table_root *root,
+       int (*is_seen)(struct ctl_table_set *))
+{
+       memset(set, 0, sizeof(*set));
+       set->is_seen = is_seen;
+       init_header(&set->dir.header, root, set, NULL, root_table);
+}
+
+void retire_sysctl_set(struct ctl_table_set *set)
+{
+       WARN_ON(!RB_EMPTY_ROOT(&set->dir.root));
+}
+
 int __init proc_sys_init(void)
 {
        struct proc_dir_entry *proc_sys_root;
@@ -480,5 +1601,6 @@ int __init proc_sys_init(void)
        proc_sys_root->proc_iops = &proc_sys_dir_operations;
        proc_sys_root->proc_fops = &proc_sys_dir_file_operations;
        proc_sys_root->nlink = 0;
-       return 0;
+
+       return sysctl_init();
 }
index 121f77c..6a0c62d 100644 (file)
@@ -89,18 +89,19 @@ static int show_stat(struct seq_file *p, void *v)
        }
        sum += arch_irq_stat();
 
-       seq_printf(p, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu %llu "
-               "%llu\n",
-               (unsigned long long)cputime64_to_clock_t(user),
-               (unsigned long long)cputime64_to_clock_t(nice),
-               (unsigned long long)cputime64_to_clock_t(system),
-               (unsigned long long)cputime64_to_clock_t(idle),
-               (unsigned long long)cputime64_to_clock_t(iowait),
-               (unsigned long long)cputime64_to_clock_t(irq),
-               (unsigned long long)cputime64_to_clock_t(softirq),
-               (unsigned long long)cputime64_to_clock_t(steal),
-               (unsigned long long)cputime64_to_clock_t(guest),
-               (unsigned long long)cputime64_to_clock_t(guest_nice));
+       seq_puts(p, "cpu ");
+       seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(user));
+       seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(nice));
+       seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(system));
+       seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(idle));
+       seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(iowait));
+       seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(irq));
+       seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(softirq));
+       seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(steal));
+       seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest));
+       seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest_nice));
+       seq_putc(p, '\n');
+
        for_each_online_cpu(i) {
                /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
                user = kcpustat_cpu(i).cpustat[CPUTIME_USER];
@@ -113,26 +114,24 @@ static int show_stat(struct seq_file *p, void *v)
                steal = kcpustat_cpu(i).cpustat[CPUTIME_STEAL];
                guest = kcpustat_cpu(i).cpustat[CPUTIME_GUEST];
                guest_nice = kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE];
-               seq_printf(p,
-                       "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu "
-                       "%llu\n",
-                       i,
-                       (unsigned long long)cputime64_to_clock_t(user),
-                       (unsigned long long)cputime64_to_clock_t(nice),
-                       (unsigned long long)cputime64_to_clock_t(system),
-                       (unsigned long long)cputime64_to_clock_t(idle),
-                       (unsigned long long)cputime64_to_clock_t(iowait),
-                       (unsigned long long)cputime64_to_clock_t(irq),
-                       (unsigned long long)cputime64_to_clock_t(softirq),
-                       (unsigned long long)cputime64_to_clock_t(steal),
-                       (unsigned long long)cputime64_to_clock_t(guest),
-                       (unsigned long long)cputime64_to_clock_t(guest_nice));
+               seq_printf(p, "cpu%d", i);
+               seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(user));
+               seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(nice));
+               seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(system));
+               seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(idle));
+               seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(iowait));
+               seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(irq));
+               seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(softirq));
+               seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(steal));
+               seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest));
+               seq_put_decimal_ull(p, ' ', cputime64_to_clock_t(guest_nice));
+               seq_putc(p, '\n');
        }
        seq_printf(p, "intr %llu", (unsigned long long)sum);
 
        /* sum again ? it could be updated? */
        for_each_irq_nr(j)
-               seq_printf(p, " %u", kstat_irqs(j));
+               seq_put_decimal_ull(p, ' ', kstat_irqs(j));
 
        seq_printf(p,
                "\nctxt %llu\n"
@@ -149,7 +148,7 @@ static int show_stat(struct seq_file *p, void *v)
        seq_printf(p, "softirq %llu", (unsigned long long)sum_softirq);
 
        for (i = 0; i < NR_SOFTIRQS; i++)
-               seq_printf(p, " %u", per_softirq_sums[i]);
+               seq_put_decimal_ull(p, ' ', per_softirq_sums[i]);
        seq_putc(p, '\n');
 
        return 0;
@@ -157,11 +156,14 @@ static int show_stat(struct seq_file *p, void *v)
 
 static int stat_open(struct inode *inode, struct file *file)
 {
-       unsigned size = 4096 * (1 + num_possible_cpus() / 32);
+       unsigned size = 1024 + 128 * num_possible_cpus();
        char *buf;
        struct seq_file *m;
        int res;
 
+       /* minimum size to display an interrupt count : 2 bytes */
+       size += 2 * nr_irqs;
+
        /* don't ask for more than the kmalloc() max size */
        if (size > KMALLOC_MAX_SIZE)
                size = KMALLOC_MAX_SIZE;
@@ -173,7 +175,7 @@ static int stat_open(struct inode *inode, struct file *file)
        if (!res) {
                m = file->private_data;
                m->buf = buf;
-               m->size = size;
+               m->size = ksize(buf);
        } else
                kfree(buf);
        return res;
index 9ec22d3..82c585f 100644 (file)
@@ -68,9 +68,25 @@ void pstore_set_kmsg_bytes(int bytes)
 /* Tag each group of saved records with a sequence number */
 static int     oopscount;
 
-static char *reason_str[] = {
-       "Oops", "Panic", "Kexec", "Restart", "Halt", "Poweroff", "Emergency"
-};
+static const char *get_reason_str(enum kmsg_dump_reason reason)
+{
+       switch (reason) {
+       case KMSG_DUMP_PANIC:
+               return "Panic";
+       case KMSG_DUMP_OOPS:
+               return "Oops";
+       case KMSG_DUMP_EMERG:
+               return "Emergency";
+       case KMSG_DUMP_RESTART:
+               return "Restart";
+       case KMSG_DUMP_HALT:
+               return "Halt";
+       case KMSG_DUMP_POWEROFF:
+               return "Poweroff";
+       default:
+               return "Unknown";
+       }
+}
 
 /*
  * callback from kmsg_dump. (s2,l2) has the most recently
@@ -85,17 +101,15 @@ static void pstore_dump(struct kmsg_dumper *dumper,
        unsigned long   s1_start, s2_start;
        unsigned long   l1_cpy, l2_cpy;
        unsigned long   size, total = 0;
-       char            *dst, *why;
+       char            *dst;
+       const char      *why;
        u64             id;
        int             hsize, ret;
        unsigned int    part = 1;
        unsigned long   flags = 0;
        int             is_locked = 0;
 
-       if (reason < ARRAY_SIZE(reason_str))
-               why = reason_str[reason];
-       else
-               why = "Unknown";
+       why = get_reason_str(reason);
 
        if (in_nmi()) {
                is_locked = spin_trylock(&psinfo->buf_lock);
index 8b4f12b..d69a1d1 100644 (file)
@@ -1110,6 +1110,13 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
        clear_bit(DQ_BLKS_B, &dquot->dq_flags);
 }
 
+struct dquot_warn {
+       struct super_block *w_sb;
+       qid_t w_dq_id;
+       short w_dq_type;
+       short w_type;
+};
+
 static int warning_issued(struct dquot *dquot, const int warntype)
 {
        int flag = (warntype == QUOTA_NL_BHARDWARN ||
@@ -1125,41 +1132,42 @@ static int warning_issued(struct dquot *dquot, const int warntype)
 #ifdef CONFIG_PRINT_QUOTA_WARNING
 static int flag_print_warnings = 1;
 
-static int need_print_warning(struct dquot *dquot)
+static int need_print_warning(struct dquot_warn *warn)
 {
        if (!flag_print_warnings)
                return 0;
 
-       switch (dquot->dq_type) {
+       switch (warn->w_dq_type) {
                case USRQUOTA:
-                       return current_fsuid() == dquot->dq_id;
+                       return current_fsuid() == warn->w_dq_id;
                case GRPQUOTA:
-                       return in_group_p(dquot->dq_id);
+                       return in_group_p(warn->w_dq_id);
        }
        return 0;
 }
 
 /* Print warning to user which exceeded quota */
-static void print_warning(struct dquot *dquot, const int warntype)
+static void print_warning(struct dquot_warn *warn)
 {
        char *msg = NULL;
        struct tty_struct *tty;
+       int warntype = warn->w_type;
 
        if (warntype == QUOTA_NL_IHARDBELOW ||
            warntype == QUOTA_NL_ISOFTBELOW ||
            warntype == QUOTA_NL_BHARDBELOW ||
-           warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot))
+           warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(warn))
                return;
 
        tty = get_current_tty();
        if (!tty)
                return;
-       tty_write_message(tty, dquot->dq_sb->s_id);
+       tty_write_message(tty, warn->w_sb->s_id);
        if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN)
                tty_write_message(tty, ": warning, ");
        else
                tty_write_message(tty, ": write failed, ");
-       tty_write_message(tty, quotatypes[dquot->dq_type]);
+       tty_write_message(tty, quotatypes[warn->w_dq_type]);
        switch (warntype) {
                case QUOTA_NL_IHARDWARN:
                        msg = " file limit reached.\r\n";
@@ -1185,26 +1193,34 @@ static void print_warning(struct dquot *dquot, const int warntype)
 }
 #endif
 
+static void prepare_warning(struct dquot_warn *warn, struct dquot *dquot,
+                           int warntype)
+{
+       if (warning_issued(dquot, warntype))
+               return;
+       warn->w_type = warntype;
+       warn->w_sb = dquot->dq_sb;
+       warn->w_dq_id = dquot->dq_id;
+       warn->w_dq_type = dquot->dq_type;
+}
+
 /*
  * Write warnings to the console and send warning messages over netlink.
  *
- * Note that this function can sleep.
+ * Note that this function can call into tty and networking code.
  */
-static void flush_warnings(struct dquot *const *dquots, char *warntype)
+static void flush_warnings(struct dquot_warn *warn)
 {
-       struct dquot *dq;
        int i;
 
        for (i = 0; i < MAXQUOTAS; i++) {
-               dq = dquots[i];
-               if (dq && warntype[i] != QUOTA_NL_NOWARN &&
-                   !warning_issued(dq, warntype[i])) {
+               if (warn[i].w_type == QUOTA_NL_NOWARN)
+                       continue;
 #ifdef CONFIG_PRINT_QUOTA_WARNING
-                       print_warning(dq, warntype[i]);
+               print_warning(&warn[i]);
 #endif
-                       quota_send_warning(dq->dq_type, dq->dq_id,
-                                          dq->dq_sb->s_dev, warntype[i]);
-               }
+               quota_send_warning(warn[i].w_dq_type, warn[i].w_dq_id,
+                                  warn[i].w_sb->s_dev, warn[i].w_type);
        }
 }
 
@@ -1218,11 +1234,11 @@ static int ignore_hardlimit(struct dquot *dquot)
 }
 
 /* needs dq_data_lock */
-static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
+static int check_idq(struct dquot *dquot, qsize_t inodes,
+                    struct dquot_warn *warn)
 {
        qsize_t newinodes = dquot->dq_dqb.dqb_curinodes + inodes;
 
-       *warntype = QUOTA_NL_NOWARN;
        if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) ||
            test_bit(DQ_FAKE_B, &dquot->dq_flags))
                return 0;
@@ -1230,7 +1246,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
        if (dquot->dq_dqb.dqb_ihardlimit &&
            newinodes > dquot->dq_dqb.dqb_ihardlimit &&
             !ignore_hardlimit(dquot)) {
-               *warntype = QUOTA_NL_IHARDWARN;
+               prepare_warning(warn, dquot, QUOTA_NL_IHARDWARN);
                return -EDQUOT;
        }
 
@@ -1239,14 +1255,14 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
            dquot->dq_dqb.dqb_itime &&
            get_seconds() >= dquot->dq_dqb.dqb_itime &&
             !ignore_hardlimit(dquot)) {
-               *warntype = QUOTA_NL_ISOFTLONGWARN;
+               prepare_warning(warn, dquot, QUOTA_NL_ISOFTLONGWARN);
                return -EDQUOT;
        }
 
        if (dquot->dq_dqb.dqb_isoftlimit &&
            newinodes > dquot->dq_dqb.dqb_isoftlimit &&
            dquot->dq_dqb.dqb_itime == 0) {
-               *warntype = QUOTA_NL_ISOFTWARN;
+               prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN);
                dquot->dq_dqb.dqb_itime = get_seconds() +
                    sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
        }
@@ -1255,12 +1271,12 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype)
 }
 
 /* needs dq_data_lock */
-static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
+static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc,
+                    struct dquot_warn *warn)
 {
        qsize_t tspace;
        struct super_block *sb = dquot->dq_sb;
 
-       *warntype = QUOTA_NL_NOWARN;
        if (!sb_has_quota_limits_enabled(sb, dquot->dq_type) ||
            test_bit(DQ_FAKE_B, &dquot->dq_flags))
                return 0;
@@ -1272,7 +1288,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
            tspace > dquot->dq_dqb.dqb_bhardlimit &&
             !ignore_hardlimit(dquot)) {
                if (!prealloc)
-                       *warntype = QUOTA_NL_BHARDWARN;
+                       prepare_warning(warn, dquot, QUOTA_NL_BHARDWARN);
                return -EDQUOT;
        }
 
@@ -1282,7 +1298,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
            get_seconds() >= dquot->dq_dqb.dqb_btime &&
             !ignore_hardlimit(dquot)) {
                if (!prealloc)
-                       *warntype = QUOTA_NL_BSOFTLONGWARN;
+                       prepare_warning(warn, dquot, QUOTA_NL_BSOFTLONGWARN);
                return -EDQUOT;
        }
 
@@ -1290,7 +1306,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
            tspace > dquot->dq_dqb.dqb_bsoftlimit &&
            dquot->dq_dqb.dqb_btime == 0) {
                if (!prealloc) {
-                       *warntype = QUOTA_NL_BSOFTWARN;
+                       prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN);
                        dquot->dq_dqb.dqb_btime = get_seconds() +
                            sb_dqopt(sb)->info[dquot->dq_type].dqi_bgrace;
                }
@@ -1543,10 +1559,9 @@ static void inode_decr_space(struct inode *inode, qsize_t number, int reserve)
 int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
 {
        int cnt, ret = 0;
-       char warntype[MAXQUOTAS];
-       int warn = flags & DQUOT_SPACE_WARN;
+       struct dquot_warn warn[MAXQUOTAS];
+       struct dquot **dquots = inode->i_dquot;
        int reserve = flags & DQUOT_SPACE_RESERVE;
-       int nofail = flags & DQUOT_SPACE_NOFAIL;
 
        /*
         * First test before acquiring mutex - solves deadlocks when we
@@ -1559,36 +1574,36 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
 
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               warntype[cnt] = QUOTA_NL_NOWARN;
+               warn[cnt].w_type = QUOTA_NL_NOWARN;
 
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (!inode->i_dquot[cnt])
+               if (!dquots[cnt])
                        continue;
-               ret = check_bdq(inode->i_dquot[cnt], number, !warn,
-                               warntype+cnt);
-               if (ret && !nofail) {
+               ret = check_bdq(dquots[cnt], number,
+                               !(flags & DQUOT_SPACE_WARN), &warn[cnt]);
+               if (ret && !(flags & DQUOT_SPACE_NOFAIL)) {
                        spin_unlock(&dq_data_lock);
                        goto out_flush_warn;
                }
        }
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (!inode->i_dquot[cnt])
+               if (!dquots[cnt])
                        continue;
                if (reserve)
-                       dquot_resv_space(inode->i_dquot[cnt], number);
+                       dquot_resv_space(dquots[cnt], number);
                else
-                       dquot_incr_space(inode->i_dquot[cnt], number);
+                       dquot_incr_space(dquots[cnt], number);
        }
        inode_incr_space(inode, number, reserve);
        spin_unlock(&dq_data_lock);
 
        if (reserve)
                goto out_flush_warn;
-       mark_all_dquot_dirty(inode->i_dquot);
+       mark_all_dquot_dirty(dquots);
 out_flush_warn:
-       flush_warnings(inode->i_dquot, warntype);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+       flush_warnings(warn);
 out:
        return ret;
 }
@@ -1600,36 +1615,37 @@ EXPORT_SYMBOL(__dquot_alloc_space);
 int dquot_alloc_inode(const struct inode *inode)
 {
        int cnt, ret = 0;
-       char warntype[MAXQUOTAS];
+       struct dquot_warn warn[MAXQUOTAS];
+       struct dquot * const *dquots = inode->i_dquot;
 
        /* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
        if (!dquot_active(inode))
                return 0;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               warntype[cnt] = QUOTA_NL_NOWARN;
+               warn[cnt].w_type = QUOTA_NL_NOWARN;
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (!inode->i_dquot[cnt])
+               if (!dquots[cnt])
                        continue;
-               ret = check_idq(inode->i_dquot[cnt], 1, warntype + cnt);
+               ret = check_idq(dquots[cnt], 1, &warn[cnt]);
                if (ret)
                        goto warn_put_all;
        }
 
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (!inode->i_dquot[cnt])
+               if (!dquots[cnt])
                        continue;
-               dquot_incr_inodes(inode->i_dquot[cnt], 1);
+               dquot_incr_inodes(dquots[cnt], 1);
        }
 
 warn_put_all:
        spin_unlock(&dq_data_lock);
        if (ret == 0)
-               mark_all_dquot_dirty(inode->i_dquot);
-       flush_warnings(inode->i_dquot, warntype);
+               mark_all_dquot_dirty(dquots);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+       flush_warnings(warn);
        return ret;
 }
 EXPORT_SYMBOL(dquot_alloc_inode);
@@ -1669,7 +1685,8 @@ EXPORT_SYMBOL(dquot_claim_space_nodirty);
 void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
 {
        unsigned int cnt;
-       char warntype[MAXQUOTAS];
+       struct dquot_warn warn[MAXQUOTAS];
+       struct dquot **dquots = inode->i_dquot;
        int reserve = flags & DQUOT_SPACE_RESERVE;
 
        /* First test before acquiring mutex - solves deadlocks when we
@@ -1682,23 +1699,28 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (!inode->i_dquot[cnt])
+               int wtype;
+
+               warn[cnt].w_type = QUOTA_NL_NOWARN;
+               if (!dquots[cnt])
                        continue;
-               warntype[cnt] = info_bdq_free(inode->i_dquot[cnt], number);
+               wtype = info_bdq_free(dquots[cnt], number);
+               if (wtype != QUOTA_NL_NOWARN)
+                       prepare_warning(&warn[cnt], dquots[cnt], wtype);
                if (reserve)
-                       dquot_free_reserved_space(inode->i_dquot[cnt], number);
+                       dquot_free_reserved_space(dquots[cnt], number);
                else
-                       dquot_decr_space(inode->i_dquot[cnt], number);
+                       dquot_decr_space(dquots[cnt], number);
        }
        inode_decr_space(inode, number, reserve);
        spin_unlock(&dq_data_lock);
 
        if (reserve)
                goto out_unlock;
-       mark_all_dquot_dirty(inode->i_dquot);
+       mark_all_dquot_dirty(dquots);
 out_unlock:
-       flush_warnings(inode->i_dquot, warntype);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+       flush_warnings(warn);
 }
 EXPORT_SYMBOL(__dquot_free_space);
 
@@ -1708,7 +1730,8 @@ EXPORT_SYMBOL(__dquot_free_space);
 void dquot_free_inode(const struct inode *inode)
 {
        unsigned int cnt;
-       char warntype[MAXQUOTAS];
+       struct dquot_warn warn[MAXQUOTAS];
+       struct dquot * const *dquots = inode->i_dquot;
 
        /* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
@@ -1718,15 +1741,20 @@ void dquot_free_inode(const struct inode *inode)
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (!inode->i_dquot[cnt])
+               int wtype;
+
+               warn[cnt].w_type = QUOTA_NL_NOWARN;
+               if (!dquots[cnt])
                        continue;
-               warntype[cnt] = info_idq_free(inode->i_dquot[cnt], 1);
-               dquot_decr_inodes(inode->i_dquot[cnt], 1);
+               wtype = info_idq_free(dquots[cnt], 1);
+               if (wtype != QUOTA_NL_NOWARN)
+                       prepare_warning(&warn[cnt], dquots[cnt], wtype);
+               dquot_decr_inodes(dquots[cnt], 1);
        }
        spin_unlock(&dq_data_lock);
-       mark_all_dquot_dirty(inode->i_dquot);
-       flush_warnings(inode->i_dquot, warntype);
+       mark_all_dquot_dirty(dquots);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+       flush_warnings(warn);
 }
 EXPORT_SYMBOL(dquot_free_inode);
 
@@ -1747,16 +1775,20 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
        struct dquot *transfer_from[MAXQUOTAS] = {};
        int cnt, ret = 0;
        char is_valid[MAXQUOTAS] = {};
-       char warntype_to[MAXQUOTAS];
-       char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS];
+       struct dquot_warn warn_to[MAXQUOTAS];
+       struct dquot_warn warn_from_inodes[MAXQUOTAS];
+       struct dquot_warn warn_from_space[MAXQUOTAS];
 
        /* First test before acquiring mutex - solves deadlocks when we
          * re-enter the quota code and are already holding the mutex */
        if (IS_NOQUOTA(inode))
                return 0;
        /* Initialize the arrays */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               warntype_to[cnt] = QUOTA_NL_NOWARN;
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               warn_to[cnt].w_type = QUOTA_NL_NOWARN;
+               warn_from_inodes[cnt].w_type = QUOTA_NL_NOWARN;
+               warn_from_space[cnt].w_type = QUOTA_NL_NOWARN;
+       }
        down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
        if (IS_NOQUOTA(inode)) {        /* File without quota accounting? */
                up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@ -1778,10 +1810,10 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
                        continue;
                is_valid[cnt] = 1;
                transfer_from[cnt] = inode->i_dquot[cnt];
-               ret = check_idq(transfer_to[cnt], 1, warntype_to + cnt);
+               ret = check_idq(transfer_to[cnt], 1, &warn_to[cnt]);
                if (ret)
                        goto over_quota;
-               ret = check_bdq(transfer_to[cnt], space, 0, warntype_to + cnt);
+               ret = check_bdq(transfer_to[cnt], space, 0, &warn_to[cnt]);
                if (ret)
                        goto over_quota;
        }
@@ -1794,10 +1826,15 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
                        continue;
                /* Due to IO error we might not have transfer_from[] structure */
                if (transfer_from[cnt]) {
-                       warntype_from_inodes[cnt] =
-                               info_idq_free(transfer_from[cnt], 1);
-                       warntype_from_space[cnt] =
-                               info_bdq_free(transfer_from[cnt], space);
+                       int wtype;
+                       wtype = info_idq_free(transfer_from[cnt], 1);
+                       if (wtype != QUOTA_NL_NOWARN)
+                               prepare_warning(&warn_from_inodes[cnt],
+                                               transfer_from[cnt], wtype);
+                       wtype = info_bdq_free(transfer_from[cnt], space);
+                       if (wtype != QUOTA_NL_NOWARN)
+                               prepare_warning(&warn_from_space[cnt],
+                                               transfer_from[cnt], wtype);
                        dquot_decr_inodes(transfer_from[cnt], 1);
                        dquot_decr_space(transfer_from[cnt], cur_space);
                        dquot_free_reserved_space(transfer_from[cnt],
@@ -1815,9 +1852,9 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
 
        mark_all_dquot_dirty(transfer_from);
        mark_all_dquot_dirty(transfer_to);
-       flush_warnings(transfer_to, warntype_to);
-       flush_warnings(transfer_from, warntype_from_inodes);
-       flush_warnings(transfer_from, warntype_from_space);
+       flush_warnings(warn_to);
+       flush_warnings(warn_from_inodes);
+       flush_warnings(warn_from_space);
        /* Pass back references to put */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
                if (is_valid[cnt])
@@ -1826,7 +1863,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
 over_quota:
        spin_unlock(&dq_data_lock);
        up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       flush_warnings(transfer_to, warntype_to);
+       flush_warnings(warn_to);
        return ret;
 }
 EXPORT_SYMBOL(__dquot_transfer);
index fc2c438..9a39120 100644 (file)
@@ -282,10 +282,9 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
        case Q_XGETQUOTA:
                return quota_getxquota(sb, type, id, addr);
        case Q_XQUOTASYNC:
-               /* caller already holds s_umount */
                if (sb->s_flags & MS_RDONLY)
                        return -EROFS;
-               writeback_inodes_sb(sb, WB_REASON_SYNC);
+               /* XFS quotas are fully coherent now, making this call a noop */
                return 0;
        default:
                return -EINVAL;
index 5ad4248..ffc99d2 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/uio.h>
 #include <linux/fsnotify.h>
 #include <linux/security.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/syscalls.h>
 #include <linux/pagemap.h>
 #include <linux/splice.h>
index 356f715..cc0a822 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
index 445d768..a59d271 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/bug.h>
 #include <linux/workqueue.h>
 #include <asm/unaligned.h>
 #include <linux/bitops.h>
index e782258..6fb8943 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/syscalls.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/personality.h> /* for STICKY_TIMEOUTS */
@@ -223,7 +223,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
        get_file(filp);
        entry->filp = filp;
        entry->wait_address = wait_address;
-       entry->key = p->key;
+       entry->key = p->_key;
        init_waitqueue_func_entry(&entry->wait, pollwake);
        entry->wait.private = pwq;
        add_wait_queue(wait_address, &entry->wait);
@@ -386,13 +386,11 @@ get_max:
 static inline void wait_key_set(poll_table *wait, unsigned long in,
                                unsigned long out, unsigned long bit)
 {
-       if (wait) {
-               wait->key = POLLEX_SET;
-               if (in & bit)
-                       wait->key |= POLLIN_SET;
-               if (out & bit)
-                       wait->key |= POLLOUT_SET;
-       }
+       wait->_key = POLLEX_SET;
+       if (in & bit)
+               wait->_key |= POLLIN_SET;
+       if (out & bit)
+               wait->_key |= POLLOUT_SET;
 }
 
 int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
@@ -414,7 +412,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
        poll_initwait(&table);
        wait = &table.pt;
        if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
-               wait = NULL;
+               wait->_qproc = NULL;
                timed_out = 1;
        }
 
@@ -459,17 +457,17 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
                                        if ((mask & POLLIN_SET) && (in & bit)) {
                                                res_in |= bit;
                                                retval++;
-                                               wait = NULL;
+                                               wait->_qproc = NULL;
                                        }
                                        if ((mask & POLLOUT_SET) && (out & bit)) {
                                                res_out |= bit;
                                                retval++;
-                                               wait = NULL;
+                                               wait->_qproc = NULL;
                                        }
                                        if ((mask & POLLEX_SET) && (ex & bit)) {
                                                res_ex |= bit;
                                                retval++;
-                                               wait = NULL;
+                                               wait->_qproc = NULL;
                                        }
                                }
                        }
@@ -481,7 +479,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
                                *rexp = res_ex;
                        cond_resched();
                }
-               wait = NULL;
+               wait->_qproc = NULL;
                if (retval || timed_out || signal_pending(current))
                        break;
                if (table.error) {
@@ -720,7 +718,7 @@ struct poll_list {
  * interested in events matching the pollfd->events mask, and the result
  * matching that mask is both recorded in pollfd->revents and returned. The
  * pwait poll_table will be used by the fd-provided poll handler for waiting,
- * if non-NULL.
+ * if pwait->_qproc is non-NULL.
  */
 static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
 {
@@ -738,9 +736,7 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
                if (file != NULL) {
                        mask = DEFAULT_POLLMASK;
                        if (file->f_op && file->f_op->poll) {
-                               if (pwait)
-                                       pwait->key = pollfd->events |
-                                                       POLLERR | POLLHUP;
+                               pwait->_key = pollfd->events|POLLERR|POLLHUP;
                                mask = file->f_op->poll(file, pwait);
                        }
                        /* Mask out unneeded events. */
@@ -763,7 +759,7 @@ static int do_poll(unsigned int nfds,  struct poll_list *list,
 
        /* Optimise the no-wait case */
        if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
-               pt = NULL;
+               pt->_qproc = NULL;
                timed_out = 1;
        }
 
@@ -781,22 +777,22 @@ static int do_poll(unsigned int nfds,  struct poll_list *list,
                        for (; pfd != pfd_end; pfd++) {
                                /*
                                 * Fish for events. If we found one, record it
-                                * and kill the poll_table, so we don't
+                                * and kill poll_table->_qproc, so we don't
                                 * needlessly register any other waiters after
                                 * this. They'll get immediately deregistered
                                 * when we break out and return.
                                 */
                                if (do_pollfd(pfd, pt)) {
                                        count++;
-                                       pt = NULL;
+                                       pt->_qproc = NULL;
                                }
                        }
                }
                /*
                 * All waiters have already been registered, so don't provide
-                * a poll_table to them on the next loop iteration.
+                * a poll_table->_qproc to them on the next loop iteration.
                 */
-               pt = NULL;
+               pt->_qproc = NULL;
                if (!count) {
                        count = wait->error;
                        if (signal_pending(current))
index aa242dc..0cbd049 100644 (file)
@@ -6,13 +6,29 @@
  */
 
 #include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
 
+
+/*
+ * seq_files have a buffer which can may overflow. When this happens a larger
+ * buffer is reallocated and all the data will be printed again.
+ * The overflow state is true when m->count == m->size.
+ */
+static bool seq_overflow(struct seq_file *m)
+{
+       return m->count == m->size;
+}
+
+static void seq_set_overflow(struct seq_file *m)
+{
+       m->count = m->size;
+}
+
 /**
  *     seq_open -      initialize sequential file
  *     @file: file we initialize
@@ -92,7 +108,7 @@ static int traverse(struct seq_file *m, loff_t offset)
                        error = 0;
                        m->count = 0;
                }
-               if (m->count == m->size)
+               if (seq_overflow(m))
                        goto Eoverflow;
                if (pos + m->count > offset) {
                        m->from = offset - pos;
@@ -234,7 +250,7 @@ Fill:
                        break;
                }
                err = m->op->show(m, p);
-               if (m->count == m->size || err) {
+               if (seq_overflow(m) || err) {
                        m->count = offs;
                        if (likely(err <= 0))
                                break;
@@ -361,7 +377,7 @@ int seq_escape(struct seq_file *m, const char *s, const char *esc)
                        *p++ = '0' + (c & 07);
                        continue;
                }
-               m->count = m->size;
+               seq_set_overflow(m);
                return -1;
         }
        m->count = p - m->buf;
@@ -383,7 +399,7 @@ int seq_printf(struct seq_file *m, const char *f, ...)
                        return 0;
                }
        }
-       m->count = m->size;
+       seq_set_overflow(m);
        return -1;
 }
 EXPORT_SYMBOL(seq_printf);
@@ -512,7 +528,7 @@ int seq_bitmap(struct seq_file *m, const unsigned long *bits,
                        return 0;
                }
        }
-       m->count = m->size;
+       seq_set_overflow(m);
        return -1;
 }
 EXPORT_SYMBOL(seq_bitmap);
@@ -528,7 +544,7 @@ int seq_bitmap_list(struct seq_file *m, const unsigned long *bits,
                        return 0;
                }
        }
-       m->count = m->size;
+       seq_set_overflow(m);
        return -1;
 }
 EXPORT_SYMBOL(seq_bitmap_list);
@@ -639,11 +655,63 @@ int seq_puts(struct seq_file *m, const char *s)
                m->count += len;
                return 0;
        }
-       m->count = m->size;
+       seq_set_overflow(m);
        return -1;
 }
 EXPORT_SYMBOL(seq_puts);
 
+/*
+ * A helper routine for putting decimal numbers without rich format of printf().
+ * only 'unsigned long long' is supported.
+ * This routine will put one byte delimiter + number into seq_file.
+ * This routine is very quick when you show lots of numbers.
+ * In usual cases, it will be better to use seq_printf(). It's easier to read.
+ */
+int seq_put_decimal_ull(struct seq_file *m, char delimiter,
+                       unsigned long long num)
+{
+       int len;
+
+       if (m->count + 2 >= m->size) /* we'll write 2 bytes at least */
+               goto overflow;
+
+       if (delimiter)
+               m->buf[m->count++] = delimiter;
+
+       if (num < 10) {
+               m->buf[m->count++] = num + '0';
+               return 0;
+       }
+
+       len = num_to_str(m->buf + m->count, m->size - m->count, num);
+       if (!len)
+               goto overflow;
+       m->count += len;
+       return 0;
+overflow:
+       seq_set_overflow(m);
+       return -1;
+}
+EXPORT_SYMBOL(seq_put_decimal_ull);
+
+int seq_put_decimal_ll(struct seq_file *m, char delimiter,
+                       long long num)
+{
+       if (num < 0) {
+               if (m->count + 3 >= m->size) {
+                       seq_set_overflow(m);
+                       return -1;
+               }
+               if (delimiter)
+                       m->buf[m->count++] = delimiter;
+               num = -num;
+               delimiter = '-';
+       }
+       return seq_put_decimal_ull(m, delimiter, num);
+
+}
+EXPORT_SYMBOL(seq_put_decimal_ll);
+
 /**
  * seq_write - write arbitrary data to buffer
  * @seq: seq_file identifying the buffer to which data should be written
@@ -659,7 +727,7 @@ int seq_write(struct seq_file *seq, const void *data, size_t len)
                seq->count += len;
                return 0;
        }
-       seq->count = seq->size;
+       seq_set_overflow(seq);
        return -1;
 }
 EXPORT_SYMBOL(seq_write);
index f16402e..5f883de 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/mm_inline.h>
 #include <linux/swap.h>
 #include <linux/writeback.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/syscalls.h>
 #include <linux/uio.h>
 #include <linux/security.h>
index 9c11519..5b53882 100644 (file)
@@ -1,4 +1,4 @@
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/fs_stack.h>
 
index 86f1356..c733dc5 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -4,7 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/file.h>
index 2aa6a22..43e6b6f 100644 (file)
@@ -1,5 +1,5 @@
 #include <linux/syscalls.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/mount.h>
index 7fcb135..cf00177 100644 (file)
@@ -20,7 +20,7 @@
  *  Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/acct.h>
 #include <linux/blkdev.h>
index f3501ef..0e8db93 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -6,7 +6,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/namei.h>
 #include <linux/sched.h>
 #include <linux/writeback.h>
index f922cba..1934084 100644 (file)
@@ -36,7 +36,7 @@
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
-DEFINE_SPINLOCK(dbg_lock);
+static DEFINE_SPINLOCK(dbg_lock);
 
 static const char *get_key_fmt(int fmt)
 {
@@ -221,15 +221,15 @@ const char *dbg_jhead(int jhead)
 
 static void dump_ch(const struct ubifs_ch *ch)
 {
-       printk(KERN_DEBUG "\tmagic          %#x\n", le32_to_cpu(ch->magic));
-       printk(KERN_DEBUG "\tcrc            %#x\n", le32_to_cpu(ch->crc));
-       printk(KERN_DEBUG "\tnode_type      %d (%s)\n", ch->node_type,
+       printk(KERN_ERR "\tmagic          %#x\n", le32_to_cpu(ch->magic));
+       printk(KERN_ERR "\tcrc            %#x\n", le32_to_cpu(ch->crc));
+       printk(KERN_ERR "\tnode_type      %d (%s)\n", ch->node_type,
               dbg_ntype(ch->node_type));
-       printk(KERN_DEBUG "\tgroup_type     %d (%s)\n", ch->group_type,
+       printk(KERN_ERR "\tgroup_type     %d (%s)\n", ch->group_type,
               dbg_gtype(ch->group_type));
-       printk(KERN_DEBUG "\tsqnum          %llu\n",
+       printk(KERN_ERR "\tsqnum          %llu\n",
               (unsigned long long)le64_to_cpu(ch->sqnum));
-       printk(KERN_DEBUG "\tlen            %u\n", le32_to_cpu(ch->len));
+       printk(KERN_ERR "\tlen            %u\n", le32_to_cpu(ch->len));
 }
 
 void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
@@ -240,43 +240,43 @@ void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
        struct ubifs_dent_node *dent, *pdent = NULL;
        int count = 2;
 
-       printk(KERN_DEBUG "Dump in-memory inode:");
-       printk(KERN_DEBUG "\tinode          %lu\n", inode->i_ino);
-       printk(KERN_DEBUG "\tsize           %llu\n",
+       printk(KERN_ERR "Dump in-memory inode:");
+       printk(KERN_ERR "\tinode          %lu\n", inode->i_ino);
+       printk(KERN_ERR "\tsize           %llu\n",
               (unsigned long long)i_size_read(inode));
-       printk(KERN_DEBUG "\tnlink          %u\n", inode->i_nlink);
-       printk(KERN_DEBUG "\tuid            %u\n", (unsigned int)inode->i_uid);
-       printk(KERN_DEBUG "\tgid            %u\n", (unsigned int)inode->i_gid);
-       printk(KERN_DEBUG "\tatime          %u.%u\n",
+       printk(KERN_ERR "\tnlink          %u\n", inode->i_nlink);
+       printk(KERN_ERR "\tuid            %u\n", (unsigned int)inode->i_uid);
+       printk(KERN_ERR "\tgid            %u\n", (unsigned int)inode->i_gid);
+       printk(KERN_ERR "\tatime          %u.%u\n",
               (unsigned int)inode->i_atime.tv_sec,
               (unsigned int)inode->i_atime.tv_nsec);
-       printk(KERN_DEBUG "\tmtime          %u.%u\n",
+       printk(KERN_ERR "\tmtime          %u.%u\n",
               (unsigned int)inode->i_mtime.tv_sec,
               (unsigned int)inode->i_mtime.tv_nsec);
-       printk(KERN_DEBUG "\tctime          %u.%u\n",
+       printk(KERN_ERR "\tctime          %u.%u\n",
               (unsigned int)inode->i_ctime.tv_sec,
               (unsigned int)inode->i_ctime.tv_nsec);
-       printk(KERN_DEBUG "\tcreat_sqnum    %llu\n", ui->creat_sqnum);
-       printk(KERN_DEBUG "\txattr_size     %u\n", ui->xattr_size);
-       printk(KERN_DEBUG "\txattr_cnt      %u\n", ui->xattr_cnt);
-       printk(KERN_DEBUG "\txattr_names    %u\n", ui->xattr_names);
-       printk(KERN_DEBUG "\tdirty          %u\n", ui->dirty);
-       printk(KERN_DEBUG "\txattr          %u\n", ui->xattr);
-       printk(KERN_DEBUG "\tbulk_read      %u\n", ui->xattr);
-       printk(KERN_DEBUG "\tsynced_i_size  %llu\n",
+       printk(KERN_ERR "\tcreat_sqnum    %llu\n", ui->creat_sqnum);
+       printk(KERN_ERR "\txattr_size     %u\n", ui->xattr_size);
+       printk(KERN_ERR "\txattr_cnt      %u\n", ui->xattr_cnt);
+       printk(KERN_ERR "\txattr_names    %u\n", ui->xattr_names);
+       printk(KERN_ERR "\tdirty          %u\n", ui->dirty);
+       printk(KERN_ERR "\txattr          %u\n", ui->xattr);
+       printk(KERN_ERR "\tbulk_read      %u\n", ui->xattr);
+       printk(KERN_ERR "\tsynced_i_size  %llu\n",
               (unsigned long long)ui->synced_i_size);
-       printk(KERN_DEBUG "\tui_size        %llu\n",
+       printk(KERN_ERR "\tui_size        %llu\n",
               (unsigned long long)ui->ui_size);
-       printk(KERN_DEBUG "\tflags          %d\n", ui->flags);
-       printk(KERN_DEBUG "\tcompr_type     %d\n", ui->compr_type);
-       printk(KERN_DEBUG "\tlast_page_read %lu\n", ui->last_page_read);
-       printk(KERN_DEBUG "\tread_in_a_row  %lu\n", ui->read_in_a_row);
-       printk(KERN_DEBUG "\tdata_len       %d\n", ui->data_len);
+       printk(KERN_ERR "\tflags          %d\n", ui->flags);
+       printk(KERN_ERR "\tcompr_type     %d\n", ui->compr_type);
+       printk(KERN_ERR "\tlast_page_read %lu\n", ui->last_page_read);
+       printk(KERN_ERR "\tread_in_a_row  %lu\n", ui->read_in_a_row);
+       printk(KERN_ERR "\tdata_len       %d\n", ui->data_len);
 
        if (!S_ISDIR(inode->i_mode))
                return;
 
-       printk(KERN_DEBUG "List of directory entries:\n");
+       printk(KERN_ERR "List of directory entries:\n");
        ubifs_assert(!mutex_is_locked(&c->tnc_mutex));
 
        lowest_dent_key(c, &key, inode->i_ino);
@@ -284,11 +284,11 @@ void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
                dent = ubifs_tnc_next_ent(c, &key, &nm);
                if (IS_ERR(dent)) {
                        if (PTR_ERR(dent) != -ENOENT)
-                               printk(KERN_DEBUG "error %ld\n", PTR_ERR(dent));
+                               printk(KERN_ERR "error %ld\n", PTR_ERR(dent));
                        break;
                }
 
-               printk(KERN_DEBUG "\t%d: %s (%s)\n",
+               printk(KERN_ERR "\t%d: %s (%s)\n",
                       count++, dent->name, get_dent_type(dent->type));
 
                nm.name = dent->name;
@@ -312,8 +312,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
 
        /* If the magic is incorrect, just hexdump the first bytes */
        if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) {
-               printk(KERN_DEBUG "Not a node, first %zu bytes:", UBIFS_CH_SZ);
-               print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+               printk(KERN_ERR "Not a node, first %zu bytes:", UBIFS_CH_SZ);
+               print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 32, 1,
                               (void *)node, UBIFS_CH_SZ, 1);
                return;
        }
@@ -326,7 +326,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
        {
                const struct ubifs_pad_node *pad = node;
 
-               printk(KERN_DEBUG "\tpad_len        %u\n",
+               printk(KERN_ERR "\tpad_len        %u\n",
                       le32_to_cpu(pad->pad_len));
                break;
        }
@@ -335,50 +335,50 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                const struct ubifs_sb_node *sup = node;
                unsigned int sup_flags = le32_to_cpu(sup->flags);
 
-               printk(KERN_DEBUG "\tkey_hash       %d (%s)\n",
+               printk(KERN_ERR "\tkey_hash       %d (%s)\n",
                       (int)sup->key_hash, get_key_hash(sup->key_hash));
-               printk(KERN_DEBUG "\tkey_fmt        %d (%s)\n",
+               printk(KERN_ERR "\tkey_fmt        %d (%s)\n",
                       (int)sup->key_fmt, get_key_fmt(sup->key_fmt));
-               printk(KERN_DEBUG "\tflags          %#x\n", sup_flags);
-               printk(KERN_DEBUG "\t  big_lpt      %u\n",
+               printk(KERN_ERR "\tflags          %#x\n", sup_flags);
+               printk(KERN_ERR "\t  big_lpt      %u\n",
                       !!(sup_flags & UBIFS_FLG_BIGLPT));
-               printk(KERN_DEBUG "\t  space_fixup  %u\n",
+               printk(KERN_ERR "\t  space_fixup  %u\n",
                       !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
-               printk(KERN_DEBUG "\tmin_io_size    %u\n",
+               printk(KERN_ERR "\tmin_io_size    %u\n",
                       le32_to_cpu(sup->min_io_size));
-               printk(KERN_DEBUG "\tleb_size       %u\n",
+               printk(KERN_ERR "\tleb_size       %u\n",
                       le32_to_cpu(sup->leb_size));
-               printk(KERN_DEBUG "\tleb_cnt        %u\n",
+               printk(KERN_ERR "\tleb_cnt        %u\n",
                       le32_to_cpu(sup->leb_cnt));
-               printk(KERN_DEBUG "\tmax_leb_cnt    %u\n",
+               printk(KERN_ERR "\tmax_leb_cnt    %u\n",
                       le32_to_cpu(sup->max_leb_cnt));
-               printk(KERN_DEBUG "\tmax_bud_bytes  %llu\n",
+               printk(KERN_ERR "\tmax_bud_bytes  %llu\n",
                       (unsigned long long)le64_to_cpu(sup->max_bud_bytes));
-               printk(KERN_DEBUG "\tlog_lebs       %u\n",
+               printk(KERN_ERR "\tlog_lebs       %u\n",
                       le32_to_cpu(sup->log_lebs));
-               printk(KERN_DEBUG "\tlpt_lebs       %u\n",
+               printk(KERN_ERR "\tlpt_lebs       %u\n",
                       le32_to_cpu(sup->lpt_lebs));
-               printk(KERN_DEBUG "\torph_lebs      %u\n",
+               printk(KERN_ERR "\torph_lebs      %u\n",
                       le32_to_cpu(sup->orph_lebs));
-               printk(KERN_DEBUG "\tjhead_cnt      %u\n",
+               printk(KERN_ERR "\tjhead_cnt      %u\n",
                       le32_to_cpu(sup->jhead_cnt));
-               printk(KERN_DEBUG "\tfanout         %u\n",
+               printk(KERN_ERR "\tfanout         %u\n",
                       le32_to_cpu(sup->fanout));
-               printk(KERN_DEBUG "\tlsave_cnt      %u\n",
+               printk(KERN_ERR "\tlsave_cnt      %u\n",
                       le32_to_cpu(sup->lsave_cnt));
-               printk(KERN_DEBUG "\tdefault_compr  %u\n",
+               printk(KERN_ERR "\tdefault_compr  %u\n",
                       (int)le16_to_cpu(sup->default_compr));
-               printk(KERN_DEBUG "\trp_size        %llu\n",
+               printk(KERN_ERR "\trp_size        %llu\n",
                       (unsigned long long)le64_to_cpu(sup->rp_size));
-               printk(KERN_DEBUG "\trp_uid         %u\n",
+               printk(KERN_ERR "\trp_uid         %u\n",
                       le32_to_cpu(sup->rp_uid));
-               printk(KERN_DEBUG "\trp_gid         %u\n",
+               printk(KERN_ERR "\trp_gid         %u\n",
                       le32_to_cpu(sup->rp_gid));
-               printk(KERN_DEBUG "\tfmt_version    %u\n",
+               printk(KERN_ERR "\tfmt_version    %u\n",
                       le32_to_cpu(sup->fmt_version));
-               printk(KERN_DEBUG "\ttime_gran      %u\n",
+               printk(KERN_ERR "\ttime_gran      %u\n",
                       le32_to_cpu(sup->time_gran));
-               printk(KERN_DEBUG "\tUUID           %pUB\n",
+               printk(KERN_ERR "\tUUID           %pUB\n",
                       sup->uuid);
                break;
        }
@@ -386,61 +386,61 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
        {
                const struct ubifs_mst_node *mst = node;
 
-               printk(KERN_DEBUG "\thighest_inum   %llu\n",
+               printk(KERN_ERR "\thighest_inum   %llu\n",
                       (unsigned long long)le64_to_cpu(mst->highest_inum));
-               printk(KERN_DEBUG "\tcommit number  %llu\n",
+               printk(KERN_ERR "\tcommit number  %llu\n",
                       (unsigned long long)le64_to_cpu(mst->cmt_no));
-               printk(KERN_DEBUG "\tflags          %#x\n",
+               printk(KERN_ERR "\tflags          %#x\n",
                       le32_to_cpu(mst->flags));
-               printk(KERN_DEBUG "\tlog_lnum       %u\n",
+               printk(KERN_ERR "\tlog_lnum       %u\n",
                       le32_to_cpu(mst->log_lnum));
-               printk(KERN_DEBUG "\troot_lnum      %u\n",
+               printk(KERN_ERR "\troot_lnum      %u\n",
                       le32_to_cpu(mst->root_lnum));
-               printk(KERN_DEBUG "\troot_offs      %u\n",
+               printk(KERN_ERR "\troot_offs      %u\n",
                       le32_to_cpu(mst->root_offs));
-               printk(KERN_DEBUG "\troot_len       %u\n",
+               printk(KERN_ERR "\troot_len       %u\n",
                       le32_to_cpu(mst->root_len));
-               printk(KERN_DEBUG "\tgc_lnum        %u\n",
+               printk(KERN_ERR "\tgc_lnum        %u\n",
                       le32_to_cpu(mst->gc_lnum));
-               printk(KERN_DEBUG "\tihead_lnum     %u\n",
+               printk(KERN_ERR "\tihead_lnum     %u\n",
                       le32_to_cpu(mst->ihead_lnum));
-               printk(KERN_DEBUG "\tihead_offs     %u\n",
+               printk(KERN_ERR "\tihead_offs     %u\n",
                       le32_to_cpu(mst->ihead_offs));
-               printk(KERN_DEBUG "\tindex_size     %llu\n",
+               printk(KERN_ERR "\tindex_size     %llu\n",
                       (unsigned long long)le64_to_cpu(mst->index_size));
-               printk(KERN_DEBUG "\tlpt_lnum       %u\n",
+               printk(KERN_ERR "\tlpt_lnum       %u\n",
                       le32_to_cpu(mst->lpt_lnum));
-               printk(KERN_DEBUG "\tlpt_offs       %u\n",
+               printk(KERN_ERR "\tlpt_offs       %u\n",
                       le32_to_cpu(mst->lpt_offs));
-               printk(KERN_DEBUG "\tnhead_lnum     %u\n",
+               printk(KERN_ERR "\tnhead_lnum     %u\n",
                       le32_to_cpu(mst->nhead_lnum));
-               printk(KERN_DEBUG "\tnhead_offs     %u\n",
+               printk(KERN_ERR "\tnhead_offs     %u\n",
                       le32_to_cpu(mst->nhead_offs));
-               printk(KERN_DEBUG "\tltab_lnum      %u\n",
+               printk(KERN_ERR "\tltab_lnum      %u\n",
                       le32_to_cpu(mst->ltab_lnum));
-               printk(KERN_DEBUG "\tltab_offs      %u\n",
+               printk(KERN_ERR "\tltab_offs      %u\n",
                       le32_to_cpu(mst->ltab_offs));
-               printk(KERN_DEBUG "\tlsave_lnum     %u\n",
+               printk(KERN_ERR "\tlsave_lnum     %u\n",
                       le32_to_cpu(mst->lsave_lnum));
-               printk(KERN_DEBUG "\tlsave_offs     %u\n",
+               printk(KERN_ERR "\tlsave_offs     %u\n",
                       le32_to_cpu(mst->lsave_offs));
-               printk(KERN_DEBUG "\tlscan_lnum     %u\n",
+               printk(KERN_ERR "\tlscan_lnum     %u\n",
                       le32_to_cpu(mst->lscan_lnum));
-               printk(KERN_DEBUG "\tleb_cnt        %u\n",
+               printk(KERN_ERR "\tleb_cnt        %u\n",
                       le32_to_cpu(mst->leb_cnt));
-               printk(KERN_DEBUG "\tempty_lebs     %u\n",
+               printk(KERN_ERR "\tempty_lebs     %u\n",
                       le32_to_cpu(mst->empty_lebs));
-               printk(KERN_DEBUG "\tidx_lebs       %u\n",
+               printk(KERN_ERR "\tidx_lebs       %u\n",
                       le32_to_cpu(mst->idx_lebs));
-               printk(KERN_DEBUG "\ttotal_free     %llu\n",
+               printk(KERN_ERR "\ttotal_free     %llu\n",
                       (unsigned long long)le64_to_cpu(mst->total_free));
-               printk(KERN_DEBUG "\ttotal_dirty    %llu\n",
+               printk(KERN_ERR "\ttotal_dirty    %llu\n",
                       (unsigned long long)le64_to_cpu(mst->total_dirty));
-               printk(KERN_DEBUG "\ttotal_used     %llu\n",
+               printk(KERN_ERR "\ttotal_used     %llu\n",
                       (unsigned long long)le64_to_cpu(mst->total_used));
-               printk(KERN_DEBUG "\ttotal_dead     %llu\n",
+               printk(KERN_ERR "\ttotal_dead     %llu\n",
                       (unsigned long long)le64_to_cpu(mst->total_dead));
-               printk(KERN_DEBUG "\ttotal_dark     %llu\n",
+               printk(KERN_ERR "\ttotal_dark     %llu\n",
                       (unsigned long long)le64_to_cpu(mst->total_dark));
                break;
        }
@@ -448,11 +448,11 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
        {
                const struct ubifs_ref_node *ref = node;
 
-               printk(KERN_DEBUG "\tlnum           %u\n",
+               printk(KERN_ERR "\tlnum           %u\n",
                       le32_to_cpu(ref->lnum));
-               printk(KERN_DEBUG "\toffs           %u\n",
+               printk(KERN_ERR "\toffs           %u\n",
                       le32_to_cpu(ref->offs));
-               printk(KERN_DEBUG "\tjhead          %u\n",
+               printk(KERN_ERR "\tjhead          %u\n",
                       le32_to_cpu(ref->jhead));
                break;
        }
@@ -461,40 +461,40 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                const struct ubifs_ino_node *ino = node;
 
                key_read(c, &ino->key, &key);
-               printk(KERN_DEBUG "\tkey            %s\n",
+               printk(KERN_ERR "\tkey            %s\n",
                       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
-               printk(KERN_DEBUG "\tcreat_sqnum    %llu\n",
+               printk(KERN_ERR "\tcreat_sqnum    %llu\n",
                       (unsigned long long)le64_to_cpu(ino->creat_sqnum));
-               printk(KERN_DEBUG "\tsize           %llu\n",
+               printk(KERN_ERR "\tsize           %llu\n",
                       (unsigned long long)le64_to_cpu(ino->size));
-               printk(KERN_DEBUG "\tnlink          %u\n",
+               printk(KERN_ERR "\tnlink          %u\n",
                       le32_to_cpu(ino->nlink));
-               printk(KERN_DEBUG "\tatime          %lld.%u\n",
+               printk(KERN_ERR "\tatime          %lld.%u\n",
                       (long long)le64_to_cpu(ino->atime_sec),
                       le32_to_cpu(ino->atime_nsec));
-               printk(KERN_DEBUG "\tmtime          %lld.%u\n",
+               printk(KERN_ERR "\tmtime          %lld.%u\n",
                       (long long)le64_to_cpu(ino->mtime_sec),
                       le32_to_cpu(ino->mtime_nsec));
-               printk(KERN_DEBUG "\tctime          %lld.%u\n",
+               printk(KERN_ERR "\tctime          %lld.%u\n",
                       (long long)le64_to_cpu(ino->ctime_sec),
                       le32_to_cpu(ino->ctime_nsec));
-               printk(KERN_DEBUG "\tuid            %u\n",
+               printk(KERN_ERR "\tuid            %u\n",
                       le32_to_cpu(ino->uid));
-               printk(KERN_DEBUG "\tgid            %u\n",
+               printk(KERN_ERR "\tgid            %u\n",
                       le32_to_cpu(ino->gid));
-               printk(KERN_DEBUG "\tmode           %u\n",
+               printk(KERN_ERR "\tmode           %u\n",
                       le32_to_cpu(ino->mode));
-               printk(KERN_DEBUG "\tflags          %#x\n",
+               printk(KERN_ERR "\tflags          %#x\n",
                       le32_to_cpu(ino->flags));
-               printk(KERN_DEBUG "\txattr_cnt      %u\n",
+               printk(KERN_ERR "\txattr_cnt      %u\n",
                       le32_to_cpu(ino->xattr_cnt));
-               printk(KERN_DEBUG "\txattr_size     %u\n",
+               printk(KERN_ERR "\txattr_size     %u\n",
                       le32_to_cpu(ino->xattr_size));
-               printk(KERN_DEBUG "\txattr_names    %u\n",
+               printk(KERN_ERR "\txattr_names    %u\n",
                       le32_to_cpu(ino->xattr_names));
-               printk(KERN_DEBUG "\tcompr_type     %#x\n",
+               printk(KERN_ERR "\tcompr_type     %#x\n",
                       (int)le16_to_cpu(ino->compr_type));
-               printk(KERN_DEBUG "\tdata len       %u\n",
+               printk(KERN_ERR "\tdata len       %u\n",
                       le32_to_cpu(ino->data_len));
                break;
        }
@@ -505,16 +505,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                int nlen = le16_to_cpu(dent->nlen);
 
                key_read(c, &dent->key, &key);
-               printk(KERN_DEBUG "\tkey            %s\n",
+               printk(KERN_ERR "\tkey            %s\n",
                       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
-               printk(KERN_DEBUG "\tinum           %llu\n",
+               printk(KERN_ERR "\tinum           %llu\n",
                       (unsigned long long)le64_to_cpu(dent->inum));
-               printk(KERN_DEBUG "\ttype           %d\n", (int)dent->type);
-               printk(KERN_DEBUG "\tnlen           %d\n", nlen);
-               printk(KERN_DEBUG "\tname           ");
+               printk(KERN_ERR "\ttype           %d\n", (int)dent->type);
+               printk(KERN_ERR "\tnlen           %d\n", nlen);
+               printk(KERN_ERR "\tname           ");
 
                if (nlen > UBIFS_MAX_NLEN)
-                       printk(KERN_DEBUG "(bad name length, not printing, "
+                       printk(KERN_ERR "(bad name length, not printing, "
                                          "bad or corrupted node)");
                else {
                        for (i = 0; i < nlen && dent->name[i]; i++)
@@ -530,16 +530,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
 
                key_read(c, &dn->key, &key);
-               printk(KERN_DEBUG "\tkey            %s\n",
+               printk(KERN_ERR "\tkey            %s\n",
                       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
-               printk(KERN_DEBUG "\tsize           %u\n",
+               printk(KERN_ERR "\tsize           %u\n",
                       le32_to_cpu(dn->size));
-               printk(KERN_DEBUG "\tcompr_typ      %d\n",
+               printk(KERN_ERR "\tcompr_typ      %d\n",
                       (int)le16_to_cpu(dn->compr_type));
-               printk(KERN_DEBUG "\tdata size      %d\n",
+               printk(KERN_ERR "\tdata size      %d\n",
                       dlen);
-               printk(KERN_DEBUG "\tdata:\n");
-               print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET, 32, 1,
+               printk(KERN_ERR "\tdata:\n");
+               print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1,
                               (void *)&dn->data, dlen, 0);
                break;
        }
@@ -547,11 +547,11 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
        {
                const struct ubifs_trun_node *trun = node;
 
-               printk(KERN_DEBUG "\tinum           %u\n",
+               printk(KERN_ERR "\tinum           %u\n",
                       le32_to_cpu(trun->inum));
-               printk(KERN_DEBUG "\told_size       %llu\n",
+               printk(KERN_ERR "\told_size       %llu\n",
                       (unsigned long long)le64_to_cpu(trun->old_size));
-               printk(KERN_DEBUG "\tnew_size       %llu\n",
+               printk(KERN_ERR "\tnew_size       %llu\n",
                       (unsigned long long)le64_to_cpu(trun->new_size));
                break;
        }
@@ -560,17 +560,17 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                const struct ubifs_idx_node *idx = node;
 
                n = le16_to_cpu(idx->child_cnt);
-               printk(KERN_DEBUG "\tchild_cnt      %d\n", n);
-               printk(KERN_DEBUG "\tlevel          %d\n",
+               printk(KERN_ERR "\tchild_cnt      %d\n", n);
+               printk(KERN_ERR "\tlevel          %d\n",
                       (int)le16_to_cpu(idx->level));
-               printk(KERN_DEBUG "\tBranches:\n");
+               printk(KERN_ERR "\tBranches:\n");
 
                for (i = 0; i < n && i < c->fanout - 1; i++) {
                        const struct ubifs_branch *br;
 
                        br = ubifs_idx_branch(c, idx, i);
                        key_read(c, &br->key, &key);
-                       printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n",
+                       printk(KERN_ERR "\t%d: LEB %d:%d len %d key %s\n",
                               i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
                               le32_to_cpu(br->len),
                               dbg_snprintf_key(c, &key, key_buf,
@@ -584,20 +584,20 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
        {
                const struct ubifs_orph_node *orph = node;
 
-               printk(KERN_DEBUG "\tcommit number  %llu\n",
+               printk(KERN_ERR "\tcommit number  %llu\n",
                       (unsigned long long)
                                le64_to_cpu(orph->cmt_no) & LLONG_MAX);
-               printk(KERN_DEBUG "\tlast node flag %llu\n",
+               printk(KERN_ERR "\tlast node flag %llu\n",
                       (unsigned long long)(le64_to_cpu(orph->cmt_no)) >> 63);
                n = (le32_to_cpu(ch->len) - UBIFS_ORPH_NODE_SZ) >> 3;
-               printk(KERN_DEBUG "\t%d orphan inode numbers:\n", n);
+               printk(KERN_ERR "\t%d orphan inode numbers:\n", n);
                for (i = 0; i < n; i++)
-                       printk(KERN_DEBUG "\t  ino %llu\n",
+                       printk(KERN_ERR "\t  ino %llu\n",
                               (unsigned long long)le64_to_cpu(orph->inos[i]));
                break;
        }
        default:
-               printk(KERN_DEBUG "node type %d was not recognized\n",
+               printk(KERN_ERR "node type %d was not recognized\n",
                       (int)ch->node_type);
        }
        spin_unlock(&dbg_lock);
@@ -606,16 +606,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
 void dbg_dump_budget_req(const struct ubifs_budget_req *req)
 {
        spin_lock(&dbg_lock);
-       printk(KERN_DEBUG "Budgeting request: new_ino %d, dirtied_ino %d\n",
+       printk(KERN_ERR "Budgeting request: new_ino %d, dirtied_ino %d\n",
               req->new_ino, req->dirtied_ino);
-       printk(KERN_DEBUG "\tnew_ino_d   %d, dirtied_ino_d %d\n",
+       printk(KERN_ERR "\tnew_ino_d   %d, dirtied_ino_d %d\n",
               req->new_ino_d, req->dirtied_ino_d);
-       printk(KERN_DEBUG "\tnew_page    %d, dirtied_page %d\n",
+       printk(KERN_ERR "\tnew_page    %d, dirtied_page %d\n",
               req->new_page, req->dirtied_page);
-       printk(KERN_DEBUG "\tnew_dent    %d, mod_dent     %d\n",
+       printk(KERN_ERR "\tnew_dent    %d, mod_dent     %d\n",
               req->new_dent, req->mod_dent);
-       printk(KERN_DEBUG "\tidx_growth  %d\n", req->idx_growth);
-       printk(KERN_DEBUG "\tdata_growth %d dd_growth     %d\n",
+       printk(KERN_ERR "\tidx_growth  %d\n", req->idx_growth);
+       printk(KERN_ERR "\tdata_growth %d dd_growth     %d\n",
               req->data_growth, req->dd_growth);
        spin_unlock(&dbg_lock);
 }
@@ -623,12 +623,12 @@ void dbg_dump_budget_req(const struct ubifs_budget_req *req)
 void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
 {
        spin_lock(&dbg_lock);
-       printk(KERN_DEBUG "(pid %d) Lprops statistics: empty_lebs %d, "
+       printk(KERN_ERR "(pid %d) Lprops statistics: empty_lebs %d, "
               "idx_lebs  %d\n", current->pid, lst->empty_lebs, lst->idx_lebs);
-       printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, "
+       printk(KERN_ERR "\ttaken_empty_lebs %d, total_free %lld, "
               "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free,
               lst->total_dirty);
-       printk(KERN_DEBUG "\ttotal_used %lld, total_dark %lld, "
+       printk(KERN_ERR "\ttotal_used %lld, total_dark %lld, "
               "total_dead %lld\n", lst->total_used, lst->total_dark,
               lst->total_dead);
        spin_unlock(&dbg_lock);
@@ -644,21 +644,21 @@ void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
 
        spin_lock(&c->space_lock);
        spin_lock(&dbg_lock);
-       printk(KERN_DEBUG "(pid %d) Budgeting info: data budget sum %lld, "
+       printk(KERN_ERR "(pid %d) Budgeting info: data budget sum %lld, "
               "total budget sum %lld\n", current->pid,
               bi->data_growth + bi->dd_growth,
               bi->data_growth + bi->dd_growth + bi->idx_growth);
-       printk(KERN_DEBUG "\tbudg_data_growth %lld, budg_dd_growth %lld, "
+       printk(KERN_ERR "\tbudg_data_growth %lld, budg_dd_growth %lld, "
               "budg_idx_growth %lld\n", bi->data_growth, bi->dd_growth,
               bi->idx_growth);
-       printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %llu, "
+       printk(KERN_ERR "\tmin_idx_lebs %d, old_idx_sz %llu, "
               "uncommitted_idx %lld\n", bi->min_idx_lebs, bi->old_idx_sz,
               bi->uncommitted_idx);
-       printk(KERN_DEBUG "\tpage_budget %d, inode_budget %d, dent_budget %d\n",
+       printk(KERN_ERR "\tpage_budget %d, inode_budget %d, dent_budget %d\n",
               bi->page_budget, bi->inode_budget, bi->dent_budget);
-       printk(KERN_DEBUG "\tnospace %u, nospace_rp %u\n",
+       printk(KERN_ERR "\tnospace %u, nospace_rp %u\n",
               bi->nospace, bi->nospace_rp);
-       printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
+       printk(KERN_ERR "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
               c->dark_wm, c->dead_wm, c->max_idx_node_sz);
 
        if (bi != &c->bi)
@@ -669,38 +669,38 @@ void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
                 */
                goto out_unlock;
 
-       printk(KERN_DEBUG "\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
+       printk(KERN_ERR "\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
               c->freeable_cnt, c->calc_idx_sz, c->idx_gc_cnt);
-       printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
+       printk(KERN_ERR "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
               "clean_zn_cnt %ld\n", atomic_long_read(&c->dirty_pg_cnt),
               atomic_long_read(&c->dirty_zn_cnt),
               atomic_long_read(&c->clean_zn_cnt));
-       printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n",
+       printk(KERN_ERR "\tgc_lnum %d, ihead_lnum %d\n",
               c->gc_lnum, c->ihead_lnum);
 
        /* If we are in R/O mode, journal heads do not exist */
        if (c->jheads)
                for (i = 0; i < c->jhead_cnt; i++)
-                       printk(KERN_DEBUG "\tjhead %s\t LEB %d\n",
+                       printk(KERN_ERR "\tjhead %s\t LEB %d\n",
                               dbg_jhead(c->jheads[i].wbuf.jhead),
                               c->jheads[i].wbuf.lnum);
        for (rb = rb_first(&c->buds); rb; rb = rb_next(rb)) {
                bud = rb_entry(rb, struct ubifs_bud, rb);
-               printk(KERN_DEBUG "\tbud LEB %d\n", bud->lnum);
+               printk(KERN_ERR "\tbud LEB %d\n", bud->lnum);
        }
        list_for_each_entry(bud, &c->old_buds, list)
-               printk(KERN_DEBUG "\told bud LEB %d\n", bud->lnum);
+               printk(KERN_ERR "\told bud LEB %d\n", bud->lnum);
        list_for_each_entry(idx_gc, &c->idx_gc, list)
-               printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n",
+               printk(KERN_ERR "\tGC'ed idx LEB %d unmap %d\n",
                       idx_gc->lnum, idx_gc->unmap);
-       printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);
+       printk(KERN_ERR "\tcommit state %d\n", c->cmt_state);
 
        /* Print budgeting predictions */
        available = ubifs_calc_available(c, c->bi.min_idx_lebs);
        outstanding = c->bi.data_growth + c->bi.dd_growth;
        free = ubifs_get_free_space_nolock(c);
-       printk(KERN_DEBUG "Budgeting predictions:\n");
-       printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",
+       printk(KERN_ERR "Budgeting predictions:\n");
+       printk(KERN_ERR "\tavailable: %lld, outstanding %lld, free %lld\n",
               available, outstanding, free);
 out_unlock:
        spin_unlock(&dbg_lock);
@@ -720,11 +720,11 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
                dark = ubifs_calc_dark(c, spc);
 
        if (lp->flags & LPROPS_INDEX)
-               printk(KERN_DEBUG "LEB %-7d free %-8d dirty %-8d used %-8d "
+               printk(KERN_ERR "LEB %-7d free %-8d dirty %-8d used %-8d "
                       "free + dirty %-8d flags %#x (", lp->lnum, lp->free,
                       lp->dirty, c->leb_size - spc, spc, lp->flags);
        else
-               printk(KERN_DEBUG "LEB %-7d free %-8d dirty %-8d used %-8d "
+               printk(KERN_ERR "LEB %-7d free %-8d dirty %-8d used %-8d "
                       "free + dirty %-8d dark %-4d dead %-4d nodes fit %-3d "
                       "flags %#-4x (", lp->lnum, lp->free, lp->dirty,
                       c->leb_size - spc, spc, dark, dead,
@@ -807,7 +807,7 @@ void dbg_dump_lprops(struct ubifs_info *c)
        struct ubifs_lprops lp;
        struct ubifs_lp_stats lst;
 
-       printk(KERN_DEBUG "(pid %d) start dumping LEB properties\n",
+       printk(KERN_ERR "(pid %d) start dumping LEB properties\n",
               current->pid);
        ubifs_get_lp_stats(c, &lst);
        dbg_dump_lstats(&lst);
@@ -819,7 +819,7 @@ void dbg_dump_lprops(struct ubifs_info *c)
 
                dbg_dump_lprop(c, &lp);
        }
-       printk(KERN_DEBUG "(pid %d) finish dumping LEB properties\n",
+       printk(KERN_ERR "(pid %d) finish dumping LEB properties\n",
               current->pid);
 }
 
@@ -828,35 +828,35 @@ void dbg_dump_lpt_info(struct ubifs_info *c)
        int i;
 
        spin_lock(&dbg_lock);
-       printk(KERN_DEBUG "(pid %d) dumping LPT information\n", current->pid);
-       printk(KERN_DEBUG "\tlpt_sz:        %lld\n", c->lpt_sz);
-       printk(KERN_DEBUG "\tpnode_sz:      %d\n", c->pnode_sz);
-       printk(KERN_DEBUG "\tnnode_sz:      %d\n", c->nnode_sz);
-       printk(KERN_DEBUG "\tltab_sz:       %d\n", c->ltab_sz);
-       printk(KERN_DEBUG "\tlsave_sz:      %d\n", c->lsave_sz);
-       printk(KERN_DEBUG "\tbig_lpt:       %d\n", c->big_lpt);
-       printk(KERN_DEBUG "\tlpt_hght:      %d\n", c->lpt_hght);
-       printk(KERN_DEBUG "\tpnode_cnt:     %d\n", c->pnode_cnt);
-       printk(KERN_DEBUG "\tnnode_cnt:     %d\n", c->nnode_cnt);
-       printk(KERN_DEBUG "\tdirty_pn_cnt:  %d\n", c->dirty_pn_cnt);
-       printk(KERN_DEBUG "\tdirty_nn_cnt:  %d\n", c->dirty_nn_cnt);
-       printk(KERN_DEBUG "\tlsave_cnt:     %d\n", c->lsave_cnt);
-       printk(KERN_DEBUG "\tspace_bits:    %d\n", c->space_bits);
-       printk(KERN_DEBUG "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
-       printk(KERN_DEBUG "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
-       printk(KERN_DEBUG "\tlpt_spc_bits:  %d\n", c->lpt_spc_bits);
-       printk(KERN_DEBUG "\tpcnt_bits:     %d\n", c->pcnt_bits);
-       printk(KERN_DEBUG "\tlnum_bits:     %d\n", c->lnum_bits);
-       printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
-       printk(KERN_DEBUG "\tLPT head is at %d:%d\n",
+       printk(KERN_ERR "(pid %d) dumping LPT information\n", current->pid);
+       printk(KERN_ERR "\tlpt_sz:        %lld\n", c->lpt_sz);
+       printk(KERN_ERR "\tpnode_sz:      %d\n", c->pnode_sz);
+       printk(KERN_ERR "\tnnode_sz:      %d\n", c->nnode_sz);
+       printk(KERN_ERR "\tltab_sz:       %d\n", c->ltab_sz);
+       printk(KERN_ERR "\tlsave_sz:      %d\n", c->lsave_sz);
+       printk(KERN_ERR "\tbig_lpt:       %d\n", c->big_lpt);
+       printk(KERN_ERR "\tlpt_hght:      %d\n", c->lpt_hght);
+       printk(KERN_ERR "\tpnode_cnt:     %d\n", c->pnode_cnt);
+       printk(KERN_ERR "\tnnode_cnt:     %d\n", c->nnode_cnt);
+       printk(KERN_ERR "\tdirty_pn_cnt:  %d\n", c->dirty_pn_cnt);
+       printk(KERN_ERR "\tdirty_nn_cnt:  %d\n", c->dirty_nn_cnt);
+       printk(KERN_ERR "\tlsave_cnt:     %d\n", c->lsave_cnt);
+       printk(KERN_ERR "\tspace_bits:    %d\n", c->space_bits);
+       printk(KERN_ERR "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
+       printk(KERN_ERR "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
+       printk(KERN_ERR "\tlpt_spc_bits:  %d\n", c->lpt_spc_bits);
+       printk(KERN_ERR "\tpcnt_bits:     %d\n", c->pcnt_bits);
+       printk(KERN_ERR "\tlnum_bits:     %d\n", c->lnum_bits);
+       printk(KERN_ERR "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
+       printk(KERN_ERR "\tLPT head is at %d:%d\n",
               c->nhead_lnum, c->nhead_offs);
-       printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n",
+       printk(KERN_ERR "\tLPT ltab is at %d:%d\n",
               c->ltab_lnum, c->ltab_offs);
        if (c->big_lpt)
-               printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n",
+               printk(KERN_ERR "\tLPT lsave is at %d:%d\n",
                       c->lsave_lnum, c->lsave_offs);
        for (i = 0; i < c->lpt_lebs; i++)
-               printk(KERN_DEBUG "\tLPT LEB %d free %d dirty %d tgc %d "
+               printk(KERN_ERR "\tLPT LEB %d free %d dirty %d tgc %d "
                       "cmt %d\n", i + c->lpt_first, c->ltab[i].free,
                       c->ltab[i].dirty, c->ltab[i].tgc, c->ltab[i].cmt);
        spin_unlock(&dbg_lock);
@@ -867,12 +867,12 @@ void dbg_dump_sleb(const struct ubifs_info *c,
 {
        struct ubifs_scan_node *snod;
 
-       printk(KERN_DEBUG "(pid %d) start dumping scanned data from LEB %d:%d\n",
+       printk(KERN_ERR "(pid %d) start dumping scanned data from LEB %d:%d\n",
               current->pid, sleb->lnum, offs);
 
        list_for_each_entry(snod, &sleb->nodes, list) {
                cond_resched();
-               printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", sleb->lnum,
+               printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", sleb->lnum,
                       snod->offs, snod->len);
                dbg_dump_node(c, snod->node);
        }
@@ -887,7 +887,7 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
        if (dbg_is_tst_rcvry(c))
                return;
 
-       printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
+       printk(KERN_ERR "(pid %d) start dumping LEB %d\n",
               current->pid, lnum);
 
        buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
@@ -902,17 +902,17 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
                goto out;
        }
 
-       printk(KERN_DEBUG "LEB %d has %d nodes ending at %d\n", lnum,
+       printk(KERN_ERR "LEB %d has %d nodes ending at %d\n", lnum,
               sleb->nodes_cnt, sleb->endpt);
 
        list_for_each_entry(snod, &sleb->nodes, list) {
                cond_resched();
-               printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", lnum,
+               printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", lnum,
                       snod->offs, snod->len);
                dbg_dump_node(c, snod->node);
        }
 
-       printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
+       printk(KERN_ERR "(pid %d) finish dumping LEB %d\n",
               current->pid, lnum);
        ubifs_scan_destroy(sleb);
 
@@ -934,7 +934,7 @@ void dbg_dump_znode(const struct ubifs_info *c,
        else
                zbr = &c->zroot;
 
-       printk(KERN_DEBUG "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
+       printk(KERN_ERR "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
               " child_cnt %d flags %lx\n", znode, zbr->lnum, zbr->offs,
               zbr->len, znode->parent, znode->iip, znode->level,
               znode->child_cnt, znode->flags);
@@ -944,18 +944,18 @@ void dbg_dump_znode(const struct ubifs_info *c,
                return;
        }
 
-       printk(KERN_DEBUG "zbranches:\n");
+       printk(KERN_ERR "zbranches:\n");
        for (n = 0; n < znode->child_cnt; n++) {
                zbr = &znode->zbranch[n];
                if (znode->level > 0)
-                       printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key "
+                       printk(KERN_ERR "\t%d: znode %p LEB %d:%d len %d key "
                                          "%s\n", n, zbr->znode, zbr->lnum,
                                          zbr->offs, zbr->len,
                                          dbg_snprintf_key(c, &zbr->key,
                                                           key_buf,
                                                           DBG_KEY_BUF_LEN));
                else
-                       printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key "
+                       printk(KERN_ERR "\t%d: LNC %p LEB %d:%d len %d key "
                                          "%s\n", n, zbr->znode, zbr->lnum,
                                          zbr->offs, zbr->len,
                                          dbg_snprintf_key(c, &zbr->key,
@@ -969,16 +969,16 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
 {
        int i;
 
-       printk(KERN_DEBUG "(pid %d) start dumping heap cat %d (%d elements)\n",
+       printk(KERN_ERR "(pid %d) start dumping heap cat %d (%d elements)\n",
               current->pid, cat, heap->cnt);
        for (i = 0; i < heap->cnt; i++) {
                struct ubifs_lprops *lprops = heap->arr[i];
 
-               printk(KERN_DEBUG "\t%d. LEB %d hpos %d free %d dirty %d "
+               printk(KERN_ERR "\t%d. LEB %d hpos %d free %d dirty %d "
                       "flags %d\n", i, lprops->lnum, lprops->hpos,
                       lprops->free, lprops->dirty, lprops->flags);
        }
-       printk(KERN_DEBUG "(pid %d) finish dumping heap\n", current->pid);
+       printk(KERN_ERR "(pid %d) finish dumping heap\n", current->pid);
 }
 
 void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
@@ -986,15 +986,15 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
 {
        int i;
 
-       printk(KERN_DEBUG "(pid %d) dumping pnode:\n", current->pid);
-       printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n",
+       printk(KERN_ERR "(pid %d) dumping pnode:\n", current->pid);
+       printk(KERN_ERR "\taddress %zx parent %zx cnext %zx\n",
               (size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
-       printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n",
+       printk(KERN_ERR "\tflags %lu iip %d level %d num %d\n",
               pnode->flags, iip, pnode->level, pnode->num);
        for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
                struct ubifs_lprops *lp = &pnode->lprops[i];
 
-               printk(KERN_DEBUG "\t%d: free %d dirty %d flags %d lnum %d\n",
+               printk(KERN_ERR "\t%d: free %d dirty %d flags %d lnum %d\n",
                       i, lp->free, lp->dirty, lp->flags, lp->lnum);
        }
 }
@@ -1004,20 +1004,20 @@ void dbg_dump_tnc(struct ubifs_info *c)
        struct ubifs_znode *znode;
        int level;
 
-       printk(KERN_DEBUG "\n");
-       printk(KERN_DEBUG "(pid %d) start dumping TNC tree\n", current->pid);
+       printk(KERN_ERR "\n");
+       printk(KERN_ERR "(pid %d) start dumping TNC tree\n", current->pid);
        znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
        level = znode->level;
-       printk(KERN_DEBUG "== Level %d ==\n", level);
+       printk(KERN_ERR "== Level %d ==\n", level);
        while (znode) {
                if (level != znode->level) {
                        level = znode->level;
-                       printk(KERN_DEBUG "== Level %d ==\n", level);
+                       printk(KERN_ERR "== Level %d ==\n", level);
                }
                dbg_dump_znode(c, znode);
                znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
        }
-       printk(KERN_DEBUG "(pid %d) finish dumping TNC tree\n", current->pid);
+       printk(KERN_ERR "(pid %d) finish dumping TNC tree\n", current->pid);
 }
 
 static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
index ad1a6fe..9f71765 100644 (file)
@@ -164,9 +164,7 @@ struct ubifs_global_debug_info {
 #define dbg_dump_stack() dump_stack()
 
 #define dbg_err(fmt, ...) do {                                                 \
-       spin_lock(&dbg_lock);                                                  \
        ubifs_err(fmt, ##__VA_ARGS__);                                         \
-       spin_unlock(&dbg_lock);                                                \
 } while (0)
 
 #define ubifs_dbg_msg(type, fmt, ...) \
@@ -217,7 +215,6 @@ struct ubifs_global_debug_info {
 /* Additional recovery messages */
 #define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
 
-extern spinlock_t dbg_lock;
 extern struct ubifs_global_debug_info ubifs_dbg;
 
 static inline int dbg_is_chk_gen(const struct ubifs_info *c)
index d6fe1c7..ec9f187 100644 (file)
@@ -566,6 +566,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
        int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
        int err, budgeted = 1;
        struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
+       unsigned int saved_nlink = inode->i_nlink;
 
        /*
         * Budget request settings: deletion direntry, deletion inode (+1 for
@@ -613,7 +614,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
 out_cancel:
        dir->i_size += sz_change;
        dir_ui->ui_size = dir->i_size;
-       inc_nlink(inode);
+       set_nlink(inode, saved_nlink);
        unlock_2_inodes(dir, inode);
        if (budgeted)
                ubifs_release_budget(c, &req);
@@ -704,8 +705,7 @@ out_cancel:
        dir->i_size += sz_change;
        dir_ui->ui_size = dir->i_size;
        inc_nlink(dir);
-       inc_nlink(inode);
-       inc_nlink(inode);
+       set_nlink(inode, 2);
        unlock_2_inodes(dir, inode);
        if (budgeted)
                ubifs_release_budget(c, &req);
@@ -977,6 +977,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
                        .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
        struct timespec time;
+       unsigned int saved_nlink;
 
        /*
         * Budget request settings: deletion direntry, new direntry, removing
@@ -1059,13 +1060,14 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (unlink) {
                /*
                 * Directories cannot have hard-links, so if this is a
-                * directory, decrement its @i_nlink twice because an empty
-                * directory has @i_nlink 2.
+                * directory, just clear @i_nlink.
                 */
+               saved_nlink = new_inode->i_nlink;
                if (is_dir)
+                       clear_nlink(new_inode);
+               else
                        drop_nlink(new_inode);
                new_inode->i_ctime = time;
-               drop_nlink(new_inode);
        } else {
                new_dir->i_size += new_sz;
                ubifs_inode(new_dir)->ui_size = new_dir->i_size;
@@ -1102,9 +1104,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 out_cancel:
        if (unlink) {
-               if (is_dir)
-                       inc_nlink(new_inode);
-               inc_nlink(new_inode);
+               set_nlink(new_inode, saved_nlink);
        } else {
                new_dir->i_size -= new_sz;
                ubifs_inode(new_dir)->ui_size = new_dir->i_size;
index ee4f43f..2a935b3 100644 (file)
@@ -679,7 +679,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                           ret == SCANNED_GARBAGE     ||
                           ret == SCANNED_A_BAD_PAD_NODE ||
                           ret == SCANNED_A_CORRUPT_NODE) {
-                       dbg_rcvry("found corruption - %d", ret);
+                       dbg_rcvry("found corruption (%d) at %d:%d",
+                                 ret, lnum, offs);
                        break;
                } else {
                        dbg_err("unexpected return value %d", ret);
index 6094c5a..771f7fb 100644 (file)
@@ -410,13 +410,23 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
        }
 
        if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
-               err = 7;
+               ubifs_err("too few main LEBs count %d, must be at least %d",
+                         c->main_lebs, UBIFS_MIN_MAIN_LEBS);
                goto failed;
        }
 
-       if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS ||
-           c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) {
-               err = 8;
+       max_bytes = (long long)c->leb_size * UBIFS_MIN_BUD_LEBS;
+       if (c->max_bud_bytes < max_bytes) {
+               ubifs_err("too small journal (%lld bytes), must be at least "
+                         "%lld bytes",  c->max_bud_bytes, max_bytes);
+               goto failed;
+       }
+
+       max_bytes = (long long)c->leb_size * c->main_lebs;
+       if (c->max_bud_bytes > max_bytes) {
+               ubifs_err("too large journal size (%lld bytes), only %lld bytes"
+                         "available in the main area",
+                         c->max_bud_bytes, max_bytes);
                goto failed;
        }
 
@@ -450,7 +460,6 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
                goto failed;
        }
 
-       max_bytes = c->main_lebs * (long long)c->leb_size;
        if (c->rp_size < 0 || max_bytes < c->rp_size) {
                err = 14;
                goto failed;
index 12e9477..93d59ac 100644 (file)
@@ -84,9 +84,6 @@
 #define INUM_WARN_WATERMARK 0xFFF00000
 #define INUM_WATERMARK      0xFFFFFF00
 
-/* Largest key size supported in this implementation */
-#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
-
 /* Maximum number of entries in each LPT (LEB category) heap */
 #define LPT_HEAP_SZ 256
 
@@ -277,10 +274,10 @@ struct ubifs_old_idx {
 
 /* The below union makes it easier to deal with keys */
 union ubifs_key {
-       uint8_t u8[CUR_MAX_KEY_LEN];
-       uint32_t u32[CUR_MAX_KEY_LEN/4];
-       uint64_t u64[CUR_MAX_KEY_LEN/8];
-       __le32 j32[CUR_MAX_KEY_LEN/4];
+       uint8_t u8[UBIFS_SK_LEN];
+       uint32_t u32[UBIFS_SK_LEN/4];
+       uint64_t u64[UBIFS_SK_LEN/8];
+       __le32 j32[UBIFS_SK_LEN/4];
 };
 
 /**
index 987585b..1ba2baa 100644 (file)
@@ -105,7 +105,6 @@ static void udf_add_free_space(struct super_block *sb, u16 partition, u32 cnt)
 }
 
 static void udf_bitmap_free_blocks(struct super_block *sb,
-                                  struct inode *inode,
                                   struct udf_bitmap *bitmap,
                                   struct kernel_lb_addr *bloc,
                                   uint32_t offset,
@@ -172,7 +171,6 @@ error_return:
 }
 
 static int udf_bitmap_prealloc_blocks(struct super_block *sb,
-                                     struct inode *inode,
                                      struct udf_bitmap *bitmap,
                                      uint16_t partition, uint32_t first_block,
                                      uint32_t block_count)
@@ -223,7 +221,6 @@ out:
 }
 
 static int udf_bitmap_new_block(struct super_block *sb,
-                               struct inode *inode,
                                struct udf_bitmap *bitmap, uint16_t partition,
                                uint32_t goal, int *err)
 {
@@ -349,7 +346,6 @@ error_return:
 }
 
 static void udf_table_free_blocks(struct super_block *sb,
-                                 struct inode *inode,
                                  struct inode *table,
                                  struct kernel_lb_addr *bloc,
                                  uint32_t offset,
@@ -581,7 +577,6 @@ error_return:
 }
 
 static int udf_table_prealloc_blocks(struct super_block *sb,
-                                    struct inode *inode,
                                     struct inode *table, uint16_t partition,
                                     uint32_t first_block, uint32_t block_count)
 {
@@ -643,7 +638,6 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
 }
 
 static int udf_table_new_block(struct super_block *sb,
-                              struct inode *inode,
                               struct inode *table, uint16_t partition,
                               uint32_t goal, int *err)
 {
@@ -743,18 +737,23 @@ void udf_free_blocks(struct super_block *sb, struct inode *inode,
        struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
 
        if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) {
-               udf_bitmap_free_blocks(sb, inode, map->s_uspace.s_bitmap,
+               udf_bitmap_free_blocks(sb, map->s_uspace.s_bitmap,
                                       bloc, offset, count);
        } else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) {
-               udf_table_free_blocks(sb, inode, map->s_uspace.s_table,
+               udf_table_free_blocks(sb, map->s_uspace.s_table,
                                      bloc, offset, count);
        } else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) {
-               udf_bitmap_free_blocks(sb, inode, map->s_fspace.s_bitmap,
+               udf_bitmap_free_blocks(sb, map->s_fspace.s_bitmap,
                                       bloc, offset, count);
        } else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) {
-               udf_table_free_blocks(sb, inode, map->s_fspace.s_table,
+               udf_table_free_blocks(sb, map->s_fspace.s_table,
                                      bloc, offset, count);
        }
+
+       if (inode) {
+               inode_sub_bytes(inode,
+                               ((sector_t)count) << sb->s_blocksize_bits);
+       }
 }
 
 inline int udf_prealloc_blocks(struct super_block *sb,
@@ -763,29 +762,34 @@ inline int udf_prealloc_blocks(struct super_block *sb,
                               uint32_t block_count)
 {
        struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
+       sector_t allocated;
 
        if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
-               return udf_bitmap_prealloc_blocks(sb, inode,
-                                                 map->s_uspace.s_bitmap,
-                                                 partition, first_block,
-                                                 block_count);
+               allocated = udf_bitmap_prealloc_blocks(sb,
+                                                      map->s_uspace.s_bitmap,
+                                                      partition, first_block,
+                                                      block_count);
        else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
-               return udf_table_prealloc_blocks(sb, inode,
-                                                map->s_uspace.s_table,
-                                                partition, first_block,
-                                                block_count);
+               allocated = udf_table_prealloc_blocks(sb,
+                                                     map->s_uspace.s_table,
+                                                     partition, first_block,
+                                                     block_count);
        else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
-               return udf_bitmap_prealloc_blocks(sb, inode,
-                                                 map->s_fspace.s_bitmap,
-                                                 partition, first_block,
-                                                 block_count);
+               allocated = udf_bitmap_prealloc_blocks(sb,
+                                                      map->s_fspace.s_bitmap,
+                                                      partition, first_block,
+                                                      block_count);
        else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
-               return udf_table_prealloc_blocks(sb, inode,
-                                                map->s_fspace.s_table,
-                                                partition, first_block,
-                                                block_count);
+               allocated = udf_table_prealloc_blocks(sb,
+                                                     map->s_fspace.s_table,
+                                                     partition, first_block,
+                                                     block_count);
        else
                return 0;
+
+       if (inode && allocated > 0)
+               inode_add_bytes(inode, allocated << sb->s_blocksize_bits);
+       return allocated;
 }
 
 inline int udf_new_block(struct super_block *sb,
@@ -793,25 +797,29 @@ inline int udf_new_block(struct super_block *sb,
                         uint16_t partition, uint32_t goal, int *err)
 {
        struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
+       int block;
 
        if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
-               return udf_bitmap_new_block(sb, inode,
-                                          map->s_uspace.s_bitmap,
-                                          partition, goal, err);
+               block = udf_bitmap_new_block(sb,
+                                            map->s_uspace.s_bitmap,
+                                            partition, goal, err);
        else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
-               return udf_table_new_block(sb, inode,
-                                          map->s_uspace.s_table,
-                                          partition, goal, err);
-       else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
-               return udf_bitmap_new_block(sb, inode,
-                                           map->s_fspace.s_bitmap,
+               block = udf_table_new_block(sb,
+                                           map->s_uspace.s_table,
                                            partition, goal, err);
+       else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
+               block = udf_bitmap_new_block(sb,
+                                            map->s_fspace.s_bitmap,
+                                            partition, goal, err);
        else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
-               return udf_table_new_block(sb, inode,
-                                          map->s_fspace.s_table,
-                                          partition, goal, err);
+               block = udf_table_new_block(sb,
+                                           map->s_fspace.s_table,
+                                           partition, goal, err);
        else {
                *err = -EIO;
                return 0;
        }
+       if (inode && block)
+               inode_add_bytes(inode, sb->s_blocksize);
+       return block;
 }
index 05ab481..7e5aae4 100644 (file)
@@ -116,6 +116,7 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode, int *err)
        iinfo->i_lenEAttr = 0;
        iinfo->i_lenAlloc = 0;
        iinfo->i_use = 0;
+       iinfo->i_checkpoint = 1;
        if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB))
                iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
        else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
index 7699df7..7d75280 100644 (file)
@@ -1358,6 +1358,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
                iinfo->i_unique = le64_to_cpu(fe->uniqueID);
                iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr);
                iinfo->i_lenAlloc = le32_to_cpu(fe->lengthAllocDescs);
+               iinfo->i_checkpoint = le32_to_cpu(fe->checkpoint);
                offset = sizeof(struct fileEntry) + iinfo->i_lenEAttr;
        } else {
                inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
@@ -1379,6 +1380,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
                iinfo->i_unique = le64_to_cpu(efe->uniqueID);
                iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr);
                iinfo->i_lenAlloc = le32_to_cpu(efe->lengthAllocDescs);
+               iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint);
                offset = sizeof(struct extendedFileEntry) +
                                                        iinfo->i_lenEAttr;
        }
@@ -1495,6 +1497,7 @@ static int udf_update_inode(struct inode *inode, int do_sync)
        struct buffer_head *bh = NULL;
        struct fileEntry *fe;
        struct extendedFileEntry *efe;
+       uint64_t lb_recorded;
        uint32_t udfperms;
        uint16_t icbflags;
        uint16_t crclen;
@@ -1589,13 +1592,18 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                dsea->minorDeviceIdent = cpu_to_le32(iminor(inode));
        }
 
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+               lb_recorded = 0; /* No extents => no blocks! */
+       else
+               lb_recorded =
+                       (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >>
+                       (blocksize_bits - 9);
+
        if (iinfo->i_efe == 0) {
                memcpy(bh->b_data + sizeof(struct fileEntry),
                       iinfo->i_ext.i_data,
                       inode->i_sb->s_blocksize - sizeof(struct fileEntry));
-               fe->logicalBlocksRecorded = cpu_to_le64(
-                       (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >>
-                       (blocksize_bits - 9));
+               fe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
 
                udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime);
                udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime);
@@ -1607,6 +1615,7 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                fe->uniqueID = cpu_to_le64(iinfo->i_unique);
                fe->lengthExtendedAttr = cpu_to_le32(iinfo->i_lenEAttr);
                fe->lengthAllocDescs = cpu_to_le32(iinfo->i_lenAlloc);
+               fe->checkpoint = cpu_to_le32(iinfo->i_checkpoint);
                fe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_FE);
                crclen = sizeof(struct fileEntry);
        } else {
@@ -1615,9 +1624,7 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                       inode->i_sb->s_blocksize -
                                        sizeof(struct extendedFileEntry));
                efe->objectSize = cpu_to_le64(inode->i_size);
-               efe->logicalBlocksRecorded = cpu_to_le64(
-                       (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >>
-                       (blocksize_bits - 9));
+               efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
 
                if (iinfo->i_crtime.tv_sec > inode->i_atime.tv_sec ||
                    (iinfo->i_crtime.tv_sec == inode->i_atime.tv_sec &&
@@ -1646,6 +1653,7 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                efe->uniqueID = cpu_to_le64(iinfo->i_unique);
                efe->lengthExtendedAttr = cpu_to_le32(iinfo->i_lenEAttr);
                efe->lengthAllocDescs = cpu_to_le32(iinfo->i_lenAlloc);
+               efe->checkpoint = cpu_to_le32(iinfo->i_checkpoint);
                efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE);
                crclen = sizeof(struct extendedFileEntry);
        }
index 85067b4..ac8a348 100644 (file)
@@ -950,11 +950,8 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index)
        else
                bitmap = vzalloc(size); /* TODO: get rid of vzalloc */
 
-       if (bitmap == NULL) {
-               udf_err(sb, "Unable to allocate space for bitmap and %d buffer_head pointers\n",
-                       nr_groups);
+       if (bitmap == NULL)
                return NULL;
-       }
 
        bitmap->s_block_bitmap = (struct buffer_head **)(bitmap + 1);
        bitmap->s_nr_groups = nr_groups;
index d1bd31e..bb8309d 100644 (file)
@@ -23,6 +23,7 @@ struct udf_inode_info {
        __u64                   i_lenExtents;
        __u32                   i_next_alloc_block;
        __u32                   i_next_alloc_goal;
+       __u32                   i_checkpoint;
        unsigned                i_alloc_type : 3;
        unsigned                i_efe : 1;      /* extendedFileEntry */
        unsigned                i_use : 1;      /* unallocSpaceEntry */
index 82f4337..d6dfd24 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/security.h>
 #include <linux/evm.h>
 #include <linux/syscalls.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/fsnotify.h>
 #include <linux/audit.h>
 #include <asm/uaccess.h>
index 8d5a506..69d06b0 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/posix_acl_xattr.h>
 #include <linux/gfp.h>
index 427a4e8..0a99779 100644 (file)
@@ -96,9 +96,6 @@ xfs-$(CONFIG_XFS_QUOTA)               += xfs_dquot.o \
                                   xfs_qm_bhv.o \
                                   xfs_qm.o \
                                   xfs_quotaops.o
-ifeq ($(CONFIG_XFS_QUOTA),y)
-xfs-$(CONFIG_PROC_FS)          += xfs_qm_stats.o
-endif
 xfs-$(CONFIG_XFS_RT)           += xfs_rtalloc.o
 xfs-$(CONFIG_XFS_POSIX_ACL)    += xfs_acl.o
 xfs-$(CONFIG_PROC_FS)          += xfs_stats.o
index ce84ffd..0f0df27 100644 (file)
@@ -35,6 +35,7 @@
 #include "xfs_error.h"
 #include "xfs_trace.h"
 
+struct workqueue_struct *xfs_alloc_wq;
 
 #define XFS_ABSDIFF(a,b)       (((a) <= (b)) ? ((b) - (a)) : ((a) - (b)))
 
@@ -68,7 +69,7 @@ xfs_alloc_lookup_eq(
  * Lookup the first record greater than or equal to [bno, len]
  * in the btree given by cur.
  */
-STATIC int                             /* error */
+int                            /* error */
 xfs_alloc_lookup_ge(
        struct xfs_btree_cur    *cur,   /* btree cursor */
        xfs_agblock_t           bno,    /* starting block of extent */
@@ -2207,7 +2208,7 @@ xfs_alloc_read_agf(
  * group or loop over the allocation groups to find the result.
  */
 int                            /* error */
-xfs_alloc_vextent(
+__xfs_alloc_vextent(
        xfs_alloc_arg_t *args)  /* allocation argument structure */
 {
        xfs_agblock_t   agsize; /* allocation group size */
@@ -2417,6 +2418,37 @@ error0:
        return error;
 }
 
+static void
+xfs_alloc_vextent_worker(
+       struct work_struct      *work)
+{
+       struct xfs_alloc_arg    *args = container_of(work,
+                                               struct xfs_alloc_arg, work);
+       unsigned long           pflags;
+
+       /* we are in a transaction context here */
+       current_set_flags_nested(&pflags, PF_FSTRANS);
+
+       args->result = __xfs_alloc_vextent(args);
+       complete(args->done);
+
+       current_restore_flags_nested(&pflags, PF_FSTRANS);
+}
+
+
+int                            /* error */
+xfs_alloc_vextent(
+       xfs_alloc_arg_t *args)  /* allocation argument structure */
+{
+       DECLARE_COMPLETION_ONSTACK(done);
+
+       args->done = &done;
+       INIT_WORK(&args->work, xfs_alloc_vextent_worker);
+       queue_work(xfs_alloc_wq, &args->work);
+       wait_for_completion(&done);
+       return args->result;
+}
+
 /*
  * Free an extent.
  * Just break up the extent address and hand off to xfs_free_ag_extent
index 2f52b92..3a7e7d8 100644 (file)
@@ -25,6 +25,8 @@ struct xfs_perag;
 struct xfs_trans;
 struct xfs_busy_extent;
 
+extern struct workqueue_struct *xfs_alloc_wq;
+
 /*
  * Freespace allocation types.  Argument to xfs_alloc_[v]extent.
  */
@@ -119,6 +121,9 @@ typedef struct xfs_alloc_arg {
        char            isfl;           /* set if is freelist blocks - !acctg */
        char            userdata;       /* set if this is user data */
        xfs_fsblock_t   firstblock;     /* io first block allocated */
+       struct completion *done;
+       struct work_struct work;
+       int             result;
 } xfs_alloc_arg_t;
 
 /*
@@ -243,6 +248,13 @@ xfs_alloc_lookup_le(
        xfs_extlen_t            len,    /* length of extent */
        int                     *stat); /* success/failure */
 
+int                            /* error */
+xfs_alloc_lookup_ge(
+       struct xfs_btree_cur    *cur,   /* btree cursor */
+       xfs_agblock_t           bno,    /* starting block of extent */
+       xfs_extlen_t            len,    /* length of extent */
+       int                     *stat); /* success/failure */
+
 int                                    /* error */
 xfs_alloc_get_rec(
        struct xfs_btree_cur    *cur,   /* btree cursor */
index 74b9baf..0dbb9e7 100644 (file)
@@ -26,6 +26,7 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
+#include "xfs_inode_item.h"
 #include "xfs_alloc.h"
 #include "xfs_error.h"
 #include "xfs_rw.h"
@@ -99,23 +100,6 @@ xfs_destroy_ioend(
 }
 
 /*
- * If the end of the current ioend is beyond the current EOF,
- * return the new EOF value, otherwise zero.
- */
-STATIC xfs_fsize_t
-xfs_ioend_new_eof(
-       xfs_ioend_t             *ioend)
-{
-       xfs_inode_t             *ip = XFS_I(ioend->io_inode);
-       xfs_fsize_t             isize;
-       xfs_fsize_t             bsize;
-
-       bsize = ioend->io_offset + ioend->io_size;
-       isize = MIN(i_size_read(VFS_I(ip)), bsize);
-       return isize > ip->i_d.di_size ? isize : 0;
-}
-
-/*
  * Fast and loose check if this write could update the on-disk inode size.
  */
 static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend)
@@ -124,32 +108,65 @@ static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend)
                XFS_I(ioend->io_inode)->i_d.di_size;
 }
 
+STATIC int
+xfs_setfilesize_trans_alloc(
+       struct xfs_ioend        *ioend)
+{
+       struct xfs_mount        *mp = XFS_I(ioend->io_inode)->i_mount;
+       struct xfs_trans        *tp;
+       int                     error;
+
+       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;
+       }
+
+       ioend->io_append_trans = tp;
+
+       /*
+        * We hand off the transaction to the completion thread now, so
+        * clear the flag here.
+        */
+       current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
+       return 0;
+}
+
 /*
  * Update on-disk file size now that data has been written to disk.
- *
- * This function does not block as blocking on the inode lock in IO completion
- * can lead to IO completion order dependency deadlocks.. If it can't get the
- * inode ilock it will return EAGAIN. Callers must handle this.
  */
 STATIC int
 xfs_setfilesize(
-       xfs_ioend_t             *ioend)
+       struct xfs_ioend        *ioend)
 {
-       xfs_inode_t             *ip = XFS_I(ioend->io_inode);
+       struct xfs_inode        *ip = XFS_I(ioend->io_inode);
+       struct xfs_trans        *tp = ioend->io_append_trans;
        xfs_fsize_t             isize;
 
-       if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL))
-               return EAGAIN;
+       /*
+        * The transaction was allocated in the I/O submission thread,
+        * thus we need to mark ourselves as beeing in a transaction
+        * manually.
+        */
+       current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
 
-       isize = xfs_ioend_new_eof(ioend);
-       if (isize) {
-               trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);
-               ip->i_d.di_size = isize;
-               xfs_mark_inode_dirty(ip);
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size);
+       if (!isize) {
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               xfs_trans_cancel(tp, 0);
+               return 0;
        }
 
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       return 0;
+       trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);
+
+       ip->i_d.di_size = isize;
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+       return xfs_trans_commit(tp, 0);
 }
 
 /*
@@ -163,10 +180,12 @@ xfs_finish_ioend(
        struct xfs_ioend        *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)
-                       queue_work(xfsconvertd_workqueue, &ioend->io_work);
-               else if (xfs_ioend_is_append(ioend))
-                       queue_work(xfsdatad_workqueue, &ioend->io_work);
+                       queue_work(mp->m_unwritten_workqueue, &ioend->io_work);
+               else if (ioend->io_append_trans)
+                       queue_work(mp->m_data_workqueue, &ioend->io_work);
                else
                        xfs_destroy_ioend(ioend);
        }
@@ -195,35 +214,36 @@ xfs_end_io(
         * range to normal written extens after the data I/O has finished.
         */
        if (ioend->io_type == IO_UNWRITTEN) {
+               /*
+                * For buffered I/O we never preallocate a transaction when
+                * doing the unwritten extent conversion, but for direct I/O
+                * we do not know if we are converting an unwritten extent
+                * or not at the point where we preallocate the transaction.
+                */
+               if (ioend->io_append_trans) {
+                       ASSERT(ioend->io_isdirect);
+
+                       current_set_flags_nested(
+                               &ioend->io_append_trans->t_pflags, PF_FSTRANS);
+                       xfs_trans_cancel(ioend->io_append_trans, 0);
+               }
+
                error = xfs_iomap_write_unwritten(ip, ioend->io_offset,
                                                 ioend->io_size);
                if (error) {
                        ioend->io_error = -error;
                        goto done;
                }
+       } else if (ioend->io_append_trans) {
+               error = xfs_setfilesize(ioend);
+               if (error)
+                       ioend->io_error = -error;
+       } else {
+               ASSERT(!xfs_ioend_is_append(ioend));
        }
 
-       /*
-        * We might have to update the on-disk file size after extending
-        * writes.
-        */
-       error = xfs_setfilesize(ioend);
-       ASSERT(!error || error == EAGAIN);
-
 done:
-       /*
-        * If we didn't complete processing of the ioend, requeue it to the
-        * tail of the workqueue for another attempt later. Otherwise destroy
-        * it.
-        */
-       if (error == EAGAIN) {
-               atomic_inc(&ioend->io_remaining);
-               xfs_finish_ioend(ioend);
-               /* ensure we don't spin on blocked ioends */
-               delay(1);
-       } else {
-               xfs_destroy_ioend(ioend);
-       }
+       xfs_destroy_ioend(ioend);
 }
 
 /*
@@ -259,6 +279,7 @@ xfs_alloc_ioend(
         */
        atomic_set(&ioend->io_remaining, 1);
        ioend->io_isasync = 0;
+       ioend->io_isdirect = 0;
        ioend->io_error = 0;
        ioend->io_list = NULL;
        ioend->io_type = type;
@@ -269,6 +290,7 @@ xfs_alloc_ioend(
        ioend->io_size = 0;
        ioend->io_iocb = NULL;
        ioend->io_result = 0;
+       ioend->io_append_trans = NULL;
 
        INIT_WORK(&ioend->io_work, xfs_end_io);
        return ioend;
@@ -379,14 +401,6 @@ xfs_submit_ioend_bio(
        atomic_inc(&ioend->io_remaining);
        bio->bi_private = ioend;
        bio->bi_end_io = xfs_end_bio;
-
-       /*
-        * If the I/O is beyond EOF we mark the inode dirty immediately
-        * but don't update the inode size until I/O completion.
-        */
-       if (xfs_ioend_new_eof(ioend))
-               xfs_mark_inode_dirty(XFS_I(ioend->io_inode));
-
        submit_bio(wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE, bio);
 }
 
@@ -1033,8 +1047,20 @@ xfs_vm_writepage(
                                  wbc, end_index);
        }
 
-       if (iohead)
+       if (iohead) {
+               /*
+                * Reserve log space if we might write beyond the on-disk
+                * inode size.
+                */
+               if (ioend->io_type != IO_UNWRITTEN &&
+                   xfs_ioend_is_append(ioend)) {
+                       err = xfs_setfilesize_trans_alloc(ioend);
+                       if (err)
+                               goto error;
+               }
+
                xfs_submit_ioend(wbc, iohead);
+       }
 
        return 0;
 
@@ -1314,17 +1340,32 @@ xfs_vm_direct_IO(
 {
        struct inode            *inode = iocb->ki_filp->f_mapping->host;
        struct block_device     *bdev = xfs_find_bdev_for_inode(inode);
+       struct xfs_ioend        *ioend = NULL;
        ssize_t                 ret;
 
        if (rw & WRITE) {
-               iocb->private = xfs_alloc_ioend(inode, IO_DIRECT);
+               size_t size = iov_length(iov, nr_segs);
+
+               /*
+                * We need to preallocate a transaction for a size update
+                * here.  In the case that this write both updates the size
+                * 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);
+               if (offset + size > XFS_I(inode)->i_d.di_size) {
+                       ret = xfs_setfilesize_trans_alloc(ioend);
+                       if (ret)
+                               goto out_destroy_ioend;
+                       ioend->io_isdirect = 1;
+               }
 
                ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
                                            offset, nr_segs,
                                            xfs_get_blocks_direct,
                                            xfs_end_io_direct_write, NULL, 0);
                if (ret != -EIOCBQUEUED && iocb->private)
-                       xfs_destroy_ioend(iocb->private);
+                       goto out_trans_cancel;
        } else {
                ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
                                            offset, nr_segs,
@@ -1333,6 +1374,16 @@ xfs_vm_direct_IO(
        }
 
        return ret;
+
+out_trans_cancel:
+       if (ioend->io_append_trans) {
+               current_set_flags_nested(&ioend->io_append_trans->t_pflags,
+                                        PF_FSTRANS);
+               xfs_trans_cancel(ioend->io_append_trans, 0);
+       }
+out_destroy_ioend:
+       xfs_destroy_ioend(ioend);
+       return ret;
 }
 
 STATIC void
index 116dd5c..84eafbc 100644 (file)
@@ -18,8 +18,6 @@
 #ifndef __XFS_AOPS_H__
 #define __XFS_AOPS_H__
 
-extern struct workqueue_struct *xfsdatad_workqueue;
-extern struct workqueue_struct *xfsconvertd_workqueue;
 extern mempool_t *xfs_ioend_pool;
 
 /*
@@ -48,12 +46,14 @@ typedef struct xfs_ioend {
        int                     io_error;       /* I/O error code */
        atomic_t                io_remaining;   /* hold count */
        unsigned int            io_isasync : 1; /* needs aio_complete */
+       unsigned int            io_isdirect : 1;/* direct I/O */
        struct inode            *io_inode;      /* file being written to */
        struct buffer_head      *io_buffer_head;/* buffer linked list head */
        struct buffer_head      *io_buffer_tail;/* buffer linked list tail */
        size_t                  io_size;        /* size of the extent */
        xfs_off_t               io_offset;      /* offset in the file */
        struct work_struct      io_work;        /* xfsdatad work queue */
+       struct xfs_trans        *io_append_trans;/* xact. for size update */
        struct kiocb            *io_iocb;
        int                     io_result;
 } xfs_ioend_t;
index 08b9ac6..65d61b9 100644 (file)
@@ -853,6 +853,8 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
 {
        int newsize, forkoff, retval;
 
+       trace_xfs_attr_sf_addname(args);
+
        retval = xfs_attr_shortform_lookup(args);
        if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
                return(retval);
@@ -896,6 +898,8 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
        xfs_dabuf_t *bp;
        int retval, error, committed, forkoff;
 
+       trace_xfs_attr_leaf_addname(args);
+
        /*
         * Read the (only) block in the attribute list in.
         */
@@ -920,6 +924,9 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                        xfs_da_brelse(args->trans, bp);
                        return(retval);
                }
+
+               trace_xfs_attr_leaf_replace(args);
+
                args->op_flags |= XFS_DA_OP_RENAME;     /* an atomic rename */
                args->blkno2 = args->blkno;             /* set 2nd entry info*/
                args->index2 = args->index;
@@ -1090,6 +1097,8 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
        xfs_dabuf_t *bp;
        int error, committed, forkoff;
 
+       trace_xfs_attr_leaf_removename(args);
+
        /*
         * Remove the attribute.
         */
@@ -1223,6 +1232,8 @@ xfs_attr_node_addname(xfs_da_args_t *args)
        xfs_mount_t *mp;
        int committed, retval, error;
 
+       trace_xfs_attr_node_addname(args);
+
        /*
         * Fill in bucket of arguments/results/context to carry around.
         */
@@ -1249,6 +1260,9 @@ restart:
        } else if (retval == EEXIST) {
                if (args->flags & ATTR_CREATE)
                        goto out;
+
+               trace_xfs_attr_node_replace(args);
+
                args->op_flags |= XFS_DA_OP_RENAME;     /* atomic rename op */
                args->blkno2 = args->blkno;             /* set 2nd entry info*/
                args->index2 = args->index;
@@ -1480,6 +1494,8 @@ xfs_attr_node_removename(xfs_da_args_t *args)
        xfs_dabuf_t *bp;
        int retval, error, committed, forkoff;
 
+       trace_xfs_attr_node_removename(args);
+
        /*
         * Tie a string around our finger to remind us where we are.
         */
index d25eafd..76d93dc 100644 (file)
@@ -235,6 +235,8 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
        xfs_inode_t *dp;
        xfs_ifork_t *ifp;
 
+       trace_xfs_attr_sf_create(args);
+
        dp = args->dp;
        ASSERT(dp != NULL);
        ifp = dp->i_afp;
@@ -268,6 +270,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
        xfs_inode_t *dp;
        xfs_ifork_t *ifp;
 
+       trace_xfs_attr_sf_add(args);
+
        dp = args->dp;
        mp = dp->i_mount;
        dp->i_d.di_forkoff = forkoff;
@@ -337,6 +341,8 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
        xfs_mount_t *mp;
        xfs_inode_t *dp;
 
+       trace_xfs_attr_sf_remove(args);
+
        dp = args->dp;
        mp = dp->i_mount;
        base = sizeof(xfs_attr_sf_hdr_t);
@@ -405,6 +411,8 @@ xfs_attr_shortform_lookup(xfs_da_args_t *args)
        int i;
        xfs_ifork_t *ifp;
 
+       trace_xfs_attr_sf_lookup(args);
+
        ifp = args->dp->i_afp;
        ASSERT(ifp->if_flags & XFS_IFINLINE);
        sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
@@ -476,6 +484,8 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
        xfs_dabuf_t *bp;
        xfs_ifork_t *ifp;
 
+       trace_xfs_attr_sf_to_leaf(args);
+
        dp = args->dp;
        ifp = dp->i_afp;
        sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
@@ -775,6 +785,8 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
        char *tmpbuffer;
        int error, i;
 
+       trace_xfs_attr_leaf_to_sf(args);
+
        dp = args->dp;
        tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP);
        ASSERT(tmpbuffer != NULL);
@@ -848,6 +860,8 @@ xfs_attr_leaf_to_node(xfs_da_args_t *args)
        xfs_dablk_t blkno;
        int error;
 
+       trace_xfs_attr_leaf_to_node(args);
+
        dp = args->dp;
        bp1 = bp2 = NULL;
        error = xfs_da_grow_inode(args, &blkno);
@@ -911,6 +925,8 @@ xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
        xfs_dabuf_t *bp;
        int error;
 
+       trace_xfs_attr_leaf_create(args);
+
        dp = args->dp;
        ASSERT(dp != NULL);
        error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp,
@@ -948,6 +964,8 @@ xfs_attr_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
        xfs_dablk_t blkno;
        int error;
 
+       trace_xfs_attr_leaf_split(state->args);
+
        /*
         * Allocate space for a new leaf node.
         */
@@ -977,10 +995,13 @@ xfs_attr_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
         *
         * Insert the "new" entry in the correct block.
         */
-       if (state->inleaf)
+       if (state->inleaf) {
+               trace_xfs_attr_leaf_add_old(state->args);
                error = xfs_attr_leaf_add(oldblk->bp, state->args);
-       else
+       } else {
+               trace_xfs_attr_leaf_add_new(state->args);
                error = xfs_attr_leaf_add(newblk->bp, state->args);
+       }
 
        /*
         * Update last hashval in each block since we added the name.
@@ -1001,6 +1022,8 @@ xfs_attr_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args)
        xfs_attr_leaf_map_t *map;
        int tablesize, entsize, sum, tmp, i;
 
+       trace_xfs_attr_leaf_add(args);
+
        leaf = bp->data;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT((args->index >= 0)
@@ -1128,8 +1151,6 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
               (be32_to_cpu(entry->hashval) <= be32_to_cpu((entry+1)->hashval)));
 
        /*
-        * Copy the attribute name and value into the new space.
-        *
         * For "remote" attribute values, simply note that we need to
         * allocate space for the "remote" value.  We can't actually
         * allocate the extents in this transaction, and we can't decide
@@ -1265,6 +1286,8 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
        ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        args = state->args;
 
+       trace_xfs_attr_leaf_rebalance(args);
+
        /*
         * Check ordering of blocks, reverse if it makes things simpler.
         *
@@ -1810,6 +1833,8 @@ xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
        xfs_mount_t *mp;
        char *tmpbuffer;
 
+       trace_xfs_attr_leaf_unbalance(state->args);
+
        /*
         * Set up environment.
         */
@@ -1919,6 +1944,8 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
        int probe, span;
        xfs_dahash_t hashval;
 
+       trace_xfs_attr_leaf_lookup(args);
+
        leaf = bp->data;
        ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
        ASSERT(be16_to_cpu(leaf->hdr.count)
@@ -2445,6 +2472,7 @@ xfs_attr_leaf_clearflag(xfs_da_args_t *args)
        char *name;
 #endif /* DEBUG */
 
+       trace_xfs_attr_leaf_clearflag(args);
        /*
         * Set up the operation.
         */
@@ -2509,6 +2537,8 @@ xfs_attr_leaf_setflag(xfs_da_args_t *args)
        xfs_dabuf_t *bp;
        int error;
 
+       trace_xfs_attr_leaf_setflag(args);
+
        /*
         * Set up the operation.
         */
@@ -2565,6 +2595,8 @@ xfs_attr_leaf_flipflags(xfs_da_args_t *args)
        char *name1, *name2;
 #endif /* DEBUG */
 
+       trace_xfs_attr_leaf_flipflags(args);
+
        /*
         * Read the block containing the "old" attr
         */
index 188ef2f..85e7e32 100644 (file)
@@ -5124,6 +5124,15 @@ xfs_bunmapi(
                cur->bc_private.b.flags = 0;
        } else
                cur = NULL;
+
+       if (isrt) {
+               /*
+                * Synchronize by locking the bitmap inode.
+                */
+               xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+       }
+
        extno = 0;
        while (bno != (xfs_fileoff_t)-1 && bno >= start && lastx >= 0 &&
               (nexts == 0 || extno < nexts)) {
@@ -5536,8 +5545,12 @@ xfs_getbmap(
        if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx))
                return XFS_ERROR(ENOMEM);
        out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx), KM_MAYFAIL);
-       if (!out)
-               return XFS_ERROR(ENOMEM);
+       if (!out) {
+               out = kmem_zalloc_large(bmv->bmv_count *
+                                       sizeof(struct getbmapx));
+               if (!out)
+                       return XFS_ERROR(ENOMEM);
+       }
 
        xfs_ilock(ip, XFS_IOLOCK_SHARED);
        if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) {
@@ -5661,7 +5674,10 @@ xfs_getbmap(
                        break;
        }
 
-       kmem_free(out);
+       if (is_vmalloc_addr(out))
+               kmem_free_large(out);
+       else
+               kmem_free(out);
        return error;
 }
 
index 4dff85c..6819b51 100644 (file)
@@ -45,8 +45,6 @@ static kmem_zone_t *xfs_buf_zone;
 STATIC int xfsbufd(void *);
 
 static struct workqueue_struct *xfslogd_workqueue;
-struct workqueue_struct *xfsdatad_workqueue;
-struct workqueue_struct *xfsconvertd_workqueue;
 
 #ifdef XFS_BUF_LOCK_TRACKING
 # define XB_SET_OWNER(bp)      ((bp)->b_last_holder = current->pid)
@@ -1793,21 +1791,8 @@ xfs_buf_init(void)
        if (!xfslogd_workqueue)
                goto out_free_buf_zone;
 
-       xfsdatad_workqueue = alloc_workqueue("xfsdatad", WQ_MEM_RECLAIM, 1);
-       if (!xfsdatad_workqueue)
-               goto out_destroy_xfslogd_workqueue;
-
-       xfsconvertd_workqueue = alloc_workqueue("xfsconvertd",
-                                               WQ_MEM_RECLAIM, 1);
-       if (!xfsconvertd_workqueue)
-               goto out_destroy_xfsdatad_workqueue;
-
        return 0;
 
- out_destroy_xfsdatad_workqueue:
-       destroy_workqueue(xfsdatad_workqueue);
- out_destroy_xfslogd_workqueue:
-       destroy_workqueue(xfslogd_workqueue);
  out_free_buf_zone:
        kmem_zone_destroy(xfs_buf_zone);
  out:
@@ -1817,8 +1802,6 @@ xfs_buf_init(void)
 void
 xfs_buf_terminate(void)
 {
-       destroy_workqueue(xfsconvertd_workqueue);
-       destroy_workqueue(xfsdatad_workqueue);
        destroy_workqueue(xfslogd_workqueue);
        kmem_zone_destroy(xfs_buf_zone);
 }
index 77c7425..7f1a6f5 100644 (file)
@@ -108,6 +108,8 @@ xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level,
        int error;
        xfs_trans_t *tp;
 
+       trace_xfs_da_node_create(args);
+
        tp = args->trans;
        error = xfs_da_get_buf(tp, args->dp, blkno, -1, &bp, whichfork);
        if (error)
@@ -140,6 +142,8 @@ xfs_da_split(xfs_da_state_t *state)
        xfs_dabuf_t *bp;
        int max, action, error, i;
 
+       trace_xfs_da_split(state->args);
+
        /*
         * Walk back up the tree splitting/inserting/adjusting as necessary.
         * If we need to insert and there isn't room, split the node, then
@@ -178,10 +182,12 @@ xfs_da_split(xfs_da_state_t *state)
                        state->extravalid = 1;
                        if (state->inleaf) {
                                state->extraafter = 0;  /* before newblk */
+                               trace_xfs_attr_leaf_split_before(state->args);
                                error = xfs_attr_leaf_split(state, oldblk,
                                                            &state->extrablk);
                        } else {
                                state->extraafter = 1;  /* after newblk */
+                               trace_xfs_attr_leaf_split_after(state->args);
                                error = xfs_attr_leaf_split(state, newblk,
                                                            &state->extrablk);
                        }
@@ -300,6 +306,8 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
        xfs_mount_t *mp;
        xfs_dir2_leaf_t *leaf;
 
+       trace_xfs_da_root_split(state->args);
+
        /*
         * Copy the existing (incorrect) block from the root node position
         * to a free space somewhere.
@@ -380,6 +388,8 @@ xfs_da_node_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
        int newcount, error;
        int useextra;
 
+       trace_xfs_da_node_split(state->args);
+
        node = oldblk->bp->data;
        ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
 
@@ -466,6 +476,8 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
        int count, tmp;
        xfs_trans_t *tp;
 
+       trace_xfs_da_node_rebalance(state->args);
+
        node1 = blk1->bp->data;
        node2 = blk2->bp->data;
        /*
@@ -574,6 +586,8 @@ xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
        xfs_da_node_entry_t *btree;
        int tmp;
 
+       trace_xfs_da_node_add(state->args);
+
        node = oldblk->bp->data;
        ASSERT(node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
        ASSERT((oldblk->index >= 0) && (oldblk->index <= be16_to_cpu(node->hdr.count)));
@@ -619,6 +633,8 @@ xfs_da_join(xfs_da_state_t *state)
        xfs_da_state_blk_t *drop_blk, *save_blk;
        int action, error;
 
+       trace_xfs_da_join(state->args);
+
        action = 0;
        drop_blk = &state->path.blk[ state->path.active-1 ];
        save_blk = &state->altpath.blk[ state->path.active-1 ];
@@ -723,6 +739,8 @@ xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk)
        xfs_dabuf_t *bp;
        int error;
 
+       trace_xfs_da_root_join(state->args);
+
        args = state->args;
        ASSERT(args != NULL);
        ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC);
@@ -941,6 +959,8 @@ xfs_da_node_remove(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk)
        xfs_da_node_entry_t *btree;
        int tmp;
 
+       trace_xfs_da_node_remove(state->args);
+
        node = drop_blk->bp->data;
        ASSERT(drop_blk->index < be16_to_cpu(node->hdr.count));
        ASSERT(drop_blk->index >= 0);
@@ -984,6 +1004,8 @@ xfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
        int tmp;
        xfs_trans_t *tp;
 
+       trace_xfs_da_node_unbalance(state->args);
+
        drop_node = drop_blk->bp->data;
        save_node = save_blk->bp->data;
        ASSERT(drop_node->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
@@ -1230,6 +1252,7 @@ xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
                /*
                 * Link new block in before existing block.
                 */
+               trace_xfs_da_link_before(args);
                new_info->forw = cpu_to_be32(old_blk->blkno);
                new_info->back = old_info->back;
                if (old_info->back) {
@@ -1251,6 +1274,7 @@ xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk,
                /*
                 * Link new block in after existing block.
                 */
+               trace_xfs_da_link_after(args);
                new_info->forw = old_info->forw;
                new_info->back = cpu_to_be32(old_blk->blkno);
                if (old_info->forw) {
@@ -1348,6 +1372,7 @@ xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
         * Unlink the leaf block from the doubly linked chain of leaves.
         */
        if (be32_to_cpu(save_info->back) == drop_blk->blkno) {
+               trace_xfs_da_unlink_back(args);
                save_info->back = drop_info->back;
                if (drop_info->back) {
                        error = xfs_da_read_buf(args->trans, args->dp,
@@ -1365,6 +1390,7 @@ xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
                        xfs_da_buf_done(bp);
                }
        } else {
+               trace_xfs_da_unlink_forward(args);
                save_info->forw = drop_info->forw;
                if (drop_info->forw) {
                        error = xfs_da_read_buf(args->trans, args->dp,
@@ -1652,6 +1678,8 @@ xfs_da_grow_inode(
        int                     count;
        int                     error;
 
+       trace_xfs_da_grow_inode(args);
+
        if (args->whichfork == XFS_DATA_FORK) {
                bno = args->dp->i_mount->m_dirleafblk;
                count = args->dp->i_mount->m_dirblkfsbs;
@@ -1690,6 +1718,8 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop,
        xfs_dir2_leaf_t *dead_leaf2;
        xfs_dahash_t dead_hash;
 
+       trace_xfs_da_swap_lastblock(args);
+
        dead_buf = *dead_bufp;
        dead_blkno = *dead_blknop;
        tp = args->trans;
@@ -1878,6 +1908,8 @@ xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
        xfs_trans_t *tp;
        xfs_mount_t *mp;
 
+       trace_xfs_da_shrink_inode(args);
+
        dp = args->dp;
        w = args->whichfork;
        tp = args->trans;
index dd974a5..1137bbc 100644 (file)
@@ -215,7 +215,7 @@ xfs_swap_extents(
        xfs_trans_t     *tp;
        xfs_bstat_t     *sbp = &sxp->sx_stat;
        xfs_ifork_t     *tempifp, *ifp, *tifp;
-       int             ilf_fields, tilf_fields;
+       int             src_log_flags, target_log_flags;
        int             error = 0;
        int             aforkblks = 0;
        int             taforkblks = 0;
@@ -385,9 +385,8 @@ xfs_swap_extents(
        tip->i_delayed_blks = ip->i_delayed_blks;
        ip->i_delayed_blks = 0;
 
-       ilf_fields = XFS_ILOG_CORE;
-
-       switch(ip->i_d.di_format) {
+       src_log_flags = XFS_ILOG_CORE;
+       switch (ip->i_d.di_format) {
        case XFS_DINODE_FMT_EXTENTS:
                /* If the extents fit in the inode, fix the
                 * pointer.  Otherwise it's already NULL or
@@ -397,16 +396,15 @@ xfs_swap_extents(
                        ifp->if_u1.if_extents =
                                ifp->if_u2.if_inline_ext;
                }
-               ilf_fields |= XFS_ILOG_DEXT;
+               src_log_flags |= XFS_ILOG_DEXT;
                break;
        case XFS_DINODE_FMT_BTREE:
-               ilf_fields |= XFS_ILOG_DBROOT;
+               src_log_flags |= XFS_ILOG_DBROOT;
                break;
        }
 
-       tilf_fields = XFS_ILOG_CORE;
-
-       switch(tip->i_d.di_format) {
+       target_log_flags = XFS_ILOG_CORE;
+       switch (tip->i_d.di_format) {
        case XFS_DINODE_FMT_EXTENTS:
                /* If the extents fit in the inode, fix the
                 * pointer.  Otherwise it's already NULL or
@@ -416,10 +414,10 @@ xfs_swap_extents(
                        tifp->if_u1.if_extents =
                                tifp->if_u2.if_inline_ext;
                }
-               tilf_fields |= XFS_ILOG_DEXT;
+               target_log_flags |= XFS_ILOG_DEXT;
                break;
        case XFS_DINODE_FMT_BTREE:
-               tilf_fields |= XFS_ILOG_DBROOT;
+               target_log_flags |= XFS_ILOG_DBROOT;
                break;
        }
 
@@ -427,8 +425,8 @@ xfs_swap_extents(
        xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
        xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 
-       xfs_trans_log_inode(tp, ip,  ilf_fields);
-       xfs_trans_log_inode(tp, tip, tilf_fields);
+       xfs_trans_log_inode(tp, ip,  src_log_flags);
+       xfs_trans_log_inode(tp, tip, target_log_flags);
 
        /*
         * If this is a synchronous mount, make sure that the
index 9245e02..d3b63ae 100644 (file)
@@ -29,6 +29,7 @@
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
+#include "xfs_dir2.h"
 #include "xfs_dir2_format.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_error.h"
index 286a051..1ad3a4b 100644 (file)
@@ -37,9 +37,9 @@ STATIC int
 xfs_trim_extents(
        struct xfs_mount        *mp,
        xfs_agnumber_t          agno,
-       xfs_fsblock_t           start,
-       xfs_fsblock_t           end,
-       xfs_fsblock_t           minlen,
+       xfs_daddr_t             start,
+       xfs_daddr_t             end,
+       xfs_daddr_t             minlen,
        __uint64_t              *blocks_trimmed)
 {
        struct block_device     *bdev = mp->m_ddev_targp->bt_bdev;
@@ -67,7 +67,7 @@ xfs_trim_extents(
        /*
         * Look up the longest btree in the AGF and start with it.
         */
-       error = xfs_alloc_lookup_le(cur, 0,
+       error = xfs_alloc_lookup_ge(cur, 0,
                            be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest), &i);
        if (error)
                goto out_del_cursor;
@@ -77,8 +77,10 @@ xfs_trim_extents(
         * enough to be worth discarding.
         */
        while (i) {
-               xfs_agblock_t fbno;
-               xfs_extlen_t flen;
+               xfs_agblock_t   fbno;
+               xfs_extlen_t    flen;
+               xfs_daddr_t     dbno;
+               xfs_extlen_t    dlen;
 
                error = xfs_alloc_get_rec(cur, &fbno, &flen, &i);
                if (error)
@@ -87,9 +89,17 @@ xfs_trim_extents(
                ASSERT(flen <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest));
 
                /*
+                * use daddr format for all range/len calculations as that is
+                * the format the range/len variables are supplied in by
+                * userspace.
+                */
+               dbno = XFS_AGB_TO_DADDR(mp, agno, fbno);
+               dlen = XFS_FSB_TO_BB(mp, flen);
+
+               /*
                 * Too small?  Give up.
                 */
-               if (flen < minlen) {
+               if (dlen < minlen) {
                        trace_xfs_discard_toosmall(mp, agno, fbno, flen);
                        goto out_del_cursor;
                }
@@ -99,8 +109,7 @@ xfs_trim_extents(
                 * supposed to discard skip it.  Do not bother to trim
                 * down partially overlapping ranges for now.
                 */
-               if (XFS_AGB_TO_FSB(mp, agno, fbno) + flen < start ||
-                   XFS_AGB_TO_FSB(mp, agno, fbno) > end) {
+               if (dbno + dlen < start || dbno > end) {
                        trace_xfs_discard_exclude(mp, agno, fbno, flen);
                        goto next_extent;
                }
@@ -115,10 +124,7 @@ xfs_trim_extents(
                }
 
                trace_xfs_discard_extent(mp, agno, fbno, flen);
-               error = -blkdev_issue_discard(bdev,
-                               XFS_AGB_TO_DADDR(mp, agno, fbno),
-                               XFS_FSB_TO_BB(mp, flen),
-                               GFP_NOFS, 0);
+               error = -blkdev_issue_discard(bdev, dbno, dlen, GFP_NOFS, 0);
                if (error)
                        goto out_del_cursor;
                *blocks_trimmed += flen;
@@ -137,6 +143,15 @@ out_put_perag:
        return error;
 }
 
+/*
+ * trim a range of the filesystem.
+ *
+ * Note: the parameters passed from userspace are byte ranges into the
+ * filesystem which does not match to the format we use for filesystem block
+ * addressing. FSB addressing is sparse (AGNO|AGBNO), while the incoming format
+ * is a linear address range. Hence we need to use DADDR based conversions and
+ * comparisons for determining the correct offset and regions to trim.
+ */
 int
 xfs_ioc_trim(
        struct xfs_mount                *mp,
@@ -145,7 +160,7 @@ xfs_ioc_trim(
        struct request_queue    *q = mp->m_ddev_targp->bt_bdev->bd_disk->queue;
        unsigned int            granularity = q->limits.discard_granularity;
        struct fstrim_range     range;
-       xfs_fsblock_t           start, end, minlen;
+       xfs_daddr_t             start, end, minlen;
        xfs_agnumber_t          start_agno, end_agno, agno;
        __uint64_t              blocks_trimmed = 0;
        int                     error, last_error = 0;
@@ -159,22 +174,22 @@ xfs_ioc_trim(
 
        /*
         * Truncating down the len isn't actually quite correct, but using
-        * XFS_B_TO_FSB would mean we trivially get overflows for values
+        * BBTOB would mean we trivially get overflows for values
         * of ULLONG_MAX or slightly lower.  And ULLONG_MAX is the default
         * used by the fstrim application.  In the end it really doesn't
         * matter as trimming blocks is an advisory interface.
         */
-       start = XFS_B_TO_FSBT(mp, range.start);
-       end = start + XFS_B_TO_FSBT(mp, range.len) - 1;
-       minlen = XFS_B_TO_FSB(mp, max_t(u64, granularity, range.minlen));
+       start = BTOBB(range.start);
+       end = start + BTOBBT(range.len) - 1;
+       minlen = BTOBB(max_t(u64, granularity, range.minlen));
 
-       if (start >= mp->m_sb.sb_dblocks)
+       if (XFS_BB_TO_FSB(mp, start) >= mp->m_sb.sb_dblocks)
                return -XFS_ERROR(EINVAL);
-       if (end > mp->m_sb.sb_dblocks - 1)
-               end = mp->m_sb.sb_dblocks - 1;
+       if (end > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) - 1)
+               end = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)- 1;
 
-       start_agno = XFS_FSB_TO_AGNO(mp, start);
-       end_agno = XFS_FSB_TO_AGNO(mp, end);
+       start_agno = xfs_daddr_to_agno(mp, start);
+       end_agno = xfs_daddr_to_agno(mp, end);
 
        for (agno = start_agno; agno <= end_agno; agno++) {
                error = -xfs_trim_extents(mp, agno, start, end, minlen,
index 53db20e..1155208 100644 (file)
  * Lock order:
  *
  * ip->i_lock
- *   qh->qh_lock
- *     qi->qi_dqlist_lock
- *       dquot->q_qlock (xfs_dqlock() and friends)
- *         dquot->q_flush (xfs_dqflock() and friends)
- *         xfs_Gqm->qm_dqfrlist_lock
+ *   qi->qi_tree_lock
+ *     dquot->q_qlock (xfs_dqlock() and friends)
+ *       dquot->q_flush (xfs_dqflock() and friends)
+ *       qi->qi_lru_lock
  *
  * If two dquots need to be locked the order is user before group/project,
  * otherwise by the lowest id first, see xfs_dqlock2.
@@ -60,6 +59,9 @@ int xfs_dqreq_num;
 int xfs_dqerror_mod = 33;
 #endif
 
+struct kmem_zone               *xfs_qm_dqtrxzone;
+static struct kmem_zone                *xfs_qm_dqzone;
+
 static struct lock_class_key xfs_dquot_other_class;
 
 /*
@@ -69,12 +71,12 @@ void
 xfs_qm_dqdestroy(
        xfs_dquot_t     *dqp)
 {
-       ASSERT(list_empty(&dqp->q_freelist));
+       ASSERT(list_empty(&dqp->q_lru));
 
        mutex_destroy(&dqp->q_qlock);
-       kmem_zone_free(xfs_Gqm->qm_dqzone, dqp);
+       kmem_zone_free(xfs_qm_dqzone, dqp);
 
-       atomic_dec(&xfs_Gqm->qm_totaldquots);
+       XFS_STATS_DEC(xs_qm_dquot);
 }
 
 /*
@@ -282,7 +284,7 @@ xfs_qm_dqalloc(
         * Return if this type of quotas is turned off while we didn't
         * have an inode lock
         */
-       if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
+       if (!xfs_this_quota_on(dqp->q_mount, dqp->dq_flags)) {
                xfs_iunlock(quotip, XFS_ILOCK_EXCL);
                return (ESRCH);
        }
@@ -384,7 +386,7 @@ xfs_qm_dqtobp(
        dqp->q_fileoffset = (xfs_fileoff_t)id / mp->m_quotainfo->qi_dqperchunk;
 
        xfs_ilock(quotip, XFS_ILOCK_SHARED);
-       if (XFS_IS_THIS_QUOTA_OFF(dqp)) {
+       if (!xfs_this_quota_on(dqp->q_mount, dqp->dq_flags)) {
                /*
                 * Return if this type of quotas is turned off while we
                 * didn't have the quota inode lock.
@@ -492,12 +494,12 @@ xfs_qm_dqread(
        int                     cancelflags = 0;
 
 
-       dqp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
+       dqp = kmem_zone_zalloc(xfs_qm_dqzone, KM_SLEEP);
 
        dqp->dq_flags = type;
        dqp->q_core.d_id = cpu_to_be32(id);
        dqp->q_mount = mp;
-       INIT_LIST_HEAD(&dqp->q_freelist);
+       INIT_LIST_HEAD(&dqp->q_lru);
        mutex_init(&dqp->q_qlock);
        init_waitqueue_head(&dqp->q_pinwait);
 
@@ -516,7 +518,7 @@ xfs_qm_dqread(
        if (!(type & XFS_DQ_USER))
                lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);
 
-       atomic_inc(&xfs_Gqm->qm_totaldquots);
+       XFS_STATS_INC(xs_qm_dquot);
 
        trace_xfs_dqread(dqp);
 
@@ -602,60 +604,6 @@ error0:
 }
 
 /*
- * Lookup a dquot in the incore dquot hashtable. We keep two separate
- * hashtables for user and group dquots; and, these are global tables
- * inside the XQM, not per-filesystem tables.
- * The hash chain must be locked by caller, and it is left locked
- * on return. Returning dquot is locked.
- */
-STATIC int
-xfs_qm_dqlookup(
-       xfs_mount_t             *mp,
-       xfs_dqid_t              id,
-       xfs_dqhash_t            *qh,
-       xfs_dquot_t             **O_dqpp)
-{
-       xfs_dquot_t             *dqp;
-
-       ASSERT(mutex_is_locked(&qh->qh_lock));
-
-       /*
-        * Traverse the hashchain looking for a match
-        */
-       list_for_each_entry(dqp, &qh->qh_list, q_hashlist) {
-               /*
-                * We already have the hashlock. We don't need the
-                * dqlock to look at the id field of the dquot, since the
-                * id can't be modified without the hashlock anyway.
-                */
-               if (be32_to_cpu(dqp->q_core.d_id) != id || dqp->q_mount != mp)
-                       continue;
-
-               trace_xfs_dqlookup_found(dqp);
-
-               xfs_dqlock(dqp);
-               if (dqp->dq_flags & XFS_DQ_FREEING) {
-                       *O_dqpp = NULL;
-                       xfs_dqunlock(dqp);
-                       return -1;
-               }
-
-               dqp->q_nrefs++;
-
-               /*
-                * move the dquot to the front of the hashchain
-                */
-               list_move(&dqp->q_hashlist, &qh->qh_list);
-               trace_xfs_dqlookup_done(dqp);
-               *O_dqpp = dqp;
-               return 0;
-       }
-
-       *O_dqpp = NULL;
-       return 1;
-}
-
-/*
  * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
  * a locked dquot, doing an allocation (if requested) as needed.
  * When both an inode and an id are given, the inode's id takes precedence.
@@ -672,10 +620,10 @@ xfs_qm_dqget(
        uint            flags,    /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */
        xfs_dquot_t     **O_dqpp) /* OUT : locked incore dquot */
 {
-       xfs_dquot_t     *dqp;
-       xfs_dqhash_t    *h;
-       uint            version;
-       int             error;
+       struct xfs_quotainfo    *qi = mp->m_quotainfo;
+       struct radix_tree_root *tree = XFS_DQUOT_TREE(qi, type);
+       struct xfs_dquot        *dqp;
+       int                     error;
 
        ASSERT(XFS_IS_QUOTA_RUNNING(mp));
        if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) ||
@@ -683,7 +631,6 @@ xfs_qm_dqget(
            (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) {
                return (ESRCH);
        }
-       h = XFS_DQ_HASH(mp, id, type);
 
 #ifdef DEBUG
        if (xfs_do_dqerror) {
@@ -699,42 +646,33 @@ xfs_qm_dqget(
               type == XFS_DQ_GROUP);
        if (ip) {
                ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-               if (type == XFS_DQ_USER)
-                       ASSERT(ip->i_udquot == NULL);
-               else
-                       ASSERT(ip->i_gdquot == NULL);
+               ASSERT(xfs_inode_dquot(ip, type) == NULL);
        }
 #endif
 
 restart:
-       mutex_lock(&h->qh_lock);
+       mutex_lock(&qi->qi_tree_lock);
+       dqp = radix_tree_lookup(tree, id);
+       if (dqp) {
+               xfs_dqlock(dqp);
+               if (dqp->dq_flags & XFS_DQ_FREEING) {
+                       xfs_dqunlock(dqp);
+                       mutex_unlock(&qi->qi_tree_lock);
+                       trace_xfs_dqget_freeing(dqp);
+                       delay(1);
+                       goto restart;
+               }
 
-       /*
-        * Look in the cache (hashtable).
-        * The chain is kept locked during lookup.
-        */
-       switch (xfs_qm_dqlookup(mp, id, h, O_dqpp)) {
-       case -1:
-               XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);
-               mutex_unlock(&h->qh_lock);
-               delay(1);
-               goto restart;
-       case 0:
-               XQM_STATS_INC(xqmstats.xs_qm_dqcachehits);
-               /*
-                * The dquot was found, moved to the front of the chain,
-                * taken off the freelist if it was on it, and locked
-                * at this point. Just unlock the hashchain and return.
-                */
-               ASSERT(*O_dqpp);
-               ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp));
-               mutex_unlock(&h->qh_lock);
-               trace_xfs_dqget_hit(*O_dqpp);
-               return 0;       /* success */
-       default:
-               XQM_STATS_INC(xqmstats.xs_qm_dqcachemisses);
-               break;
+               dqp->q_nrefs++;
+               mutex_unlock(&qi->qi_tree_lock);
+
+               trace_xfs_dqget_hit(dqp);
+               XFS_STATS_INC(xs_qm_dqcachehits);
+               *O_dqpp = dqp;
+               return 0;
        }
+       mutex_unlock(&qi->qi_tree_lock);
+       XFS_STATS_INC(xs_qm_dqcachemisses);
 
        /*
         * Dquot cache miss. We don't want to keep the inode lock across
@@ -745,12 +683,6 @@ restart:
         */
        if (ip)
                xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       /*
-        * Save the hashchain version stamp, and unlock the chain, so that
-        * we don't keep the lock across a disk read
-        */
-       version = h->qh_version;
-       mutex_unlock(&h->qh_lock);
 
        error = xfs_qm_dqread(mp, id, type, flags, &dqp);
 
@@ -760,97 +692,53 @@ restart:
        if (error)
                return error;
 
-       /*
-        * Dquot lock comes after hashlock in the lock ordering
-        */
        if (ip) {
                /*
                 * A dquot could be attached to this inode by now, since
                 * we had dropped the ilock.
                 */
-               if (type == XFS_DQ_USER) {
-                       if (!XFS_IS_UQUOTA_ON(mp)) {
-                               /* inode stays locked on return */
-                               xfs_qm_dqdestroy(dqp);
-                               return XFS_ERROR(ESRCH);
-                       }
-                       if (ip->i_udquot) {
+               if (xfs_this_quota_on(mp, type)) {
+                       struct xfs_dquot        *dqp1;
+
+                       dqp1 = xfs_inode_dquot(ip, type);
+                       if (dqp1) {
                                xfs_qm_dqdestroy(dqp);
-                               dqp = ip->i_udquot;
+                               dqp = dqp1;
                                xfs_dqlock(dqp);
                                goto dqret;
                        }
                } else {
-                       if (!XFS_IS_OQUOTA_ON(mp)) {
-                               /* inode stays locked on return */
-                               xfs_qm_dqdestroy(dqp);
-                               return XFS_ERROR(ESRCH);
-                       }
-                       if (ip->i_gdquot) {
-                               xfs_qm_dqdestroy(dqp);
-                               dqp = ip->i_gdquot;
-                               xfs_dqlock(dqp);
-                               goto dqret;
-                       }
+                       /* inode stays locked on return */
+                       xfs_qm_dqdestroy(dqp);
+                       return XFS_ERROR(ESRCH);
                }
        }
 
-       /*
-        * Hashlock comes after ilock in lock order
-        */
-       mutex_lock(&h->qh_lock);
-       if (version != h->qh_version) {
-               xfs_dquot_t *tmpdqp;
+       mutex_lock(&qi->qi_tree_lock);
+       error = -radix_tree_insert(tree, id, dqp);
+       if (unlikely(error)) {
+               WARN_ON(error != EEXIST);
+
                /*
-                * Now, see if somebody else put the dquot in the
-                * hashtable before us. This can happen because we didn't
-                * keep the hashchain lock. We don't have to worry about
-                * lock order between the two dquots here since dqp isn't
-                * on any findable lists yet.
+                * Duplicate found. Just throw away the new dquot and start
+                * over.
                 */
-               switch (xfs_qm_dqlookup(mp, id, h, &tmpdqp)) {
-               case 0:
-               case -1:
-                       /*
-                        * Duplicate found, either in cache or on its way out.
-                        * Just throw away the new dquot and start over.
-                        */
-                       if (tmpdqp)
-                               xfs_qm_dqput(tmpdqp);
-                       mutex_unlock(&h->qh_lock);
-                       xfs_qm_dqdestroy(dqp);
-                       XQM_STATS_INC(xqmstats.xs_qm_dquot_dups);
-                       goto restart;
-               default:
-                       break;
-               }
+               mutex_unlock(&qi->qi_tree_lock);
+               trace_xfs_dqget_dup(dqp);
+               xfs_qm_dqdestroy(dqp);
+               XFS_STATS_INC(xs_qm_dquot_dups);
+               goto restart;
        }
 
        /*
-        * Put the dquot at the beginning of the hash-chain and mp's list
-        * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock ..
-        */
-       ASSERT(mutex_is_locked(&h->qh_lock));
-       dqp->q_hash = h;
-       list_add(&dqp->q_hashlist, &h->qh_list);
-       h->qh_version++;
-
-       /*
-        * Attach this dquot to this filesystem's list of all dquots,
-        * kept inside the mount structure in m_quotainfo field
-        */
-       mutex_lock(&mp->m_quotainfo->qi_dqlist_lock);
-
-       /*
         * We return a locked dquot to the caller, with a reference taken
         */
        xfs_dqlock(dqp);
        dqp->q_nrefs = 1;
 
-       list_add(&dqp->q_mplist, &mp->m_quotainfo->qi_dqlist);
-       mp->m_quotainfo->qi_dquots++;
-       mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
-       mutex_unlock(&h->qh_lock);
+       qi->qi_dquots++;
+       mutex_unlock(&qi->qi_tree_lock);
+
  dqret:
        ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL));
        trace_xfs_dqget_miss(dqp);
@@ -859,37 +747,22 @@ restart:
 }
 
 
-/*
- * Release a reference to the dquot (decrement ref-count)
- * and unlock it. If there is a group quota attached to this
- * dquot, carefully release that too without tripping over
- * deadlocks'n'stuff.
- */
-void
-xfs_qm_dqput(
+STATIC void
+xfs_qm_dqput_final(
        struct xfs_dquot        *dqp)
 {
+       struct xfs_quotainfo    *qi = dqp->q_mount->m_quotainfo;
        struct xfs_dquot        *gdqp;
 
-       ASSERT(dqp->q_nrefs > 0);
-       ASSERT(XFS_DQ_IS_LOCKED(dqp));
-
-       trace_xfs_dqput(dqp);
-
-recurse:
-       if (--dqp->q_nrefs > 0) {
-               xfs_dqunlock(dqp);
-               return;
-       }
-
        trace_xfs_dqput_free(dqp);
 
-       mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
-       if (list_empty(&dqp->q_freelist)) {
-               list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
-               xfs_Gqm->qm_dqfrlist_cnt++;
+       mutex_lock(&qi->qi_lru_lock);
+       if (list_empty(&dqp->q_lru)) {
+               list_add_tail(&dqp->q_lru, &qi->qi_lru_list);
+               qi->qi_lru_count++;
+               XFS_STATS_INC(xs_qm_dquot_unused);
        }
-       mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+       mutex_unlock(&qi->qi_lru_lock);
 
        /*
         * If we just added a udquot to the freelist, then we want to release
@@ -906,10 +779,29 @@ recurse:
        /*
         * If we had a group quota hint, release it now.
         */
-       if (gdqp) {
-               dqp = gdqp;
-               goto recurse;
-       }
+       if (gdqp)
+               xfs_qm_dqput(gdqp);
+}
+
+/*
+ * Release a reference to the dquot (decrement ref-count) and unlock it.
+ *
+ * If there is a group quota attached to this dquot, carefully release that
+ * too without tripping over deadlocks'n'stuff.
+ */
+void
+xfs_qm_dqput(
+       struct xfs_dquot        *dqp)
+{
+       ASSERT(dqp->q_nrefs > 0);
+       ASSERT(XFS_DQ_IS_LOCKED(dqp));
+
+       trace_xfs_dqput(dqp);
+
+       if (--dqp->q_nrefs > 0)
+               xfs_dqunlock(dqp);
+       else
+               xfs_qm_dqput_final(dqp);
 }
 
 /*
@@ -1091,17 +983,6 @@ xfs_qm_dqflush(
 
 }
 
-void
-xfs_dqunlock(
-       xfs_dquot_t *dqp)
-{
-       xfs_dqunlock_nonotify(dqp);
-       if (dqp->q_logitem.qli_dquot == dqp) {
-               xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_ailp,
-                                       &dqp->q_logitem.qli_item);
-       }
-}
-
 /*
  * Lock two xfs_dquot structures.
  *
@@ -1131,85 +1012,6 @@ xfs_dqlock2(
 }
 
 /*
- * Take a dquot out of the mount's dqlist as well as the hashlist.  This is
- * called via unmount as well as quotaoff, and the purge will always succeed.
- */
-void
-xfs_qm_dqpurge(
-       struct xfs_dquot        *dqp)
-{
-       struct xfs_mount        *mp = dqp->q_mount;
-       struct xfs_dqhash       *qh = dqp->q_hash;
-
-       xfs_dqlock(dqp);
-
-       /*
-        * If we're turning off quotas, we have to make sure that, for
-        * example, we don't delete quota disk blocks while dquots are
-        * in the process of getting written to those disk blocks.
-        * This dquot might well be on AIL, and we can't leave it there
-        * if we're turning off quotas. Basically, we need this flush
-        * lock, and are willing to block on it.
-        */
-       if (!xfs_dqflock_nowait(dqp)) {
-               /*
-                * Block on the flush lock after nudging dquot buffer,
-                * if it is incore.
-                */
-               xfs_dqflock_pushbuf_wait(dqp);
-       }
-
-       /*
-        * If we are turning this type of quotas off, we don't care
-        * about the dirty metadata sitting in this dquot. OTOH, if
-        * we're unmounting, we do care, so we flush it and wait.
-        */
-       if (XFS_DQ_IS_DIRTY(dqp)) {
-               int     error;
-
-               /*
-                * We don't care about getting disk errors here. We need
-                * to purge this dquot anyway, so we go ahead regardless.
-                */
-               error = xfs_qm_dqflush(dqp, SYNC_WAIT);
-               if (error)
-                       xfs_warn(mp, "%s: dquot %p flush failed",
-                               __func__, dqp);
-               xfs_dqflock(dqp);
-       }
-
-       ASSERT(atomic_read(&dqp->q_pincount) == 0);
-       ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
-              !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
-
-       xfs_dqfunlock(dqp);
-       xfs_dqunlock(dqp);
-
-       mutex_lock(&qh->qh_lock);
-       list_del_init(&dqp->q_hashlist);
-       qh->qh_version++;
-       mutex_unlock(&qh->qh_lock);
-
-       mutex_lock(&mp->m_quotainfo->qi_dqlist_lock);
-       list_del_init(&dqp->q_mplist);
-       mp->m_quotainfo->qi_dqreclaims++;
-       mp->m_quotainfo->qi_dquots--;
-       mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
-
-       /*
-        * We move dquots to the freelist as soon as their reference count
-        * hits zero, so it really should be on the freelist here.
-        */
-       mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
-       ASSERT(!list_empty(&dqp->q_freelist));
-       list_del_init(&dqp->q_freelist);
-       xfs_Gqm->qm_dqfrlist_cnt--;
-       mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
-
-       xfs_qm_dqdestroy(dqp);
-}
-
-/*
  * Give the buffer a little push if it is incore and
  * wait on the flush lock.
  */
@@ -1241,3 +1043,31 @@ xfs_dqflock_pushbuf_wait(
 out_lock:
        xfs_dqflock(dqp);
 }
+
+int __init
+xfs_qm_init(void)
+{
+       xfs_qm_dqzone =
+               kmem_zone_init(sizeof(struct xfs_dquot), "xfs_dquot");
+       if (!xfs_qm_dqzone)
+               goto out;
+
+       xfs_qm_dqtrxzone =
+               kmem_zone_init(sizeof(struct xfs_dquot_acct), "xfs_dqtrx");
+       if (!xfs_qm_dqtrxzone)
+               goto out_free_dqzone;
+
+       return 0;
+
+out_free_dqzone:
+       kmem_zone_destroy(xfs_qm_dqzone);
+out:
+       return -ENOMEM;
+}
+
+void
+xfs_qm_exit(void)
+{
+       kmem_zone_destroy(xfs_qm_dqtrxzone);
+       kmem_zone_destroy(xfs_qm_dqzone);
+}
index a1d91d8..ef9190b 100644 (file)
  * when quotas are off.
  */
 
-/*
- * The hash chain headers (hash buckets)
- */
-typedef struct xfs_dqhash {
-       struct list_head  qh_list;
-       struct mutex      qh_lock;
-       uint              qh_version;   /* ever increasing version */
-       uint              qh_nelems;    /* number of dquots on the list */
-} xfs_dqhash_t;
-
 struct xfs_mount;
 struct xfs_trans;
 
@@ -47,10 +37,7 @@ struct xfs_trans;
  */
 typedef struct xfs_dquot {
        uint             dq_flags;      /* various flags (XFS_DQ_*) */
-       struct list_head q_freelist;    /* global free list of dquots */
-       struct list_head q_mplist;      /* mount's list of dquots */
-       struct list_head q_hashlist;    /* gloabl hash list of dquots */
-       xfs_dqhash_t    *q_hash;        /* the hashchain header */
+       struct list_head q_lru;         /* global free list of dquots */
        struct xfs_mount*q_mount;       /* filesystem this relates to */
        struct xfs_trans*q_transp;      /* trans this belongs to currently */
        uint             q_nrefs;       /* # active refs from inodes */
@@ -110,11 +97,37 @@ static inline void xfs_dqlock(struct xfs_dquot *dqp)
        mutex_lock(&dqp->q_qlock);
 }
 
-static inline void xfs_dqunlock_nonotify(struct xfs_dquot *dqp)
+static inline void xfs_dqunlock(struct xfs_dquot *dqp)
 {
        mutex_unlock(&dqp->q_qlock);
 }
 
+static inline int xfs_this_quota_on(struct xfs_mount *mp, int type)
+{
+       switch (type & XFS_DQ_ALLTYPES) {
+       case XFS_DQ_USER:
+               return XFS_IS_UQUOTA_ON(mp);
+       case XFS_DQ_GROUP:
+       case XFS_DQ_PROJ:
+               return XFS_IS_OQUOTA_ON(mp);
+       default:
+               return 0;
+       }
+}
+
+static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
+{
+       switch (type & XFS_DQ_ALLTYPES) {
+       case XFS_DQ_USER:
+               return ip->i_udquot;
+       case XFS_DQ_GROUP:
+       case XFS_DQ_PROJ:
+               return ip->i_gdquot;
+       default:
+               return NULL;
+       }
+}
+
 #define XFS_DQ_IS_LOCKED(dqp)  (mutex_is_locked(&((dqp)->q_qlock)))
 #define XFS_DQ_IS_DIRTY(dqp)   ((dqp)->dq_flags & XFS_DQ_DIRTY)
 #define XFS_QM_ISUDQ(dqp)      ((dqp)->dq_flags & XFS_DQ_USER)
@@ -125,15 +138,10 @@ static inline void xfs_dqunlock_nonotify(struct xfs_dquot *dqp)
                                 XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \
                                 XFS_DQ_TO_QINF(dqp)->qi_gquotaip)
 
-#define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \
-                                    (XFS_IS_UQUOTA_ON((d)->q_mount)) : \
-                                    (XFS_IS_OQUOTA_ON((d)->q_mount))))
-
 extern int             xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint,
                                        uint, struct xfs_dquot  **);
 extern void            xfs_qm_dqdestroy(xfs_dquot_t *);
 extern int             xfs_qm_dqflush(xfs_dquot_t *, uint);
-extern void            xfs_qm_dqpurge(xfs_dquot_t *);
 extern void            xfs_qm_dqunpin_wait(xfs_dquot_t *);
 extern void            xfs_qm_adjust_dqtimers(xfs_mount_t *,
                                        xfs_disk_dquot_t *);
@@ -144,7 +152,6 @@ extern int          xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *,
 extern void            xfs_qm_dqput(xfs_dquot_t *);
 
 extern void            xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
-extern void            xfs_dqunlock(struct xfs_dquot *);
 extern void            xfs_dqflock_pushbuf_wait(struct xfs_dquot *dqp);
 
 static inline struct xfs_dquot *xfs_qm_dqhold(struct xfs_dquot *dqp)
index 7e5bc87..54a67dd 100644 (file)
@@ -163,7 +163,6 @@ xfs_file_fsync(
        struct inode            *inode = file->f_mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_trans        *tp;
        int                     error = 0;
        int                     log_flushed = 0;
        xfs_lsn_t               lsn = 0;
@@ -194,75 +193,18 @@ xfs_file_fsync(
        }
 
        /*
-        * We always need to make sure that the required inode state is safe on
-        * disk.  The inode might be clean but we still might need to force the
-        * log because of committed transactions that haven't hit the disk yet.
-        * Likewise, there could be unflushed non-transactional changes to the
-        * inode core that have to go to disk and this requires us to issue
-        * a synchronous transaction to capture these changes correctly.
-        *
-        * This code relies on the assumption that if the i_update_core field
-        * of the inode is clear and the inode is unpinned then it is clean
-        * and no action is required.
+        * All metadata updates are logged, which means that we just have
+        * to flush the log up to the latest LSN that touched the inode.
         */
        xfs_ilock(ip, XFS_ILOCK_SHARED);
-
-       /*
-        * First check if the VFS inode is marked dirty.  All the dirtying
-        * of non-transactional updates do not go through mark_inode_dirty*,
-        * which allows us to distinguish between pure timestamp updates
-        * and i_size updates which need to be caught for fdatasync.
-        * After that also check for the dirty state in the XFS inode, which
-        * might gets cleared when the inode gets written out via the AIL
-        * or xfs_iflush_cluster.
-        */
-       if (((inode->i_state & I_DIRTY_DATASYNC) ||
-           ((inode->i_state & I_DIRTY_SYNC) && !datasync)) &&
-           ip->i_update_core) {
-               /*
-                * Kick off a transaction to log the inode core to get the
-                * updates.  The sync transaction will also force the log.
-                */
-               xfs_iunlock(ip, XFS_ILOCK_SHARED);
-               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);
-
-               /*
-                * Note - it's possible that we might have pushed ourselves out
-                * of the way during trans_reserve which would flush the inode.
-                * But there's no guarantee that the inode buffer has actually
-                * gone out yet (it's delwri).  Plus the buffer could be pinned
-                * anyway if it's part of an inode in another recent
-                * transaction.  So we play it safe and fire off the
-                * transaction anyway.
-                */
-               xfs_trans_ijoin(tp, ip, 0);
-               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-               error = xfs_trans_commit(tp, 0);
-
-               lsn = ip->i_itemp->ili_last_lsn;
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       } else {
-               /*
-                * Timestamps/size haven't changed since last inode flush or
-                * inode transaction commit.  That means either nothing got
-                * written or a transaction committed which caught the updates.
-                * If the latter happened and the transaction hasn't hit the
-                * disk yet, the inode will be still be pinned.  If it is,
-                * force the log.
-                */
-               if (xfs_ipincount(ip))
+       if (xfs_ipincount(ip)) {
+               if (!datasync ||
+                   (ip->i_itemp->ili_fields & ~XFS_ILOG_TIMESTAMP))
                        lsn = ip->i_itemp->ili_last_lsn;
-               xfs_iunlock(ip, XFS_ILOCK_SHARED);
        }
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
-       if (!error && lsn)
+       if (lsn)
                error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed);
 
        /*
@@ -659,9 +601,6 @@ restart:
                return error;
        }
 
-       if (likely(!(file->f_mode & FMODE_NOCMTIME)))
-               file_update_time(file);
-
        /*
         * If the offset is beyond the size of the file, we need to zero any
         * blocks that fall between the existing EOF and the start of this
@@ -685,6 +624,15 @@ restart:
                return error;
 
        /*
+        * Updating the timestamps will grab the ilock again from
+        * xfs_fs_dirty_inode, so we have to call it after dropping the
+        * lock above.  Eventually we should look into a way to avoid
+        * the pointless lock roundtrip.
+        */
+       if (likely(!(file->f_mode & FMODE_NOCMTIME)))
+               file_update_time(file);
+
+       /*
         * If we're writing the file then make sure to clear the setuid and
         * setgid bits if the process is not being run by root.  This keeps
         * people from modifying setuid and setgid binaries.
index 8c3e463..bcc6c24 100644 (file)
@@ -91,7 +91,6 @@ xfs_inode_alloc(
        ip->i_afp = NULL;
        memset(&ip->i_df, 0, sizeof(xfs_ifork_t));
        ip->i_flags = 0;
-       ip->i_update_core = 0;
        ip->i_delayed_blks = 0;
        memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
 
@@ -290,7 +289,7 @@ xfs_iget_cache_hit(
        if (lock_flags != 0)
                xfs_ilock(ip, lock_flags);
 
-       xfs_iflags_clear(ip, XFS_ISTALE);
+       xfs_iflags_clear(ip, XFS_ISTALE | XFS_IDONTCACHE);
        XFS_STATS_INC(xs_ig_found);
 
        return 0;
@@ -315,6 +314,7 @@ xfs_iget_cache_miss(
        struct xfs_inode        *ip;
        int                     error;
        xfs_agino_t             agino = XFS_INO_TO_AGINO(mp, ino);
+       int                     iflags;
 
        ip = xfs_inode_alloc(mp, ino);
        if (!ip)
@@ -350,9 +350,23 @@ xfs_iget_cache_miss(
                        BUG();
        }
 
-       spin_lock(&pag->pag_ici_lock);
+       /*
+        * These values must be set before inserting the inode into the radix
+        * tree as the moment it is inserted a concurrent lookup (allowed by the
+        * RCU locking mechanism) can find it and that lookup must see that this
+        * is an inode currently under construction (i.e. that XFS_INEW is set).
+        * The ip->i_flags_lock that protects the XFS_INEW flag forms the
+        * memory barrier that ensures this detection works correctly at lookup
+        * time.
+        */
+       iflags = XFS_INEW;
+       if (flags & XFS_IGET_DONTCACHE)
+               iflags |= XFS_IDONTCACHE;
+       ip->i_udquot = ip->i_gdquot = NULL;
+       xfs_iflags_set(ip, iflags);
 
        /* insert the new inode */
+       spin_lock(&pag->pag_ici_lock);
        error = radix_tree_insert(&pag->pag_ici_root, agino, ip);
        if (unlikely(error)) {
                WARN_ON(error != -EEXIST);
@@ -360,11 +374,6 @@ xfs_iget_cache_miss(
                error = EAGAIN;
                goto out_preload_end;
        }
-
-       /* These values _must_ be set before releasing the radix tree lock! */
-       ip->i_udquot = ip->i_gdquot = NULL;
-       xfs_iflags_set(ip, XFS_INEW);
-
        spin_unlock(&pag->pag_ici_lock);
        radix_tree_preload_end();
 
@@ -418,6 +427,15 @@ xfs_iget(
        xfs_perag_t     *pag;
        xfs_agino_t     agino;
 
+       /*
+        * xfs_reclaim_inode() uses the ILOCK to ensure an inode
+        * doesn't get freed while it's being referenced during a
+        * radix tree traversal here.  It assumes this function
+        * aqcuires only the ILOCK (and therefore it has no need to
+        * involve the IOLOCK in this synchronization).
+        */
+       ASSERT((lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)) == 0);
+
        /* reject inode numbers outside existing AGs */
        if (!ino || XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount)
                return EINVAL;
@@ -642,8 +660,7 @@ xfs_iunlock(
               (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
        ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
               (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-       ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY |
-                       XFS_LOCK_DEP_MASK)) == 0);
+       ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
        ASSERT(lock_flags != 0);
 
        if (lock_flags & XFS_IOLOCK_EXCL)
@@ -656,16 +673,6 @@ xfs_iunlock(
        else if (lock_flags & XFS_ILOCK_SHARED)
                mrunlock_shared(&ip->i_lock);
 
-       if ((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) &&
-           !(lock_flags & XFS_IUNLOCK_NONOTIFY) && ip->i_itemp) {
-               /*
-                * Let the AIL know that this item has been unlocked in case
-                * it is in the AIL and anyone is waiting on it.  Don't do
-                * this if the caller has asked us not to.
-                */
-               xfs_trans_unlocked_item(ip->i_itemp->ili_item.li_ailp,
-                                       (xfs_log_item_t*)(ip->i_itemp));
-       }
        trace_xfs_iunlock(ip, lock_flags, _RET_IP_);
 }
 
index b210224..bc46c0a 100644 (file)
@@ -1656,14 +1656,13 @@ retry:
                        iip = ip->i_itemp;
                        if (!iip || xfs_inode_clean(ip)) {
                                ASSERT(ip != free_ip);
-                               ip->i_update_core = 0;
                                xfs_ifunlock(ip);
                                xfs_iunlock(ip, XFS_ILOCK_EXCL);
                                continue;
                        }
 
-                       iip->ili_last_fields = iip->ili_format.ilf_fields;
-                       iip->ili_format.ilf_fields = 0;
+                       iip->ili_last_fields = iip->ili_fields;
+                       iip->ili_fields = 0;
                        iip->ili_logged = 1;
                        xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
                                                &iip->ili_item.li_lsn);
@@ -2177,7 +2176,7 @@ xfs_iflush_fork(
        mp = ip->i_mount;
        switch (XFS_IFORK_FORMAT(ip, whichfork)) {
        case XFS_DINODE_FMT_LOCAL:
-               if ((iip->ili_format.ilf_fields & dataflag[whichfork]) &&
+               if ((iip->ili_fields & dataflag[whichfork]) &&
                    (ifp->if_bytes > 0)) {
                        ASSERT(ifp->if_u1.if_data != NULL);
                        ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
@@ -2187,8 +2186,8 @@ xfs_iflush_fork(
 
        case XFS_DINODE_FMT_EXTENTS:
                ASSERT((ifp->if_flags & XFS_IFEXTENTS) ||
-                      !(iip->ili_format.ilf_fields & extflag[whichfork]));
-               if ((iip->ili_format.ilf_fields & extflag[whichfork]) &&
+                      !(iip->ili_fields & extflag[whichfork]));
+               if ((iip->ili_fields & extflag[whichfork]) &&
                    (ifp->if_bytes > 0)) {
                        ASSERT(xfs_iext_get_ext(ifp, 0));
                        ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
@@ -2198,7 +2197,7 @@ xfs_iflush_fork(
                break;
 
        case XFS_DINODE_FMT_BTREE:
-               if ((iip->ili_format.ilf_fields & brootflag[whichfork]) &&
+               if ((iip->ili_fields & brootflag[whichfork]) &&
                    (ifp->if_broot_bytes > 0)) {
                        ASSERT(ifp->if_broot != NULL);
                        ASSERT(ifp->if_broot_bytes <=
@@ -2211,14 +2210,14 @@ xfs_iflush_fork(
                break;
 
        case XFS_DINODE_FMT_DEV:
-               if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) {
+               if (iip->ili_fields & XFS_ILOG_DEV) {
                        ASSERT(whichfork == XFS_DATA_FORK);
                        xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev);
                }
                break;
 
        case XFS_DINODE_FMT_UUID:
-               if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) {
+               if (iip->ili_fields & XFS_ILOG_UUID) {
                        ASSERT(whichfork == XFS_DATA_FORK);
                        memcpy(XFS_DFORK_DPTR(dip),
                               &ip->i_df.if_u2.if_uuid,
@@ -2451,9 +2450,8 @@ xfs_iflush(
         * to disk, because the log record didn't make it to disk!
         */
        if (XFS_FORCED_SHUTDOWN(mp)) {
-               ip->i_update_core = 0;
                if (iip)
-                       iip->ili_format.ilf_fields = 0;
+                       iip->ili_fields = 0;
                xfs_ifunlock(ip);
                return XFS_ERROR(EIO);
        }
@@ -2533,26 +2531,6 @@ xfs_iflush_int(
        /* set *dip = inode's place in the buffer */
        dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
 
-       /*
-        * Clear i_update_core before copying out the data.
-        * This is for coordination with our timestamp updates
-        * that don't hold the inode lock. They will always
-        * update the timestamps BEFORE setting i_update_core,
-        * so if we clear i_update_core after they set it we
-        * are guaranteed to see their updates to the timestamps.
-        * I believe that this depends on strongly ordered memory
-        * semantics, but we have that.  We use the SYNCHRONIZE
-        * macro to make sure that the compiler does not reorder
-        * the i_update_core access below the data copy below.
-        */
-       ip->i_update_core = 0;
-       SYNCHRONIZE();
-
-       /*
-        * Make sure to get the latest timestamps from the Linux inode.
-        */
-       xfs_synchronize_times(ip);
-
        if (XFS_TEST_ERROR(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC),
                               mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {
                xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
@@ -2663,36 +2641,33 @@ xfs_iflush_int(
        xfs_inobp_check(mp, bp);
 
        /*
-        * We've recorded everything logged in the inode, so we'd
-        * like to clear the ilf_fields bits so we don't log and
-        * flush things unnecessarily.  However, we can't stop
-        * logging all this information until the data we've copied
-        * into the disk buffer is written to disk.  If we did we might
-        * overwrite the copy of the inode in the log with all the
-        * data after re-logging only part of it, and in the face of
-        * a crash we wouldn't have all the data we need to recover.
+        * We've recorded everything logged in the inode, so we'd like to clear
+        * the ili_fields bits so we don't log and flush things unnecessarily.
+        * However, we can't stop logging all this information until the data
+        * we've copied into the disk buffer is written to disk.  If we did we
+        * might overwrite the copy of the inode in the log with all the data
+        * after re-logging only part of it, and in the face of a crash we
+        * wouldn't have all the data we need to recover.
         *
-        * What we do is move the bits to the ili_last_fields field.
-        * When logging the inode, these bits are moved back to the
-        * ilf_fields field.  In the xfs_iflush_done() routine we
-        * clear ili_last_fields, since we know that the information
-        * those bits represent is permanently on disk.  As long as
-        * the flush completes before the inode is logged again, then
-        * both ilf_fields and ili_last_fields will be cleared.
+        * What we do is move the bits to the ili_last_fields field.  When
+        * logging the inode, these bits are moved back to the ili_fields field.
+        * In the xfs_iflush_done() routine we clear ili_last_fields, since we
+        * know that the information those bits represent is permanently on
+        * disk.  As long as the flush completes before the inode is logged
+        * again, then both ili_fields and ili_last_fields will be cleared.
         *
-        * We can play with the ilf_fields bits here, because the inode
-        * lock must be held exclusively in order to set bits there
-        * and the flush lock protects the ili_last_fields bits.
-        * Set ili_logged so the flush done
-        * routine can tell whether or not to look in the AIL.
-        * Also, store the current LSN of the inode so that we can tell
-        * whether the item has moved in the AIL from xfs_iflush_done().
-        * In order to read the lsn we need the AIL lock, because
-        * it is a 64 bit value that cannot be read atomically.
+        * We can play with the ili_fields bits here, because the inode lock
+        * must be held exclusively in order to set bits there and the flush
+        * lock protects the ili_last_fields bits.  Set ili_logged so the flush
+        * done routine can tell whether or not to look in the AIL.  Also, store
+        * the current LSN of the inode so that we can tell whether the item has
+        * moved in the AIL from xfs_iflush_done().  In order to read the lsn we
+        * need the AIL lock, because it is a 64 bit value that cannot be read
+        * atomically.
         */
-       if (iip != NULL && iip->ili_format.ilf_fields != 0) {
-               iip->ili_last_fields = iip->ili_format.ilf_fields;
-               iip->ili_format.ilf_fields = 0;
+       if (iip != NULL && iip->ili_fields != 0) {
+               iip->ili_last_fields = iip->ili_fields;
+               iip->ili_fields = 0;
                iip->ili_logged = 1;
 
                xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
@@ -2711,8 +2686,7 @@ xfs_iflush_int(
        } else {
                /*
                 * We're flushing an inode which is not in the AIL and has
-                * not been logged but has i_update_core set.  For this
-                * case we can use a B_DELWRI flush and immediately drop
+                * not been logged.  For this case we can immediately drop
                 * the inode flush lock because we can avoid the whole
                 * AIL state thing.  It's OK to drop the flush lock now,
                 * because we've already locked the buffer and to do anything
index 2f27b74..7fee338 100644 (file)
@@ -241,7 +241,6 @@ typedef struct xfs_inode {
        spinlock_t              i_flags_lock;   /* inode i_flags lock */
        /* Miscellaneous state. */
        unsigned long           i_flags;        /* see defined flags below */
-       unsigned char           i_update_core;  /* timestamps/size is dirty */
        unsigned int            i_delayed_blks; /* count of delay alloc blks */
 
        xfs_icdinode_t          i_d;            /* most of ondisk inode */
@@ -275,6 +274,20 @@ static inline xfs_fsize_t XFS_ISIZE(struct xfs_inode *ip)
 }
 
 /*
+ * If this I/O goes past the on-disk inode size update it unless it would
+ * be past the current in-core inode size.
+ */
+static inline xfs_fsize_t
+xfs_new_eof(struct xfs_inode *ip, xfs_fsize_t new_size)
+{
+       xfs_fsize_t i_size = i_size_read(VFS_I(ip));
+
+       if (new_size > i_size)
+               new_size = i_size;
+       return new_size > ip->i_d.di_size ? new_size : 0;
+}
+
+/*
  * i_flags helper functions
  */
 static inline void
@@ -374,10 +387,11 @@ xfs_set_projid(struct xfs_inode *ip,
 #define XFS_IFLOCK             (1 << __XFS_IFLOCK_BIT)
 #define __XFS_IPINNED_BIT      8        /* wakeup key for zero pin count */
 #define XFS_IPINNED            (1 << __XFS_IPINNED_BIT)
+#define XFS_IDONTCACHE         (1 << 9) /* don't cache the inode long term */
 
 /*
  * Per-lifetime flags need to be reset when re-using a reclaimable inode during
- * inode lookup. Thi prevents unintended behaviour on the new inode from
+ * inode lookup. This prevents unintended behaviour on the new inode from
  * ocurring.
  */
 #define XFS_IRECLAIM_RESET_FLAGS       \
@@ -422,7 +436,6 @@ static inline int xfs_isiflocked(struct xfs_inode *ip)
 #define        XFS_IOLOCK_SHARED       (1<<1)
 #define        XFS_ILOCK_EXCL          (1<<2)
 #define        XFS_ILOCK_SHARED        (1<<3)
-#define        XFS_IUNLOCK_NONOTIFY    (1<<4)
 
 #define XFS_LOCK_MASK          (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED \
                                | XFS_ILOCK_EXCL | XFS_ILOCK_SHARED)
@@ -431,8 +444,7 @@ static inline int xfs_isiflocked(struct xfs_inode *ip)
        { XFS_IOLOCK_EXCL,      "IOLOCK_EXCL" }, \
        { XFS_IOLOCK_SHARED,    "IOLOCK_SHARED" }, \
        { XFS_ILOCK_EXCL,       "ILOCK_EXCL" }, \
-       { XFS_ILOCK_SHARED,     "ILOCK_SHARED" }, \
-       { XFS_IUNLOCK_NONOTIFY, "IUNLOCK_NONOTIFY" }
+       { XFS_ILOCK_SHARED,     "ILOCK_SHARED" }
 
 
 /*
@@ -522,10 +534,6 @@ void               xfs_promote_inode(struct xfs_inode *);
 void           xfs_lock_inodes(xfs_inode_t **, int, uint);
 void           xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
 
-void           xfs_synchronize_times(xfs_inode_t *);
-void           xfs_mark_inode_dirty(xfs_inode_t *);
-void           xfs_mark_inode_dirty_sync(xfs_inode_t *);
-
 #define IHOLD(ip) \
 do { \
        ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \
@@ -546,6 +554,7 @@ do { \
  */
 #define XFS_IGET_CREATE                0x1
 #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 **,
index 91d71dc..05d924e 100644 (file)
@@ -57,77 +57,28 @@ xfs_inode_item_size(
        struct xfs_inode        *ip = iip->ili_inode;
        uint                    nvecs = 2;
 
-       /*
-        * Only log the data/extents/b-tree root if there is something
-        * left to log.
-        */
-       iip->ili_format.ilf_fields |= XFS_ILOG_CORE;
-
        switch (ip->i_d.di_format) {
        case XFS_DINODE_FMT_EXTENTS:
-               iip->ili_format.ilf_fields &=
-                       ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
-                         XFS_ILOG_DEV | XFS_ILOG_UUID);
-               if ((iip->ili_format.ilf_fields & XFS_ILOG_DEXT) &&
-                   (ip->i_d.di_nextents > 0) &&
-                   (ip->i_df.if_bytes > 0)) {
-                       ASSERT(ip->i_df.if_u1.if_extents != NULL);
+               if ((iip->ili_fields & XFS_ILOG_DEXT) &&
+                   ip->i_d.di_nextents > 0 &&
+                   ip->i_df.if_bytes > 0)
                        nvecs++;
-               } else {
-                       iip->ili_format.ilf_fields &= ~XFS_ILOG_DEXT;
-               }
                break;
 
        case XFS_DINODE_FMT_BTREE:
-               iip->ili_format.ilf_fields &=
-                       ~(XFS_ILOG_DDATA | XFS_ILOG_DEXT |
-                         XFS_ILOG_DEV | XFS_ILOG_UUID);
-               if ((iip->ili_format.ilf_fields & XFS_ILOG_DBROOT) &&
-                   (ip->i_df.if_broot_bytes > 0)) {
-                       ASSERT(ip->i_df.if_broot != NULL);
+               if ((iip->ili_fields & XFS_ILOG_DBROOT) &&
+                   ip->i_df.if_broot_bytes > 0)
                        nvecs++;
-               } else {
-                       ASSERT(!(iip->ili_format.ilf_fields &
-                                XFS_ILOG_DBROOT));
-#ifdef XFS_TRANS_DEBUG
-                       if (iip->ili_root_size > 0) {
-                               ASSERT(iip->ili_root_size ==
-                                      ip->i_df.if_broot_bytes);
-                               ASSERT(memcmp(iip->ili_orig_root,
-                                           ip->i_df.if_broot,
-                                           iip->ili_root_size) == 0);
-                       } else {
-                               ASSERT(ip->i_df.if_broot_bytes == 0);
-                       }
-#endif
-                       iip->ili_format.ilf_fields &= ~XFS_ILOG_DBROOT;
-               }
                break;
 
        case XFS_DINODE_FMT_LOCAL:
-               iip->ili_format.ilf_fields &=
-                       ~(XFS_ILOG_DEXT | XFS_ILOG_DBROOT |
-                         XFS_ILOG_DEV | XFS_ILOG_UUID);
-               if ((iip->ili_format.ilf_fields & XFS_ILOG_DDATA) &&
-                   (ip->i_df.if_bytes > 0)) {
-                       ASSERT(ip->i_df.if_u1.if_data != NULL);
-                       ASSERT(ip->i_d.di_size > 0);
+               if ((iip->ili_fields & XFS_ILOG_DDATA) &&
+                   ip->i_df.if_bytes > 0)
                        nvecs++;
-               } else {
-                       iip->ili_format.ilf_fields &= ~XFS_ILOG_DDATA;
-               }
                break;
 
        case XFS_DINODE_FMT_DEV:
-               iip->ili_format.ilf_fields &=
-                       ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
-                         XFS_ILOG_DEXT | XFS_ILOG_UUID);
-               break;
-
        case XFS_DINODE_FMT_UUID:
-               iip->ili_format.ilf_fields &=
-                       ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
-                         XFS_ILOG_DEXT | XFS_ILOG_DEV);
                break;
 
        default:
@@ -135,56 +86,31 @@ xfs_inode_item_size(
                break;
        }
 
-       /*
-        * If there are no attributes associated with this file,
-        * then there cannot be anything more to log.
-        * Clear all attribute-related log flags.
-        */
-       if (!XFS_IFORK_Q(ip)) {
-               iip->ili_format.ilf_fields &=
-                       ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT);
+       if (!XFS_IFORK_Q(ip))
                return nvecs;
-       }
+
 
        /*
         * Log any necessary attribute data.
         */
        switch (ip->i_d.di_aformat) {
        case XFS_DINODE_FMT_EXTENTS:
-               iip->ili_format.ilf_fields &=
-                       ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT);
-               if ((iip->ili_format.ilf_fields & XFS_ILOG_AEXT) &&
-                   (ip->i_d.di_anextents > 0) &&
-                   (ip->i_afp->if_bytes > 0)) {
-                       ASSERT(ip->i_afp->if_u1.if_extents != NULL);
+               if ((iip->ili_fields & XFS_ILOG_AEXT) &&
+                   ip->i_d.di_anextents > 0 &&
+                   ip->i_afp->if_bytes > 0)
                        nvecs++;
-               } else {
-                       iip->ili_format.ilf_fields &= ~XFS_ILOG_AEXT;
-               }
                break;
 
        case XFS_DINODE_FMT_BTREE:
-               iip->ili_format.ilf_fields &=
-                       ~(XFS_ILOG_ADATA | XFS_ILOG_AEXT);
-               if ((iip->ili_format.ilf_fields & XFS_ILOG_ABROOT) &&
-                   (ip->i_afp->if_broot_bytes > 0)) {
-                       ASSERT(ip->i_afp->if_broot != NULL);
+               if ((iip->ili_fields & XFS_ILOG_ABROOT) &&
+                   ip->i_afp->if_broot_bytes > 0)
                        nvecs++;
-               } else {
-                       iip->ili_format.ilf_fields &= ~XFS_ILOG_ABROOT;
-               }
                break;
 
        case XFS_DINODE_FMT_LOCAL:
-               iip->ili_format.ilf_fields &=
-                       ~(XFS_ILOG_AEXT | XFS_ILOG_ABROOT);
-               if ((iip->ili_format.ilf_fields & XFS_ILOG_ADATA) &&
-                   (ip->i_afp->if_bytes > 0)) {
-                       ASSERT(ip->i_afp->if_u1.if_data != NULL);
+               if ((iip->ili_fields & XFS_ILOG_ADATA) &&
+                   ip->i_afp->if_bytes > 0)
                        nvecs++;
-               } else {
-                       iip->ili_format.ilf_fields &= ~XFS_ILOG_ADATA;
-               }
                break;
 
        default:
@@ -254,48 +180,11 @@ xfs_inode_item_format(
        vecp++;
        nvecs        = 1;
 
-       /*
-        * Clear i_update_core if the timestamps (or any other
-        * non-transactional modification) need flushing/logging
-        * and we're about to log them with the rest of the core.
-        *
-        * This is the same logic as xfs_iflush() but this code can't
-        * run at the same time as xfs_iflush because we're in commit
-        * processing here and so we have the inode lock held in
-        * exclusive mode.  Although it doesn't really matter
-        * for the timestamps if both routines were to grab the
-        * timestamps or not.  That would be ok.
-        *
-        * We clear i_update_core before copying out the data.
-        * This is for coordination with our timestamp updates
-        * that don't hold the inode lock. They will always
-        * update the timestamps BEFORE setting i_update_core,
-        * so if we clear i_update_core after they set it we
-        * are guaranteed to see their updates to the timestamps
-        * either here.  Likewise, if they set it after we clear it
-        * here, we'll see it either on the next commit of this
-        * inode or the next time the inode gets flushed via
-        * xfs_iflush().  This depends on strongly ordered memory
-        * semantics, but we have that.  We use the SYNCHRONIZE
-        * macro to make sure that the compiler does not reorder
-        * the i_update_core access below the data copy below.
-        */
-       if (ip->i_update_core)  {
-               ip->i_update_core = 0;
-               SYNCHRONIZE();
-       }
-
-       /*
-        * Make sure to get the latest timestamps from the Linux inode.
-        */
-       xfs_synchronize_times(ip);
-
        vecp->i_addr = &ip->i_d;
        vecp->i_len  = sizeof(struct xfs_icdinode);
        vecp->i_type = XLOG_REG_TYPE_ICORE;
        vecp++;
        nvecs++;
-       iip->ili_format.ilf_fields |= XFS_ILOG_CORE;
 
        /*
         * If this is really an old format inode, then we need to
@@ -328,16 +217,17 @@ xfs_inode_item_format(
 
        switch (ip->i_d.di_format) {
        case XFS_DINODE_FMT_EXTENTS:
-               ASSERT(!(iip->ili_format.ilf_fields &
-                        (XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
-                         XFS_ILOG_DEV | XFS_ILOG_UUID)));
-               if (iip->ili_format.ilf_fields & XFS_ILOG_DEXT) {
-                       ASSERT(ip->i_df.if_bytes > 0);
+               iip->ili_fields &=
+                       ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
+                         XFS_ILOG_DEV | XFS_ILOG_UUID);
+
+               if ((iip->ili_fields & XFS_ILOG_DEXT) &&
+                   ip->i_d.di_nextents > 0 &&
+                   ip->i_df.if_bytes > 0) {
                        ASSERT(ip->i_df.if_u1.if_extents != NULL);
-                       ASSERT(ip->i_d.di_nextents > 0);
+                       ASSERT(ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) > 0);
                        ASSERT(iip->ili_extents_buf == NULL);
-                       ASSERT((ip->i_df.if_bytes /
-                               (uint)sizeof(xfs_bmbt_rec_t)) > 0);
+
 #ifdef XFS_NATIVE_HOST
                        if (ip->i_d.di_nextents == ip->i_df.if_bytes /
                                                (uint)sizeof(xfs_bmbt_rec_t)) {
@@ -359,15 +249,18 @@ xfs_inode_item_format(
                        iip->ili_format.ilf_dsize = vecp->i_len;
                        vecp++;
                        nvecs++;
+               } else {
+                       iip->ili_fields &= ~XFS_ILOG_DEXT;
                }
                break;
 
        case XFS_DINODE_FMT_BTREE:
-               ASSERT(!(iip->ili_format.ilf_fields &
-                        (XFS_ILOG_DDATA | XFS_ILOG_DEXT |
-                         XFS_ILOG_DEV | XFS_ILOG_UUID)));
-               if (iip->ili_format.ilf_fields & XFS_ILOG_DBROOT) {
-                       ASSERT(ip->i_df.if_broot_bytes > 0);
+               iip->ili_fields &=
+                       ~(XFS_ILOG_DDATA | XFS_ILOG_DEXT |
+                         XFS_ILOG_DEV | XFS_ILOG_UUID);
+
+               if ((iip->ili_fields & XFS_ILOG_DBROOT) &&
+                   ip->i_df.if_broot_bytes > 0) {
                        ASSERT(ip->i_df.if_broot != NULL);
                        vecp->i_addr = ip->i_df.if_broot;
                        vecp->i_len = ip->i_df.if_broot_bytes;
@@ -375,15 +268,30 @@ xfs_inode_item_format(
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_dsize = ip->i_df.if_broot_bytes;
+               } else {
+                       ASSERT(!(iip->ili_fields &
+                                XFS_ILOG_DBROOT));
+#ifdef XFS_TRANS_DEBUG
+                       if (iip->ili_root_size > 0) {
+                               ASSERT(iip->ili_root_size ==
+                                      ip->i_df.if_broot_bytes);
+                               ASSERT(memcmp(iip->ili_orig_root,
+                                           ip->i_df.if_broot,
+                                           iip->ili_root_size) == 0);
+                       } else {
+                               ASSERT(ip->i_df.if_broot_bytes == 0);
+                       }
+#endif
+                       iip->ili_fields &= ~XFS_ILOG_DBROOT;
                }
                break;
 
        case XFS_DINODE_FMT_LOCAL:
-               ASSERT(!(iip->ili_format.ilf_fields &
-                        (XFS_ILOG_DBROOT | XFS_ILOG_DEXT |
-                         XFS_ILOG_DEV | XFS_ILOG_UUID)));
-               if (iip->ili_format.ilf_fields & XFS_ILOG_DDATA) {
-                       ASSERT(ip->i_df.if_bytes > 0);
+               iip->ili_fields &=
+                       ~(XFS_ILOG_DEXT | XFS_ILOG_DBROOT |
+                         XFS_ILOG_DEV | XFS_ILOG_UUID);
+               if ((iip->ili_fields & XFS_ILOG_DDATA) &&
+                   ip->i_df.if_bytes > 0) {
                        ASSERT(ip->i_df.if_u1.if_data != NULL);
                        ASSERT(ip->i_d.di_size > 0);
 
@@ -401,24 +309,26 @@ xfs_inode_item_format(
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_dsize = (unsigned)data_bytes;
+               } else {
+                       iip->ili_fields &= ~XFS_ILOG_DDATA;
                }
                break;
 
        case XFS_DINODE_FMT_DEV:
-               ASSERT(!(iip->ili_format.ilf_fields &
-                        (XFS_ILOG_DBROOT | XFS_ILOG_DEXT |
-                         XFS_ILOG_DDATA | XFS_ILOG_UUID)));
-               if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) {
+               iip->ili_fields &=
+                       ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
+                         XFS_ILOG_DEXT | XFS_ILOG_UUID);
+               if (iip->ili_fields & XFS_ILOG_DEV) {
                        iip->ili_format.ilf_u.ilfu_rdev =
                                ip->i_df.if_u2.if_rdev;
                }
                break;
 
        case XFS_DINODE_FMT_UUID:
-               ASSERT(!(iip->ili_format.ilf_fields &
-                        (XFS_ILOG_DBROOT | XFS_ILOG_DEXT |
-                         XFS_ILOG_DDATA | XFS_ILOG_DEV)));
-               if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) {
+               iip->ili_fields &=
+                       ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT |
+                         XFS_ILOG_DEXT | XFS_ILOG_DEV);
+               if (iip->ili_fields & XFS_ILOG_UUID) {
                        iip->ili_format.ilf_u.ilfu_uuid =
                                ip->i_df.if_u2.if_uuid;
                }
@@ -430,31 +340,25 @@ xfs_inode_item_format(
        }
 
        /*
-        * If there are no attributes associated with the file,
-        * then we're done.
-        * Assert that no attribute-related log flags are set.
+        * If there are no attributes associated with the file, then we're done.
         */
        if (!XFS_IFORK_Q(ip)) {
-               iip->ili_format.ilf_size = nvecs;
-               ASSERT(!(iip->ili_format.ilf_fields &
-                        (XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT)));
-               return;
+               iip->ili_fields &=
+                       ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT);
+               goto out;
        }
 
        switch (ip->i_d.di_aformat) {
        case XFS_DINODE_FMT_EXTENTS:
-               ASSERT(!(iip->ili_format.ilf_fields &
-                        (XFS_ILOG_ADATA | XFS_ILOG_ABROOT)));
-               if (iip->ili_format.ilf_fields & XFS_ILOG_AEXT) {
-#ifdef DEBUG
-                       int nrecs = ip->i_afp->if_bytes /
-                               (uint)sizeof(xfs_bmbt_rec_t);
-                       ASSERT(nrecs > 0);
-                       ASSERT(nrecs == ip->i_d.di_anextents);
-                       ASSERT(ip->i_afp->if_bytes > 0);
+               iip->ili_fields &=
+                       ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT);
+
+               if ((iip->ili_fields & XFS_ILOG_AEXT) &&
+                   ip->i_d.di_anextents > 0 &&
+                   ip->i_afp->if_bytes > 0) {
+                       ASSERT(ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) ==
+                               ip->i_d.di_anextents);
                        ASSERT(ip->i_afp->if_u1.if_extents != NULL);
-                       ASSERT(ip->i_d.di_anextents > 0);
-#endif
 #ifdef XFS_NATIVE_HOST
                        /*
                         * There are not delayed allocation extents
@@ -471,29 +375,36 @@ xfs_inode_item_format(
                        iip->ili_format.ilf_asize = vecp->i_len;
                        vecp++;
                        nvecs++;
+               } else {
+                       iip->ili_fields &= ~XFS_ILOG_AEXT;
                }
                break;
 
        case XFS_DINODE_FMT_BTREE:
-               ASSERT(!(iip->ili_format.ilf_fields &
-                        (XFS_ILOG_ADATA | XFS_ILOG_AEXT)));
-               if (iip->ili_format.ilf_fields & XFS_ILOG_ABROOT) {
-                       ASSERT(ip->i_afp->if_broot_bytes > 0);
+               iip->ili_fields &=
+                       ~(XFS_ILOG_ADATA | XFS_ILOG_AEXT);
+
+               if ((iip->ili_fields & XFS_ILOG_ABROOT) &&
+                   ip->i_afp->if_broot_bytes > 0) {
                        ASSERT(ip->i_afp->if_broot != NULL);
+
                        vecp->i_addr = ip->i_afp->if_broot;
                        vecp->i_len = ip->i_afp->if_broot_bytes;
                        vecp->i_type = XLOG_REG_TYPE_IATTR_BROOT;
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_asize = ip->i_afp->if_broot_bytes;
+               } else {
+                       iip->ili_fields &= ~XFS_ILOG_ABROOT;
                }
                break;
 
        case XFS_DINODE_FMT_LOCAL:
-               ASSERT(!(iip->ili_format.ilf_fields &
-                        (XFS_ILOG_ABROOT | XFS_ILOG_AEXT)));
-               if (iip->ili_format.ilf_fields & XFS_ILOG_ADATA) {
-                       ASSERT(ip->i_afp->if_bytes > 0);
+               iip->ili_fields &=
+                       ~(XFS_ILOG_AEXT | XFS_ILOG_ABROOT);
+
+               if ((iip->ili_fields & XFS_ILOG_ADATA) &&
+                   ip->i_afp->if_bytes > 0) {
                        ASSERT(ip->i_afp->if_u1.if_data != NULL);
 
                        vecp->i_addr = ip->i_afp->if_u1.if_data;
@@ -510,6 +421,8 @@ xfs_inode_item_format(
                        vecp++;
                        nvecs++;
                        iip->ili_format.ilf_asize = (unsigned)data_bytes;
+               } else {
+                       iip->ili_fields &= ~XFS_ILOG_ADATA;
                }
                break;
 
@@ -518,6 +431,15 @@ xfs_inode_item_format(
                break;
        }
 
+out:
+       /*
+        * Now update the log format that goes out to disk from the in-core
+        * values.  We always write the inode core to make the arithmetic
+        * games in recovery easier, which isn't a big deal as just about any
+        * transaction would dirty it anyway.
+        */
+       iip->ili_format.ilf_fields = XFS_ILOG_CORE |
+               (iip->ili_fields & ~XFS_ILOG_TIMESTAMP);
        iip->ili_format.ilf_size = nvecs;
 }
 
@@ -596,17 +518,13 @@ xfs_inode_item_trylock(
        /* Stale items should force out the iclog */
        if (ip->i_flags & XFS_ISTALE) {
                xfs_ifunlock(ip);
-               /*
-                * we hold the AIL lock - notify the unlock routine of this
-                * so it doesn't try to get the lock again.
-                */
-               xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY);
+               xfs_iunlock(ip, XFS_ILOCK_SHARED);
                return XFS_ITEM_PINNED;
        }
 
 #ifdef DEBUG
        if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-               ASSERT(iip->ili_format.ilf_fields != 0);
+               ASSERT(iip->ili_fields != 0);
                ASSERT(iip->ili_logged == 0);
                ASSERT(lip->li_flags & XFS_LI_IN_AIL);
        }
@@ -638,7 +556,7 @@ xfs_inode_item_unlock(
        if (iip->ili_extents_buf != NULL) {
                ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS);
                ASSERT(ip->i_d.di_nextents > 0);
-               ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_DEXT);
+               ASSERT(iip->ili_fields & XFS_ILOG_DEXT);
                ASSERT(ip->i_df.if_bytes > 0);
                kmem_free(iip->ili_extents_buf);
                iip->ili_extents_buf = NULL;
@@ -646,7 +564,7 @@ xfs_inode_item_unlock(
        if (iip->ili_aextents_buf != NULL) {
                ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS);
                ASSERT(ip->i_d.di_anextents > 0);
-               ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_AEXT);
+               ASSERT(iip->ili_fields & XFS_ILOG_AEXT);
                ASSERT(ip->i_afp->if_bytes > 0);
                kmem_free(iip->ili_aextents_buf);
                iip->ili_aextents_buf = NULL;
@@ -761,8 +679,7 @@ xfs_inode_item_push(
         * lock without sleeping, then there must not have been
         * anyone in the process of flushing the inode.
         */
-       ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) ||
-              iip->ili_format.ilf_fields != 0);
+       ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || iip->ili_fields != 0);
 
        /*
         * Push the inode to it's backing buffer. This will not remove the
@@ -985,7 +902,7 @@ xfs_iflush_abort(
                 * Clear the inode logging fields so no more flushes are
                 * attempted.
                 */
-               iip->ili_format.ilf_fields = 0;
+               iip->ili_fields = 0;
        }
        /*
         * Release the inode's flush lock since we're done with it.
index d3dee61..41d61c3 100644 (file)
@@ -86,6 +86,15 @@ typedef struct xfs_inode_log_format_64 {
 #define        XFS_ILOG_AEXT   0x080   /* log i_af.if_extents */
 #define        XFS_ILOG_ABROOT 0x100   /* log i_af.i_broot */
 
+
+/*
+ * The timestamps are dirty, but not necessarily anything else in the inode
+ * core.  Unlike the other fields above this one must never make it to disk
+ * in the ilf_fields of the inode_log_format, but is purely store in-memory in
+ * ili_fields in the inode_log_item.
+ */
+#define XFS_ILOG_TIMESTAMP     0x4000
+
 #define        XFS_ILOG_NONCORE        (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \
                                 XFS_ILOG_DBROOT | XFS_ILOG_DEV | \
                                 XFS_ILOG_UUID | XFS_ILOG_ADATA | \
@@ -101,7 +110,7 @@ typedef struct xfs_inode_log_format_64 {
                                 XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \
                                 XFS_ILOG_DEV | XFS_ILOG_UUID | \
                                 XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
-                                XFS_ILOG_ABROOT)
+                                XFS_ILOG_ABROOT | XFS_ILOG_TIMESTAMP)
 
 static inline int xfs_ilog_fbroot(int w)
 {
@@ -134,6 +143,7 @@ typedef struct xfs_inode_log_item {
        unsigned short          ili_lock_flags;    /* lock flags */
        unsigned short          ili_logged;        /* flushed logged data */
        unsigned int            ili_last_fields;   /* fields when flushed */
+       unsigned int            ili_fields;        /* fields to be logged */
        struct xfs_bmbt_rec     *ili_extents_buf;  /* array of logged
                                                      data exts */
        struct xfs_bmbt_rec     *ili_aextents_buf; /* array of logged
@@ -148,9 +158,7 @@ typedef struct xfs_inode_log_item {
 
 static inline int xfs_inode_clean(xfs_inode_t *ip)
 {
-       return (!ip->i_itemp ||
-               !(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL)) &&
-              !ip->i_update_core;
+       return !ip->i_itemp || !(ip->i_itemp->ili_fields & XFS_ILOG_ALL);
 }
 
 extern void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *);
index 76f3ca5..91f8ff5 100644 (file)
@@ -209,6 +209,7 @@ xfs_open_by_handle(
        struct file             *filp;
        struct inode            *inode;
        struct dentry           *dentry;
+       fmode_t                 fmode;
 
        if (!capable(CAP_SYS_ADMIN))
                return -XFS_ERROR(EPERM);
@@ -228,26 +229,21 @@ xfs_open_by_handle(
        hreq->oflags |= O_LARGEFILE;
 #endif
 
-       /* Put open permission in namei format. */
        permflag = hreq->oflags;
-       if ((permflag+1) & O_ACCMODE)
-               permflag++;
-       if (permflag & O_TRUNC)
-               permflag |= 2;
-
+       fmode = OPEN_FMODE(permflag);
        if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&
-           (permflag & FMODE_WRITE) && IS_APPEND(inode)) {
+           (fmode & FMODE_WRITE) && IS_APPEND(inode)) {
                error = -XFS_ERROR(EPERM);
                goto out_dput;
        }
 
-       if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
+       if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) {
                error = -XFS_ERROR(EACCES);
                goto out_dput;
        }
 
        /* Can't write directories. */
-       if (S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {
+       if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) {
                error = -XFS_ERROR(EISDIR);
                goto out_dput;
        }
@@ -450,9 +446,12 @@ xfs_attrmulti_attr_get(
 
        if (*len > XATTR_SIZE_MAX)
                return EINVAL;
-       kbuf = kmalloc(*len, GFP_KERNEL);
-       if (!kbuf)
-               return ENOMEM;
+       kbuf = kmem_zalloc(*len, KM_SLEEP | KM_MAYFAIL);
+       if (!kbuf) {
+               kbuf = kmem_zalloc_large(*len);
+               if (!kbuf)
+                       return ENOMEM;
+       }
 
        error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
        if (error)
@@ -462,7 +461,10 @@ xfs_attrmulti_attr_get(
                error = EFAULT;
 
  out_kfree:
-       kfree(kbuf);
+       if (is_vmalloc_addr(kbuf))
+               kmem_free_large(kbuf);
+       else
+               kmem_free(kbuf);
        return error;
 }
 
index f9ccb7b..a849a54 100644 (file)
@@ -293,7 +293,7 @@ xfs_compat_ioc_bulkstat(
                int res;
 
                error = xfs_bulkstat_one_compat(mp, inlast, bulkreq.ubuffer,
-                               sizeof(compat_xfs_bstat_t), 0, &res);
+                               sizeof(compat_xfs_bstat_t), NULL, &res);
        } else if (cmd == XFS_IOC_FSBULKSTAT_32) {
                error = xfs_bulkstat(mp, &inlast, &count,
                        xfs_bulkstat_one_compat, sizeof(compat_xfs_bstat_t),
index 246c7d5..71a4645 100644 (file)
@@ -31,6 +31,7 @@
 #include "xfs_ialloc_btree.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
+#include "xfs_inode_item.h"
 #include "xfs_btree.h"
 #include "xfs_bmap.h"
 #include "xfs_rtalloc.h"
@@ -645,6 +646,7 @@ xfs_iomap_write_unwritten(
        xfs_trans_t     *tp;
        xfs_bmbt_irec_t imap;
        xfs_bmap_free_t free_list;
+       xfs_fsize_t     i_size;
        uint            resblks;
        int             committed;
        int             error;
@@ -705,7 +707,22 @@ xfs_iomap_write_unwritten(
                if (error)
                        goto error_on_bmapi_transaction;
 
-               error = xfs_bmap_finish(&(tp), &(free_list), &committed);
+               /*
+                * Log the updated inode size as we go.  We have to be careful
+                * to only log it up to the actual write offset if it is
+                * halfway into a block.
+                */
+               i_size = XFS_FSB_TO_B(mp, offset_fsb + count_fsb);
+               if (i_size > offset + count)
+                       i_size = offset + count;
+
+               i_size = xfs_new_eof(ip, i_size);
+               if (i_size) {
+                       ip->i_d.di_size = i_size;
+                       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+               }
+
+               error = xfs_bmap_finish(&tp, &free_list, &committed);
                if (error)
                        goto error_on_bmapi_transaction;
 
index ab30253..3011b87 100644 (file)
 #include <linux/fiemap.h>
 #include <linux/slab.h>
 
-/*
- * Bring the timestamps in the XFS inode uptodate.
- *
- * Used before writing the inode to disk.
- */
-void
-xfs_synchronize_times(
-       xfs_inode_t     *ip)
-{
-       struct inode    *inode = VFS_I(ip);
-
-       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;
-}
-
-/*
- * If the linux inode is valid, mark it dirty, else mark the dirty state
- * in the XFS inode to make sure we pick it up when reclaiming the inode.
- */
-void
-xfs_mark_inode_dirty_sync(
-       xfs_inode_t     *ip)
-{
-       struct inode    *inode = VFS_I(ip);
-
-       if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
-               mark_inode_dirty_sync(inode);
-       else {
-               barrier();
-               ip->i_update_core = 1;
-       }
-}
-
-void
-xfs_mark_inode_dirty(
-       xfs_inode_t     *ip)
-{
-       struct inode    *inode = VFS_I(ip);
-
-       if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
-               mark_inode_dirty(inode);
-       else {
-               barrier();
-               ip->i_update_core = 1;
-       }
-
-}
-
-
-int xfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
-                  void *fs_info)
+static int
+xfs_initxattrs(
+       struct inode            *inode,
+       const struct xattr      *xattr_array,
+       void                    *fs_info)
 {
-       const struct xattr *xattr;
-       struct xfs_inode *ip = XFS_I(inode);
-       int error = 0;
+       const struct xattr      *xattr;
+       struct xfs_inode        *ip = XFS_I(inode);
+       int                     error = 0;
 
        for (xattr = xattr_array; xattr->name != NULL; xattr++) {
                error = xfs_attr_set(ip, xattr->name, xattr->value,
@@ -678,19 +628,16 @@ xfs_setattr_nonsize(
                inode->i_atime = iattr->ia_atime;
                ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec;
                ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec;
-               ip->i_update_core = 1;
        }
        if (mask & ATTR_CTIME) {
                inode->i_ctime = iattr->ia_ctime;
                ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
                ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
-               ip->i_update_core = 1;
        }
        if (mask & ATTR_MTIME) {
                inode->i_mtime = iattr->ia_mtime;
                ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
                ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
-               ip->i_update_core = 1;
        }
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
@@ -918,13 +865,11 @@ xfs_setattr_size(
                inode->i_ctime = iattr->ia_ctime;
                ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;
                ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec;
-               ip->i_update_core = 1;
        }
        if (mask & ATTR_MTIME) {
                inode->i_mtime = iattr->ia_mtime;
                ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec;
                ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec;
-               ip->i_update_core = 1;
        }
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
index 751e94f..acc2bf2 100644 (file)
@@ -62,7 +62,6 @@ xfs_bulkstat_one_int(
 {
        struct xfs_icdinode     *dic;           /* dinode core info pointer */
        struct xfs_inode        *ip;            /* incore inode pointer */
-       struct inode            *inode;
        struct xfs_bstat        *buf;           /* return buffer */
        int                     error = 0;      /* error value */
 
@@ -76,7 +75,8 @@ xfs_bulkstat_one_int(
                return XFS_ERROR(ENOMEM);
 
        error = xfs_iget(mp, NULL, ino,
-                        XFS_IGET_UNTRUSTED, XFS_ILOCK_SHARED, &ip);
+                        (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED),
+                        XFS_ILOCK_SHARED, &ip);
        if (error) {
                *stat = BULKSTAT_RV_NOTHING;
                goto out_free;
@@ -86,7 +86,6 @@ xfs_bulkstat_one_int(
        ASSERT(ip->i_imap.im_blkno != 0);
 
        dic = &ip->i_d;
-       inode = VFS_I(ip);
 
        /* xfs_iget returns the following without needing
         * further change.
@@ -99,19 +98,12 @@ xfs_bulkstat_one_int(
        buf->bs_uid = dic->di_uid;
        buf->bs_gid = dic->di_gid;
        buf->bs_size = dic->di_size;
-
-       /*
-        * We need to read the timestamps from the Linux inode because
-        * the VFS keeps writing directly into the inode structure instead
-        * of telling us about the updates.
-        */
-       buf->bs_atime.tv_sec = inode->i_atime.tv_sec;
-       buf->bs_atime.tv_nsec = inode->i_atime.tv_nsec;
-       buf->bs_mtime.tv_sec = inode->i_mtime.tv_sec;
-       buf->bs_mtime.tv_nsec = inode->i_mtime.tv_nsec;
-       buf->bs_ctime.tv_sec = inode->i_ctime.tv_sec;
-       buf->bs_ctime.tv_nsec = inode->i_ctime.tv_nsec;
-
+       buf->bs_atime.tv_sec = dic->di_atime.t_sec;
+       buf->bs_atime.tv_nsec = dic->di_atime.t_nsec;
+       buf->bs_mtime.tv_sec = dic->di_mtime.t_sec;
+       buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec;
+       buf->bs_ctime.tv_sec = dic->di_ctime.t_sec;
+       buf->bs_ctime.tv_nsec = dic->di_ctime.t_nsec;
        buf->bs_xflags = xfs_ip2xflags(ip);
        buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog;
        buf->bs_extents = dic->di_nextents;
index e2cc356..6db1fef 100644 (file)
@@ -67,15 +67,10 @@ STATIC void xlog_state_switch_iclogs(xlog_t         *log,
                                     int                eventual_size);
 STATIC void xlog_state_want_sync(xlog_t        *log, xlog_in_core_t *iclog);
 
-/* local functions to manipulate grant head */
-STATIC int  xlog_grant_log_space(xlog_t                *log,
-                                xlog_ticket_t  *xtic);
 STATIC void xlog_grant_push_ail(struct log     *log,
                                int             need_bytes);
 STATIC void xlog_regrant_reserve_log_space(xlog_t       *log,
                                           xlog_ticket_t *ticket);
-STATIC int xlog_regrant_write_log_space(xlog_t         *log,
-                                        xlog_ticket_t  *ticket);
 STATIC void xlog_ungrant_log_space(xlog_t       *log,
                                   xlog_ticket_t *ticket);
 
@@ -150,78 +145,93 @@ xlog_grant_add_space(
        } while (head_val != old);
 }
 
-STATIC bool
-xlog_reserveq_wake(
-       struct log              *log,
-       int                     *free_bytes)
+STATIC void
+xlog_grant_head_init(
+       struct xlog_grant_head  *head)
+{
+       xlog_assign_grant_head(&head->grant, 1, 0);
+       INIT_LIST_HEAD(&head->waiters);
+       spin_lock_init(&head->lock);
+}
+
+STATIC void
+xlog_grant_head_wake_all(
+       struct xlog_grant_head  *head)
 {
        struct xlog_ticket      *tic;
-       int                     need_bytes;
 
-       list_for_each_entry(tic, &log->l_reserveq, t_queue) {
+       spin_lock(&head->lock);
+       list_for_each_entry(tic, &head->waiters, t_queue)
+               wake_up_process(tic->t_task);
+       spin_unlock(&head->lock);
+}
+
+static inline int
+xlog_ticket_reservation(
+       struct log              *log,
+       struct xlog_grant_head  *head,
+       struct xlog_ticket      *tic)
+{
+       if (head == &log->l_write_head) {
+               ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV);
+               return tic->t_unit_res;
+       } else {
                if (tic->t_flags & XLOG_TIC_PERM_RESERV)
-                       need_bytes = tic->t_unit_res * tic->t_cnt;
+                       return tic->t_unit_res * tic->t_cnt;
                else
-                       need_bytes = tic->t_unit_res;
-
-               if (*free_bytes < need_bytes)
-                       return false;
-               *free_bytes -= need_bytes;
-
-               trace_xfs_log_grant_wake_up(log, tic);
-               wake_up(&tic->t_wait);
+                       return tic->t_unit_res;
        }
-
-       return true;
 }
 
 STATIC bool
-xlog_writeq_wake(
+xlog_grant_head_wake(
        struct log              *log,
+       struct xlog_grant_head  *head,
        int                     *free_bytes)
 {
        struct xlog_ticket      *tic;
        int                     need_bytes;
 
-       list_for_each_entry(tic, &log->l_writeq, t_queue) {
-               ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV);
-
-               need_bytes = tic->t_unit_res;
-
+       list_for_each_entry(tic, &head->waiters, t_queue) {
+               need_bytes = xlog_ticket_reservation(log, head, tic);
                if (*free_bytes < need_bytes)
                        return false;
-               *free_bytes -= need_bytes;
 
-               trace_xfs_log_regrant_write_wake_up(log, tic);
-               wake_up(&tic->t_wait);
+               *free_bytes -= need_bytes;
+               trace_xfs_log_grant_wake_up(log, tic);
+               wake_up_process(tic->t_task);
        }
 
        return true;
 }
 
 STATIC int
-xlog_reserveq_wait(
+xlog_grant_head_wait(
        struct log              *log,
+       struct xlog_grant_head  *head,
        struct xlog_ticket      *tic,
        int                     need_bytes)
 {
-       list_add_tail(&tic->t_queue, &log->l_reserveq);
+       list_add_tail(&tic->t_queue, &head->waiters);
 
        do {
                if (XLOG_FORCED_SHUTDOWN(log))
                        goto shutdown;
                xlog_grant_push_ail(log, need_bytes);
 
+               __set_current_state(TASK_UNINTERRUPTIBLE);
+               spin_unlock(&head->lock);
+
                XFS_STATS_INC(xs_sleep_logspace);
-               trace_xfs_log_grant_sleep(log, tic);
 
-               xlog_wait(&tic->t_wait, &log->l_grant_reserve_lock);
+               trace_xfs_log_grant_sleep(log, tic);
+               schedule();
                trace_xfs_log_grant_wake(log, tic);
 
-               spin_lock(&log->l_grant_reserve_lock);
+               spin_lock(&head->lock);
                if (XLOG_FORCED_SHUTDOWN(log))
                        goto shutdown;
-       } while (xlog_space_left(log, &log->l_grant_reserve_head) < need_bytes);
+       } while (xlog_space_left(log, &head->grant) < need_bytes);
 
        list_del_init(&tic->t_queue);
        return 0;
@@ -230,35 +240,58 @@ shutdown:
        return XFS_ERROR(EIO);
 }
 
+/*
+ * Atomically get the log space required for a log ticket.
+ *
+ * Once a ticket gets put onto head->waiters, it will only return after the
+ * needed reservation is satisfied.
+ *
+ * This function is structured so that it has a lock free fast path. This is
+ * necessary because every new transaction reservation will come through this
+ * path. Hence any lock will be globally hot if we take it unconditionally on
+ * every pass.
+ *
+ * As tickets are only ever moved on and off head->waiters under head->lock, we
+ * only need to take that lock if we are going to add the ticket to the queue
+ * and sleep. We can avoid taking the lock if the ticket was never added to
+ * head->waiters because the t_queue list head will be empty and we hold the
+ * only reference to it so it can safely be checked unlocked.
+ */
 STATIC int
-xlog_writeq_wait(
+xlog_grant_head_check(
        struct log              *log,
+       struct xlog_grant_head  *head,
        struct xlog_ticket      *tic,
-       int                     need_bytes)
+       int                     *need_bytes)
 {
-       list_add_tail(&tic->t_queue, &log->l_writeq);
-
-       do {
-               if (XLOG_FORCED_SHUTDOWN(log))
-                       goto shutdown;
-               xlog_grant_push_ail(log, need_bytes);
-
-               XFS_STATS_INC(xs_sleep_logspace);
-               trace_xfs_log_regrant_write_sleep(log, tic);
+       int                     free_bytes;
+       int                     error = 0;
 
-               xlog_wait(&tic->t_wait, &log->l_grant_write_lock);
-               trace_xfs_log_regrant_write_wake(log, tic);
+       ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));
 
-               spin_lock(&log->l_grant_write_lock);
-               if (XLOG_FORCED_SHUTDOWN(log))
-                       goto shutdown;
-       } while (xlog_space_left(log, &log->l_grant_write_head) < need_bytes);
+       /*
+        * If there are other waiters on the queue then give them a chance at
+        * logspace before us.  Wake up the first waiters, if we do not wake
+        * up all the waiters then go to sleep waiting for more free space,
+        * otherwise try to get some space for this transaction.
+        */
+       *need_bytes = xlog_ticket_reservation(log, head, tic);
+       free_bytes = xlog_space_left(log, &head->grant);
+       if (!list_empty_careful(&head->waiters)) {
+               spin_lock(&head->lock);
+               if (!xlog_grant_head_wake(log, head, &free_bytes) ||
+                   free_bytes < *need_bytes) {
+                       error = xlog_grant_head_wait(log, head, tic,
+                                                    *need_bytes);
+               }
+               spin_unlock(&head->lock);
+       } else if (free_bytes < *need_bytes) {
+               spin_lock(&head->lock);
+               error = xlog_grant_head_wait(log, head, tic, *need_bytes);
+               spin_unlock(&head->lock);
+       }
 
-       list_del_init(&tic->t_queue);
-       return 0;
-shutdown:
-       list_del_init(&tic->t_queue);
-       return XFS_ERROR(EIO);
+       return error;
 }
 
 static void
@@ -286,6 +319,128 @@ xlog_tic_add_region(xlog_ticket_t *tic, uint len, uint type)
 }
 
 /*
+ * Replenish the byte reservation required by moving the grant write head.
+ */
+int
+xfs_log_regrant(
+       struct xfs_mount        *mp,
+       struct xlog_ticket      *tic)
+{
+       struct log              *log = mp->m_log;
+       int                     need_bytes;
+       int                     error = 0;
+
+       if (XLOG_FORCED_SHUTDOWN(log))
+               return XFS_ERROR(EIO);
+
+       XFS_STATS_INC(xs_try_logspace);
+
+       /*
+        * This is a new transaction on the ticket, so we need to change the
+        * transaction ID so that the next transaction has a different TID in
+        * the log. Just add one to the existing tid so that we can see chains
+        * of rolling transactions in the log easily.
+        */
+       tic->t_tid++;
+
+       xlog_grant_push_ail(log, tic->t_unit_res);
+
+       tic->t_curr_res = tic->t_unit_res;
+       xlog_tic_reset_res(tic);
+
+       if (tic->t_cnt > 0)
+               return 0;
+
+       trace_xfs_log_regrant(log, tic);
+
+       error = xlog_grant_head_check(log, &log->l_write_head, tic,
+                                     &need_bytes);
+       if (error)
+               goto out_error;
+
+       xlog_grant_add_space(log, &log->l_write_head.grant, need_bytes);
+       trace_xfs_log_regrant_exit(log, tic);
+       xlog_verify_grant_tail(log);
+       return 0;
+
+out_error:
+       /*
+        * If we are failing, make sure the ticket doesn't have any current
+        * reservations.  We don't want to add this back when the ticket/
+        * transaction gets cancelled.
+        */
+       tic->t_curr_res = 0;
+       tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */
+       return error;
+}
+
+/*
+ * Reserve log space and return a ticket corresponding the reservation.
+ *
+ * Each reservation is going to reserve extra space for a log record header.
+ * When writes happen to the on-disk log, we don't subtract the length of the
+ * log record header from any reservation.  By wasting space in each
+ * reservation, we prevent over allocation problems.
+ */
+int
+xfs_log_reserve(
+       struct xfs_mount        *mp,
+       int                     unit_bytes,
+       int                     cnt,
+       struct xlog_ticket      **ticp,
+       __uint8_t               client,
+       bool                    permanent,
+       uint                    t_type)
+{
+       struct log              *log = mp->m_log;
+       struct xlog_ticket      *tic;
+       int                     need_bytes;
+       int                     error = 0;
+
+       ASSERT(client == XFS_TRANSACTION || client == XFS_LOG);
+
+       if (XLOG_FORCED_SHUTDOWN(log))
+               return XFS_ERROR(EIO);
+
+       XFS_STATS_INC(xs_try_logspace);
+
+       ASSERT(*ticp == NULL);
+       tic = xlog_ticket_alloc(log, unit_bytes, cnt, client, permanent,
+                               KM_SLEEP | KM_MAYFAIL);
+       if (!tic)
+               return XFS_ERROR(ENOMEM);
+
+       tic->t_trans_type = t_type;
+       *ticp = tic;
+
+       xlog_grant_push_ail(log, tic->t_unit_res * tic->t_cnt);
+
+       trace_xfs_log_reserve(log, tic);
+
+       error = xlog_grant_head_check(log, &log->l_reserve_head, tic,
+                                     &need_bytes);
+       if (error)
+               goto out_error;
+
+       xlog_grant_add_space(log, &log->l_reserve_head.grant, need_bytes);
+       xlog_grant_add_space(log, &log->l_write_head.grant, need_bytes);
+       trace_xfs_log_reserve_exit(log, tic);
+       xlog_verify_grant_tail(log);
+       return 0;
+
+out_error:
+       /*
+        * If we are failing, make sure the ticket doesn't have any current
+        * reservations.  We don't want to add this back when the ticket/
+        * transaction gets cancelled.
+        */
+       tic->t_curr_res = 0;
+       tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */
+       return error;
+}
+
+
+/*
  * NOTES:
  *
  *     1. currblock field gets updated at startup and after in-core logs
@@ -395,88 +550,6 @@ xfs_log_release_iclog(
 }
 
 /*
- *  1. Reserve an amount of on-disk log space and return a ticket corresponding
- *     to the reservation.
- *  2. Potentially, push buffers at tail of log to disk.
- *
- * Each reservation is going to reserve extra space for a log record header.
- * When writes happen to the on-disk log, we don't subtract the length of the
- * log record header from any reservation.  By wasting space in each
- * reservation, we prevent over allocation problems.
- */
-int
-xfs_log_reserve(
-       struct xfs_mount        *mp,
-       int                     unit_bytes,
-       int                     cnt,
-       struct xlog_ticket      **ticket,
-       __uint8_t               client,
-       uint                    flags,
-       uint                    t_type)
-{
-       struct log              *log = mp->m_log;
-       struct xlog_ticket      *internal_ticket;
-       int                     retval = 0;
-
-       ASSERT(client == XFS_TRANSACTION || client == XFS_LOG);
-
-       if (XLOG_FORCED_SHUTDOWN(log))
-               return XFS_ERROR(EIO);
-
-       XFS_STATS_INC(xs_try_logspace);
-
-
-       if (*ticket != NULL) {
-               ASSERT(flags & XFS_LOG_PERM_RESERV);
-               internal_ticket = *ticket;
-
-               /*
-                * this is a new transaction on the ticket, so we need to
-                * change the transaction ID so that the next transaction has a
-                * different TID in the log. Just add one to the existing tid
-                * so that we can see chains of rolling transactions in the log
-                * easily.
-                */
-               internal_ticket->t_tid++;
-
-               trace_xfs_log_reserve(log, internal_ticket);
-
-               xlog_grant_push_ail(log, internal_ticket->t_unit_res);
-               retval = xlog_regrant_write_log_space(log, internal_ticket);
-       } else {
-               /* may sleep if need to allocate more tickets */
-               internal_ticket = xlog_ticket_alloc(log, unit_bytes, cnt,
-                                                 client, flags,
-                                                 KM_SLEEP|KM_MAYFAIL);
-               if (!internal_ticket)
-                       return XFS_ERROR(ENOMEM);
-               internal_ticket->t_trans_type = t_type;
-               *ticket = internal_ticket;
-
-               trace_xfs_log_reserve(log, internal_ticket);
-
-               xlog_grant_push_ail(log,
-                                   (internal_ticket->t_unit_res *
-                                    internal_ticket->t_cnt));
-               retval = xlog_grant_log_space(log, internal_ticket);
-       }
-
-       if (unlikely(retval)) {
-               /*
-                * If we are failing, make sure the ticket doesn't have any
-                * current reservations.  We don't want to add this back
-                * when the ticket/ transaction gets cancelled.
-                */
-               internal_ticket->t_curr_res = 0;
-               /* ungrant will give back unit_res * t_cnt. */
-               internal_ticket->t_cnt = 0;
-       }
-
-       return retval;
-}
-
-
-/*
  * Mount a log filesystem
  *
  * mp          - ubiquitous xfs mount point structure
@@ -653,8 +726,9 @@ xfs_log_unmount_write(xfs_mount_t *mp)
                                .lv_iovecp = &reg,
                        };
 
-                       /* remove inited flag */
+                       /* remove inited flag, and account for space used */
                        tic->t_flags = 0;
+                       tic->t_curr_res -= sizeof(magic);
                        error = xlog_write(log, &vec, tic, &lsn,
                                           NULL, XLOG_UNMOUNT_TRANS);
                        /*
@@ -760,64 +834,35 @@ xfs_log_item_init(
        INIT_LIST_HEAD(&item->li_cil);
 }
 
+/*
+ * Wake up processes waiting for log space after we have moved the log tail.
+ */
 void
-xfs_log_move_tail(xfs_mount_t  *mp,
-                 xfs_lsn_t     tail_lsn)
+xfs_log_space_wake(
+       struct xfs_mount        *mp)
 {
-       xlog_ticket_t   *tic;
-       xlog_t          *log = mp->m_log;
-       int             need_bytes, free_bytes;
+       struct log              *log = mp->m_log;
+       int                     free_bytes;
 
        if (XLOG_FORCED_SHUTDOWN(log))
                return;
 
-       if (tail_lsn == 0)
-               tail_lsn = atomic64_read(&log->l_last_sync_lsn);
-
-       /* tail_lsn == 1 implies that we weren't passed a valid value.  */
-       if (tail_lsn != 1)
-               atomic64_set(&log->l_tail_lsn, tail_lsn);
-
-       if (!list_empty_careful(&log->l_writeq)) {
-#ifdef DEBUG
-               if (log->l_flags & XLOG_ACTIVE_RECOVERY)
-                       panic("Recovery problem");
-#endif
-               spin_lock(&log->l_grant_write_lock);
-               free_bytes = xlog_space_left(log, &log->l_grant_write_head);
-               list_for_each_entry(tic, &log->l_writeq, t_queue) {
-                       ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV);
+       if (!list_empty_careful(&log->l_write_head.waiters)) {
+               ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));
 
-                       if (free_bytes < tic->t_unit_res && tail_lsn != 1)
-                               break;
-                       tail_lsn = 0;
-                       free_bytes -= tic->t_unit_res;
-                       trace_xfs_log_regrant_write_wake_up(log, tic);
-                       wake_up(&tic->t_wait);
-               }
-               spin_unlock(&log->l_grant_write_lock);
+               spin_lock(&log->l_write_head.lock);
+               free_bytes = xlog_space_left(log, &log->l_write_head.grant);
+               xlog_grant_head_wake(log, &log->l_write_head, &free_bytes);
+               spin_unlock(&log->l_write_head.lock);
        }
 
-       if (!list_empty_careful(&log->l_reserveq)) {
-#ifdef DEBUG
-               if (log->l_flags & XLOG_ACTIVE_RECOVERY)
-                       panic("Recovery problem");
-#endif
-               spin_lock(&log->l_grant_reserve_lock);
-               free_bytes = xlog_space_left(log, &log->l_grant_reserve_head);
-               list_for_each_entry(tic, &log->l_reserveq, t_queue) {
-                       if (tic->t_flags & XLOG_TIC_PERM_RESERV)
-                               need_bytes = tic->t_unit_res*tic->t_cnt;
-                       else
-                               need_bytes = tic->t_unit_res;
-                       if (free_bytes < need_bytes && tail_lsn != 1)
-                               break;
-                       tail_lsn = 0;
-                       free_bytes -= need_bytes;
-                       trace_xfs_log_grant_wake_up(log, tic);
-                       wake_up(&tic->t_wait);
-               }
-               spin_unlock(&log->l_grant_reserve_lock);
+       if (!list_empty_careful(&log->l_reserve_head.waiters)) {
+               ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));
+
+               spin_lock(&log->l_reserve_head.lock);
+               free_bytes = xlog_space_left(log, &log->l_reserve_head.grant);
+               xlog_grant_head_wake(log, &log->l_reserve_head, &free_bytes);
+               spin_unlock(&log->l_reserve_head.lock);
        }
 }
 
@@ -867,21 +912,7 @@ xfs_log_need_covered(xfs_mount_t *mp)
        return needed;
 }
 
-/******************************************************************************
- *
- *     local routines
- *
- ******************************************************************************
- */
-
-/* xfs_trans_tail_ail returns 0 when there is nothing in the list.
- * The log manager must keep track of the last LR which was committed
- * to disk.  The lsn of this LR will become the new tail_lsn whenever
- * xfs_trans_tail_ail returns 0.  If we don't do this, we run into
- * the situation where stuff could be written into the log but nothing
- * was ever in the AIL when asked.  Eventually, we panic since the
- * tail hits the head.
- *
+/*
  * We may be holding the log iclog lock upon entering this routine.
  */
 xfs_lsn_t
@@ -891,10 +922,17 @@ xlog_assign_tail_lsn(
        xfs_lsn_t               tail_lsn;
        struct log              *log = mp->m_log;
 
+       /*
+        * To make sure we always have a valid LSN for the log tail we keep
+        * track of the last LSN which was committed in log->l_last_sync_lsn,
+        * and use that when the AIL was empty and xfs_ail_min_lsn returns 0.
+        *
+        * If the AIL has been emptied we also need to wake any process
+        * waiting for this condition.
+        */
        tail_lsn = xfs_ail_min_lsn(mp->m_ail);
        if (!tail_lsn)
                tail_lsn = atomic64_read(&log->l_last_sync_lsn);
-
        atomic64_set(&log->l_tail_lsn, tail_lsn);
        return tail_lsn;
 }
@@ -1100,12 +1138,9 @@ xlog_alloc_log(xfs_mount_t       *mp,
        xlog_assign_atomic_lsn(&log->l_tail_lsn, 1, 0);
        xlog_assign_atomic_lsn(&log->l_last_sync_lsn, 1, 0);
        log->l_curr_cycle  = 1;     /* 0 is bad since this is initial value */
-       xlog_assign_grant_head(&log->l_grant_reserve_head, 1, 0);
-       xlog_assign_grant_head(&log->l_grant_write_head, 1, 0);
-       INIT_LIST_HEAD(&log->l_reserveq);
-       INIT_LIST_HEAD(&log->l_writeq);
-       spin_lock_init(&log->l_grant_reserve_lock);
-       spin_lock_init(&log->l_grant_write_lock);
+
+       xlog_grant_head_init(&log->l_reserve_head);
+       xlog_grant_head_init(&log->l_write_head);
 
        error = EFSCORRUPTED;
        if (xfs_sb_version_hassector(&mp->m_sb)) {
@@ -1280,7 +1315,7 @@ xlog_grant_push_ail(
 
        ASSERT(BTOBB(need_bytes) < log->l_logBBsize);
 
-       free_bytes = xlog_space_left(log, &log->l_grant_reserve_head);
+       free_bytes = xlog_space_left(log, &log->l_reserve_head.grant);
        free_blocks = BTOBBT(free_bytes);
 
        /*
@@ -1412,8 +1447,8 @@ xlog_sync(xlog_t          *log,
                 roundoff < BBTOB(1)));
 
        /* move grant heads by roundoff in sync */
-       xlog_grant_add_space(log, &log->l_grant_reserve_head, roundoff);
-       xlog_grant_add_space(log, &log->l_grant_write_head, roundoff);
+       xlog_grant_add_space(log, &log->l_reserve_head.grant, roundoff);
+       xlog_grant_add_space(log, &log->l_write_head.grant, roundoff);
 
        /* put cycle number in every block */
        xlog_pack_data(log, iclog, roundoff); 
@@ -2566,119 +2601,6 @@ restart:
        return 0;
 }      /* xlog_state_get_iclog_space */
 
-/*
- * Atomically get the log space required for a log ticket.
- *
- * Once a ticket gets put onto the reserveq, it will only return after the
- * needed reservation is satisfied.
- *
- * This function is structured so that it has a lock free fast path. This is
- * necessary because every new transaction reservation will come through this
- * path. Hence any lock will be globally hot if we take it unconditionally on
- * every pass.
- *
- * As tickets are only ever moved on and off the reserveq under the
- * l_grant_reserve_lock, we only need to take that lock if we are going to add
- * the ticket to the queue and sleep. We can avoid taking the lock if the ticket
- * was never added to the reserveq because the t_queue list head will be empty
- * and we hold the only reference to it so it can safely be checked unlocked.
- */
-STATIC int
-xlog_grant_log_space(
-       struct log              *log,
-       struct xlog_ticket      *tic)
-{
-       int                     free_bytes, need_bytes;
-       int                     error = 0;
-
-       ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));
-
-       trace_xfs_log_grant_enter(log, tic);
-
-       /*
-        * If there are other waiters on the queue then give them a chance at
-        * logspace before us.  Wake up the first waiters, if we do not wake
-        * up all the waiters then go to sleep waiting for more free space,
-        * otherwise try to get some space for this transaction.
-        */
-       need_bytes = tic->t_unit_res;
-       if (tic->t_flags & XFS_LOG_PERM_RESERV)
-               need_bytes *= tic->t_ocnt;
-       free_bytes = xlog_space_left(log, &log->l_grant_reserve_head);
-       if (!list_empty_careful(&log->l_reserveq)) {
-               spin_lock(&log->l_grant_reserve_lock);
-               if (!xlog_reserveq_wake(log, &free_bytes) ||
-                   free_bytes < need_bytes)
-                       error = xlog_reserveq_wait(log, tic, need_bytes);
-               spin_unlock(&log->l_grant_reserve_lock);
-       } else if (free_bytes < need_bytes) {
-               spin_lock(&log->l_grant_reserve_lock);
-               error = xlog_reserveq_wait(log, tic, need_bytes);
-               spin_unlock(&log->l_grant_reserve_lock);
-       }
-       if (error)
-               return error;
-
-       xlog_grant_add_space(log, &log->l_grant_reserve_head, need_bytes);
-       xlog_grant_add_space(log, &log->l_grant_write_head, need_bytes);
-       trace_xfs_log_grant_exit(log, tic);
-       xlog_verify_grant_tail(log);
-       return 0;
-}
-
-/*
- * Replenish the byte reservation required by moving the grant write head.
- *
- * Similar to xlog_grant_log_space, the function is structured to have a lock
- * free fast path.
- */
-STATIC int
-xlog_regrant_write_log_space(
-       struct log              *log,
-       struct xlog_ticket      *tic)
-{
-       int                     free_bytes, need_bytes;
-       int                     error = 0;
-
-       tic->t_curr_res = tic->t_unit_res;
-       xlog_tic_reset_res(tic);
-
-       if (tic->t_cnt > 0)
-               return 0;
-
-       ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY));
-
-       trace_xfs_log_regrant_write_enter(log, tic);
-
-       /*
-        * If there are other waiters on the queue then give them a chance at
-        * logspace before us.  Wake up the first waiters, if we do not wake
-        * up all the waiters then go to sleep waiting for more free space,
-        * otherwise try to get some space for this transaction.
-        */
-       need_bytes = tic->t_unit_res;
-       free_bytes = xlog_space_left(log, &log->l_grant_write_head);
-       if (!list_empty_careful(&log->l_writeq)) {
-               spin_lock(&log->l_grant_write_lock);
-               if (!xlog_writeq_wake(log, &free_bytes) ||
-                   free_bytes < need_bytes)
-                       error = xlog_writeq_wait(log, tic, need_bytes);
-               spin_unlock(&log->l_grant_write_lock);
-       } else if (free_bytes < need_bytes) {
-               spin_lock(&log->l_grant_write_lock);
-               error = xlog_writeq_wait(log, tic, need_bytes);
-               spin_unlock(&log->l_grant_write_lock);
-       }
-
-       if (error)
-               return error;
-
-       xlog_grant_add_space(log, &log->l_grant_write_head, need_bytes);
-       trace_xfs_log_regrant_write_exit(log, tic);
-       xlog_verify_grant_tail(log);
-       return 0;
-}
-
 /* The first cnt-1 times through here we don't need to
  * move the grant write head because the permanent
  * reservation has reserved cnt times the unit amount.
@@ -2695,9 +2617,9 @@ xlog_regrant_reserve_log_space(xlog_t          *log,
        if (ticket->t_cnt > 0)
                ticket->t_cnt--;
 
-       xlog_grant_sub_space(log, &log->l_grant_reserve_head,
+       xlog_grant_sub_space(log, &log->l_reserve_head.grant,
                                        ticket->t_curr_res);
-       xlog_grant_sub_space(log, &log->l_grant_write_head,
+       xlog_grant_sub_space(log, &log->l_write_head.grant,
                                        ticket->t_curr_res);
        ticket->t_curr_res = ticket->t_unit_res;
        xlog_tic_reset_res(ticket);
@@ -2708,7 +2630,7 @@ xlog_regrant_reserve_log_space(xlog_t          *log,
        if (ticket->t_cnt > 0)
                return;
 
-       xlog_grant_add_space(log, &log->l_grant_reserve_head,
+       xlog_grant_add_space(log, &log->l_reserve_head.grant,
                                        ticket->t_unit_res);
 
        trace_xfs_log_regrant_reserve_exit(log, ticket);
@@ -2754,14 +2676,13 @@ xlog_ungrant_log_space(xlog_t        *log,
                bytes += ticket->t_unit_res*ticket->t_cnt;
        }
 
-       xlog_grant_sub_space(log, &log->l_grant_reserve_head, bytes);
-       xlog_grant_sub_space(log, &log->l_grant_write_head, bytes);
+       xlog_grant_sub_space(log, &log->l_reserve_head.grant, bytes);
+       xlog_grant_sub_space(log, &log->l_write_head.grant, bytes);
 
        trace_xfs_log_ungrant_exit(log, ticket);
 
-       xfs_log_move_tail(log->l_mp, 1);
-}      /* xlog_ungrant_log_space */
-
+       xfs_log_space_wake(log->l_mp);
+}
 
 /*
  * Flush iclog to disk if this is the last reference to the given iclog and
@@ -3219,7 +3140,7 @@ xlog_ticket_alloc(
        int             unit_bytes,
        int             cnt,
        char            client,
-       uint            xflags,
+       bool            permanent,
        int             alloc_flags)
 {
        struct xlog_ticket *tic;
@@ -3313,6 +3234,7 @@ xlog_ticket_alloc(
         }
 
        atomic_set(&tic->t_ref, 1);
+       tic->t_task             = current;
        INIT_LIST_HEAD(&tic->t_queue);
        tic->t_unit_res         = unit_bytes;
        tic->t_curr_res         = unit_bytes;
@@ -3322,9 +3244,8 @@ xlog_ticket_alloc(
        tic->t_clientid         = client;
        tic->t_flags            = XLOG_TIC_INITED;
        tic->t_trans_type       = 0;
-       if (xflags & XFS_LOG_PERM_RESERV)
+       if (permanent)
                tic->t_flags |= XLOG_TIC_PERM_RESERV;
-       init_waitqueue_head(&tic->t_wait);
 
        xlog_tic_reset_res(tic);
 
@@ -3380,7 +3301,7 @@ xlog_verify_grant_tail(
        int             tail_cycle, tail_blocks;
        int             cycle, space;
 
-       xlog_crack_grant_head(&log->l_grant_write_head, &cycle, &space);
+       xlog_crack_grant_head(&log->l_write_head.grant, &cycle, &space);
        xlog_crack_atomic_lsn(&log->l_tail_lsn, &tail_cycle, &tail_blocks);
        if (tail_cycle != cycle) {
                if (cycle - 1 != tail_cycle &&
@@ -3582,7 +3503,6 @@ xfs_log_force_umount(
        struct xfs_mount        *mp,
        int                     logerror)
 {
-       xlog_ticket_t   *tic;
        xlog_t          *log;
        int             retval;
 
@@ -3650,15 +3570,8 @@ xfs_log_force_umount(
         * we don't enqueue anything once the SHUTDOWN flag is set, and this
         * action is protected by the grant locks.
         */
-       spin_lock(&log->l_grant_reserve_lock);
-       list_for_each_entry(tic, &log->l_reserveq, t_queue)
-               wake_up(&tic->t_wait);
-       spin_unlock(&log->l_grant_reserve_lock);
-
-       spin_lock(&log->l_grant_write_lock);
-       list_for_each_entry(tic, &log->l_writeq, t_queue)
-               wake_up(&tic->t_wait);
-       spin_unlock(&log->l_grant_write_lock);
+       xlog_grant_head_wake_all(&log->l_reserve_head);
+       xlog_grant_head_wake_all(&log->l_write_head);
 
        if (!(log->l_iclog->ic_state & XLOG_STATE_IOERROR)) {
                ASSERT(!logerror);
index 2aee3b2..2c622be 100644 (file)
@@ -53,15 +53,6 @@ static inline xfs_lsn_t      _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
 #define XFS_LOG_REL_PERM_RESERV        0x1
 
 /*
- * Flags to xfs_log_reserve()
- *
- *     XFS_LOG_PERM_RESERV: Permanent reservation.  When writes are
- *             performed against this type of reservation, the reservation
- *             is not decreased.  Long running transactions should use this.
- */
-#define XFS_LOG_PERM_RESERV    0x2
-
-/*
  * Flags to xfs_log_force()
  *
  *     XFS_LOG_SYNC:   Synchronous force in-core log to disk
@@ -160,8 +151,8 @@ int   xfs_log_mount(struct xfs_mount        *mp,
                        xfs_daddr_t             start_block,
                        int                     num_bblocks);
 int      xfs_log_mount_finish(struct xfs_mount *mp);
-void     xfs_log_move_tail(struct xfs_mount    *mp,
-                           xfs_lsn_t           tail_lsn);
+xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
+void     xfs_log_space_wake(struct xfs_mount *mp);
 int      xfs_log_notify(struct xfs_mount       *mp,
                         struct xlog_in_core    *iclog,
                         xfs_log_callback_t     *callback_entry);
@@ -172,8 +163,9 @@ int   xfs_log_reserve(struct xfs_mount *mp,
                          int              count,
                          struct xlog_ticket **ticket,
                          __uint8_t        clientid,
-                         uint             flags,
+                         bool             permanent,
                          uint             t_type);
+int      xfs_log_regrant(struct xfs_mount *mp, struct xlog_ticket *tic);
 int      xfs_log_unmount_write(struct xfs_mount *mp);
 void      xfs_log_unmount(struct xfs_mount *mp);
 int      xfs_log_force_umount(struct xfs_mount *mp, int logerror);
index 2d3b6a4..2152900 100644 (file)
@@ -239,8 +239,8 @@ typedef struct xlog_res {
 } xlog_res_t;
 
 typedef struct xlog_ticket {
-       wait_queue_head_t  t_wait;       /* ticket wait queue */
        struct list_head   t_queue;      /* reserve/write queue */
+       struct task_struct *t_task;      /* task that owns this ticket */
        xlog_tid_t         t_tid;        /* transaction identifier       : 4  */
        atomic_t           t_ref;        /* ticket reference count       : 4  */
        int                t_curr_res;   /* current reservation in bytes : 4  */
@@ -470,6 +470,16 @@ struct xfs_cil {
 #define XLOG_CIL_HARD_SPACE_LIMIT(log) (3 * (log->l_logsize >> 4))
 
 /*
+ * ticket grant locks, queues and accounting have their own cachlines
+ * as these are quite hot and can be operated on concurrently.
+ */
+struct xlog_grant_head {
+       spinlock_t              lock ____cacheline_aligned_in_smp;
+       struct list_head        waiters;
+       atomic64_t              grant;
+};
+
+/*
  * The reservation head lsn is not made up of a cycle number and block number.
  * Instead, it uses a cycle number and byte number.  Logs don't expect to
  * overflow 31 bits worth of byte offset, so using a byte number will mean
@@ -520,17 +530,8 @@ typedef struct log {
        /* lsn of 1st LR with unflushed * buffers */
        atomic64_t              l_tail_lsn ____cacheline_aligned_in_smp;
 
-       /*
-        * ticket grant locks, queues and accounting have their own cachlines
-        * as these are quite hot and can be operated on concurrently.
-        */
-       spinlock_t              l_grant_reserve_lock ____cacheline_aligned_in_smp;
-       struct list_head        l_reserveq;
-       atomic64_t              l_grant_reserve_head;
-
-       spinlock_t              l_grant_write_lock ____cacheline_aligned_in_smp;
-       struct list_head        l_writeq;
-       atomic64_t              l_grant_write_head;
+       struct xlog_grant_head  l_reserve_head;
+       struct xlog_grant_head  l_write_head;
 
        /* The following field are used for debugging; need to hold icloglock */
 #ifdef DEBUG
@@ -545,14 +546,13 @@ typedef struct log {
 #define XLOG_FORCED_SHUTDOWN(log)      ((log)->l_flags & XLOG_IO_ERROR)
 
 /* common routines */
-extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
 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 kmem_zone_t *xfs_log_ticket_zone;
 struct xlog_ticket *xlog_ticket_alloc(struct log *log, int unit_bytes,
-                               int count, char client, uint xflags,
+                               int count, char client, bool permanent,
                                int alloc_flags);
 
 
index 0ed9ee7..8ecad5b 100644 (file)
@@ -965,9 +965,9 @@ xlog_find_tail(
                log->l_curr_cycle++;
        atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn));
        atomic64_set(&log->l_last_sync_lsn, be64_to_cpu(rhead->h_lsn));
-       xlog_assign_grant_head(&log->l_grant_reserve_head, log->l_curr_cycle,
+       xlog_assign_grant_head(&log->l_reserve_head.grant, log->l_curr_cycle,
                                        BBTOB(log->l_curr_block));
-       xlog_assign_grant_head(&log->l_grant_write_head, log->l_curr_cycle,
+       xlog_assign_grant_head(&log->l_write_head.grant, log->l_curr_cycle,
                                        BBTOB(log->l_curr_block));
 
        /*
@@ -3161,37 +3161,26 @@ xlog_recover_process_iunlinks(
                         */
                        continue;
                }
+               /*
+                * Unlock the buffer so that it can be acquired in the normal
+                * course of the transaction to truncate and free each inode.
+                * Because we are not racing with anyone else here for the AGI
+                * buffer, we don't even need to hold it locked to read the
+                * initial unlinked bucket entries out of the buffer. We keep
+                * buffer reference though, so that it stays pinned in memory
+                * while we need the buffer.
+                */
                agi = XFS_BUF_TO_AGI(agibp);
+               xfs_buf_unlock(agibp);
 
                for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) {
                        agino = be32_to_cpu(agi->agi_unlinked[bucket]);
                        while (agino != NULLAGINO) {
-                               /*
-                                * Release the agi buffer so that it can
-                                * be acquired in the normal course of the
-                                * transaction to truncate and free the inode.
-                                */
-                               xfs_buf_relse(agibp);
-
                                agino = xlog_recover_process_one_iunlink(mp,
                                                        agno, agino, bucket);
-
-                               /*
-                                * Reacquire the agibuffer and continue around
-                                * the loop. This should never fail as we know
-                                * the buffer was good earlier on.
-                                */
-                               error = xfs_read_agi(mp, NULL, agno, &agibp);
-                               ASSERT(error == 0);
-                               agi = XFS_BUF_TO_AGI(agibp);
                        }
                }
-
-               /*
-                * Release the buffer for the current agi so we can
-                * go on to the next one.
-                */
-               xfs_buf_relse(agibp);
+               xfs_buf_rele(agibp);
        }
 
        mp->m_dmevmask = mp_dmevmask;
@@ -3695,7 +3684,7 @@ xlog_do_recover(
 
        /* Convert superblock from on-disk format */
        sbp = &log->l_mp->m_sb;
-       xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp));
+       xfs_sb_from_disk(log->l_mp, XFS_BUF_TO_SBP(bp));
        ASSERT(sbp->sb_magicnum == XFS_SB_MAGIC);
        ASSERT(xfs_sb_good_version(sbp));
        xfs_buf_relse(bp);
index d06afbc..1ffead4 100644 (file)
@@ -158,7 +158,7 @@ xfs_uuid_mount(
 
  out_duplicate:
        mutex_unlock(&xfs_uuid_table_mutex);
-       xfs_warn(mp, "Filesystem has duplicate UUID - can't mount");
+       xfs_warn(mp, "Filesystem has duplicate UUID %pU - can't mount", uuid);
        return XFS_ERROR(EINVAL);
 }
 
@@ -553,9 +553,11 @@ out_unwind:
 
 void
 xfs_sb_from_disk(
-       xfs_sb_t        *to,
+       struct xfs_mount        *mp,
        xfs_dsb_t       *from)
 {
+       struct xfs_sb *to = &mp->m_sb;
+
        to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
        to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
        to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
@@ -693,7 +695,7 @@ reread:
         * Initialize the mount structure from the superblock.
         * But first do some basic consistency checking.
         */
-       xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
+       xfs_sb_from_disk(mp, XFS_BUF_TO_SBP(bp));
        error = xfs_mount_validate_sb(mp, &(mp->m_sb), flags);
        if (error) {
                if (loud)
index 19f69e2..9eba738 100644 (file)
@@ -211,6 +211,9 @@ typedef struct xfs_mount {
        struct shrinker         m_inode_shrink; /* inode reclaim shrinker */
        int64_t                 m_low_space[XFS_LOWSP_MAX];
                                                /* low free space thresholds */
+
+       struct workqueue_struct *m_data_workqueue;
+       struct workqueue_struct *m_unwritten_workqueue;
 } xfs_mount_t;
 
 /*
@@ -395,7 +398,7 @@ extern void xfs_set_low_space_thresholds(struct xfs_mount *);
 extern void    xfs_mod_sb(struct xfs_trans *, __int64_t);
 extern int     xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t,
                                        xfs_agnumber_t *);
-extern void    xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
+extern void    xfs_sb_from_disk(struct xfs_mount *, struct xfs_dsb *);
 extern void    xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);
 
 #endif /* __XFS_MOUNT_H__ */
index c436def..55c6afe 100644 (file)
  * quota functionality, including maintaining the freelist and hash
  * tables of dquots.
  */
-struct mutex   xfs_Gqm_lock;
-struct xfs_qm  *xfs_Gqm;
-
-kmem_zone_t    *qm_dqzone;
-kmem_zone_t    *qm_dqtrxzone;
-
-STATIC void    xfs_qm_list_init(xfs_dqlist_t *, char *, int);
-STATIC void    xfs_qm_list_destroy(xfs_dqlist_t *);
-
 STATIC int     xfs_qm_init_quotainos(xfs_mount_t *);
 STATIC int     xfs_qm_init_quotainfo(xfs_mount_t *);
 STATIC int     xfs_qm_shake(struct shrinker *, struct shrink_control *);
 
-static struct shrinker xfs_qm_shaker = {
-       .shrink = xfs_qm_shake,
-       .seeks = DEFAULT_SEEKS,
-};
-
 /*
- * Initialize the XQM structure.
- * Note that there is not one quota manager per file system.
+ * We use the batch lookup interface to iterate over the dquots as it
+ * currently is the only interface into the radix tree code that allows
+ * fuzzy lookups instead of exact matches.  Holding the lock over multiple
+ * operations is fine as all callers are used either during mount/umount
+ * or quotaoff.
  */
-STATIC struct xfs_qm *
-xfs_Gqm_init(void)
+#define XFS_DQ_LOOKUP_BATCH    32
+
+STATIC int
+xfs_qm_dquot_walk(
+       struct xfs_mount        *mp,
+       int                     type,
+       int                     (*execute)(struct xfs_dquot *dqp))
 {
-       xfs_dqhash_t    *udqhash, *gdqhash;
-       xfs_qm_t        *xqm;
-       size_t          hsize;
-       uint            i;
+       struct xfs_quotainfo    *qi = mp->m_quotainfo;
+       struct radix_tree_root  *tree = XFS_DQUOT_TREE(qi, type);
+       uint32_t                next_index;
+       int                     last_error = 0;
+       int                     skipped;
+       int                     nr_found;
+
+restart:
+       skipped = 0;
+       next_index = 0;
+       nr_found = 0;
+
+       while (1) {
+               struct xfs_dquot *batch[XFS_DQ_LOOKUP_BATCH];
+               int             error = 0;
+               int             i;
+
+               mutex_lock(&qi->qi_tree_lock);
+               nr_found = radix_tree_gang_lookup(tree, (void **)batch,
+                                       next_index, XFS_DQ_LOOKUP_BATCH);
+               if (!nr_found) {
+                       mutex_unlock(&qi->qi_tree_lock);
+                       break;
+               }
 
-       /*
-        * Initialize the dquot hash tables.
-        */
-       udqhash = kmem_zalloc_greedy(&hsize,
-                                    XFS_QM_HASHSIZE_LOW * sizeof(xfs_dqhash_t),
-                                    XFS_QM_HASHSIZE_HIGH * sizeof(xfs_dqhash_t));
-       if (!udqhash)
-               goto out;
+               for (i = 0; i < nr_found; i++) {
+                       struct xfs_dquot *dqp = batch[i];
 
-       gdqhash = kmem_zalloc_large(hsize);
-       if (!gdqhash)
-               goto out_free_udqhash;
+                       next_index = be32_to_cpu(dqp->q_core.d_id) + 1;
 
-       hsize /= sizeof(xfs_dqhash_t);
+                       error = execute(batch[i]);
+                       if (error == EAGAIN) {
+                               skipped++;
+                               continue;
+                       }
+                       if (error && last_error != EFSCORRUPTED)
+                               last_error = error;
+               }
 
-       xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
-       xqm->qm_dqhashmask = hsize - 1;
-       xqm->qm_usr_dqhtable = udqhash;
-       xqm->qm_grp_dqhtable = gdqhash;
-       ASSERT(xqm->qm_usr_dqhtable != NULL);
-       ASSERT(xqm->qm_grp_dqhtable != NULL);
+               mutex_unlock(&qi->qi_tree_lock);
 
-       for (i = 0; i < hsize; i++) {
-               xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i);
-               xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i);
+               /* bail out if the filesystem is corrupted.  */
+               if (last_error == EFSCORRUPTED) {
+                       skipped = 0;
+                       break;
+               }
        }
 
-       /*
-        * Freelist of all dquots of all file systems
-        */
-       INIT_LIST_HEAD(&xqm->qm_dqfrlist);
-       xqm->qm_dqfrlist_cnt = 0;
-       mutex_init(&xqm->qm_dqfrlist_lock);
-
-       /*
-        * dquot zone. we register our own low-memory callback.
-        */
-       if (!qm_dqzone) {
-               xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t),
-                                               "xfs_dquots");
-               qm_dqzone = xqm->qm_dqzone;
-       } else
-               xqm->qm_dqzone = qm_dqzone;
-
-       register_shrinker(&xfs_qm_shaker);
-
-       /*
-        * The t_dqinfo portion of transactions.
-        */
-       if (!qm_dqtrxzone) {
-               xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t),
-                                                  "xfs_dqtrx");
-               qm_dqtrxzone = xqm->qm_dqtrxzone;
-       } else
-               xqm->qm_dqtrxzone = qm_dqtrxzone;
-
-       atomic_set(&xqm->qm_totaldquots, 0);
-       xqm->qm_nrefs = 0;
-       return xqm;
+       if (skipped) {
+               delay(1);
+               goto restart;
+       }
 
- out_free_udqhash:
-       kmem_free_large(udqhash);
- out:
-       return NULL;
+       return last_error;
 }
 
+
 /*
- * Destroy the global quota manager when its reference count goes to zero.
+ * Purge a dquot from all tracking data structures and free it.
  */
-STATIC void
-xfs_qm_destroy(
-       struct xfs_qm   *xqm)
+STATIC int
+xfs_qm_dqpurge(
+       struct xfs_dquot        *dqp)
 {
-       int             hsize, i;
+       struct xfs_mount        *mp = dqp->q_mount;
+       struct xfs_quotainfo    *qi = mp->m_quotainfo;
+       struct xfs_dquot        *gdqp = NULL;
 
-       ASSERT(xqm != NULL);
-       ASSERT(xqm->qm_nrefs == 0);
+       xfs_dqlock(dqp);
+       if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) {
+               xfs_dqunlock(dqp);
+               return EAGAIN;
+       }
 
-       unregister_shrinker(&xfs_qm_shaker);
+       /*
+        * If this quota has a group hint attached, prepare for releasing it
+        * now.
+        */
+       gdqp = dqp->q_gdquot;
+       if (gdqp) {
+               xfs_dqlock(gdqp);
+               dqp->q_gdquot = NULL;
+       }
 
-       mutex_lock(&xqm->qm_dqfrlist_lock);
-       ASSERT(list_empty(&xqm->qm_dqfrlist));
-       mutex_unlock(&xqm->qm_dqfrlist_lock);
+       dqp->dq_flags |= XFS_DQ_FREEING;
 
-       hsize = xqm->qm_dqhashmask + 1;
-       for (i = 0; i < hsize; i++) {
-               xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
-               xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));
+       /*
+        * If we're turning off quotas, we have to make sure that, for
+        * example, we don't delete quota disk blocks while dquots are
+        * in the process of getting written to those disk blocks.
+        * This dquot might well be on AIL, and we can't leave it there
+        * if we're turning off quotas. Basically, we need this flush
+        * lock, and are willing to block on it.
+        */
+       if (!xfs_dqflock_nowait(dqp)) {
+               /*
+                * Block on the flush lock after nudging dquot buffer,
+                * if it is incore.
+                */
+               xfs_dqflock_pushbuf_wait(dqp);
        }
-       kmem_free_large(xqm->qm_usr_dqhtable);
-       kmem_free_large(xqm->qm_grp_dqhtable);
-       xqm->qm_usr_dqhtable = NULL;
-       xqm->qm_grp_dqhtable = NULL;
-       xqm->qm_dqhashmask = 0;
 
-       kmem_free(xqm);
-}
-
-/*
- * Called at mount time to let XQM know that another file system is
- * starting quotas. This isn't crucial information as the individual mount
- * structures are pretty independent, but it helps the XQM keep a
- * global view of what's going on.
- */
-/* ARGSUSED */
-STATIC int
-xfs_qm_hold_quotafs_ref(
-       struct xfs_mount *mp)
-{
        /*
-        * Need to lock the xfs_Gqm structure for things like this. For example,
-        * the structure could disappear between the entry to this routine and
-        * a HOLD operation if not locked.
+        * If we are turning this type of quotas off, we don't care
+        * about the dirty metadata sitting in this dquot. OTOH, if
+        * we're unmounting, we do care, so we flush it and wait.
         */
-       mutex_lock(&xfs_Gqm_lock);
+       if (XFS_DQ_IS_DIRTY(dqp)) {
+               int     error;
 
-       if (!xfs_Gqm) {
-               xfs_Gqm = xfs_Gqm_init();
-               if (!xfs_Gqm) {
-                       mutex_unlock(&xfs_Gqm_lock);
-                       return ENOMEM;
-               }
+               /*
+                * We don't care about getting disk errors here. We need
+                * to purge this dquot anyway, so we go ahead regardless.
+                */
+               error = xfs_qm_dqflush(dqp, SYNC_WAIT);
+               if (error)
+                       xfs_warn(mp, "%s: dquot %p flush failed",
+                               __func__, dqp);
+               xfs_dqflock(dqp);
        }
 
+       ASSERT(atomic_read(&dqp->q_pincount) == 0);
+       ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
+              !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
+
+       xfs_dqfunlock(dqp);
+       xfs_dqunlock(dqp);
+
+       radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
+                         be32_to_cpu(dqp->q_core.d_id));
+       qi->qi_dquots--;
+
        /*
-        * We can keep a list of all filesystems with quotas mounted for
-        * debugging and statistical purposes, but ...
-        * Just take a reference and get out.
+        * We move dquots to the freelist as soon as their reference count
+        * hits zero, so it really should be on the freelist here.
         */
-       xfs_Gqm->qm_nrefs++;
-       mutex_unlock(&xfs_Gqm_lock);
+       mutex_lock(&qi->qi_lru_lock);
+       ASSERT(!list_empty(&dqp->q_lru));
+       list_del_init(&dqp->q_lru);
+       qi->qi_lru_count--;
+       XFS_STATS_DEC(xs_qm_dquot_unused);
+       mutex_unlock(&qi->qi_lru_lock);
 
+       xfs_qm_dqdestroy(dqp);
+
+       if (gdqp)
+               xfs_qm_dqput(gdqp);
        return 0;
 }
 
-
 /*
- * Release the reference that a filesystem took at mount time,
- * so that we know when we need to destroy the entire quota manager.
+ * Purge the dquot cache.
  */
-/* ARGSUSED */
-STATIC void
-xfs_qm_rele_quotafs_ref(
-       struct xfs_mount *mp)
+void
+xfs_qm_dqpurge_all(
+       struct xfs_mount        *mp,
+       uint                    flags)
 {
-       ASSERT(xfs_Gqm);
-       ASSERT(xfs_Gqm->qm_nrefs > 0);
-
-       /*
-        * Destroy the entire XQM. If somebody mounts with quotaon, this'll
-        * be restarted.
-        */
-       mutex_lock(&xfs_Gqm_lock);
-       if (--xfs_Gqm->qm_nrefs == 0) {
-               xfs_qm_destroy(xfs_Gqm);
-               xfs_Gqm = NULL;
-       }
-       mutex_unlock(&xfs_Gqm_lock);
+       if (flags & XFS_QMOPT_UQUOTA)
+               xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge);
+       if (flags & XFS_QMOPT_GQUOTA)
+               xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge);
+       if (flags & XFS_QMOPT_PQUOTA)
+               xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_dqpurge);
 }
 
 /*
@@ -376,175 +371,6 @@ xfs_qm_unmount_quotas(
        }
 }
 
-/*
- * Flush all dquots of the given file system to disk. The dquots are
- * _not_ purged from memory here, just their data written to disk.
- */
-STATIC int
-xfs_qm_dqflush_all(
-       struct xfs_mount        *mp)
-{
-       struct xfs_quotainfo    *q = mp->m_quotainfo;
-       int                     recl;
-       struct xfs_dquot        *dqp;
-       int                     error;
-
-       if (!q)
-               return 0;
-again:
-       mutex_lock(&q->qi_dqlist_lock);
-       list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
-               xfs_dqlock(dqp);
-               if ((dqp->dq_flags & XFS_DQ_FREEING) ||
-                   !XFS_DQ_IS_DIRTY(dqp)) {
-                       xfs_dqunlock(dqp);
-                       continue;
-               }
-
-               /* XXX a sentinel would be better */
-               recl = q->qi_dqreclaims;
-               if (!xfs_dqflock_nowait(dqp)) {
-                       /*
-                        * If we can't grab the flush lock then check
-                        * to see if the dquot has been flushed delayed
-                        * write.  If so, grab its buffer and send it
-                        * out immediately.  We'll be able to acquire
-                        * the flush lock when the I/O completes.
-                        */
-                       xfs_dqflock_pushbuf_wait(dqp);
-               }
-               /*
-                * Let go of the mplist lock. We don't want to hold it
-                * across a disk write.
-                */
-               mutex_unlock(&q->qi_dqlist_lock);
-               error = xfs_qm_dqflush(dqp, 0);
-               xfs_dqunlock(dqp);
-               if (error)
-                       return error;
-
-               mutex_lock(&q->qi_dqlist_lock);
-               if (recl != q->qi_dqreclaims) {
-                       mutex_unlock(&q->qi_dqlist_lock);
-                       /* XXX restart limit */
-                       goto again;
-               }
-       }
-
-       mutex_unlock(&q->qi_dqlist_lock);
-       /* return ! busy */
-       return 0;
-}
-
-/*
- * Release the group dquot pointers the user dquots may be
- * carrying around as a hint. mplist is locked on entry and exit.
- */
-STATIC void
-xfs_qm_detach_gdquots(
-       struct xfs_mount        *mp)
-{
-       struct xfs_quotainfo    *q = mp->m_quotainfo;
-       struct xfs_dquot        *dqp, *gdqp;
-
- again:
-       ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
-       list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
-               xfs_dqlock(dqp);
-               if (dqp->dq_flags & XFS_DQ_FREEING) {
-                       xfs_dqunlock(dqp);
-                       mutex_unlock(&q->qi_dqlist_lock);
-                       delay(1);
-                       mutex_lock(&q->qi_dqlist_lock);
-                       goto again;
-               }
-
-               gdqp = dqp->q_gdquot;
-               if (gdqp)
-                       dqp->q_gdquot = NULL;
-               xfs_dqunlock(dqp);
-
-               if (gdqp)
-                       xfs_qm_dqrele(gdqp);
-       }
-}
-
-/*
- * Go through all the incore dquots of this file system and take them
- * off the mplist and hashlist, if the dquot type matches the dqtype
- * parameter. This is used when turning off quota accounting for
- * users and/or groups, as well as when the filesystem is unmounting.
- */
-STATIC int
-xfs_qm_dqpurge_int(
-       struct xfs_mount        *mp,
-       uint                    flags)
-{
-       struct xfs_quotainfo    *q = mp->m_quotainfo;
-       struct xfs_dquot        *dqp, *n;
-       uint                    dqtype;
-       int                     nmisses = 0;
-       LIST_HEAD               (dispose_list);
-
-       if (!q)
-               return 0;
-
-       dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;
-       dqtype |= (flags & XFS_QMOPT_PQUOTA) ? XFS_DQ_PROJ : 0;
-       dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;
-
-       mutex_lock(&q->qi_dqlist_lock);
-
-       /*
-        * In the first pass through all incore dquots of this filesystem,
-        * we release the group dquot pointers the user dquots may be
-        * carrying around as a hint. We need to do this irrespective of
-        * what's being turned off.
-        */
-       xfs_qm_detach_gdquots(mp);
-
-       /*
-        * Try to get rid of all of the unwanted dquots.
-        */
-       list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) {
-               xfs_dqlock(dqp);
-               if ((dqp->dq_flags & dqtype) != 0 &&
-                   !(dqp->dq_flags & XFS_DQ_FREEING)) {
-                       if (dqp->q_nrefs == 0) {
-                               dqp->dq_flags |= XFS_DQ_FREEING;
-                               list_move_tail(&dqp->q_mplist, &dispose_list);
-                       } else
-                               nmisses++;
-               }
-               xfs_dqunlock(dqp);
-       }
-       mutex_unlock(&q->qi_dqlist_lock);
-
-       list_for_each_entry_safe(dqp, n, &dispose_list, q_mplist)
-               xfs_qm_dqpurge(dqp);
-
-       return nmisses;
-}
-
-int
-xfs_qm_dqpurge_all(
-       xfs_mount_t     *mp,
-       uint            flags)
-{
-       int             ndquots;
-
-       /*
-        * Purge the dquot cache.
-        * None of the dquots should really be busy at this point.
-        */
-       if (mp->m_quotainfo) {
-               while ((ndquots = xfs_qm_dqpurge_int(mp, flags))) {
-                       delay(ndquots * 10);
-               }
-       }
-       return 0;
-}
-
 STATIC int
 xfs_qm_dqattach_one(
        xfs_inode_t     *ip,
@@ -783,14 +609,6 @@ xfs_qm_dqdetach(
 }
 
 /*
- * The hash chains and the mplist use the same xfs_dqhash structure as
- * their list head, but we can take the mplist qh_lock and one of the
- * hash qh_locks at the same time without any problem as they aren't
- * related.
- */
-static struct lock_class_key xfs_quota_mplist_class;
-
-/*
  * This initializes all the quota information that's kept in the
  * mount structure
  */
@@ -804,13 +622,6 @@ xfs_qm_init_quotainfo(
 
        ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
-       /*
-        * Tell XQM that we exist as soon as possible.
-        */
-       if ((error = xfs_qm_hold_quotafs_ref(mp))) {
-               return error;
-       }
-
        qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP);
 
        /*
@@ -823,11 +634,13 @@ xfs_qm_init_quotainfo(
                return error;
        }
 
-       INIT_LIST_HEAD(&qinf->qi_dqlist);
-       mutex_init(&qinf->qi_dqlist_lock);
-       lockdep_set_class(&qinf->qi_dqlist_lock, &xfs_quota_mplist_class);
+       INIT_RADIX_TREE(&qinf->qi_uquota_tree, GFP_NOFS);
+       INIT_RADIX_TREE(&qinf->qi_gquota_tree, GFP_NOFS);
+       mutex_init(&qinf->qi_tree_lock);
 
-       qinf->qi_dqreclaims = 0;
+       INIT_LIST_HEAD(&qinf->qi_lru_list);
+       qinf->qi_lru_count = 0;
+       mutex_init(&qinf->qi_lru_lock);
 
        /* mutex used to serialize quotaoffs */
        mutex_init(&qinf->qi_quotaofflock);
@@ -894,6 +707,9 @@ xfs_qm_init_quotainfo(
                qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
        }
 
+       qinf->qi_shrinker.shrink = xfs_qm_shake;
+       qinf->qi_shrinker.seeks = DEFAULT_SEEKS;
+       register_shrinker(&qinf->qi_shrinker);
        return 0;
 }
 
@@ -911,17 +727,8 @@ xfs_qm_destroy_quotainfo(
 
        qi = mp->m_quotainfo;
        ASSERT(qi != NULL);
-       ASSERT(xfs_Gqm != NULL);
-
-       /*
-        * Release the reference that XQM kept, so that we know
-        * when the XQM structure should be freed. We cannot assume
-        * that xfs_Gqm is non-null after this point.
-        */
-       xfs_qm_rele_quotafs_ref(mp);
 
-       ASSERT(list_empty(&qi->qi_dqlist));
-       mutex_destroy(&qi->qi_dqlist_lock);
+       unregister_shrinker(&qi->qi_shrinker);
 
        if (qi->qi_uquotaip) {
                IRELE(qi->qi_uquotaip);
@@ -936,30 +743,6 @@ xfs_qm_destroy_quotainfo(
        mp->m_quotainfo = NULL;
 }
 
-
-
-/* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */
-
-/* ARGSUSED */
-STATIC void
-xfs_qm_list_init(
-       xfs_dqlist_t    *list,
-       char            *str,
-       int             n)
-{
-       mutex_init(&list->qh_lock);
-       INIT_LIST_HEAD(&list->qh_list);
-       list->qh_version = 0;
-       list->qh_nelems = 0;
-}
-
-STATIC void
-xfs_qm_list_destroy(
-       xfs_dqlist_t    *list)
-{
-       mutex_destroy(&(list->qh_lock));
-}
-
 /*
  * Create an inode and return with a reference already taken, but unlocked
  * This is how we create quota inodes
@@ -1397,6 +1180,28 @@ error0:
        return error;
 }
 
+STATIC int
+xfs_qm_flush_one(
+       struct xfs_dquot        *dqp)
+{
+       int                     error = 0;
+
+       xfs_dqlock(dqp);
+       if (dqp->dq_flags & XFS_DQ_FREEING)
+               goto out_unlock;
+       if (!XFS_DQ_IS_DIRTY(dqp))
+               goto out_unlock;
+
+       if (!xfs_dqflock_nowait(dqp))
+               xfs_dqflock_pushbuf_wait(dqp);
+
+       error = xfs_qm_dqflush(dqp, 0);
+
+out_unlock:
+       xfs_dqunlock(dqp);
+       return error;
+}
+
 /*
  * Walk thru all the filesystem inodes and construct a consistent view
  * of the disk quota world. If the quotacheck fails, disable quotas.
@@ -1405,7 +1210,7 @@ int
 xfs_qm_quotacheck(
        xfs_mount_t     *mp)
 {
-       int             done, count, error;
+       int             done, count, error, error2;
        xfs_ino_t       lastino;
        size_t          structsz;
        xfs_inode_t     *uip, *gip;
@@ -1419,12 +1224,6 @@ xfs_qm_quotacheck(
        ASSERT(mp->m_quotainfo->qi_uquotaip || mp->m_quotainfo->qi_gquotaip);
        ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
-       /*
-        * There should be no cached dquots. The (simplistic) quotacheck
-        * algorithm doesn't like that.
-        */
-       ASSERT(list_empty(&mp->m_quotainfo->qi_dqlist));
-
        xfs_notice(mp, "Quotacheck needed: Please wait.");
 
        /*
@@ -1463,12 +1262,21 @@ xfs_qm_quotacheck(
        } while (!done);
 
        /*
-        * We've made all the changes that we need to make incore.
-        * Flush them down to disk buffers if everything was updated
-        * successfully.
+        * We've made all the changes that we need to make incore.  Flush them
+        * down to disk buffers if everything was updated successfully.
         */
-       if (!error)
-               error = xfs_qm_dqflush_all(mp);
+       if (XFS_IS_UQUOTA_ON(mp))
+               error = xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_flush_one);
+       if (XFS_IS_GQUOTA_ON(mp)) {
+               error2 = xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_flush_one);
+               if (!error)
+                       error = error2;
+       }
+       if (XFS_IS_PQUOTA_ON(mp)) {
+               error2 = xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_flush_one);
+               if (!error)
+                       error = error2;
+       }
 
        /*
         * We can get this error if we couldn't do a dquot allocation inside
@@ -1496,7 +1304,7 @@ xfs_qm_quotacheck(
         * quotachecked status, since we won't be doing accounting for
         * that type anymore.
         */
-       mp->m_qflags &= ~(XFS_OQUOTA_CHKD | XFS_UQUOTA_CHKD);
+       mp->m_qflags &= ~XFS_ALL_QUOTA_CHKD;
        mp->m_qflags |= flags;
 
  error_return:
@@ -1508,7 +1316,6 @@ xfs_qm_quotacheck(
                 * We must turn off quotas.
                 */
                ASSERT(mp->m_quotainfo != NULL);
-               ASSERT(xfs_Gqm != NULL);
                xfs_qm_destroy_quotainfo(mp);
                if (xfs_mount_reset_sbqflags(mp)) {
                        xfs_warn(mp,
@@ -1604,16 +1411,12 @@ xfs_qm_dqfree_one(
        struct xfs_mount        *mp = dqp->q_mount;
        struct xfs_quotainfo    *qi = mp->m_quotainfo;
 
-       mutex_lock(&dqp->q_hash->qh_lock);
-       list_del_init(&dqp->q_hashlist);
-       dqp->q_hash->qh_version++;
-       mutex_unlock(&dqp->q_hash->qh_lock);
+       mutex_lock(&qi->qi_tree_lock);
+       radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
+                         be32_to_cpu(dqp->q_core.d_id));
 
-       mutex_lock(&qi->qi_dqlist_lock);
-       list_del_init(&dqp->q_mplist);
        qi->qi_dquots--;
-       qi->qi_dqreclaims++;
-       mutex_unlock(&qi->qi_dqlist_lock);
+       mutex_unlock(&qi->qi_tree_lock);
 
        xfs_qm_dqdestroy(dqp);
 }
@@ -1624,6 +1427,7 @@ xfs_qm_dqreclaim_one(
        struct list_head        *dispose_list)
 {
        struct xfs_mount        *mp = dqp->q_mount;
+       struct xfs_quotainfo    *qi = mp->m_quotainfo;
        int                     error;
 
        if (!xfs_dqlock_nowait(dqp))
@@ -1637,16 +1441,14 @@ xfs_qm_dqreclaim_one(
                xfs_dqunlock(dqp);
 
                trace_xfs_dqreclaim_want(dqp);
-               XQM_STATS_INC(xqmstats.xs_qm_dqwants);
+               XFS_STATS_INC(xs_qm_dqwants);
 
-               list_del_init(&dqp->q_freelist);
-               xfs_Gqm->qm_dqfrlist_cnt--;
+               list_del_init(&dqp->q_lru);
+               qi->qi_lru_count--;
+               XFS_STATS_DEC(xs_qm_dquot_unused);
                return;
        }
 
-       ASSERT(dqp->q_hash);
-       ASSERT(!list_empty(&dqp->q_mplist));
-
        /*
         * Try to grab the flush lock. If this dquot is in the process of
         * getting flushed to disk, we don't want to reclaim it.
@@ -1688,11 +1490,12 @@ xfs_qm_dqreclaim_one(
        xfs_dqunlock(dqp);
 
        ASSERT(dqp->q_nrefs == 0);
-       list_move_tail(&dqp->q_freelist, dispose_list);
-       xfs_Gqm->qm_dqfrlist_cnt--;
+       list_move_tail(&dqp->q_lru, dispose_list);
+       qi->qi_lru_count--;
+       XFS_STATS_DEC(xs_qm_dquot_unused);
 
        trace_xfs_dqreclaim_done(dqp);
-       XQM_STATS_INC(xqmstats.xs_qm_dqreclaims);
+       XFS_STATS_INC(xs_qm_dqreclaims);
        return;
 
 out_busy:
@@ -1701,10 +1504,10 @@ out_busy:
        /*
         * Move the dquot to the tail of the list so that we don't spin on it.
         */
-       list_move_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
+       list_move_tail(&dqp->q_lru, &qi->qi_lru_list);
 
        trace_xfs_dqreclaim_busy(dqp);
-       XQM_STATS_INC(xqmstats.xs_qm_dqreclaim_misses);
+       XFS_STATS_INC(xs_qm_dqreclaim_misses);
 }
 
 STATIC int
@@ -1712,6 +1515,8 @@ xfs_qm_shake(
        struct shrinker         *shrink,
        struct shrink_control   *sc)
 {
+       struct xfs_quotainfo    *qi =
+               container_of(shrink, struct xfs_quotainfo, qi_shrinker);
        int                     nr_to_scan = sc->nr_to_scan;
        LIST_HEAD               (dispose_list);
        struct xfs_dquot        *dqp;
@@ -1721,24 +1526,23 @@ xfs_qm_shake(
        if (!nr_to_scan)
                goto out;
 
-       mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
-       while (!list_empty(&xfs_Gqm->qm_dqfrlist)) {
+       mutex_lock(&qi->qi_lru_lock);
+       while (!list_empty(&qi->qi_lru_list)) {
                if (nr_to_scan-- <= 0)
                        break;
-               dqp = list_first_entry(&xfs_Gqm->qm_dqfrlist, struct xfs_dquot,
-                                      q_freelist);
+               dqp = list_first_entry(&qi->qi_lru_list, struct xfs_dquot,
+                                      q_lru);
                xfs_qm_dqreclaim_one(dqp, &dispose_list);
        }
-       mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+       mutex_unlock(&qi->qi_lru_lock);
 
        while (!list_empty(&dispose_list)) {
-               dqp = list_first_entry(&dispose_list, struct xfs_dquot,
-                                      q_freelist);
-               list_del_init(&dqp->q_freelist);
+               dqp = list_first_entry(&dispose_list, struct xfs_dquot, q_lru);
+               list_del_init(&dqp->q_lru);
                xfs_qm_dqfree_one(dqp);
        }
 out:
-       return (xfs_Gqm->qm_dqfrlist_cnt / 100) * sysctl_vfs_cache_pressure;
+       return (qi->qi_lru_count / 100) * sysctl_vfs_cache_pressure;
 }
 
 /*
index 9a9b997..44b858b 100644 (file)
 #include "xfs_dquot_item.h"
 #include "xfs_dquot.h"
 #include "xfs_quota_priv.h"
-#include "xfs_qm_stats.h"
 
-struct xfs_qm;
 struct xfs_inode;
 
-extern struct mutex    xfs_Gqm_lock;
-extern struct xfs_qm   *xfs_Gqm;
-extern kmem_zone_t     *qm_dqzone;
-extern kmem_zone_t     *qm_dqtrxzone;
-
-/*
- * Dquot hashtable constants/threshold values.
- */
-#define XFS_QM_HASHSIZE_LOW            (PAGE_SIZE / sizeof(xfs_dqhash_t))
-#define XFS_QM_HASHSIZE_HIGH           ((PAGE_SIZE * 4) / sizeof(xfs_dqhash_t))
+extern struct kmem_zone        *xfs_qm_dqtrxzone;
 
 /*
  * This defines the unit of allocation of dquots.
@@ -48,36 +37,20 @@ extern kmem_zone_t  *qm_dqtrxzone;
  */
 #define XFS_DQUOT_CLUSTER_SIZE_FSB     (xfs_filblks_t)1
 
-typedef xfs_dqhash_t   xfs_dqlist_t;
-
-/*
- * Quota Manager (global) structure. Lives only in core.
- */
-typedef struct xfs_qm {
-       xfs_dqlist_t    *qm_usr_dqhtable;/* udquot hash table */
-       xfs_dqlist_t    *qm_grp_dqhtable;/* gdquot hash table */
-       uint             qm_dqhashmask;  /* # buckets in dq hashtab - 1 */
-       struct list_head qm_dqfrlist;    /* freelist of dquots */
-       struct mutex     qm_dqfrlist_lock;
-       int              qm_dqfrlist_cnt;
-       atomic_t         qm_totaldquots; /* total incore dquots */
-       uint             qm_nrefs;       /* file systems with quota on */
-       kmem_zone_t     *qm_dqzone;      /* dquot mem-alloc zone */
-       kmem_zone_t     *qm_dqtrxzone;   /* t_dqinfo of transactions */
-} xfs_qm_t;
-
 /*
  * Various quota information for individual filesystems.
  * The mount structure keeps a pointer to this.
  */
 typedef struct xfs_quotainfo {
+       struct radix_tree_root qi_uquota_tree;
+       struct radix_tree_root qi_gquota_tree;
+       struct mutex qi_tree_lock;
        xfs_inode_t     *qi_uquotaip;    /* user quota inode */
        xfs_inode_t     *qi_gquotaip;    /* group quota inode */
-       struct list_head qi_dqlist;      /* all dquots in filesys */
-       struct mutex     qi_dqlist_lock;
+       struct list_head qi_lru_list;
+       struct mutex     qi_lru_lock;
+       int              qi_lru_count;
        int              qi_dquots;
-       int              qi_dqreclaims;  /* a change here indicates
-                                           a removal in the dqlist */
        time_t           qi_btimelimit;  /* limit for blks timer */
        time_t           qi_itimelimit;  /* limit for inodes timer */
        time_t           qi_rtbtimelimit;/* limit for rt blks timer */
@@ -93,8 +66,14 @@ typedef struct xfs_quotainfo {
        xfs_qcnt_t       qi_isoftlimit;  /* default inode count soft limit */
        xfs_qcnt_t       qi_rtbhardlimit;/* default realtime blk hard limit */
        xfs_qcnt_t       qi_rtbsoftlimit;/* default realtime blk soft limit */
+       struct shrinker  qi_shrinker;
 } xfs_quotainfo_t;
 
+#define XFS_DQUOT_TREE(qi, type) \
+       ((type & XFS_DQ_USER) ? \
+        &((qi)->qi_uquota_tree) : \
+        &((qi)->qi_gquota_tree))
+
 
 extern void    xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long);
 extern int     xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *,
@@ -130,7 +109,7 @@ extern int          xfs_qm_quotacheck(xfs_mount_t *);
 extern int             xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
 
 /* dquot stuff */
-extern int             xfs_qm_dqpurge_all(xfs_mount_t *, uint);
+extern void            xfs_qm_dqpurge_all(xfs_mount_t *, uint);
 extern void            xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint);
 
 /* quota ops */
index a0a829a..e6986b5 100644 (file)
 STATIC void
 xfs_fill_statvfs_from_dquot(
        struct kstatfs          *statp,
-       xfs_disk_dquot_t        *dp)
+       struct xfs_dquot        *dqp)
 {
        __uint64_t              limit;
 
-       limit = dp->d_blk_softlimit ?
-               be64_to_cpu(dp->d_blk_softlimit) :
-               be64_to_cpu(dp->d_blk_hardlimit);
+       limit = dqp->q_core.d_blk_softlimit ?
+               be64_to_cpu(dqp->q_core.d_blk_softlimit) :
+               be64_to_cpu(dqp->q_core.d_blk_hardlimit);
        if (limit && statp->f_blocks > limit) {
                statp->f_blocks = limit;
                statp->f_bfree = statp->f_bavail =
-                       (statp->f_blocks > be64_to_cpu(dp->d_bcount)) ?
-                        (statp->f_blocks - be64_to_cpu(dp->d_bcount)) : 0;
+                       (statp->f_blocks > dqp->q_res_bcount) ?
+                        (statp->f_blocks - dqp->q_res_bcount) : 0;
        }
 
-       limit = dp->d_ino_softlimit ?
-               be64_to_cpu(dp->d_ino_softlimit) :
-               be64_to_cpu(dp->d_ino_hardlimit);
+       limit = dqp->q_core.d_ino_softlimit ?
+               be64_to_cpu(dqp->q_core.d_ino_softlimit) :
+               be64_to_cpu(dqp->q_core.d_ino_hardlimit);
        if (limit && statp->f_files > limit) {
                statp->f_files = limit;
                statp->f_ffree =
-                       (statp->f_files > be64_to_cpu(dp->d_icount)) ?
-                        (statp->f_ffree - be64_to_cpu(dp->d_icount)) : 0;
+                       (statp->f_files > dqp->q_res_icount) ?
+                        (statp->f_ffree - dqp->q_res_icount) : 0;
        }
 }
 
@@ -82,7 +82,7 @@ xfs_qm_statvfs(
        xfs_dquot_t             *dqp;
 
        if (!xfs_qm_dqget(mp, NULL, xfs_get_projid(ip), XFS_DQ_PROJ, 0, &dqp)) {
-               xfs_fill_statvfs_from_dquot(statp, &dqp->q_core);
+               xfs_fill_statvfs_from_dquot(statp, dqp);
                xfs_qm_dqput(dqp);
        }
 }
@@ -156,21 +156,3 @@ xfs_qm_newmount(
 
        return 0;
 }
-
-void __init
-xfs_qm_init(void)
-{
-       printk(KERN_INFO "SGI XFS Quota Management subsystem\n");
-       mutex_init(&xfs_Gqm_lock);
-       xfs_qm_init_procfs();
-}
-
-void __exit
-xfs_qm_exit(void)
-{
-       xfs_qm_cleanup_procfs();
-       if (qm_dqzone)
-               kmem_zone_destroy(qm_dqzone);
-       if (qm_dqtrxzone)
-               kmem_zone_destroy(qm_dqtrxzone);
-}
diff --git a/fs/xfs/xfs_qm_stats.c b/fs/xfs/xfs_qm_stats.c
deleted file mode 100644 (file)
index 5729ba5..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_bit.h"
-#include "xfs_log.h"
-#include "xfs_inum.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_alloc.h"
-#include "xfs_quota.h"
-#include "xfs_mount.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_inode.h"
-#include "xfs_itable.h"
-#include "xfs_bmap.h"
-#include "xfs_rtalloc.h"
-#include "xfs_error.h"
-#include "xfs_attr.h"
-#include "xfs_buf_item.h"
-#include "xfs_qm.h"
-
-struct xqmstats xqmstats;
-
-static int xqm_proc_show(struct seq_file *m, void *v)
-{
-       /* maximum; incore; ratio free to inuse; freelist */
-       seq_printf(m, "%d\t%d\t%d\t%u\n",
-                       0,
-                       xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0,
-                       0,
-                       xfs_Gqm? xfs_Gqm->qm_dqfrlist_cnt : 0);
-       return 0;
-}
-
-static int xqm_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, xqm_proc_show, NULL);
-}
-
-static const struct file_operations xqm_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = xqm_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int xqmstat_proc_show(struct seq_file *m, void *v)
-{
-       /* quota performance statistics */
-       seq_printf(m, "qm %u %u %u %u %u %u %u %u\n",
-                       xqmstats.xs_qm_dqreclaims,
-                       xqmstats.xs_qm_dqreclaim_misses,
-                       xqmstats.xs_qm_dquot_dups,
-                       xqmstats.xs_qm_dqcachemisses,
-                       xqmstats.xs_qm_dqcachehits,
-                       xqmstats.xs_qm_dqwants,
-                       xqmstats.xs_qm_dqshake_reclaims,
-                       xqmstats.xs_qm_dqinact_reclaims);
-       return 0;
-}
-
-static int xqmstat_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, xqmstat_proc_show, NULL);
-}
-
-static const struct file_operations xqmstat_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = xqmstat_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-void
-xfs_qm_init_procfs(void)
-{
-       proc_create("fs/xfs/xqmstat", 0, NULL, &xqmstat_proc_fops);
-       proc_create("fs/xfs/xqm", 0, NULL, &xqm_proc_fops);
-}
-
-void
-xfs_qm_cleanup_procfs(void)
-{
-       remove_proc_entry("fs/xfs/xqm", NULL);
-       remove_proc_entry("fs/xfs/xqmstat", NULL);
-}
diff --git a/fs/xfs/xfs_qm_stats.h b/fs/xfs/xfs_qm_stats.h
deleted file mode 100644 (file)
index 5b964fc..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2002 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would 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 the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#ifndef __XFS_QM_STATS_H__
-#define __XFS_QM_STATS_H__
-
-#if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF)
-
-/*
- * XQM global statistics
- */
-struct xqmstats {
-       __uint32_t              xs_qm_dqreclaims;
-       __uint32_t              xs_qm_dqreclaim_misses;
-       __uint32_t              xs_qm_dquot_dups;
-       __uint32_t              xs_qm_dqcachemisses;
-       __uint32_t              xs_qm_dqcachehits;
-       __uint32_t              xs_qm_dqwants;
-       __uint32_t              xs_qm_dqshake_reclaims;
-       __uint32_t              xs_qm_dqinact_reclaims;
-};
-
-extern struct xqmstats xqmstats;
-
-# define XQM_STATS_INC(count)  ( (count)++ )
-
-extern void xfs_qm_init_procfs(void);
-extern void xfs_qm_cleanup_procfs(void);
-
-#else
-
-# define XQM_STATS_INC(count)  do { } while (0)
-
-static inline void xfs_qm_init_procfs(void) { };
-static inline void xfs_qm_cleanup_procfs(void) { };
-
-#endif
-
-#endif /* __XFS_QM_STATS_H__ */
index 711a86e..c4f396e 100644 (file)
@@ -47,9 +47,6 @@ STATIC int    xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
                                        uint);
 STATIC uint    xfs_qm_export_flags(uint);
 STATIC uint    xfs_qm_export_qtype_flags(uint);
-STATIC void    xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *,
-                                       fs_disk_quota_t *);
-
 
 /*
  * Turn off quota accounting and/or enforcement for all udquots and/or
@@ -69,7 +66,6 @@ xfs_qm_scall_quotaoff(
        int                     error;
        uint                    inactivate_flags;
        xfs_qoff_logitem_t      *qoffstart;
-       int                     nculprits;
 
        /*
         * No file system can have quotas enabled on disk but not in core.
@@ -175,18 +171,13 @@ xfs_qm_scall_quotaoff(
         * This isn't protected by a particular lock directly, because we
         * don't want to take a mrlock every time we depend on quotas being on.
         */
-       mp->m_qflags &= ~(flags);
+       mp->m_qflags &= ~flags;
 
        /*
         * Go through all the dquots of this file system and purge them,
-        * according to what was turned off. We may not be able to get rid
-        * of all dquots, because dquots can have temporary references that
-        * are not attached to inodes. eg. xfs_setattr, xfs_create.
-        * So, if we couldn't purge all the dquots from the filesystem,
-        * we can't get rid of the incore data structures.
+        * according to what was turned off.
         */
-       while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype)))
-               delay(10 * nculprits);
+       xfs_qm_dqpurge_all(mp, dqtype);
 
        /*
         * Transactions that had started before ACTIVE state bit was cleared
@@ -635,42 +626,6 @@ xfs_qm_scall_setqlim(
        return error;
 }
 
-int
-xfs_qm_scall_getquota(
-       xfs_mount_t     *mp,
-       xfs_dqid_t      id,
-       uint            type,
-       fs_disk_quota_t *out)
-{
-       xfs_dquot_t     *dqp;
-       int             error;
-
-       /*
-        * Try to get the dquot. We don't want it allocated on disk, so
-        * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
-        * exist, we'll get ENOENT back.
-        */
-       if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) {
-               return (error);
-       }
-
-       /*
-        * If everything's NULL, this dquot doesn't quite exist as far as
-        * our utility programs are concerned.
-        */
-       if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
-               xfs_qm_dqput(dqp);
-               return XFS_ERROR(ENOENT);
-       }
-       /*
-        * Convert the disk dquot to the exportable format
-        */
-       xfs_qm_export_dquot(mp, &dqp->q_core, out);
-       xfs_qm_dqput(dqp);
-       return (error ? XFS_ERROR(EFAULT) : 0);
-}
-
-
 STATIC int
 xfs_qm_log_quotaoff_end(
        xfs_mount_t             *mp,
@@ -759,50 +714,66 @@ error0:
 }
 
 
-/*
- * Translate an internal style on-disk-dquot to the exportable format.
- * The main differences are that the counters/limits are all in Basic
- * Blocks (BBs) instead of the internal FSBs, and all on-disk data has
- * to be converted to the native endianness.
- */
-STATIC void
-xfs_qm_export_dquot(
-       xfs_mount_t             *mp,
-       xfs_disk_dquot_t        *src,
+int
+xfs_qm_scall_getquota(
+       struct xfs_mount        *mp,
+       xfs_dqid_t              id,
+       uint                    type,
        struct fs_disk_quota    *dst)
 {
+       struct xfs_dquot        *dqp;
+       int                     error;
+
+       /*
+        * Try to get the dquot. We don't want it allocated on disk, so
+        * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
+        * exist, we'll get ENOENT back.
+        */
+       error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp);
+       if (error)
+               return error;
+
+       /*
+        * If everything's NULL, this dquot doesn't quite exist as far as
+        * our utility programs are concerned.
+        */
+       if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+               error = XFS_ERROR(ENOENT);
+               goto out_put;
+       }
+
        memset(dst, 0, sizeof(*dst));
-       dst->d_version = FS_DQUOT_VERSION;  /* different from src->d_version */
-       dst->d_flags = xfs_qm_export_qtype_flags(src->d_flags);
-       dst->d_id = be32_to_cpu(src->d_id);
+       dst->d_version = FS_DQUOT_VERSION;
+       dst->d_flags = xfs_qm_export_qtype_flags(dqp->q_core.d_flags);
+       dst->d_id = be32_to_cpu(dqp->q_core.d_id);
        dst->d_blk_hardlimit =
-               XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_blk_hardlimit));
+               XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
        dst->d_blk_softlimit =
-               XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_blk_softlimit));
-       dst->d_ino_hardlimit = be64_to_cpu(src->d_ino_hardlimit);
-       dst->d_ino_softlimit = be64_to_cpu(src->d_ino_softlimit);
-       dst->d_bcount = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_bcount));
-       dst->d_icount = be64_to_cpu(src->d_icount);
-       dst->d_btimer = be32_to_cpu(src->d_btimer);
-       dst->d_itimer = be32_to_cpu(src->d_itimer);
-       dst->d_iwarns = be16_to_cpu(src->d_iwarns);
-       dst->d_bwarns = be16_to_cpu(src->d_bwarns);
+               XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_blk_softlimit));
+       dst->d_ino_hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
+       dst->d_ino_softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
+       dst->d_bcount = XFS_FSB_TO_BB(mp, dqp->q_res_bcount);
+       dst->d_icount = dqp->q_res_icount;
+       dst->d_btimer = be32_to_cpu(dqp->q_core.d_btimer);
+       dst->d_itimer = be32_to_cpu(dqp->q_core.d_itimer);
+       dst->d_iwarns = be16_to_cpu(dqp->q_core.d_iwarns);
+       dst->d_bwarns = be16_to_cpu(dqp->q_core.d_bwarns);
        dst->d_rtb_hardlimit =
-               XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtb_hardlimit));
+               XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_rtb_hardlimit));
        dst->d_rtb_softlimit =
-               XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtb_softlimit));
-       dst->d_rtbcount = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtbcount));
-       dst->d_rtbtimer = be32_to_cpu(src->d_rtbtimer);
-       dst->d_rtbwarns = be16_to_cpu(src->d_rtbwarns);
+               XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit));
+       dst->d_rtbcount = XFS_FSB_TO_BB(mp, dqp->q_res_rtbcount);
+       dst->d_rtbtimer = be32_to_cpu(dqp->q_core.d_rtbtimer);
+       dst->d_rtbwarns = be16_to_cpu(dqp->q_core.d_rtbwarns);
 
        /*
         * Internally, we don't reset all the timers when quota enforcement
         * gets turned off. No need to confuse the user level code,
         * so return zeroes in that case.
         */
-       if ((!XFS_IS_UQUOTA_ENFORCED(mp) && src->d_flags == XFS_DQ_USER) ||
+       if ((!XFS_IS_UQUOTA_ENFORCED(mp) && dqp->q_core.d_flags == XFS_DQ_USER) ||
            (!XFS_IS_OQUOTA_ENFORCED(mp) &&
-                       (src->d_flags & (XFS_DQ_PROJ | XFS_DQ_GROUP)))) {
+                       (dqp->q_core.d_flags & (XFS_DQ_PROJ | XFS_DQ_GROUP)))) {
                dst->d_btimer = 0;
                dst->d_itimer = 0;
                dst->d_rtbtimer = 0;
@@ -823,6 +794,9 @@ xfs_qm_export_dquot(
                }
        }
 #endif
+out_put:
+       xfs_qm_dqput(dqp);
+       return error;
 }
 
 STATIC uint
index 8a0807e..b50ec5b 100644 (file)
@@ -174,6 +174,8 @@ typedef struct xfs_qoff_logformat {
 #define XFS_UQUOTA_ACTIVE      0x0100  /* uquotas are being turned off */
 #define XFS_PQUOTA_ACTIVE      0x0200  /* pquotas are being turned off */
 #define XFS_GQUOTA_ACTIVE      0x0400  /* gquotas are being turned off */
+#define XFS_ALL_QUOTA_ACTIVE   \
+       (XFS_UQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE)
 
 /*
  * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees
index 94a3d92..6d86219 100644 (file)
  */
 #define XFS_DQITER_MAP_SIZE    10
 
-/*
- * Hash into a bucket in the dquot hash table, based on <mp, id>.
- */
-#define XFS_DQ_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \
-                                (__psunsigned_t)(id)) & \
-                               (xfs_Gqm->qm_dqhashmask - 1))
-#define XFS_DQ_HASH(mp, id, type)   (type == XFS_DQ_USER ? \
-                                    (xfs_Gqm->qm_usr_dqhtable + \
-                                     XFS_DQ_HASHVAL(mp, id)) : \
-                                    (xfs_Gqm->qm_grp_dqhtable + \
-                                     XFS_DQ_HASHVAL(mp, id)))
 #define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \
        !dqp->q_core.d_blk_hardlimit && \
        !dqp->q_core.d_blk_softlimit && \
index 87323f1..ca4f315 100644 (file)
@@ -183,6 +183,7 @@ error_cancel:
                oblocks = map.br_startoff + map.br_blockcount;
        }
        return 0;
+
 error:
        return error;
 }
@@ -2139,11 +2140,9 @@ xfs_rtfree_extent(
        xfs_buf_t       *sumbp;         /* summary file block buffer */
 
        mp = tp->t_mountp;
-       /*
-        * Synchronize by locking the bitmap inode.
-        */
-       xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+
+       ASSERT(mp->m_rbmip->i_itemp != NULL);
+       ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
 
 #if defined(__KERNEL__) && defined(DEBUG)
        /*
index cb6ae71..f429d9d 100644 (file)
@@ -529,7 +529,6 @@ static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp)
 #define        XFS_BB_TO_FSB(mp,bb)    \
        (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
 #define        XFS_BB_TO_FSBT(mp,bb)   ((bb) >> (mp)->m_blkbb_log)
-#define        XFS_BB_FSB_OFFSET(mp,bb) ((bb) & ((mp)->m_bsize - 1))
 
 /*
  * File system block to byte conversions.
index 76fdc58..ce372b7 100644 (file)
 
 DEFINE_PER_CPU(struct xfsstats, xfsstats);
 
+static int counter_val(int idx)
+{
+       int val = 0, cpu;
+
+       for_each_possible_cpu(cpu)
+               val += *(((__u32 *)&per_cpu(xfsstats, cpu) + idx));
+       return val;
+}
+
 static int xfs_stat_proc_show(struct seq_file *m, void *v)
 {
-       int             c, i, j, val;
+       int             i, j;
        __uint64_t      xs_xstrat_bytes = 0;
        __uint64_t      xs_write_bytes = 0;
        __uint64_t      xs_read_bytes = 0;
@@ -50,20 +59,16 @@ static int xfs_stat_proc_show(struct seq_file *m, void *v)
                { "abtc2",              XFSSTAT_END_ABTC_V2             },
                { "bmbt2",              XFSSTAT_END_BMBT_V2             },
                { "ibt2",               XFSSTAT_END_IBT_V2              },
+               /* we print both series of quota information together */
+               { "qm",                 XFSSTAT_END_QM                  },
        };
 
        /* Loop over all stats groups */
-       for (i=j = 0; i < ARRAY_SIZE(xstats); i++) {
+       for (i = j = 0; i < ARRAY_SIZE(xstats); i++) {
                seq_printf(m, "%s", xstats[i].desc);
                /* inner loop does each group */
-               while (j < xstats[i].endpoint) {
-                       val = 0;
-                       /* sum over all cpus */
-                       for_each_possible_cpu(c)
-                               val += *(((__u32*)&per_cpu(xfsstats, c) + j));
-                       seq_printf(m, " %u", val);
-                       j++;
-               }
+               for (; j < xstats[i].endpoint; j++)
+                       seq_printf(m, " %u", counter_val(j));
                seq_putc(m, '\n');
        }
        /* extra precision counters */
@@ -97,6 +102,58 @@ static const struct file_operations xfs_stat_proc_fops = {
        .release        = single_release,
 };
 
+/* legacy quota interfaces */
+#ifdef CONFIG_XFS_QUOTA
+static int xqm_proc_show(struct seq_file *m, void *v)
+{
+       /* maximum; incore; ratio free to inuse; freelist */
+       seq_printf(m, "%d\t%d\t%d\t%u\n",
+                       0,
+                       counter_val(XFSSTAT_END_XQMSTAT),
+                       0,
+                       counter_val(XFSSTAT_END_XQMSTAT + 1));
+       return 0;
+}
+
+static int xqm_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, xqm_proc_show, NULL);
+}
+
+static const struct file_operations xqm_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = xqm_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/* legacy quota stats interface no 2 */
+static int xqmstat_proc_show(struct seq_file *m, void *v)
+{
+       int j;
+
+       seq_printf(m, "qm");
+       for (j = XFSSTAT_END_IBT_V2; j < XFSSTAT_END_XQMSTAT; j++)
+               seq_printf(m, " %u", counter_val(j));
+       seq_putc(m, '\n');
+       return 0;
+}
+
+static int xqmstat_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, xqmstat_proc_show, NULL);
+}
+
+static const struct file_operations xqmstat_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = xqmstat_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif /* CONFIG_XFS_QUOTA */
+
 int
 xfs_init_procfs(void)
 {
@@ -105,10 +162,24 @@ xfs_init_procfs(void)
 
        if (!proc_create("fs/xfs/stat", 0, NULL,
                         &xfs_stat_proc_fops))
-               goto out_remove_entry;
+               goto out_remove_xfs_dir;
+#ifdef CONFIG_XFS_QUOTA
+       if (!proc_create("fs/xfs/xqmstat", 0, NULL,
+                        &xqmstat_proc_fops))
+               goto out_remove_stat_file;
+       if (!proc_create("fs/xfs/xqm", 0, NULL,
+                        &xqm_proc_fops))
+               goto out_remove_xqmstat_file;
+#endif
        return 0;
 
- out_remove_entry:
+#ifdef CONFIG_XFS_QUOTA
+ out_remove_xqmstat_file:
+       remove_proc_entry("fs/xfs/xqmstat", NULL);
+ out_remove_stat_file:
+       remove_proc_entry("fs/xfs/stat", NULL);
+#endif
+ out_remove_xfs_dir:
        remove_proc_entry("fs/xfs", NULL);
  out:
        return -ENOMEM;
@@ -117,6 +188,10 @@ xfs_init_procfs(void)
 void
 xfs_cleanup_procfs(void)
 {
+#ifdef CONFIG_XFS_QUOTA
+       remove_proc_entry("fs/xfs/xqm", NULL);
+       remove_proc_entry("fs/xfs/xqmstat", NULL);
+#endif
        remove_proc_entry("fs/xfs/stat", NULL);
        remove_proc_entry("fs/xfs", NULL);
 }
index 736854b..c03ad38 100644 (file)
@@ -183,6 +183,16 @@ struct xfsstats {
        __uint32_t              xs_ibt_2_alloc;
        __uint32_t              xs_ibt_2_free;
        __uint32_t              xs_ibt_2_moves;
+#define XFSSTAT_END_XQMSTAT            (XFSSTAT_END_IBT_V2+6)
+       __uint32_t              xs_qm_dqreclaims;
+       __uint32_t              xs_qm_dqreclaim_misses;
+       __uint32_t              xs_qm_dquot_dups;
+       __uint32_t              xs_qm_dqcachemisses;
+       __uint32_t              xs_qm_dqcachehits;
+       __uint32_t              xs_qm_dqwants;
+#define XFSSTAT_END_QM                 (XFSSTAT_END_XQMSTAT+2)
+       __uint32_t              xs_qm_dquot;
+       __uint32_t              xs_qm_dquot_unused;
 /* Extra precision counters */
        __uint64_t              xs_xstrat_bytes;
        __uint64_t              xs_write_bytes;
index baf40e3..dab9a5f 100644 (file)
@@ -324,10 +324,9 @@ xfs_parseargs(
                } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) {
                        mp->m_flags |= XFS_MOUNT_FILESTREAMS;
                } else if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
-                       mp->m_qflags &= ~(XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE |
-                                         XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
-                                         XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE |
-                                         XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD);
+                       mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT;
+                       mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD;
+                       mp->m_qflags &= ~XFS_ALL_QUOTA_ACTIVE;
                } else if (!strcmp(this_char, MNTOPT_QUOTA) ||
                           !strcmp(this_char, MNTOPT_UQUOTA) ||
                           !strcmp(this_char, MNTOPT_USRQUOTA)) {
@@ -760,6 +759,36 @@ xfs_setup_devices(
        return 0;
 }
 
+STATIC int
+xfs_init_mount_workqueues(
+       struct xfs_mount        *mp)
+{
+       mp->m_data_workqueue = alloc_workqueue("xfs-data/%s",
+                       WQ_MEM_RECLAIM, 0, mp->m_fsname);
+       if (!mp->m_data_workqueue)
+               goto out;
+
+       mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s",
+                       WQ_MEM_RECLAIM, 0, mp->m_fsname);
+       if (!mp->m_unwritten_workqueue)
+               goto out_destroy_data_iodone_queue;
+
+       return 0;
+
+out_destroy_data_iodone_queue:
+       destroy_workqueue(mp->m_data_workqueue);
+out:
+       return -ENOMEM;
+}
+
+STATIC void
+xfs_destroy_mount_workqueues(
+       struct xfs_mount        *mp)
+{
+       destroy_workqueue(mp->m_data_workqueue);
+       destroy_workqueue(mp->m_unwritten_workqueue);
+}
+
 /* Catch misguided souls that try to use this interface on XFS */
 STATIC struct inode *
 xfs_fs_alloc_inode(
@@ -834,91 +863,58 @@ xfs_fs_inode_init_once(
 }
 
 /*
- * Dirty the XFS inode when mark_inode_dirty_sync() is called so that
- * we catch unlogged VFS level updates to the inode.
+ * 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 need the barrier() to maintain correct ordering between unlogged
- * updates and the transaction commit code that clears the i_update_core
- * field. This requires all updates to be completed before marking the
- * inode dirty.
+ * 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)
-{
-       barrier();
-       XFS_I(inode)->i_update_core = 1;
-}
-
-STATIC int
-xfs_fs_write_inode(
        struct inode            *inode,
-       struct writeback_control *wbc)
+       int                     flags)
 {
        struct xfs_inode        *ip = XFS_I(inode);
        struct xfs_mount        *mp = ip->i_mount;
-       int                     error = EAGAIN;
-
-       trace_xfs_write_inode(ip);
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return -XFS_ERROR(EIO);
+       struct xfs_trans        *tp;
+       int                     error;
 
-       if (wbc->sync_mode == WB_SYNC_ALL || wbc->for_kupdate) {
-               /*
-                * Make sure the inode has made it it into the log.  Instead
-                * of forcing it all the way to stable storage using a
-                * synchronous transaction we let the log force inside the
-                * ->sync_fs call do that for thus, which reduces the number
-                * of synchronous log forces dramatically.
-                */
-               error = xfs_log_dirty_inode(ip, NULL, 0);
-               if (error)
-                       goto out;
-               return 0;
-       } else {
-               if (!ip->i_update_core)
-                       return 0;
+       if (flags != I_DIRTY_SYNC)
+               return;
 
-               /*
-                * We make this non-blocking if the inode is contended, return
-                * EAGAIN to indicate to the caller that they did not succeed.
-                * This prevents the flush path from blocking on inodes inside
-                * another operation right now, they get caught later by
-                * xfs_sync.
-                */
-               if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
-                       goto out;
+       trace_xfs_dirty_inode(ip);
 
-               if (xfs_ipincount(ip) || !xfs_iflock_nowait(ip))
-                       goto out_unlock;
-
-               /*
-                * Now we have the flush lock and the inode is not pinned, we
-                * can check if the inode is really clean as we know that
-                * there are no pending transaction completions, it is not
-                * waiting on the delayed write queue and there is no IO in
-                * progress.
-                */
-               if (xfs_inode_clean(ip)) {
-                       xfs_ifunlock(ip);
-                       error = 0;
-                       goto out_unlock;
-               }
-               error = xfs_iflush(ip, SYNC_TRYLOCK);
+       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;
        }
-
- out_unlock:
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
- out:
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
        /*
-        * if we failed to write out the inode then mark
-        * it dirty again so we'll try again later.
+        * 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)
-               xfs_mark_inode_dirty_sync(ip);
-       return -error;
+               goto trouble;
+       return;
+
+trouble:
+       xfs_warn(mp, "failed to update timestamps for inode 0x%llx", ip->i_ino);
 }
 
 STATIC void
@@ -954,6 +950,22 @@ xfs_fs_evict_inode(
        xfs_inactive(ip);
 }
 
+/*
+ * We do an unlocked check for XFS_IDONTCACHE here because we are already
+ * serialised against cache hits here via the inode->i_lock and igrab() in
+ * xfs_iget_cache_hit(). Hence a lookup that might clear this flag will not be
+ * racing with us, and it avoids needing to grab a spinlock here for every inode
+ * we drop the final reference on.
+ */
+STATIC int
+xfs_fs_drop_inode(
+       struct inode            *inode)
+{
+       struct xfs_inode        *ip = XFS_I(inode);
+
+       return generic_drop_inode(inode) || (ip->i_flags & XFS_IDONTCACHE);
+}
+
 STATIC void
 xfs_free_fsname(
        struct xfs_mount        *mp)
@@ -983,6 +995,7 @@ xfs_fs_put_super(
        xfs_unmountfs(mp);
        xfs_freesb(mp);
        xfs_icsb_destroy_counters(mp);
+       xfs_destroy_mount_workqueues(mp);
        xfs_close_devices(mp);
        xfs_free_fsname(mp);
        kfree(mp);
@@ -1309,10 +1322,14 @@ xfs_fs_fill_super(
        if (error)
                goto out_free_fsname;
 
-       error = xfs_icsb_init_counters(mp);
+       error = xfs_init_mount_workqueues(mp);
        if (error)
                goto out_close_devices;
 
+       error = xfs_icsb_init_counters(mp);
+       if (error)
+               goto out_destroy_workqueues;
+
        error = xfs_readsb(mp, flags);
        if (error)
                goto out_destroy_counters;
@@ -1376,6 +1393,8 @@ xfs_fs_fill_super(
        xfs_freesb(mp);
  out_destroy_counters:
        xfs_icsb_destroy_counters(mp);
+out_destroy_workqueues:
+       xfs_destroy_mount_workqueues(mp);
  out_close_devices:
        xfs_close_devices(mp);
  out_free_fsname:
@@ -1429,8 +1448,8 @@ 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,
-       .write_inode            = xfs_fs_write_inode,
        .evict_inode            = xfs_fs_evict_inode,
+       .drop_inode             = xfs_fs_drop_inode,
        .put_super              = xfs_fs_put_super,
        .sync_fs                = xfs_fs_sync_fs,
        .freeze_fs              = xfs_fs_freeze,
@@ -1604,12 +1623,28 @@ xfs_init_workqueues(void)
        xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_NON_REENTRANT, 0);
        if (!xfs_syncd_wq)
                return -ENOMEM;
+
+       /*
+        * The allocation workqueue can be used in memory reclaim situations
+        * (writepage path), and parallelism is only limited by the number of
+        * AGs in all the filesystems mounted. Hence use the default large
+        * max_active value for this workqueue.
+        */
+       xfs_alloc_wq = alloc_workqueue("xfsalloc", WQ_MEM_RECLAIM, 0);
+       if (!xfs_alloc_wq)
+               goto out_destroy_syncd;
+
        return 0;
+
+out_destroy_syncd:
+       destroy_workqueue(xfs_syncd_wq);
+       return -ENOMEM;
 }
 
 STATIC void
 xfs_destroy_workqueues(void)
 {
+       destroy_workqueue(xfs_alloc_wq);
        destroy_workqueue(xfs_syncd_wq);
 }
 
@@ -1651,13 +1686,17 @@ init_xfs_fs(void)
        if (error)
                goto out_cleanup_procfs;
 
-       vfs_initquota();
+       error = xfs_qm_init();
+       if (error)
+               goto out_sysctl_unregister;
 
        error = register_filesystem(&xfs_fs_type);
        if (error)
-               goto out_sysctl_unregister;
+               goto out_qm_exit;
        return 0;
 
+ out_qm_exit:
+       xfs_qm_exit();
  out_sysctl_unregister:
        xfs_sysctl_unregister();
  out_cleanup_procfs:
@@ -1679,7 +1718,7 @@ init_xfs_fs(void)
 STATIC void __exit
 exit_xfs_fs(void)
 {
-       vfs_exitquota();
+       xfs_qm_exit();
        unregister_filesystem(&xfs_fs_type);
        xfs_sysctl_unregister();
        xfs_cleanup_procfs();
index 50a3266..09b0c26 100644 (file)
 #include <linux/exportfs.h>
 
 #ifdef CONFIG_XFS_QUOTA
-extern void xfs_qm_init(void);
+extern int xfs_qm_init(void);
 extern void xfs_qm_exit(void);
-# define vfs_initquota()       xfs_qm_init()
-# define vfs_exitquota()       xfs_qm_exit()
 #else
-# define vfs_initquota()       do { } while (0)
-# define vfs_exitquota()       do { } while (0)
+# define xfs_qm_init() (0)
+# define xfs_qm_exit() do { } while (0)
 #endif
 
 #ifdef CONFIG_XFS_POSIX_ACL
index 40b75ee..205ebcb 100644 (file)
@@ -336,32 +336,6 @@ xfs_sync_fsdata(
        return error;
 }
 
-int
-xfs_log_dirty_inode(
-       struct xfs_inode        *ip,
-       struct xfs_perag        *pag,
-       int                     flags)
-{
-       struct xfs_mount        *mp = ip->i_mount;
-       struct xfs_trans        *tp;
-       int                     error;
-
-       if (!ip->i_update_core)
-               return 0;
-
-       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);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       return xfs_trans_commit(tp, 0);
-}
-
 /*
  * When remounting a filesystem read-only or freezing the filesystem, we have
  * two phases to execute. This first phase is syncing the data before we
@@ -385,16 +359,6 @@ xfs_quiesce_data(
 {
        int                     error, error2 = 0;
 
-       /*
-        * Log all pending size and timestamp updates.  The vfs writeback
-        * code is supposed to do this, but due to its overagressive
-        * livelock detection it will skip inodes where appending writes
-        * were written out in the first non-blocking sync phase if their
-        * completion took long enough that it happened after taking the
-        * timestamp for the cut-off in the blocking phase.
-        */
-       xfs_inode_ag_iterator(mp, xfs_log_dirty_inode, 0);
-
        /* force out the log */
        xfs_log_force(mp, XFS_LOG_SYNC);
 
@@ -913,17 +877,15 @@ reclaim:
         * can reference the inodes in the cache without taking references.
         *
         * We make that OK here by ensuring that we wait until the inode is
-        * unlocked after the lookup before we go ahead and free it.  We get
-        * both the ilock and the iolock because the code may need to drop the
-        * ilock one but will still hold the iolock.
+        * unlocked after the lookup before we go ahead and free it.
         */
-       xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_qm_dqdetach(ip);
-       xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
 
        xfs_inode_free(ip);
-       return error;
 
+       return error;
 }
 
 /*
index fa96547..941202e 100644 (file)
@@ -34,8 +34,6 @@ void xfs_quiesce_attr(struct xfs_mount *mp);
 
 void xfs_flush_inodes(struct xfs_inode *ip);
 
-int xfs_log_dirty_inode(struct xfs_inode *ip, struct xfs_perag *pag, int flags);
-
 int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
 int xfs_reclaim_inodes_count(struct xfs_mount *mp);
 void xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);
index bb134a8..06838c4 100644 (file)
@@ -580,7 +580,7 @@ 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_write_inode);
+DEFINE_INODE_EVENT(xfs_dirty_inode);
 DEFINE_INODE_EVENT(xfs_evict_inode);
 
 DEFINE_INODE_EVENT(xfs_dquot_dqalloc);
@@ -627,16 +627,19 @@ DECLARE_EVENT_CLASS(xfs_namespace_class,
        TP_STRUCT__entry(
                __field(dev_t, dev)
                __field(xfs_ino_t, dp_ino)
+               __field(int, namelen)
                __dynamic_array(char, name, name->len)
        ),
        TP_fast_assign(
                __entry->dev = VFS_I(dp)->i_sb->s_dev;
                __entry->dp_ino = dp->i_ino;
+               __entry->namelen = name->len;
                memcpy(__get_str(name), name->name, name->len);
        ),
-       TP_printk("dev %d:%d dp ino 0x%llx name %s",
+       TP_printk("dev %d:%d dp ino 0x%llx name %.*s",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->dp_ino,
+                 __entry->namelen,
                  __get_str(name))
 )
 
@@ -658,6 +661,8 @@ TRACE_EVENT(xfs_rename,
                __field(dev_t, dev)
                __field(xfs_ino_t, src_dp_ino)
                __field(xfs_ino_t, target_dp_ino)
+               __field(int, src_namelen)
+               __field(int, target_namelen)
                __dynamic_array(char, src_name, src_name->len)
                __dynamic_array(char, target_name, target_name->len)
        ),
@@ -665,15 +670,20 @@ TRACE_EVENT(xfs_rename,
                __entry->dev = VFS_I(src_dp)->i_sb->s_dev;
                __entry->src_dp_ino = src_dp->i_ino;
                __entry->target_dp_ino = target_dp->i_ino;
+               __entry->src_namelen = src_name->len;
+               __entry->target_namelen = target_name->len;
                memcpy(__get_str(src_name), src_name->name, src_name->len);
-               memcpy(__get_str(target_name), target_name->name, target_name->len);
+               memcpy(__get_str(target_name), target_name->name,
+                       target_name->len);
        ),
        TP_printk("dev %d:%d src dp ino 0x%llx target dp ino 0x%llx"
-                 " src name %s target name %s",
+                 " src name %.*s target name %.*s",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->src_dp_ino,
                  __entry->target_dp_ino,
+                 __entry->src_namelen,
                  __get_str(src_name),
+                 __entry->target_namelen,
                  __get_str(target_name))
 )
 
@@ -741,10 +751,10 @@ DEFINE_DQUOT_EVENT(xfs_dqalloc);
 DEFINE_DQUOT_EVENT(xfs_dqtobp_read);
 DEFINE_DQUOT_EVENT(xfs_dqread);
 DEFINE_DQUOT_EVENT(xfs_dqread_fail);
-DEFINE_DQUOT_EVENT(xfs_dqlookup_found);
-DEFINE_DQUOT_EVENT(xfs_dqlookup_done);
 DEFINE_DQUOT_EVENT(xfs_dqget_hit);
 DEFINE_DQUOT_EVENT(xfs_dqget_miss);
+DEFINE_DQUOT_EVENT(xfs_dqget_freeing);
+DEFINE_DQUOT_EVENT(xfs_dqget_dup);
 DEFINE_DQUOT_EVENT(xfs_dqput);
 DEFINE_DQUOT_EVENT(xfs_dqput_wait);
 DEFINE_DQUOT_EVENT(xfs_dqput_free);
@@ -782,12 +792,12 @@ DECLARE_EVENT_CLASS(xfs_loggrant_class,
                __entry->curr_res = tic->t_curr_res;
                __entry->unit_res = tic->t_unit_res;
                __entry->flags = tic->t_flags;
-               __entry->reserveq = list_empty(&log->l_reserveq);
-               __entry->writeq = list_empty(&log->l_writeq);
-               xlog_crack_grant_head(&log->l_grant_reserve_head,
+               __entry->reserveq = list_empty(&log->l_reserve_head.waiters);
+               __entry->writeq = list_empty(&log->l_write_head.waiters);
+               xlog_crack_grant_head(&log->l_reserve_head.grant,
                                &__entry->grant_reserve_cycle,
                                &__entry->grant_reserve_bytes);
-               xlog_crack_grant_head(&log->l_grant_write_head,
+               xlog_crack_grant_head(&log->l_write_head.grant,
                                &__entry->grant_write_cycle,
                                &__entry->grant_write_bytes);
                __entry->curr_cycle = log->l_curr_cycle;
@@ -826,20 +836,14 @@ DEFINE_EVENT(xfs_loggrant_class, name, \
        TP_ARGS(log, tic))
 DEFINE_LOGGRANT_EVENT(xfs_log_done_nonperm);
 DEFINE_LOGGRANT_EVENT(xfs_log_done_perm);
-DEFINE_LOGGRANT_EVENT(xfs_log_reserve);
 DEFINE_LOGGRANT_EVENT(xfs_log_umount_write);
-DEFINE_LOGGRANT_EVENT(xfs_log_grant_enter);
-DEFINE_LOGGRANT_EVENT(xfs_log_grant_exit);
-DEFINE_LOGGRANT_EVENT(xfs_log_grant_error);
 DEFINE_LOGGRANT_EVENT(xfs_log_grant_sleep);
 DEFINE_LOGGRANT_EVENT(xfs_log_grant_wake);
 DEFINE_LOGGRANT_EVENT(xfs_log_grant_wake_up);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_enter);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_exit);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_error);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_sleep);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_wake);
-DEFINE_LOGGRANT_EVENT(xfs_log_regrant_write_wake_up);
+DEFINE_LOGGRANT_EVENT(xfs_log_reserve);
+DEFINE_LOGGRANT_EVENT(xfs_log_reserve_exit);
+DEFINE_LOGGRANT_EVENT(xfs_log_regrant);
+DEFINE_LOGGRANT_EVENT(xfs_log_regrant_exit);
 DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_enter);
 DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_exit);
 DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_sub);
@@ -1414,7 +1418,7 @@ DEFINE_ALLOC_EVENT(xfs_alloc_vextent_noagbp);
 DEFINE_ALLOC_EVENT(xfs_alloc_vextent_loopfailed);
 DEFINE_ALLOC_EVENT(xfs_alloc_vextent_allfailed);
 
-DECLARE_EVENT_CLASS(xfs_dir2_class,
+DECLARE_EVENT_CLASS(xfs_da_class,
        TP_PROTO(struct xfs_da_args *args),
        TP_ARGS(args),
        TP_STRUCT__entry(
@@ -1449,7 +1453,7 @@ DECLARE_EVENT_CLASS(xfs_dir2_class,
 )
 
 #define DEFINE_DIR2_EVENT(name) \
-DEFINE_EVENT(xfs_dir2_class, name, \
+DEFINE_EVENT(xfs_da_class, name, \
        TP_PROTO(struct xfs_da_args *args), \
        TP_ARGS(args))
 DEFINE_DIR2_EVENT(xfs_dir2_sf_addname);
@@ -1478,6 +1482,64 @@ DEFINE_DIR2_EVENT(xfs_dir2_node_replace);
 DEFINE_DIR2_EVENT(xfs_dir2_node_removename);
 DEFINE_DIR2_EVENT(xfs_dir2_node_to_leaf);
 
+#define DEFINE_ATTR_EVENT(name) \
+DEFINE_EVENT(xfs_da_class, name, \
+       TP_PROTO(struct xfs_da_args *args), \
+       TP_ARGS(args))
+DEFINE_ATTR_EVENT(xfs_attr_sf_add);
+DEFINE_ATTR_EVENT(xfs_attr_sf_addname);
+DEFINE_ATTR_EVENT(xfs_attr_sf_create);
+DEFINE_ATTR_EVENT(xfs_attr_sf_lookup);
+DEFINE_ATTR_EVENT(xfs_attr_sf_remove);
+DEFINE_ATTR_EVENT(xfs_attr_sf_removename);
+DEFINE_ATTR_EVENT(xfs_attr_sf_to_leaf);
+
+DEFINE_ATTR_EVENT(xfs_attr_leaf_add);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_add_old);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_add_new);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_addname);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_create);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_lookup);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_replace);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_removename);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_split);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_split_before);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_split_after);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_clearflag);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_setflag);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_flipflags);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_to_sf);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_to_node);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_rebalance);
+DEFINE_ATTR_EVENT(xfs_attr_leaf_unbalance);
+
+DEFINE_ATTR_EVENT(xfs_attr_node_addname);
+DEFINE_ATTR_EVENT(xfs_attr_node_lookup);
+DEFINE_ATTR_EVENT(xfs_attr_node_replace);
+DEFINE_ATTR_EVENT(xfs_attr_node_removename);
+
+#define DEFINE_DA_EVENT(name) \
+DEFINE_EVENT(xfs_da_class, name, \
+       TP_PROTO(struct xfs_da_args *args), \
+       TP_ARGS(args))
+DEFINE_DA_EVENT(xfs_da_split);
+DEFINE_DA_EVENT(xfs_da_join);
+DEFINE_DA_EVENT(xfs_da_link_before);
+DEFINE_DA_EVENT(xfs_da_link_after);
+DEFINE_DA_EVENT(xfs_da_unlink_back);
+DEFINE_DA_EVENT(xfs_da_unlink_forward);
+DEFINE_DA_EVENT(xfs_da_root_split);
+DEFINE_DA_EVENT(xfs_da_root_join);
+DEFINE_DA_EVENT(xfs_da_node_add);
+DEFINE_DA_EVENT(xfs_da_node_create);
+DEFINE_DA_EVENT(xfs_da_node_split);
+DEFINE_DA_EVENT(xfs_da_node_remove);
+DEFINE_DA_EVENT(xfs_da_node_rebalance);
+DEFINE_DA_EVENT(xfs_da_node_unbalance);
+DEFINE_DA_EVENT(xfs_da_swap_lastblock);
+DEFINE_DA_EVENT(xfs_da_grow_inode);
+DEFINE_DA_EVENT(xfs_da_shrink_inode);
+
 DECLARE_EVENT_CLASS(xfs_dir2_space_class,
        TP_PROTO(struct xfs_da_args *args, int idx),
        TP_ARGS(args, idx),
index 7adcdf1..103b00c 100644 (file)
@@ -681,7 +681,6 @@ xfs_trans_reserve(
        uint            flags,
        uint            logcount)
 {
-       int             log_flags;
        int             error = 0;
        int             rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
 
@@ -707,24 +706,32 @@ xfs_trans_reserve(
         * Reserve the log space needed for this transaction.
         */
        if (logspace > 0) {
-               ASSERT((tp->t_log_res == 0) || (tp->t_log_res == logspace));
-               ASSERT((tp->t_log_count == 0) ||
-                       (tp->t_log_count == logcount));
+               bool    permanent = false;
+
+               ASSERT(tp->t_log_res == 0 || tp->t_log_res == logspace);
+               ASSERT(tp->t_log_count == 0 || tp->t_log_count == logcount);
+
                if (flags & XFS_TRANS_PERM_LOG_RES) {
-                       log_flags = XFS_LOG_PERM_RESERV;
                        tp->t_flags |= XFS_TRANS_PERM_LOG_RES;
+                       permanent = true;
                } else {
                        ASSERT(tp->t_ticket == NULL);
                        ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES));
-                       log_flags = 0;
                }
 
-               error = xfs_log_reserve(tp->t_mountp, logspace, logcount,
-                                       &tp->t_ticket,
-                                       XFS_TRANSACTION, log_flags, tp->t_type);
-               if (error) {
-                       goto undo_blocks;
+               if (tp->t_ticket != NULL) {
+                       ASSERT(flags & XFS_TRANS_PERM_LOG_RES);
+                       error = xfs_log_regrant(tp->t_mountp, tp->t_ticket);
+               } else {
+                       error = xfs_log_reserve(tp->t_mountp, logspace,
+                                               logcount, &tp->t_ticket,
+                                               XFS_TRANSACTION, permanent,
+                                               tp->t_type);
                }
+
+               if (error)
+                       goto undo_blocks;
+
                tp->t_log_res = logspace;
                tp->t_log_count = logcount;
        }
@@ -752,6 +759,8 @@ xfs_trans_reserve(
         */
 undo_log:
        if (logspace > 0) {
+               int             log_flags;
+
                if (flags & XFS_TRANS_PERM_LOG_RES) {
                        log_flags = XFS_LOG_REL_PERM_RESERV;
                } else {
index ed9252b..1dead07 100644 (file)
@@ -611,50 +611,6 @@ xfs_ail_push_all(
 }
 
 /*
- * This is to be called when an item is unlocked that may have
- * been in the AIL.  It will wake up the first member of the AIL
- * wait list if this item's unlocking might allow it to progress.
- * If the item is in the AIL, then we need to get the AIL lock
- * while doing our checking so we don't race with someone going
- * to sleep waiting for this event in xfs_trans_push_ail().
- */
-void
-xfs_trans_unlocked_item(
-       struct xfs_ail  *ailp,
-       xfs_log_item_t  *lip)
-{
-       xfs_log_item_t  *min_lip;
-
-       /*
-        * If we're forcibly shutting down, we may have
-        * unlocked log items arbitrarily. The last thing
-        * we want to do is to move the tail of the log
-        * over some potentially valid data.
-        */
-       if (!(lip->li_flags & XFS_LI_IN_AIL) ||
-           XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
-               return;
-       }
-
-       /*
-        * This is the one case where we can call into xfs_ail_min()
-        * without holding the AIL lock because we only care about the
-        * case where we are at the tail of the AIL.  If the object isn't
-        * at the tail, it doesn't matter what result we get back.  This
-        * is slightly racy because since we were just unlocked, we could
-        * go to sleep between the call to xfs_ail_min and the call to
-        * xfs_log_move_tail, have someone else lock us, commit to us disk,
-        * move us out of the tail of the AIL, and then we wake up.  However,
-        * the call to xfs_log_move_tail() doesn't do anything if there's
-        * not enough free space to wake people up so we're safe calling it.
-        */
-       min_lip = xfs_ail_min(ailp);
-
-       if (min_lip == lip)
-               xfs_log_move_tail(ailp->xa_mount, 1);
-}      /* xfs_trans_unlocked_item */
-
-/*
  * xfs_trans_ail_update - bulk AIL insertion operation.
  *
  * @xfs_trans_ail_update takes an array of log items that all need to be
@@ -685,7 +641,6 @@ xfs_trans_ail_update_bulk(
        xfs_lsn_t               lsn) __releases(ailp->xa_lock)
 {
        xfs_log_item_t          *mlip;
-       xfs_lsn_t               tail_lsn;
        int                     mlip_changed = 0;
        int                     i;
        LIST_HEAD(tmp);
@@ -712,22 +667,12 @@ xfs_trans_ail_update_bulk(
 
        if (!list_empty(&tmp))
                xfs_ail_splice(ailp, cur, &tmp, lsn);
+       spin_unlock(&ailp->xa_lock);
 
-       if (!mlip_changed) {
-               spin_unlock(&ailp->xa_lock);
-               return;
+       if (mlip_changed && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
+               xlog_assign_tail_lsn(ailp->xa_mount);
+               xfs_log_space_wake(ailp->xa_mount);
        }
-
-       /*
-        * It is not safe to access mlip after the AIL lock is dropped, so we
-        * must get a copy of li_lsn before we do so.  This is especially
-        * important on 32-bit platforms where accessing and updating 64-bit
-        * values like li_lsn is not atomic.
-        */
-       mlip = xfs_ail_min(ailp);
-       tail_lsn = mlip->li_lsn;
-       spin_unlock(&ailp->xa_lock);
-       xfs_log_move_tail(ailp->xa_mount, tail_lsn);
 }
 
 /*
@@ -758,7 +703,6 @@ xfs_trans_ail_delete_bulk(
        int                     nr_items) __releases(ailp->xa_lock)
 {
        xfs_log_item_t          *mlip;
-       xfs_lsn_t               tail_lsn;
        int                     mlip_changed = 0;
        int                     i;
 
@@ -785,23 +729,12 @@ xfs_trans_ail_delete_bulk(
                if (mlip == lip)
                        mlip_changed = 1;
        }
+       spin_unlock(&ailp->xa_lock);
 
-       if (!mlip_changed) {
-               spin_unlock(&ailp->xa_lock);
-               return;
+       if (mlip_changed && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
+               xlog_assign_tail_lsn(ailp->xa_mount);
+               xfs_log_space_wake(ailp->xa_mount);
        }
-
-       /*
-        * It is not safe to access mlip after the AIL lock is dropped, so we
-        * must get a copy of li_lsn before we do so.  This is especially
-        * important on 32-bit platforms where accessing and updating 64-bit
-        * values like li_lsn is not atomic. It is possible we've emptied the
-        * AIL here, so if that is the case, pass an LSN of 0 to the tail move.
-        */
-       mlip = xfs_ail_min(ailp);
-       tail_lsn = mlip ? mlip->li_lsn : 0;
-       spin_unlock(&ailp->xa_lock);
-       xfs_log_move_tail(ailp->xa_mount, tail_lsn);
 }
 
 /*
index 475a4de..1302d1d 100644 (file)
@@ -463,19 +463,7 @@ xfs_trans_brelse(xfs_trans_t       *tp,
         * Default to a normal brelse() call if the tp is NULL.
         */
        if (tp == NULL) {
-               struct xfs_log_item     *lip = bp->b_fspriv;
-
                ASSERT(bp->b_transp == NULL);
-
-               /*
-                * If there's a buf log item attached to the buffer,
-                * then let the AIL know that the buffer is being
-                * unlocked.
-                */
-               if (lip != NULL && lip->li_type == XFS_LI_BUF) {
-                       bip = bp->b_fspriv;
-                       xfs_trans_unlocked_item(bip->bli_item.li_ailp, lip);
-               }
                xfs_buf_relse(bp);
                return;
        }
@@ -550,21 +538,10 @@ xfs_trans_brelse(xfs_trans_t      *tp,
                ASSERT(!(bip->bli_item.li_flags & XFS_LI_IN_AIL));
                ASSERT(!(bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF));
                xfs_buf_item_relse(bp);
-               bip = NULL;
-       }
-       bp->b_transp = NULL;
-
-       /*
-        * If we've still got a buf log item on the buffer, then
-        * tell the AIL that the buffer is being unlocked.
-        */
-       if (bip != NULL) {
-               xfs_trans_unlocked_item(bip->bli_item.li_ailp,
-                                       (xfs_log_item_t*)bip);
        }
 
+       bp->b_transp = NULL;
        xfs_buf_relse(bp);
-       return;
 }
 
 /*
index c4ba366..2790997 100644 (file)
@@ -605,7 +605,7 @@ xfs_trans_dqresv(
        time_t          timer;
        xfs_qwarncnt_t  warns;
        xfs_qwarncnt_t  warnlimit;
-       xfs_qcnt_t      count;
+       xfs_qcnt_t      total_count;
        xfs_qcnt_t      *resbcountp;
        xfs_quotainfo_t *q = mp->m_quotainfo;
 
@@ -648,13 +648,12 @@ xfs_trans_dqresv(
                         * hardlimit or exceed the timelimit if we allocate
                         * nblks.
                         */
-                       if (hardlimit > 0ULL &&
-                           hardlimit < nblks + *resbcountp) {
+                       total_count = *resbcountp + nblks;
+                       if (hardlimit && total_count > hardlimit) {
                                xfs_quota_warn(mp, dqp, QUOTA_NL_BHARDWARN);
                                goto error_return;
                        }
-                       if (softlimit > 0ULL &&
-                           softlimit < nblks + *resbcountp) {
+                       if (softlimit && total_count > softlimit) {
                                if ((timer != 0 && get_seconds() > timer) ||
                                    (warns != 0 && warns >= warnlimit)) {
                                        xfs_quota_warn(mp, dqp,
@@ -666,7 +665,7 @@ xfs_trans_dqresv(
                        }
                }
                if (ninos > 0) {
-                       count = be64_to_cpu(dqp->q_core.d_icount);
+                       total_count = be64_to_cpu(dqp->q_core.d_icount) + ninos;
                        timer = be32_to_cpu(dqp->q_core.d_itimer);
                        warns = be16_to_cpu(dqp->q_core.d_iwarns);
                        warnlimit = dqp->q_mount->m_quotainfo->qi_iwarnlimit;
@@ -677,13 +676,11 @@ xfs_trans_dqresv(
                        if (!softlimit)
                                softlimit = q->qi_isoftlimit;
 
-                       if (hardlimit > 0ULL &&
-                           hardlimit < ninos + count) {
+                       if (hardlimit && total_count > hardlimit) {
                                xfs_quota_warn(mp, dqp, QUOTA_NL_IHARDWARN);
                                goto error_return;
                        }
-                       if (softlimit > 0ULL &&
-                           softlimit < ninos + count) {
+                       if (softlimit && total_count > softlimit) {
                                if  ((timer != 0 && get_seconds() > timer) ||
                                     (warns != 0 && warns >= warnlimit)) {
                                        xfs_quota_warn(mp, dqp,
@@ -878,7 +875,7 @@ STATIC void
 xfs_trans_alloc_dqinfo(
        xfs_trans_t     *tp)
 {
-       tp->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP);
+       tp->t_dqinfo = kmem_zone_zalloc(xfs_qm_dqtrxzone, KM_SLEEP);
 }
 
 void
@@ -887,6 +884,6 @@ xfs_trans_free_dqinfo(
 {
        if (!tp->t_dqinfo)
                return;
-       kmem_zone_free(xfs_Gqm->qm_dqtrxzone, tp->t_dqinfo);
+       kmem_zone_free(xfs_qm_dqtrxzone, tp->t_dqinfo);
        tp->t_dqinfo = NULL;
 }
index 32f0288..7a7442c 100644 (file)
@@ -95,10 +95,14 @@ xfs_trans_ichgtime(
        if ((flags & XFS_ICHGTIME_MOD) &&
            !timespec_equal(&inode->i_mtime, &tv)) {
                inode->i_mtime = tv;
+               ip->i_d.di_mtime.t_sec = tv.tv_sec;
+               ip->i_d.di_mtime.t_nsec = tv.tv_nsec;
        }
        if ((flags & XFS_ICHGTIME_CHG) &&
            !timespec_equal(&inode->i_ctime, &tv)) {
                inode->i_ctime = tv;
+               ip->i_d.di_ctime.t_sec = tv.tv_sec;
+               ip->i_d.di_ctime.t_nsec = tv.tv_nsec;
        }
 }
 
@@ -126,12 +130,12 @@ xfs_trans_log_inode(
        /*
         * Always OR in the bits from the ili_last_fields field.
         * This is to coordinate with the xfs_iflush() and xfs_iflush_done()
-        * routines in the eventual clearing of the ilf_fields bits.
+        * routines in the eventual clearing of the ili_fields bits.
         * See the big comment in xfs_iflush() for an explanation of
         * this coordination mechanism.
         */
        flags |= ip->i_itemp->ili_last_fields;
-       ip->i_itemp->ili_format.ilf_fields |= flags;
+       ip->i_itemp->ili_fields |= flags;
 }
 
 #ifdef XFS_TRANS_DEBUG
index 44820b9..8ab2ced 100644 (file)
@@ -104,9 +104,6 @@ void                        xfs_ail_push(struct xfs_ail *, xfs_lsn_t);
 void                   xfs_ail_push_all(struct xfs_ail *);
 xfs_lsn_t              xfs_ail_min_lsn(struct xfs_ail *ailp);
 
-void                   xfs_trans_unlocked_item(struct xfs_ail *,
-                                       xfs_log_item_t *);
-
 struct xfs_log_item *  xfs_trans_ail_cursor_first(struct xfs_ail *ailp,
                                        struct xfs_ail_cursor *cur,
                                        xfs_lsn_t lsn);
index 7c220b4..db14d0c 100644 (file)
@@ -22,7 +22,6 @@
 
 struct file;
 struct xfs_inode;
-struct xfs_iomap;
 struct attrlist_cursor_kern;
 
 /*
index 0c877cb..447e146 100644 (file)
@@ -10,7 +10,6 @@ struct kiocb;
 struct pipe_inode_info;
 struct uio;
 struct xfs_inode;
-struct xfs_iomap;
 
 
 int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, int flags);
@@ -49,8 +48,6 @@ int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
 int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
                int flags, struct attrlist_cursor_kern *cursor);
-int xfs_bmap(struct xfs_inode *ip, xfs_off_t offset, ssize_t count,
-               int flags, struct xfs_iomap *iomapp, int *niomaps);
 void xfs_tosspages(struct xfs_inode *inode, xfs_off_t first,
                xfs_off_t last, int fiopt);
 int xfs_flushinval_pages(struct xfs_inode *ip, xfs_off_t first,
index 84458b0..2520a6e 100644 (file)
@@ -134,7 +134,7 @@ extern void warn_slowpath_null(const char *file, const int line);
 #endif
 
 #define WARN_ON_ONCE(condition)        ({                              \
-       static bool __warned;                                   \
+       static bool __section(.data.unlikely) __warned;         \
        int __ret_warn_once = !!(condition);                    \
                                                                \
        if (unlikely(__ret_warn_once))                          \
@@ -144,7 +144,7 @@ extern void warn_slowpath_null(const char *file, const int line);
 })
 
 #define WARN_ONCE(condition, format...)        ({                      \
-       static bool __warned;                                   \
+       static bool __section(.data.unlikely) __warned;         \
        int __ret_warn_once = !!(condition);                    \
                                                                \
        if (unlikely(__ret_warn_once))                          \
@@ -154,7 +154,7 @@ extern void warn_slowpath_null(const char *file, const int line);
 })
 
 #define WARN_TAINT_ONCE(condition, taint, format...)   ({      \
-       static bool __warned;                                   \
+       static bool __section(.data.unlikely) __warned;         \
        int __ret_warn_once = !!(condition);                    \
                                                                \
        if (unlikely(__ret_warn_once))                          \
index 9fa3f96..2e248d8 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_GENERIC_DMA_MAPPING_H
 
 #include <linux/kmemcheck.h>
+#include <linux/bug.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-debug.h>
 #include <linux/dma-attrs.h>
index 1ff4e22..5f52690 100644 (file)
@@ -142,9 +142,9 @@ extern int __must_check gpiochip_reserve(int start, int ngpio);
 /* add/remove chips */
 extern int gpiochip_add(struct gpio_chip *chip);
 extern int __must_check gpiochip_remove(struct gpio_chip *chip);
-extern struct gpio_chip *gpiochip_find(void *data,
+extern struct gpio_chip *gpiochip_find(const void *data,
                                        int (*match)(struct gpio_chip *chip,
-                                                    void *data));
+                                                    const void *data));
 
 
 /* Always use the library code for GPIO management calls,
index 787abbb..d030d2c 100644 (file)
 #define MADV_HUGEPAGE  14              /* Worth backing with hugepages */
 #define MADV_NOHUGEPAGE        15              /* Not worth backing with hugepages */
 
+#define MADV_DONTDUMP   16             /* Explicity exclude from the core dump,
+                                          overrides the coredump filter bits */
+#define MADV_DODUMP    17              /* Clear the MADV_NODUMP flag */
+
 /* compatibility flags */
 #define MAP_FILE       0
 
index 4a5aca2..a5b5d5a 100644 (file)
@@ -45,6 +45,11 @@ static inline void pci_add_flags(int flags)
        pci_flags |= flags;
 }
 
+static inline void pci_clear_flags(int flags)
+{
+       pci_flags &= ~flags;
+}
+
 static inline int pci_has_flag(int flag)
 {
        return pci_flags & flag;
@@ -52,6 +57,7 @@ static inline int pci_has_flag(int flag)
 #else
 static inline void pci_set_flags(int flags) { }
 static inline void pci_add_flags(int flags) { }
+static inline void pci_clear_flags(int flags) { }
 static inline int pci_has_flag(int flag)
 {
        return 0;
index 26373cf..e80a049 100644 (file)
@@ -6,30 +6,6 @@
 #ifndef _ASM_GENERIC_PCI_H
 #define _ASM_GENERIC_PCI_H
 
-/**
- * pcibios_resource_to_bus - convert resource to PCI bus address
- * @dev: device which owns this resource
- * @region: converted bus-centric region (start,end)
- * @res: resource to convert
- *
- * Convert a resource to a PCI device bus address or bus window.
- */
-static inline void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-                        struct resource *res)
-{
-       region->start = res->start;
-       region->end = res->end;
-}
-
-static inline void
-pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
-                       struct pci_bus_region *region)
-{
-       res->start = region->start;
-       res->end = region->end;
-}
-
 static inline struct resource *
 pcibios_select_root(struct pci_dev *pdev, struct resource *res)
 {
index a03c098..125c54e 100644 (file)
@@ -5,6 +5,7 @@
 #ifdef CONFIG_MMU
 
 #include <linux/mm_types.h>
+#include <linux/bug.h>
 
 #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 extern int ptep_set_access_flags(struct vm_area_struct *vma,
index c7af037..d6d0a88 100644 (file)
@@ -9,6 +9,8 @@
 #error need to implement an architecture specific asm/tlbflush.h
 #endif
 
+#include <linux/bug.h>
+
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
        BUG();
index b5e2e4c..8aeadf6 100644 (file)
        CPU_KEEP(exit.data)                                             \
        MEM_KEEP(init.data)                                             \
        MEM_KEEP(exit.data)                                             \
+       *(.data.unlikely)                                               \
        STRUCT_ALIGN();                                                 \
        *(__tracepoints)                                                \
        /* implement dynamic printk debug */                            \
                *(.init.setup)                                          \
                VMLINUX_SYMBOL(__setup_end) = .;
 
-#define INITCALLS                                                      \
-       *(.initcallearly.init)                                          \
-       VMLINUX_SYMBOL(__early_initcall_end) = .;                       \
-       *(.initcall0.init)                                              \
-       *(.initcall0s.init)                                             \
-       *(.initcall1.init)                                              \
-       *(.initcall1s.init)                                             \
-       *(.initcall2.init)                                              \
-       *(.initcall2s.init)                                             \
-       *(.initcall3.init)                                              \
-       *(.initcall3s.init)                                             \
-       *(.initcall4.init)                                              \
-       *(.initcall4s.init)                                             \
-       *(.initcall5.init)                                              \
-       *(.initcall5s.init)                                             \
-       *(.initcallrootfs.init)                                         \
-       *(.initcall6.init)                                              \
-       *(.initcall6s.init)                                             \
-       *(.initcall7.init)                                              \
-       *(.initcall7s.init)
+#define INIT_CALLS_LEVEL(level)                                                \
+               VMLINUX_SYMBOL(__initcall##level##_start) = .;          \
+               *(.initcall##level##.init)                              \
+               *(.initcall##level##s.init)                             \
 
 #define INIT_CALLS                                                     \
                VMLINUX_SYMBOL(__initcall_start) = .;                   \
-               INITCALLS                                               \
+               *(.initcallearly.init)                                  \
+               INIT_CALLS_LEVEL(0)                                     \
+               INIT_CALLS_LEVEL(1)                                     \
+               INIT_CALLS_LEVEL(2)                                     \
+               INIT_CALLS_LEVEL(3)                                     \
+               INIT_CALLS_LEVEL(4)                                     \
+               INIT_CALLS_LEVEL(5)                                     \
+               INIT_CALLS_LEVEL(rootfs)                                \
+               INIT_CALLS_LEVEL(6)                                     \
+               INIT_CALLS_LEVEL(7)                                     \
                VMLINUX_SYMBOL(__initcall_end) = .;
 
 #define CON_INITCALL                                                   \
index 2a2acda..4a0aae3 100644 (file)
@@ -27,6 +27,8 @@
 #ifndef _DRM_MODE_H
 #define _DRM_MODE_H
 
+#include <linux/types.h>
+
 #define DRM_DISPLAY_INFO_LEN   32
 #define DRM_CONNECTOR_NAME_LEN 32
 #define DRM_DISPLAY_MODE_LEN   32
index 26c1f78..d6d1da4 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
+#include <linux/bug.h>
 #include <linux/wait.h>
 #include <linux/errno.h>
 #include <linux/kobject.h>
index 3f96866..f53fea6 100644 (file)
@@ -151,6 +151,7 @@ extern int ec_write(u8 addr, u8 val);
 extern int ec_transaction(u8 command,
                           const u8 *wdata, unsigned wdata_len,
                           u8 *rdata, unsigned rdata_len);
+extern acpi_handle ec_get_handle(void);
 
 #if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
 
index 724c69c..7847e19 100644 (file)
@@ -60,6 +60,9 @@ extern struct bus_type amba_bustype;
 
 int amba_driver_register(struct amba_driver *);
 void amba_driver_unregister(struct amba_driver *);
+struct amba_device *amba_device_alloc(const char *, resource_size_t, size_t);
+void amba_device_put(struct amba_device *);
+int amba_device_add(struct amba_device *, struct resource *);
 int amba_device_register(struct amba_device *, struct resource *);
 void amba_device_unregister(struct amba_device *);
 struct amba_device *amba_find_device(const char *, struct device *, unsigned int, unsigned int);
@@ -89,4 +92,46 @@ void amba_release_regions(struct amba_device *);
 #define amba_manf(d)   AMBA_MANF_BITS((d)->periphid)
 #define amba_part(d)   AMBA_PART_BITS((d)->periphid)
 
+#define __AMBA_DEV(busid, data, mask)                          \
+       {                                                       \
+               .coherent_dma_mask = mask,                      \
+               .init_name = busid,                             \
+               .platform_data = data,                          \
+       }
+
+/*
+ * APB devices do not themselves have the ability to address memory,
+ * so DMA masks should be zero (much like USB peripheral devices.)
+ * The DMA controller DMA masks should be used instead (much like
+ * USB host controllers in conventional PCs.)
+ */
+#define AMBA_APB_DEVICE(name, busid, id, base, irqs, data)     \
+struct amba_device name##_device = {                           \
+       .dev = __AMBA_DEV(busid, data, 0),                      \
+       .res = DEFINE_RES_MEM(base, SZ_4K),                     \
+       .irq = irqs,                                            \
+       .periphid = id,                                         \
+}
+
+/*
+ * AHB devices are DMA capable, so set their DMA masks
+ */
+#define AMBA_AHB_DEVICE(name, busid, id, base, irqs, data)     \
+struct amba_device name##_device = {                           \
+       .dev = __AMBA_DEV(busid, data, ~0ULL),                  \
+       .res = DEFINE_RES_MEM(base, SZ_4K),                     \
+       .dma_mask = ~0ULL,                                      \
+       .irq = irqs,                                            \
+       .periphid = id,                                         \
+}
+
+/*
+ * module_amba_driver() - Helper macro for drivers that don't do anything
+ * special in module init/exit.  This eliminates a lot of boilerplate.  Each
+ * module may only use this macro once, and calling it replaces module_init()
+ * and module_exit()
+ */
+#define module_amba_driver(__amba_drv) \
+       module_driver(__amba_drv, amba_driver_register, amba_driver_unregister)
+
 #endif
index 0101e9c..32a89cf 100644 (file)
@@ -6,6 +6,19 @@
 
 #include <linux/mmc/host.h>
 
+
+/*
+ * These defines is places here due to access is needed from machine
+ * configuration files. The ST Micro version does not have ROD and
+ * reuse the voltage registers for direction settings.
+ */
+#define MCI_ST_DATA2DIREN      (1 << 2)
+#define MCI_ST_CMDDIREN                (1 << 3)
+#define MCI_ST_DATA0DIREN      (1 << 4)
+#define MCI_ST_DATA31DIREN     (1 << 5)
+#define MCI_ST_FBCLKEN         (1 << 7)
+#define MCI_ST_DATA74DIREN     (1 << 8)
+
 /* Just some dummy forwarding */
 struct dma_chan;
 
@@ -18,7 +31,8 @@ struct dma_chan;
  * @ocr_mask: available voltages on the 4 pins from the block, this
  * is ignored if a regulator is used, see the MMC_VDD_* masks in
  * mmc/host.h
- * @vdd_handler: a callback function to translate a MMC_VDD_*
+ * @ios_handler: a callback function to act on specfic ios changes,
+ * used for example to control a levelshifter
  * mask into a value to be binary (or set some other custom bits
  * in MMCIPWR) or:ed and written into the MMCIPWR register of the
  * block.  May also control external power based on the power_mode.
@@ -31,6 +45,8 @@ struct dma_chan;
  * @capabilities: the capabilities of the block as implemented in
  * this platform, signify anything MMC_CAP_* from mmc/host.h
  * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h
+ * @sigdir: a bit field indicating for what bits in the MMC bus the host
+ * should enable signal direction indication.
  * @dma_filter: function used to select an appropriate RX and TX
  * DMA channel to be used for DMA, if and only if you're deploying the
  * generic DMA engine
@@ -46,14 +62,14 @@ struct dma_chan;
 struct mmci_platform_data {
        unsigned int f_max;
        unsigned int ocr_mask;
-       u32 (*vdd_handler)(struct device *, unsigned int vdd,
-                          unsigned char power_mode);
+       int (*ios_handler)(struct device *, struct mmc_ios *);
        unsigned int (*status)(struct device *);
        int     gpio_wp;
        int     gpio_cd;
        bool    cd_invert;
        unsigned long capabilities;
        unsigned long capabilities2;
+       u32 sigdir;
        bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
        void *dma_rx_param;
        void *dma_tx_param;
index 3672f40..b8c5112 100644 (file)
@@ -25,8 +25,6 @@
 #ifndef _SSP_PL022_H
 #define _SSP_PL022_H
 
-#include <linux/device.h>
-
 /**
  * whether SSP is in loopback mode or not
  */
index ef00610..15f6b9e 100644 (file)
@@ -28,7 +28,7 @@ struct task_struct;
 struct pci_dev;
 
 extern int amd_iommu_detect(void);
-
+extern int amd_iommu_init_hardware(void);
 
 /**
  * amd_iommu_enable_device_erratum() - Enable erratum workaround for device
diff --git a/include/linux/apple_bl.h b/include/linux/apple_bl.h
new file mode 100644 (file)
index 0000000..47bedc0
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * apple_bl exported symbols
+ */
+
+#ifndef _LINUX_APPLE_BL_H
+#define _LINUX_APPLE_BL_H
+
+#ifdef CONFIG_BACKLIGHT_APPLE
+
+extern int apple_bl_register(void);
+extern void apple_bl_unregister(void);
+
+#else /* !CONFIG_BACKLIGHT_APPLE */
+
+static inline int apple_bl_register(void)
+{
+       return 0;
+}
+
+static inline void apple_bl_unregister(void)
+{
+}
+
+#endif /* !CONFIG_BACKLIGHT_APPLE */
+
+#endif /* _LINUX_APPLE_BL_H */
index f4ff882..06fd4bb 100644 (file)
@@ -213,10 +213,10 @@ struct atm_cirange {
 
 #ifdef __KERNEL__
 
-#include <linux/device.h>
 #include <linux/wait.h> /* wait_queue_head_t */
 #include <linux/time.h> /* struct timeval */
 #include <linux/net.h>
+#include <linux/bug.h>
 #include <linux/skbuff.h> /* struct sk_buff */
 #include <linux/uio.h>
 #include <net/sock.h>
@@ -249,6 +249,7 @@ struct k_atm_dev_stats {
        struct k_atm_aal_stats aal5;
 };
 
+struct device;
 
 enum {
        ATM_VF_ADDR,            /* Address is in use. Set by anybody, cleared
index 53ba65e..1d14b1d 100644 (file)
 struct clk;
 
 /**
+ * struct atmel_tcb_config - SoC data for a Timer/Counter Block
+ * @counter_width: size in bits of a timer counter register
+ */
+struct atmel_tcb_config {
+       size_t  counter_width;
+};
+
+/**
  * struct atmel_tc - information about a Timer/Counter Block
  * @pdev: physical device
  * @iomem: resource associated with the I/O register
  * @regs: mapping through which the I/O registers can be accessed
+ * @tcb_config: configuration data from SoC
  * @irq: irq for each of the three channels
  * @clk: internal clock source for each of the three channels
  * @node: list node, for tclib internal use
@@ -54,6 +63,7 @@ struct atmel_tc {
        struct platform_device  *pdev;
        struct resource         *iomem;
        void __iomem            *regs;
+       struct atmel_tcb_config *tcb_config;
        int                     irq[3];
        struct clk              *clk[3];
        struct list_head        node;
index c3ab814..896c689 100644 (file)
@@ -9,10 +9,11 @@
 #ifndef _ATTRIBUTE_CONTAINER_H_
 #define _ATTRIBUTE_CONTAINER_H_
 
-#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/klist.h>
 
+struct device;
+
 struct attribute_container {
        struct list_head        node;
        struct klist            containers;
index de5422a..4d94eb8 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/highmem.h>
 #include <linux/mempool.h>
 #include <linux/ioprio.h>
+#include <linux/bug.h>
 
 #ifdef CONFIG_BLOCK
 
index ac4d9f8..3b5bafc 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/kernel.h>
 #include <linux/preempt.h>
 #include <linux/atomic.h>
+#include <linux/bug.h>
 
 /*
  *  bit-based spin_lock()
index 94300fe..a3b6b82 100644 (file)
@@ -27,11 +27,22 @@ extern unsigned long __sw_hweight64(__u64 w);
             (bit) = find_next_bit((addr), (size), (bit) + 1))
 
 /* same as for_each_set_bit() but use bit as value to start with */
-#define for_each_set_bit_cont(bit, addr, size) \
+#define for_each_set_bit_from(bit, addr, size) \
        for ((bit) = find_next_bit((addr), (size), (bit));      \
             (bit) < (size);                                    \
             (bit) = find_next_bit((addr), (size), (bit) + 1))
 
+#define for_each_clear_bit(bit, addr, size) \
+       for ((bit) = find_first_zero_bit((addr), (size));       \
+            (bit) < (size);                                    \
+            (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+
+/* same as for_each_clear_bit() but use bit as value to start with */
+#define for_each_clear_bit_from(bit, addr, size) \
+       for ((bit) = find_next_zero_bit((addr), (size), (bit)); \
+            (bit) < (size);                                    \
+            (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+
 static __inline__ int get_bitmask_order(unsigned int count)
 {
        int order;
index d276b55..72961c3 100644 (file)
@@ -11,6 +11,67 @@ enum bug_trap_type {
 
 struct pt_regs;
 
+#ifdef __CHECKER__
+#define BUILD_BUG_ON_NOT_POWER_OF_2(n)
+#define BUILD_BUG_ON_ZERO(e) (0)
+#define BUILD_BUG_ON_NULL(e) ((void*)0)
+#define BUILD_BUG_ON(condition)
+#define BUILD_BUG() (0)
+#else /* __CHECKER__ */
+
+/* Force a compilation error if a constant expression is not a power of 2 */
+#define BUILD_BUG_ON_NOT_POWER_OF_2(n)                 \
+       BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
+
+/* Force a compilation error if condition is true, but also produce a
+   result (of value 0 and type size_t), so the expression can be used
+   e.g. in a structure initializer (or where-ever else comma expressions
+   aren't permitted). */
+#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
+#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
+
+/**
+ * BUILD_BUG_ON - break compile if a condition is true.
+ * @condition: the condition which the compiler should know is false.
+ *
+ * If you have some code which relies on certain constants being equal, or
+ * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
+ * detect if someone changes it.
+ *
+ * The implementation uses gcc's reluctance to create a negative array, but
+ * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
+ * to inline functions).  So as a fallback we use the optimizer; if it can't
+ * prove the condition is false, it will cause a link error on the undefined
+ * "__build_bug_on_failed".  This error message can be harder to track down
+ * though, hence the two different methods.
+ */
+#ifndef __OPTIMIZE__
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#else
+extern int __build_bug_on_failed;
+#define BUILD_BUG_ON(condition)                                        \
+       do {                                                    \
+               ((void)sizeof(char[1 - 2*!!(condition)]));      \
+               if (condition) __build_bug_on_failed = 1;       \
+       } while(0)
+#endif
+
+/**
+ * BUILD_BUG - break compile if used.
+ *
+ * If you have some code that you expect the compiler to eliminate at
+ * build time, you should use BUILD_BUG to detect if it is
+ * unexpectedly used.
+ */
+#define BUILD_BUG()                                            \
+       do {                                                    \
+               extern void __build_bug_failed(void)            \
+                       __linktime_error("BUILD_BUG failed");   \
+               __build_bug_failed();                           \
+       } while (0)
+
+#endif /* __CHECKER__ */
+
 #ifdef CONFIG_GENERIC_BUG
 #include <asm-generic/bug.h>
 
index a2f7d74..4efabcb 100644 (file)
@@ -9,11 +9,12 @@
  * the Free Software Foundation
  */
 
-#include <linux/device.h>
 #include <linux/kmemcheck.h>
 
 #define C2PORT_NAME_LEN                        32
 
+struct device;
+
 /*
  * C2 port basic structs
  */
index 7c48029..dfd7f18 100644 (file)
@@ -910,7 +910,6 @@ struct mode_page_header {
 
 #ifdef __KERNEL__
 #include <linux/fs.h>          /* not really needed, later.. */
-#include <linux/device.h>
 #include <linux/list.h>
 
 struct packet_command
index c5b6939..220ae21 100644 (file)
@@ -1,8 +1,9 @@
 #ifndef __CEPH_DECODE_H
 #define __CEPH_DECODE_H
 
-#include <asm/unaligned.h>
+#include <linux/bug.h>
 #include <linux/time.h>
+#include <asm/unaligned.h>
 
 #include "types.h"
 
index 95bd850..e71d683 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/backing-dev.h>
 #include <linux/completion.h>
 #include <linux/exportfs.h>
+#include <linux/bug.h>
 #include <linux/fs.h>
 #include <linux/mempool.h>
 #include <linux/pagemap.h>
@@ -207,7 +208,7 @@ extern struct kmem_cache *ceph_cap_cachep;
 extern struct kmem_cache *ceph_dentry_cachep;
 extern struct kmem_cache *ceph_file_cachep;
 
-extern int ceph_parse_options(struct ceph_options **popt, char *options,
+extern struct ceph_options *ceph_parse_options(char *options,
                              const char *dev_name, const char *dev_name_end,
                              int (*parse_extra_token)(char *c, void *private),
                              void *private);
index 4c5cb08..9935fac 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _FS_CEPH_MDSMAP_H
 #define _FS_CEPH_MDSMAP_H
 
+#include <linux/bug.h>
 #include "types.h"
 
 /*
index ffbeb2c..3bff047 100644 (file)
@@ -14,8 +14,6 @@
 struct ceph_msg;
 struct ceph_connection;
 
-extern struct workqueue_struct *ceph_msgr_wq;       /* receive work queue */
-
 /*
  * Ceph defines these callbacks for handling connection events.
  */
@@ -54,7 +52,6 @@ struct ceph_connection_operations {
 struct ceph_messenger {
        struct ceph_entity_inst inst;    /* my name+address */
        struct ceph_entity_addr my_enc_addr;
-       struct page *zero_page;          /* used in certain error cases */
 
        bool nocrc;
 
@@ -101,7 +98,7 @@ struct ceph_msg {
 struct ceph_msg_pos {
        int page, page_pos;  /* which page; offset in page */
        int data_pos;        /* offset in data payload */
-       int did_page_crc;    /* true if we've calculated crc for current page */
+       bool did_page_crc;   /* true if we've calculated crc for current page */
 };
 
 /* ceph connection fault delay defaults, for exponential backoff */
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
new file mode 100644 (file)
index 0000000..5e4312b
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  linux/include/linux/clk-private.h
+ *
+ *  Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *  Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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_CLK_PRIVATE_H
+#define __LINUX_CLK_PRIVATE_H
+
+#include <linux/clk-provider.h>
+#include <linux/list.h>
+
+/*
+ * WARNING: Do not include clk-private.h from any file that implements struct
+ * clk_ops.  Doing so is a layering violation!
+ *
+ * This header exists only to allow for statically initialized clock data.  Any
+ * static clock data must be defined in a separate file from the logic that
+ * implements the clock operations for that same data.
+ */
+
+#ifdef CONFIG_COMMON_CLK
+
+struct clk {
+       const char              *name;
+       const struct clk_ops    *ops;
+       struct clk_hw           *hw;
+       struct clk              *parent;
+       char                    **parent_names;
+       struct clk              **parents;
+       u8                      num_parents;
+       unsigned long           rate;
+       unsigned long           new_rate;
+       unsigned long           flags;
+       unsigned int            enable_count;
+       unsigned int            prepare_count;
+       struct hlist_head       children;
+       struct hlist_node       child_node;
+       unsigned int            notifier_count;
+#ifdef CONFIG_COMMON_CLK_DEBUG
+       struct dentry           *dentry;
+#endif
+};
+
+/*
+ * DOC: Basic clock implementations common to many platforms
+ *
+ * Each basic clock hardware type is comprised of a structure describing the
+ * clock hardware, implementations of the relevant callbacks in struct clk_ops,
+ * unique flags for that hardware type, a registration function and an
+ * alternative macro for static initialization
+ */
+
+extern struct clk_ops clk_fixed_rate_ops;
+
+#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate,            \
+                               _fixed_rate_flags)              \
+       static struct clk _name;                                \
+       static char *_name##_parent_names[] = {};               \
+       static struct clk_fixed_rate _name##_hw = {             \
+               .hw = {                                         \
+                       .clk = &_name,                          \
+               },                                              \
+               .fixed_rate = _rate,                            \
+               .flags = _fixed_rate_flags,                     \
+       };                                                      \
+       static struct clk _name = {                             \
+               .name = #_name,                                 \
+               .ops = &clk_fixed_rate_ops,                     \
+               .hw = &_name##_hw.hw,                           \
+               .parent_names = _name##_parent_names,           \
+               .num_parents =                                  \
+                       ARRAY_SIZE(_name##_parent_names),       \
+               .flags = _flags,                                \
+       };
+
+extern struct clk_ops clk_gate_ops;
+
+#define DEFINE_CLK_GATE(_name, _parent_name, _parent_ptr,      \
+                               _flags, _reg, _bit_idx,         \
+                               _gate_flags, _lock)             \
+       static struct clk _name;                                \
+       static char *_name##_parent_names[] = {                 \
+               _parent_name,                                   \
+       };                                                      \
+       static struct clk *_name##_parents[] = {                \
+               _parent_ptr,                                    \
+       };                                                      \
+       static struct clk_gate _name##_hw = {                   \
+               .hw = {                                         \
+                       .clk = &_name,                          \
+               },                                              \
+               .reg = _reg,                                    \
+               .bit_idx = _bit_idx,                            \
+               .flags = _gate_flags,                           \
+               .lock = _lock,                                  \
+       };                                                      \
+       static struct clk _name = {                             \
+               .name = #_name,                                 \
+               .ops = &clk_gate_ops,                           \
+               .hw = &_name##_hw.hw,                           \
+               .parent_names = _name##_parent_names,           \
+               .num_parents =                                  \
+                       ARRAY_SIZE(_name##_parent_names),       \
+               .parents = _name##_parents,                     \
+               .flags = _flags,                                \
+       };
+
+extern struct clk_ops clk_divider_ops;
+
+#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr,   \
+                               _flags, _reg, _shift, _width,   \
+                               _divider_flags, _lock)          \
+       static struct clk _name;                                \
+       static char *_name##_parent_names[] = {                 \
+               _parent_name,                                   \
+       };                                                      \
+       static struct clk *_name##_parents[] = {                \
+               _parent_ptr,                                    \
+       };                                                      \
+       static struct clk_divider _name##_hw = {                \
+               .hw = {                                         \
+                       .clk = &_name,                          \
+               },                                              \
+               .reg = _reg,                                    \
+               .shift = _shift,                                \
+               .width = _width,                                \
+               .flags = _divider_flags,                        \
+               .lock = _lock,                                  \
+       };                                                      \
+       static struct clk _name = {                             \
+               .name = #_name,                                 \
+               .ops = &clk_divider_ops,                        \
+               .hw = &_name##_hw.hw,                           \
+               .parent_names = _name##_parent_names,           \
+               .num_parents =                                  \
+                       ARRAY_SIZE(_name##_parent_names),       \
+               .parents = _name##_parents,                     \
+               .flags = _flags,                                \
+       };
+
+extern struct clk_ops clk_mux_ops;
+
+#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \
+                               _reg, _shift, _width,           \
+                               _mux_flags, _lock)              \
+       static struct clk _name;                                \
+       static struct clk_mux _name##_hw = {                    \
+               .hw = {                                         \
+                       .clk = &_name,                          \
+               },                                              \
+               .reg = _reg,                                    \
+               .shift = _shift,                                \
+               .width = _width,                                \
+               .flags = _mux_flags,                            \
+               .lock = _lock,                                  \
+       };                                                      \
+       static struct clk _name = {                             \
+               .name = #_name,                                 \
+               .ops = &clk_mux_ops,                            \
+               .hw = &_name##_hw.hw,                           \
+               .parent_names = _parent_names,                  \
+               .num_parents =                                  \
+                       ARRAY_SIZE(_parent_names),              \
+               .parents = _parents,                            \
+               .flags = _flags,                                \
+       };
+
+/**
+ * __clk_init - initialize the data structures in a struct clk
+ * @dev:       device initializing this clk, placeholder for now
+ * @clk:       clk being initialized
+ *
+ * Initializes the lists in struct clk, queries the hardware for the
+ * parent and rate and sets them both.
+ *
+ * Any struct clk passed into __clk_init must have the following members
+ * populated:
+ *     .name
+ *     .ops
+ *     .hw
+ *     .parent_names
+ *     .num_parents
+ *     .flags
+ *
+ * It is not necessary to call clk_register if __clk_init is used directly with
+ * statically initialized clock data.
+ */
+void __clk_init(struct device *dev, struct clk *clk);
+
+#endif /* CONFIG_COMMON_CLK */
+#endif /* CLK_PRIVATE_H */
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
new file mode 100644 (file)
index 0000000..5508897
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ *  linux/include/linux/clk-provider.h
+ *
+ *  Copyright (c) 2010-2011 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *  Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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_CLK_PROVIDER_H
+#define __LINUX_CLK_PROVIDER_H
+
+#include <linux/clk.h>
+
+#ifdef CONFIG_COMMON_CLK
+
+/**
+ * struct clk_hw - handle for traversing from a struct clk to its corresponding
+ * hardware-specific structure.  struct clk_hw should be declared within struct
+ * clk_foo and then referenced by the struct clk instance that uses struct
+ * clk_foo's clk_ops
+ *
+ * clk: pointer to the struct clk instance that points back to this struct
+ * clk_hw instance
+ */
+struct clk_hw {
+       struct clk *clk;
+};
+
+/*
+ * flags used across common struct clk.  these flags should only affect the
+ * top-level framework.  custom flags for dealing with hardware specifics
+ * belong in struct clk_foo
+ */
+#define CLK_SET_RATE_GATE      BIT(0) /* must be gated across rate change */
+#define CLK_SET_PARENT_GATE    BIT(1) /* must be gated across re-parent */
+#define CLK_SET_RATE_PARENT    BIT(2) /* propagate rate change up one level */
+#define CLK_IGNORE_UNUSED      BIT(3) /* do not gate even if unused */
+#define CLK_IS_ROOT            BIT(4) /* root clk, has no parent */
+
+/**
+ * struct clk_ops -  Callback operations for hardware clocks; these are to
+ * be provided by the clock implementation, and will be called by drivers
+ * through the clk_* api.
+ *
+ * @prepare:   Prepare the clock for enabling. This must not return until
+ *             the clock is fully prepared, and it's safe to call clk_enable.
+ *             This callback is intended to allow clock implementations to
+ *             do any initialisation that may sleep. Called with
+ *             prepare_lock held.
+ *
+ * @unprepare: Release the clock from its prepared state. This will typically
+ *             undo any work done in the @prepare callback. Called with
+ *             prepare_lock held.
+ *
+ * @enable:    Enable the clock atomically. This must not return until the
+ *             clock is generating a valid clock signal, usable by consumer
+ *             devices. Called with enable_lock held. This function must not
+ *             sleep.
+ *
+ * @disable:   Disable the clock atomically. Called with enable_lock held.
+ *             This function must not sleep.
+ *
+ * @recalc_rate        Recalculate the rate of this clock, by quering hardware.  The
+ *             parent rate is an input parameter.  It is up to the caller to
+ *             insure that the prepare_mutex is held across this call.
+ *             Returns the calculated rate.  Optional, but recommended - if
+ *             this op is not set then clock rate will be initialized to 0.
+ *
+ * @round_rate:        Given a target rate as input, returns the closest rate actually
+ *             supported by the clock.
+ *
+ * @get_parent:        Queries the hardware to determine the parent of a clock.  The
+ *             return value is a u8 which specifies the index corresponding to
+ *             the parent clock.  This index can be applied to either the
+ *             .parent_names or .parents arrays.  In short, this function
+ *             translates the parent value read from hardware into an array
+ *             index.  Currently only called when the clock is initialized by
+ *             __clk_init.  This callback is mandatory for clocks with
+ *             multiple parents.  It is optional (and unnecessary) for clocks
+ *             with 0 or 1 parents.
+ *
+ * @set_parent:        Change the input source of this clock; for clocks with multiple
+ *             possible parents specify a new parent by passing in the index
+ *             as a u8 corresponding to the parent in either the .parent_names
+ *             or .parents arrays.  This function in affect translates an
+ *             array index into the value programmed into the hardware.
+ *             Returns 0 on success, -EERROR otherwise.
+ *
+ * @set_rate:  Change the rate of this clock. If this callback returns
+ *             CLK_SET_RATE_PARENT, the rate change will be propagated to the
+ *             parent clock (which may propagate again if the parent clock
+ *             also sets this flag). The requested rate of the parent is
+ *             passed back from the callback in the second 'unsigned long *'
+ *             argument.  Note that it is up to the hardware clock's set_rate
+ *             implementation to insure that clocks do not run out of spec
+ *             when propgating the call to set_rate up to the parent.  One way
+ *             to do this is to gate the clock (via clk_disable and/or
+ *             clk_unprepare) before calling clk_set_rate, then ungating it
+ *             afterward.  If your clock also has the CLK_GATE_SET_RATE flag
+ *             set then this will insure safety.  Returns 0 on success,
+ *             -EERROR otherwise.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts.  If enabling a clock requires code that might sleep,
+ * this must be done in clk_prepare.  Clock enable code that will never be
+ * called in a sleepable context may be implement in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare MUST have been
+ * called before clk_enable.
+ */
+struct clk_ops {
+       int             (*prepare)(struct clk_hw *hw);
+       void            (*unprepare)(struct clk_hw *hw);
+       int             (*enable)(struct clk_hw *hw);
+       void            (*disable)(struct clk_hw *hw);
+       int             (*is_enabled)(struct clk_hw *hw);
+       unsigned long   (*recalc_rate)(struct clk_hw *hw,
+                                       unsigned long parent_rate);
+       long            (*round_rate)(struct clk_hw *hw, unsigned long,
+                                       unsigned long *);
+       int             (*set_parent)(struct clk_hw *hw, u8 index);
+       u8              (*get_parent)(struct clk_hw *hw);
+       int             (*set_rate)(struct clk_hw *hw, unsigned long);
+       void            (*init)(struct clk_hw *hw);
+};
+
+/*
+ * DOC: Basic clock implementations common to many platforms
+ *
+ * Each basic clock hardware type is comprised of a structure describing the
+ * clock hardware, implementations of the relevant callbacks in struct clk_ops,
+ * unique flags for that hardware type, a registration function and an
+ * alternative macro for static initialization
+ */
+
+/**
+ * struct clk_fixed_rate - fixed-rate clock
+ * @hw:                handle between common and hardware-specific interfaces
+ * @fixed_rate:        constant frequency of clock
+ */
+struct clk_fixed_rate {
+       struct          clk_hw hw;
+       unsigned long   fixed_rate;
+       u8              flags;
+};
+
+struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               unsigned long fixed_rate);
+
+/**
+ * struct clk_gate - gating clock
+ *
+ * @hw:                handle between common and hardware-specific interfaces
+ * @reg:       register controlling gate
+ * @bit_idx:   single bit controlling gate
+ * @flags:     hardware-specific flags
+ * @lock:      register lock
+ *
+ * Clock which can gate its output.  Implements .enable & .disable
+ *
+ * Flags:
+ * CLK_GATE_SET_DISABLE - by default this clock sets the bit at bit_idx to
+ *     enable the clock.  Setting this flag does the opposite: setting the bit
+ *     disable the clock and clearing it enables the clock
+ */
+struct clk_gate {
+       struct clk_hw hw;
+       void __iomem    *reg;
+       u8              bit_idx;
+       u8              flags;
+       spinlock_t      *lock;
+       char            *parent[1];
+};
+
+#define CLK_GATE_SET_TO_DISABLE                BIT(0)
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 bit_idx,
+               u8 clk_gate_flags, spinlock_t *lock);
+
+/**
+ * struct clk_divider - adjustable divider clock
+ *
+ * @hw:                handle between common and hardware-specific interfaces
+ * @reg:       register containing the divider
+ * @shift:     shift to the divider bit field
+ * @width:     width of the divider bit field
+ * @lock:      register lock
+ *
+ * Clock with an adjustable divider affecting its output frequency.  Implements
+ * .recalc_rate, .set_rate and .round_rate
+ *
+ * Flags:
+ * CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the
+ *     register plus one.  If CLK_DIVIDER_ONE_BASED is set then the divider is
+ *     the raw value read from the register, with the value of zero considered
+ *     invalid
+ * CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from
+ *     the hardware register
+ */
+struct clk_divider {
+       struct clk_hw   hw;
+       void __iomem    *reg;
+       u8              shift;
+       u8              width;
+       u8              flags;
+       spinlock_t      *lock;
+       char            *parent[1];
+};
+
+#define CLK_DIVIDER_ONE_BASED          BIT(0)
+#define CLK_DIVIDER_POWER_OF_TWO       BIT(1)
+
+struct clk *clk_register_divider(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               void __iomem *reg, u8 shift, u8 width,
+               u8 clk_divider_flags, spinlock_t *lock);
+
+/**
+ * struct clk_mux - multiplexer clock
+ *
+ * @hw:                handle between common and hardware-specific interfaces
+ * @reg:       register controlling multiplexer
+ * @shift:     shift to multiplexer bit field
+ * @width:     width of mutliplexer bit field
+ * @num_clks:  number of parent clocks
+ * @lock:      register lock
+ *
+ * Clock with multiple selectable parents.  Implements .get_parent, .set_parent
+ * and .recalc_rate
+ *
+ * Flags:
+ * CLK_MUX_INDEX_ONE - register index starts at 1, not 0
+ * CLK_MUX_INDEX_BITWISE - register index is a single bit (power of two)
+ */
+struct clk_mux {
+       struct clk_hw   hw;
+       void __iomem    *reg;
+       u8              shift;
+       u8              width;
+       u8              flags;
+       spinlock_t      *lock;
+};
+
+#define CLK_MUX_INDEX_ONE              BIT(0)
+#define CLK_MUX_INDEX_BIT              BIT(1)
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+               char **parent_names, u8 num_parents, unsigned long flags,
+               void __iomem *reg, u8 shift, u8 width,
+               u8 clk_mux_flags, spinlock_t *lock);
+
+/**
+ * clk_register - allocate a new clock, register it and return an opaque cookie
+ * @dev: device that is registering this clock
+ * @name: clock name
+ * @ops: operations this clock supports
+ * @hw: link to hardware-specific clock data
+ * @parent_names: array of string names for all possible parents
+ * @num_parents: number of possible parents
+ * @flags: framework-level hints and quirks
+ *
+ * clk_register is the primary interface for populating the clock tree with new
+ * clock nodes.  It returns a pointer to the newly allocated struct clk which
+ * cannot be dereferenced by driver code but may be used in conjuction with the
+ * rest of the clock API.
+ */
+struct clk *clk_register(struct device *dev, const char *name,
+               const struct clk_ops *ops, struct clk_hw *hw,
+               char **parent_names, u8 num_parents, unsigned long flags);
+
+/* helper functions */
+const char *__clk_get_name(struct clk *clk);
+struct clk_hw *__clk_get_hw(struct clk *clk);
+u8 __clk_get_num_parents(struct clk *clk);
+struct clk *__clk_get_parent(struct clk *clk);
+inline int __clk_get_enable_count(struct clk *clk);
+inline int __clk_get_prepare_count(struct clk *clk);
+unsigned long __clk_get_rate(struct clk *clk);
+unsigned long __clk_get_flags(struct clk *clk);
+int __clk_is_enabled(struct clk *clk);
+struct clk *__clk_lookup(const char *name);
+
+/*
+ * FIXME clock api without lock protection
+ */
+int __clk_prepare(struct clk *clk);
+void __clk_unprepare(struct clk *clk);
+void __clk_reparent(struct clk *clk, struct clk *new_parent);
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate);
+
+#endif /* CONFIG_COMMON_CLK */
+#endif /* CLK_PROVIDER_H */
index b9d46fa..b025272 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 ARM Limited.
  *  Written by Deep Blue Solutions Limited.
+ *  Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
  *
  * 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
 #define __LINUX_CLK_H
 
 #include <linux/kernel.h>
+#include <linux/notifier.h>
 
 struct device;
 
-/*
- * The base API.
+struct clk;
+
+#ifdef CONFIG_COMMON_CLK
+
+/**
+ * DOC: clk notifier callback types
+ *
+ * PRE_RATE_CHANGE - called immediately before the clk rate is changed,
+ *     to indicate that the rate change will proceed.  Drivers must
+ *     immediately terminate any operations that will be affected by the
+ *     rate change.  Callbacks may either return NOTIFY_DONE or
+ *     NOTIFY_STOP.
+ *
+ * ABORT_RATE_CHANGE: called if the rate change failed for some reason
+ *     after PRE_RATE_CHANGE.  In this case, all registered notifiers on
+ *     the clk will be called with ABORT_RATE_CHANGE. Callbacks must
+ *     always return NOTIFY_DONE.
+ *
+ * POST_RATE_CHANGE - called after the clk rate change has successfully
+ *     completed.  Callbacks must always return NOTIFY_DONE.
+ *
  */
+#define PRE_RATE_CHANGE                        BIT(0)
+#define POST_RATE_CHANGE               BIT(1)
+#define ABORT_RATE_CHANGE              BIT(2)
 
+/**
+ * struct clk_notifier - associate a clk with a notifier
+ * @clk: struct clk * to associate the notifier with
+ * @notifier_head: a blocking_notifier_head for this clk
+ * @node: linked list pointers
+ *
+ * A list of struct clk_notifier is maintained by the notifier code.
+ * An entry is created whenever code registers the first notifier on a
+ * particular @clk.  Future notifiers on that @clk are added to the
+ * @notifier_head.
+ */
+struct clk_notifier {
+       struct clk                      *clk;
+       struct srcu_notifier_head       notifier_head;
+       struct list_head                node;
+};
 
-/*
- * struct clk - an machine class defined object / cookie.
+/**
+ * struct clk_notifier_data - rate data to pass to the notifier callback
+ * @clk: struct clk * being changed
+ * @old_rate: previous rate of this clk
+ * @new_rate: new rate of this clk
+ *
+ * For a pre-notifier, old_rate is the clk's rate before this rate
+ * change, and new_rate is what the rate will be in the future.  For a
+ * post-notifier, old_rate and new_rate are both set to the clk's
+ * current rate (this was done to optimize the implementation).
  */
-struct clk;
+struct clk_notifier_data {
+       struct clk              *clk;
+       unsigned long           old_rate;
+       unsigned long           new_rate;
+};
+
+int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
+
+int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
+
+#endif /* !CONFIG_COMMON_CLK */
 
 /**
  * clk_get - lookup and obtain a reference to a clock producer.
index 3fd17c2..e5834aa 100644 (file)
@@ -87,7 +87,8 @@
  */
 #define __pure                         __attribute__((pure))
 #define __aligned(x)                   __attribute__((aligned(x)))
-#define __printf(a,b)                  __attribute__((format(printf,a,b)))
+#define __printf(a, b)                 __attribute__((format(printf, a, b)))
+#define __scanf(a, b)                  __attribute__((format(scanf, a, b)))
 #define  noinline                      __attribute__((noinline))
 #define __attribute_const__            __attribute__((__const__))
 #define __maybe_unused                 __attribute__((unused))
index 6e53b48..ee28844 100644 (file)
 #ifndef _LINUX_CPU_H_
 #define _LINUX_CPU_H_
 
-#include <linux/device.h>
 #include <linux/node.h>
 #include <linux/compiler.h>
 #include <linux/cpumask.h>
 
+struct device;
+
 struct cpu {
        int node_id;            /* The node which contains the CPU */
        int hotpluggable;       /* creates sysfs control file if hotpluggable */
index 6216115..b60f6ba 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/mutex.h>
 #include <linux/notifier.h>
 #include <linux/threads.h>
-#include <linux/device.h>
 #include <linux/kobject.h>
 #include <linux/sysfs.h>
 #include <linux/completion.h>
@@ -35,6 +34,7 @@
 #ifdef CONFIG_CPU_FREQ
 int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
 int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
+extern void disable_cpufreq(void);
 #else          /* CONFIG_CPU_FREQ */
 static inline int cpufreq_register_notifier(struct notifier_block *nb,
                                                unsigned int list)
@@ -46,6 +46,7 @@ static inline int cpufreq_unregister_notifier(struct notifier_block *nb,
 {
        return 0;
 }
+static inline void disable_cpufreq(void) { }
 #endif         /* CONFIG_CPU_FREQ */
 
 /* if (cpufreq_driver->target) exists, the ->governor decides what frequency
index 4f7a632..7b9b75a 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/threads.h>
 #include <linux/bitmap.h>
+#include <linux/bug.h>
 
 typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
 
index b936763..37e4f8d 100644 (file)
@@ -3,7 +3,6 @@
 
 #ifdef CONFIG_CRASH_DUMP
 #include <linux/kexec.h>
-#include <linux/device.h>
 #include <linux/proc_fs.h>
 #include <linux/elf.h>
 
index 391a259..68267b6 100644 (file)
@@ -11,6 +11,8 @@
 extern u32  crc32_le(u32 crc, unsigned char const *p, size_t len);
 extern u32  crc32_be(u32 crc, unsigned char const *p, size_t len);
 
+extern u32  __crc32c_le(u32 crc, unsigned char const *p, size_t len);
+
 #define crc32(seed, data, length)  crc32_le(seed, (unsigned char const *)(data), length)
 
 /*
index 48ce547..b92eadf 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/atomic.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/uaccess.h>
index 75cae8b..3bd46f7 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/kernel.h>
 #include <linux/atomic.h>
+#include <linux/bug.h>
 
 struct task_struct;
 
index f8ac076..3efbfc2 100644 (file)
 
 #include <linux/file.h>
 #include <linux/err.h>
-#include <linux/device.h>
 #include <linux/scatterlist.h>
 #include <linux/list.h>
 #include <linux/dma-mapping.h>
+#include <linux/fs.h>
 
+struct device;
 struct dma_buf;
 struct dma_buf_attachment;
 
@@ -49,6 +50,17 @@ struct dma_buf_attachment;
  * @unmap_dma_buf: decreases usecount of buffer, might deallocate scatter
  *                pages.
  * @release: release this buffer; to be called after the last dma_buf_put.
+ * @begin_cpu_access: [optional] called before cpu access to invalidate cpu
+ *                   caches and allocate backing storage (if not yet done)
+ *                   respectively pin the objet into memory.
+ * @end_cpu_access: [optional] called after cpu access to flush cashes.
+ * @kmap_atomic: maps a page from the buffer into kernel address
+ *              space, users may not block until the subsequent unmap call.
+ *              This callback must not sleep.
+ * @kunmap_atomic: [optional] unmaps a atomically mapped page from the buffer.
+ *                This Callback must not sleep.
+ * @kmap: maps a page from the buffer into kernel address space.
+ * @kunmap: [optional] unmaps a page from the buffer.
  */
 struct dma_buf_ops {
        int (*attach)(struct dma_buf *, struct device *,
@@ -63,7 +75,8 @@ struct dma_buf_ops {
        struct sg_table * (*map_dma_buf)(struct dma_buf_attachment *,
                                                enum dma_data_direction);
        void (*unmap_dma_buf)(struct dma_buf_attachment *,
-                                               struct sg_table *);
+                                               struct sg_table *,
+                                               enum dma_data_direction);
        /* TODO: Add try_map_dma_buf version, to return immed with -EBUSY
         * if the call would block.
         */
@@ -71,6 +84,14 @@ struct dma_buf_ops {
        /* after final dma_buf_put() */
        void (*release)(struct dma_buf *);
 
+       int (*begin_cpu_access)(struct dma_buf *, size_t, size_t,
+                               enum dma_data_direction);
+       void (*end_cpu_access)(struct dma_buf *, size_t, size_t,
+                              enum dma_data_direction);
+       void *(*kmap_atomic)(struct dma_buf *, unsigned long);
+       void (*kunmap_atomic)(struct dma_buf *, unsigned long, void *);
+       void *(*kmap)(struct dma_buf *, unsigned long);
+       void (*kunmap)(struct dma_buf *, unsigned long, void *);
 };
 
 /**
@@ -86,7 +107,7 @@ struct dma_buf {
        struct file *file;
        struct list_head attachments;
        const struct dma_buf_ops *ops;
-       /* mutex to serialize list manipulation and other ops */
+       /* mutex to serialize list manipulation and attach/detach */
        struct mutex lock;
        void *priv;
 };
@@ -109,20 +130,43 @@ struct dma_buf_attachment {
        void *priv;
 };
 
+/**
+ * get_dma_buf - convenience wrapper for get_file.
+ * @dmabuf:    [in]    pointer to dma_buf
+ *
+ * Increments the reference count on the dma-buf, needed in case of drivers
+ * that either need to create additional references to the dmabuf on the
+ * kernel side.  For example, an exporter that needs to keep a dmabuf ptr
+ * so that subsequent exports don't create a new dmabuf.
+ */
+static inline void get_dma_buf(struct dma_buf *dmabuf)
+{
+       get_file(dmabuf->file);
+}
+
 #ifdef CONFIG_DMA_SHARED_BUFFER
 struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
                                                        struct device *dev);
 void dma_buf_detach(struct dma_buf *dmabuf,
                                struct dma_buf_attachment *dmabuf_attach);
-struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
-                       size_t size, int flags);
-int dma_buf_fd(struct dma_buf *dmabuf);
+struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
+                              size_t size, int flags);
+int dma_buf_fd(struct dma_buf *dmabuf, int flags);
 struct dma_buf *dma_buf_get(int fd);
 void dma_buf_put(struct dma_buf *dmabuf);
 
 struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
                                        enum dma_data_direction);
-void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *);
+void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
+                               enum dma_data_direction);
+int dma_buf_begin_cpu_access(struct dma_buf *dma_buf, size_t start, size_t len,
+                            enum dma_data_direction dir);
+void dma_buf_end_cpu_access(struct dma_buf *dma_buf, size_t start, size_t len,
+                           enum dma_data_direction dir);
+void *dma_buf_kmap_atomic(struct dma_buf *, unsigned long);
+void dma_buf_kunmap_atomic(struct dma_buf *, unsigned long, void *);
+void *dma_buf_kmap(struct dma_buf *, unsigned long);
+void dma_buf_kunmap(struct dma_buf *, unsigned long, void *);
 #else
 
 static inline struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
@@ -138,13 +182,13 @@ static inline void dma_buf_detach(struct dma_buf *dmabuf,
 }
 
 static inline struct dma_buf *dma_buf_export(void *priv,
-                                               struct dma_buf_ops *ops,
-                                               size_t size, int flags)
+                                            const struct dma_buf_ops *ops,
+                                            size_t size, int flags)
 {
        return ERR_PTR(-ENODEV);
 }
 
-static inline int dma_buf_fd(struct dma_buf *dmabuf)
+static inline int dma_buf_fd(struct dma_buf *dmabuf, int flags)
 {
        return -ENODEV;
 }
@@ -166,11 +210,44 @@ static inline struct sg_table *dma_buf_map_attachment(
 }
 
 static inline void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
-                                               struct sg_table *sg)
+                       struct sg_table *sg, enum dma_data_direction dir)
 {
        return;
 }
 
+static inline int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
+                                          size_t start, size_t len,
+                                          enum dma_data_direction dir)
+{
+       return -ENODEV;
+}
+
+static inline void dma_buf_end_cpu_access(struct dma_buf *dmabuf,
+                                         size_t start, size_t len,
+                                         enum dma_data_direction dir)
+{
+}
+
+static inline void *dma_buf_kmap_atomic(struct dma_buf *dmabuf,
+                                       unsigned long pnum)
+{
+       return NULL;
+}
+
+static inline void dma_buf_kunmap_atomic(struct dma_buf *dmabuf,
+                                        unsigned long pnum, void *vaddr)
+{
+}
+
+static inline void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long pnum)
+{
+       return NULL;
+}
+
+static inline void dma_buf_kunmap(struct dma_buf *dmabuf,
+                                 unsigned long pnum, void *vaddr)
+{
+}
 #endif /* CONFIG_DMA_SHARED_BUFFER */
 
 #endif /* __DMA_BUF_H__ */
index 679b349..a5966f6 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/device.h>
 #include <linux/uio.h>
+#include <linux/bug.h>
 #include <linux/scatterlist.h>
 #include <linux/bitmap.h>
 #include <asm/page.h>
index 1cd3947..c621d76 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>
+
+struct device;
 
 #define EDAC_OPSTATE_INVAL     -1
 #define EDAC_OPSTATE_POLL      0
@@ -66,25 +70,64 @@ enum dev_type {
 #define DEV_FLAG_X32           BIT(DEV_X32)
 #define DEV_FLAG_X64           BIT(DEV_X64)
 
-/* memory types */
+/**
+ * enum mem_type - memory types. For a more detailed reference, please see
+ *                     http://en.wikipedia.org/wiki/DRAM
+ *
+ * @MEM_EMPTY          Empty csrow
+ * @MEM_RESERVED:      Reserved csrow type
+ * @MEM_UNKNOWN:       Unknown csrow type
+ * @MEM_FPM:           FPM - Fast Page Mode, used on systems up to 1995.
+ * @MEM_EDO:           EDO - Extended data out, used on systems up to 1998.
+ * @MEM_BEDO:          BEDO - Burst Extended data out, an EDO variant.
+ * @MEM_SDR:           SDR - Single data rate SDRAM
+ *                     http://en.wikipedia.org/wiki/Synchronous_dynamic_random-access_memory
+ *                     They use 3 pins for chip select: Pins 0 and 2 are
+ *                     for rank 0; pins 1 and 3 are for rank 1, if the memory
+ *                     is dual-rank.
+ * @MEM_RDR:           Registered SDR SDRAM
+ * @MEM_DDR:           Double data rate SDRAM
+ *                     http://en.wikipedia.org/wiki/DDR_SDRAM
+ * @MEM_RDDR:          Registered Double data rate SDRAM
+ *                     This is a variant of the DDR memories.
+ *                     A registered memory has a buffer inside it, hiding
+ *                     part of the memory details to the memory controller.
+ * @MEM_RMBS:          Rambus DRAM, used on a few Pentium III/IV controllers.
+ * @MEM_DDR2:          DDR2 RAM, as described at JEDEC JESD79-2F.
+ *                     Those memories are labed as "PC2-" instead of "PC" to
+ *                     differenciate from DDR.
+ * @MEM_FB_DDR2:       Fully-Buffered DDR2, as described at JEDEC Std No. 205
+ *                     and JESD206.
+ *                     Those memories are accessed per DIMM slot, and not by
+ *                     a chip select signal.
+ * @MEM_RDDR2:         Registered DDR2 RAM
+ *                     This is a variant of the DDR2 memories.
+ * @MEM_XDR:           Rambus XDR
+ *                     It is an evolution of the original RAMBUS memories,
+ *                     created to compete with DDR2. Weren't used on any
+ *                     x86 arch, but cell_edac PPC memory controller uses it.
+ * @MEM_DDR3:          DDR3 RAM
+ * @MEM_RDDR3:         Registered DDR3 RAM
+ *                     This is a variant of the DDR3 memories.
+ */
 enum mem_type {
-       MEM_EMPTY = 0,          /* Empty csrow */
-       MEM_RESERVED,           /* Reserved csrow type */
-       MEM_UNKNOWN,            /* Unknown csrow type */
-       MEM_FPM,                /* Fast page mode */
-       MEM_EDO,                /* Extended data out */
-       MEM_BEDO,               /* Burst Extended data out */
-       MEM_SDR,                /* Single data rate SDRAM */
-       MEM_RDR,                /* Registered single data rate SDRAM */
-       MEM_DDR,                /* Double data rate SDRAM */
-       MEM_RDDR,               /* Registered Double data rate SDRAM */
-       MEM_RMBS,               /* Rambus DRAM */
-       MEM_DDR2,               /* DDR2 RAM */
-       MEM_FB_DDR2,            /* fully buffered DDR2 */
-       MEM_RDDR2,              /* Registered DDR2 RAM */
-       MEM_XDR,                /* Rambus XDR */
-       MEM_DDR3,               /* DDR3 RAM */
-       MEM_RDDR3,              /* Registered DDR3 RAM */
+       MEM_EMPTY = 0,
+       MEM_RESERVED,
+       MEM_UNKNOWN,
+       MEM_FPM,
+       MEM_EDO,
+       MEM_BEDO,
+       MEM_SDR,
+       MEM_RDR,
+       MEM_DDR,
+       MEM_RDDR,
+       MEM_RMBS,
+       MEM_DDR2,
+       MEM_FB_DDR2,
+       MEM_RDDR2,
+       MEM_XDR,
+       MEM_DDR3,
+       MEM_RDDR3,
 };
 
 #define MEM_FLAG_EMPTY         BIT(MEM_EMPTY)
@@ -162,8 +205,9 @@ enum scrub_type {
 #define OP_OFFLINE             0x300
 
 /*
- * There are several things to be aware of that aren't at all obvious:
+ * Concepts used at the EDAC subsystem
  *
+ * There are several things to be aware of that aren't at all obvious:
  *
  * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc..
  *
@@ -172,36 +216,61 @@ enum scrub_type {
  * creating a common ground for discussion, terms and their definitions
  * will be established.
  *
- * Memory devices:     The individual chip on a memory stick.  These devices
- *                     commonly output 4 and 8 bits each.  Grouping several
- *                     of these in parallel provides 64 bits which is common
- *                     for a memory stick.
+ * Memory devices:     The individual DRAM chips on a memory stick.  These
+ *                     devices commonly output 4 and 8 bits each (x4, x8).
+ *                     Grouping several of these in parallel provides the
+ *                     number of bits that the memory controller expects:
+ *                     typically 72 bits, in order to provide 64 bits +
+ *                     8 bits of ECC data.
  *
  * Memory Stick:       A printed circuit board that aggregates multiple
- *                     memory devices in parallel.  This is the atomic
- *                     memory component that is purchaseable by Joe consumer
- *                     and loaded into a memory socket.
+ *                     memory devices in parallel.  In general, this is the
+ *                     Field Replaceable Unit (FRU) which gets replaced, in
+ *                     the case of excessive errors. Most often it is also
+ *                     called DIMM (Dual Inline Memory Module).
+ *
+ * Memory Socket:      A physical connector on the motherboard that accepts
+ *                     a single memory stick. Also called as "slot" on several
+ *                     datasheets.
  *
- * Socket:             A physical connector on the motherboard that accepts
- *                     a single memory stick.
+ * Channel:            A memory controller channel, responsible to communicate
+ *                     with a group of DIMMs. Each channel has its own
+ *                     independent control (command) and data bus, and can
+ *                     be used independently or grouped with other channels.
  *
- * Channel:            Set of memory devices on a memory stick that must be
- *                     grouped in parallel with one or more additional
- *                     channels from other memory sticks.  This parallel
- *                     grouping of the output from multiple channels are
- *                     necessary for the smallest granularity of memory access.
- *                     Some memory controllers are capable of single channel -
- *                     which means that memory sticks can be loaded
- *                     individually.  Other memory controllers are only
- *                     capable of dual channel - which means that memory
- *                     sticks must be loaded as pairs (see "socket set").
+ * Branch:             It is typically the highest hierarchy on a
+ *                     Fully-Buffered DIMM memory controller.
+ *                     Typically, it contains two channels.
+ *                     Two channels at the same branch can be used in single
+ *                     mode or in lockstep mode.
+ *                     When lockstep is enabled, the cacheline is doubled,
+ *                     but it generally brings some performance penalty.
+ *                     Also, it is generally not possible to point to just one
+ *                     memory stick when an error occurs, as the error
+ *                     correction code is calculated using two DIMMs instead
+ *                     of one. Due to that, it is capable of correcting more
+ *                     errors than on single mode.
  *
- * Chip-select row:    All of the memory devices that are selected together.
- *                     for a single, minimum grain of memory access.
- *                     This selects all of the parallel memory devices across
- *                     all of the parallel channels.  Common chip-select rows
- *                     for single channel are 64 bits, for dual channel 128
- *                     bits.
+ * Single-channel:     The data accessed by the memory controller is contained
+ *                     into one dimm only. E. g. if the data is 64 bits-wide,
+ *                     the data flows to the CPU using one 64 bits parallel
+ *                     access.
+ *                     Typically used with SDR, DDR, DDR2 and DDR3 memories.
+ *                     FB-DIMM and RAMBUS use a different concept for channel,
+ *                     so this concept doesn't apply there.
+ *
+ * Double-channel:     The data size accessed by the memory controller is
+ *                     interlaced into two dimms, accessed at the same time.
+ *                     E. g. if the DIMM is 64 bits-wide (72 bits with ECC),
+ *                     the data flows to the CPU using a 128 bits parallel
+ *                     access.
+ *
+ * Chip-select row:    This is the name of the DRAM signal used to select the
+ *                     DRAM ranks to be accessed. Common chip-select rows for
+ *                     single channel are 64 bits, for dual channel 128 bits.
+ *                     It may not be visible by the memory controller, as some
+ *                     DIMM types have a memory buffer that can hide direct
+ *                     access to it from the Memory Controller.
  *
  * Single-Ranked stick:        A Single-ranked stick has 1 chip-select row of memory.
  *                     Motherboards commonly drive two chip-select pins to
@@ -214,8 +283,8 @@ enum scrub_type {
  *
  * Double-sided stick: DEPRECATED TERM, see Double-Ranked stick.
  *                     A double-sided stick has two chip-select rows which
- *                     access different sets of memory devices.  The two
- *                     rows cannot be accessed concurrently.  "Double-sided"
+ *                     access different sets of memory devices. The two
+ *                     rows cannot be accessed concurrently. "Double-sided"
  *                     is irrespective of the memory devices being mounted
  *                     on both sides of the memory stick.
  *
@@ -243,10 +312,22 @@ enum scrub_type {
  * PS - I enjoyed writing all that about as much as you enjoyed reading it.
  */
 
-struct channel_info {
-       int chan_idx;           /* channel index */
-       u32 ce_count;           /* Correctable Errors for this CHANNEL */
-       char label[EDAC_MC_LABEL_LEN + 1];      /* DIMM label on motherboard */
+/**
+ * struct rank_info - contains the information for one DIMM rank
+ *
+ * @chan_idx:  channel number where the rank is (typically, 0 or 1)
+ * @ce_count:  number of correctable errors for this rank
+ * @label:     DIMM label. Different ranks for the same DIMM should be
+ *             filled, on userspace, with the same label.
+ *             FIXME: The core currently won't enforce it.
+ * @csrow:     A pointer to the chip select row structure (the parent
+ *             structure). The location of the rank is given by
+ *             the (csrow->csrow_idx, chan_idx) vector.
+ */
+struct rank_info {
+       int chan_idx;
+       u32 ce_count;
+       char label[EDAC_MC_LABEL_LEN + 1];
        struct csrow_info *csrow;       /* the parent */
 };
 
@@ -270,7 +351,7 @@ struct csrow_info {
 
        /* channel information for this csrow */
        u32 nr_channels;
-       struct channel_info *channels;
+       struct rank_info *channels;
 };
 
 struct mcidev_sysfs_group {
index 394a3e0..0698c79 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/time.h>
 #ifdef __KERNEL__
 #include <linux/user.h>
+#include <linux/bug.h>
 #endif
 #include <linux/ptrace.h>
 #include <linux/elf.h>
index f957085..f5a84ee 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/types.h>
 #include <linux/magic.h>
+#include <linux/bug.h>
 
 /*
  * The second extended filesystem constants/structures
index a395b8c..d31cb68 100644 (file)
@@ -407,7 +407,6 @@ struct fb_cursor {
 
 #include <linux/fs.h>
 #include <linux/init.h>
-#include <linux/device.h>
 #include <linux/workqueue.h>
 #include <linux/notifier.h>
 #include <linux/list.h>
index cdc9b71..4db7b68 100644 (file)
@@ -2,7 +2,6 @@
 #define _LINUX_FIREWIRE_H
 
 #include <linux/completion.h>
-#include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/kref.h>
@@ -65,6 +64,8 @@
 #define CSR_MODEL              0x17
 #define CSR_DIRECTORY_ID       0x20
 
+struct device;
+
 struct fw_csr_iterator {
        const u32 *p;
        const u32 *end;
index 9bbe1a9..c437f91 100644 (file)
@@ -389,6 +389,7 @@ struct inodes_stat_t {
 #include <linux/prio_tree.h>
 #include <linux/init.h>
 #include <linux/pid.h>
+#include <linux/bug.h>
 #include <linux/mutex.h>
 #include <linux/capability.h>
 #include <linux/semaphore.h>
@@ -1871,19 +1872,6 @@ extern struct dentry *mount_pseudo(struct file_system_type *, char *,
        const struct dentry_operations *dops,
        unsigned long);
 
-static inline void sb_mark_dirty(struct super_block *sb)
-{
-       sb->s_dirt = 1;
-}
-static inline void sb_mark_clean(struct super_block *sb)
-{
-       sb->s_dirt = 0;
-}
-static inline int sb_is_dirty(struct super_block *sb)
-{
-       return sb->s_dirt;
-}
-
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
 #define fops_get(fops) \
        (((fops) && try_module_get((fops)->owner) ? (fops) : NULL))
index 2a53f10..a6dfe69 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/fsnotify_backend.h>
 #include <linux/audit.h>
 #include <linux/slab.h>
+#include <linux/bug.h>
 
 /*
  * fsnotify_d_instantiate - instantiate a dentry for inode
index 38ac48b..6155ecf 100644 (file)
 #define GPIOF_OUT_INIT_LOW     (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
 #define GPIOF_OUT_INIT_HIGH    (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
 
+/* Gpio pin is open drain */
+#define GPIOF_OPEN_DRAIN       (1 << 2)
+
+/* Gpio pin is open source */
+#define GPIOF_OPEN_SOURCE      (1 << 3)
+
 /**
  * struct gpio - a structure describing a GPIO with configuration
  * @gpio:      the GPIO number
@@ -34,6 +40,7 @@ struct gpio {
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/bug.h>
 
 struct device;
 struct gpio_chip;
index 6549ed7..d3999b4 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/fs.h>
 #include <linux/kernel.h>
+#include <linux/bug.h>
 #include <linux/mm.h>
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
index a90c09d..1c7b89a 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef _LINUX_HWMON_SYSFS_H
 #define _LINUX_HWMON_SYSFS_H
 
+#include <linux/device.h>
+
 struct sensor_device_attribute{
        struct device_attribute dev_attr;
        int index;
index 6b6ee70..82b29ae 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef _HWMON_H_
 #define _HWMON_H_
 
-#include <linux/device.h>
+struct device;
 
 struct device *hwmon_device_register(struct device *dev);
 
index aad6bd4..3343298 100644 (file)
 
 #include <linux/err.h>
 #include <linux/sched.h>
-#include <linux/device.h>
 
 /* hwspinlock mode argument */
 #define HWLOCK_IRQSTATE        0x01    /* Disable interrupts, save state */
 #define HWLOCK_IRQ     0x02    /* Disable interrupts, don't save state */
 
+struct device;
 struct hwspinlock;
 struct hwspinlock_device;
 struct hwspinlock_ops;
index 584ffa0..63904ba 100644 (file)
@@ -15,7 +15,8 @@
 
     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.                */
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.                                                      */
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
index 0f91a95..538e8f4 100644 (file)
@@ -16,7 +16,8 @@
 
     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.                */
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.                                                      */
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
index fd53bfd..8a7406b 100644 (file)
@@ -16,7 +16,8 @@
 
     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.
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.
 */
 
 #ifndef _LINUX_I2C_DEV_H
index 34536ef..747f0cd 100644 (file)
@@ -18,7 +18,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
  */
 
 #ifndef _LINUX_I2C_MUX_H
index 63f57a8..017fb40 100644 (file)
@@ -15,7 +15,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
  */
 
 #ifndef _LINUX_I2C_SMBUS_H
index 8e25a91..195d8b3 100644 (file)
@@ -17,7 +17,8 @@
 
     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.               */
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.                                                      */
 /* ------------------------------------------------------------------------- */
 
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
index 8ace930..285025a 100644 (file)
@@ -1,19 +1,42 @@
+/*
+ * at24.h - platform_data for the at24 (generic eeprom) driver
+ * (C) Copyright 2008 by Pengutronix
+ * (C) Copyright 2012 by Wolfram Sang
+ * same license as the driver
+ */
+
 #ifndef _LINUX_AT24_H
 #define _LINUX_AT24_H
 
 #include <linux/types.h>
 #include <linux/memory.h>
 
-/*
- * As seen through Linux I2C, differences between the most common types of I2C
- * memory include:
- * - How much memory is available (usually specified in bit)?
- * - What write page size does it support?
- * - Special flags (16 bit addresses, read_only, world readable...)?
+/**
+ * struct at24_platform_data - data to set up at24 (generic eeprom) driver
+ * @byte_len: size of eeprom in byte
+ * @page_size: number of byte which can be written in one go
+ * @flags: tunable options, check AT24_FLAG_* defines
+ * @setup: an optional callback invoked after eeprom is probed; enables kernel
+       code to access eeprom via memory_accessor, see example
+ * @context: optional parameter passed to setup()
  *
  * If you set up a custom eeprom type, please double-check the parameters.
  * Especially page_size needs extra care, as you risk data loss if your value
  * is bigger than what the chip actually supports!
+ *
+ * An example in pseudo code for a setup() callback:
+ *
+ * void get_mac_addr(struct memory_accessor *mem_acc, void *context)
+ * {
+ *     u8 *mac_addr = ethernet_pdata->mac_addr;
+ *     off_t offset = context;
+ *
+ *     // Read MAC addr from EEPROM
+ *     if (mem_acc->read(mem_acc, mac_addr, offset, ETH_ALEN) == ETH_ALEN)
+ *             pr_info("Read MAC addr from EEPROM: %pM\n", mac_addr);
+ * }
+ *
+ * This function pointer and context can now be set up in at24_platform_data.
  */
 
 struct at24_platform_data {
index 7fcab23..2463b61 100644 (file)
@@ -761,7 +761,7 @@ struct twl_regulator_driver_data {
 
 /*----------------------------------------------------------------------*/
 
-int twl4030_sih_setup(int module);
+int twl4030_sih_setup(struct device *dev, int module, int irq_base);
 
 /* Offsets to Power Registers */
 #define TWL4030_VDAC_DEV_GRP           0x3B
index a6deef4..d23c3c2 100644 (file)
@@ -24,6 +24,7 @@
 #define I2O_MAX_DRIVERS                8
 
 #include <linux/pci.h>
+#include <linux/bug.h>
 #include <linux/dma-mapping.h>
 #include <linux/string.h>
 #include <linux/slab.h>
index 9e355d0..b179749 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/bio.h>
-#include <linux/device.h>
 #include <linux/pci.h>
 #include <linux/completion.h>
 #include <linux/pm.h>
@@ -42,6 +41,8 @@
 #define ERROR_RESET    3       /* Reset controller every 4th retry */
 #define ERROR_RECAL    1       /* Recalibrate every 2nd retry */
 
+struct device;
+
 /* Error codes returned in rq->errors to the higher part of the driver. */
 enum {
        IDE_DRV_ERROR_GENERAL   = 101,
index 33a6e19..a810987 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
+#include <linux/bug.h>
 
 #define VLAN_HLEN      4               /* The additional bytes required by VLAN
                                         * (in addition to the Ethernet header)
index e44e84f..657fab4 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/types.h>
 #include <linux/slab.h>
+#include <linux/bug.h>
 #include <asm/io.h>
 #include <asm/page.h>
 
index 9d57a71..e885ba2 100644 (file)
@@ -23,12 +23,6 @@ struct resource {
        struct resource *parent, *sibling, *child;
 };
 
-struct resource_list {
-       struct resource_list *next;
-       struct resource *res;
-       struct pci_dev *dev;
-};
-
 /*
  * IO resources have these defined flags.
  */
index bbd156b..48dcba9 100644 (file)
@@ -220,10 +220,10 @@ struct kernel_ipmi_msg {
  * The in-kernel interface.
  */
 #include <linux/list.h>
-#include <linux/device.h>
 #include <linux/proc_fs.h>
 
 struct module;
+struct device;
 
 /* Opaque type for a IPMI message user.  One of these is needed to
    send and receive messages. */
index 3ef0d8b..fcb5d44 100644 (file)
 
 #include <linux/ipmi_msgdefs.h>
 #include <linux/proc_fs.h>
-#include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/ipmi.h>
 
+struct device;
+
 /* This files describes the interface for IPMI system management interface
    drivers to bind into the IPMI message handler. */
 
index 062d20f..42bf725 100644 (file)
@@ -58,7 +58,11 @@ struct ivtv_dma_frame {
        __u32 src_height;
 };
 
-#define IVTV_IOC_DMA_FRAME  _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame)
+#define IVTV_IOC_DMA_FRAME             _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame)
+
+/* Select the passthrough mode (if the argument is non-zero). In the passthrough
+   mode the output of the encoder is passed immediately into the decoder. */
+#define IVTV_IOC_PASSTHROUGH_MODE      _IOW ('V', BASE_VIDIOC_PRIVATE+1, int)
 
 /* Deprecated defines: applications should use the defines from videodev2.h */
 #define IVTV_SLICED_TYPE_TELETEXT_B     V4L2_MPEG_VBI_IVTV_TELETEXT_B
index 5557bae..912c30a 100644 (file)
@@ -971,6 +971,10 @@ extern void __journal_clean_data_list(transaction_t *transaction);
 /* Log buffer allocation */
 extern struct journal_head * jbd2_journal_get_descriptor_buffer(journal_t *);
 int jbd2_journal_next_log_block(journal_t *, unsigned long long *);
+int jbd2_journal_get_log_tail(journal_t *journal, tid_t *tid,
+                             unsigned long *block);
+void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block);
+void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block);
 
 /* Commit management */
 extern void jbd2_journal_commit_transaction(journal_t *);
@@ -1020,6 +1024,11 @@ jbd2_journal_write_metadata_buffer(transaction_t   *transaction,
 /* Transaction locking */
 extern void            __wait_on_journal (journal_t *);
 
+/* Transaction cache support */
+extern void jbd2_journal_destroy_transaction_cache(void);
+extern int  jbd2_journal_init_transaction_cache(void);
+extern void jbd2_journal_free_transaction(transaction_t *);
+
 /*
  * Journal locking.
  *
@@ -1082,7 +1091,8 @@ extern int           jbd2_journal_destroy    (journal_t *);
 extern int        jbd2_journal_recover    (journal_t *journal);
 extern int        jbd2_journal_wipe       (journal_t *, int);
 extern int        jbd2_journal_skip_recovery   (journal_t *);
-extern void       jbd2_journal_update_superblock       (journal_t *, int);
+extern void       jbd2_journal_update_sb_log_tail      (journal_t *, tid_t,
+                               unsigned long, int);
 extern void       __jbd2_journal_abort_hard    (journal_t *);
 extern void       jbd2_journal_abort      (journal_t *, int);
 extern int        jbd2_journal_errno      (journal_t *);
index 423cb6d..c18b46f 100644 (file)
@@ -66,6 +66,8 @@ struct journal_head {
         * transaction (if there is one).  Only applies to buffers on a
         * transaction's data or metadata journaling list.
         * [j_list_lock] [jbd_lock_bh_state()]
+        * Either of these locks is enough for reading, both are needed for
+        * changes.
         */
        transaction_t *b_transaction;
 
index 9053f95..8184578 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef __LINUX_JZ4740_ADC
 #define __LINUX_JZ4740_ADC
 
-#include <linux/device.h>
+struct device;
 
 /*
  * jz4740_adc_set_config - Configure a JZ4740 adc device
index d801acb..5db52d0 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/printk.h>
 #include <linux/dynamic_debug.h>
 #include <asm/byteorder.h>
-#include <asm/bug.h>
 
 #define USHRT_MAX      ((u16)(~0U))
 #define SHRT_MAX       ((s16)(USHRT_MAX>>1))
@@ -312,6 +311,8 @@ extern long long simple_strtoll(const char *,char **,unsigned int);
 #define strict_strtoull        kstrtoull
 #define strict_strtoll kstrtoll
 
+extern int num_to_str(char *buf, int size, unsigned long long num);
+
 /* lib/printf utilities */
 
 extern __printf(2, 3) int sprintf(char *buf, const char * fmt, ...);
@@ -328,10 +329,10 @@ extern __printf(2, 3)
 char *kasprintf(gfp_t gfp, const char *fmt, ...);
 extern char *kvasprintf(gfp_t gfp, const char *fmt, va_list args);
 
-extern int sscanf(const char *, const char *, ...)
-       __attribute__ ((format (scanf, 2, 3)));
-extern int vsscanf(const char *, const char *, va_list)
-       __attribute__ ((format (scanf, 2, 0)));
+extern __scanf(2, 3)
+int sscanf(const char *, const char *, ...);
+extern __scanf(2, 0)
+int vsscanf(const char *, const char *, va_list);
 
 extern int get_option(char **str, int *pint);
 extern char *get_options(const char *str, int nints, int *ints);
@@ -675,67 +676,6 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})
 
-#ifdef __CHECKER__
-#define BUILD_BUG_ON_NOT_POWER_OF_2(n)
-#define BUILD_BUG_ON_ZERO(e) (0)
-#define BUILD_BUG_ON_NULL(e) ((void*)0)
-#define BUILD_BUG_ON(condition)
-#define BUILD_BUG() (0)
-#else /* __CHECKER__ */
-
-/* Force a compilation error if a constant expression is not a power of 2 */
-#define BUILD_BUG_ON_NOT_POWER_OF_2(n)                 \
-       BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
-
-/* Force a compilation error if condition is true, but also produce a
-   result (of value 0 and type size_t), so the expression can be used
-   e.g. in a structure initializer (or where-ever else comma expressions
-   aren't permitted). */
-#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
-#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
-
-/**
- * BUILD_BUG_ON - break compile if a condition is true.
- * @condition: the condition which the compiler should know is false.
- *
- * If you have some code which relies on certain constants being equal, or
- * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
- * detect if someone changes it.
- *
- * The implementation uses gcc's reluctance to create a negative array, but
- * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
- * to inline functions).  So as a fallback we use the optimizer; if it can't
- * prove the condition is false, it will cause a link error on the undefined
- * "__build_bug_on_failed".  This error message can be harder to track down
- * though, hence the two different methods.
- */
-#ifndef __OPTIMIZE__
-#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
-#else
-extern int __build_bug_on_failed;
-#define BUILD_BUG_ON(condition)                                        \
-       do {                                                    \
-               ((void)sizeof(char[1 - 2*!!(condition)]));      \
-               if (condition) __build_bug_on_failed = 1;       \
-       } while(0)
-#endif
-
-/**
- * BUILD_BUG - break compile if used.
- *
- * If you have some code that you expect the compiler to eliminate at
- * build time, you should use BUILD_BUG to detect if it is
- * unexpectedly used.
- */
-#define BUILD_BUG()                                            \
-       do {                                                    \
-               extern void __build_bug_failed(void)            \
-                       __linktime_error("BUILD_BUG failed");   \
-               __build_bug_failed();                           \
-       } while (0)
-
-#endif /* __CHECKER__ */
-
 /* Trap pasters of __FUNCTION__ at compile-time */
 #define __FUNCTION__ (__func__)
 
index 1600ebf..96933b1 100644 (file)
@@ -277,6 +277,8 @@ static inline key_serial_t key_serial(const struct key *key)
        return key ? key->serial : 0;
 }
 
+extern void key_set_timeout(struct key *, unsigned);
+
 /**
  * key_is_instantiated - Determine if a key has been positively instantiated
  * @key: The key to check.
index 722f477..9efeae6 100644 (file)
@@ -48,11 +48,10 @@ static inline int request_module_nowait(const char *name, ...) { return -ENOSYS;
 struct cred;
 struct file;
 
-enum umh_wait {
-       UMH_NO_WAIT = -1,       /* don't wait at all */
-       UMH_WAIT_EXEC = 0,      /* wait for the exec, but not the process */
-       UMH_WAIT_PROC = 1,      /* wait for the process to complete */
-};
+#define UMH_NO_WAIT    0       /* don't wait at all */
+#define UMH_WAIT_EXEC  1       /* wait for the exec, but not the process */
+#define UMH_WAIT_PROC  2       /* wait for the process to complete */
+#define UMH_KILLABLE   4       /* wait for EXEC/PROC killable */
 
 struct subprocess_info {
        struct work_struct work;
@@ -60,7 +59,7 @@ struct subprocess_info {
        char *path;
        char **argv;
        char **envp;
-       enum umh_wait wait;
+       int wait;
        int retval;
        int (*init)(struct subprocess_info *info, struct cred *new);
        void (*cleanup)(struct subprocess_info *info);
@@ -78,15 +77,14 @@ void call_usermodehelper_setfns(struct subprocess_info *info,
                    void *data);
 
 /* Actually execute the sub-process */
-int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait);
+int call_usermodehelper_exec(struct subprocess_info *info, int wait);
 
 /* Free the subprocess_info. This is only needed if you're not going
    to call call_usermodehelper_exec */
 void call_usermodehelper_freeinfo(struct subprocess_info *info);
 
 static inline int
-call_usermodehelper_fns(char *path, char **argv, char **envp,
-                       enum umh_wait wait,
+call_usermodehelper_fns(char *path, char **argv, char **envp, int wait,
                        int (*init)(struct subprocess_info *info, struct cred *new),
                        void (*cleanup)(struct subprocess_info *), void *data)
 {
@@ -104,7 +102,7 @@ call_usermodehelper_fns(char *path, char **argv, char **envp,
 }
 
 static inline int
-call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
+call_usermodehelper(char *path, char **argv, char **envp, int wait)
 {
        return call_usermodehelper_fns(path, argv, envp, wait,
                                       NULL, NULL, NULL);
index dce6e4d..b6e1f8c 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/list.h>
 #include <linux/notifier.h>
 #include <linux/smp.h>
+#include <linux/bug.h>
 #include <linux/percpu.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
index 68e67e5..6c322a9 100644 (file)
@@ -162,6 +162,7 @@ struct kvm_pit_config {
 #define KVM_EXIT_INTERNAL_ERROR   17
 #define KVM_EXIT_OSI              18
 #define KVM_EXIT_PAPR_HCALL      19
+#define KVM_EXIT_S390_UCONTROL   20
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 #define KVM_INTERNAL_ERROR_EMULATION 1
@@ -249,6 +250,11 @@ struct kvm_run {
 #define KVM_S390_RESET_CPU_INIT  8
 #define KVM_S390_RESET_IPL       16
                __u64 s390_reset_flags;
+               /* KVM_EXIT_S390_UCONTROL */
+               struct {
+                       __u64 trans_exc_code;
+                       __u32 pgm_code;
+               } s390_ucontrol;
                /* KVM_EXIT_DCR */
                struct {
                        __u32 dcrn;
@@ -273,6 +279,20 @@ struct kvm_run {
                /* Fix the size of the union. */
                char padding[256];
        };
+
+       /*
+        * shared registers between kvm and userspace.
+        * kvm_valid_regs specifies the register classes set by the host
+        * kvm_dirty_regs specified the register classes dirtied by userspace
+        * struct kvm_sync_regs is architecture specific, as well as the
+        * bits for kvm_valid_regs and kvm_dirty_regs
+        */
+       __u64 kvm_valid_regs;
+       __u64 kvm_dirty_regs;
+       union {
+               struct kvm_sync_regs regs;
+               char padding[1024];
+       } s;
 };
 
 /* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
@@ -431,6 +451,11 @@ struct kvm_ppc_pvinfo {
 
 #define KVMIO 0xAE
 
+/* machine type bits, to be used as argument to KVM_CREATE_VM */
+#define KVM_VM_S390_UCONTROL   1
+
+#define KVM_S390_SIE_PAGE_OFFSET 1
+
 /*
  * ioctls for /dev/kvm fds:
  */
@@ -555,9 +580,15 @@ struct kvm_ppc_pvinfo {
 #define KVM_CAP_PPC_SMT 64
 #define KVM_CAP_PPC_RMA        65
 #define KVM_CAP_MAX_VCPUS 66       /* returns max vcpus per vm */
+#define KVM_CAP_PPC_HIOR 67
 #define KVM_CAP_PPC_PAPR 68
+#define KVM_CAP_SW_TLB 69
+#define KVM_CAP_ONE_REG 70
 #define KVM_CAP_S390_GMAP 71
 #define KVM_CAP_TSC_DEADLINE_TIMER 72
+#define KVM_CAP_S390_UCONTROL 73
+#define KVM_CAP_SYNC_REGS 74
+#define KVM_CAP_PCI_2_3 75
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -637,6 +668,52 @@ struct kvm_clock_data {
        __u32 pad[9];
 };
 
+#define KVM_MMU_FSL_BOOKE_NOHV         0
+#define KVM_MMU_FSL_BOOKE_HV           1
+
+struct kvm_config_tlb {
+       __u64 params;
+       __u64 array;
+       __u32 mmu_type;
+       __u32 array_len;
+};
+
+struct kvm_dirty_tlb {
+       __u64 bitmap;
+       __u32 num_dirty;
+};
+
+/* Available with KVM_CAP_ONE_REG */
+
+#define KVM_REG_ARCH_MASK      0xff00000000000000ULL
+#define KVM_REG_GENERIC                0x0000000000000000ULL
+
+/*
+ * Architecture specific registers are to be defined in arch headers and
+ * ORed with the arch identifier.
+ */
+#define KVM_REG_PPC            0x1000000000000000ULL
+#define KVM_REG_X86            0x2000000000000000ULL
+#define KVM_REG_IA64           0x3000000000000000ULL
+#define KVM_REG_ARM            0x4000000000000000ULL
+#define KVM_REG_S390           0x5000000000000000ULL
+
+#define KVM_REG_SIZE_SHIFT     52
+#define KVM_REG_SIZE_MASK      0x00f0000000000000ULL
+#define KVM_REG_SIZE_U8                0x0000000000000000ULL
+#define KVM_REG_SIZE_U16       0x0010000000000000ULL
+#define KVM_REG_SIZE_U32       0x0020000000000000ULL
+#define KVM_REG_SIZE_U64       0x0030000000000000ULL
+#define KVM_REG_SIZE_U128      0x0040000000000000ULL
+#define KVM_REG_SIZE_U256      0x0050000000000000ULL
+#define KVM_REG_SIZE_U512      0x0060000000000000ULL
+#define KVM_REG_SIZE_U1024     0x0070000000000000ULL
+
+struct kvm_one_reg {
+       __u64 id;
+       __u64 addr;
+};
+
 /*
  * ioctls for VM fds
  */
@@ -655,6 +732,17 @@ struct kvm_clock_data {
                                        struct kvm_userspace_memory_region)
 #define KVM_SET_TSS_ADDR          _IO(KVMIO,   0x47)
 #define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO,  0x48, __u64)
+
+/* enable ucontrol for s390 */
+struct kvm_s390_ucas_mapping {
+       __u64 user_addr;
+       __u64 vcpu_addr;
+       __u64 length;
+};
+#define KVM_S390_UCAS_MAP        _IOW(KVMIO, 0x50, struct kvm_s390_ucas_mapping)
+#define KVM_S390_UCAS_UNMAP      _IOW(KVMIO, 0x51, struct kvm_s390_ucas_mapping)
+#define KVM_S390_VCPU_FAULT     _IOW(KVMIO, 0x52, unsigned long)
+
 /* Device model IOC */
 #define KVM_CREATE_IRQCHIP        _IO(KVMIO,   0x60)
 #define KVM_IRQ_LINE              _IOW(KVMIO,  0x61, struct kvm_irq_level)
@@ -697,6 +785,9 @@ struct kvm_clock_data {
 /* Available with KVM_CAP_TSC_CONTROL */
 #define KVM_SET_TSC_KHZ           _IO(KVMIO,  0xa2)
 #define KVM_GET_TSC_KHZ           _IO(KVMIO,  0xa3)
+/* Available with KVM_CAP_PCI_2_3 */
+#define KVM_ASSIGN_SET_INTX_MASK  _IOW(KVMIO,  0xa4, \
+                                      struct kvm_assigned_pci_dev)
 
 /*
  * ioctls for vcpu fds
@@ -763,8 +854,15 @@ struct kvm_clock_data {
 #define KVM_CREATE_SPAPR_TCE     _IOW(KVMIO,  0xa8, struct kvm_create_spapr_tce)
 /* Available with KVM_CAP_RMA */
 #define KVM_ALLOCATE_RMA         _IOR(KVMIO,  0xa9, struct kvm_allocate_rma)
+/* Available with KVM_CAP_SW_TLB */
+#define KVM_DIRTY_TLB            _IOW(KVMIO,  0xaa, struct kvm_dirty_tlb)
+/* Available with KVM_CAP_ONE_REG */
+#define KVM_GET_ONE_REG                  _IOW(KVMIO,  0xab, struct kvm_one_reg)
+#define KVM_SET_ONE_REG                  _IOW(KVMIO,  0xac, struct kvm_one_reg)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
+#define KVM_DEV_ASSIGN_PCI_2_3         (1 << 1)
+#define KVM_DEV_ASSIGN_MASK_INTX       (1 << 2)
 
 struct kvm_assigned_pci_dev {
        __u32 assigned_dev_id;
index 900c763..665a260 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/bug.h>
 #include <linux/mm.h>
 #include <linux/mmu_notifier.h>
 #include <linux/preempt.h>
@@ -171,11 +172,6 @@ static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu)
  */
 #define KVM_MEM_MAX_NR_PAGES ((1UL << 31) - 1)
 
-struct kvm_lpage_info {
-       unsigned long rmap_pde;
-       int write_count;
-};
-
 struct kvm_memory_slot {
        gfn_t base_gfn;
        unsigned long npages;
@@ -184,7 +180,7 @@ struct kvm_memory_slot {
        unsigned long *dirty_bitmap;
        unsigned long *dirty_bitmap_head;
        unsigned long nr_dirty_pages;
-       struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
+       struct kvm_arch_memory_slot arch;
        unsigned long userspace_addr;
        int user_alloc;
        int id;
@@ -376,6 +372,9 @@ int kvm_set_memory_region(struct kvm *kvm,
 int __kvm_set_memory_region(struct kvm *kvm,
                            struct kvm_userspace_memory_region *mem,
                            int user_alloc);
+void kvm_arch_free_memslot(struct kvm_memory_slot *free,
+                          struct kvm_memory_slot *dont);
+int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages);
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                struct kvm_memory_slot *memslot,
                                struct kvm_memory_slot old,
@@ -385,6 +384,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
                                struct kvm_userspace_memory_region *mem,
                                struct kvm_memory_slot old,
                                int user_alloc);
+bool kvm_largepages_enabled(void);
 void kvm_disable_largepages(void);
 void kvm_arch_flush_shadow(struct kvm *kvm);
 
@@ -450,6 +450,7 @@ long kvm_arch_dev_ioctl(struct file *filp,
                        unsigned int ioctl, unsigned long arg);
 long kvm_arch_vcpu_ioctl(struct file *filp,
                         unsigned int ioctl, unsigned long arg);
+int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf);
 
 int kvm_dev_ioctl_check_extension(long ext);
 
@@ -520,7 +521,7 @@ static inline void kvm_arch_free_vm(struct kvm *kvm)
 }
 #endif
 
-int kvm_arch_init_vm(struct kvm *kvm);
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type);
 void kvm_arch_destroy_vm(struct kvm *kvm);
 void kvm_free_all_assigned_devices(struct kvm *kvm);
 void kvm_arch_sync_events(struct kvm *kvm);
@@ -546,6 +547,7 @@ struct kvm_assigned_dev_kernel {
        unsigned int entries_nr;
        int host_irq;
        bool host_irq_disabled;
+       bool pci_2_3;
        struct msix_entry *host_msix_entries;
        int guest_irq;
        struct msix_entry *guest_msix_entries;
@@ -555,6 +557,7 @@ struct kvm_assigned_dev_kernel {
        struct pci_dev *dev;
        struct kvm *kvm;
        spinlock_t intx_lock;
+       spinlock_t intx_mask_lock;
        char irq_name[32];
        struct pci_saved_state *pci_saved_state;
 };
@@ -650,11 +653,43 @@ static inline void kvm_guest_exit(void)
        current->flags &= ~PF_VCPU;
 }
 
+/*
+ * search_memslots() and __gfn_to_memslot() are here because they are
+ * used in non-modular code in arch/powerpc/kvm/book3s_hv_rm_mmu.c.
+ * gfn_to_memslot() itself isn't here as an inline because that would
+ * bloat other code too much.
+ */
+static inline struct kvm_memory_slot *
+search_memslots(struct kvm_memslots *slots, gfn_t gfn)
+{
+       struct kvm_memory_slot *memslot;
+
+       kvm_for_each_memslot(memslot, slots)
+               if (gfn >= memslot->base_gfn &&
+                     gfn < memslot->base_gfn + memslot->npages)
+                       return memslot;
+
+       return NULL;
+}
+
+static inline struct kvm_memory_slot *
+__gfn_to_memslot(struct kvm_memslots *slots, gfn_t gfn)
+{
+       return search_memslots(slots, gfn);
+}
+
 static inline int memslot_id(struct kvm *kvm, gfn_t gfn)
 {
        return gfn_to_memslot(kvm, gfn)->id;
 }
 
+static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level)
+{
+       /* KVM_HPAGE_GFN_SHIFT(PT_PAGE_TABLE_LEVEL) must be 0. */
+       return (gfn >> KVM_HPAGE_GFN_SHIFT(level)) -
+               (base_gfn >> KVM_HPAGE_GFN_SHIFT(level));
+}
+
 static inline unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot,
                                               gfn_t gfn)
 {
@@ -701,12 +736,16 @@ static inline int mmu_notifier_retry(struct kvm_vcpu *vcpu, unsigned long mmu_se
        if (unlikely(vcpu->kvm->mmu_notifier_count))
                return 1;
        /*
-        * Both reads happen under the mmu_lock and both values are
-        * modified under mmu_lock, so there's no need of smb_rmb()
-        * here in between, otherwise mmu_notifier_count should be
-        * read before mmu_notifier_seq, see
-        * mmu_notifier_invalidate_range_end write side.
+        * Ensure the read of mmu_notifier_count happens before the read
+        * of mmu_notifier_seq.  This interacts with the smp_wmb() in
+        * mmu_notifier_invalidate_range_end to make sure that the caller
+        * either sees the old (non-zero) value of mmu_notifier_count or
+        * the new (incremented) value of mmu_notifier_seq.
+        * PowerPC Book3s HV KVM calls this under a per-page lock
+        * rather than under kvm->mmu_lock, for scalability, so
+        * can't rely on kvm->mmu_lock to keep things ordered.
         */
+       smp_rmb();
        if (vcpu->kvm->mmu_notifier_seq != mmu_seq)
                return 1;
        return 0;
@@ -769,6 +808,13 @@ static inline bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu)
 {
        return vcpu->kvm->bsp_vcpu_id == vcpu->vcpu_id;
 }
+
+bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu);
+
+#else
+
+static inline bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) { return true; }
+
 #endif
 
 #ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
index 8eb1235..eeae6e7 100644 (file)
@@ -72,6 +72,12 @@ enum lm3530_als_mode {
        LM3530_INPUT_CEIL,      /* Max of ALS1 and ALS2 */
 };
 
+/* PWM Platform Specific Data */
+struct lm3530_pwm_data {
+       void (*pwm_set_intensity) (int brightness, int max_brightness);
+       int (*pwm_get_intensity) (int max_brightness);
+};
+
 /**
  * struct lm3530_platform_data
  * @mode: mode of operation i.e. Manual, ALS or PWM
@@ -87,6 +93,7 @@ enum lm3530_als_mode {
  * @als_vmin: als input voltage calibrated for max brightness in mV
  * @als_vmax: als input voltage calibrated for min brightness in mV
  * @brt_val: brightness value (0-255)
+ * @pwm_data: PWM control functions (only valid when the mode is PWM)
  */
 struct lm3530_platform_data {
        enum lm3530_mode mode;
@@ -107,6 +114,8 @@ struct lm3530_platform_data {
        u32 als_vmax;
 
        u8 brt_val;
+
+       struct lm3530_pwm_data pwm_data;
 };
 
 #endif /* _LINUX_LED_LM3530_H__ */
index fd548d2..3f071ec 100644 (file)
 /* See Documentation/leds/leds-lp5521.txt */
 
 struct lp5521_led_config {
+       char            *name;
        u8              chan_nr;
        u8              led_current; /* mA x10, 0 if led is not connected */
        u8              max_current;
 };
 
+struct lp5521_led_pattern {
+       u8 *r;
+       u8 *g;
+       u8 *b;
+       u8 size_r;
+       u8 size_g;
+       u8 size_b;
+};
+
 #define LP5521_CLOCK_AUTO      0
 #define LP5521_CLOCK_INT       1
 #define LP5521_CLOCK_EXT       2
 
+/* Bits in CONFIG register */
+#define LP5521_PWM_HF                  0x40    /* PWM: 0 = 256Hz, 1 = 558Hz */
+#define LP5521_PWRSAVE_EN              0x20    /* 1 = Power save mode */
+#define LP5521_CP_MODE_OFF             0       /* Charge pump (CP) off */
+#define LP5521_CP_MODE_BYPASS          8       /* CP forced to bypass mode */
+#define LP5521_CP_MODE_1X5             0x10    /* CP forced to 1.5x mode */
+#define LP5521_CP_MODE_AUTO            0x18    /* Automatic mode selection */
+#define LP5521_R_TO_BATT               4       /* R out: 0 = CP, 1 = Vbat */
+#define LP5521_CLK_SRC_EXT             0       /* Ext-clk source (CLK_32K) */
+#define LP5521_CLK_INT                 1       /* Internal clock */
+#define LP5521_CLK_AUTO                        2       /* Automatic clock selection */
+
 struct lp5521_platform_data {
        struct lp5521_led_config *led_config;
        u8      num_channels;
@@ -43,6 +65,9 @@ struct lp5521_platform_data {
        void    (*release_resources)(void);
        void    (*enable)(bool state);
        const char *label;
+       u8      update_config;
+       struct lp5521_led_pattern *patterns;
+       int num_patterns;
 };
 
 #endif /* __LINUX_LP5521_H */
index fbc48f8..11a966e 100644 (file)
@@ -42,6 +42,7 @@ struct nlmclnt_initdata {
        unsigned short          protocol;
        u32                     nfs_version;
        int                     noresvport;
+       struct net              *net;
 };
 
 /*
index 88a114f..f04ce6a 100644 (file)
@@ -67,6 +67,7 @@ struct nlm_host {
        struct list_head        h_reclaim;      /* Locks in RECLAIM state */
        struct nsm_handle       *h_nsmhandle;   /* NSM status handle */
        char                    *h_addrbuf;     /* address eyecatcher */
+       struct net              *net;           /* host net */
 };
 
 /*
@@ -188,7 +189,7 @@ struct nlm_block {
 /*
  * Global variables
  */
-extern struct rpc_program      nlm_program;
+extern const struct rpc_program        nlm_program;
 extern struct svc_procedure    nlmsvc_procedures[];
 #ifdef CONFIG_LOCKD_V4
 extern struct svc_procedure    nlmsvc_procedures4[];
@@ -222,7 +223,8 @@ struct nlm_host  *nlmclnt_lookup_host(const struct sockaddr *sap,
                                        const unsigned short protocol,
                                        const u32 version,
                                        const char *hostname,
-                                       int noresvport);
+                                       int noresvport,
+                                       struct net *net);
 void             nlmclnt_release_host(struct nlm_host *);
 struct nlm_host  *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
                                        const char *hostname,
@@ -232,6 +234,7 @@ struct rpc_clnt * nlm_bind_host(struct nlm_host *);
 void             nlm_rebind_host(struct nlm_host *);
 struct nlm_host * nlm_get_host(struct nlm_host *);
 void             nlm_shutdown_hosts(void);
+void             nlm_shutdown_hosts_net(struct net *net);
 void             nlm_host_rebooted(const struct nlm_reboot *);
 
 /*
index 7353821..e58c88b 100644 (file)
@@ -42,6 +42,6 @@ int   nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 int    nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *);
 int    nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
  */
-extern struct rpc_version nlm_version4;
+extern const struct rpc_version nlm_version4;
 
 #endif /* LOCKD_XDR4_H */
diff --git a/include/linux/lp855x.h b/include/linux/lp855x.h
new file mode 100644 (file)
index 0000000..781a490
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * LP855x Backlight Driver
+ *
+ *                     Copyright (C) 2011 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _LP855X_H
+#define _LP855X_H
+
+#define BL_CTL_SHFT    (0)
+#define BRT_MODE_SHFT  (1)
+#define BRT_MODE_MASK  (0x06)
+
+/* Enable backlight. Only valid when BRT_MODE=10(I2C only) */
+#define ENABLE_BL      (1)
+#define DISABLE_BL     (0)
+
+#define I2C_CONFIG(id) id ## _I2C_CONFIG
+#define PWM_CONFIG(id) id ## _PWM_CONFIG
+
+/* DEVICE CONTROL register - LP8550 */
+#define LP8550_PWM_CONFIG      (LP8550_PWM_ONLY << BRT_MODE_SHFT)
+#define LP8550_I2C_CONFIG      ((ENABLE_BL << BL_CTL_SHFT) | \
+                               (LP8550_I2C_ONLY << BRT_MODE_SHFT))
+
+/* DEVICE CONTROL register - LP8551 */
+#define LP8551_PWM_CONFIG      LP8550_PWM_CONFIG
+#define LP8551_I2C_CONFIG      LP8550_I2C_CONFIG
+
+/* DEVICE CONTROL register - LP8552 */
+#define LP8552_PWM_CONFIG      LP8550_PWM_CONFIG
+#define LP8552_I2C_CONFIG      LP8550_I2C_CONFIG
+
+/* DEVICE CONTROL register - LP8553 */
+#define LP8553_PWM_CONFIG      LP8550_PWM_CONFIG
+#define LP8553_I2C_CONFIG      LP8550_I2C_CONFIG
+
+/* DEVICE CONTROL register - LP8556 */
+#define LP8556_PWM_CONFIG      (LP8556_PWM_ONLY << BRT_MODE_SHFT)
+#define LP8556_COMB1_CONFIG    (LP8556_COMBINED1 << BRT_MODE_SHFT)
+#define LP8556_I2C_CONFIG      ((ENABLE_BL << BL_CTL_SHFT) | \
+                               (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,
+       LP8552,
+       LP8553,
+       LP8556,
+};
+
+enum lp855x_brightness_ctrl_mode {
+       PWM_BASED = 1,
+       REGISTER_BASED,
+};
+
+enum lp8550_brighntess_source {
+       LP8550_PWM_ONLY,
+       LP8550_I2C_ONLY = 2,
+};
+
+enum lp8551_brighntess_source {
+       LP8551_PWM_ONLY = LP8550_PWM_ONLY,
+       LP8551_I2C_ONLY = LP8550_I2C_ONLY,
+};
+
+enum lp8552_brighntess_source {
+       LP8552_PWM_ONLY = LP8550_PWM_ONLY,
+       LP8552_I2C_ONLY = LP8550_I2C_ONLY,
+};
+
+enum lp8553_brighntess_source {
+       LP8553_PWM_ONLY = LP8550_PWM_ONLY,
+       LP8553_I2C_ONLY = LP8550_I2C_ONLY,
+};
+
+enum lp8556_brightness_source {
+       LP8556_PWM_ONLY,
+       LP8556_COMBINED1,       /* pwm + i2c before the shaper block */
+       LP8556_I2C_ONLY,
+       LP8556_COMBINED2,       /* pwm + i2c after the shaper block */
+};
+
+struct lp855x_pwm_data {
+       void (*pwm_set_intensity) (int brightness, int max_brightness);
+       int (*pwm_get_intensity) (int max_brightness);
+};
+
+struct lp855x_rom_data {
+       u8 addr;
+       u8 val;
+};
+
+/**
+ * struct lp855x_platform_data
+ * @name : Backlight driver name. If it is not defined, default name is set.
+ * @mode : brightness control by pwm or lp855x register
+ * @device_control : value of DEVICE CONTROL register
+ * @initial_brightness : initial value of backlight brightness
+ * @pwm_data : platform specific pwm generation functions.
+               Only valid when mode is PWM_BASED.
+ * @load_new_rom_data :
+       0 : use default configuration data
+       1 : update values of eeprom or eprom registers on loading driver
+ * @size_program : total size of lp855x_rom_data
+ * @rom_data : list of new eeprom/eprom registers
+ */
+struct lp855x_platform_data {
+       char *name;
+       enum lp855x_brightness_ctrl_mode mode;
+       u8 device_control;
+       int initial_brightness;
+       struct lp855x_pwm_data pwm_data;
+       u8 load_new_rom_data;
+       int size_program;
+       struct lp855x_rom_data *rom_data;
+};
+
+#endif
index b7ed475..e15192c 100644 (file)
@@ -9,7 +9,6 @@
 #define CRAMFS_MAGIC           0x28cd3d45      /* some random number */
 #define CRAMFS_MAGIC_WEND      0x453dcd28      /* magic number with the wrong endianess */
 #define DEBUGFS_MAGIC          0x64626720
-#define SYSFS_MAGIC            0x62656572
 #define SECURITYFS_MAGIC       0x73636673
 #define SELINUX_MAGIC          0xf97cff8c
 #define RAMFS_MAGIC            0x858458f6      /* some random number */
@@ -27,7 +26,6 @@
 #define HPFS_SUPER_MAGIC       0xf995e849
 #define ISOFS_SUPER_MAGIC      0x9660
 #define JFFS2_SUPER_MAGIC      0x72b6
-#define ANON_INODE_FS_MAGIC    0x09041934
 #define PSTOREFS_MAGIC         0x6165676C
 
 #define MINIX_SUPER_MAGIC      0x137F          /* minix v1 fs, 14 char names */
@@ -40,7 +38,6 @@
 #define NCP_SUPER_MAGIC                0x564c          /* Guess, what 0x564c is :-) */
 #define NFS_SUPER_MAGIC                0x6969
 #define OPENPROM_SUPER_MAGIC   0x9fa1
-#define PROC_SUPER_MAGIC       0x9fa0
 #define QNX4_SUPER_MAGIC       0x002f          /* qnx4 fs detection */
 #define QNX6_SUPER_MAGIC       0x68191122      /* qnx6 fs detection */
 
 #define REISER2FS_JR_SUPER_MAGIC_STRING        "ReIsEr3Fs"
 
 #define SMB_SUPER_MAGIC                0x517B
-#define USBDEVICE_SUPER_MAGIC  0x9fa2
 #define CGROUP_SUPER_MAGIC     0x27e0eb
 
-#define FUTEXFS_SUPER_MAGIC    0xBAD1DEA
 
 #define STACK_END_MAGIC                0x57AC6E9D
 
+#define V9FS_MAGIC             0x01021997
+
+#define BDEVFS_MAGIC            0x62646576
+#define BINFMTFS_MAGIC          0x42494e4d
 #define DEVPTS_SUPER_MAGIC     0x1cd1
+#define FUTEXFS_SUPER_MAGIC    0xBAD1DEA
+#define PIPEFS_MAGIC            0x50495045
+#define PROC_SUPER_MAGIC       0x9fa0
 #define SOCKFS_MAGIC           0x534F434B
-#define V9FS_MAGIC             0x01021997
+#define SYSFS_MAGIC            0x62656572
+#define USBDEVICE_SUPER_MAGIC  0x9fa2
+#define MTD_INODE_FS_MAGIC      0x11307854
+#define ANON_INODE_FS_MAGIC    0x09041934
+
 
 #endif /* __LINUX_MAGIC_H__ */
index d9a51b9..c37288b 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef __LINUX_MAPLE_H
 #define __LINUX_MAPLE_H
 
-#include <linux/device.h>
 #include <mach/maple.h>
 
+struct device;
 extern struct bus_type maple_bus_type;
 
 /* Maple Bus command and response codes */
index 0b8e2a7..910550f 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/mmzone.h>
 #include <linux/spinlock.h>
 #include <linux/notifier.h>
+#include <linux/bug.h>
 
 struct page;
 struct zone;
index 92be347..84d071a 100644 (file)
@@ -263,6 +263,22 @@ enum {
 #define PM8607_PD_PREBIAS_MASK         (0x1F << 0)
 #define PM8607_PD_PRECHG_MASK          (7 << 5)
 
+#define PM8606_REF_GP_OSC_OFF         0
+#define PM8606_REF_GP_OSC_ON          1
+#define PM8606_REF_GP_OSC_UNKNOWN     2
+
+/* Clients of reference group and 8MHz oscillator in 88PM8606 */
+enum pm8606_ref_gp_and_osc_clients {
+       REF_GP_NO_CLIENTS       = 0,
+       WLED1_DUTY              = (1<<0), /*PF 0x02.7:0*/
+       WLED2_DUTY              = (1<<1), /*PF 0x04.7:0*/
+       WLED3_DUTY              = (1<<2), /*PF 0x06.7:0*/
+       RGB1_ENABLE             = (1<<3), /*PF 0x07.1*/
+       RGB2_ENABLE             = (1<<4), /*PF 0x07.2*/
+       LDO_VBR_EN              = (1<<5), /*PF 0x12.0*/
+       REF_GP_MAX_CLIENT       = 0xFFFF
+};
+
 /* Interrupt Number in 88PM8607 */
 enum {
        PM8607_IRQ_ONKEY,
@@ -298,6 +314,7 @@ enum {
 struct pm860x_chip {
        struct device           *dev;
        struct mutex            irq_lock;
+       struct mutex            osc_lock;
        struct i2c_client       *client;
        struct i2c_client       *companion;     /* companion chip client */
        struct regmap           *regmap;
@@ -305,12 +322,15 @@ struct pm860x_chip {
 
        int                     buck3_double;   /* DVC ramp slope double */
        unsigned short          companion_addr;
+       unsigned short          osc_vote;
        int                     id;
        int                     irq_mode;
        int                     irq_base;
        int                     core_irq;
        unsigned char           chip_version;
+       unsigned char           osc_status;
 
+       unsigned int            wakeup_flag;
 };
 
 enum {
@@ -369,6 +389,9 @@ struct pm860x_platform_data {
        int             num_regulators;
 };
 
+extern int pm8606_osc_enable(struct pm860x_chip *, unsigned short);
+extern int pm8606_osc_disable(struct pm860x_chip *, unsigned short);
+
 extern int pm860x_reg_read(struct i2c_client *, int);
 extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
 extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);
index 9970337..5fa6974 100644 (file)
  * Author: Rickard Andersson <rickard.andersson@stericsson.com>
  */
 
-#include <linux/device.h>
 #include <linux/regulator/machine.h>
 
+struct device;
+
 #ifndef MFD_ABX500_H
 #define MFD_ABX500_H
 
 #define AB5500_1_1     0x21
 #define AB5500_2_0     0x24
 
-/* AB8500 CIDs*/
-#define AB8500_CUT1P0  0x10
-#define AB8500_CUT1P1  0x11
-#define AB8500_CUT2P0  0x20
-#define AB8500_CUT3P0  0x30
-#define AB8500_CUT3P3  0x33
-
 /*
  * AB3100, EVENTA1, A2 and A3 event register flags
  * these are catenated into a single 32-bit flag in the code
index a720051..54f820e 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef MFD_AB5500_H
 #define MFD_AB5500_H
 
-#include <linux/device.h>
+struct device;
 
 enum ab5500_devid {
        AB5500_DEVID_ADC,
index 488a8c9..2387c20 100644 (file)
 
 /*
  * Platform data to register a block: only the initial gpio/irq number.
+ * Array sizes are large enough to contain all AB8500 and AB9540 GPIO
+ * registers.
  */
 
 struct ab8500_gpio_platform_data {
        int gpio_base;
        u32 irq_base;
-       u8  config_reg[7];
+       u8  config_reg[8];
 };
 
 #endif /* _AB8500_GPIO_H */
index 10da029..10eb509 100644 (file)
@@ -71,6 +71,13 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
 #define AB8500_SWATCTRL                        0x230
 #define AB8500_HIQCLKCTRL              0x232
 #define AB8500_VSIMSYSCLKCTRL          0x233
+#define AB9540_SYSCLK12BUFCTRL         0x234
+#define AB9540_SYSCLK12CONFCTRL                0x235
+#define AB9540_SYSCLK12BUFCTRL2                0x236
+#define AB9540_SYSCLK12BUF1VALID       0x237
+#define AB9540_SYSCLK12BUF2VALID       0x238
+#define AB9540_SYSCLK12BUF3VALID       0x239
+#define AB9540_SYSCLK12BUF4VALID       0x23A
 
 /* Bits */
 #define AB8500_TURNONSTATUS_PORNVBAT BIT(0)
@@ -251,4 +258,40 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
 #define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ7VALID BIT(6)
 #define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ8VALID BIT(7)
 
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF1ENA BIT(0)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF2ENA BIT(1)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF3ENA BIT(2)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF4ENA BIT(3)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUFENA_MASK 0x0F
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF1STRE BIT(4)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF2STRE BIT(5)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF3STRE BIT(6)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUF4STRE BIT(7)
+#define AB9540_SYSCLK12BUFCTRL_SYSCLK12BUFSTRE_MASK 0xF0
+
+#define AB9540_SYSCLK12CONFCTRL_PLL26TO38ENA BIT(0)
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK12USBMUXSEL BIT(1)
+#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_MASK 0x0C
+#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_SHIFT 2
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK12BUFMUX BIT(4)
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK12PLLMUX BIT(5)
+#define AB9540_SYSCLK12CONFCTRL_SYSCLK2MUXVALID BIT(6)
+
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF1PDENA BIT(0)
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF2PDENA BIT(1)
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF3PDENA BIT(2)
+#define AB9540_SYSCLK12BUFCTRL2_SYSCLK12BUF4PDENA BIT(3)
+
+#define AB9540_SYSCLK12BUF1VALID_SYSCLK12BUF1VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF1VALID_SYSCLK12BUF1VALID_SHIFT 0
+
+#define AB9540_SYSCLK12BUF2VALID_SYSCLK12BUF2VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF2VALID_SYSCLK12BUF2VALID_SHIFT 0
+
+#define AB9540_SYSCLK12BUF3VALID_SYSCLK12BUF3VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF3VALID_SYSCLK12BUF3VALID_SHIFT 0
+
+#define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_MASK 0xFF
+#define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_SHIFT 0
+
 #endif /* __AB8500_SYSCTRL_H */
index 838c6b4..fccc300 100644 (file)
@@ -7,7 +7,32 @@
 #ifndef MFD_AB8500_H
 #define MFD_AB8500_H
 
-#include <linux/device.h>
+#include <linux/mutex.h>
+
+struct device;
+
+/*
+ * AB IC versions
+ *
+ * AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
+ * non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
+ * print of version string.
+ */
+enum ab8500_version {
+       AB8500_VERSION_AB8500 = 0x0,
+       AB8500_VERSION_AB8505 = 0x1,
+       AB8500_VERSION_AB9540 = 0x2,
+       AB8500_VERSION_AB8540 = 0x3,
+       AB8500_VERSION_UNDEFINED,
+};
+
+/* AB8500 CIDs*/
+#define AB8500_CUTEARLY        0x00
+#define AB8500_CUT1P0  0x10
+#define AB8500_CUT1P1  0x11
+#define AB8500_CUT2P0  0x20
+#define AB8500_CUT3P0  0x30
+#define AB8500_CUT3P3  0x33
 
 /*
  * AB8500 bank addresses
 
 /*
  * Interrupts
+ * Values used to index into array ab8500_irq_regoffset[] defined in
+ * drivers/mdf/ab8500-core.c
  */
-
-#define AB8500_INT_MAIN_EXT_CH_NOT_OK  0
-#define AB8500_INT_UN_PLUG_TV_DET      1
-#define AB8500_INT_PLUG_TV_DET         2
+/* Definitions for AB8500 and AB9540 */
+/* ab8500_irq_regoffset[0] -> IT[Source|Latch|Mask]1 */
+#define AB8500_INT_MAIN_EXT_CH_NOT_OK  0 /* not 8505/9540 */
+#define AB8500_INT_UN_PLUG_TV_DET      1 /* not 8505/9540 */
+#define AB8500_INT_PLUG_TV_DET         2 /* not 8505/9540 */
 #define AB8500_INT_TEMP_WARM           3
 #define AB8500_INT_PON_KEY2DB_F                4
 #define AB8500_INT_PON_KEY2DB_R                5
 #define AB8500_INT_PON_KEY1DB_F                6
 #define AB8500_INT_PON_KEY1DB_R                7
+/* ab8500_irq_regoffset[1] -> IT[Source|Latch|Mask]2 */
 #define AB8500_INT_BATT_OVV            8
-#define AB8500_INT_MAIN_CH_UNPLUG_DET  10
-#define AB8500_INT_MAIN_CH_PLUG_DET    11
-#define AB8500_INT_USB_ID_DET_F                12
-#define AB8500_INT_USB_ID_DET_R                13
+#define AB8500_INT_MAIN_CH_UNPLUG_DET  10 /* not 8505 */
+#define AB8500_INT_MAIN_CH_PLUG_DET    11 /* not 8505 */
 #define AB8500_INT_VBUS_DET_F          14
 #define AB8500_INT_VBUS_DET_R          15
+/* ab8500_irq_regoffset[2] -> IT[Source|Latch|Mask]3 */
 #define AB8500_INT_VBUS_CH_DROP_END    16
 #define AB8500_INT_RTC_60S             17
 #define AB8500_INT_RTC_ALARM           18
 #define AB8500_INT_BAT_CTRL_INDB       20
 #define AB8500_INT_CH_WD_EXP           21
 #define AB8500_INT_VBUS_OVV            22
-#define AB8500_INT_MAIN_CH_DROP_END    23
+#define AB8500_INT_MAIN_CH_DROP_END    23 /* not 8505/9540 */
+/* ab8500_irq_regoffset[3] -> IT[Source|Latch|Mask]4 */
 #define AB8500_INT_CCN_CONV_ACC                24
 #define AB8500_INT_INT_AUD             25
 #define AB8500_INT_CCEOC               26
@@ -67,7 +96,8 @@
 #define AB8500_INT_LOW_BAT_R           29
 #define AB8500_INT_BUP_CHG_NOT_OK      30
 #define AB8500_INT_BUP_CHG_OK          31
-#define AB8500_INT_GP_HW_ADC_CONV_END  32
+/* ab8500_irq_regoffset[4] -> IT[Source|Latch|Mask]5 */
+#define AB8500_INT_GP_HW_ADC_CONV_END  32 /* not 8505 */
 #define AB8500_INT_ACC_DETECT_1DB_F    33
 #define AB8500_INT_ACC_DETECT_1DB_R    34
 #define AB8500_INT_ACC_DETECT_22DB_F   35
 #define AB8500_INT_ACC_DETECT_21DB_F   37
 #define AB8500_INT_ACC_DETECT_21DB_R   38
 #define AB8500_INT_GP_SW_ADC_CONV_END  39
-#define AB8500_INT_GPIO6R              40
-#define AB8500_INT_GPIO7R              41
-#define AB8500_INT_GPIO8R              42
-#define AB8500_INT_GPIO9R              43
+/* ab8500_irq_regoffset[5] -> IT[Source|Latch|Mask]7 */
+#define AB8500_INT_GPIO6R              40 /* not 8505/9540 */
+#define AB8500_INT_GPIO7R              41 /* not 8505/9540 */
+#define AB8500_INT_GPIO8R              42 /* not 8505/9540 */
+#define AB8500_INT_GPIO9R              43 /* not 8505/9540 */
 #define AB8500_INT_GPIO10R             44
 #define AB8500_INT_GPIO11R             45
-#define AB8500_INT_GPIO12R             46
+#define AB8500_INT_GPIO12R             46 /* not 8505 */
 #define AB8500_INT_GPIO13R             47
-#define AB8500_INT_GPIO24R             48
-#define AB8500_INT_GPIO25R             49
-#define AB8500_INT_GPIO36R             50
-#define AB8500_INT_GPIO37R             51
-#define AB8500_INT_GPIO38R             52
-#define AB8500_INT_GPIO39R             53
+/* ab8500_irq_regoffset[6] -> IT[Source|Latch|Mask]8 */
+#define AB8500_INT_GPIO24R             48 /* not 8505 */
+#define AB8500_INT_GPIO25R             49 /* not 8505 */
+#define AB8500_INT_GPIO36R             50 /* not 8505/9540 */
+#define AB8500_INT_GPIO37R             51 /* not 8505/9540 */
+#define AB8500_INT_GPIO38R             52 /* not 8505/9540 */
+#define AB8500_INT_GPIO39R             53 /* not 8505/9540 */
 #define AB8500_INT_GPIO40R             54
 #define AB8500_INT_GPIO41R             55
-#define AB8500_INT_GPIO6F              56
-#define AB8500_INT_GPIO7F              57
-#define AB8500_INT_GPIO8F              58
-#define AB8500_INT_GPIO9F              59
+/* ab8500_irq_regoffset[7] -> IT[Source|Latch|Mask]9 */
+#define AB8500_INT_GPIO6F              56 /* not 8505/9540 */
+#define AB8500_INT_GPIO7F              57 /* not 8505/9540 */
+#define AB8500_INT_GPIO8F              58 /* not 8505/9540 */
+#define AB8500_INT_GPIO9F              59 /* not 8505/9540 */
 #define AB8500_INT_GPIO10F             60
 #define AB8500_INT_GPIO11F             61
-#define AB8500_INT_GPIO12F             62
+#define AB8500_INT_GPIO12F             62 /* not 8505 */
 #define AB8500_INT_GPIO13F             63
-#define AB8500_INT_GPIO24F             64
-#define AB8500_INT_GPIO25F             65
-#define AB8500_INT_GPIO36F             66
-#define AB8500_INT_GPIO37F             67
-#define AB8500_INT_GPIO38F             68
-#define AB8500_INT_GPIO39F             69
+/* ab8500_irq_regoffset[8] -> IT[Source|Latch|Mask]10 */
+#define AB8500_INT_GPIO24F             64 /* not 8505 */
+#define AB8500_INT_GPIO25F             65 /* not 8505 */
+#define AB8500_INT_GPIO36F             66 /* not 8505/9540 */
+#define AB8500_INT_GPIO37F             67 /* not 8505/9540 */
+#define AB8500_INT_GPIO38F             68 /* not 8505/9540 */
+#define AB8500_INT_GPIO39F             69 /* not 8505/9540 */
 #define AB8500_INT_GPIO40F             70
 #define AB8500_INT_GPIO41F             71
+/* ab8500_irq_regoffset[9] -> IT[Source|Latch|Mask]12 */
 #define AB8500_INT_ADP_SOURCE_ERROR    72
 #define AB8500_INT_ADP_SINK_ERROR      73
 #define AB8500_INT_ADP_PROBE_PLUG      74
 #define AB8500_INT_ADP_SENSE_OFF       76
 #define AB8500_INT_USB_PHY_POWER_ERR   78
 #define AB8500_INT_USB_LINK_STATUS     79
+/* ab8500_irq_regoffset[10] -> IT[Source|Latch|Mask]19 */
 #define AB8500_INT_BTEMP_LOW           80
 #define AB8500_INT_BTEMP_LOW_MEDIUM    81
 #define AB8500_INT_BTEMP_MEDIUM_HIGH   82
 #define AB8500_INT_BTEMP_HIGH          83
-#define AB8500_INT_USB_CHARGER_NOT_OK  89
+/* ab8500_irq_regoffset[11] -> IT[Source|Latch|Mask]20 */
+#define AB8500_INT_SRP_DETECT          88
+#define AB8500_INT_USB_CHARGER_NOT_OKR 89
 #define AB8500_INT_ID_WAKEUP_R         90
 #define AB8500_INT_ID_DET_R1R          92
 #define AB8500_INT_ID_DET_R2R          93
 #define AB8500_INT_ID_DET_R3R          94
 #define AB8500_INT_ID_DET_R4R          95
+/* ab8500_irq_regoffset[12] -> IT[Source|Latch|Mask]21 */
 #define AB8500_INT_ID_WAKEUP_F         96
 #define AB8500_INT_ID_DET_R1F          98
 #define AB8500_INT_ID_DET_R2F          99
 #define AB8500_INT_ID_DET_R3F          100
 #define AB8500_INT_ID_DET_R4F          101
-#define AB8500_INT_USB_CHG_DET_DONE    102
+#define AB8500_INT_CHAUTORESTARTAFTSEC  102
+#define AB8500_INT_CHSTOPBYSEC         103
+/* ab8500_irq_regoffset[13] -> IT[Source|Latch|Mask]22 */
 #define AB8500_INT_USB_CH_TH_PROT_F    104
 #define AB8500_INT_USB_CH_TH_PROT_R    105
-#define AB8500_INT_MAIN_CH_TH_PROT_F   106
-#define AB8500_INT_MAIN_CH_TH_PROT_R   107
-#define AB8500_INT_USB_CHARGER_NOT_OKF 111
+#define AB8500_INT_MAIN_CH_TH_PROT_F   106 /* not 8505/9540 */
+#define AB8500_INT_MAIN_CH_TH_PROT_R   107 /* not 8505/9540 */
+#define AB8500_INT_CHCURLIMNOHSCHIRP   109
+#define AB8500_INT_CHCURLIMHSCHIRP     110
+#define AB8500_INT_XTAL32K_KO          111
 
+/* Definitions for AB9540 */
+/* ab8500_irq_regoffset[14] -> IT[Source|Latch|Mask]13 */
+#define AB9540_INT_GPIO50R             113
+#define AB9540_INT_GPIO51R             114 /* not 8505 */
+#define AB9540_INT_GPIO52R             115
+#define AB9540_INT_GPIO53R             116
+#define AB9540_INT_GPIO54R             117 /* not 8505 */
+#define AB9540_INT_IEXT_CH_RF_BFN_R    118
+#define AB9540_INT_IEXT_CH_RF_BFN_F    119
+/* ab8500_irq_regoffset[15] -> IT[Source|Latch|Mask]14 */
+#define AB9540_INT_GPIO50F             121
+#define AB9540_INT_GPIO51F             122 /* not 8505 */
+#define AB9540_INT_GPIO52F             123
+#define AB9540_INT_GPIO53F             124
+#define AB9540_INT_GPIO54F             125 /* not 8505 */
+
+/*
+ * AB8500_AB9540_NR_IRQS is used when configuring the IRQ numbers for the
+ * entire platform. This is a "compile time" constant so this must be set to
+ * the largest possible value that may be encountered with different AB SOCs.
+ * Of the currently supported AB devices, AB8500 and AB9540, it is the AB9540
+ * which is larger.
+ */
 #define AB8500_NR_IRQS                 112
+#define AB8505_NR_IRQS                 128
+#define AB9540_NR_IRQS                 128
+/* This is set to the roof of any AB8500 chip variant IRQ counts */
+#define AB8500_MAX_NR_IRQS             AB9540_NR_IRQS
+
 #define AB8500_NUM_IRQ_REGS            14
+#define AB9540_NUM_IRQ_REGS            17
 
 /**
  * struct ab8500 - ab8500 internal structure
  * @lock: read/write operations lock
  * @irq_lock: genirq bus lock
  * @irq: irq line
+ * @version: chip version id (e.g. ab8500 or ab9540)
  * @chip_id: chip revision id
  * @write: register write
+ * @write_masked: masked register write
  * @read: register read
  * @rx_buf: rx buf for SPI
  * @tx_buf: tx buf for SPI
  * @mask: cache of IRQ regs for bus lock
  * @oldmask: cache of previous IRQ regs for bus lock
+ * @mask_size: Actual number of valid entries in mask[], oldmask[] and
+ * irq_reg_offset
+ * @irq_reg_offset: Array of offsets into IRQ registers
  */
 struct ab8500 {
        struct device   *dev;
@@ -160,16 +237,20 @@ struct ab8500 {
 
        int             irq_base;
        int             irq;
+       enum ab8500_version version;
        u8              chip_id;
 
-       int (*write) (struct ab8500 *a8500, u16 addr, u8 data);
-       int (*read) (struct ab8500 *a8500, u16 addr);
+       int (*write)(struct ab8500 *ab8500, u16 addr, u8 data);
+       int (*write_masked)(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data);
+       int (*read)(struct ab8500 *ab8500, u16 addr);
 
        unsigned long   tx_buf[4];
        unsigned long   rx_buf[4];
 
-       u8 mask[AB8500_NUM_IRQ_REGS];
-       u8 oldmask[AB8500_NUM_IRQ_REGS];
+       u8 *mask;
+       u8 *oldmask;
+       int mask_size;
+       const int *irq_reg_offset;
 };
 
 struct regulator_reg_init;
@@ -195,7 +276,52 @@ struct ab8500_platform_data {
        struct ab8500_gpio_platform_data *gpio;
 };
 
-extern int __devinit ab8500_init(struct ab8500 *ab8500);
+extern int __devinit ab8500_init(struct ab8500 *ab8500,
+                                enum ab8500_version version);
 extern int __devexit ab8500_exit(struct ab8500 *ab8500);
 
+static inline int is_ab8500(struct ab8500 *ab)
+{
+       return ab->version == AB8500_VERSION_AB8500;
+}
+
+static inline int is_ab8505(struct ab8500 *ab)
+{
+       return ab->version == AB8500_VERSION_AB8505;
+}
+
+static inline int is_ab9540(struct ab8500 *ab)
+{
+       return ab->version == AB8500_VERSION_AB9540;
+}
+
+static inline int is_ab8540(struct ab8500 *ab)
+{
+       return ab->version == AB8500_VERSION_AB8540;
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_1p0_or_earlier(struct ab8500 *ab)
+{
+       return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P0));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_1p1_or_earlier(struct ab8500 *ab)
+{
+       return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P1));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
+{
+       return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_2p0(struct ab8500 *ab)
+{
+       return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
 #endif /* MFD_AB8500_H */
diff --git a/include/linux/mfd/anatop.h b/include/linux/mfd/anatop.h
new file mode 100644 (file)
index 0000000..22c1007
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * anatop.h - Anatop MFD driver
+ *
+ *  Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *  Copyright (C) 2012 Linaro
+ *
+ * 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_ANATOP_H
+#define __LINUX_MFD_ANATOP_H
+
+#include <linux/spinlock.h>
+
+/**
+ * anatop - MFD data
+ * @ioreg: ioremap register
+ * @reglock: spinlock for register read/write
+ */
+struct anatop {
+       void *ioreg;
+       spinlock_t reglock;
+};
+
+extern u32 anatop_get_bits(struct anatop *, u32, int, int);
+extern void anatop_set_bits(struct anatop *, u32, int, int, u32);
+
+#endif /*  __LINUX_MFD_ANATOP_H */
index 5702d1b..7ffbd6e 100644 (file)
@@ -76,8 +76,6 @@ enum da9052_chip_id {
 struct da9052_pdata;
 
 struct da9052 {
-       struct mutex io_lock;
-
        struct device *dev;
        struct regmap *regmap;
 
index 60d27f7..b3a43b1 100644 (file)
 #define __MFD_DB8500_PRCMU_H
 
 #include <linux/interrupt.h>
+#include <linux/bitops.h>
+
+/*
+ * Registers
+ */
+#define DB8500_PRCM_GPIOCR 0x138
+#define DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0    BIT(0)
+#define DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD     BIT(9)
+#define DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1    BIT(11)
+#define DB8500_PRCM_GPIOCR_SPI2_SELECT         BIT(23)
+
+#define DB8500_PRCM_LINE_VALUE 0x170
+#define DB8500_PRCM_LINE_VALUE_HSI_CAWAKE0     BIT(3)
+
+#define DB8500_PRCM_DSI_SW_RESET 0x324
+#define DB8500_PRCM_DSI_SW_RESET_DSI0_SW_RESETN BIT(0)
+#define DB8500_PRCM_DSI_SW_RESET_DSI1_SW_RESETN BIT(1)
+#define DB8500_PRCM_DSI_SW_RESET_DSI2_SW_RESETN BIT(2)
 
 /* This portion previously known as <mach/prcmu-fw-defs_v1.h> */
 
@@ -421,40 +439,22 @@ enum auto_enable {
 /* End of file previously known as prcmu-fw-defs_v1.h */
 
 /**
- * enum hw_acc_dev - enum for hw accelerators
- * @HW_ACC_SVAMMDSP: for SVAMMDSP
- * @HW_ACC_SVAPIPE:  for SVAPIPE
- * @HW_ACC_SIAMMDSP: for SIAMMDSP
- * @HW_ACC_SIAPIPE: for SIAPIPE
- * @HW_ACC_SGA: for SGA
- * @HW_ACC_B2R2: for B2R2
- * @HW_ACC_MCDE: for MCDE
- * @HW_ACC_ESRAM1: for ESRAM1
- * @HW_ACC_ESRAM2: for ESRAM2
- * @HW_ACC_ESRAM3: for ESRAM3
- * @HW_ACC_ESRAM4: for ESRAM4
- * @NUM_HW_ACC: number of hardware accelerators
- *
- * Different hw accelerators which can be turned ON/
- * OFF or put into retention (MMDSPs and ESRAMs).
- * Used with EPOD API.
+ * enum prcmu_power_status - results from set_power_state
+ * @PRCMU_SLEEP_OK: Sleep went ok
+ * @PRCMU_DEEP_SLEEP_OK: DeepSleep went ok
+ * @PRCMU_IDLE_OK: Idle went ok
+ * @PRCMU_DEEPIDLE_OK: DeepIdle went ok
+ * @PRCMU_PRCMU2ARMPENDINGIT_ER: Pending interrupt detected
+ * @PRCMU_ARMPENDINGIT_ER: Pending interrupt detected
  *
- * NOTE! Deprecated, to be removed when all users switched over to use the
- * regulator API.
  */
-enum hw_acc_dev {
-       HW_ACC_SVAMMDSP,
-       HW_ACC_SVAPIPE,
-       HW_ACC_SIAMMDSP,
-       HW_ACC_SIAPIPE,
-       HW_ACC_SGA,
-       HW_ACC_B2R2,
-       HW_ACC_MCDE,
-       HW_ACC_ESRAM1,
-       HW_ACC_ESRAM2,
-       HW_ACC_ESRAM3,
-       HW_ACC_ESRAM4,
-       NUM_HW_ACC
+enum prcmu_power_status {
+       PRCMU_SLEEP_OK                  = 0xf3,
+       PRCMU_DEEP_SLEEP_OK             = 0xf6,
+       PRCMU_IDLE_OK                   = 0xf0,
+       PRCMU_DEEPIDLE_OK               = 0xe3,
+       PRCMU_PRCMU2ARMPENDINGIT_ER     = 0x91,
+       PRCMU_ARMPENDINGIT_ER           = 0x93,
 };
 
 /*
@@ -493,6 +493,20 @@ struct prcmu_auto_pm_config {
        u8 sva_policy;
 };
 
+#define PRCMU_FW_PROJECT_U8500         2
+#define PRCMU_FW_PROJECT_U9500         4
+#define PRCMU_FW_PROJECT_U8500_C2      7
+#define PRCMU_FW_PROJECT_U9500_C2      11
+#define PRCMU_FW_PROJECT_U8520         13
+#define PRCMU_FW_PROJECT_U8420         14
+
+struct prcmu_fw_version {
+       u8 project;
+       u8 api_version;
+       u8 func_version;
+       u8 errata;
+};
+
 #ifdef CONFIG_MFD_DB8500_PRCMU
 
 void db8500_prcmu_early_init(void);
@@ -500,42 +514,41 @@ int prcmu_set_rc_a2p(enum romcode_write);
 enum romcode_read prcmu_get_rc_p2a(void);
 enum ap_pwrst prcmu_get_xp70_current_state(void);
 bool prcmu_has_arm_maxopp(void);
-bool prcmu_is_u8400(void);
-int prcmu_set_ape_opp(u8 opp);
-int prcmu_get_ape_opp(void);
+struct prcmu_fw_version *prcmu_get_fw_version(void);
 int prcmu_request_ape_opp_100_voltage(bool enable);
 int prcmu_release_usb_wakeup_state(void);
-int prcmu_set_ddr_opp(u8 opp);
-int prcmu_get_ddr_opp(void);
-/* NOTE! Use regulator framework instead */
-int prcmu_set_hwacc(u16 hw_acc_dev, u8 state);
 void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
        struct prcmu_auto_pm_config *idle);
 bool prcmu_is_auto_pm_enabled(void);
 
 int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
 int prcmu_set_clock_divider(u8 clock, u8 divider);
-int prcmu_config_hotdog(u8 threshold);
-int prcmu_config_hotmon(u8 low, u8 high);
-int prcmu_start_temp_sense(u16 cycles32k);
-int prcmu_stop_temp_sense(void);
+int db8500_prcmu_config_hotdog(u8 threshold);
+int db8500_prcmu_config_hotmon(u8 low, u8 high);
+int db8500_prcmu_start_temp_sense(u16 cycles32k);
+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);
 void prcmu_ac_sleep_req(void);
-void prcmu_modem_reset(void);
-void prcmu_enable_spi2(void);
-void prcmu_disable_spi2(void);
+void db8500_prcmu_modem_reset(void);
 
-int prcmu_config_a9wdog(u8 num, bool sleep_auto_off);
-int prcmu_enable_a9wdog(u8 id);
-int prcmu_disable_a9wdog(u8 id);
-int prcmu_kick_a9wdog(u8 id);
-int prcmu_load_a9wdog(u8 id, u32 val);
+int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off);
+int db8500_prcmu_enable_a9wdog(u8 id);
+int db8500_prcmu_disable_a9wdog(u8 id);
+int db8500_prcmu_kick_a9wdog(u8 id);
+int db8500_prcmu_load_a9wdog(u8 id, u32 val);
 
 void db8500_prcmu_system_reset(u16 reset_code);
 int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
+u8 db8500_prcmu_get_power_state_result(void);
+int db8500_prcmu_gic_decouple(void);
+int db8500_prcmu_gic_recouple(void);
+int db8500_prcmu_copy_gic_settings(void);
+bool db8500_prcmu_gic_pending_irq(void);
+bool db8500_prcmu_pending_irq(void);
+bool db8500_prcmu_is_cpu_in_wfi(int cpu);
 void db8500_prcmu_enable_wakeups(u32 wakeups);
 int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state);
 int db8500_prcmu_request_clock(u8 clock, bool enable);
@@ -549,6 +562,14 @@ u16 db8500_prcmu_get_reset_code(void);
 bool db8500_prcmu_is_ac_wake_requested(void);
 int db8500_prcmu_set_arm_opp(u8 opp);
 int db8500_prcmu_get_arm_opp(void);
+int db8500_prcmu_set_ape_opp(u8 opp);
+int db8500_prcmu_get_ape_opp(void);
+int db8500_prcmu_set_ddr_opp(u8 opp);
+int db8500_prcmu_get_ddr_opp(void);
+
+u32 db8500_prcmu_read(unsigned int reg);
+void db8500_prcmu_write(unsigned int reg, u32 value);
+void db8500_prcmu_write_masked(unsigned int reg, u32 mask, u32 value);
 
 #else /* !CONFIG_MFD_DB8500_PRCMU */
 
@@ -574,17 +595,17 @@ static inline bool prcmu_has_arm_maxopp(void)
        return false;
 }
 
-static inline bool prcmu_is_u8400(void)
+static inline struct prcmu_fw_version *prcmu_get_fw_version(void)
 {
-       return false;
+       return NULL;
 }
 
-static inline int prcmu_set_ape_opp(u8 opp)
+static inline int db8500_prcmu_set_ape_opp(u8 opp)
 {
        return 0;
 }
 
-static inline int prcmu_get_ape_opp(void)
+static inline int db8500_prcmu_get_ape_opp(void)
 {
        return APE_100_OPP;
 }
@@ -599,21 +620,16 @@ static inline int prcmu_release_usb_wakeup_state(void)
        return 0;
 }
 
-static inline int prcmu_set_ddr_opp(u8 opp)
+static inline int db8500_prcmu_set_ddr_opp(u8 opp)
 {
        return 0;
 }
 
-static inline int prcmu_get_ddr_opp(void)
+static inline int db8500_prcmu_get_ddr_opp(void)
 {
        return DDR_100_OPP;
 }
 
-static inline int prcmu_set_hwacc(u16 hw_acc_dev, u8 state)
-{
-       return 0;
-}
-
 static inline void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
        struct prcmu_auto_pm_config *idle)
 {
@@ -634,22 +650,22 @@ static inline int prcmu_set_clock_divider(u8 clock, u8 divider)
        return 0;
 }
 
-static inline int prcmu_config_hotdog(u8 threshold)
+static inline int db8500_prcmu_config_hotdog(u8 threshold)
 {
        return 0;
 }
 
-static inline int prcmu_config_hotmon(u8 low, u8 high)
+static inline int db8500_prcmu_config_hotmon(u8 low, u8 high)
 {
        return 0;
 }
 
-static inline int prcmu_start_temp_sense(u16 cycles32k)
+static inline int db8500_prcmu_start_temp_sense(u16 cycles32k)
 {
        return 0;
 }
 
-static inline int prcmu_stop_temp_sense(void)
+static inline int db8500_prcmu_stop_temp_sense(void)
 {
        return 0;
 }
@@ -668,22 +684,17 @@ static inline void prcmu_ac_wake_req(void) {}
 
 static inline void prcmu_ac_sleep_req(void) {}
 
-static inline void prcmu_modem_reset(void) {}
+static inline void db8500_prcmu_modem_reset(void) {}
 
-static inline int prcmu_enable_spi2(void)
-{
-       return 0;
-}
+static inline void db8500_prcmu_system_reset(u16 reset_code) {}
 
-static inline int prcmu_disable_spi2(void)
+static inline int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk,
+       bool keep_ap_pll)
 {
        return 0;
 }
 
-static inline void db8500_prcmu_system_reset(u16 reset_code) {}
-
-static inline int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk,
-       bool keep_ap_pll)
+static inline u8 db8500_prcmu_get_power_state_result(void)
 {
        return 0;
 }
@@ -729,27 +740,27 @@ static inline u16 db8500_prcmu_get_reset_code(void)
        return 0;
 }
 
-static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+static inline int db8500_prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
 {
        return 0;
 }
 
-static inline int prcmu_enable_a9wdog(u8 id)
+static inline int db8500_prcmu_enable_a9wdog(u8 id)
 {
        return 0;
 }
 
-static inline int prcmu_disable_a9wdog(u8 id)
+static inline int db8500_prcmu_disable_a9wdog(u8 id)
 {
        return 0;
 }
 
-static inline int prcmu_kick_a9wdog(u8 id)
+static inline int db8500_prcmu_kick_a9wdog(u8 id)
 {
        return 0;
 }
 
-static inline int prcmu_load_a9wdog(u8 id, u32 val)
+static inline int db8500_prcmu_load_a9wdog(u8 id, u32 val)
 {
        return 0;
 }
@@ -769,6 +780,16 @@ static inline int db8500_prcmu_get_arm_opp(void)
        return 0;
 }
 
+static inline u32 db8500_prcmu_read(unsigned int reg)
+{
+       return 0;
+}
+
+static inline void db8500_prcmu_write(unsigned int reg, u32 value) {}
+
+static inline void db8500_prcmu_write_masked(unsigned int reg, u32 mask,
+       u32 value) {}
+
 #endif /* !CONFIG_MFD_DB8500_PRCMU */
 
 #endif /* __MFD_DB8500_PRCMU_H */
index bac942f..d7674eb 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
-#include <asm/mach-types.h>
+#include <linux/err.h>
 
 /* PRCMU Wakeup defines */
 enum prcmu_wakeup_index {
@@ -80,6 +80,29 @@ enum prcmu_wakeup_index {
 #define EPOD_STATE_ON_CLK_OFF  0x03
 #define EPOD_STATE_ON          0x04
 
+/* DB5500 CLKOUT IDs */
+enum {
+       DB5500_CLKOUT0 = 0,
+       DB5500_CLKOUT1,
+};
+
+/* DB5500 CLKOUTx sources */
+enum {
+       DB5500_CLKOUT_REF_CLK_SEL0,
+       DB5500_CLKOUT_RTC_CLK0_SEL0,
+       DB5500_CLKOUT_ULP_CLK_SEL0,
+       DB5500_CLKOUT_STATIC0,
+       DB5500_CLKOUT_REFCLK,
+       DB5500_CLKOUT_ULPCLK,
+       DB5500_CLKOUT_ARMCLK,
+       DB5500_CLKOUT_SYSACC0CLK,
+       DB5500_CLKOUT_SOC0PLLCLK,
+       DB5500_CLKOUT_SOC1PLLCLK,
+       DB5500_CLKOUT_DDRPLLCLK,
+       DB5500_CLKOUT_TVCLK,
+       DB5500_CLKOUT_IRDACLK,
+};
+
 /*
  * CLKOUT sources
  */
@@ -111,6 +134,7 @@ enum prcmu_clock {
        PRCMU_MSP1CLK,
        PRCMU_I2CCLK,
        PRCMU_SDMMCCLK,
+       PRCMU_SPARE1CLK,
        PRCMU_SLIMCLK,
        PRCMU_PER1CLK,
        PRCMU_PER2CLK,
@@ -139,12 +163,20 @@ enum prcmu_clock {
        PRCMU_IRRCCLK,
        PRCMU_SIACLK,
        PRCMU_SVACLK,
+       PRCMU_ACLK,
        PRCMU_NUM_REG_CLOCKS,
        PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
+       PRCMU_CDCLK,
        PRCMU_TIMCLK,
        PRCMU_PLLSOC0,
        PRCMU_PLLSOC1,
        PRCMU_PLLDDR,
+       PRCMU_PLLDSI,
+       PRCMU_DSI0CLK,
+       PRCMU_DSI1CLK,
+       PRCMU_DSI0ESCCLK,
+       PRCMU_DSI1ESCCLK,
+       PRCMU_DSI2ESCCLK,
 };
 
 /**
@@ -153,12 +185,14 @@ enum prcmu_clock {
  * @APE_NO_CHANGE: The APE operating point is unchanged
  * @APE_100_OPP: The new APE operating point is ape100opp
  * @APE_50_OPP: 50%
+ * @APE_50_PARTLY_25_OPP: 50%, except some clocks at 25%.
  */
 enum ape_opp {
        APE_OPP_INIT = 0x00,
        APE_NO_CHANGE = 0x01,
        APE_100_OPP = 0x02,
-       APE_50_OPP = 0x03
+       APE_50_OPP = 0x03,
+       APE_50_PARTLY_25_OPP = 0xFF,
 };
 
 /**
@@ -218,9 +252,11 @@ enum ddr_pwrst {
 
 #if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
 
+#include <mach/id.h>
+
 static inline void __init prcmu_early_init(void)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return db5500_prcmu_early_init();
        else
                return db8500_prcmu_early_init();
@@ -229,7 +265,7 @@ static inline void __init prcmu_early_init(void)
 static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
                bool keep_ap_pll)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return db5500_prcmu_set_power_state(state, keep_ulp_clk,
                        keep_ap_pll);
        else
@@ -237,9 +273,65 @@ static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
                        keep_ap_pll);
 }
 
+static inline u8 prcmu_get_power_state_result(void)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_get_power_state_result();
+}
+
+static inline int prcmu_gic_decouple(void)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_gic_decouple();
+}
+
+static inline int prcmu_gic_recouple(void)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_gic_recouple();
+}
+
+static inline bool prcmu_gic_pending_irq(void)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_gic_pending_irq();
+}
+
+static inline bool prcmu_is_cpu_in_wfi(int cpu)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_is_cpu_in_wfi(cpu);
+}
+
+static inline int prcmu_copy_gic_settings(void)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_copy_gic_settings();
+}
+
+static inline bool prcmu_pending_irq(void)
+{
+        if (cpu_is_u5500())
+                return -EINVAL;
+        else
+                return db8500_prcmu_pending_irq();
+}
+
 static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return -EINVAL;
        else
                return db8500_prcmu_set_epod(epod_id, epod_state);
@@ -247,7 +339,7 @@ static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
 
 static inline void prcmu_enable_wakeups(u32 wakeups)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                db5500_prcmu_enable_wakeups(wakeups);
        else
                db8500_prcmu_enable_wakeups(wakeups);
@@ -260,7 +352,7 @@ static inline void prcmu_disable_wakeups(void)
 
 static inline void prcmu_config_abb_event_readout(u32 abb_events)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                db5500_prcmu_config_abb_event_readout(abb_events);
        else
                db8500_prcmu_config_abb_event_readout(abb_events);
@@ -268,7 +360,7 @@ static inline void prcmu_config_abb_event_readout(u32 abb_events)
 
 static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                db5500_prcmu_get_abb_event_buffer(buf);
        else
                db8500_prcmu_get_abb_event_buffer(buf);
@@ -276,25 +368,40 @@ static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
 
 int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
 int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask, u8 size);
 
 int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
 
 static inline int prcmu_request_clock(u8 clock, bool enable)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return db5500_prcmu_request_clock(clock, enable);
        else
                return db8500_prcmu_request_clock(clock, enable);
 }
 
-int prcmu_set_ape_opp(u8 opp);
-int prcmu_get_ape_opp(void);
-int prcmu_set_ddr_opp(u8 opp);
-int prcmu_get_ddr_opp(void);
+unsigned long prcmu_clock_rate(u8 clock);
+long prcmu_round_clock_rate(u8 clock, unsigned long rate);
+int prcmu_set_clock_rate(u8 clock, unsigned long rate);
+
+static inline int prcmu_set_ddr_opp(u8 opp)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_set_ddr_opp(opp);
+}
+static inline int prcmu_get_ddr_opp(void)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_get_ddr_opp();
+}
 
 static inline int prcmu_set_arm_opp(u8 opp)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return -EINVAL;
        else
                return db8500_prcmu_set_arm_opp(opp);
@@ -302,15 +409,31 @@ static inline int prcmu_set_arm_opp(u8 opp)
 
 static inline int prcmu_get_arm_opp(void)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return -EINVAL;
        else
                return db8500_prcmu_get_arm_opp();
 }
 
+static inline int prcmu_set_ape_opp(u8 opp)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_set_ape_opp(opp);
+}
+
+static inline int prcmu_get_ape_opp(void)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_get_ape_opp();
+}
+
 static inline void prcmu_system_reset(u16 reset_code)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return db5500_prcmu_system_reset(reset_code);
        else
                return db8500_prcmu_system_reset(reset_code);
@@ -318,7 +441,7 @@ static inline void prcmu_system_reset(u16 reset_code)
 
 static inline u16 prcmu_get_reset_code(void)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return db5500_prcmu_get_reset_code();
        else
                return db8500_prcmu_get_reset_code();
@@ -326,10 +449,17 @@ static inline u16 prcmu_get_reset_code(void)
 
 void prcmu_ac_wake_req(void);
 void prcmu_ac_sleep_req(void);
-void prcmu_modem_reset(void);
+static inline void prcmu_modem_reset(void)
+{
+       if (cpu_is_u5500())
+               return;
+       else
+               return db8500_prcmu_modem_reset();
+}
+
 static inline bool prcmu_is_ac_wake_requested(void)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return db5500_prcmu_is_ac_wake_requested();
        else
                return db8500_prcmu_is_ac_wake_requested();
@@ -337,7 +467,7 @@ static inline bool prcmu_is_ac_wake_requested(void)
 
 static inline int prcmu_set_display_clocks(void)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return db5500_prcmu_set_display_clocks();
        else
                return db8500_prcmu_set_display_clocks();
@@ -345,7 +475,7 @@ static inline int prcmu_set_display_clocks(void)
 
 static inline int prcmu_disable_dsipll(void)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return db5500_prcmu_disable_dsipll();
        else
                return db8500_prcmu_disable_dsipll();
@@ -353,7 +483,7 @@ static inline int prcmu_disable_dsipll(void)
 
 static inline int prcmu_enable_dsipll(void)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return db5500_prcmu_enable_dsipll();
        else
                return db8500_prcmu_enable_dsipll();
@@ -361,11 +491,107 @@ static inline int prcmu_enable_dsipll(void)
 
 static inline int prcmu_config_esram0_deep_sleep(u8 state)
 {
-       if (machine_is_u5500())
+       if (cpu_is_u5500())
                return -EINVAL;
        else
                return db8500_prcmu_config_esram0_deep_sleep(state);
 }
+
+static inline int prcmu_config_hotdog(u8 threshold)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_config_hotdog(threshold);
+}
+
+static inline int prcmu_config_hotmon(u8 low, u8 high)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_config_hotmon(low, high);
+}
+
+static inline int prcmu_start_temp_sense(u16 cycles32k)
+{
+       if (cpu_is_u5500())
+               return  -EINVAL;
+       else
+               return  db8500_prcmu_start_temp_sense(cycles32k);
+}
+
+static inline int prcmu_stop_temp_sense(void)
+{
+       if (cpu_is_u5500())
+               return  -EINVAL;
+       else
+               return  db8500_prcmu_stop_temp_sense();
+}
+
+static inline u32 prcmu_read(unsigned int reg)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_read(reg);
+}
+
+static inline void prcmu_write(unsigned int reg, u32 value)
+{
+       if (cpu_is_u5500())
+               return;
+       else
+               db8500_prcmu_write(reg, value);
+}
+
+static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
+{
+       if (cpu_is_u5500())
+               return;
+       else
+               db8500_prcmu_write_masked(reg, mask, value);
+}
+
+static inline int prcmu_enable_a9wdog(u8 id)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_enable_a9wdog(id);
+}
+
+static inline int prcmu_disable_a9wdog(u8 id)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_disable_a9wdog(id);
+}
+
+static inline int prcmu_kick_a9wdog(u8 id)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_kick_a9wdog(id);
+}
+
+static inline int prcmu_load_a9wdog(u8 id, u32 timeout)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_load_a9wdog(id, timeout);
+}
+
+static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
+{
+       if (cpu_is_u5500())
+               return -EINVAL;
+       else
+               return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
+}
 #else
 
 static inline void __init prcmu_early_init(void) {}
@@ -395,6 +621,12 @@ static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
        return -ENOSYS;
 }
 
+static inline int prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask,
+       u8 size)
+{
+       return -ENOSYS;
+}
+
 static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
 {
        return 0;
@@ -405,6 +637,21 @@ static inline int prcmu_request_clock(u8 clock, bool enable)
        return 0;
 }
 
+static inline long prcmu_round_clock_rate(u8 clock, unsigned long rate)
+{
+       return 0;
+}
+
+static inline int prcmu_set_clock_rate(u8 clock, unsigned long rate)
+{
+       return 0;
+}
+
+static inline unsigned long prcmu_clock_rate(u8 clock)
+{
+       return 0;
+}
+
 static inline int prcmu_set_ape_opp(u8 opp)
 {
        return 0;
@@ -480,14 +727,133 @@ static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
        *buf = NULL;
 }
 
+static inline int prcmu_config_hotdog(u8 threshold)
+{
+       return 0;
+}
+
+static inline int prcmu_config_hotmon(u8 low, u8 high)
+{
+       return 0;
+}
+
+static inline int prcmu_start_temp_sense(u16 cycles32k)
+{
+       return 0;
+}
+
+static inline int prcmu_stop_temp_sense(void)
+{
+       return 0;
+}
+
+static inline u32 prcmu_read(unsigned int reg)
+{
+       return 0;
+}
+
+static inline void prcmu_write(unsigned int reg, u32 value) {}
+
+static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
+
+#endif
+
+static inline void prcmu_set(unsigned int reg, u32 bits)
+{
+       prcmu_write_masked(reg, bits, bits);
+}
+
+static inline void prcmu_clear(unsigned int reg, u32 bits)
+{
+       prcmu_write_masked(reg, bits, 0);
+}
+
+#if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
+
+/**
+ * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
+ */
+static inline void prcmu_enable_spi2(void)
+{
+       if (cpu_is_u8500())
+               prcmu_set(DB8500_PRCM_GPIOCR, DB8500_PRCM_GPIOCR_SPI2_SELECT);
+}
+
+/**
+ * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
+ */
+static inline void prcmu_disable_spi2(void)
+{
+       if (cpu_is_u8500())
+               prcmu_clear(DB8500_PRCM_GPIOCR, DB8500_PRCM_GPIOCR_SPI2_SELECT);
+}
+
+/**
+ * prcmu_enable_stm_mod_uart - Enables pin muxing for STMMOD
+ * and UARTMOD on OtherAlternateC3.
+ */
+static inline void prcmu_enable_stm_mod_uart(void)
+{
+       if (cpu_is_u8500()) {
+               prcmu_set(DB8500_PRCM_GPIOCR,
+                       (DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1 |
+                        DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0));
+       }
+}
+
+/**
+ * prcmu_disable_stm_mod_uart - Disables pin muxing for STMMOD
+ * and UARTMOD on OtherAlternateC3.
+ */
+static inline void prcmu_disable_stm_mod_uart(void)
+{
+       if (cpu_is_u8500()) {
+               prcmu_clear(DB8500_PRCM_GPIOCR,
+                       (DB8500_PRCM_GPIOCR_DBG_STM_MOD_CMD1 |
+                        DB8500_PRCM_GPIOCR_DBG_UARTMOD_CMD0));
+       }
+}
+
+/**
+ * prcmu_enable_stm_ape - Enables pin muxing for STM APE on OtherAlternateC1.
+ */
+static inline void prcmu_enable_stm_ape(void)
+{
+       if (cpu_is_u8500()) {
+               prcmu_set(DB8500_PRCM_GPIOCR,
+                       DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD);
+       }
+}
+
+/**
+ * prcmu_disable_stm_ape - Disables pin muxing for STM APE on OtherAlternateC1.
+ */
+static inline void prcmu_disable_stm_ape(void)
+{
+       if (cpu_is_u8500()) {
+               prcmu_clear(DB8500_PRCM_GPIOCR,
+                       DB8500_PRCM_GPIOCR_DBG_STM_APE_CMD);
+       }
+}
+
+#else
+
+static inline void prcmu_enable_spi2(void) {}
+static inline void prcmu_disable_spi2(void) {}
+static inline void prcmu_enable_stm_mod_uart(void) {}
+static inline void prcmu_disable_stm_mod_uart(void) {}
+static inline void prcmu_enable_stm_ape(void) {}
+static inline void prcmu_disable_stm_ape(void) {}
+
 #endif
 
 /* PRCMU QoS APE OPP class */
 #define PRCMU_QOS_APE_OPP 1
 #define PRCMU_QOS_DDR_OPP 2
+#define PRCMU_QOS_ARM_OPP 3
 #define PRCMU_QOS_DEFAULT_VALUE -1
 
-#ifdef CONFIG_UX500_PRCMU_QOS_POWER
+#ifdef CONFIG_DBX500_PRCMU_QOS_POWER
 
 unsigned long prcmu_qos_get_cpufreq_opp_delay(void);
 void prcmu_qos_set_cpufreq_opp_delay(unsigned long);
index b86ee45..10e038b 100644 (file)
@@ -38,7 +38,8 @@ int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq);
 int mc13xxx_get_flags(struct mc13xxx *mc13xxx);
 
 int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx,
-               unsigned int mode, unsigned int channel, unsigned int *sample);
+               unsigned int mode, unsigned int channel,
+               u8 ato, bool atox, unsigned int *sample);
 
 #define MC13XXX_IRQ_ADCDONE    0
 #define MC13XXX_IRQ_ADCBISDONE 1
@@ -157,6 +158,18 @@ struct mc13xxx_buttons_platform_data {
        unsigned short b3on_key;
 };
 
+struct mc13xxx_ts_platform_data {
+       /* Delay between Touchscreen polarization and ADC Conversion.
+        * Given in clock ticks of a 32 kHz clock which gives a granularity of
+        * about 30.5ms */
+       u8 ato;
+
+#define MC13783_TS_ATO_FIRST false
+#define MC13783_TS_ATO_EACH  true
+       /* Use the ATO delay only for the first conversion or for each one */
+       bool atox;
+};
+
 struct mc13xxx_platform_data {
 #define MC13XXX_USE_TOUCHSCREEN (1 << 0)
 #define MC13XXX_USE_CODEC      (1 << 1)
@@ -167,6 +180,7 @@ struct mc13xxx_platform_data {
        struct mc13xxx_regulator_platform_data regulators;
        struct mc13xxx_leds_platform_data *leds;
        struct mc13xxx_buttons_platform_data *buttons;
+       struct mc13xxx_ts_platform_data touch;
 };
 
 #define MC13XXX_ADC_MODE_TS            1
index f88c1cc..a9e8bd1 100644 (file)
@@ -10,8 +10,6 @@
 #ifndef MCP_H
 #define MCP_H
 
-#include <mach/dma.h>
-
 struct mcp_ops;
 
 struct mcp {
@@ -21,12 +19,7 @@ struct mcp {
        int             use_count;
        unsigned int    sclk_rate;
        unsigned int    rw_timeout;
-       dma_device_t    dma_audio_rd;
-       dma_device_t    dma_audio_wr;
-       dma_device_t    dma_telco_rd;
-       dma_device_t    dma_telco_wr;
        struct device   attached_device;
-       int             gpio_base;
 };
 
 struct mcp_ops {
@@ -47,15 +40,14 @@ void mcp_disable(struct mcp *);
 #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
 
 struct mcp *mcp_host_alloc(struct device *, size_t);
-int mcp_host_register(struct mcp *);
-void mcp_host_unregister(struct mcp *);
+int mcp_host_add(struct mcp *, void *);
+void mcp_host_del(struct mcp *);
+void mcp_host_free(struct mcp *);
 
 struct mcp_driver {
        struct device_driver drv;
        int (*probe)(struct mcp *);
        void (*remove)(struct mcp *);
-       int (*suspend)(struct mcp *, pm_message_t);
-       int (*resume)(struct mcp *);
 };
 
 int mcp_driver_register(struct mcp_driver *);
index d5517fd..00fa3de 100644 (file)
@@ -18,7 +18,6 @@
 #ifndef __MFD_PM8921_H
 #define __MFD_PM8921_H
 
-#include <linux/device.h>
 #include <linux/mfd/pm8xxx/irq.h>
 
 #define PM8921_NR_IRQS         256
diff --git a/include/linux/mfd/rc5t583.h b/include/linux/mfd/rc5t583.h
new file mode 100644 (file)
index 0000000..a2c6160
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Core driver interface to access RICOH_RC5T583 power management chip.
+ *
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on code
+ *      Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * 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/>.
+ *
+ */
+
+#ifndef __LINUX_MFD_RC5T583_H
+#define __LINUX_MFD_RC5T583_H
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#define RC5T583_MAX_REGS               0xF8
+
+/* Maximum number of main interrupts */
+#define MAX_MAIN_INTERRUPT             5
+#define RC5T583_MAX_GPEDGE_REG         2
+#define RC5T583_MAX_INTERRUPT_MASK_REGS        9
+
+/* Interrupt enable register */
+#define RC5T583_INT_EN_SYS1    0x19
+#define RC5T583_INT_EN_SYS2    0x1D
+#define RC5T583_INT_EN_DCDC    0x41
+#define RC5T583_INT_EN_RTC     0xED
+#define RC5T583_INT_EN_ADC1    0x90
+#define RC5T583_INT_EN_ADC2    0x91
+#define RC5T583_INT_EN_ADC3    0x92
+
+/* Interrupt status registers (monitor regs in Ricoh)*/
+#define RC5T583_INTC_INTPOL    0xAD
+#define RC5T583_INTC_INTEN     0xAE
+#define RC5T583_INTC_INTMON    0xAF
+
+#define RC5T583_INT_MON_GRP    0xAF
+#define RC5T583_INT_MON_SYS1   0x1B
+#define RC5T583_INT_MON_SYS2   0x1F
+#define RC5T583_INT_MON_DCDC   0x43
+#define RC5T583_INT_MON_RTC    0xEE
+
+/* Interrupt clearing registers */
+#define RC5T583_INT_IR_SYS1    0x1A
+#define RC5T583_INT_IR_SYS2    0x1E
+#define RC5T583_INT_IR_DCDC    0x42
+#define RC5T583_INT_IR_RTC     0xEE
+#define RC5T583_INT_IR_ADCL    0x94
+#define RC5T583_INT_IR_ADCH    0x95
+#define RC5T583_INT_IR_ADCEND  0x96
+#define RC5T583_INT_IR_GPIOR   0xA9
+#define RC5T583_INT_IR_GPIOF   0xAA
+
+/* Sleep sequence registers */
+#define RC5T583_SLPSEQ1                0x21
+#define RC5T583_SLPSEQ2                0x22
+#define RC5T583_SLPSEQ3                0x23
+#define RC5T583_SLPSEQ4                0x24
+#define RC5T583_SLPSEQ5                0x25
+#define RC5T583_SLPSEQ6                0x26
+#define RC5T583_SLPSEQ7                0x27
+#define RC5T583_SLPSEQ8                0x28
+#define RC5T583_SLPSEQ9                0x29
+#define RC5T583_SLPSEQ10       0x2A
+#define RC5T583_SLPSEQ11       0x2B
+
+/* Regulator registers */
+#define RC5T583_REG_DC0CTL     0x30
+#define RC5T583_REG_DC0DAC     0x31
+#define RC5T583_REG_DC0LATCTL  0x32
+#define RC5T583_REG_SR0CTL     0x33
+
+#define RC5T583_REG_DC1CTL     0x34
+#define RC5T583_REG_DC1DAC     0x35
+#define RC5T583_REG_DC1LATCTL  0x36
+#define RC5T583_REG_SR1CTL     0x37
+
+#define RC5T583_REG_DC2CTL     0x38
+#define RC5T583_REG_DC2DAC     0x39
+#define RC5T583_REG_DC2LATCTL  0x3A
+#define RC5T583_REG_SR2CTL     0x3B
+
+#define RC5T583_REG_DC3CTL     0x3C
+#define RC5T583_REG_DC3DAC     0x3D
+#define RC5T583_REG_DC3LATCTL  0x3E
+#define RC5T583_REG_SR3CTL     0x3F
+
+
+#define RC5T583_REG_LDOEN1     0x50
+#define RC5T583_REG_LDOEN2     0x51
+#define RC5T583_REG_LDODIS1    0x52
+#define RC5T583_REG_LDODIS2    0x53
+
+#define RC5T583_REG_LDO0DAC    0x54
+#define RC5T583_REG_LDO1DAC    0x55
+#define RC5T583_REG_LDO2DAC    0x56
+#define RC5T583_REG_LDO3DAC    0x57
+#define RC5T583_REG_LDO4DAC    0x58
+#define RC5T583_REG_LDO5DAC    0x59
+#define RC5T583_REG_LDO6DAC    0x5A
+#define RC5T583_REG_LDO7DAC    0x5B
+#define RC5T583_REG_LDO8DAC    0x5C
+#define RC5T583_REG_LDO9DAC    0x5D
+
+#define RC5T583_REG_DC0DAC_DS  0x60
+#define RC5T583_REG_DC1DAC_DS  0x61
+#define RC5T583_REG_DC2DAC_DS  0x62
+#define RC5T583_REG_DC3DAC_DS  0x63
+
+#define RC5T583_REG_LDO0DAC_DS 0x64
+#define RC5T583_REG_LDO1DAC_DS 0x65
+#define RC5T583_REG_LDO2DAC_DS 0x66
+#define RC5T583_REG_LDO3DAC_DS 0x67
+#define RC5T583_REG_LDO4DAC_DS 0x68
+#define RC5T583_REG_LDO5DAC_DS 0x69
+#define RC5T583_REG_LDO6DAC_DS 0x6A
+#define RC5T583_REG_LDO7DAC_DS 0x6B
+#define RC5T583_REG_LDO8DAC_DS 0x6C
+#define RC5T583_REG_LDO9DAC_DS 0x6D
+
+/* GPIO register base address */
+#define RC5T583_GPIO_IOSEL     0xA0
+#define RC5T583_GPIO_PDEN      0xA1
+#define RC5T583_GPIO_IOOUT     0xA2
+#define RC5T583_GPIO_PGSEL     0xA3
+#define RC5T583_GPIO_GPINV     0xA4
+#define RC5T583_GPIO_GPDEB     0xA5
+#define RC5T583_GPIO_GPEDGE1   0xA6
+#define RC5T583_GPIO_GPEDGE2   0xA7
+#define RC5T583_GPIO_EN_INT    0xA8
+#define RC5T583_GPIO_MON_IOIN  0xAB
+#define RC5T583_GPIO_GPOFUNC   0xAC
+
+/* RICOH_RC5T583 IRQ definitions */
+enum {
+       RC5T583_IRQ_ONKEY,
+       RC5T583_IRQ_ACOK,
+       RC5T583_IRQ_LIDOPEN,
+       RC5T583_IRQ_PREOT,
+       RC5T583_IRQ_CLKSTP,
+       RC5T583_IRQ_ONKEY_OFF,
+       RC5T583_IRQ_WD,
+       RC5T583_IRQ_EN_PWRREQ1,
+       RC5T583_IRQ_EN_PWRREQ2,
+       RC5T583_IRQ_PRE_VINDET,
+
+       RC5T583_IRQ_DC0LIM,
+       RC5T583_IRQ_DC1LIM,
+       RC5T583_IRQ_DC2LIM,
+       RC5T583_IRQ_DC3LIM,
+
+       RC5T583_IRQ_CTC,
+       RC5T583_IRQ_YALE,
+       RC5T583_IRQ_DALE,
+       RC5T583_IRQ_WALE,
+
+       RC5T583_IRQ_AIN1L,
+       RC5T583_IRQ_AIN2L,
+       RC5T583_IRQ_AIN3L,
+       RC5T583_IRQ_VBATL,
+       RC5T583_IRQ_VIN3L,
+       RC5T583_IRQ_VIN8L,
+       RC5T583_IRQ_AIN1H,
+       RC5T583_IRQ_AIN2H,
+       RC5T583_IRQ_AIN3H,
+       RC5T583_IRQ_VBATH,
+       RC5T583_IRQ_VIN3H,
+       RC5T583_IRQ_VIN8H,
+       RC5T583_IRQ_ADCEND,
+
+       RC5T583_IRQ_GPIO0,
+       RC5T583_IRQ_GPIO1,
+       RC5T583_IRQ_GPIO2,
+       RC5T583_IRQ_GPIO3,
+       RC5T583_IRQ_GPIO4,
+       RC5T583_IRQ_GPIO5,
+       RC5T583_IRQ_GPIO6,
+       RC5T583_IRQ_GPIO7,
+
+       /* Should be last entry */
+       RC5T583_MAX_IRQS,
+};
+
+/* Ricoh583 gpio definitions */
+enum {
+       RC5T583_GPIO0,
+       RC5T583_GPIO1,
+       RC5T583_GPIO2,
+       RC5T583_GPIO3,
+       RC5T583_GPIO4,
+       RC5T583_GPIO5,
+       RC5T583_GPIO6,
+       RC5T583_GPIO7,
+
+       /* Should be last entry */
+       RC5T583_MAX_GPIO,
+};
+
+enum {
+       RC5T583_DS_NONE,
+       RC5T583_DS_DC0,
+       RC5T583_DS_DC1,
+       RC5T583_DS_DC2,
+       RC5T583_DS_DC3,
+       RC5T583_DS_LDO0,
+       RC5T583_DS_LDO1,
+       RC5T583_DS_LDO2,
+       RC5T583_DS_LDO3,
+       RC5T583_DS_LDO4,
+       RC5T583_DS_LDO5,
+       RC5T583_DS_LDO6,
+       RC5T583_DS_LDO7,
+       RC5T583_DS_LDO8,
+       RC5T583_DS_LDO9,
+       RC5T583_DS_PSO0,
+       RC5T583_DS_PSO1,
+       RC5T583_DS_PSO2,
+       RC5T583_DS_PSO3,
+       RC5T583_DS_PSO4,
+       RC5T583_DS_PSO5,
+       RC5T583_DS_PSO6,
+       RC5T583_DS_PSO7,
+
+       /* Should be last entry */
+       RC5T583_DS_MAX,
+};
+
+/*
+ * Ricoh pmic RC5T583 supports sleep through two external controls.
+ * The output of gpios and regulator can be enable/disable through
+ * this external signals.
+ */
+enum {
+       RC5T583_EXT_PWRREQ1_CONTROL = 0x1,
+       RC5T583_EXT_PWRREQ2_CONTROL = 0x2,
+};
+
+struct rc5t583 {
+       struct device   *dev;
+       struct regmap   *regmap;
+       int             chip_irq;
+       int             irq_base;
+       struct mutex    irq_lock;
+       unsigned long   group_irq_en[MAX_MAIN_INTERRUPT];
+
+       /* For main interrupt bits in INTC */
+       uint8_t         intc_inten_reg;
+
+       /* For group interrupt bits and address */
+       uint8_t         irq_en_reg[RC5T583_MAX_INTERRUPT_MASK_REGS];
+
+       /* For gpio edge */
+       uint8_t         gpedge_reg[RC5T583_MAX_GPEDGE_REG];
+};
+
+/*
+ * rc5t583_platform_data: Platform data for ricoh rc5t583 pmu.
+ * The board specific data is provided through this structure.
+ * @irq_base: Irq base number on which this device registers their interrupts.
+ * @enable_shutdown: Enable shutdown through the input pin "shutdown".
+ */
+
+struct rc5t583_platform_data {
+       int             irq_base;
+       bool            enable_shutdown;
+};
+
+int rc5t583_write(struct device *dev, u8 reg, uint8_t val);
+int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val);
+int rc5t583_set_bits(struct device *dev, unsigned int reg,
+               unsigned int bit_mask);
+int rc5t583_clear_bits(struct device *dev, unsigned int reg,
+               unsigned int bit_mask);
+int rc5t583_update(struct device *dev, unsigned int reg,
+               unsigned int val, unsigned int mask);
+int rc5t583_ext_power_req_config(struct device *dev, int deepsleep_id,
+       int ext_pwr_req, int deepsleep_slot_nr);
+int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base);
+int rc5t583_irq_exit(struct rc5t583 *rc5t583);
+
+#endif
index ca1d7a3..8516fd1 100644 (file)
@@ -8,7 +8,9 @@
 #ifndef __LINUX_MFD_STMPE_H
 #define __LINUX_MFD_STMPE_H
 
-#include <linux/device.h>
+#include <linux/mutex.h>
+
+struct device;
 
 enum stmpe_block {
        STMPE_BLOCK_GPIO        = 1 << 0,
@@ -26,6 +28,7 @@ enum stmpe_partnum {
        STMPE1601,
        STMPE2401,
        STMPE2403,
+       STMPE_NBR_PARTS
 };
 
 /*
index 16c76e1..3acb3a8 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef __LINUX_MFD_TC3589x_H
 #define __LINUX_MFD_TC3589x_H
 
-#include <linux/device.h>
+struct device;
 
 enum tx3589x_block {
        TC3589x_BLOCK_GPIO        = 1 << 0,
diff --git a/include/linux/mfd/tps65090.h b/include/linux/mfd/tps65090.h
new file mode 100644 (file)
index 0000000..38e31c5
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Core driver interface for TI TPS65090 PMIC family
+ *
+ * Copyright (C) 2012 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_TPS65090_H
+#define __LINUX_MFD_TPS65090_H
+
+struct tps65090_subdev_info {
+       int             id;
+       const char      *name;
+       void            *platform_data;
+};
+
+struct tps65090_platform_data {
+       int irq_base;
+       int num_subdevs;
+       struct tps65090_subdev_info *subdevs;
+};
+
+/*
+ * NOTE: the functions below are not intended for use outside
+ * of the TPS65090 sub-device drivers
+ */
+extern int tps65090_write(struct device *dev, int reg, uint8_t val);
+extern int tps65090_read(struct device *dev, int reg, uint8_t *val);
+extern int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num);
+extern int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num);
+
+#endif /*__LINUX_MFD_TPS65090_H */
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
new file mode 100644 (file)
index 0000000..e030ef9
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * linux/mfd/tps65217.h
+ *
+ * Functions to access TPS65217 power management chip.
+ *
+ * Copyright (C) 2011 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 __LINUX_MFD_TPS65217_H
+#define __LINUX_MFD_TPS65217_H
+
+#include <linux/i2c.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+/* I2C ID for TPS65217 part */
+#define TPS65217_I2C_ID                        0x24
+
+/* All register addresses */
+#define TPS65217_REG_CHIPID            0X00
+#define TPS65217_REG_PPATH             0X01
+#define TPS65217_REG_INT               0X02
+#define TPS65217_REG_CHGCONFIG0                0X03
+#define TPS65217_REG_CHGCONFIG1                0X04
+#define TPS65217_REG_CHGCONFIG2                0X05
+#define TPS65217_REG_CHGCONFIG3                0X06
+#define TPS65217_REG_WLEDCTRL1         0X07
+#define TPS65217_REG_WLEDCTRL2         0X08
+#define TPS65217_REG_MUXCTRL           0X09
+#define TPS65217_REG_STATUS            0X0A
+#define TPS65217_REG_PASSWORD          0X0B
+#define TPS65217_REG_PGOOD             0X0C
+#define TPS65217_REG_DEFPG             0X0D
+#define TPS65217_REG_DEFDCDC1          0X0E
+#define TPS65217_REG_DEFDCDC2          0X0F
+#define TPS65217_REG_DEFDCDC3          0X10
+#define TPS65217_REG_DEFSLEW           0X11
+#define TPS65217_REG_DEFLDO1           0X12
+#define TPS65217_REG_DEFLDO2           0X13
+#define TPS65217_REG_DEFLS1            0X14
+#define TPS65217_REG_DEFLS2            0X15
+#define TPS65217_REG_ENABLE            0X16
+#define TPS65217_REG_DEFUVLO           0X18
+#define TPS65217_REG_SEQ1              0X19
+#define TPS65217_REG_SEQ2              0X1A
+#define TPS65217_REG_SEQ3              0X1B
+#define TPS65217_REG_SEQ4              0X1C
+#define TPS65217_REG_SEQ5              0X1D
+#define TPS65217_REG_SEQ6              0X1E
+
+/* Register field definitions */
+#define TPS65217_CHIPID_CHIP_MASK      0xF0
+#define TPS65217_CHIPID_REV_MASK       0x0F
+
+#define TPS65217_PPATH_ACSINK_ENABLE   BIT(7)
+#define TPS65217_PPATH_USBSINK_ENABLE  BIT(6)
+#define TPS65217_PPATH_AC_PW_ENABLE    BIT(5)
+#define TPS65217_PPATH_USB_PW_ENABLE   BIT(4)
+#define TPS65217_PPATH_AC_CURRENT_MASK 0x0C
+#define TPS65217_PPATH_USB_CURRENT_MASK        0x03
+
+#define TPS65217_INT_PBM               BIT(6)
+#define TPS65217_INT_ACM               BIT(5)
+#define TPS65217_INT_USBM              BIT(4)
+#define TPS65217_INT_PBI               BIT(2)
+#define TPS65217_INT_ACI               BIT(1)
+#define TPS65217_INT_USBI              BIT(0)
+
+#define TPS65217_CHGCONFIG0_TREG       BIT(7)
+#define TPS65217_CHGCONFIG0_DPPM       BIT(6)
+#define TPS65217_CHGCONFIG0_TSUSP      BIT(5)
+#define TPS65217_CHGCONFIG0_TERMI      BIT(4)
+#define TPS65217_CHGCONFIG0_ACTIVE     BIT(3)
+#define TPS65217_CHGCONFIG0_CHGTOUT    BIT(2)
+#define TPS65217_CHGCONFIG0_PCHGTOUT   BIT(1)
+#define TPS65217_CHGCONFIG0_BATTEMP    BIT(0)
+
+#define TPS65217_CHGCONFIG1_TMR_MASK   0xC0
+#define TPS65217_CHGCONFIG1_TMR_ENABLE BIT(5)
+#define TPS65217_CHGCONFIG1_NTC_TYPE   BIT(4)
+#define TPS65217_CHGCONFIG1_RESET      BIT(3)
+#define TPS65217_CHGCONFIG1_TERM       BIT(2)
+#define TPS65217_CHGCONFIG1_SUSP       BIT(1)
+#define TPS65217_CHGCONFIG1_CHG_EN     BIT(0)
+
+#define TPS65217_CHGCONFIG2_DYNTMR     BIT(7)
+#define TPS65217_CHGCONFIG2_VPREGHG    BIT(6)
+#define TPS65217_CHGCONFIG2_VOREG_MASK 0x30
+
+#define TPS65217_CHGCONFIG3_ICHRG_MASK 0xC0
+#define TPS65217_CHGCONFIG3_DPPMTH_MASK        0x30
+#define TPS65217_CHGCONFIG2_PCHRGT     BIT(3)
+#define TPS65217_CHGCONFIG2_TERMIF     0x06
+#define TPS65217_CHGCONFIG2_TRANGE     BIT(0)
+
+#define TPS65217_WLEDCTRL1_ISINK_ENABLE        BIT(3)
+#define TPS65217_WLEDCTRL1_ISEL                BIT(2)
+#define TPS65217_WLEDCTRL1_FDIM_MASK   0x03
+
+#define TPS65217_WLEDCTRL2_DUTY_MASK   0x7F
+
+#define TPS65217_MUXCTRL_MUX_MASK      0x07
+
+#define TPS65217_STATUS_OFF            BIT(7)
+#define TPS65217_STATUS_ACPWR          BIT(3)
+#define TPS65217_STATUS_USBPWR         BIT(2)
+#define TPS65217_STATUS_PB             BIT(0)
+
+#define TPS65217_PASSWORD_REGS_UNLOCK  0x7D
+
+#define TPS65217_PGOOD_LDO3_PG         BIT(6)
+#define TPS65217_PGOOD_LDO4_PG         BIT(5)
+#define TPS65217_PGOOD_DC1_PG          BIT(4)
+#define TPS65217_PGOOD_DC2_PG          BIT(3)
+#define TPS65217_PGOOD_DC3_PG          BIT(2)
+#define TPS65217_PGOOD_LDO1_PG         BIT(1)
+#define TPS65217_PGOOD_LDO2_PG         BIT(0)
+
+#define TPS65217_DEFPG_LDO1PGM         BIT(3)
+#define TPS65217_DEFPG_LDO2PGM         BIT(2)
+#define TPS65217_DEFPG_PGDLY_MASK      0x03
+
+#define TPS65217_DEFDCDCX_XADJX                BIT(7)
+#define TPS65217_DEFDCDCX_DCDC_MASK    0x3F
+
+#define TPS65217_DEFSLEW_GO            BIT(7)
+#define TPS65217_DEFSLEW_GODSBL                BIT(6)
+#define TPS65217_DEFSLEW_PFM_EN1       BIT(5)
+#define TPS65217_DEFSLEW_PFM_EN2       BIT(4)
+#define TPS65217_DEFSLEW_PFM_EN3       BIT(3)
+#define TPS65217_DEFSLEW_SLEW_MASK     0x07
+
+#define TPS65217_DEFLDO1_LDO1_MASK     0x0F
+
+#define TPS65217_DEFLDO2_TRACK         BIT(6)
+#define TPS65217_DEFLDO2_LDO2_MASK     0x3F
+
+#define TPS65217_DEFLDO3_LDO3_EN       BIT(5)
+#define TPS65217_DEFLDO3_LDO3_MASK     0x1F
+
+#define TPS65217_DEFLDO4_LDO4_EN       BIT(5)
+#define TPS65217_DEFLDO4_LDO4_MASK     0x1F
+
+#define TPS65217_ENABLE_LS1_EN         BIT(6)
+#define TPS65217_ENABLE_LS2_EN         BIT(5)
+#define TPS65217_ENABLE_DC1_EN         BIT(4)
+#define TPS65217_ENABLE_DC2_EN         BIT(3)
+#define TPS65217_ENABLE_DC3_EN         BIT(2)
+#define TPS65217_ENABLE_LDO1_EN                BIT(1)
+#define TPS65217_ENABLE_LDO2_EN                BIT(0)
+
+#define TPS65217_DEFUVLO_UVLOHYS       BIT(2)
+#define TPS65217_DEFUVLO_UVLO_MASK     0x03
+
+#define TPS65217_SEQ1_DC1_SEQ_MASK     0xF0
+#define TPS65217_SEQ1_DC2_SEQ_MASK     0x0F
+
+#define TPS65217_SEQ2_DC3_SEQ_MASK     0xF0
+#define TPS65217_SEQ2_LDO1_SEQ_MASK    0x0F
+
+#define TPS65217_SEQ3_LDO2_SEQ_MASK    0xF0
+#define TPS65217_SEQ3_LDO3_SEQ_MASK    0x0F
+
+#define TPS65217_SEQ4_LDO4_SEQ_MASK    0xF0
+
+#define TPS65217_SEQ5_DLY1_MASK                0xC0
+#define TPS65217_SEQ5_DLY2_MASK                0x30
+#define TPS65217_SEQ5_DLY3_MASK                0x0C
+#define TPS65217_SEQ5_DLY4_MASK                0x03
+
+#define TPS65217_SEQ6_DLY5_MASK                0xC0
+#define TPS65217_SEQ6_DLY6_MASK                0x30
+#define TPS65217_SEQ6_SEQUP            BIT(2)
+#define TPS65217_SEQ6_SEQDWN           BIT(1)
+#define TPS65217_SEQ6_INSTDWN          BIT(0)
+
+#define TPS65217_MAX_REGISTER          0x1E
+#define TPS65217_PROTECT_NONE          0
+#define TPS65217_PROTECT_L1            1
+#define TPS65217_PROTECT_L2            2
+
+
+enum tps65217_regulator_id {
+       /* DCDC's */
+       TPS65217_DCDC_1,
+       TPS65217_DCDC_2,
+       TPS65217_DCDC_3,
+       /* LDOs */
+       TPS65217_LDO_1,
+       TPS65217_LDO_2,
+       TPS65217_LDO_3,
+       TPS65217_LDO_4,
+};
+
+#define TPS65217_MAX_REG_ID            TPS65217_LDO_4
+
+/* Number of step-down converters available */
+#define TPS65217_NUM_DCDC              3
+/* Number of LDO voltage regulators available */
+#define TPS65217_NUM_LDO               4
+/* Number of total regulators available */
+#define TPS65217_NUM_REGULATOR         (TPS65217_NUM_DCDC + TPS65217_NUM_LDO)
+
+/**
+ * struct tps65217_board - packages regulator init data
+ * @tps65217_regulator_data: regulator initialization values
+ *
+ * Board data may be used to initialize regulator.
+ */
+struct tps65217_board {
+       struct regulator_init_data *tps65217_init_data;
+};
+
+/**
+ * struct tps_info - packages regulator constraints
+ * @name:              Voltage regulator name
+ * @min_uV:            minimum micro volts
+ * @max_uV:            minimum micro volts
+ * @vsel_to_uv:                Function pointer to get voltage from selector
+ * @uv_to_vsel:                Function pointer to get selector from voltage
+ * @table:             Table for non-uniform voltage step-size
+ * @table_len:         Length of the voltage table
+ * @enable_mask:       Regulator enable mask bits
+ * @set_vout_reg:      Regulator output voltage set register
+ * @set_vout_mask:     Regulator output voltage set mask
+ *
+ * This data is used to check the regualtor voltage limits while setting.
+ */
+struct tps_info {
+       const char *name;
+       int min_uV;
+       int max_uV;
+       int (*vsel_to_uv)(unsigned int vsel);
+       int (*uv_to_vsel)(int uV, unsigned int *vsel);
+       const int *table;
+       unsigned int table_len;
+       unsigned int enable_mask;
+       unsigned int set_vout_reg;
+       unsigned int set_vout_mask;
+};
+
+/**
+ * struct tps65217 - tps65217 sub-driver chip access routines
+ *
+ * Device data may be used to access the TPS65217 chip
+ */
+
+struct tps65217 {
+       struct device *dev;
+       struct tps65217_board *pdata;
+       struct regulator_desc desc[TPS65217_NUM_REGULATOR];
+       struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
+       struct tps_info *info[TPS65217_NUM_REGULATOR];
+       struct regmap *regmap;
+
+       /* Client devices */
+       struct platform_device *regulator_pdev[TPS65217_NUM_REGULATOR];
+};
+
+static inline struct tps65217 *dev_to_tps65217(struct device *dev)
+{
+       return dev_get_drvdata(dev);
+}
+
+int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
+                                       unsigned int *val);
+int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
+                       unsigned int val, unsigned int level);
+int tps65217_set_bits(struct tps65217 *tps, unsigned int reg,
+               unsigned int mask, unsigned int val, unsigned int level);
+int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
+               unsigned int mask, unsigned int level);
+
+#endif /*  __LINUX_MFD_TPS65217_H */
index 76700b5..1c6c286 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef __LINUX_MFD_TPS65910_H
 #define __LINUX_MFD_TPS65910_H
 
+#include <linux/gpio.h>
+
 /* TPS chip id list */
 #define TPS65910                       0
 #define TPS65911                       1
 
 
 /*Register GPIO  (0x80) register.RegisterDescription */
+#define GPIO_SLEEP_MASK                         0x80
+#define GPIO_SLEEP_SHIFT                        7
 #define GPIO_DEB_MASK                           0x10
 #define GPIO_DEB_SHIFT                          4
 #define GPIO_PUEN_MASK                          0x08
 #define TPS65910_GPIO_STS                              BIT(1)
 #define TPS65910_GPIO_SET                              BIT(0)
 
+/* Max number of TPS65910/11 GPIOs */
+#define TPS65910_NUM_GPIO                              6
+#define TPS65911_NUM_GPIO                              9
+#define TPS6591X_MAX_NUM_GPIO                          9
+
 /* Regulator Index Definitions */
 #define TPS65910_REG_VRTC                              0
 #define TPS65910_REG_VIO                               1
@@ -785,6 +794,7 @@ struct tps65910_board {
        int irq_base;
        int vmbch_threshold;
        int vmbch2_threshold;
+       bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO];
        unsigned long regulator_ext_sleep_control[TPS65910_NUM_REGS];
        struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS];
 };
@@ -796,6 +806,7 @@ struct tps65910_board {
 struct tps65910 {
        struct device *dev;
        struct i2c_client *i2c_client;
+       struct regmap *regmap;
        struct mutex io_mutex;
        unsigned int id;
        int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest);
index 4321f04..28af417 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/mfd/mcp.h>
 #include <linux/gpio.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
 
 #define UCB_IO_DATA    0x00
 #define UCB_IO_DIR     0x01
 #define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
 #define UCB_MODE_AUD_OFF_CAN   (1 << 13)
 
+enum ucb1x00_reset {
+       UCB_RST_PROBE,
+       UCB_RST_RESUME,
+       UCB_RST_SUSPEND,
+       UCB_RST_REMOVE,
+       UCB_RST_PROBE_FAIL,
+};
 
-struct ucb1x00_irq {
-       void *devid;
-       void (*fn)(int, void *);
+struct ucb1x00_plat_data {
+       void                    (*reset)(enum ucb1x00_reset);
+       unsigned                irq_base;
+       int                     gpio_base;
+       unsigned                can_wakeup;
 };
 
 struct ucb1x00 {
-       spinlock_t              lock;
+       raw_spinlock_t          irq_lock;
        struct mcp              *mcp;
        unsigned int            irq;
-       struct semaphore        adc_sem;
+       int                     irq_base;
+       struct mutex            adc_mutex;
        spinlock_t              io_lock;
        u16                     id;
        u16                     io_dir;
@@ -122,7 +132,8 @@ struct ucb1x00 {
        u16                     adc_cr;
        u16                     irq_fal_enbl;
        u16                     irq_ris_enbl;
-       struct ucb1x00_irq      irq_handler[16];
+       u16                     irq_mask;
+       u16                     irq_wake;
        struct device           dev;
        struct list_head        node;
        struct list_head        devs;
@@ -144,7 +155,7 @@ struct ucb1x00_driver {
        struct list_head        devs;
        int     (*add)(struct ucb1x00_dev *dev);
        void    (*remove)(struct ucb1x00_dev *dev);
-       int     (*suspend)(struct ucb1x00_dev *dev, pm_message_t state);
+       int     (*suspend)(struct ucb1x00_dev *dev);
        int     (*resume)(struct ucb1x00_dev *dev);
 };
 
@@ -245,15 +256,4 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
 void ucb1x00_adc_enable(struct ucb1x00 *ucb);
 void ucb1x00_adc_disable(struct ucb1x00 *ucb);
 
-/*
- * Which edges of the IRQ do you want to control today?
- */
-#define UCB_RISING     (1 << 0)
-#define UCB_FALLING    (1 << 1)
-
-int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
-void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
-void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
-int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
-
 #endif
index dc3e050..893267b 100644 (file)
@@ -22,7 +22,6 @@ struct wm8994_ldo_pdata {
        /** GPIOs to enable regulator, 0 or less if not available */
        int enable;
 
-       const char *supply;
        const struct regulator_init_data *init_data;
 };
 
index e1eebf7..5f1298b 100644 (file)
@@ -33,7 +33,6 @@
 #ifndef MLX4_DRIVER_H
 #define MLX4_DRIVER_H
 
-#include <linux/device.h>
 #include <linux/mlx4/device.h>
 
 struct mlx4_dev;
index 69f6d7b..f2a60dd 100644 (file)
@@ -6,6 +6,7 @@
 #ifdef __KERNEL__
 
 #include <linux/gfp.h>
+#include <linux/bug.h>
 #include <linux/list.h>
 #include <linux/mmzone.h>
 #include <linux/rbtree.h>
@@ -111,7 +112,7 @@ extern unsigned int kobjsize(const void *objp);
 #define VM_HUGEPAGE    0x01000000      /* MADV_HUGEPAGE marked this vma */
 #endif
 #define VM_INSERTPAGE  0x02000000      /* The vma has had "vm_insert_page()" done on it */
-#define VM_ALWAYSDUMP  0x04000000      /* Always include in core dumps */
+#define VM_NODUMP      0x04000000      /* Do not include in the core dump */
 
 #define VM_CAN_NONLINEAR 0x08000000    /* Has ->fault & does nonlinear pages */
 #define VM_MIXEDMAP    0x10000000      /* Can contain "struct page" and pure PFN pages */
index 19a41d1..6faa145 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef LINUX_MMC_CARD_H
 #define LINUX_MMC_CARD_H
 
+#include <linux/device.h>
 #include <linux/mmc/core.h>
 #include <linux/mod_devicetable.h>
 
index 87a976c..2e6a681 100644 (file)
@@ -9,7 +9,7 @@
 #define LINUX_MMC_CORE_H
 
 #include <linux/interrupt.h>
-#include <linux/device.h>
+#include <linux/completion.h>
 
 struct request;
 struct mmc_data;
index ee2b036..91924e8 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/leds.h>
 #include <linux/sched.h>
+#include <linux/device.h>
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
index 8fa5bc5..1f5e689 100644 (file)
@@ -1,5 +1,8 @@
 #ifndef LINUX_MMC_IOCTL_H
 #define LINUX_MMC_IOCTL_H
+
+#include <linux/types.h>
+
 struct mmc_ioc_cmd {
        /* Implies direction of data.  true = write, false = read */
        int write_flag;
index fb69ad1..501da4c 100644 (file)
@@ -414,6 +414,15 @@ struct hv_vmbus_device_id {
                        __attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
+/* rpmsg */
+
+#define RPMSG_NAME_SIZE                        32
+#define RPMSG_DEVICE_MODALIAS_FMT      "rpmsg:%s"
+
+struct rpmsg_device_id {
+       char name[RPMSG_NAME_SIZE];
+};
+
 /* i2c */
 
 #define I2C_NAME_SIZE  20
index 4598bf0..fbcafe2 100644 (file)
@@ -21,8 +21,6 @@
 #include <linux/percpu.h>
 #include <asm/module.h>
 
-#include <trace/events/module.h>
-
 /* Not Yet Implemented */
 #define MODULE_SUPPORTED_DEVICE(name)
 
@@ -452,33 +450,11 @@ void symbol_put_addr(void *addr);
 
 /* Sometimes we know we already have a refcount, and it's easier not
    to handle the error case (which only happens with rmmod --wait). */
-static inline void __module_get(struct module *module)
-{
-       if (module) {
-               preempt_disable();
-               __this_cpu_inc(module->refptr->incs);
-               trace_module_get(module, _THIS_IP_);
-               preempt_enable();
-       }
-}
-
-static inline int try_module_get(struct module *module)
-{
-       int ret = 1;
-
-       if (module) {
-               preempt_disable();
+extern void __module_get(struct module *module);
 
-               if (likely(module_is_live(module))) {
-                       __this_cpu_inc(module->refptr->incs);
-                       trace_module_get(module, _THIS_IP_);
-               } else
-                       ret = 0;
-
-               preempt_enable();
-       }
-       return ret;
-}
+/* This is the Right Way to get a module: if it fails, it's being removed,
+ * so pretend it's not there. */
+extern bool try_module_get(struct module *module);
 
 extern void module_put(struct module *module);
 
index c47f4d6..ea36486 100644 (file)
@@ -47,14 +47,11 @@ struct kernel_param_ops {
        void (*free)(void *arg);
 };
 
-/* Flag bits for kernel_param.flags */
-#define KPARAM_ISBOOL          2
-
 struct kernel_param {
        const char *name;
        const struct kernel_param_ops *ops;
        u16 perm;
-       u16 flags;
+       s16 level;
        union {
                void *arg;
                const struct kparam_string *str;
@@ -131,8 +128,40 @@ struct kparam_array
  * The ops can have NULL set or get functions.
  */
 #define module_param_cb(name, ops, arg, perm)                                \
-       __module_param_call(MODULE_PARAM_PREFIX,                              \
-                           name, ops, arg, __same_type((arg), bool *), perm)
+       __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, 0)
+
+/**
+ * <level>_param_cb - general callback for a module/cmdline parameter
+ *                    to be evaluated before certain initcall level
+ * @name: a valid C identifier which is the parameter name.
+ * @ops: the set & get operations for this parameter.
+ * @perm: visibility in sysfs.
+ *
+ * The ops can have NULL set or get functions.
+ */
+#define __level_param_cb(name, ops, arg, perm, level)                  \
+       __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, level)
+
+#define core_param_cb(name, ops, arg, perm)            \
+       __level_param_cb(name, ops, arg, perm, 1)
+
+#define postcore_param_cb(name, ops, arg, perm)                \
+       __level_param_cb(name, ops, arg, perm, 2)
+
+#define arch_param_cb(name, ops, arg, perm)            \
+       __level_param_cb(name, ops, arg, perm, 3)
+
+#define subsys_param_cb(name, ops, arg, perm)          \
+       __level_param_cb(name, ops, arg, perm, 4)
+
+#define fs_param_cb(name, ops, arg, perm)              \
+       __level_param_cb(name, ops, arg, perm, 5)
+
+#define device_param_cb(name, ops, arg, perm)          \
+       __level_param_cb(name, ops, arg, perm, 6)
+
+#define late_param_cb(name, ops, arg, perm)            \
+       __level_param_cb(name, ops, arg, perm, 7)
 
 /* On alpha, ia64 and ppc64 relocations to global data cannot go into
    read-only sections (which is part of respective UNIX ABI on these
@@ -146,7 +175,7 @@ struct kparam_array
 
 /* This is the fundamental function for registering boot/module
    parameters. */
-#define __module_param_call(prefix, name, ops, arg, isbool, perm)      \
+#define __module_param_call(prefix, name, ops, arg, perm, level)       \
        /* Default value instead of permissions? */                     \
        static int __param_perm_check_##name __attribute__((unused)) =  \
        BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2))  \
@@ -155,8 +184,7 @@ struct kparam_array
        static struct kernel_param __moduleparam_const __param_##name   \
        __used                                                          \
     __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
-       = { __param_str_##name, ops, perm, isbool ? KPARAM_ISBOOL : 0,  \
-           { arg } }
+       = { __param_str_##name, ops, perm, level, { arg } }
 
 /* Obsolete - use module_param_cb() */
 #define module_param_call(name, set, get, arg, perm)                   \
@@ -164,8 +192,7 @@ struct kparam_array
                 { (void *)set, (void *)get };                          \
        __module_param_call(MODULE_PARAM_PREFIX,                        \
                            name, &__param_ops_##name, arg,             \
-                           __same_type(arg, bool *),                   \
-                           (perm) + sizeof(__check_old_set_param(set))*0)
+                           (perm) + sizeof(__check_old_set_param(set))*0, 0)
 
 /* We don't get oldget: it's often a new-style param_get_uint, etc. */
 static inline int
@@ -245,8 +272,7 @@ static inline void __kernel_param_unlock(void)
  */
 #define core_param(name, var, type, perm)                              \
        param_check_##type(name, &(var));                               \
-       __module_param_call("", name, &param_ops_##type,                \
-                           &var, __same_type(var, bool), perm)
+       __module_param_call("", name, &param_ops_##type, &var, perm, 0)
 #endif /* !MODULE */
 
 /**
@@ -264,7 +290,7 @@ static inline void __kernel_param_unlock(void)
                = { len, string };                                      \
        __module_param_call(MODULE_PARAM_PREFIX, name,                  \
                            &param_ops_string,                          \
-                           .str = &__param_string_##name, 0, perm);    \
+                           .str = &__param_string_##name, perm, 0);    \
        __MODULE_PARM_TYPE(name, "string")
 
 /**
@@ -292,6 +318,8 @@ extern int parse_args(const char *name,
                      char *args,
                      const struct kernel_param *params,
                      unsigned num,
+                     s16 level_min,
+                     s16 level_max,
                      int (*unknown)(char *param, char *val));
 
 /* Called by module remove. */
@@ -403,7 +431,7 @@ extern int param_set_bint(const char *val, const struct kernel_param *kp);
        __module_param_call(MODULE_PARAM_PREFIX, name,                  \
                            &param_array_ops,                           \
                            .arr = &__param_arr_##name,                 \
-                           __same_type(array[0], bool), perm);         \
+                           perm, 0);                                   \
        __MODULE_PARM_TYPE(name, "array of " #type)
 
 extern struct kernel_param_ops param_array_ops;
index d5d2ec6..37ef6b1 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/delay.h>
 #include <linux/types.h>
+#include <linux/bug.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/flashchip.h>
 #include <linux/mtd/map.h>
index 8debe29..1f77540 100644 (file)
 #ifdef __KERNEL__
 #include <linux/pm_qos.h>
 #include <linux/timer.h>
+#include <linux/bug.h>
 #include <linux/delay.h>
 #include <linux/atomic.h>
 #include <asm/cache.h>
 #include <asm/byteorder.h>
 
-#include <linux/device.h>
 #include <linux/percpu.h>
 #include <linux/rculist.h>
 #include <linux/dmaengine.h>
@@ -56,6 +56,7 @@
 #include <linux/netdev_features.h>
 
 struct netpoll_info;
+struct device;
 struct phy_device;
 /* 802.11 specific */
 struct wireless_dev;
index 8c6ee44..6d1fb63 100644 (file)
@@ -29,7 +29,7 @@
 #define NFS_MNT_VERSION                1
 #define NFS_MNT3_VERSION       3
 
-#define NFS_PIPE_DIRNAME "/nfs"
+#define NFS_PIPE_DIRNAME "nfs"
 
 /*
  * NFS stats. The good thing with these values is that NFSv3 errors are
index 32345c2..834df8b 100644 (file)
@@ -183,15 +183,12 @@ struct nfs4_acl {
 
 typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
 
-struct nfs41_stateid {
+struct nfs_stateid4 {
        __be32 seqid;
        char other[NFS4_STATEID_OTHER_SIZE];
 } __attribute__ ((packed));
 
-typedef union {
-       char data[NFS4_STATEID_SIZE];
-       struct nfs41_stateid stateid;
-} nfs4_stateid;
+typedef struct nfs_stateid4 nfs4_stateid;
 
 enum nfs_opnum4 {
        OP_ACCESS = 3,
index 8c29950..52a1bdb 100644 (file)
 
 #ifdef __KERNEL__
 
+/*
+ * Enable dprintk() debugging support for nfs client.
+ */
+#ifdef CONFIG_NFS_DEBUG
+# define NFS_DEBUG
+#endif
+
 #include <linux/in.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
@@ -171,13 +178,9 @@ struct nfs_inode {
         */
        __be32                  cookieverf[2];
 
-       /*
-        * This is the list of dirty unwritten pages.
-        */
-       struct radix_tree_root  nfs_page_tree;
-
        unsigned long           npages;
        unsigned long           ncommit;
+       struct list_head        commit_list;
 
        /* Open contexts for shared mmap writes */
        struct list_head        open_files;
@@ -395,6 +398,29 @@ static inline void nfs_free_fhandle(const struct nfs_fh *fh)
        kfree(fh);
 }
 
+#ifdef NFS_DEBUG
+extern u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh);
+static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh)
+{
+       return _nfs_display_fhandle_hash(fh);
+}
+extern void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption);
+#define nfs_display_fhandle(fh, caption)                       \
+       do {                                                    \
+               if (unlikely(nfs_debug & NFSDBG_FACILITY))      \
+                       _nfs_display_fhandle(fh, caption);      \
+       } while (0)
+#else
+static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh)
+{
+       return 0;
+}
+static inline void nfs_display_fhandle(const struct nfs_fh *fh,
+                                      const char *caption)
+{
+}
+#endif
+
 /*
  * linux/fs/nfs/nfsroot.c
  */
@@ -632,19 +658,13 @@ nfs_fileid_to_ino_t(u64 fileid)
 
 #ifdef __KERNEL__
 
-/*
- * Enable debugging support for nfs client.
- * Requires RPC_DEBUG.
- */
-#ifdef RPC_DEBUG
-# define NFS_DEBUG
-#endif
-
 # undef ifdebug
 # ifdef NFS_DEBUG
 #  define ifdebug(fac)         if (unlikely(nfs_debug & NFSDBG_##fac))
+#  define NFS_IFDEBUG(x)       x
 # else
 #  define ifdebug(fac)         if (0)
+#  define NFS_IFDEBUG(x)
 # endif
 #endif /* __KERNEL */
 
index 8617302..a5c50d9 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef _NFS_FS_I
 #define _NFS_FS_I
 
-#include <asm/types.h>
-#include <linux/list.h>
-#include <linux/nfs.h>
-
 struct nlm_lockowner;
 
 /*
index ba4d765..7073fc7 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/list.h>
 #include <linux/backing-dev.h>
+#include <linux/idr.h>
 #include <linux/wait.h>
 #include <linux/nfs_xdr.h>
 #include <linux/sunrpc/xprt.h>
@@ -17,6 +18,7 @@ struct nfs4_sequence_res;
 struct nfs_server;
 struct nfs4_minor_version_ops;
 struct server_scope;
+struct nfs41_impl_id;
 
 /*
  * The nfs_client identifies our client state to the server.
@@ -85,6 +87,8 @@ struct nfs_client {
 #endif
 
        struct server_scope     *server_scope;  /* from exchange_id */
+       struct nfs41_impl_id    *impl_id;       /* from exchange_id */
+       struct net              *net;
 };
 
 /*
@@ -144,15 +148,18 @@ struct nfs_server {
        u32                     acl_bitmask;    /* V4 bitmask representing the ACEs
                                                   that are supported on this
                                                   filesystem */
+       u32                     fh_expire_type; /* V4 bitmask representing file
+                                                  handle volatility type for
+                                                  this filesystem */
        struct pnfs_layoutdriver_type  *pnfs_curr_ld; /* Active layout driver */
        struct rpc_wait_queue   roc_rpcwaitq;
        void                    *pnfs_ld_data;  /* per mount point data */
 
        /* the following fields are protected by nfs_client->cl_lock */
        struct rb_root          state_owners;
-       struct rb_root          openowner_id;
-       struct rb_root          lockowner_id;
 #endif
+       struct ida              openowner_id;
+       struct ida              lockowner_id;
        struct list_head        state_owners_lru;
        struct list_head        layouts;
        struct list_head        delegations;
@@ -188,21 +195,23 @@ struct nfs_server {
 
 
 /* maximum number of slots to use */
-#define NFS4_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE
+#define NFS4_DEF_SLOT_TABLE_SIZE (16U)
+#define NFS4_MAX_SLOT_TABLE (256U)
+#define NFS4_NO_SLOT ((u32)-1)
 
 #if defined(CONFIG_NFS_V4)
 
 /* Sessions */
-#define SLOT_TABLE_SZ (NFS4_MAX_SLOT_TABLE/(8*sizeof(long)))
+#define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long))
 struct nfs4_slot_table {
        struct nfs4_slot *slots;                /* seqid per slot */
        unsigned long   used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */
        spinlock_t      slot_tbl_lock;
        struct rpc_wait_queue   slot_tbl_waitq; /* allocators may wait here */
-       int             max_slots;              /* # slots in table */
-       int             highest_used_slotid;    /* sent to server on each SEQ.
+       u32             max_slots;              /* # slots in table */
+       u32             highest_used_slotid;    /* sent to server on each SEQ.
                                                 * op for dynamic resizing */
-       int             target_max_slots;       /* Set by CB_RECALL_SLOT as
+       u32             target_max_slots;       /* Set by CB_RECALL_SLOT as
                                                 * the new max_slots */
        struct completion complete;
 };
index 308c188..7eed201 100644 (file)
@@ -69,36 +69,22 @@ struct nfs_server;
 struct nfs_fattr;
 struct nfs4_string;
 
-#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
-
+#ifdef CONFIG_NFS_V4
 int nfs_idmap_init(void);
 void nfs_idmap_quit(void);
-
-static inline int nfs_idmap_new(struct nfs_client *clp)
-{
-       return 0;
-}
-
-static inline void nfs_idmap_delete(struct nfs_client *clp)
-{
-}
-
-#else /* CONFIG_NFS_USE_NEW_IDMAPPER not set */
-
+#else
 static inline int nfs_idmap_init(void)
 {
        return 0;
 }
 
 static inline void nfs_idmap_quit(void)
-{
-}
+{}
+#endif
 
 int nfs_idmap_new(struct nfs_client *);
 void nfs_idmap_delete(struct nfs_client *);
 
-#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
-
 void nfs_fattr_init_names(struct nfs_fattr *fattr,
                struct nfs4_string *owner_name,
                struct nfs4_string *group_name);
index 8866bb3..9dcbbe9 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef _LINUX_NFS_IOSTAT
 #define _LINUX_NFS_IOSTAT
 
-#define NFS_IOSTAT_VERS                "1.0"
+#define NFS_IOSTAT_VERS                "1.1"
 
 /*
  * NFS byte counters
index ab465fe..eac30d6 100644 (file)
 #include <linux/kref.h>
 
 /*
- * Valid flags for the radix tree
- */
-#define NFS_PAGE_TAG_LOCKED    0
-#define NFS_PAGE_TAG_COMMIT    1
-
-/*
  * Valid flags for a dirty buffer
  */
 enum {
@@ -33,16 +27,13 @@ enum {
        PG_CLEAN,
        PG_NEED_COMMIT,
        PG_NEED_RESCHED,
-       PG_PNFS_COMMIT,
        PG_PARTIAL_READ_FAILED,
+       PG_COMMIT_TO_DS,
 };
 
 struct nfs_inode;
 struct nfs_page {
-       union {
-               struct list_head        wb_list;        /* Defines state of page: */
-               struct pnfs_layout_segment *wb_commit_lseg; /* Used when PG_PNFS_COMMIT set */
-       };
+       struct list_head        wb_list;        /* Defines state of page: */
        struct page             *wb_page;       /* page to read in/write out */
        struct nfs_open_context *wb_context;    /* File state context info */
        struct nfs_lock_context *wb_lock_context;       /* lock context info */
@@ -90,8 +81,6 @@ extern        struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
 extern void nfs_release_request(struct nfs_page *req);
 
 
-extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst,
-                         pgoff_t idx_start, unsigned int npages, int tag);
 extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
                             struct inode *inode,
                             const struct nfs_pageio_ops *pg_ops,
@@ -106,8 +95,6 @@ extern bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc,
                                struct nfs_page *req);
 extern  int nfs_wait_on_request(struct nfs_page *);
 extern void nfs_unlock_request(struct nfs_page *req);
-extern int nfs_set_page_tag_locked(struct nfs_page *req);
-extern  void nfs_clear_page_tag_locked(struct nfs_page *req);
 
 /*
  * Lock the page of an asynchronous request without getting a new reference
@@ -118,6 +105,16 @@ nfs_lock_request_dontget(struct nfs_page *req)
        return !test_and_set_bit(PG_BUSY, &req->wb_flags);
 }
 
+static inline int
+nfs_lock_request(struct nfs_page *req)
+{
+       if (test_and_set_bit(PG_BUSY, &req->wb_flags))
+               return 0;
+       kref_get(&req->wb_kref);
+       return 1;
+}
+
+
 /**
  * nfs_list_add_request - Insert a request into a list
  * @req: request
index d6ba9a1..bfd0d1b 100644 (file)
@@ -2,7 +2,6 @@
 #define _LINUX_NFS_XDR_H
 
 #include <linux/nfsacl.h>
-#include <linux/nfs3.h>
 #include <linux/sunrpc/gss_api.h>
 
 /*
@@ -89,11 +88,12 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR_PRECTIME                (1U << 16)
 #define NFS_ATTR_FATTR_CHANGE          (1U << 17)
 #define NFS_ATTR_FATTR_PRECHANGE       (1U << 18)
-#define NFS_ATTR_FATTR_V4_REFERRAL     (1U << 19)      /* NFSv4 referral */
-#define NFS_ATTR_FATTR_MOUNTPOINT      (1U << 20)      /* Treat as mountpoint */
-#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID               (1U << 21)
-#define NFS_ATTR_FATTR_OWNER_NAME      (1U << 22)
-#define NFS_ATTR_FATTR_GROUP_NAME      (1U << 23)
+#define NFS_ATTR_FATTR_V4_LOCATIONS    (1U << 19)
+#define NFS_ATTR_FATTR_V4_REFERRAL     (1U << 20)
+#define NFS_ATTR_FATTR_MOUNTPOINT      (1U << 21)
+#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22)
+#define NFS_ATTR_FATTR_OWNER_NAME      (1U << 23)
+#define NFS_ATTR_FATTR_GROUP_NAME      (1U << 24)
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
                | NFS_ATTR_FATTR_MODE \
@@ -182,7 +182,7 @@ struct nfs4_slot {
 
 struct nfs4_sequence_args {
        struct nfs4_session     *sa_session;
-       u8                      sa_slotid;
+       u32                     sa_slotid;
        u8                      sa_cache_this;
 };
 
@@ -977,6 +977,7 @@ struct nfs4_server_caps_res {
        u32                             acl_bitmask;
        u32                             has_links;
        u32                             has_symlinks;
+       u32                             fh_expire_type;
        struct nfs4_sequence_res        seq_res;
 };
 
@@ -1055,14 +1056,6 @@ struct nfstime4 {
 };
 
 #ifdef CONFIG_NFS_V4_1
-struct nfs_impl_id4 {
-       u32             domain_len;
-       char            *domain;
-       u32             name_len;
-       char            *name;
-       struct nfstime4 date;
-};
-
 #define NFS4_EXCHANGE_ID_LEN   (48)
 struct nfs41_exchange_id_args {
        struct nfs_client               *client;
@@ -1083,10 +1076,17 @@ struct server_scope {
        char                            server_scope[NFS4_OPAQUE_LIMIT];
 };
 
+struct nfs41_impl_id {
+       char                            domain[NFS4_OPAQUE_LIMIT + 1];
+       char                            name[NFS4_OPAQUE_LIMIT + 1];
+       struct nfstime4                 date;
+};
+
 struct nfs41_exchange_id_res {
        struct nfs_client               *client;
        u32                             flags;
        struct server_scope             *server_scope;
+       struct nfs41_impl_id            *impl_id;
 };
 
 struct nfs41_create_session_args {
@@ -1192,6 +1192,27 @@ struct nfs_write_data {
        struct page             *page_array[NFS_PAGEVEC_SIZE];
 };
 
+struct nfs_unlinkdata {
+       struct hlist_node list;
+       struct nfs_removeargs args;
+       struct nfs_removeres res;
+       struct inode *dir;
+       struct rpc_cred *cred;
+       struct nfs_fattr dir_attr;
+};
+
+struct nfs_renamedata {
+       struct nfs_renameargs   args;
+       struct nfs_renameres    res;
+       struct rpc_cred         *cred;
+       struct inode            *old_dir;
+       struct dentry           *old_dentry;
+       struct nfs_fattr        old_fattr;
+       struct inode            *new_dir;
+       struct dentry           *new_dentry;
+       struct nfs_fattr        new_fattr;
+};
+
 struct nfs_access_entry;
 struct nfs_client;
 struct rpc_timeout;
@@ -1221,10 +1242,12 @@ struct nfs_rpc_ops {
                            struct iattr *, int, struct nfs_open_context *);
        int     (*remove)  (struct inode *, struct qstr *);
        void    (*unlink_setup)  (struct rpc_message *, struct inode *dir);
+       void    (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *);
        int     (*unlink_done) (struct rpc_task *, struct inode *);
        int     (*rename)  (struct inode *, struct qstr *,
                            struct inode *, struct qstr *);
        void    (*rename_setup)  (struct rpc_message *msg, struct inode *dir);
+       void    (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *);
        int     (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
        int     (*link)    (struct inode *, struct inode *, struct qstr *);
        int     (*symlink) (struct inode *, struct dentry *, struct page *,
@@ -1244,8 +1267,10 @@ 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_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_rpc_prepare)(struct rpc_task *, struct nfs_write_data *);
        int     (*write_done)  (struct rpc_task *, struct nfs_write_data *);
        void    (*commit_setup) (struct nfs_write_data *, struct rpc_message *);
        int     (*commit_done) (struct rpc_task *, struct nfs_write_data *);
@@ -1275,11 +1300,11 @@ struct nfs_rpc_ops {
 extern const struct nfs_rpc_ops        nfs_v2_clientops;
 extern const struct nfs_rpc_ops        nfs_v3_clientops;
 extern const struct nfs_rpc_ops        nfs_v4_clientops;
-extern struct rpc_version      nfs_version2;
-extern struct rpc_version      nfs_version3;
-extern struct rpc_version      nfs_version4;
+extern const struct rpc_version nfs_version2;
+extern const struct rpc_version nfs_version3;
+extern const struct rpc_version nfs_version4;
 
-extern struct rpc_version      nfsacl_version3;
-extern struct rpc_program      nfsacl_program;
+extern const struct rpc_version nfsacl_version3;
+extern const struct rpc_program nfsacl_program;
 
 #endif
index 7454ad7..89bd4a4 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 #include <linux/magic.h>
+#include <linux/bug.h>
 
 
 #define NILFS_INODE_BMAP_SIZE  7
index 2d304ef..db50840 100644 (file)
@@ -14,7 +14,7 @@
  * may be used to reset the timeout - for code which intentionally
  * disables interrupts for a long time. This call is stateless.
  */
-#if defined(ARCH_HAS_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
+#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
 #include <asm/nmi.h>
 extern void touch_nmi_watchdog(void);
 #else
index d46a18f..fa7fb1d 100644 (file)
@@ -58,9 +58,6 @@ struct device_node {
        struct  kref kref;
        unsigned long _flags;
        void    *data;
-#if defined(CONFIG_EEH)
-       struct eeh_dev *edev;
-#endif
 #if defined(CONFIG_SPARC)
        char    *path_component_name;
        unsigned int unique_id;
@@ -75,13 +72,6 @@ struct of_phandle_args {
        uint32_t args[MAX_PHANDLE_ARGS];
 };
 
-#if defined(CONFIG_EEH)
-static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
-{
-       return dn->edev;
-}
-#endif
-
 #ifdef CONFIG_OF_DYNAMIC
 extern struct device_node *of_node_get(struct device_node *node);
 extern void of_node_put(struct device_node *node);
@@ -361,6 +351,22 @@ static inline int of_machine_is_compatible(const char *compat)
 #define of_match_node(_matches, _node) NULL
 #endif /* CONFIG_OF */
 
+/**
+ * of_property_read_bool - Findfrom a property
+ * @np:                device node from which the property value is to be read.
+ * @propname:  name of the property to be searched.
+ *
+ * Search for a property in a device node.
+ * Returns true if the property exist false otherwise.
+ */
+static inline bool of_property_read_bool(const struct device_node *np,
+                                        const char *propname)
+{
+       struct property *prop = of_find_property(np, propname, NULL);
+
+       return prop ? true : false;
+}
+
 static inline int of_property_read_u32(const struct device_node *np,
                                       const char *propname,
                                       u32 *out_value)
index cbc4214..901b743 100644 (file)
@@ -5,10 +5,11 @@
 #include <linux/of_platform.h> /* temporary until merge */
 
 #ifdef CONFIG_OF_DEVICE
-#include <linux/device.h>
 #include <linux/of.h>
 #include <linux/mod_devicetable.h>
 
+struct device;
+
 extern const struct of_device_id *of_match_device(
        const struct of_device_id *matches, const struct device *dev);
 extern void of_device_make_bus_id(struct device *dev);
index b254052..81733d1 100644 (file)
@@ -50,7 +50,8 @@ static inline struct of_mm_gpio_chip *to_of_mm_gpio_chip(struct gpio_chip *gc)
 extern int of_get_named_gpio_flags(struct device_node *np,
                const char *list_name, int index, enum of_gpio_flags *flags);
 
-extern unsigned int of_gpio_count(struct device_node *np);
+extern unsigned int of_gpio_named_count(struct device_node *np,
+                                       const char* propname);
 
 extern int of_mm_gpiochip_add(struct device_node *np,
                              struct of_mm_gpio_chip *mm_gc);
@@ -71,7 +72,8 @@ static inline int of_get_named_gpio_flags(struct device_node *np,
        return -ENOSYS;
 }
 
-static inline unsigned int of_gpio_count(struct device_node *np)
+static inline unsigned int of_gpio_named_count(struct device_node *np,
+                                       const char* propname)
 {
        return 0;
 }
@@ -89,6 +91,27 @@ static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
 #endif /* CONFIG_OF_GPIO */
 
 /**
+ * of_gpio_count - Count GPIOs for a device
+ * @np:                device node to count GPIOs for
+ *
+ * The function returns the count of GPIOs specified for a node.
+ *
+ * Note that the empty GPIO specifiers counts too. For example,
+ *
+ * gpios = <0
+ *          &pio1 1 2
+ *          0
+ *          &pio2 3 4>;
+ *
+ * defines four GPIOs (so this function will return 4), two of which
+ * are not specified.
+ */
+static inline unsigned int of_gpio_count(struct device_node *np)
+{
+       return of_gpio_named_count(np, "gpios");
+}
+
+/**
  * of_get_gpio_flags() - Get a GPIO number and flags to use with GPIO API
  * @np:                device node to get GPIO from
  * @index:     index of the GPIO
diff --git a/include/linux/of_mtd.h b/include/linux/of_mtd.h
new file mode 100644 (file)
index 0000000..bae1b60
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * OF helpers for mtd.
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_OF_MTD_H
+#define __LINUX_OF_NET_H
+
+#ifdef CONFIG_OF_MTD
+#include <linux/of.h>
+extern const int of_get_nand_ecc_mode(struct device_node *np);
+int of_get_nand_bus_width(struct device_node *np);
+bool of_get_nand_on_flash_bbt(struct device_node *np);
+#endif
+
+#endif /* __LINUX_OF_MTD_H */
index ee94b33..2a4e5fa 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/notifier.h>
 
 struct opp;
+struct device;
 
 enum opp_event {
        OPP_EVENT_ADD, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
index 6b25758..c88d2a9 100644 (file)
@@ -6,6 +6,7 @@
 #define PAGE_FLAGS_H
 
 #include <linux/types.h>
+#include <linux/bug.h>
 #ifndef __GENERATING_BOUNDS_H
 #include <linux/mm_types.h>
 #include <generated/bounds.h>
index 900da5d..e444f5b 100644 (file)
@@ -299,7 +299,6 @@ struct pci_dev {
         */
        unsigned int    irq;
        struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
-       resource_size_t fw_addr[DEVICE_COUNT_RESOURCE]; /* FW-assigned addr */
 
        /* These fields are used by common fixups */
        unsigned int    transparent:1;  /* Transparent PCI bridge */
@@ -369,24 +368,17 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
        return (pdev->error_state != pci_channel_io_normal);
 }
 
-static inline struct pci_cap_saved_state *pci_find_saved_cap(
-       struct pci_dev *pci_dev, char cap)
-{
-       struct pci_cap_saved_state *tmp;
-       struct hlist_node *pos;
-
-       hlist_for_each_entry(tmp, pos, &pci_dev->saved_cap_space, next) {
-               if (tmp->cap.cap_nr == cap)
-                       return tmp;
-       }
-       return NULL;
-}
+struct pci_host_bridge_window {
+       struct list_head list;
+       struct resource *res;           /* host bridge aperture (CPU address) */
+       resource_size_t offset;         /* bus address + offset = CPU address */
+};
 
-static inline void pci_add_saved_cap(struct pci_dev *pci_dev,
-       struct pci_cap_saved_state *new_cap)
-{
-       hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
-}
+struct pci_host_bridge {
+       struct list_head list;
+       struct pci_bus *bus;            /* root bus */
+       struct list_head windows;       /* pci_host_bridge_windows */
+};
 
 /*
  * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond
@@ -656,6 +648,10 @@ void pci_fixup_cardbus(struct pci_bus *);
 
 /* Generic PCI functions used internally */
 
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+                            struct resource *res);
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+                            struct pci_bus_region *region);
 void pcibios_scan_specific_bus(int busn);
 extern struct pci_bus *pci_find_bus(int domain, int busnr);
 void pci_bus_add_devices(const struct pci_bus *bus);
@@ -690,7 +686,8 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp);
 extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
 extern void pci_dev_put(struct pci_dev *dev);
 extern void pci_remove_bus(struct pci_bus *b);
-extern void pci_remove_bus_device(struct pci_dev *dev);
+extern void __pci_remove_bus_device(struct pci_dev *dev);
+extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
 extern void pci_stop_bus_device(struct pci_dev *dev);
 void pci_setup_cardbus(struct pci_bus *bus);
 extern void pci_sort_breadthfirst(void);
@@ -883,6 +880,7 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev);
 /* Functions for PCI Hotplug drivers to use */
 int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
 #ifdef CONFIG_HOTPLUG
+unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge);
 unsigned int pci_rescan_bus(struct pci_bus *bus);
 #endif
 
@@ -892,13 +890,13 @@ ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void
 int pci_vpd_truncate(struct pci_dev *dev, size_t size);
 
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
+resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
 void pci_bus_assign_resources(const struct pci_bus *bus);
 void pci_bus_size_bridges(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
 void pdev_enable_device(struct pci_dev *);
-void pdev_sort_resources(struct pci_dev *, struct resource_list *);
 int pci_enable_resources(struct pci_dev *, int mask);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
                    int (*)(const struct pci_dev *, u8, u8));
@@ -915,6 +913,8 @@ void pci_release_selected_regions(struct pci_dev *, int);
 
 /* drivers/pci/bus.c */
 void pci_add_resource(struct list_head *resources, struct resource *res);
+void pci_add_resource_offset(struct list_head *resources, struct resource *res,
+                            resource_size_t offset);
 void pci_free_resource_list(struct list_head *resources);
 void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags);
 struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n);
@@ -960,7 +960,7 @@ void pci_unregister_driver(struct pci_driver *dev);
        module_driver(__pci_driver, pci_register_driver, \
                       pci_unregister_driver)
 
-void pci_remove_behind_bridge(struct pci_dev *dev);
+void pci_stop_and_remove_behind_bridge(struct pci_dev *dev);
 struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
 int pci_add_dynid(struct pci_driver *drv,
                  unsigned int vendor, unsigned int device,
@@ -1396,7 +1396,10 @@ static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
  */
 
 struct pci_fixup {
-       u16 vendor, device;     /* You can use PCI_ANY_ID here of course */
+       u16 vendor;             /* You can use PCI_ANY_ID here of course */
+       u16 device;             /* You can use PCI_ANY_ID here of course */
+       u32 class;              /* You can use PCI_ANY_ID here too */
+       unsigned int class_shift;       /* should be 0, 8, 16 */
        void (*hook)(struct pci_dev *dev);
 };
 
@@ -1411,30 +1414,68 @@ enum pci_fixup_pass {
 };
 
 /* Anonymous variables would be nice... */
-#define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, hook) \
-       static const struct pci_fixup __pci_fixup_##name __used         \
-       __attribute__((__section__(#section))) = { vendor, device, hook };
+#define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, class,        \
+                                 class_shift, hook)                    \
+       static const struct pci_fixup const __pci_fixup_##name __used   \
+       __attribute__((__section__(#section), aligned((sizeof(void *)))))    \
+               = { vendor, device, class, class_shift, hook };
+
+#define DECLARE_PCI_FIXUP_CLASS_EARLY(vendor, device, class,           \
+                                        class_shift, hook)             \
+       DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early,                     \
+               vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_HEADER(vendor, device, class,          \
+                                        class_shift, hook)             \
+       DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header,                    \
+               vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_FINAL(vendor, device, class,           \
+                                        class_shift, hook)             \
+       DECLARE_PCI_FIXUP_SECTION(.pci_fixup_final,                     \
+               vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_ENABLE(vendor, device, class,          \
+                                        class_shift, hook)             \
+       DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable,                    \
+               vendor##device##hook, vendor, device, class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_RESUME(vendor, device, class,          \
+                                        class_shift, hook)             \
+       DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume,                    \
+               resume##vendor##device##hook, vendor, device, class,    \
+               class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(vendor, device, class,    \
+                                        class_shift, hook)             \
+       DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume_early,              \
+               resume_early##vendor##device##hook, vendor, device,     \
+               class, class_shift, hook)
+#define DECLARE_PCI_FIXUP_CLASS_SUSPEND(vendor, device, class,         \
+                                        class_shift, hook)             \
+       DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend,                   \
+               suspend##vendor##device##hook, vendor, device, class,   \
+               class_shift, hook)
+
 #define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook)                  \
        DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early,                     \
-                       vendor##device##hook, vendor, device, hook)
+               vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_HEADER(vendor, device, hook)                 \
        DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header,                    \
-                       vendor##device##hook, vendor, device, hook)
+               vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_FINAL(vendor, device, hook)                  \
        DECLARE_PCI_FIXUP_SECTION(.pci_fixup_final,                     \
-                       vendor##device##hook, vendor, device, hook)
+               vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_ENABLE(vendor, device, hook)                 \
        DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable,                    \
-                       vendor##device##hook, vendor, device, hook)
+               vendor##device##hook, vendor, device, PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_RESUME(vendor, device, hook)                 \
        DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume,                    \
-                       resume##vendor##device##hook, vendor, device, hook)
+               resume##vendor##device##hook, vendor, device,           \
+               PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_RESUME_EARLY(vendor, device, hook)           \
        DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume_early,              \
-                       resume_early##vendor##device##hook, vendor, device, hook)
+               resume_early##vendor##device##hook, vendor, device,     \
+               PCI_ANY_ID, 0, hook)
 #define DECLARE_PCI_FIXUP_SUSPEND(vendor, device, hook)                        \
        DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend,                   \
-                       suspend##vendor##device##hook, vendor, device, hook)
+               suspend##vendor##device##hook, vendor, device,          \
+               PCI_ANY_ID, 0, hook)
 
 #ifdef CONFIG_PCI_QUIRKS
 void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
index e41a10f..4b608f5 100644 (file)
 #define  PCI_EXP_TYPE_UPSTREAM 0x5     /* Upstream Port */
 #define  PCI_EXP_TYPE_DOWNSTREAM 0x6   /* Downstream Port */
 #define  PCI_EXP_TYPE_PCI_BRIDGE 0x7   /* PCI/PCI-X Bridge */
+#define  PCI_EXP_TYPE_PCIE_BRIDGE 0x8  /* PCI/PCI-X to PCIE Bridge */
 #define  PCI_EXP_TYPE_RC_END   0x9     /* Root Complex Integrated Endpoint */
 #define  PCI_EXP_TYPE_RC_EC    0xa     /* Root Complex Event Collector */
 #define PCI_EXP_FLAGS_SLOT     0x0100  /* Slot implemented */
index c599f7e..6fe0a37 100644 (file)
@@ -19,7 +19,6 @@
 #define __PHY_H
 
 #include <linux/spinlock.h>
-#include <linux/device.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/timer.h>
@@ -88,6 +87,9 @@ typedef enum {
    IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */
 #define MII_ADDR_C45 (1<<30)
 
+struct device;
+struct sk_buff;
+
 /*
  * The Bus class for PHYs.  Devices which provide access to
  * PHYs should register using this structure
@@ -241,7 +243,6 @@ enum phy_state {
        PHY_RESUMING
 };
 
-struct sk_buff;
 
 /* phy_device: An instance of a PHY
  *
index e7cf666..f5bd679 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_PID_NS_H
 
 #include <linux/sched.h>
+#include <linux/bug.h>
 #include <linux/mm.h>
 #include <linux/threads.h>
 #include <linux/nsproxy.h>
index 77257c9..6d626ff 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _LINUX_PIPE_FS_I_H
 #define _LINUX_PIPE_FS_I_H
 
-#define PIPEFS_MAGIC 0x50495045
-
 #define PIPE_DEF_BUFFERS       16
 
 #define PIPE_BUF_FLAG_LRU      0x01    /* page is on the LRU */
diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h
new file mode 100644 (file)
index 0000000..d056263
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * atmel platform data
+ *
+ * GPL v2 Only
+ */
+
+#ifndef __ATMEL_NAND_H__
+#define __ATMEL_NAND_H__
+
+#include <linux/mtd/nand.h>
+
+ /* NAND / SmartMedia */
+struct atmel_nand_data {
+       int             enable_pin;             /* chip enable */
+       int             det_pin;                /* card detect */
+       int             rdy_pin;                /* ready/busy */
+       u8              rdy_pin_active_low;     /* rdy_pin value is inverted */
+       u8              ale;                    /* address line number connected to ALE */
+       u8              cle;                    /* address line number connected to CLE */
+       u8              bus_width_16;           /* buswidth is 16 bit */
+       u8              ecc_mode;               /* ecc mode */
+       u8              on_flash_bbt;           /* bbt on flash */
+       struct mtd_partition *parts;
+       unsigned int    num_parts;
+};
+
+#endif /* __ATMEL_NAND_H__ */
diff --git a/include/linux/platform_data/tegra_emc.h b/include/linux/platform_data/tegra_emc.h
new file mode 100644 (file)
index 0000000..df67505
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Author:
+ *     Colin Cross <ccross@android.com>
+ *     Olof Johansson <olof@lixom.net>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __TEGRA_EMC_H_
+#define __TEGRA_EMC_H_
+
+#define TEGRA_EMC_NUM_REGS 46
+
+struct tegra_emc_table {
+       unsigned long rate;
+       u32 regs[TEGRA_EMC_NUM_REGS];
+};
+
+struct tegra_emc_pdata {
+       int num_tables;
+       struct tegra_emc_table *tables;
+};
+
+#endif
index 1236d26..91f8286 100644 (file)
@@ -10,6 +10,8 @@
 #define _LINUX_PM_DOMAIN_H
 
 #include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
 #include <linux/err.h>
 #include <linux/of.h>
 
index cf40010..48fe8bc 100644 (file)
@@ -32,21 +32,46 @@ struct poll_table_struct;
  */
 typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);
 
+/*
+ * Do not touch the structure directly, use the access functions
+ * poll_does_not_wait() and poll_requested_events() instead.
+ */
 typedef struct poll_table_struct {
-       poll_queue_proc qproc;
-       unsigned long key;
+       poll_queue_proc _qproc;
+       unsigned long _key;
 } poll_table;
 
 static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
 {
-       if (p && wait_address)
-               p->qproc(filp, wait_address, p);
+       if (p && p->_qproc && wait_address)
+               p->_qproc(filp, wait_address, p);
+}
+
+/*
+ * Return true if it is guaranteed that poll will not wait. This is the case
+ * if the poll() of another file descriptor in the set got an event, so there
+ * is no need for waiting.
+ */
+static inline bool poll_does_not_wait(const poll_table *p)
+{
+       return p == NULL || p->_qproc == NULL;
+}
+
+/*
+ * Return the set of events that the application wants to poll for.
+ * This is useful for drivers that need to know whether a DMA transfer has
+ * to be started implicitly on poll(). You typically only want to do that
+ * if the application is actually polling for POLLIN and/or POLLOUT.
+ */
+static inline unsigned long poll_requested_events(const poll_table *p)
+{
+       return p ? p->_key : ~0UL;
 }
 
 static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc)
 {
-       pt->qproc = qproc;
-       pt->key   = ~0UL; /* all events enabled */
+       pt->_qproc = qproc;
+       pt->_key   = ~0UL; /* all events enabled */
 }
 
 struct poll_table_entry {
index b768110..11bad91 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __LINUX_POSIX_ACL_H
 #define __LINUX_POSIX_ACL_H
 
+#include <linux/bug.h>
 #include <linux/slab.h>
 #include <linux/rcupdate.h>
 
index fa9b962..c38c13d 100644 (file)
 #ifndef __LINUX_POWER_SUPPLY_H__
 #define __LINUX_POWER_SUPPLY_H__
 
-#include <linux/device.h>
 #include <linux/workqueue.h>
 #include <linux/leds.h>
 
+struct device;
+
 /*
  * All voltages, currents, charges, energies, time and temperatures in uV,
  * ÂµA, ÂµAh, ÂµWh, seconds and tenths of degree Celsius unless otherwise
index a0413ac..e0cfec2 100644 (file)
 #define PR_SET_PTRACER 0x59616d61
 # define PR_SET_PTRACER_ANY ((unsigned long)-1)
 
+#define PR_SET_CHILD_SUBREAPER 36
+#define PR_GET_CHILD_SUBREAPER 37
+
 #endif /* _LINUX_PRCTL_H */
index c2f1f6a..5c71962 100644 (file)
 #define PTRACE_INTERRUPT       0x4207
 #define PTRACE_LISTEN          0x4208
 
-/* flags in @data for PTRACE_SEIZE */
-#define PTRACE_SEIZE_DEVEL     0x80000000 /* temp flag for development */
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD  0x00000001
-#define PTRACE_O_TRACEFORK     0x00000002
-#define PTRACE_O_TRACEVFORK    0x00000004
-#define PTRACE_O_TRACECLONE    0x00000008
-#define PTRACE_O_TRACEEXEC     0x00000010
-#define PTRACE_O_TRACEVFORKDONE        0x00000020
-#define PTRACE_O_TRACEEXIT     0x00000040
-
-#define PTRACE_O_MASK          0x0000007f
-
 /* Wait extended result codes for the above trace options.  */
 #define PTRACE_EVENT_FORK      1
 #define PTRACE_EVENT_VFORK     2
 #define PTRACE_EVENT_EXEC      4
 #define PTRACE_EVENT_VFORK_DONE        5
 #define PTRACE_EVENT_EXIT      6
-#define PTRACE_EVENT_STOP      7
+/* Extended result codes which enabled by means other than options.  */
+#define PTRACE_EVENT_STOP      128
+
+/* Options set using PTRACE_SETOPTIONS or using PTRACE_SEIZE @data param */
+#define PTRACE_O_TRACESYSGOOD  1
+#define PTRACE_O_TRACEFORK     (1 << PTRACE_EVENT_FORK)
+#define PTRACE_O_TRACEVFORK    (1 << PTRACE_EVENT_VFORK)
+#define PTRACE_O_TRACECLONE    (1 << PTRACE_EVENT_CLONE)
+#define PTRACE_O_TRACEEXEC     (1 << PTRACE_EVENT_EXEC)
+#define PTRACE_O_TRACEVFORKDONE        (1 << PTRACE_EVENT_VFORK_DONE)
+#define PTRACE_O_TRACEEXIT     (1 << PTRACE_EVENT_EXIT)
+
+#define PTRACE_O_MASK          0x0000007f
 
 #include <asm/ptrace.h>
 
 #define PT_SEIZED      0x00010000      /* SEIZE used, enable new behavior */
 #define PT_PTRACED     0x00000001
 #define PT_DTRACE      0x00000002      /* delayed trace (used on m68k, i386) */
-#define PT_TRACESYSGOOD        0x00000004
-#define PT_PTRACE_CAP  0x00000008      /* ptracer can follow suid-exec */
+#define PT_PTRACE_CAP  0x00000004      /* ptracer can follow suid-exec */
 
+#define PT_OPT_FLAG_SHIFT      3
 /* PT_TRACE_* event enable flags */
-#define PT_EVENT_FLAG_SHIFT    4
-#define PT_EVENT_FLAG(event)   (1 << (PT_EVENT_FLAG_SHIFT + (event) - 1))
-
+#define PT_EVENT_FLAG(event)   (1 << (PT_OPT_FLAG_SHIFT + (event)))
+#define PT_TRACESYSGOOD                PT_EVENT_FLAG(0)
 #define PT_TRACE_FORK          PT_EVENT_FLAG(PTRACE_EVENT_FORK)
 #define PT_TRACE_VFORK         PT_EVENT_FLAG(PTRACE_EVENT_VFORK)
 #define PT_TRACE_CLONE         PT_EVENT_FLAG(PTRACE_EVENT_CLONE)
 #define PT_TRACE_VFORK_DONE    PT_EVENT_FLAG(PTRACE_EVENT_VFORK_DONE)
 #define PT_TRACE_EXIT          PT_EVENT_FLAG(PTRACE_EVENT_EXIT)
 
-#define PT_TRACE_MASK  0x000003f4
-
 /* single stepping state bits (used on ARM and PA-RISC) */
 #define PT_SINGLESTEP_BIT      31
 #define PT_SINGLESTEP          (1<<PT_SINGLESTEP_BIT)
 #include <linux/compiler.h>            /* For unlikely.  */
 #include <linux/sched.h>               /* For struct task_struct.  */
 #include <linux/err.h>                 /* for IS_ERR_VALUE */
+#include <linux/bug.h>                 /* For BUG_ON.  */
 
 
 extern long arch_ptrace(struct task_struct *child, long request,
@@ -199,9 +195,10 @@ static inline void ptrace_event(int event, unsigned long message)
        if (unlikely(ptrace_event_enabled(current, event))) {
                current->ptrace_message = message;
                ptrace_notify((event << 8) | SIGTRAP);
-       } else if (event == PTRACE_EVENT_EXEC && unlikely(current->ptrace)) {
+       } else if (event == PTRACE_EVENT_EXEC) {
                /* legacy EXEC report via SIGTRAP */
-               send_sig(SIGTRAP, current, 0);
+               if ((current->ptrace & (PT_PTRACED|PT_SEIZED)) == PT_PTRACED)
+                       send_sig(SIGTRAP, current, 0);
        }
 }
 
index 07e360b..e9a4823 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/preempt.h>
 #include <linux/types.h>
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/rcupdate.h>
 
index 9372174..20fb776 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/lockdep.h>
 #include <linux/completion.h>
 #include <linux/debugobjects.h>
+#include <linux/bug.h>
 #include <linux/compiler.h>
 
 #ifdef CONFIG_RCU_TORTURE_TEST
@@ -418,7 +419,7 @@ extern int rcu_my_thread_group_empty(void);
  */
 #define rcu_lockdep_assert(c, s)                                       \
        do {                                                            \
-               static bool __warned;                                   \
+               static bool __section(.data.unlikely) __warned;         \
                if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \
                        __warned = true;                                \
                        lockdep_rcu_suspicious(__FILE__, __LINE__, s);  \
index 5d7e6ad..a90abb6 100644 (file)
  * published by the Free Software Foundation.
  */
 
-#include <linux/device.h>
 #include <linux/list.h>
 
 struct module;
+struct device;
 struct i2c_client;
 struct spi_device;
 struct regmap;
index 686f373..8e0c9fe 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
+#include <linux/bug.h>
 #include <linux/uaccess.h>
 struct task_struct;
 struct user_regset;
index 76579f9..7bd73bb 100644 (file)
@@ -26,7 +26,26 @@ enum ab8500_regulator_id {
        AB8500_NUM_REGULATORS,
 };
 
-/* AB8500 register initialization */
+/* AB9450 regulators */
+enum ab9540_regulator_id {
+       AB9540_LDO_AUX1,
+       AB9540_LDO_AUX2,
+       AB9540_LDO_AUX3,
+       AB9540_LDO_AUX4,
+       AB9540_LDO_INTCORE,
+       AB9540_LDO_TVOUT,
+       AB9540_LDO_USB,
+       AB9540_LDO_AUDIO,
+       AB9540_LDO_ANAMIC1,
+       AB9540_LDO_ANAMIC2,
+       AB9540_LDO_DMIC,
+       AB9540_LDO_ANA,
+       AB9540_SYSCLKREQ_2,
+       AB9540_SYSCLKREQ_4,
+       AB9540_NUM_REGULATORS,
+};
+
+/* AB8500 and AB9540 register initialization */
 struct ab8500_regulator_reg_init {
        int id;
        u8 value;
@@ -71,4 +90,53 @@ enum ab8500_regulator_reg {
        AB8500_NUM_REGULATOR_REGISTERS,
 };
 
+
+/* AB9540 registers */
+enum ab9540_regulator_reg {
+       AB9540_REGUREQUESTCTRL1,
+       AB9540_REGUREQUESTCTRL2,
+       AB9540_REGUREQUESTCTRL3,
+       AB9540_REGUREQUESTCTRL4,
+       AB9540_REGUSYSCLKREQ1HPVALID1,
+       AB9540_REGUSYSCLKREQ1HPVALID2,
+       AB9540_REGUHWHPREQ1VALID1,
+       AB9540_REGUHWHPREQ1VALID2,
+       AB9540_REGUHWHPREQ2VALID1,
+       AB9540_REGUHWHPREQ2VALID2,
+       AB9540_REGUSWHPREQVALID1,
+       AB9540_REGUSWHPREQVALID2,
+       AB9540_REGUSYSCLKREQVALID1,
+       AB9540_REGUSYSCLKREQVALID2,
+       AB9540_REGUVAUX4REQVALID,
+       AB9540_REGUMISC1,
+       AB9540_VAUDIOSUPPLY,
+       AB9540_REGUCTRL1VAMIC,
+       AB9540_VSMPS1REGU,
+       AB9540_VSMPS2REGU,
+       AB9540_VSMPS3REGU, /* NOTE! PRCMU register */
+       AB9540_VPLLVANAREGU,
+       AB9540_EXTSUPPLYREGU,
+       AB9540_VAUX12REGU,
+       AB9540_VRF1VAUX3REGU,
+       AB9540_VSMPS1SEL1,
+       AB9540_VSMPS1SEL2,
+       AB9540_VSMPS1SEL3,
+       AB9540_VSMPS2SEL1,
+       AB9540_VSMPS2SEL2,
+       AB9540_VSMPS2SEL3,
+       AB9540_VSMPS3SEL1, /* NOTE! PRCMU register */
+       AB9540_VSMPS3SEL2, /* NOTE! PRCMU register */
+       AB9540_VAUX1SEL,
+       AB9540_VAUX2SEL,
+       AB9540_VRF1VAUX3SEL,
+       AB9540_REGUCTRL2SPARE,
+       AB9540_VAUX4REQCTRL,
+       AB9540_VAUX4REGU,
+       AB9540_VAUX4SEL,
+       AB9540_REGUCTRLDISCH,
+       AB9540_REGUCTRLDISCH2,
+       AB9540_REGUCTRLDISCH3,
+       AB9540_NUM_REGULATOR_REGISTERS,
+};
+
 #endif
diff --git a/include/linux/regulator/bq24022.h b/include/linux/regulator/bq24022.h
deleted file mode 100644 (file)
index a6d0140..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Support for TI bq24022 (bqTINY-II) Dual Input (USB/AC Adpater)
- * 1-Cell Li-Ion Charger connected via GPIOs.
- *
- * Copyright (c) 2008 Philipp Zabel
- *
- * 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 regulator_init_data;
-
-/**
- * bq24022_mach_info - platform data for bq24022
- * @gpio_nce: GPIO line connected to the nCE pin, used to enable / disable charging
- * @gpio_iset2: GPIO line connected to the ISET2 pin, used to limit charging current to 100 mA / 500 mA
- */
-struct bq24022_mach_info {
-       int gpio_nce;
-       int gpio_iset2;
-       struct regulator_init_data *init_data;
-};
index b6c8d71..4ed1b30 100644 (file)
@@ -35,7 +35,8 @@
 #ifndef __LINUX_REGULATOR_CONSUMER_H_
 #define __LINUX_REGULATOR_CONSUMER_H_
 
-#include <linux/device.h>
+struct device;
+struct notifier_block;
 
 /*
  * Regulator operating modes.
index a822fd7..91cacc3 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/kref.h>
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
new file mode 100644 (file)
index 0000000..f1ffabb
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * Remote Processor Framework
+ *
+ * Copyright(c) 2011 Texas Instruments, Inc.
+ * Copyright(c) 2011 Google, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name Texas Instruments nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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 REMOTEPROC_H
+#define REMOTEPROC_H
+
+#include <linux/types.h>
+#include <linux/kref.h>
+#include <linux/klist.h>
+#include <linux/mutex.h>
+#include <linux/virtio.h>
+#include <linux/completion.h>
+#include <linux/idr.h>
+
+/**
+ * struct resource_table - firmware resource table header
+ * @ver: version number
+ * @num: number of resource entries
+ * @reserved: reserved (must be zero)
+ * @offset: array of offsets pointing at the various resource entries
+ *
+ * A resource table is essentially a list of system resources required
+ * by the remote processor. It may also include configuration entries.
+ * If needed, the remote processor firmware should contain this table
+ * as a dedicated ".resource_table" ELF section.
+ *
+ * Some resources entries are mere announcements, where the host is informed
+ * of specific remoteproc configuration. Other entries require the host to
+ * do something (e.g. allocate a system resource). Sometimes a negotiation
+ * is expected, where the firmware requests a resource, and once allocated,
+ * the host should provide back its details (e.g. address of an allocated
+ * memory region).
+ *
+ * The header of the resource table, as expressed by this structure,
+ * contains a version number (should we need to change this format in the
+ * future), the number of available resource entries, and their offsets
+ * in the table.
+ *
+ * Immediately following this header are the resource entries themselves,
+ * each of which begins with a resource entry header (as described below).
+ */
+struct resource_table {
+       u32 ver;
+       u32 num;
+       u32 reserved[2];
+       u32 offset[0];
+} __packed;
+
+/**
+ * struct fw_rsc_hdr - firmware resource entry header
+ * @type: resource type
+ * @data: resource data
+ *
+ * Every resource entry begins with a 'struct fw_rsc_hdr' header providing
+ * its @type. The content of the entry itself will immediately follow
+ * this header, and it should be parsed according to the resource type.
+ */
+struct fw_rsc_hdr {
+       u32 type;
+       u8 data[0];
+} __packed;
+
+/**
+ * enum fw_resource_type - types of resource entries
+ *
+ * @RSC_CARVEOUT:   request for allocation of a physically contiguous
+ *                 memory region.
+ * @RSC_DEVMEM:     request to iommu_map a memory-based peripheral.
+ * @RSC_TRACE:     announces the availability of a trace buffer into which
+ *                 the remote processor will be writing logs.
+ * @RSC_VDEV:       declare support for a virtio device, and serve as its
+ *                 virtio header.
+ * @RSC_LAST:       just keep this one at the end
+ *
+ * For more details regarding a specific resource type, please see its
+ * dedicated structure below.
+ *
+ * Please note that these values are used as indices to the rproc_handle_rsc
+ * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to
+ * check the validity of an index before the lookup table is accessed, so
+ * please update it as needed.
+ */
+enum fw_resource_type {
+       RSC_CARVEOUT    = 0,
+       RSC_DEVMEM      = 1,
+       RSC_TRACE       = 2,
+       RSC_VDEV        = 3,
+       RSC_LAST        = 4,
+};
+
+#define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF)
+
+/**
+ * struct fw_rsc_carveout - physically contiguous memory request
+ * @da: device address
+ * @pa: physical address
+ * @len: length (in bytes)
+ * @flags: iommu protection flags
+ * @reserved: reserved (must be zero)
+ * @name: human-readable name of the requested memory region
+ *
+ * This resource entry requests the host to allocate a physically contiguous
+ * memory region.
+ *
+ * These request entries should precede other firmware resource entries,
+ * as other entries might request placing other data objects inside
+ * these memory regions (e.g. data/code segments, trace resource entries, ...).
+ *
+ * Allocating memory this way helps utilizing the reserved physical memory
+ * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries
+ * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB
+ * pressure is important; it may have a substantial impact on performance.
+ *
+ * If the firmware is compiled with static addresses, then @da should specify
+ * the expected device address of this memory region. If @da is set to
+ * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then
+ * overwrite @da with the dynamically allocated address.
+ *
+ * We will always use @da to negotiate the device addresses, even if it
+ * isn't using an iommu. In that case, though, it will obviously contain
+ * physical addresses.
+ *
+ * Some remote processors needs to know the allocated physical address
+ * even if they do use an iommu. This is needed, e.g., if they control
+ * hardware accelerators which access the physical memory directly (this
+ * is the case with OMAP4 for instance). In that case, the host will
+ * overwrite @pa with the dynamically allocated physical address.
+ * Generally we don't want to expose physical addresses if we don't have to
+ * (remote processors are generally _not_ trusted), so we might want to
+ * change this to happen _only_ when explicitly required by the hardware.
+ *
+ * @flags is used to provide IOMMU protection flags, and @name should
+ * (optionally) contain a human readable name of this carveout region
+ * (mainly for debugging purposes).
+ */
+struct fw_rsc_carveout {
+       u32 da;
+       u32 pa;
+       u32 len;
+       u32 flags;
+       u32 reserved;
+       u8 name[32];
+} __packed;
+
+/**
+ * struct fw_rsc_devmem - iommu mapping request
+ * @da: device address
+ * @pa: physical address
+ * @len: length (in bytes)
+ * @flags: iommu protection flags
+ * @reserved: reserved (must be zero)
+ * @name: human-readable name of the requested region to be mapped
+ *
+ * This resource entry requests the host to iommu map a physically contiguous
+ * memory region. This is needed in case the remote processor requires
+ * access to certain memory-based peripherals; _never_ use it to access
+ * regular memory.
+ *
+ * This is obviously only needed if the remote processor is accessing memory
+ * via an iommu.
+ *
+ * @da should specify the required device address, @pa should specify
+ * the physical address we want to map, @len should specify the size of
+ * the mapping and @flags is the IOMMU protection flags. As always, @name may
+ * (optionally) contain a human readable name of this mapping (mainly for
+ * debugging purposes).
+ *
+ * Note: at this point we just "trust" those devmem entries to contain valid
+ * physical addresses, but this isn't safe and will be changed: eventually we
+ * want remoteproc implementations to provide us ranges of physical addresses
+ * the firmware is allowed to request, and not allow firmwares to request
+ * access to physical addresses that are outside those ranges.
+ */
+struct fw_rsc_devmem {
+       u32 da;
+       u32 pa;
+       u32 len;
+       u32 flags;
+       u32 reserved;
+       u8 name[32];
+} __packed;
+
+/**
+ * struct fw_rsc_trace - trace buffer declaration
+ * @da: device address
+ * @len: length (in bytes)
+ * @reserved: reserved (must be zero)
+ * @name: human-readable name of the trace buffer
+ *
+ * This resource entry provides the host information about a trace buffer
+ * into which the remote processor will write log messages.
+ *
+ * @da specifies the device address of the buffer, @len specifies
+ * its size, and @name may contain a human readable name of the trace buffer.
+ *
+ * After booting the remote processor, the trace buffers are exposed to the
+ * user via debugfs entries (called trace0, trace1, etc..).
+ */
+struct fw_rsc_trace {
+       u32 da;
+       u32 len;
+       u32 reserved;
+       u8 name[32];
+} __packed;
+
+/**
+ * struct fw_rsc_vdev_vring - vring descriptor entry
+ * @da: device address
+ * @align: the alignment between the consumer and producer parts of the vring
+ * @num: num of buffers supported by this vring (must be power of two)
+ * @notifyid is a unique rproc-wide notify index for this vring. This notify
+ * index is used when kicking a remote processor, to let it know that this
+ * vring is triggered.
+ * @reserved: reserved (must be zero)
+ *
+ * This descriptor is not a resource entry by itself; it is part of the
+ * vdev resource type (see below).
+ *
+ * Note that @da should either contain the device address where
+ * the remote processor is expecting the vring, or indicate that
+ * dynamically allocation of the vring's device address is supported.
+ */
+struct fw_rsc_vdev_vring {
+       u32 da;
+       u32 align;
+       u32 num;
+       u32 notifyid;
+       u32 reserved;
+} __packed;
+
+/**
+ * struct fw_rsc_vdev - virtio device header
+ * @id: virtio device id (as in virtio_ids.h)
+ * @notifyid is a unique rproc-wide notify index for this vdev. This notify
+ * index is used when kicking a remote processor, to let it know that the
+ * status/features of this vdev have changes.
+ * @dfeatures specifies the virtio device features supported by the firmware
+ * @gfeatures is a place holder used by the host to write back the
+ * negotiated features that are supported by both sides.
+ * @config_len is the size of the virtio config space of this vdev. The config
+ * space lies in the resource table immediate after this vdev header.
+ * @status is a place holder where the host will indicate its virtio progress.
+ * @num_of_vrings indicates how many vrings are described in this vdev header
+ * @reserved: reserved (must be zero)
+ * @vring is an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'.
+ *
+ * This resource is a virtio device header: it provides information about
+ * the vdev, and is then used by the host and its peer remote processors
+ * to negotiate and share certain virtio properties.
+ *
+ * By providing this resource entry, the firmware essentially asks remoteproc
+ * to statically allocate a vdev upon registration of the rproc (dynamic vdev
+ * allocation is not yet supported).
+ *
+ * Note: unlike virtualization systems, the term 'host' here means
+ * the Linux side which is running remoteproc to control the remote
+ * processors. We use the name 'gfeatures' to comply with virtio's terms,
+ * though there isn't really any virtualized guest OS here: it's the host
+ * which is responsible for negotiating the final features.
+ * Yeah, it's a bit confusing.
+ *
+ * Note: immediately following this structure is the virtio config space for
+ * this vdev (which is specific to the vdev; for more info, read the virtio
+ * spec). the size of the config space is specified by @config_len.
+ */
+struct fw_rsc_vdev {
+       u32 id;
+       u32 notifyid;
+       u32 dfeatures;
+       u32 gfeatures;
+       u32 config_len;
+       u8 status;
+       u8 num_of_vrings;
+       u8 reserved[2];
+       struct fw_rsc_vdev_vring vring[0];
+} __packed;
+
+/**
+ * struct rproc_mem_entry - memory entry descriptor
+ * @va:        virtual address
+ * @dma: dma address
+ * @len: length, in bytes
+ * @da: device address
+ * @priv: associated data
+ * @node: list node
+ */
+struct rproc_mem_entry {
+       void *va;
+       dma_addr_t dma;
+       int len;
+       u32 da;
+       void *priv;
+       struct list_head node;
+};
+
+struct rproc;
+
+/**
+ * struct rproc_ops - platform-specific device handlers
+ * @start:     power on the device and boot it
+ * @stop:      power off the device
+ * @kick:      kick a virtqueue (virtqueue id given as a parameter)
+ */
+struct rproc_ops {
+       int (*start)(struct rproc *rproc);
+       int (*stop)(struct rproc *rproc);
+       void (*kick)(struct rproc *rproc, int vqid);
+};
+
+/**
+ * enum rproc_state - remote processor states
+ * @RPROC_OFFLINE:     device is powered off
+ * @RPROC_SUSPENDED:   device is suspended; needs to be woken up to receive
+ *                     a message.
+ * @RPROC_RUNNING:     device is up and running
+ * @RPROC_CRASHED:     device has crashed; need to start recovery
+ * @RPROC_LAST:                just keep this one at the end
+ *
+ * Please note that the values of these states are used as indices
+ * to rproc_state_string, a state-to-name lookup table,
+ * so please keep the two synchronized. @RPROC_LAST is used to check
+ * the validity of an index before the lookup table is accessed, so
+ * please update it as needed too.
+ */
+enum rproc_state {
+       RPROC_OFFLINE   = 0,
+       RPROC_SUSPENDED = 1,
+       RPROC_RUNNING   = 2,
+       RPROC_CRASHED   = 3,
+       RPROC_LAST      = 4,
+};
+
+/**
+ * struct rproc - represents a physical remote processor device
+ * @node: klist node of this rproc object
+ * @domain: iommu domain
+ * @name: human readable name of the rproc
+ * @firmware: name of firmware file to be loaded
+ * @priv: private data which belongs to the platform-specific rproc module
+ * @ops: platform-specific start/stop rproc handlers
+ * @dev: underlying device
+ * @refcount: refcount of users that have a valid pointer to this rproc
+ * @power: refcount of users who need this rproc powered up
+ * @state: state of the device
+ * @lock: lock which protects concurrent manipulations of the rproc
+ * @dbg_dir: debugfs directory of this rproc device
+ * @traces: list of trace buffers
+ * @num_traces: number of trace buffers
+ * @carveouts: list of physically contiguous memory allocations
+ * @mappings: list of iommu mappings we initiated, needed on shutdown
+ * @firmware_loading_complete: marks e/o asynchronous firmware loading
+ * @bootaddr: address of first instruction to boot rproc with (optional)
+ * @rvdevs: list of remote virtio devices
+ * @notifyids: idr for dynamically assigning rproc-wide unique notify ids
+ */
+struct rproc {
+       struct klist_node node;
+       struct iommu_domain *domain;
+       const char *name;
+       const char *firmware;
+       void *priv;
+       const struct rproc_ops *ops;
+       struct device *dev;
+       struct kref refcount;
+       atomic_t power;
+       unsigned int state;
+       struct mutex lock;
+       struct dentry *dbg_dir;
+       struct list_head traces;
+       int num_traces;
+       struct list_head carveouts;
+       struct list_head mappings;
+       struct completion firmware_loading_complete;
+       u32 bootaddr;
+       struct list_head rvdevs;
+       struct idr notifyids;
+};
+
+/* we currently support only two vrings per rvdev */
+#define RVDEV_NUM_VRINGS 2
+
+/**
+ * struct rproc_vring - remoteproc vring state
+ * @va:        virtual address
+ * @dma: dma address
+ * @len: length, in bytes
+ * @da: device address
+ * @align: vring alignment
+ * @notifyid: rproc-specific unique vring index
+ * @rvdev: remote vdev
+ * @vq: the virtqueue of this vring
+ */
+struct rproc_vring {
+       void *va;
+       dma_addr_t dma;
+       int len;
+       u32 da;
+       u32 align;
+       int notifyid;
+       struct rproc_vdev *rvdev;
+       struct virtqueue *vq;
+};
+
+/**
+ * struct rproc_vdev - remoteproc state for a supported virtio device
+ * @node: list node
+ * @rproc: the rproc handle
+ * @vdev: the virio device
+ * @vring: the vrings for this vdev
+ * @dfeatures: virtio device features
+ * @gfeatures: virtio guest features
+ */
+struct rproc_vdev {
+       struct list_head node;
+       struct rproc *rproc;
+       struct virtio_device vdev;
+       struct rproc_vring vring[RVDEV_NUM_VRINGS];
+       unsigned long dfeatures;
+       unsigned long gfeatures;
+};
+
+struct rproc *rproc_get_by_name(const char *name);
+void rproc_put(struct rproc *rproc);
+
+struct rproc *rproc_alloc(struct device *dev, const char *name,
+                               const struct rproc_ops *ops,
+                               const char *firmware, int len);
+void rproc_free(struct rproc *rproc);
+int rproc_register(struct rproc *rproc);
+int rproc_unregister(struct rproc *rproc);
+
+int rproc_boot(struct rproc *rproc);
+void rproc_shutdown(struct rproc *rproc);
+
+static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev)
+{
+       return container_of(vdev, struct rproc_vdev, vdev);
+}
+
+static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev)
+{
+       struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+
+       return rvdev->rproc;
+}
+
+#endif /* REMOTEPROC_H */
index c6c6084..6fdf027 100644 (file)
@@ -117,10 +117,10 @@ enum rfkill_user_states {
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
-#include <linux/device.h>
 #include <linux/leds.h>
 #include <linux/err.h>
 
+struct device;
 /* this is opaque */
 struct rfkill;
 
index 229b3ca..7f07470 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/ioport.h>
 #include <linux/list.h>
 #include <linux/errno.h>
-#include <linux/device.h>
 #include <linux/string.h>
 #include <linux/rio.h>
 
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
new file mode 100644 (file)
index 0000000..a8e50e4
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Remote processor messaging
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name Texas Instruments nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER 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 _LINUX_RPMSG_H
+#define _LINUX_RPMSG_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+/* The feature bitmap for virtio rpmsg */
+#define VIRTIO_RPMSG_F_NS      0 /* RP supports name service notifications */
+
+/**
+ * struct rpmsg_hdr - common header for all rpmsg messages
+ * @src: source address
+ * @dst: destination address
+ * @reserved: reserved for future use
+ * @len: length of payload (in bytes)
+ * @flags: message flags
+ * @data: @len bytes of message payload data
+ *
+ * Every message sent(/received) on the rpmsg bus begins with this header.
+ */
+struct rpmsg_hdr {
+       u32 src;
+       u32 dst;
+       u32 reserved;
+       u16 len;
+       u16 flags;
+       u8 data[0];
+} __packed;
+
+/**
+ * struct rpmsg_ns_msg - dynamic name service announcement message
+ * @name: name of remote service that is published
+ * @addr: address of remote service that is published
+ * @flags: indicates whether service is created or destroyed
+ *
+ * This message is sent across to publish a new service, or announce
+ * about its removal. When we receive these messages, an appropriate
+ * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
+ * or ->remove() handler of the appropriate rpmsg driver will be invoked
+ * (if/as-soon-as one is registered).
+ */
+struct rpmsg_ns_msg {
+       char name[RPMSG_NAME_SIZE];
+       u32 addr;
+       u32 flags;
+} __packed;
+
+/**
+ * enum rpmsg_ns_flags - dynamic name service announcement flags
+ *
+ * @RPMSG_NS_CREATE: a new remote service was just created
+ * @RPMSG_NS_DESTROY: a known remote service was just destroyed
+ */
+enum rpmsg_ns_flags {
+       RPMSG_NS_CREATE         = 0,
+       RPMSG_NS_DESTROY        = 1,
+};
+
+#define RPMSG_ADDR_ANY         0xFFFFFFFF
+
+struct virtproc_info;
+
+/**
+ * rpmsg_channel - devices that belong to the rpmsg bus are called channels
+ * @vrp: the remote processor this channel belongs to
+ * @dev: the device struct
+ * @id: device id (used to match between rpmsg drivers and devices)
+ * @src: local address
+ * @dst: destination address
+ * @ept: the rpmsg endpoint of this channel
+ * @announce: if set, rpmsg will announce the creation/removal of this channel
+ */
+struct rpmsg_channel {
+       struct virtproc_info *vrp;
+       struct device dev;
+       struct rpmsg_device_id id;
+       u32 src;
+       u32 dst;
+       struct rpmsg_endpoint *ept;
+       bool announce;
+};
+
+typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32);
+
+/**
+ * struct rpmsg_endpoint - binds a local rpmsg address to its user
+ * @rpdev: rpmsg channel device
+ * @cb: rx callback handler
+ * @addr: local rpmsg address
+ * @priv: private data for the driver's use
+ *
+ * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as
+ * it binds an rpmsg address with an rx callback handler.
+ *
+ * Simple rpmsg drivers shouldn't use this struct directly, because
+ * things just work: every rpmsg driver provides an rx callback upon
+ * registering to the bus, and that callback is then bound to its rpmsg
+ * address when the driver is probed. When relevant inbound messages arrive
+ * (i.e. messages which their dst address equals to the src address of
+ * the rpmsg channel), the driver's handler is invoked to process it.
+ *
+ * More complicated drivers though, that do need to allocate additional rpmsg
+ * addresses, and bind them to different rx callbacks, must explicitly
+ * create additional endpoints by themselves (see rpmsg_create_ept()).
+ */
+struct rpmsg_endpoint {
+       struct rpmsg_channel *rpdev;
+       rpmsg_rx_cb_t cb;
+       u32 addr;
+       void *priv;
+};
+
+/**
+ * struct rpmsg_driver - rpmsg driver struct
+ * @drv: underlying device driver
+ * @id_table: rpmsg ids serviced by this driver
+ * @probe: invoked when a matching rpmsg channel (i.e. device) is found
+ * @remove: invoked when the rpmsg channel is removed
+ * @callback: invoked when an inbound message is received on the channel
+ */
+struct rpmsg_driver {
+       struct device_driver drv;
+       const struct rpmsg_device_id *id_table;
+       int (*probe)(struct rpmsg_channel *dev);
+       void (*remove)(struct rpmsg_channel *dev);
+       void (*callback)(struct rpmsg_channel *, void *, int, void *, u32);
+};
+
+int register_rpmsg_device(struct rpmsg_channel *dev);
+void unregister_rpmsg_device(struct rpmsg_channel *dev);
+int register_rpmsg_driver(struct rpmsg_driver *drv);
+void unregister_rpmsg_driver(struct rpmsg_driver *drv);
+void rpmsg_destroy_ept(struct rpmsg_endpoint *);
+struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *,
+                               rpmsg_rx_cb_t cb, void *priv, u32 addr);
+int
+rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool);
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @rpdev channel.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to, using @rpdev's source and destination addresses.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len)
+{
+       u32 src = rpdev->src, dst = rpdev->dst;
+
+       return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to, using @rpdev's source address.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
+{
+       u32 src = rpdev->src;
+
+       return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @rpdev: the rpmsg channel
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to.
+ * In case there are no TX buffers available, the function will block until
+ * one becomes available, or a timeout of 15 seconds elapses. When the latter
+ * happens, -ERESTARTSYS is returned.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+                                                       void *data, int len)
+{
+       return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true);
+}
+
+/**
+ * rpmsg_send() - send a message across to the remote processor
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len on the @rpdev channel.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to, using @rpdev's source and destination addresses.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len)
+{
+       u32 src = rpdev->src, dst = rpdev->dst;
+
+       return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+
+/**
+ * rpmsg_sendto() - send a message across to the remote processor, specify dst
+ * @rpdev: the rpmsg channel
+ * @data: payload of message
+ * @len: length of payload
+ * @dst: destination address
+ *
+ * This function sends @data of length @len to the remote @dst address.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to, using @rpdev's source address.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
+{
+       u32 src = rpdev->src;
+
+       return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+
+/**
+ * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
+ * @rpdev: the rpmsg channel
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ *
+ * This function sends @data of length @len to the remote @dst address,
+ * and uses @src as the source address.
+ * The message will be sent to the remote processor which the @rpdev
+ * channel belongs to.
+ * In case there are no TX buffers available, the function will immediately
+ * return -ENOMEM without waiting until one becomes available.
+ *
+ * Can only be called from process context (for now).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+static inline
+int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+                                                       void *data, int len)
+{
+       return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
+}
+
+#endif /* _LINUX_RPMSG_H */
diff --git a/include/linux/sa11x0-dma.h b/include/linux/sa11x0-dma.h
new file mode 100644 (file)
index 0000000..65839a5
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SA11x0 DMA Engine support
+ *
+ * Copyright (C) 2012 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_SA11X0_DMA_H
+#define __LINUX_SA11X0_DMA_H
+
+struct dma_chan;
+
+#if defined(CONFIG_DMA_SA11X0) || defined(CONFIG_DMA_SA11X0_MODULE)
+bool sa11x0_dma_filter_fn(struct dma_chan *, void *);
+#else
+static inline bool sa11x0_dma_filter_fn(struct dma_chan *c, void *d)
+{
+       return false;
+}
+#endif
+
+#endif
index 9aaf5bf..ac9586d 100644 (file)
@@ -1,10 +1,12 @@
 #ifndef _LINUX_SCATTERLIST_H
 #define _LINUX_SCATTERLIST_H
 
+#include <linux/string.h>
+#include <linux/bug.h>
+#include <linux/mm.h>
+
 #include <asm/types.h>
 #include <asm/scatterlist.h>
-#include <linux/mm.h>
-#include <linux/string.h>
 #include <asm/io.h>
 
 struct sg_table {
index 704464d..81a173c 100644 (file)
@@ -552,6 +552,18 @@ struct signal_struct {
        int                     group_stop_count;
        unsigned int            flags; /* see SIGNAL_* flags below */
 
+       /*
+        * PR_SET_CHILD_SUBREAPER marks a process, like a service
+        * manager, to re-parent orphan (double-forking) child processes
+        * to this process instead of 'init'. The service manager is
+        * able to receive SIGCHLD signals and is able to investigate
+        * the process until it calls wait(). All children of this
+        * process will inherit a flag if they should look for a
+        * child_subreaper process at exit.
+        */
+       unsigned int            is_child_subreaper:1;
+       unsigned int            has_child_subreaper:1;
+
        /* POSIX.1b Interval Timers */
        struct list_head posix_timers;
 
index 44f1514..fc61854 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/bug.h>
 #include <linux/mutex.h>
 #include <linux/cpumask.h>
 #include <linux/nodemask.h>
@@ -121,9 +122,12 @@ int single_release(struct inode *, struct file *);
 void *__seq_open_private(struct file *, const struct seq_operations *, int);
 int seq_open_private(struct file *, const struct seq_operations *, int);
 int seq_release_private(struct inode *, struct file *);
+int seq_put_decimal_ull(struct seq_file *m, char delimiter,
+                       unsigned long long num);
+int seq_put_decimal_ll(struct seq_file *m, char delimiter,
+                       long long num);
 
 #define SEQ_START_TOKEN ((void *)1)
-
 /*
  * Helpers for iteration over list_head-s in seq_files
  */
index de6c19c..79ad87b 100644 (file)
@@ -20,7 +20,6 @@
 #define _LINUX_SERIAL_PNX8XXX_H
 
 #include <linux/serial_core.h>
-#include <linux/device.h>
 
 #define PNX8XXX_NR_PORTS       2
 
index 54341d8..0a9d8f2 100644 (file)
@@ -18,7 +18,8 @@ struct clk_mapping {
        struct kref             ref;
 };
 
-struct clk_ops {
+
+struct sh_clk_ops {
 #ifdef CONFIG_SH_CLK_CPG_LEGACY
        void (*init)(struct clk *clk);
 #endif
@@ -37,7 +38,7 @@ struct clk {
        unsigned short          parent_num;     /* choose between */
        unsigned char           src_shift;      /* source clock field in the */
        unsigned char           src_width;      /* configuration register */
-       struct clk_ops          *ops;
+       struct sh_clk_ops       *ops;
 
        struct list_head        children;
        struct list_head        sibling;        /* node for children */
index bf86abb..3337027 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/kmemcheck.h>
 #include <linux/compiler.h>
 #include <linux/time.h>
+#include <linux/bug.h>
 #include <linux/cache.h>
 
 #include <linux/atomic.h>
@@ -1243,7 +1244,7 @@ static inline void skb_fill_page_desc(struct sk_buff *skb, int i,
 }
 
 extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
-                           int off, int size);
+                           int off, int size, unsigned int truesize);
 
 #define SKB_PAGE_ASSERT(skb)   BUG_ON(skb_shinfo(skb)->nr_frags)
 #define SKB_FRAG_ASSERT(skb)   BUG_ON(skb_has_frag_list(skb))
index 573c809..a595dce 100644 (file)
@@ -190,7 +190,7 @@ size_t ksize(const void *);
 #endif
 
 /**
- * kcalloc - allocate memory for an array. The memory is set to zero.
+ * kmalloc_array - allocate memory for an array.
  * @n: number of elements.
  * @size: element size.
  * @flags: the type of memory to allocate.
@@ -240,11 +240,22 @@ size_t ksize(const void *);
  * for general use, and so are not documented here. For a full list of
  * potential flags, always refer to linux/gfp.h.
  */
-static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
+static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags)
 {
        if (size != 0 && n > ULONG_MAX / size)
                return NULL;
-       return __kmalloc(n * size, flags | __GFP_ZERO);
+       return __kmalloc(n * size, flags);
+}
+
+/**
+ * kcalloc - allocate memory for an array. The memory is set to zero.
+ * @n: number of elements.
+ * @size: element size.
+ * @flags: the type of memory to allocate (see kmalloc).
+ */
+static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
+{
+       return kmalloc_array(n, size, flags | __GFP_ZERO);
 }
 
 #if !defined(CONFIG_NUMA) && !defined(CONFIG_SLOB)
index a32bcfd..c2f8c8b 100644 (file)
@@ -8,6 +8,7 @@
  */
 #include <linux/types.h>
 #include <linux/gfp.h>
+#include <linux/bug.h>
 #include <linux/workqueue.h>
 #include <linux/kobject.h>
 
@@ -21,7 +22,7 @@ enum stat_item {
        FREE_FROZEN,            /* Freeing to frozen slab */
        FREE_ADD_PARTIAL,       /* Freeing moves slab to partial list */
        FREE_REMOVE_PARTIAL,    /* Freeing removes last object */
-       ALLOC_FROM_PARTIAL,     /* Cpu slab acquired from partial list */
+       ALLOC_FROM_PARTIAL,     /* Cpu slab acquired from node partial list */
        ALLOC_SLAB,             /* Cpu slab acquired from page allocator */
        ALLOC_REFILL,           /* Refill cpu slab from slab freelist */
        ALLOC_NODE_MISMATCH,    /* Switching cpu slab */
@@ -37,7 +38,9 @@ enum stat_item {
        CMPXCHG_DOUBLE_CPU_FAIL,/* Failure of this_cpu_cmpxchg_double */
        CMPXCHG_DOUBLE_FAIL,    /* Number of times that cmpxchg double did not match */
        CPU_PARTIAL_ALLOC,      /* Used cpu partial on alloc */
-       CPU_PARTIAL_FREE,       /* USed cpu partial on free */
+       CPU_PARTIAL_FREE,       /* Refill cpu partial on free */
+       CPU_PARTIAL_NODE,       /* Refill cpu partial from node partial */
+       CPU_PARTIAL_DRAIN,      /* Drain cpu partial to node partial */
        NR_SLUB_STAT_ITEMS };
 
 struct kmem_cache_cpu {
index 0f4eb16..32be8db 100644 (file)
@@ -1,10 +1,10 @@
 #ifndef __LINUX_SPI_MMC_SPI_H
 #define __LINUX_SPI_MMC_SPI_H
 
-#include <linux/device.h>
 #include <linux/spi/spi.h>
 #include <linux/interrupt.h>
 
+struct device;
 struct mmc_host;
 
 /* Put this in platform_data of a device being used to manage an MMC/SD
index decf6d8..b4d9fa6 100644 (file)
@@ -11,7 +11,6 @@
 
 struct orion_spi_info {
        u32     tclk;           /* no <linux/clk.h> support yet */
-       u32     enable_clock_fix;
 };
 
 
diff --git a/include/linux/spi/s3c24xx.h b/include/linux/spi/s3c24xx.h
new file mode 100644 (file)
index 0000000..c23b923
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - SPI Controller platform_device info
+ *
+ * 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_SPI_S3C24XX_H
+#define __LINUX_SPI_S3C24XX_H __FILE__
+
+struct s3c2410_spi_info {
+       int                      pin_cs;        /* simple gpio cs */
+       unsigned int             num_cs;        /* total chipselects */
+       int                      bus_num;       /* bus number to use. */
+
+       unsigned int             use_fiq:1;     /* use fiq */
+
+       void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);
+       void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
+};
+
+#endif /* __LINUX_SPI_S3C24XX_H */
index 8a98ddf..7d537ce 100644 (file)
@@ -375,10 +375,7 @@ static inline int spin_can_lock(spinlock_t *lock)
        return raw_spin_can_lock(&lock->rlock);
 }
 
-static inline void assert_spin_locked(spinlock_t *lock)
-{
-       assert_raw_spin_locked(&lock->rlock);
-}
+#define assert_spin_locked(lock)       assert_raw_spin_locked(&(lock)->rlock)
 
 /*
  * Pull the atomic_t declaration:
index eba52a1..6b05dcd 100644 (file)
@@ -2,6 +2,7 @@
 #define LINUX_SSB_DRIVER_GIGE_H_
 
 #include <linux/ssb/ssb.h>
+#include <linux/bug.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 
index 7874a8a..492a36d 100644 (file)
@@ -99,6 +99,8 @@ struct rpc_authops {
 
        struct rpc_cred *       (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);
        struct rpc_cred *       (*crcreate)(struct rpc_auth*, struct auth_cred *, int);
+       int                     (*pipes_create)(struct rpc_auth *);
+       void                    (*pipes_destroy)(struct rpc_auth *);
 };
 
 struct rpc_credops {
index f7f3ce3..969c0a6 100644 (file)
@@ -35,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt);
 void xprt_free_bc_request(struct rpc_rqst *req);
 int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs);
-void xprt_destroy_backchannel(struct rpc_xprt *, int max_reqs);
+void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs);
 int bc_send(struct rpc_rqst *req);
 
 /*
index 57531f8..f5fd616 100644 (file)
@@ -117,6 +117,7 @@ struct cache_detail {
                struct cache_detail_procfs procfs;
                struct cache_detail_pipefs pipefs;
        } u;
+       struct net              *net;
 };
 
 
@@ -197,11 +198,14 @@ extern void cache_flush(void);
 extern void cache_purge(struct cache_detail *detail);
 #define NEVER (0x7FFFFFFF)
 extern void __init cache_initialize(void);
-extern int cache_register(struct cache_detail *cd);
 extern int cache_register_net(struct cache_detail *cd, struct net *net);
-extern void cache_unregister(struct cache_detail *cd);
 extern void cache_unregister_net(struct cache_detail *cd, struct net *net);
 
+extern struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net);
+extern void cache_destroy_net(struct cache_detail *cd, struct net *net);
+
+extern void sunrpc_init_cache_detail(struct cache_detail *cd);
+extern void sunrpc_destroy_cache_detail(struct cache_detail *cd);
 extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
                                        umode_t, struct cache_detail *);
 extern void sunrpc_cache_unregister_pipefs(struct cache_detail *);
index 2c5993a..523547e 100644 (file)
@@ -35,14 +35,13 @@ struct rpc_clnt {
        struct list_head        cl_clients;     /* Global list of clients */
        struct list_head        cl_tasks;       /* List of tasks */
        spinlock_t              cl_lock;        /* spinlock */
-       struct rpc_xprt *       cl_xprt;        /* transport */
+       struct rpc_xprt __rcu * cl_xprt;        /* transport */
        struct rpc_procinfo *   cl_procinfo;    /* procedure info */
        u32                     cl_prog,        /* RPC program number */
                                cl_vers,        /* RPC version number */
                                cl_maxproc;     /* max procedure number */
 
-       char *                  cl_server;      /* server machine name */
-       char *                  cl_protname;    /* protocol name */
+       const char *            cl_protname;    /* protocol name */
        struct rpc_auth *       cl_auth;        /* authenticator */
        struct rpc_stat *       cl_stats;       /* per-program statistics */
        struct rpc_iostats *    cl_metrics;     /* per-client statistics */
@@ -57,12 +56,11 @@ struct rpc_clnt {
 
        int                     cl_nodelen;     /* nodename length */
        char                    cl_nodename[UNX_MAXNODENAME];
-       struct path             cl_path;
+       struct dentry *         cl_dentry;
        struct rpc_clnt *       cl_parent;      /* Points to parent of clones */
        struct rpc_rtt          cl_rtt_default;
        struct rpc_timeout      cl_timeout_default;
-       struct rpc_program *    cl_program;
-       char                    cl_inline_name[32];
+       const struct rpc_program *cl_program;
        char                    *cl_principal;  /* target to authenticate to */
 };
 
@@ -71,12 +69,12 @@ struct rpc_clnt {
  */
 #define RPC_MAXVERSION         4
 struct rpc_program {
-       char *                  name;           /* protocol name */
+       const char *            name;           /* protocol name */
        u32                     number;         /* program number */
        unsigned int            nrvers;         /* number of versions */
-       struct rpc_version **   version;        /* version array */
+       const struct rpc_version **     version;        /* version array */
        struct rpc_stat *       stats;          /* statistics */
-       char *                  pipe_dir_name;  /* path to rpc_pipefs dir */
+       const char *            pipe_dir_name;  /* path to rpc_pipefs dir */
 };
 
 struct rpc_version {
@@ -97,7 +95,7 @@ struct rpc_procinfo {
        unsigned int            p_count;        /* call count */
        unsigned int            p_timer;        /* Which RTT timer to use */
        u32                     p_statidx;      /* Which procedure to account */
-       char *                  p_name;         /* name of procedure */
+       const char *            p_name;         /* name of procedure */
 };
 
 #ifdef __KERNEL__
@@ -109,8 +107,8 @@ struct rpc_create_args {
        size_t                  addrsize;
        struct sockaddr         *saddress;
        const struct rpc_timeout *timeout;
-       char                    *servername;
-       struct rpc_program      *program;
+       const char              *servername;
+       const struct rpc_program *program;
        u32                     prognumber;     /* overrides program->number */
        u32                     version;
        rpc_authflavor_t        authflavor;
@@ -129,17 +127,18 @@ struct rpc_create_args {
 
 struct rpc_clnt *rpc_create(struct rpc_create_args *args);
 struct rpc_clnt        *rpc_bind_new_program(struct rpc_clnt *,
-                               struct rpc_program *, u32);
+                               const struct rpc_program *, u32);
 void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
 struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
 void           rpc_shutdown_client(struct rpc_clnt *);
 void           rpc_release_client(struct rpc_clnt *);
 void           rpc_task_release_client(struct rpc_task *);
 
-int            rpcb_create_local(void);
-void           rpcb_put_local(void);
-int            rpcb_register(u32, u32, int, unsigned short);
-int            rpcb_v4_register(const u32 program, const u32 version,
+int            rpcb_create_local(struct net *);
+void           rpcb_put_local(struct net *);
+int            rpcb_register(struct net *, u32, u32, int, unsigned short);
+int            rpcb_v4_register(struct net *net, const u32 program,
+                                const u32 version,
                                 const struct sockaddr *address,
                                 const char *netid);
 void           rpcb_getport_async(struct rpc_task *);
@@ -156,16 +155,19 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred,
 int            rpc_restart_call_prepare(struct rpc_task *);
 int            rpc_restart_call(struct rpc_task *);
 void           rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
+int            rpc_protocol(struct rpc_clnt *);
+struct net *   rpc_net_ns(struct rpc_clnt *);
 size_t         rpc_max_payload(struct rpc_clnt *);
 void           rpc_force_rebind(struct rpc_clnt *);
 size_t         rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
 const char     *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
+int            rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t);
 
 size_t         rpc_ntop(const struct sockaddr *, char *, const size_t);
-size_t         rpc_pton(const char *, const size_t,
+size_t         rpc_pton(struct net *, const char *, const size_t,
                         struct sockaddr *, const size_t);
 char *         rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t);
-size_t         rpc_uaddr2sockaddr(const char *, const size_t,
+size_t         rpc_uaddr2sockaddr(struct net *, const char *, const size_t,
                                   struct sockaddr *, const size_t);
 
 static inline unsigned short rpc_get_port(const struct sockaddr *sap)
index c2786f2..a76cc20 100644 (file)
 /*
  * Enable RPC debugging/profiling.
  */
-#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_SUNRPC_DEBUG
 #define  RPC_DEBUG
 #endif
+#ifdef CONFIG_TRACEPOINTS
+#define RPC_TRACEPOINTS
+#endif
 /* #define  RPC_PROFILE */
 
 /*
@@ -47,15 +50,32 @@ extern unsigned int         nlm_debug;
 #endif
 
 #define dprintk(args...)       dfprintk(FACILITY, ## args)
+#define dprintk_rcu(args...)   dfprintk_rcu(FACILITY, ## args)
 
 #undef ifdebug
 #ifdef RPC_DEBUG                       
 # define ifdebug(fac)          if (unlikely(rpc_debug & RPCDBG_##fac))
-# define dfprintk(fac, args...)        do { ifdebug(fac) printk(args); } while(0)
+
+# define dfprintk(fac, args...)        \
+       do { \
+               ifdebug(fac) \
+                       printk(KERN_DEFAULT args); \
+       } while (0)
+
+# define dfprintk_rcu(fac, args...)    \
+       do { \
+               ifdebug(fac) { \
+                       rcu_read_lock(); \
+                       printk(KERN_DEFAULT args); \
+                       rcu_read_unlock(); \
+               } \
+       } while (0)
+
 # define RPC_IFDEBUG(x)                x
 #else
 # define ifdebug(fac)          if (0)
-# define dfprintk(fac, args...)        do ; while (0)
+# define dfprintk(fac, args...)        do {} while (0)
+# define dfprintk_rcu(fac, args...)    do {} while (0)
 # define RPC_IFDEBUG(x)
 #endif
 
index b6edbc0..1565bbe 100644 (file)
@@ -74,14 +74,16 @@ struct rpc_clnt;
 #ifdef CONFIG_PROC_FS
 
 struct rpc_iostats *   rpc_alloc_iostats(struct rpc_clnt *);
-void                   rpc_count_iostats(struct rpc_task *);
+void                   rpc_count_iostats(const struct rpc_task *,
+                                         struct rpc_iostats *);
 void                   rpc_print_iostats(struct seq_file *, struct rpc_clnt *);
 void                   rpc_free_iostats(struct rpc_iostats *);
 
 #else  /*  CONFIG_PROC_FS  */
 
 static inline struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) { return NULL; }
-static inline void rpc_count_iostats(struct rpc_task *task) {}
+static inline void rpc_count_iostats(const struct rpc_task *task,
+                                    struct rpc_iostats *stats) {}
 static inline void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) {}
 static inline void rpc_free_iostats(struct rpc_iostats *stats) {}
 
index 2bb03d7..a7b422b 100644 (file)
@@ -21,21 +21,26 @@ struct rpc_pipe_ops {
        void (*destroy_msg)(struct rpc_pipe_msg *);
 };
 
-struct rpc_inode {
-       struct inode vfs_inode;
-       void *private;
+struct rpc_pipe {
        struct list_head pipe;
        struct list_head in_upcall;
        struct list_head in_downcall;
        int pipelen;
        int nreaders;
        int nwriters;
-       int nkern_readwriters;
-       wait_queue_head_t waitq;
 #define RPC_PIPE_WAIT_FOR_OPEN 1
        int flags;
        struct delayed_work queue_timeout;
        const struct rpc_pipe_ops *ops;
+       spinlock_t lock;
+       struct dentry *dentry;
+};
+
+struct rpc_inode {
+       struct inode vfs_inode;
+       void *private;
+       struct rpc_pipe *pipe;
+       wait_queue_head_t waitq;
 };
 
 static inline struct rpc_inode *
@@ -44,9 +49,28 @@ RPC_I(struct inode *inode)
        return container_of(inode, struct rpc_inode, vfs_inode);
 }
 
+enum {
+       SUNRPC_PIPEFS_NFS_PRIO,
+       SUNRPC_PIPEFS_RPC_PRIO,
+};
+
+extern int rpc_pipefs_notifier_register(struct notifier_block *);
+extern void rpc_pipefs_notifier_unregister(struct notifier_block *);
+
+enum {
+       RPC_PIPEFS_MOUNT,
+       RPC_PIPEFS_UMOUNT,
+};
+
+extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
+                                     const unsigned char *dir_name);
+extern void rpc_pipefs_init_net(struct net *net);
+extern struct super_block *rpc_get_sb_net(const struct net *net);
+extern void rpc_put_sb_net(const struct net *net);
+
 extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *,
                                       char __user *, size_t);
-extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
+extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *);
 
 struct rpc_clnt;
 extern struct dentry *rpc_create_client_dir(struct dentry *, struct qstr *, struct rpc_clnt *);
@@ -59,11 +83,13 @@ extern struct dentry *rpc_create_cache_dir(struct dentry *,
                                           struct cache_detail *);
 extern void rpc_remove_cache_dir(struct dentry *);
 
-extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *,
-                                const struct rpc_pipe_ops *, int flags);
+extern int rpc_rmdir(struct dentry *dentry);
+
+struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags);
+void rpc_destroy_pipe_data(struct rpc_pipe *pipe);
+extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *,
+                                       struct rpc_pipe *);
 extern int rpc_unlink(struct dentry *);
-extern struct vfsmount *rpc_get_mount(void);
-extern void rpc_put_mount(void);
 extern int register_rpc_pipefs(void);
 extern void unregister_rpc_pipefs(void);
 
index e775689..dc0c3cc 100644 (file)
@@ -103,6 +103,7 @@ typedef void                        (*rpc_action)(struct rpc_task *);
 struct rpc_call_ops {
        void (*rpc_call_prepare)(struct rpc_task *, void *);
        void (*rpc_call_done)(struct rpc_task *, void *);
+       void (*rpc_count_stats)(struct rpc_task *, void *);
        void (*rpc_release)(void *);
 };
 
@@ -195,7 +196,7 @@ struct rpc_wait_queue {
        unsigned char           nr;                     /* # tasks remaining for cookie */
        unsigned short          qlen;                   /* total # tasks waiting in queue */
        struct rpc_timer        timer_list;
-#ifdef RPC_DEBUG
+#if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS)
        const char *            name;
 #endif
 };
@@ -235,6 +236,9 @@ void                rpc_wake_up_queued_task(struct rpc_wait_queue *,
                                        struct rpc_task *);
 void           rpc_wake_up(struct rpc_wait_queue *);
 struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
+struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *,
+                                       bool (*)(struct rpc_task *, void *),
+                                       void *);
 void           rpc_wake_up_status(struct rpc_wait_queue *, int);
 int            rpc_queue_empty(struct rpc_wait_queue *);
 void           rpc_delay(struct rpc_task *, unsigned long);
@@ -244,7 +248,8 @@ int         rpciod_up(void);
 void           rpciod_down(void);
 int            __rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *));
 #ifdef RPC_DEBUG
-void           rpc_show_tasks(void);
+struct net;
+void           rpc_show_tasks(struct net *);
 #endif
 int            rpc_init_mempool(void);
 void           rpc_destroy_mempool(void);
@@ -266,11 +271,22 @@ static inline int rpc_task_has_priority(struct rpc_task *task, unsigned char pri
        return (task->tk_priority + RPC_PRIORITY_LOW == prio);
 }
 
-#ifdef RPC_DEBUG
-static inline const char * rpc_qname(struct rpc_wait_queue *q)
+#if defined(RPC_DEBUG) || defined (RPC_TRACEPOINTS)
+static inline const char * rpc_qname(const struct rpc_wait_queue *q)
 {
        return ((q && q->name) ? q->name : "unknown");
 }
+
+static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q,
+               const char *name)
+{
+       q->name = name;
+}
+#else
+static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q,
+               const char *name)
+{
+}
 #endif
 
 #endif /* _LINUX_SUNRPC_SCHED_H_ */
index 680471d..edc6421 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/proc_fs.h>
 
 struct rpc_stat {
-       struct rpc_program *    program;
+       const struct rpc_program *program;
 
        unsigned int            netcnt,
                                netudpcnt,
@@ -58,24 +58,24 @@ void                        rpc_modcount(struct inode *, int);
 #endif
 
 #ifdef CONFIG_PROC_FS
-struct proc_dir_entry *        rpc_proc_register(struct rpc_stat *);
-void                   rpc_proc_unregister(const char *);
-void                   rpc_proc_zero(struct rpc_program *);
-struct proc_dir_entry *        svc_proc_register(struct svc_stat *,
+struct proc_dir_entry *        rpc_proc_register(struct net *,struct rpc_stat *);
+void                   rpc_proc_unregister(struct net *,const char *);
+void                   rpc_proc_zero(const struct rpc_program *);
+struct proc_dir_entry *        svc_proc_register(struct net *, struct svc_stat *,
                                          const struct file_operations *);
-void                   svc_proc_unregister(const char *);
+void                   svc_proc_unregister(struct net *, const char *);
 
 void                   svc_seq_show(struct seq_file *,
                                     const struct svc_stat *);
 #else
 
-static inline struct proc_dir_entry *rpc_proc_register(struct rpc_stat *s) { return NULL; }
-static inline void rpc_proc_unregister(const char *p) {}
-static inline void rpc_proc_zero(struct rpc_program *p) {}
+static inline struct proc_dir_entry *rpc_proc_register(struct net *net, struct rpc_stat *s) { return NULL; }
+static inline void rpc_proc_unregister(struct net *net, const char *p) {}
+static inline void rpc_proc_zero(const struct rpc_program *p) {}
 
-static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s,
+static inline struct proc_dir_entry *svc_proc_register(struct net *net, struct svc_stat *s,
                                                       const struct file_operations *f) { return NULL; }
-static inline void svc_proc_unregister(const char *p) {}
+static inline void svc_proc_unregister(struct net *net, const char *p) {}
 
 static inline void svc_seq_show(struct seq_file *seq,
                                const struct svc_stat *st) {}
index 35b37b1..51b29ac 100644 (file)
@@ -84,7 +84,8 @@ struct svc_serv {
        unsigned int            sv_nrpools;     /* number of thread pools */
        struct svc_pool *       sv_pools;       /* array of thread pools */
 
-       void                    (*sv_shutdown)(struct svc_serv *serv);
+       void                    (*sv_shutdown)(struct svc_serv *serv,
+                                              struct net *net);
                                                /* Callback to use when last thread
                                                 * exits.
                                                 */
@@ -413,22 +414,24 @@ struct svc_procedure {
 /*
  * Function prototypes.
  */
-void svc_rpcb_cleanup(struct svc_serv *serv);
+int svc_rpcb_setup(struct svc_serv *serv, struct net *net);
+void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
 struct svc_serv *svc_create(struct svc_program *, unsigned int,
-                           void (*shutdown)(struct svc_serv *));
+                           void (*shutdown)(struct svc_serv *, struct net *net));
 struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
                                        struct svc_pool *pool, int node);
 void              svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
-                       void (*shutdown)(struct svc_serv *),
+                       void (*shutdown)(struct svc_serv *, struct net *net),
                        svc_thread_fn, struct module *);
 int               svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
 int               svc_pool_stats_open(struct svc_serv *serv, struct file *file);
 void              svc_destroy(struct svc_serv *);
+void              svc_shutdown_net(struct svc_serv *, struct net *);
 int               svc_process(struct svc_rqst *);
 int               bc_svc_process(struct svc_serv *, struct rpc_rqst *,
                        struct svc_rqst *);
-int               svc_register(const struct svc_serv *, const int,
+int               svc_register(const struct svc_serv *, struct net *, const int,
                                const unsigned short, const unsigned short);
 
 void              svc_wake_up(struct svc_serv *);
index dfa9009..b3f64b1 100644 (file)
@@ -121,7 +121,8 @@ void        svc_close_xprt(struct svc_xprt *xprt);
 int    svc_port_is_privileged(struct sockaddr *sin);
 int    svc_print_xprts(char *buf, int maxlen);
 struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
-                       const sa_family_t af, const unsigned short port);
+                       struct net *net, const sa_family_t af,
+                       const unsigned short port);
 int    svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
 
 static inline void svc_xprt_get(struct svc_xprt *xprt)
index 25d333c..548790e 100644 (file)
@@ -135,6 +135,9 @@ extern void svcauth_unix_purge(void);
 extern void svcauth_unix_info_release(struct svc_xprt *xpt);
 extern int svcauth_unix_set_client(struct svc_rqst *rqstp);
 
+extern int unix_gid_cache_create(struct net *net);
+extern void unix_gid_cache_destroy(struct net *net);
+
 static inline unsigned long hash_str(char *name, int bits)
 {
        unsigned long hash = 0;
index 83bbee3..7c32daa 100644 (file)
@@ -18,6 +18,8 @@
 
 int gss_svc_init(void);
 void gss_svc_shutdown(void);
+int gss_svc_init_net(struct net *net);
+void gss_svc_shutdown_net(struct net *net);
 int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
 u32 svcauth_gss_flavor(struct auth_domain *dom);
 char *svc_gss_principal(struct svc_rqst *);
index c84e974..cb4ac69 100644 (file)
@@ -34,7 +34,7 @@ struct svc_sock {
 /*
  * Function prototypes.
  */
-void           svc_close_all(struct svc_serv *);
+void           svc_close_net(struct svc_serv *, struct net *);
 int            svc_recv(struct svc_rqst *, long);
 int            svc_send(struct svc_rqst *);
 void           svc_drop(struct svc_rqst *);
index 15518a1..77d278d 100644 (file)
@@ -21,8 +21,8 @@
 
 #define RPC_MIN_SLOT_TABLE     (2U)
 #define RPC_DEF_SLOT_TABLE     (16U)
-#define RPC_MAX_SLOT_TABLE     (128U)
 #define RPC_MAX_SLOT_TABLE_LIMIT       (65536U)
+#define RPC_MAX_SLOT_TABLE     RPC_MAX_SLOT_TABLE_LIMIT
 
 /*
  * This describes a timeout strategy
@@ -219,13 +219,17 @@ struct rpc_xprt {
                                        connect_time,   /* jiffies waiting for connect */
                                        sends,          /* how many complete requests */
                                        recvs,          /* how many complete requests */
-                                       bad_xids;       /* lookup_rqst didn't find XID */
+                                       bad_xids,       /* lookup_rqst didn't find XID */
+                                       max_slots;      /* max rpc_slots used */
 
                unsigned long long      req_u,          /* average requests on the wire */
-                                       bklog_u;        /* backlog queue utilization */
+                                       bklog_u,        /* backlog queue utilization */
+                                       sending_u,      /* send q utilization */
+                                       pending_u;      /* pend q utilization */
        } stat;
 
        struct net              *xprt_net;
+       const char              *servername;
        const char              *address_strings[RPC_DISPLAY_MAX];
 };
 
@@ -255,6 +259,7 @@ struct xprt_create {
        struct sockaddr *       srcaddr;        /* optional local address */
        struct sockaddr *       dstaddr;        /* remote peer address */
        size_t                  addrlen;
+       const char              *servername;
        struct svc_xprt         *bc_xprt;       /* NFSv4.1 backchannel */
 };
 
index 3f14a02..1ad36cc 100644 (file)
 int            init_socket_xprt(void);
 void           cleanup_socket_xprt(void);
 
-/*
- * RPC slot table sizes for UDP, TCP transports
- */
-extern unsigned int xprt_udp_slot_table_entries;
-extern unsigned int xprt_tcp_slot_table_entries;
-
-/*
- * Parameters for choosing a free port
- */
-extern unsigned int xprt_min_resvport;
-extern unsigned int xprt_max_resvport;
-
 #define RPC_MIN_RESVPORT       (1U)
 #define RPC_MAX_RESVPORT       (65535U)
 #define RPC_DEF_MIN_RESVPORT   (665U)
index 2189d3f..792d16d 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_SWAPOPS_H
 
 #include <linux/radix-tree.h>
+#include <linux/bug.h>
 
 /*
  * swapcache pages are stored in the swapper_space radix tree.  We want to
index 8ec1153..3de3acb 100644 (file)
@@ -68,6 +68,7 @@ struct file_handle;
 #include <linux/aio_abi.h>
 #include <linux/capability.h>
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <linux/sem.h>
 #include <asm/siginfo.h>
 #include <asm/signal.h>
index bb9127d..c34b4c8 100644 (file)
@@ -932,34 +932,14 @@ enum
 #include <linux/list.h>
 #include <linux/rcupdate.h>
 #include <linux/wait.h>
+#include <linux/rbtree.h>
 
 /* For the /proc/sys support */
 struct ctl_table;
 struct nsproxy;
 struct ctl_table_root;
-
-struct ctl_table_set {
-       struct list_head list;
-       struct ctl_table_set *parent;
-       int (*is_seen)(struct ctl_table_set *);
-};
-
-extern void setup_sysctl_set(struct ctl_table_set *p,
-       struct ctl_table_set *parent,
-       int (*is_seen)(struct ctl_table_set *));
-
 struct ctl_table_header;
-
-extern void sysctl_head_get(struct ctl_table_header *);
-extern void sysctl_head_put(struct ctl_table_header *);
-extern int sysctl_is_seen(struct ctl_table_header *);
-extern struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *);
-extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev);
-extern struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
-                                               struct ctl_table_header *prev);
-extern void sysctl_head_finish(struct ctl_table_header *prev);
-extern int sysctl_perm(struct ctl_table_root *root,
-               struct ctl_table *table, int op);
+struct ctl_dir;
 
 typedef struct ctl_table ctl_table;
 
@@ -1023,8 +1003,6 @@ static inline void *proc_sys_poll_event(struct ctl_table_poll *poll)
        return (void *)(unsigned long)atomic_read(&poll->event);
 }
 
-void proc_sys_poll_notify(struct ctl_table_poll *poll);
-
 #define __CTL_TABLE_POLL_INITIALIZER(name) {                           \
        .event = ATOMIC_INIT(0),                                        \
        .wait = __WAIT_QUEUE_HEAD_INITIALIZER(name.wait) }
@@ -1039,21 +1017,16 @@ struct ctl_table
        void *data;
        int maxlen;
        umode_t mode;
-       struct ctl_table *child;
-       struct ctl_table *parent;       /* Automatically set */
+       struct ctl_table *child;        /* Deprecated */
        proc_handler *proc_handler;     /* Callback for text formatting */
        struct ctl_table_poll *poll;
        void *extra1;
        void *extra2;
 };
 
-struct ctl_table_root {
-       struct list_head root_list;
-       struct ctl_table_set default_set;
-       struct ctl_table_set *(*lookup)(struct ctl_table_root *root,
-                                          struct nsproxy *namespaces);
-       int (*permissions)(struct ctl_table_root *root,
-                       struct nsproxy *namespaces, struct ctl_table *table);
+struct ctl_node {
+       struct rb_node node;
+       struct ctl_table_header *header;
 };
 
 /* struct ctl_table_header is used to maintain dynamic lists of
@@ -1063,9 +1036,9 @@ struct ctl_table_header
        union {
                struct {
                        struct ctl_table *ctl_table;
-                       struct list_head ctl_entry;
                        int used;
                        int count;
+                       int nreg;
                };
                struct rcu_head rcu;
        };
@@ -1073,9 +1046,27 @@ struct ctl_table_header
        struct ctl_table *ctl_table_arg;
        struct ctl_table_root *root;
        struct ctl_table_set *set;
-       struct ctl_table *attached_by;
-       struct ctl_table *attached_to;
-       struct ctl_table_header *parent;
+       struct ctl_dir *parent;
+       struct ctl_node *node;
+};
+
+struct ctl_dir {
+       /* Header must be at the start of ctl_dir */
+       struct ctl_table_header header;
+       struct rb_root root;
+};
+
+struct ctl_table_set {
+       int (*is_seen)(struct ctl_table_set *);
+       struct ctl_dir dir;
+};
+
+struct ctl_table_root {
+       struct ctl_table_set default_set;
+       struct ctl_table_set *(*lookup)(struct ctl_table_root *root,
+                                          struct nsproxy *namespaces);
+       int (*permissions)(struct ctl_table_root *root,
+                       struct nsproxy *namespaces, struct ctl_table *table);
 };
 
 /* struct ctl_path describes where in the hierarchy a table is added */
@@ -1083,16 +1074,53 @@ struct ctl_path {
        const char *procname;
 };
 
+#ifdef CONFIG_SYSCTL
+
+void proc_sys_poll_notify(struct ctl_table_poll *poll);
+
+extern void setup_sysctl_set(struct ctl_table_set *p,
+       struct ctl_table_root *root,
+       int (*is_seen)(struct ctl_table_set *));
+extern void retire_sysctl_set(struct ctl_table_set *set);
+
 void register_sysctl_root(struct ctl_table_root *root);
+struct ctl_table_header *__register_sysctl_table(
+       struct ctl_table_set *set,
+       const char *path, struct ctl_table *table);
 struct ctl_table_header *__register_sysctl_paths(
-       struct ctl_table_root *root, struct nsproxy *namespaces,
+       struct ctl_table_set *set,
        const struct ctl_path *path, struct ctl_table *table);
+struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table);
 struct ctl_table_header *register_sysctl_table(struct ctl_table * table);
 struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
                                                struct ctl_table *table);
 
 void unregister_sysctl_table(struct ctl_table_header * table);
-int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table);
+
+extern int sysctl_init(void);
+#else /* CONFIG_SYSCTL */
+static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
+{
+       return NULL;
+}
+
+static inline struct ctl_table_header *register_sysctl_paths(
+                       const struct ctl_path *path, struct ctl_table *table)
+{
+       return NULL;
+}
+
+static inline void unregister_sysctl_table(struct ctl_table_header * table)
+{
+}
+
+static inline void setup_sysctl_set(struct ctl_table_set *p,
+       struct ctl_table_root *root,
+       int (*is_seen)(struct ctl_table_set *))
+{
+}
+
+#endif /* CONFIG_SYSCTL */
 
 #endif /* __KERNEL__ */
 
index a71a292..51bd91d 100644 (file)
@@ -54,12 +54,12 @@ struct linux_binprm;
 /*
  * ptrace report for syscall entry and exit looks identical.
  */
-static inline void ptrace_report_syscall(struct pt_regs *regs)
+static inline int ptrace_report_syscall(struct pt_regs *regs)
 {
        int ptrace = current->ptrace;
 
        if (!(ptrace & PT_PTRACED))
-               return;
+               return 0;
 
        ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
 
@@ -72,6 +72,8 @@ static inline void ptrace_report_syscall(struct pt_regs *regs)
                send_sig(current->exit_code, current, 1);
                current->exit_code = 0;
        }
+
+       return fatal_signal_pending(current);
 }
 
 /**
@@ -96,8 +98,7 @@ static inline void ptrace_report_syscall(struct pt_regs *regs)
 static inline __must_check int tracehook_report_syscall_entry(
        struct pt_regs *regs)
 {
-       ptrace_report_syscall(regs);
-       return 0;
+       return ptrace_report_syscall(regs);
 }
 
 /**
index 9ae8da3..11087cd 100644 (file)
@@ -10,6 +10,7 @@
 #define _TRANSPORT_CLASS_H_
 
 #include <linux/device.h>
+#include <linux/bug.h>
 #include <linux/attribute_container.h>
 
 struct transport_container;
index 5e11f8a..c9c9a46 100644 (file)
@@ -235,16 +235,25 @@ struct v4l2_fract {
        __u32   denominator;
 };
 
-/*
- *     D R I V E R   C A P A B I L I T I E S
- */
+/**
+  * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP
+  *
+  * @driver:      name of the driver module (e.g. "bttv")
+  * @card:        name of the card (e.g. "Hauppauge WinTV")
+  * @bus_info:    name of the bus (e.g. "PCI:" + pci_name(pci_dev) )
+  * @version:     KERNEL_VERSION
+  * @capabilities: capabilities of the physical device as a whole
+  * @device_caps:  capabilities accessed via this particular device (node)
+  * @reserved:    reserved fields for future extensions
+  */
 struct v4l2_capability {
-       __u8    driver[16];     /* i.e. "bttv" */
-       __u8    card[32];       /* i.e. "Hauppauge WinTV" */
-       __u8    bus_info[32];   /* "PCI:" + pci_name(pci_dev) */
-       __u32   version;        /* should use KERNEL_VERSION() */
-       __u32   capabilities;   /* Device capabilities */
-       __u32   reserved[4];
+       __u8    driver[16];
+       __u8    card[32];
+       __u8    bus_info[32];
+       __u32   version;
+       __u32   capabilities;
+       __u32   device_caps;
+       __u32   reserved[3];
 };
 
 /* Values for 'capabilities' field */
@@ -274,6 +283,8 @@ struct v4l2_capability {
 #define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
 #define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
 
+#define V4L2_CAP_DEVICE_CAPS            0x80000000  /* sets device capabilities field */
+
 /*
  *     V I D E O   I M A G E   F O R M A T
  */
@@ -751,20 +762,20 @@ struct v4l2_crop {
 
 /* Selection targets */
 
-/* current cropping area */
-#define V4L2_SEL_TGT_CROP_ACTIVE       0
-/* default cropping area */
-#define V4L2_SEL_TGT_CROP_DEFAULT      1
-/* cropping bounds */
-#define V4L2_SEL_TGT_CROP_BOUNDS       2
-/* current composing area */
-#define V4L2_SEL_TGT_COMPOSE_ACTIVE    256
-/* default composing area */
-#define V4L2_SEL_TGT_COMPOSE_DEFAULT   257
-/* composing bounds */
-#define V4L2_SEL_TGT_COMPOSE_BOUNDS    258
-/* current composing area plus all padding pixels */
-#define V4L2_SEL_TGT_COMPOSE_PADDED    259
+/* 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
@@ -774,7 +785,7 @@ struct v4l2_crop {
  * @r:         coordinates of selection window
  * @reserved:  for future use, rounds structure size to 64 bytes, set to zero
  *
- * Hardware may use multiple helper window to process a video stream.
+ * Hardware may use multiple helper windows to process a video stream.
  * The structure is used to exchange this selection areas between
  * an application and a driver.
  */
@@ -1125,6 +1136,7 @@ struct v4l2_ext_controls {
 #define V4L2_CTRL_CLASS_CAMERA 0x009a0000      /* Camera class controls */
 #define V4L2_CTRL_CLASS_FM_TX 0x009b0000       /* FM Modulator control class */
 #define V4L2_CTRL_CLASS_FLASH 0x009c0000       /* Camera flash controls */
+#define V4L2_CTRL_CLASS_JPEG 0x009d0000                /* JPEG-compression controls */
 
 #define V4L2_CTRL_ID_MASK                (0x0fffffff)
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
@@ -1396,6 +1408,16 @@ enum v4l2_mpeg_audio_ac3_bitrate {
        V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17,
        V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18,
 };
+#define V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK       (V4L2_CID_MPEG_BASE+112)
+enum v4l2_mpeg_audio_dec_playback {
+       V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO           = 0,
+       V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO         = 1,
+       V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT           = 2,
+       V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT          = 3,
+       V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO           = 4,
+       V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO = 5,
+};
+#define V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK (V4L2_CID_MPEG_BASE+113)
 
 /*  MPEG video controls specific to multiplexed streams */
 #define V4L2_CID_MPEG_VIDEO_ENCODING           (V4L2_CID_MPEG_BASE+200)
@@ -1446,6 +1468,9 @@ enum v4l2_mpeg_video_multi_slice_mode {
        V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES       = 2,
 };
 #define V4L2_CID_MPEG_VIDEO_VBV_SIZE                   (V4L2_CID_MPEG_BASE+222)
+#define V4L2_CID_MPEG_VIDEO_DEC_PTS                    (V4L2_CID_MPEG_BASE+223)
+#define V4L2_CID_MPEG_VIDEO_DEC_FRAME                  (V4L2_CID_MPEG_BASE+224)
+
 #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP            (V4L2_CID_MPEG_BASE+300)
 #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP            (V4L2_CID_MPEG_BASE+301)
 #define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP            (V4L2_CID_MPEG_BASE+302)
@@ -1734,6 +1759,29 @@ enum v4l2_flash_strobe_source {
 #define V4L2_CID_FLASH_CHARGE                  (V4L2_CID_FLASH_CLASS_BASE + 11)
 #define V4L2_CID_FLASH_READY                   (V4L2_CID_FLASH_CLASS_BASE + 12)
 
+/*  JPEG-class control IDs defined by V4L2 */
+#define V4L2_CID_JPEG_CLASS_BASE               (V4L2_CTRL_CLASS_JPEG | 0x900)
+#define V4L2_CID_JPEG_CLASS                    (V4L2_CTRL_CLASS_JPEG | 1)
+
+#define        V4L2_CID_JPEG_CHROMA_SUBSAMPLING        (V4L2_CID_JPEG_CLASS_BASE + 1)
+enum v4l2_jpeg_chroma_subsampling {
+       V4L2_JPEG_CHROMA_SUBSAMPLING_444        = 0,
+       V4L2_JPEG_CHROMA_SUBSAMPLING_422        = 1,
+       V4L2_JPEG_CHROMA_SUBSAMPLING_420        = 2,
+       V4L2_JPEG_CHROMA_SUBSAMPLING_411        = 3,
+       V4L2_JPEG_CHROMA_SUBSAMPLING_410        = 4,
+       V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY       = 5,
+};
+#define        V4L2_CID_JPEG_RESTART_INTERVAL          (V4L2_CID_JPEG_CLASS_BASE + 2)
+#define        V4L2_CID_JPEG_COMPRESSION_QUALITY       (V4L2_CID_JPEG_CLASS_BASE + 3)
+
+#define        V4L2_CID_JPEG_ACTIVE_MARKER             (V4L2_CID_JPEG_CLASS_BASE + 4)
+#define        V4L2_JPEG_ACTIVE_MARKER_APP0            (1 << 0)
+#define        V4L2_JPEG_ACTIVE_MARKER_APP1            (1 << 1)
+#define        V4L2_JPEG_ACTIVE_MARKER_COM             (1 << 16)
+#define        V4L2_JPEG_ACTIVE_MARKER_DQT             (1 << 17)
+#define        V4L2_JPEG_ACTIVE_MARKER_DHT             (1 << 18)
+
 /*
  *     T U N I N G
  */
@@ -1897,6 +1945,54 @@ struct v4l2_encoder_cmd {
        };
 };
 
+/* Decoder commands */
+#define V4L2_DEC_CMD_START       (0)
+#define V4L2_DEC_CMD_STOP        (1)
+#define V4L2_DEC_CMD_PAUSE       (2)
+#define V4L2_DEC_CMD_RESUME      (3)
+
+/* Flags for V4L2_DEC_CMD_START */
+#define V4L2_DEC_CMD_START_MUTE_AUDIO  (1 << 0)
+
+/* Flags for V4L2_DEC_CMD_PAUSE */
+#define V4L2_DEC_CMD_PAUSE_TO_BLACK    (1 << 0)
+
+/* Flags for V4L2_DEC_CMD_STOP */
+#define V4L2_DEC_CMD_STOP_TO_BLACK     (1 << 0)
+#define V4L2_DEC_CMD_STOP_IMMEDIATELY  (1 << 1)
+
+/* Play format requirements (returned by the driver): */
+
+/* The decoder has no special format requirements */
+#define V4L2_DEC_START_FMT_NONE                (0)
+/* The decoder requires full GOPs */
+#define V4L2_DEC_START_FMT_GOP         (1)
+
+/* The structure must be zeroed before use by the application
+   This ensures it can be extended safely in the future. */
+struct v4l2_decoder_cmd {
+       __u32 cmd;
+       __u32 flags;
+       union {
+               struct {
+                       __u64 pts;
+               } stop;
+
+               struct {
+                       /* 0 or 1000 specifies normal speed,
+                          1 specifies forward single stepping,
+                          -1 specifies backward single stepping,
+                          >1: playback at speed/1000 of the normal speed,
+                          <-1: reverse playback at (-speed/1000) of the normal speed. */
+                       __s32 speed;
+                       __u32 format;
+               } start;
+
+               struct {
+                       __u32 data[16];
+               } raw;
+       };
+};
 #endif
 
 
@@ -2307,6 +2403,11 @@ struct v4l2_create_buffers {
 #define VIDIOC_G_SELECTION     _IOWR('V', 94, struct v4l2_selection)
 #define VIDIOC_S_SELECTION     _IOWR('V', 95, struct v4l2_selection)
 
+/* Experimental, these two ioctls may change over the next couple of kernel
+   versions. */
+#define VIDIOC_DECODER_CMD     _IOWR('V', 96, struct v4l2_decoder_cmd)
+#define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
index 5206d65..7323a33 100644 (file)
@@ -53,6 +53,7 @@
 
 #ifdef __KERNEL__
 #include <linux/err.h>
+#include <linux/bug.h>
 #include <linux/virtio.h>
 
 /**
index c5d8455..7529b85 100644 (file)
@@ -34,6 +34,7 @@
 #define VIRTIO_ID_CONSOLE      3 /* virtio console */
 #define VIRTIO_ID_RNG          4 /* virtio ring */
 #define VIRTIO_ID_BALLOON      5 /* virtio balloon */
+#define VIRTIO_ID_RPMSG                7 /* virtio remote processor messaging */
 #define VIRTIO_ID_SCSI         8 /* virtio scsi */
 #define VIRTIO_ID_9P           9 /* 9p virtio console */
 
index 43ba5b3..ac40716 100644 (file)
@@ -66,6 +66,7 @@ struct watchdog_device;
  * @ping:      The routine that sends a keepalive ping to the watchdog device.
  * @status:    The routine that shows the status of the watchdog device.
  * @set_timeout:The routine for setting the watchdog devices timeout value.
+ * @get_timeleft:The routine that get's the time that's left before a reset.
  * @ioctl:     The routines that handles extra ioctl calls.
  *
  * The watchdog_ops structure contains a list of low-level operations
@@ -82,6 +83,7 @@ struct watchdog_ops {
        int (*ping)(struct watchdog_device *);
        unsigned int (*status)(struct watchdog_device *);
        int (*set_timeout)(struct watchdog_device *, unsigned int);
+       unsigned int (*get_timeleft)(struct watchdog_device *);
        long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
 };
 
@@ -127,7 +129,7 @@ struct watchdog_device {
 #endif
 
 /* Use the following function to set the nowayout feature */
-static inline void watchdog_set_nowayout(struct watchdog_device *wdd, int nowayout)
+static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool nowayout)
 {
        if (nowayout)
                set_bit(WDOG_NO_WAY_OUT, &wdd->status);
index 57031b4..aaf24ba 100644 (file)
 #define __debug__h__
 
 #include <linux/types.h>
-#include <linux/device.h>
 #include <linux/slab.h>
 
+struct device;
 
 /* Backend stuff */
 
diff --git a/include/media/adv7183.h b/include/media/adv7183.h
new file mode 100644 (file)
index 0000000..c5c2d37
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * adv7183.h - definition for adv7183 inputs and outputs
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _ADV7183_H_
+#define _ADV7183_H_
+
+/* ADV7183 HW inputs */
+#define ADV7183_COMPOSITE0  0  /* CVBS in on AIN1 */
+#define ADV7183_COMPOSITE1  1  /* CVBS in on AIN2 */
+#define ADV7183_COMPOSITE2  2  /* CVBS in on AIN3 */
+#define ADV7183_COMPOSITE3  3  /* CVBS in on AIN4 */
+#define ADV7183_COMPOSITE4  4  /* CVBS in on AIN5 */
+#define ADV7183_COMPOSITE5  5  /* CVBS in on AIN6 */
+#define ADV7183_COMPOSITE6  6  /* CVBS in on AIN7 */
+#define ADV7183_COMPOSITE7  7  /* CVBS in on AIN8 */
+#define ADV7183_COMPOSITE8  8  /* CVBS in on AIN9 */
+#define ADV7183_COMPOSITE9  9  /* CVBS in on AIN10 */
+#define ADV7183_COMPOSITE10 10 /* CVBS in on AIN11 */
+
+#define ADV7183_SVIDEO0     11 /* Y on AIN1, C on AIN4 */
+#define ADV7183_SVIDEO1     12 /* Y on AIN2, C on AIN5 */
+#define ADV7183_SVIDEO2     13 /* Y on AIN3, C on AIN6 */
+
+#define ADV7183_COMPONENT0  14 /* Y on AIN1, Pr on AIN4, Pb on AIN5 */
+#define ADV7183_COMPONENT1  15 /* Y on AIN2, Pr on AIN3, Pb on AIN6 */
+
+/* ADV7183 HW outputs */
+#define ADV7183_8BIT_OUT    0
+#define ADV7183_16BIT_OUT   1
+
+#endif
diff --git a/include/media/blackfin/bfin_capture.h b/include/media/blackfin/bfin_capture.h
new file mode 100644 (file)
index 0000000..2038a8a
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _BFIN_CAPTURE_H_
+#define _BFIN_CAPTURE_H_
+
+#include <linux/i2c.h>
+
+struct v4l2_input;
+struct ppi_info;
+
+struct bcap_route {
+       u32 input;
+       u32 output;
+};
+
+struct bfin_capture_config {
+       /* card name */
+       char *card_name;
+       /* inputs available at the sub device */
+       struct v4l2_input *inputs;
+       /* number of inputs supported */
+       int num_inputs;
+       /* routing information for each input */
+       struct bcap_route *routes;
+       /* i2c bus adapter no */
+       int i2c_adapter_id;
+       /* i2c subdevice board info */
+       struct i2c_board_info board_info;
+       /* ppi board info */
+       const struct ppi_info *ppi_info;
+       /* ppi control */
+       unsigned long ppi_control;
+       /* ppi interrupt mask */
+       u32 int_mask;
+       /* horizontal blanking clocks */
+       int blank_clocks;
+};
+
+#endif
diff --git a/include/media/blackfin/ppi.h b/include/media/blackfin/ppi.h
new file mode 100644 (file)
index 0000000..8f72f8a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Analog Devices PPI header file
+ *
+ * Copyright (c) 2011 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PPI_H_
+#define _PPI_H_
+
+#include <linux/interrupt.h>
+
+#ifdef EPPI_EN
+#define PORT_EN EPPI_EN
+#define DMA32 0
+#define PACK_EN PACKEN
+#endif
+
+struct ppi_if;
+
+struct ppi_params {
+       int width;
+       int height;
+       int bpp;
+       unsigned long ppi_control;
+       u32 int_mask;
+       int blank_clocks;
+};
+
+struct ppi_ops {
+       int (*attach_irq)(struct ppi_if *ppi, irq_handler_t handler);
+       void (*detach_irq)(struct ppi_if *ppi);
+       int (*start)(struct ppi_if *ppi);
+       int (*stop)(struct ppi_if *ppi);
+       int (*set_params)(struct ppi_if *ppi, struct ppi_params *params);
+       void (*update_addr)(struct ppi_if *ppi, unsigned long addr);
+};
+
+enum ppi_type {
+       PPI_TYPE_PPI,
+       PPI_TYPE_EPPI,
+};
+
+struct ppi_info {
+       enum ppi_type type;
+       int dma_ch;
+       int irq_err;
+       void __iomem *base;
+       const unsigned short *pin_req;
+};
+
+struct ppi_if {
+       unsigned long ppi_control;
+       const struct ppi_ops *ops;
+       const struct ppi_info *info;
+       bool err_int;
+       void *priv;
+};
+
+struct ppi_if *ppi_create_instance(const struct ppi_info *info);
+void ppi_delete_instance(struct ppi_if *ppi);
+#endif
index 9929b05..bd8217c 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef _VPIF_TYPES_H
 #define _VPIF_TYPES_H
 
+#include <linux/i2c.h>
+
 #define VPIF_CAPTURE_MAX_CHANNELS      2
 
 enum vpif_if_type {
diff --git a/include/media/gpio-ir-recv.h b/include/media/gpio-ir-recv.h
new file mode 100644 (file)
index 0000000..67797bf
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#ifndef __GPIO_IR_RECV_H__
+#define __GPIO_IR_RECV_H__
+
+struct gpio_ir_recv_platform_data {
+       int gpio_nr;
+       bool active_low;
+};
+
+#endif /* __GPIO_IR_RECV_H__ */
+
index 6a27d91..eaade98 100644 (file)
@@ -23,7 +23,6 @@
 #ifndef _MEDIA_DEVICE_H
 #define _MEDIA_DEVICE_H
 
-#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
@@ -31,6 +30,8 @@
 #include <media/media-devnode.h>
 #include <media/media-entity.h>
 
+struct device;
+
 /**
  * struct media_device - Media device
  * @dev:       Parent device
diff --git a/include/media/mt9m032.h b/include/media/mt9m032.h
new file mode 100644 (file)
index 0000000..c3a7811
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Driver for MT9M032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010-2011 Lund Engineering
+ * Contact: Gil Lund <gwlund@lundeng.com>
+ * Author: Martin Hostettler <martin@neutronstar.dyndns.org>
+ *
+ * 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 MT9M032_H
+#define MT9M032_H
+
+#define MT9M032_NAME           "mt9m032"
+#define MT9M032_I2C_ADDR       (0xb8 >> 1)
+
+struct mt9m032_platform_data {
+       u32 ext_clock;
+       u32 pix_clock;
+       bool invert_pixclock;
+
+};
+#endif /* MT9M032_H */
index f688bde..8db6741 100644 (file)
@@ -102,8 +102,11 @@ void rc_map_init(void);
 #define RC_MAP_IMON_MCE                  "rc-imon-mce"
 #define RC_MAP_IMON_PAD                  "rc-imon-pad"
 #define RC_MAP_IODATA_BCTV7E             "rc-iodata-bctv7e"
+#define RC_MAP_IT913X_V1                 "rc-it913x-v1"
+#define RC_MAP_IT913X_V2                 "rc-it913x-v2"
 #define RC_MAP_KAIOMY                    "rc-kaiomy"
 #define RC_MAP_KWORLD_315U               "rc-kworld-315u"
+#define RC_MAP_KWORLD_PC150U             "rc-kworld-pc150u"
 #define RC_MAP_KWORLD_PLUS_TV_ANALOG     "rc-kworld-plus-tv-analog"
 #define RC_MAP_LEADTEK_Y04G0051          "rc-leadtek-y04g0051"
 #define RC_MAP_LIRC                      "rc-lirc"
diff --git a/include/media/s5p_hdmi.h b/include/media/s5p_hdmi.h
new file mode 100644 (file)
index 0000000..361a751
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Driver header for S5P HDMI chip.
+ *
+ * Copyright (c) 2011 Samsung Electronics, Co. Ltd
+ * Contact: Tomasz Stanislawski <t.stanislaws@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 S5P_HDMI_H
+#define S5P_HDMI_H
+
+struct i2c_board_info;
+
+/**
+ * @hdmiphy_bus: controller id for HDMIPHY bus
+ * @hdmiphy_info: template for HDMIPHY I2C device
+ * @mhl_bus: controller id for MHL control bus
+ * @mhl_info: template for MHL I2C device
+ *
+ * NULL pointer for *_info fields indicates that
+ * the corresponding chip is not present
+ */
+struct s5p_hdmi_platform_data {
+       int hdmiphy_bus;
+       struct i2c_board_info *hdmiphy_info;
+       int mhl_bus;
+       struct i2c_board_info *mhl_info;
+};
+
+#endif /* S5P_HDMI_H */
+
index 48413b4..a90a765 100644 (file)
@@ -18,6 +18,8 @@ struct sh_mobile_ceu_companion {
 
 struct sh_mobile_ceu_info {
        unsigned long flags;
+       int max_width;
+       int max_height;
        struct sh_mobile_ceu_companion *csi2;
 };
 
diff --git a/include/media/sii9234.h b/include/media/sii9234.h
new file mode 100644 (file)
index 0000000..6a4a809
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Driver header for SII9234 MHL converter chip.
+ *
+ * Copyright (c) 2011 Samsung Electronics, Co. Ltd
+ * Contact: Tomasz Stanislawski <t.stanislaws@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 SII9234_H
+#define SII9234_H
+
+/**
+ * @gpio_n_reset: GPIO driving nRESET pin
+ */
+
+struct sii9234_platform_data {
+       int gpio_n_reset;
+};
+
+#endif /* SII9234_H */
index 29e1920..926aff9 100644 (file)
 #define TUNER_TENA_TNF_5337            86
 
 #define TUNER_XC4000                   87      /* Xceive Silicon Tuner */
+#define TUNER_XC5000C                  88      /* Xceive Silicon Tuner */
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
index 810a209..7395c81 100644 (file)
@@ -143,6 +143,9 @@ enum {
        /* module saa6588: just ident 6588 */
        V4L2_IDENT_SAA6588 = 6588,
 
+       /* module vs6624: just ident 6624 */
+       V4L2_IDENT_VS6624 = 6624,
+
        /* module saa6752hs: reserved range 6750-6759 */
        V4L2_IDENT_SAA6752HS = 6752,
        V4L2_IDENT_SAA6752HS_AC3 = 6753,
@@ -162,6 +165,9 @@ enum {
        /* module adv7180: just ident 7180 */
        V4L2_IDENT_ADV7180 = 7180,
 
+       /* module adv7183: just ident 7183 */
+       V4L2_IDENT_ADV7183 = 7183,
+
        /* module saa7185: just ident 7185 */
        V4L2_IDENT_SAA7185 = 7185,
 
index eeb3df6..11e6756 100644 (file)
@@ -22,7 +22,6 @@
 #define _V4L2_CTRLS_H
 
 #include <linux/list.h>
-#include <linux/device.h>
 #include <linux/videodev2.h>
 
 /* forward references */
@@ -33,6 +32,7 @@ struct video_device;
 struct v4l2_subdev;
 struct v4l2_subscribed_event;
 struct v4l2_fh;
+struct poll_table_struct;
 
 /** struct v4l2_ctrl_ops - The control operations that the driver has to provide.
   * @g_volatile_ctrl: Get a new value for this control. Generally only relevant
@@ -492,6 +492,18 @@ void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
 void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
                struct v4l2_subscribed_event *sev);
 
+/* Can be used as a vidioc_log_status function that just dumps all controls
+   associated with the filehandle. */
+int v4l2_ctrl_log_status(struct file *file, void *fh);
+
+/* Can be used as a vidioc_subscribe_event function that just subscribes
+   control events. */
+int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
+                               struct v4l2_event_subscription *sub);
+
+/* Can be used as a poll function that just polls for control events. */
+unsigned int v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait);
+
 /* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */
 int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc);
 int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm);
index c7c40f1..96d2221 100644 (file)
@@ -62,6 +62,9 @@ struct v4l2_file_operations {
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        long (*ioctl) (struct file *, unsigned int, unsigned long);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
+#ifdef CONFIG_COMPAT
+       long (*compat_ioctl32) (struct file *, unsigned int, unsigned long);
+#endif
        unsigned long (*get_unmapped_area) (struct file *, unsigned long,
                                unsigned long, unsigned long, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
index 3f5d60f..3cb939c 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/poll.h>
 #include <linux/fs.h>
-#include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/compiler.h> /* need __user */
 #include <linux/videodev2.h>
@@ -211,6 +210,10 @@ struct v4l2_ioctl_ops {
                                        struct v4l2_encoder_cmd *a);
        int (*vidioc_try_encoder_cmd)  (struct file *file, void *fh,
                                        struct v4l2_encoder_cmd *a);
+       int (*vidioc_decoder_cmd)      (struct file *file, void *fh,
+                                       struct v4l2_decoder_cmd *a);
+       int (*vidioc_try_decoder_cmd)  (struct file *file, void *fh,
+                                       struct v4l2_decoder_cmd *a);
 
        /* Stream type-dependent parameter ioctls */
        int (*vidioc_g_parm)           (struct file *file, void *fh,
index 69b7ad3..248fb05 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/netdevice.h>
 #include <linux/debugfs.h>
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <linux/netlink.h>
 #include <linux/skbuff.h>
 #include <linux/nl80211.h>
index 344c8dd..59c5d18 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/rcupdate.h>
+#include <linux/bug.h>
 #include <linux/jiffies.h>
 #include <net/neighbour.h>
 #include <asm/processor.h>
index ebe517f..2bdee51 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/atomic.h>                 /* for struct atomic_t */
 #include <linux/compiler.h>
 #include <linux/timer.h>
+#include <linux/bug.h>
 
 #include <net/checksum.h>
 #include <linux/netfilter.h>           /* for union nf_inet_addr */
index 9a012be..87d203f 100644 (file)
 #ifndef MAC80211_H
 #define MAC80211_H
 
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
-#include <linux/device.h>
 #include <linux/ieee80211.h>
 #include <net/cfg80211.h>
 #include <asm/unaligned.h>
@@ -87,6 +87,8 @@
  *
  */
 
+struct device;
+
 /**
  * enum ieee80211_max_queues - maximum number of queues
  *
index 90c67c7..3b572bb 100644 (file)
@@ -118,6 +118,10 @@ extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic;
 extern struct nf_conntrack_l4proto *
 __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto);
 
+extern struct nf_conntrack_l4proto *
+nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto);
+extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p);
+
 /* Protocol registration. */
 extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto);
 extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto);
index 0e04db4..34ec89f 100644 (file)
@@ -15,7 +15,7 @@ struct ctnl_timeout {
        atomic_t                refcnt;
        char                    name[CTNL_TIMEOUT_NAME_MAX];
        __u16                   l3num;
-       __u8                    l4num;
+       struct nf_conntrack_l4proto *l4proto;
        char                    data[0];
 };
 
index d55f434..0931618 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef __NET_GENERIC_H__
 #define __NET_GENERIC_H__
 
+#include <linux/bug.h>
 #include <linux/rcupdate.h>
 
 /*
index 28068ec..77d4c37 100644 (file)
@@ -2,6 +2,7 @@
 #define __NET_SCHED_RED_H
 
 #include <linux/types.h>
+#include <linux/bug.h>
 #include <net/pkt_sched.h>
 #include <net/inet_ecn.h>
 #include <net/dsfield.h>
index 04bc0b3..a6ba1f8 100644 (file)
@@ -1854,7 +1854,7 @@ static inline bool wq_has_sleeper(struct socket_wq *wq)
 static inline void sock_poll_wait(struct file *filp,
                wait_queue_head_t *wait_address, poll_table *p)
 {
-       if (p && wait_address) {
+       if (!poll_does_not_wait(p) && wait_address) {
                poll_wait(filp, wait_address, p);
                /*
                 * We need to be sure we are in sync with the
index 8607e6a..f75a04d 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/list.h>
 #include <linux/tcp.h>
+#include <linux/bug.h>
 #include <linux/slab.h>
 #include <linux/cache.h>
 #include <linux/percpu.h>
index 053b3cf..8d6689c 100644 (file)
@@ -12,6 +12,7 @@
 #define _TIMEWAIT_SOCK_H
 
 #include <linux/slab.h>
+#include <linux/bug.h>
 #include <net/sock.h>
 
 struct timewait_sock_ops {
index e39592f..5d606d9 100644 (file)
@@ -23,6 +23,7 @@
 #define _UDP_H
 
 #include <linux/list.h>
+#include <linux/bug.h>
 #include <net/inet_sock.h>
 #include <net/sock.h>
 #include <net/snmp.h>
index d86fffd..ff27f1b 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/netdevice.h>
 #include <linux/mutex.h>
+#include <linux/bug.h>
 
 struct wpan_phy {
        struct mutex pib_lock;
index f05fa82..a5f9b96 100644 (file)
@@ -26,6 +26,7 @@
 #include <scsi/osd_attributes.h>
 #include <scsi/osd_sec.h>
 #include <linux/pnfs_osd_xdr.h>
+#include <linux/bug.h>
 
 struct ore_comp {
        struct osd_obj_id       obj;
index b3a1c2d..6efb2e1 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _SCSI_SCSI_DEVICE_H
 #define _SCSI_SCSI_DEVICE_H
 
-#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
@@ -9,6 +8,7 @@
 #include <scsi/scsi.h>
 #include <linux/atomic.h>
 
+struct device;
 struct request_queue;
 struct scsi_cmnd;
 struct scsi_lun;
index 58ce8fe..5cb20cc 100644 (file)
@@ -23,7 +23,7 @@
 #define SCSI_NETLINK_H
 
 #include <linux/netlink.h>
-
+#include <linux/types.h>
 
 /*
  * This file intended to be included by both kernel and user space
index 0de32cd..af244f4 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/transport_class.h>
 #include <linux/blkdev.h>
+#include <linux/bug.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 
index d97d69f..da4a456 100644 (file)
@@ -51,6 +51,8 @@
 #ifndef __SND_COMPRESS_PARAMS_H
 #define __SND_COMPRESS_PARAMS_H
 
+#include <linux/types.h>
+
 /* AUDIO CODECS SUPPORTED */
 #define MAX_NUM_CODECS 32
 #define MAX_NUM_CODEC_DESCRIPTORS 32
index cea1b54..b6e0f57 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/mutex.h>               /* struct mutex */
 #include <linux/rwsem.h>               /* struct rw_semaphore */
 #include <linux/pm.h>                  /* pm_message_t */
-#include <linux/device.h>
 #include <linux/stringify.h>
 
 /* number of supported soundcards */
 #define CONFIG_SND_MAJOR       116     /* standard configuration */
 
 /* forward declarations */
-#ifdef CONFIG_PCI
 struct pci_dev;
-#endif
 struct module;
+struct device;
+struct device_attribute;
 
 /* device allocation stuff */
 
index e46107f..8da3c24 100644 (file)
 #ifndef __LINUX_SND_SOC_DAPM_H
 #define __LINUX_SND_SOC_DAPM_H
 
-#include <linux/device.h>
 #include <linux/types.h>
 #include <sound/control.h>
 
+struct device;
+
 /* widget has no PM register bit */
 #define SND_SOC_NOPM   -1
 
index 726e947..ec3f910 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
 
 #define TEA575X_FMIF   10700
 
@@ -42,13 +43,16 @@ struct snd_tea575x_ops {
 };
 
 struct snd_tea575x {
+       struct v4l2_device *v4l2_dev;
        struct video_device vd;         /* video device */
+       int radio_nr;                   /* radio_nr */
        bool tea5759;                   /* 5759 chip is present */
+       bool cannot_read_data;          /* Device cannot read the data pin */
        bool mute;                      /* Device is muted? */
        bool stereo;                    /* receiving stereo */
        bool tuned;                     /* tuned to a station */
        unsigned int val;               /* hw value */
-       unsigned long freq;             /* frequency */
+       u32 freq;                       /* frequency */
        struct mutex mutex;
        struct snd_tea575x_ops *ops;
        void *private_data;
index 7596441..127993d 100644 (file)
@@ -81,6 +81,13 @@ DEFINE_EVENT(jbd2_commit, jbd2_commit_logging,
        TP_ARGS(journal, commit_transaction)
 );
 
+DEFINE_EVENT(jbd2_commit, jbd2_drop_transaction,
+
+       TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
+
+       TP_ARGS(journal, commit_transaction)
+);
+
 TRACE_EVENT(jbd2_end_commit,
        TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
 
@@ -200,7 +207,7 @@ TRACE_EVENT(jbd2_checkpoint_stats,
                  __entry->forced_to_close, __entry->written, __entry->dropped)
 );
 
-TRACE_EVENT(jbd2_cleanup_journal_tail,
+TRACE_EVENT(jbd2_update_log_tail,
 
        TP_PROTO(journal_t *journal, tid_t first_tid,
                 unsigned long block_nr, unsigned long freed),
@@ -229,6 +236,26 @@ TRACE_EVENT(jbd2_cleanup_journal_tail,
                  __entry->block_nr, __entry->freed)
 );
 
+TRACE_EVENT(jbd2_write_superblock,
+
+       TP_PROTO(journal_t *journal, int write_op),
+
+       TP_ARGS(journal, write_op),
+
+       TP_STRUCT__entry(
+               __field(        dev_t,  dev                     )
+               __field(          int,  write_op                )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = journal->j_fs_dev->bd_dev;
+               __entry->write_op       = write_op;
+       ),
+
+       TP_printk("dev %d,%d write_op %x", MAJOR(__entry->dev),
+                 MINOR(__entry->dev), __entry->write_op)
+);
+
 #endif /* _TRACE_JBD2_H */
 
 /* This part must be outside protection */
index d697382..41a7dbd 100644 (file)
@@ -4,10 +4,10 @@
 #if !defined(_TRACE_REGMAP_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_REGMAP_H
 
-#include <linux/device.h>
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
 
+struct device;
 struct regmap;
 
 /*
index d62c558..33f85b6 100644 (file)
@@ -7,7 +7,8 @@
 
 #include <linux/ktime.h>
 #include <linux/tracepoint.h>
-#include <linux/device.h>
+
+struct device;
 
 /*
  * The rpm_internal events are used for tracing some important
diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h
new file mode 100644 (file)
index 0000000..43be87d
--- /dev/null
@@ -0,0 +1,177 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sunrpc
+
+#if !defined(_TRACE_SUNRPC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SUNRPC_H
+
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(rpc_task_status,
+
+       TP_PROTO(struct rpc_task *task),
+
+       TP_ARGS(task),
+
+       TP_STRUCT__entry(
+               __field(const struct rpc_task *, task)
+               __field(const struct rpc_clnt *, clnt)
+               __field(int, status)
+       ),
+
+       TP_fast_assign(
+               __entry->task = task;
+               __entry->clnt = task->tk_client;
+               __entry->status = task->tk_status;
+       ),
+
+       TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status)
+);
+
+DEFINE_EVENT(rpc_task_status, rpc_call_status,
+       TP_PROTO(struct rpc_task *task),
+
+       TP_ARGS(task)
+);
+
+DEFINE_EVENT(rpc_task_status, rpc_bind_status,
+       TP_PROTO(struct rpc_task *task),
+
+       TP_ARGS(task)
+);
+
+TRACE_EVENT(rpc_connect_status,
+       TP_PROTO(struct rpc_task *task, int status),
+
+       TP_ARGS(task, status),
+
+       TP_STRUCT__entry(
+               __field(const struct rpc_task *, task)
+               __field(const struct rpc_clnt *, clnt)
+               __field(int, status)
+       ),
+
+       TP_fast_assign(
+               __entry->task = task;
+               __entry->clnt = task->tk_client;
+               __entry->status = status;
+       ),
+
+       TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status)
+);
+
+DECLARE_EVENT_CLASS(rpc_task_running,
+
+       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+
+       TP_ARGS(clnt, task, action),
+
+       TP_STRUCT__entry(
+               __field(const struct rpc_clnt *, clnt)
+               __field(const struct rpc_task *, task)
+               __field(const void *, action)
+               __field(unsigned long, runstate)
+               __field(int, status)
+               __field(unsigned short, flags)
+               ),
+
+       TP_fast_assign(
+               __entry->clnt = clnt;
+               __entry->task = task;
+               __entry->action = action;
+               __entry->runstate = task->tk_runstate;
+               __entry->status = task->tk_status;
+               __entry->flags = task->tk_flags;
+               ),
+
+       TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d action=%pf",
+               __entry->task,
+               __entry->clnt,
+               __entry->flags,
+               __entry->runstate,
+               __entry->status,
+               __entry->action
+               )
+);
+
+DEFINE_EVENT(rpc_task_running, rpc_task_begin,
+
+       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+
+       TP_ARGS(clnt, task, action)
+
+);
+
+DEFINE_EVENT(rpc_task_running, rpc_task_run_action,
+
+       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+
+       TP_ARGS(clnt, task, action)
+
+);
+
+DEFINE_EVENT(rpc_task_running, rpc_task_complete,
+
+       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const void *action),
+
+       TP_ARGS(clnt, task, action)
+
+);
+
+DECLARE_EVENT_CLASS(rpc_task_queued,
+
+       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
+
+       TP_ARGS(clnt, task, q),
+
+       TP_STRUCT__entry(
+               __field(const struct rpc_clnt *, clnt)
+               __field(const struct rpc_task *, task)
+               __field(unsigned long, timeout)
+               __field(unsigned long, runstate)
+               __field(int, status)
+               __field(unsigned short, flags)
+               __string(q_name, rpc_qname(q))
+               ),
+
+       TP_fast_assign(
+               __entry->clnt = clnt;
+               __entry->task = task;
+               __entry->timeout = task->tk_timeout;
+               __entry->runstate = task->tk_runstate;
+               __entry->status = task->tk_status;
+               __entry->flags = task->tk_flags;
+               __assign_str(q_name, rpc_qname(q));
+               ),
+
+       TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d timeout=%lu queue=%s",
+               __entry->task,
+               __entry->clnt,
+               __entry->flags,
+               __entry->runstate,
+               __entry->status,
+               __entry->timeout,
+               __get_str(q_name)
+               )
+);
+
+DEFINE_EVENT(rpc_task_queued, rpc_task_sleep,
+
+       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
+
+       TP_ARGS(clnt, task, q)
+
+);
+
+DEFINE_EVENT(rpc_task_queued, rpc_task_wakeup,
+
+       TP_PROTO(const struct rpc_clnt *clnt, const struct rpc_task *task, const struct rpc_wait_queue *q),
+
+       TP_ARGS(clnt, task, q)
+
+);
+
+#endif /* _TRACE_SUNRPC_H */
+
+#include <trace/define_trace.h>
index 5973410..7b81887 100644 (file)
@@ -5,7 +5,6 @@
 #define _TRACE_WRITEBACK_H
 
 #include <linux/backing-dev.h>
-#include <linux/device.h>
 #include <linux/writeback.h>
 
 #define show_inode_state(state)                                        \
diff --git a/include/video/sa1100fb.h b/include/video/sa1100fb.h
new file mode 100644 (file)
index 0000000..4ab4096
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * StrongARM 1100 LCD Controller Frame Buffer Device
+ *
+ * Copyright (C) 1999 Eric A. Thomas
+ *  Based on acornfb.c Copyright (C) Russell King.
+ *  
+ * 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 _VIDEO_SA1100FB_H
+#define _VIDEO_SA1100FB_H
+
+#include <linux/fb.h>
+#include <linux/types.h>
+
+#define RGB_4  0
+#define RGB_8  1
+#define RGB_16 2
+#define NR_RGB 3
+
+/* These are the bitfields for each display depth that we support. */
+struct sa1100fb_rgb {
+       struct fb_bitfield      red;
+       struct fb_bitfield      green;
+       struct fb_bitfield      blue;
+       struct fb_bitfield      transp;
+};
+
+/* This structure describes the machine which we are running on. */
+struct sa1100fb_mach_info {
+       u_long          pixclock;
+
+       u_short         xres;
+       u_short         yres;
+
+       u_char          bpp;
+       u_char          hsync_len;
+       u_char          left_margin;
+       u_char          right_margin;
+
+       u_char          vsync_len;
+       u_char          upper_margin;
+       u_char          lower_margin;
+       u_char          sync;
+
+       u_int           cmap_greyscale:1,
+                       cmap_inverse:1,
+                       cmap_static:1,
+                       unused:29;
+
+       u_int           lccr0;
+       u_int           lccr3;
+
+       /* Overrides for the default RGB maps */
+       const struct sa1100fb_rgb *rgb[NR_RGB];
+
+       void (*backlight_power)(int);
+       void (*lcd_power)(int);
+       void (*set_visual)(u32);
+};
+
+#endif
index 0c28989..9ce788d 100644 (file)
@@ -39,6 +39,27 @@ struct physdev_eoi {
 };
 
 /*
+ * Register a shared page for the hypervisor to indicate whether the guest
+ * must issue PHYSDEVOP_eoi. The semantics of PHYSDEVOP_eoi change slightly
+ * once the guest used this function in that the associated event channel
+ * will automatically get unmasked. The page registered is used as a bit
+ * array indexed by Xen's PIRQ value.
+ */
+#define PHYSDEVOP_pirq_eoi_gmfn_v1       17
+/*
+ * Register a shared page for the hypervisor to indicate whether the
+ * guest must issue PHYSDEVOP_eoi. This hypercall is very similar to
+ * PHYSDEVOP_pirq_eoi_gmfn_v1 but it doesn't change the semantics of
+ * PHYSDEVOP_eoi. The page registered is used as a bit array indexed by
+ * Xen's PIRQ value.
+ */
+#define PHYSDEVOP_pirq_eoi_gmfn_v2       28
+struct physdev_pirq_eoi_gmfn {
+    /* IN */
+    unsigned long gmfn;
+};
+
+/*
  * Query the status of an IRQ line.
  * @arg == pointer to physdev_irq_status_query structure.
  */
index 82e2c83..591550a 100644 (file)
@@ -1,5 +1,9 @@
 #ifndef _XEN_TMEM_H
 #define _XEN_TMEM_H
+
+#include <linux/types.h>
+
 /* defined in drivers/xen/tmem.c */
-extern int tmem_enabled;
+extern bool tmem_enabled;
+
 #endif /* _XEN_TMEM_H */
index e8c599b..0a7515c 100644 (file)
@@ -139,9 +139,9 @@ int xenbus_transaction_start(struct xenbus_transaction *t);
 int xenbus_transaction_end(struct xenbus_transaction t, int abort);
 
 /* Single read and scanf: returns -errno or num scanned if > 0. */
+__scanf(4, 5)
 int xenbus_scanf(struct xenbus_transaction t,
-                const char *dir, const char *node, const char *fmt, ...)
-       __attribute__((format(scanf, 4, 5)));
+                const char *dir, const char *node, const char *fmt, ...);
 
 /* Single printf and write: returns -errno or 0. */
 __printf(4, 5)
index 5f117ca..fda0a7b 100644 (file)
@@ -267,7 +267,8 @@ void __cpuinit calibrate_delay(void)
 
        if (per_cpu(cpu_loops_per_jiffy, this_cpu)) {
                lpj = per_cpu(cpu_loops_per_jiffy, this_cpu);
-               pr_info("Calibrating delay loop (skipped) "
+               if (!printed)
+                       pr_info("Calibrating delay loop (skipped) "
                                "already calibrated this CPU");
        } else if (preset_lpj) {
                lpj = preset_lpj;
index 2974c8b..0e93f92 100644 (file)
@@ -373,8 +373,8 @@ retry:
 #ifdef CONFIG_BLOCK
                __bdevname(ROOT_DEV, b);
 #endif
-               printk("VFS: Cannot open root device \"%s\" or %s\n",
-                               root_device_name, b);
+               printk("VFS: Cannot open root device \"%s\" or %s: error %d\n",
+                               root_device_name, b, err);
                printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
 
                printk_all_partitions();
index 44c9754..9d454f0 100644 (file)
@@ -399,7 +399,7 @@ static int __init do_early_param(char *param, char *val)
 
 void __init parse_early_options(char *cmdline)
 {
-       parse_args("early options", cmdline, NULL, 0, do_early_param);
+       parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param);
 }
 
 /* Arch code calls this early on, or if not, just before other parsing. */
@@ -502,7 +502,7 @@ asmlinkage void __init start_kernel(void)
        parse_early_param();
        parse_args("Booting kernel", static_command_line, __start___param,
                   __stop___param - __start___param,
-                  &unknown_bootoption);
+                  0, 0, &unknown_bootoption);
 
        jump_label_init();
 
@@ -698,16 +698,69 @@ int __init_or_module do_one_initcall(initcall_t fn)
 }
 
 
-extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
+extern initcall_t __initcall_start[];
+extern initcall_t __initcall0_start[];
+extern initcall_t __initcall1_start[];
+extern initcall_t __initcall2_start[];
+extern initcall_t __initcall3_start[];
+extern initcall_t __initcall4_start[];
+extern initcall_t __initcall5_start[];
+extern initcall_t __initcall6_start[];
+extern initcall_t __initcall7_start[];
+extern initcall_t __initcall_end[];
+
+static initcall_t *initcall_levels[] __initdata = {
+       __initcall0_start,
+       __initcall1_start,
+       __initcall2_start,
+       __initcall3_start,
+       __initcall4_start,
+       __initcall5_start,
+       __initcall6_start,
+       __initcall7_start,
+       __initcall_end,
+};
+
+static char *initcall_level_names[] __initdata = {
+       "early parameters",
+       "core parameters",
+       "postcore parameters",
+       "arch parameters",
+       "subsys parameters",
+       "fs parameters",
+       "device parameters",
+       "late parameters",
+};
+
+static int __init ignore_unknown_bootoption(char *param, char *val)
+{
+       return 0;
+}
 
-static void __init do_initcalls(void)
+static void __init do_initcall_level(int level)
 {
+       extern const struct kernel_param __start___param[], __stop___param[];
        initcall_t *fn;
 
-       for (fn = __early_initcall_end; fn < __initcall_end; fn++)
+       strcpy(static_command_line, saved_command_line);
+       parse_args(initcall_level_names[level],
+                  static_command_line, __start___param,
+                  __stop___param - __start___param,
+                  level, level,
+                  ignore_unknown_bootoption);
+
+       for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
                do_one_initcall(*fn);
 }
 
+static void __init do_initcalls(void)
+{
+       int level;
+
+       for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
+               do_initcall_level(level);
+}
+
 /*
  * Ok, the machine is now initialized. None of the devices
  * have been touched yet, but the CPU subsystem is up and
@@ -731,7 +784,7 @@ static void __init do_pre_smp_initcalls(void)
 {
        initcall_t *fn;
 
-       for (fn = __initcall_start; fn < __early_initcall_end; fn++)
+       for (fn = __initcall_start; fn < __initcall0_start; fn++)
                do_one_initcall(*fn);
 }
 
index 2d9de86..cb41b95 100644 (file)
@@ -27,7 +27,6 @@ obj-y += power/
 
 obj-$(CONFIG_FREEZER) += freezer.o
 obj-$(CONFIG_PROFILING) += profile.o
-obj-$(CONFIG_SYSCTL_SYSCALL_CHECK) += sysctl_check.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-y += time/
 obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
index de50f7d..1dc53ba 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/sysrq.h>
+#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/kgdb.h>
 #include <linux/kdb.h>
@@ -74,6 +75,8 @@ static int                    exception_level;
 struct kgdb_io         *dbg_io_ops;
 static DEFINE_SPINLOCK(kgdb_registration_lock);
 
+/* Action for the reboot notifiter, a global allow kdb to change it */
+static int kgdbreboot;
 /* kgdb console driver is loaded */
 static int kgdb_con_registered;
 /* determine if kgdb console output should be used */
@@ -95,6 +98,7 @@ static int __init opt_kgdb_con(char *str)
 early_param("kgdbcon", opt_kgdb_con);
 
 module_param(kgdb_use_con, int, 0644);
+module_param(kgdbreboot, int, 0644);
 
 /*
  * Holds information about breakpoints in a kernel. These breakpoints are
@@ -783,6 +787,33 @@ void __init dbg_late_init(void)
        kdb_init(KDB_INIT_FULL);
 }
 
+static int
+dbg_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+       /*
+        * Take the following action on reboot notify depending on value:
+        *    1 == Enter debugger
+        *    0 == [the default] detatch debug client
+        *   -1 == Do nothing... and use this until the board resets
+        */
+       switch (kgdbreboot) {
+       case 1:
+               kgdb_breakpoint();
+       case -1:
+               goto done;
+       }
+       if (!dbg_kdb_mode)
+               gdbstub_exit(code);
+done:
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block dbg_reboot_notifier = {
+       .notifier_call          = dbg_notify_reboot,
+       .next                   = NULL,
+       .priority               = INT_MAX,
+};
+
 static void kgdb_register_callbacks(void)
 {
        if (!kgdb_io_module_registered) {
@@ -790,6 +821,7 @@ static void kgdb_register_callbacks(void)
                kgdb_arch_init();
                if (!dbg_is_early)
                        kgdb_arch_late();
+               register_reboot_notifier(&dbg_reboot_notifier);
                atomic_notifier_chain_register(&panic_notifier_list,
                                               &kgdb_panic_event_nb);
 #ifdef CONFIG_MAGIC_SYSRQ
@@ -811,6 +843,7 @@ static void kgdb_unregister_callbacks(void)
         */
        if (kgdb_io_module_registered) {
                kgdb_io_module_registered = 0;
+               unregister_reboot_notifier(&dbg_reboot_notifier);
                atomic_notifier_chain_unregister(&panic_notifier_list,
                                               &kgdb_panic_event_nb);
                kgdb_arch_exit();
index c22d8c2..ce615e0 100644 (file)
@@ -1111,6 +1111,13 @@ void gdbstub_exit(int status)
        unsigned char checksum, ch, buffer[3];
        int loop;
 
+       if (!kgdb_connected)
+               return;
+       kgdb_connected = 0;
+
+       if (!dbg_io_ops || dbg_kdb_mode)
+               return;
+
        buffer[0] = 'W';
        buffer[1] = hex_asc_hi(status);
        buffer[2] = hex_asc_lo(status);
@@ -1129,5 +1136,6 @@ void gdbstub_exit(int status)
        dbg_io_ops->write_char(hex_asc_lo(checksum));
 
        /* make sure the output is flushed, lest the bootloader clobber it */
-       dbg_io_ops->flush();
+       if (dbg_io_ops->flush)
+               dbg_io_ops->flush();
 }
index 20059ef..8418c2f 100644 (file)
@@ -153,6 +153,13 @@ static int _kdb_bp_install(struct pt_regs *regs, kdb_bp_t *bp)
        } else {
                kdb_printf("%s: failed to set breakpoint at 0x%lx\n",
                           __func__, bp->bp_addr);
+#ifdef CONFIG_DEBUG_RODATA
+               if (!bp->bp_type) {
+                       kdb_printf("Software breakpoints are unavailable.\n"
+                                  "  Change the kernel CONFIG_DEBUG_RODATA=n\n"
+                                  "  OR use hw breaks: help bph\n");
+               }
+#endif
                return 1;
        }
        return 0;
index 4802eb5..9b5f17d 100644 (file)
@@ -689,7 +689,7 @@ kdb_printit:
        if (!dbg_kdb_mode && kgdb_connected) {
                gdbstub_msg_write(kdb_buffer, retlen);
        } else {
-               if (!dbg_io_ops->is_console) {
+               if (dbg_io_ops && !dbg_io_ops->is_console) {
                        len = strlen(kdb_buffer);
                        cp = kdb_buffer;
                        while (len--) {
index 4bca634..118527a 100644 (file)
@@ -25,6 +25,7 @@
 #define KBD_STAT_MOUSE_OBF     0x20    /* Mouse output buffer full */
 
 static int kbd_exists;
+static int kbd_last_ret;
 
 /*
  * Check if the keyboard controller has a keypress for us.
@@ -90,8 +91,11 @@ int kdb_get_kbd_char(void)
                return -1;
        }
 
-       if ((scancode & 0x80) != 0)
+       if ((scancode & 0x80) != 0) {
+               if (scancode == 0x9c)
+                       kbd_last_ret = 0;
                return -1;
+       }
 
        scancode &= 0x7f;
 
@@ -178,35 +182,82 @@ int kdb_get_kbd_char(void)
                return -1;      /* ignore unprintables */
        }
 
-       if ((scancode & 0x7f) == 0x1c) {
-               /*
-                * enter key.  All done.  Absorb the release scancode.
-                */
+       if (scancode == 0x1c) {
+               kbd_last_ret = 1;
+               return 13;
+       }
+
+       return keychar & 0xff;
+}
+EXPORT_SYMBOL_GPL(kdb_get_kbd_char);
+
+/*
+ * Best effort cleanup of ENTER break codes on leaving KDB. Called on
+ * exiting KDB, when we know we processed an ENTER or KP ENTER scan
+ * code.
+ */
+void kdb_kbd_cleanup_state(void)
+{
+       int scancode, scanstatus;
+
+       /*
+        * Nothing to clean up, since either
+        * ENTER was never pressed, or has already
+        * gotten cleaned up.
+        */
+       if (!kbd_last_ret)
+               return;
+
+       kbd_last_ret = 0;
+       /*
+        * Enter key. Need to absorb the break code here, lest it gets
+        * leaked out if we exit KDB as the result of processing 'g'.
+        *
+        * This has several interesting implications:
+        * + Need to handle KP ENTER, which has break code 0xe0 0x9c.
+        * + Need to handle repeat ENTER and repeat KP ENTER. Repeats
+        *   only get a break code at the end of the repeated
+        *   sequence. This means we can't propagate the repeated key
+        *   press, and must swallow it away.
+        * + Need to handle possible PS/2 mouse input.
+        * + Need to handle mashed keys.
+        */
+
+       while (1) {
                while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
-                       ;
+                       cpu_relax();
 
                /*
-                * Fetch the scancode
+                * Fetch the scancode.
                 */
                scancode = inb(KBD_DATA_REG);
                scanstatus = inb(KBD_STATUS_REG);
 
-               while (scanstatus & KBD_STAT_MOUSE_OBF) {
-                       scancode = inb(KBD_DATA_REG);
-                       scanstatus = inb(KBD_STATUS_REG);
-               }
+               /*
+                * Skip mouse input.
+                */
+               if (scanstatus & KBD_STAT_MOUSE_OBF)
+                       continue;
 
-               if (scancode != 0x9c) {
-                       /*
-                        * Wasn't an enter-release,  why not?
-                        */
-                       kdb_printf("kdb: expected enter got 0x%x status 0x%x\n",
-                              scancode, scanstatus);
-               }
+               /*
+                * If we see 0xe0, this is either a break code for KP
+                * ENTER, or a repeat make for KP ENTER. Either way,
+                * since the second byte is equivalent to an ENTER,
+                * skip the 0xe0 and try again.
+                *
+                * If we see 0x1c, this must be a repeat ENTER or KP
+                * ENTER (and we swallowed 0xe0 before). Try again.
+                *
+                * We can also see make and break codes for other keys
+                * mashed before or after pressing ENTER. Thus, if we
+                * see anything other than 0x9c, we have to try again.
+                *
+                * Note, if you held some key as ENTER was depressed,
+                * that break code would get leaked out.
+                */
+               if (scancode != 0x9c)
+                       continue;
 
-               return 13;
+               return;
        }
-
-       return keychar & 0xff;
 }
-EXPORT_SYMBOL_GPL(kdb_get_kbd_char);
index e2ae734..67b847d 100644 (file)
@@ -1400,6 +1400,9 @@ int kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
        if (KDB_STATE(DOING_SS))
                KDB_STATE_CLEAR(SSBPT);
 
+       /* Clean up any keyboard devices before leaving */
+       kdb_kbd_cleanup_state();
+
        return result;
 }
 
index e381d10..47c4e56 100644 (file)
@@ -246,6 +246,13 @@ extern void debug_kusage(void);
 
 extern void kdb_set_current_task(struct task_struct *);
 extern struct task_struct *kdb_current_task;
+
+#ifdef CONFIG_KDB_KEYBOARD
+extern void kdb_kbd_cleanup_state(void);
+#else /* ! CONFIG_KDB_KEYBOARD */
+#define kdb_kbd_cleanup_state()
+#endif /* ! CONFIG_KDB_KEYBOARD */
+
 #ifdef CONFIG_MODULES
 extern struct list_head *kdb_modules;
 #endif /* CONFIG_MODULES */
index 16b07bf..3db1909 100644 (file)
@@ -687,11 +687,11 @@ static void exit_mm(struct task_struct * tsk)
 }
 
 /*
- * When we die, we re-parent all our children.
- * Try to give them to another thread in our thread
- * group, and if no such member exists, give it to
- * the child reaper process (ie "init") in our pid
- * space.
+ * When we die, we re-parent all our children, and try to:
+ * 1. give them to another thread in our thread group, if such a member exists
+ * 2. give it to the first ancestor process which prctl'd itself as a
+ *    child_subreaper for its children (like a service manager)
+ * 3. give it to the init process (PID 1) in our pid namespace
  */
 static struct task_struct *find_new_reaper(struct task_struct *father)
        __releases(&tasklist_lock)
@@ -711,8 +711,11 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
 
        if (unlikely(pid_ns->child_reaper == father)) {
                write_unlock_irq(&tasklist_lock);
-               if (unlikely(pid_ns == &init_pid_ns))
-                       panic("Attempted to kill init!");
+               if (unlikely(pid_ns == &init_pid_ns)) {
+                       panic("Attempted to kill init! exitcode=0x%08x\n",
+                               father->signal->group_exit_code ?:
+                                       father->exit_code);
+               }
 
                zap_pid_ns_processes(pid_ns);
                write_lock_irq(&tasklist_lock);
@@ -722,6 +725,29 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
                 * forget_original_parent() must move them somewhere.
                 */
                pid_ns->child_reaper = init_pid_ns.child_reaper;
+       } else if (father->signal->has_child_subreaper) {
+               struct task_struct *reaper;
+
+               /*
+                * Find the first ancestor marked as child_subreaper.
+                * Note that the code below checks same_thread_group(reaper,
+                * pid_ns->child_reaper).  This is what we need to DTRT in a
+                * PID namespace. However we still need the check above, see
+                * http://marc.info/?l=linux-kernel&m=131385460420380
+                */
+               for (reaper = father->real_parent;
+                    reaper != &init_task;
+                    reaper = reaper->real_parent) {
+                       if (same_thread_group(reaper, pid_ns->child_reaper))
+                               break;
+                       if (!reaper->signal->is_child_subreaper)
+                               continue;
+                       thread = reaper;
+                       do {
+                               if (!(thread->flags & PF_EXITING))
+                                       return reaper;
+                       } while_each_thread(reaper, thread);
+               }
        }
 
        return pid_ns->child_reaper;
index 37674ec..b9372a0 100644 (file)
@@ -1051,6 +1051,9 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        sig->oom_score_adj = current->signal->oom_score_adj;
        sig->oom_score_adj_min = current->signal->oom_score_adj_min;
 
+       sig->has_child_subreaper = current->signal->has_child_subreaper ||
+                                  current->signal->is_child_subreaper;
+
        mutex_init(&sig->cred_guard_mutex);
 
        return 0;
index a0a8854..957a7aa 100644 (file)
@@ -60,6 +60,43 @@ static DECLARE_RWSEM(umhelper_sem);
 */
 char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
 
+static void free_modprobe_argv(struct subprocess_info *info)
+{
+       kfree(info->argv[3]); /* check call_modprobe() */
+       kfree(info->argv);
+}
+
+static int call_modprobe(char *module_name, int wait)
+{
+       static char *envp[] = {
+               "HOME=/",
+               "TERM=linux",
+               "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+               NULL
+       };
+
+       char **argv = kmalloc(sizeof(char *[5]), GFP_KERNEL);
+       if (!argv)
+               goto out;
+
+       module_name = kstrdup(module_name, GFP_KERNEL);
+       if (!module_name)
+               goto free_argv;
+
+       argv[0] = modprobe_path;
+       argv[1] = "-q";
+       argv[2] = "--";
+       argv[3] = module_name;  /* check free_modprobe_argv() */
+       argv[4] = NULL;
+
+       return call_usermodehelper_fns(modprobe_path, argv, envp,
+               wait | UMH_KILLABLE, NULL, free_modprobe_argv, NULL);
+free_argv:
+       kfree(argv);
+out:
+       return -ENOMEM;
+}
+
 /**
  * __request_module - try to load a kernel module
  * @wait: wait (or not) for the operation to complete
@@ -81,11 +118,6 @@ int __request_module(bool wait, const char *fmt, ...)
        char module_name[MODULE_NAME_LEN];
        unsigned int max_modprobes;
        int ret;
-       char *argv[] = { modprobe_path, "-q", "--", module_name, NULL };
-       static char *envp[] = { "HOME=/",
-                               "TERM=linux",
-                               "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
-                               NULL };
        static atomic_t kmod_concurrent = ATOMIC_INIT(0);
 #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
        static int kmod_loop_msg;
@@ -128,9 +160,7 @@ int __request_module(bool wait, const char *fmt, ...)
 
        trace_module_request(module_name, wait, _RET_IP_);
 
-       ret = call_usermodehelper_fns(modprobe_path, argv, envp,
-                       wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC,
-                       NULL, NULL, NULL);
+       ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
 
        atomic_dec(&kmod_concurrent);
        return ret;
@@ -188,7 +218,7 @@ static int ____call_usermodehelper(void *data)
        /* Exec failed? */
 fail:
        sub_info->retval = retval;
-       do_exit(0);
+       return 0;
 }
 
 void call_usermodehelper_freeinfo(struct subprocess_info *info)
@@ -199,6 +229,19 @@ void call_usermodehelper_freeinfo(struct subprocess_info *info)
 }
 EXPORT_SYMBOL(call_usermodehelper_freeinfo);
 
+static void umh_complete(struct subprocess_info *sub_info)
+{
+       struct completion *comp = xchg(&sub_info->complete, NULL);
+       /*
+        * See call_usermodehelper_exec(). If xchg() returns NULL
+        * we own sub_info, the UMH_KILLABLE caller has gone away.
+        */
+       if (comp)
+               complete(comp);
+       else
+               call_usermodehelper_freeinfo(sub_info);
+}
+
 /* Keventd can't block, but this (a child) can. */
 static int wait_for_helper(void *data)
 {
@@ -235,7 +278,7 @@ static int wait_for_helper(void *data)
                        sub_info->retval = ret;
        }
 
-       complete(sub_info->complete);
+       umh_complete(sub_info);
        return 0;
 }
 
@@ -244,7 +287,7 @@ static void __call_usermodehelper(struct work_struct *work)
 {
        struct subprocess_info *sub_info =
                container_of(work, struct subprocess_info, work);
-       enum umh_wait wait = sub_info->wait;
+       int wait = sub_info->wait & ~UMH_KILLABLE;
        pid_t pid;
 
        /* CLONE_VFORK: wait until the usermode helper has execve'd
@@ -269,7 +312,7 @@ static void __call_usermodehelper(struct work_struct *work)
        case UMH_WAIT_EXEC:
                if (pid < 0)
                        sub_info->retval = pid;
-               complete(sub_info->complete);
+               umh_complete(sub_info);
        }
 }
 
@@ -435,8 +478,7 @@ EXPORT_SYMBOL(call_usermodehelper_setfns);
  * asynchronously if wait is not set, and runs as a child of keventd.
  * (ie. it runs with full root capabilities).
  */
-int call_usermodehelper_exec(struct subprocess_info *sub_info,
-                            enum umh_wait wait)
+int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
 {
        DECLARE_COMPLETION_ONSTACK(done);
        int retval = 0;
@@ -456,9 +498,21 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
        queue_work(khelper_wq, &sub_info->work);
        if (wait == UMH_NO_WAIT)        /* task has freed sub_info */
                goto unlock;
+
+       if (wait & UMH_KILLABLE) {
+               retval = wait_for_completion_killable(&done);
+               if (!retval)
+                       goto wait_done;
+
+               /* umh_complete() will see NULL and free sub_info */
+               if (xchg(&sub_info->complete, NULL))
+                       goto unlock;
+               /* fallthrough, umh_complete() was already called */
+       }
+
        wait_for_completion(&done);
+wait_done:
        retval = sub_info->retval;
-
 out:
        call_usermodehelper_freeinfo(sub_info);
 unlock:
index 2c93276..78ac6ec 100644 (file)
@@ -105,6 +105,7 @@ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
 
 /* Block module loading/unloading? */
 int modules_disabled = 0;
+core_param(nomodule, modules_disabled, bint, 0);
 
 /* Waiting for a module to finish initializing? */
 static DECLARE_WAIT_QUEUE_HEAD(module_wq);
@@ -903,6 +904,36 @@ static ssize_t show_refcnt(struct module_attribute *mattr,
 static struct module_attribute modinfo_refcnt =
        __ATTR(refcnt, 0444, show_refcnt, NULL);
 
+void __module_get(struct module *module)
+{
+       if (module) {
+               preempt_disable();
+               __this_cpu_inc(module->refptr->incs);
+               trace_module_get(module, _RET_IP_);
+               preempt_enable();
+       }
+}
+EXPORT_SYMBOL(__module_get);
+
+bool try_module_get(struct module *module)
+{
+       bool ret = true;
+
+       if (module) {
+               preempt_disable();
+
+               if (likely(module_is_live(module))) {
+                       __this_cpu_inc(module->refptr->incs);
+                       trace_module_get(module, _RET_IP_);
+               } else
+                       ret = false;
+
+               preempt_enable();
+       }
+       return ret;
+}
+EXPORT_SYMBOL(try_module_get);
+
 void module_put(struct module *module)
 {
        if (module) {
@@ -2380,8 +2411,7 @@ static int copy_and_check(struct load_info *info,
                return -ENOEXEC;
 
        /* Suck in entire file: we'll want most of it. */
-       /* vmalloc barfs on "unusual" numbers.  Check here */
-       if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
+       if ((hdr = vmalloc(len)) == NULL)
                return -ENOMEM;
 
        if (copy_from_user(hdr, umod, len) != 0) {
@@ -2922,7 +2952,8 @@ static struct module *load_module(void __user *umod,
        mutex_unlock(&module_mutex);
 
        /* Module is ready to execute: parsing args may do that. */
-       err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
+       err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
+                        -32768, 32767, NULL);
        if (err < 0)
                goto unlink;
 
index 4bc965d..f37d826 100644 (file)
@@ -15,7 +15,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
@@ -88,6 +87,8 @@ static int parse_one(char *param,
                     char *val,
                     const struct kernel_param *params,
                     unsigned num_params,
+                    s16 min_level,
+                    s16 max_level,
                     int (*handle_unknown)(char *param, char *val))
 {
        unsigned int i;
@@ -96,6 +97,9 @@ static int parse_one(char *param,
        /* Find parameter */
        for (i = 0; i < num_params; i++) {
                if (parameq(param, params[i].name)) {
+                       if (params[i].level < min_level
+                           || params[i].level > max_level)
+                               return 0;
                        /* No one handled NULL, so do it here. */
                        if (!val && params[i].ops->set != param_set_bool
                            && params[i].ops->set != param_set_bint)
@@ -175,6 +179,8 @@ int parse_args(const char *name,
               char *args,
               const struct kernel_param *params,
               unsigned num,
+              s16 min_level,
+              s16 max_level,
               int (*unknown)(char *param, char *val))
 {
        char *param, *val;
@@ -190,7 +196,8 @@ int parse_args(const char *name,
 
                args = next_arg(args, &param, &val);
                irq_was_disabled = irqs_disabled();
-               ret = parse_one(param, val, params, num, unknown);
+               ret = parse_one(param, val, params, num,
+                               min_level, max_level, unknown);
                if (irq_was_disabled && !irqs_disabled()) {
                        printk(KERN_WARNING "parse_args(): option '%s' enabled "
                                        "irq's!\n", param);
@@ -298,35 +305,18 @@ EXPORT_SYMBOL(param_ops_charp);
 /* Actually could be a bool or an int, for historical reasons. */
 int param_set_bool(const char *val, const struct kernel_param *kp)
 {
-       bool v;
-       int ret;
-
        /* No equals means "set"... */
        if (!val) val = "1";
 
        /* One of =[yYnN01] */
-       ret = strtobool(val, &v);
-       if (ret)
-               return ret;
-
-       if (kp->flags & KPARAM_ISBOOL)
-               *(bool *)kp->arg = v;
-       else
-               *(int *)kp->arg = v;
-       return 0;
+       return strtobool(val, kp->arg);
 }
 EXPORT_SYMBOL(param_set_bool);
 
 int param_get_bool(char *buffer, const struct kernel_param *kp)
 {
-       bool val;
-       if (kp->flags & KPARAM_ISBOOL)
-               val = *(bool *)kp->arg;
-       else
-               val = *(int *)kp->arg;
-
        /* Y and N chosen as being relatively non-coder friendly */
-       return sprintf(buffer, "%c", val ? 'Y' : 'N');
+       return sprintf(buffer, "%c", *(bool *)kp->arg ? 'Y' : 'N');
 }
 EXPORT_SYMBOL(param_get_bool);
 
@@ -344,7 +334,6 @@ int param_set_invbool(const char *val, const struct kernel_param *kp)
        struct kernel_param dummy;
 
        dummy.arg = &boolval;
-       dummy.flags = KPARAM_ISBOOL;
        ret = param_set_bool(val, &dummy);
        if (ret == 0)
                *(bool *)kp->arg = !boolval;
@@ -373,7 +362,6 @@ int param_set_bint(const char *val, const struct kernel_param *kp)
        /* Match bool exactly, by re-using it. */
        boolkp = *kp;
        boolkp.arg = &v;
-       boolkp.flags |= KPARAM_ISBOOL;
 
        ret = param_set_bool(val, &boolkp);
        if (ret == 0)
@@ -394,7 +382,7 @@ static int param_array(const char *name,
                       unsigned int min, unsigned int max,
                       void *elem, int elemsize,
                       int (*set)(const char *, const struct kernel_param *kp),
-                      u16 flags,
+                      s16 level,
                       unsigned int *num)
 {
        int ret;
@@ -404,7 +392,7 @@ static int param_array(const char *name,
        /* Get the name right for errors. */
        kp.name = name;
        kp.arg = elem;
-       kp.flags = flags;
+       kp.level = level;
 
        *num = 0;
        /* We expect a comma-separated list of values. */
@@ -445,7 +433,7 @@ static int param_array_set(const char *val, const struct kernel_param *kp)
        unsigned int temp_num;
 
        return param_array(kp->name, val, 1, arr->max, arr->elem,
-                          arr->elemsize, arr->ops->set, kp->flags,
+                          arr->elemsize, arr->ops->set, kp->level,
                           arr->num ?: &temp_num);
 }
 
index a896839..17b2328 100644 (file)
@@ -168,13 +168,9 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
        while (nr > 0) {
                rcu_read_lock();
 
-               /*
-                * Any nested-container's init processes won't ignore the
-                * SEND_SIG_NOINFO signal, see send_signal()->si_fromuser().
-                */
                task = pid_task(find_vpid(nr), PIDTYPE_PID);
-               if (task)
-                       send_sig_info(SIGKILL, SEND_SIG_NOINFO, task);
+               if (task && !__fatal_signal_pending(task))
+                       send_sig_info(SIGKILL, SEND_SIG_FORCED, task);
 
                rcu_read_unlock();
 
index 00ab2ca..ee8d49b 100644 (file)
@@ -231,26 +231,22 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
 }
 
 static int ptrace_attach(struct task_struct *task, long request,
+                        unsigned long addr,
                         unsigned long flags)
 {
        bool seize = (request == PTRACE_SEIZE);
        int retval;
 
-       /*
-        * SEIZE will enable new ptrace behaviors which will be implemented
-        * gradually.  SEIZE_DEVEL is used to prevent applications
-        * expecting full SEIZE behaviors trapping on kernel commits which
-        * are still in the process of implementing them.
-        *
-        * Only test programs for new ptrace behaviors being implemented
-        * should set SEIZE_DEVEL.  If unset, SEIZE will fail with -EIO.
-        *
-        * Once SEIZE behaviors are completely implemented, this flag and
-        * the following test will be removed.
-        */
        retval = -EIO;
-       if (seize && !(flags & PTRACE_SEIZE_DEVEL))
-               goto out;
+       if (seize) {
+               if (addr != 0)
+                       goto out;
+               if (flags & ~(unsigned long)PTRACE_O_MASK)
+                       goto out;
+               flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT);
+       } else {
+               flags = PT_PTRACED;
+       }
 
        audit_ptrace(task);
 
@@ -262,7 +258,7 @@ static int ptrace_attach(struct task_struct *task, long request,
 
        /*
         * Protect exec's credential calculations against our interference;
-        * interference; SUID, SGID and LSM creds get determined differently
+        * SUID, SGID and LSM creds get determined differently
         * under ptrace.
         */
        retval = -ERESTARTNOINTR;
@@ -282,11 +278,11 @@ static int ptrace_attach(struct task_struct *task, long request,
        if (task->ptrace)
                goto unlock_tasklist;
 
-       task->ptrace = PT_PTRACED;
        if (seize)
-               task->ptrace |= PT_SEIZED;
+               flags |= PT_SEIZED;
        if (ns_capable(task_user_ns(task), CAP_SYS_PTRACE))
-               task->ptrace |= PT_PTRACE_CAP;
+               flags |= PT_PTRACE_CAP;
+       task->ptrace = flags;
 
        __ptrace_link(task, current);
 
@@ -528,30 +524,18 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds
 
 static int ptrace_setoptions(struct task_struct *child, unsigned long data)
 {
-       child->ptrace &= ~PT_TRACE_MASK;
+       unsigned flags;
 
-       if (data & PTRACE_O_TRACESYSGOOD)
-               child->ptrace |= PT_TRACESYSGOOD;
-
-       if (data & PTRACE_O_TRACEFORK)
-               child->ptrace |= PT_TRACE_FORK;
-
-       if (data & PTRACE_O_TRACEVFORK)
-               child->ptrace |= PT_TRACE_VFORK;
-
-       if (data & PTRACE_O_TRACECLONE)
-               child->ptrace |= PT_TRACE_CLONE;
-
-       if (data & PTRACE_O_TRACEEXEC)
-               child->ptrace |= PT_TRACE_EXEC;
-
-       if (data & PTRACE_O_TRACEVFORKDONE)
-               child->ptrace |= PT_TRACE_VFORK_DONE;
+       if (data & ~(unsigned long)PTRACE_O_MASK)
+               return -EINVAL;
 
-       if (data & PTRACE_O_TRACEEXIT)
-               child->ptrace |= PT_TRACE_EXIT;
+       /* Avoid intermediate state when all opts are cleared */
+       flags = child->ptrace;
+       flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT);
+       flags |= (data << PT_OPT_FLAG_SHIFT);
+       child->ptrace = flags;
 
-       return (data & ~PTRACE_O_MASK) ? -EINVAL : 0;
+       return 0;
 }
 
 static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
@@ -891,7 +875,7 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
        }
 
        if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
-               ret = ptrace_attach(child, request, data);
+               ret = ptrace_attach(child, request, addr, data);
                /*
                 * Some architectures need to do book-keeping after
                 * a ptrace attach.
@@ -1034,7 +1018,7 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
        }
 
        if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) {
-               ret = ptrace_attach(child, request, data);
+               ret = ptrace_attach(child, request, addr, data);
                /*
                 * Some architectures need to do book-keeping after
                 * a ptrace attach.
index 5120f19..17afcaf 100644 (file)
@@ -59,21 +59,20 @@ static int sig_handler_ignored(void __user *handler, int sig)
                (handler == SIG_DFL && sig_kernel_ignore(sig));
 }
 
-static int sig_task_ignored(struct task_struct *t, int sig,
-               int from_ancestor_ns)
+static int sig_task_ignored(struct task_struct *t, int sig, bool force)
 {
        void __user *handler;
 
        handler = sig_handler(t, sig);
 
        if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
-                       handler == SIG_DFL && !from_ancestor_ns)
+                       handler == SIG_DFL && !force)
                return 1;
 
        return sig_handler_ignored(handler, sig);
 }
 
-static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns)
+static int sig_ignored(struct task_struct *t, int sig, bool force)
 {
        /*
         * Blocked signals are never ignored, since the
@@ -83,7 +82,7 @@ static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns)
        if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
                return 0;
 
-       if (!sig_task_ignored(t, sig, from_ancestor_ns))
+       if (!sig_task_ignored(t, sig, force))
                return 0;
 
        /*
@@ -856,7 +855,7 @@ static void ptrace_trap_notify(struct task_struct *t)
  * Returns true if the signal should be actually delivered, otherwise
  * it should be dropped.
  */
-static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns)
+static int prepare_signal(int sig, struct task_struct *p, bool force)
 {
        struct signal_struct *signal = p->signal;
        struct task_struct *t;
@@ -916,7 +915,7 @@ static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns)
                }
        }
 
-       return !sig_ignored(p, sig, from_ancestor_ns);
+       return !sig_ignored(p, sig, force);
 }
 
 /*
@@ -1060,7 +1059,8 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
        assert_spin_locked(&t->sighand->siglock);
 
        result = TRACE_SIGNAL_IGNORED;
-       if (!prepare_signal(sig, t, from_ancestor_ns))
+       if (!prepare_signal(sig, t,
+                       from_ancestor_ns || (info == SEND_SIG_FORCED)))
                goto ret;
 
        pending = group ? &t->signal->shared_pending : &t->pending;
@@ -1602,7 +1602,7 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
 
        ret = 1; /* the signal is ignored */
        result = TRACE_SIGNAL_IGNORED;
-       if (!prepare_signal(sig, t, 0))
+       if (!prepare_signal(sig, t, false))
                goto out;
 
        ret = 0;
index 888d227..9eb7fca 100644 (file)
@@ -1962,6 +1962,14 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                case PR_SET_MM:
                        error = prctl_set_mm(arg2, arg3, arg4, arg5);
                        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,
+                                        (int __user *) arg2);
+                       break;
                default:
                        error = -EINVAL;
                        break;
index 696f394..803a374 100644 (file)
@@ -195,20 +195,6 @@ static int sysrq_sysctl_handler(ctl_table *table, int write,
 
 #endif
 
-static struct ctl_table root_table[];
-static struct ctl_table_root sysctl_table_root;
-static struct ctl_table_header root_table_header = {
-       {{.count = 1,
-       .ctl_table = root_table,
-       .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}},
-       .root = &sysctl_table_root,
-       .set = &sysctl_table_root.default_set,
-};
-static struct ctl_table_root sysctl_table_root = {
-       .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list),
-       .default_set.list = LIST_HEAD_INIT(root_table_header.ctl_entry),
-};
-
 static struct ctl_table kern_table[];
 static struct ctl_table vm_table[];
 static struct ctl_table fs_table[];
@@ -225,7 +211,7 @@ int sysctl_legacy_va_layout;
 
 /* The default sysctl tables: */
 
-static struct ctl_table root_table[] = {
+static struct ctl_table sysctl_base_table[] = {
        {
                .procname       = "kernel",
                .mode           = 0555,
@@ -1562,490 +1548,12 @@ static struct ctl_table dev_table[] = {
        { }
 };
 
-static DEFINE_SPINLOCK(sysctl_lock);
-
-/* called under sysctl_lock */
-static int use_table(struct ctl_table_header *p)
-{
-       if (unlikely(p->unregistering))
-               return 0;
-       p->used++;
-       return 1;
-}
-
-/* called under sysctl_lock */
-static void unuse_table(struct ctl_table_header *p)
-{
-       if (!--p->used)
-               if (unlikely(p->unregistering))
-                       complete(p->unregistering);
-}
-
-/* called under sysctl_lock, will reacquire if has to wait */
-static void start_unregistering(struct ctl_table_header *p)
-{
-       /*
-        * if p->used is 0, nobody will ever touch that entry again;
-        * we'll eliminate all paths to it before dropping sysctl_lock
-        */
-       if (unlikely(p->used)) {
-               struct completion wait;
-               init_completion(&wait);
-               p->unregistering = &wait;
-               spin_unlock(&sysctl_lock);
-               wait_for_completion(&wait);
-               spin_lock(&sysctl_lock);
-       } else {
-               /* anything non-NULL; we'll never dereference it */
-               p->unregistering = ERR_PTR(-EINVAL);
-       }
-       /*
-        * do not remove from the list until nobody holds it; walking the
-        * list in do_sysctl() relies on that.
-        */
-       list_del_init(&p->ctl_entry);
-}
-
-void sysctl_head_get(struct ctl_table_header *head)
-{
-       spin_lock(&sysctl_lock);
-       head->count++;
-       spin_unlock(&sysctl_lock);
-}
-
-void sysctl_head_put(struct ctl_table_header *head)
-{
-       spin_lock(&sysctl_lock);
-       if (!--head->count)
-               kfree_rcu(head, rcu);
-       spin_unlock(&sysctl_lock);
-}
-
-struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
-{
-       if (!head)
-               BUG();
-       spin_lock(&sysctl_lock);
-       if (!use_table(head))
-               head = ERR_PTR(-ENOENT);
-       spin_unlock(&sysctl_lock);
-       return head;
-}
-
-void sysctl_head_finish(struct ctl_table_header *head)
-{
-       if (!head)
-               return;
-       spin_lock(&sysctl_lock);
-       unuse_table(head);
-       spin_unlock(&sysctl_lock);
-}
-
-static struct ctl_table_set *
-lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces)
-{
-       struct ctl_table_set *set = &root->default_set;
-       if (root->lookup)
-               set = root->lookup(root, namespaces);
-       return set;
-}
-
-static struct list_head *
-lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
-{
-       struct ctl_table_set *set = lookup_header_set(root, namespaces);
-       return &set->list;
-}
-
-struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
-                                           struct ctl_table_header *prev)
-{
-       struct ctl_table_root *root;
-       struct list_head *header_list;
-       struct ctl_table_header *head;
-       struct list_head *tmp;
-
-       spin_lock(&sysctl_lock);
-       if (prev) {
-               head = prev;
-               tmp = &prev->ctl_entry;
-               unuse_table(prev);
-               goto next;
-       }
-       tmp = &root_table_header.ctl_entry;
-       for (;;) {
-               head = list_entry(tmp, struct ctl_table_header, ctl_entry);
-
-               if (!use_table(head))
-                       goto next;
-               spin_unlock(&sysctl_lock);
-               return head;
-       next:
-               root = head->root;
-               tmp = tmp->next;
-               header_list = lookup_header_list(root, namespaces);
-               if (tmp != header_list)
-                       continue;
-
-               do {
-                       root = list_entry(root->root_list.next,
-                                       struct ctl_table_root, root_list);
-                       if (root == &sysctl_table_root)
-                               goto out;
-                       header_list = lookup_header_list(root, namespaces);
-               } while (list_empty(header_list));
-               tmp = header_list->next;
-       }
-out:
-       spin_unlock(&sysctl_lock);
-       return NULL;
-}
-
-struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
-{
-       return __sysctl_head_next(current->nsproxy, prev);
-}
-
-void register_sysctl_root(struct ctl_table_root *root)
-{
-       spin_lock(&sysctl_lock);
-       list_add_tail(&root->root_list, &sysctl_table_root.root_list);
-       spin_unlock(&sysctl_lock);
-}
-
-/*
- * sysctl_perm does NOT grant the superuser all rights automatically, because
- * some sysctl variables are readonly even to root.
- */
-
-static int test_perm(int mode, int op)
-{
-       if (!current_euid())
-               mode >>= 6;
-       else if (in_egroup_p(0))
-               mode >>= 3;
-       if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
-               return 0;
-       return -EACCES;
-}
-
-int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
-{
-       int mode;
-
-       if (root->permissions)
-               mode = root->permissions(root, current->nsproxy, table);
-       else
-               mode = table->mode;
-
-       return test_perm(mode, op);
-}
-
-static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table)
-{
-       for (; table->procname; table++) {
-               table->parent = parent;
-               if (table->child)
-                       sysctl_set_parent(table, table->child);
-       }
-}
-
-static __init int sysctl_init(void)
+int __init sysctl_init(void)
 {
-       sysctl_set_parent(NULL, root_table);
-#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
-       sysctl_check_table(current->nsproxy, root_table);
-#endif
+       register_sysctl_table(sysctl_base_table);
        return 0;
 }
 
-core_initcall(sysctl_init);
-
-static struct ctl_table *is_branch_in(struct ctl_table *branch,
-                                     struct ctl_table *table)
-{
-       struct ctl_table *p;
-       const char *s = branch->procname;
-
-       /* branch should have named subdirectory as its first element */
-       if (!s || !branch->child)
-               return NULL;
-
-       /* ... and nothing else */
-       if (branch[1].procname)
-               return NULL;
-
-       /* table should contain subdirectory with the same name */
-       for (p = table; p->procname; p++) {
-               if (!p->child)
-                       continue;
-               if (p->procname && strcmp(p->procname, s) == 0)
-                       return p;
-       }
-       return NULL;
-}
-
-/* see if attaching q to p would be an improvement */
-static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q)
-{
-       struct ctl_table *to = p->ctl_table, *by = q->ctl_table;
-       struct ctl_table *next;
-       int is_better = 0;
-       int not_in_parent = !p->attached_by;
-
-       while ((next = is_branch_in(by, to)) != NULL) {
-               if (by == q->attached_by)
-                       is_better = 1;
-               if (to == p->attached_by)
-                       not_in_parent = 1;
-               by = by->child;
-               to = next->child;
-       }
-
-       if (is_better && not_in_parent) {
-               q->attached_by = by;
-               q->attached_to = to;
-               q->parent = p;
-       }
-}
-
-/**
- * __register_sysctl_paths - register a sysctl hierarchy
- * @root: List of sysctl headers to register on
- * @namespaces: Data to compute which lists of sysctl entries are visible
- * @path: The path to the directory the sysctl table is in.
- * @table: the top-level table structure
- *
- * Register a sysctl table hierarchy. @table should be a filled in ctl_table
- * array. A completely 0 filled entry terminates the table.
- *
- * The members of the &struct ctl_table structure are used as follows:
- *
- * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
- *            enter a sysctl file
- *
- * data - a pointer to data for use by proc_handler
- *
- * maxlen - the maximum size in bytes of the data
- *
- * mode - the file permissions for the /proc/sys file, and for sysctl(2)
- *
- * child - a pointer to the child sysctl table if this entry is a directory, or
- *         %NULL.
- *
- * proc_handler - the text handler routine (described below)
- *
- * de - for internal use by the sysctl routines
- *
- * extra1, extra2 - extra pointers usable by the proc handler routines
- *
- * Leaf nodes in the sysctl tree will be represented by a single file
- * under /proc; non-leaf nodes will be represented by directories.
- *
- * sysctl(2) can automatically manage read and write requests through
- * the sysctl table.  The data and maxlen fields of the ctl_table
- * struct enable minimal validation of the values being written to be
- * performed, and the mode field allows minimal authentication.
- *
- * There must be a proc_handler routine for any terminal nodes
- * mirrored under /proc/sys (non-terminals are handled by a built-in
- * directory handler).  Several default handlers are available to
- * cover common cases -
- *
- * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
- * proc_dointvec_userhz_jiffies(), proc_dointvec_minmax(), 
- * proc_doulongvec_ms_jiffies_minmax(), proc_doulongvec_minmax()
- *
- * It is the handler's job to read the input buffer from user memory
- * and process it. The handler should return 0 on success.
- *
- * This routine returns %NULL on a failure to register, and a pointer
- * to the table header on success.
- */
-struct ctl_table_header *__register_sysctl_paths(
-       struct ctl_table_root *root,
-       struct nsproxy *namespaces,
-       const struct ctl_path *path, struct ctl_table *table)
-{
-       struct ctl_table_header *header;
-       struct ctl_table *new, **prevp;
-       unsigned int n, npath;
-       struct ctl_table_set *set;
-
-       /* Count the path components */
-       for (npath = 0; path[npath].procname; ++npath)
-               ;
-
-       /*
-        * For each path component, allocate a 2-element ctl_table array.
-        * The first array element will be filled with the sysctl entry
-        * for this, the second will be the sentinel (procname == 0).
-        *
-        * We allocate everything in one go so that we don't have to
-        * worry about freeing additional memory in unregister_sysctl_table.
-        */
-       header = kzalloc(sizeof(struct ctl_table_header) +
-                        (2 * npath * sizeof(struct ctl_table)), GFP_KERNEL);
-       if (!header)
-               return NULL;
-
-       new = (struct ctl_table *) (header + 1);
-
-       /* Now connect the dots */
-       prevp = &header->ctl_table;
-       for (n = 0; n < npath; ++n, ++path) {
-               /* Copy the procname */
-               new->procname = path->procname;
-               new->mode     = 0555;
-
-               *prevp = new;
-               prevp = &new->child;
-
-               new += 2;
-       }
-       *prevp = table;
-       header->ctl_table_arg = table;
-
-       INIT_LIST_HEAD(&header->ctl_entry);
-       header->used = 0;
-       header->unregistering = NULL;
-       header->root = root;
-       sysctl_set_parent(NULL, header->ctl_table);
-       header->count = 1;
-#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
-       if (sysctl_check_table(namespaces, header->ctl_table)) {
-               kfree(header);
-               return NULL;
-       }
-#endif
-       spin_lock(&sysctl_lock);
-       header->set = lookup_header_set(root, namespaces);
-       header->attached_by = header->ctl_table;
-       header->attached_to = root_table;
-       header->parent = &root_table_header;
-       for (set = header->set; set; set = set->parent) {
-               struct ctl_table_header *p;
-               list_for_each_entry(p, &set->list, ctl_entry) {
-                       if (p->unregistering)
-                               continue;
-                       try_attach(p, header);
-               }
-       }
-       header->parent->count++;
-       list_add_tail(&header->ctl_entry, &header->set->list);
-       spin_unlock(&sysctl_lock);
-
-       return header;
-}
-
-/**
- * register_sysctl_table_path - register a sysctl table hierarchy
- * @path: The path to the directory the sysctl table is in.
- * @table: the top-level table structure
- *
- * Register a sysctl table hierarchy. @table should be a filled in ctl_table
- * array. A completely 0 filled entry terminates the table.
- *
- * See __register_sysctl_paths for more details.
- */
-struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
-                                               struct ctl_table *table)
-{
-       return __register_sysctl_paths(&sysctl_table_root, current->nsproxy,
-                                       path, table);
-}
-
-/**
- * register_sysctl_table - register a sysctl table hierarchy
- * @table: the top-level table structure
- *
- * Register a sysctl table hierarchy. @table should be a filled in ctl_table
- * array. A completely 0 filled entry terminates the table.
- *
- * See register_sysctl_paths for more details.
- */
-struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
-{
-       static const struct ctl_path null_path[] = { {} };
-
-       return register_sysctl_paths(null_path, table);
-}
-
-/**
- * unregister_sysctl_table - unregister a sysctl table hierarchy
- * @header: the header returned from register_sysctl_table
- *
- * Unregisters the sysctl table and all children. proc entries may not
- * actually be removed until they are no longer used by anyone.
- */
-void unregister_sysctl_table(struct ctl_table_header * header)
-{
-       might_sleep();
-
-       if (header == NULL)
-               return;
-
-       spin_lock(&sysctl_lock);
-       start_unregistering(header);
-       if (!--header->parent->count) {
-               WARN_ON(1);
-               kfree_rcu(header->parent, rcu);
-       }
-       if (!--header->count)
-               kfree_rcu(header, rcu);
-       spin_unlock(&sysctl_lock);
-}
-
-int sysctl_is_seen(struct ctl_table_header *p)
-{
-       struct ctl_table_set *set = p->set;
-       int res;
-       spin_lock(&sysctl_lock);
-       if (p->unregistering)
-               res = 0;
-       else if (!set->is_seen)
-               res = 1;
-       else
-               res = set->is_seen(set);
-       spin_unlock(&sysctl_lock);
-       return res;
-}
-
-void setup_sysctl_set(struct ctl_table_set *p,
-       struct ctl_table_set *parent,
-       int (*is_seen)(struct ctl_table_set *))
-{
-       INIT_LIST_HEAD(&p->list);
-       p->parent = parent ? parent : &sysctl_table_root.default_set;
-       p->is_seen = is_seen;
-}
-
-#else /* !CONFIG_SYSCTL */
-struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
-{
-       return NULL;
-}
-
-struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
-                                                   struct ctl_table *table)
-{
-       return NULL;
-}
-
-void unregister_sysctl_table(struct ctl_table_header * table)
-{
-}
-
-void setup_sysctl_set(struct ctl_table_set *p,
-       struct ctl_table_set *parent,
-       int (*is_seen)(struct ctl_table_set *))
-{
-}
-
-void sysctl_head_put(struct ctl_table_header *head)
-{
-}
-
 #endif /* CONFIG_SYSCTL */
 
 /*
@@ -3011,6 +2519,3 @@ EXPORT_SYMBOL(proc_dointvec_ms_jiffies);
 EXPORT_SYMBOL(proc_dostring);
 EXPORT_SYMBOL(proc_doulongvec_minmax);
 EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
-EXPORT_SYMBOL(register_sysctl_table);
-EXPORT_SYMBOL(register_sysctl_paths);
-EXPORT_SYMBOL(unregister_sysctl_table);
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
deleted file mode 100644 (file)
index 362da65..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-#include <linux/stat.h>
-#include <linux/sysctl.h>
-#include "../fs/xfs/xfs_sysctl.h"
-#include <linux/sunrpc/debug.h>
-#include <linux/string.h>
-#include <net/ip_vs.h>
-
-
-static int sysctl_depth(struct ctl_table *table)
-{
-       struct ctl_table *tmp;
-       int depth;
-
-       depth = 0;
-       for (tmp = table; tmp->parent; tmp = tmp->parent)
-               depth++;
-
-       return depth;
-}
-
-static struct ctl_table *sysctl_parent(struct ctl_table *table, int n)
-{
-       int i;
-
-       for (i = 0; table && i < n; i++)
-               table = table->parent;
-
-       return table;
-}
-
-
-static void sysctl_print_path(struct ctl_table *table)
-{
-       struct ctl_table *tmp;
-       int depth, i;
-       depth = sysctl_depth(table);
-       if (table->procname) {
-               for (i = depth; i >= 0; i--) {
-                       tmp = sysctl_parent(table, i);
-                       printk("/%s", tmp->procname?tmp->procname:"");
-               }
-       }
-       printk(" ");
-}
-
-static struct ctl_table *sysctl_check_lookup(struct nsproxy *namespaces,
-                                               struct ctl_table *table)
-{
-       struct ctl_table_header *head;
-       struct ctl_table *ref, *test;
-       int depth, cur_depth;
-
-       depth = sysctl_depth(table);
-
-       for (head = __sysctl_head_next(namespaces, NULL); head;
-            head = __sysctl_head_next(namespaces, head)) {
-               cur_depth = depth;
-               ref = head->ctl_table;
-repeat:
-               test = sysctl_parent(table, cur_depth);
-               for (; ref->procname; ref++) {
-                       int match = 0;
-                       if (cur_depth && !ref->child)
-                               continue;
-
-                       if (test->procname && ref->procname &&
-                           (strcmp(test->procname, ref->procname) == 0))
-                                       match++;
-
-                       if (match) {
-                               if (cur_depth != 0) {
-                                       cur_depth--;
-                                       ref = ref->child;
-                                       goto repeat;
-                               }
-                               goto out;
-                       }
-               }
-       }
-       ref = NULL;
-out:
-       sysctl_head_finish(head);
-       return ref;
-}
-
-static void set_fail(const char **fail, struct ctl_table *table, const char *str)
-{
-       if (*fail) {
-               printk(KERN_ERR "sysctl table check failed: ");
-               sysctl_print_path(table);
-               printk(" %s\n", *fail);
-               dump_stack();
-       }
-       *fail = str;
-}
-
-static void sysctl_check_leaf(struct nsproxy *namespaces,
-                               struct ctl_table *table, const char **fail)
-{
-       struct ctl_table *ref;
-
-       ref = sysctl_check_lookup(namespaces, table);
-       if (ref && (ref != table))
-               set_fail(fail, table, "Sysctl already exists");
-}
-
-int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
-{
-       int error = 0;
-       for (; table->procname; table++) {
-               const char *fail = NULL;
-
-               if (table->parent) {
-                       if (!table->parent->procname)
-                               set_fail(&fail, table, "Parent without procname");
-               }
-               if (table->child) {
-                       if (table->data)
-                               set_fail(&fail, table, "Directory with data?");
-                       if (table->maxlen)
-                               set_fail(&fail, table, "Directory with maxlen?");
-                       if ((table->mode & (S_IRUGO|S_IXUGO)) != table->mode)
-                               set_fail(&fail, table, "Writable sysctl directory");
-                       if (table->proc_handler)
-                               set_fail(&fail, table, "Directory with proc_handler");
-                       if (table->extra1)
-                               set_fail(&fail, table, "Directory with extra1");
-                       if (table->extra2)
-                               set_fail(&fail, table, "Directory with extra2");
-               } else {
-                       if ((table->proc_handler == proc_dostring) ||
-                           (table->proc_handler == proc_dointvec) ||
-                           (table->proc_handler == proc_dointvec_minmax) ||
-                           (table->proc_handler == proc_dointvec_jiffies) ||
-                           (table->proc_handler == proc_dointvec_userhz_jiffies) ||
-                           (table->proc_handler == proc_dointvec_ms_jiffies) ||
-                           (table->proc_handler == proc_doulongvec_minmax) ||
-                           (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) {
-                               if (!table->data)
-                                       set_fail(&fail, table, "No data");
-                               if (!table->maxlen)
-                                       set_fail(&fail, table, "No maxlen");
-                       }
-#ifdef CONFIG_PROC_SYSCTL
-                       if (!table->proc_handler)
-                               set_fail(&fail, table, "No proc_handler");
-#endif
-                       sysctl_check_leaf(namespaces, table, &fail);
-               }
-               if (table->mode > 0777)
-                       set_fail(&fail, table, "bogus .mode");
-               if (fail) {
-                       set_fail(&fail, table, NULL);
-                       error = -EINVAL;
-               }
-               if (table->child)
-                       error |= sysctl_check_table(namespaces, table->child);
-       }
-       return error;
-}
index 14bc092..df30ee0 100644 (file)
@@ -9,6 +9,8 @@
  * to those contributors as well.
  */
 
+#define pr_fmt(fmt) "NMI watchdog: " fmt
+
 #include <linux/mm.h>
 #include <linux/cpu.h>
 #include <linux/nmi.h>
@@ -319,11 +321,9 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
  */
 static int watchdog(void *unused)
 {
-       struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+       struct sched_param param = { .sched_priority = 0 };
        struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
 
-       sched_setscheduler(current, SCHED_FIFO, &param);
-
        /* initialize timestamp */
        __touch_watchdog();
 
@@ -349,8 +349,11 @@ static int watchdog(void *unused)
 
                set_current_state(TASK_INTERRUPTIBLE);
        }
+       /*
+        * Drop the policy/priority elevation during thread exit to avoid a
+        * scheduling latency spike.
+        */
        __set_current_state(TASK_RUNNING);
-       param.sched_priority = 0;
        sched_setscheduler(current, SCHED_NORMAL, &param);
        return 0;
 }
@@ -376,18 +379,20 @@ static int watchdog_nmi_enable(int cpu)
        /* Try to register using hardware perf events */
        event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL);
        if (!IS_ERR(event)) {
-               printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n");
+               pr_info("enabled, takes one hw-pmu counter.\n");
                goto out_save;
        }
 
 
        /* vary the KERN level based on the returned errno */
        if (PTR_ERR(event) == -EOPNOTSUPP)
-               printk(KERN_INFO "NMI watchdog disabled (cpu%i): not supported (no LAPIC?)\n", cpu);
+               pr_info("disabled (cpu%i): not supported (no LAPIC?)\n", cpu);
        else if (PTR_ERR(event) == -ENOENT)
-               printk(KERN_WARNING "NMI watchdog disabled (cpu%i): hardware events not enabled\n", cpu);
+               pr_warning("disabled (cpu%i): hardware events not enabled\n",
+                        cpu);
        else
-               printk(KERN_ERR "NMI watchdog disabled (cpu%i): unable to create perf event: %ld\n", cpu, PTR_ERR(event));
+               pr_err("disabled (cpu%i): unable to create perf event: %ld\n",
+                       cpu, PTR_ERR(event));
        return PTR_ERR(event);
 
        /* success path */
@@ -439,9 +444,10 @@ static int watchdog_enable(int cpu)
 
        /* create the watchdog thread */
        if (!p) {
+               struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
                p = kthread_create_on_node(watchdog, NULL, cpu_to_node(cpu), "watchdog/%d", cpu);
                if (IS_ERR(p)) {
-                       printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu);
+                       pr_err("softlockup watchdog for %i failed\n", cpu);
                        if (!err) {
                                /* if hardlockup hasn't already set this */
                                err = PTR_ERR(p);
@@ -450,6 +456,7 @@ static int watchdog_enable(int cpu)
                        }
                        goto out;
                }
+               sched_setscheduler(p, SCHED_FIFO, &param);
                kthread_bind(p, cpu);
                per_cpu(watchdog_touch_ts, cpu) = 0;
                per_cpu(softlockup_watchdog, cpu) = p;
@@ -496,7 +503,7 @@ static void watchdog_enable_all_cpus(void)
                        watchdog_enabled = 1;
 
        if (!watchdog_enabled)
-               printk(KERN_ERR "watchdog: failed to be enabled on some cpus\n");
+               pr_err("failed to be enabled on some cpus\n");
 
 }
 
index 028aba9..a0e5900 100644 (file)
@@ -29,6 +29,10 @@ config GENERIC_IOMAP
        bool
        select GENERIC_PCI_IOMAP
 
+config GENERIC_IO
+       boolean
+       default n
+
 config CRC_CCITT
        tristate "CRC-CCITT functions"
        help
@@ -61,14 +65,67 @@ config CRC_ITU_T
          functions require M here.
 
 config CRC32
-       tristate "CRC32 functions"
+       tristate "CRC32/CRC32c functions"
        default y
        select BITREVERSE
        help
          This option is provided for the case where no in-kernel-tree
-         modules require CRC32 functions, but a module built outside the
-         kernel tree does. Such modules that use library CRC32 functions
-         require M here.
+         modules require CRC32/CRC32c functions, but a module built outside
+         the kernel tree does. Such modules that use library CRC32/CRC32c
+         functions require M here.
+
+config CRC32_SELFTEST
+       bool "CRC32 perform self test on init"
+       default n
+       depends on CRC32
+       help
+         This option enables the CRC32 library functions to perform a
+         self test on initialization. The self test computes crc32_le
+         and crc32_be over byte strings with random alignment and length
+         and computes the total elapsed time and number of bytes processed.
+
+choice
+       prompt "CRC32 implementation"
+       depends on CRC32
+       default CRC32_SLICEBY8
+
+config CRC32_SLICEBY8
+       bool "Slice by 8 bytes"
+       help
+         Calculate checksum 8 bytes at a time with a clever slicing algorithm.
+         This is the fastest algorithm, but comes with a 8KiB lookup table.
+         Most modern processors have enough cache to hold this table without
+         thrashing the cache.
+
+         This is the default implementation choice.  Choose this one unless
+         you have a good reason not to.
+
+config CRC32_SLICEBY4
+       bool "Slice by 4 bytes"
+       help
+         Calculate checksum 4 bytes at a time with a clever slicing algorithm.
+         This is a bit slower than slice by 8, but has a smaller 4KiB lookup
+         table.
+
+         Only choose this option if you know what you are doing.
+
+config CRC32_SARWATE
+       bool "Sarwate's Algorithm (one byte at a time)"
+       help
+         Calculate checksum a byte at a time using Sarwate's algorithm.  This
+         is not particularly fast, but has a small 256 byte lookup table.
+
+         Only choose this option if you know what you are doing.
+
+config CRC32_BIT
+       bool "Classic Algorithm (one bit at a time)"
+       help
+         Calculate checksum one bit at a time.  This is VERY slow, but has
+         no lookup table.  This is provided as a debugging option.
+
+         Only choose this option if you are debugging crc32.
+
+endchoice
 
 config CRC7
        tristate "CRC7 functions"
@@ -224,6 +281,7 @@ config BTREE
 config HAS_IOMEM
        boolean
        depends on !NO_IOMEM
+       select GENERIC_IO
        default y
 
 config HAS_IOPORT
index 05037dc..f7af95d 100644 (file)
@@ -184,7 +184,7 @@ config LOCKUP_DETECTOR
 
 config HARDLOCKUP_DETECTOR
        def_bool LOCKUP_DETECTOR && PERF_EVENTS && HAVE_PERF_EVENTS_NMI && \
-                !ARCH_HAS_NMI_WATCHDOG
+                !HAVE_NMI_WATCHDOG
 
 config BOOTPARAM_HARDLOCKUP_PANIC
        bool "Panic (Reboot) On Hard Lockups"
@@ -1141,14 +1141,6 @@ config LATENCYTOP
          Enable this option if you want to use the LatencyTOP tool
          to find out which userspace is blocking on what kernel operations.
 
-config SYSCTL_SYSCALL_CHECK
-       bool "Sysctl checks"
-       depends on SYSCTL
-       ---help---
-         sys_sysctl uses binary paths that have been found challenging
-         to properly maintain and use. This enables checks that help
-         you to keep things correct.
-
 source mm/Kconfig.debug
 source kernel/trace/Kconfig
 
index 4b1b083..1e9a6cb 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 static const char *skip_arg(const char *cp)
 {
index 3975470..9785378 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/cache.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/atomic.h>
 
 /*
index 0c33cde..cb99b91 100644 (file)
@@ -9,6 +9,7 @@
  * (at your option) any later version.
  */
 #include <linux/init.h>
+#include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/atomic.h>
 
index 5576c28..99a67e6 100644 (file)
@@ -5,8 +5,9 @@
  * Version 2.  See the file COPYING for more details.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/average.h>
+#include <linux/kernel.h>
 #include <linux/bug.h>
 #include <linux/log2.h>
 
index d74257f..55efaf7 100644 (file)
--- a/lib/bcd.c
+++ b/lib/bcd.c
@@ -1,5 +1,5 @@
 #include <linux/bcd.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 unsigned bcd2bin(unsigned char val)
 {
index 0d4a127..b5a8b6a 100644 (file)
@@ -5,11 +5,13 @@
  * This source code is licensed under the GNU General Public License,
  * Version 2.  See the file COPYING for more details.
  */
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/thread_info.h>
 #include <linux/ctype.h>
 #include <linux/errno.h>
 #include <linux/bitmap.h>
 #include <linux/bitops.h>
+#include <linux/bug.h>
 #include <asm/uaccess.h>
 
 /*
index 5b54758..e33c179 100644 (file)
@@ -9,7 +9,7 @@
  * published by the Free Software Foundation; version 2.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bsearch.h>
 
 /*
index fd6af19..6b49797 100644 (file)
@@ -1,5 +1,5 @@
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /**
  *     check_signature         -       find BIOS signatures
index 8df2f91..12dceb2 100644 (file)
@@ -32,7 +32,7 @@
 /* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access
  kills, so most of the assembly has to go. */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <net/checksum.h>
 
 #include <asm/byteorder.h>
index f5f3ad8..eb67911 100644 (file)
@@ -12,7 +12,7 @@
  *
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 
index 987acfa..145dec5 100644 (file)
@@ -11,7 +11,7 @@
 #ifdef CONFIG_GENERIC_HARDIRQS
 #include <linux/interrupt.h>
 #endif
-#include <linux/module.h>
+#include <linux/export.h>
 
 /*
  * These functions maintain a mapping from CPUs to some ordered set of
index af3e581..0b66011 100644 (file)
@@ -2,7 +2,7 @@
 #include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/cpumask.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bootmem.h>
 
 int __first_cpu(const cpumask_t *srcp)
index 4b35d2b..b0d278f 100644 (file)
@@ -1,4 +1,8 @@
 /*
+ * Aug 8, 2011 Bob Pearson with help from Joakim Tjernlund and George Spelvin
+ * cleaned up code to current version of sparse and added the slicing-by-8
+ * algorithm to the closely similar existing slicing-by-4 algorithm.
+ *
  * Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
  * Nicer crc32 functions/docs submitted by linux@horizon.com.  Thanks!
  * Code was from the public domain, copyright abandoned.  Code was
  * Version 2.  See the file COPYING for more details.
  */
 
+/* see: Documentation/crc32.txt for a description of algorithms */
+
 #include <linux/crc32.h>
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/compiler.h>
 #include <linux/types.h>
-#include <linux/init.h>
-#include <linux/atomic.h>
 #include "crc32defs.h"
-#if CRC_LE_BITS == 8
-# define tole(x) __constant_cpu_to_le32(x)
+
+#if CRC_LE_BITS > 8
+# define tole(x) ((__force u32) __constant_cpu_to_le32(x))
 #else
 # define tole(x) (x)
 #endif
 
-#if CRC_BE_BITS == 8
-# define tobe(x) __constant_cpu_to_be32(x)
+#if CRC_BE_BITS > 8
+# define tobe(x) ((__force u32) __constant_cpu_to_be32(x))
 #else
 # define tobe(x) (x)
 #endif
+
 #include "crc32table.h"
 
 MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>");
-MODULE_DESCRIPTION("Ethernet CRC32 calculations");
+MODULE_DESCRIPTION("Various CRC32 calculations");
 MODULE_LICENSE("GPL");
 
-#if CRC_LE_BITS == 8 || CRC_BE_BITS == 8
+#if CRC_LE_BITS > 8 || CRC_BE_BITS > 8
 
+/* implements slicing-by-4 or slicing-by-8 algorithm */
 static inline u32
 crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
 {
 # ifdef __LITTLE_ENDIAN
 #  define DO_CRC(x) crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8)
-#  define DO_CRC4 crc = t3[(crc) & 255] ^ \
-               t2[(crc >> 8) & 255] ^ \
-               t1[(crc >> 16) & 255] ^ \
-               t0[(crc >> 24) & 255]
+#  define DO_CRC4 (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \
+                  t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255])
+#  define DO_CRC8 (t7[(q) & 255] ^ t6[(q >> 8) & 255] ^ \
+                  t5[(q >> 16) & 255] ^ t4[(q >> 24) & 255])
 # else
 #  define DO_CRC(x) crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
-#  define DO_CRC4 crc = t0[(crc) & 255] ^ \
-               t1[(crc >> 8) & 255] ^  \
-               t2[(crc >> 16) & 255] ^ \
-               t3[(crc >> 24) & 255]
+#  define DO_CRC4 (t0[(q) & 255] ^ t1[(q >> 8) & 255] ^ \
+                  t2[(q >> 16) & 255] ^ t3[(q >> 24) & 255])
+#  define DO_CRC8 (t4[(q) & 255] ^ t5[(q >> 8) & 255] ^ \
+                  t6[(q >> 16) & 255] ^ t7[(q >> 24) & 255])
 # endif
        const u32 *b;
        size_t    rem_len;
+# ifdef CONFIG_X86
+       size_t i;
+# endif
        const u32 *t0=tab[0], *t1=tab[1], *t2=tab[2], *t3=tab[3];
+       const u32 *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7];
+       u32 q;
 
        /* Align it */
        if (unlikely((long)buf & 3 && len)) {
@@ -73,27 +83,51 @@ crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
                        DO_CRC(*buf++);
                } while ((--len) && ((long)buf)&3);
        }
+
+# if CRC_LE_BITS == 32
        rem_len = len & 3;
-       /* load data 32 bits wide, xor data 32 bits wide. */
        len = len >> 2;
+# else
+       rem_len = len & 7;
+       len = len >> 3;
+# endif
+
        b = (const u32 *)buf;
+# ifdef CONFIG_X86
+       --b;
+       for (i = 0; i < len; i++) {
+# else
        for (--b; len; --len) {
-               crc ^= *++b; /* use pre increment for speed */
-               DO_CRC4;
+# endif
+               q = crc ^ *++b; /* use pre increment for speed */
+# if CRC_LE_BITS == 32
+               crc = DO_CRC4;
+# else
+               crc = DO_CRC8;
+               q = *++b;
+               crc ^= DO_CRC4;
+# endif
        }
        len = rem_len;
        /* And the last few bytes */
        if (len) {
                u8 *p = (u8 *)(b + 1) - 1;
+# ifdef CONFIG_X86
+               for (i = 0; i < len; i++)
+                       DO_CRC(*++p); /* use pre increment for speed */
+# else
                do {
                        DO_CRC(*++p); /* use pre increment for speed */
                } while (--len);
+# endif
        }
        return crc;
 #undef DO_CRC
 #undef DO_CRC4
+#undef DO_CRC8
 }
 #endif
+
 /**
  * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
  * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
@@ -101,53 +135,66 @@ crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
  * @p: pointer to buffer over which CRC is run
  * @len: length of buffer @p
  */
-u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len);
-
-#if CRC_LE_BITS == 1
-/*
- * In fact, the table-based code will work in this case, but it can be
- * simplified by inlining the table in ?: form.
- */
-
-u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
+static inline u32 __pure crc32_le_generic(u32 crc, unsigned char const *p,
+                                         size_t len, const u32 (*tab)[256],
+                                         u32 polynomial)
 {
+#if CRC_LE_BITS == 1
        int i;
        while (len--) {
                crc ^= *p++;
                for (i = 0; i < 8; i++)
-                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+                       crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
+       }
+# elif CRC_LE_BITS == 2
+       while (len--) {
+               crc ^= *p++;
+               crc = (crc >> 2) ^ tab[0][crc & 3];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
        }
-       return crc;
-}
-#else                          /* Table-based approach */
-
-u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
-{
-# if CRC_LE_BITS == 8
-       const u32      (*tab)[] = crc32table_le;
-
-       crc = __cpu_to_le32(crc);
-       crc = crc32_body(crc, p, len, tab);
-       return __le32_to_cpu(crc);
 # elif CRC_LE_BITS == 4
        while (len--) {
                crc ^= *p++;
-               crc = (crc >> 4) ^ crc32table_le[crc & 15];
-               crc = (crc >> 4) ^ crc32table_le[crc & 15];
+               crc = (crc >> 4) ^ tab[0][crc & 15];
+               crc = (crc >> 4) ^ tab[0][crc & 15];
        }
-       return crc;
-# elif CRC_LE_BITS == 2
+# elif CRC_LE_BITS == 8
+       /* aka Sarwate algorithm */
        while (len--) {
                crc ^= *p++;
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
+               crc = (crc >> 8) ^ tab[0][crc & 255];
        }
+# else
+       crc = (__force u32) __cpu_to_le32(crc);
+       crc = crc32_body(crc, p, len, tab);
+       crc = __le32_to_cpu((__force __le32)crc);
+#endif
        return crc;
-# endif
+}
+
+#if CRC_LE_BITS == 1
+u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+       return crc32_le_generic(crc, p, len, NULL, CRCPOLY_LE);
+}
+u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len)
+{
+       return crc32_le_generic(crc, p, len, NULL, CRC32C_POLY_LE);
+}
+#else
+u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
+{
+       return crc32_le_generic(crc, p, len, crc32table_le, CRCPOLY_LE);
+}
+u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len)
+{
+       return crc32_le_generic(crc, p, len, crc32ctable_le, CRC32C_POLY_LE);
 }
 #endif
+EXPORT_SYMBOL(crc32_le);
+EXPORT_SYMBOL(__crc32c_le);
 
 /**
  * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
@@ -156,317 +203,913 @@ u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len)
  * @p: pointer to buffer over which CRC is run
  * @len: length of buffer @p
  */
-u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len);
-
-#if CRC_BE_BITS == 1
-/*
- * In fact, the table-based code will work in this case, but it can be
- * simplified by inlining the table in ?: form.
- */
-
-u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
+static inline u32 __pure crc32_be_generic(u32 crc, unsigned char const *p,
+                                         size_t len, const u32 (*tab)[256],
+                                         u32 polynomial)
 {
+#if CRC_BE_BITS == 1
        int i;
        while (len--) {
                crc ^= *p++ << 24;
                for (i = 0; i < 8; i++)
                        crc =
-                           (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
+                           (crc << 1) ^ ((crc & 0x80000000) ? polynomial :
                                          0);
        }
-       return crc;
-}
-
-#else                          /* Table-based approach */
-u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
-{
-# if CRC_BE_BITS == 8
-       const u32      (*tab)[] = crc32table_be;
-
-       crc = __cpu_to_be32(crc);
-       crc = crc32_body(crc, p, len, tab);
-       return __be32_to_cpu(crc);
+# elif CRC_BE_BITS == 2
+       while (len--) {
+               crc ^= *p++ << 24;
+               crc = (crc << 2) ^ tab[0][crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
+       }
 # elif CRC_BE_BITS == 4
        while (len--) {
                crc ^= *p++ << 24;
-               crc = (crc << 4) ^ crc32table_be[crc >> 28];
-               crc = (crc << 4) ^ crc32table_be[crc >> 28];
+               crc = (crc << 4) ^ tab[0][crc >> 28];
+               crc = (crc << 4) ^ tab[0][crc >> 28];
        }
-       return crc;
-# elif CRC_BE_BITS == 2
+# elif CRC_BE_BITS == 8
        while (len--) {
                crc ^= *p++ << 24;
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
+               crc = (crc << 8) ^ tab[0][crc >> 24];
        }
-       return crc;
+# else
+       crc = (__force u32) __cpu_to_be32(crc);
+       crc = crc32_body(crc, p, len, tab);
+       crc = __be32_to_cpu((__force __be32)crc);
 # endif
+       return crc;
 }
-#endif
 
-EXPORT_SYMBOL(crc32_le);
+#if CRC_LE_BITS == 1
+u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+       return crc32_be_generic(crc, p, len, NULL, CRCPOLY_BE);
+}
+#else
+u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len)
+{
+       return crc32_be_generic(crc, p, len, crc32table_be, CRCPOLY_BE);
+}
+#endif
 EXPORT_SYMBOL(crc32_be);
 
-/*
- * A brief CRC tutorial.
- *
- * A CRC is a long-division remainder.  You add the CRC to the message,
- * and the whole thing (message+CRC) is a multiple of the given
- * CRC polynomial.  To check the CRC, you can either check that the
- * CRC matches the recomputed value, *or* you can check that the
- * remainder computed on the message+CRC is 0.  This latter approach
- * is used by a lot of hardware implementations, and is why so many
- * protocols put the end-of-frame flag after the CRC.
- *
- * It's actually the same long division you learned in school, except that
- * - We're working in binary, so the digits are only 0 and 1, and
- * - When dividing polynomials, there are no carries.  Rather than add and
- *   subtract, we just xor.  Thus, we tend to get a bit sloppy about
- *   the difference between adding and subtracting.
- *
- * A 32-bit CRC polynomial is actually 33 bits long.  But since it's
- * 33 bits long, bit 32 is always going to be set, so usually the CRC
- * is written in hex with the most significant bit omitted.  (If you're
- * familiar with the IEEE 754 floating-point format, it's the same idea.)
- *
- * Note that a CRC is computed over a string of *bits*, so you have
- * to decide on the endianness of the bits within each byte.  To get
- * the best error-detecting properties, this should correspond to the
- * order they're actually sent.  For example, standard RS-232 serial is
- * little-endian; the most significant bit (sometimes used for parity)
- * is sent last.  And when appending a CRC word to a message, you should
- * do it in the right order, matching the endianness.
- *
- * Just like with ordinary division, the remainder is always smaller than
- * the divisor (the CRC polynomial) you're dividing by.  Each step of the
- * division, you take one more digit (bit) of the dividend and append it
- * to the current remainder.  Then you figure out the appropriate multiple
- * of the divisor to subtract to being the remainder back into range.
- * In binary, it's easy - it has to be either 0 or 1, and to make the
- * XOR cancel, it's just a copy of bit 32 of the remainder.
- *
- * When computing a CRC, we don't care about the quotient, so we can
- * throw the quotient bit away, but subtract the appropriate multiple of
- * the polynomial from the remainder and we're back to where we started,
- * ready to process the next bit.
- *
- * A big-endian CRC written this way would be coded like:
- * for (i = 0; i < input_bits; i++) {
- *     multiple = remainder & 0x80000000 ? CRCPOLY : 0;
- *     remainder = (remainder << 1 | next_input_bit()) ^ multiple;
- * }
- * Notice how, to get at bit 32 of the shifted remainder, we look
- * at bit 31 of the remainder *before* shifting it.
- *
- * But also notice how the next_input_bit() bits we're shifting into
- * the remainder don't actually affect any decision-making until
- * 32 bits later.  Thus, the first 32 cycles of this are pretty boring.
- * Also, to add the CRC to a message, we need a 32-bit-long hole for it at
- * the end, so we have to add 32 extra cycles shifting in zeros at the
- * end of every message,
- *
- * So the standard trick is to rearrage merging in the next_input_bit()
- * until the moment it's needed.  Then the first 32 cycles can be precomputed,
- * and merging in the final 32 zero bits to make room for the CRC can be
- * skipped entirely.
- * This changes the code to:
- * for (i = 0; i < input_bits; i++) {
- *      remainder ^= next_input_bit() << 31;
- *     multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
- *     remainder = (remainder << 1) ^ multiple;
- * }
- * With this optimization, the little-endian code is simpler:
- * for (i = 0; i < input_bits; i++) {
- *      remainder ^= next_input_bit();
- *     multiple = (remainder & 1) ? CRCPOLY : 0;
- *     remainder = (remainder >> 1) ^ multiple;
- * }
- *
- * Note that the other details of endianness have been hidden in CRCPOLY
- * (which must be bit-reversed) and next_input_bit().
- *
- * However, as long as next_input_bit is returning the bits in a sensible
- * order, we can actually do the merging 8 or more bits at a time rather
- * than one bit at a time:
- * for (i = 0; i < input_bytes; i++) {
- *     remainder ^= next_input_byte() << 24;
- *     for (j = 0; j < 8; j++) {
- *             multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
- *             remainder = (remainder << 1) ^ multiple;
- *     }
- * }
- * Or in little-endian:
- * for (i = 0; i < input_bytes; i++) {
- *     remainder ^= next_input_byte();
- *     for (j = 0; j < 8; j++) {
- *             multiple = (remainder & 1) ? CRCPOLY : 0;
- *             remainder = (remainder << 1) ^ multiple;
- *     }
- * }
- * If the input is a multiple of 32 bits, you can even XOR in a 32-bit
- * word at a time and increase the inner loop count to 32.
- *
- * You can also mix and match the two loop styles, for example doing the
- * bulk of a message byte-at-a-time and adding bit-at-a-time processing
- * for any fractional bytes at the end.
- *
- * The only remaining optimization is to the byte-at-a-time table method.
- * Here, rather than just shifting one bit of the remainder to decide
- * in the correct multiple to subtract, we can shift a byte at a time.
- * This produces a 40-bit (rather than a 33-bit) intermediate remainder,
- * but again the multiple of the polynomial to subtract depends only on
- * the high bits, the high 8 bits in this case.  
- *
- * The multiple we need in that case is the low 32 bits of a 40-bit
- * value whose high 8 bits are given, and which is a multiple of the
- * generator polynomial.  This is simply the CRC-32 of the given
- * one-byte message.
- *
- * Two more details: normally, appending zero bits to a message which
- * is already a multiple of a polynomial produces a larger multiple of that
- * polynomial.  To enable a CRC to detect this condition, it's common to
- * invert the CRC before appending it.  This makes the remainder of the
- * message+crc come out not as zero, but some fixed non-zero value.
- *
- * The same problem applies to zero bits prepended to the message, and
- * a similar solution is used.  Instead of starting with a remainder of
- * 0, an initial remainder of all ones is used.  As long as you start
- * the same way on decoding, it doesn't make a difference.
- */
-
-#ifdef UNITTEST
+#ifdef CONFIG_CRC32_SELFTEST
 
-#include <stdlib.h>
-#include <stdio.h>
+/* 4096 random bytes */
+static u8 __attribute__((__aligned__(8))) test_buf[] =
+{
+       0x5b, 0x85, 0x21, 0xcb, 0x09, 0x68, 0x7d, 0x30,
+       0xc7, 0x69, 0xd7, 0x30, 0x92, 0xde, 0x59, 0xe4,
+       0xc9, 0x6e, 0x8b, 0xdb, 0x98, 0x6b, 0xaa, 0x60,
+       0xa8, 0xb5, 0xbc, 0x6c, 0xa9, 0xb1, 0x5b, 0x2c,
+       0xea, 0xb4, 0x92, 0x6a, 0x3f, 0x79, 0x91, 0xe4,
+       0xe9, 0x70, 0x51, 0x8c, 0x7f, 0x95, 0x6f, 0x1a,
+       0x56, 0xa1, 0x5c, 0x27, 0x03, 0x67, 0x9f, 0x3a,
+       0xe2, 0x31, 0x11, 0x29, 0x6b, 0x98, 0xfc, 0xc4,
+       0x53, 0x24, 0xc5, 0x8b, 0xce, 0x47, 0xb2, 0xb9,
+       0x32, 0xcb, 0xc1, 0xd0, 0x03, 0x57, 0x4e, 0xd4,
+       0xe9, 0x3c, 0xa1, 0x63, 0xcf, 0x12, 0x0e, 0xca,
+       0xe1, 0x13, 0xd1, 0x93, 0xa6, 0x88, 0x5c, 0x61,
+       0x5b, 0xbb, 0xf0, 0x19, 0x46, 0xb4, 0xcf, 0x9e,
+       0xb6, 0x6b, 0x4c, 0x3a, 0xcf, 0x60, 0xf9, 0x7a,
+       0x8d, 0x07, 0x63, 0xdb, 0x40, 0xe9, 0x0b, 0x6f,
+       0xad, 0x97, 0xf1, 0xed, 0xd0, 0x1e, 0x26, 0xfd,
+       0xbf, 0xb7, 0xc8, 0x04, 0x94, 0xf8, 0x8b, 0x8c,
+       0xf1, 0xab, 0x7a, 0xd4, 0xdd, 0xf3, 0xe8, 0x88,
+       0xc3, 0xed, 0x17, 0x8a, 0x9b, 0x40, 0x0d, 0x53,
+       0x62, 0x12, 0x03, 0x5f, 0x1b, 0x35, 0x32, 0x1f,
+       0xb4, 0x7b, 0x93, 0x78, 0x0d, 0xdb, 0xce, 0xa4,
+       0xc0, 0x47, 0xd5, 0xbf, 0x68, 0xe8, 0x5d, 0x74,
+       0x8f, 0x8e, 0x75, 0x1c, 0xb2, 0x4f, 0x9a, 0x60,
+       0xd1, 0xbe, 0x10, 0xf4, 0x5c, 0xa1, 0x53, 0x09,
+       0xa5, 0xe0, 0x09, 0x54, 0x85, 0x5c, 0xdc, 0x07,
+       0xe7, 0x21, 0x69, 0x7b, 0x8a, 0xfd, 0x90, 0xf1,
+       0x22, 0xd0, 0xb4, 0x36, 0x28, 0xe6, 0xb8, 0x0f,
+       0x39, 0xde, 0xc8, 0xf3, 0x86, 0x60, 0x34, 0xd2,
+       0x5e, 0xdf, 0xfd, 0xcf, 0x0f, 0xa9, 0x65, 0xf0,
+       0xd5, 0x4d, 0x96, 0x40, 0xe3, 0xdf, 0x3f, 0x95,
+       0x5a, 0x39, 0x19, 0x93, 0xf4, 0x75, 0xce, 0x22,
+       0x00, 0x1c, 0x93, 0xe2, 0x03, 0x66, 0xf4, 0x93,
+       0x73, 0x86, 0x81, 0x8e, 0x29, 0x44, 0x48, 0x86,
+       0x61, 0x7c, 0x48, 0xa3, 0x43, 0xd2, 0x9c, 0x8d,
+       0xd4, 0x95, 0xdd, 0xe1, 0x22, 0x89, 0x3a, 0x40,
+       0x4c, 0x1b, 0x8a, 0x04, 0xa8, 0x09, 0x69, 0x8b,
+       0xea, 0xc6, 0x55, 0x8e, 0x57, 0xe6, 0x64, 0x35,
+       0xf0, 0xc7, 0x16, 0x9f, 0x5d, 0x5e, 0x86, 0x40,
+       0x46, 0xbb, 0xe5, 0x45, 0x88, 0xfe, 0xc9, 0x63,
+       0x15, 0xfb, 0xf5, 0xbd, 0x71, 0x61, 0xeb, 0x7b,
+       0x78, 0x70, 0x07, 0x31, 0x03, 0x9f, 0xb2, 0xc8,
+       0xa7, 0xab, 0x47, 0xfd, 0xdf, 0xa0, 0x78, 0x72,
+       0xa4, 0x2a, 0xe4, 0xb6, 0xba, 0xc0, 0x1e, 0x86,
+       0x71, 0xe6, 0x3d, 0x18, 0x37, 0x70, 0xe6, 0xff,
+       0xe0, 0xbc, 0x0b, 0x22, 0xa0, 0x1f, 0xd3, 0xed,
+       0xa2, 0x55, 0x39, 0xab, 0xa8, 0x13, 0x73, 0x7c,
+       0x3f, 0xb2, 0xd6, 0x19, 0xac, 0xff, 0x99, 0xed,
+       0xe8, 0xe6, 0xa6, 0x22, 0xe3, 0x9c, 0xf1, 0x30,
+       0xdc, 0x01, 0x0a, 0x56, 0xfa, 0xe4, 0xc9, 0x99,
+       0xdd, 0xa8, 0xd8, 0xda, 0x35, 0x51, 0x73, 0xb4,
+       0x40, 0x86, 0x85, 0xdb, 0x5c, 0xd5, 0x85, 0x80,
+       0x14, 0x9c, 0xfd, 0x98, 0xa9, 0x82, 0xc5, 0x37,
+       0xff, 0x32, 0x5d, 0xd0, 0x0b, 0xfa, 0xdc, 0x04,
+       0x5e, 0x09, 0xd2, 0xca, 0x17, 0x4b, 0x1a, 0x8e,
+       0x15, 0xe1, 0xcc, 0x4e, 0x52, 0x88, 0x35, 0xbd,
+       0x48, 0xfe, 0x15, 0xa0, 0x91, 0xfd, 0x7e, 0x6c,
+       0x0e, 0x5d, 0x79, 0x1b, 0x81, 0x79, 0xd2, 0x09,
+       0x34, 0x70, 0x3d, 0x81, 0xec, 0xf6, 0x24, 0xbb,
+       0xfb, 0xf1, 0x7b, 0xdf, 0x54, 0xea, 0x80, 0x9b,
+       0xc7, 0x99, 0x9e, 0xbd, 0x16, 0x78, 0x12, 0x53,
+       0x5e, 0x01, 0xa7, 0x4e, 0xbd, 0x67, 0xe1, 0x9b,
+       0x4c, 0x0e, 0x61, 0x45, 0x97, 0xd2, 0xf0, 0x0f,
+       0xfe, 0x15, 0x08, 0xb7, 0x11, 0x4c, 0xe7, 0xff,
+       0x81, 0x53, 0xff, 0x91, 0x25, 0x38, 0x7e, 0x40,
+       0x94, 0xe5, 0xe0, 0xad, 0xe6, 0xd9, 0x79, 0xb6,
+       0x92, 0xc9, 0xfc, 0xde, 0xc3, 0x1a, 0x23, 0xbb,
+       0xdd, 0xc8, 0x51, 0x0c, 0x3a, 0x72, 0xfa, 0x73,
+       0x6f, 0xb7, 0xee, 0x61, 0x39, 0x03, 0x01, 0x3f,
+       0x7f, 0x94, 0x2e, 0x2e, 0xba, 0x3a, 0xbb, 0xb4,
+       0xfa, 0x6a, 0x17, 0xfe, 0xea, 0xef, 0x5e, 0x66,
+       0x97, 0x3f, 0x32, 0x3d, 0xd7, 0x3e, 0xb1, 0xf1,
+       0x6c, 0x14, 0x4c, 0xfd, 0x37, 0xd3, 0x38, 0x80,
+       0xfb, 0xde, 0xa6, 0x24, 0x1e, 0xc8, 0xca, 0x7f,
+       0x3a, 0x93, 0xd8, 0x8b, 0x18, 0x13, 0xb2, 0xe5,
+       0xe4, 0x93, 0x05, 0x53, 0x4f, 0x84, 0x66, 0xa7,
+       0x58, 0x5c, 0x7b, 0x86, 0x52, 0x6d, 0x0d, 0xce,
+       0xa4, 0x30, 0x7d, 0xb6, 0x18, 0x9f, 0xeb, 0xff,
+       0x22, 0xbb, 0x72, 0x29, 0xb9, 0x44, 0x0b, 0x48,
+       0x1e, 0x84, 0x71, 0x81, 0xe3, 0x6d, 0x73, 0x26,
+       0x92, 0xb4, 0x4d, 0x2a, 0x29, 0xb8, 0x1f, 0x72,
+       0xed, 0xd0, 0xe1, 0x64, 0x77, 0xea, 0x8e, 0x88,
+       0x0f, 0xef, 0x3f, 0xb1, 0x3b, 0xad, 0xf9, 0xc9,
+       0x8b, 0xd0, 0xac, 0xc6, 0xcc, 0xa9, 0x40, 0xcc,
+       0x76, 0xf6, 0x3b, 0x53, 0xb5, 0x88, 0xcb, 0xc8,
+       0x37, 0xf1, 0xa2, 0xba, 0x23, 0x15, 0x99, 0x09,
+       0xcc, 0xe7, 0x7a, 0x3b, 0x37, 0xf7, 0x58, 0xc8,
+       0x46, 0x8c, 0x2b, 0x2f, 0x4e, 0x0e, 0xa6, 0x5c,
+       0xea, 0x85, 0x55, 0xba, 0x02, 0x0e, 0x0e, 0x48,
+       0xbc, 0xe1, 0xb1, 0x01, 0x35, 0x79, 0x13, 0x3d,
+       0x1b, 0xc0, 0x53, 0x68, 0x11, 0xe7, 0x95, 0x0f,
+       0x9d, 0x3f, 0x4c, 0x47, 0x7b, 0x4d, 0x1c, 0xae,
+       0x50, 0x9b, 0xcb, 0xdd, 0x05, 0x8d, 0x9a, 0x97,
+       0xfd, 0x8c, 0xef, 0x0c, 0x1d, 0x67, 0x73, 0xa8,
+       0x28, 0x36, 0xd5, 0xb6, 0x92, 0x33, 0x40, 0x75,
+       0x0b, 0x51, 0xc3, 0x64, 0xba, 0x1d, 0xc2, 0xcc,
+       0xee, 0x7d, 0x54, 0x0f, 0x27, 0x69, 0xa7, 0x27,
+       0x63, 0x30, 0x29, 0xd9, 0xc8, 0x84, 0xd8, 0xdf,
+       0x9f, 0x68, 0x8d, 0x04, 0xca, 0xa6, 0xc5, 0xc7,
+       0x7a, 0x5c, 0xc8, 0xd1, 0xcb, 0x4a, 0xec, 0xd0,
+       0xd8, 0x20, 0x69, 0xc5, 0x17, 0xcd, 0x78, 0xc8,
+       0x75, 0x23, 0x30, 0x69, 0xc9, 0xd4, 0xea, 0x5c,
+       0x4f, 0x6b, 0x86, 0x3f, 0x8b, 0xfe, 0xee, 0x44,
+       0xc9, 0x7c, 0xb7, 0xdd, 0x3e, 0xe5, 0xec, 0x54,
+       0x03, 0x3e, 0xaa, 0x82, 0xc6, 0xdf, 0xb2, 0x38,
+       0x0e, 0x5d, 0xb3, 0x88, 0xd9, 0xd3, 0x69, 0x5f,
+       0x8f, 0x70, 0x8a, 0x7e, 0x11, 0xd9, 0x1e, 0x7b,
+       0x38, 0xf1, 0x42, 0x1a, 0xc0, 0x35, 0xf5, 0xc7,
+       0x36, 0x85, 0xf5, 0xf7, 0xb8, 0x7e, 0xc7, 0xef,
+       0x18, 0xf1, 0x63, 0xd6, 0x7a, 0xc6, 0xc9, 0x0e,
+       0x4d, 0x69, 0x4f, 0x84, 0xef, 0x26, 0x41, 0x0c,
+       0xec, 0xc7, 0xe0, 0x7e, 0x3c, 0x67, 0x01, 0x4c,
+       0x62, 0x1a, 0x20, 0x6f, 0xee, 0x47, 0x4d, 0xc0,
+       0x99, 0x13, 0x8d, 0x91, 0x4a, 0x26, 0xd4, 0x37,
+       0x28, 0x90, 0x58, 0x75, 0x66, 0x2b, 0x0a, 0xdf,
+       0xda, 0xee, 0x92, 0x25, 0x90, 0x62, 0x39, 0x9e,
+       0x44, 0x98, 0xad, 0xc1, 0x88, 0xed, 0xe4, 0xb4,
+       0xaf, 0xf5, 0x8c, 0x9b, 0x48, 0x4d, 0x56, 0x60,
+       0x97, 0x0f, 0x61, 0x59, 0x9e, 0xa6, 0x27, 0xfe,
+       0xc1, 0x91, 0x15, 0x38, 0xb8, 0x0f, 0xae, 0x61,
+       0x7d, 0x26, 0x13, 0x5a, 0x73, 0xff, 0x1c, 0xa3,
+       0x61, 0x04, 0x58, 0x48, 0x55, 0x44, 0x11, 0xfe,
+       0x15, 0xca, 0xc3, 0xbd, 0xca, 0xc5, 0xb4, 0x40,
+       0x5d, 0x1b, 0x7f, 0x39, 0xb5, 0x9c, 0x35, 0xec,
+       0x61, 0x15, 0x32, 0x32, 0xb8, 0x4e, 0x40, 0x9f,
+       0x17, 0x1f, 0x0a, 0x4d, 0xa9, 0x91, 0xef, 0xb7,
+       0xb0, 0xeb, 0xc2, 0x83, 0x9a, 0x6c, 0xd2, 0x79,
+       0x43, 0x78, 0x5e, 0x2f, 0xe5, 0xdd, 0x1a, 0x3c,
+       0x45, 0xab, 0x29, 0x40, 0x3a, 0x37, 0x5b, 0x6f,
+       0xd7, 0xfc, 0x48, 0x64, 0x3c, 0x49, 0xfb, 0x21,
+       0xbe, 0xc3, 0xff, 0x07, 0xfb, 0x17, 0xe9, 0xc9,
+       0x0c, 0x4c, 0x5c, 0x15, 0x9e, 0x8e, 0x22, 0x30,
+       0x0a, 0xde, 0x48, 0x7f, 0xdb, 0x0d, 0xd1, 0x2b,
+       0x87, 0x38, 0x9e, 0xcc, 0x5a, 0x01, 0x16, 0xee,
+       0x75, 0x49, 0x0d, 0x30, 0x01, 0x34, 0x6a, 0xb6,
+       0x9a, 0x5a, 0x2a, 0xec, 0xbb, 0x48, 0xac, 0xd3,
+       0x77, 0x83, 0xd8, 0x08, 0x86, 0x4f, 0x48, 0x09,
+       0x29, 0x41, 0x79, 0xa1, 0x03, 0x12, 0xc4, 0xcd,
+       0x90, 0x55, 0x47, 0x66, 0x74, 0x9a, 0xcc, 0x4f,
+       0x35, 0x8c, 0xd6, 0x98, 0xef, 0xeb, 0x45, 0xb9,
+       0x9a, 0x26, 0x2f, 0x39, 0xa5, 0x70, 0x6d, 0xfc,
+       0xb4, 0x51, 0xee, 0xf4, 0x9c, 0xe7, 0x38, 0x59,
+       0xad, 0xf4, 0xbc, 0x46, 0xff, 0x46, 0x8e, 0x60,
+       0x9c, 0xa3, 0x60, 0x1d, 0xf8, 0x26, 0x72, 0xf5,
+       0x72, 0x9d, 0x68, 0x80, 0x04, 0xf6, 0x0b, 0xa1,
+       0x0a, 0xd5, 0xa7, 0x82, 0x3a, 0x3e, 0x47, 0xa8,
+       0x5a, 0xde, 0x59, 0x4f, 0x7b, 0x07, 0xb3, 0xe9,
+       0x24, 0x19, 0x3d, 0x34, 0x05, 0xec, 0xf1, 0xab,
+       0x6e, 0x64, 0x8f, 0xd3, 0xe6, 0x41, 0x86, 0x80,
+       0x70, 0xe3, 0x8d, 0x60, 0x9c, 0x34, 0x25, 0x01,
+       0x07, 0x4d, 0x19, 0x41, 0x4e, 0x3d, 0x5c, 0x7e,
+       0xa8, 0xf5, 0xcc, 0xd5, 0x7b, 0xe2, 0x7d, 0x3d,
+       0x49, 0x86, 0x7d, 0x07, 0xb7, 0x10, 0xe3, 0x35,
+       0xb8, 0x84, 0x6d, 0x76, 0xab, 0x17, 0xc6, 0x38,
+       0xb4, 0xd3, 0x28, 0x57, 0xad, 0xd3, 0x88, 0x5a,
+       0xda, 0xea, 0xc8, 0x94, 0xcc, 0x37, 0x19, 0xac,
+       0x9c, 0x9f, 0x4b, 0x00, 0x15, 0xc0, 0xc8, 0xca,
+       0x1f, 0x15, 0xaa, 0xe0, 0xdb, 0xf9, 0x2f, 0x57,
+       0x1b, 0x24, 0xc7, 0x6f, 0x76, 0x29, 0xfb, 0xed,
+       0x25, 0x0d, 0xc0, 0xfe, 0xbd, 0x5a, 0xbf, 0x20,
+       0x08, 0x51, 0x05, 0xec, 0x71, 0xa3, 0xbf, 0xef,
+       0x5e, 0x99, 0x75, 0xdb, 0x3c, 0x5f, 0x9a, 0x8c,
+       0xbb, 0x19, 0x5c, 0x0e, 0x93, 0x19, 0xf8, 0x6a,
+       0xbc, 0xf2, 0x12, 0x54, 0x2f, 0xcb, 0x28, 0x64,
+       0x88, 0xb3, 0x92, 0x0d, 0x96, 0xd1, 0xa6, 0xe4,
+       0x1f, 0xf1, 0x4d, 0xa4, 0xab, 0x1c, 0xee, 0x54,
+       0xf2, 0xad, 0x29, 0x6d, 0x32, 0x37, 0xb2, 0x16,
+       0x77, 0x5c, 0xdc, 0x2e, 0x54, 0xec, 0x75, 0x26,
+       0xc6, 0x36, 0xd9, 0x17, 0x2c, 0xf1, 0x7a, 0xdc,
+       0x4b, 0xf1, 0xe2, 0xd9, 0x95, 0xba, 0xac, 0x87,
+       0xc1, 0xf3, 0x8e, 0x58, 0x08, 0xd8, 0x87, 0x60,
+       0xc9, 0xee, 0x6a, 0xde, 0xa4, 0xd2, 0xfc, 0x0d,
+       0xe5, 0x36, 0xc4, 0x5c, 0x52, 0xb3, 0x07, 0x54,
+       0x65, 0x24, 0xc1, 0xb1, 0xd1, 0xb1, 0x53, 0x13,
+       0x31, 0x79, 0x7f, 0x05, 0x76, 0xeb, 0x37, 0x59,
+       0x15, 0x2b, 0xd1, 0x3f, 0xac, 0x08, 0x97, 0xeb,
+       0x91, 0x98, 0xdf, 0x6c, 0x09, 0x0d, 0x04, 0x9f,
+       0xdc, 0x3b, 0x0e, 0x60, 0x68, 0x47, 0x23, 0x15,
+       0x16, 0xc6, 0x0b, 0x35, 0xf8, 0x77, 0xa2, 0x78,
+       0x50, 0xd4, 0x64, 0x22, 0x33, 0xff, 0xfb, 0x93,
+       0x71, 0x46, 0x50, 0x39, 0x1b, 0x9c, 0xea, 0x4e,
+       0x8d, 0x0c, 0x37, 0xe5, 0x5c, 0x51, 0x3a, 0x31,
+       0xb2, 0x85, 0x84, 0x3f, 0x41, 0xee, 0xa2, 0xc1,
+       0xc6, 0x13, 0x3b, 0x54, 0x28, 0xd2, 0x18, 0x37,
+       0xcc, 0x46, 0x9f, 0x6a, 0x91, 0x3d, 0x5a, 0x15,
+       0x3c, 0x89, 0xa3, 0x61, 0x06, 0x7d, 0x2e, 0x78,
+       0xbe, 0x7d, 0x40, 0xba, 0x2f, 0x95, 0xb1, 0x2f,
+       0x87, 0x3b, 0x8a, 0xbe, 0x6a, 0xf4, 0xc2, 0x31,
+       0x74, 0xee, 0x91, 0xe0, 0x23, 0xaa, 0x5d, 0x7f,
+       0xdd, 0xf0, 0x44, 0x8c, 0x0b, 0x59, 0x2b, 0xfc,
+       0x48, 0x3a, 0xdf, 0x07, 0x05, 0x38, 0x6c, 0xc9,
+       0xeb, 0x18, 0x24, 0x68, 0x8d, 0x58, 0x98, 0xd3,
+       0x31, 0xa3, 0xe4, 0x70, 0x59, 0xb1, 0x21, 0xbe,
+       0x7e, 0x65, 0x7d, 0xb8, 0x04, 0xab, 0xf6, 0xe4,
+       0xd7, 0xda, 0xec, 0x09, 0x8f, 0xda, 0x6d, 0x24,
+       0x07, 0xcc, 0x29, 0x17, 0x05, 0x78, 0x1a, 0xc1,
+       0xb1, 0xce, 0xfc, 0xaa, 0x2d, 0xe7, 0xcc, 0x85,
+       0x84, 0x84, 0x03, 0x2a, 0x0c, 0x3f, 0xa9, 0xf8,
+       0xfd, 0x84, 0x53, 0x59, 0x5c, 0xf0, 0xd4, 0x09,
+       0xf0, 0xd2, 0x6c, 0x32, 0x03, 0xb0, 0xa0, 0x8c,
+       0x52, 0xeb, 0x23, 0x91, 0x88, 0x43, 0x13, 0x46,
+       0xf6, 0x1e, 0xb4, 0x1b, 0xf5, 0x8e, 0x3a, 0xb5,
+       0x3d, 0x00, 0xf6, 0xe5, 0x08, 0x3d, 0x5f, 0x39,
+       0xd3, 0x21, 0x69, 0xbc, 0x03, 0x22, 0x3a, 0xd2,
+       0x5c, 0x84, 0xf8, 0x15, 0xc4, 0x80, 0x0b, 0xbc,
+       0x29, 0x3c, 0xf3, 0x95, 0x98, 0xcd, 0x8f, 0x35,
+       0xbc, 0xa5, 0x3e, 0xfc, 0xd4, 0x13, 0x9e, 0xde,
+       0x4f, 0xce, 0x71, 0x9d, 0x09, 0xad, 0xf2, 0x80,
+       0x6b, 0x65, 0x7f, 0x03, 0x00, 0x14, 0x7c, 0x15,
+       0x85, 0x40, 0x6d, 0x70, 0xea, 0xdc, 0xb3, 0x63,
+       0x35, 0x4f, 0x4d, 0xe0, 0xd9, 0xd5, 0x3c, 0x58,
+       0x56, 0x23, 0x80, 0xe2, 0x36, 0xdd, 0x75, 0x1d,
+       0x94, 0x11, 0x41, 0x8e, 0xe0, 0x81, 0x8e, 0xcf,
+       0xe0, 0xe5, 0xf6, 0xde, 0xd1, 0xe7, 0x04, 0x12,
+       0x79, 0x92, 0x2b, 0x71, 0x2a, 0x79, 0x8b, 0x7c,
+       0x44, 0x79, 0x16, 0x30, 0x4e, 0xf4, 0xf6, 0x9b,
+       0xb7, 0x40, 0xa3, 0x5a, 0xa7, 0x69, 0x3e, 0xc1,
+       0x3a, 0x04, 0xd0, 0x88, 0xa0, 0x3b, 0xdd, 0xc6,
+       0x9e, 0x7e, 0x1e, 0x1e, 0x8f, 0x44, 0xf7, 0x73,
+       0x67, 0x1e, 0x1a, 0x78, 0xfa, 0x62, 0xf4, 0xa9,
+       0xa8, 0xc6, 0x5b, 0xb8, 0xfa, 0x06, 0x7d, 0x5e,
+       0x38, 0x1c, 0x9a, 0x39, 0xe9, 0x39, 0x98, 0x22,
+       0x0b, 0xa7, 0xac, 0x0b, 0xf3, 0xbc, 0xf1, 0xeb,
+       0x8c, 0x81, 0xe3, 0x48, 0x8a, 0xed, 0x42, 0xc2,
+       0x38, 0xcf, 0x3e, 0xda, 0xd2, 0x89, 0x8d, 0x9c,
+       0x53, 0xb5, 0x2f, 0x41, 0x01, 0x26, 0x84, 0x9c,
+       0xa3, 0x56, 0xf6, 0x49, 0xc7, 0xd4, 0x9f, 0x93,
+       0x1b, 0x96, 0x49, 0x5e, 0xad, 0xb3, 0x84, 0x1f,
+       0x3c, 0xa4, 0xe0, 0x9b, 0xd1, 0x90, 0xbc, 0x38,
+       0x6c, 0xdd, 0x95, 0x4d, 0x9d, 0xb1, 0x71, 0x57,
+       0x2d, 0x34, 0xe8, 0xb8, 0x42, 0xc7, 0x99, 0x03,
+       0xc7, 0x07, 0x30, 0x65, 0x91, 0x55, 0xd5, 0x90,
+       0x70, 0x97, 0x37, 0x68, 0xd4, 0x11, 0xf9, 0xe8,
+       0xce, 0xec, 0xdc, 0x34, 0xd5, 0xd3, 0xb7, 0xc4,
+       0xb8, 0x97, 0x05, 0x92, 0xad, 0xf8, 0xe2, 0x36,
+       0x64, 0x41, 0xc9, 0xc5, 0x41, 0x77, 0x52, 0xd7,
+       0x2c, 0xa5, 0x24, 0x2f, 0xd9, 0x34, 0x0b, 0x47,
+       0x35, 0xa7, 0x28, 0x8b, 0xc5, 0xcd, 0xe9, 0x46,
+       0xac, 0x39, 0x94, 0x3c, 0x10, 0xc6, 0x29, 0x73,
+       0x0e, 0x0e, 0x5d, 0xe0, 0x71, 0x03, 0x8a, 0x72,
+       0x0e, 0x26, 0xb0, 0x7d, 0x84, 0xed, 0x95, 0x23,
+       0x49, 0x5a, 0x45, 0x83, 0x45, 0x60, 0x11, 0x4a,
+       0x46, 0x31, 0xd4, 0xd8, 0x16, 0x54, 0x98, 0x58,
+       0xed, 0x6d, 0xcc, 0x5d, 0xd6, 0x50, 0x61, 0x9f,
+       0x9d, 0xc5, 0x3e, 0x9d, 0x32, 0x47, 0xde, 0x96,
+       0xe1, 0x5d, 0xd8, 0xf8, 0xb4, 0x69, 0x6f, 0xb9,
+       0x15, 0x90, 0x57, 0x7a, 0xf6, 0xad, 0xb0, 0x5b,
+       0xf5, 0xa6, 0x36, 0x94, 0xfd, 0x84, 0xce, 0x1c,
+       0x0f, 0x4b, 0xd0, 0xc2, 0x5b, 0x6b, 0x56, 0xef,
+       0x73, 0x93, 0x0b, 0xc3, 0xee, 0xd9, 0xcf, 0xd3,
+       0xa4, 0x22, 0x58, 0xcd, 0x50, 0x6e, 0x65, 0xf4,
+       0xe9, 0xb7, 0x71, 0xaf, 0x4b, 0xb3, 0xb6, 0x2f,
+       0x0f, 0x0e, 0x3b, 0xc9, 0x85, 0x14, 0xf5, 0x17,
+       0xe8, 0x7a, 0x3a, 0xbf, 0x5f, 0x5e, 0xf8, 0x18,
+       0x48, 0xa6, 0x72, 0xab, 0x06, 0x95, 0xe9, 0xc8,
+       0xa7, 0xf4, 0x32, 0x44, 0x04, 0x0c, 0x84, 0x98,
+       0x73, 0xe3, 0x89, 0x8d, 0x5f, 0x7e, 0x4a, 0x42,
+       0x8f, 0xc5, 0x28, 0xb1, 0x82, 0xef, 0x1c, 0x97,
+       0x31, 0x3b, 0x4d, 0xe0, 0x0e, 0x10, 0x10, 0x97,
+       0x93, 0x49, 0x78, 0x2f, 0x0d, 0x86, 0x8b, 0xa1,
+       0x53, 0xa9, 0x81, 0x20, 0x79, 0xe7, 0x07, 0x77,
+       0xb6, 0xac, 0x5e, 0xd2, 0x05, 0xcd, 0xe9, 0xdb,
+       0x8a, 0x94, 0x82, 0x8a, 0x23, 0xb9, 0x3d, 0x1c,
+       0xa9, 0x7d, 0x72, 0x4a, 0xed, 0x33, 0xa3, 0xdb,
+       0x21, 0xa7, 0x86, 0x33, 0x45, 0xa5, 0xaa, 0x56,
+       0x45, 0xb5, 0x83, 0x29, 0x40, 0x47, 0x79, 0x04,
+       0x6e, 0xb9, 0x95, 0xd0, 0x81, 0x77, 0x2d, 0x48,
+       0x1e, 0xfe, 0xc3, 0xc2, 0x1e, 0xe5, 0xf2, 0xbe,
+       0xfd, 0x3b, 0x94, 0x9f, 0xc4, 0xc4, 0x26, 0x9d,
+       0xe4, 0x66, 0x1e, 0x19, 0xee, 0x6c, 0x79, 0x97,
+       0x11, 0x31, 0x4b, 0x0d, 0x01, 0xcb, 0xde, 0xa8,
+       0xf6, 0x6d, 0x7c, 0x39, 0x46, 0x4e, 0x7e, 0x3f,
+       0x94, 0x17, 0xdf, 0xa1, 0x7d, 0xd9, 0x1c, 0x8e,
+       0xbc, 0x7d, 0x33, 0x7d, 0xe3, 0x12, 0x40, 0xca,
+       0xab, 0x37, 0x11, 0x46, 0xd4, 0xae, 0xef, 0x44,
+       0xa2, 0xb3, 0x6a, 0x66, 0x0e, 0x0c, 0x90, 0x7f,
+       0xdf, 0x5c, 0x66, 0x5f, 0xf2, 0x94, 0x9f, 0xa6,
+       0x73, 0x4f, 0xeb, 0x0d, 0xad, 0xbf, 0xc0, 0x63,
+       0x5c, 0xdc, 0x46, 0x51, 0xe8, 0x8e, 0x90, 0x19,
+       0xa8, 0xa4, 0x3c, 0x91, 0x79, 0xfa, 0x7e, 0x58,
+       0x85, 0x13, 0x55, 0xc5, 0x19, 0x82, 0x37, 0x1b,
+       0x0a, 0x02, 0x1f, 0x99, 0x6b, 0x18, 0xf1, 0x28,
+       0x08, 0xa2, 0x73, 0xb8, 0x0f, 0x2e, 0xcd, 0xbf,
+       0xf3, 0x86, 0x7f, 0xea, 0xef, 0xd0, 0xbb, 0xa6,
+       0x21, 0xdf, 0x49, 0x73, 0x51, 0xcc, 0x36, 0xd3,
+       0x3e, 0xa0, 0xf8, 0x44, 0xdf, 0xd3, 0xa6, 0xbe,
+       0x8a, 0xd4, 0x57, 0xdd, 0x72, 0x94, 0x61, 0x0f,
+       0x82, 0xd1, 0x07, 0xb8, 0x7c, 0x18, 0x83, 0xdf,
+       0x3a, 0xe5, 0x50, 0x6a, 0x82, 0x20, 0xac, 0xa9,
+       0xa8, 0xff, 0xd9, 0xf3, 0x77, 0x33, 0x5a, 0x9e,
+       0x7f, 0x6d, 0xfe, 0x5d, 0x33, 0x41, 0x42, 0xe7,
+       0x6c, 0x19, 0xe0, 0x44, 0x8a, 0x15, 0xf6, 0x70,
+       0x98, 0xb7, 0x68, 0x4d, 0xfa, 0x97, 0x39, 0xb0,
+       0x8e, 0xe8, 0x84, 0x8b, 0x75, 0x30, 0xb7, 0x7d,
+       0x92, 0x69, 0x20, 0x9c, 0x81, 0xfb, 0x4b, 0xf4,
+       0x01, 0x50, 0xeb, 0xce, 0x0c, 0x1c, 0x6c, 0xb5,
+       0x4a, 0xd7, 0x27, 0x0c, 0xce, 0xbb, 0xe5, 0x85,
+       0xf0, 0xb6, 0xee, 0xd5, 0x70, 0xdd, 0x3b, 0xfc,
+       0xd4, 0x99, 0xf1, 0x33, 0xdd, 0x8b, 0xc4, 0x2f,
+       0xae, 0xab, 0x74, 0x96, 0x32, 0xc7, 0x4c, 0x56,
+       0x3c, 0x89, 0x0f, 0x96, 0x0b, 0x42, 0xc0, 0xcb,
+       0xee, 0x0f, 0x0b, 0x8c, 0xfb, 0x7e, 0x47, 0x7b,
+       0x64, 0x48, 0xfd, 0xb2, 0x00, 0x80, 0x89, 0xa5,
+       0x13, 0x55, 0x62, 0xfc, 0x8f, 0xe2, 0x42, 0x03,
+       0xb7, 0x4e, 0x2a, 0x79, 0xb4, 0x82, 0xea, 0x23,
+       0x49, 0xda, 0xaf, 0x52, 0x63, 0x1e, 0x60, 0x03,
+       0x89, 0x06, 0x44, 0x46, 0x08, 0xc3, 0xc4, 0x87,
+       0x70, 0x2e, 0xda, 0x94, 0xad, 0x6b, 0xe0, 0xe4,
+       0xd1, 0x8a, 0x06, 0xc2, 0xa8, 0xc0, 0xa7, 0x43,
+       0x3c, 0x47, 0x52, 0x0e, 0xc3, 0x77, 0x81, 0x11,
+       0x67, 0x0e, 0xa0, 0x70, 0x04, 0x47, 0x29, 0x40,
+       0x86, 0x0d, 0x34, 0x56, 0xa7, 0xc9, 0x35, 0x59,
+       0x68, 0xdc, 0x93, 0x81, 0x70, 0xee, 0x86, 0xd9,
+       0x80, 0x06, 0x40, 0x4f, 0x1a, 0x0d, 0x40, 0x30,
+       0x0b, 0xcb, 0x96, 0x47, 0xc1, 0xb7, 0x52, 0xfd,
+       0x56, 0xe0, 0x72, 0x4b, 0xfb, 0xbd, 0x92, 0x45,
+       0x61, 0x71, 0xc2, 0x33, 0x11, 0xbf, 0x52, 0x83,
+       0x79, 0x26, 0xe0, 0x49, 0x6b, 0xb7, 0x05, 0x8b,
+       0xe8, 0x0e, 0x87, 0x31, 0xd7, 0x9d, 0x8a, 0xf5,
+       0xc0, 0x5f, 0x2e, 0x58, 0x4a, 0xdb, 0x11, 0xb3,
+       0x6c, 0x30, 0x2a, 0x46, 0x19, 0xe3, 0x27, 0x84,
+       0x1f, 0x63, 0x6e, 0xf6, 0x57, 0xc7, 0xc9, 0xd8,
+       0x5e, 0xba, 0xb3, 0x87, 0xd5, 0x83, 0x26, 0x34,
+       0x21, 0x9e, 0x65, 0xde, 0x42, 0xd3, 0xbe, 0x7b,
+       0xbc, 0x91, 0x71, 0x44, 0x4d, 0x99, 0x3b, 0x31,
+       0xe5, 0x3f, 0x11, 0x4e, 0x7f, 0x13, 0x51, 0x3b,
+       0xae, 0x79, 0xc9, 0xd3, 0x81, 0x8e, 0x25, 0x40,
+       0x10, 0xfc, 0x07, 0x1e, 0xf9, 0x7b, 0x9a, 0x4b,
+       0x6c, 0xe3, 0xb3, 0xad, 0x1a, 0x0a, 0xdd, 0x9e,
+       0x59, 0x0c, 0xa2, 0xcd, 0xae, 0x48, 0x4a, 0x38,
+       0x5b, 0x47, 0x41, 0x94, 0x65, 0x6b, 0xbb, 0xeb,
+       0x5b, 0xe3, 0xaf, 0x07, 0x5b, 0xd4, 0x4a, 0xa2,
+       0xc9, 0x5d, 0x2f, 0x64, 0x03, 0xd7, 0x3a, 0x2c,
+       0x6e, 0xce, 0x76, 0x95, 0xb4, 0xb3, 0xc0, 0xf1,
+       0xe2, 0x45, 0x73, 0x7a, 0x5c, 0xab, 0xc1, 0xfc,
+       0x02, 0x8d, 0x81, 0x29, 0xb3, 0xac, 0x07, 0xec,
+       0x40, 0x7d, 0x45, 0xd9, 0x7a, 0x59, 0xee, 0x34,
+       0xf0, 0xe9, 0xd5, 0x7b, 0x96, 0xb1, 0x3d, 0x95,
+       0xcc, 0x86, 0xb5, 0xb6, 0x04, 0x2d, 0xb5, 0x92,
+       0x7e, 0x76, 0xf4, 0x06, 0xa9, 0xa3, 0x12, 0x0f,
+       0xb1, 0xaf, 0x26, 0xba, 0x7c, 0xfc, 0x7e, 0x1c,
+       0xbc, 0x2c, 0x49, 0x97, 0x53, 0x60, 0x13, 0x0b,
+       0xa6, 0x61, 0x83, 0x89, 0x42, 0xd4, 0x17, 0x0c,
+       0x6c, 0x26, 0x52, 0xc3, 0xb3, 0xd4, 0x67, 0xf5,
+       0xe3, 0x04, 0xb7, 0xf4, 0xcb, 0x80, 0xb8, 0xcb,
+       0x77, 0x56, 0x3e, 0xaa, 0x57, 0x54, 0xee, 0xb4,
+       0x2c, 0x67, 0xcf, 0xf2, 0xdc, 0xbe, 0x55, 0xf9,
+       0x43, 0x1f, 0x6e, 0x22, 0x97, 0x67, 0x7f, 0xc4,
+       0xef, 0xb1, 0x26, 0x31, 0x1e, 0x27, 0xdf, 0x41,
+       0x80, 0x47, 0x6c, 0xe2, 0xfa, 0xa9, 0x8c, 0x2a,
+       0xf6, 0xf2, 0xab, 0xf0, 0x15, 0xda, 0x6c, 0xc8,
+       0xfe, 0xb5, 0x23, 0xde, 0xa9, 0x05, 0x3f, 0x06,
+       0x54, 0x4c, 0xcd, 0xe1, 0xab, 0xfc, 0x0e, 0x62,
+       0x33, 0x31, 0x73, 0x2c, 0x76, 0xcb, 0xb4, 0x47,
+       0x1e, 0x20, 0xad, 0xd8, 0xf2, 0x31, 0xdd, 0xc4,
+       0x8b, 0x0c, 0x77, 0xbe, 0xe1, 0x8b, 0x26, 0x00,
+       0x02, 0x58, 0xd6, 0x8d, 0xef, 0xad, 0x74, 0x67,
+       0xab, 0x3f, 0xef, 0xcb, 0x6f, 0xb0, 0xcc, 0x81,
+       0x44, 0x4c, 0xaf, 0xe9, 0x49, 0x4f, 0xdb, 0xa0,
+       0x25, 0xa4, 0xf0, 0x89, 0xf1, 0xbe, 0xd8, 0x10,
+       0xff, 0xb1, 0x3b, 0x4b, 0xfa, 0x98, 0xf5, 0x79,
+       0x6d, 0x1e, 0x69, 0x4d, 0x57, 0xb1, 0xc8, 0x19,
+       0x1b, 0xbd, 0x1e, 0x8c, 0x84, 0xb7, 0x7b, 0xe8,
+       0xd2, 0x2d, 0x09, 0x41, 0x41, 0x37, 0x3d, 0xb1,
+       0x6f, 0x26, 0x5d, 0x71, 0x16, 0x3d, 0xb7, 0x83,
+       0x27, 0x2c, 0xa7, 0xb6, 0x50, 0xbd, 0x91, 0x86,
+       0xab, 0x24, 0xa1, 0x38, 0xfd, 0xea, 0x71, 0x55,
+       0x7e, 0x9a, 0x07, 0x77, 0x4b, 0xfa, 0x61, 0x66,
+       0x20, 0x1e, 0x28, 0x95, 0x18, 0x1b, 0xa4, 0xa0,
+       0xfd, 0xc0, 0x89, 0x72, 0x43, 0xd9, 0x3b, 0x49,
+       0x5a, 0x3f, 0x9d, 0xbf, 0xdb, 0xb4, 0x46, 0xea,
+       0x42, 0x01, 0x77, 0x23, 0x68, 0x95, 0xb6, 0x24,
+       0xb3, 0xa8, 0x6c, 0x28, 0x3b, 0x11, 0x40, 0x7e,
+       0x18, 0x65, 0x6d, 0xd8, 0x24, 0x42, 0x7d, 0x88,
+       0xc0, 0x52, 0xd9, 0x05, 0xe4, 0x95, 0x90, 0x87,
+       0x8c, 0xf4, 0xd0, 0x6b, 0xb9, 0x83, 0x99, 0x34,
+       0x6d, 0xfe, 0x54, 0x40, 0x94, 0x52, 0x21, 0x4f,
+       0x14, 0x25, 0xc5, 0xd6, 0x5e, 0x95, 0xdc, 0x0a,
+       0x2b, 0x89, 0x20, 0x11, 0x84, 0x48, 0xd6, 0x3a,
+       0xcd, 0x5c, 0x24, 0xad, 0x62, 0xe3, 0xb1, 0x93,
+       0x25, 0x8d, 0xcd, 0x7e, 0xfc, 0x27, 0xa3, 0x37,
+       0xfd, 0x84, 0xfc, 0x1b, 0xb2, 0xf1, 0x27, 0x38,
+       0x5a, 0xb7, 0xfc, 0xf2, 0xfa, 0x95, 0x66, 0xd4,
+       0xfb, 0xba, 0xa7, 0xd7, 0xa3, 0x72, 0x69, 0x48,
+       0x48, 0x8c, 0xeb, 0x28, 0x89, 0xfe, 0x33, 0x65,
+       0x5a, 0x36, 0x01, 0x7e, 0x06, 0x79, 0x0a, 0x09,
+       0x3b, 0x74, 0x11, 0x9a, 0x6e, 0xbf, 0xd4, 0x9e,
+       0x58, 0x90, 0x49, 0x4f, 0x4d, 0x08, 0xd4, 0xe5,
+       0x4a, 0x09, 0x21, 0xef, 0x8b, 0xb8, 0x74, 0x3b,
+       0x91, 0xdd, 0x36, 0x85, 0x60, 0x2d, 0xfa, 0xd4,
+       0x45, 0x7b, 0x45, 0x53, 0xf5, 0x47, 0x87, 0x7e,
+       0xa6, 0x37, 0xc8, 0x78, 0x7a, 0x68, 0x9d, 0x8d,
+       0x65, 0x2c, 0x0e, 0x91, 0x5c, 0xa2, 0x60, 0xf0,
+       0x8e, 0x3f, 0xe9, 0x1a, 0xcd, 0xaa, 0xe7, 0xd5,
+       0x77, 0x18, 0xaf, 0xc9, 0xbc, 0x18, 0xea, 0x48,
+       0x1b, 0xfb, 0x22, 0x48, 0x70, 0x16, 0x29, 0x9e,
+       0x5b, 0xc1, 0x2c, 0x66, 0x23, 0xbc, 0xf0, 0x1f,
+       0xef, 0xaf, 0xe4, 0xd6, 0x04, 0x19, 0x82, 0x7a,
+       0x0b, 0xba, 0x4b, 0x46, 0xb1, 0x6a, 0x85, 0x5d,
+       0xb4, 0x73, 0xd6, 0x21, 0xa1, 0x71, 0x60, 0x14,
+       0xee, 0x0a, 0x77, 0xc4, 0x66, 0x2e, 0xf9, 0x69,
+       0x30, 0xaf, 0x41, 0x0b, 0xc8, 0x83, 0x3c, 0x53,
+       0x99, 0x19, 0x27, 0x46, 0xf7, 0x41, 0x6e, 0x56,
+       0xdc, 0x94, 0x28, 0x67, 0x4e, 0xb7, 0x25, 0x48,
+       0x8a, 0xc2, 0xe0, 0x60, 0x96, 0xcc, 0x18, 0xf4,
+       0x84, 0xdd, 0xa7, 0x5e, 0x3e, 0x05, 0x0b, 0x26,
+       0x26, 0xb2, 0x5c, 0x1f, 0x57, 0x1a, 0x04, 0x7e,
+       0x6a, 0xe3, 0x2f, 0xb4, 0x35, 0xb6, 0x38, 0x40,
+       0x40, 0xcd, 0x6f, 0x87, 0x2e, 0xef, 0xa3, 0xd7,
+       0xa9, 0xc2, 0xe8, 0x0d, 0x27, 0xdf, 0x44, 0x62,
+       0x99, 0xa0, 0xfc, 0xcf, 0x81, 0x78, 0xcb, 0xfe,
+       0xe5, 0xa0, 0x03, 0x4e, 0x6c, 0xd7, 0xf4, 0xaf,
+       0x7a, 0xbb, 0x61, 0x82, 0xfe, 0x71, 0x89, 0xb2,
+       0x22, 0x7c, 0x8e, 0x83, 0x04, 0xce, 0xf6, 0x5d,
+       0x84, 0x8f, 0x95, 0x6a, 0x7f, 0xad, 0xfd, 0x32,
+       0x9c, 0x5e, 0xe4, 0x9c, 0x89, 0x60, 0x54, 0xaa,
+       0x96, 0x72, 0xd2, 0xd7, 0x36, 0x85, 0xa9, 0x45,
+       0xd2, 0x2a, 0xa1, 0x81, 0x49, 0x6f, 0x7e, 0x04,
+       0xfa, 0xe2, 0xfe, 0x90, 0x26, 0x77, 0x5a, 0x33,
+       0xb8, 0x04, 0x9a, 0x7a, 0xe6, 0x4c, 0x4f, 0xad,
+       0x72, 0x96, 0x08, 0x28, 0x58, 0x13, 0xf8, 0xc4,
+       0x1c, 0xf0, 0xc3, 0x45, 0x95, 0x49, 0x20, 0x8c,
+       0x9f, 0x39, 0x70, 0xe1, 0x77, 0xfe, 0xd5, 0x4b,
+       0xaf, 0x86, 0xda, 0xef, 0x22, 0x06, 0x83, 0x36,
+       0x29, 0x12, 0x11, 0x40, 0xbc, 0x3b, 0x86, 0xaa,
+       0xaa, 0x65, 0x60, 0xc3, 0x80, 0xca, 0xed, 0xa9,
+       0xf3, 0xb0, 0x79, 0x96, 0xa2, 0x55, 0x27, 0x28,
+       0x55, 0x73, 0x26, 0xa5, 0x50, 0xea, 0x92, 0x4b,
+       0x3c, 0x5c, 0x82, 0x33, 0xf0, 0x01, 0x3f, 0x03,
+       0xc1, 0x08, 0x05, 0xbf, 0x98, 0xf4, 0x9b, 0x6d,
+       0xa5, 0xa8, 0xb4, 0x82, 0x0c, 0x06, 0xfa, 0xff,
+       0x2d, 0x08, 0xf3, 0x05, 0x4f, 0x57, 0x2a, 0x39,
+       0xd4, 0x83, 0x0d, 0x75, 0x51, 0xd8, 0x5b, 0x1b,
+       0xd3, 0x51, 0x5a, 0x32, 0x2a, 0x9b, 0x32, 0xb2,
+       0xf2, 0xa4, 0x96, 0x12, 0xf2, 0xae, 0x40, 0x34,
+       0x67, 0xa8, 0xf5, 0x44, 0xd5, 0x35, 0x53, 0xfe,
+       0xa3, 0x60, 0x96, 0x63, 0x0f, 0x1f, 0x6e, 0xb0,
+       0x5a, 0x42, 0xa6, 0xfc, 0x51, 0x0b, 0x60, 0x27,
+       0xbc, 0x06, 0x71, 0xed, 0x65, 0x5b, 0x23, 0x86,
+       0x4a, 0x07, 0x3b, 0x22, 0x07, 0x46, 0xe6, 0x90,
+       0x3e, 0xf3, 0x25, 0x50, 0x1b, 0x4c, 0x7f, 0x03,
+       0x08, 0xa8, 0x36, 0x6b, 0x87, 0xe5, 0xe3, 0xdb,
+       0x9a, 0x38, 0x83, 0xff, 0x9f, 0x1a, 0x9f, 0x57,
+       0xa4, 0x2a, 0xf6, 0x37, 0xbc, 0x1a, 0xff, 0xc9,
+       0x1e, 0x35, 0x0c, 0xc3, 0x7c, 0xa3, 0xb2, 0xe5,
+       0xd2, 0xc6, 0xb4, 0x57, 0x47, 0xe4, 0x32, 0x16,
+       0x6d, 0xa9, 0xae, 0x64, 0xe6, 0x2d, 0x8d, 0xc5,
+       0x8d, 0x50, 0x8e, 0xe8, 0x1a, 0x22, 0x34, 0x2a,
+       0xd9, 0xeb, 0x51, 0x90, 0x4a, 0xb1, 0x41, 0x7d,
+       0x64, 0xf9, 0xb9, 0x0d, 0xf6, 0x23, 0x33, 0xb0,
+       0x33, 0xf4, 0xf7, 0x3f, 0x27, 0x84, 0xc6, 0x0f,
+       0x54, 0xa5, 0xc0, 0x2e, 0xec, 0x0b, 0x3a, 0x48,
+       0x6e, 0x80, 0x35, 0x81, 0x43, 0x9b, 0x90, 0xb1,
+       0xd0, 0x2b, 0xea, 0x21, 0xdc, 0xda, 0x5b, 0x09,
+       0xf4, 0xcc, 0x10, 0xb4, 0xc7, 0xfe, 0x79, 0x51,
+       0xc3, 0xc5, 0xac, 0x88, 0x74, 0x84, 0x0b, 0x4b,
+       0xca, 0x79, 0x16, 0x29, 0xfb, 0x69, 0x54, 0xdf,
+       0x41, 0x7e, 0xe9, 0xc7, 0x8e, 0xea, 0xa5, 0xfe,
+       0xfc, 0x76, 0x0e, 0x90, 0xc4, 0x92, 0x38, 0xad,
+       0x7b, 0x48, 0xe6, 0x6e, 0xf7, 0x21, 0xfd, 0x4e,
+       0x93, 0x0a, 0x7b, 0x41, 0x83, 0x68, 0xfb, 0x57,
+       0x51, 0x76, 0x34, 0xa9, 0x6c, 0x00, 0xaa, 0x4f,
+       0x66, 0x65, 0x98, 0x4a, 0x4f, 0xa3, 0xa0, 0xef,
+       0x69, 0x3f, 0xe3, 0x1c, 0x92, 0x8c, 0xfd, 0xd8,
+       0xe8, 0xde, 0x7c, 0x7f, 0x3e, 0x84, 0x8e, 0x69,
+       0x3c, 0xf1, 0xf2, 0x05, 0x46, 0xdc, 0x2f, 0x9d,
+       0x5e, 0x6e, 0x4c, 0xfb, 0xb5, 0x99, 0x2a, 0x59,
+       0x63, 0xc1, 0x34, 0xbc, 0x57, 0xc0, 0x0d, 0xb9,
+       0x61, 0x25, 0xf3, 0x33, 0x23, 0x51, 0xb6, 0x0d,
+       0x07, 0xa6, 0xab, 0x94, 0x4a, 0xb7, 0x2a, 0xea,
+       0xee, 0xac, 0xa3, 0xc3, 0x04, 0x8b, 0x0e, 0x56,
+       0xfe, 0x44, 0xa7, 0x39, 0xe2, 0xed, 0xed, 0xb4,
+       0x22, 0x2b, 0xac, 0x12, 0x32, 0x28, 0x91, 0xd8,
+       0xa5, 0xab, 0xff, 0x5f, 0xe0, 0x4b, 0xda, 0x78,
+       0x17, 0xda, 0xf1, 0x01, 0x5b, 0xcd, 0xe2, 0x5f,
+       0x50, 0x45, 0x73, 0x2b, 0xe4, 0x76, 0x77, 0xf4,
+       0x64, 0x1d, 0x43, 0xfb, 0x84, 0x7a, 0xea, 0x91,
+       0xae, 0xf9, 0x9e, 0xb7, 0xb4, 0xb0, 0x91, 0x5f,
+       0x16, 0x35, 0x9a, 0x11, 0xb8, 0xc7, 0xc1, 0x8c,
+       0xc6, 0x10, 0x8d, 0x2f, 0x63, 0x4a, 0xa7, 0x57,
+       0x3a, 0x51, 0xd6, 0x32, 0x2d, 0x64, 0x72, 0xd4,
+       0x66, 0xdc, 0x10, 0xa6, 0x67, 0xd6, 0x04, 0x23,
+       0x9d, 0x0a, 0x11, 0x77, 0xdd, 0x37, 0x94, 0x17,
+       0x3c, 0xbf, 0x8b, 0x65, 0xb0, 0x2e, 0x5e, 0x66,
+       0x47, 0x64, 0xac, 0xdd, 0xf0, 0x84, 0xfd, 0x39,
+       0xfa, 0x15, 0x5d, 0xef, 0xae, 0xca, 0xc1, 0x36,
+       0xa7, 0x5c, 0xbf, 0xc7, 0x08, 0xc2, 0x66, 0x00,
+       0x74, 0x74, 0x4e, 0x27, 0x3f, 0x55, 0x8a, 0xb7,
+       0x38, 0x66, 0x83, 0x6d, 0xcf, 0x99, 0x9e, 0x60,
+       0x8f, 0xdd, 0x2e, 0x62, 0x22, 0x0e, 0xef, 0x0c,
+       0x98, 0xa7, 0x85, 0x74, 0x3b, 0x9d, 0xec, 0x9e,
+       0xa9, 0x19, 0x72, 0xa5, 0x7f, 0x2c, 0x39, 0xb7,
+       0x7d, 0xb7, 0xf1, 0x12, 0x65, 0x27, 0x4b, 0x5a,
+       0xde, 0x17, 0xfe, 0xad, 0x44, 0xf3, 0x20, 0x4d,
+       0xfd, 0xe4, 0x1f, 0xb5, 0x81, 0xb0, 0x36, 0x37,
+       0x08, 0x6f, 0xc3, 0x0c, 0xe9, 0x85, 0x98, 0x82,
+       0xa9, 0x62, 0x0c, 0xc4, 0x97, 0xc0, 0x50, 0xc8,
+       0xa7, 0x3c, 0x50, 0x9f, 0x43, 0xb9, 0xcd, 0x5e,
+       0x4d, 0xfa, 0x1c, 0x4b, 0x0b, 0xa9, 0x98, 0x85,
+       0x38, 0x92, 0xac, 0x8d, 0xe4, 0xad, 0x9b, 0x98,
+       0xab, 0xd9, 0x38, 0xac, 0x62, 0x52, 0xa3, 0x22,
+       0x63, 0x0f, 0xbf, 0x95, 0x48, 0xdf, 0x69, 0xe7,
+       0x8b, 0x33, 0xd5, 0xb2, 0xbd, 0x05, 0x49, 0x49,
+       0x9d, 0x57, 0x73, 0x19, 0x33, 0xae, 0xfa, 0x33,
+       0xf1, 0x19, 0xa8, 0x80, 0xce, 0x04, 0x9f, 0xbc,
+       0x1d, 0x65, 0x82, 0x1b, 0xe5, 0x3a, 0x51, 0xc8,
+       0x1c, 0x21, 0xe3, 0x5d, 0xf3, 0x7d, 0x9b, 0x2f,
+       0x2c, 0x1d, 0x4a, 0x7f, 0x9b, 0x68, 0x35, 0xa3,
+       0xb2, 0x50, 0xf7, 0x62, 0x79, 0xcd, 0xf4, 0x98,
+       0x4f, 0xe5, 0x63, 0x7c, 0x3e, 0x45, 0x31, 0x8c,
+       0x16, 0xa0, 0x12, 0xc8, 0x58, 0xce, 0x39, 0xa6,
+       0xbc, 0x54, 0xdb, 0xc5, 0xe0, 0xd5, 0xba, 0xbc,
+       0xb9, 0x04, 0xf4, 0x8d, 0xe8, 0x2f, 0x15, 0x9d,
+};
 
-#if 0                          /*Not used at present */
-static void
-buf_dump(char const *prefix, unsigned char const *buf, size_t len)
+/* 100 test cases */
+static struct crc_test {
+       u32 crc;        /* random starting crc */
+       u32 start;      /* random 6 bit offset in buf */
+       u32 length;     /* random 11 bit length of test */
+       u32 crc_le;     /* expected crc32_le result */
+       u32 crc_be;     /* expected crc32_be result */
+       u32 crc32c_le;  /* expected crc32c_le result */
+} test[] =
 {
-       fputs(prefix, stdout);
-       while (len--)
-               printf(" %02x", *buf++);
-       putchar('\n');
+       {0x674bf11d, 0x00000038, 0x00000542, 0x0af6d466, 0xd8b6e4c1,
+        0xf6e93d6c},
+       {0x35c672c6, 0x0000003a, 0x000001aa, 0xc6d3dfba, 0x28aaf3ad,
+        0x0fe92aca},
+       {0x496da28e, 0x00000039, 0x000005af, 0xd933660f, 0x5d57e81f,
+        0x52e1ebb8},
+       {0x09a9b90e, 0x00000027, 0x000001f8, 0xb45fe007, 0xf45fca9a,
+        0x0798af9a},
+       {0xdc97e5a9, 0x00000025, 0x000003b6, 0xf81a3562, 0xe0126ba2,
+        0x18eb3152},
+       {0x47c58900, 0x0000000a, 0x000000b9, 0x8e58eccf, 0xf3afc793,
+        0xd00d08c7},
+       {0x292561e8, 0x0000000c, 0x00000403, 0xa2ba8aaf, 0x0b797aed,
+        0x8ba966bc},
+       {0x415037f6, 0x00000003, 0x00000676, 0xa17d52e8, 0x7f0fdf35,
+        0x11d694a2},
+       {0x3466e707, 0x00000026, 0x00000042, 0x258319be, 0x75c484a2,
+        0x6ab3208d},
+       {0xafd1281b, 0x00000023, 0x000002ee, 0x4428eaf8, 0x06c7ad10,
+        0xba4603c5},
+       {0xd3857b18, 0x00000028, 0x000004a2, 0x5c430821, 0xb062b7cb,
+        0xe6071c6f},
+       {0x1d825a8f, 0x0000002b, 0x0000050b, 0xd2c45f0c, 0xd68634e0,
+        0x179ec30a},
+       {0x5033e3bc, 0x0000000b, 0x00000078, 0xa3ea4113, 0xac6d31fb,
+        0x0903beb8},
+       {0x94f1fb5e, 0x0000000f, 0x000003a2, 0xfbfc50b1, 0x3cfe50ed,
+        0x6a7cb4fa},
+       {0xc9a0fe14, 0x00000009, 0x00000473, 0x5fb61894, 0x87070591,
+        0xdb535801},
+       {0x88a034b1, 0x0000001c, 0x000005ad, 0xc1b16053, 0x46f95c67,
+        0x92bed597},
+       {0xf0f72239, 0x00000020, 0x0000026d, 0xa6fa58f3, 0xf8c2c1dd,
+        0x192a3f1b},
+       {0xcc20a5e3, 0x0000003b, 0x0000067a, 0x7740185a, 0x308b979a,
+        0xccbaec1a},
+       {0xce589c95, 0x0000002b, 0x00000641, 0xd055e987, 0x40aae25b,
+        0x7eabae4d},
+       {0x78edc885, 0x00000035, 0x000005be, 0xa39cb14b, 0x035b0d1f,
+        0x28c72982},
+       {0x9d40a377, 0x0000003b, 0x00000038, 0x1f47ccd2, 0x197fbc9d,
+        0xc3cd4d18},
+       {0x703d0e01, 0x0000003c, 0x000006f1, 0x88735e7c, 0xfed57c5a,
+        0xbca8f0e7},
+       {0x776bf505, 0x0000000f, 0x000005b2, 0x5cc4fc01, 0xf32efb97,
+        0x713f60b3},
+       {0x4a3e7854, 0x00000027, 0x000004b8, 0x8d923c82, 0x0cbfb4a2,
+        0xebd08fd5},
+       {0x209172dd, 0x0000003b, 0x00000356, 0xb89e9c2b, 0xd7868138,
+        0x64406c59},
+       {0x3ba4cc5b, 0x0000002f, 0x00000203, 0xe51601a9, 0x5b2a1032,
+        0x7421890e},
+       {0xfc62f297, 0x00000000, 0x00000079, 0x71a8e1a2, 0x5d88685f,
+        0xe9347603},
+       {0x64280b8b, 0x00000016, 0x000007ab, 0x0fa7a30c, 0xda3a455f,
+        0x1bef9060},
+       {0x97dd724b, 0x00000033, 0x000007ad, 0x5788b2f4, 0xd7326d32,
+        0x34720072},
+       {0x61394b52, 0x00000035, 0x00000571, 0xc66525f1, 0xcabe7fef,
+        0x48310f59},
+       {0x29b4faff, 0x00000024, 0x0000006e, 0xca13751e, 0x993648e0,
+        0x783a4213},
+       {0x29bfb1dc, 0x0000000b, 0x00000244, 0x436c43f7, 0x429f7a59,
+        0x9e8efd41},
+       {0x86ae934b, 0x00000035, 0x00000104, 0x0760ec93, 0x9cf7d0f4,
+        0xfc3d34a5},
+       {0xc4c1024e, 0x0000002e, 0x000006b1, 0x6516a3ec, 0x19321f9c,
+        0x17a52ae2},
+       {0x3287a80a, 0x00000026, 0x00000496, 0x0b257eb1, 0x754ebd51,
+        0x886d935a},
+       {0xa4db423e, 0x00000023, 0x0000045d, 0x9b3a66dc, 0x873e9f11,
+        0xeaaeaeb2},
+       {0x7a1078df, 0x00000015, 0x0000014a, 0x8c2484c5, 0x6a628659,
+        0x8e900a4b},
+       {0x6048bd5b, 0x00000006, 0x0000006a, 0x897e3559, 0xac9961af,
+        0xd74662b1},
+       {0xd8f9ea20, 0x0000003d, 0x00000277, 0x60eb905b, 0xed2aaf99,
+        0xd26752ba},
+       {0xea5ec3b4, 0x0000002a, 0x000004fe, 0x869965dc, 0x6c1f833b,
+        0x8b1fcd62},
+       {0x2dfb005d, 0x00000016, 0x00000345, 0x6a3b117e, 0xf05e8521,
+        0xf54342fe},
+       {0x5a214ade, 0x00000020, 0x000005b6, 0x467f70be, 0xcb22ccd3,
+        0x5b95b988},
+       {0xf0ab9cca, 0x00000032, 0x00000515, 0xed223df3, 0x7f3ef01d,
+        0x2e1176be},
+       {0x91b444f9, 0x0000002e, 0x000007f8, 0x84e9a983, 0x5676756f,
+        0x66120546},
+       {0x1b5d2ddb, 0x0000002e, 0x0000012c, 0xba638c4c, 0x3f42047b,
+        0xf256a5cc},
+       {0xd824d1bb, 0x0000003a, 0x000007b5, 0x6288653b, 0x3a3ebea0,
+        0x4af1dd69},
+       {0x0470180c, 0x00000034, 0x000001f0, 0x9d5b80d6, 0x3de08195,
+        0x56f0a04a},
+       {0xffaa3a3f, 0x00000036, 0x00000299, 0xf3a82ab8, 0x53e0c13d,
+        0x74f6b6b2},
+       {0x6406cfeb, 0x00000023, 0x00000600, 0xa920b8e8, 0xe4e2acf4,
+        0x085951fd},
+       {0xb24aaa38, 0x0000003e, 0x000004a1, 0x657cc328, 0x5077b2c3,
+        0xc65387eb},
+       {0x58b2ab7c, 0x00000039, 0x000002b4, 0x3a17ee7e, 0x9dcb3643,
+        0x1ca9257b},
+       {0x3db85970, 0x00000006, 0x000002b6, 0x95268b59, 0xb9812c10,
+        0xfd196d76},
+       {0x857830c5, 0x00000003, 0x00000590, 0x4ef439d5, 0xf042161d,
+        0x5ef88339},
+       {0xe1fcd978, 0x0000003e, 0x000007d8, 0xae8d8699, 0xce0a1ef5,
+        0x2c3714d9},
+       {0xb982a768, 0x00000016, 0x000006e0, 0x62fad3df, 0x5f8a067b,
+        0x58576548},
+       {0x1d581ce8, 0x0000001e, 0x0000058b, 0xf0f5da53, 0x26e39eee,
+        0xfd7c57de},
+       {0x2456719b, 0x00000025, 0x00000503, 0x4296ac64, 0xd50e4c14,
+        0xd5fedd59},
+       {0xfae6d8f2, 0x00000000, 0x0000055d, 0x057fdf2e, 0x2a31391a,
+        0x1cc3b17b},
+       {0xcba828e3, 0x00000039, 0x000002ce, 0xe3f22351, 0x8f00877b,
+        0x270eed73},
+       {0x13d25952, 0x0000000a, 0x0000072d, 0x76d4b4cc, 0x5eb67ec3,
+        0x91ecbb11},
+       {0x0342be3f, 0x00000015, 0x00000599, 0xec75d9f1, 0x9d4d2826,
+        0x05ed8d0c},
+       {0xeaa344e0, 0x00000014, 0x000004d8, 0x72a4c981, 0x2064ea06,
+        0x0b09ad5b},
+       {0xbbb52021, 0x0000003b, 0x00000272, 0x04af99fc, 0xaf042d35,
+        0xf8d511fb},
+       {0xb66384dc, 0x0000001d, 0x000007fc, 0xd7629116, 0x782bd801,
+        0x5ad832cc},
+       {0x616c01b6, 0x00000022, 0x000002c8, 0x5b1dab30, 0x783ce7d2,
+        0x1214d196},
+       {0xce2bdaad, 0x00000016, 0x0000062a, 0x932535c8, 0x3f02926d,
+        0x5747218a},
+       {0x00fe84d7, 0x00000005, 0x00000205, 0x850e50aa, 0x753d649c,
+        0xde8f14de},
+       {0xbebdcb4c, 0x00000006, 0x0000055d, 0xbeaa37a2, 0x2d8c9eba,
+        0x3563b7b9},
+       {0xd8b1a02a, 0x00000010, 0x00000387, 0x5017d2fc, 0x503541a5,
+        0x071475d0},
+       {0x3b96cad2, 0x00000036, 0x00000347, 0x1d2372ae, 0x926cd90b,
+        0x54c79d60},
+       {0xc94c1ed7, 0x00000005, 0x0000038b, 0x9e9fdb22, 0x144a9178,
+        0x4c53eee6},
+       {0x1aad454e, 0x00000025, 0x000002b2, 0xc3f6315c, 0x5c7a35b3,
+        0x10137a3c},
+       {0xa4fec9a6, 0x00000000, 0x000006d6, 0x90be5080, 0xa4107605,
+        0xaa9d6c73},
+       {0x1bbe71e2, 0x0000001f, 0x000002fd, 0x4e504c3b, 0x284ccaf1,
+        0xb63d23e7},
+       {0x4201c7e4, 0x00000002, 0x000002b7, 0x7822e3f9, 0x0cc912a9,
+        0x7f53e9cf},
+       {0x23fddc96, 0x00000003, 0x00000627, 0x8a385125, 0x07767e78,
+        0x13c1cd83},
+       {0xd82ba25c, 0x00000016, 0x0000063e, 0x98e4148a, 0x283330c9,
+        0x49ff5867},
+       {0x786f2032, 0x0000002d, 0x0000060f, 0xf201600a, 0xf561bfcd,
+        0x8467f211},
+       {0xfebe4e1f, 0x0000002a, 0x000004f2, 0x95e51961, 0xfd80dcab,
+        0x3f9683b2},
+       {0x1a6e0a39, 0x00000008, 0x00000672, 0x8af6c2a5, 0x78dd84cb,
+        0x76a3f874},
+       {0x56000ab8, 0x0000000e, 0x000000e5, 0x36bacb8f, 0x22ee1f77,
+        0x863b702f},
+       {0x4717fe0c, 0x00000000, 0x000006ec, 0x8439f342, 0x5c8e03da,
+        0xdc6c58ff},
+       {0xd5d5d68e, 0x0000003c, 0x000003a3, 0x46fff083, 0x177d1b39,
+        0x0622cc95},
+       {0xc25dd6c6, 0x00000024, 0x000006c0, 0x5ceb8eb4, 0x892b0d16,
+        0xe85605cd},
+       {0xe9b11300, 0x00000023, 0x00000683, 0x07a5d59a, 0x6c6a3208,
+        0x31da5f06},
+       {0x95cd285e, 0x00000001, 0x00000047, 0x7b3a4368, 0x0202c07e,
+        0xa1f2e784},
+       {0xd9245a25, 0x0000001e, 0x000003a6, 0xd33c1841, 0x1936c0d5,
+        0xb07cc616},
+       {0x103279db, 0x00000006, 0x0000039b, 0xca09b8a0, 0x77d62892,
+        0xbf943b6c},
+       {0x1cba3172, 0x00000027, 0x000001c8, 0xcb377194, 0xebe682db,
+        0x2c01af1c},
+       {0x8f613739, 0x0000000c, 0x000001df, 0xb4b0bc87, 0x7710bd43,
+        0x0fe5f56d},
+       {0x1c6aa90d, 0x0000001b, 0x0000053c, 0x70559245, 0xda7894ac,
+        0xf8943b2d},
+       {0xaabe5b93, 0x0000003d, 0x00000715, 0xcdbf42fa, 0x0c3b99e7,
+        0xe4d89272},
+       {0xf15dd038, 0x00000006, 0x000006db, 0x6e104aea, 0x8d5967f2,
+        0x7c2f6bbb},
+       {0x584dd49c, 0x00000020, 0x000007bc, 0x36b6cfd6, 0xad4e23b2,
+        0xabbf388b},
+       {0x5d8c9506, 0x00000020, 0x00000470, 0x4c62378e, 0x31d92640,
+        0x1dca1f4e},
+       {0xb80d17b0, 0x00000032, 0x00000346, 0x22a5bb88, 0x9a7ec89f,
+        0x5c170e23},
+       {0xdaf0592e, 0x00000023, 0x000007b0, 0x3cab3f99, 0x9b1fdd99,
+        0xc0e9d672},
+       {0x4793cc85, 0x0000000d, 0x00000706, 0xe82e04f6, 0xed3db6b7,
+        0xc18bdc86},
+       {0x82ebf64e, 0x00000009, 0x000007c3, 0x69d590a9, 0x9efa8499,
+        0xa874fcdd},
+       {0xb18a0319, 0x00000026, 0x000007db, 0x1cf98dcc, 0x8fa9ad6a,
+        0x9dc0bb48},
+};
 
-}
-#endif
+#include <linux/time.h>
 
-static void bytereverse(unsigned char *buf, size_t len)
+static int __init crc32c_test(void)
 {
-       while (len--) {
-               unsigned char x = bitrev8(*buf);
-               *buf++ = x;
+       int i;
+       int errors = 0;
+       int bytes = 0;
+       struct timespec start, stop;
+       u64 nsec;
+       unsigned long flags;
+
+       /* keep static to prevent cache warming code from
+        * getting eliminated by the compiler */
+       static u32 crc;
+
+       /* pre-warm the cache */
+       for (i = 0; i < 100; i++) {
+               bytes += 2*test[i].length;
+
+               crc ^= __crc32c_le(test[i].crc, test_buf +
+                   test[i].start, test[i].length);
        }
-}
 
-static void random_garbage(unsigned char *buf, size_t len)
-{
-       while (len--)
-               *buf++ = (unsigned char) random();
-}
+       /* reduce OS noise */
+       local_irq_save(flags);
+       local_irq_disable();
 
-#if 0                          /* Not used at present */
-static void store_le(u32 x, unsigned char *buf)
-{
-       buf[0] = (unsigned char) x;
-       buf[1] = (unsigned char) (x >> 8);
-       buf[2] = (unsigned char) (x >> 16);
-       buf[3] = (unsigned char) (x >> 24);
-}
-#endif
+       getnstimeofday(&start);
+       for (i = 0; i < 100; i++) {
+               if (test[i].crc32c_le != __crc32c_le(test[i].crc, test_buf +
+                   test[i].start, test[i].length))
+                       errors++;
+       }
+       getnstimeofday(&stop);
 
-static void store_be(u32 x, unsigned char *buf)
-{
-       buf[0] = (unsigned char) (x >> 24);
-       buf[1] = (unsigned char) (x >> 16);
-       buf[2] = (unsigned char) (x >> 8);
-       buf[3] = (unsigned char) x;
+       local_irq_restore(flags);
+       local_irq_enable();
+
+       nsec = stop.tv_nsec - start.tv_nsec +
+               1000000000 * (stop.tv_sec - start.tv_sec);
+
+       pr_info("crc32c: CRC_LE_BITS = %d\n", CRC_LE_BITS);
+
+       if (errors)
+               pr_warn("crc32c: %d self tests failed\n", errors);
+       else {
+               pr_info("crc32c: self tests passed, processed %d bytes in %lld nsec\n",
+                       bytes, nsec);
+       }
+
+       return 0;
 }
 
-/*
- * This checks that CRC(buf + CRC(buf)) = 0, and that
- * CRC commutes with bit-reversal.  This has the side effect
- * of bytewise bit-reversing the input buffer, and returns
- * the CRC of the reversed buffer.
- */
-static u32 test_step(u32 init, unsigned char *buf, size_t len)
+static int __init crc32_test(void)
 {
-       u32 crc1, crc2;
-       size_t i;
+       int i;
+       int errors = 0;
+       int bytes = 0;
+       struct timespec start, stop;
+       u64 nsec;
+       unsigned long flags;
+
+       /* keep static to prevent cache warming code from
+        * getting eliminated by the compiler */
+       static u32 crc;
+
+       /* pre-warm the cache */
+       for (i = 0; i < 100; i++) {
+               bytes += 2*test[i].length;
 
-       crc1 = crc32_be(init, buf, len);
-       store_be(crc1, buf + len);
-       crc2 = crc32_be(init, buf, len + 4);
-       if (crc2)
-               printf("\nCRC cancellation fail: 0x%08x should be 0\n",
-                      crc2);
-
-       for (i = 0; i <= len + 4; i++) {
-               crc2 = crc32_be(init, buf, i);
-               crc2 = crc32_be(crc2, buf + i, len + 4 - i);
-               if (crc2)
-                       printf("\nCRC split fail: 0x%08x\n", crc2);
+               crc ^= crc32_le(test[i].crc, test_buf +
+                   test[i].start, test[i].length);
+
+               crc ^= crc32_be(test[i].crc, test_buf +
+                   test[i].start, test[i].length);
        }
 
-       /* Now swap it around for the other test */
-
-       bytereverse(buf, len + 4);
-       init = bitrev32(init);
-       crc2 = bitrev32(crc1);
-       if (crc1 != bitrev32(crc2))
-               printf("\nBit reversal fail: 0x%08x -> 0x%08x -> 0x%08x\n",
-                      crc1, crc2, bitrev32(crc2));
-       crc1 = crc32_le(init, buf, len);
-       if (crc1 != crc2)
-               printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
-                      crc2);
-       crc2 = crc32_le(init, buf, len + 4);
-       if (crc2)
-               printf("\nCRC cancellation fail: 0x%08x should be 0\n",
-                      crc2);
-
-       for (i = 0; i <= len + 4; i++) {
-               crc2 = crc32_le(init, buf, i);
-               crc2 = crc32_le(crc2, buf + i, len + 4 - i);
-               if (crc2)
-                       printf("\nCRC split fail: 0x%08x\n", crc2);
+       /* reduce OS noise */
+       local_irq_save(flags);
+       local_irq_disable();
+
+       getnstimeofday(&start);
+       for (i = 0; i < 100; i++) {
+               if (test[i].crc_le != crc32_le(test[i].crc, test_buf +
+                   test[i].start, test[i].length))
+                       errors++;
+
+               if (test[i].crc_be != crc32_be(test[i].crc, test_buf +
+                   test[i].start, test[i].length))
+                       errors++;
        }
+       getnstimeofday(&stop);
 
-       return crc1;
-}
+       local_irq_restore(flags);
+       local_irq_enable();
 
-#define SIZE 64
-#define INIT1 0
-#define INIT2 0
+       nsec = stop.tv_nsec - start.tv_nsec +
+               1000000000 * (stop.tv_sec - start.tv_sec);
 
-int main(void)
-{
-       unsigned char buf1[SIZE + 4];
-       unsigned char buf2[SIZE + 4];
-       unsigned char buf3[SIZE + 4];
-       int i, j;
-       u32 crc1, crc2, crc3;
-
-       for (i = 0; i <= SIZE; i++) {
-               printf("\rTesting length %d...", i);
-               fflush(stdout);
-               random_garbage(buf1, i);
-               random_garbage(buf2, i);
-               for (j = 0; j < i; j++)
-                       buf3[j] = buf1[j] ^ buf2[j];
-
-               crc1 = test_step(INIT1, buf1, i);
-               crc2 = test_step(INIT2, buf2, i);
-               /* Now check that CRC(buf1 ^ buf2) = CRC(buf1) ^ CRC(buf2) */
-               crc3 = test_step(INIT1 ^ INIT2, buf3, i);
-               if (crc3 != (crc1 ^ crc2))
-                       printf("CRC XOR fail: 0x%08x != 0x%08x ^ 0x%08x\n",
-                              crc3, crc1, crc2);
+       pr_info("crc32: CRC_LE_BITS = %d, CRC_BE BITS = %d\n",
+                CRC_LE_BITS, CRC_BE_BITS);
+
+       if (errors)
+               pr_warn("crc32: %d self tests failed\n", errors);
+       else {
+               pr_info("crc32: self tests passed, processed %d bytes in %lld nsec\n",
+                       bytes, nsec);
        }
-       printf("\nAll test complete.  No failures expected.\n");
+
        return 0;
 }
 
-#endif                         /* UNITTEST */
+static int __init crc32test_init(void)
+{
+       crc32_test();
+       crc32c_test();
+       return 0;
+}
+
+static void __exit crc32_exit(void)
+{
+}
+
+module_init(crc32test_init);
+module_exit(crc32_exit);
+#endif /* CONFIG_CRC32_SELFTEST */
index 9b6773d..64cba2c 100644 (file)
@@ -6,27 +6,67 @@
 #define CRCPOLY_LE 0xedb88320
 #define CRCPOLY_BE 0x04c11db7
 
-/* How many bits at a time to use.  Requires a table of 4<<CRC_xx_BITS bytes. */
-/* For less performance-sensitive, use 4 */
-#ifndef CRC_LE_BITS 
+/*
+ * This is the CRC32c polynomial, as outlined by Castagnoli.
+ * x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+
+ * x^8+x^6+x^0
+ */
+#define CRC32C_POLY_LE 0x82F63B78
+
+/* Try to choose an implementation variant via Kconfig */
+#ifdef CONFIG_CRC32_SLICEBY8
+# define CRC_LE_BITS 64
+# define CRC_BE_BITS 64
+#endif
+#ifdef CONFIG_CRC32_SLICEBY4
+# define CRC_LE_BITS 32
+# define CRC_BE_BITS 32
+#endif
+#ifdef CONFIG_CRC32_SARWATE
 # define CRC_LE_BITS 8
+# define CRC_BE_BITS 8
+#endif
+#ifdef CONFIG_CRC32_BIT
+# define CRC_LE_BITS 1
+# define CRC_BE_BITS 1
+#endif
+
+/*
+ * How many bits at a time to use.  Valid values are 1, 2, 4, 8, 32 and 64.
+ * For less performance-sensitive, use 4 or 8 to save table size.
+ * For larger systems choose same as CPU architecture as default.
+ * This works well on X86_64, SPARC64 systems. This may require some
+ * elaboration after experiments with other architectures.
+ */
+#ifndef CRC_LE_BITS
+#  ifdef CONFIG_64BIT
+#  define CRC_LE_BITS 64
+#  else
+#  define CRC_LE_BITS 32
+#  endif
 #endif
 #ifndef CRC_BE_BITS
-# define CRC_BE_BITS 8
+#  ifdef CONFIG_64BIT
+#  define CRC_BE_BITS 64
+#  else
+#  define CRC_BE_BITS 32
+#  endif
 #endif
 
 /*
  * Little-endian CRC computation.  Used with serial bit streams sent
  * lsbit-first.  Be sure to use cpu_to_le32() to append the computed CRC.
  */
-#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
-# error CRC_LE_BITS must be a power of 2 between 1 and 8
+#if CRC_LE_BITS > 64 || CRC_LE_BITS < 1 || CRC_LE_BITS == 16 || \
+       CRC_LE_BITS & CRC_LE_BITS-1
+# error "CRC_LE_BITS must be one of {1, 2, 4, 8, 32, 64}"
 #endif
 
 /*
  * Big-endian CRC computation.  Used with serial bit streams sent
  * msbit-first.  Be sure to use cpu_to_be32() to append the computed CRC.
  */
-#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
-# error CRC_BE_BITS must be a power of 2 between 1 and 8
+#if CRC_BE_BITS > 64 || CRC_BE_BITS < 1 || CRC_BE_BITS == 16 || \
+       CRC_BE_BITS & CRC_BE_BITS-1
+# error "CRC_BE_BITS must be one of {1, 2, 4, 8, 32, 64}"
 #endif
index 26baa62..c646df9 100644 (file)
@@ -5,7 +5,8 @@
  */
 
 #include <linux/ctype.h>
-#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/export.h>
 
 const unsigned char _ctype[] = {
 _C,_C,_C,_C,_C,_C,_C,_C,                               /* 0-7 */
index b1c1773..f2fa60c 100644 (file)
@@ -10,7 +10,7 @@
  */
 #include <linux/rwsem.h>
 #include <linux/mutex.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/debug_locks.h>
 
index b525772..e262785 100644 (file)
@@ -1,4 +1,4 @@
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/atomic.h>
 
index 9676617..80b9c76 100644 (file)
@@ -1,7 +1,7 @@
 #include <linux/pci.h>
 #include <linux/io.h>
 #include <linux/gfp.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 void devm_ioremap_release(struct device *dev, void *res)
 {
index 5b49191..3ea2490 100644 (file)
@@ -16,7 +16,8 @@
  * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
 #include <linux/math64.h>
 
 /* Not needed on 64bit architectures */
index 53bff4c..42f4f55 100644 (file)
@@ -4,7 +4,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 void dump_stack(void)
 {
index b4801f5..6805453 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/stat.h>
 #include <linux/types.h>
 #include <linux/fs.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/stacktrace.h>
 #include <linux/fault-inject.h>
index d903959..91ca09f 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 #include <linux/bitops.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/types.h>
 #include <asm/byteorder.h>
 
index 4bd75a7..0cbfc0b 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/bitops.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/types.h>
 #include <asm/byteorder.h>
 
index 9b8b894..6948a66 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/flex_array.h>
 #include <linux/slab.h>
 #include <linux/stddef.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/reciprocal_div.h>
 
 struct flex_array_part {
index f879033..cce4f3c 100644 (file)
--- a/lib/gcd.c
+++ b/lib/gcd.c
@@ -1,6 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/gcd.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /* Greatest common divisor */
 unsigned long gcd(unsigned long a, unsigned long b)
index 85d0e41..8f8d543 100644 (file)
@@ -1,14 +1,29 @@
 #include <stdio.h>
+#include "../include/generated/autoconf.h"
 #include "crc32defs.h"
 #include <inttypes.h>
 
 #define ENTRIES_PER_LINE 4
 
-#define LE_TABLE_SIZE (1 << CRC_LE_BITS)
-#define BE_TABLE_SIZE (1 << CRC_BE_BITS)
+#if CRC_LE_BITS > 8
+# define LE_TABLE_ROWS (CRC_LE_BITS/8)
+# define LE_TABLE_SIZE 256
+#else
+# define LE_TABLE_ROWS 1
+# define LE_TABLE_SIZE (1 << CRC_LE_BITS)
+#endif
 
-static uint32_t crc32table_le[4][LE_TABLE_SIZE];
-static uint32_t crc32table_be[4][BE_TABLE_SIZE];
+#if CRC_BE_BITS > 8
+# define BE_TABLE_ROWS (CRC_BE_BITS/8)
+# define BE_TABLE_SIZE 256
+#else
+# define BE_TABLE_ROWS 1
+# define BE_TABLE_SIZE (1 << CRC_BE_BITS)
+#endif
+
+static uint32_t crc32table_le[LE_TABLE_ROWS][256];
+static uint32_t crc32table_be[BE_TABLE_ROWS][256];
+static uint32_t crc32ctable_le[LE_TABLE_ROWS][256];
 
 /**
  * crc32init_le() - allocate and initialize LE table data
@@ -17,27 +32,38 @@ static uint32_t crc32table_be[4][BE_TABLE_SIZE];
  * fact that crctable[i^j] = crctable[i] ^ crctable[j].
  *
  */
-static void crc32init_le(void)
+static void crc32init_le_generic(const uint32_t polynomial,
+                                uint32_t (*tab)[256])
 {
        unsigned i, j;
        uint32_t crc = 1;
 
-       crc32table_le[0][0] = 0;
+       tab[0][0] = 0;
 
-       for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
-               crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+       for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) {
+               crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
                for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
-                       crc32table_le[0][i + j] = crc ^ crc32table_le[0][j];
+                       tab[0][i + j] = crc ^ tab[0][j];
        }
        for (i = 0; i < LE_TABLE_SIZE; i++) {
-               crc = crc32table_le[0][i];
-               for (j = 1; j < 4; j++) {
-                       crc = crc32table_le[0][crc & 0xff] ^ (crc >> 8);
-                       crc32table_le[j][i] = crc;
+               crc = tab[0][i];
+               for (j = 1; j < LE_TABLE_ROWS; j++) {
+                       crc = tab[0][crc & 0xff] ^ (crc >> 8);
+                       tab[j][i] = crc;
                }
        }
 }
 
+static void crc32init_le(void)
+{
+       crc32init_le_generic(CRCPOLY_LE, crc32table_le);
+}
+
+static void crc32cinit_le(void)
+{
+       crc32init_le_generic(CRC32C_POLY_LE, crc32ctable_le);
+}
+
 /**
  * crc32init_be() - allocate and initialize BE table data
  */
@@ -55,18 +81,18 @@ static void crc32init_be(void)
        }
        for (i = 0; i < BE_TABLE_SIZE; i++) {
                crc = crc32table_be[0][i];
-               for (j = 1; j < 4; j++) {
+               for (j = 1; j < BE_TABLE_ROWS; j++) {
                        crc = crc32table_be[0][(crc >> 24) & 0xff] ^ (crc << 8);
                        crc32table_be[j][i] = crc;
                }
        }
 }
 
-static void output_table(uint32_t table[4][256], int len, char *trans)
+static void output_table(uint32_t (*table)[256], int rows, int len, char *trans)
 {
        int i, j;
 
-       for (j = 0 ; j < 4; j++) {
+       for (j = 0 ; j < rows; j++) {
                printf("{");
                for (i = 0; i < len - 1; i++) {
                        if (i % ENTRIES_PER_LINE == 0)
@@ -83,15 +109,30 @@ int main(int argc, char** argv)
 
        if (CRC_LE_BITS > 1) {
                crc32init_le();
-               printf("static const u32 crc32table_le[4][256] = {");
-               output_table(crc32table_le, LE_TABLE_SIZE, "tole");
+               printf("static const u32 __cacheline_aligned "
+                      "crc32table_le[%d][%d] = {",
+                      LE_TABLE_ROWS, LE_TABLE_SIZE);
+               output_table(crc32table_le, LE_TABLE_ROWS,
+                            LE_TABLE_SIZE, "tole");
                printf("};\n");
        }
 
        if (CRC_BE_BITS > 1) {
                crc32init_be();
-               printf("static const u32 crc32table_be[4][256] = {");
-               output_table(crc32table_be, BE_TABLE_SIZE, "tobe");
+               printf("static const u32 __cacheline_aligned "
+                      "crc32table_be[%d][%d] = {",
+                      BE_TABLE_ROWS, BE_TABLE_SIZE);
+               output_table(crc32table_be, LE_TABLE_ROWS,
+                            BE_TABLE_SIZE, "tobe");
+               printf("};\n");
+       }
+       if (CRC_LE_BITS > 1) {
+               crc32cinit_le();
+               printf("static const u32 __cacheline_aligned "
+                      "crc32ctable_le[%d][%d] = {",
+                      LE_TABLE_ROWS, LE_TABLE_SIZE);
+               output_table(crc32ctable_le, LE_TABLE_ROWS,
+                            LE_TABLE_SIZE, "tole");
                printf("};\n");
        }
 
index f352cc4..6bc04aa 100644 (file)
@@ -29,7 +29,7 @@
  */
 
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bitmap.h>
 #include <linux/rculist.h>
 #include <linux/interrupt.h>
index e11db26..66d0ee8 100644 (file)
@@ -1,5 +1,5 @@
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/cryptohash.h>
 
 /* F, G and H are basic MD4 functions: selection, majority, parity */
index 51d5ae2..6540d65 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/types.h>
 #include <linux/ctype.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 const char hex_asc[] = "0123456789abcdef";
 EXPORT_SYMBOL(hex_asc);
index 3c79d50..b7d81ba 100644 (file)
@@ -1,4 +1,4 @@
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bitops.h>
 #include <asm/types.h>
 
index 12499ba..4046e29 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -29,7 +29,7 @@
 #ifndef TEST                        // to test in user space...
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #endif
 #include <linux/err.h>
 #include <linux/string.h>
index fd355a9..fc2eeb7 100644 (file)
@@ -1,6 +1,6 @@
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /**
  * int_sqrt - rough approximation to sqrt
index ada922a..2c08f36 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/pci.h>
 #include <linux/io.h>
 
-#include <linux/module.h>
+#include <linux/export.h>
 
 /*
  * Read/write from/to an (offsettable) iomem cookie. It might be a PIO
index 864fc5e..4527e75 100644 (file)
@@ -15,7 +15,7 @@
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/io.h>
 
 /**
index da05331..c27e269 100644 (file)
@@ -2,8 +2,9 @@
  * IOMMU helper functions for the free area management
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bitmap.h>
+#include <linux/bug.h>
 
 int iommu_is_span_boundary(unsigned int index, unsigned int nr,
                           unsigned long shift,
index da4e2ad..0c9216c 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/cacheflush.h>
 #include <asm/pgtable.h>
 
index 753880a..9c0a1d7 100644 (file)
@@ -8,7 +8,8 @@
  * 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/export.h>
+#include <linux/percpu.h>
 #include <asm/irq_regs.h>
 
 #ifndef ARCH_HAS_OWN_IRQ_REGS
index 9c4233b..ae0de80 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #include <stdarg.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/string.h>
index 573d606..0874e41 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 #include <linux/klist.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/sched.h>
 
 /*
index c33d7a1..21dee7c 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/kobject.h>
 #include <linux/string.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/stat.h>
 #include <linux/slab.h>
 
index 75cbdb5..1a91efa 100644 (file)
@@ -17,7 +17,8 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/kobject.h>
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/kmod.h>
 #include <linux/slab.h>
 #include <linux/user_namespace.h>
 #include <linux/socket.h>
index b1dd3e7..c3615ea 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/math64.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/types.h>
 #include <asm/uaccess.h>
 #include "kstrtox.h"
index 10b5cfc..b9c8de4 100644 (file)
--- a/lib/lcm.c
+++ b/lib/lcm.c
@@ -1,6 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/gcd.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/lcm.h>
 
 /* Lowest common multiple */
index b8029a5..982b850 100644 (file)
@@ -6,8 +6,10 @@
  * DEBUG_LIST.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/list.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
 
 /*
  * Insert a new entry between two known consecutive entries.
index e429d27..4a15115 100644 (file)
@@ -23,7 +23,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/llist.h>
 
index 507a22f..7aae0f2 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
-#include <linux/module.h>
 #include <linux/lockdep.h>
 #include <linux/spinlock.h>
 #include <linux/kallsyms.h>
index c777180..958a3c1 100644 (file)
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -1,5 +1,5 @@
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/cryptohash.h>
 
 #define F1(x, y, z)    (z ^ (x & (y ^ z)))
index a8408b6..4226dfe 100644 (file)
@@ -5,7 +5,7 @@
  *                             Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/jiffies.h>
index dcbaaef..c434100 100644 (file)
@@ -6,7 +6,8 @@
  */
 
 #include <linux/ctype.h>
-#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/export.h>
 #include <linux/parser.h>
 #include <linux/slab.h>
 #include <linux/string.h>
index a0a4da4..6ab0e52 100644 (file)
@@ -23,6 +23,7 @@
  * information.
  */
 
+#include <linux/bug.h>
 #include <linux/plist.h>
 #include <linux/spinlock.h>
 
index ccfd850..8d443af 100644 (file)
@@ -85,6 +85,17 @@ static inline unsigned long prio_tree_maxindex(unsigned int bits)
        return index_bits_to_maxindex[bits - 1];
 }
 
+static void prio_set_parent(struct prio_tree_node *parent,
+                           struct prio_tree_node *child, bool left)
+{
+       if (left)
+               parent->left = child;
+       else
+               parent->right = child;
+
+       child->parent = parent;
+}
+
 /*
  * Extend a priority search tree so that it can store a node with heap_index
  * max_heap_index. In the worst case, this algorithm takes O((log n)^2).
@@ -94,45 +105,32 @@ static inline unsigned long prio_tree_maxindex(unsigned int bits)
 static struct prio_tree_node *prio_tree_expand(struct prio_tree_root *root,
                struct prio_tree_node *node, unsigned long max_heap_index)
 {
-       struct prio_tree_node *first = NULL, *prev, *last = NULL;
+       struct prio_tree_node *prev;
 
        if (max_heap_index > prio_tree_maxindex(root->index_bits))
                root->index_bits++;
 
+       prev = node;
+       INIT_PRIO_TREE_NODE(node);
+
        while (max_heap_index > prio_tree_maxindex(root->index_bits)) {
+               struct prio_tree_node *tmp = root->prio_tree_node;
+
                root->index_bits++;
 
                if (prio_tree_empty(root))
                        continue;
 
-               if (first == NULL) {
-                       first = root->prio_tree_node;
-                       prio_tree_remove(root, root->prio_tree_node);
-                       INIT_PRIO_TREE_NODE(first);
-                       last = first;
-               } else {
-                       prev = last;
-                       last = root->prio_tree_node;
-                       prio_tree_remove(root, root->prio_tree_node);
-                       INIT_PRIO_TREE_NODE(last);
-                       prev->left = last;
-                       last->parent = prev;
-               }
-       }
-
-       INIT_PRIO_TREE_NODE(node);
-
-       if (first) {
-               node->left = first;
-               first->parent = node;
-       } else
-               last = node;
+               prio_tree_remove(root, root->prio_tree_node);
+               INIT_PRIO_TREE_NODE(tmp);
 
-       if (!prio_tree_empty(root)) {
-               last->left = root->prio_tree_node;
-               last->left->parent = last;
+               prio_set_parent(prev, tmp, true);
+               prev = tmp;
        }
 
+       if (!prio_tree_empty(root))
+               prio_set_parent(prev, root->prio_tree_node, true);
+
        root->prio_tree_node = node;
        return node;
 }
@@ -151,25 +149,15 @@ struct prio_tree_node *prio_tree_replace(struct prio_tree_root *root,
                 * We can reduce root->index_bits here. However, it is complex
                 * and does not help much to improve performance (IMO).
                 */
-               node->parent = node;
                root->prio_tree_node = node;
-       } else {
-               node->parent = old->parent;
-               if (old->parent->left == old)
-                       old->parent->left = node;
-               else
-                       old->parent->right = node;
-       }
+       } else
+               prio_set_parent(old->parent, node, old->parent->left == old);
 
-       if (!prio_tree_left_empty(old)) {
-               node->left = old->left;
-               old->left->parent = node;
-       }
+       if (!prio_tree_left_empty(old))
+               prio_set_parent(node, old->left, true);
 
-       if (!prio_tree_right_empty(old)) {
-               node->right = old->right;
-               old->right->parent = node;
-       }
+       if (!prio_tree_right_empty(old))
+               prio_set_parent(node, old->right, false);
 
        return old;
 }
@@ -229,16 +217,14 @@ struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root,
                if (index & mask) {
                        if (prio_tree_right_empty(cur)) {
                                INIT_PRIO_TREE_NODE(node);
-                               cur->right = node;
-                               node->parent = cur;
+                               prio_set_parent(cur, node, false);
                                return res;
                        } else
                                cur = cur->right;
                } else {
                        if (prio_tree_left_empty(cur)) {
                                INIT_PRIO_TREE_NODE(node);
-                               cur->left = node;
-                               node->parent = cur;
+                               prio_set_parent(cur, node, true);
                                return res;
                        } else
                                cur = cur->left;
@@ -305,6 +291,40 @@ void prio_tree_remove(struct prio_tree_root *root, struct prio_tree_node *node)
                cur = prio_tree_replace(root, cur->parent, cur);
 }
 
+static void iter_walk_down(struct prio_tree_iter *iter)
+{
+       iter->mask >>= 1;
+       if (iter->mask) {
+               if (iter->size_level)
+                       iter->size_level++;
+               return;
+       }
+
+       if (iter->size_level) {
+               BUG_ON(!prio_tree_left_empty(iter->cur));
+               BUG_ON(!prio_tree_right_empty(iter->cur));
+               iter->size_level++;
+               iter->mask = ULONG_MAX;
+       } else {
+               iter->size_level = 1;
+               iter->mask = 1UL << (BITS_PER_LONG - 1);
+       }
+}
+
+static void iter_walk_up(struct prio_tree_iter *iter)
+{
+       if (iter->mask == ULONG_MAX)
+               iter->mask = 1UL;
+       else if (iter->size_level == 1)
+               iter->mask = 1UL;
+       else
+               iter->mask <<= 1;
+       if (iter->size_level)
+               iter->size_level--;
+       if (!iter->size_level && (iter->value & iter->mask))
+               iter->value ^= iter->mask;
+}
+
 /*
  * Following functions help to enumerate all prio_tree_nodes in the tree that
  * overlap with the input interval X [radix_index, heap_index]. The enumeration
@@ -323,21 +343,7 @@ static struct prio_tree_node *prio_tree_left(struct prio_tree_iter *iter,
 
        if (iter->r_index <= *h_index) {
                iter->cur = iter->cur->left;
-               iter->mask >>= 1;
-               if (iter->mask) {
-                       if (iter->size_level)
-                               iter->size_level++;
-               } else {
-                       if (iter->size_level) {
-                               BUG_ON(!prio_tree_left_empty(iter->cur));
-                               BUG_ON(!prio_tree_right_empty(iter->cur));
-                               iter->size_level++;
-                               iter->mask = ULONG_MAX;
-                       } else {
-                               iter->size_level = 1;
-                               iter->mask = 1UL << (BITS_PER_LONG - 1);
-                       }
-               }
+               iter_walk_down(iter);
                return iter->cur;
        }
 
@@ -364,22 +370,7 @@ static struct prio_tree_node *prio_tree_right(struct prio_tree_iter *iter,
 
        if (iter->r_index <= *h_index) {
                iter->cur = iter->cur->right;
-               iter->mask >>= 1;
-               iter->value = value;
-               if (iter->mask) {
-                       if (iter->size_level)
-                               iter->size_level++;
-               } else {
-                       if (iter->size_level) {
-                               BUG_ON(!prio_tree_left_empty(iter->cur));
-                               BUG_ON(!prio_tree_right_empty(iter->cur));
-                               iter->size_level++;
-                               iter->mask = ULONG_MAX;
-                       } else {
-                               iter->size_level = 1;
-                               iter->mask = 1UL << (BITS_PER_LONG - 1);
-                       }
-               }
+               iter_walk_down(iter);
                return iter->cur;
        }
 
@@ -389,16 +380,7 @@ static struct prio_tree_node *prio_tree_right(struct prio_tree_iter *iter,
 static struct prio_tree_node *prio_tree_parent(struct prio_tree_iter *iter)
 {
        iter->cur = iter->cur->parent;
-       if (iter->mask == ULONG_MAX)
-               iter->mask = 1UL;
-       else if (iter->size_level == 1)
-               iter->mask = 1UL;
-       else
-               iter->mask <<= 1;
-       if (iter->size_level)
-               iter->size_level--;
-       if (!iter->size_level && (iter->value & iter->mask))
-               iter->value ^= iter->mask;
+       iter_walk_up(iter);
        return iter->cur;
 }
 
index dc63d08..3e69c2b 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/radix-tree.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
index fc3545a..938bde5 100644 (file)
@@ -35,7 +35,7 @@
 
 #include <linux/types.h>
 #include <linux/percpu.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/jiffies.h>
 #include <linux/random.h>
 
index c96d500..40e03ea 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <linux/ratelimit.h>
 #include <linux/jiffies.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /*
  * __ratelimit - rate limiting
index 3ed247b..d326da3 100644 (file)
@@ -7,7 +7,8 @@
  */
 
 #include <linux/rational.h>
-#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/export.h>
 
 /*
  * calculate best rational approximation for a given fraction
index a16be19..d417556 100644 (file)
@@ -21,7 +21,7 @@
 */
 
 #include <linux/rbtree.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
 {
index f2393c2..7e0d6a5 100644 (file)
@@ -7,7 +7,7 @@
  */
 #include <linux/rwsem.h>
 #include <linux/sched.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 struct rwsem_waiter {
        struct list_head list;
index 410aa11..8337e1b 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/rwsem.h>
 #include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /*
  * Initialize an rwsem:
index 33b2cbb..6096e89 100644 (file)
@@ -6,7 +6,7 @@
  * This source code is licensed under the GNU General Public License,
  * Version 2. See the file COPYING for more details.
  */
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
 #include <linux/highmem.h>
index 1de509a..1df191e 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/bitops.h>
 #include <linux/cryptohash.h>
 #include <asm/unaligned.h>
index 503f087..4c0d0e5 100644 (file)
@@ -3,7 +3,7 @@
  *
  * DEBUG_PREEMPT variant of smp_processor_id().
  */
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kallsyms.h>
 #include <linux/sched.h>
 
index 5f3eacd..525d160 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/debug_locks.h>
 #include <linux/delay.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
                          struct lock_class_key *key)
index dc4a863..e5878de 100644 (file)
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
-#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
 
 #ifndef __HAVE_ARCH_STRNICMP
 /**
@@ -785,12 +788,24 @@ void *memchr_inv(const void *start, int c, size_t bytes)
        if (bytes <= 16)
                return check_bytes8(start, value, bytes);
 
-       value64 = value | value << 8 | value << 16 | value << 24;
-       value64 = (value64 & 0xffffffff) | value64 << 32;
-       prefix = 8 - ((unsigned long)start) % 8;
+       value64 = value;
+#if defined(ARCH_HAS_FAST_MULTIPLIER) && BITS_PER_LONG == 64
+       value64 *= 0x0101010101010101;
+#elif defined(ARCH_HAS_FAST_MULTIPLIER)
+       value64 *= 0x01010101;
+       value64 |= value64 << 32;
+#else
+       value64 |= value64 << 8;
+       value64 |= value64 << 16;
+       value64 |= value64 << 32;
+#endif
 
+       prefix = (unsigned long)start % 8;
        if (prefix) {
-               u8 *r = check_bytes8(start, value, prefix);
+               u8 *r;
+
+               prefix = 8 - prefix;
+               r = check_bytes8(start, value, prefix);
                if (r)
                        return r;
                start += prefix;
index ab431d4..dd4ece3 100644 (file)
@@ -5,7 +5,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/math64.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/string_helpers.h>
 
 /**
index d0f6315..414f46e 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/cache.h>
 #include <linux/dma-mapping.h>
 #include <linux/mm.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/swiotlb.h>
index a4f7067..58710ee 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/ptrace.h>
 #include <linux/sched.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/syscall.h>
 
 static int collect_syscall(struct task_struct *target, long *callno,
index 191176a..a382e4a 100644 (file)
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/bug.h>
 #include <linux/timerqueue.h>
 #include <linux/rbtree.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 /**
  * timerqueue_add - Adds timer to timerqueue.
index 8fadd7c..52a6fe6 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/uuid.h>
 #include <linux/random.h>
 
index 38e612e..abbabec 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 #include <stdarg.h>
-#include <linux/module.h>
+#include <linux/module.h>      /* for KSYM_SYMBOL_LEN */
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
@@ -212,6 +212,26 @@ char *put_dec(char *buf, unsigned long long num)
        }
 }
 
+/*
+ * Convert passed number to decimal string.
+ * Returns the length of string.  On buffer overflow, returns 0.
+ *
+ * If speed is not important, use snprintf(). It's easy to read the code.
+ */
+int num_to_str(char *buf, int size, unsigned long long num)
+{
+       char tmp[21];           /* Enough for 2^64 in decimal */
+       int idx, len;
+
+       len = put_dec(tmp, num) - tmp;
+
+       if (len > size)
+               return 0;
+       for (idx = 0; idx < len; ++idx)
+               buf[idx] = tmp[len - idx - 1];
+       return  len;
+}
+
 #define ZEROPAD        1               /* pad with zero */
 #define SIGN   2               /* unsigned/signed long */
 #define PLUS   4               /* show plus */
index afa057a..b8ce6f4 100644 (file)
@@ -2331,16 +2331,23 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
                if (huge_pmd_unshare(mm, &address, ptep))
                        continue;
 
+               pte = huge_ptep_get(ptep);
+               if (huge_pte_none(pte))
+                       continue;
+
+               /*
+                * HWPoisoned hugepage is already unmapped and dropped reference
+                */
+               if (unlikely(is_hugetlb_entry_hwpoisoned(pte)))
+                       continue;
+
+               page = pte_page(pte);
                /*
                 * If a reference page is supplied, it is because a specific
                 * page is being unmapped, not a range. Ensure the page we
                 * are about to unmap is the actual page of interest.
                 */
                if (ref_page) {
-                       pte = huge_ptep_get(ptep);
-                       if (huge_pte_none(pte))
-                               continue;
-                       page = pte_page(pte);
                        if (page != ref_page)
                                continue;
 
@@ -2353,16 +2360,6 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
                }
 
                pte = huge_ptep_get_and_clear(mm, address, ptep);
-               if (huge_pte_none(pte))
-                       continue;
-
-               /*
-                * HWPoisoned hugepage is already unmapped and dropped reference
-                */
-               if (unlikely(is_hugetlb_entry_hwpoisoned(pte)))
-                       continue;
-
-               page = pte_page(pte);
                if (pte_dirty(pte))
                        set_page_dirty(page);
                list_add(&page->lru, &page_list);
index f5ab745..1ccbba5 100644 (file)
@@ -65,6 +65,12 @@ static long madvise_behavior(struct vm_area_struct * vma,
                }
                new_flags &= ~VM_DONTCOPY;
                break;
+       case MADV_DONTDUMP:
+               new_flags |= VM_NODUMP;
+               break;
+       case MADV_DODUMP:
+               new_flags &= ~VM_NODUMP;
+               break;
        case MADV_MERGEABLE:
        case MADV_UNMERGEABLE:
                error = ksm_madvise(vma, start, end, behavior, &new_flags);
@@ -293,6 +299,8 @@ madvise_behavior_valid(int behavior)
        case MADV_HUGEPAGE:
        case MADV_NOHUGEPAGE:
 #endif
+       case MADV_DONTDUMP:
+       case MADV_DODUMP:
                return 1;
 
        default:
index 3416b6e..6105f47 100644 (file)
@@ -3623,13 +3623,7 @@ static int __init gate_vma_init(void)
        gate_vma.vm_end = FIXADDR_USER_END;
        gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
        gate_vma.vm_page_prot = __P101;
-       /*
-        * Make sure the vDSO gets into every core dump.
-        * Dumping its contents makes post-mortem fully interpretable later
-        * without matching up the same kernel and hardware config to see
-        * what PC values meant.
-        */
-       gate_vma.vm_flags |= VM_ALWAYSDUMP;
+
        return 0;
 }
 __initcall(gate_vma_init);
index 4198e00..46bf2ed 100644 (file)
@@ -521,11 +521,11 @@ static void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                        pr_err("Kill process %d (%s) sharing same memory\n",
                                task_pid_nr(p), p->comm);
                        task_unlock(p);
-                       force_sig(SIGKILL, p);
+                       do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true);
                }
 
        set_tsk_thread_flag(victim, TIF_MEMDIE);
-       force_sig(SIGKILL, victim);
+       do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, true);
 }
 #undef K
 
index 3fc2617..26adea8 100644 (file)
@@ -95,6 +95,8 @@ unsigned long vm_dirty_bytes;
  */
 unsigned int dirty_writeback_interval = 5 * 100; /* centiseconds */
 
+EXPORT_SYMBOL_GPL(dirty_writeback_interval);
+
 /*
  * The longest time for which data is allowed to remain dirty
  */
index 29c8716..e901a36 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1731,6 +1731,52 @@ static int __init cpucache_init(void)
 }
 __initcall(cpucache_init);
 
+static noinline void
+slab_out_of_memory(struct kmem_cache *cachep, gfp_t gfpflags, int nodeid)
+{
+       struct kmem_list3 *l3;
+       struct slab *slabp;
+       unsigned long flags;
+       int node;
+
+       printk(KERN_WARNING
+               "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);
+
+       for_each_online_node(node) {
+               unsigned long active_objs = 0, num_objs = 0, free_objects = 0;
+               unsigned long active_slabs = 0, num_slabs = 0;
+
+               l3 = cachep->nodelists[node];
+               if (!l3)
+                       continue;
+
+               spin_lock_irqsave(&l3->list_lock, flags);
+               list_for_each_entry(slabp, &l3->slabs_full, list) {
+                       active_objs += cachep->num;
+                       active_slabs++;
+               }
+               list_for_each_entry(slabp, &l3->slabs_partial, list) {
+                       active_objs += slabp->inuse;
+                       active_slabs++;
+               }
+               list_for_each_entry(slabp, &l3->slabs_free, list)
+                       num_slabs++;
+
+               free_objects += l3->free_objects;
+               spin_unlock_irqrestore(&l3->list_lock, flags);
+
+               num_slabs += active_slabs;
+               num_objs = num_slabs * cachep->num;
+               printk(KERN_WARNING
+                       "  node %d: slabs: %ld/%ld, objs: %ld/%ld, free: %ld\n",
+                       node, active_slabs, num_slabs, active_objs, num_objs,
+                       free_objects);
+       }
+}
+
 /*
  * Interface to system's page allocator. No need to hold the cache-lock.
  *
@@ -1757,8 +1803,11 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid)
                flags |= __GFP_RECLAIMABLE;
 
        page = alloc_pages_exact_node(nodeid, flags | __GFP_NOTRACK, cachep->gfporder);
-       if (!page)
+       if (!page) {
+               if (!(flags & __GFP_NOWARN) && printk_ratelimit())
+                       slab_out_of_memory(cachep, flags, nodeid);
                return NULL;
+       }
 
        nr_pages = (1 << cachep->gfporder);
        if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
@@ -3696,13 +3745,12 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp,
 
        if (likely(ac->avail < ac->limit)) {
                STATS_INC_FREEHIT(cachep);
-               ac->entry[ac->avail++] = objp;
-               return;
        } else {
                STATS_INC_FREEMISS(cachep);
                cache_flusharray(cachep, ac);
-               ac->entry[ac->avail++] = objp;
        }
+
+       ac->entry[ac->avail++] = objp;
 }
 
 /**
index f4a6229..64d9966 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -29,6 +29,7 @@
 #include <linux/math64.h>
 #include <linux/fault-inject.h>
 #include <linux/stacktrace.h>
+#include <linux/prefetch.h>
 
 #include <trace/events/kmem.h>
 
@@ -269,6 +270,11 @@ static inline void *get_freepointer(struct kmem_cache *s, void *object)
        return *(void **)(object + s->offset);
 }
 
+static void prefetch_freepointer(const struct kmem_cache *s, void *object)
+{
+       prefetch(object + s->offset);
+}
+
 static inline void *get_freepointer_safe(struct kmem_cache *s, void *object)
 {
        void *p;
@@ -1560,6 +1566,7 @@ static void *get_partial_node(struct kmem_cache *s,
                } else {
                        page->freelist = t;
                        available = put_cpu_partial(s, page, 0);
+                       stat(s, CPU_PARTIAL_NODE);
                }
                if (kmem_cache_debug(s) || available > s->cpu_partial / 2)
                        break;
@@ -1983,6 +1990,7 @@ int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
                                local_irq_restore(flags);
                                pobjects = 0;
                                pages = 0;
+                               stat(s, CPU_PARTIAL_DRAIN);
                        }
                }
 
@@ -1994,7 +2002,6 @@ int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
                page->next = oldpage;
 
        } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page) != oldpage);
-       stat(s, CPU_PARTIAL_FREE);
        return pobjects;
 }
 
@@ -2319,6 +2326,8 @@ redo:
                object = __slab_alloc(s, gfpflags, node, addr, c);
 
        else {
+               void *next_object = get_freepointer_safe(s, object);
+
                /*
                 * The cmpxchg will only match if there was no additional
                 * operation and if we are on the right processor.
@@ -2334,11 +2343,12 @@ redo:
                if (unlikely(!this_cpu_cmpxchg_double(
                                s->cpu_slab->freelist, s->cpu_slab->tid,
                                object, tid,
-                               get_freepointer_safe(s, object), next_tid(tid)))) {
+                               next_object, next_tid(tid)))) {
 
                        note_cmpxchg_failure("slab_alloc", s, tid);
                        goto redo;
                }
+               prefetch_freepointer(s, next_object);
                stat(s, ALLOC_FASTPATH);
        }
 
@@ -2475,9 +2485,10 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                 * If we just froze the page then put it onto the
                 * per cpu partial list.
                 */
-               if (new.frozen && !was_frozen)
+               if (new.frozen && !was_frozen) {
                        put_cpu_partial(s, page, 1);
-
+                       stat(s, CPU_PARTIAL_FREE);
+               }
                /*
                 * The list lock was not taken therefore no list
                 * activity can be necessary.
@@ -3939,13 +3950,14 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
                if (kmem_cache_open(s, n,
                                size, align, flags, ctor)) {
                        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;
                        }
-                       up_write(&slub_lock);
                        return s;
                }
                kfree(n);
@@ -5069,6 +5081,8 @@ STAT_ATTR(CMPXCHG_DOUBLE_CPU_FAIL, cmpxchg_double_cpu_fail);
 STAT_ATTR(CMPXCHG_DOUBLE_FAIL, cmpxchg_double_fail);
 STAT_ATTR(CPU_PARTIAL_ALLOC, cpu_partial_alloc);
 STAT_ATTR(CPU_PARTIAL_FREE, cpu_partial_free);
+STAT_ATTR(CPU_PARTIAL_NODE, cpu_partial_node);
+STAT_ATTR(CPU_PARTIAL_DRAIN, cpu_partial_drain);
 #endif
 
 static struct attribute *slab_attrs[] = {
@@ -5134,6 +5148,8 @@ static struct attribute *slab_attrs[] = {
        &cmpxchg_double_cpu_fail_attr.attr,
        &cpu_partial_alloc_attr.attr,
        &cpu_partial_free_attr.attr,
+       &cpu_partial_node_attr.attr,
+       &cpu_partial_drain_attr.attr,
 #endif
 #ifdef CONFIG_FAILSLAB
        &failslab_attr.attr,
index 49f15ef..33c332b 100644 (file)
@@ -2817,7 +2817,7 @@ loop_again:
                                testorder = 0;
 
                        if ((buffer_heads_over_limit && is_highmem_idx(i)) ||
-                                   !zone_watermark_ok_safe(zone, order,
+                                   !zone_watermark_ok_safe(zone, testorder,
                                        high_wmark_pages(zone) + balance_gap,
                                        end_zone, 0)) {
                                shrink_zone(priority, zone, &sc);
@@ -2946,7 +2946,8 @@ out:
                                continue;
 
                        /* Would compaction fail due to lack of free memory? */
-                       if (compaction_suitable(zone, order) == COMPACT_SKIPPED)
+                       if (COMPACTION_BUILD &&
+                           compaction_suitable(zone, order) == COMPACT_SKIPPED)
                                goto loop_again;
 
                        /* Confirm the zone is balanced for order-0 */
index 776618c..b23a17c 100644 (file)
@@ -740,10 +740,18 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
                        c->status = Disconnected;
                goto reterr;
        }
+again:
        /* Wait for the response */
        err = wait_event_interruptible(*req->wq,
                                       req->status >= REQ_STATUS_RCVD);
 
+       if ((err == -ERESTARTSYS) && (c->status == Connected)
+                                 && (type == P9_TFLUSH)) {
+               sigpending = 1;
+               clear_thread_flag(TIF_SIGPENDING);
+               goto again;
+       }
+
        if (req->status == REQ_STATUS_ERROR) {
                p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
                err = req->t_err;
@@ -1420,6 +1428,7 @@ int p9_client_clunk(struct p9_fid *fid)
        int err;
        struct p9_client *clnt;
        struct p9_req_t *req;
+       int retries = 0;
 
        if (!fid) {
                pr_warn("%s (%d): Trying to clunk with NULL fid\n",
@@ -1428,7 +1437,9 @@ int p9_client_clunk(struct p9_fid *fid)
                return 0;
        }
 
-       p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
+again:
+       p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d (try %d)\n", fid->fid,
+                                                               retries);
        err = 0;
        clnt = fid->clnt;
 
@@ -1444,8 +1455,14 @@ int p9_client_clunk(struct p9_fid *fid)
 error:
        /*
         * Fid is not valid even after a failed clunk
+        * If interrupted, retry once then give up and
+        * leak fid until umount.
         */
-       p9_fid_destroy(fid);
+       if (err == -ERESTARTSYS) {
+               if (retries++ == 0)
+                       goto again;
+       } else
+               p9_fid_destroy(fid);
        return err;
 }
 EXPORT_SYMBOL(p9_client_clunk);
@@ -1470,7 +1487,10 @@ int p9_client_remove(struct p9_fid *fid)
 
        p9_free_req(clnt, req);
 error:
-       p9_fid_destroy(fid);
+       if (err == -ERESTARTSYS)
+               p9_client_clunk(fid);
+       else
+               p9_fid_destroy(fid);
        return err;
 }
 EXPORT_SYMBOL(p9_client_remove);
index 761ad9d..cc91319 100644 (file)
@@ -201,7 +201,9 @@ enum {
        Opt_ip,
        Opt_last_string,
        /* string args above */
+       Opt_share,
        Opt_noshare,
+       Opt_crc,
        Opt_nocrc,
 };
 
@@ -217,7 +219,9 @@ static match_table_t opt_tokens = {
        {Opt_key, "key=%s"},
        {Opt_ip, "ip=%s"},
        /* string args above */
+       {Opt_share, "share"},
        {Opt_noshare, "noshare"},
+       {Opt_crc, "crc"},
        {Opt_nocrc, "nocrc"},
        {-1, NULL}
 };
@@ -277,10 +281,11 @@ out:
        return err;
 }
 
-int ceph_parse_options(struct ceph_options **popt, char *options,
-                      const char *dev_name, const char *dev_name_end,
-                      int (*parse_extra_token)(char *c, void *private),
-                      void *private)
+struct ceph_options *
+ceph_parse_options(char *options, const char *dev_name,
+                       const char *dev_name_end,
+                       int (*parse_extra_token)(char *c, void *private),
+                       void *private)
 {
        struct ceph_options *opt;
        const char *c;
@@ -289,7 +294,7 @@ int ceph_parse_options(struct ceph_options **popt, char *options,
 
        opt = kzalloc(sizeof(*opt), GFP_KERNEL);
        if (!opt)
-               return err;
+               return ERR_PTR(-ENOMEM);
        opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
                                GFP_KERNEL);
        if (!opt->mon_addr)
@@ -398,10 +403,16 @@ int ceph_parse_options(struct ceph_options **popt, char *options,
                        opt->mount_timeout = intval;
                        break;
 
+               case Opt_share:
+                       opt->flags &= ~CEPH_OPT_NOSHARE;
+                       break;
                case Opt_noshare:
                        opt->flags |= CEPH_OPT_NOSHARE;
                        break;
 
+               case Opt_crc:
+                       opt->flags &= ~CEPH_OPT_NOCRC;
+                       break;
                case Opt_nocrc:
                        opt->flags |= CEPH_OPT_NOCRC;
                        break;
@@ -412,12 +423,11 @@ int ceph_parse_options(struct ceph_options **popt, char *options,
        }
 
        /* success */
-       *popt = opt;
-       return 0;
+       return opt;
 
 out:
        ceph_destroy_options(opt);
-       return err;
+       return ERR_PTR(err);
 }
 EXPORT_SYMBOL(ceph_parse_options);
 
index ad5b708..f0993af 100644 (file)
@@ -38,48 +38,54 @@ static char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE;
 static struct lock_class_key socket_class;
 #endif
 
+/*
+ * When skipping (ignoring) a block of input we read it into a "skip
+ * buffer," which is this many bytes in size.
+ */
+#define SKIP_BUF_SIZE  1024
 
 static void queue_con(struct ceph_connection *con);
 static void con_work(struct work_struct *);
 static void ceph_fault(struct ceph_connection *con);
 
 /*
- * nicely render a sockaddr as a string.
+ * Nicely render a sockaddr as a string.  An array of formatted
+ * strings is used, to approximate reentrancy.
  */
-#define MAX_ADDR_STR 20
-#define MAX_ADDR_STR_LEN 60
-static char addr_str[MAX_ADDR_STR][MAX_ADDR_STR_LEN];
-static DEFINE_SPINLOCK(addr_str_lock);
-static int last_addr_str;
+#define ADDR_STR_COUNT_LOG     5       /* log2(# address strings in array) */
+#define ADDR_STR_COUNT         (1 << ADDR_STR_COUNT_LOG)
+#define ADDR_STR_COUNT_MASK    (ADDR_STR_COUNT - 1)
+#define MAX_ADDR_STR_LEN       64      /* 54 is enough */
+
+static char addr_str[ADDR_STR_COUNT][MAX_ADDR_STR_LEN];
+static atomic_t addr_str_seq = ATOMIC_INIT(0);
+
+static struct page *zero_page;         /* used in certain error cases */
 
 const char *ceph_pr_addr(const struct sockaddr_storage *ss)
 {
        int i;
        char *s;
-       struct sockaddr_in *in4 = (void *)ss;
-       struct sockaddr_in6 *in6 = (void *)ss;
-
-       spin_lock(&addr_str_lock);
-       i = last_addr_str++;
-       if (last_addr_str == MAX_ADDR_STR)
-               last_addr_str = 0;
-       spin_unlock(&addr_str_lock);
+       struct sockaddr_in *in4 = (struct sockaddr_in *) ss;
+       struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) ss;
+
+       i = atomic_inc_return(&addr_str_seq) & ADDR_STR_COUNT_MASK;
        s = addr_str[i];
 
        switch (ss->ss_family) {
        case AF_INET:
-               snprintf(s, MAX_ADDR_STR_LEN, "%pI4:%u", &in4->sin_addr,
-                        (unsigned int)ntohs(in4->sin_port));
+               snprintf(s, MAX_ADDR_STR_LEN, "%pI4:%hu", &in4->sin_addr,
+                        ntohs(in4->sin_port));
                break;
 
        case AF_INET6:
-               snprintf(s, MAX_ADDR_STR_LEN, "[%pI6c]:%u", &in6->sin6_addr,
-                        (unsigned int)ntohs(in6->sin6_port));
+               snprintf(s, MAX_ADDR_STR_LEN, "[%pI6c]:%hu", &in6->sin6_addr,
+                        ntohs(in6->sin6_port));
                break;
 
        default:
-               snprintf(s, MAX_ADDR_STR_LEN, "(unknown sockaddr family %d)",
-                        (int)ss->ss_family);
+               snprintf(s, MAX_ADDR_STR_LEN, "(unknown sockaddr family %hu)",
+                        ss->ss_family);
        }
 
        return s;
@@ -95,22 +101,43 @@ static void encode_my_addr(struct ceph_messenger *msgr)
 /*
  * work queue for all reading and writing to/from the socket.
  */
-struct workqueue_struct *ceph_msgr_wq;
+static struct workqueue_struct *ceph_msgr_wq;
+
+void _ceph_msgr_exit(void)
+{
+       if (ceph_msgr_wq) {
+               destroy_workqueue(ceph_msgr_wq);
+               ceph_msgr_wq = NULL;
+       }
+
+       BUG_ON(zero_page == NULL);
+       kunmap(zero_page);
+       page_cache_release(zero_page);
+       zero_page = NULL;
+}
 
 int ceph_msgr_init(void)
 {
+       BUG_ON(zero_page != NULL);
+       zero_page = ZERO_PAGE(0);
+       page_cache_get(zero_page);
+
        ceph_msgr_wq = alloc_workqueue("ceph-msgr", WQ_NON_REENTRANT, 0);
-       if (!ceph_msgr_wq) {
-               pr_err("msgr_init failed to create workqueue\n");
-               return -ENOMEM;
-       }
-       return 0;
+       if (ceph_msgr_wq)
+               return 0;
+
+       pr_err("msgr_init failed to create workqueue\n");
+       _ceph_msgr_exit();
+
+       return -ENOMEM;
 }
 EXPORT_SYMBOL(ceph_msgr_init);
 
 void ceph_msgr_exit(void)
 {
-       destroy_workqueue(ceph_msgr_wq);
+       BUG_ON(ceph_msgr_wq == NULL);
+
+       _ceph_msgr_exit();
 }
 EXPORT_SYMBOL(ceph_msgr_exit);
 
@@ -128,8 +155,8 @@ EXPORT_SYMBOL(ceph_msgr_flush);
 /* data available on socket, or listen socket received a connect */
 static void ceph_data_ready(struct sock *sk, int count_unused)
 {
-       struct ceph_connection *con =
-               (struct ceph_connection *)sk->sk_user_data;
+       struct ceph_connection *con = sk->sk_user_data;
+
        if (sk->sk_state != TCP_CLOSE_WAIT) {
                dout("ceph_data_ready on %p state = %lu, queueing work\n",
                     con, con->state);
@@ -140,26 +167,30 @@ static void ceph_data_ready(struct sock *sk, int count_unused)
 /* socket has buffer space for writing */
 static void ceph_write_space(struct sock *sk)
 {
-       struct ceph_connection *con =
-               (struct ceph_connection *)sk->sk_user_data;
+       struct ceph_connection *con = sk->sk_user_data;
 
-       /* only queue to workqueue if there is data we want to write. */
+       /* 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()
+        * 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)) {
-               dout("ceph_write_space %p queueing write work\n", con);
-               queue_con(con);
+               if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
+                       dout("ceph_write_space %p queueing write work\n", con);
+                       clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+                       queue_con(con);
+               }
        } else {
                dout("ceph_write_space %p nothing to write\n", con);
        }
-
-       /* since we have our own write_space, clear the SOCK_NOSPACE flag */
-       clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
 }
 
 /* socket's state has changed */
 static void ceph_state_change(struct sock *sk)
 {
-       struct ceph_connection *con =
-               (struct ceph_connection *)sk->sk_user_data;
+       struct ceph_connection *con = sk->sk_user_data;
 
        dout("ceph_state_change %p state = %lu sk_state = %u\n",
             con, con->state, sk->sk_state);
@@ -184,6 +215,8 @@ static void ceph_state_change(struct sock *sk)
                dout("ceph_state_change TCP_ESTABLISHED\n");
                queue_con(con);
                break;
+       default:        /* Everything else is uninteresting */
+               break;
        }
 }
 
@@ -194,7 +227,7 @@ static void set_sock_callbacks(struct socket *sock,
                               struct ceph_connection *con)
 {
        struct sock *sk = sock->sk;
-       sk->sk_user_data = (void *)con;
+       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;
@@ -208,7 +241,7 @@ static void set_sock_callbacks(struct socket *sock,
 /*
  * initiate connection to a remote socket.
  */
-static struct socket *ceph_tcp_connect(struct ceph_connection *con)
+static int ceph_tcp_connect(struct ceph_connection *con)
 {
        struct sockaddr_storage *paddr = &con->peer_addr.in_addr;
        struct socket *sock;
@@ -218,8 +251,7 @@ static struct socket *ceph_tcp_connect(struct ceph_connection *con)
        ret = sock_create_kern(con->peer_addr.in_addr.ss_family, SOCK_STREAM,
                               IPPROTO_TCP, &sock);
        if (ret)
-               return ERR_PTR(ret);
-       con->sock = sock;
+               return ret;
        sock->sk->sk_allocation = GFP_NOFS;
 
 #ifdef CONFIG_LOCKDEP
@@ -236,19 +268,17 @@ static struct socket *ceph_tcp_connect(struct ceph_connection *con)
                dout("connect %s EINPROGRESS sk_state = %u\n",
                     ceph_pr_addr(&con->peer_addr.in_addr),
                     sock->sk->sk_state);
-               ret = 0;
-       }
-       if (ret < 0) {
+       } else if (ret < 0) {
                pr_err("connect %s error %d\n",
                       ceph_pr_addr(&con->peer_addr.in_addr), ret);
                sock_release(sock);
-               con->sock = NULL;
                con->error_msg = "connect error";
+
+               return ret;
        }
+       con->sock = sock;
 
-       if (ret < 0)
-               return ERR_PTR(ret);
-       return sock;
+       return 0;
 }
 
 static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len)
@@ -284,6 +314,19 @@ static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov,
        return r;
 }
 
+static int ceph_tcp_sendpage(struct socket *sock, struct page *page,
+                    int offset, size_t size, int more)
+{
+       int flags = MSG_DONTWAIT | MSG_NOSIGNAL | (more ? MSG_MORE : MSG_EOR);
+       int ret;
+
+       ret = kernel_sendpage(sock, page, offset, size, flags);
+       if (ret == -EAGAIN)
+               ret = 0;
+
+       return ret;
+}
+
 
 /*
  * Shutdown/close the socket for the given connection.
@@ -391,22 +434,23 @@ bool ceph_con_opened(struct ceph_connection *con)
  */
 struct ceph_connection *ceph_con_get(struct ceph_connection *con)
 {
-       dout("con_get %p nref = %d -> %d\n", con,
-            atomic_read(&con->nref), atomic_read(&con->nref) + 1);
-       if (atomic_inc_not_zero(&con->nref))
-               return con;
-       return NULL;
+       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)
 {
-       dout("con_put %p nref = %d -> %d\n", con,
-            atomic_read(&con->nref), atomic_read(&con->nref) - 1);
-       BUG_ON(atomic_read(&con->nref) == 0);
-       if (atomic_dec_and_test(&con->nref)) {
+       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);
 }
 
 /*
@@ -442,14 +486,35 @@ static u32 get_global_seq(struct ceph_messenger *msgr, u32 gt)
        return ret;
 }
 
+static void ceph_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,
+                               size_t size, void *data)
+{
+       int index;
+
+       index = con->out_kvec_left;
+       BUG_ON(index >= ARRAY_SIZE(con->out_kvec));
+
+       con->out_kvec[index].iov_len = size;
+       con->out_kvec[index].iov_base = data;
+       con->out_kvec_left++;
+       con->out_kvec_bytes += size;
+}
 
 /*
  * Prepare footer for currently outgoing message, and finish things
  * off.  Assumes out_kvec* are already valid.. we just add on to the end.
  */
-static void prepare_write_message_footer(struct ceph_connection *con, int v)
+static void prepare_write_message_footer(struct ceph_connection *con)
 {
        struct ceph_msg *m = con->out_msg;
+       int v = con->out_kvec_left;
 
        dout("prepare_write_message_footer %p\n", con);
        con->out_kvec_is_msg = true;
@@ -467,9 +532,9 @@ static void prepare_write_message_footer(struct ceph_connection *con, int v)
 static void prepare_write_message(struct ceph_connection *con)
 {
        struct ceph_msg *m;
-       int v = 0;
+       u32 crc;
 
-       con->out_kvec_bytes = 0;
+       ceph_con_out_kvec_reset(con);
        con->out_kvec_is_msg = true;
        con->out_msg_done = false;
 
@@ -477,16 +542,13 @@ 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;
-               con->out_kvec[v].iov_base = &tag_ack;
-               con->out_kvec[v++].iov_len = 1;
+               ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
                con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
-               con->out_kvec[v].iov_base = &con->out_temp_ack;
-               con->out_kvec[v++].iov_len = sizeof(con->out_temp_ack);
-               con->out_kvec_bytes = 1 + sizeof(con->out_temp_ack);
+               ceph_con_out_kvec_add(con, sizeof (con->out_temp_ack),
+                       &con->out_temp_ack);
        }
 
-       m = list_first_entry(&con->out_queue,
-                      struct ceph_msg, list_head);
+       m = list_first_entry(&con->out_queue, struct ceph_msg, list_head);
        con->out_msg = m;
 
        /* put message on sent list */
@@ -510,30 +572,26 @@ 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 */
-       con->out_kvec[v].iov_base = &tag_msg;
-       con->out_kvec[v++].iov_len = 1;
-       con->out_kvec[v].iov_base = &m->hdr;
-       con->out_kvec[v++].iov_len = sizeof(m->hdr);
-       con->out_kvec[v++] = m->front;
+       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);
+
        if (m->middle)
-               con->out_kvec[v++] = m->middle->vec;
-       con->out_kvec_left = v;
-       con->out_kvec_bytes += 1 + sizeof(m->hdr) + m->front.iov_len +
-               (m->middle ? m->middle->vec.iov_len : 0);
-       con->out_kvec_cur = con->out_kvec;
+               ceph_con_out_kvec_add(con, m->middle->vec.iov_len,
+                       m->middle->vec.iov_base);
 
        /* fill in crc (except data pages), footer */
-       con->out_msg->hdr.crc =
-               cpu_to_le32(crc32c(0, (void *)&m->hdr,
-                                     sizeof(m->hdr) - sizeof(m->hdr.crc)));
+       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.front_crc =
-               cpu_to_le32(crc32c(0, m->front.iov_base, m->front.iov_len));
-       if (m->middle)
-               con->out_msg->footer.middle_crc =
-                       cpu_to_le32(crc32c(0, m->middle->vec.iov_base,
-                                          m->middle->vec.iov_len));
-       else
+
+       crc = crc32c(0, m->front.iov_base, m->front.iov_len);
+       con->out_msg->footer.front_crc = cpu_to_le32(crc);
+       if (m->middle) {
+               crc = crc32c(0, m->middle->vec.iov_base,
+                               m->middle->vec.iov_len);
+               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",
@@ -549,11 +607,11 @@ static void prepare_write_message(struct ceph_connection *con)
                else
                        con->out_msg_pos.page_pos = 0;
                con->out_msg_pos.data_pos = 0;
-               con->out_msg_pos.did_page_crc = 0;
+               con->out_msg_pos.did_page_crc = false;
                con->out_more = 1;  /* data + footer will follow */
        } else {
                /* no, queue up footer too and be done */
-               prepare_write_message_footer(con, v);
+               prepare_write_message_footer(con);
        }
 
        set_bit(WRITE_PENDING, &con->state);
@@ -568,14 +626,14 @@ static void prepare_write_ack(struct ceph_connection *con)
             con->in_seq_acked, con->in_seq);
        con->in_seq_acked = con->in_seq;
 
-       con->out_kvec[0].iov_base = &tag_ack;
-       con->out_kvec[0].iov_len = 1;
+       ceph_con_out_kvec_reset(con);
+
+       ceph_con_out_kvec_add(con, sizeof (tag_ack), &tag_ack);
+
        con->out_temp_ack = cpu_to_le64(con->in_seq_acked);
-       con->out_kvec[1].iov_base = &con->out_temp_ack;
-       con->out_kvec[1].iov_len = sizeof(con->out_temp_ack);
-       con->out_kvec_left = 2;
-       con->out_kvec_bytes = 1 + sizeof(con->out_temp_ack);
-       con->out_kvec_cur = con->out_kvec;
+       ceph_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);
 }
@@ -586,11 +644,8 @@ 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);
-       con->out_kvec[0].iov_base = &tag_keepalive;
-       con->out_kvec[0].iov_len = 1;
-       con->out_kvec_left = 1;
-       con->out_kvec_bytes = 1;
-       con->out_kvec_cur = con->out_kvec;
+       ceph_con_out_kvec_reset(con);
+       ceph_con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive);
        set_bit(WRITE_PENDING, &con->state);
 }
 
@@ -619,12 +674,9 @@ static int prepare_connect_authorizer(struct ceph_connection *con)
        con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol);
        con->out_connect.authorizer_len = cpu_to_le32(auth_len);
 
-       if (auth_len) {
-               con->out_kvec[con->out_kvec_left].iov_base = auth_buf;
-               con->out_kvec[con->out_kvec_left].iov_len = auth_len;
-               con->out_kvec_left++;
-               con->out_kvec_bytes += auth_len;
-       }
+       if (auth_len)
+               ceph_con_out_kvec_add(con, auth_len, auth_buf);
+
        return 0;
 }
 
@@ -634,22 +686,18 @@ static int prepare_connect_authorizer(struct ceph_connection *con)
 static void prepare_write_banner(struct ceph_messenger *msgr,
                                 struct ceph_connection *con)
 {
-       int len = strlen(CEPH_BANNER);
+       ceph_con_out_kvec_reset(con);
+       ceph_con_out_kvec_add(con, strlen(CEPH_BANNER), CEPH_BANNER);
+       ceph_con_out_kvec_add(con, sizeof (msgr->my_enc_addr),
+                                       &msgr->my_enc_addr);
 
-       con->out_kvec[0].iov_base = CEPH_BANNER;
-       con->out_kvec[0].iov_len = len;
-       con->out_kvec[1].iov_base = &msgr->my_enc_addr;
-       con->out_kvec[1].iov_len = sizeof(msgr->my_enc_addr);
-       con->out_kvec_left = 2;
-       con->out_kvec_bytes = len + sizeof(msgr->my_enc_addr);
-       con->out_kvec_cur = con->out_kvec;
        con->out_more = 0;
        set_bit(WRITE_PENDING, &con->state);
 }
 
 static int prepare_write_connect(struct ceph_messenger *msgr,
                                 struct ceph_connection *con,
-                                int after_banner)
+                                int include_banner)
 {
        unsigned global_seq = get_global_seq(con->msgr, 0);
        int proto;
@@ -678,22 +726,18 @@ static int prepare_write_connect(struct ceph_messenger *msgr,
        con->out_connect.protocol_version = cpu_to_le32(proto);
        con->out_connect.flags = 0;
 
-       if (!after_banner) {
-               con->out_kvec_left = 0;
-               con->out_kvec_bytes = 0;
-       }
-       con->out_kvec[con->out_kvec_left].iov_base = &con->out_connect;
-       con->out_kvec[con->out_kvec_left].iov_len = sizeof(con->out_connect);
-       con->out_kvec_left++;
-       con->out_kvec_bytes += sizeof(con->out_connect);
-       con->out_kvec_cur = con->out_kvec;
+       if (include_banner)
+               prepare_write_banner(msgr, con);
+       else
+               ceph_con_out_kvec_reset(con);
+       ceph_con_out_kvec_add(con, sizeof (con->out_connect), &con->out_connect);
+
        con->out_more = 0;
        set_bit(WRITE_PENDING, &con->state);
 
        return prepare_connect_authorizer(con);
 }
 
-
 /*
  * write as much of pending kvecs to the socket as we can.
  *  1 -> done
@@ -714,17 +758,18 @@ static int write_partial_kvec(struct ceph_connection *con)
                con->out_kvec_bytes -= ret;
                if (con->out_kvec_bytes == 0)
                        break;            /* done */
-               while (ret > 0) {
-                       if (ret >= con->out_kvec_cur->iov_len) {
-                               ret -= con->out_kvec_cur->iov_len;
-                               con->out_kvec_cur++;
-                               con->out_kvec_left--;
-                       } else {
-                               con->out_kvec_cur->iov_len -= ret;
-                               con->out_kvec_cur->iov_base += ret;
-                               ret = 0;
-                               break;
-                       }
+
+               /* account for full iov entries consumed */
+               while (ret >= con->out_kvec_cur->iov_len) {
+                       BUG_ON(!con->out_kvec_left);
+                       ret -= con->out_kvec_cur->iov_len;
+                       con->out_kvec_cur++;
+                       con->out_kvec_left--;
+               }
+               /* and for a partially-consumed entry */
+               if (ret) {
+                       con->out_kvec_cur->iov_len -= ret;
+                       con->out_kvec_cur->iov_base += ret;
                }
        }
        con->out_kvec_left = 0;
@@ -773,7 +818,7 @@ static int write_partial_msg_pages(struct ceph_connection *con)
        struct ceph_msg *msg = con->out_msg;
        unsigned data_len = le32_to_cpu(msg->hdr.data_len);
        size_t len;
-       int crc = con->msgr->nocrc;
+       bool do_datacrc = !con->msgr->nocrc;
        int ret;
        int total_max_write;
        int in_trail = 0;
@@ -790,9 +835,8 @@ static int write_partial_msg_pages(struct ceph_connection *con)
 
        while (data_len > con->out_msg_pos.data_pos) {
                struct page *page = NULL;
-               void *kaddr = NULL;
                int max_write = PAGE_SIZE;
-               int page_shift = 0;
+               int bio_offset = 0;
 
                total_max_write = data_len - trail_len -
                        con->out_msg_pos.data_pos;
@@ -811,58 +855,47 @@ static int write_partial_msg_pages(struct ceph_connection *con)
 
                        page = list_first_entry(&msg->trail->head,
                                                struct page, lru);
-                       if (crc)
-                               kaddr = kmap(page);
                        max_write = PAGE_SIZE;
                } else if (msg->pages) {
                        page = msg->pages[con->out_msg_pos.page];
-                       if (crc)
-                               kaddr = kmap(page);
                } else if (msg->pagelist) {
                        page = list_first_entry(&msg->pagelist->head,
                                                struct page, lru);
-                       if (crc)
-                               kaddr = kmap(page);
 #ifdef CONFIG_BLOCK
                } else if (msg->bio) {
                        struct bio_vec *bv;
 
                        bv = bio_iovec_idx(msg->bio_iter, msg->bio_seg);
                        page = bv->bv_page;
-                       page_shift = bv->bv_offset;
-                       if (crc)
-                               kaddr = kmap(page) + page_shift;
+                       bio_offset = bv->bv_offset;
                        max_write = bv->bv_len;
 #endif
                } else {
-                       page = con->msgr->zero_page;
-                       if (crc)
-                               kaddr = page_address(con->msgr->zero_page);
+                       page = zero_page;
                }
                len = min_t(int, max_write - con->out_msg_pos.page_pos,
                            total_max_write);
 
-               if (crc && !con->out_msg_pos.did_page_crc) {
-                       void *base = kaddr + con->out_msg_pos.page_pos;
+               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);
+                       char *kaddr;
 
+                       kaddr = kmap(page);
                        BUG_ON(kaddr == NULL);
-                       con->out_msg->footer.data_crc =
-                               cpu_to_le32(crc32c(tmpcrc, base, len));
-                       con->out_msg_pos.did_page_crc = 1;
+                       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);
+                       con->out_msg_pos.did_page_crc = true;
                }
-               ret = kernel_sendpage(con->sock, page,
-                                     con->out_msg_pos.page_pos + page_shift,
-                                     len,
-                                     MSG_DONTWAIT | MSG_NOSIGNAL |
-                                     MSG_MORE);
-
-               if (crc &&
-                   (msg->pages || msg->pagelist || msg->bio || in_trail))
+               ret = ceph_tcp_sendpage(con->sock, page,
+                                     con->out_msg_pos.page_pos + bio_offset,
+                                     len, 1);
+
+               if (do_datacrc)
                        kunmap(page);
 
-               if (ret == -EAGAIN)
-                       ret = 0;
                if (ret <= 0)
                        goto out;
 
@@ -871,7 +904,7 @@ static int write_partial_msg_pages(struct ceph_connection *con)
                if (ret == len) {
                        con->out_msg_pos.page_pos = 0;
                        con->out_msg_pos.page++;
-                       con->out_msg_pos.did_page_crc = 0;
+                       con->out_msg_pos.did_page_crc = false;
                        if (in_trail)
                                list_move_tail(&page->lru,
                                               &msg->trail->head);
@@ -888,12 +921,10 @@ static int write_partial_msg_pages(struct ceph_connection *con)
        dout("write_partial_msg_pages %p msg %p done\n", con, msg);
 
        /* prepare and queue up footer, too */
-       if (!crc)
+       if (!do_datacrc)
                con->out_msg->footer.flags |= CEPH_MSG_FOOTER_NOCRC;
-       con->out_kvec_bytes = 0;
-       con->out_kvec_left = 0;
-       con->out_kvec_cur = con->out_kvec;
-       prepare_write_message_footer(con, 0);
+       ceph_con_out_kvec_reset(con);
+       prepare_write_message_footer(con);
        ret = 1;
 out:
        return ret;
@@ -907,12 +938,9 @@ static int write_partial_skip(struct ceph_connection *con)
        int ret;
 
        while (con->out_skip > 0) {
-               struct kvec iov = {
-                       .iov_base = page_address(con->msgr->zero_page),
-                       .iov_len = min(con->out_skip, (int)PAGE_CACHE_SIZE)
-               };
+               size_t size = min(con->out_skip, (int) PAGE_CACHE_SIZE);
 
-               ret = ceph_tcp_sendmsg(con->sock, &iov, 1, iov.iov_len, 1);
+               ret = ceph_tcp_sendpage(con->sock, zero_page, 0, size, 1);
                if (ret <= 0)
                        goto out;
                con->out_skip -= ret;
@@ -1085,8 +1113,8 @@ static void addr_set_port(struct sockaddr_storage *ss, int p)
 static int ceph_pton(const char *str, size_t len, struct sockaddr_storage *ss,
                char delim, const char **ipend)
 {
-       struct sockaddr_in *in4 = (void *)ss;
-       struct sockaddr_in6 *in6 = (void *)ss;
+       struct sockaddr_in *in4 = (struct sockaddr_in *) ss;
+       struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) ss;
 
        memset(ss, 0, sizeof(*ss));
 
@@ -1512,10 +1540,9 @@ static int read_partial_message_section(struct ceph_connection *con,
                if (ret <= 0)
                        return ret;
                section->iov_len += ret;
-               if (section->iov_len == sec_len)
-                       *crc = crc32c(0, section->iov_base,
-                                     section->iov_len);
        }
+       if (section->iov_len == sec_len)
+               *crc = crc32c(0, section->iov_base, section->iov_len);
 
        return 1;
 }
@@ -1527,7 +1554,7 @@ static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
 
 static int read_partial_message_pages(struct ceph_connection *con,
                                      struct page **pages,
-                                     unsigned data_len, int datacrc)
+                                     unsigned data_len, bool do_datacrc)
 {
        void *p;
        int ret;
@@ -1540,7 +1567,7 @@ static int read_partial_message_pages(struct ceph_connection *con,
        p = kmap(pages[con->in_msg_pos.page]);
        ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos,
                               left);
-       if (ret > 0 && datacrc)
+       if (ret > 0 && do_datacrc)
                con->in_data_crc =
                        crc32c(con->in_data_crc,
                                  p + con->in_msg_pos.page_pos, ret);
@@ -1560,7 +1587,7 @@ static int read_partial_message_pages(struct ceph_connection *con,
 #ifdef CONFIG_BLOCK
 static int read_partial_message_bio(struct ceph_connection *con,
                                    struct bio **bio_iter, int *bio_seg,
-                                   unsigned data_len, int datacrc)
+                                   unsigned data_len, bool do_datacrc)
 {
        struct bio_vec *bv = bio_iovec_idx(*bio_iter, *bio_seg);
        void *p;
@@ -1576,7 +1603,7 @@ static int read_partial_message_bio(struct ceph_connection *con,
 
        ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos,
                               left);
-       if (ret > 0 && datacrc)
+       if (ret > 0 && do_datacrc)
                con->in_data_crc =
                        crc32c(con->in_data_crc,
                                  p + con->in_msg_pos.page_pos, ret);
@@ -1603,9 +1630,10 @@ static int read_partial_message(struct ceph_connection *con)
        int ret;
        int to, left;
        unsigned front_len, middle_len, data_len;
-       int datacrc = con->msgr->nocrc;
+       bool do_datacrc = !con->msgr->nocrc;
        int skip;
        u64 seq;
+       u32 crc;
 
        dout("read_partial_message con %p msg %p\n", con, m);
 
@@ -1618,17 +1646,16 @@ static int read_partial_message(struct ceph_connection *con)
                if (ret <= 0)
                        return ret;
                con->in_base_pos += ret;
-               if (con->in_base_pos == sizeof(con->in_hdr)) {
-                       u32 crc = crc32c(0, (void *)&con->in_hdr,
-                                sizeof(con->in_hdr) - sizeof(con->in_hdr.crc));
-                       if (crc != le32_to_cpu(con->in_hdr.crc)) {
-                               pr_err("read_partial_message bad hdr "
-                                      " crc %u != expected %u\n",
-                                      crc, con->in_hdr.crc);
-                               return -EBADMSG;
-                       }
-               }
        }
+
+       crc = crc32c(0, &con->in_hdr, offsetof(struct ceph_msg_header, crc));
+       if (cpu_to_le32(crc) != con->in_hdr.crc) {
+               pr_err("read_partial_message bad hdr "
+                      " crc %u != expected %u\n",
+                      crc, con->in_hdr.crc);
+               return -EBADMSG;
+       }
+
        front_len = le32_to_cpu(con->in_hdr.front_len);
        if (front_len > CEPH_MSG_MAX_FRONT_LEN)
                return -EIO;
@@ -1714,7 +1741,7 @@ static int read_partial_message(struct ceph_connection *con)
        while (con->in_msg_pos.data_pos < data_len) {
                if (m->pages) {
                        ret = read_partial_message_pages(con, m->pages,
-                                                data_len, datacrc);
+                                                data_len, do_datacrc);
                        if (ret <= 0)
                                return ret;
 #ifdef CONFIG_BLOCK
@@ -1722,7 +1749,7 @@ static int read_partial_message(struct ceph_connection *con)
 
                        ret = read_partial_message_bio(con,
                                                 &m->bio_iter, &m->bio_seg,
-                                                data_len, datacrc);
+                                                data_len, do_datacrc);
                        if (ret <= 0)
                                return ret;
 #endif
@@ -1757,7 +1784,7 @@ static int read_partial_message(struct ceph_connection *con)
                       m, con->in_middle_crc, m->footer.middle_crc);
                return -EBADMSG;
        }
-       if (datacrc &&
+       if (do_datacrc &&
            (m->footer.flags & CEPH_MSG_FOOTER_NOCRC) == 0 &&
            con->in_data_crc != le32_to_cpu(m->footer.data_crc)) {
                pr_err("read_partial_message %p data crc %u != exp. %u\n", m,
@@ -1819,7 +1846,6 @@ more:
 
        /* open the socket first? */
        if (con->sock == NULL) {
-               prepare_write_banner(msgr, con);
                prepare_write_connect(msgr, con, 1);
                prepare_read_banner(con);
                set_bit(CONNECTING, &con->state);
@@ -1829,11 +1855,9 @@ more:
                con->in_tag = CEPH_MSGR_TAG_READY;
                dout("try_write initiating connect on %p new state %lu\n",
                     con, con->state);
-               con->sock = ceph_tcp_connect(con);
-               if (IS_ERR(con->sock)) {
-                       con->sock = NULL;
+               ret = ceph_tcp_connect(con);
+               if (ret < 0) {
                        con->error_msg = "connect error";
-                       ret = -1;
                        goto out;
                }
        }
@@ -1953,8 +1977,9 @@ more:
                 *
                 * FIXME: there must be a better way to do this!
                 */
-               static char buf[1024];
-               int skip = min(1024, -con->in_base_pos);
+               static char buf[SKIP_BUF_SIZE];
+               int skip = min((int) sizeof (buf), -con->in_base_pos);
+
                dout("skipping %d / %d bytes\n", skip, -con->in_base_pos);
                ret = ceph_tcp_recvmsg(con->sock, buf, skip);
                if (ret <= 0)
@@ -2216,15 +2241,6 @@ struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr,
 
        spin_lock_init(&msgr->global_seq_lock);
 
-       /* the zero page is needed if a request is "canceled" while the message
-        * is being written over the socket */
-       msgr->zero_page = __page_cache_alloc(GFP_KERNEL | __GFP_ZERO);
-       if (!msgr->zero_page) {
-               kfree(msgr);
-               return ERR_PTR(-ENOMEM);
-       }
-       kmap(msgr->zero_page);
-
        if (myaddr)
                msgr->inst.addr = *myaddr;
 
@@ -2241,8 +2257,6 @@ EXPORT_SYMBOL(ceph_messenger_create);
 void ceph_messenger_destroy(struct ceph_messenger *msgr)
 {
        dout("destroy %p\n", msgr);
-       kunmap(msgr->zero_page);
-       __free_page(msgr->zero_page);
        kfree(msgr);
        dout("destroyed messenger %p\n", msgr);
 }
index fd863fe..29ad46e 100644 (file)
@@ -283,7 +283,8 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
                ceph_decode_32_safe(p, end, yes, bad);
 #if BITS_PER_LONG == 32
                err = -EINVAL;
-               if (yes > ULONG_MAX / sizeof(struct crush_rule_step))
+               if (yes > (ULONG_MAX - sizeof(*r))
+                         / sizeof(struct crush_rule_step))
                        goto bad;
 #endif
                r = c->rules[i] = kmalloc(sizeof(*r) +
index 926411b..5d59155 100644 (file)
@@ -3559,7 +3559,8 @@ EXPORT_SYMBOL(napi_gro_receive);
 static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
 {
        __skb_pull(skb, skb_headlen(skb));
-       skb_reserve(skb, NET_IP_ALIGN - skb_headroom(skb));
+       /* restore the reserve we had after netdev_alloc_skb_ip_align() */
+       skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN - skb_headroom(skb));
        skb->vlan_tci = 0;
        skb->dev = napi->dev;
        skb->skb_iif = 0;
index 9e602a3..f223cdc 100644 (file)
@@ -320,12 +320,12 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
 EXPORT_SYMBOL(__netdev_alloc_skb);
 
 void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
-               int size)
+                    int size, unsigned int truesize)
 {
        skb_fill_page_desc(skb, i, page, off, size);
        skb->len += size;
        skb->data_len += size;
-       skb->truesize += size;
+       skb->truesize += truesize;
 }
 EXPORT_SYMBOL(skb_add_rx_frag);
 
index 39e0c16..6e447ff 100644 (file)
@@ -1078,6 +1078,7 @@ __be32 inet_confirm_addr(struct in_device *in_dev,
 
        return addr;
 }
+EXPORT_SYMBOL(inet_confirm_addr);
 
 /*
  *     Device notifier
index 0e58f09..851acec 100644 (file)
@@ -52,7 +52,7 @@ iptable_filter_hook(unsigned int hook, struct sk_buff *skb,
 static struct nf_hook_ops *filter_ops __read_mostly;
 
 /* Default to forward because I got too much mail already. */
-static bool forward = NF_ACCEPT;
+static bool forward = true;
 module_param(forward, bool, 0000);
 
 static int __net_init iptable_filter_net_init(struct net *net)
@@ -64,7 +64,7 @@ static int __net_init iptable_filter_net_init(struct net *net)
                return -ENOMEM;
        /* Entry 1 is the FORWARD hook */
        ((struct ipt_standard *)repl->entries)[1].target.verdict =
-               -forward - 1;
+               forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
 
        net->ipv4.iptable_filter =
                ipt_register_table(net, &packet_filter, repl);
@@ -88,11 +88,6 @@ static int __init iptable_filter_init(void)
 {
        int ret;
 
-       if (forward < 0 || forward > NF_MAX_VERDICT) {
-               pr_err("iptables forward must be 0 or 1\n");
-               return -EINVAL;
-       }
-
        ret = register_pernet_subsys(&iptable_filter_net_ops);
        if (ret < 0)
                return ret;
index a8f6da9..325e59a 100644 (file)
@@ -44,7 +44,7 @@ ip6table_filter_hook(unsigned int hook, struct sk_buff *skb,
 static struct nf_hook_ops *filter_ops __read_mostly;
 
 /* Default to forward because I got too much mail already. */
-static bool forward = NF_ACCEPT;
+static bool forward = true;
 module_param(forward, bool, 0000);
 
 static int __net_init ip6table_filter_net_init(struct net *net)
@@ -56,7 +56,7 @@ static int __net_init ip6table_filter_net_init(struct net *net)
                return -ENOMEM;
        /* Entry 1 is the FORWARD hook */
        ((struct ip6t_standard *)repl->entries)[1].target.verdict =
-               -forward - 1;
+               forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
 
        net->ipv6.ip6table_filter =
                ip6t_register_table(net, &packet_filter, repl);
@@ -80,11 +80,6 @@ static int __init ip6table_filter_init(void)
 {
        int ret;
 
-       if (forward < 0 || forward > NF_MAX_VERDICT) {
-               pr_err("iptables forward must be 0 or 1\n");
-               return -EINVAL;
-       }
-
        ret = register_pernet_subsys(&ip6table_filter_net_ops);
        if (ret < 0)
                return ret;
index 24c456e..496b627 100644 (file)
@@ -2474,8 +2474,12 @@ static int rt6_fill_node(struct net *net,
 
        rcu_read_lock();
        n = dst_get_neighbour_noref(&rt->dst);
-       if (n)
-               NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key);
+       if (n) {
+               if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) {
+                       rcu_read_unlock();
+                       goto nla_put_failure;
+               }
+       }
        rcu_read_unlock();
 
        if (rt->dst.dev)
index 9b07191..1addd9f 100644 (file)
@@ -1845,3 +1845,4 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
 MODULE_DESCRIPTION("PPP over L2TP over UDP");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(PPPOL2TP_DRV_VERSION);
+MODULE_ALIAS("pppox-proto-" __stringify(PX_PROTO_OL2TP));
index 7b48035..cbdb754 100644 (file)
@@ -768,8 +768,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
               struct nf_conntrack_l3proto *l3proto,
               struct nf_conntrack_l4proto *l4proto,
               struct sk_buff *skb,
-              unsigned int dataoff, u32 hash,
-              unsigned int *timeouts)
+              unsigned int dataoff, u32 hash)
 {
        struct nf_conn *ct;
        struct nf_conn_help *help;
@@ -777,6 +776,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
        struct nf_conntrack_ecache *ecache;
        struct nf_conntrack_expect *exp;
        u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
+       struct nf_conn_timeout *timeout_ext;
+       unsigned int *timeouts;
 
        if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) {
                pr_debug("Can't invert tuple.\n");
@@ -788,12 +789,21 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
        if (IS_ERR(ct))
                return (struct nf_conntrack_tuple_hash *)ct;
 
+       timeout_ext = tmpl ? nf_ct_timeout_find(tmpl) : NULL;
+       if (timeout_ext)
+               timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
+       else
+               timeouts = l4proto->get_timeouts(net);
+
        if (!l4proto->new(ct, skb, dataoff, timeouts)) {
                nf_conntrack_free(ct);
                pr_debug("init conntrack: can't track with proto module\n");
                return NULL;
        }
 
+       if (timeout_ext)
+               nf_ct_timeout_ext_add(ct, timeout_ext->timeout, GFP_ATOMIC);
+
        nf_ct_acct_ext_add(ct, GFP_ATOMIC);
        nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
 
@@ -854,8 +864,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
                  struct nf_conntrack_l3proto *l3proto,
                  struct nf_conntrack_l4proto *l4proto,
                  int *set_reply,
-                 enum ip_conntrack_info *ctinfo,
-                 unsigned int *timeouts)
+                 enum ip_conntrack_info *ctinfo)
 {
        struct nf_conntrack_tuple tuple;
        struct nf_conntrack_tuple_hash *h;
@@ -875,7 +884,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
        h = __nf_conntrack_find_get(net, zone, &tuple, hash);
        if (!h) {
                h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
-                                  skb, dataoff, hash, timeouts);
+                                  skb, dataoff, hash);
                if (!h)
                        return NULL;
                if (IS_ERR(h))
@@ -964,19 +973,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
                        goto out;
        }
 
-       /* Decide what timeout policy we want to apply to this flow. */
-       if (tmpl) {
-               timeout_ext = nf_ct_timeout_find(tmpl);
-               if (timeout_ext)
-                       timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
-               else
-                       timeouts = l4proto->get_timeouts(net);
-       } else
-               timeouts = l4proto->get_timeouts(net);
-
        ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,
-                              l3proto, l4proto, &set_reply, &ctinfo,
-                              timeouts);
+                              l3proto, l4proto, &set_reply, &ctinfo);
        if (!ct) {
                /* Not valid part of a connection */
                NF_CT_STAT_INC_ATOMIC(net, invalid);
@@ -993,6 +991,13 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
 
        NF_CT_ASSERT(skb->nfct);
 
+       /* Decide what timeout policy we want to apply to this flow. */
+       timeout_ext = nf_ct_timeout_find(ct);
+       if (timeout_ext)
+               timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
+       else
+               timeouts = l4proto->get_timeouts(net);
+
        ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts);
        if (ret <= 0) {
                /* Invalid: inverse of the return code tells
index 5701c8d..be3da2c 100644 (file)
@@ -127,6 +127,27 @@ void nf_ct_l3proto_module_put(unsigned short l3proto)
 }
 EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put);
 
+struct nf_conntrack_l4proto *
+nf_ct_l4proto_find_get(u_int16_t l3num, u_int8_t l4num)
+{
+       struct nf_conntrack_l4proto *p;
+
+       rcu_read_lock();
+       p = __nf_ct_l4proto_find(l3num, l4num);
+       if (!try_module_get(p->me))
+               p = &nf_conntrack_l4proto_generic;
+       rcu_read_unlock();
+
+       return p;
+}
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get);
+
+void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p)
+{
+       module_put(p->me);
+}
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_put);
+
 static int kill_l3proto(struct nf_conn *i, void *data)
 {
        return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto;
index fec29a4..2b9e79f 100644 (file)
@@ -98,11 +98,13 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
                break;
        }
 
-       l4proto = __nf_ct_l4proto_find(l3num, l4num);
+       l4proto = nf_ct_l4proto_find_get(l3num, l4num);
 
        /* This protocol is not supportted, skip. */
-       if (l4proto->l4proto != l4num)
-               return -EOPNOTSUPP;
+       if (l4proto->l4proto != l4num) {
+               ret = -EOPNOTSUPP;
+               goto err_proto_put;
+       }
 
        if (matching) {
                if (nlh->nlmsg_flags & NLM_F_REPLACE) {
@@ -110,20 +112,25 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
                         * different kind, sorry.
                         */
                        if (matching->l3num != l3num ||
-                           matching->l4num != l4num)
-                               return -EINVAL;
+                           matching->l4proto->l4proto != l4num) {
+                               ret = -EINVAL;
+                               goto err_proto_put;
+                       }
 
                        ret = ctnl_timeout_parse_policy(matching, l4proto,
                                                        cda[CTA_TIMEOUT_DATA]);
                        return ret;
                }
-               return -EBUSY;
+               ret = -EBUSY;
+               goto err_proto_put;
        }
 
        timeout = kzalloc(sizeof(struct ctnl_timeout) +
                          l4proto->ctnl_timeout.obj_size, GFP_KERNEL);
-       if (timeout == NULL)
-               return -ENOMEM;
+       if (timeout == NULL) {
+               ret = -ENOMEM;
+               goto err_proto_put;
+       }
 
        ret = ctnl_timeout_parse_policy(timeout, l4proto,
                                        cda[CTA_TIMEOUT_DATA]);
@@ -132,13 +139,15 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
 
        strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME]));
        timeout->l3num = l3num;
-       timeout->l4num = l4num;
+       timeout->l4proto = l4proto;
        atomic_set(&timeout->refcnt, 1);
        list_add_tail_rcu(&timeout->head, &cttimeout_list);
 
        return 0;
 err:
        kfree(timeout);
+err_proto_put:
+       nf_ct_l4proto_put(l4proto);
        return ret;
 }
 
@@ -149,7 +158,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
        struct nlmsghdr *nlh;
        struct nfgenmsg *nfmsg;
        unsigned int flags = pid ? NLM_F_MULTI : 0;
-       struct nf_conntrack_l4proto *l4proto;
+       struct nf_conntrack_l4proto *l4proto = timeout->l4proto;
 
        event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8;
        nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
@@ -163,20 +172,10 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
 
        NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name);
        NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num));
-       NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num);
+       NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto);
        NLA_PUT_BE32(skb, CTA_TIMEOUT_USE,
                        htonl(atomic_read(&timeout->refcnt)));
 
-       l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num);
-
-       /* If the timeout object does not match the layer 4 protocol tracker,
-        * then skip dumping the data part since we don't know how to
-        * interpret it. This may happen for UPDlite, SCTP and DCCP since
-        * you can unload the module.
-        */
-       if (timeout->l4num != l4proto->l4proto)
-               goto out;
-
        if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
                struct nlattr *nest_parms;
                int ret;
@@ -192,7 +191,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
 
                nla_nest_end(skb, nest_parms);
        }
-out:
+
        nlmsg_end(skb, nlh);
        return skb->len;
 
@@ -293,6 +292,7 @@ static int ctnl_timeout_try_del(struct ctnl_timeout *timeout)
        if (atomic_dec_and_test(&timeout->refcnt)) {
                /* We are protected by nfnl mutex. */
                list_del_rcu(&timeout->head);
+               nf_ct_l4proto_put(timeout->l4proto);
                kfree_rcu(timeout, rcu_head);
        } else {
                /* still in use, restore reference counter. */
@@ -417,6 +417,7 @@ static void __exit cttimeout_exit(void)
                /* We are sure that our objects have no clients at this point,
                 * it's safe to release them all without checking refcnt.
                 */
+               nf_ct_l4proto_put(cur->l4proto);
                kfree_rcu(cur, rcu_head);
        }
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
index b873445..0c8e438 100644 (file)
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_CT.h>
 #include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_l4proto.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_l4proto.h>
 #include <net/netfilter/nf_conntrack_timeout.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 
@@ -217,50 +219,59 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
                struct ctnl_timeout *timeout;
                struct nf_conn_timeout *timeout_ext;
 
+               rcu_read_lock();
                timeout_find_get =
                        rcu_dereference(nf_ct_timeout_find_get_hook);
 
                if (timeout_find_get) {
                        const struct ipt_entry *e = par->entryinfo;
+                       struct nf_conntrack_l4proto *l4proto;
 
                        if (e->ip.invflags & IPT_INV_PROTO) {
                                ret = -EINVAL;
                                pr_info("You cannot use inversion on "
                                         "L4 protocol\n");
-                               goto err3;
+                               goto err4;
                        }
                        timeout = timeout_find_get(info->timeout);
                        if (timeout == NULL) {
                                ret = -ENOENT;
                                pr_info("No such timeout policy \"%s\"\n",
                                        info->timeout);
-                               goto err3;
+                               goto err4;
                        }
                        if (timeout->l3num != par->family) {
                                ret = -EINVAL;
                                pr_info("Timeout policy `%s' can only be "
                                        "used by L3 protocol number %d\n",
                                        info->timeout, timeout->l3num);
-                               goto err3;
+                               goto err4;
                        }
-                       if (timeout->l4num != e->ip.proto) {
+                       /* Make sure the timeout policy matches any existing
+                        * protocol tracker, otherwise default to generic.
+                        */
+                       l4proto = __nf_ct_l4proto_find(par->family,
+                                                      e->ip.proto);
+                       if (timeout->l4proto->l4proto != l4proto->l4proto) {
                                ret = -EINVAL;
                                pr_info("Timeout policy `%s' can only be "
                                        "used by L4 protocol number %d\n",
-                                       info->timeout, timeout->l4num);
-                               goto err3;
+                                       info->timeout,
+                                       timeout->l4proto->l4proto);
+                               goto err4;
                        }
                        timeout_ext = nf_ct_timeout_ext_add(ct, timeout,
                                                            GFP_KERNEL);
                        if (timeout_ext == NULL) {
                                ret = -ENOMEM;
-                               goto err3;
+                               goto err4;
                        }
                } else {
                        ret = -ENOENT;
                        pr_info("Timeout policy base is empty\n");
-                       goto err3;
+                       goto err4;
                }
+               rcu_read_unlock();
        }
 #endif
 
@@ -270,6 +281,8 @@ out:
        info->ct = ct;
        return 0;
 
+err4:
+       rcu_read_unlock();
 err3:
        nf_conntrack_free(ct);
 err2:
@@ -311,6 +324,7 @@ static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
                nf_ct_l3proto_module_put(par->family);
 
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
+               rcu_read_lock();
                timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
 
                if (timeout_put) {
@@ -318,6 +332,7 @@ static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
                        if (timeout_ext)
                                timeout_put(timeout_ext->timeout);
                }
+               rcu_read_unlock();
 #endif
        }
        nf_ct_put(info->ct);
index f99f8de..ff5f75f 100644 (file)
@@ -480,7 +480,7 @@ ipt_log_packet(u_int8_t pf,
        sb_close(m);
 }
 
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 /* One level of recursion won't kill us */
 static void dump_ipv6_packet(struct sbuff *m,
                        const struct nf_loginfo *info,
@@ -824,7 +824,7 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par)
        if (par->family == NFPROTO_IPV4)
                ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in,
                               par->out, &li, loginfo->prefix);
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
        else if (par->family == NFPROTO_IPV6)
                ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in,
                                par->out, &li, loginfo->prefix);
@@ -864,7 +864,7 @@ static struct xt_target log_tg_regs[] __read_mostly = {
                .checkentry     = log_tg_check,
                .me             = THIS_MODULE,
        },
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
        {
                .name           = "LOG",
                .family         = NFPROTO_IPV6,
@@ -882,7 +882,7 @@ static struct nf_logger ipt_log_logger __read_mostly = {
        .me             = THIS_MODULE,
 };
 
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 static struct nf_logger ip6t_log_logger __read_mostly = {
        .name           = "ip6t_LOG",
        .logfn          = &ip6t_log_packet,
@@ -899,7 +899,7 @@ static int __init log_tg_init(void)
                return ret;
 
        nf_log_register(NFPROTO_IPV4, &ipt_log_logger);
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
        nf_log_register(NFPROTO_IPV6, &ip6t_log_logger);
 #endif
        return 0;
@@ -908,7 +908,7 @@ static int __init log_tg_init(void)
 static void __exit log_tg_exit(void)
 {
        nf_log_unregister(&ipt_log_logger);
-#if IS_ENABLED(CONFIG_IPV6)
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
        nf_log_unregister(&ip6t_log_logger);
 #endif
        xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs));
index 2560e7b..7c94aed 100644 (file)
@@ -597,7 +597,7 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
                        iter = iter->next;
                        iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
                }
-               ret_val = netlbl_secattr_catmap_setbit(iter, spot, GFP_ATOMIC);
+               ret_val = netlbl_secattr_catmap_setbit(iter, spot, flags);
        }
 
        return ret_val;
index 51c8689..a1e1162 100644 (file)
@@ -749,7 +749,7 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp)
        int ret;
 
        /* XXX too lazy? */
-       ic = kzalloc(sizeof(struct rds_ib_connection), GFP_KERNEL);
+       ic = kzalloc(sizeof(struct rds_ib_connection), gfp);
        if (!ic)
                return -ENOMEM;
 
index 9556d28..a91e1db 100644 (file)
@@ -694,7 +694,7 @@ int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp)
        unsigned long flags;
 
        /* XXX too lazy? */
-       ic = kzalloc(sizeof(struct rds_iw_connection), GFP_KERNEL);
+       ic = kzalloc(sizeof(struct rds_iw_connection), gfp);
        if (!ic)
                return -ENOMEM;
 
index 87ff2a8..6b12b68 100644 (file)
@@ -121,7 +121,7 @@ static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp)
        struct rds_loop_connection *lc;
        unsigned long flags;
 
-       lc = kzalloc(sizeof(struct rds_loop_connection), GFP_KERNEL);
+       lc = kzalloc(sizeof(struct rds_loop_connection), gfp);
        if (!lc)
                return -ENOMEM;
 
index 354760e..f974961 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/rfkill.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/device.h>
 #include <linux/miscdevice.h>
 #include <linux/wait.h>
 #include <linux/poll.h>
index ffd243d..9fe8857 100644 (file)
@@ -39,3 +39,16 @@ config RPCSEC_GSS_KRB5
          Kerberos support should be installed.
 
          If unsure, say Y.
+
+config SUNRPC_DEBUG
+       bool "RPC: Enable dprintk debugging"
+       depends on SUNRPC && SYSCTL
+       help
+         This option enables a sysctl-based debugging interface
+         that is be used by the 'rpcdebug' utility to turn on or off
+         logging of different aspects of the kernel RPC activity.
+
+         Disabling this option will make your kernel slightly smaller,
+         but makes troubleshooting NFS issues significantly harder.
+
+         If unsure, say Y.
index ee77742..d11418f 100644 (file)
@@ -156,8 +156,9 @@ static size_t rpc_pton4(const char *buf, const size_t buflen,
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
-static int rpc_parse_scope_id(const char *buf, const size_t buflen,
-                             const char *delim, struct sockaddr_in6 *sin6)
+static int rpc_parse_scope_id(struct net *net, const char *buf,
+                             const size_t buflen, const char *delim,
+                             struct sockaddr_in6 *sin6)
 {
        char *p;
        size_t len;
@@ -177,7 +178,7 @@ static int rpc_parse_scope_id(const char *buf, const size_t buflen,
                unsigned long scope_id = 0;
                struct net_device *dev;
 
-               dev = dev_get_by_name(&init_net, p);
+               dev = dev_get_by_name(net, p);
                if (dev != NULL) {
                        scope_id = dev->ifindex;
                        dev_put(dev);
@@ -197,7 +198,7 @@ static int rpc_parse_scope_id(const char *buf, const size_t buflen,
        return 0;
 }
 
-static size_t rpc_pton6(const char *buf, const size_t buflen,
+static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen,
                        struct sockaddr *sap, const size_t salen)
 {
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
@@ -213,14 +214,14 @@ static size_t rpc_pton6(const char *buf, const size_t buflen,
        if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0)
                return 0;
 
-       if (!rpc_parse_scope_id(buf, buflen, delim, sin6))
+       if (!rpc_parse_scope_id(net, buf, buflen, delim, sin6))
                return 0;
 
        sin6->sin6_family = AF_INET6;
        return sizeof(struct sockaddr_in6);
 }
 #else
-static size_t rpc_pton6(const char *buf, const size_t buflen,
+static size_t rpc_pton6(struct net *net, const char *buf, const size_t buflen,
                        struct sockaddr *sap, const size_t salen)
 {
        return 0;
@@ -229,6 +230,7 @@ static size_t rpc_pton6(const char *buf, const size_t buflen,
 
 /**
  * rpc_pton - Construct a sockaddr in @sap
+ * @net: applicable network namespace
  * @buf: C string containing presentation format IP address
  * @buflen: length of presentation address in bytes
  * @sap: buffer into which to plant socket address
@@ -241,14 +243,14 @@ static size_t rpc_pton6(const char *buf, const size_t buflen,
  * socket address, if successful.  Returns zero if an error
  * occurred.
  */
-size_t rpc_pton(const char *buf, const size_t buflen,
+size_t rpc_pton(struct net *net, const char *buf, const size_t buflen,
                struct sockaddr *sap, const size_t salen)
 {
        unsigned int i;
 
        for (i = 0; i < buflen; i++)
                if (buf[i] == ':')
-                       return rpc_pton6(buf, buflen, sap, salen);
+                       return rpc_pton6(net, buf, buflen, sap, salen);
        return rpc_pton4(buf, buflen, sap, salen);
 }
 EXPORT_SYMBOL_GPL(rpc_pton);
@@ -295,6 +297,7 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags)
 
 /**
  * rpc_uaddr2sockaddr - convert a universal address to a socket address.
+ * @net: applicable network namespace
  * @uaddr: C string containing universal address to convert
  * @uaddr_len: length of universal address string
  * @sap: buffer into which to plant socket address
@@ -306,8 +309,9 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags)
  * Returns the size of the socket address if successful; otherwise
  * zero is returned.
  */
-size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len,
-                         struct sockaddr *sap, const size_t salen)
+size_t rpc_uaddr2sockaddr(struct net *net, const char *uaddr,
+                         const size_t uaddr_len, struct sockaddr *sap,
+                         const size_t salen)
 {
        char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')];
        unsigned long portlo, porthi;
@@ -339,7 +343,7 @@ size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len,
        port = (unsigned short)((porthi << 8) | portlo);
 
        *c = '\0';
-       if (rpc_pton(buf, strlen(buf), sap, salen) == 0)
+       if (rpc_pton(net, buf, strlen(buf), sap, salen) == 0)
                return 0;
 
        switch (sap->sa_family) {
index affa631..d3ad81f 100644 (file)
@@ -81,7 +81,7 @@ struct gss_auth {
         * mechanism (for example, "krb5") and exists for
         * backwards-compatibility with older gssd's.
         */
-       struct dentry *dentry[2];
+       struct rpc_pipe *pipe[2];
 };
 
 /* pipe_version >= 0 if and only if someone has a pipe open. */
@@ -112,7 +112,7 @@ gss_put_ctx(struct gss_cl_ctx *ctx)
 /* gss_cred_set_ctx:
  * called by gss_upcall_callback and gss_create_upcall in order
  * to set the gss context. The actual exchange of an old context
- * and a new one is protected by the inode->i_lock.
+ * and a new one is protected by the pipe->lock.
  */
 static void
 gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
@@ -251,7 +251,7 @@ struct gss_upcall_msg {
        struct rpc_pipe_msg msg;
        struct list_head list;
        struct gss_auth *auth;
-       struct rpc_inode *inode;
+       struct rpc_pipe *pipe;
        struct rpc_wait_queue rpc_waitqueue;
        wait_queue_head_t waitqueue;
        struct gss_cl_ctx *ctx;
@@ -294,10 +294,10 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
 }
 
 static struct gss_upcall_msg *
-__gss_find_upcall(struct rpc_inode *rpci, uid_t uid)
+__gss_find_upcall(struct rpc_pipe *pipe, uid_t uid)
 {
        struct gss_upcall_msg *pos;
-       list_for_each_entry(pos, &rpci->in_downcall, list) {
+       list_for_each_entry(pos, &pipe->in_downcall, list) {
                if (pos->uid != uid)
                        continue;
                atomic_inc(&pos->count);
@@ -315,18 +315,17 @@ __gss_find_upcall(struct rpc_inode *rpci, uid_t uid)
 static inline struct gss_upcall_msg *
 gss_add_msg(struct gss_upcall_msg *gss_msg)
 {
-       struct rpc_inode *rpci = gss_msg->inode;
-       struct inode *inode = &rpci->vfs_inode;
+       struct rpc_pipe *pipe = gss_msg->pipe;
        struct gss_upcall_msg *old;
 
-       spin_lock(&inode->i_lock);
-       old = __gss_find_upcall(rpci, gss_msg->uid);
+       spin_lock(&pipe->lock);
+       old = __gss_find_upcall(pipe, gss_msg->uid);
        if (old == NULL) {
                atomic_inc(&gss_msg->count);
-               list_add(&gss_msg->list, &rpci->in_downcall);
+               list_add(&gss_msg->list, &pipe->in_downcall);
        } else
                gss_msg = old;
-       spin_unlock(&inode->i_lock);
+       spin_unlock(&pipe->lock);
        return gss_msg;
 }
 
@@ -342,14 +341,14 @@ __gss_unhash_msg(struct gss_upcall_msg *gss_msg)
 static void
 gss_unhash_msg(struct gss_upcall_msg *gss_msg)
 {
-       struct inode *inode = &gss_msg->inode->vfs_inode;
+       struct rpc_pipe *pipe = gss_msg->pipe;
 
        if (list_empty(&gss_msg->list))
                return;
-       spin_lock(&inode->i_lock);
+       spin_lock(&pipe->lock);
        if (!list_empty(&gss_msg->list))
                __gss_unhash_msg(gss_msg);
-       spin_unlock(&inode->i_lock);
+       spin_unlock(&pipe->lock);
 }
 
 static void
@@ -376,11 +375,11 @@ gss_upcall_callback(struct rpc_task *task)
        struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred,
                        struct gss_cred, gc_base);
        struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
-       struct inode *inode = &gss_msg->inode->vfs_inode;
+       struct rpc_pipe *pipe = gss_msg->pipe;
 
-       spin_lock(&inode->i_lock);
+       spin_lock(&pipe->lock);
        gss_handle_downcall_result(gss_cred, gss_msg);
-       spin_unlock(&inode->i_lock);
+       spin_unlock(&pipe->lock);
        task->tk_status = gss_msg->msg.errno;
        gss_release_msg(gss_msg);
 }
@@ -450,7 +449,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt,
                kfree(gss_msg);
                return ERR_PTR(vers);
        }
-       gss_msg->inode = RPC_I(gss_auth->dentry[vers]->d_inode);
+       gss_msg->pipe = gss_auth->pipe[vers];
        INIT_LIST_HEAD(&gss_msg->list);
        rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
        init_waitqueue_head(&gss_msg->waitqueue);
@@ -474,8 +473,7 @@ gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cr
                return gss_new;
        gss_msg = gss_add_msg(gss_new);
        if (gss_msg == gss_new) {
-               struct inode *inode = &gss_new->inode->vfs_inode;
-               int res = rpc_queue_upcall(inode, &gss_new->msg);
+               int res = rpc_queue_upcall(gss_new->pipe, &gss_new->msg);
                if (res) {
                        gss_unhash_msg(gss_new);
                        gss_msg = ERR_PTR(res);
@@ -506,7 +504,7 @@ gss_refresh_upcall(struct rpc_task *task)
        struct gss_cred *gss_cred = container_of(cred,
                        struct gss_cred, gc_base);
        struct gss_upcall_msg *gss_msg;
-       struct inode *inode;
+       struct rpc_pipe *pipe;
        int err = 0;
 
        dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid,
@@ -524,8 +522,8 @@ gss_refresh_upcall(struct rpc_task *task)
                err = PTR_ERR(gss_msg);
                goto out;
        }
-       inode = &gss_msg->inode->vfs_inode;
-       spin_lock(&inode->i_lock);
+       pipe = gss_msg->pipe;
+       spin_lock(&pipe->lock);
        if (gss_cred->gc_upcall != NULL)
                rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
        else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
@@ -538,7 +536,7 @@ gss_refresh_upcall(struct rpc_task *task)
                gss_handle_downcall_result(gss_cred, gss_msg);
                err = gss_msg->msg.errno;
        }
-       spin_unlock(&inode->i_lock);
+       spin_unlock(&pipe->lock);
        gss_release_msg(gss_msg);
 out:
        dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n",
@@ -549,7 +547,7 @@ out:
 static inline int
 gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
 {
-       struct inode *inode;
+       struct rpc_pipe *pipe;
        struct rpc_cred *cred = &gss_cred->gc_base;
        struct gss_upcall_msg *gss_msg;
        DEFINE_WAIT(wait);
@@ -573,14 +571,14 @@ retry:
                err = PTR_ERR(gss_msg);
                goto out;
        }
-       inode = &gss_msg->inode->vfs_inode;
+       pipe = gss_msg->pipe;
        for (;;) {
                prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_KILLABLE);
-               spin_lock(&inode->i_lock);
+               spin_lock(&pipe->lock);
                if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) {
                        break;
                }
-               spin_unlock(&inode->i_lock);
+               spin_unlock(&pipe->lock);
                if (fatal_signal_pending(current)) {
                        err = -ERESTARTSYS;
                        goto out_intr;
@@ -591,7 +589,7 @@ retry:
                gss_cred_set_ctx(cred, gss_msg->ctx);
        else
                err = gss_msg->msg.errno;
-       spin_unlock(&inode->i_lock);
+       spin_unlock(&pipe->lock);
 out_intr:
        finish_wait(&gss_msg->waitqueue, &wait);
        gss_release_msg(gss_msg);
@@ -609,7 +607,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        const void *p, *end;
        void *buf;
        struct gss_upcall_msg *gss_msg;
-       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct rpc_pipe *pipe = RPC_I(filp->f_dentry->d_inode)->pipe;
        struct gss_cl_ctx *ctx;
        uid_t uid;
        ssize_t err = -EFBIG;
@@ -639,14 +637,14 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 
        err = -ENOENT;
        /* Find a matching upcall */
-       spin_lock(&inode->i_lock);
-       gss_msg = __gss_find_upcall(RPC_I(inode), uid);
+       spin_lock(&pipe->lock);
+       gss_msg = __gss_find_upcall(pipe, uid);
        if (gss_msg == NULL) {
-               spin_unlock(&inode->i_lock);
+               spin_unlock(&pipe->lock);
                goto err_put_ctx;
        }
        list_del_init(&gss_msg->list);
-       spin_unlock(&inode->i_lock);
+       spin_unlock(&pipe->lock);
 
        p = gss_fill_context(p, end, ctx, gss_msg->auth->mech);
        if (IS_ERR(p)) {
@@ -674,9 +672,9 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        err = mlen;
 
 err_release_msg:
-       spin_lock(&inode->i_lock);
+       spin_lock(&pipe->lock);
        __gss_unhash_msg(gss_msg);
-       spin_unlock(&inode->i_lock);
+       spin_unlock(&pipe->lock);
        gss_release_msg(gss_msg);
 err_put_ctx:
        gss_put_ctx(ctx);
@@ -722,23 +720,23 @@ static int gss_pipe_open_v1(struct inode *inode)
 static void
 gss_pipe_release(struct inode *inode)
 {
-       struct rpc_inode *rpci = RPC_I(inode);
+       struct rpc_pipe *pipe = RPC_I(inode)->pipe;
        struct gss_upcall_msg *gss_msg;
 
 restart:
-       spin_lock(&inode->i_lock);
-       list_for_each_entry(gss_msg, &rpci->in_downcall, list) {
+       spin_lock(&pipe->lock);
+       list_for_each_entry(gss_msg, &pipe->in_downcall, list) {
 
                if (!list_empty(&gss_msg->msg.list))
                        continue;
                gss_msg->msg.errno = -EPIPE;
                atomic_inc(&gss_msg->count);
                __gss_unhash_msg(gss_msg);
-               spin_unlock(&inode->i_lock);
+               spin_unlock(&pipe->lock);
                gss_release_msg(gss_msg);
                goto restart;
        }
-       spin_unlock(&inode->i_lock);
+       spin_unlock(&pipe->lock);
 
        put_pipe_version();
 }
@@ -759,6 +757,75 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
        }
 }
 
+static void gss_pipes_dentries_destroy(struct rpc_auth *auth)
+{
+       struct gss_auth *gss_auth;
+
+       gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+       if (gss_auth->pipe[0]->dentry)
+               rpc_unlink(gss_auth->pipe[0]->dentry);
+       if (gss_auth->pipe[1]->dentry)
+               rpc_unlink(gss_auth->pipe[1]->dentry);
+}
+
+static int gss_pipes_dentries_create(struct rpc_auth *auth)
+{
+       int err;
+       struct gss_auth *gss_auth;
+       struct rpc_clnt *clnt;
+
+       gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+       clnt = gss_auth->client;
+
+       gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry,
+                                                     "gssd",
+                                                     clnt, gss_auth->pipe[1]);
+       if (IS_ERR(gss_auth->pipe[1]->dentry))
+               return PTR_ERR(gss_auth->pipe[1]->dentry);
+       gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry,
+                                                     gss_auth->mech->gm_name,
+                                                     clnt, gss_auth->pipe[0]);
+       if (IS_ERR(gss_auth->pipe[0]->dentry)) {
+               err = PTR_ERR(gss_auth->pipe[0]->dentry);
+               goto err_unlink_pipe_1;
+       }
+       return 0;
+
+err_unlink_pipe_1:
+       rpc_unlink(gss_auth->pipe[1]->dentry);
+       return err;
+}
+
+static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt,
+                                          struct rpc_auth *auth)
+{
+       struct net *net = rpc_net_ns(clnt);
+       struct super_block *sb;
+
+       sb = rpc_get_sb_net(net);
+       if (sb) {
+               if (clnt->cl_dentry)
+                       gss_pipes_dentries_destroy(auth);
+               rpc_put_sb_net(net);
+       }
+}
+
+static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt,
+                                        struct rpc_auth *auth)
+{
+       struct net *net = rpc_net_ns(clnt);
+       struct super_block *sb;
+       int err = 0;
+
+       sb = rpc_get_sb_net(net);
+       if (sb) {
+               if (clnt->cl_dentry)
+                       err = gss_pipes_dentries_create(auth);
+               rpc_put_sb_net(net);
+       }
+       return err;
+}
+
 /*
  * NOTE: we have the opportunity to use different
  * parameters based on the input flavor (which must be a pseudoflavor)
@@ -801,32 +868,33 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
         * that we supported only the old pipe.  So we instead create
         * the new pipe first.
         */
-       gss_auth->dentry[1] = rpc_mkpipe(clnt->cl_path.dentry,
-                                        "gssd",
-                                        clnt, &gss_upcall_ops_v1,
-                                        RPC_PIPE_WAIT_FOR_OPEN);
-       if (IS_ERR(gss_auth->dentry[1])) {
-               err = PTR_ERR(gss_auth->dentry[1]);
+       gss_auth->pipe[1] = rpc_mkpipe_data(&gss_upcall_ops_v1,
+                                           RPC_PIPE_WAIT_FOR_OPEN);
+       if (IS_ERR(gss_auth->pipe[1])) {
+               err = PTR_ERR(gss_auth->pipe[1]);
                goto err_put_mech;
        }
 
-       gss_auth->dentry[0] = rpc_mkpipe(clnt->cl_path.dentry,
-                                        gss_auth->mech->gm_name,
-                                        clnt, &gss_upcall_ops_v0,
-                                        RPC_PIPE_WAIT_FOR_OPEN);
-       if (IS_ERR(gss_auth->dentry[0])) {
-               err = PTR_ERR(gss_auth->dentry[0]);
-               goto err_unlink_pipe_1;
+       gss_auth->pipe[0] = rpc_mkpipe_data(&gss_upcall_ops_v0,
+                                           RPC_PIPE_WAIT_FOR_OPEN);
+       if (IS_ERR(gss_auth->pipe[0])) {
+               err = PTR_ERR(gss_auth->pipe[0]);
+               goto err_destroy_pipe_1;
        }
+       err = gss_pipes_dentries_create_net(clnt, auth);
+       if (err)
+               goto err_destroy_pipe_0;
        err = rpcauth_init_credcache(auth);
        if (err)
-               goto err_unlink_pipe_0;
+               goto err_unlink_pipes;
 
        return auth;
-err_unlink_pipe_0:
-       rpc_unlink(gss_auth->dentry[0]);
-err_unlink_pipe_1:
-       rpc_unlink(gss_auth->dentry[1]);
+err_unlink_pipes:
+       gss_pipes_dentries_destroy_net(clnt, auth);
+err_destroy_pipe_0:
+       rpc_destroy_pipe_data(gss_auth->pipe[0]);
+err_destroy_pipe_1:
+       rpc_destroy_pipe_data(gss_auth->pipe[1]);
 err_put_mech:
        gss_mech_put(gss_auth->mech);
 err_free:
@@ -839,8 +907,9 @@ out_dec:
 static void
 gss_free(struct gss_auth *gss_auth)
 {
-       rpc_unlink(gss_auth->dentry[1]);
-       rpc_unlink(gss_auth->dentry[0]);
+       gss_pipes_dentries_destroy_net(gss_auth->client, &gss_auth->rpc_auth);
+       rpc_destroy_pipe_data(gss_auth->pipe[0]);
+       rpc_destroy_pipe_data(gss_auth->pipe[1]);
        gss_mech_put(gss_auth->mech);
 
        kfree(gss_auth);
@@ -1547,7 +1616,9 @@ static const struct rpc_authops authgss_ops = {
        .create         = gss_create,
        .destroy        = gss_destroy,
        .lookup_cred    = gss_lookup_cred,
-       .crcreate       = gss_create_cred
+       .crcreate       = gss_create_cred,
+       .pipes_create   = gss_pipes_dentries_create,
+       .pipes_destroy  = gss_pipes_dentries_destroy,
 };
 
 static const struct rpc_credops gss_credops = {
@@ -1591,6 +1662,21 @@ static const struct rpc_pipe_ops gss_upcall_ops_v1 = {
        .release_pipe   = gss_pipe_release,
 };
 
+static __net_init int rpcsec_gss_init_net(struct net *net)
+{
+       return gss_svc_init_net(net);
+}
+
+static __net_exit void rpcsec_gss_exit_net(struct net *net)
+{
+       gss_svc_shutdown_net(net);
+}
+
+static struct pernet_operations rpcsec_gss_net_ops = {
+       .init = rpcsec_gss_init_net,
+       .exit = rpcsec_gss_exit_net,
+};
+
 /*
  * Initialize RPCSEC_GSS module
  */
@@ -1604,8 +1690,13 @@ static int __init init_rpcsec_gss(void)
        err = gss_svc_init();
        if (err)
                goto out_unregister;
+       err = register_pernet_subsys(&rpcsec_gss_net_ops);
+       if (err)
+               goto out_svc_exit;
        rpc_init_wait_queue(&pipe_version_rpc_waitqueue, "gss pipe version");
        return 0;
+out_svc_exit:
+       gss_svc_shutdown();
 out_unregister:
        rpcauth_unregister(&authgss_ops);
 out:
@@ -1614,6 +1705,7 @@ out:
 
 static void __exit exit_rpcsec_gss(void)
 {
+       unregister_pernet_subsys(&rpcsec_gss_net_ops);
        gss_svc_shutdown();
        rpcauth_unregister(&authgss_ops);
        rcu_barrier(); /* Wait for completion of call_rcu()'s */
index 9576f35..0f43e89 100644 (file)
@@ -600,11 +600,14 @@ gss_krb5_cts_crypt(struct crypto_blkcipher *cipher, struct xdr_buf *buf,
        u32 ret;
        struct scatterlist sg[1];
        struct blkcipher_desc desc = { .tfm = cipher, .info = iv };
-       u8 data[crypto_blkcipher_blocksize(cipher) * 2];
+       u8 data[GSS_KRB5_MAX_BLOCKSIZE * 2];
        struct page **save_pages;
        u32 len = buf->len - offset;
 
-       BUG_ON(len > crypto_blkcipher_blocksize(cipher) * 2);
+       if (len > ARRAY_SIZE(data)) {
+               WARN_ON(0);
+               return -ENOMEM;
+       }
 
        /*
         * For encryption, we want to read from the cleartext
index 8c67890..8eff8c3 100644 (file)
@@ -344,7 +344,7 @@ out_err:
        return PTR_ERR(p);
 }
 
-struct crypto_blkcipher *
+static struct crypto_blkcipher *
 context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key)
 {
        struct crypto_blkcipher *cp;
index d7941ea..62ae327 100644 (file)
@@ -159,7 +159,7 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
        return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
 }
 
-u32
+static u32
 gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
                struct xdr_netobj *token)
 {
index 8d0f7d3..1600cfb 100644 (file)
@@ -48,6 +48,8 @@
 #include <linux/sunrpc/svcauth_gss.h>
 #include <linux/sunrpc/cache.h>
 
+#include "../netns.h"
+
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_AUTH
 #endif
@@ -75,10 +77,8 @@ struct rsi {
        int                     major_status, minor_status;
 };
 
-static struct cache_head *rsi_table[RSI_HASHMAX];
-static struct cache_detail rsi_cache;
-static struct rsi *rsi_update(struct rsi *new, struct rsi *old);
-static struct rsi *rsi_lookup(struct rsi *item);
+static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old);
+static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item);
 
 static void rsi_free(struct rsi *rsii)
 {
@@ -216,7 +216,7 @@ static int rsi_parse(struct cache_detail *cd,
        if (dup_to_netobj(&rsii.in_token, buf, len))
                goto out;
 
-       rsip = rsi_lookup(&rsii);
+       rsip = rsi_lookup(cd, &rsii);
        if (!rsip)
                goto out;
 
@@ -258,21 +258,20 @@ static int rsi_parse(struct cache_detail *cd,
        if (dup_to_netobj(&rsii.out_token, buf, len))
                goto out;
        rsii.h.expiry_time = expiry;
-       rsip = rsi_update(&rsii, rsip);
+       rsip = rsi_update(cd, &rsii, rsip);
        status = 0;
 out:
        rsi_free(&rsii);
        if (rsip)
-               cache_put(&rsip->h, &rsi_cache);
+               cache_put(&rsip->h, cd);
        else
                status = -ENOMEM;
        return status;
 }
 
-static struct cache_detail rsi_cache = {
+static struct cache_detail rsi_cache_template = {
        .owner          = THIS_MODULE,
        .hash_size      = RSI_HASHMAX,
-       .hash_table     = rsi_table,
        .name           = "auth.rpcsec.init",
        .cache_put      = rsi_put,
        .cache_upcall   = rsi_upcall,
@@ -283,24 +282,24 @@ static struct cache_detail rsi_cache = {
        .alloc          = rsi_alloc,
 };
 
-static struct rsi *rsi_lookup(struct rsi *item)
+static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item)
 {
        struct cache_head *ch;
        int hash = rsi_hash(item);
 
-       ch = sunrpc_cache_lookup(&rsi_cache, &item->h, hash);
+       ch = sunrpc_cache_lookup(cd, &item->h, hash);
        if (ch)
                return container_of(ch, struct rsi, h);
        else
                return NULL;
 }
 
-static struct rsi *rsi_update(struct rsi *new, struct rsi *old)
+static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old)
 {
        struct cache_head *ch;
        int hash = rsi_hash(new);
 
-       ch = sunrpc_cache_update(&rsi_cache, &new->h,
+       ch = sunrpc_cache_update(cd, &new->h,
                                 &old->h, hash);
        if (ch)
                return container_of(ch, struct rsi, h);
@@ -339,10 +338,8 @@ struct rsc {
        char                    *client_name;
 };
 
-static struct cache_head *rsc_table[RSC_HASHMAX];
-static struct cache_detail rsc_cache;
-static struct rsc *rsc_update(struct rsc *new, struct rsc *old);
-static struct rsc *rsc_lookup(struct rsc *item);
+static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old);
+static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item);
 
 static void rsc_free(struct rsc *rsci)
 {
@@ -444,7 +441,7 @@ static int rsc_parse(struct cache_detail *cd,
        if (expiry == 0)
                goto out;
 
-       rscp = rsc_lookup(&rsci);
+       rscp = rsc_lookup(cd, &rsci);
        if (!rscp)
                goto out;
 
@@ -506,22 +503,21 @@ static int rsc_parse(struct cache_detail *cd,
 
        }
        rsci.h.expiry_time = expiry;
-       rscp = rsc_update(&rsci, rscp);
+       rscp = rsc_update(cd, &rsci, rscp);
        status = 0;
 out:
        gss_mech_put(gm);
        rsc_free(&rsci);
        if (rscp)
-               cache_put(&rscp->h, &rsc_cache);
+               cache_put(&rscp->h, cd);
        else
                status = -ENOMEM;
        return status;
 }
 
-static struct cache_detail rsc_cache = {
+static struct cache_detail rsc_cache_template = {
        .owner          = THIS_MODULE,
        .hash_size      = RSC_HASHMAX,
-       .hash_table     = rsc_table,
        .name           = "auth.rpcsec.context",
        .cache_put      = rsc_put,
        .cache_parse    = rsc_parse,
@@ -531,24 +527,24 @@ static struct cache_detail rsc_cache = {
        .alloc          = rsc_alloc,
 };
 
-static struct rsc *rsc_lookup(struct rsc *item)
+static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item)
 {
        struct cache_head *ch;
        int hash = rsc_hash(item);
 
-       ch = sunrpc_cache_lookup(&rsc_cache, &item->h, hash);
+       ch = sunrpc_cache_lookup(cd, &item->h, hash);
        if (ch)
                return container_of(ch, struct rsc, h);
        else
                return NULL;
 }
 
-static struct rsc *rsc_update(struct rsc *new, struct rsc *old)
+static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old)
 {
        struct cache_head *ch;
        int hash = rsc_hash(new);
 
-       ch = sunrpc_cache_update(&rsc_cache, &new->h,
+       ch = sunrpc_cache_update(cd, &new->h,
                                 &old->h, hash);
        if (ch)
                return container_of(ch, struct rsc, h);
@@ -558,7 +554,7 @@ static struct rsc *rsc_update(struct rsc *new, struct rsc *old)
 
 
 static struct rsc *
-gss_svc_searchbyctx(struct xdr_netobj *handle)
+gss_svc_searchbyctx(struct cache_detail *cd, struct xdr_netobj *handle)
 {
        struct rsc rsci;
        struct rsc *found;
@@ -566,11 +562,11 @@ gss_svc_searchbyctx(struct xdr_netobj *handle)
        memset(&rsci, 0, sizeof(rsci));
        if (dup_to_netobj(&rsci.handle, handle->data, handle->len))
                return NULL;
-       found = rsc_lookup(&rsci);
+       found = rsc_lookup(cd, &rsci);
        rsc_free(&rsci);
        if (!found)
                return NULL;
-       if (cache_check(&rsc_cache, &found->h, NULL))
+       if (cache_check(cd, &found->h, NULL))
                return NULL;
        return found;
 }
@@ -968,20 +964,20 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
 }
 
 static inline int
-gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
+gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi *rsip)
 {
        struct rsc *rsci;
        int        rc;
 
        if (rsip->major_status != GSS_S_COMPLETE)
                return gss_write_null_verf(rqstp);
-       rsci = gss_svc_searchbyctx(&rsip->out_handle);
+       rsci = gss_svc_searchbyctx(cd, &rsip->out_handle);
        if (rsci == NULL) {
                rsip->major_status = GSS_S_NO_CONTEXT;
                return gss_write_null_verf(rqstp);
        }
        rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
-       cache_put(&rsci->h, &rsc_cache);
+       cache_put(&rsci->h, cd);
        return rc;
 }
 
@@ -1000,6 +996,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
        struct xdr_netobj tmpobj;
        struct rsi *rsip, rsikey;
        int ret;
+       struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
 
        /* Read the verifier; should be NULL: */
        *authp = rpc_autherr_badverf;
@@ -1028,17 +1025,17 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
        }
 
        /* Perform upcall, or find upcall result: */
-       rsip = rsi_lookup(&rsikey);
+       rsip = rsi_lookup(sn->rsi_cache, &rsikey);
        rsi_free(&rsikey);
        if (!rsip)
                return SVC_CLOSE;
-       if (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0)
+       if (cache_check(sn->rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0)
                /* No upcall result: */
                return SVC_CLOSE;
 
        ret = SVC_CLOSE;
        /* Got an answer to the upcall; use it: */
-       if (gss_write_init_verf(rqstp, rsip))
+       if (gss_write_init_verf(sn->rsc_cache, rqstp, rsip))
                goto out;
        if (resv->iov_len + 4 > PAGE_SIZE)
                goto out;
@@ -1055,7 +1052,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
 
        ret = SVC_COMPLETE;
 out:
-       cache_put(&rsip->h, &rsi_cache);
+       cache_put(&rsip->h, sn->rsi_cache);
        return ret;
 }
 
@@ -1079,6 +1076,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
        __be32          *rpcstart;
        __be32          *reject_stat = resv->iov_base + resv->iov_len;
        int             ret;
+       struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
 
        dprintk("RPC:       svcauth_gss: argv->iov_len = %zd\n",
                        argv->iov_len);
@@ -1129,7 +1127,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
        case RPC_GSS_PROC_DESTROY:
                /* Look up the context, and check the verifier: */
                *authp = rpcsec_gsserr_credproblem;
-               rsci = gss_svc_searchbyctx(&gc->gc_ctx);
+               rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx);
                if (!rsci)
                        goto auth_err;
                switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) {
@@ -1209,7 +1207,7 @@ drop:
        ret = SVC_DROP;
 out:
        if (rsci)
-               cache_put(&rsci->h, &rsc_cache);
+               cache_put(&rsci->h, sn->rsc_cache);
        return ret;
 }
 
@@ -1362,6 +1360,7 @@ svcauth_gss_release(struct svc_rqst *rqstp)
        struct rpc_gss_wire_cred *gc = &gsd->clcred;
        struct xdr_buf *resbuf = &rqstp->rq_res;
        int stat = -EINVAL;
+       struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);
 
        if (gc->gc_proc != RPC_GSS_PROC_DATA)
                goto out;
@@ -1404,7 +1403,7 @@ out_err:
                put_group_info(rqstp->rq_cred.cr_group_info);
        rqstp->rq_cred.cr_group_info = NULL;
        if (gsd->rsci)
-               cache_put(&gsd->rsci->h, &rsc_cache);
+               cache_put(&gsd->rsci->h, sn->rsc_cache);
        gsd->rsci = NULL;
 
        return stat;
@@ -1429,30 +1428,96 @@ static struct auth_ops svcauthops_gss = {
        .set_client     = svcauth_gss_set_client,
 };
 
+static int rsi_cache_create_net(struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct cache_detail *cd;
+       int err;
+
+       cd = cache_create_net(&rsi_cache_template, net);
+       if (IS_ERR(cd))
+               return PTR_ERR(cd);
+       err = cache_register_net(cd, net);
+       if (err) {
+               cache_destroy_net(cd, net);
+               return err;
+       }
+       sn->rsi_cache = cd;
+       return 0;
+}
+
+static void rsi_cache_destroy_net(struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct cache_detail *cd = sn->rsi_cache;
+
+       sn->rsi_cache = NULL;
+       cache_purge(cd);
+       cache_unregister_net(cd, net);
+       cache_destroy_net(cd, net);
+}
+
+static int rsc_cache_create_net(struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct cache_detail *cd;
+       int err;
+
+       cd = cache_create_net(&rsc_cache_template, net);
+       if (IS_ERR(cd))
+               return PTR_ERR(cd);
+       err = cache_register_net(cd, net);
+       if (err) {
+               cache_destroy_net(cd, net);
+               return err;
+       }
+       sn->rsc_cache = cd;
+       return 0;
+}
+
+static void rsc_cache_destroy_net(struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct cache_detail *cd = sn->rsc_cache;
+
+       sn->rsc_cache = NULL;
+       cache_purge(cd);
+       cache_unregister_net(cd, net);
+       cache_destroy_net(cd, net);
+}
+
 int
-gss_svc_init(void)
+gss_svc_init_net(struct net *net)
 {
-       int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
+       int rv;
+
+       rv = rsc_cache_create_net(net);
        if (rv)
                return rv;
-       rv = cache_register(&rsc_cache);
+       rv = rsi_cache_create_net(net);
        if (rv)
                goto out1;
-       rv = cache_register(&rsi_cache);
-       if (rv)
-               goto out2;
        return 0;
-out2:
-       cache_unregister(&rsc_cache);
 out1:
-       svc_auth_unregister(RPC_AUTH_GSS);
+       rsc_cache_destroy_net(net);
        return rv;
 }
 
 void
+gss_svc_shutdown_net(struct net *net)
+{
+       rsi_cache_destroy_net(net);
+       rsc_cache_destroy_net(net);
+}
+
+int
+gss_svc_init(void)
+{
+       return svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
+}
+
+void
 gss_svc_shutdown(void)
 {
-       cache_unregister(&rsc_cache);
-       cache_unregister(&rsi_cache);
        svc_auth_unregister(RPC_AUTH_GSS);
 }
index 3ad435a..31def68 100644 (file)
@@ -25,6 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <linux/slab.h>
 #include <linux/sunrpc/xprt.h>
 #include <linux/export.h>
+#include <linux/sunrpc/bc_xprt.h>
 
 #ifdef RPC_DEBUG
 #define RPCDBG_FACILITY        RPCDBG_TRANS
index 465df9a..f21ece0 100644 (file)
@@ -344,7 +344,7 @@ static int current_index;
 static void do_cache_clean(struct work_struct *work);
 static struct delayed_work cache_cleaner;
 
-static void sunrpc_init_cache_detail(struct cache_detail *cd)
+void sunrpc_init_cache_detail(struct cache_detail *cd)
 {
        rwlock_init(&cd->hash_lock);
        INIT_LIST_HEAD(&cd->queue);
@@ -360,8 +360,9 @@ static void sunrpc_init_cache_detail(struct cache_detail *cd)
        /* start the cleaning process */
        schedule_delayed_work(&cache_cleaner, 0);
 }
+EXPORT_SYMBOL_GPL(sunrpc_init_cache_detail);
 
-static void sunrpc_destroy_cache_detail(struct cache_detail *cd)
+void sunrpc_destroy_cache_detail(struct cache_detail *cd)
 {
        cache_purge(cd);
        spin_lock(&cache_list_lock);
@@ -384,6 +385,7 @@ static void sunrpc_destroy_cache_detail(struct cache_detail *cd)
 out:
        printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name);
 }
+EXPORT_SYMBOL_GPL(sunrpc_destroy_cache_detail);
 
 /* clean cache tries to find something to clean
  * and cleans it.
@@ -1643,12 +1645,6 @@ int cache_register_net(struct cache_detail *cd, struct net *net)
 }
 EXPORT_SYMBOL_GPL(cache_register_net);
 
-int cache_register(struct cache_detail *cd)
-{
-       return cache_register_net(cd, &init_net);
-}
-EXPORT_SYMBOL_GPL(cache_register);
-
 void cache_unregister_net(struct cache_detail *cd, struct net *net)
 {
        remove_cache_proc_entries(cd, net);
@@ -1656,11 +1652,31 @@ void cache_unregister_net(struct cache_detail *cd, struct net *net)
 }
 EXPORT_SYMBOL_GPL(cache_unregister_net);
 
-void cache_unregister(struct cache_detail *cd)
+struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net)
+{
+       struct cache_detail *cd;
+
+       cd = kmemdup(tmpl, sizeof(struct cache_detail), GFP_KERNEL);
+       if (cd == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       cd->hash_table = kzalloc(cd->hash_size * sizeof(struct cache_head *),
+                                GFP_KERNEL);
+       if (cd->hash_table == NULL) {
+               kfree(cd);
+               return ERR_PTR(-ENOMEM);
+       }
+       cd->net = net;
+       return cd;
+}
+EXPORT_SYMBOL_GPL(cache_create_net);
+
+void cache_destroy_net(struct cache_detail *cd, struct net *net)
 {
-       cache_unregister_net(cd, &init_net);
+       kfree(cd->hash_table);
+       kfree(cd);
 }
-EXPORT_SYMBOL_GPL(cache_unregister);
+EXPORT_SYMBOL_GPL(cache_destroy_net);
 
 static ssize_t cache_read_pipefs(struct file *filp, char __user *buf,
                                 size_t count, loff_t *ppos)
@@ -1787,17 +1803,14 @@ int sunrpc_cache_register_pipefs(struct dentry *parent,
        struct dentry *dir;
        int ret = 0;
 
-       sunrpc_init_cache_detail(cd);
        q.name = name;
        q.len = strlen(name);
        q.hash = full_name_hash(q.name, q.len);
        dir = rpc_create_cache_dir(parent, &q, umode, cd);
        if (!IS_ERR(dir))
                cd->u.pipefs.dir = dir;
-       else {
-               sunrpc_destroy_cache_detail(cd);
+       else
                ret = PTR_ERR(dir);
-       }
        return ret;
 }
 EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs);
@@ -1806,7 +1819,6 @@ void sunrpc_cache_unregister_pipefs(struct cache_detail *cd)
 {
        rpc_remove_cache_dir(cd->u.pipefs.dir);
        cd->u.pipefs.dir = NULL;
-       sunrpc_destroy_cache_detail(cd);
 }
 EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs);
 
index d3daab6..6797246 100644 (file)
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/un.h>
+#include <linux/rcupdate.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/metrics.h>
 #include <linux/sunrpc/bc_xprt.h>
+#include <trace/events/sunrpc.h>
 
 #include "sunrpc.h"
+#include "netns.h"
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_CALL
@@ -49,8 +52,6 @@
 /*
  * All RPC clients are linked into this list
  */
-static LIST_HEAD(all_clients);
-static DEFINE_SPINLOCK(rpc_client_lock);
 
 static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
 
@@ -80,82 +81,191 @@ static int rpc_ping(struct rpc_clnt *clnt);
 
 static void rpc_register_client(struct rpc_clnt *clnt)
 {
-       spin_lock(&rpc_client_lock);
-       list_add(&clnt->cl_clients, &all_clients);
-       spin_unlock(&rpc_client_lock);
+       struct net *net = rpc_net_ns(clnt);
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+       spin_lock(&sn->rpc_client_lock);
+       list_add(&clnt->cl_clients, &sn->all_clients);
+       spin_unlock(&sn->rpc_client_lock);
 }
 
 static void rpc_unregister_client(struct rpc_clnt *clnt)
 {
-       spin_lock(&rpc_client_lock);
+       struct net *net = rpc_net_ns(clnt);
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+       spin_lock(&sn->rpc_client_lock);
        list_del(&clnt->cl_clients);
-       spin_unlock(&rpc_client_lock);
+       spin_unlock(&sn->rpc_client_lock);
 }
 
-static int
-rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
+static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
+{
+       if (clnt->cl_dentry) {
+               if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy)
+                       clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth);
+               rpc_remove_client_dir(clnt->cl_dentry);
+       }
+       clnt->cl_dentry = NULL;
+}
+
+static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
+{
+       struct net *net = rpc_net_ns(clnt);
+       struct super_block *pipefs_sb;
+
+       pipefs_sb = rpc_get_sb_net(net);
+       if (pipefs_sb) {
+               __rpc_clnt_remove_pipedir(clnt);
+               rpc_put_sb_net(net);
+       }
+}
+
+static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
+                                   struct rpc_clnt *clnt,
+                                   const char *dir_name)
 {
        static uint32_t clntid;
-       struct path path, dir;
        char name[15];
        struct qstr q = {
                .name = name,
        };
+       struct dentry *dir, *dentry;
        int error;
 
-       clnt->cl_path.mnt = ERR_PTR(-ENOENT);
-       clnt->cl_path.dentry = ERR_PTR(-ENOENT);
-       if (dir_name == NULL)
-               return 0;
-
-       path.mnt = rpc_get_mount();
-       if (IS_ERR(path.mnt))
-               return PTR_ERR(path.mnt);
-       error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &dir);
-       if (error)
-               goto err;
-
+       dir = rpc_d_lookup_sb(sb, dir_name);
+       if (dir == NULL)
+               return dir;
        for (;;) {
                q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
                name[sizeof(name) - 1] = '\0';
                q.hash = full_name_hash(q.name, q.len);
-               path.dentry = rpc_create_client_dir(dir.dentry, &q, clnt);
-               if (!IS_ERR(path.dentry))
+               dentry = rpc_create_client_dir(dir, &q, clnt);
+               if (!IS_ERR(dentry))
                        break;
-               error = PTR_ERR(path.dentry);
+               error = PTR_ERR(dentry);
                if (error != -EEXIST) {
                        printk(KERN_INFO "RPC: Couldn't create pipefs entry"
                                        " %s/%s, error %d\n",
                                        dir_name, name, error);
-                       goto err_path_put;
+                       break;
                }
        }
-       path_put(&dir);
-       clnt->cl_path = path;
+       dput(dir);
+       return dentry;
+}
+
+static int
+rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name)
+{
+       struct net *net = rpc_net_ns(clnt);
+       struct super_block *pipefs_sb;
+       struct dentry *dentry;
+
+       clnt->cl_dentry = NULL;
+       if (dir_name == NULL)
+               return 0;
+       pipefs_sb = rpc_get_sb_net(net);
+       if (!pipefs_sb)
+               return 0;
+       dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name);
+       rpc_put_sb_net(net);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+       clnt->cl_dentry = dentry;
        return 0;
-err_path_put:
-       path_put(&dir);
-err:
-       rpc_put_mount();
+}
+
+static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
+                               struct super_block *sb)
+{
+       struct dentry *dentry;
+       int err = 0;
+
+       switch (event) {
+       case RPC_PIPEFS_MOUNT:
+               if (clnt->cl_program->pipe_dir_name == NULL)
+                       break;
+               dentry = rpc_setup_pipedir_sb(sb, clnt,
+                                             clnt->cl_program->pipe_dir_name);
+               BUG_ON(dentry == NULL);
+               if (IS_ERR(dentry))
+                       return PTR_ERR(dentry);
+               clnt->cl_dentry = dentry;
+               if (clnt->cl_auth->au_ops->pipes_create) {
+                       err = clnt->cl_auth->au_ops->pipes_create(clnt->cl_auth);
+                       if (err)
+                               __rpc_clnt_remove_pipedir(clnt);
+               }
+               break;
+       case RPC_PIPEFS_UMOUNT:
+               __rpc_clnt_remove_pipedir(clnt);
+               break;
+       default:
+               printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event);
+               return -ENOTSUPP;
+       }
+       return err;
+}
+
+static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct rpc_clnt *clnt;
+
+       spin_lock(&sn->rpc_client_lock);
+       list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
+               if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) ||
+                   ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry))
+                       continue;
+               atomic_inc(&clnt->cl_count);
+               spin_unlock(&sn->rpc_client_lock);
+               return clnt;
+       }
+       spin_unlock(&sn->rpc_client_lock);
+       return NULL;
+}
+
+static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
+                           void *ptr)
+{
+       struct super_block *sb = ptr;
+       struct rpc_clnt *clnt;
+       int error = 0;
+
+       while ((clnt = rpc_get_client_for_event(sb->s_fs_info, event))) {
+               error = __rpc_pipefs_event(clnt, event, sb);
+               rpc_release_client(clnt);
+               if (error)
+                       break;
+       }
        return error;
 }
 
+static struct notifier_block rpc_clients_block = {
+       .notifier_call  = rpc_pipefs_event,
+       .priority       = SUNRPC_PIPEFS_RPC_PRIO,
+};
+
+int rpc_clients_notifier_register(void)
+{
+       return rpc_pipefs_notifier_register(&rpc_clients_block);
+}
+
+void rpc_clients_notifier_unregister(void)
+{
+       return rpc_pipefs_notifier_unregister(&rpc_clients_block);
+}
+
 static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
 {
-       struct rpc_program      *program = args->program;
-       struct rpc_version      *version;
+       const struct rpc_program *program = args->program;
+       const struct rpc_version *version;
        struct rpc_clnt         *clnt = NULL;
        struct rpc_auth         *auth;
        int err;
-       size_t len;
 
        /* sanity check the name before trying to print it */
-       err = -EINVAL;
-       len = strlen(args->servername);
-       if (len > RPC_MAXNETNAMELEN)
-               goto out_no_rpciod;
-       len++;
-
        dprintk("RPC:       creating %s client for %s (xprt %p)\n",
                        program->name, args->servername, xprt);
 
@@ -178,17 +288,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
                goto out_err;
        clnt->cl_parent = clnt;
 
-       clnt->cl_server = clnt->cl_inline_name;
-       if (len > sizeof(clnt->cl_inline_name)) {
-               char *buf = kmalloc(len, GFP_KERNEL);
-               if (buf != NULL)
-                       clnt->cl_server = buf;
-               else
-                       len = sizeof(clnt->cl_inline_name);
-       }
-       strlcpy(clnt->cl_server, args->servername, len);
-
-       clnt->cl_xprt     = xprt;
+       rcu_assign_pointer(clnt->cl_xprt, xprt);
        clnt->cl_procinfo = version->procs;
        clnt->cl_maxproc  = version->nrprocs;
        clnt->cl_protname = program->name;
@@ -203,7 +303,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
        INIT_LIST_HEAD(&clnt->cl_tasks);
        spin_lock_init(&clnt->cl_lock);
 
-       if (!xprt_bound(clnt->cl_xprt))
+       if (!xprt_bound(xprt))
                clnt->cl_autobind = 1;
 
        clnt->cl_timeout = xprt->timeout;
@@ -245,17 +345,12 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
        return clnt;
 
 out_no_auth:
-       if (!IS_ERR(clnt->cl_path.dentry)) {
-               rpc_remove_client_dir(clnt->cl_path.dentry);
-               rpc_put_mount();
-       }
+       rpc_clnt_remove_pipedir(clnt);
 out_no_path:
        kfree(clnt->cl_principal);
 out_no_principal:
        rpc_free_iostats(clnt->cl_metrics);
 out_no_stats:
-       if (clnt->cl_server != clnt->cl_inline_name)
-               kfree(clnt->cl_server);
        kfree(clnt);
 out_err:
        xprt_put(xprt);
@@ -285,6 +380,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
                .srcaddr = args->saddress,
                .dstaddr = args->address,
                .addrlen = args->addrsize,
+               .servername = args->servername,
                .bc_xprt = args->bc_xprt,
        };
        char servername[48];
@@ -293,7 +389,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
         * If the caller chooses not to specify a hostname, whip
         * up a string representation of the passed-in address.
         */
-       if (args->servername == NULL) {
+       if (xprtargs.servername == NULL) {
                struct sockaddr_un *sun =
                                (struct sockaddr_un *)args->address;
                struct sockaddr_in *sin =
@@ -320,7 +416,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
                         * address family isn't recognized. */
                        return ERR_PTR(-EINVAL);
                }
-               args->servername = servername;
+               xprtargs.servername = servername;
        }
 
        xprt = xprt_create_transport(&xprtargs);
@@ -373,6 +469,7 @@ struct rpc_clnt *
 rpc_clone_client(struct rpc_clnt *clnt)
 {
        struct rpc_clnt *new;
+       struct rpc_xprt *xprt;
        int err = -ENOMEM;
 
        new = kmemdup(clnt, sizeof(*new), GFP_KERNEL);
@@ -392,18 +489,25 @@ rpc_clone_client(struct rpc_clnt *clnt)
                if (new->cl_principal == NULL)
                        goto out_no_principal;
        }
+       rcu_read_lock();
+       xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
+       rcu_read_unlock();
+       if (xprt == NULL)
+               goto out_no_transport;
+       rcu_assign_pointer(new->cl_xprt, xprt);
        atomic_set(&new->cl_count, 1);
        err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
        if (err != 0)
                goto out_no_path;
        if (new->cl_auth)
                atomic_inc(&new->cl_auth->au_count);
-       xprt_get(clnt->cl_xprt);
        atomic_inc(&clnt->cl_count);
        rpc_register_client(new);
        rpciod_up();
        return new;
 out_no_path:
+       xprt_put(xprt);
+out_no_transport:
        kfree(new->cl_principal);
 out_no_principal:
        rpc_free_iostats(new->cl_metrics);
@@ -452,8 +556,9 @@ EXPORT_SYMBOL_GPL(rpc_killall_tasks);
  */
 void rpc_shutdown_client(struct rpc_clnt *clnt)
 {
-       dprintk("RPC:       shutting down %s client for %s\n",
-                       clnt->cl_protname, clnt->cl_server);
+       dprintk_rcu("RPC:       shutting down %s client for %s\n",
+                       clnt->cl_protname,
+                       rcu_dereference(clnt->cl_xprt)->servername);
 
        while (!list_empty(&clnt->cl_tasks)) {
                rpc_killall_tasks(clnt);
@@ -471,24 +576,17 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client);
 static void
 rpc_free_client(struct rpc_clnt *clnt)
 {
-       dprintk("RPC:       destroying %s client for %s\n",
-                       clnt->cl_protname, clnt->cl_server);
-       if (!IS_ERR(clnt->cl_path.dentry)) {
-               rpc_remove_client_dir(clnt->cl_path.dentry);
-               rpc_put_mount();
-       }
-       if (clnt->cl_parent != clnt) {
+       dprintk_rcu("RPC:       destroying %s client for %s\n",
+                       clnt->cl_protname,
+                       rcu_dereference(clnt->cl_xprt)->servername);
+       if (clnt->cl_parent != clnt)
                rpc_release_client(clnt->cl_parent);
-               goto out_free;
-       }
-       if (clnt->cl_server != clnt->cl_inline_name)
-               kfree(clnt->cl_server);
-out_free:
        rpc_unregister_client(clnt);
+       rpc_clnt_remove_pipedir(clnt);
        rpc_free_iostats(clnt->cl_metrics);
        kfree(clnt->cl_principal);
        clnt->cl_metrics = NULL;
-       xprt_put(clnt->cl_xprt);
+       xprt_put(rcu_dereference_raw(clnt->cl_xprt));
        rpciod_down();
        kfree(clnt);
 }
@@ -541,11 +639,11 @@ rpc_release_client(struct rpc_clnt *clnt)
  * The Sun NFSv2/v3 ACL protocol can do this.
  */
 struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
-                                     struct rpc_program *program,
+                                     const struct rpc_program *program,
                                      u32 vers)
 {
        struct rpc_clnt *clnt;
-       struct rpc_version *version;
+       const struct rpc_version *version;
        int err;
 
        BUG_ON(vers >= program->nrvers || !program->version[vers]);
@@ -777,13 +875,18 @@ EXPORT_SYMBOL_GPL(rpc_call_start);
 size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize)
 {
        size_t bytes;
-       struct rpc_xprt *xprt = clnt->cl_xprt;
+       struct rpc_xprt *xprt;
 
-       bytes = sizeof(xprt->addr);
+       rcu_read_lock();
+       xprt = rcu_dereference(clnt->cl_xprt);
+
+       bytes = xprt->addrlen;
        if (bytes > bufsize)
                bytes = bufsize;
-       memcpy(buf, &clnt->cl_xprt->addr, bytes);
-       return xprt->addrlen;
+       memcpy(buf, &xprt->addr, bytes);
+       rcu_read_unlock();
+
+       return bytes;
 }
 EXPORT_SYMBOL_GPL(rpc_peeraddr);
 
@@ -792,11 +895,16 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr);
  * @clnt: RPC client structure
  * @format: address format
  *
+ * NB: the lifetime of the memory referenced by the returned pointer is
+ * the same as the rpc_xprt itself.  As long as the caller uses this
+ * pointer, it must hold the RCU read lock.
  */
 const char *rpc_peeraddr2str(struct rpc_clnt *clnt,
                             enum rpc_display_format_t format)
 {
-       struct rpc_xprt *xprt = clnt->cl_xprt;
+       struct rpc_xprt *xprt;
+
+       xprt = rcu_dereference(clnt->cl_xprt);
 
        if (xprt->address_strings[format] != NULL)
                return xprt->address_strings[format];
@@ -805,17 +913,203 @@ const char *rpc_peeraddr2str(struct rpc_clnt *clnt,
 }
 EXPORT_SYMBOL_GPL(rpc_peeraddr2str);
 
+static const struct sockaddr_in rpc_inaddr_loopback = {
+       .sin_family             = AF_INET,
+       .sin_addr.s_addr        = htonl(INADDR_ANY),
+};
+
+static const struct sockaddr_in6 rpc_in6addr_loopback = {
+       .sin6_family            = AF_INET6,
+       .sin6_addr              = IN6ADDR_ANY_INIT,
+};
+
+/*
+ * Try a getsockname() on a connected datagram socket.  Using a
+ * connected datagram socket prevents leaving a socket in TIME_WAIT.
+ * This conserves the ephemeral port number space.
+ *
+ * Returns zero and fills in "buf" if successful; otherwise, a
+ * negative errno is returned.
+ */
+static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen,
+                       struct sockaddr *buf, int buflen)
+{
+       struct socket *sock;
+       int err;
+
+       err = __sock_create(net, sap->sa_family,
+                               SOCK_DGRAM, IPPROTO_UDP, &sock, 1);
+       if (err < 0) {
+               dprintk("RPC:       can't create UDP socket (%d)\n", err);
+               goto out;
+       }
+
+       switch (sap->sa_family) {
+       case AF_INET:
+               err = kernel_bind(sock,
+                               (struct sockaddr *)&rpc_inaddr_loopback,
+                               sizeof(rpc_inaddr_loopback));
+               break;
+       case AF_INET6:
+               err = kernel_bind(sock,
+                               (struct sockaddr *)&rpc_in6addr_loopback,
+                               sizeof(rpc_in6addr_loopback));
+               break;
+       default:
+               err = -EAFNOSUPPORT;
+               goto out;
+       }
+       if (err < 0) {
+               dprintk("RPC:       can't bind UDP socket (%d)\n", err);
+               goto out_release;
+       }
+
+       err = kernel_connect(sock, sap, salen, 0);
+       if (err < 0) {
+               dprintk("RPC:       can't connect UDP socket (%d)\n", err);
+               goto out_release;
+       }
+
+       err = kernel_getsockname(sock, buf, &buflen);
+       if (err < 0) {
+               dprintk("RPC:       getsockname failed (%d)\n", err);
+               goto out_release;
+       }
+
+       err = 0;
+       if (buf->sa_family == AF_INET6) {
+               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf;
+               sin6->sin6_scope_id = 0;
+       }
+       dprintk("RPC:       %s succeeded\n", __func__);
+
+out_release:
+       sock_release(sock);
+out:
+       return err;
+}
+
+/*
+ * Scraping a connected socket failed, so we don't have a useable
+ * local address.  Fallback: generate an address that will prevent
+ * the server from calling us back.
+ *
+ * Returns zero and fills in "buf" if successful; otherwise, a
+ * negative errno is returned.
+ */
+static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen)
+{
+       switch (family) {
+       case AF_INET:
+               if (buflen < sizeof(rpc_inaddr_loopback))
+                       return -EINVAL;
+               memcpy(buf, &rpc_inaddr_loopback,
+                               sizeof(rpc_inaddr_loopback));
+               break;
+       case AF_INET6:
+               if (buflen < sizeof(rpc_in6addr_loopback))
+                       return -EINVAL;
+               memcpy(buf, &rpc_in6addr_loopback,
+                               sizeof(rpc_in6addr_loopback));
+       default:
+               dprintk("RPC:       %s: address family not supported\n",
+                       __func__);
+               return -EAFNOSUPPORT;
+       }
+       dprintk("RPC:       %s: succeeded\n", __func__);
+       return 0;
+}
+
+/**
+ * rpc_localaddr - discover local endpoint address for an RPC client
+ * @clnt: RPC client structure
+ * @buf: target buffer
+ * @buflen: size of target buffer, in bytes
+ *
+ * Returns zero and fills in "buf" and "buflen" if successful;
+ * otherwise, a negative errno is returned.
+ *
+ * This works even if the underlying transport is not currently connected,
+ * or if the upper layer never previously provided a source address.
+ *
+ * The result of this function call is transient: multiple calls in
+ * succession may give different results, depending on how local
+ * networking configuration changes over time.
+ */
+int rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen)
+{
+       struct sockaddr_storage address;
+       struct sockaddr *sap = (struct sockaddr *)&address;
+       struct rpc_xprt *xprt;
+       struct net *net;
+       size_t salen;
+       int err;
+
+       rcu_read_lock();
+       xprt = rcu_dereference(clnt->cl_xprt);
+       salen = xprt->addrlen;
+       memcpy(sap, &xprt->addr, salen);
+       net = get_net(xprt->xprt_net);
+       rcu_read_unlock();
+
+       rpc_set_port(sap, 0);
+       err = rpc_sockname(net, sap, salen, buf, buflen);
+       put_net(net);
+       if (err != 0)
+               /* Couldn't discover local address, return ANYADDR */
+               return rpc_anyaddr(sap->sa_family, buf, buflen);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rpc_localaddr);
+
 void
 rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
 {
-       struct rpc_xprt *xprt = clnt->cl_xprt;
+       struct rpc_xprt *xprt;
+
+       rcu_read_lock();
+       xprt = rcu_dereference(clnt->cl_xprt);
        if (xprt->ops->set_buffer_size)
                xprt->ops->set_buffer_size(xprt, sndsize, rcvsize);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(rpc_setbufsize);
 
-/*
- * Return size of largest payload RPC client can support, in bytes
+/**
+ * rpc_protocol - Get transport protocol number for an RPC client
+ * @clnt: RPC client to query
+ *
+ */
+int rpc_protocol(struct rpc_clnt *clnt)
+{
+       int protocol;
+
+       rcu_read_lock();
+       protocol = rcu_dereference(clnt->cl_xprt)->prot;
+       rcu_read_unlock();
+       return protocol;
+}
+EXPORT_SYMBOL_GPL(rpc_protocol);
+
+/**
+ * rpc_net_ns - Get the network namespace for this RPC client
+ * @clnt: RPC client to query
+ *
+ */
+struct net *rpc_net_ns(struct rpc_clnt *clnt)
+{
+       struct net *ret;
+
+       rcu_read_lock();
+       ret = rcu_dereference(clnt->cl_xprt)->xprt_net;
+       rcu_read_unlock();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(rpc_net_ns);
+
+/**
+ * rpc_max_payload - Get maximum payload size for a transport, in bytes
+ * @clnt: RPC client to query
  *
  * For stream transports, this is one RPC record fragment (see RFC
  * 1831), as we don't support multi-record requests yet.  For datagram
@@ -824,7 +1118,12 @@ EXPORT_SYMBOL_GPL(rpc_setbufsize);
  */
 size_t rpc_max_payload(struct rpc_clnt *clnt)
 {
-       return clnt->cl_xprt->max_payload;
+       size_t ret;
+
+       rcu_read_lock();
+       ret = rcu_dereference(clnt->cl_xprt)->max_payload;
+       rcu_read_unlock();
+       return ret;
 }
 EXPORT_SYMBOL_GPL(rpc_max_payload);
 
@@ -835,8 +1134,11 @@ EXPORT_SYMBOL_GPL(rpc_max_payload);
  */
 void rpc_force_rebind(struct rpc_clnt *clnt)
 {
-       if (clnt->cl_autobind)
-               xprt_clear_bound(clnt->cl_xprt);
+       if (clnt->cl_autobind) {
+               rcu_read_lock();
+               xprt_clear_bound(rcu_dereference(clnt->cl_xprt));
+               rcu_read_unlock();
+       }
 }
 EXPORT_SYMBOL_GPL(rpc_force_rebind);
 
@@ -1162,6 +1464,7 @@ call_bind_status(struct rpc_task *task)
                return;
        }
 
+       trace_rpc_bind_status(task);
        switch (task->tk_status) {
        case -ENOMEM:
                dprintk("RPC: %5u rpcbind out of memory\n", task->tk_pid);
@@ -1261,6 +1564,7 @@ call_connect_status(struct rpc_task *task)
                return;
        }
 
+       trace_rpc_connect_status(task, status);
        switch (status) {
                /* if soft mounted, test if we've timed out */
        case -ETIMEDOUT:
@@ -1449,6 +1753,7 @@ call_status(struct rpc_task *task)
                return;
        }
 
+       trace_rpc_call_status(task);
        task->tk_status = 0;
        switch(status) {
        case -EHOSTDOWN:
@@ -1512,8 +1817,11 @@ call_timeout(struct rpc_task *task)
        }
        if (RPC_IS_SOFT(task)) {
                if (clnt->cl_chatty)
+                       rcu_read_lock();
                        printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
-                               clnt->cl_protname, clnt->cl_server);
+                               clnt->cl_protname,
+                               rcu_dereference(clnt->cl_xprt)->servername);
+                       rcu_read_unlock();
                if (task->tk_flags & RPC_TASK_TIMEOUT)
                        rpc_exit(task, -ETIMEDOUT);
                else
@@ -1523,9 +1831,13 @@ call_timeout(struct rpc_task *task)
 
        if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) {
                task->tk_flags |= RPC_CALL_MAJORSEEN;
-               if (clnt->cl_chatty)
+               if (clnt->cl_chatty) {
+                       rcu_read_lock();
                        printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
-                       clnt->cl_protname, clnt->cl_server);
+                       clnt->cl_protname,
+                       rcu_dereference(clnt->cl_xprt)->servername);
+                       rcu_read_unlock();
+               }
        }
        rpc_force_rebind(clnt);
        /*
@@ -1554,9 +1866,13 @@ call_decode(struct rpc_task *task)
        dprint_status(task);
 
        if (task->tk_flags & RPC_CALL_MAJORSEEN) {
-               if (clnt->cl_chatty)
+               if (clnt->cl_chatty) {
+                       rcu_read_lock();
                        printk(KERN_NOTICE "%s: server %s OK\n",
-                               clnt->cl_protname, clnt->cl_server);
+                               clnt->cl_protname,
+                               rcu_dereference(clnt->cl_xprt)->servername);
+                       rcu_read_unlock();
+               }
                task->tk_flags &= ~RPC_CALL_MAJORSEEN;
        }
 
@@ -1634,6 +1950,7 @@ rpc_encode_header(struct rpc_task *task)
 static __be32 *
 rpc_verify_header(struct rpc_task *task)
 {
+       struct rpc_clnt *clnt = task->tk_client;
        struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
        int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
        __be32  *p = iov->iov_base;
@@ -1706,8 +2023,11 @@ rpc_verify_header(struct rpc_task *task)
                        task->tk_action = call_bind;
                        goto out_retry;
                case RPC_AUTH_TOOWEAK:
+                       rcu_read_lock();
                        printk(KERN_NOTICE "RPC: server %s requires stronger "
-                              "authentication.\n", task->tk_client->cl_server);
+                              "authentication.\n",
+                              rcu_dereference(clnt->cl_xprt)->servername);
+                       rcu_read_unlock();
                        break;
                default:
                        dprintk("RPC: %5u %s: unknown auth error: %x\n",
@@ -1730,28 +2050,27 @@ rpc_verify_header(struct rpc_task *task)
        case RPC_SUCCESS:
                return p;
        case RPC_PROG_UNAVAIL:
-               dprintk("RPC: %5u %s: program %u is unsupported by server %s\n",
-                               task->tk_pid, __func__,
-                               (unsigned int)task->tk_client->cl_prog,
-                               task->tk_client->cl_server);
+               dprintk_rcu("RPC: %5u %s: program %u is unsupported "
+                               "by server %s\n", task->tk_pid, __func__,
+                               (unsigned int)clnt->cl_prog,
+                               rcu_dereference(clnt->cl_xprt)->servername);
                error = -EPFNOSUPPORT;
                goto out_err;
        case RPC_PROG_MISMATCH:
-               dprintk("RPC: %5u %s: program %u, version %u unsupported by "
-                               "server %s\n", task->tk_pid, __func__,
-                               (unsigned int)task->tk_client->cl_prog,
-                               (unsigned int)task->tk_client->cl_vers,
-                               task->tk_client->cl_server);
+               dprintk_rcu("RPC: %5u %s: program %u, version %u unsupported "
+                               "by server %s\n", task->tk_pid, __func__,
+                               (unsigned int)clnt->cl_prog,
+                               (unsigned int)clnt->cl_vers,
+                               rcu_dereference(clnt->cl_xprt)->servername);
                error = -EPROTONOSUPPORT;
                goto out_err;
        case RPC_PROC_UNAVAIL:
-               dprintk("RPC: %5u %s: proc %s unsupported by program %u, "
+               dprintk_rcu("RPC: %5u %s: proc %s unsupported by program %u, "
                                "version %u on server %s\n",
                                task->tk_pid, __func__,
                                rpc_proc_name(task),
-                               task->tk_client->cl_prog,
-                               task->tk_client->cl_vers,
-                               task->tk_client->cl_server);
+                               clnt->cl_prog, clnt->cl_vers,
+                               rcu_dereference(clnt->cl_xprt)->servername);
                error = -EOPNOTSUPP;
                goto out_err;
        case RPC_GARBAGE_ARGS:
@@ -1765,7 +2084,7 @@ rpc_verify_header(struct rpc_task *task)
        }
 
 out_garbage:
-       task->tk_client->cl_stats->rpcgarbage++;
+       clnt->cl_stats->rpcgarbage++;
        if (task->tk_garb_retry) {
                task->tk_garb_retry--;
                dprintk("RPC: %5u %s: retrying\n",
@@ -1851,14 +2170,15 @@ static void rpc_show_task(const struct rpc_clnt *clnt,
                task->tk_action, rpc_waitq);
 }
 
-void rpc_show_tasks(void)
+void rpc_show_tasks(struct net *net)
 {
        struct rpc_clnt *clnt;
        struct rpc_task *task;
        int header = 0;
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
-       spin_lock(&rpc_client_lock);
-       list_for_each_entry(clnt, &all_clients, cl_clients) {
+       spin_lock(&sn->rpc_client_lock);
+       list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
                spin_lock(&clnt->cl_lock);
                list_for_each_entry(task, &clnt->cl_tasks, tk_task) {
                        if (!header) {
@@ -1869,6 +2189,6 @@ void rpc_show_tasks(void)
                }
                spin_unlock(&clnt->cl_lock);
        }
-       spin_unlock(&rpc_client_lock);
+       spin_unlock(&sn->rpc_client_lock);
 }
 #endif
index d013bf2..ce7bd44 100644 (file)
@@ -9,6 +9,20 @@ struct cache_detail;
 struct sunrpc_net {
        struct proc_dir_entry *proc_net_rpc;
        struct cache_detail *ip_map_cache;
+       struct cache_detail *unix_gid_cache;
+       struct cache_detail *rsc_cache;
+       struct cache_detail *rsi_cache;
+
+       struct super_block *pipefs_sb;
+       struct mutex pipefs_sb_lock;
+
+       struct list_head all_clients;
+       spinlock_t rpc_client_lock;
+
+       struct rpc_clnt *rpcb_local_clnt;
+       struct rpc_clnt *rpcb_local_clnt4;
+       spinlock_t rpcb_clnt_lock;
+       unsigned int rpcb_users;
 };
 
 extern int sunrpc_net_id;
index 7d6dd6e..c84c0e0 100644 (file)
@@ -16,9 +16,9 @@
 #include <linux/namei.h>
 #include <linux/fsnotify.h>
 #include <linux/kernel.h>
+#include <linux/rcupdate.h>
 
 #include <asm/ioctls.h>
-#include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/wait.h>
 #include <linux/seq_file.h>
 #include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/cache.h>
+#include <linux/nsproxy.h>
+#include <linux/notifier.h>
 
-static struct vfsmount *rpc_mnt __read_mostly;
-static int rpc_mount_count;
+#include "netns.h"
+#include "sunrpc.h"
+
+#define RPCDBG_FACILITY RPCDBG_DEBUG
+
+#define NET_NAME(net)  ((net == &init_net) ? " (init_net)" : "")
 
 static struct file_system_type rpc_pipe_fs_type;
 
@@ -38,7 +44,21 @@ static struct kmem_cache *rpc_inode_cachep __read_mostly;
 
 #define RPC_UPCALL_TIMEOUT (30*HZ)
 
-static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head,
+static BLOCKING_NOTIFIER_HEAD(rpc_pipefs_notifier_list);
+
+int rpc_pipefs_notifier_register(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_cond_register(&rpc_pipefs_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_register);
+
+void rpc_pipefs_notifier_unregister(struct notifier_block *nb)
+{
+       blocking_notifier_chain_unregister(&rpc_pipefs_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(rpc_pipefs_notifier_unregister);
+
+static void rpc_purge_list(wait_queue_head_t *waitq, struct list_head *head,
                void (*destroy_msg)(struct rpc_pipe_msg *), int err)
 {
        struct rpc_pipe_msg *msg;
@@ -51,30 +71,31 @@ static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head,
                msg->errno = err;
                destroy_msg(msg);
        } while (!list_empty(head));
-       wake_up(&rpci->waitq);
+       wake_up(waitq);
 }
 
 static void
 rpc_timeout_upcall_queue(struct work_struct *work)
 {
        LIST_HEAD(free_list);
-       struct rpc_inode *rpci =
-               container_of(work, struct rpc_inode, queue_timeout.work);
-       struct inode *inode = &rpci->vfs_inode;
+       struct rpc_pipe *pipe =
+               container_of(work, struct rpc_pipe, queue_timeout.work);
        void (*destroy_msg)(struct rpc_pipe_msg *);
+       struct dentry *dentry;
 
-       spin_lock(&inode->i_lock);
-       if (rpci->ops == NULL) {
-               spin_unlock(&inode->i_lock);
-               return;
+       spin_lock(&pipe->lock);
+       destroy_msg = pipe->ops->destroy_msg;
+       if (pipe->nreaders == 0) {
+               list_splice_init(&pipe->pipe, &free_list);
+               pipe->pipelen = 0;
        }
-       destroy_msg = rpci->ops->destroy_msg;
-       if (rpci->nreaders == 0) {
-               list_splice_init(&rpci->pipe, &free_list);
-               rpci->pipelen = 0;
+       dentry = dget(pipe->dentry);
+       spin_unlock(&pipe->lock);
+       if (dentry) {
+               rpc_purge_list(&RPC_I(dentry->d_inode)->waitq,
+                              &free_list, destroy_msg, -ETIMEDOUT);
+               dput(dentry);
        }
-       spin_unlock(&inode->i_lock);
-       rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT);
 }
 
 ssize_t rpc_pipe_generic_upcall(struct file *filp, struct rpc_pipe_msg *msg,
@@ -108,30 +129,31 @@ EXPORT_SYMBOL_GPL(rpc_pipe_generic_upcall);
  * initialize the fields of @msg (other than @msg->list) appropriately.
  */
 int
-rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
+rpc_queue_upcall(struct rpc_pipe *pipe, struct rpc_pipe_msg *msg)
 {
-       struct rpc_inode *rpci = RPC_I(inode);
        int res = -EPIPE;
+       struct dentry *dentry;
 
-       spin_lock(&inode->i_lock);
-       if (rpci->ops == NULL)
-               goto out;
-       if (rpci->nreaders) {
-               list_add_tail(&msg->list, &rpci->pipe);
-               rpci->pipelen += msg->len;
+       spin_lock(&pipe->lock);
+       if (pipe->nreaders) {
+               list_add_tail(&msg->list, &pipe->pipe);
+               pipe->pipelen += msg->len;
                res = 0;
-       } else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) {
-               if (list_empty(&rpci->pipe))
+       } else if (pipe->flags & RPC_PIPE_WAIT_FOR_OPEN) {
+               if (list_empty(&pipe->pipe))
                        queue_delayed_work(rpciod_workqueue,
-                                       &rpci->queue_timeout,
+                                       &pipe->queue_timeout,
                                        RPC_UPCALL_TIMEOUT);
-               list_add_tail(&msg->list, &rpci->pipe);
-               rpci->pipelen += msg->len;
+               list_add_tail(&msg->list, &pipe->pipe);
+               pipe->pipelen += msg->len;
                res = 0;
        }
-out:
-       spin_unlock(&inode->i_lock);
-       wake_up(&rpci->waitq);
+       dentry = dget(pipe->dentry);
+       spin_unlock(&pipe->lock);
+       if (dentry) {
+               wake_up(&RPC_I(dentry->d_inode)->waitq);
+               dput(dentry);
+       }
        return res;
 }
 EXPORT_SYMBOL_GPL(rpc_queue_upcall);
@@ -145,29 +167,26 @@ rpc_inode_setowner(struct inode *inode, void *private)
 static void
 rpc_close_pipes(struct inode *inode)
 {
-       struct rpc_inode *rpci = RPC_I(inode);
-       const struct rpc_pipe_ops *ops;
+       struct rpc_pipe *pipe = RPC_I(inode)->pipe;
        int need_release;
+       LIST_HEAD(free_list);
 
        mutex_lock(&inode->i_mutex);
-       ops = rpci->ops;
-       if (ops != NULL) {
-               LIST_HEAD(free_list);
-               spin_lock(&inode->i_lock);
-               need_release = rpci->nreaders != 0 || rpci->nwriters != 0;
-               rpci->nreaders = 0;
-               list_splice_init(&rpci->in_upcall, &free_list);
-               list_splice_init(&rpci->pipe, &free_list);
-               rpci->pipelen = 0;
-               rpci->ops = NULL;
-               spin_unlock(&inode->i_lock);
-               rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE);
-               rpci->nwriters = 0;
-               if (need_release && ops->release_pipe)
-                       ops->release_pipe(inode);
-               cancel_delayed_work_sync(&rpci->queue_timeout);
-       }
+       spin_lock(&pipe->lock);
+       need_release = pipe->nreaders != 0 || pipe->nwriters != 0;
+       pipe->nreaders = 0;
+       list_splice_init(&pipe->in_upcall, &free_list);
+       list_splice_init(&pipe->pipe, &free_list);
+       pipe->pipelen = 0;
+       pipe->dentry = NULL;
+       spin_unlock(&pipe->lock);
+       rpc_purge_list(&RPC_I(inode)->waitq, &free_list, pipe->ops->destroy_msg, -EPIPE);
+       pipe->nwriters = 0;
+       if (need_release && pipe->ops->release_pipe)
+               pipe->ops->release_pipe(inode);
+       cancel_delayed_work_sync(&pipe->queue_timeout);
        rpc_inode_setowner(inode, NULL);
+       RPC_I(inode)->pipe = NULL;
        mutex_unlock(&inode->i_mutex);
 }
 
@@ -197,23 +216,24 @@ rpc_destroy_inode(struct inode *inode)
 static int
 rpc_pipe_open(struct inode *inode, struct file *filp)
 {
-       struct rpc_inode *rpci = RPC_I(inode);
+       struct rpc_pipe *pipe;
        int first_open;
        int res = -ENXIO;
 
        mutex_lock(&inode->i_mutex);
-       if (rpci->ops == NULL)
+       pipe = RPC_I(inode)->pipe;
+       if (pipe == NULL)
                goto out;
-       first_open = rpci->nreaders == 0 && rpci->nwriters == 0;
-       if (first_open && rpci->ops->open_pipe) {
-               res = rpci->ops->open_pipe(inode);
+       first_open = pipe->nreaders == 0 && pipe->nwriters == 0;
+       if (first_open && pipe->ops->open_pipe) {
+               res = pipe->ops->open_pipe(inode);
                if (res)
                        goto out;
        }
        if (filp->f_mode & FMODE_READ)
-               rpci->nreaders++;
+               pipe->nreaders++;
        if (filp->f_mode & FMODE_WRITE)
-               rpci->nwriters++;
+               pipe->nwriters++;
        res = 0;
 out:
        mutex_unlock(&inode->i_mutex);
@@ -223,38 +243,39 @@ out:
 static int
 rpc_pipe_release(struct inode *inode, struct file *filp)
 {
-       struct rpc_inode *rpci = RPC_I(inode);
+       struct rpc_pipe *pipe;
        struct rpc_pipe_msg *msg;
        int last_close;
 
        mutex_lock(&inode->i_mutex);
-       if (rpci->ops == NULL)
+       pipe = RPC_I(inode)->pipe;
+       if (pipe == NULL)
                goto out;
        msg = filp->private_data;
        if (msg != NULL) {
-               spin_lock(&inode->i_lock);
+               spin_lock(&pipe->lock);
                msg->errno = -EAGAIN;
                list_del_init(&msg->list);
-               spin_unlock(&inode->i_lock);
-               rpci->ops->destroy_msg(msg);
+               spin_unlock(&pipe->lock);
+               pipe->ops->destroy_msg(msg);
        }
        if (filp->f_mode & FMODE_WRITE)
-               rpci->nwriters --;
+               pipe->nwriters --;
        if (filp->f_mode & FMODE_READ) {
-               rpci->nreaders --;
-               if (rpci->nreaders == 0) {
+               pipe->nreaders --;
+               if (pipe->nreaders == 0) {
                        LIST_HEAD(free_list);
-                       spin_lock(&inode->i_lock);
-                       list_splice_init(&rpci->pipe, &free_list);
-                       rpci->pipelen = 0;
-                       spin_unlock(&inode->i_lock);
-                       rpc_purge_list(rpci, &free_list,
-                                       rpci->ops->destroy_msg, -EAGAIN);
+                       spin_lock(&pipe->lock);
+                       list_splice_init(&pipe->pipe, &free_list);
+                       pipe->pipelen = 0;
+                       spin_unlock(&pipe->lock);
+                       rpc_purge_list(&RPC_I(inode)->waitq, &free_list,
+                                       pipe->ops->destroy_msg, -EAGAIN);
                }
        }
-       last_close = rpci->nwriters == 0 && rpci->nreaders == 0;
-       if (last_close && rpci->ops->release_pipe)
-               rpci->ops->release_pipe(inode);
+       last_close = pipe->nwriters == 0 && pipe->nreaders == 0;
+       if (last_close && pipe->ops->release_pipe)
+               pipe->ops->release_pipe(inode);
 out:
        mutex_unlock(&inode->i_mutex);
        return 0;
@@ -264,39 +285,40 @@ static ssize_t
 rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
 {
        struct inode *inode = filp->f_path.dentry->d_inode;
-       struct rpc_inode *rpci = RPC_I(inode);
+       struct rpc_pipe *pipe;
        struct rpc_pipe_msg *msg;
        int res = 0;
 
        mutex_lock(&inode->i_mutex);
-       if (rpci->ops == NULL) {
+       pipe = RPC_I(inode)->pipe;
+       if (pipe == NULL) {
                res = -EPIPE;
                goto out_unlock;
        }
        msg = filp->private_data;
        if (msg == NULL) {
-               spin_lock(&inode->i_lock);
-               if (!list_empty(&rpci->pipe)) {
-                       msg = list_entry(rpci->pipe.next,
+               spin_lock(&pipe->lock);
+               if (!list_empty(&pipe->pipe)) {
+                       msg = list_entry(pipe->pipe.next,
                                        struct rpc_pipe_msg,
                                        list);
-                       list_move(&msg->list, &rpci->in_upcall);
-                       rpci->pipelen -= msg->len;
+                       list_move(&msg->list, &pipe->in_upcall);
+                       pipe->pipelen -= msg->len;
                        filp->private_data = msg;
                        msg->copied = 0;
                }
-               spin_unlock(&inode->i_lock);
+               spin_unlock(&pipe->lock);
                if (msg == NULL)
                        goto out_unlock;
        }
        /* NOTE: it is up to the callback to update msg->copied */
-       res = rpci->ops->upcall(filp, msg, buf, len);
+       res = pipe->ops->upcall(filp, msg, buf, len);
        if (res < 0 || msg->len == msg->copied) {
                filp->private_data = NULL;
-               spin_lock(&inode->i_lock);
+               spin_lock(&pipe->lock);
                list_del_init(&msg->list);
-               spin_unlock(&inode->i_lock);
-               rpci->ops->destroy_msg(msg);
+               spin_unlock(&pipe->lock);
+               pipe->ops->destroy_msg(msg);
        }
 out_unlock:
        mutex_unlock(&inode->i_mutex);
@@ -307,13 +329,12 @@ static ssize_t
 rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
 {
        struct inode *inode = filp->f_path.dentry->d_inode;
-       struct rpc_inode *rpci = RPC_I(inode);
        int res;
 
        mutex_lock(&inode->i_mutex);
        res = -EPIPE;
-       if (rpci->ops != NULL)
-               res = rpci->ops->downcall(filp, buf, len);
+       if (RPC_I(inode)->pipe != NULL)
+               res = RPC_I(inode)->pipe->ops->downcall(filp, buf, len);
        mutex_unlock(&inode->i_mutex);
        return res;
 }
@@ -321,17 +342,18 @@ rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *of
 static unsigned int
 rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait)
 {
-       struct rpc_inode *rpci;
-       unsigned int mask = 0;
+       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct rpc_inode *rpci = RPC_I(inode);
+       unsigned int mask = POLLOUT | POLLWRNORM;
 
-       rpci = RPC_I(filp->f_path.dentry->d_inode);
        poll_wait(filp, &rpci->waitq, wait);
 
-       mask = POLLOUT | POLLWRNORM;
-       if (rpci->ops == NULL)
+       mutex_lock(&inode->i_mutex);
+       if (rpci->pipe == NULL)
                mask |= POLLERR | POLLHUP;
-       if (filp->private_data || !list_empty(&rpci->pipe))
+       else if (filp->private_data || !list_empty(&rpci->pipe->pipe))
                mask |= POLLIN | POLLRDNORM;
+       mutex_unlock(&inode->i_mutex);
        return mask;
 }
 
@@ -339,23 +361,26 @@ static long
 rpc_pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct inode *inode = filp->f_path.dentry->d_inode;
-       struct rpc_inode *rpci = RPC_I(inode);
+       struct rpc_pipe *pipe;
        int len;
 
        switch (cmd) {
        case FIONREAD:
-               spin_lock(&inode->i_lock);
-               if (rpci->ops == NULL) {
-                       spin_unlock(&inode->i_lock);
+               mutex_lock(&inode->i_mutex);
+               pipe = RPC_I(inode)->pipe;
+               if (pipe == NULL) {
+                       mutex_unlock(&inode->i_mutex);
                        return -EPIPE;
                }
-               len = rpci->pipelen;
+               spin_lock(&pipe->lock);
+               len = pipe->pipelen;
                if (filp->private_data) {
                        struct rpc_pipe_msg *msg;
                        msg = filp->private_data;
                        len += msg->len - msg->copied;
                }
-               spin_unlock(&inode->i_lock);
+               spin_unlock(&pipe->lock);
+               mutex_unlock(&inode->i_mutex);
                return put_user(len, (int __user *)arg);
        default:
                return -EINVAL;
@@ -378,12 +403,15 @@ rpc_show_info(struct seq_file *m, void *v)
 {
        struct rpc_clnt *clnt = m->private;
 
-       seq_printf(m, "RPC server: %s\n", clnt->cl_server);
+       rcu_read_lock();
+       seq_printf(m, "RPC server: %s\n",
+                       rcu_dereference(clnt->cl_xprt)->servername);
        seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname,
                        clnt->cl_prog, clnt->cl_vers);
        seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
        seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
        seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT));
+       rcu_read_unlock();
        return 0;
 }
 
@@ -440,23 +468,6 @@ struct rpc_filelist {
        umode_t mode;
 };
 
-struct vfsmount *rpc_get_mount(void)
-{
-       int err;
-
-       err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mnt, &rpc_mount_count);
-       if (err != 0)
-               return ERR_PTR(err);
-       return rpc_mnt;
-}
-EXPORT_SYMBOL_GPL(rpc_get_mount);
-
-void rpc_put_mount(void)
-{
-       simple_release_fs(&rpc_mnt, &rpc_mount_count);
-}
-EXPORT_SYMBOL_GPL(rpc_put_mount);
-
 static int rpc_delete_dentry(const struct dentry *dentry)
 {
        return 1;
@@ -540,12 +551,47 @@ static int __rpc_mkdir(struct inode *dir, struct dentry *dentry,
        return 0;
 }
 
-static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry,
-                       umode_t mode,
-                       const struct file_operations *i_fop,
-                       void *private,
-                       const struct rpc_pipe_ops *ops,
-                       int flags)
+static void
+init_pipe(struct rpc_pipe *pipe)
+{
+       pipe->nreaders = 0;
+       pipe->nwriters = 0;
+       INIT_LIST_HEAD(&pipe->in_upcall);
+       INIT_LIST_HEAD(&pipe->in_downcall);
+       INIT_LIST_HEAD(&pipe->pipe);
+       pipe->pipelen = 0;
+       INIT_DELAYED_WORK(&pipe->queue_timeout,
+                           rpc_timeout_upcall_queue);
+       pipe->ops = NULL;
+       spin_lock_init(&pipe->lock);
+       pipe->dentry = NULL;
+}
+
+void rpc_destroy_pipe_data(struct rpc_pipe *pipe)
+{
+       kfree(pipe);
+}
+EXPORT_SYMBOL_GPL(rpc_destroy_pipe_data);
+
+struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags)
+{
+       struct rpc_pipe *pipe;
+
+       pipe = kzalloc(sizeof(struct rpc_pipe), GFP_KERNEL);
+       if (!pipe)
+               return ERR_PTR(-ENOMEM);
+       init_pipe(pipe);
+       pipe->ops = ops;
+       pipe->flags = flags;
+       return pipe;
+}
+EXPORT_SYMBOL_GPL(rpc_mkpipe_data);
+
+static int __rpc_mkpipe_dentry(struct inode *dir, struct dentry *dentry,
+                              umode_t mode,
+                              const struct file_operations *i_fop,
+                              void *private,
+                              struct rpc_pipe *pipe)
 {
        struct rpc_inode *rpci;
        int err;
@@ -554,10 +600,8 @@ static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry,
        if (err)
                return err;
        rpci = RPC_I(dentry->d_inode);
-       rpci->nkern_readwriters = 1;
        rpci->private = private;
-       rpci->flags = flags;
-       rpci->ops = ops;
+       rpci->pipe = pipe;
        fsnotify_create(dir, dentry);
        return 0;
 }
@@ -573,6 +617,22 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
        return ret;
 }
 
+int rpc_rmdir(struct dentry *dentry)
+{
+       struct dentry *parent;
+       struct inode *dir;
+       int error;
+
+       parent = dget_parent(dentry);
+       dir = parent->d_inode;
+       mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+       error = __rpc_rmdir(dir, dentry);
+       mutex_unlock(&dir->i_mutex);
+       dput(parent);
+       return error;
+}
+EXPORT_SYMBOL_GPL(rpc_rmdir);
+
 static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
 {
        int ret;
@@ -587,16 +647,12 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
 static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = dentry->d_inode;
-       struct rpc_inode *rpci = RPC_I(inode);
 
-       rpci->nkern_readwriters--;
-       if (rpci->nkern_readwriters != 0)
-               return 0;
        rpc_close_pipes(inode);
        return __rpc_unlink(dir, dentry);
 }
 
-static struct dentry *__rpc_lookup_create(struct dentry *parent,
+static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
                                          struct qstr *name)
 {
        struct dentry *dentry;
@@ -604,27 +660,13 @@ static struct dentry *__rpc_lookup_create(struct dentry *parent,
        dentry = d_lookup(parent, name);
        if (!dentry) {
                dentry = d_alloc(parent, name);
-               if (!dentry) {
-                       dentry = ERR_PTR(-ENOMEM);
-                       goto out_err;
-               }
+               if (!dentry)
+                       return ERR_PTR(-ENOMEM);
        }
-       if (!dentry->d_inode)
+       if (dentry->d_inode == NULL) {
                d_set_d_op(dentry, &rpc_dentry_operations);
-out_err:
-       return dentry;
-}
-
-static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
-                                         struct qstr *name)
-{
-       struct dentry *dentry;
-
-       dentry = __rpc_lookup_create(parent, name);
-       if (IS_ERR(dentry))
-               return dentry;
-       if (dentry->d_inode == NULL)
                return dentry;
+       }
        dput(dentry);
        return ERR_PTR(-EEXIST);
 }
@@ -779,7 +821,7 @@ static int rpc_rmdir_depopulate(struct dentry *dentry,
  * @private: private data to associate with the pipe, for the caller's use
  * @ops: operations defining the behavior of the pipe: upcall, downcall,
  *     release_pipe, open_pipe, and destroy_msg.
- * @flags: rpc_inode flags
+ * @flags: rpc_pipe flags
  *
  * Data is made available for userspace to read by calls to
  * rpc_queue_upcall().  The actual reads will result in calls to
@@ -792,9 +834,8 @@ static int rpc_rmdir_depopulate(struct dentry *dentry,
  * The @private argument passed here will be available to all these methods
  * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private.
  */
-struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,
-                         void *private, const struct rpc_pipe_ops *ops,
-                         int flags)
+struct dentry *rpc_mkpipe_dentry(struct dentry *parent, const char *name,
+                                void *private, struct rpc_pipe *pipe)
 {
        struct dentry *dentry;
        struct inode *dir = parent->d_inode;
@@ -802,9 +843,9 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,
        struct qstr q;
        int err;
 
-       if (ops->upcall == NULL)
+       if (pipe->ops->upcall == NULL)
                umode &= ~S_IRUGO;
-       if (ops->downcall == NULL)
+       if (pipe->ops->downcall == NULL)
                umode &= ~S_IWUGO;
 
        q.name = name;
@@ -812,24 +853,11 @@ struct dentry *rpc_mkpipe(struct dentry *parent, const char *name,
        q.hash = full_name_hash(q.name, q.len),
 
        mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
-       dentry = __rpc_lookup_create(parent, &q);
+       dentry = __rpc_lookup_create_exclusive(parent, &q);
        if (IS_ERR(dentry))
                goto out;
-       if (dentry->d_inode) {
-               struct rpc_inode *rpci = RPC_I(dentry->d_inode);
-               if (rpci->private != private ||
-                               rpci->ops != ops ||
-                               rpci->flags != flags) {
-                       dput (dentry);
-                       err = -EBUSY;
-                       goto out_err;
-               }
-               rpci->nkern_readwriters++;
-               goto out;
-       }
-
-       err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops,
-                          private, ops, flags);
+       err = __rpc_mkpipe_dentry(dir, dentry, umode, &rpc_pipe_fops,
+                                 private, pipe);
        if (err)
                goto out_err;
 out:
@@ -842,7 +870,7 @@ out_err:
                        err);
        goto out;
 }
-EXPORT_SYMBOL_GPL(rpc_mkpipe);
+EXPORT_SYMBOL_GPL(rpc_mkpipe_dentry);
 
 /**
  * rpc_unlink - remove a pipe
@@ -915,7 +943,7 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry,
 
 /**
  * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
- * @dentry: directory to remove
+ * @clnt: rpc client
  */
 int rpc_remove_client_dir(struct dentry *dentry)
 {
@@ -1020,11 +1048,64 @@ static const struct rpc_filelist files[] = {
        },
 };
 
+/*
+ * This call can be used only in RPC pipefs mount notification hooks.
+ */
+struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
+                              const unsigned char *dir_name)
+{
+       struct qstr dir = {
+               .name = dir_name,
+               .len = strlen(dir_name),
+               .hash = full_name_hash(dir_name, strlen(dir_name)),
+       };
+
+       return d_lookup(sb->s_root, &dir);
+}
+EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
+
+void rpc_pipefs_init_net(struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+       mutex_init(&sn->pipefs_sb_lock);
+}
+
+/*
+ * This call will be used for per network namespace operations calls.
+ * Note: Function will be returned with pipefs_sb_lock taken if superblock was
+ * found. This lock have to be released by rpc_put_sb_net() when all operations
+ * will be completed.
+ */
+struct super_block *rpc_get_sb_net(const struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+       mutex_lock(&sn->pipefs_sb_lock);
+       if (sn->pipefs_sb)
+               return sn->pipefs_sb;
+       mutex_unlock(&sn->pipefs_sb_lock);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(rpc_get_sb_net);
+
+void rpc_put_sb_net(const struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+       BUG_ON(sn->pipefs_sb == NULL);
+       mutex_unlock(&sn->pipefs_sb_lock);
+}
+EXPORT_SYMBOL_GPL(rpc_put_sb_net);
+
 static int
 rpc_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *inode;
        struct dentry *root;
+       struct net *net = data;
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       int err;
 
        sb->s_blocksize = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -1038,21 +1119,54 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
        if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
                return -ENOMEM;
+       dprintk("RPC:   sending pipefs MOUNT notification for net %p%s\n", net,
+                                                               NET_NAME(net));
+       err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
+                                          RPC_PIPEFS_MOUNT,
+                                          sb);
+       if (err)
+               goto err_depopulate;
+       sb->s_fs_info = get_net(net);
+       sn->pipefs_sb = sb;
        return 0;
+
+err_depopulate:
+       blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
+                                          RPC_PIPEFS_UMOUNT,
+                                          sb);
+       __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
+       return err;
 }
 
 static struct dentry *
 rpc_mount(struct file_system_type *fs_type,
                int flags, const char *dev_name, void *data)
 {
-       return mount_single(fs_type, flags, data, rpc_fill_super);
+       return mount_ns(fs_type, flags, current->nsproxy->net_ns, rpc_fill_super);
+}
+
+static void rpc_kill_sb(struct super_block *sb)
+{
+       struct net *net = sb->s_fs_info;
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+       mutex_lock(&sn->pipefs_sb_lock);
+       sn->pipefs_sb = NULL;
+       mutex_unlock(&sn->pipefs_sb_lock);
+       put_net(net);
+       dprintk("RPC:   sending pipefs UMOUNT notification for net %p%s\n", net,
+                                                               NET_NAME(net));
+       blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
+                                          RPC_PIPEFS_UMOUNT,
+                                          sb);
+       kill_litter_super(sb);
 }
 
 static struct file_system_type rpc_pipe_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "rpc_pipefs",
        .mount          = rpc_mount,
-       .kill_sb        = kill_litter_super,
+       .kill_sb        = rpc_kill_sb,
 };
 
 static void
@@ -1062,16 +1176,8 @@ init_once(void *foo)
 
        inode_init_once(&rpci->vfs_inode);
        rpci->private = NULL;
-       rpci->nreaders = 0;
-       rpci->nwriters = 0;
-       INIT_LIST_HEAD(&rpci->in_upcall);
-       INIT_LIST_HEAD(&rpci->in_downcall);
-       INIT_LIST_HEAD(&rpci->pipe);
-       rpci->pipelen = 0;
+       rpci->pipe = NULL;
        init_waitqueue_head(&rpci->waitq);
-       INIT_DELAYED_WORK(&rpci->queue_timeout,
-                           rpc_timeout_upcall_queue);
-       rpci->ops = NULL;
 }
 
 int register_rpc_pipefs(void)
@@ -1085,17 +1191,24 @@ int register_rpc_pipefs(void)
                                init_once);
        if (!rpc_inode_cachep)
                return -ENOMEM;
+       err = rpc_clients_notifier_register();
+       if (err)
+               goto err_notifier;
        err = register_filesystem(&rpc_pipe_fs_type);
-       if (err) {
-               kmem_cache_destroy(rpc_inode_cachep);
-               return err;
-       }
-
+       if (err)
+               goto err_register;
        return 0;
+
+err_register:
+       rpc_clients_notifier_unregister();
+err_notifier:
+       kmem_cache_destroy(rpc_inode_cachep);
+       return err;
 }
 
 void unregister_rpc_pipefs(void)
 {
+       rpc_clients_notifier_unregister();
        kmem_cache_destroy(rpc_inode_cachep);
        unregister_filesystem(&rpc_pipe_fs_type);
 }
index 8761bf8..207a746 100644 (file)
 #include <linux/errno.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/nsproxy.h>
 #include <net/ipv6.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/xprtsock.h>
 
+#include "netns.h"
+
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_BIND
 #endif
@@ -109,13 +112,7 @@ enum {
 
 static void                    rpcb_getport_done(struct rpc_task *, void *);
 static void                    rpcb_map_release(void *data);
-static struct rpc_program      rpcb_program;
-
-static struct rpc_clnt *       rpcb_local_clnt;
-static struct rpc_clnt *       rpcb_local_clnt4;
-
-DEFINE_SPINLOCK(rpcb_clnt_lock);
-unsigned int                   rpcb_users;
+static const struct rpc_program        rpcb_program;
 
 struct rpcbind_args {
        struct rpc_xprt *       r_xprt;
@@ -140,8 +137,8 @@ struct rpcb_info {
        struct rpc_procinfo *   rpc_proc;
 };
 
-static struct rpcb_info rpcb_next_version[];
-static struct rpcb_info rpcb_next_version6[];
+static const struct rpcb_info rpcb_next_version[];
+static const struct rpcb_info rpcb_next_version6[];
 
 static const struct rpc_call_ops rpcb_getport_ops = {
        .rpc_call_done          = rpcb_getport_done,
@@ -164,32 +161,34 @@ static void rpcb_map_release(void *data)
        kfree(map);
 }
 
-static int rpcb_get_local(void)
+static int rpcb_get_local(struct net *net)
 {
        int cnt;
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
-       spin_lock(&rpcb_clnt_lock);
-       if (rpcb_users)
-               rpcb_users++;
-       cnt = rpcb_users;
-       spin_unlock(&rpcb_clnt_lock);
+       spin_lock(&sn->rpcb_clnt_lock);
+       if (sn->rpcb_users)
+               sn->rpcb_users++;
+       cnt = sn->rpcb_users;
+       spin_unlock(&sn->rpcb_clnt_lock);
 
        return cnt;
 }
 
-void rpcb_put_local(void)
+void rpcb_put_local(struct net *net)
 {
-       struct rpc_clnt *clnt = rpcb_local_clnt;
-       struct rpc_clnt *clnt4 = rpcb_local_clnt4;
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct rpc_clnt *clnt = sn->rpcb_local_clnt;
+       struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4;
        int shutdown;
 
-       spin_lock(&rpcb_clnt_lock);
-       if (--rpcb_users == 0) {
-               rpcb_local_clnt = NULL;
-               rpcb_local_clnt4 = NULL;
+       spin_lock(&sn->rpcb_clnt_lock);
+       if (--sn->rpcb_users == 0) {
+               sn->rpcb_local_clnt = NULL;
+               sn->rpcb_local_clnt4 = NULL;
        }
-       shutdown = !rpcb_users;
-       spin_unlock(&rpcb_clnt_lock);
+       shutdown = !sn->rpcb_users;
+       spin_unlock(&sn->rpcb_clnt_lock);
 
        if (shutdown) {
                /*
@@ -202,30 +201,34 @@ void rpcb_put_local(void)
        }
 }
 
-static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4)
+static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt,
+                       struct rpc_clnt *clnt4)
 {
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
        /* Protected by rpcb_create_local_mutex */
-       rpcb_local_clnt = clnt;
-       rpcb_local_clnt4 = clnt4;
+       sn->rpcb_local_clnt = clnt;
+       sn->rpcb_local_clnt4 = clnt4;
        smp_wmb(); 
-       rpcb_users = 1;
+       sn->rpcb_users = 1;
        dprintk("RPC:       created new rpcb local clients (rpcb_local_clnt: "
-                       "%p, rpcb_local_clnt4: %p)\n", rpcb_local_clnt,
-                       rpcb_local_clnt4);
+                       "%p, rpcb_local_clnt4: %p) for net %p%s\n",
+                       sn->rpcb_local_clnt, sn->rpcb_local_clnt4,
+                       net, (net == &init_net) ? " (init_net)" : "");
 }
 
 /*
  * Returns zero on success, otherwise a negative errno value
  * is returned.
  */
-static int rpcb_create_local_unix(void)
+static int rpcb_create_local_unix(struct net *net)
 {
        static const struct sockaddr_un rpcb_localaddr_rpcbind = {
                .sun_family             = AF_LOCAL,
                .sun_path               = RPCBIND_SOCK_PATHNAME,
        };
        struct rpc_create_args args = {
-               .net            = &init_net,
+               .net            = net,
                .protocol       = XPRT_TRANSPORT_LOCAL,
                .address        = (struct sockaddr *)&rpcb_localaddr_rpcbind,
                .addrsize       = sizeof(rpcb_localaddr_rpcbind),
@@ -258,7 +261,7 @@ static int rpcb_create_local_unix(void)
                clnt4 = NULL;
        }
 
-       rpcb_set_local(clnt, clnt4);
+       rpcb_set_local(net, clnt, clnt4);
 
 out:
        return result;
@@ -268,7 +271,7 @@ out:
  * Returns zero on success, otherwise a negative errno value
  * is returned.
  */
-static int rpcb_create_local_net(void)
+static int rpcb_create_local_net(struct net *net)
 {
        static const struct sockaddr_in rpcb_inaddr_loopback = {
                .sin_family             = AF_INET,
@@ -276,7 +279,7 @@ static int rpcb_create_local_net(void)
                .sin_port               = htons(RPCBIND_PORT),
        };
        struct rpc_create_args args = {
-               .net            = &init_net,
+               .net            = net,
                .protocol       = XPRT_TRANSPORT_TCP,
                .address        = (struct sockaddr *)&rpcb_inaddr_loopback,
                .addrsize       = sizeof(rpcb_inaddr_loopback),
@@ -310,7 +313,7 @@ static int rpcb_create_local_net(void)
                clnt4 = NULL;
        }
 
-       rpcb_set_local(clnt, clnt4);
+       rpcb_set_local(net, clnt, clnt4);
 
 out:
        return result;
@@ -320,31 +323,32 @@ out:
  * Returns zero on success, otherwise a negative errno value
  * is returned.
  */
-int rpcb_create_local(void)
+int rpcb_create_local(struct net *net)
 {
        static DEFINE_MUTEX(rpcb_create_local_mutex);
        int result = 0;
 
-       if (rpcb_get_local())
+       if (rpcb_get_local(net))
                return result;
 
        mutex_lock(&rpcb_create_local_mutex);
-       if (rpcb_get_local())
+       if (rpcb_get_local(net))
                goto out;
 
-       if (rpcb_create_local_unix() != 0)
-               result = rpcb_create_local_net();
+       if (rpcb_create_local_unix(net) != 0)
+               result = rpcb_create_local_net(net);
 
 out:
        mutex_unlock(&rpcb_create_local_mutex);
        return result;
 }
 
-static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
-                                   size_t salen, int proto, u32 version)
+static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname,
+                                   struct sockaddr *srvaddr, size_t salen,
+                                   int proto, u32 version)
 {
        struct rpc_create_args args = {
-               .net            = &init_net,
+               .net            = net,
                .protocol       = proto,
                .address        = srvaddr,
                .addrsize       = salen,
@@ -420,7 +424,7 @@ static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg)
  * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
  * addresses).
  */
-int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
+int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short port)
 {
        struct rpcbind_args map = {
                .r_prog         = prog,
@@ -431,6 +435,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
        struct rpc_message msg = {
                .rpc_argp       = &map,
        };
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
        dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
                        "rpcbind\n", (port ? "" : "un"),
@@ -440,13 +445,14 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
        if (port)
                msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
 
-       return rpcb_register_call(rpcb_local_clnt, &msg);
+       return rpcb_register_call(sn->rpcb_local_clnt, &msg);
 }
 
 /*
  * Fill in AF_INET family-specific arguments to register
  */
-static int rpcb_register_inet4(const struct sockaddr *sap,
+static int rpcb_register_inet4(struct sunrpc_net *sn,
+                              const struct sockaddr *sap,
                               struct rpc_message *msg)
 {
        const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
@@ -465,7 +471,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap,
        if (port)
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
 
-       result = rpcb_register_call(rpcb_local_clnt4, msg);
+       result = rpcb_register_call(sn->rpcb_local_clnt4, msg);
        kfree(map->r_addr);
        return result;
 }
@@ -473,7 +479,8 @@ static int rpcb_register_inet4(const struct sockaddr *sap,
 /*
  * Fill in AF_INET6 family-specific arguments to register
  */
-static int rpcb_register_inet6(const struct sockaddr *sap,
+static int rpcb_register_inet6(struct sunrpc_net *sn,
+                              const struct sockaddr *sap,
                               struct rpc_message *msg)
 {
        const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
@@ -492,12 +499,13 @@ static int rpcb_register_inet6(const struct sockaddr *sap,
        if (port)
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
 
-       result = rpcb_register_call(rpcb_local_clnt4, msg);
+       result = rpcb_register_call(sn->rpcb_local_clnt4, msg);
        kfree(map->r_addr);
        return result;
 }
 
-static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
+static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn,
+                                            struct rpc_message *msg)
 {
        struct rpcbind_args *map = msg->rpc_argp;
 
@@ -508,7 +516,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
        map->r_addr = "";
        msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
 
-       return rpcb_register_call(rpcb_local_clnt4, msg);
+       return rpcb_register_call(sn->rpcb_local_clnt4, msg);
 }
 
 /**
@@ -554,7 +562,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
  * service on any IPv4 address, but not on IPv6.  The latter
  * advertises the service on all IPv4 and IPv6 addresses.
  */
-int rpcb_v4_register(const u32 program, const u32 version,
+int rpcb_v4_register(struct net *net, const u32 program, const u32 version,
                     const struct sockaddr *address, const char *netid)
 {
        struct rpcbind_args map = {
@@ -566,18 +574,19 @@ int rpcb_v4_register(const u32 program, const u32 version,
        struct rpc_message msg = {
                .rpc_argp       = &map,
        };
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
-       if (rpcb_local_clnt4 == NULL)
+       if (sn->rpcb_local_clnt4 == NULL)
                return -EPROTONOSUPPORT;
 
        if (address == NULL)
-               return rpcb_unregister_all_protofamilies(&msg);
+               return rpcb_unregister_all_protofamilies(sn, &msg);
 
        switch (address->sa_family) {
        case AF_INET:
-               return rpcb_register_inet4(address, &msg);
+               return rpcb_register_inet4(sn, address, &msg);
        case AF_INET6:
-               return rpcb_register_inet6(address, &msg);
+               return rpcb_register_inet6(sn, address, &msg);
        }
 
        return -EAFNOSUPPORT;
@@ -611,9 +620,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi
 static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt)
 {
        struct rpc_clnt *parent = clnt->cl_parent;
+       struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
 
        while (parent != clnt) {
-               if (parent->cl_xprt != clnt->cl_xprt)
+               if (rcu_dereference(parent->cl_xprt) != xprt)
                        break;
                if (clnt->cl_autobind)
                        break;
@@ -644,12 +654,16 @@ void rpcb_getport_async(struct rpc_task *task)
        size_t salen;
        int status;
 
-       clnt = rpcb_find_transport_owner(task->tk_client);
-       xprt = clnt->cl_xprt;
+       rcu_read_lock();
+       do {
+               clnt = rpcb_find_transport_owner(task->tk_client);
+               xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
+       } while (xprt == NULL);
+       rcu_read_unlock();
 
        dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
                task->tk_pid, __func__,
-               clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);
+               xprt->servername, clnt->cl_prog, clnt->cl_vers, xprt->prot);
 
        /* Put self on the wait queue to ensure we get notified if
         * some other task is already attempting to bind the port */
@@ -658,6 +672,7 @@ void rpcb_getport_async(struct rpc_task *task)
        if (xprt_test_and_set_binding(xprt)) {
                dprintk("RPC: %5u %s: waiting for another binder\n",
                        task->tk_pid, __func__);
+               xprt_put(xprt);
                return;
        }
 
@@ -699,8 +714,8 @@ void rpcb_getport_async(struct rpc_task *task)
        dprintk("RPC: %5u %s: trying rpcbind version %u\n",
                task->tk_pid, __func__, bind_version);
 
-       rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
-                               bind_version);
+       rpcb_clnt = rpcb_create(xprt->xprt_net, xprt->servername, sap, salen,
+                               xprt->prot, bind_version);
        if (IS_ERR(rpcb_clnt)) {
                status = PTR_ERR(rpcb_clnt);
                dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
@@ -725,7 +740,7 @@ void rpcb_getport_async(struct rpc_task *task)
        switch (bind_version) {
        case RPCBVERS_4:
        case RPCBVERS_3:
-               map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
+               map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID];
                map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC);
                map->r_owner = "";
                break;
@@ -754,6 +769,7 @@ bailout_release_client:
 bailout_nofree:
        rpcb_wake_rpcbind_waiters(xprt, status);
        task->tk_status = status;
+       xprt_put(xprt);
 }
 EXPORT_SYMBOL_GPL(rpcb_getport_async);
 
@@ -801,11 +817,11 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
 static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr,
                             const struct rpcbind_args *rpcb)
 {
-       struct rpc_task *task = req->rq_task;
        __be32 *p;
 
        dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n",
-                       task->tk_pid, task->tk_msg.rpc_proc->p_name,
+                       req->rq_task->tk_pid,
+                       req->rq_task->tk_msg.rpc_proc->p_name,
                        rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
 
        p = xdr_reserve_space(xdr, RPCB_mappingargs_sz << 2);
@@ -818,7 +834,6 @@ static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr,
 static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,
                            struct rpcbind_args *rpcb)
 {
-       struct rpc_task *task = req->rq_task;
        unsigned long port;
        __be32 *p;
 
@@ -829,8 +844,8 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,
                return -EIO;
 
        port = be32_to_cpup(p);
-       dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid,
-                       task->tk_msg.rpc_proc->p_name, port);
+       dprintk("RPC: %5u PMAP_%s result: %lu\n", req->rq_task->tk_pid,
+                       req->rq_task->tk_msg.rpc_proc->p_name, port);
        if (unlikely(port > USHRT_MAX))
                return -EIO;
 
@@ -841,7 +856,6 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,
 static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr,
                        unsigned int *boolp)
 {
-       struct rpc_task *task = req->rq_task;
        __be32 *p;
 
        p = xdr_inline_decode(xdr, 4);
@@ -853,7 +867,8 @@ static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr,
                *boolp = 1;
 
        dprintk("RPC: %5u RPCB_%s call %s\n",
-                       task->tk_pid, task->tk_msg.rpc_proc->p_name,
+                       req->rq_task->tk_pid,
+                       req->rq_task->tk_msg.rpc_proc->p_name,
                        (*boolp ? "succeeded" : "failed"));
        return 0;
 }
@@ -873,11 +888,11 @@ static void encode_rpcb_string(struct xdr_stream *xdr, const char *string,
 static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
                             const struct rpcbind_args *rpcb)
 {
-       struct rpc_task *task = req->rq_task;
        __be32 *p;
 
        dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n",
-                       task->tk_pid, task->tk_msg.rpc_proc->p_name,
+                       req->rq_task->tk_pid,
+                       req->rq_task->tk_msg.rpc_proc->p_name,
                        rpcb->r_prog, rpcb->r_vers,
                        rpcb->r_netid, rpcb->r_addr);
 
@@ -895,7 +910,6 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
 {
        struct sockaddr_storage address;
        struct sockaddr *sap = (struct sockaddr *)&address;
-       struct rpc_task *task = req->rq_task;
        __be32 *p;
        u32 len;
 
@@ -912,7 +926,7 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
         */
        if (len == 0) {
                dprintk("RPC: %5u RPCB reply: program not registered\n",
-                               task->tk_pid);
+                               req->rq_task->tk_pid);
                return 0;
        }
 
@@ -922,10 +936,11 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
        p = xdr_inline_decode(xdr, len);
        if (unlikely(p == NULL))
                goto out_fail;
-       dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid,
-                       task->tk_msg.rpc_proc->p_name, (char *)p);
+       dprintk("RPC: %5u RPCB_%s reply: %s\n", req->rq_task->tk_pid,
+                       req->rq_task->tk_msg.rpc_proc->p_name, (char *)p);
 
-       if (rpc_uaddr2sockaddr((char *)p, len, sap, sizeof(address)) == 0)
+       if (rpc_uaddr2sockaddr(req->rq_xprt->xprt_net, (char *)p, len,
+                               sap, sizeof(address)) == 0)
                goto out_fail;
        rpcb->r_port = rpc_get_port(sap);
 
@@ -933,7 +948,8 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
 
 out_fail:
        dprintk("RPC: %5u malformed RPCB_%s reply\n",
-                       task->tk_pid, task->tk_msg.rpc_proc->p_name);
+                       req->rq_task->tk_pid,
+                       req->rq_task->tk_msg.rpc_proc->p_name);
        return -EIO;
 }
 
@@ -1041,7 +1057,7 @@ static struct rpc_procinfo rpcb_procedures4[] = {
        },
 };
 
-static struct rpcb_info rpcb_next_version[] = {
+static const struct rpcb_info rpcb_next_version[] = {
        {
                .rpc_vers       = RPCBVERS_2,
                .rpc_proc       = &rpcb_procedures2[RPCBPROC_GETPORT],
@@ -1051,7 +1067,7 @@ static struct rpcb_info rpcb_next_version[] = {
        },
 };
 
-static struct rpcb_info rpcb_next_version6[] = {
+static const struct rpcb_info rpcb_next_version6[] = {
        {
                .rpc_vers       = RPCBVERS_4,
                .rpc_proc       = &rpcb_procedures4[RPCBPROC_GETADDR],
@@ -1065,25 +1081,25 @@ static struct rpcb_info rpcb_next_version6[] = {
        },
 };
 
-static struct rpc_version rpcb_version2 = {
+static const struct rpc_version rpcb_version2 = {
        .number         = RPCBVERS_2,
        .nrprocs        = ARRAY_SIZE(rpcb_procedures2),
        .procs          = rpcb_procedures2
 };
 
-static struct rpc_version rpcb_version3 = {
+static const struct rpc_version rpcb_version3 = {
        .number         = RPCBVERS_3,
        .nrprocs        = ARRAY_SIZE(rpcb_procedures3),
        .procs          = rpcb_procedures3
 };
 
-static struct rpc_version rpcb_version4 = {
+static const struct rpc_version rpcb_version4 = {
        .number         = RPCBVERS_4,
        .nrprocs        = ARRAY_SIZE(rpcb_procedures4),
        .procs          = rpcb_procedures4
 };
 
-static struct rpc_version *rpcb_version[] = {
+static const struct rpc_version *rpcb_version[] = {
        NULL,
        NULL,
        &rpcb_version2,
@@ -1093,7 +1109,7 @@ static struct rpc_version *rpcb_version[] = {
 
 static struct rpc_stat rpcb_stats;
 
-static struct rpc_program rpcb_program = {
+static const struct rpc_program rpcb_program = {
        .name           = "rpcbind",
        .number         = RPCBIND_PROGRAM,
        .nrvers         = ARRAY_SIZE(rpcb_version),
index 3341d89..994cfea 100644 (file)
@@ -28,6 +28,9 @@
 #define RPCDBG_FACILITY                RPCDBG_SCHED
 #endif
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/sunrpc.h>
+
 /*
  * RPC slabs and memory pools
  */
@@ -205,9 +208,7 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c
        queue->qlen = 0;
        setup_timer(&queue->timer_list.timer, __rpc_queue_timer_fn, (unsigned long)queue);
        INIT_LIST_HEAD(&queue->timer_list.list);
-#ifdef RPC_DEBUG
-       queue->name = qname;
-#endif
+       rpc_assign_waitqueue_name(queue, qname);
 }
 
 void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname)
@@ -251,6 +252,8 @@ static inline void rpc_task_set_debuginfo(struct rpc_task *task)
 
 static void rpc_set_active(struct rpc_task *task)
 {
+       trace_rpc_task_begin(task->tk_client, task, NULL);
+
        rpc_task_set_debuginfo(task);
        set_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
 }
@@ -267,6 +270,8 @@ static int rpc_complete_task(struct rpc_task *task)
        unsigned long flags;
        int ret;
 
+       trace_rpc_task_complete(task->tk_client, task, NULL);
+
        spin_lock_irqsave(&wq->lock, flags);
        clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
        ret = atomic_dec_and_test(&task->tk_count);
@@ -324,6 +329,8 @@ static void __rpc_sleep_on_priority(struct rpc_wait_queue *q,
        dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n",
                        task->tk_pid, rpc_qname(q), jiffies);
 
+       trace_rpc_task_sleep(task->tk_client, task, q);
+
        __rpc_add_wait_queue(q, task, queue_priority);
 
        BUG_ON(task->tk_callback != NULL);
@@ -378,6 +385,8 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task
                return;
        }
 
+       trace_rpc_task_wakeup(task->tk_client, task, queue);
+
        __rpc_remove_wait_queue(queue, task);
 
        rpc_make_runnable(task);
@@ -422,7 +431,7 @@ EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task);
 /*
  * Wake up the next task on a priority queue.
  */
-static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue)
+static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *queue)
 {
        struct list_head *q;
        struct rpc_task *task;
@@ -467,30 +476,54 @@ new_queue:
 new_owner:
        rpc_set_waitqueue_owner(queue, task->tk_owner);
 out:
-       rpc_wake_up_task_queue_locked(queue, task);
        return task;
 }
 
+static struct rpc_task *__rpc_find_next_queued(struct rpc_wait_queue *queue)
+{
+       if (RPC_IS_PRIORITY(queue))
+               return __rpc_find_next_queued_priority(queue);
+       if (!list_empty(&queue->tasks[0]))
+               return list_first_entry(&queue->tasks[0], struct rpc_task, u.tk_wait.list);
+       return NULL;
+}
+
 /*
- * Wake up the next task on the wait queue.
+ * Wake up the first task on the wait queue.
  */
-struct rpc_task * rpc_wake_up_next(struct rpc_wait_queue *queue)
+struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue,
+               bool (*func)(struct rpc_task *, void *), void *data)
 {
        struct rpc_task *task = NULL;
 
-       dprintk("RPC:       wake_up_next(%p \"%s\")\n",
+       dprintk("RPC:       wake_up_first(%p \"%s\")\n",
                        queue, rpc_qname(queue));
        spin_lock_bh(&queue->lock);
-       if (RPC_IS_PRIORITY(queue))
-               task = __rpc_wake_up_next_priority(queue);
-       else {
-               task_for_first(task, &queue->tasks[0])
+       task = __rpc_find_next_queued(queue);
+       if (task != NULL) {
+               if (func(task, data))
                        rpc_wake_up_task_queue_locked(queue, task);
+               else
+                       task = NULL;
        }
        spin_unlock_bh(&queue->lock);
 
        return task;
 }
+EXPORT_SYMBOL_GPL(rpc_wake_up_first);
+
+static bool rpc_wake_up_next_func(struct rpc_task *task, void *data)
+{
+       return true;
+}
+
+/*
+ * Wake up the next task on the wait queue.
+*/
+struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *queue)
+{
+       return rpc_wake_up_first(queue, rpc_wake_up_next_func, NULL);
+}
 EXPORT_SYMBOL_GPL(rpc_wake_up_next);
 
 /**
@@ -501,14 +534,18 @@ EXPORT_SYMBOL_GPL(rpc_wake_up_next);
  */
 void rpc_wake_up(struct rpc_wait_queue *queue)
 {
-       struct rpc_task *task, *next;
        struct list_head *head;
 
        spin_lock_bh(&queue->lock);
        head = &queue->tasks[queue->maxpriority];
        for (;;) {
-               list_for_each_entry_safe(task, next, head, u.tk_wait.list)
+               while (!list_empty(head)) {
+                       struct rpc_task *task;
+                       task = list_first_entry(head,
+                                       struct rpc_task,
+                                       u.tk_wait.list);
                        rpc_wake_up_task_queue_locked(queue, task);
+               }
                if (head == &queue->tasks[0])
                        break;
                head--;
@@ -526,13 +563,16 @@ EXPORT_SYMBOL_GPL(rpc_wake_up);
  */
 void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
 {
-       struct rpc_task *task, *next;
        struct list_head *head;
 
        spin_lock_bh(&queue->lock);
        head = &queue->tasks[queue->maxpriority];
        for (;;) {
-               list_for_each_entry_safe(task, next, head, u.tk_wait.list) {
+               while (!list_empty(head)) {
+                       struct rpc_task *task;
+                       task = list_first_entry(head,
+                                       struct rpc_task,
+                                       u.tk_wait.list);
                        task->tk_status = status;
                        rpc_wake_up_task_queue_locked(queue, task);
                }
@@ -677,6 +717,7 @@ static void __rpc_execute(struct rpc_task *task)
                        if (do_action == NULL)
                                break;
                }
+               trace_rpc_task_run_action(task->tk_client, task, task->tk_action);
                do_action(task);
 
                /*
index 80df89d..bc2068e 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/sunrpc/metrics.h>
+#include <linux/rcupdate.h>
 
 #include "netns.h"
 
@@ -133,20 +134,19 @@ EXPORT_SYMBOL_GPL(rpc_free_iostats);
 /**
  * rpc_count_iostats - tally up per-task stats
  * @task: completed rpc_task
+ * @stats: array of stat structures
  *
  * Relies on the caller for serialization.
  */
-void rpc_count_iostats(struct rpc_task *task)
+void rpc_count_iostats(const struct rpc_task *task, struct rpc_iostats *stats)
 {
        struct rpc_rqst *req = task->tk_rqstp;
-       struct rpc_iostats *stats;
        struct rpc_iostats *op_metrics;
        ktime_t delta;
 
-       if (!task->tk_client || !task->tk_client->cl_metrics || !req)
+       if (!stats || !req)
                return;
 
-       stats = task->tk_client->cl_metrics;
        op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx];
 
        op_metrics->om_ops++;
@@ -164,6 +164,7 @@ void rpc_count_iostats(struct rpc_task *task)
        delta = ktime_sub(ktime_get(), task->tk_start);
        op_metrics->om_execute = ktime_add(op_metrics->om_execute, delta);
 }
+EXPORT_SYMBOL_GPL(rpc_count_iostats);
 
 static void _print_name(struct seq_file *seq, unsigned int op,
                        struct rpc_procinfo *procs)
@@ -179,7 +180,7 @@ static void _print_name(struct seq_file *seq, unsigned int op,
 void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
 {
        struct rpc_iostats *stats = clnt->cl_metrics;
-       struct rpc_xprt *xprt = clnt->cl_xprt;
+       struct rpc_xprt *xprt;
        unsigned int op, maxproc = clnt->cl_maxproc;
 
        if (!stats)
@@ -189,8 +190,11 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
        seq_printf(seq, "p/v: %u/%u (%s)\n",
                        clnt->cl_prog, clnt->cl_vers, clnt->cl_protname);
 
+       rcu_read_lock();
+       xprt = rcu_dereference(clnt->cl_xprt);
        if (xprt)
                xprt->ops->print_stats(xprt, seq);
+       rcu_read_unlock();
 
        seq_printf(seq, "\tper-op statistics\n");
        for (op = 0; op < maxproc; op++) {
@@ -213,45 +217,46 @@ EXPORT_SYMBOL_GPL(rpc_print_iostats);
  * Register/unregister RPC proc files
  */
 static inline struct proc_dir_entry *
-do_register(const char *name, void *data, const struct file_operations *fops)
+do_register(struct net *net, const char *name, void *data,
+           const struct file_operations *fops)
 {
        struct sunrpc_net *sn;
 
        dprintk("RPC:       registering /proc/net/rpc/%s\n", name);
-       sn = net_generic(&init_net, sunrpc_net_id);
+       sn = net_generic(net, sunrpc_net_id);
        return proc_create_data(name, 0, sn->proc_net_rpc, fops, data);
 }
 
 struct proc_dir_entry *
-rpc_proc_register(struct rpc_stat *statp)
+rpc_proc_register(struct net *net, struct rpc_stat *statp)
 {
-       return do_register(statp->program->name, statp, &rpc_proc_fops);
+       return do_register(net, statp->program->name, statp, &rpc_proc_fops);
 }
 EXPORT_SYMBOL_GPL(rpc_proc_register);
 
 void
-rpc_proc_unregister(const char *name)
+rpc_proc_unregister(struct net *net, const char *name)
 {
        struct sunrpc_net *sn;
 
-       sn = net_generic(&init_net, sunrpc_net_id);
+       sn = net_generic(net, sunrpc_net_id);
        remove_proc_entry(name, sn->proc_net_rpc);
 }
 EXPORT_SYMBOL_GPL(rpc_proc_unregister);
 
 struct proc_dir_entry *
-svc_proc_register(struct svc_stat *statp, const struct file_operations *fops)
+svc_proc_register(struct net *net, struct svc_stat *statp, const struct file_operations *fops)
 {
-       return do_register(statp->program->pg_name, statp, fops);
+       return do_register(net, statp->program->pg_name, statp, fops);
 }
 EXPORT_SYMBOL_GPL(svc_proc_register);
 
 void
-svc_proc_unregister(const char *name)
+svc_proc_unregister(struct net *net, const char *name)
 {
        struct sunrpc_net *sn;
 
-       sn = net_generic(&init_net, sunrpc_net_id);
+       sn = net_generic(net, sunrpc_net_id);
        remove_proc_entry(name, sn->proc_net_rpc);
 }
 EXPORT_SYMBOL_GPL(svc_proc_unregister);
index 90c292e..14c9f6d 100644 (file)
@@ -47,5 +47,7 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
                    struct page *headpage, unsigned long headoffset,
                    struct page *tailpage, unsigned long tailoffset);
 
+int rpc_clients_notifier_register(void);
+void rpc_clients_notifier_unregister(void);
 #endif /* _NET_SUNRPC_SUNRPC_H */
 
index 8ec9778..8adfc88 100644 (file)
 #include "netns.h"
 
 int sunrpc_net_id;
+EXPORT_SYMBOL_GPL(sunrpc_net_id);
 
 static __net_init int sunrpc_init_net(struct net *net)
 {
        int err;
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
        err = rpc_proc_init(net);
        if (err)
@@ -38,8 +40,18 @@ static __net_init int sunrpc_init_net(struct net *net)
        if (err)
                goto err_ipmap;
 
+       err = unix_gid_cache_create(net);
+       if (err)
+               goto err_unixgid;
+
+       rpc_pipefs_init_net(net);
+       INIT_LIST_HEAD(&sn->all_clients);
+       spin_lock_init(&sn->rpc_client_lock);
+       spin_lock_init(&sn->rpcb_clnt_lock);
        return 0;
 
+err_unixgid:
+       ip_map_cache_destroy(net);
 err_ipmap:
        rpc_proc_exit(net);
 err_proc:
@@ -48,6 +60,7 @@ err_proc:
 
 static __net_exit void sunrpc_exit_net(struct net *net)
 {
+       unix_gid_cache_destroy(net);
        ip_map_cache_destroy(net);
        rpc_proc_exit(net);
 }
@@ -59,8 +72,6 @@ static struct pernet_operations sunrpc_net_ops = {
        .size = sizeof(struct sunrpc_net),
 };
 
-extern struct cache_detail unix_gid_cache;
-
 static int __init
 init_sunrpc(void)
 {
@@ -82,7 +93,6 @@ init_sunrpc(void)
 #ifdef RPC_DEBUG
        rpc_register_sysctl();
 #endif
-       cache_register(&unix_gid_cache);
        svc_init_xprt_sock();   /* svc sock transport */
        init_socket_xprt();     /* clnt sock transport */
        return 0;
@@ -105,7 +115,6 @@ cleanup_sunrpc(void)
        svc_cleanup_xprt_sock();
        unregister_rpc_pipefs();
        rpc_destroy_mempool();
-       cache_unregister(&unix_gid_cache);
        unregister_pernet_subsys(&sunrpc_net_ops);
 #ifdef RPC_DEBUG
        rpc_unregister_sysctl();
index e4aabc0..4153846 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/module.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
+#include <linux/nsproxy.h>
 
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
@@ -30,7 +31,7 @@
 
 #define RPCDBG_FACILITY        RPCDBG_SVCDSP
 
-static void svc_unregister(const struct svc_serv *serv);
+static void svc_unregister(const struct svc_serv *serv, struct net *net);
 
 #define svc_serv_is_pooled(serv)    ((serv)->sv_function)
 
@@ -368,23 +369,24 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)
        return &serv->sv_pools[pidx % serv->sv_nrpools];
 }
 
-static int svc_rpcb_setup(struct svc_serv *serv)
+int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
 {
        int err;
 
-       err = rpcb_create_local();
+       err = rpcb_create_local(net);
        if (err)
                return err;
 
        /* Remove any stale portmap registrations */
-       svc_unregister(serv);
+       svc_unregister(serv, net);
        return 0;
 }
+EXPORT_SYMBOL_GPL(svc_rpcb_setup);
 
-void svc_rpcb_cleanup(struct svc_serv *serv)
+void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net)
 {
-       svc_unregister(serv);
-       rpcb_put_local();
+       svc_unregister(serv, net);
+       rpcb_put_local(net);
 }
 EXPORT_SYMBOL_GPL(svc_rpcb_cleanup);
 
@@ -410,7 +412,7 @@ static int svc_uses_rpcbind(struct svc_serv *serv)
  */
 static struct svc_serv *
 __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
-            void (*shutdown)(struct svc_serv *serv))
+            void (*shutdown)(struct svc_serv *serv, struct net *net))
 {
        struct svc_serv *serv;
        unsigned int vers;
@@ -470,7 +472,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
        }
 
        if (svc_uses_rpcbind(serv)) {
-               if (svc_rpcb_setup(serv) < 0) {
+               if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) {
                        kfree(serv->sv_pools);
                        kfree(serv);
                        return NULL;
@@ -484,7 +486,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
 
 struct svc_serv *
 svc_create(struct svc_program *prog, unsigned int bufsize,
-          void (*shutdown)(struct svc_serv *serv))
+          void (*shutdown)(struct svc_serv *serv, struct net *net))
 {
        return __svc_create(prog, bufsize, /*npools*/1, shutdown);
 }
@@ -492,7 +494,7 @@ EXPORT_SYMBOL_GPL(svc_create);
 
 struct svc_serv *
 svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
-                 void (*shutdown)(struct svc_serv *serv),
+                 void (*shutdown)(struct svc_serv *serv, struct net *net),
                  svc_thread_fn func, struct module *mod)
 {
        struct svc_serv *serv;
@@ -509,6 +511,24 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
 }
 EXPORT_SYMBOL_GPL(svc_create_pooled);
 
+void svc_shutdown_net(struct svc_serv *serv, struct net *net)
+{
+       /*
+        * The set of xprts (contained in the sv_tempsocks and
+        * sv_permsocks lists) is now constant, since it is modified
+        * only by accepting new sockets (done by service threads in
+        * svc_recv) or aging old ones (done by sv_temptimer), or
+        * configuration changes (excluded by whatever locking the
+        * caller is using--nfsd_mutex in the case of nfsd).  So it's
+        * safe to traverse those lists and shut everything down:
+        */
+       svc_close_net(serv, net);
+
+       if (serv->sv_shutdown)
+               serv->sv_shutdown(serv, net);
+}
+EXPORT_SYMBOL_GPL(svc_shutdown_net);
+
 /*
  * Destroy an RPC service. Should be called with appropriate locking to
  * protect the sv_nrthreads, sv_permsocks and sv_tempsocks.
@@ -516,6 +536,8 @@ EXPORT_SYMBOL_GPL(svc_create_pooled);
 void
 svc_destroy(struct svc_serv *serv)
 {
+       struct net *net = current->nsproxy->net_ns;
+
        dprintk("svc: svc_destroy(%s, %d)\n",
                                serv->sv_program->pg_name,
                                serv->sv_nrthreads);
@@ -529,19 +551,15 @@ svc_destroy(struct svc_serv *serv)
                printk("svc_destroy: no threads for serv=%p!\n", serv);
 
        del_timer_sync(&serv->sv_temptimer);
+
+       svc_shutdown_net(serv, net);
+
        /*
-        * The set of xprts (contained in the sv_tempsocks and
-        * sv_permsocks lists) is now constant, since it is modified
-        * only by accepting new sockets (done by service threads in
-        * svc_recv) or aging old ones (done by sv_temptimer), or
-        * configuration changes (excluded by whatever locking the
-        * caller is using--nfsd_mutex in the case of nfsd).  So it's
-        * safe to traverse those lists and shut everything down:
+        * The last user is gone and thus all sockets have to be destroyed to
+        * the point. Check this.
         */
-       svc_close_all(serv);
-
-       if (serv->sv_shutdown)
-               serv->sv_shutdown(serv);
+       BUG_ON(!list_empty(&serv->sv_permsocks));
+       BUG_ON(!list_empty(&serv->sv_tempsocks));
 
        cache_clean_deferred(serv);
 
@@ -795,7 +813,8 @@ EXPORT_SYMBOL_GPL(svc_exit_thread);
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_rpcb_register4(const u32 program, const u32 version,
+static int __svc_rpcb_register4(struct net *net, const u32 program,
+                               const u32 version,
                                const unsigned short protocol,
                                const unsigned short port)
 {
@@ -818,7 +837,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
                return -ENOPROTOOPT;
        }
 
-       error = rpcb_v4_register(program, version,
+       error = rpcb_v4_register(net, program, version,
                                        (const struct sockaddr *)&sin, netid);
 
        /*
@@ -826,7 +845,7 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
         * registration request with the legacy rpcbind v2 protocol.
         */
        if (error == -EPROTONOSUPPORT)
-               error = rpcb_register(program, version, protocol, port);
+               error = rpcb_register(net, program, version, protocol, port);
 
        return error;
 }
@@ -842,7 +861,8 @@ static int __svc_rpcb_register4(const u32 program, const u32 version,
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_rpcb_register6(const u32 program, const u32 version,
+static int __svc_rpcb_register6(struct net *net, const u32 program,
+                               const u32 version,
                                const unsigned short protocol,
                                const unsigned short port)
 {
@@ -865,7 +885,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
                return -ENOPROTOOPT;
        }
 
-       error = rpcb_v4_register(program, version,
+       error = rpcb_v4_register(net, program, version,
                                        (const struct sockaddr *)&sin6, netid);
 
        /*
@@ -885,7 +905,7 @@ static int __svc_rpcb_register6(const u32 program, const u32 version,
  * Returns zero on success; a negative errno value is returned
  * if any error occurs.
  */
-static int __svc_register(const char *progname,
+static int __svc_register(struct net *net, const char *progname,
                          const u32 program, const u32 version,
                          const int family,
                          const unsigned short protocol,
@@ -895,12 +915,12 @@ static int __svc_register(const char *progname,
 
        switch (family) {
        case PF_INET:
-               error = __svc_rpcb_register4(program, version,
+               error = __svc_rpcb_register4(net, program, version,
                                                protocol, port);
                break;
 #if IS_ENABLED(CONFIG_IPV6)
        case PF_INET6:
-               error = __svc_rpcb_register6(program, version,
+               error = __svc_rpcb_register6(net, program, version,
                                                protocol, port);
 #endif
        }
@@ -914,14 +934,16 @@ static int __svc_register(const char *progname,
 /**
  * svc_register - register an RPC service with the local portmapper
  * @serv: svc_serv struct for the service to register
+ * @net: net namespace for the service to register
  * @family: protocol family of service's listener socket
  * @proto: transport protocol number to advertise
  * @port: port to advertise
  *
  * Service is registered for any address in the passed-in protocol family
  */
-int svc_register(const struct svc_serv *serv, const int family,
-                const unsigned short proto, const unsigned short port)
+int svc_register(const struct svc_serv *serv, struct net *net,
+                const int family, const unsigned short proto,
+                const unsigned short port)
 {
        struct svc_program      *progp;
        unsigned int            i;
@@ -946,7 +968,7 @@ int svc_register(const struct svc_serv *serv, const int family,
                        if (progp->pg_vers[i]->vs_hidden)
                                continue;
 
-                       error = __svc_register(progp->pg_name, progp->pg_prog,
+                       error = __svc_register(net, progp->pg_name, progp->pg_prog,
                                                i, family, proto, port);
                        if (error < 0)
                                break;
@@ -963,19 +985,19 @@ int svc_register(const struct svc_serv *serv, const int family,
  * any "inet6" entries anyway.  So a PMAP_UNSET should be sufficient
  * in this case to clear all existing entries for [program, version].
  */
-static void __svc_unregister(const u32 program, const u32 version,
+static void __svc_unregister(struct net *net, const u32 program, const u32 version,
                             const char *progname)
 {
        int error;
 
-       error = rpcb_v4_register(program, version, NULL, "");
+       error = rpcb_v4_register(net, program, version, NULL, "");
 
        /*
         * User space didn't support rpcbind v4, so retry this
         * request with the legacy rpcbind v2 protocol.
         */
        if (error == -EPROTONOSUPPORT)
-               error = rpcb_register(program, version, 0, 0);
+               error = rpcb_register(net, program, version, 0, 0);
 
        dprintk("svc: %s(%sv%u), error %d\n",
                        __func__, progname, version, error);
@@ -989,7 +1011,7 @@ static void __svc_unregister(const u32 program, const u32 version,
  * The result of unregistration is reported via dprintk for those who want
  * verification of the result, but is otherwise not important.
  */
-static void svc_unregister(const struct svc_serv *serv)
+static void svc_unregister(const struct svc_serv *serv, struct net *net)
 {
        struct svc_program *progp;
        unsigned long flags;
@@ -1006,7 +1028,7 @@ static void svc_unregister(const struct svc_serv *serv)
 
                        dprintk("svc: attempting to unregister %sv%u\n",
                                progp->pg_name, i);
-                       __svc_unregister(progp->pg_prog, i, progp->pg_name);
+                       __svc_unregister(net, progp->pg_prog, i, progp->pg_name);
                }
        }
 
index 74cb0d8..4bda09d 100644 (file)
@@ -922,48 +922,65 @@ void svc_close_xprt(struct svc_xprt *xprt)
 }
 EXPORT_SYMBOL_GPL(svc_close_xprt);
 
-static void svc_close_list(struct list_head *xprt_list)
+static void svc_close_list(struct list_head *xprt_list, struct net *net)
 {
        struct svc_xprt *xprt;
 
        list_for_each_entry(xprt, xprt_list, xpt_list) {
+               if (xprt->xpt_net != net)
+                       continue;
                set_bit(XPT_CLOSE, &xprt->xpt_flags);
                set_bit(XPT_BUSY, &xprt->xpt_flags);
        }
 }
 
-void svc_close_all(struct svc_serv *serv)
+static void svc_clear_pools(struct svc_serv *serv, struct net *net)
 {
        struct svc_pool *pool;
        struct svc_xprt *xprt;
        struct svc_xprt *tmp;
        int i;
 
-       svc_close_list(&serv->sv_tempsocks);
-       svc_close_list(&serv->sv_permsocks);
-
        for (i = 0; i < serv->sv_nrpools; i++) {
                pool = &serv->sv_pools[i];
 
                spin_lock_bh(&pool->sp_lock);
-               while (!list_empty(&pool->sp_sockets)) {
-                       xprt = list_first_entry(&pool->sp_sockets, struct svc_xprt, xpt_ready);
+               list_for_each_entry_safe(xprt, tmp, &pool->sp_sockets, xpt_ready) {
+                       if (xprt->xpt_net != net)
+                               continue;
                        list_del_init(&xprt->xpt_ready);
                }
                spin_unlock_bh(&pool->sp_lock);
        }
+}
+
+static void svc_clear_list(struct list_head *xprt_list, struct net *net)
+{
+       struct svc_xprt *xprt;
+       struct svc_xprt *tmp;
+
+       list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
+               if (xprt->xpt_net != net)
+                       continue;
+               svc_delete_xprt(xprt);
+       }
+       list_for_each_entry(xprt, xprt_list, xpt_list)
+               BUG_ON(xprt->xpt_net == net);
+}
+
+void svc_close_net(struct svc_serv *serv, struct net *net)
+{
+       svc_close_list(&serv->sv_tempsocks, net);
+       svc_close_list(&serv->sv_permsocks, net);
+
+       svc_clear_pools(serv, net);
        /*
         * At this point the sp_sockets lists will stay empty, since
         * svc_enqueue will not add new entries without taking the
         * sp_lock and checking XPT_BUSY.
         */
-       list_for_each_entry_safe(xprt, tmp, &serv->sv_tempsocks, xpt_list)
-               svc_delete_xprt(xprt);
-       list_for_each_entry_safe(xprt, tmp, &serv->sv_permsocks, xpt_list)
-               svc_delete_xprt(xprt);
-
-       BUG_ON(!list_empty(&serv->sv_permsocks));
-       BUG_ON(!list_empty(&serv->sv_tempsocks));
+       svc_clear_list(&serv->sv_tempsocks, net);
+       svc_clear_list(&serv->sv_permsocks, net);
 }
 
 /*
@@ -1089,6 +1106,7 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
  * svc_find_xprt - find an RPC transport instance
  * @serv: pointer to svc_serv to search
  * @xcl_name: C string containing transport's class name
+ * @net: owner net pointer
  * @af: Address family of transport's local address
  * @port: transport's IP port number
  *
@@ -1101,7 +1119,8 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
  * service's list that has a matching class name.
  */
 struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
-                              const sa_family_t af, const unsigned short port)
+                              struct net *net, const sa_family_t af,
+                              const unsigned short port)
 {
        struct svc_xprt *xprt;
        struct svc_xprt *found = NULL;
@@ -1112,6 +1131,8 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
 
        spin_lock_bh(&serv->sv_lock);
        list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
+               if (xprt->xpt_net != net)
+                       continue;
                if (strcmp(xprt->xpt_class->xcl_name, xcl_name))
                        continue;
                if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family)
index 01153ea..bcd574f 100644 (file)
@@ -211,7 +211,7 @@ static int ip_map_parse(struct cache_detail *cd,
        len = qword_get(&mesg, buf, mlen);
        if (len <= 0) return -EINVAL;
 
-       if (rpc_pton(buf, len, &address.sa, sizeof(address)) == 0)
+       if (rpc_pton(cd->net, buf, len, &address.sa, sizeof(address)) == 0)
                return -EINVAL;
        switch (address.sa.sa_family) {
        case AF_INET:
@@ -436,7 +436,6 @@ struct unix_gid {
        uid_t                   uid;
        struct group_info       *gi;
 };
-static struct cache_head       *gid_table[GID_HASHMAX];
 
 static void unix_gid_put(struct kref *kref)
 {
@@ -494,8 +493,7 @@ static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h)
        return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request);
 }
 
-static struct unix_gid *unix_gid_lookup(uid_t uid);
-extern struct cache_detail unix_gid_cache;
+static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid);
 
 static int unix_gid_parse(struct cache_detail *cd,
                        char *mesg, int mlen)
@@ -539,19 +537,19 @@ static int unix_gid_parse(struct cache_detail *cd,
                GROUP_AT(ug.gi, i) = gid;
        }
 
-       ugp = unix_gid_lookup(uid);
+       ugp = unix_gid_lookup(cd, uid);
        if (ugp) {
                struct cache_head *ch;
                ug.h.flags = 0;
                ug.h.expiry_time = expiry;
-               ch = sunrpc_cache_update(&unix_gid_cache,
+               ch = sunrpc_cache_update(cd,
                                         &ug.h, &ugp->h,
                                         hash_long(uid, GID_HASHBITS));
                if (!ch)
                        err = -ENOMEM;
                else {
                        err = 0;
-                       cache_put(ch, &unix_gid_cache);
+                       cache_put(ch, cd);
                }
        } else
                err = -ENOMEM;
@@ -587,10 +585,9 @@ static int unix_gid_show(struct seq_file *m,
        return 0;
 }
 
-struct cache_detail unix_gid_cache = {
+static struct cache_detail unix_gid_cache_template = {
        .owner          = THIS_MODULE,
        .hash_size      = GID_HASHMAX,
-       .hash_table     = gid_table,
        .name           = "auth.unix.gid",
        .cache_put      = unix_gid_put,
        .cache_upcall   = unix_gid_upcall,
@@ -602,14 +599,42 @@ struct cache_detail unix_gid_cache = {
        .alloc          = unix_gid_alloc,
 };
 
-static struct unix_gid *unix_gid_lookup(uid_t uid)
+int unix_gid_cache_create(struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct cache_detail *cd;
+       int err;
+
+       cd = cache_create_net(&unix_gid_cache_template, net);
+       if (IS_ERR(cd))
+               return PTR_ERR(cd);
+       err = cache_register_net(cd, net);
+       if (err) {
+               cache_destroy_net(cd, net);
+               return err;
+       }
+       sn->unix_gid_cache = cd;
+       return 0;
+}
+
+void unix_gid_cache_destroy(struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct cache_detail *cd = sn->unix_gid_cache;
+
+       sn->unix_gid_cache = NULL;
+       cache_purge(cd);
+       cache_unregister_net(cd, net);
+       cache_destroy_net(cd, net);
+}
+
+static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid)
 {
        struct unix_gid ug;
        struct cache_head *ch;
 
        ug.uid = uid;
-       ch = sunrpc_cache_lookup(&unix_gid_cache, &ug.h,
-                                hash_long(uid, GID_HASHBITS));
+       ch = sunrpc_cache_lookup(cd, &ug.h, hash_long(uid, GID_HASHBITS));
        if (ch)
                return container_of(ch, struct unix_gid, h);
        else
@@ -621,11 +646,13 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp)
        struct unix_gid *ug;
        struct group_info *gi;
        int ret;
+       struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net,
+                                           sunrpc_net_id);
 
-       ug = unix_gid_lookup(uid);
+       ug = unix_gid_lookup(sn->unix_gid_cache, uid);
        if (!ug)
                return ERR_PTR(-EAGAIN);
-       ret = cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle);
+       ret = cache_check(sn->unix_gid_cache, &ug->h, &rqstp->rq_chandle);
        switch (ret) {
        case -ENOENT:
                return ERR_PTR(-ENOENT);
@@ -633,7 +660,7 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp)
                return ERR_PTR(-ESHUTDOWN);
        case 0:
                gi = get_group_info(ug->gi);
-               cache_put(&ug->h, &unix_gid_cache);
+               cache_put(&ug->h, sn->unix_gid_cache);
                return gi;
        default:
                return ERR_PTR(-EAGAIN);
@@ -849,56 +876,45 @@ struct auth_ops svcauth_unix = {
        .set_client     = svcauth_unix_set_client,
 };
 
+static struct cache_detail ip_map_cache_template = {
+       .owner          = THIS_MODULE,
+       .hash_size      = IP_HASHMAX,
+       .name           = "auth.unix.ip",
+       .cache_put      = ip_map_put,
+       .cache_upcall   = ip_map_upcall,
+       .cache_parse    = ip_map_parse,
+       .cache_show     = ip_map_show,
+       .match          = ip_map_match,
+       .init           = ip_map_init,
+       .update         = update,
+       .alloc          = ip_map_alloc,
+};
+
 int ip_map_cache_create(struct net *net)
 {
-       int err = -ENOMEM;
-       struct cache_detail *cd;
-       struct cache_head **tbl;
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct cache_detail *cd;
+       int err;
 
-       cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL);
-       if (cd == NULL)
-               goto err_cd;
-
-       tbl = kzalloc(IP_HASHMAX * sizeof(struct cache_head *), GFP_KERNEL);
-       if (tbl == NULL)
-               goto err_tbl;
-
-       cd->owner = THIS_MODULE,
-       cd->hash_size = IP_HASHMAX,
-       cd->hash_table = tbl,
-       cd->name = "auth.unix.ip",
-       cd->cache_put = ip_map_put,
-       cd->cache_upcall = ip_map_upcall,
-       cd->cache_parse = ip_map_parse,
-       cd->cache_show = ip_map_show,
-       cd->match = ip_map_match,
-       cd->init = ip_map_init,
-       cd->update = update,
-       cd->alloc = ip_map_alloc,
-
+       cd = cache_create_net(&ip_map_cache_template, net);
+       if (IS_ERR(cd))
+               return PTR_ERR(cd);
        err = cache_register_net(cd, net);
-       if (err)
-               goto err_reg;
-
+       if (err) {
+               cache_destroy_net(cd, net);
+               return err;
+       }
        sn->ip_map_cache = cd;
        return 0;
-
-err_reg:
-       kfree(tbl);
-err_tbl:
-       kfree(cd);
-err_cd:
-       return err;
 }
 
 void ip_map_cache_destroy(struct net *net)
 {
-       struct sunrpc_net *sn;
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct cache_detail *cd = sn->ip_map_cache;
 
-       sn = net_generic(net, sunrpc_net_id);
-       cache_purge(sn->ip_map_cache);
-       cache_unregister_net(sn->ip_map_cache, net);
-       kfree(sn->ip_map_cache->hash_table);
-       kfree(sn->ip_map_cache);
+       sn->ip_map_cache = NULL;
+       cache_purge(cd);
+       cache_unregister_net(cd, net);
+       cache_destroy_net(cd, net);
 }
index 4645709..40ae884 100644 (file)
@@ -396,7 +396,7 @@ static int svc_partial_recvfrom(struct svc_rqst *rqstp,
                                int buflen, unsigned int base)
 {
        size_t save_iovlen;
-       void __user *save_iovbase;
+       void *save_iovbase;
        unsigned int i;
        int ret;
 
@@ -1409,7 +1409,8 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
 
        /* Register socket with portmapper */
        if (*errp >= 0 && pmap_register)
-               *errp = svc_register(serv, inet->sk_family, inet->sk_protocol,
+               *errp = svc_register(serv, sock_net(sock->sk), inet->sk_family,
+                                    inet->sk_protocol,
                                     ntohs(inet_sk(inet)->inet_sport));
 
        if (*errp < 0) {
index e65dcc6..af7d339 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/svc_xprt.h>
 
+#include "netns.h"
+
 /*
  * Declare the debug flags here
  */
@@ -110,7 +112,7 @@ proc_dodebug(ctl_table *table, int write,
                *(unsigned int *) table->data = value;
                /* Display the RPC tasks on writing to rpc_debug */
                if (strcmp(table->procname, "rpc_debug") == 0)
-                       rpc_show_tasks();
+                       rpc_show_tasks(&init_net);
        } else {
                if (!access_ok(VERIFY_WRITE, buffer, left))
                        return -EFAULT;
index c64c0ef..0cbcd1a 100644 (file)
@@ -66,6 +66,7 @@ static void    xprt_init(struct rpc_xprt *xprt, struct net *net);
 static void    xprt_request_init(struct rpc_task *, struct rpc_xprt *);
 static void    xprt_connect_status(struct rpc_task *task);
 static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
+static void     xprt_destroy(struct rpc_xprt *xprt);
 
 static DEFINE_SPINLOCK(xprt_list_lock);
 static LIST_HEAD(xprt_list);
@@ -292,54 +293,57 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
        return retval;
 }
 
-static void __xprt_lock_write_next(struct rpc_xprt *xprt)
+static bool __xprt_lock_write_func(struct rpc_task *task, void *data)
 {
-       struct rpc_task *task;
+       struct rpc_xprt *xprt = data;
        struct rpc_rqst *req;
 
-       if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
-               return;
-
-       task = rpc_wake_up_next(&xprt->sending);
-       if (task == NULL)
-               goto out_unlock;
-
        req = task->tk_rqstp;
        xprt->snd_task = task;
        if (req) {
                req->rq_bytes_sent = 0;
                req->rq_ntrans++;
        }
-       return;
+       return true;
+}
 
-out_unlock:
+static void __xprt_lock_write_next(struct rpc_xprt *xprt)
+{
+       if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
+               return;
+
+       if (rpc_wake_up_first(&xprt->sending, __xprt_lock_write_func, xprt))
+               return;
        xprt_clear_locked(xprt);
 }
 
-static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
+static bool __xprt_lock_write_cong_func(struct rpc_task *task, void *data)
 {
-       struct rpc_task *task;
+       struct rpc_xprt *xprt = data;
        struct rpc_rqst *req;
 
-       if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
-               return;
-       if (RPCXPRT_CONGESTED(xprt))
-               goto out_unlock;
-       task = rpc_wake_up_next(&xprt->sending);
-       if (task == NULL)
-               goto out_unlock;
-
        req = task->tk_rqstp;
        if (req == NULL) {
                xprt->snd_task = task;
-               return;
+               return true;
        }
        if (__xprt_get_cong(xprt, task)) {
                xprt->snd_task = task;
                req->rq_bytes_sent = 0;
                req->rq_ntrans++;
-               return;
+               return true;
        }
+       return false;
+}
+
+static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
+{
+       if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
+               return;
+       if (RPCXPRT_CONGESTED(xprt))
+               goto out_unlock;
+       if (rpc_wake_up_first(&xprt->sending, __xprt_lock_write_cong_func, xprt))
+               return;
 out_unlock:
        xprt_clear_locked(xprt);
 }
@@ -712,9 +716,7 @@ void xprt_connect(struct rpc_task *task)
        if (xprt_connected(xprt))
                xprt_release_write(xprt, task);
        else {
-               if (task->tk_rqstp)
-                       task->tk_rqstp->rq_bytes_sent = 0;
-
+               task->tk_rqstp->rq_bytes_sent = 0;
                task->tk_timeout = task->tk_rqstp->rq_timeout;
                rpc_sleep_on(&xprt->pending, task, xprt_connect_status);
 
@@ -750,7 +752,7 @@ static void xprt_connect_status(struct rpc_task *task)
        default:
                dprintk("RPC: %5u xprt_connect_status: error %d connecting to "
                                "server %s\n", task->tk_pid, -task->tk_status,
-                               task->tk_client->cl_server);
+                               xprt->servername);
                xprt_release_write(xprt, task);
                task->tk_status = -EIO;
        }
@@ -884,7 +886,7 @@ void xprt_transmit(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = req->rq_xprt;
-       int status;
+       int status, numreqs;
 
        dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen);
 
@@ -921,9 +923,14 @@ void xprt_transmit(struct rpc_task *task)
 
        xprt->ops->set_retrans_timeout(task);
 
+       numreqs = atomic_read(&xprt->num_reqs);
+       if (numreqs > xprt->stat.max_slots)
+               xprt->stat.max_slots = numreqs;
        xprt->stat.sends++;
        xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
        xprt->stat.bklog_u += xprt->backlog.qlen;
+       xprt->stat.sending_u += xprt->sending.qlen;
+       xprt->stat.pending_u += xprt->pending.qlen;
 
        /* Don't race with disconnect */
        if (!xprt_connected(xprt))
@@ -1131,7 +1138,10 @@ void xprt_release(struct rpc_task *task)
                return;
 
        xprt = req->rq_xprt;
-       rpc_count_iostats(task);
+       if (task->tk_ops->rpc_count_stats != NULL)
+               task->tk_ops->rpc_count_stats(task, task->tk_calldata);
+       else if (task->tk_client)
+               rpc_count_iostats(task, task->tk_client->cl_metrics);
        spin_lock_bh(&xprt->transport_lock);
        xprt->ops->release_xprt(xprt, task);
        if (xprt->ops->release_request)
@@ -1220,6 +1230,17 @@ found:
                            (unsigned long)xprt);
        else
                init_timer(&xprt->timer);
+
+       if (strlen(args->servername) > RPC_MAXNETNAMELEN) {
+               xprt_destroy(xprt);
+               return ERR_PTR(-EINVAL);
+       }
+       xprt->servername = kstrdup(args->servername, GFP_KERNEL);
+       if (xprt->servername == NULL) {
+               xprt_destroy(xprt);
+               return ERR_PTR(-ENOMEM);
+       }
+
        dprintk("RPC:       created transport %p with %u slots\n", xprt,
                        xprt->max_reqs);
 out:
@@ -1242,6 +1263,7 @@ static void xprt_destroy(struct rpc_xprt *xprt)
        rpc_destroy_wait_queue(&xprt->sending);
        rpc_destroy_wait_queue(&xprt->backlog);
        cancel_work_sync(&xprt->task_cleanup);
+       kfree(xprt->servername);
        /*
         * Tear down transport state and free the rpc_xprt
         */
index 1776e57..558fbab 100644 (file)
@@ -771,13 +771,18 @@ repost:
 
        /* get request object */
        req = rpcr_to_rdmar(rqst);
+       if (req->rl_reply) {
+               spin_unlock(&xprt->transport_lock);
+               dprintk("RPC:       %s: duplicate reply 0x%p to RPC "
+                       "request 0x%p: xid 0x%08x\n", __func__, rep, req,
+                       headerp->rm_xid);
+               goto repost;
+       }
 
        dprintk("RPC:       %s: reply 0x%p completes request 0x%p\n"
                "                   RPC request 0x%p xid 0x%08x\n",
                        __func__, rep, req, rqst, headerp->rm_xid);
 
-       BUG_ON(!req || req->rl_reply);
-
        /* from here on, the reply is no longer an orphan */
        req->rl_reply = rep;
 
index 28236ba..745973b 100644 (file)
@@ -1490,6 +1490,9 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
        u8 key;
        int len, pageoff;
        int i, rc;
+       int seg_len;
+       u64 pa;
+       int page_no;
 
        pageoff = offset_in_page(seg1->mr_offset);
        seg1->mr_offset -= pageoff;     /* start of page */
@@ -1497,11 +1500,15 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
        len = -pageoff;
        if (*nsegs > RPCRDMA_MAX_DATA_SEGS)
                *nsegs = RPCRDMA_MAX_DATA_SEGS;
-       for (i = 0; i < *nsegs;) {
+       for (page_no = i = 0; i < *nsegs;) {
                rpcrdma_map_one(ia, seg, writing);
-               seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->page_list[i] = seg->mr_dma;
+               pa = seg->mr_dma;
+               for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) {
+                       seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->
+                               page_list[page_no++] = pa;
+                       pa += PAGE_SIZE;
+               }
                len += seg->mr_len;
-               BUG_ON(seg->mr_len > PAGE_SIZE);
                ++seg;
                ++i;
                /* Check for holes */
@@ -1540,9 +1547,9 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
        frmr_wr.send_flags = IB_SEND_SIGNALED;
        frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma;
        frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl;
-       frmr_wr.wr.fast_reg.page_list_len = i;
+       frmr_wr.wr.fast_reg.page_list_len = page_no;
        frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
-       frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT;
+       frmr_wr.wr.fast_reg.length = page_no << PAGE_SHIFT;
        BUG_ON(frmr_wr.wr.fast_reg.length < len);
        frmr_wr.wr.fast_reg.access_flags = (writing ?
                                IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
index 55472c4..92bc518 100644 (file)
@@ -53,12 +53,12 @@ static void xs_close(struct rpc_xprt *xprt);
 /*
  * xprtsock tunables
  */
-unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE;
-unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE;
-unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE;
+static unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE;
+static unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE;
+static unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE;
 
-unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT;
-unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT;
+static unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT;
+static unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT;
 
 #define XS_TCP_LINGER_TO       (15U * HZ)
 static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO;
@@ -2227,7 +2227,7 @@ static void xs_local_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
                idle_time = (long)(jiffies - xprt->last_used) / HZ;
 
        seq_printf(seq, "\txprt:\tlocal %lu %lu %lu %ld %lu %lu %lu "
-                       "%llu %llu\n",
+                       "%llu %llu %lu %llu %llu\n",
                        xprt->stat.bind_count,
                        xprt->stat.connect_count,
                        xprt->stat.connect_time,
@@ -2236,7 +2236,10 @@ static void xs_local_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
                        xprt->stat.recvs,
                        xprt->stat.bad_xids,
                        xprt->stat.req_u,
-                       xprt->stat.bklog_u);
+                       xprt->stat.bklog_u,
+                       xprt->stat.max_slots,
+                       xprt->stat.sending_u,
+                       xprt->stat.pending_u);
 }
 
 /**
@@ -2249,14 +2252,18 @@ static void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
 {
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
 
-       seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n",
+       seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %llu %llu "
+                       "%lu %llu %llu\n",
                        transport->srcport,
                        xprt->stat.bind_count,
                        xprt->stat.sends,
                        xprt->stat.recvs,
                        xprt->stat.bad_xids,
                        xprt->stat.req_u,
-                       xprt->stat.bklog_u);
+                       xprt->stat.bklog_u,
+                       xprt->stat.max_slots,
+                       xprt->stat.sending_u,
+                       xprt->stat.pending_u);
 }
 
 /**
@@ -2273,7 +2280,8 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
        if (xprt_connected(xprt))
                idle_time = (long)(jiffies - xprt->last_used) / HZ;
 
-       seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n",
+       seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu "
+                       "%llu %llu %lu %llu %llu\n",
                        transport->srcport,
                        xprt->stat.bind_count,
                        xprt->stat.connect_count,
@@ -2283,7 +2291,10 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
                        xprt->stat.recvs,
                        xprt->stat.bad_xids,
                        xprt->stat.req_u,
-                       xprt->stat.bklog_u);
+                       xprt->stat.bklog_u,
+                       xprt->stat.max_slots,
+                       xprt->stat.sending_u,
+                       xprt->stat.pending_u);
 }
 
 /*
index e758139..c3e65ae 100644 (file)
@@ -74,15 +74,13 @@ static struct ctl_table_root net_sysctl_ro_root = {
 
 static int __net_init sysctl_net_init(struct net *net)
 {
-       setup_sysctl_set(&net->sysctls,
-                        &net_sysctl_ro_root.default_set,
-                        is_seen);
+       setup_sysctl_set(&net->sysctls, &net_sysctl_root, is_seen);
        return 0;
 }
 
 static void __net_exit sysctl_net_exit(struct net *net)
 {
-       WARN_ON(!list_empty(&net->sysctls.list));
+       retire_sysctl_set(&net->sysctls);
 }
 
 static struct pernet_operations sysctl_pernet_ops = {
@@ -90,36 +88,32 @@ static struct pernet_operations sysctl_pernet_ops = {
        .exit = sysctl_net_exit,
 };
 
-static __init int sysctl_init(void)
+static __init int net_sysctl_init(void)
 {
        int ret;
        ret = register_pernet_subsys(&sysctl_pernet_ops);
        if (ret)
                goto out;
-       register_sysctl_root(&net_sysctl_root);
-       setup_sysctl_set(&net_sysctl_ro_root.default_set, NULL, NULL);
+       setup_sysctl_set(&net_sysctl_ro_root.default_set, &net_sysctl_ro_root, NULL);
        register_sysctl_root(&net_sysctl_ro_root);
+       register_sysctl_root(&net_sysctl_root);
 out:
        return ret;
 }
-subsys_initcall(sysctl_init);
+subsys_initcall(net_sysctl_init);
 
 struct ctl_table_header *register_net_sysctl_table(struct net *net,
        const struct ctl_path *path, struct ctl_table *table)
 {
-       struct nsproxy namespaces;
-       namespaces = *current->nsproxy;
-       namespaces.net_ns = net;
-       return __register_sysctl_paths(&net_sysctl_root,
-                                       &namespaces, path, table);
+       return __register_sysctl_paths(&net->sysctls, path, table);
 }
 EXPORT_SYMBOL_GPL(register_net_sysctl_table);
 
 struct ctl_table_header *register_net_sysctl_rotable(const
                struct ctl_path *path, struct ctl_table *table)
 {
-       return __register_sysctl_paths(&net_sysctl_ro_root,
-                       &init_nsproxy, path, table);
+       return __register_sysctl_paths(&net_sysctl_ro_root.default_set,
+                                       path, table);
 }
 EXPORT_SYMBOL_GPL(register_net_sysctl_rotable);
 
index eb4277c..d510353 100644 (file)
@@ -2206,7 +2206,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
        }
 
        /* No write status requested, avoid expensive OUT tests. */
-       if (wait && !(wait->key & (POLLWRBAND | POLLWRNORM | POLLOUT)))
+       if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT)))
                return mask;
 
        writable = unix_writable(sk);
index 47bacd8..95a338c 100644 (file)
@@ -21,7 +21,7 @@
 
 static int xfrm_output2(struct sk_buff *skb);
 
-static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
+static int xfrm_skb_check_space(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
        int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev)
@@ -48,7 +48,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
                goto resume;
 
        do {
-               err = xfrm_state_check_space(x, skb);
+               err = xfrm_skb_check_space(skb);
                if (err) {
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
                        goto error_nolock;
index 39e02c5..2f6d11d 100644 (file)
@@ -167,7 +167,7 @@ static void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
        }
 
        if (xfrm_aevent_is_on(xs_net(x)))
-               xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
+               x->repl->notify(x, XFRM_REPLAY_UPDATE);
 }
 
 static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
@@ -279,7 +279,7 @@ static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq)
        replay_esn->bmp[nr] |= (1U << bitnr);
 
        if (xfrm_aevent_is_on(xs_net(x)))
-               xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
+               x->repl->notify(x, XFRM_REPLAY_UPDATE);
 }
 
 static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
@@ -473,7 +473,7 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq)
        replay_esn->bmp[nr] |= (1U << bitnr);
 
        if (xfrm_aevent_is_on(xs_net(x)))
-               xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
+               x->repl->notify(x, XFRM_REPLAY_UPDATE);
 }
 
 static struct xfrm_replay xfrm_replay_legacy = {
index 41063e7..7b6792a 100644 (file)
@@ -61,4 +61,12 @@ config SAMPLE_KDB
          Build an example of how to dynamically add the hello
          command to the kdb shell.
 
+config SAMPLE_RPMSG_CLIENT
+       tristate "Build rpmsg client sample -- loadable modules only"
+       depends on RPMSG && m
+       help
+         Build an rpmsg client sample driver, which demonstrates how
+         to communicate with an AMP-configured remote processor over
+         the rpmsg bus.
+
 endif # SAMPLES
index 6280817..2f75851 100644 (file)
@@ -1,4 +1,4 @@
 # Makefile for Linux samples code
 
 obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ tracepoints/ trace_events/ \
-                          hw_breakpoint/ kfifo/ kdb/ hidraw/
+                          hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/
diff --git a/samples/rpmsg/Makefile b/samples/rpmsg/Makefile
new file mode 100644 (file)
index 0000000..2d4973c
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_SAMPLE_RPMSG_CLIENT) += rpmsg_client_sample.o
diff --git a/samples/rpmsg/rpmsg_client_sample.c b/samples/rpmsg/rpmsg_client_sample.c
new file mode 100644 (file)
index 0000000..23ea9f2
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Remote processor messaging - sample client driver
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rpmsg.h>
+
+#define MSG            "hello world!"
+#define MSG_LIMIT      100
+
+static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len,
+                                               void *priv, u32 src)
+{
+       int ret;
+       static int rx_count;
+
+       dev_info(&rpdev->dev, "incoming msg %d (src: 0x%x)\n", ++rx_count, src);
+
+       print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
+                      data, len,  true);
+
+       /* samples should not live forever */
+       if (rx_count >= MSG_LIMIT) {
+               dev_info(&rpdev->dev, "goodbye!\n");
+               return;
+       }
+
+       /* send a new message now */
+       ret = rpmsg_send(rpdev, MSG, strlen(MSG));
+       if (ret)
+               dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+}
+
+static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
+{
+       int ret;
+
+       dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+                                       rpdev->src, rpdev->dst);
+
+       /* send a message to our remote processor */
+       ret = rpmsg_send(rpdev, MSG, strlen(MSG));
+       if (ret) {
+               dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __devexit rpmsg_sample_remove(struct rpmsg_channel *rpdev)
+{
+       dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
+}
+
+static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
+       { .name = "rpmsg-client-sample" },
+       { },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);
+
+static struct rpmsg_driver rpmsg_sample_client = {
+       .drv.name       = KBUILD_MODNAME,
+       .drv.owner      = THIS_MODULE,
+       .id_table       = rpmsg_driver_sample_id_table,
+       .probe          = rpmsg_sample_probe,
+       .callback       = rpmsg_sample_cb,
+       .remove         = __devexit_p(rpmsg_sample_remove),
+};
+
+static int __init rpmsg_client_sample_init(void)
+{
+       return register_rpmsg_driver(&rpmsg_sample_client);
+}
+module_init(rpmsg_client_sample_init);
+
+static void __exit rpmsg_client_sample_fini(void)
+{
+       unregister_rpmsg_driver(&rpmsg_sample_client);
+}
+module_exit(rpmsg_client_sample_fini);
+
+MODULE_DESCRIPTION("Remote processor messaging sample client driver");
+MODULE_LICENSE("GPL v2");
index a3b9782..de639ee 100755 (executable)
@@ -323,17 +323,22 @@ sub build_types {
                  }x;
        $Type   = qr{
                        $NonptrType
-                       (?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)?
+                       (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)?
                        (?:\s+$Inline|\s+$Modifier)*
                  }x;
        $Declare        = qr{(?:$Storage\s+)?$Type};
 }
 build_types();
 
-our $match_balanced_parentheses = qr/(\((?:[^\(\)]+|(-1))*\))/;
 
 our $Typecast  = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
-our $LvalOrFunc        = qr{($Lval)\s*($match_balanced_parentheses{0,1})\s*};
+
+# Using $balanced_parens, $LvalOrFunc, or $FuncArg
+# requires at least perl version v5.10.0
+# Any use must be runtime checked with $^V
+
+our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/;
+our $LvalOrFunc        = qr{($Lval)\s*($balanced_parens{0,1})\s*};
 our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)};
 
 sub deparenthesize {
@@ -1330,6 +1335,36 @@ sub check_absolute_file {
        }
 }
 
+sub pos_last_openparen {
+       my ($line) = @_;
+
+       my $pos = 0;
+
+       my $opens = $line =~ tr/\(/\(/;
+       my $closes = $line =~ tr/\)/\)/;
+
+       my $last_openparen = 0;
+
+       if (($opens == 0) || ($closes >= $opens)) {
+               return -1;
+       }
+
+       my $len = length($line);
+
+       for ($pos = 0; $pos < $len; $pos++) {
+               my $string = substr($line, $pos);
+               if ($string =~ /^($FuncArg|$balanced_parens)/) {
+                       $pos += length($1) - 1;
+               } elsif (substr($line, $pos, 1) eq '(') {
+                       $last_openparen = $pos;
+               } elsif (index($string, '(') == -1) {
+                       last;
+               }
+       }
+
+       return $last_openparen + 1;
+}
+
 sub process {
        my $filename = shift;
 
@@ -1737,6 +1772,21 @@ sub process {
                             "line over 80 characters\n" . $herecurr);
                }
 
+# Check for user-visible strings broken across lines, which breaks the ability
+# to grep for the string.  Limited to strings used as parameters (those
+# following an open parenthesis), which almost completely eliminates false
+# positives, as well as warning only once per parameter rather than once per
+# line of the string.  Make an exception when the previous string ends in a
+# newline (multiple lines in one string constant) or \n\t (common in inline
+# assembly to indent the instruction on the following line).
+               if ($line =~ /^\+\s*"/ &&
+                   $prevline =~ /"\s*$/ &&
+                   $prevline =~ /\(/ &&
+                   $prevrawline !~ /\\n(?:\\t)*"\s*$/) {
+                       WARN("SPLIT_STRING",
+                            "quoted string split across lines\n" . $hereprev);
+               }
+
 # check for spaces before a quoted newline
                if ($rawline =~ /^.*\".*\s\\n/) {
                        WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
@@ -1783,6 +1833,48 @@ sub process {
                             "please, no space before tabs\n" . $herevet);
                }
 
+# check for && or || at the start of a line
+               if ($rawline =~ /^\+\s*(&&|\|\|)/) {
+                       CHK("LOGICAL_CONTINUATIONS",
+                           "Logical continuations should be on the previous line\n" . $hereprev);
+               }
+
+# check multi-line statement indentation matches previous line
+               if ($^V && $^V ge 5.10.0 &&
+                   $prevline =~ /^\+(\t*)(if \(|$Ident\().*(\&\&|\|\||,)\s*$/) {
+                       $prevline =~ /^\+(\t*)(.*)$/;
+                       my $oldindent = $1;
+                       my $rest = $2;
+
+                       my $pos = pos_last_openparen($rest);
+                       if ($pos >= 0) {
+                               $line =~ /^\+([ \t]*)/;
+                               my $newindent = $1;
+
+                               my $goodtabindent = $oldindent .
+                                       "\t" x ($pos / 8) .
+                                       " "  x ($pos % 8);
+                               my $goodspaceindent = $oldindent . " "  x $pos;
+
+                               if ($newindent ne $goodtabindent &&
+                                   $newindent ne $goodspaceindent) {
+                                       CHK("PARENTHESIS_ALIGNMENT",
+                                           "Alignment should match open parenthesis\n" . $hereprev);
+                               }
+                       }
+               }
+
+               if ($line =~ /^\+.*\*[ \t]*\)[ \t]+/) {
+                       CHK("SPACING",
+                           "No space is necessary after a cast\n" . $hereprev);
+               }
+
+               if ($rawline =~ /^\+[ \t]*\/\*[ \t]*$/ &&
+                   $prevrawline =~ /^\+[ \t]*$/) {
+                       CHK("BLOCK_COMMENT_STYLE",
+                           "Don't begin block comments with only a /* line, use /* comment...\n" . $hereprev);
+               }
+
 # check for spaces at the beginning of a line.
 # Exceptions:
 #  1) within comments
@@ -2325,7 +2417,7 @@ sub process {
                        my ($where, $prefix) = ($-[1], $1);
                        if ($prefix !~ /$Type\s+$/ &&
                            ($where != 0 || $prefix !~ /^.\s+$/) &&
-                           $prefix !~ /{\s+$/) {
+                           $prefix !~ /[{,]\s+$/) {
                                ERROR("BRACKET_SPACE",
                                      "space prohibited before open square bracket '['\n" . $herecurr);
                        }
@@ -2828,6 +2920,12 @@ sub process {
                        {
                        }
 
+                       # Flatten any obvious string concatentation.
+                       while ($dstat =~ s/("X*")\s*$Ident/$1/ ||
+                              $dstat =~ s/$Ident\s*("X*")/$1/)
+                       {
+                       }
+
                        my $exceptions = qr{
                                $Declare|
                                module_param_named|
@@ -2844,7 +2942,8 @@ sub process {
                        if ($dstat ne '' &&
                            $dstat !~ /^(?:$Ident|-?$Constant),$/ &&                    # 10, // foo(),
                            $dstat !~ /^(?:$Ident|-?$Constant);$/ &&                    # foo();
-                           $dstat !~ /^(?:$Ident|-?$Constant)$/ &&                     # 10 // foo()
+                           $dstat !~ /^[!~-]?(?:$Ident|$Constant)$/ &&         # 10 // foo() // !foo // ~foo // -foo
+                           $dstat !~ /^'X'$/ &&                                        # character constants
                            $dstat !~ /$exceptions/ &&
                            $dstat !~ /^\.$Ident\s*=/ &&                                # .foo =
                            $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ &&       # do {...} while (...); // do {...} while (...)
@@ -2888,7 +2987,8 @@ sub process {
                        #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
                        #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
                        if ($#chunks > 0 && $level == 0) {
-                               my $allowed = 0;
+                               my @allowed = ();
+                               my $allow = 0;
                                my $seen = 0;
                                my $herectx = $here . "\n";
                                my $ln = $linenr - 1;
@@ -2899,6 +2999,7 @@ sub process {
                                        my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
                                        my $offset = statement_rawlines($whitespace) - 1;
 
+                                       $allowed[$allow] = 0;
                                        #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
 
                                        # We have looked at and allowed this specific line.
@@ -2911,23 +3012,34 @@ sub process {
 
                                        $seen++ if ($block =~ /^\s*{/);
 
-                                       #print "cond<$cond> block<$block> allowed<$allowed>\n";
+                                       #print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n";
                                        if (statement_lines($cond) > 1) {
                                                #print "APW: ALLOWED: cond<$cond>\n";
-                                               $allowed = 1;
+                                               $allowed[$allow] = 1;
                                        }
                                        if ($block =~/\b(?:if|for|while)\b/) {
                                                #print "APW: ALLOWED: block<$block>\n";
-                                               $allowed = 1;
+                                               $allowed[$allow] = 1;
                                        }
                                        if (statement_block_size($block) > 1) {
                                                #print "APW: ALLOWED: lines block<$block>\n";
-                                               $allowed = 1;
+                                               $allowed[$allow] = 1;
                                        }
+                                       $allow++;
                                }
-                               if ($seen && !$allowed) {
-                                       WARN("BRACES",
-                                            "braces {} are not necessary for any arm of this statement\n" . $herectx);
+                               if ($seen) {
+                                       my $sum_allowed = 0;
+                                       foreach (@allowed) {
+                                               $sum_allowed += $_;
+                                       }
+                                       if ($sum_allowed == 0) {
+                                               WARN("BRACES",
+                                                    "braces {} are not necessary for any arm of this statement\n" . $herectx);
+                                       } elsif ($sum_allowed != $allow &&
+                                                $seen != $allow) {
+                                               CHK("BRACES",
+                                                   "braces {} should be used on all arms of this statement\n" . $herectx);
+                                       }
                                }
                        }
                }
@@ -3123,6 +3235,12 @@ sub process {
                             "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr);
                }
 
+# Check for __attribute__ format(scanf, prefer __scanf
+               if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) {
+                       WARN("PREFER_SCANF",
+                            "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr);
+               }
+
 # check for sizeof(&)
                if ($line =~ /\bsizeof\s*\(\s*\&/) {
                        WARN("SIZEOF_ADDRESS",
@@ -3136,12 +3254,13 @@ sub process {
                }
 
 # Check for misused memsets
-               if (defined $stat &&
+               if ($^V && $^V ge 5.10.0 &&
+                   defined $stat &&
                    $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/s) {
 
                        my $ms_addr = $2;
-                       my $ms_val = $8;
-                       my $ms_size = $14;
+                       my $ms_val = $7;
+                       my $ms_size = $12;
 
                        if ($ms_size =~ /^(0x|)0$/i) {
                                ERROR("MEMSET",
@@ -3153,17 +3272,18 @@ sub process {
                }
 
 # typecasts on min/max could be min_t/max_t
-               if (defined $stat &&
+               if ($^V && $^V ge 5.10.0 &&
+                   defined $stat &&
                    $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) {
-                       if (defined $2 || defined $8) {
+                       if (defined $2 || defined $7) {
                                my $call = $1;
                                my $cast1 = deparenthesize($2);
                                my $arg1 = $3;
-                               my $cast2 = deparenthesize($8);
-                               my $arg2 = $9;
+                               my $cast2 = deparenthesize($7);
+                               my $arg2 = $8;
                                my $cast;
 
-                               if ($cast1 ne "" && $cast2 ne "") {
+                               if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) {
                                        $cast = "$cast1 or $cast2";
                                } elsif ($cast1 ne "") {
                                        $cast = $cast1;
@@ -3233,22 +3353,30 @@ sub process {
                             "__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr);
                }
 
+# check for use of yield()
+               if ($line =~ /\byield\s*\(\s*\)/) {
+                       WARN("YIELD",
+                            "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n"  . $herecurr);
+               }
+
 # check for semaphores initialized locked
                if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
                        WARN("CONSIDER_COMPLETION",
                             "consider using a completion\n" . $herecurr);
-
                }
+
 # recommend kstrto* over simple_strto* and strict_strto*
                if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) {
                        WARN("CONSIDER_KSTRTO",
                             "$1 is obsolete, use k$3 instead\n" . $herecurr);
                }
+
 # check for __initcall(), use device_initcall() explicitly please
                if ($line =~ /^.\s*__initcall\s*\(/) {
                        WARN("USE_DEVICE_INITCALL",
                             "please use device_initcall() instead of __initcall()\n" . $herecurr);
                }
+
 # check for various ops structs, ensure they are const.
                my $struct_ops = qr{acpi_dock_ops|
                                address_space_operations|
@@ -3385,6 +3513,12 @@ sub process {
        }
 
        if ($quiet == 0) {
+
+               if ($^V lt 5.10.0) {
+                       print("NOTE: perl $^V is not modern enough to detect all possible issues.\n");
+                       print("An upgrade to at least perl v5.10.0 is suggested.\n\n");
+               }
+
                # If there were whitespace errors which cleanpatch can fix
                # then suggest that.
                if ($rpt_cleaners) {
@@ -3394,13 +3528,12 @@ sub process {
                }
        }
 
-       if (keys %ignore_type) {
+       if ($quiet == 0 && keys %ignore_type) {
            print "NOTE: Ignored message types:";
            foreach my $ignore (sort keys %ignore_type) {
                print " $ignore";
            }
-           print "\n";
-           print "\n" if ($quiet == 0);
+           print "\n\n";
        }
 
        if ($clean == 1 && $quiet == 0) {
index f32a04c..0948c6b 100755 (executable)
@@ -931,7 +931,7 @@ sub get_maintainer_role {
     my $start = find_starting_index($index);
     my $end = find_ending_index($index);
 
-    my $role;
+    my $role = "unknown";
     my $subsystem = $typevalue[$start];
     if (length($subsystem) > 20) {
        $subsystem = substr($subsystem, 0, 17);
@@ -1027,8 +1027,13 @@ sub add_categories {
                    if ($email_list) {
                        if (!$hash_list_to{lc($list_address)}) {
                            $hash_list_to{lc($list_address)} = 1;
-                           push(@list_to, [$list_address,
-                                           "open list${list_role}"]);
+                           if ($list_additional =~ m/moderated/) {
+                               push(@list_to, [$list_address,
+                                               "moderated list${list_role}"]);
+                           } else {
+                               push(@list_to, [$list_address,
+                                               "open list${list_role}"]);
+                           }
                        }
                    }
                }
index 7c69599..6327685 100644 (file)
@@ -410,7 +410,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                 * exec\0change_profile
                 */
                state = aa_dfa_null_transition(profile->file.dfa, state);
-               cp = change_profile_perms(profile, cxt->onexec->ns, name,
+               cp = change_profile_perms(profile, cxt->onexec->ns,
+                                         cxt->onexec->base.name,
                                          AA_MAY_ONEXEC, state);
 
                if (!(cp.allow & AA_MAY_ONEXEC))
index 3022c0f..5d176f2 100644 (file)
@@ -215,6 +215,8 @@ static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state,
        /* change_profile wasn't determined by ownership in old mapping */
        if (ACCEPT_TABLE(dfa)[state] & 0x80000000)
                perms.allow |= AA_MAY_CHANGE_PROFILE;
+       if (ACCEPT_TABLE(dfa)[state] & 0x40000000)
+               perms.allow |= AA_MAY_ONEXEC;
 
        return perms;
 }
index 7ada801..06783cf 100644 (file)
@@ -671,6 +671,26 @@ found_kernel_type:
        return ktype;
 }
 
+void key_set_timeout(struct key *key, unsigned timeout)
+{
+       struct timespec now;
+       time_t expiry = 0;
+
+       /* make the changes with the locks held to prevent races */
+       down_write(&key->sem);
+
+       if (timeout > 0) {
+               now = current_kernel_time();
+               expiry = now.tv_sec + timeout;
+       }
+
+       key->expiry = expiry;
+       key_schedule_gc(key->expiry + key_gc_delay);
+
+       up_write(&key->sem);
+}
+EXPORT_SYMBOL_GPL(key_set_timeout);
+
 /*
  * Unlock a key type locked by key_type_lookup().
  */
index 6523599..fb767c6 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
+#include <linux/key.h>
 #include <linux/keyctl.h>
 #include <linux/fs.h>
 #include <linux/capability.h>
@@ -1257,10 +1258,8 @@ error:
  */
 long keyctl_set_timeout(key_serial_t id, unsigned timeout)
 {
-       struct timespec now;
        struct key *key, *instkey;
        key_ref_t key_ref;
-       time_t expiry;
        long ret;
 
        key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
@@ -1286,20 +1285,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
 
 okay:
        key = key_ref_to_ptr(key_ref);
-
-       /* make the changes with the locks held to prevent races */
-       down_write(&key->sem);
-
-       expiry = 0;
-       if (timeout > 0) {
-               now = current_kernel_time();
-               expiry = now.tv_sec + timeout;
-       }
-
-       key->expiry = expiry;
-       key_schedule_gc(key->expiry + key_gc_delay);
-
-       up_write(&key->sem);
+       key_set_timeout(key, timeout);
        key_put(key);
 
        ret = 0;
index 8246532..cc37903 100644 (file)
@@ -91,7 +91,7 @@ static void umh_keys_cleanup(struct subprocess_info *info)
  * Call a usermode helper with a specific session keyring.
  */
 static int call_usermodehelper_keys(char *path, char **argv, char **envp,
-                        struct key *session_keyring, enum umh_wait wait)
+                                       struct key *session_keyring, int wait)
 {
        gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
        struct subprocess_info *info =
index 6797540..078fac0 100644 (file)
@@ -102,7 +102,7 @@ void tomoyo_load_policy(const char *filename)
        envp[0] = "HOME=/";
        envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
        envp[2] = NULL;
-       call_usermodehelper(argv[0], argv, envp, 1);
+       call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
        tomoyo_check_profile();
 }
 
index b37b702..5119fda 100644 (file)
@@ -1110,18 +1110,7 @@ static struct amba_driver aaci_driver = {
        .id_table       = aaci_ids,
 };
 
-static int __init aaci_init(void)
-{
-       return amba_driver_register(&aaci_driver);
-}
-
-static void __exit aaci_exit(void)
-{
-       amba_driver_unregister(&aaci_driver);
-}
-
-module_init(aaci_init);
-module_exit(aaci_exit);
+module_amba_driver(aaci_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver");
index 068cf08..d8ec849 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/module.h>
+#include <linux/device.h>
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/time.h>
index 6e4bfcc..1a3070b 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
+#include <linux/device.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/pcm.h>
index 9d8379a..7121105 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/device.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 
index 8e7561d..6ddcf06 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
+#include <linux/device.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <sound/core.h>
index 6b68c82..a63faec 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/version.h>
+#include <linux/sched.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 #include <sound/tea575x-tuner.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
 MODULE_LICENSE("GPL");
 
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-#define FREQ_LO                 (50UL * 16000)
-#define FREQ_HI                (150UL * 16000)
+#define FREQ_LO                 (76U * 16000)
+#define FREQ_HI                (108U * 16000)
 
 /*
  * definitions
@@ -90,7 +89,7 @@ static void snd_tea575x_write(struct snd_tea575x *tea, unsigned int val)
                tea->ops->set_pins(tea, 0);
 }
 
-static unsigned int snd_tea575x_read(struct snd_tea575x *tea)
+static u32 snd_tea575x_read(struct snd_tea575x *tea)
 {
        u16 l, rdata;
        u32 data = 0;
@@ -121,11 +120,13 @@ static unsigned int snd_tea575x_read(struct snd_tea575x *tea)
        return data;
 }
 
-static void snd_tea575x_get_freq(struct snd_tea575x *tea)
+static u32 snd_tea575x_get_freq(struct snd_tea575x *tea)
 {
-       unsigned long freq;
+       u32 freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
+
+       if (freq == 0)
+               return freq;
 
-       freq = snd_tea575x_read(tea) & TEA575X_BIT_FREQ_MASK;
        /* freq *= 12.5 */
        freq *= 125;
        freq /= 10;
@@ -135,14 +136,13 @@ static void snd_tea575x_get_freq(struct snd_tea575x *tea)
        else
                freq -= TEA575X_FMIF;
 
-       tea->freq = freq * 16;          /* from kHz */
+       return clamp(freq * 16, FREQ_LO, FREQ_HI); /* from kHz */
 }
 
 static void snd_tea575x_set_freq(struct snd_tea575x *tea)
 {
-       unsigned long freq;
+       u32 freq = tea->freq;
 
-       freq = clamp(tea->freq, FREQ_LO, FREQ_HI);
        freq /= 16;             /* to kHz */
        /* crystal fixup */
        if (tea->tea5759)
@@ -167,12 +167,14 @@ static int vidioc_querycap(struct file *file, void  *priv,
 {
        struct snd_tea575x *tea = video_drvdata(file);
 
-       strlcpy(v->driver, "tea575x-tuner", sizeof(v->driver));
+       strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver));
        strlcpy(v->card, tea->card, sizeof(v->card));
        strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card));
        strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       if (!tea->cannot_read_data)
+               v->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
+       v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
 
@@ -191,18 +193,24 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
        v->rangelow = FREQ_LO;
        v->rangehigh = FREQ_HI;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       v->audmode = tea->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+       v->rxsubchans = tea->stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+       v->audmode = (tea->val & TEA575X_BIT_MONO) ?
+               V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO;
        v->signal = tea->tuned ? 0xffff : 0;
-
        return 0;
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       if (v->index > 0)
+       struct snd_tea575x *tea = video_drvdata(file);
+
+       if (v->index)
                return -EINVAL;
+       tea->val &= ~TEA575X_BIT_MONO;
+       if (v->audmode == V4L2_TUNER_MODE_MONO)
+               tea->val |= TEA575X_BIT_MONO;
+       snd_tea575x_write(tea, tea->val);
        return 0;
 }
 
@@ -214,7 +222,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        if (f->tuner != 0)
                return -EINVAL;
        f->type = V4L2_TUNER_RADIO;
-       snd_tea575x_get_freq(tea);
        f->frequency = tea->freq;
        return 0;
 }
@@ -227,33 +234,72 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
                return -EINVAL;
 
-       if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
-               return -EINVAL;
-
-       tea->freq = f->frequency;
-
+       tea->val &= ~TEA575X_BIT_SEARCH;
+       tea->freq = clamp(f->frequency, FREQ_LO, FREQ_HI);
        snd_tea575x_set_freq(tea);
-
        return 0;
 }
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
+static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
+                                       struct v4l2_hw_freq_seek *a)
 {
-       if (a->index > 1)
-               return -EINVAL;
-
-       strcpy(a->name, "Radio");
-       a->capability = V4L2_AUDCAP_STEREO;
-       return 0;
-}
+       struct snd_tea575x *tea = video_drvdata(file);
+       unsigned long timeout;
+       int i;
 
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       if (a->index != 0)
+       if (tea->cannot_read_data)
+               return -ENOTTY;
+       if (a->tuner || a->wrap_around)
                return -EINVAL;
-       return 0;
+
+       /* clear the frequency, HW will fill it in */
+       tea->val &= ~TEA575X_BIT_FREQ_MASK;
+       tea->val |= TEA575X_BIT_SEARCH;
+       if (a->seek_upward)
+               tea->val |= TEA575X_BIT_UPDOWN;
+       else
+               tea->val &= ~TEA575X_BIT_UPDOWN;
+       snd_tea575x_write(tea, tea->val);
+       timeout = jiffies + msecs_to_jiffies(10000);
+       for (;;) {
+               if (time_after(jiffies, timeout))
+                       break;
+               if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
+                       /* some signal arrived, stop search */
+                       tea->val &= ~TEA575X_BIT_SEARCH;
+                       snd_tea575x_set_freq(tea);
+                       return -ERESTARTSYS;
+               }
+               if (!(snd_tea575x_read(tea) & TEA575X_BIT_SEARCH)) {
+                       u32 freq;
+
+                       /* Found a frequency, wait until it can be read */
+                       for (i = 0; i < 100; i++) {
+                               msleep(10);
+                               freq = snd_tea575x_get_freq(tea);
+                               if (freq) /* available */
+                                       break;
+                       }
+                       if (freq == 0) /* shouldn't happen */
+                               break;
+                       /*
+                        * if we moved by less than 50 kHz, or in the wrong
+                        * direction, continue seeking
+                        */
+                       if (abs(tea->freq - freq) < 16 * 50 ||
+                                       (a->seek_upward && freq < tea->freq) ||
+                                       (!a->seek_upward && freq > tea->freq)) {
+                               snd_tea575x_write(tea, tea->val);
+                               continue;
+                       }
+                       tea->freq = freq;
+                       tea->val &= ~TEA575X_BIT_SEARCH;
+                       return 0;
+               }
+       }
+       tea->val &= ~TEA575X_BIT_SEARCH;
+       snd_tea575x_set_freq(tea);
+       return -EAGAIN;
 }
 
 static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -273,23 +319,27 @@ static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
 static const struct v4l2_file_operations tea575x_fops = {
        .owner          = THIS_MODULE,
        .unlocked_ioctl = video_ioctl2,
+       .open           = v4l2_fh_open,
+       .release        = v4l2_fh_release,
+       .poll           = v4l2_ctrl_poll,
 };
 
 static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
        .vidioc_querycap    = vidioc_querycap,
        .vidioc_g_tuner     = vidioc_g_tuner,
        .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
        .vidioc_g_frequency = vidioc_g_frequency,
        .vidioc_s_frequency = vidioc_s_frequency,
+       .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
+       .vidioc_log_status  = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
-static struct video_device tea575x_radio = {
-       .name           = "tea575x-tuner",
+static const struct video_device tea575x_radio = {
        .fops           = &tea575x_fops,
        .ioctl_ops      = &tea575x_ioctl_ops,
-       .release        = video_device_release_empty,
+       .release        = video_device_release_empty,
 };
 
 static const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
@@ -303,27 +353,34 @@ int snd_tea575x_init(struct snd_tea575x *tea)
 {
        int retval;
 
-       tea->mute = 1;
+       tea->mute = true;
 
-       snd_tea575x_write(tea, 0x55AA);
-       if (snd_tea575x_read(tea) != 0x55AA)
-               return -ENODEV;
+       /* Not all devices can or know how to read the data back.
+          Such devices can set cannot_read_data to true. */
+       if (!tea->cannot_read_data) {
+               snd_tea575x_write(tea, 0x55AA);
+               if (snd_tea575x_read(tea) != 0x55AA)
+                       return -ENODEV;
+       }
 
-       tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
+       tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_5_28;
        tea->freq = 90500 * 16;         /* 90.5Mhz default */
        snd_tea575x_set_freq(tea);
 
        tea->vd = tea575x_radio;
        video_set_drvdata(&tea->vd, tea);
        mutex_init(&tea->mutex);
+       strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name));
        tea->vd.lock = &tea->mutex;
+       tea->vd.v4l2_dev = tea->v4l2_dev;
+       tea->vd.ctrl_handler = &tea->ctrl_handler;
+       set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags);
 
        v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
-       tea->vd.ctrl_handler = &tea->ctrl_handler;
        v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
        retval = tea->ctrl_handler.error;
        if (retval) {
-               printk(KERN_ERR "tea575x-tuner: can't initialize controls\n");
+               v4l2_err(tea->v4l2_dev, "can't initialize controls\n");
                v4l2_ctrl_handler_free(&tea->ctrl_handler);
                return retval;
        }
@@ -338,9 +395,9 @@ int snd_tea575x_init(struct snd_tea575x *tea)
 
        v4l2_ctrl_handler_setup(&tea->ctrl_handler);
 
-       retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, radio_nr);
+       retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->radio_nr);
        if (retval) {
-               printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
+               v4l2_err(tea->v4l2_dev, "can't register video device!\n");
                v4l2_ctrl_handler_free(&tea->ctrl_handler);
                return retval;
        }
index cb557c6..a8faae1 100644 (file)
@@ -142,6 +142,7 @@ static int enable_mpu[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
 #ifdef SUPPORT_JOYSTICK
 static bool joystick[SNDRV_CARDS];
 #endif
+static int radio_nr[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
@@ -165,6 +166,9 @@ MODULE_PARM_DESC(enable_mpu, "Enable MPU401.  (0 = off, 1 = on, 2 = auto)");
 module_param_array(joystick, bool, NULL, 0444);
 MODULE_PARM_DESC(joystick, "Enable joystick.");
 #endif
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
 
 
 #define NR_APUS                        64
@@ -558,6 +562,7 @@ struct es1968 {
        struct work_struct hwvol_work;
 
 #ifdef CONFIG_SND_ES1968_RADIO
+       struct v4l2_device v4l2_dev;
        struct snd_tea575x tea;
 #endif
 };
@@ -2613,6 +2618,7 @@ static int snd_es1968_free(struct es1968 *chip)
 
 #ifdef CONFIG_SND_ES1968_RADIO
        snd_tea575x_exit(&chip->tea);
+       v4l2_device_unregister(&chip->v4l2_dev);
 #endif
 
        if (chip->irq >= 0)
@@ -2655,6 +2661,7 @@ static int __devinit snd_es1968_create(struct snd_card *card,
                                       int capt_streams,
                                       int chip_type,
                                       int do_pm,
+                                      int radio_nr,
                                       struct es1968 **chip_ret)
 {
        static struct snd_device_ops ops = {
@@ -2751,7 +2758,14 @@ static int __devinit snd_es1968_create(struct snd_card *card,
        snd_card_set_dev(card, &pci->dev);
 
 #ifdef CONFIG_SND_ES1968_RADIO
+       err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
+       if (err < 0) {
+               snd_es1968_free(chip);
+               return err;
+       }
+       chip->tea.v4l2_dev = &chip->v4l2_dev;
        chip->tea.private_data = chip;
+       chip->tea.radio_nr = radio_nr;
        chip->tea.ops = &snd_es1968_tea_ops;
        strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
        sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
@@ -2797,6 +2811,7 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci,
                                     pcm_substreams_c[dev],
                                     pci_id->driver_data,
                                     use_pm[dev],
+                                    radio_nr[dev],
                                     &chip)) < 0) {
                snd_card_free(card);
                return err;
index 9597ef1..a416ea8 100644 (file)
@@ -58,6 +58,7 @@ static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;   /* Enable this card
  *  High 16-bits are video (radio) device number + 1
  */
 static int tea575x_tuner[SNDRV_CARDS];
+static int radio_nr[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the FM801 soundcard.");
@@ -67,6 +68,9 @@ module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable FM801 soundcard.");
 module_param_array(tea575x_tuner, int, NULL, 0444);
 MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (0 = auto, 1 = SF256-PCS, 2=SF256-PCP, 3=SF64-PCR, 8=disable, +16=tuner-only).");
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
+
 
 #define TUNER_DISABLED         (1<<3)
 #define TUNER_ONLY             (1<<4)
@@ -197,6 +201,7 @@ struct fm801 {
        struct snd_info_entry *proc_entry;
 
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
+       struct v4l2_device v4l2_dev;
        struct snd_tea575x tea;
 #endif
 
@@ -1154,8 +1159,10 @@ static int snd_fm801_free(struct fm801 *chip)
 
       __end_hw:
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
-       if (!(chip->tea575x_tuner & TUNER_DISABLED))
+       if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
                snd_tea575x_exit(&chip->tea);
+               v4l2_device_unregister(&chip->v4l2_dev);
+       }
 #endif
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
@@ -1175,6 +1182,7 @@ static int snd_fm801_dev_free(struct snd_device *device)
 static int __devinit snd_fm801_create(struct snd_card *card,
                                      struct pci_dev * pci,
                                      int tea575x_tuner,
+                                     int radio_nr,
                                      struct fm801 ** rchip)
 {
        struct fm801 *chip;
@@ -1234,6 +1242,13 @@ static int __devinit snd_fm801_create(struct snd_card *card,
        snd_card_set_dev(card, &pci->dev);
 
 #ifdef CONFIG_SND_FM801_TEA575X_BOOL
+       err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
+       if (err < 0) {
+               snd_fm801_free(chip);
+               return err;
+       }
+       chip->tea.v4l2_dev = &chip->v4l2_dev;
+       chip->tea.radio_nr = radio_nr;
        chip->tea.private_data = chip;
        chip->tea.ops = &snd_fm801_tea_ops;
        sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
@@ -1241,6 +1256,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
            (tea575x_tuner & TUNER_TYPE_MASK) < 4) {
                if (snd_tea575x_init(&chip->tea)) {
                        snd_printk(KERN_ERR "TEA575x radio not found\n");
+                       snd_fm801_free(chip);
                        return -ENODEV;
                }
        } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) {
@@ -1287,7 +1303,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
        err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
-       if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], &chip)) < 0) {
+       if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], radio_nr[dev], &chip)) < 0) {
                snd_card_free(card);
                return err;
        }
index a839494..601df80 100644 (file)
@@ -80,13 +80,13 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
                return -ENOMEM;
 
        if (audmux_clk)
-               clk_enable(audmux_clk);
+               clk_prepare_enable(audmux_clk);
 
        ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port));
        pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port));
 
        if (audmux_clk)
-               clk_disable(audmux_clk);
+               clk_disable_unprepare(audmux_clk);
 
        ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n",
                       pdcr, ptcr);
@@ -237,13 +237,13 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
                return -ENOSYS;
 
        if (audmux_clk)
-               clk_enable(audmux_clk);
+               clk_prepare_enable(audmux_clk);
 
        writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port));
        writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port));
 
        if (audmux_clk)
-               clk_disable(audmux_clk);
+               clk_disable_unprepare(audmux_clk);
 
        return 0;
 }
index 49fe63c..7d4fa8e 100644 (file)
@@ -426,29 +426,6 @@ static struct snd_soc_ops ams_delta_ops = {
 };
 
 
-/* Board specific codec bias level control */
-static int ams_delta_set_bias_level(struct snd_soc_card *card,
-                                   struct snd_soc_dapm_context *dapm,
-                                   enum snd_soc_bias_level level)
-{
-       switch (level) {
-       case SND_SOC_BIAS_ON:
-       case SND_SOC_BIAS_PREPARE:
-       case SND_SOC_BIAS_STANDBY:
-               if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
-                       ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
-                                               AMS_DELTA_LATCH2_MODEM_NRESET);
-               break;
-       case SND_SOC_BIAS_OFF:
-               if (card->dapm.bias_level != SND_SOC_BIAS_OFF)
-                       ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
-                                               0);
-       }
-       card->dapm.bias_level = level;
-
-       return 0;
-}
-
 /* Digital mute implemented using modem/CPU multiplexer.
  * Shares hardware with codec config pulse generation */
 static bool ams_delta_muted = 1;
@@ -512,9 +489,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
                ams_delta_ops.shutdown = ams_delta_shutdown;
        }
 
-       /* Set codec bias level */
-       ams_delta_set_bias_level(card, dapm, SND_SOC_BIAS_STANDBY);
-
        /* Add hook switch - can be used to control the codec from userspace
         * even if line discipline fails */
        ret = snd_soc_jack_new(rtd->codec, "hook_switch",
@@ -598,7 +572,6 @@ static struct snd_soc_card ams_delta_audio_card = {
        .owner = THIS_MODULE,
        .dai_link = &ams_delta_dai_link,
        .num_links = 1,
-       .set_bias_level = ams_delta_set_bias_level,
 };
 
 /* Module init/exit */
@@ -635,7 +608,7 @@ err:
        platform_device_put(ams_delta_audio_platform_device);
        return ret;
 }
-module_init(ams_delta_module_init);
+late_initcall(ams_delta_module_init);
 
 static void __exit ams_delta_module_exit(void)
 {
@@ -647,11 +620,6 @@ static void __exit ams_delta_module_exit(void)
                        ARRAY_SIZE(ams_delta_hook_switch_gpios),
                        ams_delta_hook_switch_gpios);
 
-       /* Keep modem power on */
-       ams_delta_set_bias_level(&ams_delta_audio_card,
-                                &ams_delta_audio_card.rtd[0].codec->dapm,
-                                SND_SOC_BIAS_STANDBY);
-
        platform_device_unregister(cx20442_platform_device);
        platform_device_unregister(ams_delta_audio_platform_device);
 }
index f3417f2..fe3995c 100644 (file)
@@ -1,8 +1,8 @@
 config SND_SOC_SAMSUNG
        tristate "ASoC support for Samsung"
-       depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4
+       depends on ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4
        select S3C64XX_DMA if ARCH_S3C64XX
-       select S3C2410_DMA if ARCH_S3C2410
+       select S3C2410_DMA if ARCH_S3C24XX
        help
          Say Y or M if you want to add support for codecs attached to
          the Samsung SoCs' Audio interfaces. You will also need to
@@ -84,7 +84,7 @@ config SND_SOC_SAMSUNG_SMDK2443_WM9710
 
 config SND_SOC_SAMSUNG_LN2440SBC_ALC650
        tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
-       depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+       depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
        select S3C2410_DMA
        select AC97_BUS
        select SND_SOC_AC97_CODEC
@@ -95,7 +95,7 @@ config SND_SOC_SAMSUNG_LN2440SBC_ALC650
 
 config SND_SOC_SAMSUNG_S3C24XX_UDA134X
        tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
-       depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+       depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
        select SND_S3C24XX_I2S
        select SND_SOC_L3
        select SND_SOC_UDA134X
@@ -107,14 +107,14 @@ config SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
        tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
-       depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+       depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
        select SND_S3C24XX_I2S
        select SND_SOC_TLV320AIC23
        select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_HERMES
        tristate "SoC I2S Audio support for Simtec Hermes board"
-       depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+       depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
        select SND_S3C24XX_I2S
        select SND_SOC_TLV320AIC3X
        select SND_SOC_SAMSUNG_SIMTEC
index 62cdee7..f158483 100644 (file)
@@ -15,7 +15,7 @@
             (bit) = find_next_bit((addr), (size), (bit) + 1))
 
 /* same as for_each_set_bit() but use bit as value to start with */
-#define for_each_set_bit_cont(bit, addr, size) \
+#define for_each_set_bit_from(bit, addr, size) \
        for ((bit) = find_next_bit((addr), (size), (bit));      \
             (bit) < (size);                                    \
             (bit) = find_next_bit((addr), (size), (bit) + 1))
index 758ec2a..95d6a6f 100755 (executable)
@@ -46,6 +46,7 @@ my %default = (
     "DIE_ON_FAILURE"           => 1,
     "SSH_EXEC"                 => "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND",
     "SCP_TO_TARGET"            => "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE",
+    "SCP_TO_TARGET_INSTALL"    => "\${SCP_TO_TARGET}",
     "REBOOT"                   => "ssh \$SSH_USER\@\$MACHINE reboot",
     "STOP_AFTER_SUCCESS"       => 10,
     "STOP_AFTER_FAILURE"       => 60,
@@ -86,11 +87,13 @@ my $reboot_on_error;
 my $switch_to_good;
 my $switch_to_test;
 my $poweroff_on_error;
+my $reboot_on_success;
 my $die_on_failure;
 my $powercycle_after_reboot;
 my $poweroff_after_halt;
 my $ssh_exec;
 my $scp_to_target;
+my $scp_to_target_install;
 my $power_off;
 my $grub_menu;
 my $grub_number;
@@ -211,6 +214,7 @@ my %option_map = (
     "SWITCH_TO_GOOD"           => \$switch_to_good,
     "SWITCH_TO_TEST"           => \$switch_to_test,
     "POWEROFF_ON_ERROR"                => \$poweroff_on_error,
+    "REBOOT_ON_SUCCESS"                => \$reboot_on_success,
     "DIE_ON_FAILURE"           => \$die_on_failure,
     "POWER_OFF"                        => \$power_off,
     "POWERCYCLE_AFTER_REBOOT"  => \$powercycle_after_reboot,
@@ -243,6 +247,7 @@ my %option_map = (
     "BUILD_TARGET"             => \$build_target,
     "SSH_EXEC"                 => \$ssh_exec,
     "SCP_TO_TARGET"            => \$scp_to_target,
+    "SCP_TO_TARGET_INSTALL"    => \$scp_to_target_install,
     "CHECKOUT"                 => \$checkout,
     "TARGET_IMAGE"             => \$target_image,
     "LOCALVERSION"             => \$localversion,
@@ -1113,7 +1118,6 @@ sub reboot_to_good {
 
     if (defined($switch_to_good)) {
        run_command $switch_to_good;
-       return;
     }
 
     reboot $time;
@@ -1349,8 +1353,7 @@ sub run_ssh {
 }
 
 sub run_scp {
-    my ($src, $dst) = @_;
-    my $cp_scp = $scp_to_target;
+    my ($src, $dst, $cp_scp) = @_;
 
     $cp_scp =~ s/\$SRC_FILE/$src/g;
     $cp_scp =~ s/\$DST_FILE/$dst/g;
@@ -1358,6 +1361,22 @@ sub run_scp {
     return run_command "$cp_scp";
 }
 
+sub run_scp_install {
+    my ($src, $dst) = @_;
+
+    my $cp_scp = $scp_to_target_install;
+
+    return run_scp($src, $dst, $cp_scp);
+}
+
+sub run_scp_mod {
+    my ($src, $dst) = @_;
+
+    my $cp_scp = $scp_to_target;
+
+    return run_scp($src, $dst, $cp_scp);
+}
+
 sub get_grub_index {
 
     if ($reboot_type ne "grub") {
@@ -1460,6 +1479,7 @@ sub get_sha1 {
 sub monitor {
     my $booted = 0;
     my $bug = 0;
+    my $bug_ignored = 0;
     my $skip_call_trace = 0;
     my $loops;
 
@@ -1531,9 +1551,13 @@ sub monitor {
        }
 
        if ($full_line =~ /call trace:/i) {
-           if (!$ignore_errors && !$bug && !$skip_call_trace) {
-               $bug = 1;
-               $failure_start = time;
+           if (!$bug && !$skip_call_trace) {
+               if ($ignore_errors) {
+                   $bug_ignored = 1;
+               } else {
+                   $bug = 1;
+                   $failure_start = time;
+               }
            }
        }
 
@@ -1595,6 +1619,10 @@ sub monitor {
        fail "failed - never got a boot prompt." and return 0;
     }
 
+    if ($bug_ignored) {
+       doprint "WARNING: Call Trace detected but ignored due to IGNORE_ERRORS=1\n";
+    }
+
     return 1;
 }
 
@@ -1621,7 +1649,7 @@ sub install {
 
     my $cp_target = eval_kernel_version $target_image;
 
-    run_scp "$outputdir/$build_target", "$cp_target" or
+    run_scp_install "$outputdir/$build_target", "$cp_target" or
        dodie "failed to copy image";
 
     my $install_mods = 0;
@@ -1643,7 +1671,7 @@ sub install {
        return;
     }
 
-    run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or
+    run_command "$make INSTALL_MOD_STRIP=1 INSTALL_MOD_PATH=$tmpdir modules_install" or
        dodie "Failed to install modules";
 
     my $modlib = "/lib/modules/$version";
@@ -1656,7 +1684,7 @@ sub install {
     run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or
        dodie "making tarball";
 
-    run_scp "$tmpdir/$modtar", "/tmp" or
+    run_scp_mod "$tmpdir/$modtar", "/tmp" or
        dodie "failed to copy modules";
 
     unlink "$tmpdir/$modtar";
@@ -3526,8 +3554,10 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
            die "failed to checkout $checkout";
     }
 
-    $no_reboot = 0;
-
+    # A test may opt to not reboot the box
+    if ($reboot_on_success) {
+       $no_reboot = 0;
+    }
 
     if ($test_type eq "bisect") {
        bisect $i;
@@ -3572,8 +3602,12 @@ if ($opt{"POWEROFF_ON_SUCCESS"}) {
     halt;
 } elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) {
     reboot_to_good;
+} elsif (defined($switch_to_good)) {
+    # still need to get to the good kernel
+    run_command $switch_to_good;
 }
 
+
 doprint "\n    $successes of $opt{NUM_TESTS} tests were successful\n\n";
 
 exit 0;
index 5ea04c6..b682456 100644 (file)
 # The variables SSH_USER, MACHINE and SSH_COMMAND are defined
 #SSH_EXEC = ssh $SSH_USER@$MACHINE $SSH_COMMAND";
 
-# The way to copy a file to the target
+# The way to copy a file to the target (install and modules)
 # (default scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE)
-# The variables SSH_USER, MACHINE, SRC_FILE and DST_FILE are defined.
-#SCP_TO_TARGET = scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE
+# The variables SSH_USER, MACHINE are defined by the config
+# SRC_FILE and DST_FILE are ktest internal variables and
+# should only have '$' and not the '${}' notation.
+# (default scp $SRC_FILE ${SSH_USER}@${MACHINE}:$DST_FILE)
+#SCP_TO_TARGET = echo skip scp for $SRC_FILE $DST_FILE
+
+# If install needs to be different than modules, then this
+# option will override the SCP_TO_TARGET for installation.
+# (default ${SCP_TO_TARGET} )
+#SCP_TO_TARGET_INSTALL = scp $SRC_FILE tftp@tftpserver:$DST_FILE
 
 # The nice way to reboot the target
 # (default ssh $SSH_USER@$MACHINE reboot)
diff --git a/tools/virtio/linux/hrtimer.h b/tools/virtio/linux/hrtimer.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tools/virtio/linux/module.h b/tools/virtio/linux/module.h
new file mode 100644 (file)
index 0000000..e69de29
index b4fbc91..7579f19 100644 (file)
@@ -181,6 +181,9 @@ struct virtqueue {
 #define smp_mb()       mb()
 # define smp_rmb()     barrier()
 # define smp_wmb()     barrier()
+/* Weak barriers should be used. If not - it's a bug */
+# define rmb() abort()
+# define wmb() abort()
 #else
 #error Please fill in barrier macros
 #endif
index 758e3b3..01f572c 100644 (file)
@@ -49,31 +49,73 @@ static int find_index_from_host_irq(struct kvm_assigned_dev_kernel
                        index = i;
                        break;
                }
-       if (index < 0) {
+       if (index < 0)
                printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n");
-               return 0;
-       }
 
        return index;
 }
 
-static irqreturn_t kvm_assigned_dev_thread(int irq, void *dev_id)
+static irqreturn_t kvm_assigned_dev_intx(int irq, void *dev_id)
 {
        struct kvm_assigned_dev_kernel *assigned_dev = dev_id;
+       int ret;
+
+       spin_lock(&assigned_dev->intx_lock);
+       if (pci_check_and_mask_intx(assigned_dev->dev)) {
+               assigned_dev->host_irq_disabled = true;
+               ret = IRQ_WAKE_THREAD;
+       } else
+               ret = IRQ_NONE;
+       spin_unlock(&assigned_dev->intx_lock);
+
+       return ret;
+}
 
-       if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_INTX) {
-               spin_lock(&assigned_dev->intx_lock);
+static void
+kvm_assigned_dev_raise_guest_irq(struct kvm_assigned_dev_kernel *assigned_dev,
+                                int vector)
+{
+       if (unlikely(assigned_dev->irq_requested_type &
+                    KVM_DEV_IRQ_GUEST_INTX)) {
+               spin_lock(&assigned_dev->intx_mask_lock);
+               if (!(assigned_dev->flags & KVM_DEV_ASSIGN_MASK_INTX))
+                       kvm_set_irq(assigned_dev->kvm,
+                                   assigned_dev->irq_source_id, vector, 1);
+               spin_unlock(&assigned_dev->intx_mask_lock);
+       } else
+               kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
+                           vector, 1);
+}
+
+static irqreturn_t kvm_assigned_dev_thread_intx(int irq, void *dev_id)
+{
+       struct kvm_assigned_dev_kernel *assigned_dev = dev_id;
+
+       if (!(assigned_dev->flags & KVM_DEV_ASSIGN_PCI_2_3)) {
+               spin_lock_irq(&assigned_dev->intx_lock);
                disable_irq_nosync(irq);
                assigned_dev->host_irq_disabled = true;
-               spin_unlock(&assigned_dev->intx_lock);
+               spin_unlock_irq(&assigned_dev->intx_lock);
        }
 
-       kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
-                   assigned_dev->guest_irq, 1);
+       kvm_assigned_dev_raise_guest_irq(assigned_dev,
+                                        assigned_dev->guest_irq);
 
        return IRQ_HANDLED;
 }
 
+#ifdef __KVM_HAVE_MSI
+static irqreturn_t kvm_assigned_dev_thread_msi(int irq, void *dev_id)
+{
+       struct kvm_assigned_dev_kernel *assigned_dev = dev_id;
+
+       kvm_assigned_dev_raise_guest_irq(assigned_dev,
+                                        assigned_dev->guest_irq);
+
+       return IRQ_HANDLED;
+}
+#endif
+
 #ifdef __KVM_HAVE_MSIX
 static irqreturn_t kvm_assigned_dev_thread_msix(int irq, void *dev_id)
 {
@@ -83,8 +125,7 @@ static irqreturn_t kvm_assigned_dev_thread_msix(int irq, void *dev_id)
 
        if (index >= 0) {
                vector = assigned_dev->guest_msix_entries[index].vector;
-               kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
-                           vector, 1);
+               kvm_assigned_dev_raise_guest_irq(assigned_dev, vector);
        }
 
        return IRQ_HANDLED;
@@ -100,15 +141,31 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
 
        kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0);
 
-       /* The guest irq may be shared so this ack may be
-        * from another device.
-        */
-       spin_lock(&dev->intx_lock);
-       if (dev->host_irq_disabled) {
-               enable_irq(dev->host_irq);
-               dev->host_irq_disabled = false;
+       spin_lock(&dev->intx_mask_lock);
+
+       if (!(dev->flags & KVM_DEV_ASSIGN_MASK_INTX)) {
+               bool reassert = false;
+
+               spin_lock_irq(&dev->intx_lock);
+               /*
+                * The guest IRQ may be shared so this ack can come from an
+                * IRQ for another guest device.
+                */
+               if (dev->host_irq_disabled) {
+                       if (!(dev->flags & KVM_DEV_ASSIGN_PCI_2_3))
+                               enable_irq(dev->host_irq);
+                       else if (!pci_check_and_unmask_intx(dev->dev))
+                               reassert = true;
+                       dev->host_irq_disabled = reassert;
+               }
+               spin_unlock_irq(&dev->intx_lock);
+
+               if (reassert)
+                       kvm_set_irq(dev->kvm, dev->irq_source_id,
+                                   dev->guest_irq, 1);
        }
-       spin_unlock(&dev->intx_lock);
+
+       spin_unlock(&dev->intx_mask_lock);
 }
 
 static void deassign_guest_irq(struct kvm *kvm,
@@ -156,7 +213,15 @@ static void deassign_host_irq(struct kvm *kvm,
                pci_disable_msix(assigned_dev->dev);
        } else {
                /* Deal with MSI and INTx */
-               disable_irq(assigned_dev->host_irq);
+               if ((assigned_dev->irq_requested_type &
+                    KVM_DEV_IRQ_HOST_INTX) &&
+                   (assigned_dev->flags & KVM_DEV_ASSIGN_PCI_2_3)) {
+                       spin_lock_irq(&assigned_dev->intx_lock);
+                       pci_intx(assigned_dev->dev, false);
+                       spin_unlock_irq(&assigned_dev->intx_lock);
+                       synchronize_irq(assigned_dev->host_irq);
+               } else
+                       disable_irq(assigned_dev->host_irq);
 
                free_irq(assigned_dev->host_irq, assigned_dev);
 
@@ -237,15 +302,34 @@ void kvm_free_all_assigned_devices(struct kvm *kvm)
 static int assigned_device_enable_host_intx(struct kvm *kvm,
                                            struct kvm_assigned_dev_kernel *dev)
 {
+       irq_handler_t irq_handler;
+       unsigned long flags;
+
        dev->host_irq = dev->dev->irq;
-       /* Even though this is PCI, we don't want to use shared
-        * interrupts. Sharing host devices with guest-assigned devices
-        * on the same interrupt line is not a happy situation: there
-        * are going to be long delays in accepting, acking, etc.
+
+       /*
+        * We can only share the IRQ line with other host devices if we are
+        * able to disable the IRQ source at device-level - independently of
+        * the guest driver. Otherwise host devices may suffer from unbounded
+        * IRQ latencies when the guest keeps the line asserted.
         */
-       if (request_threaded_irq(dev->host_irq, NULL, kvm_assigned_dev_thread,
-                                IRQF_ONESHOT, dev->irq_name, dev))
+       if (dev->flags & KVM_DEV_ASSIGN_PCI_2_3) {
+               irq_handler = kvm_assigned_dev_intx;
+               flags = IRQF_SHARED;
+       } else {
+               irq_handler = NULL;
+               flags = IRQF_ONESHOT;
+       }
+       if (request_threaded_irq(dev->host_irq, irq_handler,
+                                kvm_assigned_dev_thread_intx, flags,
+                                dev->irq_name, dev))
                return -EIO;
+
+       if (dev->flags & KVM_DEV_ASSIGN_PCI_2_3) {
+               spin_lock_irq(&dev->intx_lock);
+               pci_intx(dev->dev, true);
+               spin_unlock_irq(&dev->intx_lock);
+       }
        return 0;
 }
 
@@ -262,8 +346,9 @@ static int assigned_device_enable_host_msi(struct kvm *kvm,
        }
 
        dev->host_irq = dev->dev->irq;
-       if (request_threaded_irq(dev->host_irq, NULL, kvm_assigned_dev_thread,
-                                0, dev->irq_name, dev)) {
+       if (request_threaded_irq(dev->host_irq, NULL,
+                                kvm_assigned_dev_thread_msi, 0,
+                                dev->irq_name, dev)) {
                pci_disable_msi(dev->dev);
                return -EIO;
        }
@@ -321,7 +406,6 @@ static int assigned_device_enable_guest_msi(struct kvm *kvm,
 {
        dev->guest_irq = irq->guest_irq;
        dev->ack_notifier.gsi = -1;
-       dev->host_irq_disabled = false;
        return 0;
 }
 #endif
@@ -333,7 +417,6 @@ static int assigned_device_enable_guest_msix(struct kvm *kvm,
 {
        dev->guest_irq = irq->guest_irq;
        dev->ack_notifier.gsi = -1;
-       dev->host_irq_disabled = false;
        return 0;
 }
 #endif
@@ -367,6 +450,7 @@ static int assign_host_irq(struct kvm *kvm,
        default:
                r = -EINVAL;
        }
+       dev->host_irq_disabled = false;
 
        if (!r)
                dev->irq_requested_type |= host_irq_type;
@@ -468,6 +552,7 @@ static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm,
 {
        int r = -ENODEV;
        struct kvm_assigned_dev_kernel *match;
+       unsigned long irq_type;
 
        mutex_lock(&kvm->lock);
 
@@ -476,7 +561,9 @@ static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm,
        if (!match)
                goto out;
 
-       r = kvm_deassign_irq(kvm, match, assigned_irq->flags);
+       irq_type = assigned_irq->flags & (KVM_DEV_IRQ_HOST_MASK |
+                                         KVM_DEV_IRQ_GUEST_MASK);
+       r = kvm_deassign_irq(kvm, match, irq_type);
 out:
        mutex_unlock(&kvm->lock);
        return r;
@@ -609,6 +696,10 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
        if (!match->pci_saved_state)
                printk(KERN_DEBUG "%s: Couldn't store %s saved state\n",
                       __func__, dev_name(&dev->dev));
+
+       if (!pci_intx_mask_supported(dev))
+               assigned_dev->flags &= ~KVM_DEV_ASSIGN_PCI_2_3;
+
        match->assigned_dev_id = assigned_dev->assigned_dev_id;
        match->host_segnr = assigned_dev->segnr;
        match->host_busnr = assigned_dev->busnr;
@@ -616,6 +707,7 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
        match->flags = assigned_dev->flags;
        match->dev = dev;
        spin_lock_init(&match->intx_lock);
+       spin_lock_init(&match->intx_mask_lock);
        match->irq_source_id = -1;
        match->kvm = kvm;
        match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq;
@@ -761,6 +853,55 @@ msix_entry_out:
 }
 #endif
 
+static int kvm_vm_ioctl_set_pci_irq_mask(struct kvm *kvm,
+               struct kvm_assigned_pci_dev *assigned_dev)
+{
+       int r = 0;
+       struct kvm_assigned_dev_kernel *match;
+
+       mutex_lock(&kvm->lock);
+
+       match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+                                     assigned_dev->assigned_dev_id);
+       if (!match) {
+               r = -ENODEV;
+               goto out;
+       }
+
+       spin_lock(&match->intx_mask_lock);
+
+       match->flags &= ~KVM_DEV_ASSIGN_MASK_INTX;
+       match->flags |= assigned_dev->flags & KVM_DEV_ASSIGN_MASK_INTX;
+
+       if (match->irq_requested_type & KVM_DEV_IRQ_GUEST_INTX) {
+               if (assigned_dev->flags & KVM_DEV_ASSIGN_MASK_INTX) {
+                       kvm_set_irq(match->kvm, match->irq_source_id,
+                                   match->guest_irq, 0);
+                       /*
+                        * Masking at hardware-level is performed on demand,
+                        * i.e. when an IRQ actually arrives at the host.
+                        */
+               } else if (!(assigned_dev->flags & KVM_DEV_ASSIGN_PCI_2_3)) {
+                       /*
+                        * Unmask the IRQ line if required. Unmasking at
+                        * device level will be performed by user space.
+                        */
+                       spin_lock_irq(&match->intx_lock);
+                       if (match->host_irq_disabled) {
+                               enable_irq(match->host_irq);
+                               match->host_irq_disabled = false;
+                       }
+                       spin_unlock_irq(&match->intx_lock);
+               }
+       }
+
+       spin_unlock(&match->intx_mask_lock);
+
+out:
+       mutex_unlock(&kvm->lock);
+       return r;
+}
+
 long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
                                  unsigned long arg)
 {
@@ -868,6 +1009,15 @@ long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
                break;
        }
 #endif
+       case KVM_ASSIGN_SET_INTX_MASK: {
+               struct kvm_assigned_pci_dev assigned_dev;
+
+               r = -EFAULT;
+               if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
+                       goto out;
+               r = kvm_vm_ioctl_set_pci_irq_mask(kvm, &assigned_dev);
+               break;
+       }
        default:
                r = -ENOTTY;
                break;
@@ -875,4 +1025,3 @@ long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
 out:
        return r;
 }
-
index a91f980..42b7393 100644 (file)
@@ -203,7 +203,7 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
 
 void kvm_flush_remote_tlbs(struct kvm *kvm)
 {
-       int dirty_count = kvm->tlbs_dirty;
+       long dirty_count = kvm->tlbs_dirty;
 
        smp_mb();
        if (make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH))
@@ -289,15 +289,15 @@ static void kvm_mmu_notifier_invalidate_page(struct mmu_notifier *mn,
         */
        idx = srcu_read_lock(&kvm->srcu);
        spin_lock(&kvm->mmu_lock);
+
        kvm->mmu_notifier_seq++;
        need_tlb_flush = kvm_unmap_hva(kvm, address) | kvm->tlbs_dirty;
-       spin_unlock(&kvm->mmu_lock);
-       srcu_read_unlock(&kvm->srcu, idx);
-
        /* we've to flush the tlb before the pages can be freed */
        if (need_tlb_flush)
                kvm_flush_remote_tlbs(kvm);
 
+       spin_unlock(&kvm->mmu_lock);
+       srcu_read_unlock(&kvm->srcu, idx);
 }
 
 static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn,
@@ -335,12 +335,12 @@ static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
        for (; start < end; start += PAGE_SIZE)
                need_tlb_flush |= kvm_unmap_hva(kvm, start);
        need_tlb_flush |= kvm->tlbs_dirty;
-       spin_unlock(&kvm->mmu_lock);
-       srcu_read_unlock(&kvm->srcu, idx);
-
        /* we've to flush the tlb before the pages can be freed */
        if (need_tlb_flush)
                kvm_flush_remote_tlbs(kvm);
+
+       spin_unlock(&kvm->mmu_lock);
+       srcu_read_unlock(&kvm->srcu, idx);
 }
 
 static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,
@@ -357,11 +357,11 @@ static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,
         * been freed.
         */
        kvm->mmu_notifier_seq++;
+       smp_wmb();
        /*
         * The above sequence increase must be visible before the
-        * below count decrease but both values are read by the kvm
-        * page fault under mmu_lock spinlock so we don't need to add
-        * a smb_wmb() here in between the two.
+        * below count decrease, which is ensured by the smp_wmb above
+        * in conjunction with the smp_rmb in mmu_notifier_retry().
         */
        kvm->mmu_notifier_count--;
        spin_unlock(&kvm->mmu_lock);
@@ -378,13 +378,14 @@ static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn,
 
        idx = srcu_read_lock(&kvm->srcu);
        spin_lock(&kvm->mmu_lock);
-       young = kvm_age_hva(kvm, address);
-       spin_unlock(&kvm->mmu_lock);
-       srcu_read_unlock(&kvm->srcu, idx);
 
+       young = kvm_age_hva(kvm, address);
        if (young)
                kvm_flush_remote_tlbs(kvm);
 
+       spin_unlock(&kvm->mmu_lock);
+       srcu_read_unlock(&kvm->srcu, idx);
+
        return young;
 }
 
@@ -449,7 +450,7 @@ static void kvm_init_memslots_id(struct kvm *kvm)
                slots->id_to_index[i] = slots->memslots[i].id = i;
 }
 
-static struct kvm *kvm_create_vm(void)
+static struct kvm *kvm_create_vm(unsigned long type)
 {
        int r, i;
        struct kvm *kvm = kvm_arch_alloc_vm();
@@ -457,7 +458,7 @@ static struct kvm *kvm_create_vm(void)
        if (!kvm)
                return ERR_PTR(-ENOMEM);
 
-       r = kvm_arch_init_vm(kvm);
+       r = kvm_arch_init_vm(kvm, type);
        if (r)
                goto out_err_nodisable;
 
@@ -535,21 +536,13 @@ static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot)
 static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
                                  struct kvm_memory_slot *dont)
 {
-       int i;
-
        if (!dont || free->rmap != dont->rmap)
                vfree(free->rmap);
 
        if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
                kvm_destroy_dirty_bitmap(free);
 
-
-       for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
-               if (!dont || free->lpage_info[i] != dont->lpage_info[i]) {
-                       vfree(free->lpage_info[i]);
-                       free->lpage_info[i] = NULL;
-               }
-       }
+       kvm_arch_free_memslot(free, dont);
 
        free->npages = 0;
        free->rmap = NULL;
@@ -616,7 +609,6 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-#ifndef CONFIG_S390
 /*
  * Allocation size is twice as large as the actual dirty bitmap size.
  * This makes it possible to do double buffering: see x86's
@@ -624,6 +616,7 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
  */
 static int kvm_create_dirty_bitmap(struct kvm_memory_slot *memslot)
 {
+#ifndef CONFIG_S390
        unsigned long dirty_bytes = 2 * kvm_dirty_bitmap_bytes(memslot);
 
        if (dirty_bytes > PAGE_SIZE)
@@ -636,21 +629,8 @@ static int kvm_create_dirty_bitmap(struct kvm_memory_slot *memslot)
 
        memslot->dirty_bitmap_head = memslot->dirty_bitmap;
        memslot->nr_dirty_pages = 0;
-       return 0;
-}
 #endif /* !CONFIG_S390 */
-
-static struct kvm_memory_slot *
-search_memslots(struct kvm_memslots *slots, gfn_t gfn)
-{
-       struct kvm_memory_slot *memslot;
-
-       kvm_for_each_memslot(memslot, slots)
-               if (gfn >= memslot->base_gfn &&
-                     gfn < memslot->base_gfn + memslot->npages)
-                       return memslot;
-
-       return NULL;
+       return 0;
 }
 
 static int cmp_memslot(const void *slot1, const void *slot2)
@@ -778,69 +758,24 @@ int __kvm_set_memory_region(struct kvm *kvm,
        r = -ENOMEM;
 
        /* Allocate if a slot is being created */
+       if (npages && !old.npages) {
+               new.user_alloc = user_alloc;
+               new.userspace_addr = mem->userspace_addr;
 #ifndef CONFIG_S390
-       if (npages && !new.rmap) {
                new.rmap = vzalloc(npages * sizeof(*new.rmap));
-
                if (!new.rmap)
                        goto out_free;
-
-               new.user_alloc = user_alloc;
-               new.userspace_addr = mem->userspace_addr;
-       }
-       if (!npages)
-               goto skip_lpage;
-
-       for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
-               unsigned long ugfn;
-               unsigned long j;
-               int lpages;
-               int level = i + 2;
-
-               /* Avoid unused variable warning if no large pages */
-               (void)level;
-
-               if (new.lpage_info[i])
-                       continue;
-
-               lpages = 1 + ((base_gfn + npages - 1)
-                            >> KVM_HPAGE_GFN_SHIFT(level));
-               lpages -= base_gfn >> KVM_HPAGE_GFN_SHIFT(level);
-
-               new.lpage_info[i] = vzalloc(lpages * sizeof(*new.lpage_info[i]));
-
-               if (!new.lpage_info[i])
+#endif /* not defined CONFIG_S390 */
+               if (kvm_arch_create_memslot(&new, npages))
                        goto out_free;
-
-               if (base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
-                       new.lpage_info[i][0].write_count = 1;
-               if ((base_gfn+npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
-                       new.lpage_info[i][lpages - 1].write_count = 1;
-               ugfn = new.userspace_addr >> PAGE_SHIFT;
-               /*
-                * If the gfn and userspace address are not aligned wrt each
-                * other, or if explicitly asked to, disable large page
-                * support for this slot
-                */
-               if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE(level) - 1) ||
-                   !largepages_enabled)
-                       for (j = 0; j < lpages; ++j)
-                               new.lpage_info[i][j].write_count = 1;
        }
 
-skip_lpage:
-
        /* Allocate page dirty bitmap if needed */
        if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
                if (kvm_create_dirty_bitmap(&new) < 0)
                        goto out_free;
                /* destroy any largepage mappings for dirty tracking */
        }
-#else  /* not defined CONFIG_S390 */
-       new.user_alloc = user_alloc;
-       if (user_alloc)
-               new.userspace_addr = mem->userspace_addr;
-#endif /* not defined CONFIG_S390 */
 
        if (!npages) {
                struct kvm_memory_slot *slot;
@@ -890,8 +825,7 @@ skip_lpage:
        if (!npages) {
                new.rmap = NULL;
                new.dirty_bitmap = NULL;
-               for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i)
-                       new.lpage_info[i] = NULL;
+               memset(&new.arch, 0, sizeof(new.arch));
        }
 
        update_memslots(slots, &new);
@@ -978,6 +912,11 @@ out:
        return r;
 }
 
+bool kvm_largepages_enabled(void)
+{
+       return largepages_enabled;
+}
+
 void kvm_disable_largepages(void)
 {
        largepages_enabled = false;
@@ -1031,12 +970,6 @@ int kvm_is_error_hva(unsigned long addr)
 }
 EXPORT_SYMBOL_GPL(kvm_is_error_hva);
 
-static struct kvm_memory_slot *__gfn_to_memslot(struct kvm_memslots *slots,
-                                               gfn_t gfn)
-{
-       return search_memslots(slots, gfn);
-}
-
 struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
 {
        return __gfn_to_memslot(kvm_memslots(kvm), gfn);
@@ -1459,7 +1392,7 @@ int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 
        ghc->gpa = gpa;
        ghc->generation = slots->generation;
-       ghc->memslot = __gfn_to_memslot(slots, gfn);
+       ghc->memslot = gfn_to_memslot(kvm, gfn);
        ghc->hva = gfn_to_hva_many(ghc->memslot, gfn, NULL);
        if (!kvm_is_error_hva(ghc->hva))
                ghc->hva += offset;
@@ -1657,7 +1590,7 @@ static int kvm_vcpu_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                page = virt_to_page(vcpu->kvm->coalesced_mmio_ring);
 #endif
        else
-               return VM_FAULT_SIGBUS;
+               return kvm_arch_vcpu_fault(vcpu, vmf);
        get_page(page);
        vmf->page = page;
        return 0;
@@ -1718,6 +1651,10 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
                goto vcpu_destroy;
 
        mutex_lock(&kvm->lock);
+       if (!kvm_vcpu_compatible(vcpu)) {
+               r = -EINVAL;
+               goto unlock_vcpu_destroy;
+       }
        if (atomic_read(&kvm->online_vcpus) == KVM_MAX_VCPUS) {
                r = -EINVAL;
                goto unlock_vcpu_destroy;
@@ -2198,12 +2135,12 @@ static struct file_operations kvm_vm_fops = {
        .llseek         = noop_llseek,
 };
 
-static int kvm_dev_ioctl_create_vm(void)
+static int kvm_dev_ioctl_create_vm(unsigned long type)
 {
        int r;
        struct kvm *kvm;
 
-       kvm = kvm_create_vm();
+       kvm = kvm_create_vm(type);
        if (IS_ERR(kvm))
                return PTR_ERR(kvm);
 #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
@@ -2254,10 +2191,7 @@ static long kvm_dev_ioctl(struct file *filp,
                r = KVM_API_VERSION;
                break;
        case KVM_CREATE_VM:
-               r = -EINVAL;
-               if (arg)
-                       goto out;
-               r = kvm_dev_ioctl_create_vm();
+               r = kvm_dev_ioctl_create_vm(arg);
                break;
        case KVM_CHECK_EXTENSION:
                r = kvm_dev_ioctl_check_extension_generic(arg);